@servlyadmin/runtime-core 0.1.7 → 0.1.9

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.cjs DELETED
@@ -1,2818 +0,0 @@
1
- "use strict";
2
- var __defProp = Object.defineProperty;
3
- var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
- var __getOwnPropNames = Object.getOwnPropertyNames;
5
- var __hasOwnProp = Object.prototype.hasOwnProperty;
6
- var __esm = (fn, res) => function __init() {
7
- return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
8
- };
9
- var __export = (target, all) => {
10
- for (var name in all)
11
- __defProp(target, name, { get: all[name], enumerable: true });
12
- };
13
- var __copyProps = (to, from, except, desc) => {
14
- if (from && typeof from === "object" || typeof from === "function") {
15
- for (let key of __getOwnPropNames(from))
16
- if (!__hasOwnProp.call(to, key) && key !== except)
17
- __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
18
- }
19
- return to;
20
- };
21
- var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
22
-
23
- // src/registry.ts
24
- var registry_exports = {};
25
- __export(registry_exports, {
26
- buildRegistryFromBundle: () => buildRegistryFromBundle,
27
- collectAllDependencies: () => collectAllDependencies,
28
- createRegistry: () => createRegistry,
29
- detectCircularDependencies: () => detectCircularDependencies,
30
- extractDependencies: () => extractDependencies,
31
- extractDependenciesFromCode: () => extractDependenciesFromCode
32
- });
33
- function createRegistry() {
34
- const components = /* @__PURE__ */ new Map();
35
- return {
36
- get(id, version) {
37
- if (version) {
38
- const key = `${id}@${version}`;
39
- if (components.has(key)) {
40
- return components.get(key);
41
- }
42
- }
43
- for (const [key, component] of components) {
44
- if (key.startsWith(`${id}@`)) {
45
- return component;
46
- }
47
- }
48
- return components.get(id);
49
- },
50
- has(id, version) {
51
- if (version) {
52
- return components.has(`${id}@${version}`);
53
- }
54
- for (const key of components.keys()) {
55
- if (key.startsWith(`${id}@`) || key === id) {
56
- return true;
57
- }
58
- }
59
- return false;
60
- },
61
- set(id, version, component) {
62
- components.set(`${id}@${version}`, component);
63
- }
64
- };
65
- }
66
- function buildRegistryFromBundle(data) {
67
- const registry = createRegistry();
68
- registry.set(data.id, data.version, {
69
- layout: data.layout,
70
- propsInterface: data.propsInterface
71
- });
72
- if (data.bundle) {
73
- for (const [key, component] of Object.entries(data.bundle)) {
74
- const [id, version] = key.split("@");
75
- if (id && version) {
76
- registry.set(id, version, component);
77
- }
78
- }
79
- }
80
- return registry;
81
- }
82
- function extractDependencies(elements) {
83
- const dependencies = [];
84
- for (const element of elements) {
85
- const config = element.configuration;
86
- if (!config) continue;
87
- if (config.componentViewRef) {
88
- dependencies.push({
89
- id: config.componentViewRef,
90
- version: config.componentViewVersion,
91
- type: "viewRef",
92
- elementId: element.i
93
- });
94
- }
95
- if (config.blueprint) {
96
- dependencies.push({
97
- id: config.blueprint,
98
- version: config.blueprintVersion,
99
- type: "blueprint",
100
- elementId: element.i
101
- });
102
- }
103
- }
104
- return dependencies;
105
- }
106
- function extractDependenciesFromCode(code) {
107
- const dependencies = [];
108
- const pattern = /renderDynamicList\s*\(\s*\{[^}]*blueprint\s*:\s*["']([^"']+)["']/g;
109
- let match;
110
- while ((match = pattern.exec(code)) !== null) {
111
- dependencies.push({
112
- id: match[1],
113
- type: "blueprint"
114
- });
115
- }
116
- return dependencies;
117
- }
118
- async function collectAllDependencies(rootId, rootVersion, fetchComponent2, maxDepth = 10) {
119
- const manifest = {};
120
- const visited = /* @__PURE__ */ new Set();
121
- async function collect(id, version, via, depth) {
122
- if (depth > maxDepth) {
123
- console.warn(`Max dependency depth (${maxDepth}) reached for ${id}`);
124
- return;
125
- }
126
- const key = `${id}@${version || "latest"}`;
127
- if (visited.has(key)) {
128
- return;
129
- }
130
- visited.add(key);
131
- try {
132
- const component = await fetchComponent2(id, version);
133
- if (!component) {
134
- console.warn(`Dependency not found: ${id}@${version || "latest"}`);
135
- return;
136
- }
137
- manifest[id] = {
138
- version: version || "latest",
139
- resolved: component.version,
140
- type: via ? "viewRef" : "viewRef",
141
- // Will be set by caller
142
- via
143
- };
144
- const nestedDeps = extractDependencies(component.layout);
145
- for (const dep of nestedDeps) {
146
- await collect(dep.id, dep.version, id, depth + 1);
147
- }
148
- } catch (error) {
149
- console.error(`Failed to fetch dependency ${id}:`, error);
150
- }
151
- }
152
- const rootComponent = await fetchComponent2(rootId, rootVersion);
153
- if (rootComponent) {
154
- const rootDeps = extractDependencies(rootComponent.layout);
155
- for (const dep of rootDeps) {
156
- manifest[dep.id] = {
157
- version: dep.version || "latest",
158
- resolved: "",
159
- // Will be filled when fetched
160
- type: dep.type
161
- };
162
- await collect(dep.id, dep.version, void 0, 1);
163
- }
164
- }
165
- return manifest;
166
- }
167
- function detectCircularDependencies(manifest) {
168
- const graph = /* @__PURE__ */ new Map();
169
- for (const [id, entry] of Object.entries(manifest)) {
170
- if (entry.via) {
171
- const deps = graph.get(entry.via) || [];
172
- deps.push(id);
173
- graph.set(entry.via, deps);
174
- }
175
- }
176
- const visited = /* @__PURE__ */ new Set();
177
- const stack = /* @__PURE__ */ new Set();
178
- const path = [];
179
- function dfs(node) {
180
- if (stack.has(node)) {
181
- const cycleStart = path.indexOf(node);
182
- return [...path.slice(cycleStart), node];
183
- }
184
- if (visited.has(node)) {
185
- return null;
186
- }
187
- visited.add(node);
188
- stack.add(node);
189
- path.push(node);
190
- const neighbors = graph.get(node) || [];
191
- for (const neighbor of neighbors) {
192
- const cycle = dfs(neighbor);
193
- if (cycle) return cycle;
194
- }
195
- stack.delete(node);
196
- path.pop();
197
- return null;
198
- }
199
- for (const node of graph.keys()) {
200
- const cycle = dfs(node);
201
- if (cycle) return cycle;
202
- }
203
- return null;
204
- }
205
- var init_registry = __esm({
206
- "src/registry.ts"() {
207
- "use strict";
208
- }
209
- });
210
-
211
- // src/index.ts
212
- var index_exports = {};
213
- __export(index_exports, {
214
- AnalyticsCollector: () => AnalyticsCollector,
215
- DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG,
216
- DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
217
- LongTaskObserver: () => LongTaskObserver,
218
- MemorySampler: () => MemorySampler,
219
- SessionManager: () => SessionManager,
220
- analytics: () => analytics,
221
- applyStyles: () => applyStyles,
222
- batchFetchComponents: () => batchFetchComponents,
223
- buildClassName: () => buildClassName,
224
- buildElementStyles: () => buildElementStyles,
225
- buildRegistryFromBundle: () => buildRegistryFromBundle,
226
- bumpVersion: () => bumpVersion,
227
- camelToKebab: () => camelToKebab,
228
- clearAllCaches: () => clearAllCaches,
229
- clearLocalStorageCache: () => clearLocalStorageCache,
230
- clearMemoryCache: () => clearMemoryCache,
231
- clearStyles: () => clearStyles,
232
- collectAllDependencies: () => collectAllDependencies,
233
- compareVersions: () => compareVersions,
234
- configureAnalytics: () => configureAnalytics,
235
- createRegistry: () => createRegistry,
236
- detectCircularDependencies: () => detectCircularDependencies,
237
- extractBindingKeys: () => extractBindingKeys,
238
- extractDependencies: () => extractDependencies,
239
- extractDependenciesFromCode: () => extractDependenciesFromCode,
240
- fetchComponent: () => fetchComponent,
241
- fetchComponentWithDependencies: () => fetchComponentWithDependencies,
242
- formatStyleValue: () => formatStyleValue,
243
- formatVersion: () => formatVersion,
244
- generateTestCases: () => generateTestCases,
245
- getAnalytics: () => getAnalytics,
246
- getCacheKey: () => getCacheKey,
247
- getDependencyTree: () => getDependencyTree,
248
- getFromCache: () => getFromCache,
249
- getLongTaskObserver: () => getLongTaskObserver,
250
- getMemoryCacheSize: () => getMemoryCacheSize,
251
- getMemorySampler: () => getMemorySampler,
252
- getRegistryUrl: () => getRegistryUrl,
253
- getSessionManager: () => getSessionManager,
254
- hasTemplateSyntax: () => hasTemplateSyntax,
255
- invalidateCache: () => invalidateCache,
256
- isComponentAvailable: () => isComponentAvailable,
257
- isValidSpecifier: () => isValidSpecifier,
258
- parseVersion: () => parseVersion,
259
- prefetchComponents: () => prefetchComponents,
260
- processStyles: () => processStyles,
261
- render: () => render,
262
- renderDynamicList: () => renderDynamicList,
263
- resetAnalytics: () => resetAnalytics,
264
- resetLongTaskObserver: () => resetLongTaskObserver,
265
- resetMemorySampler: () => resetMemorySampler,
266
- resetSessionManager: () => resetSessionManager,
267
- resolveBindingPath: () => resolveBindingPath,
268
- resolveTemplate: () => resolveTemplate,
269
- resolveTemplateValue: () => resolveTemplateValue,
270
- resolveTemplatesDeep: () => resolveTemplatesDeep,
271
- resolveVersion: () => resolveVersion,
272
- runAllTests: () => runAllTests,
273
- runTestCase: () => runTestCase,
274
- satisfiesVersion: () => satisfiesVersion,
275
- setInCache: () => setInCache,
276
- setRegistryUrl: () => setRegistryUrl,
277
- updateStyles: () => updateStyles,
278
- validateAssertion: () => validateAssertion,
279
- validateProps: () => validateProps
280
- });
281
- module.exports = __toCommonJS(index_exports);
282
-
283
- // src/analyticsTypes.ts
284
- var DEFAULT_ANALYTICS_CONFIG = {
285
- enabled: true,
286
- endpoint: "/api/v1/analytics/events",
287
- batchSize: 50,
288
- flushInterval: 3e4,
289
- // 30 seconds
290
- sampleRate: 1,
291
- environment: "production",
292
- debug: false
293
- };
294
- var MAX_ERROR_MESSAGE_LENGTH = 1e3;
295
- var MAX_STACK_TRACE_LENGTH = 500;
296
- var MAX_QUEUE_SIZE = 500;
297
- var MAX_RETRY_ATTEMPTS = 3;
298
- var SESSION_TIMEOUT_MS = 30 * 60 * 1e3;
299
- var SDK_VERSION = "1.0.0";
300
-
301
- // src/sessionManager.ts
302
- var SESSION_STORAGE_KEY = "servly_analytics_session";
303
- function generateUUID() {
304
- if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
305
- return crypto.randomUUID();
306
- }
307
- return "xxxxxxxx-xxxx-4xxx-yxxx-xxxxxxxxxxxx".replace(/[xy]/g, (c) => {
308
- const r = Math.random() * 16 | 0;
309
- const v = c === "x" ? r : r & 3 | 8;
310
- return v.toString(16);
311
- });
312
- }
313
- function isSessionStorageAvailable() {
314
- try {
315
- if (typeof sessionStorage === "undefined") {
316
- return false;
317
- }
318
- const testKey = "__servly_test__";
319
- sessionStorage.setItem(testKey, "test");
320
- sessionStorage.removeItem(testKey);
321
- return true;
322
- } catch {
323
- return false;
324
- }
325
- }
326
- function loadSession() {
327
- if (!isSessionStorageAvailable()) {
328
- return null;
329
- }
330
- try {
331
- const stored = sessionStorage.getItem(SESSION_STORAGE_KEY);
332
- if (!stored) {
333
- return null;
334
- }
335
- return JSON.parse(stored);
336
- } catch {
337
- return null;
338
- }
339
- }
340
- function saveSession(session) {
341
- if (!isSessionStorageAvailable()) {
342
- return;
343
- }
344
- try {
345
- sessionStorage.setItem(SESSION_STORAGE_KEY, JSON.stringify(session));
346
- } catch {
347
- }
348
- }
349
- function clearSession() {
350
- if (!isSessionStorageAvailable()) {
351
- return;
352
- }
353
- try {
354
- sessionStorage.removeItem(SESSION_STORAGE_KEY);
355
- } catch {
356
- }
357
- }
358
- function isSessionExpired(session) {
359
- const now = Date.now();
360
- return now - session.lastActivityAt > SESSION_TIMEOUT_MS;
361
- }
362
- var SessionManager = class {
363
- constructor() {
364
- this.session = null;
365
- this.initialize();
366
- }
367
- /**
368
- * Initialize session manager
369
- */
370
- initialize() {
371
- const stored = loadSession();
372
- if (stored && !isSessionExpired(stored)) {
373
- this.session = stored;
374
- this.touch();
375
- } else {
376
- this.createNewSession();
377
- }
378
- }
379
- /**
380
- * Create a new session
381
- */
382
- createNewSession() {
383
- const now = Date.now();
384
- this.session = {
385
- id: generateUUID(),
386
- createdAt: now,
387
- lastActivityAt: now
388
- };
389
- saveSession(this.session);
390
- }
391
- /**
392
- * Get current session ID
393
- * Creates new session if expired
394
- */
395
- getSessionId() {
396
- if (!this.session || isSessionExpired(this.session)) {
397
- this.createNewSession();
398
- }
399
- return this.session.id;
400
- }
401
- /**
402
- * Update last activity timestamp
403
- */
404
- touch() {
405
- if (this.session) {
406
- this.session.lastActivityAt = Date.now();
407
- saveSession(this.session);
408
- }
409
- }
410
- /**
411
- * Force create a new session
412
- */
413
- rotate() {
414
- this.createNewSession();
415
- }
416
- /**
417
- * Clear current session
418
- */
419
- clear() {
420
- this.session = null;
421
- clearSession();
422
- }
423
- /**
424
- * Get session info (for debugging)
425
- */
426
- getSessionInfo() {
427
- return this.session ? { ...this.session } : null;
428
- }
429
- };
430
- var sessionManagerInstance = null;
431
- function getSessionManager() {
432
- if (!sessionManagerInstance) {
433
- sessionManagerInstance = new SessionManager();
434
- }
435
- return sessionManagerInstance;
436
- }
437
- function resetSessionManager() {
438
- if (sessionManagerInstance) {
439
- sessionManagerInstance.clear();
440
- }
441
- sessionManagerInstance = null;
442
- }
443
-
444
- // src/analytics.ts
445
- var AnalyticsCollector = class {
446
- constructor(config) {
447
- this.eventQueue = [];
448
- this.flushTimer = null;
449
- this.isFlushing = false;
450
- this.retryDelay = 1e3;
451
- this.config = { ...DEFAULT_ANALYTICS_CONFIG, ...config };
452
- this.isEnabled = this.config.enabled;
453
- this.startFlushTimer();
454
- }
455
- // ============================================
456
- // Configuration
457
- // ============================================
458
- /**
459
- * Configure analytics
460
- */
461
- configure(config) {
462
- this.config = { ...this.config, ...config };
463
- this.isEnabled = this.config.enabled;
464
- this.stopFlushTimer();
465
- if (this.isEnabled) {
466
- this.startFlushTimer();
467
- }
468
- }
469
- /**
470
- * Disable analytics collection
471
- */
472
- disable() {
473
- this.isEnabled = false;
474
- this.stopFlushTimer();
475
- this.eventQueue = [];
476
- }
477
- /**
478
- * Enable analytics collection
479
- */
480
- enable() {
481
- this.isEnabled = true;
482
- this.startFlushTimer();
483
- }
484
- /**
485
- * Destroy and cleanup
486
- */
487
- destroy() {
488
- this.disable();
489
- }
490
- // ============================================
491
- // Event Tracking
492
- // ============================================
493
- /**
494
- * Track component render
495
- */
496
- trackRender(componentId, version, duration, metadata) {
497
- if (!this.shouldTrack()) {
498
- return;
499
- }
500
- const event = {
501
- type: "render",
502
- componentId,
503
- version,
504
- timestamp: Date.now(),
505
- sessionId: getSessionManager().getSessionId(),
506
- appId: this.config.appId,
507
- duration: Math.round(duration),
508
- metadata
509
- };
510
- this.queueEvent(event);
511
- }
512
- /**
513
- * Track component fetch
514
- */
515
- trackFetch(componentId, version, duration, fromCache, metadata) {
516
- if (!this.shouldTrack()) {
517
- return;
518
- }
519
- const event = {
520
- type: "fetch",
521
- componentId,
522
- version,
523
- timestamp: Date.now(),
524
- sessionId: getSessionManager().getSessionId(),
525
- appId: this.config.appId,
526
- duration: Math.round(duration),
527
- metadata: {
528
- cacheHit: fromCache,
529
- fetchDuration: Math.round(duration),
530
- ...metadata
531
- }
532
- };
533
- this.queueEvent(event);
534
- }
535
- /**
536
- * Track error
537
- */
538
- trackError(componentId, version, error, context) {
539
- if (!this.shouldTrack()) {
540
- return;
541
- }
542
- const errorMessage = this.truncateString(
543
- error.message || "Unknown error",
544
- MAX_ERROR_MESSAGE_LENGTH
545
- );
546
- const stackTrace = error.stack ? this.truncateString(error.stack, MAX_STACK_TRACE_LENGTH) : void 0;
547
- const event = {
548
- type: "error",
549
- componentId,
550
- version,
551
- timestamp: Date.now(),
552
- sessionId: getSessionManager().getSessionId(),
553
- appId: this.config.appId,
554
- metadata: {
555
- errorType: context?.errorType || "render",
556
- errorMessage,
557
- stackTrace,
558
- bindingPath: context?.bindingPath,
559
- elementId: context?.elementId
560
- }
561
- };
562
- this.queueEvent(event);
563
- }
564
- // ============================================
565
- // Queue Management
566
- // ============================================
567
- /**
568
- * Check if event should be tracked (sampling + enabled)
569
- */
570
- shouldTrack() {
571
- if (!this.isEnabled) {
572
- return false;
573
- }
574
- if (this.config.sampleRate < 1) {
575
- return Math.random() < this.config.sampleRate;
576
- }
577
- return true;
578
- }
579
- /**
580
- * Add event to queue
581
- */
582
- queueEvent(event) {
583
- if (this.eventQueue.length >= MAX_QUEUE_SIZE) {
584
- this.eventQueue.shift();
585
- this.log("Queue full, dropping oldest event");
586
- }
587
- this.eventQueue.push({
588
- event,
589
- retryCount: 0,
590
- addedAt: Date.now()
591
- });
592
- if (this.eventQueue.length >= this.config.batchSize) {
593
- this.flush();
594
- }
595
- }
596
- /**
597
- * Get current queue size
598
- */
599
- getQueueSize() {
600
- return this.eventQueue.length;
601
- }
602
- // ============================================
603
- // Flush Logic
604
- // ============================================
605
- /**
606
- * Start the flush timer
607
- */
608
- startFlushTimer() {
609
- if (this.flushTimer) {
610
- return;
611
- }
612
- this.flushTimer = setInterval(() => {
613
- this.flush();
614
- }, this.config.flushInterval);
615
- }
616
- /**
617
- * Stop the flush timer
618
- */
619
- stopFlushTimer() {
620
- if (this.flushTimer) {
621
- clearInterval(this.flushTimer);
622
- this.flushTimer = null;
623
- }
624
- }
625
- /**
626
- * Flush events to server
627
- */
628
- async flush() {
629
- if (this.isFlushing || this.eventQueue.length === 0) {
630
- return;
631
- }
632
- this.isFlushing = true;
633
- if (typeof requestIdleCallback !== "undefined") {
634
- requestIdleCallback(
635
- () => {
636
- this.doFlush();
637
- },
638
- { timeout: 5e3 }
639
- );
640
- } else {
641
- setTimeout(() => {
642
- this.doFlush();
643
- }, 0);
644
- }
645
- }
646
- /**
647
- * Perform the actual flush
648
- */
649
- async doFlush() {
650
- const eventsToSend = this.eventQueue.splice(0, this.config.batchSize);
651
- if (eventsToSend.length === 0) {
652
- this.isFlushing = false;
653
- return;
654
- }
655
- const request = {
656
- events: eventsToSend.map((q) => q.event),
657
- clientInfo: {
658
- sdkVersion: SDK_VERSION,
659
- environment: this.config.environment
660
- }
661
- };
662
- try {
663
- const response = await this.sendEvents(request);
664
- if (response.success) {
665
- this.log(`Flushed ${response.accepted} events`);
666
- this.retryDelay = 1e3;
667
- } else {
668
- this.handleFailedEvents(eventsToSend, response);
669
- }
670
- } catch (error) {
671
- this.handleNetworkError(eventsToSend, error);
672
- } finally {
673
- this.isFlushing = false;
674
- }
675
- }
676
- /**
677
- * Send events to the API
678
- */
679
- async sendEvents(request) {
680
- const headers = {
681
- "Content-Type": "application/json"
682
- };
683
- if (this.config.apiKey) {
684
- headers["Authorization"] = `Bearer ${this.config.apiKey}`;
685
- }
686
- const response = await fetch(this.config.endpoint, {
687
- method: "POST",
688
- headers,
689
- body: JSON.stringify(request)
690
- });
691
- if (response.status === 429) {
692
- const retryAfter = parseInt(response.headers.get("Retry-After") || "60", 10);
693
- return {
694
- success: false,
695
- accepted: 0,
696
- rejected: request.events.length,
697
- retryAfter
698
- };
699
- }
700
- if (!response.ok) {
701
- throw new Error(`HTTP ${response.status}: ${response.statusText}`);
702
- }
703
- return await response.json();
704
- }
705
- /**
706
- * Handle failed events (partial success)
707
- */
708
- handleFailedEvents(events, response) {
709
- const eventsToRetry = events.filter((e) => e.retryCount < MAX_RETRY_ATTEMPTS);
710
- eventsToRetry.forEach((e) => {
711
- e.retryCount++;
712
- this.eventQueue.unshift(e);
713
- });
714
- const dropped = events.length - eventsToRetry.length;
715
- if (dropped > 0) {
716
- this.log(`Dropped ${dropped} events after max retries`);
717
- }
718
- if (response.retryAfter) {
719
- this.scheduleRetry(response.retryAfter * 1e3);
720
- }
721
- }
722
- /**
723
- * Handle network error
724
- */
725
- handleNetworkError(events, error) {
726
- this.log(`Network error: ${error}`);
727
- const eventsToRetry = events.filter((e) => e.retryCount < MAX_RETRY_ATTEMPTS);
728
- eventsToRetry.forEach((e) => {
729
- e.retryCount++;
730
- this.eventQueue.unshift(e);
731
- });
732
- this.scheduleRetry(this.retryDelay);
733
- this.retryDelay = Math.min(this.retryDelay * 2, 3e4);
734
- }
735
- /**
736
- * Schedule a retry flush
737
- */
738
- scheduleRetry(delayMs) {
739
- setTimeout(() => {
740
- this.flush();
741
- }, delayMs);
742
- }
743
- // ============================================
744
- // Utilities
745
- // ============================================
746
- /**
747
- * Truncate string to max length
748
- */
749
- truncateString(str, maxLength) {
750
- if (str.length <= maxLength) {
751
- return str;
752
- }
753
- return str.substring(0, maxLength - 3) + "...";
754
- }
755
- /**
756
- * Log debug message
757
- */
758
- log(message) {
759
- if (this.config.debug) {
760
- console.log(`[Analytics] ${message}`);
761
- }
762
- }
763
- };
764
- var analyticsInstance = null;
765
- function getAnalytics() {
766
- if (!analyticsInstance) {
767
- analyticsInstance = new AnalyticsCollector();
768
- }
769
- return analyticsInstance;
770
- }
771
- function configureAnalytics(config) {
772
- getAnalytics().configure(config);
773
- }
774
- function resetAnalytics() {
775
- if (analyticsInstance) {
776
- analyticsInstance.destroy();
777
- }
778
- analyticsInstance = null;
779
- }
780
- var analytics = {
781
- get instance() {
782
- return getAnalytics();
783
- },
784
- configure: configureAnalytics,
785
- trackRender: (componentId, version, duration, metadata) => getAnalytics().trackRender(componentId, version, duration, metadata),
786
- trackFetch: (componentId, version, duration, fromCache, metadata) => getAnalytics().trackFetch(componentId, version, duration, fromCache, metadata),
787
- trackError: (componentId, version, error, context) => getAnalytics().trackError(componentId, version, error, context),
788
- flush: () => getAnalytics().flush(),
789
- disable: () => getAnalytics().disable(),
790
- enable: () => getAnalytics().enable()
791
- };
792
-
793
- // src/bindings.ts
794
- var BINDING_SOURCES = [
795
- "props",
796
- "state",
797
- "appState",
798
- "context",
799
- "input",
800
- "currentItem",
801
- "localStore",
802
- "config",
803
- "element",
804
- "self",
805
- "params",
806
- "query"
807
- ];
808
- var TEMPLATE_REGEX = /\{\{([^}]+)\}\}/g;
809
- function hasTemplateSyntax(value) {
810
- return typeof value === "string" && value.includes("{{") && value.includes("}}");
811
- }
812
- function resolveBindingPath(path, context) {
813
- const trimmed = path.trim();
814
- const parts = trimmed.split(".");
815
- if (parts.length === 0) {
816
- return void 0;
817
- }
818
- const prefix = parts[0].toLowerCase();
819
- let source;
820
- let startIndex = 0;
821
- if (prefix === "props" || prefix === "input") {
822
- source = context.props;
823
- startIndex = 1;
824
- } else if (prefix === "state" || prefix === "appstate") {
825
- source = context.state;
826
- startIndex = 1;
827
- } else if (prefix === "context") {
828
- source = context.context;
829
- startIndex = 1;
830
- } else if (BINDING_SOURCES.includes(prefix)) {
831
- source = context.props;
832
- startIndex = 1;
833
- } else {
834
- source = context.props;
835
- startIndex = 0;
836
- }
837
- if (!source) {
838
- return void 0;
839
- }
840
- let value = source;
841
- for (let i = startIndex; i < parts.length; i++) {
842
- if (value === null || value === void 0) {
843
- return void 0;
844
- }
845
- value = value[parts[i]];
846
- }
847
- return value;
848
- }
849
- function resolveExpression(expression, context) {
850
- const trimmed = expression.trim();
851
- const defaultMatch = trimmed.match(/^(.+?)\|\|(.+)$/);
852
- if (defaultMatch) {
853
- const mainValue = resolveExpression(defaultMatch[1].trim(), context);
854
- if (mainValue !== void 0 && mainValue !== null && mainValue !== "") {
855
- return mainValue;
856
- }
857
- const defaultVal = defaultMatch[2].trim();
858
- if (defaultVal.startsWith('"') && defaultVal.endsWith('"') || defaultVal.startsWith("'") && defaultVal.endsWith("'")) {
859
- return defaultVal.slice(1, -1);
860
- }
861
- if (!isNaN(Number(defaultVal))) {
862
- return Number(defaultVal);
863
- }
864
- if (defaultVal === "true") return true;
865
- if (defaultVal === "false") return false;
866
- return resolveExpression(defaultVal, context);
867
- }
868
- const ternaryMatch = trimmed.match(/^(.+?)\s*\?\s*(.+?)\s*:\s*(.+)$/);
869
- if (ternaryMatch) {
870
- const condition = resolveExpression(ternaryMatch[1].trim(), context);
871
- if (condition) {
872
- return resolveTernaryValue(ternaryMatch[2].trim(), context);
873
- }
874
- return resolveTernaryValue(ternaryMatch[3].trim(), context);
875
- }
876
- if (trimmed.includes("&&")) {
877
- const parts = trimmed.split("&&");
878
- for (const part of parts) {
879
- const value = resolveExpression(part.trim(), context);
880
- if (!value) return value;
881
- }
882
- return resolveExpression(parts[parts.length - 1].trim(), context);
883
- }
884
- return resolveBindingPath(trimmed, context);
885
- }
886
- function resolveTernaryValue(value, context) {
887
- if (value.startsWith("'") && value.endsWith("'") || value.startsWith('"') && value.endsWith('"')) {
888
- return value.slice(1, -1);
889
- }
890
- if (!isNaN(Number(value))) {
891
- return Number(value);
892
- }
893
- if (value === "true") return true;
894
- if (value === "false") return false;
895
- if (value === "null") return null;
896
- if (value === "undefined") return void 0;
897
- return resolveExpression(value, context);
898
- }
899
- function resolveTemplate(template, context, componentId) {
900
- if (!template || typeof template !== "string") {
901
- return template;
902
- }
903
- if (!hasTemplateSyntax(template)) {
904
- return template;
905
- }
906
- try {
907
- const singleMatch = template.match(/^\{\{([^}]+)\}\}$/);
908
- if (singleMatch) {
909
- const value = resolveExpression(singleMatch[1], context);
910
- if (value === void 0 || value === null) {
911
- return "";
912
- }
913
- return String(value);
914
- }
915
- return template.replace(TEMPLATE_REGEX, (match, expression) => {
916
- const value = resolveExpression(expression, context);
917
- if (value === void 0 || value === null) {
918
- return "";
919
- }
920
- if (typeof value === "object") {
921
- return JSON.stringify(value);
922
- }
923
- return String(value);
924
- });
925
- } catch (error) {
926
- if (componentId) {
927
- analytics.trackError(componentId, "latest", error, {
928
- errorType: "binding",
929
- bindingPath: template
930
- });
931
- }
932
- return "";
933
- }
934
- }
935
- function resolveTemplateValue(template, context, componentId) {
936
- if (!template || typeof template !== "string") {
937
- return template;
938
- }
939
- if (!hasTemplateSyntax(template)) {
940
- return template;
941
- }
942
- try {
943
- const singleMatch = template.match(/^\{\{([^}]+)\}\}$/);
944
- if (singleMatch) {
945
- return resolveExpression(singleMatch[1], context);
946
- }
947
- return resolveTemplate(template, context, componentId);
948
- } catch (error) {
949
- if (componentId) {
950
- analytics.trackError(componentId, "latest", error, {
951
- errorType: "binding",
952
- bindingPath: template
953
- });
954
- }
955
- return void 0;
956
- }
957
- }
958
- function isPlainObject(value) {
959
- return Object.prototype.toString.call(value) === "[object Object]";
960
- }
961
- function resolveTemplatesDeep(input, context) {
962
- if (typeof input === "string") {
963
- return resolveTemplateValue(input, context);
964
- }
965
- if (Array.isArray(input)) {
966
- let changed = false;
967
- const result = input.map((item) => {
968
- const resolved = resolveTemplatesDeep(item, context);
969
- if (resolved !== item) {
970
- changed = true;
971
- }
972
- return resolved;
973
- });
974
- return changed ? result : input;
975
- }
976
- if (input && typeof input === "object") {
977
- if (!isPlainObject(input)) {
978
- return input;
979
- }
980
- let mutable = null;
981
- const original = input;
982
- for (const key of Object.keys(original)) {
983
- const current = original[key];
984
- const resolved = resolveTemplatesDeep(current, context);
985
- if (resolved !== current) {
986
- const target = mutable ?? (mutable = { ...original });
987
- target[key] = resolved;
988
- }
989
- }
990
- return mutable ?? input;
991
- }
992
- return input;
993
- }
994
- function extractBindingKeys(template) {
995
- if (!template || typeof template !== "string") {
996
- return [];
997
- }
998
- const keys = /* @__PURE__ */ new Set();
999
- const matches = template.matchAll(TEMPLATE_REGEX);
1000
- for (const match of matches) {
1001
- const expression = match[1].trim();
1002
- const pathMatch = expression.match(/^([a-zA-Z_][a-zA-Z0-9_.]*)/);
1003
- if (pathMatch) {
1004
- const parts = pathMatch[1].split(".");
1005
- if (parts.length > 1 && BINDING_SOURCES.includes(parts[0].toLowerCase())) {
1006
- keys.add(parts[parts.length - 1]);
1007
- } else {
1008
- keys.add(parts[0]);
1009
- }
1010
- }
1011
- }
1012
- return Array.from(keys);
1013
- }
1014
-
1015
- // src/styles.ts
1016
- var UNITLESS_PROPERTIES = /* @__PURE__ */ new Set([
1017
- "animationIterationCount",
1018
- "borderImageOutset",
1019
- "borderImageSlice",
1020
- "borderImageWidth",
1021
- "boxFlex",
1022
- "boxFlexGroup",
1023
- "boxOrdinalGroup",
1024
- "columnCount",
1025
- "columns",
1026
- "flex",
1027
- "flexGrow",
1028
- "flexPositive",
1029
- "flexShrink",
1030
- "flexNegative",
1031
- "flexOrder",
1032
- "gridRow",
1033
- "gridRowEnd",
1034
- "gridRowSpan",
1035
- "gridRowStart",
1036
- "gridColumn",
1037
- "gridColumnEnd",
1038
- "gridColumnSpan",
1039
- "gridColumnStart",
1040
- "fontWeight",
1041
- "lineClamp",
1042
- "lineHeight",
1043
- "opacity",
1044
- "order",
1045
- "orphans",
1046
- "tabSize",
1047
- "widows",
1048
- "zIndex",
1049
- "zoom",
1050
- "fillOpacity",
1051
- "floodOpacity",
1052
- "stopOpacity",
1053
- "strokeDasharray",
1054
- "strokeDashoffset",
1055
- "strokeMiterlimit",
1056
- "strokeOpacity",
1057
- "strokeWidth"
1058
- ]);
1059
- function camelToKebab(str) {
1060
- return str.replace(/([A-Z])/g, "-$1").toLowerCase();
1061
- }
1062
- function needsUnits(property) {
1063
- if (property.startsWith("--")) {
1064
- return false;
1065
- }
1066
- return !UNITLESS_PROPERTIES.has(property);
1067
- }
1068
- function formatStyleValue(property, value) {
1069
- if (value === null || value === void 0) {
1070
- return "";
1071
- }
1072
- if (typeof value === "number" && needsUnits(property)) {
1073
- return `${value}px`;
1074
- }
1075
- return String(value);
1076
- }
1077
- function processStyles(style, context) {
1078
- if (!style || Object.keys(style).length === 0) {
1079
- return {};
1080
- }
1081
- const processed = {};
1082
- for (const [key, value] of Object.entries(style)) {
1083
- if (value === void 0 || value === null || value === "") {
1084
- continue;
1085
- }
1086
- let resolvedValue = value;
1087
- if (typeof value === "string" && hasTemplateSyntax(value)) {
1088
- resolvedValue = resolveTemplate(value, context);
1089
- }
1090
- if (resolvedValue === void 0 || resolvedValue === null || resolvedValue === "") {
1091
- continue;
1092
- }
1093
- const formattedValue = formatStyleValue(key, resolvedValue);
1094
- if (formattedValue) {
1095
- processed[key] = formattedValue;
1096
- }
1097
- }
1098
- return processed;
1099
- }
1100
- function applyStyles(element, styles) {
1101
- for (const [property, value] of Object.entries(styles)) {
1102
- if (property.startsWith("--")) {
1103
- element.style.setProperty(property, value);
1104
- } else {
1105
- element.style[property] = value;
1106
- }
1107
- }
1108
- }
1109
- var CANVAS_ONLY_STYLES = /* @__PURE__ */ new Set([
1110
- "transform",
1111
- "--translate-x",
1112
- "--translate-y",
1113
- "--width",
1114
- "--height",
1115
- "z-index",
1116
- "zIndex"
1117
- ]);
1118
- function filterCanvasStyles(style) {
1119
- const filtered = {};
1120
- for (const [key, value] of Object.entries(style)) {
1121
- if (CANVAS_ONLY_STYLES.has(key)) {
1122
- continue;
1123
- }
1124
- if (key === "transform" && typeof value === "string" && value.includes("translate(")) {
1125
- continue;
1126
- }
1127
- filtered[key] = value;
1128
- }
1129
- return filtered;
1130
- }
1131
- function buildElementStyles(element, context) {
1132
- const config = element.configuration || {};
1133
- const combined = {};
1134
- if (element.style) {
1135
- Object.assign(combined, filterCanvasStyles(element.style));
1136
- }
1137
- if (config.style) {
1138
- Object.assign(combined, filterCanvasStyles(config.style));
1139
- }
1140
- if (config.cssVariables) {
1141
- Object.assign(combined, filterCanvasStyles(config.cssVariables));
1142
- }
1143
- return processStyles(combined, context);
1144
- }
1145
- function buildClassName(element, context) {
1146
- const config = element.configuration || {};
1147
- const classes = [];
1148
- if (element.className) {
1149
- classes.push(element.className);
1150
- }
1151
- if (config.className) {
1152
- const resolved = hasTemplateSyntax(config.className) ? resolveTemplate(config.className, context) : config.className;
1153
- if (resolved) classes.push(resolved);
1154
- }
1155
- if (config.classNames) {
1156
- const resolved = hasTemplateSyntax(config.classNames) ? resolveTemplate(config.classNames, context) : config.classNames;
1157
- if (resolved) classes.push(resolved);
1158
- }
1159
- if (config.dynamicClassName) {
1160
- const resolved = resolveTemplate(config.dynamicClassName, context);
1161
- if (resolved) classes.push(resolved);
1162
- }
1163
- return classes.filter(Boolean).join(" ").trim();
1164
- }
1165
- function clearStyles(element) {
1166
- element.removeAttribute("style");
1167
- }
1168
- function updateStyles(element, oldStyles, newStyles) {
1169
- for (const property of Object.keys(oldStyles)) {
1170
- if (!(property in newStyles)) {
1171
- if (property.startsWith("--")) {
1172
- element.style.removeProperty(property);
1173
- } else {
1174
- element.style[property] = "";
1175
- }
1176
- }
1177
- }
1178
- for (const [property, value] of Object.entries(newStyles)) {
1179
- if (oldStyles[property] !== value) {
1180
- if (property.startsWith("--")) {
1181
- element.style.setProperty(property, value);
1182
- } else {
1183
- element.style[property] = value;
1184
- }
1185
- }
1186
- }
1187
- }
1188
-
1189
- // src/memorySampler.ts
1190
- var MemorySampler = class {
1191
- constructor() {
1192
- this.isSupported = this.checkSupport();
1193
- }
1194
- /**
1195
- * Check if memory API is available
1196
- */
1197
- checkSupport() {
1198
- if (typeof performance === "undefined") {
1199
- return false;
1200
- }
1201
- const perf = performance;
1202
- return typeof perf.memory !== "undefined";
1203
- }
1204
- /**
1205
- * Check if memory sampling is available
1206
- */
1207
- isAvailable() {
1208
- return this.isSupported;
1209
- }
1210
- /**
1211
- * Take a memory sample
1212
- * Returns null if memory API is not available
1213
- */
1214
- sample() {
1215
- if (!this.isSupported) {
1216
- return null;
1217
- }
1218
- const perf = performance;
1219
- if (!perf.memory) {
1220
- return null;
1221
- }
1222
- return {
1223
- heapUsedKB: Math.round(perf.memory.usedJSHeapSize / 1024),
1224
- heapTotalKB: Math.round(perf.memory.totalJSHeapSize / 1024),
1225
- timestamp: Date.now()
1226
- };
1227
- }
1228
- /**
1229
- * Calculate heap delta between two samples
1230
- * Returns the difference in KB (positive = memory increased)
1231
- */
1232
- calculateDelta(before, after) {
1233
- if (!before || !after) {
1234
- return null;
1235
- }
1236
- return after.heapUsedKB - before.heapUsedKB;
1237
- }
1238
- };
1239
- var memorySamplerInstance = null;
1240
- function getMemorySampler() {
1241
- if (!memorySamplerInstance) {
1242
- memorySamplerInstance = new MemorySampler();
1243
- }
1244
- return memorySamplerInstance;
1245
- }
1246
- function resetMemorySampler() {
1247
- memorySamplerInstance = null;
1248
- }
1249
-
1250
- // src/longTaskObserver.ts
1251
- var LongTaskObserver = class {
1252
- constructor() {
1253
- this.observer = null;
1254
- this.longTaskCount = 0;
1255
- this.isObserving = false;
1256
- this.isSupported = this.checkSupport();
1257
- }
1258
- /**
1259
- * Check if PerformanceObserver with longtask support is available
1260
- */
1261
- checkSupport() {
1262
- if (typeof PerformanceObserver === "undefined") {
1263
- return false;
1264
- }
1265
- try {
1266
- const supportedTypes = PerformanceObserver.supportedEntryTypes;
1267
- return Array.isArray(supportedTypes) && supportedTypes.includes("longtask");
1268
- } catch {
1269
- return false;
1270
- }
1271
- }
1272
- /**
1273
- * Check if long task observation is available
1274
- */
1275
- isAvailable() {
1276
- return this.isSupported;
1277
- }
1278
- /**
1279
- * Start observing long tasks
1280
- */
1281
- start() {
1282
- if (!this.isSupported || this.isObserving) {
1283
- return;
1284
- }
1285
- this.longTaskCount = 0;
1286
- try {
1287
- this.observer = new PerformanceObserver((list) => {
1288
- const entries = list.getEntries();
1289
- this.longTaskCount += entries.length;
1290
- });
1291
- this.observer.observe({ entryTypes: ["longtask"] });
1292
- this.isObserving = true;
1293
- } catch {
1294
- this.isSupported = false;
1295
- }
1296
- }
1297
- /**
1298
- * Stop observing and return the count of long tasks
1299
- */
1300
- stop() {
1301
- if (!this.isObserving || !this.observer) {
1302
- return this.longTaskCount;
1303
- }
1304
- try {
1305
- this.observer.disconnect();
1306
- } catch {
1307
- }
1308
- this.observer = null;
1309
- this.isObserving = false;
1310
- return this.longTaskCount;
1311
- }
1312
- /**
1313
- * Reset the long task counter
1314
- */
1315
- reset() {
1316
- this.longTaskCount = 0;
1317
- }
1318
- /**
1319
- * Get current count without stopping observation
1320
- */
1321
- getCount() {
1322
- return this.longTaskCount;
1323
- }
1324
- /**
1325
- * Check if currently observing
1326
- */
1327
- isActive() {
1328
- return this.isObserving;
1329
- }
1330
- };
1331
- var longTaskObserverInstance = null;
1332
- function getLongTaskObserver() {
1333
- if (!longTaskObserverInstance) {
1334
- longTaskObserverInstance = new LongTaskObserver();
1335
- }
1336
- return longTaskObserverInstance;
1337
- }
1338
- function resetLongTaskObserver() {
1339
- if (longTaskObserverInstance) {
1340
- longTaskObserverInstance.stop();
1341
- }
1342
- longTaskObserverInstance = null;
1343
- }
1344
-
1345
- // src/renderer.ts
1346
- var COMPONENT_TO_TAG = {
1347
- container: "div",
1348
- text: "span",
1349
- button: "button",
1350
- input: "input",
1351
- image: "img",
1352
- link: "a",
1353
- form: "form",
1354
- label: "label",
1355
- textarea: "textarea",
1356
- select: "select",
1357
- option: "option",
1358
- list: "ul",
1359
- listItem: "li",
1360
- heading: "h1",
1361
- paragraph: "p",
1362
- section: "section",
1363
- article: "article",
1364
- header: "header",
1365
- footer: "footer",
1366
- nav: "nav",
1367
- aside: "aside",
1368
- main: "main",
1369
- span: "span",
1370
- div: "div"
1371
- };
1372
- var SELF_CLOSING_TAGS = /* @__PURE__ */ new Set([
1373
- "input",
1374
- "img",
1375
- "br",
1376
- "hr",
1377
- "area",
1378
- "base",
1379
- "col",
1380
- "embed",
1381
- "link",
1382
- "meta",
1383
- "param",
1384
- "source",
1385
- "track",
1386
- "wbr"
1387
- ]);
1388
- function getElementTag(element) {
1389
- const config = element.configuration;
1390
- if (config?.tag) {
1391
- return config.tag;
1392
- }
1393
- if (element.componentId && COMPONENT_TO_TAG[element.componentId]) {
1394
- return COMPONENT_TO_TAG[element.componentId];
1395
- }
1396
- if (element.isGroup) {
1397
- return "div";
1398
- }
1399
- return "div";
1400
- }
1401
- function isSelfClosing(tag) {
1402
- return SELF_CLOSING_TAGS.has(tag.toLowerCase());
1403
- }
1404
- function buildTree(elements) {
1405
- const tree = /* @__PURE__ */ new Map();
1406
- for (const element of elements) {
1407
- const parentId = element.parent || null;
1408
- if (!tree.has(parentId)) {
1409
- tree.set(parentId, []);
1410
- }
1411
- tree.get(parentId).push(element);
1412
- }
1413
- return tree;
1414
- }
1415
- function getTextContent(element, context) {
1416
- const config = element.configuration;
1417
- if (config?.dynamicText) {
1418
- return resolveTemplate(config.dynamicText, context);
1419
- }
1420
- if (config?.text) {
1421
- if (hasTemplateSyntax(config.text)) {
1422
- return resolveTemplate(config.text, context);
1423
- }
1424
- return config.text;
1425
- }
1426
- return "";
1427
- }
1428
- function applyAttributes(domElement, element, context) {
1429
- const config = element.configuration || {};
1430
- const attributeMap = [
1431
- { key: "id", attr: "id" },
1432
- { key: "src", dynamicKey: "dynamicSrc", attr: "src" },
1433
- { key: "alt", attr: "alt" },
1434
- { key: "href", dynamicKey: "dynamicHref", attr: "href" },
1435
- { key: "target", attr: "target" },
1436
- { key: "placeholder", attr: "placeholder" },
1437
- { key: "type", attr: "type" },
1438
- { key: "name", attr: "name" },
1439
- { key: "value", dynamicKey: "dynamicValue", attr: "value" }
1440
- ];
1441
- for (const { key, dynamicKey, attr } of attributeMap) {
1442
- const dynamicValue = dynamicKey ? config[dynamicKey] : void 0;
1443
- if (dynamicValue !== void 0 && dynamicValue !== null && dynamicValue !== "") {
1444
- const resolved = resolveTemplate(String(dynamicValue), context);
1445
- if (resolved) {
1446
- domElement.setAttribute(attr, resolved);
1447
- }
1448
- continue;
1449
- }
1450
- const staticValue = config[key];
1451
- if (staticValue !== void 0 && staticValue !== null && staticValue !== "") {
1452
- const resolved = hasTemplateSyntax(String(staticValue)) ? resolveTemplate(String(staticValue), context) : String(staticValue);
1453
- if (resolved) {
1454
- domElement.setAttribute(attr, resolved);
1455
- }
1456
- }
1457
- }
1458
- if (config.disabled) domElement.setAttribute("disabled", "");
1459
- if (config.required) domElement.setAttribute("required", "");
1460
- if (config.readOnly) domElement.setAttribute("readonly", "");
1461
- for (const [key, value] of Object.entries(config)) {
1462
- if (key.startsWith("data-") && value !== void 0) {
1463
- const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
1464
- domElement.setAttribute(key, resolved);
1465
- }
1466
- }
1467
- for (const [key, value] of Object.entries(config)) {
1468
- if (key.startsWith("aria-") && value !== void 0) {
1469
- const resolved = hasTemplateSyntax(String(value)) ? resolveTemplate(String(value), context) : String(value);
1470
- domElement.setAttribute(key, resolved);
1471
- }
1472
- }
1473
- }
1474
- function resolveFunctionBinding(binding, context) {
1475
- if (binding.source === "props" || binding.source === "parent") {
1476
- const path = binding.path;
1477
- if (!path) return void 0;
1478
- const parts = path.split(".");
1479
- let value = context.props;
1480
- for (const part of parts) {
1481
- if (value === null || value === void 0) return void 0;
1482
- value = value[part];
1483
- }
1484
- if (typeof value === "function") {
1485
- return value;
1486
- }
1487
- return void 0;
1488
- }
1489
- if (binding.source === "static" && typeof binding.value === "function") {
1490
- return binding.value;
1491
- }
1492
- return void 0;
1493
- }
1494
- function attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement = false) {
1495
- const elementId = element.i;
1496
- if (eventHandlers && eventHandlers[elementId]) {
1497
- const handlers = eventHandlers[elementId];
1498
- for (const [eventName, handler] of Object.entries(handlers)) {
1499
- const domEventName = eventName.replace(/^on/, "").toLowerCase();
1500
- elementState.eventListeners.set(domEventName, handler);
1501
- domElement.addEventListener(domEventName, handler);
1502
- }
1503
- }
1504
- const bindings = element.configuration?.bindings?.inputs;
1505
- if (bindings) {
1506
- for (const [propName, binding] of Object.entries(bindings)) {
1507
- if (propName.startsWith("on") && propName.length > 2) {
1508
- const handler = resolveFunctionBinding(binding, context);
1509
- if (handler) {
1510
- const domEventName = propName.slice(2).toLowerCase();
1511
- if (!elementState.eventListeners.has(domEventName)) {
1512
- elementState.eventListeners.set(domEventName, handler);
1513
- domElement.addEventListener(domEventName, handler);
1514
- }
1515
- }
1516
- }
1517
- }
1518
- }
1519
- if (isRootElement && context.props) {
1520
- for (const [propName, value] of Object.entries(context.props)) {
1521
- if (propName.startsWith("on") && propName.length > 2 && typeof value === "function") {
1522
- const domEventName = propName.slice(2).toLowerCase();
1523
- if (!elementState.eventListeners.has(domEventName)) {
1524
- const handler = value;
1525
- elementState.eventListeners.set(domEventName, handler);
1526
- domElement.addEventListener(domEventName, handler);
1527
- }
1528
- }
1529
- }
1530
- }
1531
- }
1532
- function detachEventHandlers(elementState) {
1533
- for (const [eventName, handler] of elementState.eventListeners) {
1534
- elementState.domElement.removeEventListener(eventName, handler);
1535
- }
1536
- elementState.eventListeners.clear();
1537
- }
1538
- function createElement(element, context, eventHandlers, isRootElement = false) {
1539
- const tag = getElementTag(element);
1540
- const domElement = document.createElement(tag);
1541
- domElement.setAttribute("data-servly-id", element.i);
1542
- const styles = buildElementStyles(element, context);
1543
- applyStyles(domElement, styles);
1544
- const className = buildClassName(element, context);
1545
- if (className) {
1546
- domElement.className = className;
1547
- }
1548
- applyAttributes(domElement, element, context);
1549
- let textContent = "";
1550
- if (element.componentId === "text" || !isSelfClosing(tag)) {
1551
- textContent = getTextContent(element, context);
1552
- if (textContent && !element.children?.length) {
1553
- domElement.textContent = textContent;
1554
- }
1555
- }
1556
- const elementState = {
1557
- element,
1558
- domElement,
1559
- styles,
1560
- className,
1561
- textContent,
1562
- eventListeners: /* @__PURE__ */ new Map()
1563
- };
1564
- attachEventHandlers(domElement, element, eventHandlers, context, elementState, isRootElement);
1565
- return elementState;
1566
- }
1567
- var globalRenderingStack = /* @__PURE__ */ new Set();
1568
- function renderComponentRef(element, container, context, state) {
1569
- const config = element.configuration;
1570
- if (!config?.componentViewRef) return void 0;
1571
- const refId = config.componentViewRef;
1572
- const refVersion = config.componentViewVersion;
1573
- if (globalRenderingStack.has(refId)) {
1574
- console.warn(`Circular dependency detected: ${refId} is already being rendered`);
1575
- const placeholder = document.createElement("div");
1576
- placeholder.setAttribute("data-servly-circular", refId);
1577
- placeholder.textContent = `[Circular: ${refId}]`;
1578
- container.appendChild(placeholder);
1579
- return void 0;
1580
- }
1581
- let component;
1582
- if (state.componentRegistry) {
1583
- component = state.componentRegistry.get(refId, refVersion);
1584
- }
1585
- if (!component) {
1586
- const placeholder = document.createElement("div");
1587
- placeholder.setAttribute("data-servly-loading", refId);
1588
- placeholder.className = "servly-loading";
1589
- container.appendChild(placeholder);
1590
- if (state.onDependencyNeeded) {
1591
- state.onDependencyNeeded(refId, refVersion).then((loaded) => {
1592
- if (loaded && state.componentRegistry) {
1593
- state.componentRegistry.set(refId, refVersion || "latest", loaded);
1594
- container.innerHTML = "";
1595
- renderComponentRef(element, container, context, state);
1596
- }
1597
- }).catch((err) => {
1598
- console.error(`Failed to load dependency ${refId}:`, err);
1599
- placeholder.textContent = `[Failed to load: ${refId}]`;
1600
- placeholder.className = "servly-error";
1601
- });
1602
- }
1603
- return void 0;
1604
- }
1605
- const refProps = config.componentViewProps ? resolveTemplatesDeep(config.componentViewProps, context) : {};
1606
- globalRenderingStack.add(refId);
1607
- const refContext = {
1608
- props: refProps,
1609
- state: context.state,
1610
- context: context.context
1611
- };
1612
- try {
1613
- const result = render({
1614
- container,
1615
- elements: component.layout,
1616
- context: refContext,
1617
- componentRegistry: state.componentRegistry,
1618
- onDependencyNeeded: state.onDependencyNeeded
1619
- });
1620
- return result;
1621
- } finally {
1622
- globalRenderingStack.delete(refId);
1623
- }
1624
- }
1625
- function renderElement(element, tree, context, eventHandlers, elementStates, state, isRootElement = false) {
1626
- const elementState = createElement(element, context, eventHandlers, isRootElement);
1627
- elementStates.set(element.i, elementState);
1628
- const config = element.configuration;
1629
- if (config?.componentViewRef) {
1630
- const nestedResult = renderComponentRef(element, elementState.domElement, context, state);
1631
- if (nestedResult) {
1632
- elementState.nestedRender = nestedResult;
1633
- }
1634
- return elementState.domElement;
1635
- }
1636
- const children = tree.get(element.i) || [];
1637
- for (const child of children) {
1638
- const childElement = renderElement(child, tree, context, eventHandlers, elementStates, state, false);
1639
- elementState.domElement.appendChild(childElement);
1640
- }
1641
- return elementState.domElement;
1642
- }
1643
- function render(options) {
1644
- const { container, elements, context, eventHandlers, componentRegistry, onDependencyNeeded } = options;
1645
- const startTime = performance.now();
1646
- const memorySampler = getMemorySampler();
1647
- const longTaskObserver = getLongTaskObserver();
1648
- const memoryBefore = memorySampler.sample();
1649
- longTaskObserver.start();
1650
- const rootElements = elements.filter((el) => !el.parent || el.parent === null);
1651
- const componentId = rootElements[0]?.componentId || "unknown";
1652
- const version = "latest";
1653
- try {
1654
- const tree = buildTree(elements);
1655
- const state = {
1656
- container,
1657
- elements,
1658
- context,
1659
- eventHandlers,
1660
- elementStates: /* @__PURE__ */ new Map(),
1661
- rootElement: null,
1662
- componentRegistry,
1663
- onDependencyNeeded,
1664
- renderingStack: /* @__PURE__ */ new Set()
1665
- };
1666
- container.innerHTML = "";
1667
- if (rootElements.length === 0) {
1668
- const duration2 = performance.now() - startTime;
1669
- const longTasks2 = longTaskObserver.stop();
1670
- analytics.trackRender(componentId, version, duration2, {
1671
- elementCount: 0,
1672
- longTaskCount: longTasks2
1673
- });
1674
- return {
1675
- rootElement: null,
1676
- update: (newContext) => update(state, newContext),
1677
- destroy: () => destroy(state)
1678
- };
1679
- }
1680
- if (rootElements.length === 1) {
1681
- state.rootElement = renderElement(
1682
- rootElements[0],
1683
- tree,
1684
- context,
1685
- eventHandlers,
1686
- state.elementStates,
1687
- state,
1688
- true
1689
- // isRootElement
1690
- );
1691
- container.appendChild(state.rootElement);
1692
- } else {
1693
- const wrapper = document.createElement("div");
1694
- wrapper.setAttribute("data-servly-wrapper", "true");
1695
- for (const root of rootElements) {
1696
- const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state, true);
1697
- wrapper.appendChild(rootElement);
1698
- }
1699
- state.rootElement = wrapper;
1700
- container.appendChild(wrapper);
1701
- }
1702
- const duration = performance.now() - startTime;
1703
- const memoryAfter = memorySampler.sample();
1704
- const longTasks = longTaskObserver.stop();
1705
- const heapDelta = memorySampler.calculateDelta(memoryBefore, memoryAfter);
1706
- analytics.trackRender(componentId, version, duration, {
1707
- elementCount: elements.length,
1708
- heapDeltaKB: heapDelta ?? void 0,
1709
- longTaskCount: longTasks,
1710
- hasEventHandlers: !!eventHandlers && Object.keys(eventHandlers).length > 0,
1711
- hasDependencies: !!componentRegistry
1712
- });
1713
- return {
1714
- rootElement: state.rootElement,
1715
- update: (newContext) => update(state, newContext),
1716
- destroy: () => destroy(state)
1717
- };
1718
- } catch (error) {
1719
- longTaskObserver.stop();
1720
- analytics.trackError(componentId, version, error, {
1721
- errorType: "render"
1722
- });
1723
- throw error;
1724
- }
1725
- }
1726
- function update(state, newContext) {
1727
- state.context = newContext;
1728
- for (const [elementId, elementState] of state.elementStates) {
1729
- const { element, domElement } = elementState;
1730
- const newStyles = buildElementStyles(element, newContext);
1731
- updateStyles(domElement, elementState.styles, newStyles);
1732
- elementState.styles = newStyles;
1733
- const newClassName = buildClassName(element, newContext);
1734
- if (newClassName !== elementState.className) {
1735
- domElement.className = newClassName;
1736
- elementState.className = newClassName;
1737
- }
1738
- const newTextContent = getTextContent(element, newContext);
1739
- if (newTextContent !== elementState.textContent) {
1740
- const children = state.elements.filter((el) => el.parent === elementId);
1741
- if (children.length === 0) {
1742
- domElement.textContent = newTextContent;
1743
- }
1744
- elementState.textContent = newTextContent;
1745
- }
1746
- applyAttributes(domElement, element, newContext);
1747
- }
1748
- }
1749
- function destroy(state) {
1750
- for (const elementState of state.elementStates.values()) {
1751
- detachEventHandlers(elementState);
1752
- if (elementState.nestedRender) {
1753
- elementState.nestedRender.destroy();
1754
- }
1755
- }
1756
- state.elementStates.clear();
1757
- if (state.rootElement && state.rootElement.parentNode) {
1758
- state.rootElement.parentNode.removeChild(state.rootElement);
1759
- }
1760
- state.rootElement = null;
1761
- }
1762
- function renderDynamicList(options) {
1763
- const {
1764
- targetContainer,
1765
- blueprint,
1766
- blueprintVersion,
1767
- data,
1768
- renderType = "renderInto",
1769
- itemKey = "item",
1770
- indexKey = "index",
1771
- componentRegistry,
1772
- context = { props: {} }
1773
- } = options;
1774
- let container;
1775
- if (typeof targetContainer === "string") {
1776
- container = document.querySelector(targetContainer);
1777
- } else {
1778
- container = targetContainer;
1779
- }
1780
- if (!container) {
1781
- console.error(`renderDynamicList: Container not found: ${targetContainer}`);
1782
- return [];
1783
- }
1784
- const blueprintComponent = componentRegistry.get(blueprint, blueprintVersion);
1785
- if (!blueprintComponent) {
1786
- console.error(`renderDynamicList: Blueprint not found: ${blueprint}`);
1787
- return [];
1788
- }
1789
- if (renderType === "renderInto") {
1790
- container.innerHTML = "";
1791
- }
1792
- const results = [];
1793
- const fragment = document.createDocumentFragment();
1794
- data.forEach((item, index) => {
1795
- const itemContainer = document.createElement("div");
1796
- itemContainer.setAttribute("data-servly-list-item", String(index));
1797
- const itemContext = {
1798
- props: {
1799
- ...context.props,
1800
- [itemKey]: item,
1801
- [indexKey]: index
1802
- },
1803
- state: context.state,
1804
- context: context.context
1805
- };
1806
- const result = render({
1807
- container: itemContainer,
1808
- elements: blueprintComponent.layout,
1809
- context: itemContext,
1810
- componentRegistry
1811
- });
1812
- results.push(result);
1813
- fragment.appendChild(itemContainer);
1814
- });
1815
- if (renderType === "prepend") {
1816
- container.insertBefore(fragment, container.firstChild);
1817
- } else {
1818
- container.appendChild(fragment);
1819
- }
1820
- return results;
1821
- }
1822
-
1823
- // src/cache.ts
1824
- var DEFAULT_CACHE_CONFIG = {
1825
- maxEntries: 50,
1826
- ttl: 5 * 60 * 1e3,
1827
- // 5 minutes
1828
- storageKeyPrefix: "servly_component_"
1829
- };
1830
- var memoryCache = /* @__PURE__ */ new Map();
1831
- function getCacheKey(id, version = "latest") {
1832
- return `${id}@${version}`;
1833
- }
1834
- function getFromMemoryCache(id, version = "latest", config = DEFAULT_CACHE_CONFIG) {
1835
- const key = getCacheKey(id, version);
1836
- const entry = memoryCache.get(key);
1837
- if (!entry) {
1838
- return null;
1839
- }
1840
- const ttl = config.ttl ?? DEFAULT_CACHE_CONFIG.ttl;
1841
- if (Date.now() - entry.timestamp > ttl) {
1842
- memoryCache.delete(key);
1843
- return null;
1844
- }
1845
- entry.accessCount++;
1846
- entry.lastAccessed = Date.now();
1847
- return entry.data;
1848
- }
1849
- function setInMemoryCache(id, version, data, config = DEFAULT_CACHE_CONFIG) {
1850
- const key = getCacheKey(id, version);
1851
- const maxEntries = config.maxEntries ?? DEFAULT_CACHE_CONFIG.maxEntries;
1852
- if (memoryCache.size >= maxEntries && !memoryCache.has(key)) {
1853
- evictLRUFromMemory();
1854
- }
1855
- memoryCache.set(key, {
1856
- data,
1857
- timestamp: Date.now(),
1858
- version,
1859
- accessCount: 1,
1860
- lastAccessed: Date.now()
1861
- });
1862
- }
1863
- function evictLRUFromMemory() {
1864
- let lruKey = null;
1865
- let lruTime = Infinity;
1866
- for (const [key, entry] of memoryCache.entries()) {
1867
- if (entry.lastAccessed < lruTime) {
1868
- lruTime = entry.lastAccessed;
1869
- lruKey = key;
1870
- }
1871
- }
1872
- if (lruKey) {
1873
- memoryCache.delete(lruKey);
1874
- }
1875
- }
1876
- function clearMemoryCache() {
1877
- memoryCache.clear();
1878
- }
1879
- function getMemoryCacheSize() {
1880
- return memoryCache.size;
1881
- }
1882
- function isLocalStorageAvailable() {
1883
- try {
1884
- const test = "__servly_test__";
1885
- localStorage.setItem(test, test);
1886
- localStorage.removeItem(test);
1887
- return true;
1888
- } catch {
1889
- return false;
1890
- }
1891
- }
1892
- function getStorageKey(id, version, config) {
1893
- const prefix = config.storageKeyPrefix ?? DEFAULT_CACHE_CONFIG.storageKeyPrefix;
1894
- return `${prefix}${getCacheKey(id, version)}`;
1895
- }
1896
- function getFromLocalStorage(id, version = "latest", config = DEFAULT_CACHE_CONFIG) {
1897
- if (!isLocalStorageAvailable()) {
1898
- return null;
1899
- }
1900
- try {
1901
- const key = getStorageKey(id, version, config);
1902
- const stored = localStorage.getItem(key);
1903
- if (!stored) {
1904
- return null;
1905
- }
1906
- const entry = JSON.parse(stored);
1907
- const ttl = config.ttl ?? DEFAULT_CACHE_CONFIG.ttl;
1908
- if (Date.now() - entry.timestamp > ttl) {
1909
- localStorage.removeItem(key);
1910
- return null;
1911
- }
1912
- entry.accessCount++;
1913
- entry.lastAccessed = Date.now();
1914
- localStorage.setItem(key, JSON.stringify(entry));
1915
- return entry.data;
1916
- } catch (error) {
1917
- console.warn("Error reading from localStorage cache:", error);
1918
- return null;
1919
- }
1920
- }
1921
- function setInLocalStorage(id, version, data, config = DEFAULT_CACHE_CONFIG) {
1922
- if (!isLocalStorageAvailable()) {
1923
- return;
1924
- }
1925
- try {
1926
- const key = getStorageKey(id, version, config);
1927
- const maxEntries = config.maxEntries ?? DEFAULT_CACHE_CONFIG.maxEntries;
1928
- const currentCount = getLocalStorageCacheCount(config);
1929
- if (currentCount >= maxEntries) {
1930
- evictLRUFromLocalStorage(config);
1931
- }
1932
- const entry = {
1933
- data,
1934
- timestamp: Date.now(),
1935
- version,
1936
- accessCount: 1,
1937
- lastAccessed: Date.now()
1938
- };
1939
- localStorage.setItem(key, JSON.stringify(entry));
1940
- } catch (error) {
1941
- console.warn("Error writing to localStorage cache:", error);
1942
- if (error instanceof DOMException && error.name === "QuotaExceededError") {
1943
- evictLRUFromLocalStorage(config);
1944
- try {
1945
- const key = getStorageKey(id, version, config);
1946
- const entry = {
1947
- data,
1948
- timestamp: Date.now(),
1949
- version,
1950
- accessCount: 1,
1951
- lastAccessed: Date.now()
1952
- };
1953
- localStorage.setItem(key, JSON.stringify(entry));
1954
- } catch {
1955
- }
1956
- }
1957
- }
1958
- }
1959
- function getLocalStorageCacheCount(config) {
1960
- const prefix = config.storageKeyPrefix ?? DEFAULT_CACHE_CONFIG.storageKeyPrefix;
1961
- let count = 0;
1962
- for (let i = 0; i < localStorage.length; i++) {
1963
- const key = localStorage.key(i);
1964
- if (key?.startsWith(prefix)) {
1965
- count++;
1966
- }
1967
- }
1968
- return count;
1969
- }
1970
- function evictLRUFromLocalStorage(config) {
1971
- const prefix = config.storageKeyPrefix ?? DEFAULT_CACHE_CONFIG.storageKeyPrefix;
1972
- let lruKey = null;
1973
- let lruTime = Infinity;
1974
- for (let i = 0; i < localStorage.length; i++) {
1975
- const key = localStorage.key(i);
1976
- if (!key?.startsWith(prefix)) continue;
1977
- try {
1978
- const stored = localStorage.getItem(key);
1979
- if (stored) {
1980
- const entry = JSON.parse(stored);
1981
- if (entry.lastAccessed < lruTime) {
1982
- lruTime = entry.lastAccessed;
1983
- lruKey = key;
1984
- }
1985
- }
1986
- } catch {
1987
- if (key) localStorage.removeItem(key);
1988
- }
1989
- }
1990
- if (lruKey) {
1991
- localStorage.removeItem(lruKey);
1992
- }
1993
- }
1994
- function clearLocalStorageCache(config = DEFAULT_CACHE_CONFIG) {
1995
- if (!isLocalStorageAvailable()) {
1996
- return;
1997
- }
1998
- const prefix = config.storageKeyPrefix ?? DEFAULT_CACHE_CONFIG.storageKeyPrefix;
1999
- const keysToRemove = [];
2000
- for (let i = 0; i < localStorage.length; i++) {
2001
- const key = localStorage.key(i);
2002
- if (key?.startsWith(prefix)) {
2003
- keysToRemove.push(key);
2004
- }
2005
- }
2006
- keysToRemove.forEach((key) => localStorage.removeItem(key));
2007
- }
2008
- function getFromCache(id, version = "latest", strategy = "memory", config = DEFAULT_CACHE_CONFIG) {
2009
- if (strategy === "none") {
2010
- return null;
2011
- }
2012
- const memoryResult = getFromMemoryCache(id, version, config);
2013
- if (memoryResult) {
2014
- return memoryResult;
2015
- }
2016
- if (strategy === "localStorage") {
2017
- const localResult = getFromLocalStorage(id, version, config);
2018
- if (localResult) {
2019
- setInMemoryCache(id, version, localResult, config);
2020
- return localResult;
2021
- }
2022
- }
2023
- return null;
2024
- }
2025
- function setInCache(id, version, data, strategy = "memory", config = DEFAULT_CACHE_CONFIG) {
2026
- if (strategy === "none") {
2027
- return;
2028
- }
2029
- setInMemoryCache(id, version, data, config);
2030
- if (strategy === "localStorage") {
2031
- setInLocalStorage(id, version, data, config);
2032
- }
2033
- }
2034
- function clearAllCaches(config = DEFAULT_CACHE_CONFIG) {
2035
- clearMemoryCache();
2036
- clearLocalStorageCache(config);
2037
- }
2038
- function invalidateCache(id, version, config = DEFAULT_CACHE_CONFIG) {
2039
- if (version) {
2040
- const key = getCacheKey(id, version);
2041
- memoryCache.delete(key);
2042
- if (isLocalStorageAvailable()) {
2043
- const storageKey = getStorageKey(id, version, config);
2044
- localStorage.removeItem(storageKey);
2045
- }
2046
- } else {
2047
- const prefix = `${id}@`;
2048
- for (const key of memoryCache.keys()) {
2049
- if (key.startsWith(prefix)) {
2050
- memoryCache.delete(key);
2051
- }
2052
- }
2053
- if (isLocalStorageAvailable()) {
2054
- const storagePrefix = (config.storageKeyPrefix ?? DEFAULT_CACHE_CONFIG.storageKeyPrefix) + prefix;
2055
- const keysToRemove = [];
2056
- for (let i = 0; i < localStorage.length; i++) {
2057
- const key = localStorage.key(i);
2058
- if (key?.startsWith(storagePrefix)) {
2059
- keysToRemove.push(key);
2060
- }
2061
- }
2062
- keysToRemove.forEach((key) => localStorage.removeItem(key));
2063
- }
2064
- }
2065
- }
2066
-
2067
- // src/fetcher.ts
2068
- init_registry();
2069
- var DEFAULT_RETRY_CONFIG = {
2070
- maxRetries: 3,
2071
- initialDelay: 1e3,
2072
- maxDelay: 1e4,
2073
- backoffMultiplier: 2
2074
- };
2075
- var registryBaseUrl = "/api/views/registry";
2076
- function setRegistryUrl(url) {
2077
- registryBaseUrl = url;
2078
- }
2079
- function getRegistryUrl() {
2080
- if (typeof window !== "undefined") {
2081
- const envUrl = window.__SERVLY_REGISTRY_URL__;
2082
- if (envUrl) return envUrl;
2083
- }
2084
- if (typeof process !== "undefined" && process.env?.SERVLY_REGISTRY_URL) {
2085
- return process.env.SERVLY_REGISTRY_URL;
2086
- }
2087
- return registryBaseUrl;
2088
- }
2089
- function calculateBackoffDelay(retryCount, config) {
2090
- const delay = config.initialDelay * Math.pow(config.backoffMultiplier, retryCount);
2091
- return Math.min(delay, config.maxDelay);
2092
- }
2093
- function sleep(ms) {
2094
- return new Promise((resolve) => setTimeout(resolve, ms));
2095
- }
2096
- async function resolveVersionFromApi(id, specifier, apiKey) {
2097
- if (/^\d+\.\d+\.\d+$/.test(specifier)) {
2098
- return specifier;
2099
- }
2100
- const baseUrl = getRegistryUrl();
2101
- const headers = {
2102
- "Content-Type": "application/json"
2103
- };
2104
- if (apiKey) {
2105
- headers["Authorization"] = `Bearer ${apiKey}`;
2106
- }
2107
- try {
2108
- const response = await fetch(
2109
- `${baseUrl}/${id}/resolve?specifier=${encodeURIComponent(specifier)}`,
2110
- { headers }
2111
- );
2112
- if (!response.ok) {
2113
- throw new Error(`Failed to resolve version: ${response.statusText}`);
2114
- }
2115
- const data = await response.json();
2116
- if (data.success && data.data?.resolved) {
2117
- return data.data.resolved;
2118
- }
2119
- throw new Error(data.error || "Failed to resolve version");
2120
- } catch (error) {
2121
- console.warn(`Failed to resolve version for ${id}@${specifier}:`, error);
2122
- return "latest";
2123
- }
2124
- }
2125
- async function fetchFromRegistry(id, version, apiKey, includeBundle) {
2126
- const baseUrl = getRegistryUrl();
2127
- const headers = {
2128
- "Content-Type": "application/json"
2129
- };
2130
- if (apiKey) {
2131
- headers["Authorization"] = `Bearer ${apiKey}`;
2132
- }
2133
- let url;
2134
- if (version && version !== "latest" && /^\d+\.\d+\.\d+/.test(version)) {
2135
- url = `${baseUrl}/${id}/versions/${version}`;
2136
- } else if (version && version !== "latest") {
2137
- url = `${baseUrl}/${id}?version=${encodeURIComponent(version)}`;
2138
- } else {
2139
- url = `${baseUrl}/${id}`;
2140
- }
2141
- if (includeBundle) {
2142
- url += (url.includes("?") ? "&" : "?") + "bundle=true";
2143
- }
2144
- const response = await fetch(url, { headers });
2145
- if (!response.ok) {
2146
- if (response.status === 404) {
2147
- throw new Error(`View not found: ${id}@${version}`);
2148
- }
2149
- if (response.status === 401) {
2150
- throw new Error("Unauthorized: Invalid or missing API key");
2151
- }
2152
- if (response.status === 403) {
2153
- throw new Error("Forbidden: Access denied to this view");
2154
- }
2155
- throw new Error(`Failed to fetch view: ${response.statusText}`);
2156
- }
2157
- const data = await response.json();
2158
- if (!data.success || !data.data) {
2159
- throw new Error(data.error || "Failed to fetch view data");
2160
- }
2161
- const result = data.data;
2162
- if (result.viewId && !result.id) {
2163
- result.id = result.viewId;
2164
- }
2165
- return result;
2166
- }
2167
- async function fetchComponent(id, options = {}) {
2168
- const {
2169
- version = "latest",
2170
- apiKey,
2171
- cacheStrategy = "memory",
2172
- cacheConfig = DEFAULT_CACHE_CONFIG,
2173
- retryConfig = {},
2174
- forceRefresh = false,
2175
- signal,
2176
- bundleStrategy = "eager",
2177
- includeBundle = true
2178
- } = options;
2179
- const fullRetryConfig = {
2180
- ...DEFAULT_RETRY_CONFIG,
2181
- ...retryConfig
2182
- };
2183
- const startTime = performance.now();
2184
- if (!forceRefresh) {
2185
- const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
2186
- if (cached) {
2187
- let registry;
2188
- if (cached.bundle) {
2189
- registry = buildRegistryFromBundle(cached);
2190
- }
2191
- const duration = performance.now() - startTime;
2192
- analytics.trackFetch(id, cached.version, duration, true, {
2193
- cacheHit: true,
2194
- fetchDuration: Math.round(duration)
2195
- });
2196
- return {
2197
- data: cached,
2198
- fromCache: true,
2199
- version: cached.version,
2200
- registry
2201
- };
2202
- }
2203
- }
2204
- const resolvedVersion = await resolveVersionFromApi(id, version, apiKey);
2205
- if (!forceRefresh && resolvedVersion !== version) {
2206
- const cached = getFromCache(id, resolvedVersion, cacheStrategy, cacheConfig);
2207
- if (cached) {
2208
- let registry;
2209
- if (cached.bundle) {
2210
- registry = buildRegistryFromBundle(cached);
2211
- }
2212
- return {
2213
- data: cached,
2214
- fromCache: true,
2215
- version: resolvedVersion,
2216
- registry
2217
- };
2218
- }
2219
- }
2220
- let lastError = null;
2221
- const shouldIncludeBundle = bundleStrategy !== "none" && includeBundle;
2222
- for (let attempt = 0; attempt <= fullRetryConfig.maxRetries; attempt++) {
2223
- if (signal?.aborted) {
2224
- throw new Error("Fetch aborted");
2225
- }
2226
- try {
2227
- const data = await fetchFromRegistry(id, resolvedVersion, apiKey, shouldIncludeBundle);
2228
- setInCache(id, resolvedVersion, data, cacheStrategy, cacheConfig);
2229
- if (version !== resolvedVersion) {
2230
- setInCache(id, version, data, cacheStrategy, cacheConfig);
2231
- }
2232
- let registry;
2233
- let pendingDependencies;
2234
- if (data.bundle) {
2235
- registry = buildRegistryFromBundle(data);
2236
- } else if (data.dependencies && bundleStrategy === "lazy") {
2237
- pendingDependencies = Object.entries(data.dependencies).map(([depId, entry]) => ({
2238
- id: depId,
2239
- version: entry.resolved || entry.version
2240
- }));
2241
- }
2242
- const duration = performance.now() - startTime;
2243
- analytics.trackFetch(id, resolvedVersion, duration, false, {
2244
- cacheHit: false,
2245
- fetchDuration: Math.round(duration),
2246
- dependencyCount: data.dependencies ? Object.keys(data.dependencies).length : 0
2247
- });
2248
- return {
2249
- data,
2250
- fromCache: false,
2251
- version: resolvedVersion,
2252
- registry,
2253
- pendingDependencies
2254
- };
2255
- } catch (error) {
2256
- lastError = error instanceof Error ? error : new Error(String(error));
2257
- if (lastError.message.includes("not found") || lastError.message.includes("Unauthorized") || lastError.message.includes("Forbidden")) {
2258
- throw lastError;
2259
- }
2260
- if (attempt < fullRetryConfig.maxRetries) {
2261
- const delay = calculateBackoffDelay(attempt, fullRetryConfig);
2262
- await sleep(delay);
2263
- }
2264
- }
2265
- }
2266
- const finalError = lastError || new Error("Failed to fetch component");
2267
- analytics.trackError(id, version, finalError, {
2268
- errorType: "fetch"
2269
- });
2270
- throw finalError;
2271
- }
2272
- async function fetchComponentWithDependencies(id, options = {}) {
2273
- const result = await fetchComponent(id, { ...options, includeBundle: true });
2274
- if (result.pendingDependencies && result.pendingDependencies.length > 0) {
2275
- const { createRegistry: createRegistry2 } = await Promise.resolve().then(() => (init_registry(), registry_exports));
2276
- const registry = result.registry || createRegistry2();
2277
- await Promise.all(
2278
- result.pendingDependencies.map(async (dep) => {
2279
- try {
2280
- const depResult = await fetchComponent(dep.id, {
2281
- ...options,
2282
- version: dep.version,
2283
- bundleStrategy: "none"
2284
- // Don't recursively bundle
2285
- });
2286
- registry.set(dep.id, depResult.version, {
2287
- layout: depResult.data.layout,
2288
- propsInterface: depResult.data.propsInterface
2289
- });
2290
- } catch (err) {
2291
- console.warn(`Failed to fetch dependency ${dep.id}:`, err);
2292
- }
2293
- })
2294
- );
2295
- result.registry = registry;
2296
- result.pendingDependencies = void 0;
2297
- }
2298
- return result;
2299
- }
2300
- async function batchFetchComponents(components, options = {}) {
2301
- const baseUrl = getRegistryUrl();
2302
- const headers = {
2303
- "Content-Type": "application/json"
2304
- };
2305
- if (options.apiKey) {
2306
- headers["Authorization"] = `Bearer ${options.apiKey}`;
2307
- }
2308
- const response = await fetch(`${baseUrl}/batch`, {
2309
- method: "POST",
2310
- headers,
2311
- body: JSON.stringify({ components })
2312
- });
2313
- if (!response.ok) {
2314
- throw new Error(`Batch fetch failed: ${response.statusText}`);
2315
- }
2316
- const data = await response.json();
2317
- if (!data.success || !data.data) {
2318
- throw new Error(data.error || "Batch fetch failed");
2319
- }
2320
- return data.data;
2321
- }
2322
- async function prefetchComponents(ids, options = {}) {
2323
- const promises = ids.map(
2324
- ({ id, version }) => fetchComponent(id, { ...options, version }).catch((error) => {
2325
- console.warn(`Failed to prefetch view ${id}:`, error);
2326
- })
2327
- );
2328
- await Promise.all(promises);
2329
- }
2330
- async function isComponentAvailable(id, version = "latest", options = {}) {
2331
- const { cacheStrategy = "memory", cacheConfig = DEFAULT_CACHE_CONFIG } = options;
2332
- const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
2333
- if (cached) {
2334
- return { available: true, cached: true, version: cached.version };
2335
- }
2336
- const baseUrl = getRegistryUrl();
2337
- const headers = {
2338
- "Content-Type": "application/json"
2339
- };
2340
- if (options.apiKey) {
2341
- headers["Authorization"] = `Bearer ${options.apiKey}`;
2342
- }
2343
- try {
2344
- const url = version && version !== "latest" ? `${baseUrl}/${id}/available?version=${encodeURIComponent(version)}` : `${baseUrl}/${id}/available`;
2345
- const response = await fetch(url, { headers });
2346
- if (!response.ok) {
2347
- return { available: false, cached: false };
2348
- }
2349
- const data = await response.json();
2350
- if (data.success && data.data) {
2351
- return data.data;
2352
- }
2353
- return { available: false, cached: false };
2354
- } catch {
2355
- return { available: false, cached: false };
2356
- }
2357
- }
2358
- async function getDependencyTree(id, options = {}) {
2359
- const baseUrl = getRegistryUrl();
2360
- const headers = {
2361
- "Content-Type": "application/json"
2362
- };
2363
- if (options.apiKey) {
2364
- headers["Authorization"] = `Bearer ${options.apiKey}`;
2365
- }
2366
- const params = new URLSearchParams();
2367
- if (options.version) params.set("version", options.version);
2368
- if (options.depth) params.set("depth", String(options.depth));
2369
- const url = `${baseUrl}/${id}/dependencies${params.toString() ? "?" + params.toString() : ""}`;
2370
- const response = await fetch(url, { headers });
2371
- if (!response.ok) {
2372
- throw new Error(`Failed to get dependency tree: ${response.statusText}`);
2373
- }
2374
- const data = await response.json();
2375
- if (!data.success || !data.data) {
2376
- throw new Error(data.error || "Failed to get dependency tree");
2377
- }
2378
- return data.data;
2379
- }
2380
-
2381
- // src/version.ts
2382
- function parseVersion(version) {
2383
- const match = version.match(/^(\d+)\.(\d+)\.(\d+)$/);
2384
- if (!match) return null;
2385
- return {
2386
- major: parseInt(match[1], 10),
2387
- minor: parseInt(match[2], 10),
2388
- patch: parseInt(match[3], 10)
2389
- };
2390
- }
2391
- function compareVersions(a, b) {
2392
- const parsedA = parseVersion(a);
2393
- const parsedB = parseVersion(b);
2394
- if (!parsedA || !parsedB) return 0;
2395
- if (parsedA.major !== parsedB.major) {
2396
- return parsedA.major > parsedB.major ? 1 : -1;
2397
- }
2398
- if (parsedA.minor !== parsedB.minor) {
2399
- return parsedA.minor > parsedB.minor ? 1 : -1;
2400
- }
2401
- if (parsedA.patch !== parsedB.patch) {
2402
- return parsedA.patch > parsedB.patch ? 1 : -1;
2403
- }
2404
- return 0;
2405
- }
2406
- function satisfiesVersion(version, specifier) {
2407
- if (specifier === "latest" || specifier === "*") {
2408
- return true;
2409
- }
2410
- const parsed = parseVersion(version);
2411
- if (!parsed) return false;
2412
- if (/^\d+\.\d+\.\d+$/.test(specifier)) {
2413
- return version === specifier;
2414
- }
2415
- if (specifier.startsWith("^")) {
2416
- const specParsed = parseVersion(specifier.slice(1));
2417
- if (!specParsed) return false;
2418
- if (parsed.major !== specParsed.major) return false;
2419
- if (parsed.major === 0) {
2420
- return parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
2421
- }
2422
- return compareVersions(version, specifier.slice(1)) >= 0;
2423
- }
2424
- if (specifier.startsWith("~")) {
2425
- const specParsed = parseVersion(specifier.slice(1));
2426
- if (!specParsed) return false;
2427
- return parsed.major === specParsed.major && parsed.minor === specParsed.minor && parsed.patch >= specParsed.patch;
2428
- }
2429
- if (specifier.startsWith(">=")) {
2430
- return compareVersions(version, specifier.slice(2)) >= 0;
2431
- }
2432
- if (specifier.startsWith(">")) {
2433
- return compareVersions(version, specifier.slice(1)) > 0;
2434
- }
2435
- if (specifier.startsWith("<=")) {
2436
- return compareVersions(version, specifier.slice(2)) <= 0;
2437
- }
2438
- if (specifier.startsWith("<")) {
2439
- return compareVersions(version, specifier.slice(1)) < 0;
2440
- }
2441
- return false;
2442
- }
2443
- function resolveVersion(versions, specifier = "latest") {
2444
- if (versions.length === 0) {
2445
- return null;
2446
- }
2447
- const sorted = [...versions].sort((a, b) => compareVersions(b, a));
2448
- if (specifier === "latest" || specifier === "*") {
2449
- return sorted[0];
2450
- }
2451
- if (/^\d+\.\d+\.\d+$/.test(specifier)) {
2452
- return versions.includes(specifier) ? specifier : null;
2453
- }
2454
- for (const version of sorted) {
2455
- if (satisfiesVersion(version, specifier)) {
2456
- return version;
2457
- }
2458
- }
2459
- return null;
2460
- }
2461
- function bumpVersion(currentVersion, bumpType) {
2462
- const parsed = parseVersion(currentVersion);
2463
- if (!parsed) return "1.0.0";
2464
- switch (bumpType) {
2465
- case "major":
2466
- return `${parsed.major + 1}.0.0`;
2467
- case "minor":
2468
- return `${parsed.major}.${parsed.minor + 1}.0`;
2469
- case "patch":
2470
- return `${parsed.major}.${parsed.minor}.${parsed.patch + 1}`;
2471
- default:
2472
- return currentVersion;
2473
- }
2474
- }
2475
- function isValidSpecifier(specifier) {
2476
- if (specifier === "latest" || specifier === "*") {
2477
- return true;
2478
- }
2479
- if (/^\d+\.\d+\.\d+$/.test(specifier)) {
2480
- return true;
2481
- }
2482
- if (/^[\^~><]=?\d+\.\d+\.\d+$/.test(specifier)) {
2483
- return true;
2484
- }
2485
- return false;
2486
- }
2487
- function formatVersion(version) {
2488
- const parsed = parseVersion(version);
2489
- if (!parsed) return version;
2490
- return `v${parsed.major}.${parsed.minor}.${parsed.patch}`;
2491
- }
2492
-
2493
- // src/testRunner.ts
2494
- function runTestCase(elements, testCase, container) {
2495
- const startTime = performance.now();
2496
- const assertionResults = [];
2497
- let renderResult = null;
2498
- let error;
2499
- const testContainer = container || document.createElement("div");
2500
- if (!container) {
2501
- document.body.appendChild(testContainer);
2502
- }
2503
- try {
2504
- const context = {
2505
- props: testCase.props
2506
- };
2507
- renderResult = render({
2508
- container: testContainer,
2509
- elements,
2510
- context
2511
- });
2512
- for (const assertion of testCase.assertions) {
2513
- const result = validateAssertion(testContainer, assertion);
2514
- assertionResults.push(result);
2515
- }
2516
- } catch (err) {
2517
- error = err instanceof Error ? err.message : String(err);
2518
- } finally {
2519
- if (renderResult) {
2520
- renderResult.destroy();
2521
- }
2522
- if (!container) {
2523
- document.body.removeChild(testContainer);
2524
- }
2525
- }
2526
- const duration = performance.now() - startTime;
2527
- const passed = !error && assertionResults.every((r) => r.passed);
2528
- return {
2529
- testId: testCase.id,
2530
- testName: testCase.name,
2531
- passed,
2532
- assertions: assertionResults,
2533
- duration,
2534
- error
2535
- };
2536
- }
2537
- function runAllTests(elements, testCases) {
2538
- const startTime = performance.now();
2539
- const results = [];
2540
- for (const testCase of testCases) {
2541
- const result = runTestCase(elements, testCase);
2542
- results.push(result);
2543
- }
2544
- const duration = performance.now() - startTime;
2545
- const passed = results.filter((r) => r.passed).length;
2546
- const failed = results.filter((r) => !r.passed).length;
2547
- return {
2548
- total: testCases.length,
2549
- passed,
2550
- failed,
2551
- duration,
2552
- results
2553
- };
2554
- }
2555
- function validateAssertion(container, assertion) {
2556
- const elements = container.querySelectorAll(assertion.selector);
2557
- switch (assertion.type) {
2558
- case "exists":
2559
- return {
2560
- assertion,
2561
- passed: elements.length > 0,
2562
- actual: elements.length > 0,
2563
- expected: true,
2564
- message: elements.length > 0 ? `Element "${assertion.selector}" exists` : `Element "${assertion.selector}" not found`
2565
- };
2566
- case "count":
2567
- const count = elements.length;
2568
- const expectedCount = assertion.expected;
2569
- return {
2570
- assertion,
2571
- passed: count === expectedCount,
2572
- actual: count,
2573
- expected: expectedCount,
2574
- message: count === expectedCount ? `Found ${count} elements matching "${assertion.selector}"` : `Expected ${expectedCount} elements, found ${count}`
2575
- };
2576
- case "text":
2577
- if (elements.length === 0) {
2578
- return {
2579
- assertion,
2580
- passed: false,
2581
- actual: null,
2582
- expected: assertion.expected,
2583
- message: `Element "${assertion.selector}" not found`
2584
- };
2585
- }
2586
- const textContent = elements[0].textContent?.trim();
2587
- const expectedText = assertion.expected;
2588
- return {
2589
- assertion,
2590
- passed: textContent === expectedText,
2591
- actual: textContent,
2592
- expected: expectedText,
2593
- message: textContent === expectedText ? `Text matches: "${expectedText}"` : `Expected text "${expectedText}", got "${textContent}"`
2594
- };
2595
- case "attribute":
2596
- if (elements.length === 0) {
2597
- return {
2598
- assertion,
2599
- passed: false,
2600
- actual: null,
2601
- expected: assertion.expected,
2602
- message: `Element "${assertion.selector}" not found`
2603
- };
2604
- }
2605
- const attrValue = elements[0].getAttribute(assertion.attribute || "");
2606
- const expectedAttr = assertion.expected;
2607
- return {
2608
- assertion,
2609
- passed: attrValue === expectedAttr,
2610
- actual: attrValue,
2611
- expected: expectedAttr,
2612
- message: attrValue === expectedAttr ? `Attribute "${assertion.attribute}" matches` : `Expected attribute "${assertion.attribute}" to be "${expectedAttr}", got "${attrValue}"`
2613
- };
2614
- case "class":
2615
- if (elements.length === 0) {
2616
- return {
2617
- assertion,
2618
- passed: false,
2619
- actual: null,
2620
- expected: assertion.expected,
2621
- message: `Element "${assertion.selector}" not found`
2622
- };
2623
- }
2624
- const hasClass = elements[0].classList.contains(assertion.expected);
2625
- return {
2626
- assertion,
2627
- passed: hasClass,
2628
- actual: Array.from(elements[0].classList),
2629
- expected: assertion.expected,
2630
- message: hasClass ? `Element has class "${assertion.expected}"` : `Element does not have class "${assertion.expected}"`
2631
- };
2632
- case "style":
2633
- if (elements.length === 0) {
2634
- return {
2635
- assertion,
2636
- passed: false,
2637
- actual: null,
2638
- expected: assertion.expected,
2639
- message: `Element "${assertion.selector}" not found`
2640
- };
2641
- }
2642
- const el = elements[0];
2643
- const styleValue = el.style.getPropertyValue(assertion.property || "");
2644
- const expectedStyle = assertion.expected;
2645
- return {
2646
- assertion,
2647
- passed: styleValue === expectedStyle,
2648
- actual: styleValue,
2649
- expected: expectedStyle,
2650
- message: styleValue === expectedStyle ? `Style "${assertion.property}" matches` : `Expected style "${assertion.property}" to be "${expectedStyle}", got "${styleValue}"`
2651
- };
2652
- case "visible":
2653
- if (elements.length === 0) {
2654
- return {
2655
- assertion,
2656
- passed: false,
2657
- actual: null,
2658
- expected: true,
2659
- message: `Element "${assertion.selector}" not found`
2660
- };
2661
- }
2662
- const visible = isElementVisible(elements[0]);
2663
- const expectedVisible = assertion.expected !== false;
2664
- return {
2665
- assertion,
2666
- passed: visible === expectedVisible,
2667
- actual: visible,
2668
- expected: expectedVisible,
2669
- message: visible === expectedVisible ? `Element visibility matches expected` : `Expected element to be ${expectedVisible ? "visible" : "hidden"}`
2670
- };
2671
- default:
2672
- return {
2673
- assertion,
2674
- passed: false,
2675
- message: `Unknown assertion type: ${assertion.type}`
2676
- };
2677
- }
2678
- }
2679
- function isElementVisible(element) {
2680
- const style = window.getComputedStyle(element);
2681
- return style.display !== "none" && style.visibility !== "hidden" && style.opacity !== "0" && element.offsetWidth > 0 && element.offsetHeight > 0;
2682
- }
2683
- function validateProps(props, definitions) {
2684
- const errors = [];
2685
- for (const def of definitions) {
2686
- const value = props[def.name];
2687
- if (def.required && (value === void 0 || value === null)) {
2688
- errors.push(`Required prop "${def.name}" is missing`);
2689
- continue;
2690
- }
2691
- if (value === void 0) continue;
2692
- const actualType = Array.isArray(value) ? "array" : typeof value;
2693
- if (def.type === "array" && !Array.isArray(value)) {
2694
- errors.push(`Prop "${def.name}" should be an array, got ${actualType}`);
2695
- } else if (def.type !== "array" && actualType !== def.type) {
2696
- errors.push(`Prop "${def.name}" should be ${def.type}, got ${actualType}`);
2697
- }
2698
- }
2699
- return {
2700
- valid: errors.length === 0,
2701
- errors
2702
- };
2703
- }
2704
- function generateTestCases(definitions) {
2705
- const testCases = [];
2706
- const defaultProps = {};
2707
- for (const def of definitions) {
2708
- if (def.defaultValue !== void 0) {
2709
- defaultProps[def.name] = def.defaultValue;
2710
- }
2711
- }
2712
- testCases.push({
2713
- id: "default-props",
2714
- name: "Render with default props",
2715
- props: defaultProps,
2716
- assertions: [{ type: "exists", selector: "*" }]
2717
- });
2718
- for (const def of definitions) {
2719
- const sampleValue = getSampleValue(def);
2720
- if (sampleValue !== void 0) {
2721
- testCases.push({
2722
- id: `prop-${def.name}`,
2723
- name: `Test prop: ${def.name}`,
2724
- props: { ...defaultProps, [def.name]: sampleValue },
2725
- assertions: [{ type: "exists", selector: "*" }]
2726
- });
2727
- }
2728
- }
2729
- return testCases;
2730
- }
2731
- function getSampleValue(def) {
2732
- switch (def.type) {
2733
- case "string":
2734
- return "Sample Text";
2735
- case "number":
2736
- return 42;
2737
- case "boolean":
2738
- return true;
2739
- case "array":
2740
- return [];
2741
- case "object":
2742
- return {};
2743
- default:
2744
- return def.defaultValue;
2745
- }
2746
- }
2747
-
2748
- // src/index.ts
2749
- init_registry();
2750
- // Annotate the CommonJS export names for ESM import in node:
2751
- 0 && (module.exports = {
2752
- AnalyticsCollector,
2753
- DEFAULT_CACHE_CONFIG,
2754
- DEFAULT_RETRY_CONFIG,
2755
- LongTaskObserver,
2756
- MemorySampler,
2757
- SessionManager,
2758
- analytics,
2759
- applyStyles,
2760
- batchFetchComponents,
2761
- buildClassName,
2762
- buildElementStyles,
2763
- buildRegistryFromBundle,
2764
- bumpVersion,
2765
- camelToKebab,
2766
- clearAllCaches,
2767
- clearLocalStorageCache,
2768
- clearMemoryCache,
2769
- clearStyles,
2770
- collectAllDependencies,
2771
- compareVersions,
2772
- configureAnalytics,
2773
- createRegistry,
2774
- detectCircularDependencies,
2775
- extractBindingKeys,
2776
- extractDependencies,
2777
- extractDependenciesFromCode,
2778
- fetchComponent,
2779
- fetchComponentWithDependencies,
2780
- formatStyleValue,
2781
- formatVersion,
2782
- generateTestCases,
2783
- getAnalytics,
2784
- getCacheKey,
2785
- getDependencyTree,
2786
- getFromCache,
2787
- getLongTaskObserver,
2788
- getMemoryCacheSize,
2789
- getMemorySampler,
2790
- getRegistryUrl,
2791
- getSessionManager,
2792
- hasTemplateSyntax,
2793
- invalidateCache,
2794
- isComponentAvailable,
2795
- isValidSpecifier,
2796
- parseVersion,
2797
- prefetchComponents,
2798
- processStyles,
2799
- render,
2800
- renderDynamicList,
2801
- resetAnalytics,
2802
- resetLongTaskObserver,
2803
- resetMemorySampler,
2804
- resetSessionManager,
2805
- resolveBindingPath,
2806
- resolveTemplate,
2807
- resolveTemplateValue,
2808
- resolveTemplatesDeep,
2809
- resolveVersion,
2810
- runAllTests,
2811
- runTestCase,
2812
- satisfiesVersion,
2813
- setInCache,
2814
- setRegistryUrl,
2815
- updateStyles,
2816
- validateAssertion,
2817
- validateProps
2818
- });