@servlyadmin/runtime-core 0.1.2 → 0.1.4
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 +825 -63
- package/dist/index.d.cts +432 -3
- package/dist/index.d.ts +432 -3
- package/dist/index.js +811 -63
- package/package.json +1 -1
package/dist/index.cjs
CHANGED
|
@@ -211,8 +211,13 @@ var init_registry = __esm({
|
|
|
211
211
|
// src/index.ts
|
|
212
212
|
var index_exports = {};
|
|
213
213
|
__export(index_exports, {
|
|
214
|
+
AnalyticsCollector: () => AnalyticsCollector,
|
|
214
215
|
DEFAULT_CACHE_CONFIG: () => DEFAULT_CACHE_CONFIG,
|
|
215
216
|
DEFAULT_RETRY_CONFIG: () => DEFAULT_RETRY_CONFIG,
|
|
217
|
+
LongTaskObserver: () => LongTaskObserver,
|
|
218
|
+
MemorySampler: () => MemorySampler,
|
|
219
|
+
SessionManager: () => SessionManager,
|
|
220
|
+
analytics: () => analytics,
|
|
216
221
|
applyStyles: () => applyStyles,
|
|
217
222
|
batchFetchComponents: () => batchFetchComponents,
|
|
218
223
|
buildClassName: () => buildClassName,
|
|
@@ -226,6 +231,7 @@ __export(index_exports, {
|
|
|
226
231
|
clearStyles: () => clearStyles,
|
|
227
232
|
collectAllDependencies: () => collectAllDependencies,
|
|
228
233
|
compareVersions: () => compareVersions,
|
|
234
|
+
configureAnalytics: () => configureAnalytics,
|
|
229
235
|
createRegistry: () => createRegistry,
|
|
230
236
|
detectCircularDependencies: () => detectCircularDependencies,
|
|
231
237
|
extractBindingKeys: () => extractBindingKeys,
|
|
@@ -236,11 +242,15 @@ __export(index_exports, {
|
|
|
236
242
|
formatStyleValue: () => formatStyleValue,
|
|
237
243
|
formatVersion: () => formatVersion,
|
|
238
244
|
generateTestCases: () => generateTestCases,
|
|
245
|
+
getAnalytics: () => getAnalytics,
|
|
239
246
|
getCacheKey: () => getCacheKey,
|
|
240
247
|
getDependencyTree: () => getDependencyTree,
|
|
241
248
|
getFromCache: () => getFromCache,
|
|
249
|
+
getLongTaskObserver: () => getLongTaskObserver,
|
|
242
250
|
getMemoryCacheSize: () => getMemoryCacheSize,
|
|
251
|
+
getMemorySampler: () => getMemorySampler,
|
|
243
252
|
getRegistryUrl: () => getRegistryUrl,
|
|
253
|
+
getSessionManager: () => getSessionManager,
|
|
244
254
|
hasTemplateSyntax: () => hasTemplateSyntax,
|
|
245
255
|
invalidateCache: () => invalidateCache,
|
|
246
256
|
isComponentAvailable: () => isComponentAvailable,
|
|
@@ -250,6 +260,10 @@ __export(index_exports, {
|
|
|
250
260
|
processStyles: () => processStyles,
|
|
251
261
|
render: () => render,
|
|
252
262
|
renderDynamicList: () => renderDynamicList,
|
|
263
|
+
resetAnalytics: () => resetAnalytics,
|
|
264
|
+
resetLongTaskObserver: () => resetLongTaskObserver,
|
|
265
|
+
resetMemorySampler: () => resetMemorySampler,
|
|
266
|
+
resetSessionManager: () => resetSessionManager,
|
|
253
267
|
resolveBindingPath: () => resolveBindingPath,
|
|
254
268
|
resolveTemplate: () => resolveTemplate,
|
|
255
269
|
resolveTemplateValue: () => resolveTemplateValue,
|
|
@@ -266,6 +280,516 @@ __export(index_exports, {
|
|
|
266
280
|
});
|
|
267
281
|
module.exports = __toCommonJS(index_exports);
|
|
268
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
|
+
|
|
269
793
|
// src/bindings.ts
|
|
270
794
|
var BINDING_SOURCES = [
|
|
271
795
|
"props",
|
|
@@ -372,44 +896,64 @@ function resolveTernaryValue(value, context) {
|
|
|
372
896
|
if (value === "undefined") return void 0;
|
|
373
897
|
return resolveExpression(value, context);
|
|
374
898
|
}
|
|
375
|
-
function resolveTemplate(template, context) {
|
|
899
|
+
function resolveTemplate(template, context, componentId) {
|
|
376
900
|
if (!template || typeof template !== "string") {
|
|
377
901
|
return template;
|
|
378
902
|
}
|
|
379
903
|
if (!hasTemplateSyntax(template)) {
|
|
380
904
|
return template;
|
|
381
905
|
}
|
|
382
|
-
|
|
383
|
-
|
|
384
|
-
|
|
385
|
-
|
|
386
|
-
|
|
387
|
-
|
|
388
|
-
|
|
389
|
-
|
|
390
|
-
return template.replace(TEMPLATE_REGEX, (match, expression) => {
|
|
391
|
-
const value = resolveExpression(expression, context);
|
|
392
|
-
if (value === void 0 || value === null) {
|
|
393
|
-
return "";
|
|
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);
|
|
394
914
|
}
|
|
395
|
-
|
|
396
|
-
|
|
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
|
+
});
|
|
397
931
|
}
|
|
398
|
-
return
|
|
399
|
-
}
|
|
932
|
+
return "";
|
|
933
|
+
}
|
|
400
934
|
}
|
|
401
|
-
function resolveTemplateValue(template, context) {
|
|
935
|
+
function resolveTemplateValue(template, context, componentId) {
|
|
402
936
|
if (!template || typeof template !== "string") {
|
|
403
937
|
return template;
|
|
404
938
|
}
|
|
405
939
|
if (!hasTemplateSyntax(template)) {
|
|
406
940
|
return template;
|
|
407
941
|
}
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
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;
|
|
411
956
|
}
|
|
412
|
-
return resolveTemplate(template, context);
|
|
413
957
|
}
|
|
414
958
|
function isPlainObject(value) {
|
|
415
959
|
return Object.prototype.toString.call(value) === "[object Object]";
|
|
@@ -642,6 +1186,162 @@ function updateStyles(element, oldStyles, newStyles) {
|
|
|
642
1186
|
}
|
|
643
1187
|
}
|
|
644
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
|
+
|
|
645
1345
|
// src/renderer.ts
|
|
646
1346
|
var COMPONENT_TO_TAG = {
|
|
647
1347
|
container: "div",
|
|
@@ -895,52 +1595,84 @@ function renderElement(element, tree, context, eventHandlers, elementStates, sta
|
|
|
895
1595
|
}
|
|
896
1596
|
function render(options) {
|
|
897
1597
|
const { container, elements, context, eventHandlers, componentRegistry, onDependencyNeeded } = options;
|
|
898
|
-
const
|
|
1598
|
+
const startTime = performance.now();
|
|
1599
|
+
const memorySampler = getMemorySampler();
|
|
1600
|
+
const longTaskObserver = getLongTaskObserver();
|
|
1601
|
+
const memoryBefore = memorySampler.sample();
|
|
1602
|
+
longTaskObserver.start();
|
|
899
1603
|
const rootElements = elements.filter((el) => !el.parent || el.parent === null);
|
|
900
|
-
const
|
|
901
|
-
|
|
902
|
-
|
|
903
|
-
|
|
904
|
-
|
|
905
|
-
|
|
906
|
-
|
|
907
|
-
|
|
908
|
-
|
|
909
|
-
|
|
910
|
-
};
|
|
911
|
-
container.innerHTML = "";
|
|
912
|
-
if (rootElements.length === 0) {
|
|
913
|
-
return {
|
|
1604
|
+
const componentId = rootElements[0]?.componentId || "unknown";
|
|
1605
|
+
const version = "latest";
|
|
1606
|
+
try {
|
|
1607
|
+
const tree = buildTree(elements);
|
|
1608
|
+
const state = {
|
|
1609
|
+
container,
|
|
1610
|
+
elements,
|
|
1611
|
+
context,
|
|
1612
|
+
eventHandlers,
|
|
1613
|
+
elementStates: /* @__PURE__ */ new Map(),
|
|
914
1614
|
rootElement: null,
|
|
1615
|
+
componentRegistry,
|
|
1616
|
+
onDependencyNeeded,
|
|
1617
|
+
renderingStack: /* @__PURE__ */ new Set()
|
|
1618
|
+
};
|
|
1619
|
+
container.innerHTML = "";
|
|
1620
|
+
if (rootElements.length === 0) {
|
|
1621
|
+
const duration2 = performance.now() - startTime;
|
|
1622
|
+
const longTasks2 = longTaskObserver.stop();
|
|
1623
|
+
analytics.trackRender(componentId, version, duration2, {
|
|
1624
|
+
elementCount: 0,
|
|
1625
|
+
longTaskCount: longTasks2
|
|
1626
|
+
});
|
|
1627
|
+
return {
|
|
1628
|
+
rootElement: null,
|
|
1629
|
+
update: (newContext) => update(state, newContext),
|
|
1630
|
+
destroy: () => destroy(state)
|
|
1631
|
+
};
|
|
1632
|
+
}
|
|
1633
|
+
if (rootElements.length === 1) {
|
|
1634
|
+
state.rootElement = renderElement(
|
|
1635
|
+
rootElements[0],
|
|
1636
|
+
tree,
|
|
1637
|
+
context,
|
|
1638
|
+
eventHandlers,
|
|
1639
|
+
state.elementStates,
|
|
1640
|
+
state
|
|
1641
|
+
);
|
|
1642
|
+
container.appendChild(state.rootElement);
|
|
1643
|
+
} else {
|
|
1644
|
+
const wrapper = document.createElement("div");
|
|
1645
|
+
wrapper.setAttribute("data-servly-wrapper", "true");
|
|
1646
|
+
for (const root of rootElements) {
|
|
1647
|
+
const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state);
|
|
1648
|
+
wrapper.appendChild(rootElement);
|
|
1649
|
+
}
|
|
1650
|
+
state.rootElement = wrapper;
|
|
1651
|
+
container.appendChild(wrapper);
|
|
1652
|
+
}
|
|
1653
|
+
const duration = performance.now() - startTime;
|
|
1654
|
+
const memoryAfter = memorySampler.sample();
|
|
1655
|
+
const longTasks = longTaskObserver.stop();
|
|
1656
|
+
const heapDelta = memorySampler.calculateDelta(memoryBefore, memoryAfter);
|
|
1657
|
+
analytics.trackRender(componentId, version, duration, {
|
|
1658
|
+
elementCount: elements.length,
|
|
1659
|
+
heapDeltaKB: heapDelta ?? void 0,
|
|
1660
|
+
longTaskCount: longTasks,
|
|
1661
|
+
hasEventHandlers: !!eventHandlers && Object.keys(eventHandlers).length > 0,
|
|
1662
|
+
hasDependencies: !!componentRegistry
|
|
1663
|
+
});
|
|
1664
|
+
return {
|
|
1665
|
+
rootElement: state.rootElement,
|
|
915
1666
|
update: (newContext) => update(state, newContext),
|
|
916
1667
|
destroy: () => destroy(state)
|
|
917
1668
|
};
|
|
1669
|
+
} catch (error) {
|
|
1670
|
+
longTaskObserver.stop();
|
|
1671
|
+
analytics.trackError(componentId, version, error, {
|
|
1672
|
+
errorType: "render"
|
|
1673
|
+
});
|
|
1674
|
+
throw error;
|
|
918
1675
|
}
|
|
919
|
-
if (rootElements.length === 1) {
|
|
920
|
-
state.rootElement = renderElement(
|
|
921
|
-
rootElements[0],
|
|
922
|
-
tree,
|
|
923
|
-
context,
|
|
924
|
-
eventHandlers,
|
|
925
|
-
state.elementStates,
|
|
926
|
-
state
|
|
927
|
-
);
|
|
928
|
-
container.appendChild(state.rootElement);
|
|
929
|
-
} else {
|
|
930
|
-
const wrapper = document.createElement("div");
|
|
931
|
-
wrapper.setAttribute("data-servly-wrapper", "true");
|
|
932
|
-
for (const root of rootElements) {
|
|
933
|
-
const rootElement = renderElement(root, tree, context, eventHandlers, state.elementStates, state);
|
|
934
|
-
wrapper.appendChild(rootElement);
|
|
935
|
-
}
|
|
936
|
-
state.rootElement = wrapper;
|
|
937
|
-
container.appendChild(wrapper);
|
|
938
|
-
}
|
|
939
|
-
return {
|
|
940
|
-
rootElement: state.rootElement,
|
|
941
|
-
update: (newContext) => update(state, newContext),
|
|
942
|
-
destroy: () => destroy(state)
|
|
943
|
-
};
|
|
944
1676
|
}
|
|
945
1677
|
function update(state, newContext) {
|
|
946
1678
|
state.context = newContext;
|
|
@@ -1399,6 +2131,7 @@ async function fetchComponent(id, options = {}) {
|
|
|
1399
2131
|
...DEFAULT_RETRY_CONFIG,
|
|
1400
2132
|
...retryConfig
|
|
1401
2133
|
};
|
|
2134
|
+
const startTime = performance.now();
|
|
1402
2135
|
if (!forceRefresh) {
|
|
1403
2136
|
const cached = getFromCache(id, version, cacheStrategy, cacheConfig);
|
|
1404
2137
|
if (cached) {
|
|
@@ -1406,6 +2139,11 @@ async function fetchComponent(id, options = {}) {
|
|
|
1406
2139
|
if (cached.bundle) {
|
|
1407
2140
|
registry = buildRegistryFromBundle(cached);
|
|
1408
2141
|
}
|
|
2142
|
+
const duration = performance.now() - startTime;
|
|
2143
|
+
analytics.trackFetch(id, cached.version, duration, true, {
|
|
2144
|
+
cacheHit: true,
|
|
2145
|
+
fetchDuration: Math.round(duration)
|
|
2146
|
+
});
|
|
1409
2147
|
return {
|
|
1410
2148
|
data: cached,
|
|
1411
2149
|
fromCache: true,
|
|
@@ -1452,6 +2190,12 @@ async function fetchComponent(id, options = {}) {
|
|
|
1452
2190
|
version: entry.resolved || entry.version
|
|
1453
2191
|
}));
|
|
1454
2192
|
}
|
|
2193
|
+
const duration = performance.now() - startTime;
|
|
2194
|
+
analytics.trackFetch(id, resolvedVersion, duration, false, {
|
|
2195
|
+
cacheHit: false,
|
|
2196
|
+
fetchDuration: Math.round(duration),
|
|
2197
|
+
dependencyCount: data.dependencies ? Object.keys(data.dependencies).length : 0
|
|
2198
|
+
});
|
|
1455
2199
|
return {
|
|
1456
2200
|
data,
|
|
1457
2201
|
fromCache: false,
|
|
@@ -1470,7 +2214,11 @@ async function fetchComponent(id, options = {}) {
|
|
|
1470
2214
|
}
|
|
1471
2215
|
}
|
|
1472
2216
|
}
|
|
1473
|
-
|
|
2217
|
+
const finalError = lastError || new Error("Failed to fetch component");
|
|
2218
|
+
analytics.trackError(id, version, finalError, {
|
|
2219
|
+
errorType: "fetch"
|
|
2220
|
+
});
|
|
2221
|
+
throw finalError;
|
|
1474
2222
|
}
|
|
1475
2223
|
async function fetchComponentWithDependencies(id, options = {}) {
|
|
1476
2224
|
const result = await fetchComponent(id, { ...options, includeBundle: true });
|
|
@@ -1952,8 +2700,13 @@ function getSampleValue(def) {
|
|
|
1952
2700
|
init_registry();
|
|
1953
2701
|
// Annotate the CommonJS export names for ESM import in node:
|
|
1954
2702
|
0 && (module.exports = {
|
|
2703
|
+
AnalyticsCollector,
|
|
1955
2704
|
DEFAULT_CACHE_CONFIG,
|
|
1956
2705
|
DEFAULT_RETRY_CONFIG,
|
|
2706
|
+
LongTaskObserver,
|
|
2707
|
+
MemorySampler,
|
|
2708
|
+
SessionManager,
|
|
2709
|
+
analytics,
|
|
1957
2710
|
applyStyles,
|
|
1958
2711
|
batchFetchComponents,
|
|
1959
2712
|
buildClassName,
|
|
@@ -1967,6 +2720,7 @@ init_registry();
|
|
|
1967
2720
|
clearStyles,
|
|
1968
2721
|
collectAllDependencies,
|
|
1969
2722
|
compareVersions,
|
|
2723
|
+
configureAnalytics,
|
|
1970
2724
|
createRegistry,
|
|
1971
2725
|
detectCircularDependencies,
|
|
1972
2726
|
extractBindingKeys,
|
|
@@ -1977,11 +2731,15 @@ init_registry();
|
|
|
1977
2731
|
formatStyleValue,
|
|
1978
2732
|
formatVersion,
|
|
1979
2733
|
generateTestCases,
|
|
2734
|
+
getAnalytics,
|
|
1980
2735
|
getCacheKey,
|
|
1981
2736
|
getDependencyTree,
|
|
1982
2737
|
getFromCache,
|
|
2738
|
+
getLongTaskObserver,
|
|
1983
2739
|
getMemoryCacheSize,
|
|
2740
|
+
getMemorySampler,
|
|
1984
2741
|
getRegistryUrl,
|
|
2742
|
+
getSessionManager,
|
|
1985
2743
|
hasTemplateSyntax,
|
|
1986
2744
|
invalidateCache,
|
|
1987
2745
|
isComponentAvailable,
|
|
@@ -1991,6 +2749,10 @@ init_registry();
|
|
|
1991
2749
|
processStyles,
|
|
1992
2750
|
render,
|
|
1993
2751
|
renderDynamicList,
|
|
2752
|
+
resetAnalytics,
|
|
2753
|
+
resetLongTaskObserver,
|
|
2754
|
+
resetMemorySampler,
|
|
2755
|
+
resetSessionManager,
|
|
1994
2756
|
resolveBindingPath,
|
|
1995
2757
|
resolveTemplate,
|
|
1996
2758
|
resolveTemplateValue,
|