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
|
@@ -0,0 +1,152 @@
|
|
|
1
|
+
import { Inject, Injectable } from '@angular/core';
|
|
2
|
+
import { firstValueFrom } from 'rxjs';
|
|
3
|
+
import { catchError, tap } from 'rxjs/operators';
|
|
4
|
+
import { VALTECH_AUTH_CONFIG } from './config';
|
|
5
|
+
import * as i0 from "@angular/core";
|
|
6
|
+
import * as i1 from "@angular/common/http";
|
|
7
|
+
import * as i2 from "./auth.service";
|
|
8
|
+
import * as i3 from "@angular/router";
|
|
9
|
+
/**
|
|
10
|
+
* Name of the query param that carries the handoff token. Apps may override
|
|
11
|
+
* via `detectAndExchangeHandoff({ tokenParam })` but the default keeps the
|
|
12
|
+
* convention consistent across the factory.
|
|
13
|
+
*/
|
|
14
|
+
export const HANDOFF_TOKEN_PARAM = 'handoff';
|
|
15
|
+
/**
|
|
16
|
+
* Name of the query param that carries the post-exchange route.
|
|
17
|
+
*/
|
|
18
|
+
export const HANDOFF_ROUTE_PARAM = 'route';
|
|
19
|
+
/**
|
|
20
|
+
* HandoffService — cross-app session transfer.
|
|
21
|
+
*
|
|
22
|
+
* Implements the OAuth Authorization Code pattern, applied internally between
|
|
23
|
+
* apps that share the same backend.
|
|
24
|
+
*
|
|
25
|
+
* **Origin app (user is authenticated):**
|
|
26
|
+
*
|
|
27
|
+
* ```typescript
|
|
28
|
+
* const { token, route } = await firstValueFrom(
|
|
29
|
+
* handoff.createHandoff({ targetAppId: 'myvaltech', route: '/app/dashboard' })
|
|
30
|
+
* );
|
|
31
|
+
* window.location.href = `https://myvaltech.app/?handoff=${token}&route=${encodeURIComponent(route ?? '/')}`;
|
|
32
|
+
* ```
|
|
33
|
+
*
|
|
34
|
+
* **Target app (boot):** call `exchangeHandoff(token)`. On success, the session
|
|
35
|
+
* is installed (`AuthService.setExternalAuth`) and the user is authenticated.
|
|
36
|
+
* See `detectAndExchangeHandoff` helper for the typical bootstrap pattern.
|
|
37
|
+
*
|
|
38
|
+
* Security notes:
|
|
39
|
+
* - Token is single-use and short-lived (30s) — enforced server-side.
|
|
40
|
+
* - Token in URL must be removed from history after exchange to avoid log leakage.
|
|
41
|
+
* - The exchange endpoint is public; do NOT add auth header. The
|
|
42
|
+
* `HttpClient` request below avoids triggering the auth interceptor since the
|
|
43
|
+
* user isn't logged in yet on the target app.
|
|
44
|
+
*/
|
|
45
|
+
export class HandoffService {
|
|
46
|
+
constructor(config, http, auth, router) {
|
|
47
|
+
this.config = config;
|
|
48
|
+
this.http = http;
|
|
49
|
+
this.auth = auth;
|
|
50
|
+
this.router = router;
|
|
51
|
+
this.detected = false;
|
|
52
|
+
}
|
|
53
|
+
/**
|
|
54
|
+
* Create a handoff token. Caller must be authenticated.
|
|
55
|
+
*
|
|
56
|
+
* @param request Optional metadata: target app id and intended route.
|
|
57
|
+
* @returns Observable emitting `{ token, expiresAt, route? }`.
|
|
58
|
+
*/
|
|
59
|
+
createHandoff(request = {}) {
|
|
60
|
+
return this.http.post(`${this.baseUrl}/handoff`, request);
|
|
61
|
+
}
|
|
62
|
+
/**
|
|
63
|
+
* Exchange a handoff token for a session and install it.
|
|
64
|
+
*
|
|
65
|
+
* On success, the response is piped through `AuthService.setExternalAuth`
|
|
66
|
+
* so the user becomes authenticated. Subsequent navigation can proceed.
|
|
67
|
+
*
|
|
68
|
+
* On failure, the observable errors. The caller is responsible for
|
|
69
|
+
* showing an error and routing to `/login`.
|
|
70
|
+
*
|
|
71
|
+
* @param token Raw handoff token read from the URL.
|
|
72
|
+
*/
|
|
73
|
+
exchangeHandoff(token) {
|
|
74
|
+
return this.http
|
|
75
|
+
.post(`${this.baseUrl}/handoff/exchange`, { token })
|
|
76
|
+
.pipe(tap(response => this.installSession(response)), catchError(err => {
|
|
77
|
+
// Surface the error untouched — the caller decides how to react
|
|
78
|
+
// (typically: redirect to /login + toast). Don't install a bad session.
|
|
79
|
+
throw err;
|
|
80
|
+
}));
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Bootstrap helper — reads the handoff token from the current URL, exchanges
|
|
84
|
+
* it for a session, and navigates to the intended route with the token
|
|
85
|
+
* stripped from history.
|
|
86
|
+
*
|
|
87
|
+
* Idempotent: subsequent calls are no-ops. Wire from an
|
|
88
|
+
* `APP_INITIALIZER`/`provideAppInitializer` factory in `main.ts`.
|
|
89
|
+
*
|
|
90
|
+
* ```typescript
|
|
91
|
+
* // main.ts
|
|
92
|
+
* provideAppInitializer(() => inject(HandoffService).detectAndExchangeHandoff())
|
|
93
|
+
* ```
|
|
94
|
+
*
|
|
95
|
+
* On error (expired/used/invalid token), redirects to `errorRoute` (default:
|
|
96
|
+
* the app's configured `loginRoute`). The URL is always cleaned, even on
|
|
97
|
+
* error, so the token cannot be retried by refreshing the page.
|
|
98
|
+
*
|
|
99
|
+
* @returns `true` if a handoff was detected and processed (success or fail).
|
|
100
|
+
* `false` if no token was present (cold boot, normal flow).
|
|
101
|
+
*/
|
|
102
|
+
async detectAndExchangeHandoff(options = {}) {
|
|
103
|
+
if (this.detected || typeof window === 'undefined') {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
this.detected = true;
|
|
107
|
+
const tokenParam = options.tokenParam ?? HANDOFF_TOKEN_PARAM;
|
|
108
|
+
const routeParam = options.routeParam ?? HANDOFF_ROUTE_PARAM;
|
|
109
|
+
const defaultRoute = options.defaultRoute ?? '/';
|
|
110
|
+
const errorRoute = options.errorRoute ?? this.config.loginRoute ?? '/login';
|
|
111
|
+
const params = new URLSearchParams(window.location.search);
|
|
112
|
+
const token = params.get(tokenParam);
|
|
113
|
+
if (!token) {
|
|
114
|
+
return false;
|
|
115
|
+
}
|
|
116
|
+
const targetRoute = params.get(routeParam) || defaultRoute;
|
|
117
|
+
try {
|
|
118
|
+
await firstValueFrom(this.exchangeHandoff(token));
|
|
119
|
+
await this.router.navigateByUrl(targetRoute, { replaceUrl: true });
|
|
120
|
+
}
|
|
121
|
+
catch (err) {
|
|
122
|
+
console.warn('[Handoff] Exchange failed, redirecting to login', err);
|
|
123
|
+
await this.router.navigateByUrl(errorRoute, { replaceUrl: true });
|
|
124
|
+
}
|
|
125
|
+
return true;
|
|
126
|
+
}
|
|
127
|
+
/**
|
|
128
|
+
* Persist the session in `AuthService`. Mirrors the install flow used by
|
|
129
|
+
* the normal signin path so timers, Firebase, and tab-sync all kick in.
|
|
130
|
+
*/
|
|
131
|
+
installSession(response) {
|
|
132
|
+
this.auth.setExternalAuth({
|
|
133
|
+
accessToken: response.accessToken,
|
|
134
|
+
refreshToken: response.refreshToken,
|
|
135
|
+
firebaseToken: response.firebaseToken,
|
|
136
|
+
expiresIn: response.expiresIn,
|
|
137
|
+
});
|
|
138
|
+
}
|
|
139
|
+
get baseUrl() {
|
|
140
|
+
return `${this.config.apiUrl}${this.config.authPrefix}`;
|
|
141
|
+
}
|
|
142
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1.HttpClient }, { token: i2.AuthService }, { token: i3.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
143
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, providedIn: 'root' }); }
|
|
144
|
+
}
|
|
145
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: HandoffService, decorators: [{
|
|
146
|
+
type: Injectable,
|
|
147
|
+
args: [{ providedIn: 'root' }]
|
|
148
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
149
|
+
type: Inject,
|
|
150
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
151
|
+
}] }, { type: i1.HttpClient }, { type: i2.AuthService }, { type: i3.Router }] });
|
|
152
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaGFuZG9mZi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9hdXRoL2hhbmRvZmYuc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFDQSxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsY0FBYyxFQUFjLE1BQU0sTUFBTSxDQUFDO0FBQ2xELE9BQU8sRUFBRSxVQUFVLEVBQUUsR0FBRyxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFHakQsT0FBTyxFQUFFLG1CQUFtQixFQUFFLE1BQU0sVUFBVSxDQUFDOzs7OztBQUcvQzs7OztHQUlHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsU0FBUyxDQUFDO0FBRTdDOztHQUVHO0FBQ0gsTUFBTSxDQUFDLE1BQU0sbUJBQW1CLEdBQUcsT0FBTyxDQUFDO0FBeUQzQzs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXlCRztBQUVILE1BQU0sT0FBTyxjQUFjO0lBR3pCLFlBQ3VDLE1BQXlCLEVBQ3RELElBQWdCLEVBQ2hCLElBQWlCLEVBQ2pCLE1BQWM7UUFIZSxXQUFNLEdBQU4sTUFBTSxDQUFtQjtRQUN0RCxTQUFJLEdBQUosSUFBSSxDQUFZO1FBQ2hCLFNBQUksR0FBSixJQUFJLENBQWE7UUFDakIsV0FBTSxHQUFOLE1BQU0sQ0FBUTtRQU5oQixhQUFRLEdBQUcsS0FBSyxDQUFDO0lBT3RCLENBQUM7SUFFSjs7Ozs7T0FLRztJQUNILGFBQWEsQ0FBQyxVQUFnQyxFQUFFO1FBQzlDLE9BQU8sSUFBSSxDQUFDLElBQUksQ0FBQyxJQUFJLENBQXdCLEdBQUcsSUFBSSxDQUFDLE9BQU8sVUFBVSxFQUFFLE9BQU8sQ0FBQyxDQUFDO0lBQ25GLENBQUM7SUFFRDs7Ozs7Ozs7OztPQVVHO0lBQ0gsZUFBZSxDQUFDLEtBQWE7UUFDM0IsT0FBTyxJQUFJLENB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bnQiOlsiaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcbmltcG9ydCB7IEluamVjdCwgSW5qZWN0YWJsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xuaW1wb3J0IHsgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcbmltcG9ydCB7IGZpcnN0VmFsdWVGcm9tLCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XG5pbXBvcnQgeyBjYXRjaEVycm9yLCB0YXAgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XG5cbmltcG9ydCB7IEF1dGhTZXJ2aWNlIH0gZnJvbSAnLi9hdXRoLnNlcnZpY2UnO1xuaW1wb3J0IHsgVkFMVEVDSF9BVVRIX0NPTkZJRyB9IGZyb20gJy4vY29uZmlnJztcbmltcG9ydCB7IFZhbHRlY2hBdXRoQ29uZmlnIH0gZnJvbSAnLi90eXBlcyc7XG5cbi8qKlxuICogTmFtZSBvZiB0aGUgcXVlcnkgcGFyYW0gdGhhdCBjYXJyaWVzIHRoZSBoYW5kb2ZmIHRva2VuLiBBcHBzIG1heSBvdmVycmlkZVxuICogdmlhIGBkZXRlY3RBbmRFeGNoYW5nZUhhbmRvZmYoeyB0b2tlblBhcmFtIH0pYCBidXQgdGhlIGRlZmF1bHQga2VlcHMgdGhlXG4gKiBjb252ZW50aW9uIGNvbnNpc3RlbnQgYWNyb3NzIHRoZSBmYWN0b3J5LlxuICovXG5leHBvcnQgY29uc3QgSEFORE9GRl9UT0tFTl9QQVJBTSA9ICdoYW5kb2ZmJztcblxuLyoqXG4gKiBOYW1lIG9mIHRoZSBxdWVyeSBwYXJhbSB0aGF0IGNhcnJpZXMgdGhlIHBvc3QtZXhjaGFuZ2Ugcm91dGUuXG4gKi9cbmV4cG9ydCBjb25zdCBIQU5ET0ZGX1JPVVRFX1BBUkFNID0gJ3JvdXRlJztcblxuLyoqXG4gKiBPcHRpb25zIGZvciBgSGFuZG9mZlNlcnZpY2UuZGV0ZWN0QW5kRXhjaGFuZ2VIYW5kb2ZmYC5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBEZXRlY3RBbmRFeGNoYW5nZU9wdGlvbnMge1xuICAvKiogT3ZlcnJpZGUgdGhlIHF1ZXJ5IHBhcmFtIG5hbWUuIERlZmF1bHQ6IGAnaGFuZG9mZidgLiAqL1xuICB0b2tlblBhcmFtPzogc3RyaW5nO1xuICAvKiogT3ZlcnJpZGUgdGhlIHJvdXRlIHBhcmFtIG5hbWUuIERlZmF1bHQ6IGAncm91dGUnYC4gKi9cbiAgcm91dGVQYXJhbT86IHN0cmluZztcbiAgLyoqIFdoZXJlIHRvIG5hdmlnYXRlIGlmIG5vIHJvdXRlIHBhcmFtIGlzIHByZXNlbnQuIERlZmF1bHQ6IGAnLydgLiAqL1xuICBkZWZhdWx0Um91dGU/OiBzdHJpbmc7XG4gIC8qKiBXaGVyZSB0byBuYXZpZ2F0ZSBvbiBleGNoYW5nZSBlcnJvci4gRGVmYXVsdDogYXBwJ3MgY29uZmlndXJlZCBgbG9naW5Sb3V0ZWAuICovXG4gIGVycm9yUm91dGU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVxdWVzdCBib2R5IGZvciBgUE9TVCAvdjIvYXV0aC9oYW5kb2ZmYC5cbiAqXG4gKiBCb3RoIGZpZWxkcyBhcmUgb3B0aW9uYWwgYW5kIHN0b3JlZCBmb3IgYXVkaXQgb25seSDigJQgdGhlIGV4Y2hhbmdlIHN0ZXBcbiAqIGRvZXMgbm90IGVuZm9yY2UgdGhhdCB0aGUgcmVkZWVtaW5nIGFwcCBtYXRjaGVzIGB0YXJnZXRBcHBJZGAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGFuZG9mZkNyZWF0ZVJlcXVlc3Qge1xuICAvKiogVGFyZ2V0IGFwcCB0aGUgaGFuZG9mZiBpcyBpbnRlbmRlZCBmb3IgKGUuZy4gYFwibXl2YWx0ZWNoXCJgKS4gQXVkaXQtb25seS4gKi9cbiAgdGFyZ2V0QXBwSWQ/OiBzdHJpbmc7XG4gIC8qKiBSb3V0ZSB0aGUgdGFyZ2V0IGFwcCBzaG91bGQgbmF2aWdhdGUgdG8gYWZ0ZXIgZXhjaGFuZ2UuIEVjaG9lZCBiYWNrLiAqL1xuICByb3V0ZT86IHN0cmluZztcbn1cblxuLyoqXG4gKiBSZXNwb25zZSBib2R5IGZyb20gYFBPU1QgL3YyL2F1dGgvaGFuZG9mZmAuXG4gKi9cbmV4cG9ydCBpbnRlcmZhY2UgSGFuZG9mZkNyZWF0ZVJlc3BvbnNlIHtcbiAgb3BlcmF0aW9uSWQ6IHN0cmluZztcbiAgLyoqIFJhdyB0b2tlbiB0byBlbWJlZCBpbiB0aGUgcmVkaXJlY3QgVVJMIGFzIGA/aGFuZG9mZj08dG9rZW4+YC4gMzBzIFRUTCwgc2luZ2xlLXVzZS4gKi9cbiAgdG9rZW46IHN0cmluZztcbiAgLyoqIFJGQzMzMzkgZXhwaXJhdGlvbiB0aW1lc3RhbXAuICovXG4gIGV4cGlyZXNBdDogc3RyaW5nO1xuICAvKiogRWNob2VkIGByb3V0ZWAgZnJvbSB0aGUgcmVxdWVzdCwgd2hlbiBwcm92aWRlZC4gKi9cbiAgcm91dGU/OiBzdHJpbmc7XG59XG5cbi8qKlxuICogUmVzcG9uc2UgYm9keSBmcm9tIGBQT1NUIC92Mi9hdXRoL2hhbmRvZmYvZXhjaGFuZ2VgLlxuICpcbiAqIFNhbWUgc2hhcGUgYXMgYFNpZ25pblJlc3BvbnNlYCDigJQgaW5zdGFsbGFibGUgdmlhIGBBdXRoU2VydmljZS5zZXRFeHRlcm5hbEF1dGhgLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIEhhbmRvZmZFeGNoYW5nZVJlc3BvbnNlIHtcbiAgb3BlcmF0aW9uSWQ6IHN0cmluZztcbiAgYWNjZXNzVG9rZW46IHN0cmluZztcbiAgcmVmcmVzaFRva2VuOiBzdHJpbmc7XG4gIGZpcmViYXNlVG9rZW4/OiBzdHJpbmc7XG4gIGV4cGlyZXNJbjogbnVtYmVyO1xuICB0b2tlblR5cGU6IHN0cmluZztcbiAgdXNlcklkOiBzdHJpbmc7XG59XG5cbi8qKlxuICogSGFuZG9mZlNlcnZpY2Ug4oCUIGNyb3NzLWFwcCBzZXNzaW9uIHRyYW5zZmVyLlxuICpcbiAqIEltcGxlbWVudHMgdGhlIE9BdXRoIEF1dGhvcml6YXRpb24gQ29kZSBwYXR0ZXJuLCBhcHBsaWVkIGludGVybmFsbHkgYmV0d2VlblxuICogYXBwcyB0aGF0IHNoYXJlIHRoZSBzYW1lIGJhY2tlbmQuXG4gKlxuICogKipPcmlnaW4gYXBwICh1c2VyIGlzIGF1dGhlbnRpY2F0ZWQpOioqXG4gKlxuICogYGBgdHlwZXNjcmlwdFxuICogY29uc3QgeyB0b2tlbiwgcm91dGUgfSA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKFxuICogICBoYW5kb2ZmLmNyZWF0ZUhhbmRvZmYoeyB0YXJnZXRBcHBJZDogJ215dmFsdGVjaCcsIHJvdXRlOiAnL2FwcC9kYXNoYm9hcmQnIH0pXG4gKiApO1xuICogd2luZG93LmxvY2F0aW9uLmhyZWYgPSBgaHR0cHM6Ly9teXZhbHRlY2guYXBwLz9oYW5kb2ZmPSR7dG9rZW59JnJvdXRlPSR7ZW5jb2RlVVJJQ29tcG9uZW50KHJvdXRlID8/ICcvJyl9YDtcbiAqIGBgYFxuICpcbiAqICoqVGFyZ2V0IGFwcCAoYm9vdCk6KiogY2FsbCBgZXhjaGFuZ2VIYW5kb2ZmKHRva2VuKWAuIE9uIHN1Y2Nlc3MsIHRoZSBzZXNzaW9uXG4gKiBpcyBpbnN0YWxsZWQgKGBBdXRoU2VydmljZS5zZXRFeHRlcm5hbEF1dGhgKSBhbmQgdGhlIHVzZXIgaXMgYXV0aGVudGljYXRlZC5cbiAqIFNlZSBgZGV0ZWN0QW5kRXhjaGFuZ2VIYW5kb2ZmYCBoZWxwZXIgZm9yIHRoZSB0eXBpY2FsIGJvb3RzdHJhcCBwYXR0ZXJuLlxuICpcbiAqIFNlY3VyaXR5IG5vdGVzOlxuICogLSBUb2tlbiBpcyBzaW5nbGUtdXNlIGFuZCBzaG9ydC1saXZlZCAoMzBzKSDigJQgZW5mb3JjZWQgc2VydmVyLXNpZGUuXG4gKiAtIFRva2VuIGluIFVSTCBtdXN0IGJlIHJlbW92ZWQgZnJvbSBoaXN0b3J5IGFmdGVyIGV4Y2hhbmdlIHRvIGF2b2lkIGxvZyBsZWFrYWdlLlxuICogLSBUaGUgZXhjaGFuZ2UgZW5kcG9pbnQgaXMgcHVibGljOyBkbyBOT1QgYWRkIGF1dGggaGVhZGVyLiBUaGVcbiAqICAgYEh0dHBDbGllbnRgIHJlcXVlc3QgYmVsb3cgYXZvaWRzIHRyaWdnZXJpbmcgdGhlIGF1dGggaW50ZXJjZXB0b3Igc2luY2UgdGhlXG4gKiAgIHVzZXIgaXNuJ3QgbG9nZ2VkIGluIHlldCBvbiB0aGUgdGFyZ2V0IGFwcC5cbiAqL1xuQEluamVjdGFibGUoeyBwcm92aWRlZEluOiAncm9vdCcgfSlcbmV4cG9ydCBjbGFzcyBIYW5kb2ZmU2VydmljZSB7XG4gIHByaXZhdGUgZGV0ZWN0ZWQgPSBmYWxzZTtcblxuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KFZBTFRFQ0hfQVVUSF9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBWYWx0ZWNoQXV0aENvbmZpZyxcbiAgICBwcml2YXRlIGh0dHA6IEh0dHBDbGllbnQsXG4gICAgcHJpdmF0ZSBhdXRoOiBBdXRoU2VydmljZSxcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyXG4gICkge31cblxuICAvKipcbiAgICogQ3JlYXRlIGEgaGFuZG9mZiB0b2tlbi4gQ2FsbGVyIG11c3QgYmUgYXV0aGVudGljYXRlZC5cbiAgICpcbiAgICogQHBhcmFtIHJlcXVlc3QgT3B0aW9uYWwgbWV0YWRhdGE6IHRhcmdldCBhcHAgaWQgYW5kIGludGVuZGVkIHJvdXRlLlxuICAgKiBAcmV0dXJucyBPYnNlcnZhYmxlIGVtaXR0aW5nIGB7IHRva2VuLCBleHBpcmVzQXQsIHJvdXRlPyB9YC5cbiAgICovXG4gIGNyZWF0ZUhhbmRvZmYocmVxdWVzdDogSGFuZG9mZkNyZWF0ZVJlcXVlc3QgPSB7fSk6IE9ic2VydmFibGU8SGFuZG9mZkNyZWF0ZVJlc3BvbnNlPiB7XG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wb3N0PEhhbmRvZmZDcmVhdGVSZXNwb25zZT4oYCR7dGhpcy5iYXNlVXJsfS9oYW5kb2ZmYCwgcmVxdWVzdCk7XG4gIH1cblxuICAvKipcbiAgICogRXhjaGFuZ2UgYSBoYW5kb2ZmIHRva2VuIGZvciBhIHNlc3Npb24gYW5kIGluc3RhbGwgaXQuXG4gICAqXG4gICAqIE9uIHN1Y2Nlc3MsIHRoZSByZXNwb25zZSBpcyBwaXBlZCB0aHJvdWdoIGBBdXRoU2VydmljZS5zZXRFeHRlcm5hbEF1dGhgXG4gICAqIHNvIHRoZSB1c2VyIGJlY29tZXMgYXV0aGVudGljYXRlZC4gU3Vic2VxdWVudCBuYXZpZ2F0aW9uIGNhbiBwcm9jZWVkLlxuICAgKlxuICAgKiBPbiBmYWlsdXJlLCB0aGUgb2JzZXJ2YWJsZSBlcnJvcnMuIFRoZSBjYWxsZXIgaXMgcmVzcG9uc2libGUgZm9yXG4gICAqIHNob3dpbmcgYW4gZXJyb3IgYW5kIHJvdXRpbmcgdG8gYC9sb2dpbmAuXG4gICAqXG4gICAqIEBwYXJhbSB0b2tlbiBSYXcgaGFuZG9mZiB0b2tlbiByZWFkIGZyb20gdGhlIFVSTC5cbiAgICovXG4gIGV4Y2hhbmdlSGFuZG9mZih0b2tlbjogc3RyaW5nKTogT2JzZXJ2YWJsZTxIYW5kb2ZmRXhjaGFuZ2VSZXNwb25zZT4ge1xuICAgIHJldHVybiB0aGlzLmh0dHBcbiAgICAgIC5wb3N0PEhhbmRvZmZFeGNoYW5nZVJlc3BvbnNlPihgJHt0aGlzLmJhc2VVcmx9L2hhbmRvZmYvZXhjaGFuZ2VgLCB7IHRva2VuIH0pXG4gICAgICAucGlwZShcbiAgICAgICAgdGFwKHJlc3BvbnNlID0+IHRoaXMuaW5zdGFsbFNlc3Npb24ocmVzcG9uc2UpKSxcbiAgICAgICAgY2F0Y2hFcnJvcihlcnIgPT4ge1xuICAgICAgICAgIC8vIFN1cmZhY2UgdGhlIGVycm9yIHVudG91Y2hlZCDigJQgdGhlIGNhbGxlciBkZWNpZGVzIGhvdyB0byByZWFjdFxuICAgICAgICAgIC8vICh0eXBpY2FsbHk6IHJlZGlyZWN0IHRvIC9sb2dpbiArIHRvYXN0KS4gRG9uJ3QgaW5zdGFsbCBhIGJhZCBzZXNzaW9uLlxuICAgICAgICAgIHRocm93IGVycjtcbiAgICAgICAgfSlcbiAgICAgICk7XG4gIH1cblxuICAvKipcbiAgICogQm9vdHN0cmFwIGhlbHBlciDigJQgcmVhZHMgdGhlIGhhbmRvZmYgdG9rZW4gZnJvbSB0aGUgY3VycmVudCBVUkwsIGV4Y2hhbmdlc1xuICAgKiBpdCBmb3IgYSBzZXNzaW9uLCBhbmQgbmF2aWdhdGVzIHRvIHRoZSBpbnRlbmRlZCByb3V0ZSB3aXRoIHRoZSB0b2tlblxuICAgKiBzdHJpcHBlZCBmcm9tIGhpc3RvcnkuXG4gICAqXG4gICAqIElkZW1wb3RlbnQ6IHN1YnNlcXVlbnQgY2FsbHMgYXJlIG5vLW9wcy4gV2lyZSBmcm9tIGFuXG4gICAqIGBBUFBfSU5JVElBTElaRVJgL2Bwcm92aWRlQXBwSW5pdGlhbGl6ZXJgIGZhY3RvcnkgaW4gYG1haW4udHNgLlxuICAgKlxuICAgKiBgYGB0eXBlc2NyaXB0XG4gICAqIC8vIG1haW4udHNcbiAgICogcHJvdmlkZUFwcEluaXRpYWxpemVyKCgpID0+IGluamVjdChIYW5kb2ZmU2VydmljZSkuZGV0ZWN0QW5kRXhjaGFuZ2VIYW5kb2ZmKCkpXG4gICAqIGBgYFxuICAgKlxuICAgKiBPbiBlcnJvciAoZXhwaXJlZC91c2VkL2ludmFsaWQgdG9rZW4pLCByZWRpcmVjdHMgdG8gYGVycm9yUm91dGVgIChkZWZhdWx0OlxuICAgKiB0aGUgYXBwJ3MgY29uZmlndXJlZCBgbG9naW5Sb3V0ZWApLiBUaGUgVVJMIGlzIGFsd2F5cyBjbGVhbmVkLCBldmVuIG9uXG4gICAqIGVycm9yLCBzbyB0aGUgdG9rZW4gY2Fubm90IGJlIHJldHJpZWQgYnkgcmVmcmVzaGluZyB0aGUgcGFnZS5cbiAgICpcbiAgICogQHJldHVybnMgYHRydWVgIGlmIGEgaGFuZG9mZiB3YXMgZGV0ZWN0ZWQgYW5kIHByb2Nlc3NlZCAoc3VjY2VzcyBvciBmYWlsKS5cbiAgICogICAgICAgICAgYGZhbHNlYCBpZiBubyB0b2tlbiB3YXMgcHJlc2VudCAoY29sZCBib290LCBub3JtYWwgZmxvdykuXG4gICAqL1xuICBhc3luYyBkZXRlY3RBbmRFeGNoYW5nZUhhbmRvZmYob3B0aW9uczogRGV0ZWN0QW5kRXhjaGFuZ2VPcHRpb25zID0ge30pOiBQcm9taXNlPGJvb2xlYW4+IHtcbiAgICBpZiAodGhpcy5kZXRlY3RlZCB8fCB0eXBlb2Ygd2luZG93ID09PSAndW5kZWZpbmVkJykge1xuICAgICAgcmV0dXJuIGZhbHNlO1xuICAgIH1cbiAgICB0aGlzLmRldGVjdGVkID0gdHJ1ZTtcblxuICAgIGNvbnN0IHRva2VuUGFyYW0gPSBvcHRpb25zLnRva2VuUGFyYW0gPz8gSEFORE9GRl9UT0tFTl9QQVJBTTtcbiAgICBjb25zdCByb3V0ZVBhcmFtID0gb3B0aW9ucy5yb3V0ZVBhcmFtID8/IEhBTkRPRkZfUk9VVEVfUEFSQU07XG4gICAgY29uc3QgZGVmYXVsdFJvdXRlID0gb3B0aW9ucy5kZWZhdWx0Um91dGUgPz8gJy8nO1xuICAgIGNvbnN0IGVycm9yUm91dGUgPSBvcHRpb25zLmVycm9yUm91dGUgPz8gdGhpcy5jb25maWcubG9naW5Sb3V0ZSA/PyAnL2xvZ2luJztcblxuICAgIGNvbnN0IHBhcmFtcyA9IG5ldyBVUkxTZWFyY2hQYXJhbXMod2luZG93LmxvY2F0aW9uLnNlYXJjaCk7XG4gICAgY29uc3QgdG9rZW4gPSBwYXJhbXMuZ2V0KHRva2VuUGFyYW0pO1xuICAgIGlmICghdG9rZW4pIHtcbiAgICAgIHJldHVybiBmYWxzZTtcbiAgICB9XG5cbiAgICBjb25zdCB0YXJnZXRSb3V0ZSA9IHBhcmFtcy5nZXQocm91dGVQYXJhbSkgfHwgZGVmYXVsdFJvdXRlO1xuXG4gICAgdHJ5IHtcbiAgICAgIGF3YWl0IGZpcnN0VmFsdWVGcm9tKHRoaXMuZXhjaGFuZ2VIYW5kb2ZmKHRva2VuKSk7XG4gICAgICBhd2FpdCB0aGlzLnJvdXRlci5uYXZpZ2F0ZUJ5VXJsKHRhcmdldFJvdXRlLCB7IHJlcGxhY2VVcmw6IHRydWUgfSk7XG4gICAgfSBjYXRjaCAoZXJyKSB7XG4gICAgICBjb25zb2xlLndhcm4oJ1tIYW5kb2ZmXSBFeGNoYW5nZSBmYWlsZWQsIHJlZGlyZWN0aW5nIHRvIGxvZ2luJywgZXJyKTtcbiAgICAgIGF3YWl0IHRoaXMucm91dGVyLm5hdmlnYXRlQnlVcmwoZXJyb3JSb3V0ZSwgeyByZXBsYWNlVXJsOiB0cnVlIH0pO1xuICAgIH1cblxuICAgIHJldHVybiB0cnVlO1xuICB9XG5cbiAgLyoqXG4gICAqIFBlcnNpc3QgdGhlIHNlc3Npb24gaW4gYEF1dGhTZXJ2aWNlYC4gTWlycm9ycyB0aGUgaW5zdGFsbCBmbG93IHVzZWQgYnlcbiAgICogdGhlIG5vcm1hbCBzaWduaW4gcGF0aCBzbyB0aW1lcnMsIEZpcmViYXNlLCBhbmQgdGFiLXN5bmMgYWxsIGtpY2sgaW4uXG4gICAqL1xuICBwcml2YXRlIGluc3RhbGxTZXNzaW9uKHJlc3BvbnNlOiBIYW5kb2ZmRXhjaGFuZ2VSZXNwb25zZSk6IHZvaWQge1xuICAgIHRoaXMuYXV0aC5zZXRFeHRlcm5hbEF1dGgoe1xuICAgICAgYWNjZXNzVG9rZW46IHJlc3BvbnNlLmFjY2Vzc1Rva2VuLFxuICAgICAgcmVmcmVzaFRva2VuOiByZXNwb25zZS5yZWZyZXNoVG9rZW4sXG4gICAgICBmaXJlYmFzZVRva2VuOiByZXNwb25zZS5maXJlYmFzZVRva2VuLFxuICAgICAgZXhwaXJlc0luOiByZXNwb25zZS5leHBpcmVzSW4sXG4gICAgfSk7XG4gIH1cblxuICBwcml2YXRlIGdldCBiYXNlVXJsKCk6IHN0cmluZyB7XG4gICAgcmV0dXJuIGAke3RoaXMuY29uZmlnLmFwaVVybH0ke3RoaXMuY29uZmlnLmF1dGhQcmVmaXh9YDtcbiAgfVxufVxuIl19
|
|
@@ -89,4 +89,10 @@ export { SessionService } from './session.service';
|
|
|
89
89
|
// OAuth (Login social)
|
|
90
90
|
export { OAuthService } from './oauth.service';
|
|
91
91
|
export { OAuthCallbackComponent } from './oauth-callback.component';
|
|
92
|
-
|
|
92
|
+
// Cross-app session handoff (OAuth Authorization Code pattern internal)
|
|
93
|
+
export { HandoffService, HANDOFF_TOKEN_PARAM, HANDOFF_ROUTE_PARAM } from './handoff.service';
|
|
94
|
+
// Active organization switch orchestration
|
|
95
|
+
export { OrgSwitchService } from './org-switch.service';
|
|
96
|
+
// Cross-app cross-org notification click handler
|
|
97
|
+
export { NotificationActionService } from './notification-action.service';
|
|
98
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi8uLi8uLi8uLi8uLi9zcmMvbGliL3NlcnZpY2VzL2F1dGgvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUE7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7OztHQXFFRztBQUVILFFBQVE7QUFDUixjQUFjLFNBQVMsQ0FBQztBQUV4QixnQkFBZ0I7QUFDaEIsT0FBTyxFQUNMLG1CQUFtQixFQUNuQixrQkFBa0IsRUFDbEIsNkJBQTZCLEVBQzdCLG1CQUFtQixHQUNwQixNQUFNLFVBQVUsQ0FBQztBQUVsQixxQkFBcUI7QUFDckIsT0FBTyxFQUFFLFdBQVcsRUFBRSxNQUFNLGdCQUFnQixDQUFDO0FBRTdDLFNBQVM7QUFDVCxPQUFPLEVBQ0wsU0FBUyxFQUNULFVBQVUsRUFDVixlQUFlLEVBQ2Ysd0JBQXdCLEVBQ3hCLGVBQWUsRUFDZixTQUFTLEdBQ1YsTUFBTSxVQUFVLENBQUM7QUFFbEIsa0NBQWtDO0FBQ2xDLE9BQU8sRUFBRSxlQUFlLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFaEQsZ0RBQWdEO0FBQ2hELE9BQU8sRUFBRSxnQkFBZ0IsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3hELE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSxtQkFBbUIsQ0FBQztBQUN2RCxPQUFPLEVBQUUsZUFBZSxFQUFFLE1BQU0sZ0JBQWdCLENBQUM7QUFFakQsa0RBQWtEO0FBQ2xELE9BQU8sRUFBRSxhQUFhLEVBQUUsTUFBTSxrQkFBa0IsQ0FBQztBQUNqRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sbUJBQW1CLENBQUM7QUFFbkQsdUJBQXVCO0FBQ3ZCLE9BQU8sRUFBRSxZQUFZLEVBQUUsTUFBTSxpQkFBaUIsQ0FBQztBQUMvQyxPQUFPLEVBQUUsc0JBQXNCLEVBQUUsTUFBTSw0QkFBNEIsQ0FBQztBQUVwRSx3RUFBd0U7QUFDeEUsT0FBTyxFQUFFLGNBQWMsRUFBRSxtQkFBbUIsRUFBRSxtQkFBbUIsRUFBRSxNQUFNLG1CQUFtQixDQUFDO0FBUTdGLDJDQUEyQztBQUMzQyxPQUFPLEVBQUUsZ0JBQWdCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUd4RCxpREFBaUQ7QUFDakQsT0FBTyxFQUFFLHlCQUF5QixFQUFFLE1BQU0sK0JBQStCLENBQUMiLCJzb3VyY2VzQ29udGVudCI6WyIvKipcbiAqIFZhbHRlY2ggQXV0aCBTZXJ2aWNlXG4gKlxuICogU2VydmljaW8gZGUgYXV0ZW50aWNhY2nDs24gcmV1dGlsaXphYmxlIHBhcmEgYXBsaWNhY2lvbmVzIEFuZ3VsYXIuXG4gKiBQcm9wb3JjaW9uYSBhdXRlbnRpY2FjacOzbiBjb24gQXV0aFYyLCBNRkEsIHNpbmNyb25pemFjacOzbiBlbnRyZSBwZXN0YcOxYXMsXG4gKiByZWZyZXNoIHByb2FjdGl2byBkZSB0b2tlbnMsIHkgcmVnaXN0cm8gYXV0b23DoXRpY28gZGUgZGlzcG9zaXRpdm9zIHBhcmFcbiAqIHB1c2ggbm90aWZpY2F0aW9ucy5cbiAqXG4gKiBAZXhhbXBsZVxuICogYGBgdHlwZXNjcmlwdFxuICogLy8gRW4gbWFpbi50c1xuICogaW1wb3J0IHsgYm9vdHN0cmFwQXBwbGljYXRpb24gfSBmcm9tICdAYW5ndWxhci9wbGF0Zm9ybS1icm93c2VyJztcbiAqIGltcG9ydCB7IHByb3ZpZGVWYWx0ZWNoQXV0aCwgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZSB9IGZyb20gJ3ZhbHRlY2gtY29tcG9uZW50cyc7XG4gKiBpbXBvcnQgeyBlbnZpcm9ubWVudCB9IGZyb20gJy4vZW52aXJvbm1lbnRzL2Vudmlyb25tZW50JztcbiAqXG4gKiBib290c3RyYXBBcHBsaWNhdGlvbihBcHBDb21wb25lbnQsIHtcbiAqICAgcHJvdmlkZXJzOiBbXG4gKiAgICAgcHJvdmlkZVZhbHRlY2hGaXJlYmFzZShlbnZpcm9ubWVudC5maXJlYmFzZSksXG4gKiAgICAgcHJvdmlkZVZhbHRlY2hBdXRoKHtcbiAqICAgICAgIGFwaVVybDogZW52aXJvbm1lbnQuYXBpVXJsLFxuICogICAgICAgZW5hYmxlRmlyZWJhc2VJbnRlZ3JhdGlvbjogdHJ1ZSxcbiAqICAgICAgIGVuYWJsZURldmljZVJlZ2lzdHJhdGlvbjogdHJ1ZSwgLy8gQXV0by1yZWdpc3RyYSBkaXNwb3NpdGl2b3MgcGFyYSBwdXNoXG4gKiAgICAgfSksXG4gKiAgIF0sXG4gKiB9KTtcbiAqXG4gKiAvLyBFbiBhcHAucm91dGVzLnRzXG4gKiBpbXBvcnQgeyBhdXRoR3VhcmQsIGd1ZXN0R3VhcmQsIHBlcm1pc3Npb25HdWFyZCB9IGZyb20gJ3ZhbHRlY2gtY29tcG9uZW50cyc7XG4gKlxuICogY29uc3Qgcm91dGVzOiBSb3V0ZXMgPSBbXG4gKiAgIHsgcGF0aDogJ2xvZ2luJywgY2FuQWN0aXZhdGU6IFtndWVzdEd1YXJkXSwgbG9hZENvbXBvbmVudDogKCkgPT4gaW1wb3J0KCcuL2xvZ2luLnBhZ2UnKSB9LFxuICogICB7IHBhdGg6ICdkYXNoYm9hcmQnLCBjYW5BY3RpdmF0ZTogW2F1dGhHdWFyZF0sIGxvYWRDb21wb25lbnQ6ICgpID0+IGltcG9ydCgnLi9kYXNoYm9hcmQucGFnZScpIH0sXG4gKiAgIHsgcGF0aDogJ2FkbWluJywgY2FuQWN0aXZhdGU6IFthdXRoR3VhcmQsIHBlcm1pc3Npb25HdWFyZCgnYWRtaW46KicpXSwgbG9hZENvbXBvbmVudDogKCkgPT4gaW1wb3J0KCcuL2FkbWluLnBhZ2UnKSB9LFxuICogXTtcbiAqXG4gKiAvLyBFbiBjb21wb25lbnRlc1xuICogaW1wb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICd2YWx0ZWNoLWNvbXBvbmVudHMnO1xuICpcbiAqIEBDb21wb25lbnQoey4uLn0pXG4gKiBleHBvcnQgY2xhc3MgTG9naW5Db21wb25lbnQge1xuICogICBwcml2YXRlIGF1dGggPSBpbmplY3QoQXV0aFNlcnZpY2UpO1xuICpcbiAqICAgYXN5bmMgbG9naW4oKSB7XG4gKiAgICAgYXdhaXQgZmlyc3RWYWx1ZUZyb20odGhpcy5hdXRoLnNpZ25pbih7IGVtYWlsLCBwYXNzd29yZCB9KSk7XG4gKiAgICAgaWYgKHRoaXMuYXV0aC5tZmFQZW5kaW5nKCkucmVxdWlyZWQpIHtcbiAqICAgICAgIC8vIE1vc3RyYXIgVUkgZGUgTUZBXG4gKiAgICAgfSBlbHNlIHtcbiAqICAgICAgIHRoaXMucm91dGVyLm5hdmlnYXRlKFsnL2Rhc2hib2FyZCddKTtcbiAqICAgICB9XG4gKiAgIH1cbiAqXG4gKiAgIC8vIEhhYmlsaXRhciBub3RpZmljYWNpb25lcyBwdXNoIChzb2xpY2l0YSBwZXJtaXNvcyArIHJlZ2lzdHJhIGRpc3Bvc2l0aXZvKVxuICogICBhc3luYyBlbmFibGVOb3RpZmljYXRpb25zKCkge1xuICogICAgIGNvbnN0IHJlc3VsdCA9IGF3YWl0IHRoaXMuYXV0aC5lbmFibGVOb3RpZmljYXRpb25zKCk7XG4gKiAgICAgaWYgKHJlc3VsdC5ncmFudGVkKSB7XG4gKiAgICAgICBjb25zb2xlLmxvZygnTm90aWZpY2FjaW9uZXMgaGFiaWxpdGFkYXMnKTtcbiAqICAgICB9XG4gKiAgIH1cbiAqXG4gKiAgIC8vIFZlcmlmaWNhciBlc3RhZG8gZGUgcGVybWlzb3NcbiAqICAgZ2V0IGNhblJlY2VpdmVOb3RpZmljYXRpb25zKCk6IGJvb2xlYW4ge1xuICogICAgIHJldHVybiB0aGlzLmF1dGguZ2V0Tm90aWZpY2F0aW9uUGVybWlzc2lvblN0YXRlKCkgPT09ICdncmFudGVkJztcbiAqICAgfVxuICpcbiAqICAgLy8gRW4gdGVtcGxhdGU6IHVzYXIgc2lnbmFscyBkaXJlY3RhbWVudGVcbiAqICAgLy8ge3sgYXV0aC51c2VyKCk/LmVtYWlsIH19XG4gKiAgIC8vIEBpZiAoYXV0aC5oYXNQZXJtaXNzaW9uKCd0ZW1wbGF0ZXM6ZWRpdCcpKSB7IC4uLiB9XG4gKiB9XG4gKiBgYGBcbiAqL1xuXG4vLyBUaXBvc1xuZXhwb3J0ICogZnJvbSAnLi90eXBlcyc7XG5cbi8vIENvbmZpZ3VyYWNpw7NuXG5leHBvcnQge1xuICBWQUxURUNIX0FVVEhfQ09ORklHLFxuICBwcm92aWRlVmFsdGVjaEF1dGgsXG4gIHByb3ZpZGVWYWx0ZWNoQXV0aEludGVyY2VwdG9yLFxuICBERUZBVUxUX0FVVEhfQ09ORklHLFxufSBmcm9tICcuL2NvbmZpZyc7XG5cbi8vIFNlcnZpY2lvIHByaW5jaXBhbFxuZXhwb3J0IHsgQXV0aFNlcnZpY2UgfSBmcm9tICcuL2F1dGguc2VydmljZSc7XG5cbi8vIEd1YXJkc1xuZXhwb3J0IHtcbiAgYXV0aEd1YXJkLFxuICBndWVzdEd1YXJkLFxuICBwZXJtaXNzaW9uR3VhcmQsXG4gIHBlcm1pc3Npb25HdWFyZEZyb21Sb3V0ZSxcbiAgc3VwZXJBZG1pbkd1YXJkLFxuICByb2xlR3VhcmQsXG59IGZyb20gJy4vZ3VhcmRzJztcblxuLy8gSW50ZXJjZXB0b3IgKHBhcmEgdXNvIGF2YW56YWRvKVxuZXhwb3J0IHsgYXV0aEludGVyY2VwdG9yIH0gZnJvbSAnLi9pbnRlcmNlcHRvcic7XG5cbi8vIFNlcnZpY2lvcyBpbnRlcm5vcyAocGFyYSB0ZXN0aW5nIG8gZXh0ZW5zacOzbilcbmV4cG9ydCB7IEF1dGhTdGF0ZVNlcnZpY2UgfSBmcm9tICcuL2F1dGgtc3RhdGUuc2VydmljZSc7XG5leHBvcnQgeyBUb2tlblNlcnZpY2UgfSBmcm9tICcuL3Rva2VuLnNlcnZpY2UnO1xuZXhwb3J0IHsgQXV0aFN0b3JhZ2VTZXJ2aWNlIH0gZnJvbSAnLi9zdG9yYWdlLnNlcnZpY2UnO1xuZXhwb3J0IHsgQXV0aFN5bmNTZXJ2aWNlIH0gZnJvbSAnLi9zeW5jLnNlcnZpY2UnO1xuXG4vLyBTZXJ2aWNpb3MgZGUgZ2VzdGnDs24gZGUgZGlzcG9zaXRpdm9zIHkgc2VzaW9uZXNcbmV4cG9ydCB7IERldmljZVNlcnZpY2UgfSBmcm9tICcuL2RldmljZS5zZXJ2aWNlJztcbmV4cG9ydCB7IFNlc3Npb25TZXJ2aWNlIH0gZnJvbSAnLi9zZXNzaW9uLnNlcnZpY2UnO1xuXG4vLyBPQXV0aCAoTG9naW4gc29jaWFsKVxuZXhwb3J0IHsgT0F1dGhTZXJ2aWNlIH0gZnJvbSAnLi9vYXV0aC5zZXJ2aWNlJztcbmV4cG9ydCB7IE9BdXRoQ2FsbGJhY2tDb21wb25lbnQgfSBmcm9tICcuL29hdXRoLWNhbGxiYWNrLmNvbXBvbmVudCc7XG5cbi8vIENyb3NzLWFwcCBzZXNzaW9uIGhhbmRvZmYgKE9BdXRoIEF1dGhvcml6YXRpb24gQ29kZSBwYXR0ZXJuIGludGVybmFsKVxuZXhwb3J0IHsgSGFuZG9mZlNlcnZpY2UsIEhBTkRPRkZfVE9LRU5fUEFSQU0sIEhBTkRPRkZfUk9VVEVfUEFSQU0gfSBmcm9tICcuL2hhbmRvZmYuc2VydmljZSc7XG5leHBvcnQgdHlwZSB7XG4gIEhhbmRvZmZDcmVhdGVSZXF1ZXN0LFxuICBIYW5kb2ZmQ3JlYXRlUmVzcG9uc2UsXG4gIEhhbmRvZmZFeGNoYW5nZVJlc3BvbnNlLFxuICBEZXRlY3RBbmRFeGNoYW5nZU9wdGlvbnMsXG59IGZyb20gJy4vaGFuZG9mZi5zZXJ2aWNlJztcblxuLy8gQWN0aXZlIG9yZ2FuaXphdGlvbiBzd2l0Y2ggb3JjaGVzdHJhdGlvblxuZXhwb3J0IHsgT3JnU3dpdGNoU2VydmljZSB9IGZyb20gJy4vb3JnLXN3aXRjaC5zZXJ2aWNlJztcbmV4cG9ydCB0eXBlIHsgT3JnQ2hhbmdlZEV2ZW50LCBTd2l0Y2hPcmdPcHRpb25zIH0gZnJvbSAnLi9vcmctc3dpdGNoLnNlcnZpY2UnO1xuXG4vLyBDcm9zcy1hcHAgY3Jvc3Mtb3JnIG5vdGlmaWNhdGlvbiBjbGljayBoYW5kbGVyXG5leHBvcnQgeyBOb3RpZmljYXRpb25BY3Rpb25TZXJ2aWNlIH0gZnJvbSAnLi9ub3RpZmljYXRpb24tYWN0aW9uLnNlcnZpY2UnO1xuZXhwb3J0IHR5cGUgeyBOb3RpZmljYXRpb25PcGVuUmVzdWx0IH0gZnJvbSAnLi9ub3RpZmljYXRpb24tYWN0aW9uLnNlcnZpY2UnO1xuIl19
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* NotificationActionService — orquesta el "click en notificación" cross-app cross-org.
|
|
3
|
+
*
|
|
4
|
+
* Flujo:
|
|
5
|
+
* 1. markAsRead (best-effort, no bloquea)
|
|
6
|
+
* 2. Si appId destino !== appId actual → handoff token + redirect a app destino
|
|
7
|
+
* 3. Si orgId destino !== activeOrg → switchTo(orgId) (sin reload, navega después)
|
|
8
|
+
* 4. router.navigateByUrl(actionRoute)
|
|
9
|
+
*
|
|
10
|
+
* Requiere:
|
|
11
|
+
* - ValtechAuthConfig.appId (identifica la app actual)
|
|
12
|
+
* - ValtechAuthConfig.appUrls (mapa baseUrl para handoff cross-app)
|
|
13
|
+
*/
|
|
14
|
+
import { HttpErrorResponse } from '@angular/common/http';
|
|
15
|
+
import { Inject, Injectable } from '@angular/core';
|
|
16
|
+
import { firstValueFrom } from 'rxjs';
|
|
17
|
+
import { VALTECH_AUTH_CONFIG } from './config';
|
|
18
|
+
import * as i0 from "@angular/core";
|
|
19
|
+
import * as i1 from "./auth.service";
|
|
20
|
+
import * as i2 from "./org-switch.service";
|
|
21
|
+
import * as i3 from "./handoff.service";
|
|
22
|
+
import * as i4 from "../firebase/notifications.service";
|
|
23
|
+
import * as i5 from "@angular/router";
|
|
24
|
+
export class NotificationActionService {
|
|
25
|
+
constructor(config, auth, orgSwitch, handoff, notifications, router) {
|
|
26
|
+
this.config = config;
|
|
27
|
+
this.auth = auth;
|
|
28
|
+
this.orgSwitch = orgSwitch;
|
|
29
|
+
this.handoff = handoff;
|
|
30
|
+
this.notifications = notifications;
|
|
31
|
+
this.router = router;
|
|
32
|
+
}
|
|
33
|
+
/**
|
|
34
|
+
* Abre la notificación: marca como leída, switch-org si toca, navegación local o
|
|
35
|
+
* redirect cross-app vía handoff.
|
|
36
|
+
*
|
|
37
|
+
* No lanza errores hacia la UI — devuelve un resultado descriptivo. Errores
|
|
38
|
+
* técnicos quedan en console.warn.
|
|
39
|
+
*/
|
|
40
|
+
async open(notif) {
|
|
41
|
+
// 1) Mark as read (best-effort, no bloquea el flujo principal)
|
|
42
|
+
if (notif.id && !notif.isRead) {
|
|
43
|
+
this.notifications.markAsRead(notif.id).catch(err => {
|
|
44
|
+
console.warn('[NotificationAction] markAsRead failed', err);
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
const route = notif.actionRoute;
|
|
48
|
+
if (!route) {
|
|
49
|
+
return 'no-action-route';
|
|
50
|
+
}
|
|
51
|
+
const currentApp = this.config.appId;
|
|
52
|
+
const targetApp = notif.appId;
|
|
53
|
+
// 2) Cross-app: handoff + full redirect
|
|
54
|
+
if (targetApp && currentApp && targetApp !== currentApp) {
|
|
55
|
+
const baseUrl = this.config.appUrls?.[targetApp];
|
|
56
|
+
if (!baseUrl) {
|
|
57
|
+
console.warn(`[NotificationAction] Missing appUrls['${targetApp}'] — configure ValtechAuthConfig.appUrls`);
|
|
58
|
+
return 'cross-app-unconfigured';
|
|
59
|
+
}
|
|
60
|
+
try {
|
|
61
|
+
const resp = await firstValueFrom(this.handoff.createHandoff({ targetAppId: targetApp, route }));
|
|
62
|
+
const url = this.buildHandoffUrl(baseUrl, resp.token, route);
|
|
63
|
+
if (typeof window !== 'undefined') {
|
|
64
|
+
window.location.href = url;
|
|
65
|
+
}
|
|
66
|
+
return 'redirected-cross-app';
|
|
67
|
+
}
|
|
68
|
+
catch (err) {
|
|
69
|
+
const msg = err instanceof HttpErrorResponse ? err.message : String(err);
|
|
70
|
+
console.warn('[NotificationAction] createHandoff failed:', msg);
|
|
71
|
+
return 'handoff-failed';
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
// 3) Same app — switch-org si toca (sin reload — la navegación posterior monta page fresh)
|
|
75
|
+
let switched = false;
|
|
76
|
+
if (notif.orgId) {
|
|
77
|
+
const active = this.activeOrg();
|
|
78
|
+
if (active && active !== notif.orgId) {
|
|
79
|
+
await this.orgSwitch.switchTo(notif.orgId);
|
|
80
|
+
switched = true;
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
// 4) Navigate local
|
|
84
|
+
await this.router.navigateByUrl(route);
|
|
85
|
+
return switched ? 'navigated-after-switch-org' : 'navigated';
|
|
86
|
+
}
|
|
87
|
+
activeOrg() {
|
|
88
|
+
const user = this.auth.user();
|
|
89
|
+
return (user?.activeOrgId ??
|
|
90
|
+
user?.activeOrg ??
|
|
91
|
+
'');
|
|
92
|
+
}
|
|
93
|
+
/**
|
|
94
|
+
* Construye URL absoluta para handoff cross-app preservando pathname y otros
|
|
95
|
+
* params existentes de la baseUrl.
|
|
96
|
+
*/
|
|
97
|
+
buildHandoffUrl(baseUrl, token, route) {
|
|
98
|
+
const url = new URL(baseUrl);
|
|
99
|
+
url.searchParams.set('handoff', token);
|
|
100
|
+
url.searchParams.set('route', route);
|
|
101
|
+
return url.toString();
|
|
102
|
+
}
|
|
103
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, deps: [{ token: VALTECH_AUTH_CONFIG }, { token: i1.AuthService }, { token: i2.OrgSwitchService }, { token: i3.HandoffService }, { token: i4.NotificationsService }, { token: i5.Router }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
104
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, providedIn: 'root' }); }
|
|
105
|
+
}
|
|
106
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: NotificationActionService, decorators: [{
|
|
107
|
+
type: Injectable,
|
|
108
|
+
args: [{ providedIn: 'root' }]
|
|
109
|
+
}], ctorParameters: () => [{ type: undefined, decorators: [{
|
|
110
|
+
type: Inject,
|
|
111
|
+
args: [VALTECH_AUTH_CONFIG]
|
|
112
|
+
}] }, { type: i1.AuthService }, { type: i2.OrgSwitchService }, { type: i3.HandoffService }, { type: i4.NotificationsService }, { type: i5.Router }] });
|
|
113
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLWFjdGlvbi5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9hdXRoL25vdGlmaWNhdGlvbi1hY3Rpb24uc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7Ozs7Ozs7Ozs7O0dBWUc7QUFFSCxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsTUFBTSxzQkFBc0IsQ0FBQztBQUN6RCxPQUFPLEVBQUUsTUFBTSxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUVuRCxPQUFPLEVBQUUsY0FBYyxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBR3RDLE9BQU8sRUFBRSxtQkFBbUIsRUFBRSxNQUFNLFVBQVUsQ0FBQzs7Ozs7OztBQWdCL0MsTUFBTSxPQUFPLHlCQUF5QjtJQUNwQyxZQUN1QyxNQUF5QixFQUN0RCxJQUFpQixFQUNqQixTQUEyQixFQUMzQixPQUF1QixFQUN2QixhQUFtQyxFQUNuQyxNQUFjO1FBTGUsV0FBTSxHQUFOLE1BQU0sQ0FBbUI7UUFDdEQsU0FBSSxHQUFKLElBQUksQ0FBYTtRQUNqQixjQUFTLEdBQVQsU0FBUyxDQUFrQjtRQUMzQixZQUFPLEdBQVAsT0FBTyxDQUFnQjtRQUN2QixrQkFBYSxHQUFiLGFBQWEsQ0FBc0I7UUFDbkMsV0FBTSxHQUFOLE1BQU0sQ0FBUTtJQUNyQixDQUFDO0lBRUo7Ozs7OztPQU1HO0lBQ0gsS0FBSyxDQUFDLElBQUksQ0FBQyxLQUEyQjtRQUNwQywrREFBK0Q7UUFDL0QsSUFBSSxLQUFLLENBQUMsRUFBRSxJQUFJLENBQUMsS0FBSyxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzlCLElBQUksQ0FBQyxhQUFhLENBQUMsVUFBVSxDQUFDLEtBQUssQ0FBQyxFQUFFLENBQUMsQ0FBQyxLQUFLLENBQUMsR0FBRyxDQUFDLEVBQUU7Z0JBQ2xELE9BQU8sQ0FBQyxJQUFJLENBQUMsd0NBQXdDLEVBQUUs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Q0FBQyxHQUFHLENBQUMsU0FBUyxFQUFFLEtBQUssQ0FBQyxDQUFDO1FBQ3ZDLEdBQUcsQ0FBQyxZQUFZLENBQUMsR0FBRyxDQUFDLE9BQU8sRUFBRSxLQUFLLENBQUMsQ0FBQztRQUNyQyxPQUFPLEdBQUcsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUN4QixDQUFDOytHQTVGVSx5QkFBeUIsa0JBRTFCLG1CQUFtQjttSEFGbEIseUJBQXlCLGNBRFosTUFBTTs7NEZBQ25CLHlCQUF5QjtrQkFEckMsVUFBVTttQkFBQyxFQUFFLFVBQVUsRUFBRSxNQUFNLEVBQUU7OzBCQUc3QixNQUFNOzJCQUFDLG1CQUFtQiIsInNvdXJjZXNDb250ZW50IjpbIi8qKlxuICogTm90aWZpY2F0aW9uQWN0aW9uU2VydmljZSDigJQgb3JxdWVzdGEgZWwgXCJjbGljayBlbiBub3RpZmljYWNpw7NuXCIgY3Jvc3MtYXBwIGNyb3NzLW9yZy5cbiAqXG4gKiBGbHVqbzpcbiAqICAgMS4gbWFya0FzUmVhZCAoYmVzdC1lZmZvcnQsIG5vIGJsb3F1ZWEpXG4gKiAgIDIuIFNpIGFwcElkIGRlc3Rpbm8gIT09IGFwcElkIGFjdHVhbCDihpIgaGFuZG9mZiB0b2tlbiArIHJlZGlyZWN0IGEgYXBwIGRlc3Rpbm9cbiAqICAgMy4gU2kgb3JnSWQgZGVzdGlubyAhPT0gYWN0aXZlT3JnIOKGkiBzd2l0Y2hUbyhvcmdJZCkgKHNpbiByZWxvYWQsIG5hdmVnYSBkZXNwdcOpcylcbiAqICAgNC4gcm91dGVyLm5hdmlnYXRlQnlVcmwoYWN0aW9uUm91dGUpXG4gKlxuICogUmVxdWllcmU6XG4gKiAgIC0gVmFsdGVjaEF1dGhDb25maWcuYXBwSWQgIChpZGVudGlmaWNhIGxhIGFwcCBhY3R1YWwpXG4gKiAgIC0gVmFsdGVjaEF1dGhDb25maWcuYXBwVXJscyAobWFwYSBiYXNlVXJsIHBhcmEgaGFuZG9mZiBjcm9zcy1hcHApXG4gKi9cblxuaW1wb3J0IHsgSHR0cEVycm9yUmVzcG9uc2UgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XG5pbXBvcnQgeyBJbmplY3QsIEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcbmltcG9ydCB7IFJvdXRlciB9IGZyb20gJ0Bhbmd1bGFyL3JvdXRlcic7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBBdXRoU2VydmljZSB9IGZyb20gJy4vYXV0aC5zZXJ2aWNlJztcbmltcG9ydCB7IFZBTFRFQ0hfQVVUSF9DT05GSUcgfSBmcm9tICcuL2NvbmZpZyc7XG5pbXBvcnQgeyBIYW5kb2ZmU2VydmljZSB9IGZyb20gJy4vaGFuZG9mZi5zZXJ2aWNlJztcbmltcG9ydCB7IE9yZ1N3aXRjaFNlcnZpY2UgfSBmcm9tICcuL29yZy1zd2l0Y2guc2VydmljZSc7XG5pbXBvcnQgeyBWYWx0ZWNoQXV0aENvbmZpZyB9IGZyb20gJy4vdHlwZXMnO1xuaW1wb3J0IHsgTm90aWZpY2F0aW9uRG9jdW1lbnQsIE5vdGlmaWNhdGlvbnNTZXJ2aWNlIH0gZnJvbSAnLi4vZmlyZWJhc2Uvbm90aWZpY2F0aW9ucy5zZXJ2aWNlJztcblxuLyoqIFJlc3VsdGFkbyBkZXNjcmlwdGl2byBkZWwgb3BlbigpIOKAlCDDunRpbCBwYXJhIHRlc3RzIHkgdGVsZW1ldHLDrWEuICovXG5leHBvcnQgdHlwZSBOb3RpZmljYXRpb25PcGVuUmVzdWx0ID1cbiAgfCAnbmF2aWdhdGVkJ1xuICB8ICduYXZpZ2F0ZWQtYWZ0ZXItc3dpdGNoLW9yZydcbiAgfCAncmVkaXJlY3RlZC1jcm9zcy1hcHAnXG4gIHwgJ25vLWFjdGlvbi1yb3V0ZSdcbiAgfCAnY3Jvc3MtYXBwLXVuY29uZmlndXJlZCdcbiAgfCAnaGFuZG9mZi1mYWlsZWQnO1xuXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIE5vdGlmaWNhdGlvbkFjdGlvblNlcnZpY2Uge1xuICBjb25zdHJ1Y3RvcihcbiAgICBASW5qZWN0KFZBTFRFQ0hfQVVUSF9DT05GSUcpIHByaXZhdGUgY29uZmlnOiBWYWx0ZWNoQXV0aENvbmZpZyxcbiAgICBwcml2YXRlIGF1dGg6IEF1dGhTZXJ2aWNlLFxuICAgIHByaXZhdGUgb3JnU3dpdGNoOiBPcmdTd2l0Y2hTZXJ2aWNlLFxuICAgIHByaXZhdGUgaGFuZG9mZjogSGFuZG9mZlNlcnZpY2UsXG4gICAgcHJpdmF0ZSBub3RpZmljYXRpb25zOiBOb3RpZmljYXRpb25zU2VydmljZSxcbiAgICBwcml2YXRlIHJvdXRlcjogUm91dGVyXG4gICkge31cblxuICAvKipcbiAgICogQWJyZSBsYSBub3RpZmljYWNpw7NuOiBtYXJjYSBjb21vIGxlw61kYSwgc3dpdGNoLW9yZyBzaSB0b2NhLCBuYXZlZ2FjacOzbiBsb2NhbCBvXG4gICAqIHJlZGlyZWN0IGNyb3NzLWFwcCB2w61hIGhhbmRvZmYuXG4gICAqXG4gICAqIE5vIGxhbnphIGVycm9yZXMgaGFjaWEgbGEgVUkg4oCUIGRldnVlbHZlIHVuIHJlc3VsdGFkbyBkZXNjcmlwdGl2by4gRXJyb3Jlc1xuICAgKiB0w6ljbmljb3MgcXVlZGFuIGVuIGNvbnNvbGUud2Fybi5cbiAgICovXG4gIGFzeW5jIG9wZW4obm90aWY6IE5vdGlmaWNhdGlvbkRvY3VtZW50KTogUHJvbWlzZTxOb3RpZmljYXRpb25PcGVuUmVzdWx0PiB7XG4gICAgLy8gMSkgTWFyayBhcyByZWFkIChiZXN0LWVmZm9ydCwgbm8gYmxvcXVlYSBlbCBmbHVqbyBwcmluY2lwYWwpXG4gICAgaWYgKG5vdGlmLmlkICYmICFub3RpZi5pc1JlYWQpIHtcbiAgICAgIHRoaXMubm90aWZpY2F0aW9ucy5tYXJrQXNSZWFkKG5vdGlmLmlkKS5jYXRjaChlcnIgPT4ge1xuICAgICAgICBjb25zb2xlLndhcm4oJ1tOb3RpZmljYXRpb25BY3Rpb25dIG1hcmtBc1JlYWQgZmFpbGVkJywgZXJyKTtcbiAgICAgIH0pO1xuICAgIH1cblxuICAgIGNvbnN0IHJvdXRlID0gbm90aWYuYWN0aW9uUm91dGU7XG4gICAgaWYgKCFyb3V0ZSkge1xuICAgICAgcmV0dXJuICduby1hY3Rpb24tcm91dGUnO1xuICAgIH1cblxuICAgIGNvbnN0IGN1cnJlbnRBcHAgPSB0aGlzLmNvbmZpZy5hcHBJZDtcbiAgICBjb25zdCB0YXJnZXRBcHAgPSBub3RpZi5hcHBJZDtcblxuICAgIC8vIDIpIENyb3NzLWFwcDogaGFuZG9mZiArIGZ1bGwgcmVkaXJlY3RcbiAgICBpZiAodGFyZ2V0QXBwICYmIGN1cnJlbnRBcHAgJiYgdGFyZ2V0QXBwICE9PSBjdXJyZW50QXBwKSB7XG4gICAgICBjb25zdCBiYXNlVXJsID0gdGhpcy5jb25maWcuYXBwVXJscz8uW3RhcmdldEFwcF07XG4gICAgICBpZiAoIWJhc2VVcmwpIHtcbiAgICAgICAgY29uc29sZS53YXJuKFxuICAgICAgICAgIGBbTm90aWZpY2F0aW9uQWN0aW9uXSBNaXNzaW5nIGFwcFVybHNbJyR7dGFyZ2V0QXBwfSddIOKAlCBjb25maWd1cmUgVmFsdGVjaEF1dGhDb25maWcuYXBwVXJsc2BcbiAgICAgICAgKTtcbiAgICAgICAgcmV0dXJuICdjcm9zcy1hcHAtdW5jb25maWd1cmVkJztcbiAgICAgIH1cblxuICAgICAgdHJ5IHtcbiAgICAgICAgY29uc3QgcmVzcCA9IGF3YWl0IGZpcnN0VmFsdWVGcm9tKFxuICAgICAgICAgIHRoaXMuaGFuZG9mZi5jcmVhdGVIYW5kb2ZmKHsgdGFyZ2V0QXBwSWQ6IHRhcmdldEFwcCwgcm91dGUgfSlcbiAgICAgICAgKTtcbiAgICAgICAgY29uc3QgdXJsID0gdGhpcy5idWlsZEhhbmRvZmZVcmwoYmFzZVVybCwgcmVzcC50b2tlbiwgcm91dGUpO1xuICAgICAgICBpZiAodHlwZW9mIHdpbmRvdyAhPT0gJ3VuZGVmaW5lZCcpIHtcbiAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IHVybDtcbiAgICAgICAgfVxuICAgICAgICByZXR1cm4gJ3JlZGlyZWN0ZWQtY3Jvc3MtYXBwJztcbiAgICAgIH0gY2F0Y2ggKGVycikge1xuICAgICAgICBjb25zdCBtc2cgPSBlcnIgaW5zdGFuY2VvZiBIdHRwRXJyb3JSZXNwb25zZSA/IGVyci5tZXNzYWdlIDogU3RyaW5nKGVycik7XG4gICAgICAgIGNvbnNvbGUud2FybignW05vdGlmaWNhdGlvbkFjdGlvbl0gY3JlYXRlSGFuZG9mZiBmYWlsZWQ6JywgbXNnKTtcbiAgICAgICAgcmV0dXJuICdoYW5kb2ZmLWZhaWxlZCc7XG4gICAgICB9XG4gICAgfVxuXG4gICAgLy8gMykgU2FtZSBhcHAg4oCUIHN3aXRjaC1vcmcgc2kgdG9jYSAoc2luIHJlbG9hZCDigJQgbGEgbmF2ZWdhY2nDs24gcG9zdGVyaW9yIG1vbnRhIHBhZ2UgZnJlc2gpXG4gICAgbGV0IHN3aXRjaGVkID0gZmFsc2U7XG4gICAgaWYgKG5vdGlmLm9yZ0lkKSB7XG4gICAgICBjb25zdCBhY3RpdmUgPSB0aGlzLmFjdGl2ZU9yZygpO1xuICAgICAgaWYgKGFjdGl2ZSAmJiBhY3RpdmUgIT09IG5vdGlmLm9yZ0lkKSB7XG4gICAgICAgIGF3YWl0IHRoaXMub3JnU3dpdGNoLnN3aXRjaFRvKG5vdGlmLm9yZ0lkKTtcbiAgICAgICAgc3dpdGNoZWQgPSB0cnVlO1xuICAgICAgfVxuICAgIH1cblxuICAgIC8vIDQpIE5hdmlnYXRlIGxvY2FsXG4gICAgYXdhaXQgdGhpcy5yb3V0ZXIubmF2aWdhdGVCeVVybChyb3V0ZSk7XG4gICAgcmV0dXJuIHN3aXRjaGVkID8gJ25hdmlnYXRlZC1hZnRlci1zd2l0Y2gtb3JnJyA6ICduYXZpZ2F0ZWQnO1xuICB9XG5cbiAgcHJpdmF0ZSBhY3RpdmVPcmcoKTogc3RyaW5nIHtcbiAgICBjb25zdCB1c2VyID0gdGhpcy5hdXRoLnVzZXIoKTtcbiAgICByZXR1cm4gKFxuICAgICAgKHVzZXIgYXMgeyBhY3RpdmVPcmdJZD86IHN0cmluZzsgYWN0aXZlT3JnPzogc3RyaW5nIH0gfCBudWxsKT8uYWN0aXZlT3JnSWQgPz9cbiAgICAgICh1c2VyIGFzIHsgYWN0aXZlT3JnSWQ/OiBzdHJpbmc7IGFjdGl2ZU9yZz86IHN0cmluZyB9IHwgbnVsbCk/LmFjdGl2ZU9yZyA/P1xuICAgICAgJydcbiAgICApO1xuICB9XG5cbiAgLyoqXG4gICAqIENvbnN0cnV5ZSBVUkwgYWJzb2x1dGEgcGFyYSBoYW5kb2ZmIGNyb3NzLWFwcCBwcmVzZXJ2YW5kbyBwYXRobmFtZSB5IG90cm9zXG4gICAqIHBhcmFtcyBleGlzdGVudGVzIGRlIGxhIGJhc2VVcmwuXG4gICAqL1xuICBwcml2YXRlIGJ1aWxkSGFuZG9mZlVybChiYXNlVXJsOiBzdHJpbmcsIHRva2VuOiBzdHJpbmcsIHJvdXRlOiBzdHJpbmcpOiBzdHJpbmcge1xuICAgIGNvbnN0IHVybCA9IG5ldyBVUkwoYmFzZVVybCk7XG4gICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoJ2hhbmRvZmYnLCB0b2tlbik7XG4gICAgdXJsLnNlYXJjaFBhcmFtcy5zZXQoJ3JvdXRlJywgcm91dGUpO1xuICAgIHJldHVybiB1cmwudG9TdHJpbmcoKTtcbiAgfVxufVxuIl19
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
import { Injectable, signal } from '@angular/core';
|
|
2
|
+
import { firstValueFrom, Subject } from 'rxjs';
|
|
3
|
+
import * as i0 from "@angular/core";
|
|
4
|
+
import * as i1 from "./auth.service";
|
|
5
|
+
/**
|
|
6
|
+
* OrgSwitchService — orchestrates active organization changes across the app.
|
|
7
|
+
*
|
|
8
|
+
* Built on top of `AuthService.switchOrg`, which already:
|
|
9
|
+
* - Hits `POST /v2/auth/switch-org` and receives a new Firebase custom token.
|
|
10
|
+
* - Re-authenticates Firebase Auth with the new token (RBAC claims update).
|
|
11
|
+
* - Broadcasts `ORG_SWITCH` to other tabs via `AuthSyncService` (multi-tab sync).
|
|
12
|
+
*
|
|
13
|
+
* What this service adds on top:
|
|
14
|
+
* - A `switching` signal so the UI can show a loading indicator (1-2s switch).
|
|
15
|
+
* - An `orgChanged$` Observable that components subscribe to in order to
|
|
16
|
+
* invalidate their org-scoped caches (e.g. drop old query results, reset
|
|
17
|
+
* page state) without a full page reload.
|
|
18
|
+
* - Optional `reload: true` for apps where invalidating in-memory state piece
|
|
19
|
+
* by piece is impractical.
|
|
20
|
+
*
|
|
21
|
+
* **What this service does NOT do automatically:**
|
|
22
|
+
*
|
|
23
|
+
* 1. **Teardown Firestore listeners.** Listeners are owned by their subscribing
|
|
24
|
+
* components (typically via `takeUntilDestroyed` or async pipe). When the
|
|
25
|
+
* component re-renders or unsubscribes, the listener disposes. If a
|
|
26
|
+
* component does NOT unsubscribe on org change, its listener will keep
|
|
27
|
+
* pointing at the previous org's path and may start failing rules. The fix
|
|
28
|
+
* is component-level: subscribe to `orgChanged$` and reset state, or use
|
|
29
|
+
* the `reload: true` option.
|
|
30
|
+
*
|
|
31
|
+
* 2. **Re-instantiate routed components.** Angular keeps mounted components
|
|
32
|
+
* alive across navigations. If you need fresh state, either subscribe to
|
|
33
|
+
* `orgChanged$` in the component, or use `reload: true`.
|
|
34
|
+
*
|
|
35
|
+
* @example Basic switch with loading state
|
|
36
|
+
* ```typescript
|
|
37
|
+
* private orgSwitch = inject(OrgSwitchService);
|
|
38
|
+
*
|
|
39
|
+
* async onSwitchOrg(orgId: string) {
|
|
40
|
+
* await this.orgSwitch.switchTo(orgId);
|
|
41
|
+
* // Components subscribed to orgChanged$ have already reset their state.
|
|
42
|
+
* }
|
|
43
|
+
*
|
|
44
|
+
* // In template:
|
|
45
|
+
* @if (orgSwitch.switching()) { <val-loading /> }
|
|
46
|
+
* ```
|
|
47
|
+
*
|
|
48
|
+
* @example Component reacting to org change
|
|
49
|
+
* ```typescript
|
|
50
|
+
* private orgSwitch = inject(OrgSwitchService);
|
|
51
|
+
*
|
|
52
|
+
* constructor() {
|
|
53
|
+
* this.orgSwitch.orgChanged$
|
|
54
|
+
* .pipe(takeUntilDestroyed())
|
|
55
|
+
* .subscribe(() => this.resetState());
|
|
56
|
+
* }
|
|
57
|
+
* ```
|
|
58
|
+
*
|
|
59
|
+
* @example Brutal reload mode
|
|
60
|
+
* ```typescript
|
|
61
|
+
* await this.orgSwitch.switchTo(orgId, { reload: true });
|
|
62
|
+
* // window.location.reload() — clean slate, loses scroll position
|
|
63
|
+
* ```
|
|
64
|
+
*/
|
|
65
|
+
export class OrgSwitchService {
|
|
66
|
+
constructor(auth) {
|
|
67
|
+
this.auth = auth;
|
|
68
|
+
this._switching = signal(false);
|
|
69
|
+
this._orgChanged = new Subject();
|
|
70
|
+
/**
|
|
71
|
+
* `true` while a switch is in flight. UI should disable interactions
|
|
72
|
+
* with org-scoped data and show a loading indicator.
|
|
73
|
+
*/
|
|
74
|
+
this.switching = this._switching.asReadonly();
|
|
75
|
+
/**
|
|
76
|
+
* Fires after a successful switch, with the previous and new org ids.
|
|
77
|
+
* Components subscribe to invalidate caches / reset state.
|
|
78
|
+
*
|
|
79
|
+
* Fires AFTER the Firebase re-auth completes — listeners attached here
|
|
80
|
+
* see the updated Firebase user / activeOrg claim.
|
|
81
|
+
*/
|
|
82
|
+
this.orgChanged$ = this._orgChanged.asObservable();
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Switch the user's active organization.
|
|
86
|
+
*
|
|
87
|
+
* Re-entrant safe: while a switch is in flight, additional calls are
|
|
88
|
+
* rejected silently (returns immediately). Inspect `switching()` to gate UI.
|
|
89
|
+
*
|
|
90
|
+
* @param orgId Target organization id. Must be one the user has a role in
|
|
91
|
+
* — backend rejects otherwise with `PERMISSION_DENIED`.
|
|
92
|
+
* @param options See `SwitchOrgOptions`.
|
|
93
|
+
*
|
|
94
|
+
* @throws The error from `auth.switchOrg` if the backend call fails.
|
|
95
|
+
* `switching` returns to `false` before the error propagates.
|
|
96
|
+
*/
|
|
97
|
+
async switchTo(orgId, options = {}) {
|
|
98
|
+
if (this._switching()) {
|
|
99
|
+
return;
|
|
100
|
+
}
|
|
101
|
+
const previousOrg = this.currentActiveOrg();
|
|
102
|
+
if (previousOrg === orgId) {
|
|
103
|
+
// No-op — already on this org.
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
this._switching.set(true);
|
|
107
|
+
try {
|
|
108
|
+
await firstValueFrom(this.auth.switchOrg(orgId));
|
|
109
|
+
this._orgChanged.next({ previousOrg, newOrg: orgId });
|
|
110
|
+
if (options.reload && typeof window !== 'undefined') {
|
|
111
|
+
window.location.reload();
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
finally {
|
|
115
|
+
this._switching.set(false);
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Read the current `activeOrg` from the auth user signal.
|
|
120
|
+
* Falls back to empty string if the user isn't loaded yet.
|
|
121
|
+
*/
|
|
122
|
+
currentActiveOrg() {
|
|
123
|
+
const user = this.auth.user();
|
|
124
|
+
// AuthUser may expose activeOrgId under different names depending on
|
|
125
|
+
// backend version — keep tolerant.
|
|
126
|
+
return (user?.activeOrgId ??
|
|
127
|
+
user?.activeOrg ??
|
|
128
|
+
'');
|
|
129
|
+
}
|
|
130
|
+
static { this.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, deps: [{ token: i1.AuthService }], target: i0.ɵɵFactoryTarget.Injectable }); }
|
|
131
|
+
static { this.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, providedIn: 'root' }); }
|
|
132
|
+
}
|
|
133
|
+
i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "18.2.14", ngImport: i0, type: OrgSwitchService, decorators: [{
|
|
134
|
+
type: Injectable,
|
|
135
|
+
args: [{ providedIn: 'root' }]
|
|
136
|
+
}], ctorParameters: () => [{ type: i1.AuthService }] });
|
|
137
|
+
//# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoib3JnLXN3aXRjaC5zZXJ2aWNlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vLi4vLi4vLi4vLi4vc3JjL2xpYi9zZXJ2aWNlcy9hdXRoL29yZy1zd2l0Y2guc2VydmljZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsVUFBVSxFQUFFLE1BQU0sRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUNuRCxPQUFPLEVBQUUsY0FBYyxFQUFjLE9BQU8sRUFBRSxNQUFNLE1BQU0sQ0FBQzs7O0FBOEIzRDs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7Ozs7R0EyREc7QUFFSCxNQUFNLE9BQU8sZ0JBQWdCO0lBbUIzQixZQUFvQixJQUFpQjtRQUFqQixTQUFJLEdBQUosSUFBSSxDQUFhO1FBbEJwQixlQUFVLEdBQUcsTUFBTSxDQUFDLEtBQUssQ0FBQyxDQUFDO1FBQzNCLGdCQUFXLEdBQUcsSUFBSSxPQUFPLEVBQW1CLENBQUM7UUFFOUQ7OztXQUdHO1FBQ00sY0FBUyxHQUFHLElBQUksQ0FBQyxVQUFVLENBQUMsVUFBVSxFQUFFLENBQUM7UUFFbEQ7Ozs7OztXQU1HO1FBQ00sZ0JBQVcsR0FBZ0MsSUFBSSxDQUFDLFdBQVcsQ0FBQyxZQUFZLEVBQUUsQ0FBQztJQUU1QyxDQUFDO0lBRXpDOzs7Ozs7Ozs7Ozs7T0FZRztJQUNILEtBQUssQ0FBQyxRQUFRLENBQUMsS0FBYSxFQUFFLFVBQTRCLEVBQUU7UUFDMUQsSUFBSSxJQUFJLENBQUMsVUFBVSxFQUFFLEVBQUUsQ0FBQztZQUN0QixPQUFPO1FBQ1QsQ0FBQztRQUVELE1BQU0sV0FBVyxHQUFHLElBQUksQ0FBQyxnQkFBZ0IsRUFBRSxDQUFDO1FBQzVDLElBQUksV0FBVyxLQUFLLEtBQUssRUFBRSxDQUFDO1lBQzFCLCtCQUErQjtZQUMvQixPQUFPO1FBQ1QsQ0FBQztRQUVELElBQUksQ0FBQyxVQUFVLENBQUMsR0FBRyxDQUFDLElBQUksQ0FBQyxDQUFDO1FBQzFCLElBQUksQ0FBQztZQUNILE1BQU0sY0FBYyxDQUFDLElBQUksQ0FBQyxJQUFJLENBQUMsU0FBUyxDQUFDLEtBQUssQ0FBQyxDQUFDLENBQUM7WUFDakQsSUFBSSxDQUFDLFdBQVcsQ0FBQyxJQUFJLENBQUMsRUFBRSxXQUFXLEVBQUUsTUFBTSxFQUFFLEtBQUssRUFBRSxDQUFDLENBQUM7WUFFdEQsSUFBSSxPQUFPLENBQUMsTUFBTSxJQUFJLE9BQU8sTUFBTSxLQUFLLFdBQVcsRUFBRSxDQUFDO2dCQUNwRCxNQUFNLENBQUMsUUFBUSxDQUFDLE1BQU0sRUFBRSxDQUFDO1lBQzNCLENBQUM7UUFDSCxDQUFDO2dCQUFTLENBQUM7WUFDVCxJQUFJLENBQUMsVUFBVSxDQUFDLEdBQUcsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUM3QixDQUFDO0lBQ0gsQ0FBQztJQUVEOzs7T0FHRztJQUNLLGdCQUFnQjtRQUN0QixNQUFNLElBQUksR0FBRyxJQUFJLENBQUMsSUFBSSxDQUFDLElBQUksRUFBRSxDQUFDO1FBQzlCLHFFQUFxRTtRQUNyRSxtQ0FBbUM7UUFDbkMsT0FBTyxDQUNKLElBQTRELEVBQUUsV0FBVztZQUN6RSxJQUE0RCxFQUFFLFNBQVM7WUFDeEUsRUFBRSxDQUNILENBQUM7SUFDSixDQUFDOytHQXZFVSxnQkFBZ0I7bUhBQWhCLGdCQUFnQixjQURILE1BQU07OzRGQUNuQixnQkFBZ0I7a0JBRDVCLFVBQVU7bUJBQUMsRUFBRSxVQUFVLEVBQUUsTUFBTSxFQUFFIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgSW5qZWN0YWJsZSwgc2lnbmFsIH0gZnJvbSAnQGFuZ3VsYXIvY29yZSc7XG5pbXBvcnQgeyBmaXJzdFZhbHVlRnJvbSwgT2JzZXJ2YWJsZSwgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xuXG5pbXBvcnQgeyBBdXRoU2VydmljZSB9IGZyb20gJy4vYXV0aC5zZXJ2aWNlJztcblxuLyoqXG4gKiBFdmVudCBlbWl0dGVkIHdoZW4gdGhlIGFjdGl2ZSBvcmdhbml6YXRpb24gY2hhbmdlcy5cbiAqL1xuZXhwb3J0IGludGVyZmFjZSBPcmdDaGFuZ2VkRXZlbnQge1xuICAvKiogT3JnIHRoZSB1c2VyIHdhcyBvbiBiZWZvcmUgdGhlIHN3aXRjaC4gTWF5IGJlIGVtcHR5IG9uIGZpcnN0IHNpZ24taW4uICovXG4gIHByZXZpb3VzT3JnOiBzdHJpbmc7XG4gIC8qKiBPcmcgdGhlIHVzZXIganVzdCBzd2l0Y2hlZCB0by4gKi9cbiAgbmV3T3JnOiBzdHJpbmc7XG59XG5cbi8qKlxuICogT3B0aW9ucyBmb3IgYE9yZ1N3aXRjaFNlcnZpY2Uuc3dpdGNoVG9gLlxuICovXG5leHBvcnQgaW50ZXJmYWNlIFN3aXRjaE9yZ09wdGlvbnMge1xuICAvKipcbiAgICogSWYgYHRydWVgLCBhZnRlciB0aGUgc3dpdGNoIHN1Y2NlZWRzIHRoZSBwYWdlIGlzIGZ1bGx5IHJlbG9hZGVkIHZpYVxuICAgKiBgd2luZG93LmxvY2F0aW9uLnJlbG9hZCgpYC4gVXNlZnVsIGZvciBhcHBzIHdpdGggc2lnbmlmaWNhbnQgaW4tbWVtb3J5XG4gICAqIHN0YXRlIHRpZWQgdG8gdGhlIHByZXZpb3VzIG9yZyB0aGF0J3MgaGFyZCB0byBpbnZhbGlkYXRlIHBpZWNlIGJ5IHBpZWNlLlxuICAgKlxuICAgKiBUcmFkZS1vZmY6IHJlbG9hZCBsb3NlcyBhbGwgaW4tbWVtb3J5IHN0YXRlIChmb3Jtcywgc2Nyb2xsIHBvc2l0aW9uKS5cbiAgICogRGVmYXVsdDogYGZhbHNlYCDigJQgcmVsaWVzIG9uIGBvcmdDaGFuZ2VkJGAgYW5kIGBhdXRoLnVzZXIoKWAgc2lnbmFsXG4gICAqIHByb3BhZ2F0aW9uIGZvciBjb21wb25lbnRzIHRvIHJlYWN0LlxuICAgKi9cbiAgcmVsb2FkPzogYm9vbGVhbjtcbn1cblxuLyoqXG4gKiBPcmdTd2l0Y2hTZXJ2aWNlIOKAlCBvcmNoZXN0cmF0ZXMgYWN0aXZlIG9yZ2FuaXphdGlvbiBjaGFuZ2VzIGFjcm9zcyB0aGUgYXBwLlxuICpcbiAqIEJ1aWx0IG9uIHRvcCBvZiBgQXV0aFNlcnZpY2Uuc3dpdGNoT3JnYCwgd2hpY2ggYWxyZWFkeTpcbiAqIC0gSGl0cyBgUE9TVCAvdjIvYXV0aC9zd2l0Y2gtb3JnYCBhbmQgcmVjZWl2ZXMgYSBuZXcgRmlyZWJhc2UgY3VzdG9tIHRva2VuLlxuICogLSBSZS1hdXRoZW50aWNhdGVzIEZpcmViYXNlIEF1dGggd2l0aCB0aGUgbmV3IHRva2VuIChSQkFDIGNsYWltcyB1cGRhdGUpLlxuICogLSBCcm9hZGNhc3RzIGBPUkdfU1dJVENIYCB0byBvdGhlciB0YWJzIHZpYSBgQXV0aFN5bmNTZXJ2aWNlYCAobXVsdGktdGFiIHN5bmMpLlxuICpcbiAqIFdoYXQgdGhpcyBzZXJ2aWNlIGFkZHMgb24gdG9wOlxuICogLSBBIGBzd2l0Y2hpbmdgIHNpZ25hbCBzbyB0aGUgVUkgY2FuIHNob3cgYSBsb2FkaW5nIGluZGljYXRvciAoMS0ycyBzd2l0Y2gpLlxuICogLSBBbiBgb3JnQ2hhbmdlZCRgIE9ic2VydmFibGUgdGhhdCBjb21wb25lbnRzIHN1YnNjcmliZSB0byBpbiBvcmRlciB0b1xuICogICBpbnZhbGlkYXRlIHRoZWlyIG9yZy1zY29wZWQgY2FjaGVzIChlLmcuIGRyb3Agb2xkIHF1ZXJ5IHJlc3VsdHMsIHJlc2V0XG4gKiAgIHBhZ2Ugc3RhdGUpIHdpdGhvdXQgYSBmdWxsIHBhZ2UgcmVsb2FkLlxuICogLSBPcHRpb25hbCBgcmVsb2FkOiB0cnVlYCBmb3IgYXBwcyB3aGVyZSBpbnZhbGlkYXRpbmcgaW4tbWVtb3J5IHN0YXRlIHBpZWNlXG4gKiAgIGJ5IHBpZWNlIGlzIGltcHJhY3RpY2FsLlxuICpcbiAqICoqV2hhdCB0aGlzIHNlcnZpY2UgZG9lcyBOT1QgZG8gYXV0b21hdGljYWxseToqKlxuICpcbiAqIDEuICoqVGVhcmRvd24gRmlyZXN0b3JlIGxpc3RlbmVycy4qKiBMaXN0ZW5lcnMgYXJlIG93bmVkIGJ5IHRoZWlyIHN1YnNjcmliaW5nXG4gKiAgICBjb21wb25lbnRzICh0eXBpY2FsbHkgdmlhIGB0YWtlVW50aWxEZXN0cm95ZWRgIG9yIGFzeW5jIHBpcGUpLiBXaGVuIHRoZVxuICogICAgY29tcG9uZW50IHJlLXJlbmRlcnMgb3IgdW5zdWJzY3JpYmVzLCB0aGUgbGlzdGVuZXIgZGlzcG9zZXMuIElmIGFcbiAqICAgIGNvbXBvbmVudCBkb2VzIE5PVCB1bnN1YnNjcmliZSBvbiBvcmcgY2hhbmdlLCBpdHMgbGlzdGVuZXIgd2lsbCBrZWVwXG4gKiAgICBwb2ludGluZyBhdCB0aGUgcHJldmlvdXMgb3JnJ3MgcGF0aCBhbmQgbWF5IHN0YXJ0IGZhaWxpbmcgcnVsZXMuIFRoZSBmaXhcbiAqICAgIGlzIGNvbXBvbmVudC1sZXZlbDogc3Vic2NyaWJlIHRvIGBvcmdDaGFuZ2VkJGAgYW5kIHJlc2V0IHN0YXRlLCBvciB1c2VcbiAqICAgIHRoZSBgcmVsb2FkOiB0cnVlYCBvcHRpb24uXG4gKlxuICogMi4gKipSZS1pbnN0YW50aWF0ZSByb3V0ZWQgY29tcG9uZW50cy4qKiBBbmd1bGFyIGtlZXBzIG1vdW50ZWQgY29tcG9uZW50c1xuICogICAgYWxpdmUgYWNyb3NzIG5hdmlnYXRpb25zLiBJZiB5b3UgbmVlZCBmcmVzaCBzdGF0ZSwgZWl0aGVyIHN1YnNjcmliZSB0b1xuICogICAgYG9yZ0NoYW5nZWQkYCBpbiB0aGUgY29tcG9uZW50LCBvciB1c2UgYHJlbG9hZDogdHJ1ZWAuXG4gKlxuICogQGV4YW1wbGUgQmFzaWMgc3dpdGNoIHdpdGggbG9hZGluZyBzdGF0ZVxuICogYGBgdHlwZXNjcmlwdFxuICogcHJpdmF0ZSBvcmdTd2l0Y2ggPSBpbmplY3QoT3JnU3dpdGNoU2VydmljZSk7XG4gKlxuICogYXN5bmMgb25Td2l0Y2hPcmcob3JnSWQ6IHN0cmluZykge1xuICogICBhd2FpdCB0aGlzLm9yZ1N3aXRjaC5zd2l0Y2hUbyhvcmdJZCk7XG4gKiAgIC8vIENvbXBvbmVudHMgc3Vic2NyaWJlZCB0byBvcmdDaGFuZ2VkJCBoYXZlIGFscmVhZHkgcmVzZXQgdGhlaXIgc3RhdGUuXG4gKiB9XG4gKlxuICogLy8gSW4gdGVtcGxhdGU6XG4gKiBAaWYgKG9yZ1N3aXRjaC5zd2l0Y2hpbmcoKSkgeyA8dmFsLWxvYWRpbmcgLz4gfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGUgQ29tcG9uZW50IHJlYWN0aW5nIHRvIG9yZyBjaGFuZ2VcbiAqIGBgYHR5cGVzY3JpcHRcbiAqIHByaXZhdGUgb3JnU3dpdGNoID0gaW5qZWN0KE9yZ1N3aXRjaFNlcnZpY2UpO1xuICpcbiAqIGNvbnN0cnVjdG9yKCkge1xuICogICB0aGlzLm9yZ1N3aXRjaC5vcmdDaGFuZ2VkJFxuICogICAgIC5waXBlKHRha2VVbnRpbERlc3Ryb3llZCgpKVxuICogICAgIC5zdWJzY3JpYmUoKCkgPT4gdGhpcy5yZXNldFN0YXRlKCkpO1xuICogfVxuICogYGBgXG4gKlxuICogQGV4YW1wbGUgQnJ1dGFsIHJlbG9hZCBtb2RlXG4gKiBgYGB0eXBlc2NyaXB0XG4gKiBhd2FpdCB0aGlzLm9yZ1N3aXRjaC5zd2l0Y2hUbyhvcmdJZCwgeyByZWxvYWQ6IHRydWUgfSk7XG4gKiAvLyB3aW5kb3cubG9jYXRpb24ucmVsb2FkKCkg4oCUIGNsZWFuIHNsYXRlLCBsb3NlcyBzY3JvbGwgcG9zaXRpb25cbiAqIGBgYFxuICovXG5ASW5qZWN0YWJsZSh7IHByb3ZpZGVkSW46ICdyb290JyB9KVxuZXhwb3J0IGNsYXNzIE9yZ1N3aXRjaFNlcnZpY2Uge1xuICBwcml2YXRlIHJlYWRvbmx5IF9zd2l0Y2hpbmcgPSBzaWduYWwoZmFsc2UpO1xuICBwcml2YXRlIHJlYWRvbmx5IF9vcmdDaGFuZ2VkID0gbmV3IFN1YmplY3Q8T3JnQ2hhbmdlZEV2ZW50PigpO1xuXG4gIC8qKlxuICAgKiBgdHJ1ZWAgd2hpbGUgYSBzd2l0Y2ggaXMgaW4gZmxpZ2h0LiBVSSBzaG91bGQgZGlzYWJsZSBpbnRlcmFjdGlvbnNcbiAgICogd2l0aCBvcmctc2NvcGVkIGRhdGEgYW5kIHNob3cgYSBsb2FkaW5nIGluZGljYXRvci5cbiAgICovXG4gIHJlYWRvbmx5IHN3aXRjaGluZyA9IHRoaXMuX3N3aXRjaGluZy5hc1JlYWRvbmx5KCk7XG5cbiAgLyoqXG4gICAqIEZpcmVzIGFmdGVyIGEgc3VjY2Vzc2Z1bCBzd2l0Y2gsIHdpdGggdGhlIHByZXZpb3VzIGFuZCBuZXcgb3JnIGlkcy5cbiAgICogQ29tcG9uZW50cyBzdWJzY3JpYmUgdG8gaW52YWxpZGF0ZSBjYWNoZXMgLyByZXNldCBzdGF0ZS5cbiAgICpcbiAgICogRmlyZXMgQUZURVIgdGhlIEZpcmViYXNlIHJlLWF1dGggY29tcGxldGVzIOKAlCBsaXN0ZW5lcnMgYXR0YWNoZWQgaGVyZVxuICAgKiBzZWUgdGhlIHVwZGF0ZWQgRmlyZWJhc2UgdXNlciAvIGFjdGl2ZU9yZyBjbGFpbS5cbiAgICovXG4gIHJlYWRvbmx5IG9yZ0NoYW5nZWQkOiBPYnNlcnZhYmxlPE9yZ0NoYW5nZWRFdmVudD4gPSB0aGlzLl9vcmdDaGFuZ2VkLmFzT2JzZXJ2YWJsZSgpO1xuXG4gIGNvbnN0cnVjdG9yKHByaXZhdGUgYXV0aDogQXV0aFNlcnZpY2UpIHt9XG5cbiAgLyoqXG4gICAqIFN3aXRjaCB0aGUgdXNlcidzIGFjdGl2ZSBvcmdhbml6YXRpb24uXG4gICAqXG4gICAqIFJlLWVudHJhbnQgc2FmZTogd2hpbGUgYSBzd2l0Y2ggaXMgaW4gZmxpZ2h0LCBhZGRpdGlvbmFsIGNhbGxzIGFyZVxuICAgKiByZWplY3RlZCBzaWxlbnRseSAocmV0dXJucyBpbW1lZGlhdGVseSkuIEluc3BlY3QgYHN3aXRjaGluZygpYCB0byBnYXRlIFVJLlxuICAgKlxuICAgKiBAcGFyYW0gb3JnSWQgVGFyZ2V0IG9yZ2FuaXphdGlvbiBpZC4gTXVzdCBiZSBvbmUgdGhlIHVzZXIgaGFzIGEgcm9sZSBpblxuICAgKiAgICAgICAgICAgICAg4oCUIGJhY2tlbmQgcmVqZWN0cyBvdGhlcndpc2Ugd2l0aCBgUEVSTUlTU0lPTl9ERU5JRURgLlxuICAgKiBAcGFyYW0gb3B0aW9ucyBTZWUgYFN3aXRjaE9yZ09wdGlvbnNgLlxuICAgKlxuICAgKiBAdGhyb3dzIFRoZSBlcnJvciBmcm9tIGBhdXRoLnN3aXRjaE9yZ2AgaWYgdGhlIGJhY2tlbmQgY2FsbCBmYWlscy5cbiAgICogICAgICAgICBgc3dpdGNoaW5nYCByZXR1cm5zIHRvIGBmYWxzZWAgYmVmb3JlIHRoZSBlcnJvciBwcm9wYWdhdGVzLlxuICAgKi9cbiAgYXN5bmMgc3dpdGNoVG8ob3JnSWQ6IHN0cmluZywgb3B0aW9uczogU3dpdGNoT3JnT3B0aW9ucyA9IHt9KTogUHJvbWlzZTx2b2lkPiB7XG4gICAgaWYgKHRoaXMuX3N3aXRjaGluZygpKSB7XG4gICAgICByZXR1cm47XG4gICAgfVxuXG4gICAgY29uc3QgcHJldmlvdXNPcmcgPSB0aGlzLmN1cnJlbnRBY3RpdmVPcmcoKTtcbiAgICBpZiAocHJldmlvdXNPcmcgPT09IG9yZ0lkKSB7XG4gICAgICAvLyBOby1vcCDigJQgYWxyZWFkeSBvbiB0aGlzIG9yZy5cbiAgICAgIHJldHVybjtcbiAgICB9XG5cbiAgICB0aGlzLl9zd2l0Y2hpbmcuc2V0KHRydWUpO1xuICAgIHRyeSB7XG4gICAgICBhd2FpdCBmaXJzdFZhbHVlRnJvbSh0aGlzLmF1dGguc3dpdGNoT3JnKG9yZ0lkKSk7XG4gICAgICB0aGlzLl9vcmdDaGFuZ2VkLm5leHQoeyBwcmV2aW91c09yZywgbmV3T3JnOiBvcmdJZCB9KTtcblxuICAgICAgaWYgKG9wdGlvbnMucmVsb2FkICYmIHR5cGVvZiB3aW5kb3cgIT09ICd1bmRlZmluZWQnKSB7XG4gICAgICAgIHdpbmRvdy5sb2NhdGlvbi5yZWxvYWQoKTtcbiAgICAgIH1cbiAgICB9IGZpbmFsbHkge1xuICAgICAgdGhpcy5fc3dpdGNoaW5nLnNldChmYWxzZSk7XG4gICAgfVxuICB9XG5cbiAgLyoqXG4gICAqIFJlYWQgdGhlIGN1cnJlbnQgYGFjdGl2ZU9yZ2AgZnJvbSB0aGUgYXV0aCB1c2VyIHNpZ25hbC5cbiAgICogRmFsbHMgYmFjayB0byBlbXB0eSBzdHJpbmcgaWYgdGhlIHVzZXIgaXNuJ3QgbG9hZGVkIHlldC5cbiAgICovXG4gIHByaXZhdGUgY3VycmVudEFjdGl2ZU9yZygpOiBzdHJpbmcge1xuICAgIGNvbnN0IHVzZXIgPSB0aGlzLmF1dGgudXNlcigpO1xuICAgIC8vIEF1dGhVc2VyIG1heSBleHBvc2UgYWN0aXZlT3JnSWQgdW5kZXIgZGlmZmVyZW50IG5hbWVzIGRlcGVuZGluZyBvblxuICAgIC8vIGJhY2tlbmQgdmVyc2lvbiDigJQga2VlcCB0b2xlcmFudC5cbiAgICByZXR1cm4gKFxuICAgICAgKHVzZXIgYXMgeyBhY3RpdmVPcmdJZD86IHN0cmluZzsgYWN0aXZlT3JnPzogc3RyaW5nIH0gfCBudWxsKT8uYWN0aXZlT3JnSWQgPz9cbiAgICAgICh1c2VyIGFzIHsgYWN0aXZlT3JnSWQ/OiBzdHJpbmc7IGFjdGl2ZU9yZz86IHN0cmluZyB9IHwgbnVsbCk/LmFjdGl2ZU9yZyA/P1xuICAgICAgJydcbiAgICApO1xuICB9XG59XG4iXX0=
|