mesauth-angular 0.1.9 → 0.1.11

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.
Files changed (37) hide show
  1. package/dist/README.md +265 -0
  2. package/dist/esm2020/index.mjs +9 -0
  3. package/dist/esm2020/ma-user.component.mjs +26 -0
  4. package/dist/esm2020/mes-auth.interceptor.mjs +29 -0
  5. package/dist/esm2020/mes-auth.module.mjs +23 -0
  6. package/dist/esm2020/mes-auth.service.mjs +103 -0
  7. package/dist/esm2020/mesauth-angular.mjs +5 -0
  8. package/dist/esm2020/notification-badge.component.mjs +57 -0
  9. package/dist/esm2020/notification-panel.component.mjs +196 -0
  10. package/dist/esm2020/toast-container.component.mjs +60 -0
  11. package/dist/esm2020/toast.service.mjs +41 -0
  12. package/dist/esm2020/user-profile.component.mjs +197 -0
  13. package/dist/fesm2015/mesauth-angular.mjs +701 -0
  14. package/dist/fesm2015/mesauth-angular.mjs.map +1 -0
  15. package/dist/fesm2020/mesauth-angular.mjs +700 -0
  16. package/dist/fesm2020/mesauth-angular.mjs.map +1 -0
  17. package/dist/ma-user.component.d.ts +3 -0
  18. package/dist/mes-auth.interceptor.d.ts +3 -0
  19. package/dist/mes-auth.module.d.ts +4 -0
  20. package/dist/mes-auth.service.d.ts +5 -1
  21. package/dist/notification-badge.component.d.ts +3 -0
  22. package/dist/notification-panel.component.d.ts +3 -0
  23. package/dist/package.json +52 -0
  24. package/dist/toast-container.component.d.ts +3 -0
  25. package/dist/toast.service.d.ts +3 -0
  26. package/dist/user-profile.component.d.ts +3 -0
  27. package/package.json +16 -10
  28. package/dist/index.js +0 -8
  29. package/dist/ma-user.component.js +0 -33
  30. package/dist/mes-auth.interceptor.js +0 -36
  31. package/dist/mes-auth.module.js +0 -33
  32. package/dist/mes-auth.service.js +0 -108
  33. package/dist/notification-badge.component.js +0 -100
  34. package/dist/notification-panel.component.js +0 -327
  35. package/dist/toast-container.component.js +0 -185
  36. package/dist/toast.service.js +0 -43
  37. package/dist/user-profile.component.js +0 -363
