@abyss-project/commons-front-core 3.3.2 → 4.0.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (101) hide show
  1. package/dist/{CookieConsentSettings.component-tRVw_4zH.js → CookieConsentSettings.component-B06_BnQP.js} +2703 -2118
  2. package/dist/auth/client/auth-bridge.d.ts +51 -0
  3. package/dist/auth/client/auth-client.d.ts +125 -0
  4. package/dist/auth/client/auth-client.spec.d.ts +1 -0
  5. package/dist/auth/client/capacitor-bridge.d.ts +16 -0
  6. package/dist/auth/client/index.d.ts +6 -0
  7. package/dist/auth/client/native-bridge.d.ts +53 -0
  8. package/dist/auth/client/native-bridge.spec.d.ts +1 -0
  9. package/dist/auth/client/token-storage.d.ts +31 -0
  10. package/dist/auth/client/web-bridge.d.ts +13 -0
  11. package/dist/auth/client/web-bridge.spec.d.ts +1 -0
  12. package/dist/auth/components/AuthFlow/AuthFlow.component.d.ts +30 -0
  13. package/dist/auth/components/AuthFlow/AuthFlow.component.spec.d.ts +1 -0
  14. package/dist/auth/components/AuthFlow/auth-flow.types.d.ts +62 -0
  15. package/dist/auth/components/AuthFlow/steps/CodeStep.component.d.ts +17 -0
  16. package/dist/auth/components/AuthFlow/steps/EmailStep.component.d.ts +22 -0
  17. package/dist/auth/components/AuthFlow/steps/MfaEnrollmentStep.component.d.ts +13 -0
  18. package/dist/auth/components/AuthFlow/steps/MfaStep.component.d.ts +20 -0
  19. package/dist/auth/components/AuthFlow/steps/PasskeyNudgeStep.component.d.ts +11 -0
  20. package/dist/auth/components/AuthFlow/steps/PasswordStep.component.d.ts +17 -0
  21. package/dist/auth/components/AuthFlow/steps/SignupStep.component.d.ts +24 -0
  22. package/dist/auth/components/AuthFlow/steps/steps.autocomplete.spec.d.ts +1 -0
  23. package/dist/auth/components/AuthProviderButtons/AuthProviderButtons.component.d.ts +30 -0
  24. package/dist/auth/components/MfaRequirementBanner/MfaRequirementBanner.component.d.ts +12 -0
  25. package/dist/auth/components/MfaRequirementBanner/MfaRequirementBanner.component.spec.d.ts +1 -0
  26. package/dist/auth/components/ReauthDialog/AuthReauthHost.component.d.ts +8 -0
  27. package/dist/auth/components/ReauthDialog/ReauthDialog.component.d.ts +22 -0
  28. package/dist/auth/components/ReauthDialog/ReauthDialog.component.spec.d.ts +1 -0
  29. package/dist/auth/components/SecuritySettings/SecuritySettings.component.d.ts +7 -0
  30. package/dist/auth/components/SecuritySettings/SecuritySettings.component.spec.d.ts +1 -0
  31. package/dist/auth/components/SecuritySettings/sections/EmailSection.component.d.ts +6 -0
  32. package/dist/auth/components/SecuritySettings/sections/PasskeysSection.component.d.ts +10 -0
  33. package/dist/auth/components/SecuritySettings/sections/PasswordSection.component.d.ts +9 -0
  34. package/dist/auth/components/SecuritySettings/sections/RecoveryCodesSection.component.d.ts +10 -0
  35. package/dist/auth/components/SecuritySettings/sections/SecuritySection.component.d.ts +26 -0
  36. package/dist/auth/components/SecuritySettings/sections/SessionsSection.component.d.ts +8 -0
  37. package/dist/auth/components/SecuritySettings/sections/TotpSection.component.d.ts +11 -0
  38. package/dist/auth/components/SecuritySettings/sections/use-section-action.hook.d.ts +9 -0
  39. package/dist/auth/components/index.d.ts +11 -0
  40. package/dist/auth/components/shared/AuthStepFrame.component.d.ts +19 -0
  41. package/dist/auth/components/shared/OneTimeCodeField.component.d.ts +17 -0
  42. package/dist/auth/components/shared/RecoveryCodesPanel.component.d.ts +12 -0
  43. package/dist/auth/components/shared/TotpSetupPanel.component.d.ts +14 -0
  44. package/dist/auth/components/shared/auth-errors.d.ts +42 -0
  45. package/dist/auth/components/shared/mfa-status-events.d.ts +2 -0
  46. package/dist/auth/components/shared/passkey-ceremonies.d.ts +17 -0
  47. package/dist/auth/components/shared/use-async-resource.hook.d.ts +18 -0
  48. package/dist/auth/components/shared/use-offline.hook.d.ts +2 -0
  49. package/dist/auth/components/shared/use-passkey-name.hook.d.ts +5 -0
  50. package/dist/auth/components/test-support/auth-sdk.mock.d.ts +57 -0
  51. package/dist/auth/components/test-support/auth-test-harness.d.ts +48 -0
  52. package/dist/auth/index.d.ts +2 -0
  53. package/dist/auth/react/AuthProvider.component.d.ts +15 -0
  54. package/dist/auth/react/AuthProvider.component.spec.d.ts +1 -0
  55. package/dist/auth/react/use-auth.hook.d.ts +3 -0
  56. package/dist/auth-client.d.ts +2 -0
  57. package/dist/auth-client.js +26 -0
  58. package/dist/auth-native.d.ts +2 -0
  59. package/dist/auth-native.js +84 -0
  60. package/dist/components/Layouts/AbyssLayoutProvider/AbyssLayoutProvider.component.d.ts +2 -3
  61. package/dist/components/Layouts/AbyssLayoutProvider/abyss-layout.store.d.ts +1 -1
  62. package/dist/components/Support/SupportTicketDetail.mobile-layout.spec.d.ts +1 -0
  63. package/dist/cookie-consent.js +1 -1
  64. package/dist/hooks/use-rich-intl.hook.d.ts +654 -4
  65. package/dist/{index-g_LMIl_j.js → index-B99FVtM1.js} +2 -2
  66. package/dist/{index-Cy5aV6-7.js → index-BAiia-Dl.js} +4 -4
  67. package/dist/{index-CSOs_Ccx.js → index-BI56obfe.js} +1 -1
  68. package/dist/{index-sAQE8yH0.js → index-BLjfAtDQ.js} +2 -2
  69. package/dist/{index-BHSTpRDB.js → index-BQMgvLh9.js} +4 -4
  70. package/dist/{index-Bb8UEu0K.js → index-BU5c0hG9.js} +3 -3
  71. package/dist/{index-CJghyDOF.js → index-B_rGVaUU.js} +2 -2
  72. package/dist/{index-nT4uFN7k.js → index-BokeagcV.js} +3 -3
  73. package/dist/{index-N73aWpoj.js → index-C36LEiRs.js} +2 -2
  74. package/dist/{index-Dn4CNQkV.js → index-C4fkwJmM.js} +2 -2
  75. package/dist/{index-TbU1rvxC.js → index-COBKSaJ6.js} +2 -2
  76. package/dist/{index-DUuSQC1S.js → index-CQcl-JnX.js} +2 -2
  77. package/dist/{index-BDwKynBn.js → index-Cp_oEtd_.js} +33265 -30088
  78. package/dist/{index-DUxqfZmd.js → index-D1vKJSB3.js} +3 -3
  79. package/dist/index-D7cgykJH.js +324 -0
  80. package/dist/{index-C2SpycHF.js → index-DA5MOwJ6.js} +2 -2
  81. package/dist/{index-DDBCCwMT.js → index-DAEl7d3x.js} +2 -2
  82. package/dist/{index-D84kdr5l.js → index-DPDhWaXC.js} +2 -2
  83. package/dist/{index-Hf4VgoUQ.js → index-Dy57KM7a.js} +2 -2
  84. package/dist/{index-BDI9bSnM.js → index-QsS__hk5.js} +3 -3
  85. package/dist/{index-D8hjJcQ2.js → index-cHPTPlez.js} +2 -2
  86. package/dist/{index-DlNShbQC.js → index-pmj-p-Pq.js} +2 -2
  87. package/dist/{index-DcZU8Tc4.js → index-rgzxHuXo.js} +4 -4
  88. package/dist/index.d.ts +1 -0
  89. package/dist/index.js +273 -242
  90. package/dist/token-storage-D3e11ePD.js +38 -0
  91. package/dist/translations/en.d.ts +289 -0
  92. package/dist/translations/fr.d.ts +289 -0
  93. package/dist/translations/translations-parity.spec.d.ts +1 -0
  94. package/dist/use-auth.hook-B_TU5W3g.js +391 -0
  95. package/dist/utils/billing.utils.d.ts +2 -2
  96. package/dist/utils/cookie.utils.d.ts +1 -1
  97. package/dist/utils/space-display-name.utils.d.ts +2 -2
  98. package/package.json +32 -10
  99. package/scripts/check-auth-entry-isolation.cjs +140 -0
  100. package/vite.config.ts +24 -1
  101. package/vitest.config.ts +1 -1
