@hichchi/ngx-auth 0.0.1-alpha.4 → 0.0.1

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.
@@ -1,94 +1,47 @@
1
1
  import * as i0 from '@angular/core';
2
- import { Injectable, Inject, computed, inject, input, output, signal, effect, Component, TemplateRef, ViewContainerRef, Directive, NgModule } from '@angular/core';
3
- import * as i1$1 from '@angular/forms';
4
- import { Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
5
- import { AuthEndpoint, AuthField, isRoleObject, AuthErrorResponseCode } from '@hichchi/nest-connector/auth';
6
- import * as i1 from '@angular/common/http';
7
- import { provideHttpClient } from '@angular/common/http';
8
- import { take, map, tap, catchError, EMPTY, ReplaySubject, throwError, switchMap, filter } from 'rxjs';
2
+ import { InjectionToken, Inject, Injectable, computed, inject, input, output, signal, effect, Component, TemplateRef, ViewContainerRef, Directive, NgModule } from '@angular/core';
3
+ import * as i1 from '@angular/forms';
4
+ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angular/forms';
5
+ import { AuthEndpoint, isRoleObject, AuthField, AuthErrorResponseCode } from '@hichchi/nest-connector/auth';
6
+ import { take, map, tap, catchError, EMPTY, firstValueFrom, ReplaySubject, throwError, switchMap, filter } from 'rxjs';
9
7
  import { Endpoint, HttpClientErrorStatus } from '@hichchi/nest-connector';
10
- import { skipNotifyContext, validatedFormData } from '@hichchi/ngx-utils';
8
+ import { CrudHttpService, skipNotifyContext, validatedFormData } from '@hichchi/ngx-utils';
11
9
  import { toFirstCase } from '@hichchi/utils';
12
10
  import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
13
11
  import { withStorageSync } from '@angular-architects/ngrx-toolkit';
14
12
  import { Router } from '@angular/router';
15
- import * as i3 from '@hichchi/ngx-ui';
13
+ import * as i2 from '@hichchi/ngx-ui';
16
14
  import { ButtonComponent, HcCardComponent, HcSeparatorComponent } from '@hichchi/ngx-ui';
17
15
  import { CommonModule } from '@angular/common';
18
16
 
19
17
  /**
20
- * Injection token for authentication configuration
18
+ * Injection token for the ngx-auth runtime configuration.
21
19
  *
22
- * This constant defines the injection token used by Angular's dependency injection
23
- * system to provide authentication configuration throughout the ngx-auth module.
24
- * It allows the AuthConfig interface to be injected into services and components
25
- * that need access to authentication settings.
26
- *
27
- * The token is used internally by the NgxHichchiAuthModule.forRoot() method to
28
- * register the authentication configuration as a provider, making it available
29
- * for injection in services like AuthService.
30
- *
31
- * This follows Angular's recommended pattern for providing configuration objects
32
- * to libraries and modules, ensuring type safety and proper dependency injection.
20
+ * This token is bound in `NgxHichchiAuthModule.forRoot(config)` as:
21
+ * `{ provide: AUTH_CONFIG, useValue: config }`.
22
+ * Consumers can inject it to access the same `AuthConfig` object
23
+ * (for example `apiBaseURL` and optional `authField`).
33
24
  *
34
25
  * @example
35
26
  * ```typescript
36
- * // Used internally by the module to provide configuration
37
- * @NgModule({
38
- * providers: [
39
- * { provide: AUTH_CONFIG, useValue: config },
40
- * AuthService
41
- * ]
42
- * })
43
- * export class NgxHichchiAuthModule {
44
- * static forRoot(config: AuthConfig): ModuleWithProviders<NgxHichchiAuthModule> {
45
- * return {
46
- * ngModule: NgxHichchiAuthModule,
47
- * providers: [
48
- * { provide: AUTH_CONFIG, useValue: config },
49
- * provideHttpClient(),
50
- * AuthService
51
- * ]
52
- * };
53
- * }
54
- * }
27
+ * NgxHichchiAuthModule.forRoot({
28
+ * apiBaseURL: "https://api.example.com",
29
+ * });
55
30
  * ```
56
31
  *
57
32
  * @example
58
33
  * ```typescript
59
- * // Injecting the configuration in a service
60
34
  * @Injectable()
61
- * export class AuthService {
62
- * constructor(
63
- * @Inject(AUTH_CONFIG) private readonly config: AuthConfig
64
- * ) {
65
- * console.log('API Base URL:', this.config.apiBaseURL);
66
- * console.log('Auth Field:', this.config.authField);
67
- * }
68
- * }
69
- * ```
70
- *
71
- * @example
72
- * ```typescript
73
- * // Using in a component (though typically not recommended)
74
- * @Component({
75
- * selector: 'app-auth-info',
76
- * template: `<p>API URL: {{ apiUrl }}</p>`
77
- * })
78
- * export class AuthInfoComponent {
79
- * apiUrl: string;
80
- *
81
- * constructor(@Inject(AUTH_CONFIG) private config: AuthConfig) {
82
- * this.apiUrl = config.apiBaseURL;
35
+ * export class ExampleService {
36
+ * constructor(@Inject(AUTH_CONFIG) private readonly config: AuthConfig) {
37
+ * console.log(this.config.apiBaseURL);
83
38
  * }
84
39
  * }
85
40
  * ```
86
41
  *
87
- * @see {@link AuthConfig} Interface that defines the structure of the configuration object
88
- * @see {@link NgxHichchiAuthModule} Module that uses this token to provide configuration
89
- * @see {@link AuthService} Service that injects this configuration
42
+ * @see {@link AuthConfig} Configuration contract provided through this token
90
43
  */
91
- const AUTH_CONFIG = "AUTH_CONFIG";
44
+ const AUTH_CONFIG = new InjectionToken("AUTH_CONFIG");
92
45
 
93
46
  /**
94
47
  * Width of the Google OAuth authentication popup window in pixels
@@ -233,20 +186,22 @@ const AUTH_GUARD_OPTIONS_KEY = "authGuardOptions";
233
186
  * @see {@link AuthState} State management service for authentication
234
187
  * @see {@link AuthResponse} Response interface for authentication operations
235
188
  */
236
- class AuthService {
237
- http;
189
+ /**
190
+ * HTTP client wrapper for authentication and token lifecycle endpoints.
191
+ */
192
+ class AuthService extends CrudHttpService {
238
193
  config;
239
194
  /**
240
195
  * Creates an instance of AuthService
241
196
  *
242
- * @param http - Http client
243
197
  * @param config - The authentication configuration injected from AUTH_CONFIG token
244
198
  *
245
199
  * @see {@link AUTH_CONFIG} Injection token for authentication configuration
246
200
  * @see {@link AuthConfig} Interface defining the configuration structure
247
201
  */
248
- constructor(http, config) {
249
- this.http = http;
202
+ // eslint-disable-next-line @angular-eslint/prefer-inject
203
+ constructor(config) {
204
+ super();
250
205
  this.config = config;
251
206
  }
252
207
  /**
@@ -257,7 +212,7 @@ class AuthService {
257
212
  * into JavaScript Date objects for easier handling in the client application.
258
213
  *
259
214
  * @param dto - The sign-in data containing user credentials
260
- * @param skipErrorNotify - Optional flag to skip error notifications for this request
215
+ * @param skipNotify - Optional flag to skip error notifications for this request
261
216
  * @returns Observable that emits the authentication response with user data and tokens
262
217
  *
263
218
  * @example
@@ -281,10 +236,8 @@ class AuthService {
281
236
  * @see {@link AuthResponse} Interface for authentication response
282
237
  * @see {@link AuthEndpoint.SIGN_IN} Backend endpoint for user authentication
283
238
  */
284
- signIn(dto, skipErrorNotify) {
285
- return this.http
286
- .post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_IN}`, dto, skipNotifyContext(skipErrorNotify))
287
- .pipe(take(1), map(res => ({
239
+ signIn(dto, skipNotify) {
240
+ return this.post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_IN}`, dto, { skipNotify }).pipe(take(1), map(res => ({
288
241
  ...res,
289
242
  accessTokenExpiresOn: new Date(res.accessTokenExpiresOn),
290
243
  refreshTokenExpiresOn: new Date(res.refreshTokenExpiresOn),
@@ -392,7 +345,7 @@ class AuthService {
392
345
  * Date objects for easier handling in the client application.
393
346
  *
394
347
  * @param accessToken - The access token to exchange for authentication response
395
- * @param skipErrorNotify - Optional flag to skip error notifications for this request
348
+ * @param skipNotify - Optional flag to skip error notifications for this request
396
349
  * @returns Observable that emits the complete authentication response
397
350
  *
398
351
  * @example
@@ -418,11 +371,11 @@ class AuthService {
418
371
  * @see {@link AuthEndpoint.GET_AUTH_RESPONSE} Backend endpoint for token exchange
419
372
  * @see {@link googleSignIn} Method that provides access tokens for this operation
420
373
  */
421
- getAuthResponse(accessToken, skipErrorNotify) {
374
+ getAuthResponse(accessToken, skipNotify) {
422
375
  return this.http
423
376
  .post(`${Endpoint.AUTH}/${AuthEndpoint.GET_AUTH_RESPONSE}`, {
424
377
  accessToken,
425
- }, skipNotifyContext(skipErrorNotify))
378
+ }, skipNotifyContext(skipNotify))
426
379
  .pipe(take(1), map(res => ({
427
380
  ...res,
428
381
  accessTokenExpiresOn: new Date(res.accessTokenExpiresOn),
@@ -441,7 +394,7 @@ class AuthService {
441
394
  * or handle email verification depending on your application's configuration.
442
395
  *
443
396
  * @param dto - The sign-up data containing user registration information
444
- * @param skipErrorNotify - Optional flag to skip error notifications for this request
397
+ * @param skipNotify - Optional flag to skip error notifications for this request
445
398
  * @returns Observable that emits the newly created user data
446
399
  *
447
400
  * @example
@@ -470,9 +423,9 @@ class AuthService {
470
423
  * @see {@link AuthEndpoint.SIGN_UP} Backend endpoint for user registration
471
424
  * @see {@link signIn} Method to authenticate user after registration
472
425
  */
473
- signUp(dto, skipErrorNotify) {
426
+ signUp(dto, skipNotify) {
474
427
  return this.http
475
- .post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_UP}`, dto, skipNotifyContext(skipErrorNotify))
428
+ .post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_UP}`, dto, skipNotifyContext(skipNotify))
476
429
  .pipe(take(1));
477
430
  }
478
431
  /**
@@ -486,7 +439,7 @@ class AuthService {
486
439
  * while keeping access tokens short-lived for better security.
487
440
  *
488
441
  * @param refreshToken - The refresh token to exchange for new tokens
489
- * @param skipErrorNotify - Optional flag to skip error notifications for this request
442
+ * @param skipNotify - Optional flag to skip error notifications for this request
490
443
  * @returns Observable that emits the new token response
491
444
  *
492
445
  * @example
@@ -515,11 +468,11 @@ class AuthService {
515
468
  * @see {@link AuthEndpoint.REFRESH_TOKEN} Backend endpoint for token refresh
516
469
  * @see {@link signIn} Method to get initial tokens through authentication
517
470
  */
518
- refreshToken(refreshToken, skipErrorNotify) {
471
+ refreshToken(refreshToken, skipNotify) {
519
472
  return this.http
520
473
  .post(`${Endpoint.AUTH}/${AuthEndpoint.REFRESH_TOKEN}`, {
521
474
  refreshToken,
522
- }, skipNotifyContext(skipErrorNotify))
475
+ }, skipNotifyContext(skipNotify))
523
476
  .pipe(take(1));
524
477
  }
525
478
  /**
@@ -532,7 +485,7 @@ class AuthService {
532
485
  * After calling this method, you should also clear any client-side authentication
533
486
  * data such as tokens stored in localStorage, sessionStorage, or application state.
534
487
  *
535
- * @param skipErrorNotify - Optional flag to skip error notifications for this request
488
+ * @param skipNotify - Optional flag to skip error notifications for this request
536
489
  * @returns Observable that emits a success response when sign-out is complete
537
490
  *
538
491
  * @example
@@ -578,21 +531,21 @@ class AuthService {
578
531
  * @see {@link AuthEndpoint.SIGN_OUT} Backend endpoint for user sign-out
579
532
  * @see {@link signIn} Method to authenticate user after sign-out
580
533
  */
581
- signOut(skipErrorNotify) {
534
+ signOut(skipNotify) {
582
535
  // this.app.startSpinner();
583
536
  return this.http
584
- .post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_OUT}`, {}, skipNotifyContext(skipErrorNotify))
537
+ .post(`${Endpoint.AUTH}/${AuthEndpoint.SIGN_OUT}`, {}, skipNotifyContext(skipNotify))
585
538
  .pipe(take(1));
586
539
  }
587
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, deps: [{ token: i1.HttpClient }, { token: AUTH_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
588
- static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, providedIn: "root" });
540
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthService, deps: [{ token: AUTH_CONFIG }], target: i0.ɵɵFactoryTarget.Injectable });
541
+ static ɵprov = i0.ɵɵngDeclareInjectable({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthService, providedIn: "root" });
589
542
  }
590
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthService, decorators: [{
543
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthService, decorators: [{
591
544
  type: Injectable,
592
545
  args: [{
593
546
  providedIn: "root",
594
547
  }]
595
- }], ctorParameters: () => [{ type: i1.HttpClient }, { type: undefined, decorators: [{
548
+ }], ctorParameters: () => [{ type: undefined, decorators: [{
596
549
  type: Inject,
597
550
  args: [AUTH_CONFIG]
598
551
  }] }] });
@@ -607,6 +560,7 @@ const initialState = {
607
560
  refreshToken: null,
608
561
  accessTokenExpiresOn: null,
609
562
  refreshTokenExpiresOn: null,
563
+ data: {}
610
564
  };
611
565
  /**
612
566
  * Authentication state management store using NgRx Signals
@@ -730,6 +684,10 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
730
684
  * ```
731
685
  */
732
686
  role: computed(() => user()?.role),
687
+ permissions: computed(() => {
688
+ const role = user()?.role;
689
+ return role && isRoleObject(role) ? role.permissions || [] : [];
690
+ }),
733
691
  /**
734
692
  * Computed signal that returns the current user's role name as a string
735
693
  *
@@ -879,7 +837,7 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
879
837
  *
880
838
  * This method handles user sign-in by calling the AuthService and updating
881
839
  * the authentication state with the response. It supports both Observable
882
- * and Promise return types based on the returnSub parameter, and can
840
+ * and Promise return types based on the asPromise parameter, and can
883
841
  * automatically redirect users after successful authentication.
884
842
  *
885
843
  * The method integrates with the error notification system and can
@@ -887,9 +845,9 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
887
845
  *
888
846
  * @param signInBody - The sign-in credentials containing email/username and password
889
847
  * @param redirect - Optional redirect path or function that returns a path after successful sign-in
890
- * @param returnSub - Optional flag to return Observable instead of Promise (defaults to false)
848
+ * @param asPromise - Optional flag to return a Promise instead of an Observable (defaults to false)
891
849
  * @param showError - Optional flag to control error notification display (defaults to true for Promise mode, false for Observable mode)
892
- * @returns Observable<AuthResponse> if returnSub is true, Promise<void> otherwise
850
+ * @returns Promise<AuthResponse> if asPromise is true, otherwise Observable<AuthResponse>
893
851
  *
894
852
  * @example
895
853
  * ```typescript
@@ -974,19 +932,17 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
974
932
  * @see {@link SignInBody} Interface for sign-in request data
975
933
  * @see {@link AuthResponse} Interface for authentication response
976
934
  */
977
- signIn: (signInBody, redirect, returnSub, showError) => {
978
- const sub = authService.signIn(signInBody, !(showError || !returnSub && showError === undefined)).pipe(tap((res) => {
935
+ signIn: (signInBody, redirect, asPromise, showError) => {
936
+ const sub = authService.signIn(signInBody, !(showError || asPromise && showError === undefined)).pipe(tap((res) => {
979
937
  patchState(state, { ...res, signedIn: true });
980
938
  if (redirect) {
981
939
  void router.navigateByUrl(typeof redirect === "string" ? redirect : redirect(res));
982
940
  }
983
941
  }));
984
- if (returnSub) {
985
- return sub;
942
+ if (asPromise) {
943
+ return firstValueFrom(sub);
986
944
  }
987
- return new Promise((resolve) => {
988
- sub.subscribe({ next: () => resolve(), error: () => resolve() });
989
- });
945
+ return sub;
990
946
  },
991
947
  /**
992
948
  * Authenticates a user using an existing access token
@@ -1002,9 +958,9 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1002
958
  *
1003
959
  * @param accessToken - The access token to authenticate with
1004
960
  * @param redirect - Optional redirect path or function that returns a path after successful authentication
1005
- * @param returnSub - Optional flag to return Observable instead of Promise (defaults to false)
961
+ * @param asPromise - Optional flag to return a Promise instead of an Observable (defaults to false)
1006
962
  * @param showError - Optional flag to control error notification display (defaults to true for Promise mode, false for Observable mode)
1007
- * @returns Observable<AuthResponse> if returnSub is true, Promise<void> otherwise
963
+ * @returns Promise<AuthResponse> if asPromise is true, otherwise Observable<AuthResponse>
1008
964
  *
1009
965
  * @example
1010
966
  * ```typescript
@@ -1083,8 +1039,8 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1083
1039
  * @see {@link AccessToken} Type representing access tokens
1084
1040
  * @see {@link AuthResponse} Interface for authentication response
1085
1041
  */
1086
- authenticateWithToken: (accessToken, redirect, returnSub, showError) => {
1087
- const sub = authService.getAuthResponse(accessToken, !(showError || !returnSub && showError === undefined)).pipe(tap((res) => {
1042
+ authenticateWithToken: (accessToken, redirect, asPromise, showError) => {
1043
+ const sub = authService.getAuthResponse(accessToken, !(showError || asPromise && showError === undefined)).pipe(tap((res) => {
1088
1044
  patchState(state, {
1089
1045
  ...res,
1090
1046
  signedIn: Boolean(res.user.role)
@@ -1093,12 +1049,10 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1093
1049
  void router.navigateByUrl(typeof redirect === "string" ? redirect : redirect(res));
1094
1050
  }
1095
1051
  }), catchError(() => EMPTY));
1096
- if (returnSub) {
1097
- return sub;
1052
+ if (asPromise) {
1053
+ return firstValueFrom(sub);
1098
1054
  }
1099
- return new Promise((resolve) => {
1100
- sub.subscribe({ next: () => resolve(), error: () => resolve() });
1101
- });
1055
+ return sub;
1102
1056
  },
1103
1057
  /**
1104
1058
  * Signs out the current user and clears authentication state
@@ -1112,9 +1066,9 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1112
1066
  * handling that ensures local state is cleared even if server sign-out fails.
1113
1067
  *
1114
1068
  * @param redirect - Optional redirect path after successful sign-out
1115
- * @param returnSub - Optional flag to return Observable instead of Promise (defaults to false)
1069
+ * @param asPromise - Optional flag to return a Promise instead of an Observable (defaults to false)
1116
1070
  * @param showError - Optional flag to control error notification display (defaults to true for Promise mode, false for Observable mode)
1117
- * @returns Observable<SuccessResponse | null> if returnSub is true, Promise<void> otherwise
1071
+ * @returns Promise<SuccessResponse | null> if asPromise is true, otherwise Observable<SuccessResponse | null>
1118
1072
  *
1119
1073
  * @example
1120
1074
  * ```typescript
@@ -1204,8 +1158,8 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1204
1158
  * @see {@link SuccessResponse} Interface for success response
1205
1159
  * @see {@link reset} Method to manually clear authentication state
1206
1160
  */
1207
- signOut: (redirect, returnSub, showError) => {
1208
- const sub = authService.signOut(!(showError || !returnSub && showError === undefined)).pipe(tap({
1161
+ signOut: (redirect, asPromise, showError) => {
1162
+ const sub = authService.signOut(!(showError || asPromise && showError === undefined)).pipe(tap({
1209
1163
  next: () => {
1210
1164
  patchState(state, initialState);
1211
1165
  if (redirect) {
@@ -1213,13 +1167,17 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1213
1167
  }
1214
1168
  },
1215
1169
  }), catchError(() => EMPTY));
1216
- if (returnSub) {
1217
- return sub;
1170
+ if (asPromise) {
1171
+ return firstValueFrom(sub);
1218
1172
  }
1219
- return new Promise((resolve) => {
1220
- sub.subscribe({ next: () => resolve(), error: () => resolve() });
1221
- });
1173
+ return sub;
1222
1174
  },
1175
+ setData(stateData) {
1176
+ patchState(state, data => ({
1177
+ ...data,
1178
+ data: { ...data.data, ...stateData },
1179
+ }));
1180
+ }
1223
1181
  })));
1224
1182
 
1225
1183
  /* eslint-disable @angular-eslint/no-output-on-prefix */
@@ -1293,15 +1251,15 @@ const AuthState = signalStore({ providedIn: "root" }, withState(initialState), w
1293
1251
  * @see {@link HttpError} Interface for HTTP error handling
1294
1252
  */
1295
1253
  class AuthFormComponent {
1296
- config;
1297
- fb;
1298
- authService;
1254
+ config = inject(AUTH_CONFIG);
1255
+ fb = inject(FormBuilder);
1256
+ authService = inject(AuthService);
1299
1257
  /** Input signal to control whether local authentication (username/email + password) is enabled */
1300
- local = input(true);
1258
+ local = input(true, ...(ngDevMode ? [{ debugName: "local" }] : []));
1301
1259
  /** Input signal to control whether Google OAuth authentication is enabled */
1302
- google = input(true);
1260
+ google = input(true, ...(ngDevMode ? [{ debugName: "google" }] : []));
1303
1261
  /** Input signal to control whether Facebook authentication is enabled */
1304
- facebook = input(true);
1262
+ facebook = input(true, ...(ngDevMode ? [{ debugName: "facebook" }] : []));
1305
1263
  /** Output emitter that fires when an authentication error occurs */
1306
1264
  onError = output();
1307
1265
  /** Output emitter that fires when a user successfully signs in */
@@ -1309,26 +1267,23 @@ class AuthFormComponent {
1309
1267
  /** Output emitter that fires when a user successfully signs up */
1310
1268
  onSignUp = output();
1311
1269
  /** Writable signal indicating whether an authentication operation is in progress */
1312
- isLoading = signal(false);
1270
+ isLoading = signal(false, ...(ngDevMode ? [{ debugName: "isLoading" }] : []));
1313
1271
  /** Writable signal indicating whether the form is in sign-up mode (true) or sign-in mode (false) */
1314
- isSignUp = signal(false);
1272
+ isSignUp = signal(false, ...(ngDevMode ? [{ debugName: "isSignUp" }] : []));
1315
1273
  /** Writable signal indicating whether an error state is currently active */
1316
- isError = signal(false);
1274
+ isError = signal(false, ...(ngDevMode ? [{ debugName: "isError" }] : []));
1317
1275
  /** Writable signal containing the current authentication field type (EMAIL or USERNAME) */
1318
- authField = signal(AuthField.EMAIL);
1276
+ authField = signal(AuthField.EMAIL, ...(ngDevMode ? [{ debugName: "authField" }] : []));
1319
1277
  /** Writable signal containing the display label for the authentication field */
1320
- authFieldLabel = signal(toFirstCase(AuthField.EMAIL));
1278
+ authFieldLabel = signal(toFirstCase(AuthField.EMAIL), ...(ngDevMode ? [{ debugName: "authFieldLabel" }] : []));
1321
1279
  /** Writable signal containing the current error object, if any */
1322
- error = signal(null);
1280
+ error = signal(null, ...(ngDevMode ? [{ debugName: "error" }] : []));
1323
1281
  /** Injected AuthState service for managing authentication state */
1324
1282
  authState = inject(AuthState);
1325
1283
  /** Reactive form group for handling authentication form data */
1326
1284
  authForm;
1327
- constructor(config, fb, authService) {
1328
- this.config = config;
1329
- this.fb = fb;
1330
- this.authService = authService;
1331
- this.authField.set(config.authField === AuthField.USERNAME ? AuthField.USERNAME : AuthField.EMAIL);
1285
+ constructor() {
1286
+ this.authField.set(this.config.authField === AuthField.USERNAME ? AuthField.USERNAME : AuthField.EMAIL);
1332
1287
  this.authFieldLabel.set(toFirstCase(this.authField()));
1333
1288
  this.authForm = this.fb.group({
1334
1289
  firstName: ["", Validators.required],
@@ -1365,7 +1320,7 @@ class AuthFormComponent {
1365
1320
  async handleGoogleSignIn() {
1366
1321
  const accessToken = await this.authService.googleSignIn();
1367
1322
  // noinspection ES6MissingAwait
1368
- this.authState.authenticateWithToken(accessToken, undefined, true).subscribe({
1323
+ this.authState.authenticateWithToken(accessToken, undefined, false).subscribe({
1369
1324
  next: authResponse => {
1370
1325
  this.isLoading.set(false);
1371
1326
  this.onSignIn.emit(authResponse);
@@ -1394,7 +1349,15 @@ class AuthFormComponent {
1394
1349
  handleLocalAuth(signInBody) {
1395
1350
  this.isLoading.set(true);
1396
1351
  this.isError.set(false);
1397
- this.authState.signIn(signInBody, undefined, true, false).subscribe();
1352
+ this.authState.signIn(signInBody, "/", false).subscribe({
1353
+ next: () => {
1354
+ this.isLoading.set(false);
1355
+ },
1356
+ error: () => {
1357
+ this.isLoading.set(false);
1358
+ this.isError.set(true);
1359
+ },
1360
+ });
1398
1361
  }
1399
1362
  /**
1400
1363
  * Handles user registration (sign-up) process
@@ -1490,16 +1453,13 @@ class AuthFormComponent {
1490
1453
  this.error.set(error);
1491
1454
  this.onError.emit(error);
1492
1455
  }
1493
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthFormComponent, deps: [{ token: AUTH_CONFIG }, { token: i1$1.FormBuilder }, { token: AuthService }], target: i0.ɵɵFactoryTarget.Component });
1494
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "19.0.7", type: AuthFormComponent, isStandalone: false, selector: "hc-auth-card", inputs: { local: { classPropertyName: "local", publicName: "local", isSignal: true, isRequired: false, transformFunction: null }, google: { classPropertyName: "google", publicName: "google", isSignal: true, isRequired: false, transformFunction: null }, facebook: { classPropertyName: "facebook", publicName: "facebook", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onError: "onError", onSignIn: "onSignIn", onSignUp: "onSignUp" }, ngImport: i0, template: "<!--<div class=\"auth-container d-flex justify-content-center align-items-center\">-->\r\n<!-- -->\r\n<!--</div>-->\r\n<hc-card>\r\n <!-- @if (isLoading()) {-->\r\n <!-- <div class=\"loading-overlay w-100 h-100\"></div>-->\r\n <!-- }-->\r\n <form\r\n class=\"d-inline-flex flex-column align-items-center w-100\"\r\n [formGroup]=\"authForm\"\r\n (ngSubmit)=\"handleSubmit($event)\"\r\n >\r\n @if (isSignUp()) {\r\n <div class=\"form-group w-100\">\r\n <label for=\"firstName\" class=\"form-label\">First Name</label>\r\n <input\r\n id=\"firstName\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"firstName\"\r\n placeholder=\"Enter your first name\"\r\n />\r\n </div>\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"lastName\" class=\"form-label\">Last Name</label>\r\n <input\r\n id=\"lastName\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"lastName\"\r\n placeholder=\"Enter your last name\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"authField\" class=\"form-label\">{{ authFieldLabel() }}</label>\r\n <input\r\n id=\"authField\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"authFieldValue\"\r\n [placeholder]=\"'Enter your ' + authFieldLabel().toLowerCase()\"\r\n />\r\n </div>\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <input\r\n id=\"password\"\r\n type=\"password\"\r\n class=\"form-control w-100\"\r\n formControlName=\"password\"\r\n placeholder=\"Enter your password\"\r\n />\r\n </div>\r\n\r\n <button type=\"submit\" class=\"btn btn-primary mb-3 w-100\" [disabled]=\"isLoading()\">\r\n {{ isSignUp() ? (isLoading() ? \"Signing Up...\" : \"Sign Up\") : isLoading() ? \"Signing In...\" : \"Sign In\" }}\r\n </button>\r\n\r\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" (click)=\"isSignUp.set(!isSignUp())\">\r\n {{ isSignUp() ? \"Already have an account? Sign In\" : \"Don't have an account? Sign Up\" }}\r\n </button>\r\n\r\n @if (!isSignUp()) {\r\n @if (local() && (google() || facebook())) {\r\n <hc-separator label=\"OR\"></hc-separator>\r\n }\r\n\r\n @if (google()) {\r\n <button type=\"button\" class=\"btn google-btn btn-light mb-3 w-100\" (click)=\"handleGoogleSignIn()\">\r\n <div class=\"icon\"></div>\r\n Sign in with Google\r\n </button>\r\n }\r\n\r\n @if (facebook()) {\r\n <button type=\"button\" class=\"btn facebook-btn btn-light mb-3 w-100\">\r\n <div class=\"icon\"></div>\r\n Sign in with Facebook\r\n </button>\r\n }\r\n\r\n @if (isError()) {\r\n <div class=\"error-message w-100\">\r\n {{ error()?.error?.message || \"Something went wrong!\" }}\r\n </div>\r\n }\r\n }\r\n </form>\r\n</hc-card>\r\n", styles: [".auth-form{background:#fffffff2;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);border-radius:16px;margin:8px;padding:2rem;position:relative;z-index:1}.loading-overlay{background:#ffffffe6;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border-radius:16px;display:flex;align-items:center;justify-content:center;font-weight:600;color:var(--secondary-color);font-size:1.1rem;position:absolute;top:0;left:0}.loading-overlay:after{content:\"\";width:50px;height:50px;border:5px solid var(--secondary-color);border-top:5px solid transparent;border-radius:50%;animation:spin 1s linear infinite;margin-left:10px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.form-group{position:relative;margin-bottom:1.5rem}.form-label{font-weight:600;color:var(--text-color);margin-bottom:.5rem;font-size:.9rem;text-transform:uppercase;letter-spacing:.5px}.form-control{border:2px solid var(--border-color);border-radius:12px;padding:.75rem 1rem;font-size:1rem;transition:all .3s ease;background:#fffc;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.form-control:focus{border-color:var(--secondary-color);box-shadow:0 0 0 3px #667eea1a;background:#fffffff2}.form-control::placeholder{color:var(--text-light)}.btn{border-radius:12px;padding:.75rem 1.5rem;font-weight:600;font-size:1rem;transition:all .3s ease;border:none;position:relative;overflow:hidden}.btn:before{content:\"\";position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);transition:left .5s}.btn:hover:before{left:100%}.btn-primary{background:var(--secondary-gradient);color:#fff;box-shadow:var(--shadow-md)}.btn-primary:hover{box-shadow:var(--shadow-lg)}.btn-link{color:var(--text-light);text-decoration:none;font-size:.9rem;transition:all .3s ease}.btn-link:hover{color:var(--secondary-color);text-decoration:underline}.google-btn,.facebook-btn{display:flex;align-items:center;justify-content:center;gap:12px;color:var(--text-color);background:#ffffffe6;border:2px solid var(--border-color);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);font-weight:600;transition:all .3s ease}.google-btn:hover,.facebook-btn:hover{background:#fff;border-color:var(--secondary-color);box-shadow:var(--shadow-md)}.google-btn .icon,.facebook-btn .icon{height:24px;width:24px;background-repeat:no-repeat;background-size:contain;background-position:center}.google-btn .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTcuNiA5LjJsLS4xLTEuOEg5djMuNGg0LjhDMTMuNiAxMiAxMyAxMyAxMiAxMy42djIuMmgzYTguOCA4LjggMCAwIDAgMi42LTYuNnoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxwYXRoIGQ9Ik05IDE4YzIuNCAwIDQuNS0uOCA2LTIuMmwtMy0yLjJhNS40IDUuNCAwIDAgMS04LTIuOUgxVjEzYTkgOSAwIDAgMCA4IDV6IiBmaWxsPSIjMzRBODUzIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNNCAxMC43YTUuNCA1LjQgMCAwIDEgMC0zLjRWNUgxYTkgOSAwIDAgMCAwIDhsMy0yLjN6IiBmaWxsPSIjRkJCQzA1IiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNOSAzLjZjMS4zIDAgMi41LjQgMy40IDEuM0wxNSAyLjNBOSA5IDAgMCAwIDEgNWwzIDIuNGE1LjQgNS40IDAgMCAxIDUtMy43eiIgZmlsbD0iI0VBNDMzNSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PHBhdGggZD0iTTAgMGgxOHYxOEgweiIvPjwvZz48L3N2Zz4=)}.facebook-btn .icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAmJJREFUaEPtmj9oFEEUxr9v7nIpzkIRLQQVFLUSBBs7IbfGwkrhtNHbvYiiRTqbNKIRbGwD/iFkd88uISmsEtwErRQsLEVUiGIbsDAK8W6e3IESkuzt3eVucwMz7b5hvt/73rwZluHwtcr+Wrb6BMJhgnkYMASyKlotDGZqt1goT81R1EUDdG+SqDXnWPD8n6ZkfiNB3Qk6XiAmZv+fZguw0+5ZBzp3QITAOw1EiupDrYYVZvFHaZ0DkNfCHCn7ILwAwolbZ0ccEMgCtRqLKu77pAQ45eAOBI/6CID3oqA0DrCl7tdfAIKJKPRGk7K+/nsfAci3Pav5YzMzl9fMBCBHI9+daEd8PbZvHKhmswdfTV79biSACD4tht7xOPHF4nTux65fD7RIEcIDJAZbBU2ljYrm0mLFLcSJKpSD+xTcbVX0+rhUADT19JI/ciUWwAveEDjTtwAAn0eBW4oT6LjBFxBHzAUohctQctgCdJKB1uYklJB1oLU0JkYJMZ7ReLExUFFW5oPycuwm9vyTSli/Rm8aNWKSwKmUbqNyPQrKU4mkbQQ4nv8V4CEjAU7ffDqwey33m2DGSIAhNziqiM/NDOvySdzdEiqMhA61vDQWwPH8GwCfGQtwzg0eCjGWGoCGvFbkxy0WfBv5nh8npCFUYe8WPfQslJxIDSB+IXsSx+amy10otls3v07bu1AbR3tnoXYP2D3QWeX8n2VLyJaQLaGm/4XsQbbNAkmebrtQfBdK56lBbxxoPDUYKoWzSsml5DLYTkRvAADMsv7cpkp5TKXP9+7RR3cBGpkH5weob/8FwaStQs990hUAAAAASUVORK5CYII=)}.separator{position:relative;width:calc(100% - 40px);height:1px;background:linear-gradient(90deg,transparent,var(--border-color),transparent);margin:2rem auto}.separator:after{content:\"OR\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:#ffffffe6;padding:0 1rem;font-size:.8rem;font-weight:600;color:var(--text-light);letter-spacing:1px}.error-message{color:var(--danger-color);margin-top:1rem;font-weight:600;text-align:center}@keyframes slideIn{0%{opacity:0}to{opacity:1}}@media (max-width: 480px){.auth-container{margin:1rem;border-radius:16px}.auth-form{padding:1.5rem;margin:4px}.btn{padding:.875rem 1.25rem;font-size:.95rem}}\n"], dependencies: [{ kind: "directive", type: i1$1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1$1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1$1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1$1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1$1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1$1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i3.HcCardComponent, selector: "hc-card" }, { kind: "component", type: i3.HcSeparatorComponent, selector: "hc-separator", inputs: ["label"] }] });
1456
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthFormComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1457
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "21.1.4", type: AuthFormComponent, isStandalone: false, selector: "hc-auth-card", inputs: { local: { classPropertyName: "local", publicName: "local", isSignal: true, isRequired: false, transformFunction: null }, google: { classPropertyName: "google", publicName: "google", isSignal: true, isRequired: false, transformFunction: null }, facebook: { classPropertyName: "facebook", publicName: "facebook", isSignal: true, isRequired: false, transformFunction: null } }, outputs: { onError: "onError", onSignIn: "onSignIn", onSignUp: "onSignUp" }, ngImport: i0, template: "<hc-card>\r\n <section class=\"auth-shell\">\r\n <header class=\"auth-header\">\r\n <div class=\"auth-badge\">{{ isSignUp() ? \"Create Account\" : \"Welcome Back\" }}</div>\r\n <h2 class=\"auth-title\">{{ isSignUp() ? \"Create your account\" : \"Sign in to your account\" }}</h2>\r\n <p class=\"auth-subtitle\">\r\n {{ isSignUp() ? \"Set up your account to get started.\" : \"Use your credentials to continue.\" }}\r\n </p>\r\n </header>\r\n\r\n <form class=\"auth-form\" [formGroup]=\"authForm\" (ngSubmit)=\"handleSubmit($event)\">\r\n @if (isSignUp()) {\r\n <div class=\"auth-grid\">\r\n <div class=\"auth-field\">\r\n <label for=\"firstName\" class=\"auth-label\">First Name</label>\r\n <input\r\n id=\"firstName\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"firstName\"\r\n placeholder=\"Enter your first name\"\r\n />\r\n </div>\r\n <div class=\"auth-field\">\r\n <label for=\"lastName\" class=\"auth-label\">Last Name</label>\r\n <input\r\n id=\"lastName\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"lastName\"\r\n placeholder=\"Enter your last name\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-field\">\r\n <label for=\"authField\" class=\"auth-label\">{{ authFieldLabel() }}</label>\r\n <input\r\n id=\"authField\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"authFieldValue\"\r\n [placeholder]=\"'Enter your ' + authFieldLabel().toLowerCase()\"\r\n />\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <label for=\"password\" class=\"auth-label\">Password</label>\r\n <input\r\n id=\"password\"\r\n type=\"password\"\r\n class=\"auth-input\"\r\n formControlName=\"password\"\r\n placeholder=\"Enter your password\"\r\n />\r\n </div>\r\n\r\n <button type=\"submit\" class=\"auth-btn auth-btn-primary\">\r\n {{ isSignUp() ? (isLoading() ? \"Signing Up...\" : \"Sign Up\") : isLoading() ? \"Signing In...\" : \"Sign In\" }}\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn-link\" (click)=\"isSignUp.set(!isSignUp())\">\r\n {{ isSignUp() ? \"Already have an account? Sign In\" : \"Don't have an account? Sign Up\" }}\r\n </button>\r\n\r\n @if (!isSignUp()) {\r\n @if (local() && (google() || facebook())) {\r\n <hc-separator label=\"or\"></hc-separator>\r\n }\r\n\r\n @if (google()) {\r\n <button type=\"button\" class=\"auth-btn social-btn google-btn\" (click)=\"handleGoogleSignIn()\">\r\n <div class=\"icon\"></div>\r\n Continue with Google\r\n </button>\r\n }\r\n\r\n @if (facebook()) {\r\n <button type=\"button\" class=\"auth-btn social-btn facebook-btn\">\r\n <div class=\"icon\"></div>\r\n Continue with Facebook\r\n </button>\r\n }\r\n\r\n @if (isError()) {\r\n <p class=\"error-message\">\r\n {{ error()?.error?.message || \"Something went wrong!\" }}\r\n </p>\r\n }\r\n }\r\n </form>\r\n </section>\r\n</hc-card>\r\n", styles: [".auth-shell{display:grid;gap:1rem}.auth-header{text-align:center}.auth-badge{display:inline-flex;align-items:center;border-radius:999px;padding:.3rem .65rem;background:#2563eb17;color:#1d4ed8;font-size:.68rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase}.auth-title{margin:.55rem 0 .25rem;color:#0f172a;font-size:clamp(1.1rem,2.8vw,1.45rem);font-weight:700;line-height:1.25;letter-spacing:-.02em}.auth-subtitle{margin:0;color:#64748b;font-size:.88rem}.auth-form{display:grid;gap:.85rem}.auth-grid{display:grid;grid-template-columns:1fr 1fr;gap:.75rem}.auth-field{display:grid;gap:.4rem}.auth-label{display:block;font-weight:700;color:#334155;font-size:.69rem;text-transform:uppercase;letter-spacing:.08em}.auth-input{width:100%;border:1px solid #cbd5e1;border-radius:.75rem;padding:.74rem .82rem;font-size:.92rem;color:#0f172a;background:#fff;transition:border-color .2s ease,box-shadow .2s ease}.auth-input:focus{border-color:#2563eb;box-shadow:0 0 0 3px #2563eb26;outline:0}.auth-input::placeholder{color:#94a3b8}.auth-btn{width:100%;min-height:2.7rem;border:0;border-radius:.78rem;font-size:.9rem;font-weight:700;line-height:1.2;cursor:pointer;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease}.auth-btn:disabled{cursor:not-allowed;opacity:.7}.auth-btn-primary{background:linear-gradient(135deg,#2563eb,#4f46e5);color:#fff;box-shadow:0 16px 26px -18px #2563ebd9}.auth-btn-primary:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 20px 28px -18px #2563ebe6}.auth-btn-link{min-height:1.65rem;margin-top:-.1rem;border-radius:0;background:transparent;color:#64748b;font-size:.82rem;font-weight:600;box-shadow:none}.auth-btn-link:hover{color:#2563eb;text-decoration:underline}.social-btn{display:flex;align-items:center;justify-content:center;gap:.6rem;border:1px solid #cbd5e1;background:#fff;color:#1e293b}.social-btn:hover{background:#f8fafc;border-color:#94a3b8}.social-btn .icon{height:1.1rem;width:1.1rem;background-repeat:no-repeat;background-size:contain;background-position:center}.google-btn .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTcuNiA5LjJsLS4xLTEuOEg5djMuNGg0LjhDMTMuNiAxMiAxMyAxMyAxMiAxMy42djIuMmgzYTguOCA4LjggMCAwIDAgMi42LTYuNnoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxwYXRoIGQ9Ik05IDE4YzIuNCAwIDQuNS0uOCA2LTIuMmwtMy0yLjJhNS40IDUuNCAwIDAgMS04LTIuOUgxVjEzYTkgOSAwIDAgMCA4IDV6IiBmaWxsPSIjMzRBODUzIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNNCAxMC43YTUuNCA1LjQgMCAwIDEgMC0zLjRWNUgxYTkgOSAwIDAgMCAwIDhsMy0yLjN6IiBmaWxsPSIjRkJCQzA1IiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNOSAzLjZjMS4zIDAgMi41LjQgMy40IDEuM0wxNSAyLjNBOSA5IDAgMCAwIDEgNWwzIDIuNGE1LjQgNS40IDAgMCAxIDUtMy43eiIgZmlsbD0iI0VBNDMzNSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PHBhdGggZD0iTTAgMGgxOHYxOEgweiIvPjwvZz48L3N2Zz4=)}.facebook-btn .icon{background:#1877f2;border-radius:999px;position:relative}.facebook-btn .icon:before{content:\"f\";position:absolute;left:50%;top:50%;transform:translate(-44%,-56%);color:#fff;font-weight:700;font-size:.9rem;font-family:Arial,sans-serif}.error-message{margin:0;border-radius:.7rem;padding:.62rem .75rem;background:#fee2e2;border:1px solid #fecaca;color:#b91c1c;text-align:center;font-size:.82rem;font-weight:600}@media(max-width:480px){.auth-grid{grid-template-columns:1fr}}\n"], dependencies: [{ kind: "directive", type: i1.ɵNgNoValidate, selector: "form:not([ngNoForm]):not([ngNativeValidate])" }, { kind: "directive", type: i1.DefaultValueAccessor, selector: "input:not([type=checkbox])[formControlName],textarea[formControlName],input:not([type=checkbox])[formControl],textarea[formControl],input:not([type=checkbox])[ngModel],textarea[ngModel],[ngDefaultControl]" }, { kind: "directive", type: i1.NgControlStatus, selector: "[formControlName],[ngModel],[formControl]" }, { kind: "directive", type: i1.NgControlStatusGroup, selector: "[formGroupName],[formArrayName],[ngModelGroup],[formGroup],[formArray],form:not([ngNoForm]),[ngForm]" }, { kind: "directive", type: i1.FormGroupDirective, selector: "[formGroup]", inputs: ["formGroup"], outputs: ["ngSubmit"], exportAs: ["ngForm"] }, { kind: "directive", type: i1.FormControlName, selector: "[formControlName]", inputs: ["formControlName", "disabled", "ngModel"], outputs: ["ngModelChange"] }, { kind: "component", type: i2.HcCardComponent, selector: "hc-card" }, { kind: "component", type: i2.HcSeparatorComponent, selector: "hc-separator", inputs: ["label"] }] });
1495
1458
  }
1496
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: AuthFormComponent, decorators: [{
1459
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthFormComponent, decorators: [{
1497
1460
  type: Component,
1498
- args: [{ selector: "hc-auth-card", standalone: false, template: "<!--<div class=\"auth-container d-flex justify-content-center align-items-center\">-->\r\n<!-- -->\r\n<!--</div>-->\r\n<hc-card>\r\n <!-- @if (isLoading()) {-->\r\n <!-- <div class=\"loading-overlay w-100 h-100\"></div>-->\r\n <!-- }-->\r\n <form\r\n class=\"d-inline-flex flex-column align-items-center w-100\"\r\n [formGroup]=\"authForm\"\r\n (ngSubmit)=\"handleSubmit($event)\"\r\n >\r\n @if (isSignUp()) {\r\n <div class=\"form-group w-100\">\r\n <label for=\"firstName\" class=\"form-label\">First Name</label>\r\n <input\r\n id=\"firstName\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"firstName\"\r\n placeholder=\"Enter your first name\"\r\n />\r\n </div>\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"lastName\" class=\"form-label\">Last Name</label>\r\n <input\r\n id=\"lastName\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"lastName\"\r\n placeholder=\"Enter your last name\"\r\n />\r\n </div>\r\n }\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"authField\" class=\"form-label\">{{ authFieldLabel() }}</label>\r\n <input\r\n id=\"authField\"\r\n type=\"text\"\r\n class=\"form-control w-100\"\r\n formControlName=\"authFieldValue\"\r\n [placeholder]=\"'Enter your ' + authFieldLabel().toLowerCase()\"\r\n />\r\n </div>\r\n\r\n <div class=\"form-group w-100\">\r\n <label for=\"password\" class=\"form-label\">Password</label>\r\n <input\r\n id=\"password\"\r\n type=\"password\"\r\n class=\"form-control w-100\"\r\n formControlName=\"password\"\r\n placeholder=\"Enter your password\"\r\n />\r\n </div>\r\n\r\n <button type=\"submit\" class=\"btn btn-primary mb-3 w-100\" [disabled]=\"isLoading()\">\r\n {{ isSignUp() ? (isLoading() ? \"Signing Up...\" : \"Sign Up\") : isLoading() ? \"Signing In...\" : \"Sign In\" }}\r\n </button>\r\n\r\n <button type=\"button\" class=\"btn btn-link p-0 mb-3\" (click)=\"isSignUp.set(!isSignUp())\">\r\n {{ isSignUp() ? \"Already have an account? Sign In\" : \"Don't have an account? Sign Up\" }}\r\n </button>\r\n\r\n @if (!isSignUp()) {\r\n @if (local() && (google() || facebook())) {\r\n <hc-separator label=\"OR\"></hc-separator>\r\n }\r\n\r\n @if (google()) {\r\n <button type=\"button\" class=\"btn google-btn btn-light mb-3 w-100\" (click)=\"handleGoogleSignIn()\">\r\n <div class=\"icon\"></div>\r\n Sign in with Google\r\n </button>\r\n }\r\n\r\n @if (facebook()) {\r\n <button type=\"button\" class=\"btn facebook-btn btn-light mb-3 w-100\">\r\n <div class=\"icon\"></div>\r\n Sign in with Facebook\r\n </button>\r\n }\r\n\r\n @if (isError()) {\r\n <div class=\"error-message w-100\">\r\n {{ error()?.error?.message || \"Something went wrong!\" }}\r\n </div>\r\n }\r\n }\r\n </form>\r\n</hc-card>\r\n", styles: [".auth-form{background:#fffffff2;-webkit-backdrop-filter:blur(20px);backdrop-filter:blur(20px);border-radius:16px;margin:8px;padding:2rem;position:relative;z-index:1}.loading-overlay{background:#ffffffe6;-webkit-backdrop-filter:blur(5px);backdrop-filter:blur(5px);border-radius:16px;display:flex;align-items:center;justify-content:center;font-weight:600;color:var(--secondary-color);font-size:1.1rem;position:absolute;top:0;left:0}.loading-overlay:after{content:\"\";width:50px;height:50px;border:5px solid var(--secondary-color);border-top:5px solid transparent;border-radius:50%;animation:spin 1s linear infinite;margin-left:10px}@keyframes spin{0%{transform:rotate(0)}to{transform:rotate(360deg)}}.form-group{position:relative;margin-bottom:1.5rem}.form-label{font-weight:600;color:var(--text-color);margin-bottom:.5rem;font-size:.9rem;text-transform:uppercase;letter-spacing:.5px}.form-control{border:2px solid var(--border-color);border-radius:12px;padding:.75rem 1rem;font-size:1rem;transition:all .3s ease;background:#fffc;-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px)}.form-control:focus{border-color:var(--secondary-color);box-shadow:0 0 0 3px #667eea1a;background:#fffffff2}.form-control::placeholder{color:var(--text-light)}.btn{border-radius:12px;padding:.75rem 1.5rem;font-weight:600;font-size:1rem;transition:all .3s ease;border:none;position:relative;overflow:hidden}.btn:before{content:\"\";position:absolute;top:0;left:-100%;width:100%;height:100%;background:linear-gradient(90deg,transparent,rgba(255,255,255,.2),transparent);transition:left .5s}.btn:hover:before{left:100%}.btn-primary{background:var(--secondary-gradient);color:#fff;box-shadow:var(--shadow-md)}.btn-primary:hover{box-shadow:var(--shadow-lg)}.btn-link{color:var(--text-light);text-decoration:none;font-size:.9rem;transition:all .3s ease}.btn-link:hover{color:var(--secondary-color);text-decoration:underline}.google-btn,.facebook-btn{display:flex;align-items:center;justify-content:center;gap:12px;color:var(--text-color);background:#ffffffe6;border:2px solid var(--border-color);-webkit-backdrop-filter:blur(10px);backdrop-filter:blur(10px);font-weight:600;transition:all .3s ease}.google-btn:hover,.facebook-btn:hover{background:#fff;border-color:var(--secondary-color);box-shadow:var(--shadow-md)}.google-btn .icon,.facebook-btn .icon{height:24px;width:24px;background-repeat:no-repeat;background-size:contain;background-position:center}.google-btn .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTcuNiA5LjJsLS4xLTEuOEg5djMuNGg0LjhDMTMuNiAxMiAxMyAxMyAxMiAxMy42djIuMmgzYTguOCA4LjggMCAwIDAgMi42LTYuNnoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxwYXRoIGQ9Ik05IDE4YzIuNCAwIDQuNS0uOCA2LTIuMmwtMy0yLjJhNS40IDUuNCAwIDAgMS04LTIuOUgxVjEzYTkgOSAwIDAgMCA4IDV6IiBmaWxsPSIjMzRBODUzIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNNCAxMC43YTUuNCA1LjQgMCAwIDEgMC0zLjRWNUgxYTkgOSAwIDAgMCAwIDhsMy0yLjN6IiBmaWxsPSIjRkJCQzA1IiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNOSAzLjZjMS4zIDAgMi41LjQgMy40IDEuM0wxNSAyLjNBOSA5IDAgMCAwIDEgNWwzIDIuNGE1LjQgNS40IDAgMCAxIDUtMy43eiIgZmlsbD0iI0VBNDMzNSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PHBhdGggZD0iTTAgMGgxOHYxOEgweiIvPjwvZz48L3N2Zz4=)}.facebook-btn .icon{background-image:url(data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAADAAAAAwCAYAAABXAvmHAAAAAXNSR0IArs4c6QAAAmJJREFUaEPtmj9oFEEUxr9v7nIpzkIRLQQVFLUSBBs7IbfGwkrhtNHbvYiiRTqbNKIRbGwD/iFkd88uISmsEtwErRQsLEVUiGIbsDAK8W6e3IESkuzt3eVucwMz7b5hvt/73rwZluHwtcr+Wrb6BMJhgnkYMASyKlotDGZqt1goT81R1EUDdG+SqDXnWPD8n6ZkfiNB3Qk6XiAmZv+fZguw0+5ZBzp3QITAOw1EiupDrYYVZvFHaZ0DkNfCHCn7ILwAwolbZ0ccEMgCtRqLKu77pAQ45eAOBI/6CID3oqA0DrCl7tdfAIKJKPRGk7K+/nsfAci3Pav5YzMzl9fMBCBHI9+daEd8PbZvHKhmswdfTV79biSACD4tht7xOPHF4nTux65fD7RIEcIDJAZbBU2ljYrm0mLFLcSJKpSD+xTcbVX0+rhUADT19JI/ciUWwAveEDjTtwAAn0eBW4oT6LjBFxBHzAUohctQctgCdJKB1uYklJB1oLU0JkYJMZ7ReLExUFFW5oPycuwm9vyTSli/Rm8aNWKSwKmUbqNyPQrKU4mkbQQ4nv8V4CEjAU7ffDqwey33m2DGSIAhNziqiM/NDOvySdzdEiqMhA61vDQWwPH8GwCfGQtwzg0eCjGWGoCGvFbkxy0WfBv5nh8npCFUYe8WPfQslJxIDSB+IXsSx+amy10otls3v07bu1AbR3tnoXYP2D3QWeX8n2VLyJaQLaGm/4XsQbbNAkmebrtQfBdK56lBbxxoPDUYKoWzSsml5DLYTkRvAADMsv7cpkp5TKXP9+7RR3cBGpkH5weob/8FwaStQs990hUAAAAASUVORK5CYII=)}.separator{position:relative;width:calc(100% - 40px);height:1px;background:linear-gradient(90deg,transparent,var(--border-color),transparent);margin:2rem auto}.separator:after{content:\"OR\";position:absolute;top:50%;left:50%;transform:translate(-50%,-50%);background:#ffffffe6;padding:0 1rem;font-size:.8rem;font-weight:600;color:var(--text-light);letter-spacing:1px}.error-message{color:var(--danger-color);margin-top:1rem;font-weight:600;text-align:center}@keyframes slideIn{0%{opacity:0}to{opacity:1}}@media (max-width: 480px){.auth-container{margin:1rem;border-radius:16px}.auth-form{padding:1.5rem;margin:4px}.btn{padding:.875rem 1.25rem;font-size:.95rem}}\n"] }]
1499
- }], ctorParameters: () => [{ type: undefined, decorators: [{
1500
- type: Inject,
1501
- args: [AUTH_CONFIG]
1502
- }] }, { type: i1$1.FormBuilder }, { type: AuthService }] });
1461
+ args: [{ selector: "hc-auth-card", standalone: false, template: "<hc-card>\r\n <section class=\"auth-shell\">\r\n <header class=\"auth-header\">\r\n <div class=\"auth-badge\">{{ isSignUp() ? \"Create Account\" : \"Welcome Back\" }}</div>\r\n <h2 class=\"auth-title\">{{ isSignUp() ? \"Create your account\" : \"Sign in to your account\" }}</h2>\r\n <p class=\"auth-subtitle\">\r\n {{ isSignUp() ? \"Set up your account to get started.\" : \"Use your credentials to continue.\" }}\r\n </p>\r\n </header>\r\n\r\n <form class=\"auth-form\" [formGroup]=\"authForm\" (ngSubmit)=\"handleSubmit($event)\">\r\n @if (isSignUp()) {\r\n <div class=\"auth-grid\">\r\n <div class=\"auth-field\">\r\n <label for=\"firstName\" class=\"auth-label\">First Name</label>\r\n <input\r\n id=\"firstName\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"firstName\"\r\n placeholder=\"Enter your first name\"\r\n />\r\n </div>\r\n <div class=\"auth-field\">\r\n <label for=\"lastName\" class=\"auth-label\">Last Name</label>\r\n <input\r\n id=\"lastName\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"lastName\"\r\n placeholder=\"Enter your last name\"\r\n />\r\n </div>\r\n </div>\r\n }\r\n\r\n <div class=\"auth-field\">\r\n <label for=\"authField\" class=\"auth-label\">{{ authFieldLabel() }}</label>\r\n <input\r\n id=\"authField\"\r\n type=\"text\"\r\n class=\"auth-input\"\r\n formControlName=\"authFieldValue\"\r\n [placeholder]=\"'Enter your ' + authFieldLabel().toLowerCase()\"\r\n />\r\n </div>\r\n\r\n <div class=\"auth-field\">\r\n <label for=\"password\" class=\"auth-label\">Password</label>\r\n <input\r\n id=\"password\"\r\n type=\"password\"\r\n class=\"auth-input\"\r\n formControlName=\"password\"\r\n placeholder=\"Enter your password\"\r\n />\r\n </div>\r\n\r\n <button type=\"submit\" class=\"auth-btn auth-btn-primary\">\r\n {{ isSignUp() ? (isLoading() ? \"Signing Up...\" : \"Sign Up\") : isLoading() ? \"Signing In...\" : \"Sign In\" }}\r\n </button>\r\n\r\n <button type=\"button\" class=\"auth-btn auth-btn-link\" (click)=\"isSignUp.set(!isSignUp())\">\r\n {{ isSignUp() ? \"Already have an account? Sign In\" : \"Don't have an account? Sign Up\" }}\r\n </button>\r\n\r\n @if (!isSignUp()) {\r\n @if (local() && (google() || facebook())) {\r\n <hc-separator label=\"or\"></hc-separator>\r\n }\r\n\r\n @if (google()) {\r\n <button type=\"button\" class=\"auth-btn social-btn google-btn\" (click)=\"handleGoogleSignIn()\">\r\n <div class=\"icon\"></div>\r\n Continue with Google\r\n </button>\r\n }\r\n\r\n @if (facebook()) {\r\n <button type=\"button\" class=\"auth-btn social-btn facebook-btn\">\r\n <div class=\"icon\"></div>\r\n Continue with Facebook\r\n </button>\r\n }\r\n\r\n @if (isError()) {\r\n <p class=\"error-message\">\r\n {{ error()?.error?.message || \"Something went wrong!\" }}\r\n </p>\r\n }\r\n }\r\n </form>\r\n </section>\r\n</hc-card>\r\n", styles: [".auth-shell{display:grid;gap:1rem}.auth-header{text-align:center}.auth-badge{display:inline-flex;align-items:center;border-radius:999px;padding:.3rem .65rem;background:#2563eb17;color:#1d4ed8;font-size:.68rem;font-weight:700;letter-spacing:.09em;text-transform:uppercase}.auth-title{margin:.55rem 0 .25rem;color:#0f172a;font-size:clamp(1.1rem,2.8vw,1.45rem);font-weight:700;line-height:1.25;letter-spacing:-.02em}.auth-subtitle{margin:0;color:#64748b;font-size:.88rem}.auth-form{display:grid;gap:.85rem}.auth-grid{display:grid;grid-template-columns:1fr 1fr;gap:.75rem}.auth-field{display:grid;gap:.4rem}.auth-label{display:block;font-weight:700;color:#334155;font-size:.69rem;text-transform:uppercase;letter-spacing:.08em}.auth-input{width:100%;border:1px solid #cbd5e1;border-radius:.75rem;padding:.74rem .82rem;font-size:.92rem;color:#0f172a;background:#fff;transition:border-color .2s ease,box-shadow .2s ease}.auth-input:focus{border-color:#2563eb;box-shadow:0 0 0 3px #2563eb26;outline:0}.auth-input::placeholder{color:#94a3b8}.auth-btn{width:100%;min-height:2.7rem;border:0;border-radius:.78rem;font-size:.9rem;font-weight:700;line-height:1.2;cursor:pointer;transition:transform .2s ease,box-shadow .2s ease,background-color .2s ease}.auth-btn:disabled{cursor:not-allowed;opacity:.7}.auth-btn-primary{background:linear-gradient(135deg,#2563eb,#4f46e5);color:#fff;box-shadow:0 16px 26px -18px #2563ebd9}.auth-btn-primary:hover:not(:disabled){transform:translateY(-1px);box-shadow:0 20px 28px -18px #2563ebe6}.auth-btn-link{min-height:1.65rem;margin-top:-.1rem;border-radius:0;background:transparent;color:#64748b;font-size:.82rem;font-weight:600;box-shadow:none}.auth-btn-link:hover{color:#2563eb;text-decoration:underline}.social-btn{display:flex;align-items:center;justify-content:center;gap:.6rem;border:1px solid #cbd5e1;background:#fff;color:#1e293b}.social-btn:hover{background:#f8fafc;border-color:#94a3b8}.social-btn .icon{height:1.1rem;width:1.1rem;background-repeat:no-repeat;background-size:contain;background-position:center}.google-btn .icon{background-image:url(data:image/svg+xml;base64,PHN2ZyB3aWR0aD0iMTgiIGhlaWdodD0iMTgiIHhtbG5zPSJodHRwOi8vd3d3LnczLm9yZy8yMDAwL3N2ZyI+PGcgZmlsbD0ibm9uZSIgZmlsbC1ydWxlPSJldmVub2RkIj48cGF0aCBkPSJNMTcuNiA5LjJsLS4xLTEuOEg5djMuNGg0LjhDMTMuNiAxMiAxMyAxMyAxMiAxMy42djIuMmgzYTguOCA4LjggMCAwIDAgMi42LTYuNnoiIGZpbGw9IiM0Mjg1RjQiIGZpbGwtcnVsZT0ibm9uemVybyIvPjxwYXRoIGQ9Ik05IDE4YzIuNCAwIDQuNS0uOCA2LTIuMmwtMy0yLjJhNS40IDUuNCAwIDAgMS04LTIuOUgxVjEzYTkgOSAwIDAgMCA4IDV6IiBmaWxsPSIjMzRBODUzIiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNNCAxMC43YTUuNCA1LjQgMCAwIDEgMC0zLjRWNUgxYTkgOSAwIDAgMCAwIDhsMy0yLjN6IiBmaWxsPSIjRkJCQzA1IiBmaWxsLXJ1bGU9Im5vbnplcm8iLz48cGF0aCBkPSJNOSAzLjZjMS4zIDAgMi41LjQgMy40IDEuM0wxNSAyLjNBOSA5IDAgMCAwIDEgNWwzIDIuNGE1LjQgNS40IDAgMCAxIDUtMy43eiIgZmlsbD0iI0VBNDMzNSIgZmlsbC1ydWxlPSJub256ZXJvIi8+PHBhdGggZD0iTTAgMGgxOHYxOEgweiIvPjwvZz48L3N2Zz4=)}.facebook-btn .icon{background:#1877f2;border-radius:999px;position:relative}.facebook-btn .icon:before{content:\"f\";position:absolute;left:50%;top:50%;transform:translate(-44%,-56%);color:#fff;font-weight:700;font-size:.9rem;font-family:Arial,sans-serif}.error-message{margin:0;border-radius:.7rem;padding:.62rem .75rem;background:#fee2e2;border:1px solid #fecaca;color:#b91c1c;text-align:center;font-size:.82rem;font-weight:600}@media(max-width:480px){.auth-grid{grid-template-columns:1fr}}\n"] }]
1462
+ }], ctorParameters: () => [], propDecorators: { local: [{ type: i0.Input, args: [{ isSignal: true, alias: "local", required: false }] }], google: [{ type: i0.Input, args: [{ isSignal: true, alias: "google", required: false }] }], facebook: [{ type: i0.Input, args: [{ isSignal: true, alias: "facebook", required: false }] }], onError: [{ type: i0.Output, args: ["onError"] }], onSignIn: [{ type: i0.Output, args: ["onSignIn"] }], onSignUp: [{ type: i0.Output, args: ["onSignUp"] }] } });
1503
1463
 
1504
1464
  /**
1505
1465
  * Angular structural directive for permission-based conditional rendering
@@ -1595,7 +1555,7 @@ class PermissionDirective {
1595
1555
  * <div *hcPermission="['users.read', 'users.write']">Content</div>
1596
1556
  * ```
1597
1557
  */
1598
- hcPermission = input.required();
1558
+ hcPermission = input.required(...(ngDevMode ? [{ debugName: "hcPermission" }] : []));
1599
1559
  /**
1600
1560
  * Constructor that sets up the permission checking effect
1601
1561
  *
@@ -1650,15 +1610,15 @@ class PermissionDirective {
1650
1610
  : user.role.permissions.includes(requiredPermission)
1651
1611
  : false;
1652
1612
  }
1653
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: PermissionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1654
- static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "19.0.7", type: PermissionDirective, isStandalone: true, selector: "[hcPermission]", inputs: { hcPermission: { classPropertyName: "hcPermission", publicName: "hcPermission", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
1613
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: PermissionDirective, deps: [], target: i0.ɵɵFactoryTarget.Directive });
1614
+ static ɵdir = i0.ɵɵngDeclareDirective({ minVersion: "17.1.0", version: "21.1.4", type: PermissionDirective, isStandalone: true, selector: "[hcPermission]", inputs: { hcPermission: { classPropertyName: "hcPermission", publicName: "hcPermission", isSignal: true, isRequired: true, transformFunction: null } }, ngImport: i0 });
1655
1615
  }
1656
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: PermissionDirective, decorators: [{
1616
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: PermissionDirective, decorators: [{
1657
1617
  type: Directive,
1658
1618
  args: [{
1659
1619
  selector: "[hcPermission]",
1660
1620
  }]
1661
- }], ctorParameters: () => [] });
1621
+ }], ctorParameters: () => [], propDecorators: { hcPermission: [{ type: i0.Input, args: [{ isSignal: true, alias: "hcPermission", required: true }] }] } });
1662
1622
 
1663
1623
  /**
1664
1624
  * Enumeration of authentication guard conditions
@@ -2002,7 +1962,7 @@ function roleGuard(role, options) {
2002
1962
  return false;
2003
1963
  }
2004
1964
  }
2005
- await authState.signOut("/auth");
1965
+ await authState.signOut("/auth", true);
2006
1966
  return false;
2007
1967
  };
2008
1968
  }
@@ -2274,6 +2234,9 @@ function authInterceptor(redirect, onRedirect) {
2274
2234
  * @see {@link PermissionDirective} Permission-based conditional rendering directive
2275
2235
  * @see {@link AuthService} Authentication service for managing user sessions
2276
2236
  */
2237
+ /**
2238
+ * Root module for reusable authentication UI, directives, and providers.
2239
+ */
2277
2240
  class NgxHichchiAuthModule {
2278
2241
  /**
2279
2242
  * Configures the NgxHichchiAuthModule with the provided authentication configuration
@@ -2309,27 +2272,25 @@ class NgxHichchiAuthModule {
2309
2272
  static forRoot(config) {
2310
2273
  return {
2311
2274
  ngModule: NgxHichchiAuthModule,
2312
- providers: [{ provide: AUTH_CONFIG, useValue: config }, provideHttpClient(), AuthService],
2275
+ providers: [{ provide: AUTH_CONFIG, useValue: config }, AuthService],
2313
2276
  };
2314
2277
  }
2315
- static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: NgxHichchiAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2316
- static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "19.0.7", ngImport: i0, type: NgxHichchiAuthModule, declarations: [AuthFormComponent], imports: [CommonModule,
2278
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: NgxHichchiAuthModule, deps: [], target: i0.ɵɵFactoryTarget.NgModule });
2279
+ static ɵmod = i0.ɵɵngDeclareNgModule({ minVersion: "14.0.0", version: "21.1.4", ngImport: i0, type: NgxHichchiAuthModule, declarations: [AuthFormComponent], imports: [CommonModule,
2317
2280
  FormsModule,
2318
2281
  ReactiveFormsModule,
2319
2282
  ButtonComponent,
2320
2283
  HcCardComponent,
2321
- HcCardComponent,
2322
2284
  HcSeparatorComponent,
2323
2285
  PermissionDirective], exports: [AuthFormComponent, PermissionDirective] });
2324
- static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: NgxHichchiAuthModule, imports: [CommonModule,
2286
+ static ɵinj = i0.ɵɵngDeclareInjector({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: NgxHichchiAuthModule, imports: [CommonModule,
2325
2287
  FormsModule,
2326
2288
  ReactiveFormsModule,
2327
2289
  ButtonComponent,
2328
2290
  HcCardComponent,
2329
- HcCardComponent,
2330
2291
  HcSeparatorComponent] });
2331
2292
  }
2332
- i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImport: i0, type: NgxHichchiAuthModule, decorators: [{
2293
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: NgxHichchiAuthModule, decorators: [{
2333
2294
  type: NgModule,
2334
2295
  args: [{
2335
2296
  declarations: [AuthFormComponent],
@@ -2339,7 +2300,6 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "19.0.7", ngImpor
2339
2300
  ReactiveFormsModule,
2340
2301
  ButtonComponent,
2341
2302
  HcCardComponent,
2342
- HcCardComponent,
2343
2303
  HcSeparatorComponent,
2344
2304
  PermissionDirective,
2345
2305
  ],