valtech-components 2.0.452 → 2.0.454
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/esm2022/lib/components/molecules/pin-input/pin-input.component.mjs +10 -2
- package/esm2022/lib/services/auth/auth-state.service.mjs +173 -0
- package/esm2022/lib/services/auth/auth.service.mjs +454 -0
- package/esm2022/lib/services/auth/config.mjs +76 -0
- package/esm2022/lib/services/auth/guards.mjs +194 -0
- package/esm2022/lib/services/auth/index.mjs +70 -0
- package/esm2022/lib/services/auth/interceptor.mjs +98 -0
- package/esm2022/lib/services/auth/storage.service.mjs +141 -0
- package/esm2022/lib/services/auth/sync.service.mjs +149 -0
- package/esm2022/lib/services/auth/token.service.mjs +113 -0
- package/esm2022/lib/services/auth/types.mjs +29 -0
- package/esm2022/lib/services/firebase/config.mjs +108 -0
- package/esm2022/lib/services/firebase/firebase.service.mjs +288 -0
- package/esm2022/lib/services/firebase/firestore-collection.mjs +254 -0
- package/esm2022/lib/services/firebase/firestore.service.mjs +509 -0
- package/esm2022/lib/services/firebase/index.mjs +49 -0
- package/esm2022/lib/services/firebase/messaging.service.mjs +512 -0
- package/esm2022/lib/services/firebase/shared-config.mjs +138 -0
- package/esm2022/lib/services/firebase/storage.service.mjs +422 -0
- package/esm2022/lib/services/firebase/types.mjs +8 -0
- package/esm2022/lib/services/firebase/utils/path-builder.mjs +195 -0
- package/esm2022/lib/services/firebase/utils/query-builder.mjs +302 -0
- package/esm2022/public-api.mjs +3 -5
- package/fesm2022/valtech-components.mjs +4204 -5
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/services/auth/auth-state.service.d.ts +85 -0
- package/lib/services/auth/auth.service.d.ts +146 -0
- package/lib/services/auth/config.d.ts +38 -0
- package/lib/services/auth/guards.d.ts +123 -0
- package/lib/services/auth/index.d.ts +63 -0
- package/lib/services/auth/interceptor.d.ts +22 -0
- package/lib/services/auth/storage.service.d.ts +48 -0
- package/lib/services/auth/sync.service.d.ts +49 -0
- package/lib/services/auth/token.service.d.ts +51 -0
- package/lib/services/auth/types.d.ts +315 -0
- package/lib/services/firebase/config.d.ts +49 -0
- package/lib/services/firebase/firebase.service.d.ts +140 -0
- package/lib/services/firebase/firestore-collection.d.ts +175 -0
- package/lib/services/firebase/firestore.service.d.ts +304 -0
- package/lib/services/firebase/index.d.ts +39 -0
- package/lib/services/firebase/messaging.service.d.ts +263 -0
- package/lib/services/firebase/shared-config.d.ts +126 -0
- package/lib/services/firebase/storage.service.d.ts +206 -0
- package/lib/services/firebase/types.d.ts +281 -0
- package/lib/services/firebase/utils/path-builder.d.ts +132 -0
- package/lib/services/firebase/utils/query-builder.d.ts +210 -0
- package/package.json +1 -1
- package/public-api.d.ts +2 -0
|
@@ -0,0 +1,509 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firestore Service
|
|
3
|
+
*
|
|
4
|
+
* Servicio genérico para operaciones CRUD en Firestore.
|
|
5
|
+
* Soporta lecturas one-time, subscripciones real-time, paginación y queries complejas.
|
|
6
|
+
*/
|
|
7
|
+
import { Injectable } from '@angular/core';
|
|
8
|
+
import { addDoc, collection, collectionData, deleteDoc, doc, docData, getDoc, getDocs, limit, orderBy, query, serverTimestamp, setDoc, startAfter, startAt, endBefore, endAt, Timestamp, updateDoc, where, writeBatch, increment, arrayUnion, arrayRemove, } from '@angular/fire/firestore';
|
|
9
|
+
import { map } from 'rxjs';
|
|
10
|
+
import { buildPath } from './utils/path-builder';
|
|
11
|
+
import * as i0 from "@angular/core";
|
|
12
|
+
import * as i1 from "@angular/fire/firestore";
|
|
13
|
+
/**
|
|
14
|
+
* Servicio para operaciones CRUD en Firestore.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```typescript
|
|
18
|
+
* interface User extends FirestoreDocument {
|
|
19
|
+
* name: string;
|
|
20
|
+
* email: string;
|
|
21
|
+
* role: 'admin' | 'user';
|
|
22
|
+
* }
|
|
23
|
+
*
|
|
24
|
+
* @Component({...})
|
|
25
|
+
* export class UsersComponent {
|
|
26
|
+
* private firestore = inject(FirestoreService);
|
|
27
|
+
*
|
|
28
|
+
* // Lectura one-time
|
|
29
|
+
* async loadUser(id: string) {
|
|
30
|
+
* const user = await this.firestore.getDoc<User>('users', id);
|
|
31
|
+
* }
|
|
32
|
+
*
|
|
33
|
+
* // Subscripción real-time
|
|
34
|
+
* users$ = this.firestore.collectionChanges<User>('users', {
|
|
35
|
+
* where: [{ field: 'role', operator: '==', value: 'admin' }],
|
|
36
|
+
* orderBy: [{ field: 'name', direction: 'asc' }]
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* // Crear documento
|
|
40
|
+
* async createUser(data: Omit<User, 'id'>) {
|
|
41
|
+
* const user = await this.firestore.addDoc<User>('users', data);
|
|
42
|
+
* }
|
|
43
|
+
* }
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class FirestoreService {
|
|
47
|
+
constructor(firestore) {
|
|
48
|
+
this.firestore = firestore;
|
|
49
|
+
}
|
|
50
|
+
// ===========================================================================
|
|
51
|
+
// LECTURAS ONE-TIME (Promise)
|
|
52
|
+
// ===========================================================================
|
|
53
|
+
/**
|
|
54
|
+
* Obtiene un documento por ID (lectura única).
|
|
55
|
+
*
|
|
56
|
+
* @param collectionPath - Ruta de la colección
|
|
57
|
+
* @param docId - ID del documento
|
|
58
|
+
* @returns Documento o null si no existe
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* ```typescript
|
|
62
|
+
* const user = await firestoreService.getDoc<User>('users', 'abc123');
|
|
63
|
+
* if (user) {
|
|
64
|
+
* console.log(user.name);
|
|
65
|
+
* }
|
|
66
|
+
* ```
|
|
67
|
+
*/
|
|
68
|
+
async getDoc(collectionPath, docId) {
|
|
69
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
70
|
+
const snapshot = await getDoc(docRef);
|
|
71
|
+
if (!snapshot.exists()) {
|
|
72
|
+
return null;
|
|
73
|
+
}
|
|
74
|
+
return this.mapDocument(snapshot);
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Obtiene múltiples documentos con opciones de query.
|
|
78
|
+
*
|
|
79
|
+
* @param collectionPath - Ruta de la colección
|
|
80
|
+
* @param options - Opciones de query (where, orderBy, limit)
|
|
81
|
+
* @returns Array de documentos
|
|
82
|
+
*
|
|
83
|
+
* @example
|
|
84
|
+
* ```typescript
|
|
85
|
+
* // Todos los usuarios activos ordenados por nombre
|
|
86
|
+
* const users = await firestoreService.getDocs<User>('users', {
|
|
87
|
+
* where: [{ field: 'active', operator: '==', value: true }],
|
|
88
|
+
* orderBy: [{ field: 'name', direction: 'asc' }],
|
|
89
|
+
* limit: 50
|
|
90
|
+
* });
|
|
91
|
+
* ```
|
|
92
|
+
*/
|
|
93
|
+
async getDocs(collectionPath, options) {
|
|
94
|
+
const collectionRef = collection(this.firestore, collectionPath);
|
|
95
|
+
const constraints = this.buildQueryConstraints(options);
|
|
96
|
+
const q = query(collectionRef, ...constraints);
|
|
97
|
+
const snapshot = await getDocs(q);
|
|
98
|
+
return snapshot.docs.map((doc) => this.mapDocument(doc));
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Obtiene documentos con paginación basada en cursores.
|
|
102
|
+
*
|
|
103
|
+
* @param collectionPath - Ruta de la colección
|
|
104
|
+
* @param options - Opciones de query (debe incluir limit)
|
|
105
|
+
* @returns Resultado paginado con cursor para la siguiente página
|
|
106
|
+
*
|
|
107
|
+
* @example
|
|
108
|
+
* ```typescript
|
|
109
|
+
* // Primera página
|
|
110
|
+
* const page1 = await firestoreService.getPaginated<User>('users', {
|
|
111
|
+
* orderBy: [{ field: 'createdAt', direction: 'desc' }],
|
|
112
|
+
* limit: 10
|
|
113
|
+
* });
|
|
114
|
+
*
|
|
115
|
+
* // Siguiente página
|
|
116
|
+
* if (page1.hasMore) {
|
|
117
|
+
* const page2 = await firestoreService.getPaginated<User>('users', {
|
|
118
|
+
* orderBy: [{ field: 'createdAt', direction: 'desc' }],
|
|
119
|
+
* limit: 10,
|
|
120
|
+
* startAfter: page1.lastDoc
|
|
121
|
+
* });
|
|
122
|
+
* }
|
|
123
|
+
* ```
|
|
124
|
+
*/
|
|
125
|
+
async getPaginated(collectionPath, options) {
|
|
126
|
+
const collectionRef = collection(this.firestore, collectionPath);
|
|
127
|
+
const constraints = this.buildQueryConstraints(options);
|
|
128
|
+
// Pedir uno más para saber si hay más páginas
|
|
129
|
+
const q = query(collectionRef, ...constraints, limit(options.limit + 1));
|
|
130
|
+
const snapshot = await getDocs(q);
|
|
131
|
+
const docs = snapshot.docs;
|
|
132
|
+
const hasMore = docs.length > options.limit;
|
|
133
|
+
// Si hay más, remover el documento extra
|
|
134
|
+
const resultDocs = hasMore ? docs.slice(0, -1) : docs;
|
|
135
|
+
const lastDoc = resultDocs.length > 0 ? resultDocs[resultDocs.length - 1] : null;
|
|
136
|
+
return {
|
|
137
|
+
data: resultDocs.map((doc) => this.mapDocument(doc)),
|
|
138
|
+
hasMore,
|
|
139
|
+
lastDoc,
|
|
140
|
+
};
|
|
141
|
+
}
|
|
142
|
+
/**
|
|
143
|
+
* Verifica si un documento existe.
|
|
144
|
+
*
|
|
145
|
+
* @param collectionPath - Ruta de la colección
|
|
146
|
+
* @param docId - ID del documento
|
|
147
|
+
* @returns true si el documento existe
|
|
148
|
+
*/
|
|
149
|
+
async exists(collectionPath, docId) {
|
|
150
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
151
|
+
const snapshot = await getDoc(docRef);
|
|
152
|
+
return snapshot.exists();
|
|
153
|
+
}
|
|
154
|
+
// ===========================================================================
|
|
155
|
+
// SUBSCRIPCIONES REAL-TIME (Observable)
|
|
156
|
+
// ===========================================================================
|
|
157
|
+
/**
|
|
158
|
+
* Suscribe a cambios de un documento (real-time).
|
|
159
|
+
*
|
|
160
|
+
* @param collectionPath - Ruta de la colección
|
|
161
|
+
* @param docId - ID del documento
|
|
162
|
+
* @returns Observable que emite cuando el documento cambia
|
|
163
|
+
*
|
|
164
|
+
* @example
|
|
165
|
+
* ```typescript
|
|
166
|
+
* // En el componente
|
|
167
|
+
* user$ = this.firestoreService.docChanges<User>('users', this.userId);
|
|
168
|
+
*
|
|
169
|
+
* // En el template
|
|
170
|
+
* @if (user$ | async; as user) {
|
|
171
|
+
* <p>{{ user.name }}</p>
|
|
172
|
+
* }
|
|
173
|
+
* ```
|
|
174
|
+
*/
|
|
175
|
+
docChanges(collectionPath, docId) {
|
|
176
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
177
|
+
return docData(docRef, { idField: 'id' }).pipe(map((data) => {
|
|
178
|
+
if (!data)
|
|
179
|
+
return null;
|
|
180
|
+
return this.convertTimestamps(data);
|
|
181
|
+
}));
|
|
182
|
+
}
|
|
183
|
+
/**
|
|
184
|
+
* Suscribe a cambios de una colección (real-time).
|
|
185
|
+
*
|
|
186
|
+
* @param collectionPath - Ruta de la colección
|
|
187
|
+
* @param options - Opciones de query
|
|
188
|
+
* @returns Observable que emite cuando la colección cambia
|
|
189
|
+
*
|
|
190
|
+
* @example
|
|
191
|
+
* ```typescript
|
|
192
|
+
* // Usuarios activos en tiempo real
|
|
193
|
+
* activeUsers$ = this.firestoreService.collectionChanges<User>('users', {
|
|
194
|
+
* where: [{ field: 'status', operator: '==', value: 'online' }]
|
|
195
|
+
* });
|
|
196
|
+
* ```
|
|
197
|
+
*/
|
|
198
|
+
collectionChanges(collectionPath, options) {
|
|
199
|
+
const collectionRef = collection(this.firestore, collectionPath);
|
|
200
|
+
const constraints = this.buildQueryConstraints(options);
|
|
201
|
+
const q = query(collectionRef, ...constraints);
|
|
202
|
+
return collectionData(q, { idField: 'id' }).pipe(map((docs) => docs.map((doc) => this.convertTimestamps(doc))));
|
|
203
|
+
}
|
|
204
|
+
// ===========================================================================
|
|
205
|
+
// ESCRITURA
|
|
206
|
+
// ===========================================================================
|
|
207
|
+
/**
|
|
208
|
+
* Agrega un documento con ID auto-generado.
|
|
209
|
+
*
|
|
210
|
+
* @param collectionPath - Ruta de la colección
|
|
211
|
+
* @param data - Datos del documento (sin id, createdAt, updatedAt)
|
|
212
|
+
* @returns Documento creado con su ID
|
|
213
|
+
*
|
|
214
|
+
* @example
|
|
215
|
+
* ```typescript
|
|
216
|
+
* const newUser = await firestoreService.addDoc<User>('users', {
|
|
217
|
+
* name: 'John Doe',
|
|
218
|
+
* email: 'john@example.com',
|
|
219
|
+
* role: 'user'
|
|
220
|
+
* });
|
|
221
|
+
* console.log('Created user with ID:', newUser.id);
|
|
222
|
+
* ```
|
|
223
|
+
*/
|
|
224
|
+
async addDoc(collectionPath, data) {
|
|
225
|
+
const collectionRef = collection(this.firestore, collectionPath);
|
|
226
|
+
const timestamp = serverTimestamp();
|
|
227
|
+
const docData = {
|
|
228
|
+
...data,
|
|
229
|
+
createdAt: timestamp,
|
|
230
|
+
updatedAt: timestamp,
|
|
231
|
+
};
|
|
232
|
+
const docRef = await addDoc(collectionRef, docData);
|
|
233
|
+
// Obtener el documento creado para retornarlo con timestamps resueltos
|
|
234
|
+
const snapshot = await getDoc(docRef);
|
|
235
|
+
return this.mapDocument(snapshot);
|
|
236
|
+
}
|
|
237
|
+
/**
|
|
238
|
+
* Crea o sobrescribe un documento con ID específico.
|
|
239
|
+
*
|
|
240
|
+
* @param collectionPath - Ruta de la colección
|
|
241
|
+
* @param docId - ID del documento
|
|
242
|
+
* @param data - Datos del documento
|
|
243
|
+
* @param options - Opciones (merge: true para merge en lugar de sobrescribir)
|
|
244
|
+
*
|
|
245
|
+
* @example
|
|
246
|
+
* ```typescript
|
|
247
|
+
* // Sobrescribir completamente
|
|
248
|
+
* await firestoreService.setDoc<User>('users', 'user123', userData);
|
|
249
|
+
*
|
|
250
|
+
* // Merge con datos existentes
|
|
251
|
+
* await firestoreService.setDoc<User>('users', 'user123', { name: 'New Name' }, { merge: true });
|
|
252
|
+
* ```
|
|
253
|
+
*/
|
|
254
|
+
async setDoc(collectionPath, docId, data, options) {
|
|
255
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
256
|
+
const timestamp = serverTimestamp();
|
|
257
|
+
const docData = {
|
|
258
|
+
...data,
|
|
259
|
+
updatedAt: timestamp,
|
|
260
|
+
...(options?.merge ? {} : { createdAt: timestamp }),
|
|
261
|
+
};
|
|
262
|
+
await setDoc(docRef, docData, { merge: options?.merge ?? false });
|
|
263
|
+
}
|
|
264
|
+
/**
|
|
265
|
+
* Actualiza campos específicos de un documento.
|
|
266
|
+
*
|
|
267
|
+
* @param collectionPath - Ruta de la colección
|
|
268
|
+
* @param docId - ID del documento
|
|
269
|
+
* @param data - Campos a actualizar
|
|
270
|
+
*
|
|
271
|
+
* @example
|
|
272
|
+
* ```typescript
|
|
273
|
+
* await firestoreService.updateDoc<User>('users', 'user123', {
|
|
274
|
+
* name: 'Updated Name',
|
|
275
|
+
* lastLogin: new Date()
|
|
276
|
+
* });
|
|
277
|
+
* ```
|
|
278
|
+
*/
|
|
279
|
+
async updateDoc(collectionPath, docId, data) {
|
|
280
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
281
|
+
await updateDoc(docRef, {
|
|
282
|
+
...data,
|
|
283
|
+
updatedAt: serverTimestamp(),
|
|
284
|
+
});
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Elimina un documento.
|
|
288
|
+
*
|
|
289
|
+
* @param collectionPath - Ruta de la colección
|
|
290
|
+
* @param docId - ID del documento
|
|
291
|
+
*
|
|
292
|
+
* @example
|
|
293
|
+
* ```typescript
|
|
294
|
+
* await firestoreService.deleteDoc('users', 'user123');
|
|
295
|
+
* ```
|
|
296
|
+
*/
|
|
297
|
+
async deleteDoc(collectionPath, docId) {
|
|
298
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
299
|
+
await deleteDoc(docRef);
|
|
300
|
+
}
|
|
301
|
+
// ===========================================================================
|
|
302
|
+
// OPERACIONES EN LOTE
|
|
303
|
+
// ===========================================================================
|
|
304
|
+
/**
|
|
305
|
+
* Ejecuta múltiples operaciones de escritura de forma atómica.
|
|
306
|
+
*
|
|
307
|
+
* @param operations - Función que recibe el batch y agrega operaciones
|
|
308
|
+
*
|
|
309
|
+
* @example
|
|
310
|
+
* ```typescript
|
|
311
|
+
* await firestoreService.batch((batch) => {
|
|
312
|
+
* batch.set('users/user1', { name: 'User 1' });
|
|
313
|
+
* batch.update('users/user2', { status: 'inactive' });
|
|
314
|
+
* batch.delete('users/user3');
|
|
315
|
+
* });
|
|
316
|
+
* ```
|
|
317
|
+
*/
|
|
318
|
+
async batch(operations) {
|
|
319
|
+
const batch = writeBatch(this.firestore);
|
|
320
|
+
const batchApi = {
|
|
321
|
+
set: (path, data) => {
|
|
322
|
+
const [collectionPath, docId] = this.splitPath(path);
|
|
323
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
324
|
+
batch.set(docRef, {
|
|
325
|
+
...data,
|
|
326
|
+
createdAt: serverTimestamp(),
|
|
327
|
+
updatedAt: serverTimestamp(),
|
|
328
|
+
});
|
|
329
|
+
},
|
|
330
|
+
update: (path, data) => {
|
|
331
|
+
const [collectionPath, docId] = this.splitPath(path);
|
|
332
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
333
|
+
batch.update(docRef, {
|
|
334
|
+
...data,
|
|
335
|
+
updatedAt: serverTimestamp(),
|
|
336
|
+
});
|
|
337
|
+
},
|
|
338
|
+
delete: (path) => {
|
|
339
|
+
const [collectionPath, docId] = this.splitPath(path);
|
|
340
|
+
const docRef = doc(this.firestore, collectionPath, docId);
|
|
341
|
+
batch.delete(docRef);
|
|
342
|
+
},
|
|
343
|
+
};
|
|
344
|
+
operations(batchApi);
|
|
345
|
+
await batch.commit();
|
|
346
|
+
}
|
|
347
|
+
// ===========================================================================
|
|
348
|
+
// UTILIDADES
|
|
349
|
+
// ===========================================================================
|
|
350
|
+
/**
|
|
351
|
+
* Construye una ruta a partir de un template.
|
|
352
|
+
*
|
|
353
|
+
* @param template - Template con placeholders {param}
|
|
354
|
+
* @param params - Valores para los placeholders
|
|
355
|
+
* @returns Ruta construida
|
|
356
|
+
*
|
|
357
|
+
* @example
|
|
358
|
+
* ```typescript
|
|
359
|
+
* const path = firestoreService.buildPath('users/{userId}/documents/{docId}', {
|
|
360
|
+
* userId: 'user123',
|
|
361
|
+
* docId: 'doc456'
|
|
362
|
+
* });
|
|
363
|
+
* // => 'users/user123/documents/doc456'
|
|
364
|
+
* ```
|
|
365
|
+
*/
|
|
366
|
+
buildPath(template, params) {
|
|
367
|
+
return buildPath(template, params);
|
|
368
|
+
}
|
|
369
|
+
/**
|
|
370
|
+
* Genera un ID único para un documento (sin crearlo).
|
|
371
|
+
*
|
|
372
|
+
* @param collectionPath - Ruta de la colección
|
|
373
|
+
* @returns ID único generado por Firestore
|
|
374
|
+
*/
|
|
375
|
+
generateId(collectionPath) {
|
|
376
|
+
const collectionRef = collection(this.firestore, collectionPath);
|
|
377
|
+
return doc(collectionRef).id;
|
|
378
|
+
}
|
|
379
|
+
/**
|
|
380
|
+
* Retorna un valor de timestamp del servidor.
|
|
381
|
+
* Usar en campos de fecha para que Firestore asigne el timestamp.
|
|
382
|
+
*/
|
|
383
|
+
serverTimestamp() {
|
|
384
|
+
return serverTimestamp();
|
|
385
|
+
}
|
|
386
|
+
/**
|
|
387
|
+
* Retorna un valor para agregar elementos a un array.
|
|
388
|
+
*
|
|
389
|
+
* @example
|
|
390
|
+
* ```typescript
|
|
391
|
+
* await firestoreService.updateDoc('users', 'user123', {
|
|
392
|
+
* tags: firestoreService.arrayUnion('new-tag')
|
|
393
|
+
* });
|
|
394
|
+
* ```
|
|
395
|
+
*/
|
|
396
|
+
arrayUnion(...elements) {
|
|
397
|
+
return arrayUnion(...elements);
|
|
398
|
+
}
|
|
399
|
+
/**
|
|
400
|
+
* Retorna un valor para remover elementos de un array.
|
|
401
|
+
*/
|
|
402
|
+
arrayRemove(...elements) {
|
|
403
|
+
return arrayRemove(...elements);
|
|
404
|
+
}
|
|
405
|
+
/**
|
|
406
|
+
* Retorna un valor para incrementar un campo numérico.
|
|
407
|
+
*
|
|
408
|
+
* @example
|
|
409
|
+
* ```typescript
|
|
410
|
+
* await firestoreService.updateDoc('users', 'user123', {
|
|
411
|
+
* loginCount: firestoreService.increment(1)
|
|
412
|
+
* });
|
|
413
|
+
* ```
|
|
414
|
+
*/
|
|
415
|
+
increment(n) {
|
|
416
|
+
return increment(n);
|
|
417
|
+
}
|
|
418
|
+
// ===========================================================================
|
|
419
|
+
// MÉTODOS PRIVADOS
|
|
420
|
+
// ===========================================================================
|
|
421
|
+
/**
|
|
422
|
+
* Construye los QueryConstraints a partir de QueryOptions
|
|
423
|
+
*/
|
|
424
|
+
buildQueryConstraints(options) {
|
|
425
|
+
const constraints = [];
|
|
426
|
+
if (!options)
|
|
427
|
+
return constraints;
|
|
428
|
+
// Where clauses
|
|
429
|
+
if (options.where) {
|
|
430
|
+
for (const clause of options.where) {
|
|
431
|
+
constraints.push(where(clause.field, clause.operator, clause.value));
|
|
432
|
+
}
|
|
433
|
+
}
|
|
434
|
+
// OrderBy clauses
|
|
435
|
+
if (options.orderBy) {
|
|
436
|
+
for (const clause of options.orderBy) {
|
|
437
|
+
constraints.push(orderBy(clause.field, clause.direction));
|
|
438
|
+
}
|
|
439
|
+
}
|
|
440
|
+
// Cursors para paginación
|
|
441
|
+
if (options.startAfter) {
|
|
442
|
+
constraints.push(startAfter(options.startAfter));
|
|
443
|
+
}
|
|
444
|
+
if (options.startAt) {
|
|
445
|
+
constraints.push(startAt(options.startAt));
|
|
446
|
+
}
|
|
447
|
+
if (options.endBefore) {
|
|
448
|
+
constraints.push(endBefore(options.endBefore));
|
|
449
|
+
}
|
|
450
|
+
if (options.endAt) {
|
|
451
|
+
constraints.push(endAt(options.endAt));
|
|
452
|
+
}
|
|
453
|
+
// Limit (se agrega al final)
|
|
454
|
+
if (options.limit) {
|
|
455
|
+
constraints.push(limit(options.limit));
|
|
456
|
+
}
|
|
457
|
+
return constraints;
|
|
458
|
+
}
|
|
459
|
+
/**
|
|
460
|
+
* Mapea un DocumentSnapshot a nuestro tipo
|
|
461
|
+
*/
|
|
462
|
+
mapDocument(snapshot) {
|
|
463
|
+
const data = snapshot.data();
|
|
464
|
+
if (!data) {
|
|
465
|
+
throw new Error('Documento no tiene datos');
|
|
466
|
+
}
|
|
467
|
+
return {
|
|
468
|
+
id: snapshot.id,
|
|
469
|
+
...this.convertTimestamps(data),
|
|
470
|
+
};
|
|
471
|
+
}
|
|
472
|
+
/**
|
|
473
|
+
* Convierte Timestamps de Firestore a Date de JavaScript
|
|
474
|
+
*/
|
|
475
|
+
convertTimestamps(data) {
|
|
476
|
+
const result = {};
|
|
477
|
+
for (const [key, value] of Object.entries(data)) {
|
|
478
|
+
if (value instanceof Timestamp) {
|
|
479
|
+
result[key] = value.toDate();
|
|
480
|
+
}
|
|
481
|
+
else if (value && typeof value === 'object' && !Array.isArray(value)) {
|
|
482
|
+
result[key] = this.convertTimestamps(value);
|
|
483
|
+
}
|
|
484
|
+
else {
|
|
485
|
+
result[key] = value;
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
return result;
|
|
489
|
+
}
|
|
490
|
+
/**
|
|
491
|
+
* Divide una ruta de documento en colección e ID
|
|
492
|
+
*/
|
|
493
|
+
splitPath(path) {
|
|
494
|
+
const segments = path.split('/');
|
|
495
|
+
if (segments.length < 2 || segments.length % 2 !== 0) {
|
|
496
|
+
throw new Error(`Ruta de documento inválida: ${path}`);
|
|
497
|
+
}
|
|
498
|
+
const docId = segments.pop();
|
|
499
|
+
const collectionPath = segments.join('/');
|
|
500
|
+
return [collectionPath, docId];
|
|
501
|
+
}
|
|
502
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, deps: [{ token: i1.Firestore }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
503
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, providedIn: 'root' }); }
|
|
504
|
+
}
|
|
505
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: FirestoreService, decorators: [{
|
|
506
|
+
type: Injectable,
|
|
507
|
+
args: [{ providedIn: 'root' }]
|
|
508
|
+
}], ctorParameters: () => [{ type: i1.Firestore }] });
|
|
509
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiZmlyZXN0b3JlLnNlcnZpY2UuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2ZpcmVzdG9yZS5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7OztHQUtHO0FBRUgsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMzQyxPQUFPLEVBQ0wsTUFBTSxFQUNOLFVBQVUsRUFDVixjQUFjLEVBQ2QsU0FBUyxFQUNULEdBQUcsRUFDSCxPQUFPLEVBS1AsTUFBTSxFQUNOLE9BQU8sRUFDUCxLQUFLLEVBQ0wsT0FBTyxFQUNQLEtBQUssRUFFTCxlQUFlLEVBQ2YsTUFBTSxFQUNOLFVBQVUsRUFDVixPQUFPLEVBQ1AsU0FBUyxFQUNULEtBQUssRUFDTCxTQUFTLEVBQ1QsU0FBUyxFQUNULEtBQUssRUFDTCxVQUFVLEVBQ1YsU0FBUyxFQUNULFVBQVUsRUFDVixXQUFXLEdBRVosTUFBTSx5QkFBeUIsQ0FBQztBQUNqQyxPQUFPLEVBQUUsR0FBRyxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBR3ZDLE9BQU8sRUFBRSxTQUFTLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQzs7O0FBRWpEOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQWdDRztBQUVILE1BQU0sT0FBTyxnQkFBZ0I7SUFDM0IsWUFBb0IsU0FBb0I7UUFBcEIsY0FBUyxHQUFULFNBQVMsQ0FBVztJQUFHLENBQUM7SUFFNUMsOEVBQThFO0lBQzlFLDhCQUE4QjtJQUM5Qiw4RUFBOEU7SUFFOUU7Ozs7Ozs7Ozs7Ozs7O09BY0c7SUFDSCxLQUFLLENBQUMsTUFBTSxDQUNWLGNBQXNCLEVBQ3RCLEtBQWE7UUFFYixNQUFNLE1BQU0sR0FBRyxHQUFHLENBQUMsSUFBSSxDQUFDLFNBQVMsRUFBRSxjQUFjLEVBQUUsS0FBSyxDQUFDLENBQUM7UUFDMUQsTUFBTSxRQUFRLEdBQUcsTUFBTSxN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O21IQUFoQixnQkFBZ0IsY0FESCxNQUFNOzs0RkFDbkIsZ0JBQWdCO2tCQUQ1QixVQUFVO21CQUFDLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogRmlyZXN0b3JlIFNlcnZpY2VcbiAqXG4gKiBTZXJ2aWNpbyBnZW7DqXJpY28gcGFyYSBvcGVyYWNpb25lcyBDUlVEIGVuIEZpcmVzdG9yZS5cbiAqIFNvcG9ydGEgbGVjdHVyYXMgb25lLXRpbWUsIHN1YnNjcmlwY2lvbmVzIHJlYWwtdGltZSwgcGFnaW5hY2nDs24geSBxdWVyaWVzIGNvbXBsZWphcy5cbiAqL1xuXG5pbXBvcnQgeyBJbmplY3RhYmxlIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQge1xuICBhZGREb2MsXG4gIGNvbGxlY3Rpb24sXG4gIGNvbGxlY3Rpb25EYXRhLFxuICBkZWxldGVEb2MsXG4gIGRvYyxcbiAgZG9jRGF0YSxcbiAgRG9jdW1lbnREYXRhLFxuICBEb2N1bWVudFJlZmVyZW5jZSxcbiAgRG9jdW1lbnRTbmFwc2hvdCxcbiAgRmlyZXN0b3JlLFxuICBnZXREb2MsXG4gIGdldERvY3MsXG4gIGxpbWl0LFxuICBvcmRlckJ5LFxuICBxdWVyeSxcbiAgUXVlcnlDb25zdHJhaW50LFxuICBzZXJ2ZXJUaW1lc3RhbXAsXG4gIHNldERvYyxcbiAgc3RhcnRBZnRlcixcbiAgc3RhcnRBdCxcbiAgZW5kQmVmb3JlLFxuICBlbmRBdCxcbiAgVGltZXN0YW1wLFxuICB1cGRhdGVEb2MsXG4gIHdoZXJlLFxuICB3cml0ZUJhdGNoLFxuICBpbmNyZW1lbnQsXG4gIGFycmF5VW5pb24sXG4gIGFycmF5UmVtb3ZlLFxuICBGaWVsZFZhbHVlLFxufSBmcm9tICdAYW5ndWxhci9maXJlL2ZpcmVzdG9yZSc7XG5pbXBvcnQgeyBtYXAsIE9ic2VydmFibGUgfSBmcm9tICdyeGpzJztcblxuaW1wb3J0IHsgRmlyZXN0b3JlRG9jdW1lbnQsIFBhZ2luYXRlZFJlc3VsdCwgUXVlcnlPcHRpb25zIH0gZnJvbSAnLi90eXBlcyc7XG5pbXBvcnQgeyBidWlsZFBhdGggfSBmcm9tICcuL3V0aWxzL3BhdGgtYnVpbGRlcic7XG5cbi8qKlxuICogU2VydmljaW8gcGFyYSBvcGVyYWNpb25lcyBDUlVEIGVuIEZpcmVzdG9yZS5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogaW50ZXJmYWNlIFVzZXIgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudCB7XG4gKiAgIG5hbWU6IHN0cmluZztcbiAqICAgZW1haWw6IHN0cmluZztcbiAqICAgcm9sZTogJ2FkbWluJyB8ICd1c2VyJztcbiAqIH1cbiAqXG4gKiBAQ29tcG9uZW50KHsuLi59KVxuICogZXhwb3J0IGNsYXNzIFVzZXJzQ29tcG9uZW50IHtcbiAqICAgcHJpdmF0ZSBmaXJlc3RvcmUgPSBpbmplY3QoRmlyZXN0b3JlU2VydmljZSk7XG4gKlxuICogICAvLyBMZWN0dXJhIG9uZS10aW1lXG4gKiAgIGFzeW5jIGxvYWRVc2VyKGlkOiBzdHJpbmcpIHtcbiAqICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5maXJlc3RvcmUuZ2V0RG9jPFVzZXI+KCd1c2VycycsIGlkKTtcbiAqICAgfVxuICpcbiAqICAgLy8gU3Vic2NyaXBjacOzbiByZWFsLXRpbWVcbiAqICAgdXNlcnMkID0gdGhpcy5maXJlc3RvcmUuY29sbGVjdGlvbkNoYW5nZXM8VXNlcj4oJ3VzZXJzJywge1xuICogICAgIHdoZXJlOiBbeyBmaWVsZDogJ3JvbGUnLCBvcGVyYXRvcjogJz09JywgdmFsdWU6ICdhZG1pbicgfV0sXG4gKiAgICAgb3JkZXJCeTogW3sgZmllbGQ6ICduYW1lJywgZGlyZWN0aW9uOiAnYXNjJyB9XVxuICogICB9KTtcbiAqXG4gKiAgIC8vIENyZWFyIGRvY3VtZW50b1xuICogICBhc3luYyBjcmVhdGVVc2VyKGRhdGE6IE9taXQ8VXNlciwgJ2lkJz4pIHtcbiAqICAgICBjb25zdCB1c2VyID0gYXdhaXQgdGhpcy5maXJlc3RvcmUuYWRkRG9jPFVzZXI+KCd1c2VycycsIGRhdGEpO1xuICogICB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBGaXJlc3RvcmVTZXJ2aWNlIHtcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBmaXJlc3RvcmU6IEZpcmVzdG9yZSkge31cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gTEVDVFVSQVMgT05FLVRJTUUgKFByb21pc2UpXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBPYnRpZW5lIHVuIGRvY3VtZW50byBwb3IgSUQgKGxlY3R1cmEgw7puaWNhKS5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBkb2NJZCAtIElEIGRlbCBkb2N1bWVudG9cbiAgICogQHJldHVybnMgRG9jdW1lbnRvIG8gbnVsbCBzaSBubyBleGlzdGVcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBjb25zdCB1c2VyID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXREb2M8VXNlcj4oJ3VzZXJzJywgJ2FiYzEyMycpO1xuICAgKiBpZiAodXNlcikge1xuICAgKiAgIGNvbnNvbGUubG9nKHVzZXIubmFtZSk7XG4gICAqIH1cbiAgICogYGBgXG4gICAqL1xuICBhc3luYyBnZXREb2M8VCBleHRlbmRzIEZpcmVzdG9yZURvY3VtZW50PihcbiAgICBjb2xsZWN0aW9uUGF0aDogc3RyaW5nLFxuICAgIGRvY0lkOiBzdHJpbmdcbiAgKTogUHJvbWlzZTxUIHwgbnVsbD4ge1xuICAgIGNvbnN0IGRvY1JlZiA9IGRvYyh0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgsIGRvY0lkKTtcbiAgICBjb25zdCBzbmFwc2hvdCA9IGF3YWl0IGdldERvYyhkb2NSZWYpO1xuXG4gICAgaWYgKCFzbmFwc2hvdC5leGlzdHMoKSkge1xuICAgICAgcmV0dXJuIG51bGw7XG4gICAgfVxuXG4gICAgcmV0dXJuIHRoaXMubWFwRG9jdW1lbnQ8VD4oc25hcHNob3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGllbmUgbcO6bHRpcGxlcyBkb2N1bWVudG9zIGNvbiBvcGNpb25lcyBkZSBxdWVyeS5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBvcHRpb25zIC0gT3BjaW9uZXMgZGUgcXVlcnkgKHdoZXJlLCBvcmRlckJ5LCBsaW1pdClcbiAgICogQHJldHVybnMgQXJyYXkgZGUgZG9jdW1lbnRvc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIFRvZG9zIGxvcyB1c3VhcmlvcyBhY3Rpdm9zIG9yZGVuYWRvcyBwb3Igbm9tYnJlXG4gICAqIGNvbnN0IHVzZXJzID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXREb2NzPFVzZXI+KCd1c2VycycsIHtcbiAgICogICB3aGVyZTogW3sgZmllbGQ6ICdhY3RpdmUnLCBvcGVyYXRvcjogJz09JywgdmFsdWU6IHRydWUgfV0sXG4gICAqICAgb3JkZXJCeTogW3sgZmllbGQ6ICduYW1lJywgZGlyZWN0aW9uOiAnYXNjJyB9XSxcbiAgICogICBsaW1pdDogNTBcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgZ2V0RG9jczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFF1ZXJ5T3B0aW9uc1xuICApOiBQcm9taXNlPFRbXT4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25SZWYgPSBjb2xsZWN0aW9uKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCk7XG4gICAgY29uc3QgY29uc3RyYWludHMgPSB0aGlzLmJ1aWxkUXVlcnlDb25zdHJhaW50cyhvcHRpb25zKTtcbiAgICBjb25zdCBxID0gcXVlcnkoY29sbGVjdGlvblJlZiwgLi4uY29uc3RyYWludHMpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jcyhxKTtcblxuICAgIHJldHVybiBzbmFwc2hvdC5kb2NzLm1hcCgoZG9jKSA9PiB0aGlzLm1hcERvY3VtZW50PFQ+KGRvYykpO1xuICB9XG5cbiAgLyoqXG4gICAqIE9idGllbmUgZG9jdW1lbnRvcyBjb24gcGFnaW5hY2nDs24gYmFzYWRhIGVuIGN1cnNvcmVzLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyBkZSBxdWVyeSAoZGViZSBpbmNsdWlyIGxpbWl0KVxuICAgKiBAcmV0dXJucyBSZXN1bHRhZG8gcGFnaW5hZG8gY29uIGN1cnNvciBwYXJhIGxhIHNpZ3VpZW50ZSBww6FnaW5hXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gUHJpbWVyYSBww6FnaW5hXG4gICAqIGNvbnN0IHBhZ2UxID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXRQYWdpbmF0ZWQ8VXNlcj4oJ3VzZXJzJywge1xuICAgKiAgIG9yZGVyQnk6IFt7IGZpZWxkOiAnY3JlYXRlZEF0JywgZGlyZWN0aW9uOiAnZGVzYycgfV0sXG4gICAqICAgbGltaXQ6IDEwXG4gICAqIH0pO1xuICAgKlxuICAgKiAvLyBTaWd1aWVudGUgcMOhZ2luYVxuICAgKiBpZiAocGFnZTEuaGFzTW9yZSkge1xuICAgKiAgIGNvbnN0IHBhZ2UyID0gYXdhaXQgZmlyZXN0b3JlU2VydmljZS5nZXRQYWdpbmF0ZWQ8VXNlcj4oJ3VzZXJzJywge1xuICAgKiAgICAgb3JkZXJCeTogW3sgZmllbGQ6ICdjcmVhdGVkQXQnLCBkaXJlY3Rpb246ICdkZXNjJyB9XSxcbiAgICogICAgIGxpbWl0OiAxMCxcbiAgICogICAgIHN0YXJ0QWZ0ZXI6IHBhZ2UxLmxhc3REb2NcbiAgICogICB9KTtcbiAgICogfVxuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGdldFBhZ2luYXRlZDxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9uczogUXVlcnlPcHRpb25zICYgeyBsaW1pdDogbnVtYmVyIH1cbiAgKTogUHJvbWlzZTxQYWdpbmF0ZWRSZXN1bHQ8VD4+IHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIGNvbnN0IGNvbnN0cmFpbnRzID0gdGhpcy5idWlsZFF1ZXJ5Q29uc3RyYWludHMob3B0aW9ucyk7XG5cbiAgICAvLyBQZWRpciB1bm8gbcOhcyBwYXJhIHNhYmVyIHNpIGhheSBtw6FzIHDDoWdpbmFzXG4gICAgY29uc3QgcSA9IHF1ZXJ5KGNvbGxlY3Rpb25SZWYsIC4uLmNvbnN0cmFpbnRzLCBsaW1pdChvcHRpb25zLmxpbWl0ICsgMSkpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jcyhxKTtcblxuICAgIGNvbnN0IGRvY3MgPSBzbmFwc2hvdC5kb2NzO1xuICAgIGNvbnN0IGhhc01vcmUgPSBkb2NzLmxlbmd0aCA+IG9wdGlvbnMubGltaXQ7XG5cbiAgICAvLyBTaSBoYXkgbcOhcywgcmVtb3ZlciBlbCBkb2N1bWVudG8gZXh0cmFcbiAgICBjb25zdCByZXN1bHREb2NzID0gaGFzTW9yZSA/IGRvY3Muc2xpY2UoMCwgLTEpIDogZG9jcztcbiAgICBjb25zdCBsYXN0RG9jID0gcmVzdWx0RG9jcy5sZW5ndGggPiAwID8gcmVzdWx0RG9jc1tyZXN1bHREb2NzLmxlbmd0aCAtIDFdIDogbnVsbDtcblxuICAgIHJldHVybiB7XG4gICAgICBkYXRhOiByZXN1bHREb2NzLm1hcCgoZG9jKSA9PiB0aGlzLm1hcERvY3VtZW50PFQ+KGRvYykpLFxuICAgICAgaGFzTW9yZSxcbiAgICAgIGxhc3REb2MsXG4gICAgfTtcbiAgfVxuXG4gIC8qKlxuICAgKiBWZXJpZmljYSBzaSB1biBkb2N1bWVudG8gZXhpc3RlLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcmV0dXJucyB0cnVlIHNpIGVsIGRvY3VtZW50byBleGlzdGVcbiAgICovXG4gIGFzeW5jIGV4aXN0cyhjb2xsZWN0aW9uUGF0aDogc3RyaW5nLCBkb2NJZDogc3RyaW5nKTogUHJvbWlzZTxib29sZWFuPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jKGRvY1JlZik7XG4gICAgcmV0dXJuIHNuYXBzaG90LmV4aXN0cygpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIFNVQlNDUklQQ0lPTkVTIFJFQUwtVElNRSAoT2JzZXJ2YWJsZSlcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIFN1c2NyaWJlIGEgY2FtYmlvcyBkZSB1biBkb2N1bWVudG8gKHJlYWwtdGltZSkuXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcGFyYW0gZG9jSWQgLSBJRCBkZWwgZG9jdW1lbnRvXG4gICAqIEByZXR1cm5zIE9ic2VydmFibGUgcXVlIGVtaXRlIGN1YW5kbyBlbCBkb2N1bWVudG8gY2FtYmlhXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gRW4gZWwgY29tcG9uZW50ZVxuICAgKiB1c2VyJCA9IHRoaXMuZmlyZXN0b3JlU2VydmljZS5kb2NDaGFuZ2VzPFVzZXI+KCd1c2VycycsIHRoaXMudXNlcklkKTtcbiAgICpcbiAgICogLy8gRW4gZWwgdGVtcGxhdGVcbiAgICogQGlmICh1c2VyJCB8IGFzeW5jOyBhcyB1c2VyKSB7XG4gICAqICAgPHA+e3sgdXNlci5uYW1lIH19PC9wPlxuICAgKiB9XG4gICAqIGBgYFxuICAgKi9cbiAgZG9jQ2hhbmdlczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgZG9jSWQ6IHN0cmluZ1xuICApOiBPYnNlcnZhYmxlPFQgfCBudWxsPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIHJldHVybiBkb2NEYXRhKGRvY1JlZiwgeyBpZEZpZWxkOiAnaWQnIH0pLnBpcGUoXG4gICAgICBtYXAoKGRhdGEpID0+IHtcbiAgICAgICAgaWYgKCFkYXRhKSByZXR1cm4gbnVsbDtcbiAgICAgICAgcmV0dXJuIHRoaXMuY29udmVydFRpbWVzdGFtcHMoZGF0YSBhcyBEb2N1bWVudERhdGEpIGFzIFQ7XG4gICAgICB9KVxuICAgICk7XG4gIH1cblxuICAvKipcbiAgICogU3VzY3JpYmUgYSBjYW1iaW9zIGRlIHVuYSBjb2xlY2Npw7NuIChyZWFsLXRpbWUpLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyBkZSBxdWVyeVxuICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlIHF1ZSBlbWl0ZSBjdWFuZG8gbGEgY29sZWNjacOzbiBjYW1iaWFcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiAvLyBVc3VhcmlvcyBhY3Rpdm9zIGVuIHRpZW1wbyByZWFsXG4gICAqIGFjdGl2ZVVzZXJzJCA9IHRoaXMuZmlyZXN0b3JlU2VydmljZS5jb2xsZWN0aW9uQ2hhbmdlczxVc2VyPigndXNlcnMnLCB7XG4gICAqICAgd2hlcmU6IFt7IGZpZWxkOiAnc3RhdHVzJywgb3BlcmF0b3I6ICc9PScsIHZhbHVlOiAnb25saW5lJyB9XVxuICAgKiB9KTtcbiAgICogYGBgXG4gICAqL1xuICBjb2xsZWN0aW9uQ2hhbmdlczxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIGNvbGxlY3Rpb25QYXRoOiBzdHJpbmcsXG4gICAgb3B0aW9ucz86IFF1ZXJ5T3B0aW9uc1xuICApOiBPYnNlcnZhYmxlPFRbXT4ge1xuICAgIGNvbnN0IGNvbGxlY3Rpb25SZWYgPSBjb2xsZWN0aW9uKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCk7XG4gICAgY29uc3QgY29uc3RyYWludHMgPSB0aGlzLmJ1aWxkUXVlcnlDb25zdHJhaW50cyhvcHRpb25zKTtcbiAgICBjb25zdCBxID0gcXVlcnkoY29sbGVjdGlvblJlZiwgLi4uY29uc3RyYWludHMpO1xuXG4gICAgcmV0dXJuIGNvbGxlY3Rpb25EYXRhKHEsIHsgaWRGaWVsZDogJ2lkJyB9KS5waXBlKFxuICAgICAgbWFwKChkb2NzKSA9PiBkb2NzLm1hcCgoZG9jKSA9PiB0aGlzLmNvbnZlcnRUaW1lc3RhbXBzKGRvYykgYXMgVCkpXG4gICAgKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBFU0NSSVRVUkFcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEFncmVnYSB1biBkb2N1bWVudG8gY29uIElEIGF1dG8tZ2VuZXJhZG8uXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcGFyYW0gZGF0YSAtIERhdG9zIGRlbCBkb2N1bWVudG8gKHNpbiBpZCwgY3JlYXRlZEF0LCB1cGRhdGVkQXQpXG4gICAqIEByZXR1cm5zIERvY3VtZW50byBjcmVhZG8gY29uIHN1IElEXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgbmV3VXNlciA9IGF3YWl0IGZpcmVzdG9yZVNlcnZpY2UuYWRkRG9jPFVzZXI+KCd1c2VycycsIHtcbiAgICogICBuYW1lOiAnSm9obiBEb2UnLFxuICAgKiAgIGVtYWlsOiAnam9obkBleGFtcGxlLmNvbScsXG4gICAqICAgcm9sZTogJ3VzZXInXG4gICAqIH0pO1xuICAgKiBjb25zb2xlLmxvZygnQ3JlYXRlZCB1c2VyIHdpdGggSUQ6JywgbmV3VXNlci5pZCk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYWRkRG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkYXRhOiBPbWl0PFQsICdpZCcgfCAnY3JlYXRlZEF0JyB8ICd1cGRhdGVkQXQnPlxuICApOiBQcm9taXNlPFQ+IHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIGNvbnN0IHRpbWVzdGFtcCA9IHNlcnZlclRpbWVzdGFtcCgpO1xuXG4gICAgY29uc3QgZG9jRGF0YSA9IHtcbiAgICAgIC4uLmRhdGEsXG4gICAgICBjcmVhdGVkQXQ6IHRpbWVzdGFtcCxcbiAgICAgIHVwZGF0ZWRBdDogdGltZXN0YW1wLFxuICAgIH07XG5cbiAgICBjb25zdCBkb2NSZWYgPSBhd2FpdCBhZGREb2MoY29sbGVjdGlvblJlZiwgZG9jRGF0YSk7XG5cbiAgICAvLyBPYnRlbmVyIGVsIGRvY3VtZW50byBjcmVhZG8gcGFyYSByZXRvcm5hcmxvIGNvbiB0aW1lc3RhbXBzIHJlc3VlbHRvc1xuICAgIGNvbnN0IHNuYXBzaG90ID0gYXdhaXQgZ2V0RG9jKGRvY1JlZik7XG4gICAgcmV0dXJuIHRoaXMubWFwRG9jdW1lbnQ8VD4oc25hcHNob3QpO1xuICB9XG5cbiAgLyoqXG4gICAqIENyZWEgbyBzb2JyZXNjcmliZSB1biBkb2N1bWVudG8gY29uIElEIGVzcGVjw61maWNvLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcGFyYW0gZGF0YSAtIERhdG9zIGRlbCBkb2N1bWVudG9cbiAgICogQHBhcmFtIG9wdGlvbnMgLSBPcGNpb25lcyAobWVyZ2U6IHRydWUgcGFyYSBtZXJnZSBlbiBsdWdhciBkZSBzb2JyZXNjcmliaXIpXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogLy8gU29icmVzY3JpYmlyIGNvbXBsZXRhbWVudGVcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS5zZXREb2M8VXNlcj4oJ3VzZXJzJywgJ3VzZXIxMjMnLCB1c2VyRGF0YSk7XG4gICAqXG4gICAqIC8vIE1lcmdlIGNvbiBkYXRvcyBleGlzdGVudGVzXG4gICAqIGF3YWl0IGZpcmVzdG9yZVNlcnZpY2Uuc2V0RG9jPFVzZXI+KCd1c2VycycsICd1c2VyMTIzJywgeyBuYW1lOiAnTmV3IE5hbWUnIH0sIHsgbWVyZ2U6IHRydWUgfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgc2V0RG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkb2NJZDogc3RyaW5nLFxuICAgIGRhdGE6IE9taXQ8VCwgJ2lkJz4sXG4gICAgb3B0aW9ucz86IHsgbWVyZ2U/OiBib29sZWFuIH1cbiAgKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGNvbnN0IHRpbWVzdGFtcCA9IHNlcnZlclRpbWVzdGFtcCgpO1xuXG4gICAgY29uc3QgZG9jRGF0YSA9IHtcbiAgICAgIC4uLmRhdGEsXG4gICAgICB1cGRhdGVkQXQ6IHRpbWVzdGFtcCxcbiAgICAgIC4uLihvcHRpb25zPy5tZXJnZSA/IHt9IDogeyBjcmVhdGVkQXQ6IHRpbWVzdGFtcCB9KSxcbiAgICB9O1xuXG4gICAgYXdhaXQgc2V0RG9jKGRvY1JlZiwgZG9jRGF0YSwgeyBtZXJnZTogb3B0aW9ucz8ubWVyZ2UgPz8gZmFsc2UgfSk7XG4gIH1cblxuICAvKipcbiAgICogQWN0dWFsaXphIGNhbXBvcyBlc3BlY8OtZmljb3MgZGUgdW4gZG9jdW1lbnRvLlxuICAgKlxuICAgKiBAcGFyYW0gY29sbGVjdGlvblBhdGggLSBSdXRhIGRlIGxhIGNvbGVjY2nDs25cbiAgICogQHBhcmFtIGRvY0lkIC0gSUQgZGVsIGRvY3VtZW50b1xuICAgKiBAcGFyYW0gZGF0YSAtIENhbXBvcyBhIGFjdHVhbGl6YXJcbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBmaXJlc3RvcmVTZXJ2aWNlLnVwZGF0ZURvYzxVc2VyPigndXNlcnMnLCAndXNlcjEyMycsIHtcbiAgICogICBuYW1lOiAnVXBkYXRlZCBOYW1lJyxcbiAgICogICBsYXN0TG9naW46IG5ldyBEYXRlKClcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgdXBkYXRlRG9jPFQgZXh0ZW5kcyBGaXJlc3RvcmVEb2N1bWVudD4oXG4gICAgY29sbGVjdGlvblBhdGg6IHN0cmluZyxcbiAgICBkb2NJZDogc3RyaW5nLFxuICAgIGRhdGE6IFBhcnRpYWw8T21pdDxULCAnaWQnIHwgJ2NyZWF0ZWRBdCc+PlxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBkb2NSZWYgPSBkb2ModGhpcy5maXJlc3RvcmUsIGNvbGxlY3Rpb25QYXRoLCBkb2NJZCk7XG5cbiAgICBhd2FpdCB1cGRhdGVEb2MoZG9jUmVmLCB7XG4gICAgICAuLi5kYXRhLFxuICAgICAgdXBkYXRlZEF0OiBzZXJ2ZXJUaW1lc3RhbXAoKSxcbiAgICB9KTtcbiAgfVxuXG4gIC8qKlxuICAgKiBFbGltaW5hIHVuIGRvY3VtZW50by5cbiAgICpcbiAgICogQHBhcmFtIGNvbGxlY3Rpb25QYXRoIC0gUnV0YSBkZSBsYSBjb2xlY2Npw7NuXG4gICAqIEBwYXJhbSBkb2NJZCAtIElEIGRlbCBkb2N1bWVudG9cbiAgICpcbiAgICogQGV4YW1wbGVcbiAgICogYGBgdHlwZXNjcmlwdFxuICAgKiBhd2FpdCBmaXJlc3RvcmVTZXJ2aWNlLmRlbGV0ZURvYygndXNlcnMnLCAndXNlcjEyMycpO1xuICAgKiBgYGBcbiAgICovXG4gIGFzeW5jIGRlbGV0ZURvYyhjb2xsZWN0aW9uUGF0aDogc3RyaW5nLCBkb2NJZDogc3RyaW5nKTogUHJvbWlzZTx2b2lkPiB7XG4gICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgIGF3YWl0IGRlbGV0ZURvYyhkb2NSZWYpO1xuICB9XG5cbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG4gIC8vIE9QRVJBQ0lPTkVTIEVOIExPVEVcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIEVqZWN1dGEgbcO6bHRpcGxlcyBvcGVyYWNpb25lcyBkZSBlc2NyaXR1cmEgZGUgZm9ybWEgYXTDs21pY2EuXG4gICAqXG4gICAqIEBwYXJhbSBvcGVyYXRpb25zIC0gRnVuY2nDs24gcXVlIHJlY2liZSBlbCBiYXRjaCB5IGFncmVnYSBvcGVyYWNpb25lc1xuICAgKlxuICAgKiBAZXhhbXBsZVxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIGF3YWl0IGZpcmVzdG9yZVNlcnZpY2UuYmF0Y2goKGJhdGNoKSA9PiB7XG4gICAqICAgYmF0Y2guc2V0KCd1c2Vycy91c2VyMScsIHsgbmFtZTogJ1VzZXIgMScgfSk7XG4gICAqICAgYmF0Y2gudXBkYXRlKCd1c2Vycy91c2VyMicsIHsgc3RhdHVzOiAnaW5hY3RpdmUnIH0pO1xuICAgKiAgIGJhdGNoLmRlbGV0ZSgndXNlcnMvdXNlcjMnKTtcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXN5bmMgYmF0Y2goXG4gICAgb3BlcmF0aW9uczogKGJhdGNoOiB7XG4gICAgICBzZXQ6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFQpID0+IHZvaWQ7XG4gICAgICB1cGRhdGU6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFBhcnRpYWw8VD4pID0+IHZvaWQ7XG4gICAgICBkZWxldGU6IChwYXRoOiBzdHJpbmcpID0+IHZvaWQ7XG4gICAgfSkgPT4gdm9pZFxuICApOiBQcm9taXNlPHZvaWQ+IHtcbiAgICBjb25zdCBiYXRjaCA9IHdyaXRlQmF0Y2godGhpcy5maXJlc3RvcmUpO1xuXG4gICAgY29uc3QgYmF0Y2hBcGkgPSB7XG4gICAgICBzZXQ6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFQpID0+IHtcbiAgICAgICAgY29uc3QgW2NvbGxlY3Rpb25QYXRoLCBkb2NJZF0gPSB0aGlzLnNwbGl0UGF0aChwYXRoKTtcbiAgICAgICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgICAgICBiYXRjaC5zZXQoZG9jUmVmLCB7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICBjcmVhdGVkQXQ6IHNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICAgIHVwZGF0ZWRBdDogc2VydmVyVGltZXN0YW1wKCksXG4gICAgICAgIH0gYXMgRG9jdW1lbnREYXRhKTtcbiAgICAgIH0sXG4gICAgICB1cGRhdGU6IDxUPihwYXRoOiBzdHJpbmcsIGRhdGE6IFBhcnRpYWw8VD4pID0+IHtcbiAgICAgICAgY29uc3QgW2NvbGxlY3Rpb25QYXRoLCBkb2NJZF0gPSB0aGlzLnNwbGl0UGF0aChwYXRoKTtcbiAgICAgICAgY29uc3QgZG9jUmVmID0gZG9jKHRoaXMuZmlyZXN0b3JlLCBjb2xsZWN0aW9uUGF0aCwgZG9jSWQpO1xuICAgICAgICBiYXRjaC51cGRhdGUoZG9jUmVmLCB7XG4gICAgICAgICAgLi4uZGF0YSxcbiAgICAgICAgICB1cGRhdGVkQXQ6IHNlcnZlclRpbWVzdGFtcCgpLFxuICAgICAgICB9IGFzIERvY3VtZW50RGF0YSk7XG4gICAgICB9LFxuICAgICAgZGVsZXRlOiAocGF0aDogc3RyaW5nKSA9PiB7XG4gICAgICAgIGNvbnN0IFtjb2xsZWN0aW9uUGF0aCwgZG9jSWRdID0gdGhpcy5zcGxpdFBhdGgocGF0aCk7XG4gICAgICAgIGNvbnN0IGRvY1JlZiA9IGRvYyh0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgsIGRvY0lkKTtcbiAgICAgICAgYmF0Y2guZGVsZXRlKGRvY1JlZik7XG4gICAgICB9LFxuICAgIH07XG5cbiAgICBvcGVyYXRpb25zKGJhdGNoQXBpKTtcbiAgICBhd2FpdCBiYXRjaC5jb21taXQoKTtcbiAgfVxuXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuICAvLyBVVElMSURBREVTXG4gIC8vID09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PVxuXG4gIC8qKlxuICAgKiBDb25zdHJ1eWUgdW5hIHJ1dGEgYSBwYXJ0aXIgZGUgdW4gdGVtcGxhdGUuXG4gICAqXG4gICAqIEBwYXJhbSB0ZW1wbGF0ZSAtIFRlbXBsYXRlIGNvbiBwbGFjZWhvbGRlcnMge3BhcmFtfVxuICAgKiBAcGFyYW0gcGFyYW1zIC0gVmFsb3JlcyBwYXJhIGxvcyBwbGFjZWhvbGRlcnNcbiAgICogQHJldHVybnMgUnV0YSBjb25zdHJ1aWRhXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogY29uc3QgcGF0aCA9IGZpcmVzdG9yZVNlcnZpY2UuYnVpbGRQYXRoKCd1c2Vycy97dXNlcklkfS9kb2N1bWVudHMve2RvY0lkfScsIHtcbiAgICogICB1c2VySWQ6ICd1c2VyMTIzJyxcbiAgICogICBkb2NJZDogJ2RvYzQ1NidcbiAgICogfSk7XG4gICAqIC8vID0+ICd1c2Vycy91c2VyMTIzL2RvY3VtZW50cy9kb2M0NTYnXG4gICAqIGBgYFxuICAgKi9cbiAgYnVpbGRQYXRoKHRlbXBsYXRlOiBzdHJpbmcsIHBhcmFtczogUmVjb3JkPHN0cmluZywgc3RyaW5nPik6IHN0cmluZyB7XG4gICAgcmV0dXJuIGJ1aWxkUGF0aCh0ZW1wbGF0ZSwgcGFyYW1zKTtcbiAgfVxuXG4gIC8qKlxuICAgKiBHZW5lcmEgdW4gSUQgw7puaWNvIHBhcmEgdW4gZG9jdW1lbnRvIChzaW4gY3JlYXJsbykuXG4gICAqXG4gICAqIEBwYXJhbSBjb2xsZWN0aW9uUGF0aCAtIFJ1dGEgZGUgbGEgY29sZWNjacOzblxuICAgKiBAcmV0dXJucyBJRCDDum5pY28gZ2VuZXJhZG8gcG9yIEZpcmVzdG9yZVxuICAgKi9cbiAgZ2VuZXJhdGVJZChjb2xsZWN0aW9uUGF0aDogc3RyaW5nKTogc3RyaW5nIHtcbiAgICBjb25zdCBjb2xsZWN0aW9uUmVmID0gY29sbGVjdGlvbih0aGlzLmZpcmVzdG9yZSwgY29sbGVjdGlvblBhdGgpO1xuICAgIHJldHVybiBkb2MoY29sbGVjdGlvblJlZikuaWQ7XG4gIH1cblxuICAvKipcbiAgICogUmV0b3JuYSB1biB2YWxvciBkZSB0aW1lc3RhbXAgZGVsIHNlcnZpZG9yLlxuICAgKiBVc2FyIGVuIGNhbXBvcyBkZSBmZWNoYSBwYXJhIHF1ZSBGaXJlc3RvcmUgYXNpZ25lIGVsIHRpbWVzdGFtcC5cbiAgICovXG4gIHNlcnZlclRpbWVzdGFtcCgpOiBGaWVsZFZhbHVlIHtcbiAgICByZXR1cm4gc2VydmVyVGltZXN0YW1wKCk7XG4gIH1cblxuICAvKipcbiAgICogUmV0b3JuYSB1biB2YWxvciBwYXJhIGFncmVnYXIgZWxlbWVudG9zIGEgdW4gYXJyYXkuXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS51cGRhdGVEb2MoJ3VzZXJzJywgJ3VzZXIxMjMnLCB7XG4gICAqICAgdGFnczogZmlyZXN0b3JlU2VydmljZS5hcnJheVVuaW9uKCduZXctdGFnJylcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgYXJyYXlVbmlvbiguLi5lbGVtZW50czogdW5rbm93bltdKTogRmllbGRWYWx1ZSB7XG4gICAgcmV0dXJuIGFycmF5VW5pb24oLi4uZWxlbWVudHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldG9ybmEgdW4gdmFsb3IgcGFyYSByZW1vdmVyIGVsZW1lbnRvcyBkZSB1biBhcnJheS5cbiAgICovXG4gIGFycmF5UmVtb3ZlKC4uLmVsZW1lbnRzOiB1bmtub3duW10pOiBGaWVsZFZhbHVlIHtcbiAgICByZXR1cm4gYXJyYXlSZW1vdmUoLi4uZWxlbWVudHMpO1xuICB9XG5cbiAgLyoqXG4gICAqIFJldG9ybmEgdW4gdmFsb3IgcGFyYSBpbmNyZW1lbnRhciB1biBjYW1wbyBudW3DqXJpY28uXG4gICAqXG4gICAqIEBleGFtcGxlXG4gICAqIGBgYHR5cGVzY3JpcHRcbiAgICogYXdhaXQgZmlyZXN0b3JlU2VydmljZS51cGRhdGVEb2MoJ3VzZXJzJywgJ3VzZXIxMjMnLCB7XG4gICAqICAgbG9naW5Db3VudDogZmlyZXN0b3JlU2VydmljZS5pbmNyZW1lbnQoMSlcbiAgICogfSk7XG4gICAqIGBgYFxuICAgKi9cbiAgaW5jcmVtZW50KG46IG51bWJlcik6IEZpZWxkVmFsdWUge1xuICAgIHJldHVybiBpbmNyZW1lbnQobik7XG4gIH1cblxuICAvLyA9PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT1cbiAgLy8gTcOJVE9ET1MgUFJJVkFET1NcbiAgLy8gPT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09PT09XG5cbiAgLyoqXG4gICAqIENvbnN0cnV5ZSBsb3MgUXVlcnlDb25zdHJhaW50cyBhIHBhcnRpciBkZSBRdWVyeU9wdGlvbnNcbiAgICovXG4gIHByaXZhdGUgYnVpbGRRdWVyeUNvbnN0cmFpbnRzKG9wdGlvbnM/OiBRdWVyeU9wdGlvbnMpOiBRdWVyeUNvbnN0cmFpbnRbXSB7XG4gICAgY29uc3QgY29uc3RyYWludHM6IFF1ZXJ5Q29uc3RyYWludFtdID0gW107XG5cbiAgICBpZiAoIW9wdGlvbnMpIHJldHVybiBjb25zdHJhaW50cztcblxuICAgIC8vIFdoZXJlIGNsYXVzZXNcbiAgICBpZiAob3B0aW9ucy53aGVyZSkge1xuICAgICAgZm9yIChjb25zdCBjbGF1c2Ugb2Ygb3B0aW9ucy53aGVyZSkge1xuICAgICAgICBjb25zdHJhaW50cy5wdXNoKHdoZXJlKGNsYXVzZS5maWVsZCwgY2xhdXNlLm9wZXJhdG9yLCBjbGF1c2UudmFsdWUpKTtcbiAgICAgIH1cbiAgICB9XG5cbiAgICAvLyBPcmRlckJ5IGNsYXVzZXNcbiAgICBpZiAob3B0aW9ucy5vcmRlckJ5KSB7XG4gICAgICBmb3IgKGNvbnN0IGNsYXVzZSBvZiBvcHRpb25zLm9yZGVyQnkpIHtcbiAgICAgICAgY29uc3RyYWludHMucHVzaChvcmRlckJ5KGNsYXVzZS5maWVsZCwgY2xhdXNlLmRpcmVjdGlvbikpO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIEN1cnNvcnMgcGFyYSBwYWdpbmFjacOzblxuICAgIGlmIChvcHRpb25zLnN0YXJ0QWZ0ZXIpIHtcbiAgICAgIGNvbnN0cmFpbnRzLnB1c2goc3RhcnRBZnRlcihvcHRpb25zLnN0YXJ0QWZ0ZXIpKTtcbiAgICB9XG4gICAgaWYgKG9wdGlvbnMuc3RhcnRBdCkge1xuICAgICAgY29uc3RyYWludHMucHVzaChzdGFydEF0KG9wdGlvbnMuc3RhcnRBdCkpO1xuICAgIH1cbiAgICBpZiAob3B0aW9ucy5lbmRCZWZvcmUpIHtcbiAgICAgIGNvbnN0cmFpbnRzLnB1c2goZW5kQmVmb3JlKG9wdGlvbnMuZW5kQmVmb3JlKSk7XG4gICAgfVxuICAgIGlmIChvcHRpb25zLmVuZEF0KSB7XG4gICAgICBjb25zdHJhaW50cy5wdXNoKGVuZEF0KG9wdGlvbnMuZW5kQXQpKTtcbiAgICB9XG5cbiAgICAvLyBMaW1pdCAoc2UgYWdyZWdhIGFsIGZpbmFsKVxuICAgIGlmIChvcHRpb25zLmxpbWl0KSB7XG4gICAgICBjb25zdHJhaW50cy5wdXNoKGxpbWl0KG9wdGlvbnMubGltaXQpKTtcbiAgICB9XG5cbiAgICByZXR1cm4gY29uc3RyYWludHM7XG4gIH1cblxuICAvKipcbiAgICogTWFwZWEgdW4gRG9jdW1lbnRTbmFwc2hvdCBhIG51ZXN0cm8gdGlwb1xuICAgKi9cbiAgcHJpdmF0ZSBtYXBEb2N1bWVudDxUIGV4dGVuZHMgRmlyZXN0b3JlRG9jdW1lbnQ+KFxuICAgIHNuYXBzaG90OiBEb2N1bWVudFNuYXBzaG90PERvY3VtZW50RGF0YT5cbiAgKTogVCB7XG4gICAgY29uc3QgZGF0YSA9IHNuYXBzaG90LmRhdGEoKTtcbiAgICBpZiAoIWRhdGEpIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcignRG9jdW1lbnRvIG5vIHRpZW5lIGRhdG9zJyk7XG4gICAgfVxuXG4gICAgcmV0dXJuIHtcbiAgICAgIGlkOiBzbmFwc2hvdC5pZCxcbiAgICAgIC4uLnRoaXMuY29udmVydFRpbWVzdGFtcHMoZGF0YSksXG4gICAgfSBhcyBUO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnZpZXJ0ZSBUaW1lc3RhbXBzIGRlIEZpcmVzdG9yZSBhIERhdGUgZGUgSmF2YVNjcmlwdFxuICAgKi9cbiAgcHJpdmF0ZSBjb252ZXJ0VGltZXN0YW1wcyhkYXRhOiBEb2N1bWVudERhdGEpOiBEb2N1bWVudERhdGEge1xuICAgIGNvbnN0IHJlc3VsdDogRG9jdW1lbnREYXRhID0ge307XG5cbiAgICBmb3IgKGNvbnN0IFtrZXksIHZhbHVlXSBvZiBPYmplY3QuZW50cmllcyhkYXRhKSkge1xuICAgICAgaWYgKHZhbHVlIGluc3RhbmNlb2YgVGltZXN0YW1wKSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdmFsdWUudG9EYXRlKCk7XG4gICAgICB9IGVsc2UgaWYgKHZhbHVlICYmIHR5cGVvZiB2YWx1ZSA9PT0gJ29iamVjdCcgJiYgIUFycmF5LmlzQXJyYXkodmFsdWUpKSB7XG4gICAgICAgIHJlc3VsdFtrZXldID0gdGhpcy5jb252ZXJ0VGltZXN0YW1wcyh2YWx1ZSk7XG4gICAgICB9IGVsc2Uge1xuICAgICAgICByZXN1bHRba2V5XSA9IHZhbHVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIHJldHVybiByZXN1bHQ7XG4gIH1cblxuICAvKipcbiAgICogRGl2aWRlIHVuYSBydXRhIGRlIGRvY3VtZW50byBlbiBjb2xlY2Npw7NuIGUgSURcbiAgICovXG4gIHByaXZhdGUgc3BsaXRQYXRoKHBhdGg6IHN0cmluZyk6IFtzdHJpbmcsIHN0cmluZ10ge1xuICAgIGNvbnN0IHNlZ21lbnRzID0gcGF0aC5zcGxpdCgnLycpO1xuICAgIGlmIChzZWdtZW50cy5sZW5ndGggPCAyIHx8IHNlZ21lbnRzLmxlbmd0aCAlIDIgIT09IDApIHtcbiAgICAgIHRocm93IG5ldyBFcnJvcihgUnV0YSBkZSBkb2N1bWVudG8gaW52w6FsaWRhOiAke3BhdGh9YCk7XG4gICAgfVxuICAgIGNvbnN0IGRvY0lkID0gc2VnbWVudHMucG9wKCkhO1xuICAgIGNvbnN0IGNvbGxlY3Rpb25QYXRoID0gc2VnbWVudHMuam9pbignLycpO1xuICAgIHJldHVybiBbY29sbGVjdGlvblBhdGgsIGRvY0lkXTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Firebase Services
|
|
3
|
+
*
|
|
4
|
+
* Servicios reutilizables para integración con Firebase.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* // En main.ts
|
|
9
|
+
* import { provideValtechFirebase } from 'valtech-components';
|
|
10
|
+
*
|
|
11
|
+
* bootstrapApplication(AppComponent, {
|
|
12
|
+
* providers: [
|
|
13
|
+
* provideValtechFirebase({
|
|
14
|
+
* firebase: environment.firebase,
|
|
15
|
+
* persistence: true,
|
|
16
|
+
* }),
|
|
17
|
+
* ],
|
|
18
|
+
* });
|
|
19
|
+
*
|
|
20
|
+
* // En componentes
|
|
21
|
+
* import { FirebaseService, FirestoreService } from 'valtech-components';
|
|
22
|
+
*
|
|
23
|
+
* @Component({...})
|
|
24
|
+
* export class MyComponent {
|
|
25
|
+
* private firebase = inject(FirebaseService);
|
|
26
|
+
* private firestore = inject(FirestoreService);
|
|
27
|
+
* }
|
|
28
|
+
* ```
|
|
29
|
+
*/
|
|
30
|
+
// Tipos
|
|
31
|
+
export * from './types';
|
|
32
|
+
// Configuración
|
|
33
|
+
export { VALTECH_FIREBASE_CONFIG, hasEmulators, provideValtechFirebase } from './config';
|
|
34
|
+
// Configuración compartida del monorepo
|
|
35
|
+
export { APP_IDS, FIREBASE_PROJECTS, SHARED_EMULATOR_CONFIG, collections, createFirebaseConfig, isEmulatorMode, storagePaths, } from './shared-config';
|
|
36
|
+
// Servicios
|
|
37
|
+
export { FirebaseService } from './firebase.service';
|
|
38
|
+
// Firestore
|
|
39
|
+
export { FirestoreService } from './firestore.service';
|
|
40
|
+
// Firestore Collections (Factory Pattern)
|
|
41
|
+
export { FirestoreCollectionFactory, TypedCollection, } from './firestore-collection';
|
|
42
|
+
// Utilidades
|
|
43
|
+
export { QueryBuilder, query } from './utils/query-builder';
|
|
44
|
+
export { buildPath, extractPathParams, getCollectionPath, getDocumentId, isCollectionPath, isDocumentPath, isValidPath, joinPath, } from './utils/path-builder';
|
|
45
|
+
// Storage
|
|
46
|
+
export { StorageService } from './storage.service';
|
|
47
|
+
// Messaging (FCM)
|
|
48
|
+
export { MessagingService } from './messaging.service';
|
|
49
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2ZpcmViYXNlL2luZGV4LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBOzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7O0dBNEJHO0FBRUgsUUFBUTtBQUNSLGNBQWMsU0FBUyxDQUFDO0FBRXhCLGdCQUFnQjtBQUNoQixPQUFPLEVBQUUsdUJBQXVCLEVBQUUsWUFBWSxFQUFFLHNCQUFzQixFQUFFLE1BQU0sVUFBVSxDQUFDO0FBRXpGLHdDQUF3QztBQUN4QyxPQUFPLEVBQ0wsT0FBTyxFQUNQLGlCQUFpQixFQUNqQixzQkFBc0IsRUFDdEIsV0FBVyxFQUNYLG9CQUFvQixFQUNwQixjQUFjLEVBQ2QsWUFBWSxHQUdiLE1BQU0saUJBQWlCLENBQUM7QUFFekIsWUFBWTtBQUNaLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUVyRCxZQUFZO0FBQ1osT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUM7QUFFdkQsMENBQTBDO0FBQzFDLE9BQU8sRUFHTCwwQkFBMEIsRUFFMUIsZUFBZSxHQUNoQixNQUFNLHdCQUF3QixDQUFDO0FBRWhDLGFBQWE7QUFDYixPQUFPLEVBQUUsWUFBWSxFQUFFLEtBQUssRUFBRSxNQUFNLHVCQUF1QixDQUFDO0FBQzVELE9BQU8sRUFDTCxTQUFTLEVBQ1QsaUJBQWlCLEVBQ2pCLGlCQUFpQixFQUNqQixhQUFhLEVBQ2IsZ0JBQWdCLEVBQ2hCLGNBQWMsRUFDZCxXQUFXLEVBQ1gsUUFBUSxHQUNULE1BQU0sc0JBQXNCLENBQUM7QUFFOUIsVUFBVTtBQUNWLE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUVuRCxrQkFBa0I7QUFDbEIsT0FBTyxFQUFFLGdCQUFnQixFQUFFLE1BQU0scUJBQXFCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIEZpcmViYXNlIFNlcnZpY2VzXG4gKlxuICogU2VydmljaW9zIHJldXRpbGl6YWJsZXMgcGFyYSBpbnRlZ3JhY2nDs24gY29uIEZpcmViYXNlLlxuICpcbiAqIEBleGFtcGxlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiAvLyBFbiBtYWluLnRzXG4gKiBpbXBvcnQgeyBwcm92aWRlVmFsdGVjaEZpcmViYXNlIH0gZnJvbSAndmFsdGVjaC1jb21wb25lbnRzJztcbiAqXG4gKiBib290c3RyYXBBcHBsaWNhdGlvbihBcHBDb21wb25lbnQsIHtcbiAqICAgcHJvdmlkZXJzOiBbXG4gKiAgICAgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSh7XG4gKiAgICAgICBmaXJlYmFzZTogZW52aXJvbm1lbnQuZmlyZWJhc2UsXG4gKiAgICAgICBwZXJzaXN0ZW5jZTogdHJ1ZSxcbiAqICAgICB9KSxcbiAqICAgXSxcbiAqIH0pO1xuICpcbiAqIC8vIEVuIGNvbXBvbmVudGVzXG4gKiBpbXBvcnQgeyBGaXJlYmFzZVNlcnZpY2UsIEZpcmVzdG9yZVNlcnZpY2UgfSBmcm9tICd2YWx0ZWNoLWNvbXBvbmVudHMnO1xuICpcbiAqIEBDb21wb25lbnQoey4uLn0pXG4gKiBleHBvcnQgY2xhc3MgTXlDb21wb25lbnQge1xuICogICBwcml2YXRlIGZpcmViYXNlID0gaW5qZWN0KEZpcmViYXNlU2VydmljZSk7XG4gKiAgIHByaXZhdGUgZmlyZXN0b3JlID0gaW5qZWN0KEZpcmVzdG9yZVNlcnZpY2UpO1xuICogfVxuICogYGBgXG4gKi9cblxuLy8gVGlwb3NcbmV4cG9ydCAqIGZyb20gJy4vdHlwZXMnO1xuXG4vLyBDb25maWd1cmFjacOzblxuZXhwb3J0IHsgVkFMVEVDSF9GSVJFQkFTRV9DT05GSUcsIGhhc0VtdWxhdG9ycywgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSB9IGZyb20gJy4vY29uZmlnJztcblxuLy8gQ29uZmlndXJhY2nDs24gY29tcGFydGlkYSBkZWwgbW9ub3JlcG9cbmV4cG9ydCB7XG4gIEFQUF9JRFMsXG4gIEZJUkVCQVNFX1BST0pFQ1RTLFxuICBTSEFSRURfRU1VTEFUT1JfQ09ORklHLFxuICBjb2xsZWN0aW9ucyxcbiAgY3JlYXRlRmlyZWJhc2VDb25maWcsXG4gIGlzRW11bGF0b3JNb2RlLFxuICBzdG9yYWdlUGF0aHMsXG4gIHR5cGUgQXBwSWQsXG4gIHR5cGUgQ3JlYXRlRmlyZWJhc2VDb25maWdPcHRpb25zLFxufSBmcm9tICcuL3NoYXJlZC1jb25maWcnO1xuXG4vLyBTZXJ2aWNpb3NcbmV4cG9ydCB7IEZpcmViYXNlU2VydmljZSB9IGZyb20gJy4vZmlyZWJhc2Uuc2VydmljZSc7XG5cbi8vIEZpcmVzdG9yZVxuZXhwb3J0IHsgRmlyZXN0b3JlU2VydmljZSB9IGZyb20gJy4vZmlyZXN0b3JlLnNlcnZpY2UnO1xuXG4vLyBGaXJlc3RvcmUgQ29sbGVjdGlvbnMgKEZhY3RvcnkgUGF0dGVybilcbmV4cG9ydCB7XG4gIENvbGxlY3Rpb25PcHRpb25zLFxuICBGaXJlc3RvcmVDb2xsZWN0aW9uLFxuICBGaXJlc3RvcmVDb2xsZWN0aW9uRmFjdG9yeSxcbiAgU3ViQ29sbGVjdGlvblJlZixcbiAgVHlwZWRDb2xsZWN0aW9uLFxufSBmcm9tICcuL2ZpcmVzdG9yZS1jb2xsZWN0aW9uJztcblxuLy8gVXRpbGlkYWRlc1xuZXhwb3J0IHsgUXVlcnlCdWlsZGVyLCBxdWVyeSB9IGZyb20gJy4vdXRpbHMvcXVlcnktYnVpbGRlcic7XG5leHBvcnQge1xuICBidWlsZFBhdGgsXG4gIGV4dHJhY3RQYXRoUGFyYW1zLFxuICBnZXRDb2xsZWN0aW9uUGF0aCxcbiAgZ2V0RG9jdW1lbnRJZCxcbiAgaXNDb2xsZWN0aW9uUGF0aCxcbiAgaXNEb2N1bWVudFBhdGgsXG4gIGlzVmFsaWRQYXRoLFxuICBqb2luUGF0aCxcbn0gZnJvbSAnLi91dGlscy9wYXRoLWJ1aWxkZXInO1xuXG4vLyBTdG9yYWdlXG5leHBvcnQgeyBTdG9yYWdlU2VydmljZSB9IGZyb20gJy4vc3RvcmFnZS5zZXJ2aWNlJztcblxuLy8gTWVzc2FnaW5nIChGQ00pXG5leHBvcnQgeyBNZXNzYWdpbmdTZXJ2aWNlIH0gZnJvbSAnLi9tZXNzYWdpbmcuc2VydmljZSc7XG4iXX0=
|