package/dist/README.md ADDED
@@ -0,0 +1,265 @@
1
+ # mesauth-angular
2
+
3
+ Angular helper library to connect to a backend API and SignalR hub to surface the current logged-in user and incoming notifications.
4
+
5
+ ## Quick Start
6
+
7
+ 1. Install (from local folder during development):
8
+
9
+ ```bash
10
+ cd /path/to/your/angular-app
11
+ npm install ../path/to/mesauth-angular
12
+ ```
13
+
14
+ 2. Provide the service and import components:
15
+ - **For standalone components/apps**: Import `MesAuthModule` in your standalone component or `app.config.ts`.
16
+ ```ts
17
+ import { MesAuthModule } from 'mesauth-angular';
18
+
19
+ @Component({
20
+ standalone: true,
21
+ imports: [MesAuthModule, /* other imports */],
22
+ // ...
23
+ })
24
+ export class MyComponent {}
25
+ ```
26
+ Or in `app.config.ts`:
27
+ ```ts
28
+ import { MesAuthModule } from 'mesauth-angular';
29
+
30
+ export const appConfig: ApplicationConfig = {
31
+ imports: [MesAuthModule],
32
+ // ... other config
33
+ };
34
+ ```
35
+ - **For module-based apps**: Import `MesAuthModule` in your `AppModule` or feature module.
36
+ ```ts
37
+ import { MesAuthModule } from 'mesauth-angular';
38
+
39
+ @NgModule({
40
+ imports: [MesAuthModule],
41
+ // ... other config
42
+ })
43
+ export class AppModule { }
44
+ ```
45
+
46
+ 3. (Optional) Provide the HTTP interceptor to handle 403 errors:
47
+ - The interceptor redirects to `${userBaseUrl}/403?returnUrl=encodedCurrentUrl` using `window.location.href` for external URLs (since `userBaseUrl` may be outside the client app).
48
+ - **For module-based apps**: Add `MesAuthInterceptor` to providers in `AppModule`.
49
+ ```ts
50
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
51
+ import { MesAuthInterceptor } from 'mesauth-angular';
52
+
53
+ @NgModule({
54
+ // ... other module config ...
55
+ providers: [
56
+ // ... other providers ...
57
+ { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
58
+ ]
59
+ })
60
+ export class AppModule { }
61
+ ```
62
+ - **For standalone apps**: Add `MesAuthInterceptor` to providers in `app.config.ts`.
63
+ ```ts
64
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
65
+ import { MesAuthInterceptor } from 'mesauth-angular';
66
+
67
+ export const appConfig: ApplicationConfig = {
68
+ providers: [
69
+ // ... other providers ...
70
+ { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
71
+ ]
72
+ };
73
+ ```
74
+
75
+ 4. Initialize in your app (e.g. `AppComponent` constructor or `AppModule` bootstrap):
76
+
77
+ ```ts
78
+ // in AppComponent
79
+ constructor(private mesAuth: MesAuthService) {
80
+ this.mesAuth.init({
81
+ apiBaseUrl: 'https://api.example.com',
82
+ withCredentials: true,
83
+ avatarUrl: 'https://api.example.com/avatars',
84
+ userBaseUrl: 'https://api.example.com/users'
85
+ });
86
+
87
+ this.mesAuth.currentUser$.subscribe(user => console.log('user', user));
88
+ this.mesAuth.notifications$.subscribe(n => console.log('notif', n));
89
+ }
90
+ ```
91
+
92
+ Alternatively, for standalone components or functions (where constructor injection isn't available), use Angular's `inject()`:
93
+
94
+ ```ts
95
+ // In a standalone component or function
96
+ const mesAuth = inject(MesAuthService);
97
+ mesAuth.init({
98
+ apiBaseUrl: 'https://api.example.com',
99
+ withCredentials: true,
100
+ avatarUrl: 'https://api.example.com/avatars',
101
+ userBaseUrl: 'https://api.example.com/users'
102
+ });
103
+
104
+ mesAuth.currentUser$.subscribe(user => console.log('user', user));
105
+ mesAuth.notifications$.subscribe(n => console.log('notif', n));
106
+ ```
107
+
108
+ **For Standalone Apps (using `bootstrapApplication`):**
109
+ - After providing the service as above, initialize it using `APP_INITIALIZER` in your `app.config.ts` for app-wide setup, or in the root component.
110
+ - Example in `app.config.ts` (add to providers):
111
+
112
+ ```ts
113
+ import { APP_INITIALIZER } from '@angular/core';
114
+ import { MesAuthService } from 'mesauth-angular';
115
+
116
+ export const appConfig: ApplicationConfig = {
117
+ providers: [
118
+ // ... other providers ...
119
+ MesAuthService,
120
+ {
121
+ provide: APP_INITIALIZER,
122
+ useFactory: (mesAuth: MesAuthService) => () => {
123
+ mesAuth.init({
124
+ apiBaseUrl: 'https://api.example.com',
125
+ withCredentials: true,
126
+ avatarUrl: 'https://api.example.com/avatars',
127
+ userBaseUrl: 'https://api.example.com/users'
128
+ });
129
+ },
130
+ deps: [MesAuthService],
131
+ multi: true
132
+ }
133
+ ]
134
+ };
135
+ ```
136
+
137
+ - Then, in your root component (e.g., `AppComponent`), subscribe to observables as usual:
138
+
139
+ ```ts
140
+ // In AppComponent (standalone)
141
+ constructor() {
142
+ const mesAuth = inject(MesAuthService);
143
+ mesAuth.currentUser$.subscribe(user => console.log('user', user));
144
+ mesAuth.notifications$.subscribe(n => console.log('notif', n));
145
+ }
146
+ ```
147
+
148
+ 5. Build the package for publishing:
149
+
150
+ ```bash
151
+ cd /path/to/mesauth-angular
152
+ npm install
153
+ npm run build
154
+ ```
155
+
156
+ ## Components
157
+
158
+ **Note:** All components are standalone and can only be imported in standalone components or apps. If your app uses NgModules, use dynamic imports or convert to standalone.
159
+
160
+ ### ma-user-profile
161
+
162
+ A reusable Angular component for displaying the current user's profile information, with options for navigation and logout.
163
+
164
+ - **Description**: Renders user details (e.g., name, avatar) fetched via the MesAuthService. Supports custom event handlers for navigation and logout actions.
165
+ - **Inputs**: None (data is sourced from the MesAuthService).
166
+ - **Outputs**:
167
+ - `onNavigate`: Emits an event when the user triggers navigation (e.g., to a profile page). Pass a handler to define behavior.
168
+ - `onLogout`: Emits an event when the user logs out. Pass a handler to perform logout logic (e.g., clear tokens, redirect).
169
+ - **Usage Example**:
170
+
171
+ ```html
172
+ <ma-user-profile
173
+ (onNavigate)="handleNavigation($event)"
174
+ (onLogout)="handleLogout()">
175
+ </ma-user-profile>
176
+ ```
177
+
178
+ In your component's TypeScript file:
179
+
180
+ ```ts
181
+ handleNavigation(event: any) {
182
+ // Navigate to user profile page
183
+ this.router.navigate(['/profile']);
184
+ }
185
+
186
+ handleLogout() {
187
+ // Perform logout, e.g., clear session and redirect
188
+ this.mesAuth.logout(); // Assuming a logout method exists
189
+ this.router.navigate(['/login']);
190
+ }
191
+ ```
192
+
193
+ ### ma-notification-panel
194
+
195
+ A standalone component for displaying a slide-out notification panel with real-time updates.
196
+
197
+ - **Description**: Shows a list of notifications, allows marking as read/delete, and integrates with toast notifications for new alerts.
198
+ - **Inputs**: None.
199
+ - **Outputs**: None (uses internal methods for actions).
200
+ - **Usage Example**:
201
+
202
+ ```html
203
+ <ma-notification-panel #notificationPanel></ma-notification-panel>
204
+ ```
205
+
206
+ In your component:
207
+
208
+ ```ts
209
+ // To open the panel
210
+ notificationPanel.open();
211
+ ```
212
+
213
+ ## Notes
214
+ - The service expects an endpoint `GET /api/user/current` that returns the current user.
215
+ - SignalR events used: `UserUpdated` and `NewNotification` (adjust to your backend).
216
+
217
+ ## Troubleshooting
218
+
219
+ ### JIT Compiler Error in Production or AOT Mode
220
+ If you encounter an error like "The injectable 'MesAuthService' needs to be compiled using the JIT compiler, but '@angular/compiler' is not available," this typically occurs because:
221
+ - The package is being imported directly from source code (e.g., during development) without building it first.
222
+ - The client app is running in AOT (Ahead-of-Time) compilation mode, which requires pre-compiled libraries.
223
+ - **Why JIT is required:** Originally, `MesAuthService` used `@Injectable({ providedIn: 'root' })`, making it a library-provided service. Angular libraries must be built with tools like ng-packagr to generate AOT-compatible code. If not, or if imported from source, the service requires JIT compilation in the client's app. This change (removing `providedIn: 'root'` and requiring manual provision) allows the service to be compiled in your app's context, supporting both JIT and AOT modes.
224
+
225
+ **Solutions:**
226
+ 1. **Build the package for production/AOT compatibility:**
227
+ - Ensure you have built the package using `npm run build` (which uses ng-packagr or similar to generate AOT-ready code).
228
+ - Install the built package via npm (e.g., from a local tarball or registry) instead of linking to the source folder.
229
+
230
+ 2. **For development (if you must link to source):**
231
+ - Switch your Angular app to JIT mode by bootstrapping with `@angular/platform-browser-dynamic` instead of `@angular/platform-browser`.
232
+ - Example in `main.ts`:
233
+ ```ts
234
+ import { platformBrowserDynamic } from '@angular/platform-browser-dynamic';
235
+ import { AppModule } from './app/app.module';
236
+
237
+ platformBrowserDynamic().bootstrapModule(AppModule);
238
+ ```
239
+ - Note: JIT is not recommended for production; use AOT for better performance.
240
+
241
+ 3. **Verify imports:**
242
+ - Ensure you're importing from the built package (e.g., `import { MesAuthService } from 'mesauth-angular';`) and not from the `src` folder.
243
+ - If using standalone components, confirm the service is available in the injection context.
244
+
245
+ If issues persist, check your Angular version compatibility and ensure the package's `package.json` includes the correct entry points for AOT.
246
+
247
+ ### Components Appear Empty
248
+ If components like `ma-user` or `ma-user-profile` render as empty:
249
+ - Ensure `MesAuthService` is provided in your app (see Quick Start step 2).
250
+ - Check browser console for logs from components (e.g., "UserProfileComponent: currentUser").
251
+ - If `currentUser` is null, the component shows a login button—verify the service is initialized and the API returns user data.
252
+ - For standalone apps, confirm `APP_INITIALIZER` or manual init is used.
253
+
254
+ ---
255
+
256
+ # Dynamic import in a module-based component
257
+ import { Component } from '@angular/core';
258
+
259
+ @Component({...})
260
+ export class DefaultHeaderComponent {
261
+ async ngOnInit() {
262
+ const { MaUserComponent } = await import('mesauth-angular');
263
+ // Use it dynamically
264
+ }
265
+ }
@@ -0,0 +1,9 @@
1
+ export * from './mes-auth.service';
2
+ export * from './mes-auth.interceptor';
3
+ export * from './mes-auth.module';
4
+ export * from './user-profile.component';
5
+ export * from './ma-user.component';
6
+ export * from './notification-badge.component';
7
+ export * from './notification-panel.component';
8
+ export * from './toast-container.component';
9
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoiaW5kZXguanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvaW5kZXgudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsY0FBYyxvQkFBb0IsQ0FBQztBQUNuQyxjQUFjLHdCQUF3QixDQUFDO0FBQ3ZDLGNBQWMsbUJBQW1CLENBQUM7QUFDbEMsY0FBYywwQkFBMEIsQ0FBQztBQUN6QyxjQUFjLHFCQUFxQixDQUFDO0FBQ3BDLGNBQWMsZ0NBQWdDLENBQUM7QUFDL0MsY0FBYyxnQ0FBZ0MsQ0FBQztBQUMvQyxjQUFjLDZCQUE2QixDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiZXhwb3J0ICogZnJvbSAnLi9tZXMtYXV0aC5zZXJ2aWNlJztcclxuZXhwb3J0ICogZnJvbSAnLi9tZXMtYXV0aC5pbnRlcmNlcHRvcic7XHJcbmV4cG9ydCAqIGZyb20gJy4vbWVzLWF1dGgubW9kdWxlJztcclxuZXhwb3J0ICogZnJvbSAnLi91c2VyLXByb2ZpbGUuY29tcG9uZW50JztcclxuZXhwb3J0ICogZnJvbSAnLi9tYS11c2VyLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbm90aWZpY2F0aW9uLWJhZGdlLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vbm90aWZpY2F0aW9uLXBhbmVsLmNvbXBvbmVudCc7XHJcbmV4cG9ydCAqIGZyb20gJy4vdG9hc3QtY29udGFpbmVyLmNvbXBvbmVudCc7Il19
@@ -0,0 +1,26 @@
1
+ import { Component } from '@angular/core';
2
+ import { ToastContainerComponent } from './toast-container.component';
3
+ import { UserProfileComponent } from './user-profile.component';
4
+ import { NotificationPanelComponent } from './notification-panel.component';
5
+ import * as i0 from "@angular/core";
6
+ export class MaUserComponent {
7
+ }
8
+ MaUserComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MaUserComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
9
+ MaUserComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: MaUserComponent, isStandalone: true, selector: "ma-user", ngImport: i0, template: `
10
+ <ma-toast-container></ma-toast-container>
11
+ <div class="user-header">
12
+ <ma-user-profile (notificationClick)="notificationPanel.open()"></ma-user-profile>
13
+ </div>
14
+ <ma-notification-panel #notificationPanel></ma-notification-panel>
15
+ `, isInline: true, styles: [".user-header{display:flex;justify-content:flex-end}\n"], dependencies: [{ kind: "component", type: ToastContainerComponent, selector: "ma-toast-container" }, { kind: "component", type: UserProfileComponent, selector: "ma-user-profile", outputs: ["notificationClick"] }, { kind: "component", type: NotificationPanelComponent, selector: "ma-notification-panel" }] });
16
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MaUserComponent, decorators: [{
17
+ type: Component,
18
+ args: [{ selector: 'ma-user', standalone: true, imports: [ToastContainerComponent, UserProfileComponent, NotificationPanelComponent], template: `
19
+ <ma-toast-container></ma-toast-container>
20
+ <div class="user-header">
21
+ <ma-user-profile (notificationClick)="notificationPanel.open()"></ma-user-profile>
22
+ </div>
23
+ <ma-notification-panel #notificationPanel></ma-notification-panel>
24
+ `, styles: [".user-header{display:flex;justify-content:flex-end}\n"] }]
25
+ }] });
26
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWEtdXNlci5jb21wb25lbnQuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWEtdXNlci5jb21wb25lbnQudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUMxQyxPQUFPLEVBQUUsdUJBQXVCLEVBQUUsTUFBTSw2QkFBNkIsQ0FBQztBQUN0RSxPQUFPLEVBQUUsb0JBQW9CLEVBQUUsTUFBTSwwQkFBMEIsQ0FBQztBQUNoRSxPQUFPLEVBQUUsMEJBQTBCLEVBQUUsTUFBTSxnQ0FBZ0MsQ0FBQzs7QUFvQjVFLE1BQU0sT0FBTyxlQUFlOzs0R0FBZixlQUFlO2dHQUFmLGVBQWUsbUVBZGhCOzs7Ozs7R0FNVCwrSEFQUyx1QkFBdUIsK0RBQUUsb0JBQW9CLDRGQUFFLDBCQUEwQjsyRkFleEUsZUFBZTtrQkFsQjNCLFNBQVM7K0JBQ0UsU0FBUyxjQUNQLElBQUksV0FDUCxDQUFDLHVCQUF1QixFQUFFLG9CQUFvQixFQUFFLDBCQUEwQixDQUFDLFlBQzFFOzs7Ozs7R0FNVCIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IENvbXBvbmVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBUb2FzdENvbnRhaW5lckNvbXBvbmVudCB9IGZyb20gJy4vdG9hc3QtY29udGFpbmVyLmNvbXBvbmVudCc7XHJcbmltcG9ydCB7IFVzZXJQcm9maWxlQ29tcG9uZW50IH0gZnJvbSAnLi91c2VyLXByb2ZpbGUuY29tcG9uZW50JztcclxuaW1wb3J0IHsgTm90aWZpY2F0aW9uUGFuZWxDb21wb25lbnQgfSBmcm9tICcuL25vdGlmaWNhdGlvbi1wYW5lbC5jb21wb25lbnQnO1xyXG5cclxuQENvbXBvbmVudCh7XHJcbiAgc2VsZWN0b3I6ICdtYS11c2VyJyxcclxuICBzdGFuZGFsb25lOiB0cnVlLFxyXG4gIGltcG9ydHM6IFtUb2FzdENvbnRhaW5lckNvbXBvbmVudCwgVXNlclByb2ZpbGVDb21wb25lbnQsIE5vdGlmaWNhdGlvblBhbmVsQ29tcG9uZW50XSxcclxuICB0ZW1wbGF0ZTogYFxyXG4gICAgPG1hLXRvYXN0LWNvbnRhaW5lcj48L21hLXRvYXN0LWNvbnRhaW5lcj5cclxuICAgIDxkaXYgY2xhc3M9XCJ1c2VyLWhlYWRlclwiPlxyXG4gICAgICA8bWEtdXNlci1wcm9maWxlIChub3RpZmljYXRpb25DbGljayk9XCJub3RpZmljYXRpb25QYW5lbC5vcGVuKClcIj48L21hLXVzZXItcHJvZmlsZT5cclxuICAgIDwvZGl2PlxyXG4gICAgPG1hLW5vdGlmaWNhdGlvbi1wYW5lbCAjbm90aWZpY2F0aW9uUGFuZWw+PC9tYS1ub3RpZmljYXRpb24tcGFuZWw+XHJcbiAgYCxcclxuICBzdHlsZXM6IFtgXHJcbiAgICAudXNlci1oZWFkZXIge1xyXG4gICAgICBkaXNwbGF5OiBmbGV4O1xyXG4gICAgICBqdXN0aWZ5LWNvbnRlbnQ6IGZsZXgtZW5kO1xyXG4gICAgfVxyXG4gIGBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNYVVzZXJDb21wb25lbnQge31cclxuIl19
@@ -0,0 +1,29 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { throwError } from 'rxjs';
3
+ import { catchError } from 'rxjs/operators';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "./mes-auth.service";
6
+ import * as i2 from "@angular/router";
7
+ export class MesAuthInterceptor {
8
+ constructor(authService, router) {
9
+ this.authService = authService;
10
+ this.router = router;
11
+ }
12
+ intercept(req, next) {
13
+ return next.handle(req).pipe(catchError((error) => {
14
+ if (error.status === 403) {
15
+ const config = this.authService.getConfig();
16
+ const baseUrl = config?.userBaseUrl || '';
17
+ const returnUrl = encodeURIComponent(window.location.href);
18
+ window.location.href = `${baseUrl}/403?returnUrl=${returnUrl}`;
19
+ }
20
+ return throwError(error);
21
+ }));
22
+ }
23
+ }
24
+ MesAuthInterceptor.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthInterceptor, deps: [{ token: i1.MesAuthService }, { token: i2.Router }], target: i0.ɵɵFactoryTarget.Injectable });
25
+ MesAuthInterceptor.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthInterceptor });
26
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthInterceptor, decorators: [{
27
+ type: Injectable
28
+ }], ctorParameters: function () { return [{ type: i1.MesAuthService }, { type: i2.Router }]; } });
29
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzLWF1dGguaW50ZXJjZXB0b3IuanMiLCJzb3VyY2VSb290IjoiIiwic291cmNlcyI6WyIuLi8uLi9zcmMvbWVzLWF1dGguaW50ZXJjZXB0b3IudHMiXSwibmFtZXMiOltdLCJtYXBwaW5ncyI6IkFBQUEsT0FBTyxFQUFFLFVBQVUsRUFBRSxNQUFNLGVBQWUsQ0FBQztBQUUzQyxPQUFPLEVBQWMsVUFBVSxFQUFFLE1BQU0sTUFBTSxDQUFDO0FBQzlDLE9BQU8sRUFBRSxVQUFVLEVBQUUsTUFBTSxnQkFBZ0IsQ0FBQzs7OztBQUs1QyxNQUFNLE9BQU8sa0JBQWtCO0lBQzdCLFlBQW9CLFdBQTJCLEVBQVUsTUFBYztRQUFuRCxnQkFBVyxHQUFYLFdBQVcsQ0FBZ0I7UUFBVSxXQUFNLEdBQU4sTUFBTSxDQUFRO0lBQUcsQ0FBQztJQUUzRSxTQUFTLENBQUMsR0FBcUIsRUFBRSxJQUFpQjtRQUNoRCxPQUFPLElBQUksQ0FBQyxNQUFNLENBQUMsR0FBRyxDQUFDLENBQUMsSUFBSSxDQUMxQixVQUFVLENBQUMsQ0FBQyxLQUF3QixFQUFFLEVBQUU7WUFDdEMsSUFBSSxLQUFLLENBQUMsTUFBTSxLQUFLLEdBQUcsRUFBRTtnQkFDeEIsTUFBTSxNQUFNLEdBQUcsSUFBSSxDQUFDLFdBQVcsQ0FBQyxTQUFTLEVBQUUsQ0FBQztnQkFDNUMsTUFBTSxPQUFPLEdBQUcsTUFBTSxFQUFFLFdBQVcsSUFBSSxFQUFFLENBQUM7Z0JBQzFDLE1BQU0sU0FBUyxHQUFHLGtCQUFrQixDQUFDLE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxDQUFDLENBQUM7Z0JBQzNELE1BQU0sQ0FBQyxRQUFRLENBQUMsSUFBSSxHQUFHLEdBQUcsT0FBTyxrQkFBa0IsU0FBUyxFQUFFLENBQUM7YUFDaEU7WUFDRCxPQUFPLFVBQVUsQ0FBQyxLQUFLLENBQUMsQ0FBQztRQUMzQixDQUFDLENBQUMsQ0FDSCxDQUFDO0lBQ0osQ0FBQzs7K0dBZlUsa0JBQWtCO21IQUFsQixrQkFBa0I7MkZBQWxCLGtCQUFrQjtrQkFEOUIsVUFBVSIsInNvdXJjZXNDb250ZW50IjpbImltcG9ydCB7IEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgSHR0cEludGVyY2VwdG9yLCBIdHRwUmVxdWVzdCwgSHR0cEhhbmRsZXIsIEh0dHBFdmVudCwgSHR0cEVycm9yUmVzcG9uc2UgfSBmcm9tICdAYW5ndWxhci9jb21tb24vaHR0cCc7XHJcbmltcG9ydCB7IE9ic2VydmFibGUsIHRocm93RXJyb3IgfSBmcm9tICdyeGpzJztcclxuaW1wb3J0IHsgY2F0Y2hFcnJvciB9IGZyb20gJ3J4anMvb3BlcmF0b3JzJztcclxuaW1wb3J0IHsgUm91dGVyIH0gZnJvbSAnQGFuZ3VsYXIvcm91dGVyJztcclxuaW1wb3J0IHsgTWVzQXV0aFNlcnZpY2UgfSBmcm9tICcuL21lcy1hdXRoLnNlcnZpY2UnO1xyXG5cclxuQEluamVjdGFibGUoKVxyXG5leHBvcnQgY2xhc3MgTWVzQXV0aEludGVyY2VwdG9yIGltcGxlbWVudHMgSHR0cEludGVyY2VwdG9yIHtcclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGF1dGhTZXJ2aWNlOiBNZXNBdXRoU2VydmljZSwgcHJpdmF0ZSByb3V0ZXI6IFJvdXRlcikge31cclxuXHJcbiAgaW50ZXJjZXB0KHJlcTogSHR0cFJlcXVlc3Q8YW55PiwgbmV4dDogSHR0cEhhbmRsZXIpOiBPYnNlcnZhYmxlPEh0dHBFdmVudDxhbnk+PiB7XHJcbiAgICByZXR1cm4gbmV4dC5oYW5kbGUocmVxKS5waXBlKFxyXG4gICAgICBjYXRjaEVycm9yKChlcnJvcjogSHR0cEVycm9yUmVzcG9uc2UpID0+IHtcclxuICAgICAgICBpZiAoZXJyb3Iuc3RhdHVzID09PSA0MDMpIHtcclxuICAgICAgICAgIGNvbnN0IGNvbmZpZyA9IHRoaXMuYXV0aFNlcnZpY2UuZ2V0Q29uZmlnKCk7XHJcbiAgICAgICAgICBjb25zdCBiYXNlVXJsID0gY29uZmlnPy51c2VyQmFzZVVybCB8fCAnJztcclxuICAgICAgICAgIGNvbnN0IHJldHVyblVybCA9IGVuY29kZVVSSUNvbXBvbmVudCh3aW5kb3cubG9jYXRpb24uaHJlZik7XHJcbiAgICAgICAgICB3aW5kb3cubG9jYXRpb24uaHJlZiA9IGAke2Jhc2VVcmx9LzQwMz9yZXR1cm5Vcmw9JHtyZXR1cm5Vcmx9YDtcclxuICAgICAgICB9XHJcbiAgICAgICAgcmV0dXJuIHRocm93RXJyb3IoZXJyb3IpO1xyXG4gICAgICB9KVxyXG4gICAgKTtcclxuICB9XHJcbn1cclxuIl19
@@ -0,0 +1,23 @@
1
+ import { NgModule } from '@angular/core';
2
+ import { HTTP_INTERCEPTORS } from '@angular/common/http';
3
+ import { MesAuthService } from './mes-auth.service';
4
+ import { MesAuthInterceptor } from './mes-auth.interceptor';
5
+ import * as i0 from "@angular/core";
6
+ export class MesAuthModule {
7
+ }
8
+ MesAuthModule.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
9
+ MesAuthModule.ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "14.3.0", ngImport: i0, type: MesAuthModule });
10
+ MesAuthModule.ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthModule, providers: [
11
+ MesAuthService,
12
+ { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
13
+ ] });
14
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthModule, decorators: [{
15
+ type: NgModule,
16
+ args: [{
17
+ providers: [
18
+ MesAuthService,
19
+ { provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
20
+ ]
21
+ }]
22
+ }] });
23
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzLWF1dGgubW9kdWxlLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21lcy1hdXRoLm1vZHVsZS50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQSxPQUFPLEVBQUUsUUFBUSxFQUFFLE1BQU0sZUFBZSxDQUFDO0FBQ3pDLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxNQUFNLHNCQUFzQixDQUFDO0FBQ3pELE9BQU8sRUFBRSxjQUFjLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNwRCxPQUFPLEVBQUUsa0JBQWtCLEVBQUUsTUFBTSx3QkFBd0IsQ0FBQzs7QUFRNUQsTUFBTSxPQUFPLGFBQWE7OzBHQUFiLGFBQWE7MkdBQWIsYUFBYTsyR0FBYixhQUFhLGFBTGI7UUFDVCxjQUFjO1FBQ2QsRUFBRSxPQUFPLEVBQUUsaUJBQWlCLEVBQUUsUUFBUSxFQUFFLGtCQUFrQixFQUFFLEtBQUssRUFBRSxJQUFJLEVBQUU7S0FDMUU7MkZBRVUsYUFBYTtrQkFOekIsUUFBUTttQkFBQztvQkFDUixTQUFTLEVBQUU7d0JBQ1QsY0FBYzt3QkFDZCxFQUFFLE9BQU8sRUFBRSxpQkFBaUIsRUFBRSxRQUFRLEVBQUUsa0JBQWtCLEVBQUUsS0FBSyxFQUFFLElBQUksRUFBRTtxQkFDMUU7aUJBQ0YiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBOZ01vZHVsZSB9IGZyb20gJ0Bhbmd1bGFyL2NvcmUnO1xyXG5pbXBvcnQgeyBIVFRQX0lOVEVSQ0VQVE9SUyB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcclxuaW1wb3J0IHsgTWVzQXV0aFNlcnZpY2UgfSBmcm9tICcuL21lcy1hdXRoLnNlcnZpY2UnO1xyXG5pbXBvcnQgeyBNZXNBdXRoSW50ZXJjZXB0b3IgfSBmcm9tICcuL21lcy1hdXRoLmludGVyY2VwdG9yJztcclxuXHJcbkBOZ01vZHVsZSh7XHJcbiAgcHJvdmlkZXJzOiBbXHJcbiAgICBNZXNBdXRoU2VydmljZSxcclxuICAgIHsgcHJvdmlkZTogSFRUUF9JTlRFUkNFUFRPUlMsIHVzZUNsYXNzOiBNZXNBdXRoSW50ZXJjZXB0b3IsIG11bHRpOiB0cnVlIH1cclxuICBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBNZXNBdXRoTW9kdWxlIHt9XHJcbiJdfQ==
@@ -0,0 +1,103 @@
1
+ import { Injectable } from '@angular/core';
2
+ import { HubConnectionBuilder, LogLevel } from '@microsoft/signalr';
3
+ import { BehaviorSubject, Subject } from 'rxjs';
4
+ import * as i0 from "@angular/core";
5
+ import * as i1 from "@angular/common/http";
6
+ export var NotificationType;
7
+ (function (NotificationType) {
8
+ NotificationType["Info"] = "Info";
9
+ NotificationType["Warning"] = "Warning";
10
+ NotificationType["Error"] = "Error";
11
+ NotificationType["Success"] = "Success";
12
+ })(NotificationType || (NotificationType = {}));
13
+ export class MesAuthService {
14
+ constructor(http) {
15
+ this.http = http;
16
+ this.hubConnection = null;
17
+ this._currentUser = new BehaviorSubject(null);
18
+ this.currentUser$ = this._currentUser.asObservable();
19
+ this._notifications = new Subject();
20
+ this.notifications$ = this._notifications.asObservable();
21
+ this.apiBase = '';
22
+ this.config = null;
23
+ }
24
+ init(config) {
25
+ this.config = config;
26
+ this.apiBase = config.apiBaseUrl.replace(/\/$/, '');
27
+ this.fetchCurrentUser();
28
+ this.fetchInitialNotifications();
29
+ this.startConnection(config);
30
+ }
31
+ getConfig() {
32
+ return this.config;
33
+ }
34
+ fetchCurrentUser() {
35
+ if (!this.apiBase)
36
+ return;
37
+ this.http.get(`${this.apiBase}/auth/me`).subscribe({
38
+ next: (u) => this._currentUser.next(u),
39
+ error: (err) => console.error('fetchCurrentUser error', err)
40
+ });
41
+ }
42
+ fetchInitialNotifications() {
43
+ if (!this.apiBase)
44
+ return;
45
+ this.http.get(`${this.apiBase}/notif/me`).subscribe({
46
+ next: (notifications) => {
47
+ if (Array.isArray(notifications?.items)) {
48
+ notifications.items.forEach((n) => this._notifications.next(n));
49
+ }
50
+ },
51
+ error: (err) => console.error('fetchInitialNotifications error', err)
52
+ });
53
+ }
54
+ getUnreadCount() {
55
+ return this.http.get(`${this.apiBase}/notif/me/unread-count`);
56
+ }
57
+ getNotifications(page = 1, pageSize = 20, includeRead = false, type) {
58
+ let url = `${this.apiBase}/notif/me?page=${page}&pageSize=${pageSize}&includeRead=${includeRead}`;
59
+ if (type) {
60
+ url += `&type=${type}`;
61
+ }
62
+ return this.http.get(url);
63
+ }
64
+ markAsRead(notificationId) {
65
+ return this.http.patch(`${this.apiBase}/notif/${notificationId}/read`, {});
66
+ }
67
+ markAllAsRead() {
68
+ return this.http.patch(`${this.apiBase}/notif/me/read-all`, {});
69
+ }
70
+ deleteNotification(notificationId) {
71
+ return this.http.delete(`${this.apiBase}/notif/${notificationId}`);
72
+ }
73
+ startConnection(config) {
74
+ if (this.hubConnection)
75
+ return;
76
+ const signalrUrl = config.apiBaseUrl.replace(/\/$/, '') + '/hub/notification';
77
+ const builder = new HubConnectionBuilder()
78
+ .withUrl(signalrUrl, { withCredentials: config.withCredentials ?? true })
79
+ .withAutomaticReconnect()
80
+ .configureLogging(LogLevel.Warning);
81
+ this.hubConnection = builder.build();
82
+ this.hubConnection.on('ReceiveNotification', (n) => this._notifications.next(n));
83
+ this.hubConnection.start().catch((err) => console.error('SignalR start error', err));
84
+ }
85
+ stop() {
86
+ if (!this.hubConnection)
87
+ return;
88
+ this.hubConnection.stop().catch(() => { });
89
+ this.hubConnection = null;
90
+ }
91
+ logout() {
92
+ return this.http.post(`${this.apiBase}/auth/logout`, {});
93
+ }
94
+ refreshUser() {
95
+ this.fetchCurrentUser();
96
+ }
97
+ }
98
+ MesAuthService.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthService, deps: [{ token: i1.HttpClient }], target: i0.ɵɵFactoryTarget.Injectable });
99
+ MesAuthService.ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthService });
100
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: MesAuthService, decorators: [{
101
+ type: Injectable
102
+ }], ctorParameters: function () { return [{ type: i1.HttpClient }]; } });
103
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzLWF1dGguc2VydmljZS5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9tZXMtYXV0aC5zZXJ2aWNlLnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBVSxVQUFVLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFFbkQsT0FBTyxFQUFpQixvQkFBb0IsRUFBRSxRQUFRLEVBQUUsTUFBTSxvQkFBb0IsQ0FBQztBQUNuRixPQUFPLEVBQUUsZUFBZSxFQUFFLE9BQU8sRUFBYyxNQUFNLE1BQU0sQ0FBQzs7O0FBcUM1RCxNQUFNLENBQU4sSUFBWSxnQkFLWDtBQUxELFdBQVksZ0JBQWdCO0lBQzFCLGlDQUFhLENBQUE7SUFDYix1Q0FBbUIsQ0FBQTtJQUNuQixtQ0FBZSxDQUFBO0lBQ2YsdUNBQW1CLENBQUE7QUFDckIsQ0FBQyxFQUxXLGdCQUFnQixLQUFoQixnQkFBZ0IsUUFLM0I7QUFzQ0QsTUFBTSxPQUFPLGNBQWM7SUFVekIsWUFBb0IsSUFBZ0I7UUFBaEIsU0FBSSxHQUFKLElBQUksQ0FBWTtRQVQ1QixrQkFBYSxHQUF5QixJQUFJLENBQUM7UUFDM0MsaUJBQVksR0FBRyxJQUFJLGVBQWUsQ0FBZSxJQUFJLENBQUMsQ0FBQztRQUN4RCxpQkFBWSxHQUE2QixJQUFJLENBQUMsWUFBWSxDQUFDLFlBQVksRUFBRSxDQUFDO1FBQ3pFLG1CQUFjLEdBQUcsSUFBSSxPQUFPLEVBQU8sQ0FBQztRQUNyQyxtQkFBYyxHQUFvQixJQUFJLENBQUMsY0FBYyxDQUFDLFlBQVksRUFBRSxDQUFDO1FBRXBFLFlBQU8sR0FBRyxFQUFFLENBQUM7UUFDYixXQUFNLEdBQXlCLElBQUksQ0FBQztJQUVMLENBQUM7SUFFeEMsSUFBSSxDQUFDLE1BQXFCO1FBQ3hCLElBQUksQ0FBQyxNQUFNLEdBQUcsTUFBTSxDQUFDO1FBQ3JCLElBQUksQ0FBQyxPQUFPLEdBQUcsTUFBTSxDQUFDLFVBQVUsQ0FBQyxPQUFPLENBQUMsS0FBSyxFQUFFLEVB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QUFjOzJGQUFkLGNBQWM7a0JBRDFCLFVBQVUiLCJzb3VyY2VzQ29udGVudCI6WyJpbXBvcnQgeyBpbmplY3QsIEluamVjdGFibGUgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgSHR0cENsaWVudCB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbi9odHRwJztcclxuaW1wb3J0IHsgSHViQ29ubmVjdGlvbiwgSHViQ29ubmVjdGlvbkJ1aWxkZXIsIExvZ0xldmVsIH0gZnJvbSAnQG1pY3Jvc29mdC9zaWduYWxyJztcclxuaW1wb3J0IHsgQmVoYXZpb3JTdWJqZWN0LCBTdWJqZWN0LCBPYnNlcnZhYmxlIH0gZnJvbSAncnhqcyc7XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIE1lc0F1dGhDb25maWcgeyAgXHJcbiAgYXBpQmFzZVVybDogc3RyaW5nO1xyXG4gIHdpdGhDcmVkZW50aWFscz86IGJvb2xlYW47XHJcbiAgYXZhdGFyVXJsPzogc3RyaW5nO1xyXG4gIHVzZXJCYXNlVXJsPzogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIElVc2VyIHtcclxuICB1c2VySWQ/OiBzdHJpbmc7XHJcbiAgdXNlck5hbWU/OiBzdHJpbmc7XHJcbiAgZnVsbE5hbWU/OiBzdHJpbmc7XHJcbiAgZ2VuZGVyPzogc3RyaW5nO1xyXG4gIGVtYWlsPzogc3RyaW5nO1xyXG4gIHBob25lTnVtYmVyPzogc3RyaW5nO1xyXG4gIGRlcGFydG1lbnQ/OiBzdHJpbmc7XHJcbiAgcG9zaXRpb24/OiBzdHJpbmc7XHJcbiAgdG9rZW5WZXJzaW9uPzogc3RyaW5nO1xyXG4gIHBlcm1FbmRwb2ludD86IHN0cmluZztcclxuICBwZXJtcz86IFNldDxzdHJpbmc+O1xyXG4gIGVtcGxveWVlQ29kZT86IHN0cmluZztcclxuICBockZ1bGxOYW1lVm4/OiBzdHJpbmc7XHJcbiAgaHJGdWxsTmFtZUVuPzogc3RyaW5nO1xyXG4gIGhyUG9zaXRpb24/OiBzdHJpbmc7XHJcbiAgaHJKb2JUaXRsZT86IHN0cmluZztcclxuICBockdlbmRlcj86IHN0cmluZztcclxuICBock1vYmlsZT86IHN0cmluZztcclxuICBockVtYWlsPzogc3RyaW5nO1xyXG4gIGhySm9pbkRhdGU/OiBzdHJpbmc7XHJcbiAgaHJCaXJ0aERhdGU/OiBzdHJpbmc7XHJcbiAgaHJXb3JrU3RhdHVzPzogc3RyaW5nO1xyXG4gIGhyRG9pVHVvbmc/OiBzdHJpbmc7XHJcbiAgaHJUZWFtQ29kZT86IHN0cmluZztcclxuICBockxpbmVDb2RlPzogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgZW51bSBOb3RpZmljYXRpb25UeXBlIHtcclxuICBJbmZvID0gJ0luZm8nLFxyXG4gIFdhcm5pbmcgPSAnV2FybmluZycsXHJcbiAgRXJyb3IgPSAnRXJyb3InLFxyXG4gIFN1Y2Nlc3MgPSAnU3VjY2VzcydcclxufVxyXG5cclxuZXhwb3J0IGludGVyZmFjZSBOb3RpZmljYXRpb25EdG8ge1xyXG4gIGlkOiBzdHJpbmc7XHJcbiAgdGl0bGU6IHN0cmluZztcclxuICBtZXNzYWdlOiBzdHJpbmc7XHJcbiAgbWVzc2FnZUh0bWw/OiBzdHJpbmc7XHJcbiAgdXJsPzogc3RyaW5nO1xyXG4gIHR5cGU6IE5vdGlmaWNhdGlvblR5cGU7XHJcbiAgaXNSZWFkOiBib29sZWFuO1xyXG4gIGNyZWF0ZWRBdDogc3RyaW5nO1xyXG4gIHNvdXJjZUFwcE5hbWU6IHN0cmluZztcclxuICBzb3VyY2VBcHBJY29uVXJsPzogc3RyaW5nO1xyXG59XHJcblxyXG5leHBvcnQgaW50ZXJmYWNlIFBhZ2VkTGlzdDxUPiB7XHJcbiAgaXRlbXM6IFRbXTtcclxuICB0b3RhbENvdW50OiBudW1iZXI7XHJcbiAgcGFnZTogbnVtYmVyO1xyXG4gIHBhZ2VTaXplOiBudW1iZXI7XHJcbiAgdG90YWxQYWdlczogbnVtYmVyO1xyXG4gIGhhc05leHQ6IGJvb2xlYW47XHJcbiAgaGFzUHJldmlvdXM6IGJvb2xlYW47XHJcbn1cclxuXHJcbmV4cG9ydCBpbnRlcmZhY2UgUmVhbFRpbWVOb3RpZmljYXRpb25EdG8ge1xyXG4gIGlkOiBzdHJpbmc7XHJcbiAgdGl0bGU6IHN0cmluZztcclxuICBtZXNzYWdlOiBzdHJpbmc7XHJcbiAgbWVzc2FnZUh0bWw/OiBzdHJpbmc7XHJcbiAgdXJsPzogc3RyaW5nO1xyXG4gIHR5cGU6IE5vdGlmaWNhdGlvblR5cGU7XHJcbiAgY3JlYXRlZEF0OiBzdHJpbmc7XHJcbiAgc291cmNlQXBwTmFtZTogc3RyaW5nO1xyXG4gIHNvdXJjZUFwcEljb25Vcmw/OiBzdHJpbmc7XHJcbn1cclxuXHJcbkBJbmplY3RhYmxlKClcclxuZXhwb3J0IGNsYXNzIE1lc0F1dGhTZXJ2aWNlIHtcclxuICBwcml2YXRlIGh1YkNvbm5lY3Rpb246IEh1YkNvbm5lY3Rpb24gfCBudWxsID0gbnVsbDtcclxuICBwcml2YXRlIF9jdXJyZW50VXNlciA9IG5ldyBCZWhhdmlvclN1YmplY3Q8SVVzZXIgfCBudWxsPihudWxsKTtcclxuICBwdWJsaWMgY3VycmVudFVzZXIkOiBPYnNlcnZhYmxlPElVc2VyIHwgbnVsbD4gPSB0aGlzLl9jdXJyZW50VXNlci5hc09ic2VydmFibGUoKTtcclxuICBwcml2YXRlIF9ub3RpZmljYXRpb25zID0gbmV3IFN1YmplY3Q8YW55PigpO1xyXG4gIHB1YmxpYyBub3RpZmljYXRpb25zJDogT2JzZXJ2YWJsZTxhbnk+ID0gdGhpcy5fbm90aWZpY2F0aW9ucy5hc09ic2VydmFibGUoKTtcclxuXHJcbiAgcHJpdmF0ZSBhcGlCYXNlID0gJyc7XHJcbiAgcHJpdmF0ZSBjb25maWc6IE1lc0F1dGhDb25maWcgfCBudWxsID0gbnVsbDtcclxuXHJcbiAgY29uc3RydWN0b3IocHJpdmF0ZSBodHRwOiBIdHRwQ2xpZW50KSB7fVxyXG5cclxuICBpbml0KGNvbmZpZzogTWVzQXV0aENvbmZpZykge1xyXG4gICAgdGhpcy5jb25maWcgPSBjb25maWc7XHJcbiAgICB0aGlzLmFwaUJhc2UgPSBjb25maWcuYXBpQmFzZVVybC5yZXBsYWNlKC9cXC8kLywgJycpO1xyXG4gICAgdGhpcy5mZXRjaEN1cnJlbnRVc2VyKCk7XHJcbiAgICB0aGlzLmZldGNoSW5pdGlhbE5vdGlmaWNhdGlvbnMoKTtcclxuICAgIHRoaXMuc3RhcnRDb25uZWN0aW9uKGNvbmZpZyk7XHJcbiAgfVxyXG5cclxuICBnZXRDb25maWcoKTogTWVzQXV0aENvbmZpZyB8IG51bGwge1xyXG4gICAgcmV0dXJuIHRoaXMuY29uZmlnO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBmZXRjaEN1cnJlbnRVc2VyKCkge1xyXG4gICAgaWYgKCF0aGlzLmFwaUJhc2UpIHJldHVybjtcclxuICAgIHRoaXMuaHR0cC5nZXQoYCR7dGhpcy5hcGlCYXNlfS9hdXRoL21lYCkuc3Vic2NyaWJlKHtcclxuICAgICAgbmV4dDogKHUpID0+IHRoaXMuX2N1cnJlbnRVc2VyLm5leHQodSksXHJcbiAgICAgIGVycm9yOiAoZXJyKSA9PiBjb25zb2xlLmVycm9yKCdmZXRjaEN1cnJlbnRVc2VyIGVycm9yJywgZXJyKVxyXG4gICAgfSk7XHJcbiAgfVxyXG5cclxuICBwcml2YXRlIGZldGNoSW5pdGlhbE5vdGlmaWNhdGlvbnMoKSB7XHJcbiAgICBpZiAoIXRoaXMuYXBpQmFzZSkgcmV0dXJuO1xyXG4gICAgdGhpcy5odHRwLmdldChgJHt0aGlzLmFwaUJhc2V9L25vdGlmL21lYCkuc3Vic2NyaWJlKHtcclxuICAgICAgbmV4dDogKG5vdGlmaWNhdGlvbnM6IGFueSkgPT4ge1xyXG4gICAgICAgIGlmIChBcnJheS5pc0FycmF5KG5vdGlmaWNhdGlvbnM/Lml0ZW1zKSkge1xyXG4gICAgICAgICAgbm90aWZpY2F0aW9ucy5pdGVtcy5mb3JFYWNoKChuOiBhbnkpID0+IHRoaXMuX25vdGlmaWNhdGlvbnMubmV4dChuKSk7XHJcbiAgICAgICAgfVxyXG4gICAgICB9LFxyXG4gICAgICBlcnJvcjogKGVycikgPT4gY29uc29sZS5lcnJvcignZmV0Y2hJbml0aWFsTm90aWZpY2F0aW9ucyBlcnJvcicsIGVycilcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGdldFVucmVhZENvdW50KCk6IE9ic2VydmFibGU8YW55PiB7XHJcbiAgICByZXR1cm4gdGhpcy5odHRwLmdldChgJHt0aGlzLmFwaUJhc2V9L25vdGlmL21lL3VucmVhZC1jb3VudGApO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGdldE5vdGlmaWNhdGlvbnMocGFnZTogbnVtYmVyID0gMSwgcGFnZVNpemU6IG51bWJlciA9IDIwLCBpbmNsdWRlUmVhZDogYm9vbGVhbiA9IGZhbHNlLCB0eXBlPzogc3RyaW5nKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIGxldCB1cmwgPSBgJHt0aGlzLmFwaUJhc2V9L25vdGlmL21lP3BhZ2U9JHtwYWdlfSZwYWdlU2l6ZT0ke3BhZ2VTaXplfSZpbmNsdWRlUmVhZD0ke2luY2x1ZGVSZWFkfWA7XHJcbiAgICBpZiAodHlwZSkge1xyXG4gICAgICB1cmwgKz0gYCZ0eXBlPSR7dHlwZX1gO1xyXG4gICAgfVxyXG4gICAgcmV0dXJuIHRoaXMuaHR0cC5nZXQodXJsKTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyBtYXJrQXNSZWFkKG5vdGlmaWNhdGlvbklkOiBzdHJpbmcpOiBPYnNlcnZhYmxlPGFueT4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wYXRjaChgJHt0aGlzLmFwaUJhc2V9L25vdGlmLyR7bm90aWZpY2F0aW9uSWR9L3JlYWRgLCB7fSk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbWFya0FsbEFzUmVhZCgpOiBPYnNlcnZhYmxlPGFueT4ge1xyXG4gICAgcmV0dXJuIHRoaXMuaHR0cC5wYXRjaChgJHt0aGlzLmFwaUJhc2V9L25vdGlmL21lL3JlYWQtYWxsYCwge30pO1xyXG4gIH1cclxuXHJcbiAgcHVibGljIGRlbGV0ZU5vdGlmaWNhdGlvbihub3RpZmljYXRpb25JZDogc3RyaW5nKTogT2JzZXJ2YWJsZTxhbnk+IHtcclxuICAgIHJldHVybiB0aGlzLmh0dHAuZGVsZXRlKGAke3RoaXMuYXBpQmFzZX0vbm90aWYvJHtub3RpZmljYXRpb25JZH1gKTtcclxuICB9XHJcblxyXG4gIHByaXZhdGUgc3RhcnRDb25uZWN0aW9uKGNvbmZpZzogTWVzQXV0aENvbmZpZykge1xyXG4gICAgaWYgKHRoaXMuaHViQ29ubmVjdGlvbikgcmV0dXJuO1xyXG4gICAgY29uc3Qgc2lnbmFsclVybCA9IGNvbmZpZy5hcGlCYXNlVXJsLnJlcGxhY2UoL1xcLyQvLCAnJykgKyAnL2h1Yi9ub3RpZmljYXRpb24nO1xyXG4gICAgY29uc3QgYnVpbGRlciA9IG5ldyBIdWJDb25uZWN0aW9uQnVpbGRlcigpXHJcbiAgICAgIC53aXRoVXJsKHNpZ25hbHJVcmwsIHsgd2l0aENyZWRlbnRpYWxzOiBjb25maWcud2l0aENyZWRlbnRpYWxzID8/IHRydWUgfSlcclxuICAgICAgLndpdGhBdXRvbWF0aWNSZWNvbm5lY3QoKVxyXG4gICAgICAuY29uZmlndXJlTG9nZ2luZyhMb2dMZXZlbC5XYXJuaW5nKTtcclxuXHJcbiAgICB0aGlzLmh1YkNvbm5lY3Rpb24gPSBidWlsZGVyLmJ1aWxkKCk7XHJcblxyXG4gICAgdGhpcy5odWJDb25uZWN0aW9uLm9uKCdSZWNlaXZlTm90aWZpY2F0aW9uJywgKG46IGFueSkgPT4gdGhpcy5fbm90aWZpY2F0aW9ucy5uZXh0KG4pKTtcclxuXHJcbiAgICB0aGlzLmh1YkNvbm5lY3Rpb24uc3RhcnQoKS5jYXRjaCgoZXJyKSA9PiBjb25zb2xlLmVycm9yKCdTaWduYWxSIHN0YXJ0IGVycm9yJywgZXJyKSk7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgc3RvcCgpIHtcclxuICAgIGlmICghdGhpcy5odWJDb25uZWN0aW9uKSByZXR1cm47XHJcbiAgICB0aGlzLmh1YkNvbm5lY3Rpb24uc3RvcCgpLmNhdGNoKCgpID0+IHt9KTtcclxuICAgIHRoaXMuaHViQ29ubmVjdGlvbiA9IG51bGw7XHJcbiAgfVxyXG5cclxuICBwdWJsaWMgbG9nb3V0KCk6IE9ic2VydmFibGU8YW55PiB7XHJcbiAgICByZXR1cm4gdGhpcy5odHRwLnBvc3QoYCR7dGhpcy5hcGlCYXNlfS9hdXRoL2xvZ291dGAsIHt9KTtcclxuICB9XHJcblxyXG4gIHB1YmxpYyByZWZyZXNoVXNlcigpIHtcclxuICAgIHRoaXMuZmV0Y2hDdXJyZW50VXNlcigpO1xyXG4gIH1cclxufVxyXG4iXX0=
@@ -0,0 +1,5 @@
1
+ /**
2
+ * Generated bundle index. Do not edit.
3
+ */
4
+ export * from './index';
5
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibWVzYXV0aC1hbmd1bGFyLmpzIiwic291cmNlUm9vdCI6IiIsInNvdXJjZXMiOlsiLi4vLi4vc3JjL21lc2F1dGgtYW5ndWxhci50cyJdLCJuYW1lcyI6W10sIm1hcHBpbmdzIjoiQUFBQTs7R0FFRztBQUVILGNBQWMsU0FBUyxDQUFDIiwic291cmNlc0NvbnRlbnQiOlsiLyoqXG4gKiBHZW5lcmF0ZWQgYnVuZGxlIGluZGV4LiBEbyBub3QgZWRpdC5cbiAqL1xuXG5leHBvcnQgKiBmcm9tICcuL2luZGV4JztcbiJdfQ==
@@ -0,0 +1,57 @@
1
+ import { Component, Output, EventEmitter } from '@angular/core';
2
+ import { NgIf } from '@angular/common';
3
+ import { Subject } from 'rxjs';
4
+ import { takeUntil } from 'rxjs/operators';
5
+ import * as i0 from "@angular/core";
6
+ import * as i1 from "./mes-auth.service";
7
+ export class NotificationBadgeComponent {
8
+ constructor(authService) {
9
+ this.authService = authService;
10
+ this.notificationClick = new EventEmitter();
11
+ this.unreadCount = 0;
12
+ this.destroy$ = new Subject();
13
+ }
14
+ ngOnInit() {
15
+ this.loadUnreadCount();
16
+ // Listen for new notifications
17
+ this.authService.notifications$
18
+ .pipe(takeUntil(this.destroy$))
19
+ .subscribe(() => {
20
+ this.loadUnreadCount();
21
+ });
22
+ }
23
+ ngOnDestroy() {
24
+ this.destroy$.next();
25
+ this.destroy$.complete();
26
+ }
27
+ loadUnreadCount() {
28
+ this.authService.getUnreadCount().subscribe({
29
+ next: (response) => {
30
+ this.unreadCount = response.unreadCount || 0;
31
+ },
32
+ error: (err) => console.error('Error loading unread count:', err)
33
+ });
34
+ }
35
+ onNotificationClick() {
36
+ this.notificationClick.emit();
37
+ }
38
+ }
39
+ NotificationBadgeComponent.ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NotificationBadgeComponent, deps: [{ token: i1.MesAuthService }], target: i0.ɵɵFactoryTarget.Component });
40
+ NotificationBadgeComponent.ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "14.0.0", version: "14.3.0", type: NotificationBadgeComponent, isStandalone: true, selector: "ma-notification-badge", outputs: { notificationClick: "notificationClick" }, ngImport: i0, template: `
41
+ <button class="notification-btn" (click)="onNotificationClick()" title="Notifications">
42
+ <span class="icon">🔔</span>
43
+ <span class="badge" *ngIf="unreadCount > 0">{{ unreadCount }}</span>
44
+ </button>
45
+ `, isInline: true, styles: [".notification-btn{position:relative;background:none;border:none;font-size:24px;cursor:pointer;padding:8px;transition:opacity .2s}.notification-btn:hover{opacity:.7}.icon{display:inline-block}.badge{position:absolute;top:0;right:0;background-color:#f44336;color:#fff;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}\n"], dependencies: [{ kind: "directive", type: NgIf, selector: "[ngIf]", inputs: ["ngIf", "ngIfThen", "ngIfElse"] }] });
46
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "14.3.0", ngImport: i0, type: NotificationBadgeComponent, decorators: [{
47
+ type: Component,
48
+ args: [{ selector: 'ma-notification-badge', standalone: true, imports: [NgIf], template: `
49
+ <button class="notification-btn" (click)="onNotificationClick()" title="Notifications">
50
+ <span class="icon">🔔</span>
51
+ <span class="badge" *ngIf="unreadCount > 0">{{ unreadCount }}</span>
52
+ </button>
53
+ `, styles: [".notification-btn{position:relative;background:none;border:none;font-size:24px;cursor:pointer;padding:8px;transition:opacity .2s}.notification-btn:hover{opacity:.7}.icon{display:inline-block}.badge{position:absolute;top:0;right:0;background-color:#f44336;color:#fff;border-radius:50%;width:20px;height:20px;display:flex;align-items:center;justify-content:center;font-size:12px;font-weight:700}\n"] }]
54
+ }], ctorParameters: function () { return [{ type: i1.MesAuthService }]; }, propDecorators: { notificationClick: [{
55
+ type: Output
56
+ }] } });
57
+ //# sourceMappingURL=data:application/json;base64,eyJ2ZXJzaW9uIjozLCJmaWxlIjoibm90aWZpY2F0aW9uLWJhZGdlLmNvbXBvbmVudC5qcyIsInNvdXJjZVJvb3QiOiIiLCJzb3VyY2VzIjpbIi4uLy4uL3NyYy9ub3RpZmljYXRpb24tYmFkZ2UuY29tcG9uZW50LnRzIl0sIm5hbWVzIjpbXSwibWFwcGluZ3MiOiJBQUFBLE9BQU8sRUFBRSxTQUFTLEVBQXFCLE1BQU0sRUFBRSxZQUFZLEVBQUUsTUFBTSxlQUFlLENBQUM7QUFDbkYsT0FBTyxFQUFFLElBQUksRUFBRSxNQUFNLGlCQUFpQixDQUFDO0FBRXZDLE9BQU8sRUFBRSxPQUFPLEVBQUUsTUFBTSxNQUFNLENBQUM7QUFDL0IsT0FBTyxFQUFFLFNBQVMsRUFBRSxNQUFNLGdCQUFnQixDQUFDOzs7QUFnRDNDLE1BQU0sT0FBTywwQkFBMEI7SUFNckMsWUFBb0IsV0FBMkI7UUFBM0IsZ0JBQVcsR0FBWCxXQUFXLENBQWdCO1FBTHJDLHNCQUFpQixHQUFHLElBQUksWUFBWSxFQUFRLENBQUM7UUFFdkQsZ0JBQVcsR0FBRyxDQUFDLENBQUM7UUFDUixhQUFRLEdBQUcsSUFBSSxPQUFPLEVBQVEsQ0FBQztJQUVXLENBQUM7SUFFbkQsUUFBUTtRQUNOLElBQUksQ0FBQyxlQUFlLEVBQUUsQ0FBQztRQUV2QiwrQkFBK0I7UUFDL0IsSUFBSSxDQUFDLFdBQVcsQ0FBQyxjQUFjO2FBQzVCLElBQUksQ0FBQyxTQUFTLENBQUMsSUFBSSxDQUFDLFFBQVEsQ0FBQyxDQUFDO2FBQzlCLFNBQVMsQ0FBQyxHQUFHLEVBQUU7WUFDZCxJQUFJLENBQUMsZUFBZSxFQUFFLENBQUM7UUFDekIsQ0FBQyxDQUFDLENBQUM7SUFDUCxDQUFDO0lBRUQsV0FBVztRQUNULElBQUksQ0FBQyxRQUFRLENBQUMsSUFBSSxFQUFFLENBQUM7UUFDckIsSUFBSSxDQUFDLFFBQVEsQ0FBQyxRQUFRLEVBQUUsQ0FBQztJQUMzQixDQUFDO0lBRU8sZUFBZTtRQUNyQixJQUFJLENBQUMsV0FBVyxDQUFDLGNBQWMsRUFBRSxDQUFDLFNBQVMsQ0FBQztZQUMxQyxJQUFJLEVBQUUsQ0FBQyxRQUFhLEVBQUUsRUFBRTtnQkFDdEIsSUFBSSxDQUFDLFdBQVcsR0FBRyxRQUFRLENBQUMsV0FBVyxJQUFJLENBQUMsQ0FBQztZQUMvQyxDQUFDO1lBQ0QsS0FBSyxFQUFFLENBQUMsR0FBRyxFQUFFLEVBQUUsQ0FBQyxPQUFPLENBQUMsS0FBSyxDQUFDLDZCQUE2QixFQUFFLEdBQUcsQ0FBQztTQUNsRSxDQUFDLENBQUM7SUFDTCxDQUFDO0lBRUQsbUJBQW1CO1FBQ2pCLElBQUksQ0FBQyxpQkFBaUIsQ0FBQyxJQUFJLEVBQUUsQ0FBQztJQUNoQyxDQUFDOzt1SEFuQ1UsMEJBQTBCOzJHQUExQiwwQkFBMEIsc0lBMUMzQjs7Ozs7R0FLVCxxZEFOUyxJQUFJOzJGQTJDSCwwQkFBMEI7a0JBOUN0QyxTQUFTOytCQUNFLHVCQUF1QixjQUNyQixJQUFJLFdBQ1AsQ0FBQyxJQUFJLENBQUMsWUFDTDs7Ozs7R0FLVDtxR0FzQ1MsaUJBQWlCO3NCQUExQixNQUFNIiwic291cmNlc0NvbnRlbnQiOlsiaW1wb3J0IHsgQ29tcG9uZW50LCBPbkluaXQsIE9uRGVzdHJveSwgT3V0cHV0LCBFdmVudEVtaXR0ZXIgfSBmcm9tICdAYW5ndWxhci9jb3JlJztcclxuaW1wb3J0IHsgTmdJZiB9IGZyb20gJ0Bhbmd1bGFyL2NvbW1vbic7XHJcbmltcG9ydCB7IE1lc0F1dGhTZXJ2aWNlIH0gZnJvbSAnLi9tZXMtYXV0aC5zZXJ2aWNlJztcclxuaW1wb3J0IHsgU3ViamVjdCB9IGZyb20gJ3J4anMnO1xyXG5pbXBvcnQgeyB0YWtlVW50aWwgfSBmcm9tICdyeGpzL29wZXJhdG9ycyc7XHJcblxyXG5AQ29tcG9uZW50KHtcclxuICBzZWxlY3RvcjogJ21hLW5vdGlmaWNhdGlvbi1iYWRnZScsXHJcbiAgc3RhbmRhbG9uZTogdHJ1ZSxcclxuICBpbXBvcnRzOiBbTmdJZl0sXHJcbiAgdGVtcGxhdGU6IGBcclxuICAgIDxidXR0b24gY2xhc3M9XCJub3RpZmljYXRpb24tYnRuXCIgKGNsaWNrKT1cIm9uTm90aWZpY2F0aW9uQ2xpY2soKVwiIHRpdGxlPVwiTm90aWZpY2F0aW9uc1wiPlxyXG4gICAgICA8c3BhbiBjbGFzcz1cImljb25cIj7wn5SUPC9zcGFuPlxyXG4gICAgICA8c3BhbiBjbGFzcz1cImJhZGdlXCIgKm5nSWY9XCJ1bnJlYWRDb3VudCA+IDBcIj57eyB1bnJlYWRDb3VudCB9fTwvc3Bhbj5cclxuICAgIDwvYnV0dG9uPlxyXG4gIGAsXHJcbiAgc3R5bGVzOiBbYFxyXG4gICAgLm5vdGlmaWNhdGlvbi1idG4ge1xyXG4gICAgICBwb3NpdGlvbjogcmVsYXRpdmU7XHJcbiAgICAgIGJhY2tncm91bmQ6IG5vbmU7XHJcbiAgICAgIGJvcmRlcjogbm9uZTtcclxuICAgICAgZm9udC1zaXplOiAyNHB4O1xyXG4gICAgICBjdXJzb3I6IHBvaW50ZXI7XHJcbiAgICAgIHBhZGRpbmc6IDhweDtcclxuICAgICAgdHJhbnNpdGlvbjogb3BhY2l0eSAwLjJzO1xyXG4gICAgfVxyXG5cclxuICAgIC5ub3RpZmljYXRpb24tYnRuOmhvdmVyIHtcclxuICAgICAgb3BhY2l0eTogMC43O1xyXG4gICAgfVxyXG5cclxuICAgIC5pY29uIHtcclxuICAgICAgZGlzcGxheTogaW5saW5lLWJsb2NrO1xyXG4gICAgfVxyXG5cclxuICAgIC5iYWRnZSB7XHJcbiAgICAgIHBvc2l0aW9uOiBhYnNvbHV0ZTtcclxuICAgICAgdG9wOiAwO1xyXG4gICAgICByaWdodDogMDtcclxuICAgICAgYmFja2dyb3VuZC1jb2xvcjogI2Y0NDMzNjtcclxuICAgICAgY29sb3I6IHdoaXRlO1xyXG4gICAgICBib3JkZXItcmFkaXVzOiA1MCU7XHJcbiAgICAgIHdpZHRoOiAyMHB4O1xyXG4gICAgICBoZWlnaHQ6IDIwcHg7XHJcbiAgICAgIGRpc3BsYXk6IGZsZXg7XHJcbiAgICAgIGFsaWduLWl0ZW1zOiBjZW50ZXI7XHJcbiAgICAgIGp1c3RpZnktY29udGVudDogY2VudGVyO1xyXG4gICAgICBmb250LXNpemU6IDEycHg7XHJcbiAgICAgIGZvbnQtd2VpZ2h0OiBib2xkO1xyXG4gICAgfVxyXG4gIGBdXHJcbn0pXHJcbmV4cG9ydCBjbGFzcyBOb3RpZmljYXRpb25CYWRnZUNvbXBvbmVudCBpbXBsZW1lbnRzIE9uSW5pdCwgT25EZXN0cm95IHtcclxuICBAT3V0cHV0KCkgbm90aWZpY2F0aW9uQ2xpY2sgPSBuZXcgRXZlbnRFbWl0dGVyPHZvaWQ+KCk7XHJcbiAgXHJcbiAgdW5yZWFkQ291bnQgPSAwO1xyXG4gIHByaXZhdGUgZGVzdHJveSQgPSBuZXcgU3ViamVjdDx2b2lkPigpO1xyXG5cclxuICBjb25zdHJ1Y3Rvcihwcml2YXRlIGF1dGhTZXJ2aWNlOiBNZXNBdXRoU2VydmljZSkge31cclxuXHJcbiAgbmdPbkluaXQoKSB7XHJcbiAgICB0aGlzLmxvYWRVbnJlYWRDb3VudCgpO1xyXG4gICAgXHJcbiAgICAvLyBMaXN0ZW4gZm9yIG5ldyBub3RpZmljYXRpb25zXHJcbiAgICB0aGlzLmF1dGhTZXJ2aWNlLm5vdGlmaWNhdGlvbnMkXHJcbiAgICAgIC5waXBlKHRha2VVbnRpbCh0aGlzLmRlc3Ryb3kkKSlcclxuICAgICAgLnN1YnNjcmliZSgoKSA9PiB7XHJcbiAgICAgICAgdGhpcy5sb2FkVW5yZWFkQ291bnQoKTtcclxuICAgICAgfSk7XHJcbiAgfVxyXG5cclxuICBuZ09uRGVzdHJveSgpIHtcclxuICAgIHRoaXMuZGVzdHJveSQubmV4dCgpO1xyXG4gICAgdGhpcy5kZXN0cm95JC5jb21wbGV0ZSgpO1xyXG4gIH1cclxuXHJcbiAgcHJpdmF0ZSBsb2FkVW5yZWFkQ291bnQoKSB7XHJcbiAgICB0aGlzLmF1dGhTZXJ2aWNlLmdldFVucmVhZENvdW50KCkuc3Vic2NyaWJlKHtcclxuICAgICAgbmV4dDogKHJlc3BvbnNlOiBhbnkpID0+IHtcclxuICAgICAgICB0aGlzLnVucmVhZENvdW50ID0gcmVzcG9uc2UudW5yZWFkQ291bnQgfHwgMDtcclxuICAgICAgfSxcclxuICAgICAgZXJyb3I6IChlcnIpID0+IGNvbnNvbGUuZXJyb3IoJ0Vycm9yIGxvYWRpbmcgdW5yZWFkIGNvdW50OicsIGVycilcclxuICAgIH0pO1xyXG4gIH1cclxuXHJcbiAgb25Ob3RpZmljYXRpb25DbGljaygpIHtcclxuICAgIHRoaXMubm90aWZpY2F0aW9uQ2xpY2suZW1pdCgpO1xyXG4gIH1cclxufVxyXG4iXX0=