mesauth-angular 1.16.0 → 1.16.2
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/README.md +337 -337
- package/fesm2022/mesauth-angular.mjs +104 -100
- package/fesm2022/mesauth-angular.mjs.map +1 -1
- package/package.json +1 -1
- package/types/mesauth-angular.d.ts +1 -1
- package/mesauth-angular-1.16.0.tgz +0 -0
package/README.md
CHANGED
|
@@ -1,337 +1,337 @@
|
|
|
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 with dark/light theme support.
|
|
4
|
-
|
|
5
|
-
## Changelog
|
|
6
|
-
|
|
7
|
-
### v1.6.8 (2026-04-01) - **Permission Header Support**
|
|
8
|
-
- **New `withXMaPerm()` RxJS operator**: Extracts `X-MA-PERM` permission header from HTTP responses, returning `{ data, allowedActions }`. Use with `observe: 'response'` on any `HttpClient` call for zero-overhead permission-gated UI.
|
|
9
|
-
- **New `xMaResource()` helper**: Combines `rxResource` with automatic permission extraction for GET endpoints. Returns a signal-based resource with `.value().allowedActions`.
|
|
10
|
-
- **New `extractXMaPerm()` utility**: Standalone function to parse the `X-MA-PERM` header from any `HttpResponse`.
|
|
11
|
-
- **Wildcard `*` expansion**: `extractXMaPerm` automatically expands `["*"]` into all known HTTP methods (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `WEBSOCKET`).
|
|
12
|
-
- **`ALL_ACTIONS` constant**: Exported array of all recognized HTTP action strings for permission checks.
|
|
13
|
-
- **Exports**: `withXMaPerm`, `xMaResource`, `extractXMaPerm`, `PermissionHeader`, `RequestConfig`, `ALL_ACTIONS`.
|
|
14
|
-
|
|
15
|
-
### v1.6.0 (2026-03-28) - **Approval Module Enhancements**
|
|
16
|
-
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
17
|
-
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
18
|
-
- **Automatic theme support**: `<ma-arv-container>` applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
19
|
-
- **`previewRole(orgCode, level)`** added to `MaApprovalService`: Fetch candidate users for a role-based approval step.
|
|
20
|
-
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
21
|
-
|
|
22
|
-
### v1.5.0 (2026-03-24) - **Approval Module**
|
|
23
|
-
- **New `<ma-approval-panel>` component**: Slide-out sidebar with 3 tabs (Processing / Approved / Rejected). Shows all pending approvals requiring action, and recent approved/rejected items. Listens to `approvalEvents$` for real-time refresh via SignalR.
|
|
24
|
-
- **New `<ma-arv-container>` component**: Content capture container for submitting documents for approval. Captures projected `<ng-content>` as a self-contained HTML document by inlining all computed styles, replacing canvas elements with images, and stripping Angular/script artifacts. Supports ad-hoc step builder and template selector.
|
|
25
|
-
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
26
|
-
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
27
|
-
- **Automatic theme support**: Applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
28
|
-
- **New `MaApprovalService`**: Service for all approval API calls — `getPendingApprovals()`, `getMyRequests()`, `getDashboard()`, `approve()`, `reject()`, `delegate()`, `getTemplates()`, `createApproval()`, `previewRole(orgCode, level)`, etc. Manual init pattern (same as `MesAuthService`).
|
|
29
|
-
- **Approval icon in `ma-user-profile`**: Clipboard/checkmark icon button added between notification bell and avatar. Shows pending count badge. Emits `approvalClick` output for panel toggle.
|
|
30
|
-
- **`approvalEvents$` observable in `MesAuthService`**: Real-time SignalR events (`ApprovalCompleted`, `ApprovalStepChanged`) exposed as an observable stream.
|
|
31
|
-
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
32
|
-
- **New exports**: `MaApprovalService`, `MaApprovalPanelComponent`, `MaArvContainerComponent`, and all approval model interfaces/enums.
|
|
33
|
-
|
|
34
|
-
### v1.4.0 (2026-03-20) - **Remove Unused Route Registration API**
|
|
35
|
-
- Removed `registerRoutes()`, `unregisterRoute()`, `getRoutesByRole()` and related methods from `MesAuthService`. Frontend route master/mapping CRUD is handled by `MesExtensionSite` via direct HTTP calls, not through the library.
|
|
36
|
-
- `getFrontEndRoutes()` and `UserFrontEndRoutesGrouped`/`FrontEndRoute` interfaces are retained as the public API for consuming route data.
|
|
37
|
-
|
|
38
|
-
### v1.2.3 (2026-02-11) - **Fix Register Page Auto-Redirect**
|
|
39
|
-
- **Fixed 401 redirect on public pages**: The interceptor now skips the login redirect when the user is on `/register`, `/forgot-password`, or `/reset-password` pages. Previously, unauthenticated users on the register page were incorrectly redirected to login when any API call returned 401.
|
|
40
|
-
|
|
41
|
-
### v1.2.2 (2026-02-06) - **Z-Index Fix for Notification UI**
|
|
42
|
-
- **Fixed notification panel z-index**: Increased from `1000` to `1030` to appear above CoreUI sticky table headers (`z-index: 1020`)
|
|
43
|
-
- **Fixed modal overlay z-index**: Increased from `9999` to `1060` to maintain proper layering hierarchy
|
|
44
|
-
- **Better integration with CoreUI/Bootstrap**: Follows standard z-index scale (sticky: 1020, modals: 1050+, overlays: 1060+)
|
|
45
|
-
|
|
46
|
-
### v1.2.0 (2026-02-05) - **Notification & Auth Interceptor Fix**
|
|
47
|
-
- **Removed route-change user polling**: `MesAuthService` no longer re-fetches the user on every `NavigationEnd` event. User is fetched once on app init; SignalR handles real-time updates. This eliminates redundant API calls and notification toast spam on every route change.
|
|
48
|
-
- **Removed `fetchInitialNotifications()`**: Historical notifications were being emitted through `notifications$` Subject on every user refresh, causing toast popups for old notifications. The `notifications$` observable now only carries truly new real-time events from SignalR.
|
|
49
|
-
- **`refreshUser()` returns `Observable`**: Callers can now subscribe and wait for user data to load before proceeding (e.g., navigate after login). Previously returned `void`.
|
|
50
|
-
- **Fixed 401 redirect for expired sessions**: Removed the `!isAuthenticated` guard from the interceptor's 401 condition. When a session expires, the `BehaviorSubject` still holds stale user data, so this check was blocking the redirect to login. The `!isMeAuthPage`, `!isLoginPage`, and `!isAuthPage` guards are sufficient to prevent redirect loops.
|
|
51
|
-
|
|
52
|
-
### v1.1.0 (2026-01-21) - **Major Update**
|
|
53
|
-
- 🚀 **New `provideMesAuth()` Function**: Simplified setup with a single function call
|
|
54
|
-
- ✨ **Functional Interceptor**: New `mesAuthInterceptor` for better compatibility with standalone apps
|
|
55
|
-
- 📦 **Automatic Initialization**: `provideMesAuth()` handles service initialization via `APP_INITIALIZER`
|
|
56
|
-
- 🔧 **Simplified API**: Just pass `apiBaseUrl` and `userBaseUrl` - no manual DI required
|
|
57
|
-
|
|
58
|
-
### v1.0.1 (2026-01-21)
|
|
59
|
-
- 🔧 Internal refactoring for better module compatibility
|
|
60
|
-
|
|
61
|
-
### v0.2.28 (2026-01-19)
|
|
62
|
-
- ✨ **Enhanced Avatar Support**: Direct `avatarPath` usage from user data for instant display without backend calls
|
|
63
|
-
- 🔄 **Improved Avatar Refresh**: Timestamp-based cache busting prevents request cancellation issues
|
|
64
|
-
- 🎯 **Better Change Detection**: Signal-based user updates with `ChangeDetectorRef` for reliable UI updates
|
|
65
|
-
|
|
66
|
-
### v0.2.27 (2026-01-19)
|
|
67
|
-
- 🐛 Fixed avatar refresh issues in header components
|
|
68
|
-
- 📦 Improved build process and dependencies
|
|
69
|
-
|
|
70
|
-
## Features
|
|
71
|
-
|
|
72
|
-
- 🔐 **Authentication**: User login/logout with API integration
|
|
73
|
-
- 🔔 **Real-time Notifications**: SignalR integration for live notifications
|
|
74
|
-
- ✅ **Approval Workflows**: `<ma-approval-panel>`, `<ma-arv-container>`, `MaApprovalService` for multi-step document approval
|
|
75
|
-
- 🎨 **Dark/Light Theme**: Automatic theme detection and support
|
|
76
|
-
- 🖼️ **Avatar Support**: Direct API-based avatar loading
|
|
77
|
-
- 🍞 **Toast Notifications**: In-app notification toasts
|
|
78
|
-
- 🛡️ **HTTP Interceptor**: Automatic 401/403 error handling with redirects
|
|
79
|
-
|
|
80
|
-
## Quick Start (v1.1.0+)
|
|
81
|
-
|
|
82
|
-
### 1. Install
|
|
83
|
-
|
|
84
|
-
```bash
|
|
85
|
-
npm install mesauth-angular
|
|
86
|
-
```
|
|
87
|
-
|
|
88
|
-
### 2. Configure in app.config.ts (Recommended for Angular 14+)
|
|
89
|
-
|
|
90
|
-
```ts
|
|
91
|
-
import { ApplicationConfig } from '@angular/core';
|
|
92
|
-
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
93
|
-
import { provideMesAuth, mesAuthInterceptor } from 'mesauth-angular';
|
|
94
|
-
|
|
95
|
-
export const appConfig: ApplicationConfig = {
|
|
96
|
-
providers: [
|
|
97
|
-
provideHttpClient(
|
|
98
|
-
withInterceptors([mesAuthInterceptor]) // Handles 401/403 redirects
|
|
99
|
-
),
|
|
100
|
-
provideMesAuth({
|
|
101
|
-
apiBaseUrl: 'https://mes.kefico.vn/auth',
|
|
102
|
-
userBaseUrl: 'https://mes.kefico.vn/x' // For login/403 redirects
|
|
103
|
-
})
|
|
104
|
-
]
|
|
105
|
-
};
|
|
106
|
-
```
|
|
107
|
-
|
|
108
|
-
That's it! The library handles:
|
|
109
|
-
- Service initialization via `APP_INITIALIZER`
|
|
110
|
-
- `HttpClient` and `Router` injection automatically
|
|
111
|
-
- 401 → redirects to `{userBaseUrl}/login?returnUrl=...`
|
|
112
|
-
- 403 → redirects to `{userBaseUrl}/403?returnUrl=...`
|
|
113
|
-
|
|
114
|
-
### 3. Use in Components
|
|
115
|
-
|
|
116
|
-
```ts
|
|
117
|
-
import { MesAuthService } from 'mesauth-angular';
|
|
118
|
-
|
|
119
|
-
@Component({...})
|
|
120
|
-
export class MyComponent {
|
|
121
|
-
private auth = inject(MesAuthService);
|
|
122
|
-
|
|
123
|
-
// Observable streams
|
|
124
|
-
currentUser$ = this.auth.currentUser$;
|
|
125
|
-
notifications$ = this.auth.notifications$;
|
|
126
|
-
|
|
127
|
-
logout() {
|
|
128
|
-
this.auth.logout().subscribe();
|
|
129
|
-
}
|
|
130
|
-
}
|
|
131
|
-
```
|
|
132
|
-
|
|
133
|
-
## Configuration Options
|
|
134
|
-
|
|
135
|
-
```ts
|
|
136
|
-
interface MesAuthConfig {
|
|
137
|
-
apiBaseUrl: string; // Required: MesAuth API base URL
|
|
138
|
-
userBaseUrl?: string; // Optional: Base URL for login/403 redirects
|
|
139
|
-
withCredentials?: boolean; // Optional: Send cookies (default: true)
|
|
140
|
-
}
|
|
141
|
-
```
|
|
142
|
-
|
|
143
|
-
## Theme Support
|
|
144
|
-
|
|
145
|
-
The library automatically detects and adapts to your application's theme:
|
|
146
|
-
|
|
147
|
-
### Automatic Theme Detection
|
|
148
|
-
The library checks for theme indicators on the `<html>` element:
|
|
149
|
-
- `class="dark"`
|
|
150
|
-
- `data-theme="dark"`
|
|
151
|
-
- `theme="dark"`
|
|
152
|
-
- `data-coreui-theme="dark"`
|
|
153
|
-
|
|
154
|
-
### Dynamic Theme Changes
|
|
155
|
-
Theme changes are detected in real-time using `MutationObserver`, so components automatically update when your app switches themes.
|
|
156
|
-
|
|
157
|
-
### Manual Theme Control
|
|
158
|
-
```ts
|
|
159
|
-
import { ThemeService } from 'mesauth-angular';
|
|
160
|
-
|
|
161
|
-
// Check current theme
|
|
162
|
-
const currentTheme = themeService.currentTheme; // 'light' | 'dark'
|
|
163
|
-
|
|
164
|
-
// Manually set theme
|
|
165
|
-
themeService.setTheme('dark');
|
|
166
|
-
|
|
167
|
-
// Listen for theme changes
|
|
168
|
-
themeService.currentTheme$.subscribe(theme => {
|
|
169
|
-
console.log('Theme changed to:', theme);
|
|
170
|
-
});
|
|
171
|
-
```
|
|
172
|
-
|
|
173
|
-
## Avatar Loading
|
|
174
|
-
|
|
175
|
-
Avatars are loaded efficiently using multiple strategies:
|
|
176
|
-
|
|
177
|
-
### Primary Method: Direct Path Usage
|
|
178
|
-
If the user object contains an `avatarPath`, it's used directly:
|
|
179
|
-
- **Full URLs**: Used as-is (e.g., `https://example.com/avatar.jpg`)
|
|
180
|
-
- **Relative Paths**: Combined with API base URL (e.g., `/uploads/avatar.jpg` → `{apiBaseUrl}/uploads/avatar.jpg`)
|
|
181
|
-
|
|
182
|
-
### Fallback Method: API Endpoint
|
|
183
|
-
If no `avatarPath` is available, avatars are loaded via API:
|
|
184
|
-
- **API Endpoint**: `GET {apiBaseUrl}/auth/{userId}/avatar`
|
|
185
|
-
- **Authentication**: Uses the same credentials as other API calls
|
|
186
|
-
|
|
187
|
-
### Cache Busting
|
|
188
|
-
Avatar URLs include timestamps to prevent browser caching issues during updates:
|
|
189
|
-
- Automatic refresh when user data changes
|
|
190
|
-
- Manual refresh triggers for upload/delete operations
|
|
191
|
-
|
|
192
|
-
### Fallback Service
|
|
193
|
-
- **UI Avatars**: Generates initials-based avatars if no user data available
|
|
194
|
-
- **Authentication**: Not required for fallback avatars
|
|
195
|
-
|
|
196
|
-
## Components
|
|
197
|
-
|
|
198
|
-
**Note:** All components are standalone and can be imported directly.
|
|
199
|
-
|
|
200
|
-
### ma-user-profile
|
|
201
|
-
|
|
202
|
-
A reusable Angular component for displaying the current user's profile information, with options for navigation and logout.
|
|
203
|
-
|
|
204
|
-
- **Description**: Renders user details (e.g., name, avatar) fetched via the MesAuthService. Supports custom event handlers for navigation and logout actions.
|
|
205
|
-
- **Inputs**: None (data is sourced from the MesAuthService).
|
|
206
|
-
- **Outputs**:
|
|
207
|
-
- `onNavigate`: Emits an event when the user triggers navigation (e.g., to a profile page). Pass a handler to define behavior.
|
|
208
|
-
- `onLogout`: Emits an event when the user logs out. Pass a handler to perform logout logic (e.g., clear tokens, redirect).
|
|
209
|
-
- **Usage Example**:
|
|
210
|
-
|
|
211
|
-
```html
|
|
212
|
-
<ma-user-profile
|
|
213
|
-
(onNavigate)="handleNavigation($event)"
|
|
214
|
-
(onLogout)="handleLogout()">
|
|
215
|
-
</ma-user-profile>
|
|
216
|
-
```
|
|
217
|
-
|
|
218
|
-
In your component's TypeScript file:
|
|
219
|
-
|
|
220
|
-
```ts
|
|
221
|
-
handleNavigation(event: any) {
|
|
222
|
-
// Navigate to user profile page
|
|
223
|
-
this.router.navigate(['/profile']);
|
|
224
|
-
}
|
|
225
|
-
|
|
226
|
-
handleLogout() {
|
|
227
|
-
// Perform logout, e.g., clear session and redirect
|
|
228
|
-
this.mesAuth.logout(); // Assuming a logout method exists
|
|
229
|
-
this.router.navigate(['/login']);
|
|
230
|
-
}
|
|
231
|
-
```
|
|
232
|
-
|
|
233
|
-
### ma-notification-panel
|
|
234
|
-
|
|
235
|
-
A standalone component for displaying a slide-out notification panel with real-time updates.
|
|
236
|
-
|
|
237
|
-
- **Description**: Shows a list of notifications, allows marking as read/delete, and integrates with toast notifications for new alerts.
|
|
238
|
-
- **Inputs**: None.
|
|
239
|
-
- **Outputs**: None (uses internal methods for actions).
|
|
240
|
-
- **Usage Example**:
|
|
241
|
-
|
|
242
|
-
```html
|
|
243
|
-
<ma-notification-panel #notificationPanel></ma-notification-panel>
|
|
244
|
-
```
|
|
245
|
-
|
|
246
|
-
In your component:
|
|
247
|
-
|
|
248
|
-
```ts
|
|
249
|
-
// To open the panel
|
|
250
|
-
notificationPanel.open();
|
|
251
|
-
```
|
|
252
|
-
|
|
253
|
-
## Migration Guide
|
|
254
|
-
|
|
255
|
-
### Upgrading from v0.x to v1.1.0+
|
|
256
|
-
|
|
257
|
-
The setup has been greatly simplified. Here's how to migrate:
|
|
258
|
-
|
|
259
|
-
**Before (v0.x):**
|
|
260
|
-
```ts
|
|
261
|
-
// app.config.ts - OLD WAY
|
|
262
|
-
import { MesAuthModule, MesAuthService } from 'mesauth-angular';
|
|
263
|
-
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
264
|
-
|
|
265
|
-
export const appConfig: ApplicationConfig = {
|
|
266
|
-
providers: [
|
|
267
|
-
importProvidersFrom(MesAuthModule),
|
|
268
|
-
{ provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
|
|
269
|
-
]
|
|
270
|
-
};
|
|
271
|
-
|
|
272
|
-
// app.component.ts - OLD WAY
|
|
273
|
-
export class AppComponent {
|
|
274
|
-
constructor() {
|
|
275
|
-
this.mesAuthService.init({
|
|
276
|
-
apiBaseUrl: '...',
|
|
277
|
-
userBaseUrl: '...'
|
|
278
|
-
}, inject(HttpClient), inject(Router));
|
|
279
|
-
}
|
|
280
|
-
}
|
|
281
|
-
```
|
|
282
|
-
|
|
283
|
-
**After (v1.1.0+):**
|
|
284
|
-
```ts
|
|
285
|
-
// app.config.ts - NEW WAY (everything in one place!)
|
|
286
|
-
import { provideMesAuth, mesAuthInterceptor } from 'mesauth-angular';
|
|
287
|
-
|
|
288
|
-
export const appConfig: ApplicationConfig = {
|
|
289
|
-
providers: [
|
|
290
|
-
provideHttpClient(withInterceptors([mesAuthInterceptor])),
|
|
291
|
-
provideMesAuth({
|
|
292
|
-
apiBaseUrl: 'https://mes.kefico.vn/auth',
|
|
293
|
-
userBaseUrl: 'https://mes.kefico.vn/x'
|
|
294
|
-
})
|
|
295
|
-
]
|
|
296
|
-
};
|
|
297
|
-
|
|
298
|
-
// app.component.ts - No init() needed!
|
|
299
|
-
export class AppComponent {
|
|
300
|
-
// Just inject and use - no manual initialization required
|
|
301
|
-
}
|
|
302
|
-
```
|
|
303
|
-
|
|
304
|
-
**Key Changes:**
|
|
305
|
-
- `provideMesAuth()` replaces `MesAuthModule` + manual `init()` call
|
|
306
|
-
- `mesAuthInterceptor` (functional) replaces `MesAuthInterceptor` (class-based)
|
|
307
|
-
- No need to inject `HttpClient` or `Router` manually
|
|
308
|
-
- Configuration moved from `AppComponent` to `app.config.ts`
|
|
309
|
-
|
|
310
|
-
## Troubleshooting
|
|
311
|
-
|
|
312
|
-
### JIT Compiler Error in Production or AOT Mode
|
|
313
|
-
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:
|
|
314
|
-
- The package is being imported directly from source code (e.g., during development) without building it first.
|
|
315
|
-
- The client app is running in AOT (Ahead-of-Time) compilation mode, which requires pre-compiled libraries.
|
|
316
|
-
|
|
317
|
-
**Solutions:**
|
|
318
|
-
1. **Build the package for production/AOT compatibility:**
|
|
319
|
-
- Ensure you have built the package using `npm run build` (which uses ng-packagr or similar to generate AOT-ready code).
|
|
320
|
-
- Install the built package via npm (e.g., from a local tarball or registry) instead of linking to the source folder.
|
|
321
|
-
|
|
322
|
-
2. **For development (if you must link to source):**
|
|
323
|
-
- Switch your Angular app to JIT mode by bootstrapping with `@angular/platform-browser-dynamic` instead of `@angular/platform-browser`.
|
|
324
|
-
|
|
325
|
-
3. **Verify imports:**
|
|
326
|
-
- Ensure you're importing from the built package (e.g., `import { MesAuthService } from 'mesauth-angular';`) and not from the `src` folder.
|
|
327
|
-
|
|
328
|
-
### Components Appear Empty
|
|
329
|
-
If components like `ma-user` or `ma-user-profile` render as empty:
|
|
330
|
-
- Ensure `provideMesAuth()` is called in your `app.config.ts`.
|
|
331
|
-
- Check browser console for logs from components.
|
|
332
|
-
- If `currentUser` is null, the component shows a login button—verify the API returns user data.
|
|
333
|
-
|
|
334
|
-
## Notes
|
|
335
|
-
- The service expects an endpoint `GET {apiBaseUrl}/auth/me` that returns the current user.
|
|
336
|
-
- Avatar endpoint: `GET {apiBaseUrl}/auth/{userId}/avatar`
|
|
337
|
-
- SignalR events used: `ReceiveNotification` (adjust to your backend).
|
|
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 with dark/light theme support.
|
|
4
|
+
|
|
5
|
+
## Changelog
|
|
6
|
+
|
|
7
|
+
### v1.6.8 (2026-04-01) - **Permission Header Support**
|
|
8
|
+
- **New `withXMaPerm()` RxJS operator**: Extracts `X-MA-PERM` permission header from HTTP responses, returning `{ data, allowedActions }`. Use with `observe: 'response'` on any `HttpClient` call for zero-overhead permission-gated UI.
|
|
9
|
+
- **New `xMaResource()` helper**: Combines `rxResource` with automatic permission extraction for GET endpoints. Returns a signal-based resource with `.value().allowedActions`.
|
|
10
|
+
- **New `extractXMaPerm()` utility**: Standalone function to parse the `X-MA-PERM` header from any `HttpResponse`.
|
|
11
|
+
- **Wildcard `*` expansion**: `extractXMaPerm` automatically expands `["*"]` into all known HTTP methods (`GET`, `POST`, `PUT`, `DELETE`, `PATCH`, `WEBSOCKET`).
|
|
12
|
+
- **`ALL_ACTIONS` constant**: Exported array of all recognized HTTP action strings for permission checks.
|
|
13
|
+
- **Exports**: `withXMaPerm`, `xMaResource`, `extractXMaPerm`, `PermissionHeader`, `RequestConfig`, `ALL_ACTIONS`.
|
|
14
|
+
|
|
15
|
+
### v1.6.0 (2026-03-28) - **Approval Module Enhancements**
|
|
16
|
+
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
17
|
+
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
18
|
+
- **Automatic theme support**: `<ma-arv-container>` applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
19
|
+
- **`previewRole(orgCode, level)`** added to `MaApprovalService`: Fetch candidate users for a role-based approval step.
|
|
20
|
+
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
21
|
+
|
|
22
|
+
### v1.5.0 (2026-03-24) - **Approval Module**
|
|
23
|
+
- **New `<ma-approval-panel>` component**: Slide-out sidebar with 3 tabs (Processing / Approved / Rejected). Shows all pending approvals requiring action, and recent approved/rejected items. Listens to `approvalEvents$` for real-time refresh via SignalR.
|
|
24
|
+
- **New `<ma-arv-container>` component**: Content capture container for submitting documents for approval. Captures projected `<ng-content>` as a self-contained HTML document by inlining all computed styles, replacing canvas elements with images, and stripping Angular/script artifacts. Supports ad-hoc step builder and template selector.
|
|
25
|
+
- **`[templateId]` locks routing UI**: When bound, the routing mode toggle and template dropdown are hidden — the template name is shown as read-only. Role-based steps auto-load candidate pickers from `GET /approval/roles/preview`; the requester selects one user per step before submitting. Pass as number binding: `[templateId]="6"`.
|
|
26
|
+
- **`(approvalSubmitting)` output** *(corrected from single-t typo)*: Fires before content capture starts. Use it to hide edit controls (`*ngIf="!isSubmitting"`) so they are excluded from the approval snapshot. Angular CD runs after the emit so DOM updates are captured.
|
|
27
|
+
- **Automatic theme support**: Applies `ThemeService` internally — adapts to the app's light/dark theme via `@HostBinding('class')` with no extra setup.
|
|
28
|
+
- **New `MaApprovalService`**: Service for all approval API calls — `getPendingApprovals()`, `getMyRequests()`, `getDashboard()`, `approve()`, `reject()`, `delegate()`, `getTemplates()`, `createApproval()`, `previewRole(orgCode, level)`, etc. Manual init pattern (same as `MesAuthService`).
|
|
29
|
+
- **Approval icon in `ma-user-profile`**: Clipboard/checkmark icon button added between notification bell and avatar. Shows pending count badge. Emits `approvalClick` output for panel toggle.
|
|
30
|
+
- **`approvalEvents$` observable in `MesAuthService`**: Real-time SignalR events (`ApprovalCompleted`, `ApprovalStepChanged`) exposed as an observable stream.
|
|
31
|
+
- **Callback security**: MesAuth.Api sends `X-APP-ID` + `X-APP-KEY` headers on every callback POST using its own app credentials. Protect callback endpoints with `[MesAuth]` from `MesAuth.Authorizer`.
|
|
32
|
+
- **New exports**: `MaApprovalService`, `MaApprovalPanelComponent`, `MaArvContainerComponent`, and all approval model interfaces/enums.
|
|
33
|
+
|
|
34
|
+
### v1.4.0 (2026-03-20) - **Remove Unused Route Registration API**
|
|
35
|
+
- Removed `registerRoutes()`, `unregisterRoute()`, `getRoutesByRole()` and related methods from `MesAuthService`. Frontend route master/mapping CRUD is handled by `MesExtensionSite` via direct HTTP calls, not through the library.
|
|
36
|
+
- `getFrontEndRoutes()` and `UserFrontEndRoutesGrouped`/`FrontEndRoute` interfaces are retained as the public API for consuming route data.
|
|
37
|
+
|
|
38
|
+
### v1.2.3 (2026-02-11) - **Fix Register Page Auto-Redirect**
|
|
39
|
+
- **Fixed 401 redirect on public pages**: The interceptor now skips the login redirect when the user is on `/register`, `/forgot-password`, or `/reset-password` pages. Previously, unauthenticated users on the register page were incorrectly redirected to login when any API call returned 401.
|
|
40
|
+
|
|
41
|
+
### v1.2.2 (2026-02-06) - **Z-Index Fix for Notification UI**
|
|
42
|
+
- **Fixed notification panel z-index**: Increased from `1000` to `1030` to appear above CoreUI sticky table headers (`z-index: 1020`)
|
|
43
|
+
- **Fixed modal overlay z-index**: Increased from `9999` to `1060` to maintain proper layering hierarchy
|
|
44
|
+
- **Better integration with CoreUI/Bootstrap**: Follows standard z-index scale (sticky: 1020, modals: 1050+, overlays: 1060+)
|
|
45
|
+
|
|
46
|
+
### v1.2.0 (2026-02-05) - **Notification & Auth Interceptor Fix**
|
|
47
|
+
- **Removed route-change user polling**: `MesAuthService` no longer re-fetches the user on every `NavigationEnd` event. User is fetched once on app init; SignalR handles real-time updates. This eliminates redundant API calls and notification toast spam on every route change.
|
|
48
|
+
- **Removed `fetchInitialNotifications()`**: Historical notifications were being emitted through `notifications$` Subject on every user refresh, causing toast popups for old notifications. The `notifications$` observable now only carries truly new real-time events from SignalR.
|
|
49
|
+
- **`refreshUser()` returns `Observable`**: Callers can now subscribe and wait for user data to load before proceeding (e.g., navigate after login). Previously returned `void`.
|
|
50
|
+
- **Fixed 401 redirect for expired sessions**: Removed the `!isAuthenticated` guard from the interceptor's 401 condition. When a session expires, the `BehaviorSubject` still holds stale user data, so this check was blocking the redirect to login. The `!isMeAuthPage`, `!isLoginPage`, and `!isAuthPage` guards are sufficient to prevent redirect loops.
|
|
51
|
+
|
|
52
|
+
### v1.1.0 (2026-01-21) - **Major Update**
|
|
53
|
+
- 🚀 **New `provideMesAuth()` Function**: Simplified setup with a single function call
|
|
54
|
+
- ✨ **Functional Interceptor**: New `mesAuthInterceptor` for better compatibility with standalone apps
|
|
55
|
+
- 📦 **Automatic Initialization**: `provideMesAuth()` handles service initialization via `APP_INITIALIZER`
|
|
56
|
+
- 🔧 **Simplified API**: Just pass `apiBaseUrl` and `userBaseUrl` - no manual DI required
|
|
57
|
+
|
|
58
|
+
### v1.0.1 (2026-01-21)
|
|
59
|
+
- 🔧 Internal refactoring for better module compatibility
|
|
60
|
+
|
|
61
|
+
### v0.2.28 (2026-01-19)
|
|
62
|
+
- ✨ **Enhanced Avatar Support**: Direct `avatarPath` usage from user data for instant display without backend calls
|
|
63
|
+
- 🔄 **Improved Avatar Refresh**: Timestamp-based cache busting prevents request cancellation issues
|
|
64
|
+
- 🎯 **Better Change Detection**: Signal-based user updates with `ChangeDetectorRef` for reliable UI updates
|
|
65
|
+
|
|
66
|
+
### v0.2.27 (2026-01-19)
|
|
67
|
+
- 🐛 Fixed avatar refresh issues in header components
|
|
68
|
+
- 📦 Improved build process and dependencies
|
|
69
|
+
|
|
70
|
+
## Features
|
|
71
|
+
|
|
72
|
+
- 🔐 **Authentication**: User login/logout with API integration
|
|
73
|
+
- 🔔 **Real-time Notifications**: SignalR integration for live notifications
|
|
74
|
+
- ✅ **Approval Workflows**: `<ma-approval-panel>`, `<ma-arv-container>`, `MaApprovalService` for multi-step document approval
|
|
75
|
+
- 🎨 **Dark/Light Theme**: Automatic theme detection and support
|
|
76
|
+
- 🖼️ **Avatar Support**: Direct API-based avatar loading
|
|
77
|
+
- 🍞 **Toast Notifications**: In-app notification toasts
|
|
78
|
+
- 🛡️ **HTTP Interceptor**: Automatic 401/403 error handling with redirects
|
|
79
|
+
|
|
80
|
+
## Quick Start (v1.1.0+)
|
|
81
|
+
|
|
82
|
+
### 1. Install
|
|
83
|
+
|
|
84
|
+
```bash
|
|
85
|
+
npm install mesauth-angular
|
|
86
|
+
```
|
|
87
|
+
|
|
88
|
+
### 2. Configure in app.config.ts (Recommended for Angular 14+)
|
|
89
|
+
|
|
90
|
+
```ts
|
|
91
|
+
import { ApplicationConfig } from '@angular/core';
|
|
92
|
+
import { provideHttpClient, withInterceptors } from '@angular/common/http';
|
|
93
|
+
import { provideMesAuth, mesAuthInterceptor } from 'mesauth-angular';
|
|
94
|
+
|
|
95
|
+
export const appConfig: ApplicationConfig = {
|
|
96
|
+
providers: [
|
|
97
|
+
provideHttpClient(
|
|
98
|
+
withInterceptors([mesAuthInterceptor]) // Handles 401/403 redirects
|
|
99
|
+
),
|
|
100
|
+
provideMesAuth({
|
|
101
|
+
apiBaseUrl: 'https://mes.kefico.vn/auth',
|
|
102
|
+
userBaseUrl: 'https://mes.kefico.vn/x' // For login/403 redirects
|
|
103
|
+
})
|
|
104
|
+
]
|
|
105
|
+
};
|
|
106
|
+
```
|
|
107
|
+
|
|
108
|
+
That's it! The library handles:
|
|
109
|
+
- Service initialization via `APP_INITIALIZER`
|
|
110
|
+
- `HttpClient` and `Router` injection automatically
|
|
111
|
+
- 401 → redirects to `{userBaseUrl}/login?returnUrl=...`
|
|
112
|
+
- 403 → redirects to `{userBaseUrl}/403?returnUrl=...`
|
|
113
|
+
|
|
114
|
+
### 3. Use in Components
|
|
115
|
+
|
|
116
|
+
```ts
|
|
117
|
+
import { MesAuthService } from 'mesauth-angular';
|
|
118
|
+
|
|
119
|
+
@Component({...})
|
|
120
|
+
export class MyComponent {
|
|
121
|
+
private auth = inject(MesAuthService);
|
|
122
|
+
|
|
123
|
+
// Observable streams
|
|
124
|
+
currentUser$ = this.auth.currentUser$;
|
|
125
|
+
notifications$ = this.auth.notifications$;
|
|
126
|
+
|
|
127
|
+
logout() {
|
|
128
|
+
this.auth.logout().subscribe();
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Configuration Options
|
|
134
|
+
|
|
135
|
+
```ts
|
|
136
|
+
interface MesAuthConfig {
|
|
137
|
+
apiBaseUrl: string; // Required: MesAuth API base URL
|
|
138
|
+
userBaseUrl?: string; // Optional: Base URL for login/403 redirects
|
|
139
|
+
withCredentials?: boolean; // Optional: Send cookies (default: true)
|
|
140
|
+
}
|
|
141
|
+
```
|
|
142
|
+
|
|
143
|
+
## Theme Support
|
|
144
|
+
|
|
145
|
+
The library automatically detects and adapts to your application's theme:
|
|
146
|
+
|
|
147
|
+
### Automatic Theme Detection
|
|
148
|
+
The library checks for theme indicators on the `<html>` element:
|
|
149
|
+
- `class="dark"`
|
|
150
|
+
- `data-theme="dark"`
|
|
151
|
+
- `theme="dark"`
|
|
152
|
+
- `data-coreui-theme="dark"`
|
|
153
|
+
|
|
154
|
+
### Dynamic Theme Changes
|
|
155
|
+
Theme changes are detected in real-time using `MutationObserver`, so components automatically update when your app switches themes.
|
|
156
|
+
|
|
157
|
+
### Manual Theme Control
|
|
158
|
+
```ts
|
|
159
|
+
import { ThemeService } from 'mesauth-angular';
|
|
160
|
+
|
|
161
|
+
// Check current theme
|
|
162
|
+
const currentTheme = themeService.currentTheme; // 'light' | 'dark'
|
|
163
|
+
|
|
164
|
+
// Manually set theme
|
|
165
|
+
themeService.setTheme('dark');
|
|
166
|
+
|
|
167
|
+
// Listen for theme changes
|
|
168
|
+
themeService.currentTheme$.subscribe(theme => {
|
|
169
|
+
console.log('Theme changed to:', theme);
|
|
170
|
+
});
|
|
171
|
+
```
|
|
172
|
+
|
|
173
|
+
## Avatar Loading
|
|
174
|
+
|
|
175
|
+
Avatars are loaded efficiently using multiple strategies:
|
|
176
|
+
|
|
177
|
+
### Primary Method: Direct Path Usage
|
|
178
|
+
If the user object contains an `avatarPath`, it's used directly:
|
|
179
|
+
- **Full URLs**: Used as-is (e.g., `https://example.com/avatar.jpg`)
|
|
180
|
+
- **Relative Paths**: Combined with API base URL (e.g., `/uploads/avatar.jpg` → `{apiBaseUrl}/uploads/avatar.jpg`)
|
|
181
|
+
|
|
182
|
+
### Fallback Method: API Endpoint
|
|
183
|
+
If no `avatarPath` is available, avatars are loaded via API:
|
|
184
|
+
- **API Endpoint**: `GET {apiBaseUrl}/auth/{userId}/avatar`
|
|
185
|
+
- **Authentication**: Uses the same credentials as other API calls
|
|
186
|
+
|
|
187
|
+
### Cache Busting
|
|
188
|
+
Avatar URLs include timestamps to prevent browser caching issues during updates:
|
|
189
|
+
- Automatic refresh when user data changes
|
|
190
|
+
- Manual refresh triggers for upload/delete operations
|
|
191
|
+
|
|
192
|
+
### Fallback Service
|
|
193
|
+
- **UI Avatars**: Generates initials-based avatars if no user data available
|
|
194
|
+
- **Authentication**: Not required for fallback avatars
|
|
195
|
+
|
|
196
|
+
## Components
|
|
197
|
+
|
|
198
|
+
**Note:** All components are standalone and can be imported directly.
|
|
199
|
+
|
|
200
|
+
### ma-user-profile
|
|
201
|
+
|
|
202
|
+
A reusable Angular component for displaying the current user's profile information, with options for navigation and logout.
|
|
203
|
+
|
|
204
|
+
- **Description**: Renders user details (e.g., name, avatar) fetched via the MesAuthService. Supports custom event handlers for navigation and logout actions.
|
|
205
|
+
- **Inputs**: None (data is sourced from the MesAuthService).
|
|
206
|
+
- **Outputs**:
|
|
207
|
+
- `onNavigate`: Emits an event when the user triggers navigation (e.g., to a profile page). Pass a handler to define behavior.
|
|
208
|
+
- `onLogout`: Emits an event when the user logs out. Pass a handler to perform logout logic (e.g., clear tokens, redirect).
|
|
209
|
+
- **Usage Example**:
|
|
210
|
+
|
|
211
|
+
```html
|
|
212
|
+
<ma-user-profile
|
|
213
|
+
(onNavigate)="handleNavigation($event)"
|
|
214
|
+
(onLogout)="handleLogout()">
|
|
215
|
+
</ma-user-profile>
|
|
216
|
+
```
|
|
217
|
+
|
|
218
|
+
In your component's TypeScript file:
|
|
219
|
+
|
|
220
|
+
```ts
|
|
221
|
+
handleNavigation(event: any) {
|
|
222
|
+
// Navigate to user profile page
|
|
223
|
+
this.router.navigate(['/profile']);
|
|
224
|
+
}
|
|
225
|
+
|
|
226
|
+
handleLogout() {
|
|
227
|
+
// Perform logout, e.g., clear session and redirect
|
|
228
|
+
this.mesAuth.logout(); // Assuming a logout method exists
|
|
229
|
+
this.router.navigate(['/login']);
|
|
230
|
+
}
|
|
231
|
+
```
|
|
232
|
+
|
|
233
|
+
### ma-notification-panel
|
|
234
|
+
|
|
235
|
+
A standalone component for displaying a slide-out notification panel with real-time updates.
|
|
236
|
+
|
|
237
|
+
- **Description**: Shows a list of notifications, allows marking as read/delete, and integrates with toast notifications for new alerts.
|
|
238
|
+
- **Inputs**: None.
|
|
239
|
+
- **Outputs**: None (uses internal methods for actions).
|
|
240
|
+
- **Usage Example**:
|
|
241
|
+
|
|
242
|
+
```html
|
|
243
|
+
<ma-notification-panel #notificationPanel></ma-notification-panel>
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
In your component:
|
|
247
|
+
|
|
248
|
+
```ts
|
|
249
|
+
// To open the panel
|
|
250
|
+
notificationPanel.open();
|
|
251
|
+
```
|
|
252
|
+
|
|
253
|
+
## Migration Guide
|
|
254
|
+
|
|
255
|
+
### Upgrading from v0.x to v1.1.0+
|
|
256
|
+
|
|
257
|
+
The setup has been greatly simplified. Here's how to migrate:
|
|
258
|
+
|
|
259
|
+
**Before (v0.x):**
|
|
260
|
+
```ts
|
|
261
|
+
// app.config.ts - OLD WAY
|
|
262
|
+
import { MesAuthModule, MesAuthService } from 'mesauth-angular';
|
|
263
|
+
import { HTTP_INTERCEPTORS } from '@angular/common/http';
|
|
264
|
+
|
|
265
|
+
export const appConfig: ApplicationConfig = {
|
|
266
|
+
providers: [
|
|
267
|
+
importProvidersFrom(MesAuthModule),
|
|
268
|
+
{ provide: HTTP_INTERCEPTORS, useClass: MesAuthInterceptor, multi: true }
|
|
269
|
+
]
|
|
270
|
+
};
|
|
271
|
+
|
|
272
|
+
// app.component.ts - OLD WAY
|
|
273
|
+
export class AppComponent {
|
|
274
|
+
constructor() {
|
|
275
|
+
this.mesAuthService.init({
|
|
276
|
+
apiBaseUrl: '...',
|
|
277
|
+
userBaseUrl: '...'
|
|
278
|
+
}, inject(HttpClient), inject(Router));
|
|
279
|
+
}
|
|
280
|
+
}
|
|
281
|
+
```
|
|
282
|
+
|
|
283
|
+
**After (v1.1.0+):**
|
|
284
|
+
```ts
|
|
285
|
+
// app.config.ts - NEW WAY (everything in one place!)
|
|
286
|
+
import { provideMesAuth, mesAuthInterceptor } from 'mesauth-angular';
|
|
287
|
+
|
|
288
|
+
export const appConfig: ApplicationConfig = {
|
|
289
|
+
providers: [
|
|
290
|
+
provideHttpClient(withInterceptors([mesAuthInterceptor])),
|
|
291
|
+
provideMesAuth({
|
|
292
|
+
apiBaseUrl: 'https://mes.kefico.vn/auth',
|
|
293
|
+
userBaseUrl: 'https://mes.kefico.vn/x'
|
|
294
|
+
})
|
|
295
|
+
]
|
|
296
|
+
};
|
|
297
|
+
|
|
298
|
+
// app.component.ts - No init() needed!
|
|
299
|
+
export class AppComponent {
|
|
300
|
+
// Just inject and use - no manual initialization required
|
|
301
|
+
}
|
|
302
|
+
```
|
|
303
|
+
|
|
304
|
+
**Key Changes:**
|
|
305
|
+
- `provideMesAuth()` replaces `MesAuthModule` + manual `init()` call
|
|
306
|
+
- `mesAuthInterceptor` (functional) replaces `MesAuthInterceptor` (class-based)
|
|
307
|
+
- No need to inject `HttpClient` or `Router` manually
|
|
308
|
+
- Configuration moved from `AppComponent` to `app.config.ts`
|
|
309
|
+
|
|
310
|
+
## Troubleshooting
|
|
311
|
+
|
|
312
|
+
### JIT Compiler Error in Production or AOT Mode
|
|
313
|
+
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:
|
|
314
|
+
- The package is being imported directly from source code (e.g., during development) without building it first.
|
|
315
|
+
- The client app is running in AOT (Ahead-of-Time) compilation mode, which requires pre-compiled libraries.
|
|
316
|
+
|
|
317
|
+
**Solutions:**
|
|
318
|
+
1. **Build the package for production/AOT compatibility:**
|
|
319
|
+
- Ensure you have built the package using `npm run build` (which uses ng-packagr or similar to generate AOT-ready code).
|
|
320
|
+
- Install the built package via npm (e.g., from a local tarball or registry) instead of linking to the source folder.
|
|
321
|
+
|
|
322
|
+
2. **For development (if you must link to source):**
|
|
323
|
+
- Switch your Angular app to JIT mode by bootstrapping with `@angular/platform-browser-dynamic` instead of `@angular/platform-browser`.
|
|
324
|
+
|
|
325
|
+
3. **Verify imports:**
|
|
326
|
+
- Ensure you're importing from the built package (e.g., `import { MesAuthService } from 'mesauth-angular';`) and not from the `src` folder.
|
|
327
|
+
|
|
328
|
+
### Components Appear Empty
|
|
329
|
+
If components like `ma-user` or `ma-user-profile` render as empty:
|
|
330
|
+
- Ensure `provideMesAuth()` is called in your `app.config.ts`.
|
|
331
|
+
- Check browser console for logs from components.
|
|
332
|
+
- If `currentUser` is null, the component shows a login button—verify the API returns user data.
|
|
333
|
+
|
|
334
|
+
## Notes
|
|
335
|
+
- The service expects an endpoint `GET {apiBaseUrl}/auth/me` that returns the current user.
|
|
336
|
+
- Avatar endpoint: `GET {apiBaseUrl}/auth/{userId}/avatar`
|
|
337
|
+
- SignalR events used: `ReceiveNotification` (adjust to your backend).
|