@atlasauth/angular 0.15.1 → 0.16.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,10 +1,10 @@
1
1
  import * as i0 from '@angular/core';
2
- import { InjectionToken, signal, inject, PLATFORM_ID, computed, Injectable, TemplateRef, ViewContainerRef, Directive, Input, ElementRef, Renderer2, EventEmitter, Output, ChangeDetectionStrategy, Component, ChangeDetectorRef, effect, untracked, DestroyRef, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
2
+ import { InjectionToken, signal, inject, PLATFORM_ID, computed, Injectable, TemplateRef, ViewContainerRef, Directive, Input, ElementRef, Renderer2, EventEmitter, Output, ChangeDetectionStrategy, Component, ChangeDetectorRef, afterNextRender, effect, untracked, DestroyRef, makeEnvironmentProviders, ENVIRONMENT_INITIALIZER, NgModule } from '@angular/core';
3
3
  import { isPlatformBrowser, DOCUMENT } from '@angular/common';
4
4
  import { toSignal } from '@angular/core/rxjs-interop';
5
5
  import { BehaviorSubject, Subject, combineLatest, firstValueFrom } from 'rxjs';
6
6
  import { map, distinctUntilChanged, filter, take } from 'rxjs/operators';
7
- import { createOrganizationAuditLog, POLICY_STRINGS, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, policyTranslator, injectPolicyStyles, mountPolicyClickwrap, mountPolicyConsent, controllerForPending, mountPolicyAcceptStep, joinTitles, formatPolicyDate, PolicyGateController, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, PolicyAcceptanceController, flowFromPending, initialFlow, createMfaEnrollment, createPasskeySignInController, startSignInWithAtlas, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, preparePasswordHoldProof, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, attemptPasswordHoldProof, advanceWithCaptcha, loadPolicies, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, pendingExistingAccountNotice, acknowledgeExistingAccount, shouldKeepPolling, pollAttempt, lastUsedMethodLabel, signUp, passkeysSupported, confirmPolicies, existingAccountResetUrl, signUpProvedByLink, signInAfterProofUrl, awaitingPasskey, listCibaRequests, getCibaPin, decideCibaRequest, setCibaPin, clearCibaPin, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
7
+ import { createOrganizationAuditLog, POLICY_STRINGS, TokenCache, SignOutNotifier, resolveFrontendApi, withDevBrowser, catalogLocale, configureReferralCapture, FapiClient, SignOutGuard, localizedErrorMessage, reauthenticate, getTemplateToken, getProviderToken, signOutReasonFromClient, readRedirectResult, completeOAuthPopupLanding, mapOAuthPopupPayload, stripRedirectParams, closeOAuthPopupAfterSignIn, SDK_HEADER, sdkHeaderValue, reportSdkAdvisory, readExpiry, msUntilRefresh, policyTranslator, injectPolicyStyles, mountPolicyClickwrap, mountPolicyConsent, controllerForPending, mountPolicyAcceptStep, joinTitles, formatPolicyDate, PolicyGateController, enrollmentOptionKey, groupSetupKey, enrollmentSubmitKey, nextStep, awaitingSignUpLink, createEmailLinkConfirmation, canDownloadRecoveryCodes, copyRecoveryCodes, downloadRecoveryCodes, createCaptchaController, atlasCaptchaLabels, PolicyAcceptanceController, flowFromPending, initialFlow, createMfaEnrollment, createPasskeySignInController, startSignInWithAtlas, mfaChoicesFrom, fetchInstanceSettings, fetchLastSignInMethod, offeredFirstFactors, preparePasswordHoldProof, prepareFactor, signInCaptchaOptions, flowNeedsCaptcha, planFirstFactor, attemptPasswordHoldProof, advanceWithCaptcha, loadPolicies, createSignUp, prepareSecondFactorCode, resendSignUpVerification, createPasskeySignUp, finishPasskeySignUp, pendingRecoveryCodes, acknowledgeRecoveryCodes, pendingExistingAccountNotice, acknowledgeExistingAccount, shouldKeepPolling, pollAttempt, emailLinkFromUrl, lastUsedMethodLabel, signUp, passkeysSupported, confirmPolicies, existingAccountResetUrl, signUpProvedByLink, signInAfterProofUrl, awaitingPasskey, listCibaRequests, getCibaPin, decideCibaRequest, setCibaPin, clearCibaPin, OrganizationProfileController, describeAuditAction, actorFromClaims } from '@atlasauth/js';
8
8
  export { FapiClient, SIGN_OUT_EVENT, SignOutError, advance, flowFromPending, getProviderToken, initialFlow, onAtlasSignOut, pollAttempt, prepareFactor, requestForStep, shouldKeepPolling } from '@atlasauth/js';
9
9
  import { evaluate } from '@atlasauth/authz';
10
10
  export { evaluate, hasFromClaims } from '@atlasauth/authz';
@@ -266,6 +266,23 @@ const EN_US = {
266
266
  'mfa.enrollChoose': 'Set up a second step for signing in.',
267
267
  'mfa.enrollTotpOption': 'Use an authenticator app',
268
268
  'mfa.enrollSmsOption': 'Use text messages',
269
+ 'link.title': "Confirm it's you",
270
+ 'link.matchCodeHint': 'Opening the link on another device? Enter this code there.',
271
+ 'link.checking': 'Checking your link…',
272
+ 'link.enterCodeHelp': 'Enter the code shown on the device where you started.',
273
+ 'link.codeLabel': 'Code',
274
+ 'link.confirm': 'Confirm',
275
+ 'link.confirmed': 'Confirmed. You can close this tab and go back to where you started.',
276
+ 'link.invalid': 'This link is no longer valid. Go back to where you started and ask for a new one.',
277
+ 'mfa.enrollHotpOption': 'Use a counter-based code generator',
278
+ 'mfa.enrollYubikeyOption': 'Use a YubiKey',
279
+ 'mfa.enrollDuoOption': 'Use Duo',
280
+ 'mfa.enrollPasskeyOption': 'Use a passkey',
281
+ 'mfa.yubikeyLabel': 'Touch your YubiKey',
282
+ 'mfa.enrollDuoHelp': 'Open Duo and approve the request, then come back and continue.',
283
+ 'mfa.enrollDuoOpen': 'Open Duo',
284
+ 'mfa.enrollPasskeyHelp': 'Create a passkey on this device to use as your second step. It must ask for your PIN or biometrics.',
285
+ 'mfa.enrollPasskeyCreate': 'Create passkey',
269
286
  'mfa.enrollScan': 'Scan this QR code with your authenticator app, or enter the setup key.',
270
287
  'mfa.enrollQrAlt': 'QR code for your authenticator app',
271
288
  'mfa.enrollSetupKey': 'Setup key',
@@ -364,6 +381,7 @@ const EN_US = {
364
381
  'error.form_password_reused': 'Your new password must not match any of your last {history_count} passwords.',
365
382
  'error.password_expired': 'Your password has expired. Reset it to continue.',
366
383
  'error.email_not_verified': 'Your email address is not verified yet. Verify it before signing in with your password.',
384
+ 'error.mfa_setup_unavailable': "This account needs 2-Step Verification, but it can't be set up here. Contact the app's support to continue.",
367
385
  'error.sign_in_token_invalid': 'That sign-in token is invalid or has expired.',
368
386
  'error.too_many_attempts': 'Too many failed attempts. Try again later.',
369
387
  'error.too_many_requests': 'Too many requests. Please try again later.',
@@ -403,7 +421,7 @@ function withFallback(locale) {
403
421
  }
404
422
 
405
423
  /** This package's version, sent as `X-Atlas-SDK` (kept in step with package.json by a test). */
406
- const ATLAS_ANGULAR_VERSION = '0.15.1';
424
+ const ATLAS_ANGULAR_VERSION = '0.16.1';
407
425
  const ATLAS_ANGULAR_SDK = { name: '@atlasauth/angular', version: ATLAS_ANGULAR_VERSION };
408
426
 
409
427
  /**
@@ -1481,6 +1499,8 @@ class AttemptFlowComponent {
1481
1499
  /** `FlowState.sessionKept`: whether this browser kept the session the sign-in created. */
1482
1500
  sessionKept = undefined;
1483
1501
  titleKey = 'signIn.title';
1502
+ /** Sign-up only: the sign-in link beside the code step's "an account already uses this email". */
1503
+ signInHref = null;
1484
1504
  /**
1485
1505
  * The sign-in captcha, drawn above the submit button on the identifier step
1486
1506
  * (an always-on sign-in captcha) and on the challenge step the server demands
@@ -1536,6 +1556,8 @@ class AttemptFlowComponent {
1536
1556
  * while the flow polls, and offers a resend (`resend`).
1537
1557
  */
1538
1558
  emailVerification = 'code';
1559
+ /** `FlowState.matchCode`: shown while a mailed link waits, to type if it's opened on another device. */
1560
+ matchCode = null;
1539
1561
  resend = new EventEmitter();
1540
1562
  /** The user declined a policy the sign-in was waiting on (`needs_policy_acceptance`): cancel the attempt. */
1541
1563
  policyDeclined = new EventEmitter();
@@ -1583,6 +1605,12 @@ class AttemptFlowComponent {
1583
1605
  resendEnrollment() {
1584
1606
  void this.enrollment?.resend();
1585
1607
  }
1608
+ optionKey(method) {
1609
+ return enrollmentOptionKey(method);
1610
+ }
1611
+ showMatchCode() {
1612
+ return !!this.matchCode && (this.step().kind === 'collect_email_code' || this.linkSentText() !== null);
1613
+ }
1586
1614
  otherMethods(state) {
1587
1615
  return state.options.filter((m) => m !== state.method);
1588
1616
  }
@@ -1604,6 +1632,9 @@ class AttemptFlowComponent {
1604
1632
  formErrors() {
1605
1633
  return this.errors.filter((error) => !error.param);
1606
1634
  }
1635
+ signInLink(error) {
1636
+ return this.step().kind === 'collect_email_code' && error.code === 'IDENTIFIER_EXISTS' ? this.signInHref : null;
1637
+ }
1607
1638
  fieldErrorsFor(name) {
1608
1639
  return this.errors.filter((error) => error.param === name);
1609
1640
  }
@@ -1730,12 +1761,17 @@ class AttemptFlowComponent {
1730
1761
  }
1731
1762
  }
1732
1763
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: AttemptFlowComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
1733
- static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", passwordHold: "passwordHold", holdProof: "holdProof", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", usePassword: "usePassword", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend", policyDeclined: "policyDeclined" }, ngImport: i0, template: `
1764
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: AttemptFlowComponent, isStandalone: true, selector: "atlas-attempt-flow", inputs: { attempt: "attempt", busy: "busy", errors: "errors", sessionKept: "sessionKept", titleKey: "titleKey", signInHref: "signInHref", captcha: "captcha", firstFactors: "firstFactors", preparedFactor: "preparedFactor", passwordHold: "passwordHold", holdProof: "holdProof", offerEmailSecondFactor: "offerEmailSecondFactor", emailedSecondFactor: "emailedSecondFactor", offerSmsSecondFactor: "offerSmsSecondFactor", textedSecondFactor: "textedSecondFactor", enrollment: "enrollment", enrollmentState: "enrollmentState", emailVerification: "emailVerification", matchCode: "matchCode" }, outputs: { submitFlow: "submitFlow", chooseFactor: "chooseFactor", usePassword: "usePassword", emailSecondFactor: "emailSecondFactor", smsSecondFactor: "smsSecondFactor", resend: "resend", policyDeclined: "policyDeclined" }, ngImport: i0, template: `
1734
1765
  <div [class]="cls('card', 'atlas-card')">
1735
1766
  <h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
1736
1767
 
1737
1768
  @for (error of formErrors(); track error.code) {
1738
- <p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
1769
+ <p [class]="cls('formFieldError', 'atlas-error')" role="alert">
1770
+ {{ errorText(error) }}
1771
+ @if (signInLink(error); as href) {
1772
+ <a class="atlas-link" [href]="href">{{ t('signIn.title') }}</a>
1773
+ }
1774
+ </p>
1739
1775
  }
1740
1776
 
1741
1777
  <form (submit)="onSubmit($event)">
@@ -1760,6 +1796,9 @@ class AttemptFlowComponent {
1760
1796
  {{ t('signIn.resendLink') }}
1761
1797
  </button>
1762
1798
  }
1799
+ @if (showMatchCode()) {
1800
+ <p class="atlas-text" data-atlas="link-match-code">{{ t('link.matchCodeHint') }} <strong><code>{{ matchCode }}</code></strong></p>
1801
+ }
1763
1802
  @if (enrolling() && enrollmentState; as enrol) {
1764
1803
  @if (enrol.method === null) {
1765
1804
  <p class="atlas-text">{{ t('mfa.enrollChoose') }}</p>
@@ -1771,10 +1810,31 @@ class AttemptFlowComponent {
1771
1810
  [disabled]="busy || enrol.busy"
1772
1811
  (click)="chooseMethod(m)"
1773
1812
  >
1774
- {{ t(m === 'totp' ? 'mfa.enrollTotpOption' : 'mfa.enrollSmsOption') }}
1813
+ {{ t(optionKey(m)) }}
1775
1814
  </button>
1776
1815
  }
1777
- } @else if (enrol.method === 'totp') {
1816
+ } @else if (enrol.method === 'yubikey') {
1817
+ <label class="atlas-field">
1818
+ <span>{{ t('mfa.yubikeyLabel') }}</span>
1819
+ <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="otp" autocomplete="off" [value]="values['otp'] ?? ''" (input)="setValue('otp', $any($event.target).value)" />
1820
+ @for (error of fieldErrorsFor('otp'); track error.code) {
1821
+ <span [class]="cls('formFieldError', 'atlas-error')">{{ errorText(error) }}</span>
1822
+ }
1823
+ </label>
1824
+ } @else if (enrol.method === 'duo' || enrol.method === 'passkey') {
1825
+ @if (enrol.enrollment; as setup) {
1826
+ @if (enrol.method === 'passkey') {
1827
+ <p class="atlas-text">{{ t('mfa.enrollPasskeyHelp') }}</p>
1828
+ } @else {
1829
+ <p class="atlas-text">{{ t('mfa.enrollDuoHelp') }}</p>
1830
+ @if (setup.authorizationUrl) {
1831
+ <a class="atlas-link" data-atlas="mfa-duo-open" [href]="setup.authorizationUrl" target="_blank" rel="noopener noreferrer">{{ t('mfa.enrollDuoOpen') }}</a>
1832
+ }
1833
+ }
1834
+ } @else {
1835
+ <p class="atlas-text" aria-live="polite">{{ enrol.busy ? t('mfa.enrollPreparing') : '' }}</p>
1836
+ }
1837
+ } @else if (enrol.method === 'totp' || enrol.method === 'hotp') {
1778
1838
  @if (enrol.enrollment; as setup) {
1779
1839
  <p class="atlas-text">{{ t('mfa.enrollScan') }}</p>
1780
1840
  @if (setup.qrCode) {
@@ -1787,7 +1847,7 @@ class AttemptFlowComponent {
1787
1847
  <span>{{ t('mfa.enrollFirstCodeLabel') }}</span>
1788
1848
  <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="code" autocomplete="one-time-code" inputmode="numeric" [value]="values['code'] ?? ''" (input)="setValue('code', $any($event.target).value)" />
1789
1849
  </label>
1790
- @if (enrol.totpCodes >= 2) {
1850
+ @if (enrol.method === 'totp' && enrol.totpCodes >= 2) {
1791
1851
  <label class="atlas-field">
1792
1852
  <span>{{ t('mfa.enrollSecondCodeLabel') }}</span>
1793
1853
  <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="secondCode" autocomplete="one-time-code" inputmode="numeric" [value]="values['secondCode'] ?? ''" (input)="setValue('secondCode', $any($event.target).value)" />
@@ -1832,7 +1892,7 @@ class AttemptFlowComponent {
1832
1892
  [disabled]="busy || enrol.busy"
1833
1893
  (click)="chooseMethod(other)"
1834
1894
  >
1835
- {{ t(other === 'totp' ? 'mfa.enrollTotpOption' : 'mfa.enrollSmsOption') }}
1895
+ {{ t(optionKey(other)) }}
1836
1896
  </button>
1837
1897
  }
1838
1898
  }
@@ -1977,7 +2037,12 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
1977
2037
  <h1 [class]="cls('headerTitle', 'atlas-title')">{{ t(titleKey) }}</h1>
1978
2038
 
1979
2039
  @for (error of formErrors(); track error.code) {
1980
- <p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
2040
+ <p [class]="cls('formFieldError', 'atlas-error')" role="alert">
2041
+ {{ errorText(error) }}
2042
+ @if (signInLink(error); as href) {
2043
+ <a class="atlas-link" [href]="href">{{ t('signIn.title') }}</a>
2044
+ }
2045
+ </p>
1981
2046
  }
1982
2047
 
1983
2048
  <form (submit)="onSubmit($event)">
@@ -2002,6 +2067,9 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2002
2067
  {{ t('signIn.resendLink') }}
2003
2068
  </button>
2004
2069
  }
2070
+ @if (showMatchCode()) {
2071
+ <p class="atlas-text" data-atlas="link-match-code">{{ t('link.matchCodeHint') }} <strong><code>{{ matchCode }}</code></strong></p>
2072
+ }
2005
2073
  @if (enrolling() && enrollmentState; as enrol) {
2006
2074
  @if (enrol.method === null) {
2007
2075
  <p class="atlas-text">{{ t('mfa.enrollChoose') }}</p>
@@ -2013,10 +2081,31 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2013
2081
  [disabled]="busy || enrol.busy"
2014
2082
  (click)="chooseMethod(m)"
2015
2083
  >
2016
- {{ t(m === 'totp' ? 'mfa.enrollTotpOption' : 'mfa.enrollSmsOption') }}
2084
+ {{ t(optionKey(m)) }}
2017
2085
  </button>
2018
2086
  }
2019
- } @else if (enrol.method === 'totp') {
2087
+ } @else if (enrol.method === 'yubikey') {
2088
+ <label class="atlas-field">
2089
+ <span>{{ t('mfa.yubikeyLabel') }}</span>
2090
+ <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="otp" autocomplete="off" [value]="values['otp'] ?? ''" (input)="setValue('otp', $any($event.target).value)" />
2091
+ @for (error of fieldErrorsFor('otp'); track error.code) {
2092
+ <span [class]="cls('formFieldError', 'atlas-error')">{{ errorText(error) }}</span>
2093
+ }
2094
+ </label>
2095
+ } @else if (enrol.method === 'duo' || enrol.method === 'passkey') {
2096
+ @if (enrol.enrollment; as setup) {
2097
+ @if (enrol.method === 'passkey') {
2098
+ <p class="atlas-text">{{ t('mfa.enrollPasskeyHelp') }}</p>
2099
+ } @else {
2100
+ <p class="atlas-text">{{ t('mfa.enrollDuoHelp') }}</p>
2101
+ @if (setup.authorizationUrl) {
2102
+ <a class="atlas-link" data-atlas="mfa-duo-open" [href]="setup.authorizationUrl" target="_blank" rel="noopener noreferrer">{{ t('mfa.enrollDuoOpen') }}</a>
2103
+ }
2104
+ }
2105
+ } @else {
2106
+ <p class="atlas-text" aria-live="polite">{{ enrol.busy ? t('mfa.enrollPreparing') : '' }}</p>
2107
+ }
2108
+ } @else if (enrol.method === 'totp' || enrol.method === 'hotp') {
2020
2109
  @if (enrol.enrollment; as setup) {
2021
2110
  <p class="atlas-text">{{ t('mfa.enrollScan') }}</p>
2022
2111
  @if (setup.qrCode) {
@@ -2029,7 +2118,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2029
2118
  <span>{{ t('mfa.enrollFirstCodeLabel') }}</span>
2030
2119
  <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="code" autocomplete="one-time-code" inputmode="numeric" [value]="values['code'] ?? ''" (input)="setValue('code', $any($event.target).value)" />
2031
2120
  </label>
2032
- @if (enrol.totpCodes >= 2) {
2121
+ @if (enrol.method === 'totp' && enrol.totpCodes >= 2) {
2033
2122
  <label class="atlas-field">
2034
2123
  <span>{{ t('mfa.enrollSecondCodeLabel') }}</span>
2035
2124
  <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="secondCode" autocomplete="one-time-code" inputmode="numeric" [value]="values['secondCode'] ?? ''" (input)="setValue('secondCode', $any($event.target).value)" />
@@ -2074,7 +2163,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2074
2163
  [disabled]="busy || enrol.busy"
2075
2164
  (click)="chooseMethod(other)"
2076
2165
  >
2077
- {{ t(other === 'totp' ? 'mfa.enrollTotpOption' : 'mfa.enrollSmsOption') }}
2166
+ {{ t(optionKey(other)) }}
2078
2167
  </button>
2079
2168
  }
2080
2169
  }
@@ -2217,6 +2306,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2217
2306
  type: Input
2218
2307
  }], titleKey: [{
2219
2308
  type: Input
2309
+ }], signInHref: [{
2310
+ type: Input
2220
2311
  }], captcha: [{
2221
2312
  type: Input
2222
2313
  }], firstFactors: [{
@@ -2251,6 +2342,8 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2251
2342
  type: Input
2252
2343
  }], emailVerification: [{
2253
2344
  type: Input
2345
+ }], matchCode: [{
2346
+ type: Input
2254
2347
  }], resend: [{
2255
2348
  type: Output
2256
2349
  }], policyDeclined: [{
@@ -2264,6 +2357,103 @@ function released() {
2264
2357
  return { kind: 'released', name: '', labelKey: 'signIn.passwordHoldReleased', type: 'text' };
2265
2358
  }
2266
2359
 
2360
+ /**
2361
+ * What `<atlas-sign-in>` / `<atlas-sign-up>` draw when opened from a mailed link:
2362
+ * tries this browser's stored secret, then asks for the code the starting tab
2363
+ * shows. A success signs nobody in here: the starting tab continues on its own.
2364
+ */
2365
+ class EmailLinkComponent {
2366
+ atlas = inject(AtlasService);
2367
+ link;
2368
+ state = signal({ status: 'checking', busy: false, errors: [] });
2369
+ code = '';
2370
+ controller = null;
2371
+ stop = null;
2372
+ ngOnInit() {
2373
+ this.controller = createEmailLinkConfirmation(this.atlas.createFapiClient(), this.link);
2374
+ this.stop = this.controller.subscribe((next) => this.state.set(next));
2375
+ void this.controller.start();
2376
+ }
2377
+ ngOnDestroy() {
2378
+ this.stop?.();
2379
+ }
2380
+ onSubmit(event) {
2381
+ event.preventDefault();
2382
+ void this.controller?.submitCode(this.code);
2383
+ }
2384
+ message() {
2385
+ const status = this.state().status;
2386
+ return status === 'confirmed' ? 'link.confirmed' : status === 'invalid' ? 'link.invalid' : 'link.checking';
2387
+ }
2388
+ t(key) {
2389
+ return translate(this.atlas.localization, key);
2390
+ }
2391
+ cls(key, base) {
2392
+ return classFor(key, this.atlas.appearance, base);
2393
+ }
2394
+ errorText(error) {
2395
+ return localizedErrorMessage(error, this.atlas.localization);
2396
+ }
2397
+ static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmailLinkComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2398
+ static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: EmailLinkComponent, isStandalone: true, selector: "atlas-email-link", inputs: { link: "link" }, ngImport: i0, template: `
2399
+ <div [class]="cls('card', 'atlas-card')" data-atlas="email-link" [attr.data-atlas-status]="state().status">
2400
+ <h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('link.title') }}</h1>
2401
+ @if (state().status === 'needs_code') {
2402
+ <form (submit)="onSubmit($event)">
2403
+ <p class="atlas-text">{{ t('link.enterCodeHelp') }}</p>
2404
+ <label class="atlas-field">
2405
+ <span>{{ t('link.codeLabel') }}</span>
2406
+ <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="match_code" autocomplete="off" inputmode="numeric" required [value]="code" (input)="code = $any($event.target).value" />
2407
+ </label>
2408
+ @for (error of state().errors; track error.code) {
2409
+ <p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
2410
+ }
2411
+ <button [class]="cls('formButtonPrimary', 'atlas-button')" type="submit" [disabled]="state().busy">{{ t('link.confirm') }}</button>
2412
+ </form>
2413
+ } @else {
2414
+ <p class="atlas-text" role="status" aria-live="polite">{{ t(message()) }}</p>
2415
+ }
2416
+ @if (state().resetUrl; as resetUrl) {
2417
+ <p class="atlas-text"><a class="atlas-link" data-atlas-reset-link="" [href]="resetUrl">{{ t('signIn.forgotPassword') }}</a></p>
2418
+ }
2419
+ </div>
2420
+ `, isInline: true, changeDetection: i0.ChangeDetectionStrategy.OnPush });
2421
+ }
2422
+ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: EmailLinkComponent, decorators: [{
2423
+ type: Component,
2424
+ args: [{
2425
+ selector: 'atlas-email-link',
2426
+ standalone: true,
2427
+ changeDetection: ChangeDetectionStrategy.OnPush,
2428
+ template: `
2429
+ <div [class]="cls('card', 'atlas-card')" data-atlas="email-link" [attr.data-atlas-status]="state().status">
2430
+ <h1 [class]="cls('headerTitle', 'atlas-title')">{{ t('link.title') }}</h1>
2431
+ @if (state().status === 'needs_code') {
2432
+ <form (submit)="onSubmit($event)">
2433
+ <p class="atlas-text">{{ t('link.enterCodeHelp') }}</p>
2434
+ <label class="atlas-field">
2435
+ <span>{{ t('link.codeLabel') }}</span>
2436
+ <input [class]="cls('formFieldInput', 'atlas-input')" type="text" name="match_code" autocomplete="off" inputmode="numeric" required [value]="code" (input)="code = $any($event.target).value" />
2437
+ </label>
2438
+ @for (error of state().errors; track error.code) {
2439
+ <p [class]="cls('formFieldError', 'atlas-error')" role="alert">{{ errorText(error) }}</p>
2440
+ }
2441
+ <button [class]="cls('formButtonPrimary', 'atlas-button')" type="submit" [disabled]="state().busy">{{ t('link.confirm') }}</button>
2442
+ </form>
2443
+ } @else {
2444
+ <p class="atlas-text" role="status" aria-live="polite">{{ t(message()) }}</p>
2445
+ }
2446
+ @if (state().resetUrl; as resetUrl) {
2447
+ <p class="atlas-text"><a class="atlas-link" data-atlas-reset-link="" [href]="resetUrl">{{ t('signIn.forgotPassword') }}</a></p>
2448
+ }
2449
+ </div>
2450
+ `,
2451
+ }]
2452
+ }], propDecorators: { link: [{
2453
+ type: Input,
2454
+ args: [{ required: true }]
2455
+ }] } });
2456
+
2267
2457
  /**
2268
2458
  * The recovery codes a mid-sign-in MFA enrolment came with, shown once before
2269
2459
  * the sign-in finishes: copy them, download them as a .txt file, then
@@ -2801,8 +2991,11 @@ class AtlasFlowController {
2801
2991
  return;
2802
2992
  this.pollTimer = setInterval(() => {
2803
2993
  void (async () => {
2804
- const { state: next, ticket } = await pollAttempt(this.client, this.state());
2805
- this.setState(next);
2994
+ const polled = this.state();
2995
+ const { state: next, ticket } = await pollAttempt(this.client, polled);
2996
+ // A resend rotated the secret meanwhile: this answer is stale.
2997
+ if (this.state().pollSecret === polled.pollSecret)
2998
+ this.setState(next);
2806
2999
  // e.g. a passkey sign-up whose email was just proven: only this tab can go on.
2807
3000
  if (!ticket && !shouldKeepPolling(next))
2808
3001
  this.stopPolling();
@@ -2847,6 +3040,11 @@ class AtlasFlowController {
2847
3040
  */
2848
3041
  class SignInComponent {
2849
3042
  atlas = inject(AtlasService);
3043
+ /** Opened from a mailed link: that page, not the flow. Read after the first render, so hydration matches. */
3044
+ emailLink = signal(null);
3045
+ constructor() {
3046
+ afterNextRender(() => this.emailLink.set(emailLinkFromUrl(undefined, 'sign_in')));
3047
+ }
2850
3048
  /** Where to send the user once the flow completes. Reserved for host routing. */
2851
3049
  afterUrl;
2852
3050
  /**
@@ -2912,6 +3110,9 @@ class SignInComponent {
2912
3110
  }
2913
3111
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignInComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
2914
3112
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignInComponent, isStandalone: true, selector: "atlas-sign-in", inputs: { afterUrl: "afterUrl", signUpUrl: "signUpUrl" }, ngImport: i0, template: `
3113
+ @if (emailLink(); as link) {
3114
+ <atlas-email-link [link]="link"></atlas-email-link>
3115
+ } @else {
2915
3116
  @if (lastUsedLabel(); as label) {
2916
3117
  <p class="atlas-text atlas-last-used-hint" data-atlas="last-used" [attr.data-atlas-method]="flow.lastMethod()">
2917
3118
  {{ t('signIn.lastUsed') }}: {{ label }}
@@ -2937,6 +3138,7 @@ class SignInComponent {
2937
3138
  [captcha]="flow.captchaDrawn() ? flow.captcha : null"
2938
3139
  [firstFactors]="flow.firstFactors()"
2939
3140
  [preparedFactor]="flow.preparedFactor()"
3141
+ [matchCode]="flow.state().matchCode ?? null"
2940
3142
  [passwordHold]="flow.state().passwordHold ?? null"
2941
3143
  [holdProof]="flow.holdProof()"
2942
3144
  (usePassword)="flow.usePassword()"
@@ -2969,7 +3171,8 @@ class SignInComponent {
2969
3171
  {{ t('signIn.noAccount') }} <a class="atlas-link" [href]="href">{{ t('signIn.signUpLink') }}</a>
2970
3172
  </p>
2971
3173
  }
2972
- `, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3174
+ }
3175
+ `, isInline: true, dependencies: [{ kind: "component", type: EmailLinkComponent, selector: "atlas-email-link", inputs: ["link"] }, { kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "signInHref", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification", "matchCode"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
2973
3176
  }
2974
3177
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignInComponent, decorators: [{
2975
3178
  type: Component,
@@ -2977,8 +3180,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
2977
3180
  selector: 'atlas-sign-in',
2978
3181
  standalone: true,
2979
3182
  changeDetection: ChangeDetectionStrategy.OnPush,
2980
- imports: [AttemptFlowComponent, RecoveryCodesComponent],
3183
+ imports: [EmailLinkComponent, AttemptFlowComponent, RecoveryCodesComponent],
2981
3184
  template: `
3185
+ @if (emailLink(); as link) {
3186
+ <atlas-email-link [link]="link"></atlas-email-link>
3187
+ } @else {
2982
3188
  @if (lastUsedLabel(); as label) {
2983
3189
  <p class="atlas-text atlas-last-used-hint" data-atlas="last-used" [attr.data-atlas-method]="flow.lastMethod()">
2984
3190
  {{ t('signIn.lastUsed') }}: {{ label }}
@@ -3004,6 +3210,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3004
3210
  [captcha]="flow.captchaDrawn() ? flow.captcha : null"
3005
3211
  [firstFactors]="flow.firstFactors()"
3006
3212
  [preparedFactor]="flow.preparedFactor()"
3213
+ [matchCode]="flow.state().matchCode ?? null"
3007
3214
  [passwordHold]="flow.state().passwordHold ?? null"
3008
3215
  [holdProof]="flow.holdProof()"
3009
3216
  (usePassword)="flow.usePassword()"
@@ -3036,9 +3243,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3036
3243
  {{ t('signIn.noAccount') }} <a class="atlas-link" [href]="href">{{ t('signIn.signUpLink') }}</a>
3037
3244
  </p>
3038
3245
  }
3246
+ }
3039
3247
  `,
3040
3248
  }]
3041
- }], propDecorators: { afterUrl: [{
3249
+ }], ctorParameters: () => [], propDecorators: { afterUrl: [{
3042
3250
  type: Input
3043
3251
  }], signUpUrl: [{
3044
3252
  type: Input
@@ -3615,6 +3823,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3615
3823
  */
3616
3824
  class SignUpComponent {
3617
3825
  atlas = inject(AtlasService);
3826
+ /** Opened from a mailed link: that page, not the flow. Read after the first render, so hydration matches. */
3827
+ emailLink = signal(null);
3828
+ constructor() {
3829
+ afterNextRender(() => this.emailLink.set(emailLinkFromUrl(undefined, 'sign_up')));
3830
+ }
3618
3831
  /** Where to send the user once the flow completes. Reserved for host routing. */
3619
3832
  afterUrl;
3620
3833
  /** Where the existing-account notice's "Forgot password?" goes. Default: the hosted sign-in page; `null` hides it. */
@@ -3670,6 +3883,9 @@ class SignUpComponent {
3670
3883
  }
3671
3884
  static ɵfac = i0.ɵɵngDeclareFactory({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpComponent, deps: [], target: i0.ɵɵFactoryTarget.Component });
3672
3885
  static ɵcmp = i0.ɵɵngDeclareComponent({ minVersion: "17.0.0", version: "17.3.12", type: SignUpComponent, isStandalone: true, selector: "atlas-sign-up", inputs: { afterUrl: "afterUrl", resetPasswordUrl: "resetPasswordUrl", signInUrl: "signInUrl" }, ngImport: i0, template: `
3886
+ @if (emailLink(); as link) {
3887
+ <atlas-email-link [link]="link"></atlas-email-link>
3888
+ } @else {
3673
3889
  @if (flow.recoveryCodes(); as codes) {
3674
3890
  <atlas-recovery-codes [codes]="codes" [busy]="flow.state().busy" (saved)="flow.saveRecoveryCodes()"></atlas-recovery-codes>
3675
3891
  } @else if (flow.existingAccountNotice()) {
@@ -3722,6 +3938,7 @@ class SignUpComponent {
3722
3938
  [emailVerification]="flow.settings()?.account?.emailVerification ?? 'code'"
3723
3939
  (submitFlow)="flow.submit($event)"
3724
3940
  (resend)="flow.resendSignUp()"
3941
+ [matchCode]="flow.state().matchCode ?? null"
3725
3942
  [offerEmailSecondFactor]="flow.settings()?.account?.emailSecondFactor === true"
3726
3943
  [emailedSecondFactor]="flow.emailSecondFactor()"
3727
3944
  [offerSmsSecondFactor]="flow.settings() !== null && flow.mfaChoices().sms"
@@ -3731,6 +3948,7 @@ class SignUpComponent {
3731
3948
  (emailSecondFactor)="flow.sendEmailSecondFactor()"
3732
3949
  (smsSecondFactor)="flow.sendSmsSecondFactor()"
3733
3950
  (policyDeclined)="flow.declinePolicy($event)"
3951
+ [signInHref]="signInHref()"
3734
3952
  ></atlas-attempt-flow>
3735
3953
  } @else {
3736
3954
  <atlas-sign-up-form
@@ -3747,7 +3965,8 @@ class SignUpComponent {
3747
3965
  "
3748
3966
  ></atlas-sign-up-form>
3749
3967
  }
3750
- `, isInline: true, dependencies: [{ kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }, { kind: "component", type: SignUpFormComponent, selector: "atlas-sign-up-form", inputs: ["settings", "busy", "errors", "captcha", "passkey", "switchable", "policies"], outputs: ["switchMode", "submitSignUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3968
+ }
3969
+ `, isInline: true, dependencies: [{ kind: "component", type: EmailLinkComponent, selector: "atlas-email-link", inputs: ["link"] }, { kind: "component", type: AttemptFlowComponent, selector: "atlas-attempt-flow", inputs: ["attempt", "busy", "errors", "sessionKept", "titleKey", "signInHref", "captcha", "firstFactors", "preparedFactor", "passwordHold", "holdProof", "offerEmailSecondFactor", "emailedSecondFactor", "offerSmsSecondFactor", "textedSecondFactor", "enrollment", "enrollmentState", "emailVerification", "matchCode"], outputs: ["submitFlow", "chooseFactor", "usePassword", "emailSecondFactor", "smsSecondFactor", "resend", "policyDeclined"] }, { kind: "component", type: RecoveryCodesComponent, selector: "atlas-recovery-codes", inputs: ["codes", "busy"], outputs: ["saved"] }, { kind: "component", type: SignUpFormComponent, selector: "atlas-sign-up-form", inputs: ["settings", "busy", "errors", "captcha", "passkey", "switchable", "policies"], outputs: ["switchMode", "submitSignUp"] }], changeDetection: i0.ChangeDetectionStrategy.OnPush });
3751
3970
  }
3752
3971
  i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImport: i0, type: SignUpComponent, decorators: [{
3753
3972
  type: Component,
@@ -3755,8 +3974,11 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3755
3974
  selector: 'atlas-sign-up',
3756
3975
  standalone: true,
3757
3976
  changeDetection: ChangeDetectionStrategy.OnPush,
3758
- imports: [AttemptFlowComponent, RecoveryCodesComponent, SignUpFormComponent],
3977
+ imports: [EmailLinkComponent, AttemptFlowComponent, RecoveryCodesComponent, SignUpFormComponent],
3759
3978
  template: `
3979
+ @if (emailLink(); as link) {
3980
+ <atlas-email-link [link]="link"></atlas-email-link>
3981
+ } @else {
3760
3982
  @if (flow.recoveryCodes(); as codes) {
3761
3983
  <atlas-recovery-codes [codes]="codes" [busy]="flow.state().busy" (saved)="flow.saveRecoveryCodes()"></atlas-recovery-codes>
3762
3984
  } @else if (flow.existingAccountNotice()) {
@@ -3809,6 +4031,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3809
4031
  [emailVerification]="flow.settings()?.account?.emailVerification ?? 'code'"
3810
4032
  (submitFlow)="flow.submit($event)"
3811
4033
  (resend)="flow.resendSignUp()"
4034
+ [matchCode]="flow.state().matchCode ?? null"
3812
4035
  [offerEmailSecondFactor]="flow.settings()?.account?.emailSecondFactor === true"
3813
4036
  [emailedSecondFactor]="flow.emailSecondFactor()"
3814
4037
  [offerSmsSecondFactor]="flow.settings() !== null && flow.mfaChoices().sms"
@@ -3818,6 +4041,7 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3818
4041
  (emailSecondFactor)="flow.sendEmailSecondFactor()"
3819
4042
  (smsSecondFactor)="flow.sendSmsSecondFactor()"
3820
4043
  (policyDeclined)="flow.declinePolicy($event)"
4044
+ [signInHref]="signInHref()"
3821
4045
  ></atlas-attempt-flow>
3822
4046
  } @else {
3823
4047
  <atlas-sign-up-form
@@ -3834,9 +4058,10 @@ i0.ɵɵngDeclareClassMetadata({ minVersion: "12.0.0", version: "17.3.12", ngImpo
3834
4058
  "
3835
4059
  ></atlas-sign-up-form>
3836
4060
  }
4061
+ }
3837
4062
  `,
3838
4063
  }]
3839
- }], propDecorators: { afterUrl: [{
4064
+ }], ctorParameters: () => [], propDecorators: { afterUrl: [{
3840
4065
  type: Input
3841
4066
  }], resetPasswordUrl: [{
3842
4067
  type: Input
@@ -5298,5 +5523,5 @@ function atlasChildGuard(options = {}) {
5298
5523
  * Generated bundle index. Do not edit.
5299
5524
  */
5300
5525
 
5301
- export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasPoliciesDirective, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, ImpersonationBannerComponent, ManageCibaComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, PolicyAcceptStepComponent, PolicyGateComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
5526
+ export { ATLAS_ANGULAR_SDK, ATLAS_ANGULAR_VERSION, ATLAS_OPTIONS, ATLAS_UI, AtlasCaptchaSlotDirective, AtlasFlowController, AtlasLoadedDirective, AtlasLoadingDirective, AtlasModule, AtlasOrganizationAuditLog, AtlasPoliciesDirective, AtlasProtectDirective, AtlasRootDirective, AtlasService, AtlasSignedInDirective, AtlasSignedOutDirective, AttemptFlowComponent, DEFAULT_TOKENS, EN_US, EmailLinkComponent, ImpersonationBannerComponent, ManageCibaComponent, OrganizationAuditLogComponent, OrganizationProfileComponent, OrganizationSwitcherComponent, PolicyAcceptStepComponent, PolicyGateComponent, SignInComponent, SignUpComponent, SignUpFormComponent, THEMES, UserButtonComponent, UserProfileComponent, atlasChildGuard, atlasGuard, classFor, cssVariables, explicitTokens, provideAtlas, renderAppearance, resolveTokens, translate, withFallback };
5302
5527
  //# sourceMappingURL=atlasauth-angular.mjs.map