valtech-components 2.0.498 → 2.0.500

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.
@@ -0,0 +1,141 @@
1
+ /**
2
+ * Analytics Error Handler
3
+ *
4
+ * ErrorHandler personalizado que envía errores no capturados a Firebase Analytics.
5
+ * Se activa si enableErrorTracking=true en analyticsConfig.
6
+ */
7
+ import { ErrorHandler, Injectable, inject } from '@angular/core';
8
+ import { AnalyticsService } from './analytics.service';
9
+ import * as i0 from "@angular/core";
10
+ /**
11
+ * ErrorHandler que trackea errores en Firebase Analytics.
12
+ *
13
+ * Captura errores no manejados de la aplicación y los envía a GA4
14
+ * como eventos 'error_occurred'. También delega al ErrorHandler
15
+ * default para mantener el comportamiento de console.error.
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * // Se activa automáticamente si enableErrorTracking=true
20
+ * provideValtechFirebase({
21
+ * firebase: environment.firebase,
22
+ * enableAnalytics: true,
23
+ * analyticsConfig: {
24
+ * enableErrorTracking: true,
25
+ * },
26
+ * });
27
+ * ```
28
+ */
29
+ export class AnalyticsErrorHandler {
30
+ constructor() {
31
+ this.analytics = inject(AnalyticsService);
32
+ this.defaultHandler = new ErrorHandler();
33
+ }
34
+ /**
35
+ * Maneja un error no capturado.
36
+ * Envía el error a Analytics y luego al handler default.
37
+ */
38
+ handleError(error) {
39
+ // Enviar a Analytics
40
+ try {
41
+ this.trackError(error);
42
+ }
43
+ catch (trackingError) {
44
+ // No fallar si el tracking falla
45
+ console.warn('[AnalyticsErrorHandler] Error tracking failed:', trackingError);
46
+ }
47
+ // Delegar al handler default (console.error)
48
+ this.defaultHandler.handleError(error);
49
+ }
50
+ /**
51
+ * Trackea el error en Analytics
52
+ */
53
+ trackError(error) {
54
+ // Extraer información del error
55
+ const errorInfo = this.extractErrorInfo(error);
56
+ this.analytics.logError(errorInfo.error, {
57
+ source: 'uncaught',
58
+ url: this.getCurrentUrl(),
59
+ ...errorInfo.context,
60
+ });
61
+ }
62
+ /**
63
+ * Extrae información útil del error
64
+ */
65
+ extractErrorInfo(error) {
66
+ const context = {};
67
+ // Error estándar
68
+ if (error instanceof Error) {
69
+ // Detectar errores de chunk loading (lazy loading)
70
+ if (error.message.includes('Loading chunk')) {
71
+ context['error_category'] = 'chunk_loading';
72
+ }
73
+ // Detectar errores de red
74
+ if (error.message.includes('NetworkError') || error.message.includes('Failed to fetch')) {
75
+ context['error_category'] = 'network';
76
+ }
77
+ return { error, context };
78
+ }
79
+ // ErrorEvent (ej: errores de script)
80
+ if (typeof ErrorEvent !== 'undefined' && error instanceof ErrorEvent) {
81
+ return {
82
+ error: new Error(error.message || 'Script error'),
83
+ context: {
84
+ filename: error.filename || 'unknown',
85
+ lineno: String(error.lineno || 0),
86
+ colno: String(error.colno || 0),
87
+ },
88
+ };
89
+ }
90
+ // PromiseRejection
91
+ if (this.isPromiseRejection(error)) {
92
+ const reason = error.reason;
93
+ if (reason instanceof Error) {
94
+ return {
95
+ error: reason,
96
+ context: { error_category: 'unhandled_promise' },
97
+ };
98
+ }
99
+ return {
100
+ error: new Error(String(reason) || 'Unhandled promise rejection'),
101
+ context: { error_category: 'unhandled_promise' },
102
+ };
103
+ }
104
+ // Objeto con message
105
+ if (error && typeof error === 'object' && 'message' in error) {
106
+ return {
107
+ error: new Error(String(error.message)),
108
+ context,
109
+ };
110
+ }
111
+ // Fallback: convertir a string
112
+ return {
113
+ error: new Error(String(error) || 'Unknown error'),
114
+ context,
115
+ };
116
+ }
117
+ /**
118
+ * Verifica si es un PromiseRejectionEvent
119
+ */
120
+ isPromiseRejection(error) {
121
+ return (typeof PromiseRejectionEvent !== 'undefined' &&
122
+ error instanceof PromiseRejectionEvent);
123
+ }
124
+ /**
125
+ * Obtiene la URL actual de forma segura
126
+ */
127
+ getCurrentUrl() {
128
+ try {
129
+ return window?.location?.href || 'unknown';
130
+ }
131
+ catch {
132
+ return 'unknown';
133
+ }
134
+ }
135
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler, deps: [], target: i0.ɵɵFactoryTarget.Injectable }); }
136
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler }); }
137
+ }
138
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsErrorHandler, decorators: [{
139
+ type: Injectable
140
+ }] });
141
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl0aWNzLWVycm9yLWhhbmRsZXIuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2FuYWx5dGljcy1lcnJvci1oYW5kbGVyLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFlBQVksRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ2pFLE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHFCQUFxQixDQUFDOztBQUV2RDs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBa0JHO0FBRUgsTUFBTSxPQUFPLHFCQUFxQjtJQURsQztRQUVtQixjQUFTLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDckMsbUJBQWMsR0FBRyxJQUFJLFlBQVksRUFBRSxDQUFDO0tBMEh0RDtJQXhIQzs7O09BR0c7SUFDSCxXQUFXLENBQUMsS0FBYztRQUN4QixxQkFBcUI7UUFDckIsSUFBSSxDQUFDO1lBQ0gsSUFBSSxDQUFDLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUN6QixDQUFDO1FBQUMsT0FBTyxhQUFhLEVBQUUsQ0FBQztZQUN2QixpQ0FBaUM7WUFDakMsT0FBTyxDQUFDLElBQUksQ0FBQyxnREFBZ0QsRUFBRSxhQUFhLENBQUMsQ0FBQztRQUNoRixDQUFDO1FBRUQsNkNBQTZDO1FBQzdDLElBQUksQ0FBQyxjQUFjLENBQUMsV0FBVyxDQUFDLEtBQUssQ0FBQyxDQUFDO0lBQ3pDLENBQUM7SUFFRDs7T0FFRztJQUNLLFVBQVUsQ0FBQyxLQUFjO1FBQy9CLGdDQUFnQztRQUNoQyxNQUFNLFNBQVMsR0FBRyxJQUFJLENBQUMsZ0JBQWdCLENBQUMsS0FBSyxDQUFDLENBQUM7UUFFL0MsSUFBSSxDQUFDLFNBQVMsQ0FBQyxRQUFRLENBQ3JCLFNBQVMsQ0FBQyxLQUFLLEVBQ2Y7WUFDRSxNQUFNLEVBQUUs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QUFDO1FBQzdDLENBQUM7UUFBQyxNQUFNLENBQUM7WUFDUCxPQUFPLFNBQVMsQ0FBQztRQUNuQixDQUFDO0lBQ0gsQ0FBQzsrR0EzSFUscUJBQXFCO21IQUFyQixxQkFBcUI7OzRGQUFyQixxQkFBcUI7a0JBRGpDLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEFuYWx5dGljcyBFcnJvciBIYW5kbGVyXG4gKlxuICogRXJyb3JIYW5kbGVyIHBlcnNvbmFsaXphZG8gcXVlIGVudsOtYSBlcnJvcmVzIG5vIGNhcHR1cmFkb3MgYSBGaXJlYmFzZSBBbmFseXRpY3MuXG4gKiBTZSBhY3RpdmEgc2kgZW5hYmxlRXJyb3JUcmFja2luZz10cnVlIGVuIGFuYWx5dGljc0NvbmZpZy5cbiAqL1xuXG5pbXBvcnQgeyBFcnJvckhhbmRsZXIsIEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgQW5hbHl0aWNzU2VydmljZSB9IGZyb20gJy4vYW5hbHl0aWNzLnNlcnZpY2UnO1xuXG4vKipcbiAqIEVycm9ySGFuZGxlciBxdWUgdHJhY2tlYSBlcnJvcmVzIGVuIEZpcmViYXNlIEFuYWx5dGljcy5cbiAqXG4gKiBDYXB0dXJhIGVycm9yZXMgbm8gbWFuZWphZG9zIGRlIGxhIGFwbGljYWNpw7NuIHkgbG9zIGVudsOtYSBhIEdBNFxuICogY29tbyBldmVudG9zICdlcnJvcl9vY2N1cnJlZCcuIFRhbWJpw6luIGRlbGVnYSBhbCBFcnJvckhhbmRsZXJcbiAqIGRlZmF1bHQgcGFyYSBtYW50ZW5lciBlbCBjb21wb3J0YW1pZW50byBkZSBjb25zb2xlLmVycm9yLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBTZSBhY3RpdmEgYXV0b23DoXRpY2FtZW50ZSBzaSBlbmFibGVFcnJvclRyYWNraW5nPXRydWVcbiAqIHByb3ZpZGVWYWx0ZWNoRmlyZWJhc2Uoe1xuICogICBmaXJlYmFzZTogZW52aXJvbm1lbnQuZmlyZWJhc2UsXG4gKiAgIGVuYWJsZUFuYWx5dGljczogdHJ1ZSxcbiAqICAgYW5hbHl0aWNzQ29uZmlnOiB7XG4gKiAgICAgZW5hYmxlRXJyb3JUcmFja2luZzogdHJ1ZSxcbiAqICAgfSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKClcbmV4cG9ydCBjbGFzcyBBbmFseXRpY3NFcnJvckhhbmRsZXIgaW1wbGVtZW50cyBFcnJvckhhbmRsZXIge1xuICBwcml2YXRlIHJlYWRvbmx5IGFuYWx5dGljcyA9IGluamVjdChBbmFseXRpY3NTZXJ2aWNlKTtcbiAgcHJpdmF0ZSByZWFkb25seSBkZWZhdWx0SGFuZGxlciA9IG5ldyBFcnJvckhhbmRsZXIoKTtcblxuICAvKipcbiAgICogTWFuZWphIHVuIGVycm9yIG5vIGNhcHR1cmFkby5cbiAgICogRW52w61hIGVsIGVycm9yIGEgQW5hbHl0aWNzIHkgbHVlZ28gYWwgaGFuZGxlciBkZWZhdWx0LlxuICAgKi9cbiAgaGFuZGxlRXJyb3IoZXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICAvLyBFbnZpYXIgYSBBbmFseXRpY3NcbiAgICB0cnkge1xuICAgICAgdGhpcy50cmFja0Vycm9yKGVycm9yKTtcbiAgICB9IGNhdGNoICh0cmFja2luZ0Vycm9yKSB7XG4gICAgICAvLyBObyBmYWxsYXIgc2kgZWwgdHJhY2tpbmcgZmFsbGFcbiAgICAgIGNvbnNvbGUud2FybignW0FuYWx5dGljc0Vycm9ySGFuZGxlcl0gRXJyb3IgdHJhY2tpbmcgZmFpbGVkOicsIHRyYWNraW5nRXJyb3IpO1xuICAgIH1cblxuICAgIC8vIERlbGVnYXIgYWwgaGFuZGxlciBkZWZhdWx0IChjb25zb2xlLmVycm9yKVxuICAgIHRoaXMuZGVmYXVsdEhhbmRsZXIuaGFuZGxlRXJyb3IoZXJyb3IpO1xuICB9XG5cbiAgLyoqXG4gICAqIFRyYWNrZWEgZWwgZXJyb3IgZW4gQW5hbHl0aWNzXG4gICAqL1xuICBwcml2YXRlIHRyYWNrRXJyb3IoZXJyb3I6IHVua25vd24pOiB2b2lkIHtcbiAgICAvLyBFeHRyYWVyIGluZm9ybWFjacOzbiBkZWwgZXJyb3JcbiAgICBjb25zdCBlcnJvckluZm8gPSB0aGlzLmV4dHJhY3RFcnJvckluZm8oZXJyb3IpO1xuXG4gICAgdGhpcy5hbmFseXRpY3MubG9nRXJyb3IoXG4gICAgICBlcnJvckluZm8uZXJyb3IsXG4gICAgICB7XG4gICAgICAgIHNvdXJjZTogJ3VuY2F1Z2h0JyxcbiAgICAgICAgdXJsOiB0aGlzLmdldEN1cnJlbnRVcmwoKSxcbiAgICAgICAgLi4uZXJyb3JJbmZvLmNvbnRleHQsXG4gICAgICB9XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFeHRyYWUgaW5mb3JtYWNpw7NuIMO6dGlsIGRlbCBlcnJvclxuICAgKi9cbiAgcHJpdmF0ZSBleHRyYWN0RXJyb3JJbmZvKGVycm9yOiB1bmtub3duKToge1xuICAgIGVycm9yOiBFcnJvcjtcbiAgICBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+O1xuICB9IHtcbiAgICBjb25zdCBjb250ZXh0OiBSZWNvcmQ8c3RyaW5nLCBzdHJpbmc+ID0ge307XG5cbiAgICAvLyBFcnJvciBlc3TDoW5kYXJcbiAgICBpZiAoZXJyb3IgaW5zdGFuY2VvZiBFcnJvcikge1xuICAgICAgLy8gRGV0ZWN0YXIgZXJyb3JlcyBkZSBjaHVuayBsb2FkaW5nIChsYXp5IGxvYWRpbmcpXG4gICAgICBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnTG9hZGluZyBjaHVuaycpKSB7XG4gICAgICAgIGNvbnRleHRbJ2Vycm9yX2NhdGVnb3J5J10gPSAnY2h1bmtfbG9hZGluZyc7XG4gICAgICB9XG5cbiAgICAgIC8vIERldGVjdGFyIGVycm9yZXMgZGUgcmVkXG4gICAgICBpZiAoZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnTmV0d29ya0Vycm9yJykgfHwgZXJyb3IubWVzc2FnZS5pbmNsdWRlcygnRmFpbGVkIHRvIGZldGNoJykpIHtcbiAgICAgICAgY29udGV4dFsnZXJyb3JfY2F0ZWdvcnknXSA9ICduZXR3b3JrJztcbiAgICAgIH1cblxuICAgICAgcmV0dXJuIHsgZXJyb3IsIGNvbnRleHQgfTtcbiAgICB9XG5cbiAgICAvLyBFcnJvckV2ZW50IChlajogZXJyb3JlcyBkZSBzY3JpcHQpXG4gICAgaWYgKHR5cGVvZiBFcnJvckV2ZW50ICE9PSAndW5kZWZpbmVkJyAmJiBlcnJvciBpbnN0YW5jZW9mIEVycm9yRXZlbnQpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVycm9yOiBuZXcgRXJyb3IoZXJyb3IubWVzc2FnZSB8fCAnU2NyaXB0IGVycm9yJyksXG4gICAgICAgIGNvbnRleHQ6IHtcbiAgICAgICAgICBmaWxlbmFtZTogZXJyb3IuZmlsZW5hbWUgfHwgJ3Vua25vd24nLFxuICAgICAgICAgIGxpbmVubzogU3RyaW5nKGVycm9yLmxpbmVubyB8fCAwKSxcbiAgICAgICAgICBjb2xubzogU3RyaW5nKGVycm9yLmNvbG5vIHx8IDApLFxuICAgICAgICB9LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBQcm9taXNlUmVqZWN0aW9uXG4gICAgaWYgKHRoaXMuaXNQcm9taXNlUmVqZWN0aW9uKGVycm9yKSkge1xuICAgICAgY29uc3QgcmVhc29uID0gKGVycm9yIGFzIFByb21pc2VSZWplY3Rpb25FdmVudCkucmVhc29uO1xuICAgICAgaWYgKHJlYXNvbiBpbnN0YW5jZW9mIEVycm9yKSB7XG4gICAgICAgIHJldHVybiB7XG4gICAgICAgICAgZXJyb3I6IHJlYXNvbixcbiAgICAgICAgICBjb250ZXh0OiB7IGVycm9yX2NhdGVnb3J5OiAndW5oYW5kbGVkX3Byb21pc2UnIH0sXG4gICAgICAgIH07XG4gICAgICB9XG4gICAgICByZXR1cm4ge1xuICAgICAgICBlcnJvcjogbmV3IEVycm9yKFN0cmluZyhyZWFzb24pIHx8ICdVbmhhbmRsZWQgcHJvbWlzZSByZWplY3Rpb24nKSxcbiAgICAgICAgY29udGV4dDogeyBlcnJvcl9jYXRlZ29yeTogJ3VuaGFuZGxlZF9wcm9taXNlJyB9LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBPYmpldG8gY29uIG1lc3NhZ2VcbiAgICBpZiAoZXJyb3IgJiYgdHlwZW9mIGVycm9yID09PSAnb2JqZWN0JyAmJiAnbWVzc2FnZScgaW4gZXJyb3IpIHtcbiAgICAgIHJldHVybiB7XG4gICAgICAgIGVycm9yOiBuZXcgRXJyb3IoU3RyaW5nKChlcnJvciBhcyB7IG1lc3NhZ2U6IHVua25vd24gfSkubWVzc2FnZSkpLFxuICAgICAgICBjb250ZXh0LFxuICAgICAgfTtcbiAgICB9XG5cbiAgICAvLyBGYWxsYmFjazogY29udmVydGlyIGEgc3RyaW5nXG4gICAgcmV0dXJuIHtcbiAgICAgIGVycm9yOiBuZXcgRXJyb3IoU3RyaW5nKGVycm9yKSB8fCAnVW5rbm93biBlcnJvcicpLFxuICAgICAgY29udGV4dCxcbiAgICB9O1xuICB9XG5cbiAgLyoqXG4gICAqIFZlcmlmaWNhIHNpIGVzIHVuIFByb21pc2VSZWplY3Rpb25FdmVudFxuICAgKi9cbiAgcHJpdmF0ZSBpc1Byb21pc2VSZWplY3Rpb24oZXJyb3I6IHVua25vd24pOiBib29sZWFuIHtcbiAgICByZXR1cm4gKFxuICAgICAgdHlwZW9mIFByb21pc2VSZWplY3Rpb25FdmVudCAhPT0gJ3VuZGVmaW5lZCcgJiZcbiAgICAgIGVycm9yIGluc3RhbmNlb2YgUHJvbWlzZVJlamVjdGlvbkV2ZW50XG4gICAgKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIGxhIFVSTCBhY3R1YWwgZGUgZm9ybWEgc2VndXJhXG4gICAqL1xuICBwcml2YXRlIGdldEN1cnJlbnRVcmwoKTogc3RyaW5nIHtcbiAgICB0cnkge1xuICAgICAgcmV0dXJuIHdpbmRvdz8ubG9jYXRpb24/LmhyZWYgfHwgJ3Vua25vd24nO1xuICAgIH0gY2F0Y2gge1xuICAgICAgcmV0dXJuICd1bmtub3duJztcbiAgICB9XG4gIH1cbn1cbiJdfQ==
@@ -0,0 +1,99 @@
1
+ /**
2
+ * Analytics Router Tracker
3
+ *
4
+ * Servicio que trackea automáticamente page views cuando el usuario navega.
5
+ * Se activa automáticamente si enablePageViewTracking=true en analyticsConfig.
6
+ */
7
+ import { DestroyRef, Inject, Injectable, inject } from '@angular/core';
8
+ import { takeUntilDestroyed } from '@angular/core/rxjs-interop';
9
+ import { NavigationEnd, Router } from '@angular/router';
10
+ import { filter } from 'rxjs/operators';
11
+ import { VALTECH_FIREBASE_CONFIG } from './config';
12
+ import { AnalyticsService } from './analytics.service';
13
+ import * as i0 from "@angular/core";
14
+ /**
15
+ * Tracker automático de page views via Router.
16
+ *
17
+ * Este servicio escucha eventos de navegación del Router y registra
18
+ * page views automáticamente en Firebase Analytics.
19
+ *
20
+ * Se excluyen rutas configuradas en `analyticsConfig.excludeRoutes`.
21
+ *
22
+ * @example
23
+ * ```typescript
24
+ * // Se activa automáticamente si enablePageViewTracking=true
25
+ * provideValtechFirebase({
26
+ * firebase: environment.firebase,
27
+ * enableAnalytics: true,
28
+ * analyticsConfig: {
29
+ * enablePageViewTracking: true,
30
+ * excludeRoutes: ['/admin/*', '/debug/*'],
31
+ * },
32
+ * });
33
+ * ```
34
+ */
35
+ export class AnalyticsRouterTracker {
36
+ constructor(config) {
37
+ this.config = config;
38
+ this.analytics = inject(AnalyticsService);
39
+ this.router = inject(Router);
40
+ this.destroyRef = inject(DestroyRef);
41
+ const analyticsConfig = config.analyticsConfig ?? {};
42
+ this.enabled = analyticsConfig.enablePageViewTracking !== false;
43
+ this.excludePatterns = this.compileExcludePatterns(analyticsConfig.excludeRoutes ?? []);
44
+ if (this.enabled && config.enableAnalytics) {
45
+ this.startTracking();
46
+ }
47
+ }
48
+ /**
49
+ * Inicia el tracking de navegación
50
+ */
51
+ startTracking() {
52
+ this.router.events
53
+ .pipe(filter((event) => event instanceof NavigationEnd), filter((event) => !this.isExcluded(event.urlAfterRedirects)), takeUntilDestroyed(this.destroyRef))
54
+ .subscribe((event) => {
55
+ this.analytics.logPageView(event.urlAfterRedirects);
56
+ });
57
+ }
58
+ /**
59
+ * Compila patrones de exclusión a RegExp
60
+ */
61
+ compileExcludePatterns(patterns) {
62
+ return patterns.map((pattern) => {
63
+ // Convertir glob pattern a regex
64
+ // Ej: '/admin/*' -> /^\/admin\/.*$/
65
+ const regexPattern = pattern
66
+ .replace(/[.+?^${}()|[\]\\]/g, '\\$&') // Escapar caracteres especiales
67
+ .replace(/\*/g, '.*'); // Convertir * a .*
68
+ return new RegExp(`^${regexPattern}$`);
69
+ });
70
+ }
71
+ /**
72
+ * Verifica si una URL debe ser excluida del tracking
73
+ */
74
+ isExcluded(url) {
75
+ // Remover query params para la comparación
76
+ const path = url.split('?')[0];
77
+ return this.excludePatterns.some((pattern) => pattern.test(path));
78
+ }
79
+ /**
80
+ * Registra un page view manualmente.
81
+ * Útil para casos donde necesitas trackear manualmente.
82
+ */
83
+ trackPageView(path, title) {
84
+ if (this.isExcluded(path)) {
85
+ return;
86
+ }
87
+ this.analytics.logPageView(path, title);
88
+ }
89
+ static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, deps: [{ token: VALTECH_FIREBASE_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable }); }
90
+ static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, providedIn: 'root' }); }
91
+ }
92
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: AnalyticsRouterTracker, decorators: [{
93
+ type: Injectable,
94
+ args: [{ providedIn: 'root' }]
95
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
96
+ type: Inject,
97
+ args: [VALTECH_FIREBASE_CONFIG]
98
+ }] }] });
99
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiYW5hbHl0aWNzLXJvdXRlci10cmFja2VyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9maXJlYmFzZS9hbmFseXRpY3Mtcm91dGVyLXRyYWNrZXIudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7O0dBS0c7QUFFSCxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3ZFLE9BQU8sRUFBRSxrQkFBa0IsRUFBRSxNQUFNLDRCQUE0QixDQUFDO0FBQ2hFLE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxFQUFFLE1BQU0saUJBQWlCLENBQUM7QUFDeEQsT0FBTyxFQUFFLE1BQU0sRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRXhDLE9BQU8sRUFBRSx1QkFBdUIsRUFBRSxNQUFNLFVBQVUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxxQkFBcUIsQ0FBQzs7QUFFdkQ7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBb0JHO0FBRUgsTUFBTSxPQUFPLHNCQUFzQjtJQVFqQyxZQUMyQyxNQUE2QjtRQUE3QixXQUFNLEdBQU4sTUFBTSxDQUF1QjtRQVJ2RCxjQUFTLEdBQUcsTUFBTSxDQUFDLGdCQUFnQixDQUFDLENBQUM7UUFDckMsV0FBTSxHQUFHLE1BQU0sQ0FBQyxNQUFNLENBQUMsQ0FBQztRQUN4QixlQUFVLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxDQUFDO1FBUS9DLE1BQU0sZUFBZSxHQUFHLE1BQU0sQ0FBQyxlQUFlLElBQUksRUFBRSxDQUFDO1FBQ3JELElBQUksQ0FBQyxPQUFPLEdBQUcsZUFBZSxDQUFDLHNCQUFzQixLQUFLLEtBQUssQ0FBQztRQUNoRSxJQUFJLENBQUMsZUFBZSxHQUFHLElBQUksQ0FBQyxzQkFBc0IsQ0FBQyxlQUFlLENBQUMsYUFBYSxJQUFJLEVBQUUsQ0FBQyxDQUFDO1FBRXhGLElBQUksSUFBSSxDQUFDLE9BQU8sSUFBSSxNQUFNLENBQUMsZUFBZSxFQUFFLENBQUM7WUFDM0MsSUFBSSxDQUFDLGFBQWEsRUFBRSxDQUFDO1FBQ3ZCLENBQUM7SUFDSCxDQUFDO0lBRUQ7O09BRUc7SUFDSyxhQUFhO1FBQ25CLElBQUksQ0FBQyxNQUFNLENBQUMsTUFBTTthQUNmLElBQUksQ0FDSCxNQUFNLENBQUMsQ0FBQyxLQUFLLEVBQTBCLEVBQUUsQ0FBQyxLQUFLLFlBQVksYUFBYSxDQUFDLEVBQ3pFLE1BQU0sQ0FBQyxDQUFDLEtBQUssRUFBRSxFQUFFLENBQUMsQ0FBQyxJQUFJLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxpQkFBaUIsQ0FBQyxDQUFDLEVBQzVELGtCQUFrQixDQUFDLElBQUksQ0FBQyxVQUFVLENBQUMsQ0FDcEM7YUFDQSxTQUFTLENBQUMsQ0FBQyxLQUFLLEVBQUUsRUFBRTtZQUNuQixJQUFJLENBQUMsU0FBUyxDQUFDLFdBQVcsQ0FBQyxLQUFLLENBQUMsaUJBQWlCLENBQUMsQ0FBQztRQUN0RCxDQUFDLENBQUMsQ0FBQztJQUNQLENBQUM7SUFFRDs7T0FFRztJQUNLLHNCQUFzQixDQUFDLFFBQWtCO1FBQy9DLE9BQU8sUUFBUSxDQUFDLEdBQUcsQ0FBQyxDQUFDLE9BQU8sRUFBRSxFQUFFO1lBQzlCLGlDQUFpQztZQUNqQyxvQ0FBb0M7WUFDcEMsTUFBTSxZQUFZLEdBQUcsT0FBTztpQkFDekIsT0FBTyxDQUFDLG9CQUFvQixFQUFFLE1BQU0sQ0FBQyxDQUFDLGdDQUFnQztpQkFDdEUsT0FBTyxDQUFDLEtBQUssRUFBRSxJQUFJLENBQUMsQ0FBQyxDQUFDLG1CQUFtQjtZQUU1QyxPQUFPLElBQUksTUFBTSxDQUFDLElBQUksWUFBWSxHQUFHLENBQUMsQ0FBQztRQUN6QyxDQUFDLENBQUMsQ0FBQztJQUNMLENBQUM7SUFFRDs7T0FFRztJQUNLLFVBQVUsQ0FBQyxHQUFXO1FBQzVCLDJDQUEyQztRQUMzQyxNQUFNLElBQUksR0FBRyxHQUFHLENBQUMsS0FBSyxDQUFDLEdBQUcsQ0FBQyxDQUFDLENBQUMsQ0FBQyxDQUFDO1FBRS9CLE9BQU8sSUFBSSxDQUFDLGVBQWUsQ0FBQyxJQUFJLENBQUMsQ0FBQyxPQUFPLEVBQUUsRUFBRSxDQUFDLE9BQU8sQ0FBQyxJQUFJLENBQUMsSUFBSSxDQUFDLENBQUMsQ0FBQztJQUNwRSxDQUFDO0lBRUQ7OztPQUdHO0lBQ0gsYUFBYSxDQUFDLElBQVksRUFBRSxLQUFjO1FBQ3hDLElBQUksSUFBSSxDQUFDLFVBQVUsQ0FBQyxJQUFJLENBQUMsRUFBRSxDQUFDO1lBQzFCLE9BQU87UUFDVCxDQUFDO1FBQ0QsSUFBSSxDQUFDLFNBQVMsQ0FBQyxXQUFXLENBQUMsSUFBSSxFQUFFLEtBQUssQ0FBQyxDQUFDO0lBQzFDLENBQUM7K0dBckVVLHNCQUFzQixrQkFTdkIsdUJBQXVCO21IQVR0QixzQkFBc0IsY0FEVCxNQUFNOzs0RkFDbkIsc0JBQXNCO2tCQURsQyxVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRTs7MEJBVTdCLE1BQU07MkJBQUMsdUJBQXVCIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBBbmFseXRpY3MgUm91dGVyIFRyYWNrZXJcbiAqXG4gKiBTZXJ2aWNpbyBxdWUgdHJhY2tlYSBhdXRvbcOhdGljYW1lbnRlIHBhZ2Ugdmlld3MgY3VhbmRvIGVsIHVzdWFyaW8gbmF2ZWdhLlxuICogU2UgYWN0aXZhIGF1dG9tw6F0aWNhbWVudGUgc2kgZW5hYmxlUGFnZVZpZXdUcmFja2luZz10cnVlIGVuIGFuYWx5dGljc0NvbmZpZy5cbiAqL1xuXG5pbXBvcnQgeyBEZXN0cm95UmVmLCBJbmplY3QsIEluamVjdGFibGUsIGluamVjdCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgdGFrZVVudGlsRGVzdHJveWVkIH0gZnJvbSAnQGFuZ3VsYXIvY29yZS9yeGpzLWludGVyb3AnO1xuaW1wb3J0IHsgTmF2aWdhdGlvbkVuZCwgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IGZpbHRlciB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcblxuaW1wb3J0IHsgVkFMVEVDSF9GSVJFQkFTRV9DT05GSUcgfSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBWYWx0ZWNoRmlyZWJhc2VDb25maWcgfSBmcm9tICcuL3R5cGVzJztcbmltcG9ydCB7IEFuYWx5dGljc1NlcnZpY2UgfSBmcm9tICcuL2FuYWx5dGljcy5zZXJ2aWNlJztcblxuLyoqXG4gKiBUcmFja2VyIGF1dG9tw6F0aWNvIGRlIHBhZ2Ugdmlld3MgdmlhIFJvdXRlci5cbiAqXG4gKiBFc3RlIHNlcnZpY2lvIGVzY3VjaGEgZXZlbnRvcyBkZSBuYXZlZ2FjacOzbiBkZWwgUm91dGVyIHkgcmVnaXN0cmFcbiAqIHBhZ2Ugdmlld3MgYXV0b23DoXRpY2FtZW50ZSBlbiBGaXJlYmFzZSBBbmFseXRpY3MuXG4gKlxuICogU2UgZXhjbHV5ZW4gcnV0YXMgY29uZmlndXJhZGFzIGVuIGBhbmFseXRpY3NDb25maWcuZXhjbHVkZVJvdXRlc2AuXG4gKlxuICogQGV4YW1wbGVcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIC8vIFNlIGFjdGl2YSBhdXRvbcOhdGljYW1lbnRlIHNpIGVuYWJsZVBhZ2VWaWV3VHJhY2tpbmc9dHJ1ZVxuICogcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSh7XG4gKiAgIGZpcmViYXNlOiBlbnZpcm9ubWVudC5maXJlYmFzZSxcbiAqICAgZW5hYmxlQW5hbHl0aWNzOiB0cnVlLFxuICogICBhbmFseXRpY3NDb25maWc6IHtcbiAqICAgICBlbmFibGVQYWdlVmlld1RyYWNraW5nOiB0cnVlLFxuICogICAgIGV4Y2x1ZGVSb3V0ZXM6IFsnL2FkbWluLyonLCAnL2RlYnVnLyonXSxcbiAqICAgfSxcbiAqIH0pO1xuICogYGBgXG4gKi9cbkBJbmplY3RhYmxlKHsgcHJvdmlkZWRJbjogJ3Jvb3QnIH0pXG5leHBvcnQgY2xhc3MgQW5hbHl0aWNzUm91dGVyVHJhY2tlciB7XG4gIHByaXZhdGUgcmVhZG9ubHkgYW5hbHl0aWNzID0gaW5qZWN0KEFuYWx5dGljc1NlcnZpY2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IHJvdXRlciA9IGluamVjdChSb3V0ZXIpO1xuICBwcml2YXRlIHJlYWRvbmx5IGRlc3Ryb3lSZWYgPSBpbmplY3QoRGVzdHJveVJlZik7XG5cbiAgcHJpdmF0ZSByZWFkb25seSBleGNsdWRlUGF0dGVybnM6IFJlZ0V4cFtdO1xuICBwcml2YXRlIHJlYWRvbmx5IGVuYWJsZWQ6IGJvb2xlYW47XG5cbiAgY29uc3RydWN0b3IoXG4gICAgQEluamVjdChWQUxURUNIX0ZJUkVCQVNFX0NPTkZJRykgcHJpdmF0ZSBjb25maWc6IFZhbHRlY2hGaXJlYmFzZUNvbmZpZ1xuICApIHtcbiAgICBjb25zdCBhbmFseXRpY3NDb25maWcgPSBjb25maWcuYW5hbHl0aWNzQ29uZmlnID8/IHt9O1xuICAgIHRoaXMuZW5hYmxlZCA9IGFuYWx5dGljc0NvbmZpZy5lbmFibGVQYWdlVmlld1RyYWNraW5nICE9PSBmYWxzZTtcbiAgICB0aGlzLmV4Y2x1ZGVQYXR0ZXJucyA9IHRoaXMuY29tcGlsZUV4Y2x1ZGVQYXR0ZXJucyhhbmFseXRpY3NDb25maWcuZXhjbHVkZVJvdXRlcyA/PyBbXSk7XG5cbiAgICBpZiAodGhpcy5lbmFibGVkICYmIGNvbmZpZy5lbmFibGVBbmFseXRpY3MpIHtcbiAgICAgIHRoaXMuc3RhcnRUcmFja2luZygpO1xuICAgIH1cbiAgfVxuXG4gIC8qKlxuICAgKiBJbmljaWEgZWwgdHJhY2tpbmcgZGUgbmF2ZWdhY2nDs25cbiAgICovXG4gIHByaXZhdGUgc3RhcnRUcmFja2luZygpOiB2b2lkIHtcbiAgICB0aGlzLnJvdXRlci5ldmVudHNcbiAgICAgIC5waXBlKFxuICAgICAgICBmaWx0ZXIoKGV2ZW50KTogZXZlbnQgaXMgTmF2aWdhdGlvbkVuZCA9PiBldmVudCBpbnN0YW5jZW9mIE5hdmlnYXRpb25FbmQpLFxuICAgICAgICBmaWx0ZXIoKGV2ZW50KSA9PiAhdGhpcy5pc0V4Y2x1ZGVkKGV2ZW50LnVybEFmdGVyUmVkaXJlY3RzKSksXG4gICAgICAgIHRha2VVbnRpbERlc3Ryb3llZCh0aGlzLmRlc3Ryb3lSZWYpXG4gICAgICApXG4gICAgICAuc3Vic2NyaWJlKChldmVudCkgPT4ge1xuICAgICAgICB0aGlzLmFuYWx5dGljcy5sb2dQYWdlVmlldyhldmVudC51cmxBZnRlclJlZGlyZWN0cyk7XG4gICAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBDb21waWxhIHBhdHJvbmVzIGRlIGV4Y2x1c2nDs24gYSBSZWdFeHBcbiAgICovXG4gIHByaXZhdGUgY29tcGlsZUV4Y2x1ZGVQYXR0ZXJucyhwYXR0ZXJuczogc3RyaW5nW10pOiBSZWdFeHBbXSB7XG4gICAgcmV0dXJuIHBhdHRlcm5zLm1hcCgocGF0dGVybikgPT4ge1xuICAgICAgLy8gQ29udmVydGlyIGdsb2IgcGF0dGVybiBhIHJlZ2V4XG4gICAgICAvLyBFajogJy9hZG1pbi8qJyAtPiAvXlxcL2FkbWluXFwvLiokL1xuICAgICAgY29uc3QgcmVnZXhQYXR0ZXJuID0gcGF0dGVyblxuICAgICAgICAucmVwbGFjZSgvWy4rP14ke30oKXxbXFxdXFxcXF0vZywgJ1xcXFwkJicpIC8vIEVzY2FwYXIgY2FyYWN0ZXJlcyBlc3BlY2lhbGVzXG4gICAgICAgIC5yZXBsYWNlKC9cXCovZywgJy4qJyk7IC8vIENvbnZlcnRpciAqIGEgLipcblxuICAgICAgcmV0dXJuIG5ldyBSZWdFeHAoYF4ke3JlZ2V4UGF0dGVybn0kYCk7XG4gICAgfSk7XG4gIH1cblxuICAvKipcbiAgICogVmVyaWZpY2Egc2kgdW5hIFVSTCBkZWJlIHNlciBleGNsdWlkYSBkZWwgdHJhY2tpbmdcbiAgICovXG4gIHByaXZhdGUgaXNFeGNsdWRlZCh1cmw6IHN0cmluZyk6IGJvb2xlYW4ge1xuICAgIC8vIFJlbW92ZXIgcXVlcnkgcGFyYW1zIHBhcmEgbGEgY29tcGFyYWNpw7NuXG4gICAgY29uc3QgcGF0aCA9IHVybC5zcGxpdCgnPycpWzBdO1xuXG4gICAgcmV0dXJuIHRoaXMuZXhjbHVkZVBhdHRlcm5zLnNvbWUoKHBhdHRlcm4pID0+IHBhdHRlcm4udGVzdChwYXRoKSk7XG4gIH1cblxuICAvKipcbiAgICogUmVnaXN0cmEgdW4gcGFnZSB2aWV3IG1hbnVhbG1lbnRlLlxuICAgKiDDmnRpbCBwYXJhIGNhc29zIGRvbmRlIG5lY2VzaXRhcyB0cmFja2VhciBtYW51YWxtZW50ZS5cbiAgICovXG4gIHRyYWNrUGFnZVZpZXcocGF0aDogc3RyaW5nLCB0aXRsZT86IHN0cmluZyk6IHZvaWQge1xuICAgIGlmICh0aGlzLmlzRXhjbHVkZWQocGF0aCkpIHtcbiAgICAgIHJldHVybjtcbiAgICB9XG4gICAgdGhpcy5hbmFseXRpY3MubG9nUGFnZVZpZXcocGF0aCwgdGl0bGUpO1xuICB9XG59XG4iXX0=