@hichchi/ngx-auth 0.0.3 → 0.0.5

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.
@@ -5,7 +5,7 @@ import { FormBuilder, Validators, FormsModule, ReactiveFormsModule } from '@angu
5
5
  import { AuthEndpoint, isRoleObject, AuthField, AuthErrorResponseCode } from '@hichchi/nest-connector/auth';
6
6
  import { take, map, tap, catchError, EMPTY, firstValueFrom, ReplaySubject, throwError, switchMap, filter } from 'rxjs';
7
7
  import { Endpoint, HttpClientErrorStatus } from '@hichchi/nest-connector';
8
- import { CrudHttpService, skipNotifyContext, validatedFormData } from '@hichchi/ngx-utils';
8
+ import { CrudHttpService, extractSubdomain, skipNotifyContext, validatedFormData } from '@hichchi/ngx-utils';
9
9
  import { toFirstCase } from '@hichchi/utils';
10
10
  import { signalStore, withState, withComputed, withMethods, patchState } from '@ngrx/signals';
11
11
  import { withStorageSync } from '@angular-architects/ngrx-toolkit';
@@ -303,7 +303,8 @@ class AuthService extends CrudHttpService {
303
303
  const left = (window.screen.width - GOOGLE_AUTH_POPUP_WIDTH) / 2;
304
304
  // eslint-disable-next-line @typescript-eslint/no-magic-numbers
305
305
  const top = (window.screen.height - GOOGLE_AUTH_POPUP_HEIGHT) / 2;
306
- const popup = window.open(`${this.config.apiBaseURL}/${Endpoint.AUTH}/${AuthEndpoint.GOOGLE_SIGN_IN}?redirectUrl=${window.location.origin}`, "google-login-popup",
306
+ const tenant = extractSubdomain(this.config.splitDomain) || this.config.tenant;
307
+ const popup = window.open(`${this.config.apiBaseURL}/${Endpoint.AUTH}/${AuthEndpoint.GOOGLE_SIGN_IN}?redirectUrl=${window.location.origin}&tenant=${tenant}`, "google-login-popup",
307
308
  // eslint-disable-next-line prefer-template
308
309
  "resizable=no, location=no, toolbar=false, width=" +
309
310
  GOOGLE_AUTH_POPUP_WIDTH +
@@ -1454,11 +1455,11 @@ class AuthFormComponent {
1454
1455
  this.onError.emit(error);
1455
1456
  }
1456
1457
  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"] }] });
1458
+ 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 (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 </form>\r\n </section>\r\n</hc-card>\r\n", styles: ["*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box!important;margin:0;padding:0;border:0 solid}.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-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=)}.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"] }] });
1458
1459
  }
1459
1460
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "21.1.4", ngImport: i0, type: AuthFormComponent, decorators: [{
1460
1461
  type: Component,
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
+ 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 (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 </form>\r\n </section>\r\n</hc-card>\r\n", styles: ["*,:after,:before,::backdrop,::file-selector-button{box-sizing:border-box!important;margin:0;padding:0;border:0 solid}.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-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=)}.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
1463
  }], 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"] }] } });
1463
1464
 
1464
1465
  /**
@@ -2202,6 +2203,11 @@ function authInterceptor(redirect, onRedirect) {
2202
2203
  * The module must be configured using the forRoot() method to provide the necessary
2203
2204
  * authentication configuration.
2204
2205
  *
2206
+ * Tenant handling:
2207
+ * - `tenant` can be provided in the configuration or dynamically set in requests
2208
+ * via a custom HTTP header (`x-tenant`, controlled by `TENANT_HEADER_KEY`).
2209
+ * - This approach replaces previous subdomain-based tenant resolution.
2210
+ *
2205
2211
  * @example
2206
2212
  * ```typescript
2207
2213
  * // Basic module configuration
@@ -2229,6 +2235,20 @@ function authInterceptor(redirect, onRedirect) {
2229
2235
  * export class AppModule { }
2230
2236
  * ```
2231
2237
  *
2238
+ * @example
2239
+ * ```typescript
2240
+ * // Optional static tenant header
2241
+ * @NgModule({
2242
+ * imports: [
2243
+ * NgxHichchiAuthModule.forRoot({
2244
+ * apiBaseURL: 'https://api.example.com',
2245
+ * tenant: 'tenant-a'
2246
+ * })
2247
+ * ]
2248
+ * })
2249
+ * export class AppModule { }
2250
+ * ```
2251
+ *
2232
2252
  * @see {@link AuthConfig} Configuration interface for the authentication module
2233
2253
  * @see {@link AuthFormComponent} Authentication form component
2234
2254
  * @see {@link PermissionDirective} Permission-based conditional rendering directive
@@ -2242,10 +2262,11 @@ class NgxHichchiAuthModule {
2242
2262
  * Configures the NgxHichchiAuthModule with the provided authentication configuration
2243
2263
  *
2244
2264
  * This static method sets up the module with the necessary providers and configuration
2245
- * for authentication functionality. It provides the AuthService, HTTP client, and
2246
- * authentication configuration token that are required for the module to function properly.
2265
+ * for authentication functionality. The configuration includes the `apiBaseURL` for
2266
+ * all authentication requests, and optionally a `tenant` string that is attached
2267
+ * to requests via the `TENANT_HEADER_KEY` header.
2247
2268
  *
2248
- * @param config - The authentication configuration object containing API endpoints and settings
2269
+ * @param config - The authentication configuration object containing API endpoints, tenant, and other settings
2249
2270
  * @returns A ModuleWithProviders object configured with authentication providers
2250
2271
  *
2251
2272
  * @example
@@ -2265,9 +2286,19 @@ class NgxHichchiAuthModule {
2265
2286
  * })
2266
2287
  * ```
2267
2288
  *
2289
+ * @example
2290
+ * ```typescript
2291
+ * // Configuration with static tenant
2292
+ * NgxHichchiAuthModule.forRoot({
2293
+ * apiBaseURL: 'https://api.example.com',
2294
+ * tenant: 'tenant-a'
2295
+ * })
2296
+ * ```
2297
+ *
2268
2298
  * @see {@link AuthConfig} Interface defining the configuration structure
2269
2299
  * @see {@link AUTH_CONFIG} Injection token for the authentication configuration
2270
2300
  * @see {@link AuthService} Service that uses the provided configuration
2301
+ * @see {@link TENANT_HEADER_KEY} Constant used to attach tenant header to requests
2271
2302
  */
2272
2303
  static forRoot(config) {
2273
2304
  return {