valtech-components 2.0.725 → 2.0.727
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/services/auth/handoff.service.mjs +152 -0
- package/esm2022/lib/services/auth/index.mjs +7 -1
- package/esm2022/lib/services/auth/notification-action.service.mjs +113 -0
- package/esm2022/lib/services/auth/org-switch.service.mjs +137 -0
- package/esm2022/lib/services/auth/types.mjs +1 -1
- package/esm2022/lib/services/firebase/firestore-collection.mjs +10 -2
- package/esm2022/lib/services/firebase/firestore.service.mjs +22 -1
- package/esm2022/lib/services/firebase/notifications.service.mjs +4 -3
- package/esm2022/lib/services/firebase/shared-config.mjs +63 -30
- package/esm2022/lib/version.mjs +2 -2
- package/fesm2022/valtech-components.mjs +477 -35
- package/fesm2022/valtech-components.mjs.map +1 -1
- package/lib/services/auth/handoff.service.d.ts +149 -0
- package/lib/services/auth/index.d.ts +6 -0
- package/lib/services/auth/notification-action.service.d.ts +34 -0
- package/lib/services/auth/org-switch.service.d.ts +127 -0
- package/lib/services/auth/types.d.ts +12 -0
- package/lib/services/firebase/firestore-collection.d.ts +12 -1
- package/lib/services/firebase/firestore.service.d.ts +18 -0
- package/lib/services/firebase/notifications.service.d.ts +9 -1
- package/lib/services/firebase/shared-config.d.ts +61 -28
- package/lib/version.d.ts +1 -1
- package/package.json +1 -1
|
@@ -41,7 +41,7 @@ import { takeUntilDestroyed, toSignal } from '@angular/core/rxjs-interop';
|
|
|
41
41
|
import { filter, switchMap as switchMap$1, catchError as catchError$1, tap, map as map$1, finalize, take, debounceTime as debounceTime$1, takeUntil as takeUntil$1 } from 'rxjs/operators';
|
|
42
42
|
import { ImageCropperComponent } from 'ngx-image-cropper';
|
|
43
43
|
import * as i1$8 from '@angular/common/http';
|
|
44
|
-
import { provideHttpClient, withInterceptors, HttpClient } from '@angular/common/http';
|
|
44
|
+
import { provideHttpClient, withInterceptors, HttpErrorResponse, HttpClient } from '@angular/common/http';
|
|
45
45
|
import { Capacitor } from '@capacitor/core';
|
|
46
46
|
import 'prismjs/components/prism-scss';
|
|
47
47
|
import 'prismjs/components/prism-json';
|
|
@@ -50,7 +50,7 @@ import 'prismjs/components/prism-json';
|
|
|
50
50
|
* Current version of valtech-components.
|
|
51
51
|
* This is automatically updated during the publish process.
|
|
52
52
|
*/
|
|
53
|
-
const VERSION = '2.0.
|
|
53
|
+
const VERSION = '2.0.727';
|
|
54
54
|
|
|
55
55
|
/**
|
|
56
56
|
* Servicio para gestionar presets de componentes.
|
|
@@ -17863,6 +17863,19 @@ function joinPath(...segments) {
|
|
|
17863
17863
|
* Servicio genérico para operaciones CRUD en Firestore.
|
|
17864
17864
|
* Soporta lecturas one-time, subscripciones real-time, paginación y queries complejas.
|
|
17865
17865
|
*/
|
|
17866
|
+
/**
|
|
17867
|
+
* Internal sentinel used to mark a collection path as global cross-app —
|
|
17868
|
+
* i.e. it should NOT be prefixed with `apps/{appId}/`.
|
|
17869
|
+
*
|
|
17870
|
+
* Apps consume this via `CollectionOptions.skipAppPrefix`; the sentinel
|
|
17871
|
+
* stays in `TypedCollection` and is stripped here before Firestore sees it.
|
|
17872
|
+
*
|
|
17873
|
+
* Format keeps it impossible to collide with a real Firestore path (`:` is
|
|
17874
|
+
* not allowed in collection segments).
|
|
17875
|
+
*
|
|
17876
|
+
* @internal
|
|
17877
|
+
*/
|
|
17878
|
+
const ABS_PATH_SENTINEL = '__abs__:';
|
|
17866
17879
|
/**
|
|
17867
17880
|
* Servicio para operaciones CRUD en Firestore.
|
|
17868
17881
|
*
|
|
@@ -17905,9 +17918,17 @@ class FirestoreService {
|
|
|
17905
17918
|
* Prefija el path de colección con el appId si está configurado.
|
|
17906
17919
|
* Si no hay appId, retorna el path sin modificar (backward compatible).
|
|
17907
17920
|
*
|
|
17921
|
+
* Si el path empieza con `ABS_PATH_SENTINEL` (`__abs__:`), se asume que el
|
|
17922
|
+
* caller quiere un path global cross-app (ej. `users/{uid}/notifications` —
|
|
17923
|
+
* el inbox global de notificaciones). El sentinel se strippea y el resto
|
|
17924
|
+
* del path se pasa verbatim, sin prefijo `apps/{appId}/`.
|
|
17925
|
+
*
|
|
17908
17926
|
* @internal
|
|
17909
17927
|
*/
|
|
17910
17928
|
prefixCollectionPath(collectionPath) {
|
|
17929
|
+
if (collectionPath.startsWith(ABS_PATH_SENTINEL)) {
|
|
17930
|
+
return collectionPath.slice(ABS_PATH_SENTINEL.length);
|
|
17931
|
+
}
|
|
17911
17932
|
if (!this.config?.appId)
|
|
17912
17933
|
return collectionPath;
|
|
17913
17934
|
return `apps/${this.config.appId}/${collectionPath}`;
|
|
@@ -25930,57 +25951,90 @@ const DEFAULT_EMULATOR_CONFIG = {
|
|
|
25930
25951
|
// STORAGE PATH BUILDERS
|
|
25931
25952
|
// ============================================================================
|
|
25932
25953
|
/**
|
|
25933
|
-
* Genera paths de Storage con
|
|
25954
|
+
* Genera paths de Storage alineados con storage.rules.
|
|
25955
|
+
*
|
|
25956
|
+
* Convenciones (ver frontend/firebase/storage.rules):
|
|
25957
|
+
* - Avatar global del user (cross-app): /users/{uid}/avatar.jpg
|
|
25958
|
+
* - Files privados del user (cross-app): /users/{uid}/files/{path}
|
|
25959
|
+
* - Avatar per-app del user: /apps/{appId}/users/{uid}/avatar.jpg
|
|
25960
|
+
* - Files per-app del user: /apps/{appId}/users/{uid}/files/{path}
|
|
25961
|
+
* - Public per-app: /apps/{appId}/public/{path}
|
|
25962
|
+
* - Shared per-app (auth-only): /apps/{appId}/shared/{path}
|
|
25963
|
+
* - Public global: /public/{path}
|
|
25934
25964
|
*
|
|
25935
25965
|
* @example
|
|
25936
|
-
*
|
|
25937
|
-
*
|
|
25938
|
-
*
|
|
25966
|
+
* storagePaths.forApp('showcase', 'public', 'banner.jpg')
|
|
25967
|
+
* // => 'apps/showcase/public/banner.jpg'
|
|
25968
|
+
*
|
|
25969
|
+
* storagePaths.userAvatar('user123')
|
|
25970
|
+
* // => 'users/user123/avatar.jpg'
|
|
25939
25971
|
*
|
|
25940
|
-
*
|
|
25941
|
-
*
|
|
25942
|
-
* // => 'profile-photos/user123/avatar.jpg'
|
|
25972
|
+
* storagePaths.appUserFile('showcase', 'user123', 'doc.pdf')
|
|
25973
|
+
* // => 'apps/showcase/users/user123/files/doc.pdf'
|
|
25943
25974
|
*/
|
|
25944
25975
|
const storagePaths = {
|
|
25945
|
-
/**
|
|
25946
|
-
forApp: (appId, ...paths) => [appId, ...paths].join('/'),
|
|
25947
|
-
/**
|
|
25948
|
-
|
|
25949
|
-
|
|
25950
|
-
|
|
25951
|
-
|
|
25952
|
-
|
|
25953
|
-
|
|
25976
|
+
/** Path per-app: apps/{appId}/{...paths} */
|
|
25977
|
+
forApp: (appId, ...paths) => ['apps', appId, ...paths].join('/'),
|
|
25978
|
+
/** Avatar global del user (cross-app) */
|
|
25979
|
+
userAvatar: (userId) => `users/${userId}/avatar.jpg`,
|
|
25980
|
+
/** Thumbnail global del user (cross-app) */
|
|
25981
|
+
userThumb: (userId) => `users/${userId}/thumb.jpg`,
|
|
25982
|
+
/** File privado global del user (cross-app) */
|
|
25983
|
+
userFile: (userId, ...paths) => ['users', userId, 'files', ...paths].join('/'),
|
|
25984
|
+
/** Avatar per-app del user */
|
|
25985
|
+
appUserAvatar: (appId, userId) => `apps/${appId}/users/${userId}/avatar.jpg`,
|
|
25986
|
+
/** File per-app del user */
|
|
25987
|
+
appUserFile: (appId, userId, ...paths) => ['apps', appId, 'users', userId, 'files', ...paths].join('/'),
|
|
25988
|
+
/** Public global (acceso sin auth, write admin-only) */
|
|
25989
|
+
public: (...paths) => `public/${paths.join('/')}`,
|
|
25954
25990
|
};
|
|
25955
25991
|
// ============================================================================
|
|
25956
25992
|
// FIRESTORE COLLECTION BUILDERS
|
|
25957
25993
|
// ============================================================================
|
|
25958
25994
|
/**
|
|
25959
|
-
* Genera paths de colecciones con
|
|
25995
|
+
* Genera paths de colecciones alineados con firestore.rules.
|
|
25960
25996
|
*
|
|
25961
|
-
*
|
|
25962
|
-
*
|
|
25997
|
+
* Convenciones (ver frontend/firebase/firestore.rules):
|
|
25998
|
+
* - Cross-app shared:
|
|
25999
|
+
* /users/{uid} (privado), /profiles/{uid} (público global),
|
|
26000
|
+
* /users/{uid}/notifications (INBOX GLOBAL cross-app cross-org)
|
|
26001
|
+
* - Per-app:
|
|
26002
|
+
* /apps/{appId}/{collection}, /apps/{appId}/profiles/{uid}
|
|
26003
|
+
* - Per-app per-user (notifications NO viven aquí):
|
|
26004
|
+
* /apps/{appId}/users/{uid}/{collection}
|
|
26005
|
+
* - Per-app per-org:
|
|
26006
|
+
* /apps/{appId}/orgs/{orgId}/{collection}
|
|
25963
26007
|
*
|
|
25964
26008
|
* @example
|
|
25965
|
-
* // Colección específica de la app
|
|
25966
26009
|
* collections.forApp('showcase', 'items')
|
|
25967
26010
|
* // => 'apps/showcase/items'
|
|
25968
26011
|
*
|
|
25969
|
-
*
|
|
25970
|
-
*
|
|
25971
|
-
*
|
|
26012
|
+
* collections.appUser('showcase', 'user123', 'drafts')
|
|
26013
|
+
* // => 'apps/showcase/users/user123/drafts'
|
|
26014
|
+
*
|
|
26015
|
+
* collections.appOrg('showcase', 'org_abc', 'posts')
|
|
26016
|
+
* // => 'apps/showcase/orgs/org_abc/posts'
|
|
26017
|
+
*
|
|
26018
|
+
* collections.userNotifications('user123')
|
|
26019
|
+
* // => 'users/user123/notifications'
|
|
25972
26020
|
*/
|
|
25973
26021
|
const collections = {
|
|
25974
|
-
/**
|
|
26022
|
+
/** Per-app cross-user: apps/{appId}/{collection} */
|
|
25975
26023
|
forApp: (appId, collectionName) => `apps/${appId}/${collectionName}`,
|
|
25976
|
-
/**
|
|
26024
|
+
/** Per-app per-user: apps/{appId}/users/{uid}/{collection} */
|
|
26025
|
+
appUser: (appId, userId, collectionName) => `apps/${appId}/users/${userId}/${collectionName}`,
|
|
26026
|
+
/** Per-app per-org: apps/{appId}/orgs/{orgId}/{collection} */
|
|
26027
|
+
appOrg: (appId, orgId, collectionName) => `apps/${appId}/orgs/${orgId}/${collectionName}`,
|
|
26028
|
+
/** Per-app perfil público del user: apps/{appId}/profiles/{uid} */
|
|
26029
|
+
appProfile: (appId, userId) => `apps/${appId}/profiles/${userId}`,
|
|
26030
|
+
/** Inbox global del user (cross-app cross-org) */
|
|
26031
|
+
userNotifications: (userId) => `users/${userId}/notifications`,
|
|
26032
|
+
/** Cross-app shared (sin namespace, nivel raíz) */
|
|
25977
26033
|
shared: {
|
|
25978
|
-
/**
|
|
26034
|
+
/** Doc privado del user — /users/{uid} */
|
|
25979
26035
|
users: 'users',
|
|
25980
|
-
/** Perfiles públicos */
|
|
26036
|
+
/** Perfiles públicos globales — /profiles/{uid} */
|
|
25981
26037
|
profiles: 'profiles',
|
|
25982
|
-
/** Notificaciones de usuarios */
|
|
25983
|
-
notifications: 'notifications',
|
|
25984
26038
|
},
|
|
25985
26039
|
};
|
|
25986
26040
|
/**
|
|
@@ -26541,12 +26595,19 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
26541
26595
|
class TypedCollection {
|
|
26542
26596
|
constructor(firestore, collectionPath, options = {}) {
|
|
26543
26597
|
this.firestore = firestore;
|
|
26544
|
-
this.collectionPath = collectionPath;
|
|
26545
26598
|
this.options = {
|
|
26546
26599
|
softDelete: false,
|
|
26547
26600
|
timestamps: true,
|
|
26601
|
+
skipAppPrefix: false,
|
|
26548
26602
|
...options,
|
|
26549
26603
|
};
|
|
26604
|
+
// Marcar el path con el sentinel cuando skipAppPrefix=true. FirestoreService
|
|
26605
|
+
// detecta el sentinel y devuelve el path sin prefijo `apps/{appId}/`.
|
|
26606
|
+
// Subcolecciones (subPath = `${this.collectionPath}/...`) heredan el sentinel
|
|
26607
|
+
// automáticamente por concatenación.
|
|
26608
|
+
this.collectionPath = this.options.skipAppPrefix
|
|
26609
|
+
? `${ABS_PATH_SENTINEL}${collectionPath}`
|
|
26610
|
+
: collectionPath;
|
|
26550
26611
|
}
|
|
26551
26612
|
// ===========================================================================
|
|
26552
26613
|
// LECTURAS ONE-TIME
|
|
@@ -28218,11 +28279,12 @@ class NotificationsService {
|
|
|
28218
28279
|
return;
|
|
28219
28280
|
}
|
|
28220
28281
|
this.currentUserId = userId;
|
|
28221
|
-
// Path
|
|
28222
|
-
//
|
|
28282
|
+
// Path global cross-app: /users/{uid}/notifications (sin prefijo apps/{appId}/).
|
|
28283
|
+
// skipAppPrefix bypassa FirestoreService.prefixCollectionPath para fan-out compartido.
|
|
28223
28284
|
const basePath = `users/${userId}/notifications`;
|
|
28224
28285
|
this.collection = this.collectionFactory.create(basePath, {
|
|
28225
28286
|
timestamps: true,
|
|
28287
|
+
skipAppPrefix: true,
|
|
28226
28288
|
});
|
|
28227
28289
|
this.collectionReady$.next(this.collection);
|
|
28228
28290
|
console.log('[Notifications] Initialized with path:', basePath);
|
|
@@ -30782,6 +30844,386 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImpo
|
|
|
30782
30844
|
`, styles: [".oauth-callback{display:flex;flex-direction:column;align-items:center;justify-content:center;height:100vh;font-family:-apple-system,BlinkMacSystemFont,Segoe UI,Roboto,sans-serif}.oauth-callback__spinner{width:40px;height:40px;border:3px solid #f3f3f3;border-top:3px solid #3498db;border-radius:50%;animation:spin 1s linear infinite;margin-bottom:16px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.oauth-callback__text{color:#666;font-size:14px}\n"] }]
|
|
30783
30845
|
}] });
|
|
30784
30846
|
|
|
30847
|
+
/**
|
|
30848
|
+
* Name of the query param that carries the handoff token. Apps may override
|
|
30849
|
+
* via `detectAndExchangeHandoff({ tokenParam })` but the default keeps the
|
|
30850
|
+
* convention consistent across the factory.
|
|
30851
|
+
*/
|
|
30852
|
+
const HANDOFF_TOKEN_PARAM = 'handoff';
|
|
30853
|
+
/**
|
|
30854
|
+
* Name of the query param that carries the post-exchange route.
|
|
30855
|
+
*/
|
|
30856
|
+
const HANDOFF_ROUTE_PARAM = 'route';
|
|
30857
|
+
/**
|
|
30858
|
+
* HandoffService — cross-app session transfer.
|
|
30859
|
+
*
|
|
30860
|
+
* Implements the OAuth Authorization Code pattern, applied internally between
|
|
30861
|
+
* apps that share the same backend.
|
|
30862
|
+
*
|
|
30863
|
+
* **Origin app (user is authenticated):**
|
|
30864
|
+
*
|
|
30865
|
+
* ```typescript
|
|
30866
|
+
* const { token, route } = await firstValueFrom(
|
|
30867
|
+
* handoff.createHandoff({ targetAppId: 'myvaltech', route: '/app/dashboard' })
|
|
30868
|
+
* );
|
|
30869
|
+
* window.location.href = `https://myvaltech.app/?handoff=${token}&route=${encodeURIComponent(route ?? '/')}`;
|
|
30870
|
+
* ```
|
|
30871
|
+
*
|
|
30872
|
+
* **Target app (boot):** call `exchangeHandoff(token)`. On success, the session
|
|
30873
|
+
* is installed (`AuthService.setExternalAuth`) and the user is authenticated.
|
|
30874
|
+
* See `detectAndExchangeHandoff` helper for the typical bootstrap pattern.
|
|
30875
|
+
*
|
|
30876
|
+
* Security notes:
|
|
30877
|
+
* - Token is single-use and short-lived (30s) — enforced server-side.
|
|
30878
|
+
* - Token in URL must be removed from history after exchange to avoid log leakage.
|
|
30879
|
+
* - The exchange endpoint is public; do NOT add auth header. The
|
|
30880
|
+
* `HttpClient` request below avoids triggering the auth interceptor since the
|
|
30881
|
+
* user isn't logged in yet on the target app.
|
|
30882
|
+
*/
|
|
30883
|
+
class HandoffService {
|
|
30884
|
+
constructor(config, http, auth, router) {
|
|
30885
|
+
this.config = config;
|
|
30886
|
+
this.http = http;
|
|
30887
|
+
this.auth = auth;
|
|
30888
|
+
this.router = router;
|
|
30889
|
+
this.detected = false;
|
|
30890
|
+
}
|
|
30891
|
+
/**
|
|
30892
|
+
* Create a handoff token. Caller must be authenticated.
|
|
30893
|
+
*
|
|
30894
|
+
* @param request Optional metadata: target app id and intended route.
|
|
30895
|
+
* @returns Observable emitting `{ token, expiresAt, route? }`.
|
|
30896
|
+
*/
|
|
30897
|
+
createHandoff(request = {}) {
|
|
30898
|
+
return this.http.post(`${this.baseUrl}/handoff`, request);
|
|
30899
|
+
}
|
|
30900
|
+
/**
|
|
30901
|
+
* Exchange a handoff token for a session and install it.
|
|
30902
|
+
*
|
|
30903
|
+
* On success, the response is piped through `AuthService.setExternalAuth`
|
|
30904
|
+
* so the user becomes authenticated. Subsequent navigation can proceed.
|
|
30905
|
+
*
|
|
30906
|
+
* On failure, the observable errors. The caller is responsible for
|
|
30907
|
+
* showing an error and routing to `/login`.
|
|
30908
|
+
*
|
|
30909
|
+
* @param token Raw handoff token read from the URL.
|
|
30910
|
+
*/
|
|
30911
|
+
exchangeHandoff(token) {
|
|
30912
|
+
return this.http
|
|
30913
|
+
.post(`${this.baseUrl}/handoff/exchange`, { token })
|
|
30914
|
+
.pipe(tap(response => this.installSession(response)), catchError$1(err => {
|
|
30915
|
+
// Surface the error untouched — the caller decides how to react
|
|
30916
|
+
// (typically: redirect to /login + toast). Don't install a bad session.
|
|
30917
|
+
throw err;
|
|
30918
|
+
}));
|
|
30919
|
+
}
|
|
30920
|
+
/**
|
|
30921
|
+
* Bootstrap helper — reads the handoff token from the current URL, exchanges
|
|
30922
|
+
* it for a session, and navigates to the intended route with the token
|
|
30923
|
+
* stripped from history.
|
|
30924
|
+
*
|
|
30925
|
+
* Idempotent: subsequent calls are no-ops. Wire from an
|
|
30926
|
+
* `APP_INITIALIZER`/`provideAppInitializer` factory in `main.ts`.
|
|
30927
|
+
*
|
|
30928
|
+
* ```typescript
|
|
30929
|
+
* // main.ts
|
|
30930
|
+
* provideAppInitializer(() => inject(HandoffService).detectAndExchangeHandoff())
|
|
30931
|
+
* ```
|
|
30932
|
+
*
|
|
30933
|
+
* On error (expired/used/invalid token), redirects to `errorRoute` (default:
|
|
30934
|
+
* the app's configured `loginRoute`). The URL is always cleaned, even on
|
|
30935
|
+
* error, so the token cannot be retried by refreshing the page.
|
|
30936
|
+
*
|
|
30937
|
+
* @returns `true` if a handoff was detected and processed (success or fail).
|
|
30938
|
+
* `false` if no token was present (cold boot, normal flow).
|
|
30939
|
+
*/
|
|
30940
|
+
async detectAndExchangeHandoff(options = {}) {
|
|
30941
|
+
if (this.detected || typeof window === 'undefined') {
|
|
30942
|
+
return false;
|
|
30943
|
+
}
|
|
30944
|
+
this.detected = true;
|
|
30945
|
+
const tokenParam = options.tokenParam ?? HANDOFF_TOKEN_PARAM;
|
|
30946
|
+
const routeParam = options.routeParam ?? HANDOFF_ROUTE_PARAM;
|
|
30947
|
+
const defaultRoute = options.defaultRoute ?? '/';
|
|
30948
|
+
const errorRoute = options.errorRoute ?? this.config.loginRoute ?? '/login';
|
|
30949
|
+
const params = new URLSearchParams(window.location.search);
|
|
30950
|
+
const token = params.get(tokenParam);
|
|
30951
|
+
if (!token) {
|
|
30952
|
+
return false;
|
|
30953
|
+
}
|
|
30954
|
+
const targetRoute = params.get(routeParam) || defaultRoute;
|
|
30955
|
+
try {
|
|
30956
|
+
await firstValueFrom(this.exchangeHandoff(token));
|
|
30957
|
+
await this.router.navigateByUrl(targetRoute, { replaceUrl: true });
|
|
30958
|
+
}
|
|
30959
|
+
catch (err) {
|
|
30960
|
+
console.warn('[Handoff] Exchange failed, redirecting to login', err);
|
|
30961
|
+
await this.router.navigateByUrl(errorRoute, { replaceUrl: true });
|
|
30962
|
+
}
|
|
30963
|
+
return true;
|
|
30964
|
+
}
|
|
30965
|
+
/**
|
|
30966
|
+
* Persist the session in `AuthService`. Mirrors the install flow used by
|
|
30967
|
+
* the normal signin path so timers, Firebase, and tab-sync all kick in.
|
|
30968
|
+
*/
|
|
30969
|
+
installSession(response) {
|
|
30970
|
+
this.auth.setExternalAuth({
|
|
30971
|
+
accessToken: response.accessToken,
|
|
30972
|
+
refreshToken: response.refreshToken,
|
|
30973
|
+
firebaseToken: response.firebaseToken,
|
|
30974
|
+
expiresIn: response.expiresIn,
|
|
30975
|
+
});
|
|
30976
|
+
}
|
|
30977
|
+
get baseUrl() {
|
|
30978
|
+
return `${this.config.apiUrl}${this.config.authPrefix}`;
|
|
30979
|
+
}
|
|
30980
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1$8.HttpClient }, { token: AuthService }, { token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
30981
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, providedIn: 'root' }); }
|
|
30982
|
+
}
|
|
30983
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, decorators: [{
|
|
30984
|
+
type: Injectable,
|
|
30985
|
+
args: [{ providedIn: 'root' }]
|
|
30986
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
30987
|
+
type: Inject,
|
|
30988
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
30989
|
+
}] }, { type: i1$8.HttpClient }, { type: AuthService }, { type: i1$1.Router }] });
|
|
30990
|
+
|
|
30991
|
+
/**
|
|
30992
|
+
* OrgSwitchService — orchestrates active organization changes across the app.
|
|
30993
|
+
*
|
|
30994
|
+
* Built on top of `AuthService.switchOrg`, which already:
|
|
30995
|
+
* - Hits `POST /v2/auth/switch-org` and receives a new Firebase custom token.
|
|
30996
|
+
* - Re-authenticates Firebase Auth with the new token (RBAC claims update).
|
|
30997
|
+
* - Broadcasts `ORG_SWITCH` to other tabs via `AuthSyncService` (multi-tab sync).
|
|
30998
|
+
*
|
|
30999
|
+
* What this service adds on top:
|
|
31000
|
+
* - A `switching` signal so the UI can show a loading indicator (1-2s switch).
|
|
31001
|
+
* - An `orgChanged$` Observable that components subscribe to in order to
|
|
31002
|
+
* invalidate their org-scoped caches (e.g. drop old query results, reset
|
|
31003
|
+
* page state) without a full page reload.
|
|
31004
|
+
* - Optional `reload: true` for apps where invalidating in-memory state piece
|
|
31005
|
+
* by piece is impractical.
|
|
31006
|
+
*
|
|
31007
|
+
* **What this service does NOT do automatically:**
|
|
31008
|
+
*
|
|
31009
|
+
* 1. **Teardown Firestore listeners.** Listeners are owned by their subscribing
|
|
31010
|
+
* components (typically via `takeUntilDestroyed` or async pipe). When the
|
|
31011
|
+
* component re-renders or unsubscribes, the listener disposes. If a
|
|
31012
|
+
* component does NOT unsubscribe on org change, its listener will keep
|
|
31013
|
+
* pointing at the previous org's path and may start failing rules. The fix
|
|
31014
|
+
* is component-level: subscribe to `orgChanged$` and reset state, or use
|
|
31015
|
+
* the `reload: true` option.
|
|
31016
|
+
*
|
|
31017
|
+
* 2. **Re-instantiate routed components.** Angular keeps mounted components
|
|
31018
|
+
* alive across navigations. If you need fresh state, either subscribe to
|
|
31019
|
+
* `orgChanged$` in the component, or use `reload: true`.
|
|
31020
|
+
*
|
|
31021
|
+
* @example Basic switch with loading state
|
|
31022
|
+
* ```typescript
|
|
31023
|
+
* private orgSwitch = inject(OrgSwitchService);
|
|
31024
|
+
*
|
|
31025
|
+
* async onSwitchOrg(orgId: string) {
|
|
31026
|
+
* await this.orgSwitch.switchTo(orgId);
|
|
31027
|
+
* // Components subscribed to orgChanged$ have already reset their state.
|
|
31028
|
+
* }
|
|
31029
|
+
*
|
|
31030
|
+
* // In template:
|
|
31031
|
+
* @if (orgSwitch.switching()) { <val-loading /> }
|
|
31032
|
+
* ```
|
|
31033
|
+
*
|
|
31034
|
+
* @example Component reacting to org change
|
|
31035
|
+
* ```typescript
|
|
31036
|
+
* private orgSwitch = inject(OrgSwitchService);
|
|
31037
|
+
*
|
|
31038
|
+
* constructor() {
|
|
31039
|
+
* this.orgSwitch.orgChanged$
|
|
31040
|
+
* .pipe(takeUntilDestroyed())
|
|
31041
|
+
* .subscribe(() => this.resetState());
|
|
31042
|
+
* }
|
|
31043
|
+
* ```
|
|
31044
|
+
*
|
|
31045
|
+
* @example Brutal reload mode
|
|
31046
|
+
* ```typescript
|
|
31047
|
+
* await this.orgSwitch.switchTo(orgId, { reload: true });
|
|
31048
|
+
* // window.location.reload() — clean slate, loses scroll position
|
|
31049
|
+
* ```
|
|
31050
|
+
*/
|
|
31051
|
+
class OrgSwitchService {
|
|
31052
|
+
constructor(auth) {
|
|
31053
|
+
this.auth = auth;
|
|
31054
|
+
this._switching = signal(false);
|
|
31055
|
+
this._orgChanged = new Subject();
|
|
31056
|
+
/**
|
|
31057
|
+
* `true` while a switch is in flight. UI should disable interactions
|
|
31058
|
+
* with org-scoped data and show a loading indicator.
|
|
31059
|
+
*/
|
|
31060
|
+
this.switching = this._switching.asReadonly();
|
|
31061
|
+
/**
|
|
31062
|
+
* Fires after a successful switch, with the previous and new org ids.
|
|
31063
|
+
* Components subscribe to invalidate caches / reset state.
|
|
31064
|
+
*
|
|
31065
|
+
* Fires AFTER the Firebase re-auth completes — listeners attached here
|
|
31066
|
+
* see the updated Firebase user / activeOrg claim.
|
|
31067
|
+
*/
|
|
31068
|
+
this.orgChanged$ = this._orgChanged.asObservable();
|
|
31069
|
+
}
|
|
31070
|
+
/**
|
|
31071
|
+
* Switch the user's active organization.
|
|
31072
|
+
*
|
|
31073
|
+
* Re-entrant safe: while a switch is in flight, additional calls are
|
|
31074
|
+
* rejected silently (returns immediately). Inspect `switching()` to gate UI.
|
|
31075
|
+
*
|
|
31076
|
+
* @param orgId Target organization id. Must be one the user has a role in
|
|
31077
|
+
* — backend rejects otherwise with `PERMISSION_DENIED`.
|
|
31078
|
+
* @param options See `SwitchOrgOptions`.
|
|
31079
|
+
*
|
|
31080
|
+
* @throws The error from `auth.switchOrg` if the backend call fails.
|
|
31081
|
+
* `switching` returns to `false` before the error propagates.
|
|
31082
|
+
*/
|
|
31083
|
+
async switchTo(orgId, options = {}) {
|
|
31084
|
+
if (this._switching()) {
|
|
31085
|
+
return;
|
|
31086
|
+
}
|
|
31087
|
+
const previousOrg = this.currentActiveOrg();
|
|
31088
|
+
if (previousOrg === orgId) {
|
|
31089
|
+
// No-op — already on this org.
|
|
31090
|
+
return;
|
|
31091
|
+
}
|
|
31092
|
+
this._switching.set(true);
|
|
31093
|
+
try {
|
|
31094
|
+
await firstValueFrom(this.auth.switchOrg(orgId));
|
|
31095
|
+
this._orgChanged.next({ previousOrg, newOrg: orgId });
|
|
31096
|
+
if (options.reload && typeof window !== 'undefined') {
|
|
31097
|
+
window.location.reload();
|
|
31098
|
+
}
|
|
31099
|
+
}
|
|
31100
|
+
finally {
|
|
31101
|
+
this._switching.set(false);
|
|
31102
|
+
}
|
|
31103
|
+
}
|
|
31104
|
+
/**
|
|
31105
|
+
* Read the current `activeOrg` from the auth user signal.
|
|
31106
|
+
* Falls back to empty string if the user isn't loaded yet.
|
|
31107
|
+
*/
|
|
31108
|
+
currentActiveOrg() {
|
|
31109
|
+
const user = this.auth.user();
|
|
31110
|
+
// AuthUser may expose activeOrgId under different names depending on
|
|
31111
|
+
// backend version — keep tolerant.
|
|
31112
|
+
return (user?.activeOrgId ??
|
|
31113
|
+
user?.activeOrg ??
|
|
31114
|
+
'');
|
|
31115
|
+
}
|
|
31116
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, deps: [{ token: AuthService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31117
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, providedIn: 'root' }); }
|
|
31118
|
+
}
|
|
31119
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, decorators: [{
|
|
31120
|
+
type: Injectable,
|
|
31121
|
+
args: [{ providedIn: 'root' }]
|
|
31122
|
+
}], ctorParameters: () => [{ type: AuthService }] });
|
|
31123
|
+
|
|
31124
|
+
/**
|
|
31125
|
+
* NotificationActionService — orquesta el "click en notificación" cross-app cross-org.
|
|
31126
|
+
*
|
|
31127
|
+
* Flujo:
|
|
31128
|
+
* 1. markAsRead (best-effort, no bloquea)
|
|
31129
|
+
* 2. Si appId destino !== appId actual → handoff token + redirect a app destino
|
|
31130
|
+
* 3. Si orgId destino !== activeOrg → switchTo(orgId) (sin reload, navega después)
|
|
31131
|
+
* 4. router.navigateByUrl(actionRoute)
|
|
31132
|
+
*
|
|
31133
|
+
* Requiere:
|
|
31134
|
+
* - ValtechAuthConfig.appId (identifica la app actual)
|
|
31135
|
+
* - ValtechAuthConfig.appUrls (mapa baseUrl para handoff cross-app)
|
|
31136
|
+
*/
|
|
31137
|
+
class NotificationActionService {
|
|
31138
|
+
constructor(config, auth, orgSwitch, handoff, notifications, router) {
|
|
31139
|
+
this.config = config;
|
|
31140
|
+
this.auth = auth;
|
|
31141
|
+
this.orgSwitch = orgSwitch;
|
|
31142
|
+
this.handoff = handoff;
|
|
31143
|
+
this.notifications = notifications;
|
|
31144
|
+
this.router = router;
|
|
31145
|
+
}
|
|
31146
|
+
/**
|
|
31147
|
+
* Abre la notificación: marca como leída, switch-org si toca, navegación local o
|
|
31148
|
+
* redirect cross-app vía handoff.
|
|
31149
|
+
*
|
|
31150
|
+
* No lanza errores hacia la UI — devuelve un resultado descriptivo. Errores
|
|
31151
|
+
* técnicos quedan en console.warn.
|
|
31152
|
+
*/
|
|
31153
|
+
async open(notif) {
|
|
31154
|
+
// 1) Mark as read (best-effort, no bloquea el flujo principal)
|
|
31155
|
+
if (notif.id && !notif.isRead) {
|
|
31156
|
+
this.notifications.markAsRead(notif.id).catch(err => {
|
|
31157
|
+
console.warn('[NotificationAction] markAsRead failed', err);
|
|
31158
|
+
});
|
|
31159
|
+
}
|
|
31160
|
+
const route = notif.actionRoute;
|
|
31161
|
+
if (!route) {
|
|
31162
|
+
return 'no-action-route';
|
|
31163
|
+
}
|
|
31164
|
+
const currentApp = this.config.appId;
|
|
31165
|
+
const targetApp = notif.appId;
|
|
31166
|
+
// 2) Cross-app: handoff + full redirect
|
|
31167
|
+
if (targetApp && currentApp && targetApp !== currentApp) {
|
|
31168
|
+
const baseUrl = this.config.appUrls?.[targetApp];
|
|
31169
|
+
if (!baseUrl) {
|
|
31170
|
+
console.warn(`[NotificationAction] Missing appUrls['${targetApp}'] — configure ValtechAuthConfig.appUrls`);
|
|
31171
|
+
return 'cross-app-unconfigured';
|
|
31172
|
+
}
|
|
31173
|
+
try {
|
|
31174
|
+
const resp = await firstValueFrom(this.handoff.createHandoff({ targetAppId: targetApp, route }));
|
|
31175
|
+
const url = this.buildHandoffUrl(baseUrl, resp.token, route);
|
|
31176
|
+
if (typeof window !== 'undefined') {
|
|
31177
|
+
window.location.href = url;
|
|
31178
|
+
}
|
|
31179
|
+
return 'redirected-cross-app';
|
|
31180
|
+
}
|
|
31181
|
+
catch (err) {
|
|
31182
|
+
const msg = err instanceof HttpErrorResponse ? err.message : String(err);
|
|
31183
|
+
console.warn('[NotificationAction] createHandoff failed:', msg);
|
|
31184
|
+
return 'handoff-failed';
|
|
31185
|
+
}
|
|
31186
|
+
}
|
|
31187
|
+
// 3) Same app — switch-org si toca (sin reload — la navegación posterior monta page fresh)
|
|
31188
|
+
let switched = false;
|
|
31189
|
+
if (notif.orgId) {
|
|
31190
|
+
const active = this.activeOrg();
|
|
31191
|
+
if (active && active !== notif.orgId) {
|
|
31192
|
+
await this.orgSwitch.switchTo(notif.orgId);
|
|
31193
|
+
switched = true;
|
|
31194
|
+
}
|
|
31195
|
+
}
|
|
31196
|
+
// 4) Navigate local
|
|
31197
|
+
await this.router.navigateByUrl(route);
|
|
31198
|
+
return switched ? 'navigated-after-switch-org' : 'navigated';
|
|
31199
|
+
}
|
|
31200
|
+
activeOrg() {
|
|
31201
|
+
const user = this.auth.user();
|
|
31202
|
+
return (user?.activeOrgId ??
|
|
31203
|
+
user?.activeOrg ??
|
|
31204
|
+
'');
|
|
31205
|
+
}
|
|
31206
|
+
/**
|
|
31207
|
+
* Construye URL absoluta para handoff cross-app preservando pathname y otros
|
|
31208
|
+
* params existentes de la baseUrl.
|
|
31209
|
+
*/
|
|
31210
|
+
buildHandoffUrl(baseUrl, token, route) {
|
|
31211
|
+
const url = new URL(baseUrl);
|
|
31212
|
+
url.searchParams.set('handoff', token);
|
|
31213
|
+
url.searchParams.set('route', route);
|
|
31214
|
+
return url.toString();
|
|
31215
|
+
}
|
|
31216
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: AuthService }, { token: OrgSwitchService }, { token: HandoffService }, { token: NotificationsService }, { token: i1$1.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
31217
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, providedIn: 'root' }); }
|
|
31218
|
+
}
|
|
31219
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, decorators: [{
|
|
31220
|
+
type: Injectable,
|
|
31221
|
+
args: [{ providedIn: 'root' }]
|
|
31222
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
31223
|
+
type: Inject,
|
|
31224
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
31225
|
+
}] }, { type: AuthService }, { type: OrgSwitchService }, { type: HandoffService }, { type: NotificationsService }, { type: i1$1.Router }] });
|
|
31226
|
+
|
|
30785
31227
|
/**
|
|
30786
31228
|
* Valtech Auth Service
|
|
30787
31229
|
*
|
|
@@ -41627,5 +42069,5 @@ function buildFooterLinks(links, t) {
|
|
|
41627
42069
|
* Generated bundle index. Do not edit.
|
|
41628
42070
|
*/
|
|
41629
42071
|
|
|
41630
|
-
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentTransformer, CountdownComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlowCardComponent, GridSkeletonComponent, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTION, MaintenancePageComponent, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UpdateBannerComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_DEFAULT_CONTENT, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_SOCIAL_LINKS, VERSION, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, blogPost, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createTitleProps, docs, extractPathParams, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, news, permissionGuard, permissionGuardFromRoute, provideValtechAds, provideValtechAppConfig, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechPresets, provideValtechSkeleton, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
42072
|
+
export { ACTION_CARD_DEFAULTS, AD_SIZE_MAP, API_TABLE_COLUMN_LABELS, ARTICLE_SPACING, AVATAR_UPLOAD_DEFAULTS, AccordionComponent, ActionCardComponent, ActionHeaderComponent, ActionType, AdSlotComponent, AdsLoaderService, AdsService, AlertBoxComponent, AnalyticsErrorHandler, AnalyticsRouterTracker, AnalyticsService, AppConfigService, ArticleBuilder, ArticleComponent, AuthBackgroundComponent, AuthService, AuthStateService, AuthStorageService, AuthSyncService, AvatarComponent, AvatarUploadComponent, BOTTOM_NAV_DEFAULTS, BannerComponent, BaseDefault, BlogPostBuilder, BottomNavComponent, BoxComponent, BreadcrumbComponent, ButtonComponent, ButtonGroupComponent, COMMON_COUNTRY_CODES, COMMON_CURRENCIES, CURRENCY_INFO, CardComponent, CardSection, CardType, CardsCarouselComponent, CheckInputComponent, CheckboxRadioInputComponent, ChipGroupComponent, ClearDefault, ClearDefaultBlock, ClearDefaultFull, ClearDefaultRound, ClearDefaultRoundBlock, ClearDefaultRoundFull, CodeDisplayComponent, CommandDisplayComponent, CommentComponent, CommentInputComponent, CommentSectionComponent, CompanyFooterComponent, ComponentStates, ConfirmationDialogService, ContainerComponent, ContentLoaderComponent, ContentReactionComponent, ContentTransformer, CountdownComponent, CurrencyInputComponent, DEFAULT_ADS_CONFIG, DEFAULT_APP_CONFIG_SERVICE_CONFIG, DEFAULT_AUTH_CONFIG, DEFAULT_BACK_HEADER, DEFAULT_CANCEL_BUTTON, DEFAULT_CONFIRM_BUTTON, DEFAULT_COUNTDOWN_LABELS, DEFAULT_COUNTDOWN_LABELS_EN, DEFAULT_EMPTY_STATE, DEFAULT_EMULATOR_CONFIG, DEFAULT_FEEDBACK_CONFIG, DEFAULT_FEEDBACK_TYPE_OPTIONS, DEFAULT_HOME_HEADER, DEFAULT_INFINITE_LIST_METADATA, DEFAULT_MODAL_CANCEL_BUTTON, DEFAULT_MODAL_CONFIRM_BUTTON, DEFAULT_PAGE_SIZE_OPTIONS, DEFAULT_PLATFORMS, DEFAULT_REFRESHER_METADATA, DEFAULT_SKELETON_CONFIG, DataTableComponent, DateInputComponent, DateRangeInputComponent, DetailSkeletonComponent, DeviceService, DisplayComponent, DividerComponent, DocsApiTableComponent, DocsBreadcrumbComponent, DocsBuilder, DocsCalloutComponent, DocsCodeExampleComponent, DocsLayoutComponent, DocsNavLinksComponent, DocsNavigationService, DocsPageComponent, DocsSearchComponent, DocsSectionComponent, DocsShellComponent, DocsSidebarComponent, DocsTocComponent, DownloadService, EmailInputComponent, ExpandableTextComponent, FEATURES_LIST_DEFAULTS, FabComponent, FeaturesListComponent, FeedbackFormComponent, FeedbackService, FileInputComponent, FirebaseService, FirestoreCollectionFactory, FirestoreService, FooterComponent, FooterLinksComponent, FormComponent, FormFooterComponent, FormSkeletonComponent, FunHeaderComponent, GlowCardComponent, GridSkeletonComponent, HANDOFF_ROUTE_PARAM, HANDOFF_TOKEN_PARAM, HandoffService, HeaderComponent, HintComponent, HorizontalScrollComponent, HourInputComponent, HrefComponent, I18nService, IMAGE_DEFAULTS, INITIAL_AUTH_STATE, INITIAL_MFA_STATE, Icon, IconComponent, IconService, ImageComponent, ImageCropComponent, ImageService, InAppBrowserService, InfiniteListComponent, InfoComponent, InputI18nHelper, InputType, ItemListComponent, LANG_STORAGE_KEY$1 as LANG_STORAGE_KEY, LOGIN_DEFAULTS, LanguageSelectorComponent, LayeredCardComponent, LinkComponent, LinkProcessorService, LinkedProvidersComponent, LinksAccordionComponent, LinksCakeComponent, ListSkeletonComponent, LoadingDirective, LocalStorageService, LocaleService, LoginComponent, MODAL_SIZES, MOTION, MaintenancePageComponent, MenuComponent, MessagingService, MetaService, ModalService, MultiSelectSearchComponent, NavigationService, NewsBuilder, NoContentComponent, NotesBoxComponent, NotificationActionService, NotificationsService, NumberFromToComponent, NumberInputComponent, NumberStepperComponent, OAUTH_PROVIDERS_INFO, OAuthCallbackComponent, OAuthService, OrgSwitchService, OutlineDefault, OutlineDefaultBlock, OutlineDefaultFull, OutlineDefaultRound, OutlineDefaultRoundBlock, OutlineDefaultRoundFull, PLATFORM_CONFIGS, PageContentComponent, PageTemplateComponent, PageWrapperComponent, PaginationComponent, PaginationService, PasswordInputComponent, PhoneInputComponent, PillComponent, PinInputComponent, PlainCodeBoxComponent, PopoverSelectorComponent, PresetService, PriceTagComponent, PrimarySolidBlockButton, PrimarySolidBlockHrefButton, PrimarySolidBlockIconButton, PrimarySolidBlockIconHrefButton, PrimarySolidDefaultRoundButton, PrimarySolidDefaultRoundHrefButton, PrimarySolidDefaultRoundIconButton, PrimarySolidDefaultRoundIconHrefButton, PrimarySolidFullButton, PrimarySolidFullHrefButton, PrimarySolidFullIconButton, PrimarySolidFullIconHrefButton, PrimarySolidLargeRoundButton, PrimarySolidLargeRoundHrefButton, PrimarySolidLargeRoundIconButton, PrimarySolidLargeRoundIconHrefButton, PrimarySolidSmallRoundButton, PrimarySolidSmallRoundHrefButton, PrimarySolidSmallRoundIconButton, PrimarySolidSmallRoundIconHrefButton, ProcessLinksPipe, ProfileSkeletonComponent, ProgressBarComponent, ProgressRingComponent, ProgressStatusComponent, PrompterComponent, QR_PRESETS, QrCodeComponent, QrGeneratorService, QueryBuilder, QuoteBoxComponent, RadioInputComponent, RangeInputComponent, RatingComponent, RefresherComponent, RightsFooterComponent, RotatingTextComponent, SKELETON_PRESETS, SearchSelectorComponent, SearchbarComponent, SecondarySolidBlockButton, SecondarySolidBlockHrefButton, SecondarySolidBlockIconButton, SecondarySolidBlockIconHrefButton, SecondarySolidDefaultRoundButton, SecondarySolidDefaultRoundHrefButton, SecondarySolidDefaultRoundIconButton, SecondarySolidDefaultRoundIconHrefButton, SecondarySolidFullButton, SecondarySolidFullHrefButton, SecondarySolidFullIconButton, SecondarySolidFullIconHrefButton, SecondarySolidLargeRoundButton, SecondarySolidLargeRoundHrefButton, SecondarySolidLargeRoundIconButton, SecondarySolidLargeRoundIconHrefButton, SecondarySolidSmallRoundButton, SecondarySolidSmallRoundHrefButton, SecondarySolidSmallRoundIconButton, SecondarySolidSmallRoundIconHrefButton, SegmentControlComponent, SelectSearchComponent, SessionService, ShareButtonsComponent, SimpleComponent, SkeletonComponent, SkeletonService, SolidBlockButton, SolidDefault, SolidDefaultBlock, SolidDefaultButton, SolidDefaultFull, SolidDefaultRound, SolidDefaultRoundBlock, SolidDefaultRoundButton, SolidDefaultRoundFull, SolidFullButton, SolidLargeButton, SolidLargeRoundButton, SolidSmallButton, SolidSmallRoundButton, StatsCardComponent, StepperComponent, StorageService, SwipeCarouselComponent, TabbedContentComponent, TableSkeletonComponent, TabsComponent, Terminal404Component, TestimonialCardComponent, TestimonialCarouselComponent, TextComponent, TextInputComponent, TextareaInputComponent, ThemeOption, ThemeService, TimelineComponent, TitleBlockComponent, TitleComponent, ToastService, ToggleInputComponent, TokenService, ToolbarActionType, ToolbarComponent, TranslatePipe, TypedCollection, UpdateBannerComponent, UsernameInputComponent, VALTECH_ADS_CONFIG, VALTECH_APP_CONFIG, VALTECH_AUTH_CONFIG, VALTECH_COMPANY_LINKS, VALTECH_DEFAULT_CONTENT, VALTECH_FEEDBACK_CONFIG, VALTECH_FIREBASE_CONFIG, VALTECH_FOOTER_I18N, VALTECH_FOOTER_LOGO, VALTECH_LANGUAGE_SELECTOR, VALTECH_SOCIAL_LINKS, VERSION, WizardComponent, WizardFooterComponent, applyDefaultValueToControl, authGuard, authInterceptor, blogPost, buildFooterLinks, buildPath, collections, createFirebaseConfig, createGlowCardProps, createInitialPaginationState, createNumberFromToField, createTitleProps, docs, extractPathParams, getAppInfo, getAppVersion, getCollectionPath, getDocumentId, getTimeOfDayKey, goToTop, guestGuard, hasEmulators, isAtEnd, isCollectionPath, isDocumentPath, isEmulatorMode, isValidPath, joinPath, maxLength, news, permissionGuard, permissionGuardFromRoute, provideValtechAds, provideValtechAppConfig, provideValtechAuth, provideValtechAuthInterceptor, provideValtechFeedback, provideValtechFirebase, provideValtechI18n, provideValtechPresets, provideValtechSkeleton, query, replaceSpecialChars, resolveColor, resolveInputDefaultValue, roleGuard, storagePaths, superAdminGuard, toArticle };
|
|
41631
42073
|
//# sourceMappingURL=valtech-components.mjs.map
|