@edgespark/web 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.
- package/auth/styles/styles.css +59 -2
- package/dist/auth/local-dev.d.ts +5 -0
- package/dist/auth-ui/ManagedAuthUI.d.ts +15 -4
- package/dist/auth-ui/config.d.ts +20 -0
- package/dist/auth-ui/google-one-tap.d.ts +47 -0
- package/dist/auth-ui/index.d.ts +1 -1
- package/dist/auth-ui/mount.d.ts +20 -2
- package/dist/auth-ui/prompt-google-one-tap.d.ts +43 -0
- package/dist/auth-ui/types.d.ts +26 -1
- package/dist/index.cjs +28 -13
- package/dist/index.d.ts +1 -1
- package/dist/index.es.js +786 -454
- package/package.json +1 -1
package/auth/styles/styles.css
CHANGED
|
@@ -96,6 +96,40 @@
|
|
|
96
96
|
gap: 8px;
|
|
97
97
|
}
|
|
98
98
|
|
|
99
|
+
.edgespark-auth__tabs {
|
|
100
|
+
display: grid;
|
|
101
|
+
grid-template-columns: repeat(2, minmax(0, 1fr));
|
|
102
|
+
gap: 4px;
|
|
103
|
+
min-height: 44px;
|
|
104
|
+
padding: 4px;
|
|
105
|
+
border: 1px solid var(--edgespark-auth-border);
|
|
106
|
+
border-radius: var(--edgespark-auth-radius-control);
|
|
107
|
+
background: var(--edgespark-auth-bg-muted);
|
|
108
|
+
}
|
|
109
|
+
|
|
110
|
+
.edgespark-auth__tab {
|
|
111
|
+
min-width: 0;
|
|
112
|
+
border: 0;
|
|
113
|
+
border-radius: calc(var(--edgespark-auth-radius-control) - 4px);
|
|
114
|
+
background: transparent;
|
|
115
|
+
color: var(--edgespark-auth-text-muted);
|
|
116
|
+
cursor: pointer;
|
|
117
|
+
font: inherit;
|
|
118
|
+
font-size: 0.92rem;
|
|
119
|
+
font-weight: 600;
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
.edgespark-auth__tab--active {
|
|
123
|
+
background: var(--edgespark-auth-bg);
|
|
124
|
+
color: var(--edgespark-auth-text);
|
|
125
|
+
box-shadow: 0 1px 2px rgba(15, 23, 42, 0.08);
|
|
126
|
+
}
|
|
127
|
+
|
|
128
|
+
.edgespark-auth__tab:disabled {
|
|
129
|
+
cursor: not-allowed;
|
|
130
|
+
opacity: 0.6;
|
|
131
|
+
}
|
|
132
|
+
|
|
99
133
|
.edgespark-auth__label {
|
|
100
134
|
font-size: 0.9rem;
|
|
101
135
|
font-weight: 600;
|
|
@@ -119,7 +153,8 @@
|
|
|
119
153
|
}
|
|
120
154
|
|
|
121
155
|
.edgespark-auth__button,
|
|
122
|
-
.edgespark-auth__link
|
|
156
|
+
.edgespark-auth__link,
|
|
157
|
+
.edgespark-auth__text-action {
|
|
123
158
|
font: inherit;
|
|
124
159
|
}
|
|
125
160
|
|
|
@@ -136,7 +171,8 @@
|
|
|
136
171
|
}
|
|
137
172
|
|
|
138
173
|
.edgespark-auth__button:disabled,
|
|
139
|
-
.edgespark-auth__link:disabled
|
|
174
|
+
.edgespark-auth__link:disabled,
|
|
175
|
+
.edgespark-auth__text-action:disabled {
|
|
140
176
|
cursor: not-allowed;
|
|
141
177
|
opacity: 0.6;
|
|
142
178
|
}
|
|
@@ -174,6 +210,27 @@
|
|
|
174
210
|
cursor: pointer;
|
|
175
211
|
}
|
|
176
212
|
|
|
213
|
+
.edgespark-auth__text-action {
|
|
214
|
+
justify-self: center;
|
|
215
|
+
padding: 2px 4px;
|
|
216
|
+
border: 0;
|
|
217
|
+
background: transparent;
|
|
218
|
+
color: var(--edgespark-auth-primary);
|
|
219
|
+
cursor: pointer;
|
|
220
|
+
font-size: 0.95rem;
|
|
221
|
+
font-weight: 600;
|
|
222
|
+
line-height: 1.4;
|
|
223
|
+
}
|
|
224
|
+
|
|
225
|
+
.edgespark-auth__text-action:hover:not(:disabled) {
|
|
226
|
+
color: var(--edgespark-auth-primary-hover);
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
.edgespark-auth__text-action:disabled {
|
|
230
|
+
color: var(--edgespark-auth-text-muted);
|
|
231
|
+
opacity: 1;
|
|
232
|
+
}
|
|
233
|
+
|
|
177
234
|
.edgespark-auth__divider {
|
|
178
235
|
position: relative;
|
|
179
236
|
text-align: center;
|
package/dist/auth/local-dev.d.ts
CHANGED
|
@@ -29,3 +29,8 @@ export declare function autoVerifyLocalDev(email: string): Promise<boolean>;
|
|
|
29
29
|
* Returns the OTP string or null if not available.
|
|
30
30
|
*/
|
|
31
31
|
export declare function fetchOtpLocalDev(email: string): Promise<string | null>;
|
|
32
|
+
/**
|
|
33
|
+
* Fetch the pending OTP for email sign-in in local dev.
|
|
34
|
+
* Returns the OTP string or null if not available.
|
|
35
|
+
*/
|
|
36
|
+
export declare function fetchSignInOtpLocalDev(email: string): Promise<string | null>;
|
|
@@ -1,14 +1,18 @@
|
|
|
1
1
|
import { BetterAuthClientInstance } from '../auth/types';
|
|
2
2
|
import { NormalizedAuthUIConfig } from './config';
|
|
3
|
+
import { AuthUIModuleRuntimeOptions } from './mount';
|
|
3
4
|
import { MountAuthUIOptions, MountedAuthUI } from './types';
|
|
4
|
-
export interface ManagedAuthUIRuntimeOptions {
|
|
5
|
-
syncPublicSession?: () => Promise<void> | void;
|
|
6
|
-
}
|
|
7
5
|
/**
|
|
8
6
|
* Internal managed auth UI implementation.
|
|
9
7
|
*
|
|
10
8
|
* The public API only exposes `authUI.mount(...)`; this class owns the DOM,
|
|
11
9
|
* form flows, and lifecycle.
|
|
10
|
+
*
|
|
11
|
+
* DOM ownership: the instance owns a single root element it appends to the
|
|
12
|
+
* mount container. It never writes to `container.innerHTML`. This keeps
|
|
13
|
+
* tear-down safe when the container is a DOM node a reconciling framework
|
|
14
|
+
* (React/Vue/Solid) reuses across conditional branches — wiping the
|
|
15
|
+
* container would erase sibling content the framework just rendered.
|
|
12
16
|
*/
|
|
13
17
|
export declare class ManagedAuthUI implements MountedAuthUI {
|
|
14
18
|
private readonly container;
|
|
@@ -27,7 +31,7 @@ export declare class ManagedAuthUI implements MountedAuthUI {
|
|
|
27
31
|
private pendingFocusSnapshot;
|
|
28
32
|
private focusRestoreTimer;
|
|
29
33
|
private verificationCompletionAction;
|
|
30
|
-
constructor(container: HTMLElement, auth: BetterAuthClientInstance, options: MountAuthUIOptions, loadConfig: () => Promise<NormalizedAuthUIConfig>, runtimeOptions?:
|
|
34
|
+
constructor(container: HTMLElement, auth: BetterAuthClientInstance, options: MountAuthUIOptions, loadConfig: () => Promise<NormalizedAuthUIConfig>, runtimeOptions?: AuthUIModuleRuntimeOptions | undefined);
|
|
31
35
|
destroy(): void;
|
|
32
36
|
private initialize;
|
|
33
37
|
private redirectAfterManagedReturnLookupFailure;
|
|
@@ -48,6 +52,9 @@ export declare class ManagedAuthUI implements MountedAuthUI {
|
|
|
48
52
|
private bindDOM;
|
|
49
53
|
private switchView;
|
|
50
54
|
private handleSignIn;
|
|
55
|
+
private handleEmailOtpSignIn;
|
|
56
|
+
private sendSignInOtp;
|
|
57
|
+
private resendSignInCode;
|
|
51
58
|
private handleSignUp;
|
|
52
59
|
private handleOAuthSignIn;
|
|
53
60
|
private handleForgotPassword;
|
|
@@ -81,6 +88,10 @@ export declare class ManagedAuthUI implements MountedAuthUI {
|
|
|
81
88
|
private scheduleFocusRestore;
|
|
82
89
|
private clearFocusRestoreTimer;
|
|
83
90
|
private passwordResetEndpoints;
|
|
91
|
+
private emailOtpSignInEndpoints;
|
|
92
|
+
private resolveInitialSignInMethod;
|
|
93
|
+
private setSignInMethod;
|
|
94
|
+
private canUseEmailOtpSignIn;
|
|
84
95
|
private extractRedirectURL;
|
|
85
96
|
private extractUser;
|
|
86
97
|
private canUsePasswordResetEmailOtp;
|
package/dist/auth-ui/config.d.ts
CHANGED
|
@@ -1,6 +1,15 @@
|
|
|
1
1
|
export type OAuthProviderId = "google" | "apple" | "microsoft" | "github" | "gitlab" | "discord";
|
|
2
|
+
interface OAuthProviderConfig {
|
|
3
|
+
/**
|
|
4
|
+
* OAuth Client ID resolved server-side. Present only when both the Client
|
|
5
|
+
* ID var and the corresponding secret resolve, so a non-empty value is
|
|
6
|
+
* the "this provider is fully wired browser-side" signal.
|
|
7
|
+
*/
|
|
8
|
+
clientId?: string;
|
|
9
|
+
}
|
|
2
10
|
interface OAuthProviderBlock {
|
|
3
11
|
enabled?: boolean;
|
|
12
|
+
config?: OAuthProviderConfig;
|
|
4
13
|
}
|
|
5
14
|
interface ProviderEmailPassword {
|
|
6
15
|
enabled?: boolean;
|
|
@@ -10,9 +19,13 @@ interface ProviderEmailPassword {
|
|
|
10
19
|
requirePasswordResetEmailVerification?: boolean;
|
|
11
20
|
};
|
|
12
21
|
}
|
|
22
|
+
interface ProviderEmailOtp {
|
|
23
|
+
enabled?: boolean;
|
|
24
|
+
}
|
|
13
25
|
interface AuthConfigResponse {
|
|
14
26
|
disableSignUp?: boolean;
|
|
15
27
|
providerEmailPassword?: ProviderEmailPassword;
|
|
28
|
+
providerEmailOtp?: ProviderEmailOtp;
|
|
16
29
|
providerGoogle?: OAuthProviderBlock;
|
|
17
30
|
providerApple?: OAuthProviderBlock;
|
|
18
31
|
providerMicrosoft?: OAuthProviderBlock;
|
|
@@ -23,10 +36,17 @@ interface AuthConfigResponse {
|
|
|
23
36
|
export interface NormalizedAuthUIConfig {
|
|
24
37
|
disableSignUp: boolean;
|
|
25
38
|
emailPasswordEnabled: boolean;
|
|
39
|
+
emailOtpSignInEnabled: boolean;
|
|
26
40
|
minPasswordLength: number;
|
|
27
41
|
requireEmailVerification: boolean;
|
|
28
42
|
passwordResetEmailOtpEnabled: boolean;
|
|
29
43
|
oauthProviders: OAuthProviderId[];
|
|
44
|
+
/**
|
|
45
|
+
* Resolved Google OAuth Client ID when Google is enabled and both
|
|
46
|
+
* credentials resolved server-side; `null` otherwise. Signals that
|
|
47
|
+
* Google client-side wiring is ready.
|
|
48
|
+
*/
|
|
49
|
+
googleClientId: string | null;
|
|
30
50
|
isLocalDev: boolean;
|
|
31
51
|
}
|
|
32
52
|
export declare function loadNormalizedAuthUIConfig(): Promise<NormalizedAuthUIConfig>;
|
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Minimal helpers for driving Google Identity Services (One Tap) from the
|
|
3
|
+
* managed auth UI. Loads the GIS client script on demand and exposes a tiny
|
|
4
|
+
* typed surface around the global `google.accounts.id` namespace.
|
|
5
|
+
*
|
|
6
|
+
* GIS is treated as a UX enhancement: any load failure falls back silently
|
|
7
|
+
* to the regular "Continue with Google" OAuth button.
|
|
8
|
+
*/
|
|
9
|
+
interface GsiCredentialResponse {
|
|
10
|
+
credential: string;
|
|
11
|
+
select_by?: string;
|
|
12
|
+
}
|
|
13
|
+
interface GsiInitializeOptions {
|
|
14
|
+
client_id: string;
|
|
15
|
+
callback: (response: GsiCredentialResponse) => void;
|
|
16
|
+
auto_select?: boolean;
|
|
17
|
+
cancel_on_tap_outside?: boolean;
|
|
18
|
+
use_fedcm_for_prompt?: boolean;
|
|
19
|
+
context?: "signin" | "signup" | "use";
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Subset of Google's `PromptMomentNotification`. Methods are optional because
|
|
23
|
+
* GIS's FedCM-era roadmap retires some of them, and EdgeSpark does not depend
|
|
24
|
+
* on `@types/google.accounts` for the full type surface.
|
|
25
|
+
*/
|
|
26
|
+
interface GsiPromptNotification {
|
|
27
|
+
isNotDisplayed?: () => boolean;
|
|
28
|
+
isSkippedMoment?: () => boolean;
|
|
29
|
+
isDismissedMoment?: () => boolean;
|
|
30
|
+
getDismissedReason?: () => string | undefined;
|
|
31
|
+
}
|
|
32
|
+
interface GsiIdAccounts {
|
|
33
|
+
initialize(options: GsiInitializeOptions): void;
|
|
34
|
+
prompt(notificationCallback?: (notification: GsiPromptNotification) => void): void;
|
|
35
|
+
cancel(): void;
|
|
36
|
+
disableAutoSelect(): void;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Loads `accounts.google.com/gsi/client` once per page and resolves with
|
|
40
|
+
* the `google.accounts.id` namespace. Subsequent calls return the same
|
|
41
|
+
* promise; load failures reject and reset so a caller can retry next mount.
|
|
42
|
+
*/
|
|
43
|
+
export declare function loadGoogleIdentityServices(): Promise<GsiIdAccounts>;
|
|
44
|
+
export type GoogleIdentityServices = GsiIdAccounts;
|
|
45
|
+
export type GoogleCredentialResponse = GsiCredentialResponse;
|
|
46
|
+
export type GooglePromptNotification = GsiPromptNotification;
|
|
47
|
+
export {};
|
package/dist/auth-ui/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export { createAuthUIModule } from './mount';
|
|
2
2
|
export { AUTH_UI_APPEARANCE_VARIABLE, AUTH_UI_APPEARANCE_VARIABLE_NAMES, AUTH_UI_THEME, AUTH_UI_DEFAULT_THEME, AUTH_UI_THEME_DARK, AUTH_UI_THEME_LIGHT, AUTH_UI_THEMES, } from './appearance';
|
|
3
3
|
export type { AuthUIAppearance, AuthUIAppearanceVariableName, AuthUIAppearanceVariables, AuthUITheme, } from './appearance';
|
|
4
|
-
export type { AuthSuccessEvent, AuthUILabelOverrides, AuthUILabels, ControlledAuthUIOptions, EdgeSparkAuthUI, MountAuthUIOptions, MountedAuthUI, RedirectAuthUIOptions, } from './types';
|
|
4
|
+
export type { AuthenticatedAuthSuccessEvent, AuthSuccessEvent, AuthUILabelOverrides, AuthUILabels, ControlledAuthUIOptions, EdgeSparkAuthUI, MountAuthUIOptions, MountedAuthUI, OneTapPromptHandle, PromptGoogleOneTapOptions, RedirectAuthUIOptions, } from './types';
|
package/dist/auth-ui/mount.d.ts
CHANGED
|
@@ -1,4 +1,22 @@
|
|
|
1
1
|
import { BetterAuthClientInstance } from '../auth/types';
|
|
2
|
-
import { ManagedAuthUIRuntimeOptions } from './ManagedAuthUI';
|
|
3
2
|
import { EdgeSparkAuthUI } from './types';
|
|
4
|
-
|
|
3
|
+
/**
|
|
4
|
+
* Internal runtime config for the auth-UI module factory. Threads cross-cutting
|
|
5
|
+
* auth wiring into `ManagedAuthUI` (modal/redirect flows) and
|
|
6
|
+
* `promptGoogleOneTap` (page-load One Tap prompt).
|
|
7
|
+
*/
|
|
8
|
+
export interface AuthUIModuleRuntimeOptions {
|
|
9
|
+
/**
|
|
10
|
+
* Best-effort hook to nudge the public auth session after the managed UI
|
|
11
|
+
* completes a sign-in. Used by `ManagedAuthUI`'s email and OAuth flows.
|
|
12
|
+
*/
|
|
13
|
+
syncPublicSession?: () => Promise<void> | void;
|
|
14
|
+
/**
|
|
15
|
+
* The public auth client used by `promptGoogleOneTap` for credential
|
|
16
|
+
* exchange. Routing One Tap through the same client as `signIn`/`signUp`
|
|
17
|
+
* keeps session updates and `onSessionChange` consistent across all
|
|
18
|
+
* sign-in methods.
|
|
19
|
+
*/
|
|
20
|
+
publicAuthClient: BetterAuthClientInstance;
|
|
21
|
+
}
|
|
22
|
+
export declare function createAuthUIModule(auth: BetterAuthClientInstance, runtimeOptions: AuthUIModuleRuntimeOptions): EdgeSparkAuthUI;
|
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { BetterAuthClientInstance } from '../auth/types';
|
|
2
|
+
import { EdgeSparkAuthError } from '../errors';
|
|
3
|
+
import { NormalizedAuthUIConfig } from './config';
|
|
4
|
+
import { AuthenticatedAuthSuccessEvent } from './types';
|
|
5
|
+
export interface PromptGoogleOneTapOptions {
|
|
6
|
+
/**
|
|
7
|
+
* Fires when Google One Tap sign-in completes.
|
|
8
|
+
*
|
|
9
|
+
* **Most apps should prefer `client.auth.onSessionChange`** as the single
|
|
10
|
+
* source of truth — it fires for One Tap, modal sign-in, sign-out, and
|
|
11
|
+
* cross-tab session changes. Use `onSuccess` only for flow-local concerns
|
|
12
|
+
* scoped to this specific prompt (e.g., per-flow analytics).
|
|
13
|
+
*/
|
|
14
|
+
onSuccess?: (event: AuthenticatedAuthSuccessEvent) => void;
|
|
15
|
+
/**
|
|
16
|
+
* Fires on credential-exchange or post-sign-in errors.
|
|
17
|
+
*/
|
|
18
|
+
onError?: (error: EdgeSparkAuthError) => void;
|
|
19
|
+
/**
|
|
20
|
+
* Fires when Google declines to display the prompt — e.g., FedCM cooldown,
|
|
21
|
+
* no eligible accounts, or browser permission denied. Use this to render a
|
|
22
|
+
* fallback "Sign in with Google" button.
|
|
23
|
+
*/
|
|
24
|
+
onUnavailable?: () => void;
|
|
25
|
+
}
|
|
26
|
+
export interface OneTapPromptHandle {
|
|
27
|
+
/**
|
|
28
|
+
* Dismiss the prompt and suppress any pending callbacks. Idempotent and
|
|
29
|
+
* safe to call after the prompt has already closed.
|
|
30
|
+
*/
|
|
31
|
+
cancel(): void;
|
|
32
|
+
}
|
|
33
|
+
interface PromptRuntime {
|
|
34
|
+
/**
|
|
35
|
+
* The wrapped public auth client. Calls flow through its path-proxy so
|
|
36
|
+
* `oneTap.callback` triggers the same session-atom refresh and
|
|
37
|
+
* `onSessionChange` emit as `signIn`/`signUp`.
|
|
38
|
+
*/
|
|
39
|
+
authClient: BetterAuthClientInstance;
|
|
40
|
+
loadConfig: () => Promise<NormalizedAuthUIConfig>;
|
|
41
|
+
}
|
|
42
|
+
export declare function createPromptGoogleOneTap(runtime: PromptRuntime): (options?: PromptGoogleOneTapOptions) => OneTapPromptHandle;
|
|
43
|
+
export {};
|
package/dist/auth-ui/types.d.ts
CHANGED
|
@@ -3,6 +3,8 @@ import { EdgeSparkAuthError } from '../errors';
|
|
|
3
3
|
import { RedirectTarget } from '../redirect';
|
|
4
4
|
import { DeepPartial } from '../shared/types';
|
|
5
5
|
import { AuthUIAppearance } from './appearance';
|
|
6
|
+
import { OneTapPromptHandle, PromptGoogleOneTapOptions } from './prompt-google-one-tap';
|
|
7
|
+
export type { OneTapPromptHandle, PromptGoogleOneTapOptions } from './prompt-google-one-tap';
|
|
6
8
|
/** Sign-in or sign-up completed with an authenticated session. */
|
|
7
9
|
export type AuthenticatedAuthSuccessEvent = {
|
|
8
10
|
action: "sign-in";
|
|
@@ -38,7 +40,14 @@ export interface AuthUILabels {
|
|
|
38
40
|
subtitle: string;
|
|
39
41
|
emailLabel: string;
|
|
40
42
|
passwordLabel: string;
|
|
43
|
+
codeLabel?: string;
|
|
41
44
|
submitButton: string;
|
|
45
|
+
sendCodeButton?: string;
|
|
46
|
+
verifyCodeButton?: string;
|
|
47
|
+
resendCodeButton?: string;
|
|
48
|
+
resendCountdown?: string;
|
|
49
|
+
passwordTab?: string;
|
|
50
|
+
codeTab?: string;
|
|
42
51
|
forgotPassword: string;
|
|
43
52
|
switchToSignUp: string;
|
|
44
53
|
signUpPrompt: string;
|
|
@@ -152,5 +161,21 @@ export interface EdgeSparkAuthUI {
|
|
|
152
161
|
* surrounding app wants to control routing/state after auth completes.
|
|
153
162
|
*/
|
|
154
163
|
mount(container: HTMLElement, options: MountAuthUIOptions): MountedAuthUI;
|
|
164
|
+
/**
|
|
165
|
+
* Triggers a Google One Tap prompt. Calling the function is the opt-in —
|
|
166
|
+
* there is no separate server config or option flag.
|
|
167
|
+
*
|
|
168
|
+
* The prompt shows only when Google is fully wired server-side (the
|
|
169
|
+
* project's `auth-config.yaml` enables Google with resolvable credentials).
|
|
170
|
+
* Otherwise the call logs a clear error to the console and returns an
|
|
171
|
+
* inert handle.
|
|
172
|
+
*
|
|
173
|
+
* @example
|
|
174
|
+
* useEffect(() => {
|
|
175
|
+
* if (session) return;
|
|
176
|
+
* const prompt = client.authUI.promptGoogleOneTap();
|
|
177
|
+
* return () => prompt.cancel();
|
|
178
|
+
* }, [session]);
|
|
179
|
+
*/
|
|
180
|
+
promptGoogleOneTap(options?: PromptGoogleOneTapOptions): OneTapPromptHandle;
|
|
155
181
|
}
|
|
156
|
-
export {};
|