@@ -0,0 +1,51 @@
1
+ import { IWebAuthnAuthenticationCredential, IWebAuthnCreationOptions, IWebAuthnRegistrationCredential, IWebAuthnRequestOptions, SessionPlatform } from '@abyss-project/main';
2
+ /**
3
+ * What a platform does on the device during a sign-in: passkeys, the Google and Apple buttons.
4
+ * Two implementations: the web one (`createWebBridge`: WebAuthn, Google Identity Services,
5
+ * Sign in with Apple JS) and the native one (`createCapacitorBridge`, entry
6
+ * `@abyss-project/commons-front-core/auth-native`: the `@abyss-project/capacitor-auth` plugin).
7
+ *
8
+ * Passkey options and credentials are the JSON abyss-main hands out and expects back (every binary
9
+ * field base64url), forwarded untouched.
10
+ */
11
+ export interface AuthBridge {
12
+ /** The platform the session opened through this bridge lives on (`platform` of every sign-in). */
13
+ readonly platform: SessionPlatform;
14
+ passkeySupported(): Promise<boolean>;
15
+ /**
16
+ * `conditional` = passkeys offered by the email field autofill (web) / only when one is already
17
+ * on the device, without the "use another device" fallback (native).
18
+ */
19
+ getPasskey(options: IWebAuthnRequestOptions, conditional?: boolean): Promise<IWebAuthnAuthenticationCredential>;
20
+ createPasskey(options: IWebAuthnCreationOptions): Promise<IWebAuthnRegistrationCredential>;
21
+ /**
22
+ * `nonce` is the raw single-use value abyss-main issued (`auth.createIdTokenNonce`), copied as is into
23
+ * the id_token.
24
+ */
25
+ google(nonce: string): Promise<{
26
+ idToken: string;
27
+ }>;
28
+ /** `nonce` is the raw issued value; Apple receives its SHA-256 (hex), as abyss-main checks it. */
29
+ apple(nonce: string): Promise<{
30
+ idToken: string;
31
+ givenName?: string;
32
+ familyName?: string;
33
+ }>;
34
+ }
35
+ /** Same values as the native plugin's `AbyssAuthErrorCode`, so both bridges fail alike. */
36
+ export declare enum AuthBridgeErrorCode {
37
+ /** The user closed the sheet, the popup or the prompt: not an error to show. */
38
+ CANCELLED = "cancelled",
39
+ /** This device or browser cannot do it (no WebAuthn, Google on iOS, Apple on Android…). */
40
+ UNSUPPORTED = "unsupported",
41
+ /** No passkey of this relying party on the device. */
42
+ NO_CREDENTIAL = "no_credential",
43
+ FAILED = "failed"
44
+ }
45
+ export declare class AuthBridgeError extends Error {
46
+ readonly code: AuthBridgeErrorCode;
47
+ readonly cause?: unknown;
48
+ constructor(code: AuthBridgeErrorCode, message: string, cause?: unknown);
49
+ }
50
+ /** SHA-256 of the UTF-8 value, lowercase hex: what Apple carries in its id_token `nonce`. */
51
+ export declare const sha256Hex: (value: string) => Promise<string>;
@@ -0,0 +1,125 @@
1
+ import { IAuthResult, IUser } from '@abyss-project/main';
2
+ import { AuthBridge } from './auth-bridge';
3
+ import { TokenStorage } from './token-storage';
4
+ export declare enum AuthStatus {
5
+ /** `bootstrap()` has not settled yet. */
6
+ LOADING = "loading",
7
+ ANONYMOUS = "anonymous",
8
+ AUTHENTICATED = "authenticated"
9
+ }
10
+ /** How a signed-in user proves again who they are (re-authentication, 5.3). */
11
+ export declare enum ReauthMethod {
12
+ PASSKEY = "passkey",
13
+ TOTP = "totp",
14
+ PASSWORD = "password",
15
+ EMAIL_CODE = "email-code"
16
+ }
17
+ /** What a 403 `reauth_required` asks for. */
18
+ export interface ReauthRequest {
19
+ /**
20
+ * The only methods the server accepts for this action — a second factor, when an enrolled
21
+ * account touches its factors (`IReauthRequiredErrorParams.methods` of the error). Absent: any
22
+ * method.
23
+ */
24
+ methods?: ReauthMethod[];
25
+ }
26
+ export interface AuthState {
27
+ status: AuthStatus;
28
+ user?: IUser;
29
+ /** An administrator without a second factor: admin access waits for its set-up. */
30
+ mfaEnrollmentRequired?: boolean;
31
+ /** abyss-main could not be reached: the session is kept and refreshed when it comes back. */
32
+ offline?: boolean;
33
+ }
34
+ export interface AuthClientConfig {
35
+ bridge: AuthBridge;
36
+ storage: TokenStorage;
37
+ /**
38
+ * Puts the access token on every SDK core of the app (main + its own satellite core); `null`
39
+ * removes it (sign-out). The token stays in memory: never in `localStorage`.
40
+ */
41
+ applyToken: (accessToken: string | null) => void;
42
+ /** Defaults to `navigator.onLine`. */
43
+ isOnline?: () => boolean;
44
+ /**
45
+ * Keeps the signed-in user in the app's own storage, for an offline start; `null` on sign-out.
46
+ * The user only: no token.
47
+ */
48
+ onPersistUser?: (user: IUser | null) => void;
49
+ /** The user `onPersistUser` kept, read once by `bootstrap()`. */
50
+ restoreUser?: () => IUser | null | Promise<IUser | null>;
51
+ }
52
+ export interface AuthClient {
53
+ readonly bridge: AuthBridge;
54
+ state(): AuthState;
55
+ /** Called on every state change (not with the current state). Returns the unsubscribe. */
56
+ subscribe(listener: (state: AuthState) => void): () => void;
57
+ /** The access token in use, `null` when signed out. */
58
+ accessToken(): string | null;
59
+ /**
60
+ * Called at once with the current access token, then with each new one (`null` on sign-out):
61
+ * for a process that holds its own copy, such as the Memories background runner (ruling R4).
62
+ */
63
+ subscribeToken(listener: (accessToken: string | null) => void): () => void;
64
+ /**
65
+ * Restores the session at launch (idempotent). Offline or abyss-main unreachable: the persisted
66
+ * user stays signed in with `offline: true`, and a single refresh runs when the network is back.
67
+ * Only an explicit refusal (401) signs out.
68
+ */
69
+ bootstrap(): Promise<void>;
70
+ /** `AUTHENTICATED`: stores the refresh token, applies the access token, schedules the refresh. */
71
+ handleResult(result: IAuthResult): Promise<IAuthResult>;
72
+ /**
73
+ * Rotates the refresh token, one rotation at a time (in-process shared promise, plus the
74
+ * `abyss-auth-refresh` Web Lock across the tabs of a web origin). Settles once the state says
75
+ * the outcome; rejects only if an app callback (`applyToken`, `onPersistUser`, storage) throws.
76
+ */
77
+ refresh(): Promise<void>;
78
+ /**
79
+ * Runs an API call; on 401 `Token Expired`, one refresh and one replay. On 403
80
+ * `reauth_required`, awaits the `onReauthRequired` handler and replays once if it proved.
81
+ */
82
+ withAuthRetry<T>(call: () => Promise<T>): Promise<T>;
83
+ /**
84
+ * The UI's re-authentication dialog: resolves `true` once the user proved again (and the new
85
+ * session went through `handleResult`), `false` if cancelled. Receives the methods the server
86
+ * restricted the proof to. One handler; returns the removal.
87
+ */
88
+ onReauthRequired(handler: (request: ReauthRequest) => Promise<boolean>): () => void;
89
+ /** Revokes the session server-side, then forgets it locally (even if the call failed). */
90
+ logout(): Promise<void>;
91
+ /** Stops the timers and listeners (tests, hot reload). */
92
+ dispose(): void;
93
+ }
94
+ /** Refresh a minute before the access token expires. */
95
+ export declare const REFRESH_MARGIN_MS = 60000;
96
+ /**
97
+ * abyss-main answers the same token pair again to a refresh token replayed less than 30 s after
98
+ * its rotation (ADR-0153); past that, the replay counts as a reuse and revokes the session.
99
+ */
100
+ export declare const REFRESH_REPLAY_GRACE_MS = 30000;
101
+ /**
102
+ * No answer to a refresh (network error, 5xx) while the device is online: the request may have
103
+ * reached abyss-main and rotated the token, only the response being lost. The refresh is replayed
104
+ * at once: three more attempts after these delays (3.5 s in all).
105
+ */
106
+ export declare const LOST_RESPONSE_RETRY_DELAYS_MS: readonly number[];
107
+ /**
108
+ * Still no answer after those replays: later attempts, timed from the first unanswered call (the
109
+ * rotation, if it happened, came after it), all inside the grace. The last one leaves 3 s for the
110
+ * request to travel. Coming back online or to the foreground replays at once as well.
111
+ */
112
+ export declare const LOST_RESPONSE_LATE_RETRIES_AT_MS: readonly number[];
113
+ /**
114
+ * abyss-main still unreachable once that grace is over, or the device offline: next attempt,
115
+ * unless the network or the app comes back first.
116
+ */
117
+ export declare const UNREACHABLE_RETRY_MS = 30000;
118
+ /**
119
+ * One refresh attempt is given up after this long (its request aborted) and counts as unanswered:
120
+ * a connection frozen after the request reached abyss-main would otherwise hold the replays, and
121
+ * the reconnect and foreground replays, past the grace.
122
+ */
123
+ export declare const REFRESH_ATTEMPT_TIMEOUT_MS = 5000;
124
+ export declare const REFRESH_LOCK_NAME = "abyss-auth-refresh";
125
+ export declare const createAuthClient: (config: AuthClientConfig) => AuthClient;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,16 @@
1
+ import { AuthBridge } from './auth-bridge';
2
+ import { TokenStorage } from './token-storage';
3
+ export interface CapacitorBridgeConfig {
4
+ /** The Google OAuth client id of the web application type (Credential Manager audience). */
5
+ googleServerClientId: string;
6
+ /**
7
+ * Offer passkeys in the app. Off by default: a native passkey only works once abyss-project.fr
8
+ * serves the app's domain association files (AASA, assetlinks). Off, the bridge reports passkeys
9
+ * unsupported and no screen offers them.
10
+ */
11
+ nativePasskeys?: boolean;
12
+ }
13
+ /** The bridge of the iOS and Android apps. Throws on the web: use `createWebBridge` there. */
14
+ export declare const createCapacitorBridge: (config: CapacitorBridgeConfig) => AuthBridge;
15
+ /** The refresh token in the Keychain (iOS) / Keystore (Android). */
16
+ export declare const createCapacitorTokenStorage: () => TokenStorage;
@@ -0,0 +1,6 @@
1
+ export * from './auth-bridge';
2
+ export * from './auth-client';
3
+ export * from './token-storage';
4
+ export * from './web-bridge';
5
+ export * from '../react/AuthProvider.component';
6
+ export * from '../react/use-auth.hook';
@@ -0,0 +1,53 @@
1
+ import { SessionPlatform } from '@abyss-project/main';
2
+ import { AuthBridge } from './auth-bridge';
3
+ /**
4
+ * The calls the native bridge makes on `@abyss-project/capacitor-auth` (its `AbyssAuthPlugin`).
5
+ * Declared here so this file never imports the plugin: only `capacitor-bridge.ts` does, and the
6
+ * plugin's own type is checked against this one there.
7
+ */
8
+ export interface NativeAuthPlugin {
9
+ isPasskeySupported(): Promise<{
10
+ supported: boolean;
11
+ }>;
12
+ createPasskey(options: {
13
+ optionsJson: string;
14
+ }): Promise<{
15
+ responseJson: string;
16
+ }>;
17
+ getPasskey(options: {
18
+ optionsJson: string;
19
+ preferImmediatelyAvailable?: boolean;
20
+ }): Promise<{
21
+ responseJson: string;
22
+ }>;
23
+ signInWithGoogle(options: {
24
+ serverClientId: string;
25
+ nonce: string;
26
+ }): Promise<{
27
+ idToken: string;
28
+ }>;
29
+ signInWithApple(options: {
30
+ nonce: string;
31
+ }): Promise<{
32
+ idToken: string;
33
+ givenName?: string;
34
+ familyName?: string;
35
+ }>;
36
+ }
37
+ export interface NativeBridgeConfig {
38
+ platform: SessionPlatform.IOS | SessionPlatform.ANDROID;
39
+ /** The Google OAuth client id of the web application type, the audience of the id_token. */
40
+ googleServerClientId: string;
41
+ /**
42
+ * Whether the app may use passkeys. They need the domain association files (`apple-app-site-
43
+ * association`, `assetlinks.json`) served for the app: until then the bridge reports passkeys
44
+ * unsupported, and every screen hides them.
45
+ */
46
+ passkeys: boolean;
47
+ loadPlugin: () => Promise<NativeAuthPlugin>;
48
+ }
49
+ /**
50
+ * The bridge over the native plugin. The webview (origin `localhost`) cannot use WebAuthn itself:
51
+ * Credential Manager / ASAuthorization do it, the options and the credential crossing as JSON.
52
+ */
53
+ export declare const createNativeBridge: (config: NativeBridgeConfig) => AuthBridge;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,31 @@
1
+ /**
2
+ * Where the refresh token lives between two launches. Never `localStorage`: on the web the browser
3
+ * keeps it in the `HttpOnly` cookie `abyss_refresh` (JavaScript never sees it), on native apps the
4
+ * Keychain / Keystore holds it.
5
+ */
6
+ export interface TokenStorage {
7
+ getRefreshToken(): Promise<string | null>;
8
+ /** `null` forgets it (sign-out, revoked session). */
9
+ setRefreshToken(token: string | null): Promise<void>;
10
+ }
11
+ /** The native secure store, as `@abyss-project/capacitor-auth` exposes it. */
12
+ export interface SecureStore {
13
+ secureGet(options: {
14
+ key: string;
15
+ }): Promise<{
16
+ value: string | null;
17
+ }>;
18
+ secureSet(options: {
19
+ key: string;
20
+ value: string;
21
+ }): Promise<void>;
22
+ secureRemove(options: {
23
+ key: string;
24
+ }): Promise<void>;
25
+ }
26
+ /** Each app has its own Keychain / Keystore, so one key name serves them all. */
27
+ export declare const REFRESH_TOKEN_STORAGE_KEY = "abyss_refresh_token";
28
+ /** Web: nothing to keep, the cookie travels with every `auth/refresh` call (`withCredentials`). */
29
+ export declare const createWebTokenStorage: () => TokenStorage;
30
+ /** Native: the refresh token in the secure store `loadStore` resolves to. */
31
+ export declare const createSecureTokenStorage: (loadStore: () => Promise<SecureStore>) => TokenStorage;
@@ -0,0 +1,13 @@
1
+ import { AuthBridge } from './auth-bridge';
2
+ export declare const GOOGLE_IDENTITY_SCRIPT_URL = "https://accounts.google.com/gsi/client";
3
+ export declare const APPLE_ID_SCRIPT_URL = "https://appleid.cdn-apple.com/appleauth/static/jsapi/appleid/1.0/en_US/appleid.auth.js";
4
+ export interface WebBridgeConfig {
5
+ /** Google OAuth client id (web application type). */
6
+ googleClientId: string;
7
+ /** Apple Services ID of the site. */
8
+ appleServiceId: string;
9
+ /** Return URL declared on the Services ID; required by Apple JS even in popup mode. */
10
+ appleRedirectUri: string;
11
+ }
12
+ /** The bridge of every web front: WebAuthn, Google Identity Services, Sign in with Apple JS. */
13
+ export declare const createWebBridge: (config: WebBridgeConfig) => AuthBridge;
@@ -0,0 +1 @@
1
+ export {};
@@ -0,0 +1,30 @@
1
+ import { IAuthResult } from '@abyss-project/main';
2
+ import { AuthFlowProviders } from '../AuthProviderButtons/AuthProviderButtons.component';
3
+ import { AuthFlowContext, AuthFlowLegal, AuthFlowResult } from './auth-flow.types';
4
+ export type AuthFlowProps = {
5
+ initialEmail?: string;
6
+ /**
7
+ * A result the host already obtained outside this flow (its own OAuth callback page, which
8
+ * calls `sdk.auth.oauth` / `signInWithIdToken` itself): the flow starts at the step it calls
9
+ * for instead of the e-mail step. `AUTHENTICATED` applies the session and either finishes or
10
+ * opens the mandatory enrolment step (`session.mfaEnrollmentRequired`); `MFA_REQUIRED` opens
11
+ * the second-factor step with that challenge; `SIGNUP_REQUIRED` opens the sign-up step with
12
+ * that token (the e-mail shown is never an editable field, there or here).
13
+ */
14
+ initialResult?: IAuthResult;
15
+ context: AuthFlowContext;
16
+ providers: AuthFlowProviders;
17
+ /**
18
+ * The user is signed in (session applied through the auth client): the host navigates to the
19
+ * page that was asked for, in its own front (CA8).
20
+ */
21
+ onAuthenticated: (result: AuthFlowResult) => void;
22
+ legal: AuthFlowLegal;
23
+ };
24
+ /**
25
+ * The single sign-in / sign-up flow of every Abyss front (5.1): e-mail first, then passkey, e-mail
26
+ * code or password; Google and Apple; an account created by the same code; second factor;
27
+ * mandatory MFA set-up for an administrator; passkey proposal. Must be rendered inside
28
+ * `<AuthProvider>`: every session goes through its client.
29
+ */
30
+ export declare const AuthFlow: ({ initialEmail, initialResult, context, providers, onAuthenticated, legal, }: AuthFlowProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,62 @@
1
+ import { AuthMethod, IUser, MfaFactorType, UserLanguage } from '@abyss-project/main';
2
+ /** What the arrival link carried, applied to an account created during this flow (D4). */
3
+ export interface AuthFlowContext {
4
+ sponsorId?: string;
5
+ invitationTokenId?: string;
6
+ /** Pre-selected language of a new account (the interface language). */
7
+ language: UserLanguage;
8
+ /**
9
+ * Query forwarded to the Discord / Slack connect URL (web code flow), relayed back to the host's
10
+ * OAuth callback page: typically its redirect path and target service. `sponsorId` and
11
+ * `invitationTokenId` are added by the flow itself.
12
+ */
13
+ oauthQuery?: Record<string, string>;
14
+ }
15
+ /** Links of the terms checkbox of the sign-up step. */
16
+ export interface AuthFlowLegal {
17
+ termsUrl: string;
18
+ privacyUrl: string;
19
+ }
20
+ export interface AuthFlowResult {
21
+ user: IUser;
22
+ /** Always `false` once the flow ends: an enrolment it required was completed inside it. */
23
+ mfaEnrollmentRequired: boolean;
24
+ }
25
+ export declare enum AuthFlowStepKind {
26
+ EMAIL = "email",
27
+ CODE = "code",
28
+ PASSWORD = "password",
29
+ SIGNUP = "signup",
30
+ MFA = "mfa",
31
+ ENROLLMENT = "enrollment",
32
+ NUDGE = "nudge"
33
+ }
34
+ export type AuthFlowStep = {
35
+ kind: AuthFlowStepKind.EMAIL;
36
+ } | {
37
+ kind: AuthFlowStepKind.CODE;
38
+ } | {
39
+ kind: AuthFlowStepKind.PASSWORD;
40
+ } | {
41
+ kind: AuthFlowStepKind.SIGNUP;
42
+ signupToken: string;
43
+ email: string;
44
+ /** How the address was proven (e-mail code, Google, Apple). */
45
+ method: AuthMethod;
46
+ } | {
47
+ kind: AuthFlowStepKind.MFA;
48
+ challengeToken: string;
49
+ factors: MfaFactorType[];
50
+ } | {
51
+ kind: AuthFlowStepKind.ENROLLMENT;
52
+ user: IUser;
53
+ } | {
54
+ kind: AuthFlowStepKind.NUDGE;
55
+ user: IUser;
56
+ };
57
+ /** A confirmation a step shows in its live region. */
58
+ export declare enum AuthFlowNotice {
59
+ CODE_RESENT = "code-resent",
60
+ RESET_SENT = "reset-sent",
61
+ PASSKEY_CANCELLED = "passkey-cancelled"
62
+ }
@@ -0,0 +1,17 @@
1
+ import { AuthErrorKind } from '../../shared/auth-errors';
2
+ export type CodeStepProps = {
3
+ email: string;
4
+ busy: boolean;
5
+ error: AuthErrorKind | null;
6
+ /** A new code was sent: the previous one no longer works. */
7
+ resent: boolean;
8
+ onSubmit: (code: string) => void;
9
+ onResend: () => void;
10
+ onUsePassword: () => void;
11
+ onChangeEmail: () => void;
12
+ };
13
+ /**
14
+ * The 6-digit code sent by e-mail (10 min, 5 tries, one live code per address). A complete code is
15
+ * submitted at once — typed, pasted or filled in by the platform.
16
+ */
17
+ export declare const CodeStep: ({ email, busy, error, resent, onSubmit, onResend, onUsePassword, onChangeEmail, }: CodeStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { ReactNode } from 'react';
2
+ import { AuthErrorKind } from '../../shared/auth-errors';
3
+ export declare const isEmailLike: (value: string) => boolean;
4
+ export type EmailStepProps = {
5
+ email: string;
6
+ onEmailChange: (email: string) => void;
7
+ onSubmit: () => void;
8
+ busy: boolean;
9
+ error: AuthErrorKind | null;
10
+ /**
11
+ * Resolved support of passkeys on this device. When `true`, `onStartConditionalPasskey` runs
12
+ * at mount: the passkeys of the device show in the e-mail field's suggestions (web) or in the
13
+ * system sheet (native).
14
+ */
15
+ passkeySupported: boolean;
16
+ onStartConditionalPasskey: () => void;
17
+ /** The modal passkey ceremony, offered as a secondary button while `passkeySupported`. */
18
+ onPasskey: () => void;
19
+ /** Google / Apple (and Discord / Slack on the web) above the form. */
20
+ providers?: ReactNode;
21
+ };
22
+ export declare const EmailStep: ({ email, onEmailChange, onSubmit, busy, error, passkeySupported, onStartConditionalPasskey, onPasskey, providers, }: EmailStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,13 @@
1
+ export type MfaEnrollmentStepProps = {
2
+ passkeySupported: boolean;
3
+ /** The factor is set up and the session re-proven with it: admin access is open. */
4
+ onEnrolled: () => void;
5
+ /** The only way out besides enrolling. */
6
+ onSignOut: () => void;
7
+ };
8
+ /**
9
+ * Mandatory set-up of a second factor (an administrator without one, Q6): no skip. Once the factor
10
+ * exists, the session is re-proven with it — a session only counts as MFA once a second factor was
11
+ * presented on it — so the admin token is granted right after this step, without signing in again.
12
+ */
13
+ export declare const MfaEnrollmentStep: ({ passkeySupported, onEnrolled, onSignOut, }: MfaEnrollmentStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,20 @@
1
+ import { MfaFactorType } from '@abyss-project/main';
2
+ import { AuthErrorKind } from '../../shared/auth-errors';
3
+ export type MfaStepProps = {
4
+ /** The factors the account has, from the `MFA_REQUIRED` challenge. */
5
+ factors: MfaFactorType[];
6
+ passkeySupported: boolean;
7
+ busy: boolean;
8
+ error: AuthErrorKind | null;
9
+ /** The passkey sheet was dismissed: the user may try again or pick another factor. */
10
+ passkeyCancelled: boolean;
11
+ onSubmitCode: (factor: MfaFactorType.TOTP | MfaFactorType.RECOVERY_CODE, code: string) => void;
12
+ onPasskey: () => void;
13
+ /** The challenge expired (5 min): back to the e-mail step. */
14
+ onRestart: () => void;
15
+ };
16
+ /**
17
+ * Second factor of a sign-in proven by password, e-mail code, Google or Apple (D6): authenticator
18
+ * code, passkey, or one of the recovery codes (each usable once).
19
+ */
20
+ export declare const MfaStep: ({ factors, passkeySupported, busy, error, passkeyCancelled, onSubmitCode, onPasskey, onRestart, }: MfaStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,11 @@
1
+ import { IUser } from '@abyss-project/main';
2
+ export type PasskeyNudgeStepProps = {
3
+ user: IUser;
4
+ /** Created, or declined: the sign-in goes on to the page that was asked for. */
5
+ onDone: () => void;
6
+ };
7
+ /**
8
+ * After a sign-in without passkey, on a device that can hold one (5.1, 7): a proposal to create
9
+ * one, never a requirement. "Later" is remembered for this user on this device.
10
+ */
11
+ export declare const PasskeyNudgeStep: ({ user, onDone }: PasskeyNudgeStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,17 @@
1
+ import { AuthErrorKind } from '../../shared/auth-errors';
2
+ export type PasswordStepProps = {
3
+ email: string;
4
+ busy: boolean;
5
+ error: AuthErrorKind | null;
6
+ /** The reset e-mail was requested (same answer whether the account exists or not). */
7
+ resetSent: boolean;
8
+ onSubmit: (password: string) => void;
9
+ onForgotPassword: () => void;
10
+ onUseCode: () => void;
11
+ onChangeEmail: () => void;
12
+ };
13
+ /**
14
+ * Password sign-in. The address travels in a hidden `username` field of the same form, so a
15
+ * password manager files the password under the right account and offers it back.
16
+ */
17
+ export declare const PasswordStep: ({ email, busy, error, resetSent, onSubmit, onForgotPassword, onUseCode, onChangeEmail, }: PasswordStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,24 @@
1
+ import { UserLanguage } from '@abyss-project/main';
2
+ import { AuthErrorKind } from '../../shared/auth-errors';
3
+ import { AuthFlowLegal } from '../auth-flow.types';
4
+ /** Mirrors the `alias` floor of the API sign-up validator (as the current web sign-up does). */
5
+ export declare const ALIAS_MIN_LENGTH = 3;
6
+ export type SignupStepProps = {
7
+ email: string;
8
+ defaultLanguage: UserLanguage;
9
+ legal: AuthFlowLegal;
10
+ busy: boolean;
11
+ error: AuthErrorKind | null;
12
+ onSubmit: (values: {
13
+ alias: string;
14
+ language: UserLanguage;
15
+ }) => void;
16
+ /** The sign-up token expired (30 min): back to the e-mail step. */
17
+ onRestart: () => void;
18
+ };
19
+ /**
20
+ * Completes an account for an address no account matches: the fields of the current web sign-up
21
+ * (alias pre-filled from the e-mail local part, language, mandatory terms). Sponsorship and
22
+ * invitation come from the flow's context, not from this form.
23
+ */
24
+ export declare const SignupStep: ({ email, defaultLanguage, legal, busy, error, onSubmit, onRestart, }: SignupStepProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,30 @@
1
+ export declare enum AuthProviderKind {
2
+ GOOGLE = "google",
3
+ APPLE = "apple",
4
+ /** Code flow through the browser (redirect): web only (Q5). */
5
+ DISCORD = "discord",
6
+ /** Code flow through the browser (redirect): web only (Q5). */
7
+ SLACK = "slack"
8
+ }
9
+ /** Which sign-in providers the host offers. Discord and Slack are ignored outside the web. */
10
+ export interface AuthFlowProviders {
11
+ google: boolean;
12
+ apple: boolean;
13
+ discord?: boolean;
14
+ slack?: boolean;
15
+ }
16
+ export type AuthProviderButtonsProps = {
17
+ providers: AuthFlowProviders;
18
+ /** `false` on native apps: Discord and Slack have no native SDK (Q5). */
19
+ allowCodeFlowProviders: boolean;
20
+ /** The provider whose sign-in is under way (spinner on its button). */
21
+ pending: AuthProviderKind | null;
22
+ disabled?: boolean;
23
+ onSelect: (provider: AuthProviderKind) => void;
24
+ };
25
+ /**
26
+ * "Continuer avec Google / Apple" (full width, one per line), then Discord and Slack side by side
27
+ * on the web when the host enables them, then the "or" separator above the e-mail form.
28
+ * Renders nothing when no provider is enabled.
29
+ */
30
+ export declare const AuthProviderButtons: ({ providers, allowCodeFlowProviders, pending, disabled, onSelect, }: AuthProviderButtonsProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,12 @@
1
+ export type MfaRequirementBannerProps = {
2
+ /** Opens the host's Security page; without it, the banner informs without a button. */
3
+ onConfigure?: () => void;
4
+ };
5
+ /**
6
+ * Says why a second factor is required while the user has none (`GET /user/me/mfa`): an
7
+ * administrator account, or an organisation requiring it (Q1: 7 days of grace, then no access to
8
+ * its projects — the personal account stays intact). Disappears once a factor exists, including
9
+ * one added in this tab. Renders nothing for a signed-out user, while loading, or if the status
10
+ * cannot be read: the server enforces the requirement either way, the banner only announces it.
11
+ */
12
+ export declare const MfaRequirementBanner: ({ onConfigure, }: MfaRequirementBannerProps) => import("react/jsx-runtime").JSX.Element | null;
@@ -0,0 +1,8 @@
1
+ /**
2
+ * Registers the re-authentication dialog with the auth client: a call answering 403
3
+ * `reauth_required` (through `withAuthRetry`) opens it, and is replayed once the user proved
4
+ * again. Calls that hit it while it is open wait for the same answer. A 403 that restricts the
5
+ * methods (a second factor only) opens the dialog with that restriction. Mount once, inside
6
+ * `<AuthProvider>` and the theme / intl providers.
7
+ */
8
+ export declare const AuthReauthHost: () => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,22 @@
1
+ import { ReauthMethod } from '../../client/auth-client';
2
+ export type ReauthDialogProps = {
3
+ open: boolean;
4
+ /** Closed without proving: the action that asked for it is abandoned. */
5
+ onClose: () => void;
6
+ /** Proven: the new session is applied, the action can be replayed. */
7
+ onReauthenticated: () => void;
8
+ /**
9
+ * The only methods the server accepts for this action (the `methods` of its 403
10
+ * `reauth_required`): a second factor, for an enrolled account touching its factors. Absent:
11
+ * every method of the user.
12
+ */
13
+ allowedMethods?: ReauthMethod[];
14
+ };
15
+ /**
16
+ * Re-authentication (5.3, CA17): a proof of less than 5 minutes for a sensitive action, with the
17
+ * strongest method the user has — passkey, authenticator code, password — or a code by e-mail;
18
+ * only a second factor when the server says so (`allowedMethods`). The new session goes through
19
+ * the auth client before `onReauthenticated`. Opened by `<AuthReauthHost />` when an API call
20
+ * answers 403 `reauth_required`.
21
+ */
22
+ export declare const ReauthDialog: ({ open, onClose, onReauthenticated, allowedMethods, }: ReauthDialogProps) => import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,7 @@
1
+ /**
2
+ * The Security page of every Abyss front (5.2, 5.3): connected devices, passkeys, authenticator
3
+ * app, recovery codes, e-mail address, password. Must be rendered inside `<AuthProvider>`;
4
+ * sensitive actions open the re-authentication dialog through the client (mount
5
+ * `<AuthReauthHost />` once).
6
+ */
7
+ export declare const SecuritySettings: () => import("react/jsx-runtime").JSX.Element;