@authara/react 0.0.1-trusted.3 → 0.1.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.
- package/README.md +331 -77
- package/dist/AppleButton.d.ts +24 -5
- package/dist/AppleButton.js +125 -7
- package/dist/GoogleButton.d.ts +17 -3
- package/dist/GoogleButton.js +162 -28
- package/dist/actions.d.ts +17 -0
- package/dist/actions.js +88 -0
- package/dist/color-mode.d.ts +3 -0
- package/dist/color-mode.js +20 -0
- package/dist/context.d.ts +1 -0
- package/dist/context.js +1 -0
- package/dist/contract.d.ts +99 -0
- package/dist/errors.d.ts +33 -0
- package/dist/errors.js +96 -0
- package/dist/generated-error-codes.d.ts +8 -0
- package/dist/generated-error-codes.js +42 -0
- package/dist/index.d.ts +6 -4
- package/dist/index.js +4 -3
- package/dist/provider-sdks.d.ts +20 -15
- package/dist/provider-sdks.js +6 -3
- package/dist/services.d.ts +3 -7
- package/dist/services.js +25 -41
- package/package.json +14 -7
package/dist/GoogleButton.d.ts
CHANGED
|
@@ -1,15 +1,29 @@
|
|
|
1
1
|
import { type ComponentPropsWithoutRef, type ReactNode } from "react";
|
|
2
|
-
import type { MaybePromise } from "./contract.js";
|
|
2
|
+
import type { AutharaActionProps, MaybePromise } from "./contract.js";
|
|
3
3
|
import type { GoogleButtonConfiguration } from "./provider-sdks.js";
|
|
4
4
|
import type { GoogleCredential } from "./services.js";
|
|
5
|
+
import { type AutharaColorMode } from "./color-mode.js";
|
|
5
6
|
type GoogleAppearance = Pick<GoogleButtonConfiguration, "type" | "theme" | "size" | "text" | "shape" | "logo_alignment" | "width">;
|
|
6
|
-
export interface
|
|
7
|
+
export interface GoogleCredentialButtonProps extends Omit<ComponentPropsWithoutRef<"button">, "children" | "onError" | "size" | "type">, GoogleAppearance {
|
|
7
8
|
disabled?: boolean;
|
|
9
|
+
border?: boolean;
|
|
10
|
+
buttonText?: string;
|
|
8
11
|
locale?: string;
|
|
9
12
|
fallback?: ReactNode;
|
|
10
13
|
onCredential: (credential: GoogleCredential) => MaybePromise<void>;
|
|
11
14
|
onError?: (error: Error) => void;
|
|
12
15
|
onUnavailable?: () => void;
|
|
13
16
|
}
|
|
14
|
-
export declare function
|
|
17
|
+
export declare function GoogleCredentialButton({ disabled, border, buttonText, locale, fallback, onCredential, onError, onUnavailable, type, theme, size, text, shape, logo_alignment, width, style, onClick, ...buttonProps }: GoogleCredentialButtonProps): React.JSX.Element | null;
|
|
18
|
+
export type GoogleButtonVariant = "icon" | "text";
|
|
19
|
+
export type GoogleButtonLabel = "continue" | "sign-in" | "sign-up";
|
|
20
|
+
type GoogleButtonVisualProps = Omit<GoogleCredentialButtonProps, "logo_alignment" | "onCredential" | "onError" | "size" | "text" | "type"> & {
|
|
21
|
+
variant?: GoogleButtonVariant;
|
|
22
|
+
size?: "small" | "medium" | "large";
|
|
23
|
+
label?: GoogleButtonLabel;
|
|
24
|
+
logoAlignment?: "left" | "center";
|
|
25
|
+
mode?: AutharaColorMode;
|
|
26
|
+
};
|
|
27
|
+
export type GoogleButtonProps = GoogleButtonVisualProps & AutharaActionProps<"google">;
|
|
28
|
+
export declare function GoogleButton(props: GoogleButtonProps): React.JSX.Element | null;
|
|
15
29
|
export {};
|
package/dist/GoogleButton.js
CHANGED
|
@@ -1,10 +1,64 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
2
2
|
import { useEffect, useRef, useState, } from "react";
|
|
3
|
-
import {
|
|
3
|
+
import { resolveAction, runGoogleAction } from "./actions.js";
|
|
4
|
+
import { isProviderUnavailable, toAutharaButtonError, toError, } from "./errors.js";
|
|
4
5
|
import { useAutharaServices } from "./context.js";
|
|
5
|
-
|
|
6
|
+
import { useResolvedAutharaColorMode, } from "./color-mode.js";
|
|
7
|
+
const googleButtonHeights = {
|
|
8
|
+
small: 30,
|
|
9
|
+
medium: 36,
|
|
10
|
+
large: 44,
|
|
11
|
+
};
|
|
12
|
+
const googleIconButtonSizes = {
|
|
13
|
+
small: 36,
|
|
14
|
+
medium: 44,
|
|
15
|
+
large: 52,
|
|
16
|
+
};
|
|
17
|
+
function googleButtonText(text) {
|
|
18
|
+
switch (text) {
|
|
19
|
+
case "signin":
|
|
20
|
+
case "signin_with":
|
|
21
|
+
return "Sign in with Google";
|
|
22
|
+
case "signup_with":
|
|
23
|
+
return "Sign up with Google";
|
|
24
|
+
case "continue_with":
|
|
25
|
+
return "Continue with Google";
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
function googleButtonRadius(shape, height) {
|
|
29
|
+
switch (shape) {
|
|
30
|
+
case "circle":
|
|
31
|
+
case "pill":
|
|
32
|
+
return height / 2;
|
|
33
|
+
case "square":
|
|
34
|
+
return 6;
|
|
35
|
+
case "rectangular":
|
|
36
|
+
return 12;
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
function googleButtonColors(theme) {
|
|
40
|
+
switch (theme) {
|
|
41
|
+
case "light":
|
|
42
|
+
return { background: "#fff", borderColor: "#747775", color: "#1f1f1f" };
|
|
43
|
+
case "dark":
|
|
44
|
+
return {
|
|
45
|
+
background: "#131314",
|
|
46
|
+
borderColor: "#8e918f",
|
|
47
|
+
color: "#e3e3e3",
|
|
48
|
+
};
|
|
49
|
+
case "neutral":
|
|
50
|
+
return {
|
|
51
|
+
background: "#f2f2f2",
|
|
52
|
+
borderColor: "transparent",
|
|
53
|
+
color: "#1f1f1f",
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
function GoogleLogo() {
|
|
58
|
+
return (_jsxs("svg", { "aria-hidden": "true", viewBox: "0 0 18 18", width: "18", height: "18", focusable: "false", children: [_jsx("path", { fill: "#4285F4", d: "M17.64 9.205c0-.638-.057-1.252-.164-1.841H9v3.481h4.844a4.14 4.14 0 0 1-1.797 2.715v2.258h2.909c1.702-1.567 2.684-3.875 2.684-6.613Z" }), _jsx("path", { fill: "#34A853", d: "M9 18c2.43 0 4.468-.806 5.956-2.182l-2.91-2.258c-.805.54-1.835.86-3.046.86-2.344 0-4.328-1.585-5.037-3.714H.956v2.332A9 9 0 0 0 9 18Z" }), _jsx("path", { fill: "#FBBC05", d: "M3.963 10.706A5.41 5.41 0 0 1 3.682 9c0-.592.102-1.168.281-1.706V4.962H.956A9 9 0 0 0 0 9c0 1.452.347 2.827.956 4.038l3.007-2.332Z" }), _jsx("path", { fill: "#EA4335", d: "M9 3.58c1.321 0 2.507.454 3.44 1.345l2.581-2.58C13.464.892 11.426 0 9 0A9 9 0 0 0 .956 4.962l3.007 2.332C4.672 5.165 6.656 3.58 9 3.58Z" })] }));
|
|
59
|
+
}
|
|
60
|
+
export function GoogleCredentialButton({ disabled = false, border, buttonText, locale, fallback = null, onCredential, onError, onUnavailable, type = "standard", theme = "light", size = "large", text = "continue_with", shape = "rectangular", logo_alignment = "center", width, style, onClick, ...buttonProps }) {
|
|
6
61
|
const { google } = useAutharaServices();
|
|
7
|
-
const targetRef = useRef(null);
|
|
8
62
|
const credentialRef = useRef(onCredential);
|
|
9
63
|
const errorRef = useRef(onError);
|
|
10
64
|
const unavailableRef = useRef(onUnavailable);
|
|
@@ -12,41 +66,34 @@ export function GoogleButton({ disabled = false, locale, fallback = null, onCred
|
|
|
12
66
|
const [available, setAvailable] = useState(true);
|
|
13
67
|
const [ready, setReady] = useState(false);
|
|
14
68
|
const [busy, setBusy] = useState(false);
|
|
69
|
+
const [requestCode, setRequestCode] = useState();
|
|
15
70
|
credentialRef.current = onCredential;
|
|
16
71
|
errorRef.current = onError;
|
|
17
72
|
unavailableRef.current = onUnavailable;
|
|
18
73
|
disabledRef.current = disabled;
|
|
19
74
|
useEffect(() => {
|
|
20
|
-
const element = targetRef.current;
|
|
21
|
-
if (!element)
|
|
22
|
-
return;
|
|
23
75
|
let active = true;
|
|
24
|
-
let dispose;
|
|
25
76
|
void google
|
|
26
|
-
.
|
|
27
|
-
type,
|
|
28
|
-
theme,
|
|
29
|
-
size,
|
|
30
|
-
text,
|
|
31
|
-
shape,
|
|
32
|
-
logo_alignment,
|
|
33
|
-
width: width ?? Math.min(element.clientWidth || 320, 400),
|
|
34
|
-
}, locale, (credential) => {
|
|
77
|
+
.prepare(locale, (credential) => {
|
|
35
78
|
if (!active || disabledRef.current)
|
|
36
79
|
return;
|
|
37
80
|
setBusy(true);
|
|
38
|
-
void Promise.resolve(
|
|
81
|
+
void Promise.resolve()
|
|
82
|
+
.then(() => credentialRef.current(credential))
|
|
39
83
|
.catch((error) => errorRef.current?.(toError(error, "Google authentication failed.")))
|
|
40
84
|
.finally(() => {
|
|
41
85
|
if (active)
|
|
42
86
|
setBusy(false);
|
|
43
87
|
});
|
|
44
|
-
})
|
|
45
|
-
.then((cleanup) => {
|
|
88
|
+
}, (error) => {
|
|
46
89
|
if (!active)
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
|
|
90
|
+
return;
|
|
91
|
+
setBusy(false);
|
|
92
|
+
errorRef.current?.(error);
|
|
93
|
+
})
|
|
94
|
+
.then((trigger) => {
|
|
95
|
+
if (active) {
|
|
96
|
+
setRequestCode(() => trigger);
|
|
50
97
|
setReady(true);
|
|
51
98
|
}
|
|
52
99
|
})
|
|
@@ -62,14 +109,101 @@ export function GoogleButton({ disabled = false, locale, fallback = null, onCred
|
|
|
62
109
|
});
|
|
63
110
|
return () => {
|
|
64
111
|
active = false;
|
|
65
|
-
dispose?.();
|
|
66
112
|
};
|
|
67
|
-
}, [google, locale
|
|
113
|
+
}, [google, locale]);
|
|
68
114
|
if (!available)
|
|
69
115
|
return _jsx(_Fragment, { children: fallback });
|
|
70
116
|
const inactive = disabled || busy;
|
|
71
|
-
|
|
117
|
+
const iconOnly = type === "icon";
|
|
118
|
+
const height = iconOnly
|
|
119
|
+
? googleIconButtonSizes[size]
|
|
120
|
+
: googleButtonHeights[size];
|
|
121
|
+
const colors = googleButtonColors(theme);
|
|
122
|
+
const radius = googleButtonRadius(shape, height);
|
|
123
|
+
const label = buttonText ?? googleButtonText(text);
|
|
124
|
+
const showBorder = border ?? theme !== "neutral";
|
|
125
|
+
return (_jsxs("button", { ...buttonProps, type: "button", disabled: !ready || inactive, "aria-busy": busy || undefined, "aria-label": buttonProps["aria-label"] ?? (iconOnly ? label : undefined), "data-authara-provider": "google", "data-authara-ready": ready ? "true" : "false", "data-authara-google-presentation": true, "data-border": String(showBorder), onClick: (event) => {
|
|
126
|
+
onClick?.(event);
|
|
127
|
+
if (event.defaultPrevented || !requestCode)
|
|
128
|
+
return;
|
|
129
|
+
setBusy(true);
|
|
130
|
+
requestCode();
|
|
131
|
+
}, style: {
|
|
132
|
+
position: "relative",
|
|
133
|
+
display: "inline-flex",
|
|
134
|
+
width: width ?? (iconOnly ? height : "100%"),
|
|
135
|
+
height,
|
|
136
|
+
alignItems: "center",
|
|
137
|
+
justifyContent: "center",
|
|
138
|
+
gap: iconOnly || logo_alignment === "left" ? 0 : 10,
|
|
139
|
+
padding: iconOnly ? 0 : "0 12px",
|
|
140
|
+
overflow: "hidden",
|
|
141
|
+
border: "1px solid",
|
|
142
|
+
borderRadius: radius,
|
|
143
|
+
boxSizing: "border-box",
|
|
144
|
+
boxShadow: "none",
|
|
145
|
+
cursor: !ready ? "wait" : inactive ? "not-allowed" : "pointer",
|
|
146
|
+
fontFamily: '"Google Sans", Roboto, Arial, sans-serif',
|
|
147
|
+
fontSize: 14,
|
|
148
|
+
fontWeight: 500,
|
|
149
|
+
lineHeight: "20px",
|
|
150
|
+
whiteSpace: "nowrap",
|
|
151
|
+
...colors,
|
|
152
|
+
borderColor: showBorder ? colors.borderColor : "transparent",
|
|
153
|
+
outlineOffset: 2,
|
|
154
|
+
opacity: inactive ? 0.62 : 1,
|
|
155
|
+
transition: "opacity 150ms ease",
|
|
156
|
+
verticalAlign: "middle",
|
|
157
|
+
WebkitTapHighlightColor: "transparent",
|
|
72
158
|
...style,
|
|
73
|
-
|
|
74
|
-
|
|
159
|
+
}, children: [_jsx("span", { "aria-hidden": "true", style: {
|
|
160
|
+
display: "inline-flex",
|
|
161
|
+
width: 20,
|
|
162
|
+
height: 20,
|
|
163
|
+
flex: "0 0 20px",
|
|
164
|
+
alignItems: "center",
|
|
165
|
+
justifyContent: "center",
|
|
166
|
+
background: "#fff",
|
|
167
|
+
borderRadius: 2,
|
|
168
|
+
position: !iconOnly && logo_alignment === "left" ? "absolute" : "static",
|
|
169
|
+
left: !iconOnly && logo_alignment === "left" ? 12 : undefined,
|
|
170
|
+
}, children: _jsx(GoogleLogo, {}) }), !iconOnly && _jsx("span", { children: label })] }));
|
|
171
|
+
}
|
|
172
|
+
function googleText(label) {
|
|
173
|
+
switch (label) {
|
|
174
|
+
case "sign-in":
|
|
175
|
+
return "signin_with";
|
|
176
|
+
case "sign-up":
|
|
177
|
+
return "signup_with";
|
|
178
|
+
case "continue":
|
|
179
|
+
return "continue_with";
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
export function GoogleButton(props) {
|
|
183
|
+
const { client } = useAutharaServices();
|
|
184
|
+
const internal = props;
|
|
185
|
+
const { action = "login", audience, authenticationChallengeId, recoveryLinkId, onSuccess, onError, variant = "text", size = "large", label = action === "login" ? "sign-in" : "continue", logoAlignment = "center", mode = "light", border, shape, theme, ...buttonProps } = internal;
|
|
186
|
+
const resolvedMode = useResolvedAutharaColorMode(mode);
|
|
187
|
+
return (_jsx(GoogleCredentialButton, { ...buttonProps, border: border, theme: theme ?? resolvedMode, type: variant === "icon" ? "icon" : "standard", size: size, text: googleText(label), shape: shape ?? "rectangular", logo_alignment: logoAlignment, onCredential: async (proof) => {
|
|
188
|
+
let result;
|
|
189
|
+
let selected;
|
|
190
|
+
try {
|
|
191
|
+
selected = resolveAction(action, audience, authenticationChallengeId, recoveryLinkId);
|
|
192
|
+
}
|
|
193
|
+
catch (error) {
|
|
194
|
+
throw toAutharaButtonError(error, "The Google button action is not configured correctly.", "configuration");
|
|
195
|
+
}
|
|
196
|
+
try {
|
|
197
|
+
result = await runGoogleAction(client, selected, proof);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
throw toAutharaButtonError(error, `Google ${action} failed.`, "authara");
|
|
201
|
+
}
|
|
202
|
+
try {
|
|
203
|
+
await onSuccess?.(result);
|
|
204
|
+
}
|
|
205
|
+
catch (error) {
|
|
206
|
+
throw toAutharaButtonError(error, "The Google success callback failed.", "consumer");
|
|
207
|
+
}
|
|
208
|
+
}, onError: (error) => onError?.(toAutharaButtonError(error, "Google authentication failed.", "provider")) }));
|
|
75
209
|
}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { AppleProof, AutharaAction, AutharaActionSuccess, AutharaAudience, AutharaReactClient, GoogleProof } from "./contract.js";
|
|
2
|
+
export type ResolvedAutharaAction = {
|
|
3
|
+
action: "login";
|
|
4
|
+
audience: AutharaAudience;
|
|
5
|
+
} | {
|
|
6
|
+
action: "link";
|
|
7
|
+
} | {
|
|
8
|
+
action: "reauthenticate";
|
|
9
|
+
authenticationChallengeId: string;
|
|
10
|
+
} | {
|
|
11
|
+
action: "recover";
|
|
12
|
+
audience: "app";
|
|
13
|
+
recoveryLinkId: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function runGoogleAction(client: AutharaReactClient, selected: ResolvedAutharaAction, proof: GoogleProof): Promise<AutharaActionSuccess<"google">>;
|
|
16
|
+
export declare function runAppleAction(client: AutharaReactClient, selected: ResolvedAutharaAction, proof: AppleProof): Promise<AutharaActionSuccess<"apple">>;
|
|
17
|
+
export declare function resolveAction(action: AutharaAction | undefined, audience: AutharaAudience | undefined, authenticationChallengeId: string | undefined, recoveryLinkId: string | undefined): ResolvedAutharaAction;
|
package/dist/actions.js
ADDED
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
export async function runGoogleAction(client, selected, proof) {
|
|
2
|
+
await client.getCsrfToken();
|
|
3
|
+
const body = { code: proof.code, redirect_uri: proof.redirect_uri };
|
|
4
|
+
switch (selected.action) {
|
|
5
|
+
case "login":
|
|
6
|
+
return {
|
|
7
|
+
action: "login",
|
|
8
|
+
provider: "google",
|
|
9
|
+
session: await client.loginWithGoogle({
|
|
10
|
+
audience: selected.audience,
|
|
11
|
+
body,
|
|
12
|
+
}),
|
|
13
|
+
};
|
|
14
|
+
case "link":
|
|
15
|
+
await client.linkCurrentUserGoogle({ body });
|
|
16
|
+
return { action: "link", provider: "google" };
|
|
17
|
+
case "reauthenticate":
|
|
18
|
+
await client.reauthenticateWithGoogle({
|
|
19
|
+
body: {
|
|
20
|
+
...body,
|
|
21
|
+
authentication_challenge_id: selected.authenticationChallengeId,
|
|
22
|
+
},
|
|
23
|
+
});
|
|
24
|
+
return { action: "reauthenticate", provider: "google" };
|
|
25
|
+
case "recover":
|
|
26
|
+
return {
|
|
27
|
+
action: "recover",
|
|
28
|
+
provider: "google",
|
|
29
|
+
session: await client.completeAccountRecoveryLinkWithGoogle({
|
|
30
|
+
linkID: selected.recoveryLinkId,
|
|
31
|
+
audience: selected.audience,
|
|
32
|
+
body,
|
|
33
|
+
}),
|
|
34
|
+
};
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
export async function runAppleAction(client, selected, proof) {
|
|
38
|
+
await client.getCsrfToken();
|
|
39
|
+
switch (selected.action) {
|
|
40
|
+
case "login":
|
|
41
|
+
return {
|
|
42
|
+
action: "login",
|
|
43
|
+
provider: "apple",
|
|
44
|
+
session: await client.loginWithApple({
|
|
45
|
+
audience: selected.audience,
|
|
46
|
+
body: proof,
|
|
47
|
+
}),
|
|
48
|
+
};
|
|
49
|
+
case "link":
|
|
50
|
+
await client.linkCurrentUserApple({ body: proof });
|
|
51
|
+
return { action: "link", provider: "apple" };
|
|
52
|
+
case "reauthenticate":
|
|
53
|
+
await client.reauthenticateWithApple({
|
|
54
|
+
body: {
|
|
55
|
+
...proof,
|
|
56
|
+
authentication_challenge_id: selected.authenticationChallengeId,
|
|
57
|
+
},
|
|
58
|
+
});
|
|
59
|
+
return { action: "reauthenticate", provider: "apple" };
|
|
60
|
+
case "recover":
|
|
61
|
+
return {
|
|
62
|
+
action: "recover",
|
|
63
|
+
provider: "apple",
|
|
64
|
+
session: await client.completeAccountRecoveryLinkWithApple({
|
|
65
|
+
linkID: selected.recoveryLinkId,
|
|
66
|
+
audience: selected.audience,
|
|
67
|
+
body: proof,
|
|
68
|
+
}),
|
|
69
|
+
};
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
export function resolveAction(action, audience, authenticationChallengeId, recoveryLinkId) {
|
|
73
|
+
if (action === "link")
|
|
74
|
+
return { action };
|
|
75
|
+
if (action === "reauthenticate") {
|
|
76
|
+
if (!authenticationChallengeId) {
|
|
77
|
+
throw new Error("authenticationChallengeId is required for reauthentication.");
|
|
78
|
+
}
|
|
79
|
+
return { action, authenticationChallengeId };
|
|
80
|
+
}
|
|
81
|
+
if (action === "recover") {
|
|
82
|
+
if (!recoveryLinkId) {
|
|
83
|
+
throw new Error("recoveryLinkId is required for account recovery.");
|
|
84
|
+
}
|
|
85
|
+
return { action, audience: "app", recoveryLinkId };
|
|
86
|
+
}
|
|
87
|
+
return { action: "login", audience: audience ?? "app" };
|
|
88
|
+
}
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import { useSyncExternalStore } from "react";
|
|
2
|
+
const darkModeQuery = "(prefers-color-scheme: dark)";
|
|
3
|
+
function systemColorMode() {
|
|
4
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
5
|
+
return "light";
|
|
6
|
+
return window.matchMedia(darkModeQuery).matches ? "dark" : "light";
|
|
7
|
+
}
|
|
8
|
+
function subscribeSystemColorMode(update) {
|
|
9
|
+
if (typeof window === "undefined" || !window.matchMedia)
|
|
10
|
+
return () => { };
|
|
11
|
+
const query = window.matchMedia(darkModeQuery);
|
|
12
|
+
query.addEventListener("change", update);
|
|
13
|
+
return () => query.removeEventListener("change", update);
|
|
14
|
+
}
|
|
15
|
+
const noSubscription = () => () => { };
|
|
16
|
+
const serverColorMode = () => "light";
|
|
17
|
+
export function useResolvedAutharaColorMode(mode) {
|
|
18
|
+
const systemMode = useSyncExternalStore(mode === "system" ? subscribeSystemColorMode : noSubscription, systemColorMode, serverColorMode);
|
|
19
|
+
return mode === "system" ? systemMode : mode;
|
|
20
|
+
}
|
package/dist/context.d.ts
CHANGED
|
@@ -3,6 +3,7 @@ import type { AutharaReactClient } from "./contract.js";
|
|
|
3
3
|
import { AppleService, GoogleService } from "./services.js";
|
|
4
4
|
type AutharaReactContextValue = {
|
|
5
5
|
apple: AppleService;
|
|
6
|
+
client: AutharaReactClient;
|
|
6
7
|
google: GoogleService;
|
|
7
8
|
};
|
|
8
9
|
export type AutharaProviderProps = PropsWithChildren<{
|
package/dist/context.js
CHANGED
|
@@ -9,6 +9,7 @@ const AutharaContext = createContext(null);
|
|
|
9
9
|
export function AutharaProvider({ client, children, }) {
|
|
10
10
|
const value = useMemo(() => ({
|
|
11
11
|
apple: new AppleService(client),
|
|
12
|
+
client,
|
|
12
13
|
google: new GoogleService(client),
|
|
13
14
|
}), [client]);
|
|
14
15
|
return (_jsx(AutharaContext.Provider, { value: value, children: children }));
|
package/dist/contract.d.ts
CHANGED
|
@@ -1,3 +1,11 @@
|
|
|
1
|
+
import type { AccountRecoveryLink as BrowserAccountRecoveryLink, AuthSession } from "@authara/browser";
|
|
2
|
+
import type { AutharaButtonError, AutharaLinkErrorCode, AutharaLoginErrorCode, AutharaRecoveryErrorCode, AutharaReauthenticationErrorCode } from "./errors.js";
|
|
3
|
+
export type AutharaAudience = "app" | "admin" | "operator";
|
|
4
|
+
export type AutharaAction = "login" | "link" | "reauthenticate" | "recover";
|
|
5
|
+
export type AutharaProviderName = "apple" | "google";
|
|
6
|
+
export type AutharaAccountRecoveryLink = BrowserAccountRecoveryLink & {
|
|
7
|
+
provider: AutharaProviderName;
|
|
8
|
+
};
|
|
1
9
|
export interface GoogleLoginOptions {
|
|
2
10
|
client_id: string;
|
|
3
11
|
nonce: string;
|
|
@@ -8,13 +16,104 @@ export interface AppleLoginOptions {
|
|
|
8
16
|
state: string;
|
|
9
17
|
nonce: string;
|
|
10
18
|
}
|
|
19
|
+
export type GoogleProof = {
|
|
20
|
+
code: string;
|
|
21
|
+
redirect_uri: string;
|
|
22
|
+
};
|
|
23
|
+
export type AppleProof = {
|
|
24
|
+
code: string;
|
|
25
|
+
state: string;
|
|
26
|
+
};
|
|
11
27
|
/**
|
|
12
28
|
* The generated @authara/browser contract slice used by the React components.
|
|
13
29
|
* AutharaBrowserClient satisfies this interface once both providers are
|
|
14
30
|
* available in the released Core contract.
|
|
15
31
|
*/
|
|
16
32
|
export interface AutharaReactClient {
|
|
33
|
+
getCsrfToken(): Promise<unknown>;
|
|
17
34
|
getGoogleLoginOptions(): Promise<GoogleLoginOptions>;
|
|
18
35
|
getAppleLoginOptions(): Promise<AppleLoginOptions>;
|
|
36
|
+
loginWithGoogle(options: {
|
|
37
|
+
audience?: AutharaAudience;
|
|
38
|
+
body: GoogleProof;
|
|
39
|
+
}): Promise<AuthSession>;
|
|
40
|
+
loginWithApple(options: {
|
|
41
|
+
audience?: AutharaAudience;
|
|
42
|
+
body: AppleProof;
|
|
43
|
+
}): Promise<AuthSession>;
|
|
44
|
+
linkCurrentUserGoogle(options: {
|
|
45
|
+
body: GoogleProof;
|
|
46
|
+
}): Promise<void>;
|
|
47
|
+
linkCurrentUserApple(options: {
|
|
48
|
+
body: AppleProof;
|
|
49
|
+
}): Promise<void>;
|
|
50
|
+
reauthenticateWithGoogle(options: {
|
|
51
|
+
body: GoogleProof & {
|
|
52
|
+
authentication_challenge_id: string;
|
|
53
|
+
};
|
|
54
|
+
}): Promise<void>;
|
|
55
|
+
reauthenticateWithApple(options: {
|
|
56
|
+
body: AppleProof & {
|
|
57
|
+
authentication_challenge_id: string;
|
|
58
|
+
};
|
|
59
|
+
}): Promise<void>;
|
|
60
|
+
completeAccountRecoveryLinkWithGoogle(options: {
|
|
61
|
+
linkID: AutharaAccountRecoveryLink["link_id"];
|
|
62
|
+
audience?: "app";
|
|
63
|
+
body: GoogleProof;
|
|
64
|
+
}): Promise<AuthSession>;
|
|
65
|
+
completeAccountRecoveryLinkWithApple(options: {
|
|
66
|
+
linkID: AutharaAccountRecoveryLink["link_id"];
|
|
67
|
+
audience?: "app";
|
|
68
|
+
body: AppleProof;
|
|
69
|
+
}): Promise<AuthSession>;
|
|
19
70
|
}
|
|
71
|
+
export type AutharaLoginSuccess<P extends AutharaProviderName> = {
|
|
72
|
+
action: "login";
|
|
73
|
+
provider: P;
|
|
74
|
+
session: AuthSession;
|
|
75
|
+
};
|
|
76
|
+
export type AutharaLinkSuccess<P extends AutharaProviderName> = {
|
|
77
|
+
action: "link";
|
|
78
|
+
provider: P;
|
|
79
|
+
};
|
|
80
|
+
export type AutharaReauthenticationSuccess<P extends AutharaProviderName> = {
|
|
81
|
+
action: "reauthenticate";
|
|
82
|
+
provider: P;
|
|
83
|
+
};
|
|
84
|
+
export type AutharaRecoverySuccess<P extends AutharaProviderName> = {
|
|
85
|
+
action: "recover";
|
|
86
|
+
provider: P;
|
|
87
|
+
session: AuthSession;
|
|
88
|
+
};
|
|
89
|
+
export type AutharaActionSuccess<P extends AutharaProviderName> = AutharaLoginSuccess<P> | AutharaLinkSuccess<P> | AutharaReauthenticationSuccess<P> | AutharaRecoverySuccess<P>;
|
|
90
|
+
export type AutharaActionProps<P extends AutharaProviderName> = {
|
|
91
|
+
action?: "login";
|
|
92
|
+
audience?: AutharaAudience;
|
|
93
|
+
authenticationChallengeId?: never;
|
|
94
|
+
recoveryLinkId?: never;
|
|
95
|
+
onSuccess?: (result: AutharaLoginSuccess<P>) => MaybePromise<void>;
|
|
96
|
+
onError?: (error: AutharaButtonError<AutharaLoginErrorCode>) => void;
|
|
97
|
+
} | {
|
|
98
|
+
action: "link";
|
|
99
|
+
audience?: never;
|
|
100
|
+
authenticationChallengeId?: never;
|
|
101
|
+
recoveryLinkId?: never;
|
|
102
|
+
onSuccess?: (result: AutharaLinkSuccess<P>) => MaybePromise<void>;
|
|
103
|
+
onError?: (error: AutharaButtonError<AutharaLinkErrorCode>) => void;
|
|
104
|
+
} | {
|
|
105
|
+
action: "reauthenticate";
|
|
106
|
+
audience?: never;
|
|
107
|
+
authenticationChallengeId: string;
|
|
108
|
+
recoveryLinkId?: never;
|
|
109
|
+
onSuccess?: (result: AutharaReauthenticationSuccess<P>) => MaybePromise<void>;
|
|
110
|
+
onError?: (error: AutharaButtonError<AutharaReauthenticationErrorCode>) => void;
|
|
111
|
+
} | {
|
|
112
|
+
action: "recover";
|
|
113
|
+
audience?: "app";
|
|
114
|
+
authenticationChallengeId?: never;
|
|
115
|
+
recoveryLinkId: AutharaAccountRecoveryLink["link_id"];
|
|
116
|
+
onSuccess?: (result: AutharaRecoverySuccess<P>) => MaybePromise<void>;
|
|
117
|
+
onError?: (error: AutharaButtonError<AutharaRecoveryErrorCode>) => void;
|
|
118
|
+
};
|
|
20
119
|
export type MaybePromise<T> = T | Promise<T>;
|
package/dist/errors.d.ts
CHANGED
|
@@ -1,3 +1,36 @@
|
|
|
1
|
+
import type { AutharaAccountRecoveryLink } from "./contract.js";
|
|
2
|
+
import { type AutharaContractErrorCode } from "./generated-error-codes.js";
|
|
1
3
|
export declare function isProviderUnavailable(error: unknown): boolean;
|
|
2
4
|
export declare function toError(error: unknown, fallback: string): Error;
|
|
5
|
+
export type AutharaButtonErrorSource = "authara" | "provider" | "configuration" | "consumer";
|
|
6
|
+
export type AutharaLocalErrorCode = "csrf_token_missing" | "unknown_authara_error";
|
|
7
|
+
export type AutharaLoginErrorCode = AutharaContractErrorCode<"login"> | AutharaLocalErrorCode;
|
|
8
|
+
export type AutharaLinkErrorCode = AutharaContractErrorCode<"link"> | AutharaLocalErrorCode;
|
|
9
|
+
export type AutharaReauthenticationErrorCode = AutharaContractErrorCode<"reauthenticate"> | AutharaLocalErrorCode;
|
|
10
|
+
export type AutharaRecoveryErrorCode = AutharaContractErrorCode<"recover"> | AutharaLocalErrorCode;
|
|
11
|
+
export type AutharaButtonErrorCode = AutharaLoginErrorCode | AutharaLinkErrorCode | AutharaReauthenticationErrorCode | AutharaRecoveryErrorCode;
|
|
12
|
+
export type AutharaAuthenticationChallenge = {
|
|
13
|
+
id: string;
|
|
14
|
+
expires_at: string;
|
|
15
|
+
};
|
|
16
|
+
export declare class AutharaButtonError<Code extends string = AutharaButtonErrorCode> extends Error {
|
|
17
|
+
readonly source: AutharaButtonErrorSource;
|
|
18
|
+
readonly code?: Code;
|
|
19
|
+
readonly serverCode?: string;
|
|
20
|
+
readonly status?: number;
|
|
21
|
+
readonly authenticationChallenge?: AutharaAuthenticationChallenge;
|
|
22
|
+
readonly reauthenticateUrl?: string;
|
|
23
|
+
readonly recovery?: AutharaAccountRecoveryLink;
|
|
24
|
+
readonly originalError: unknown;
|
|
25
|
+
constructor(message: string, source: AutharaButtonErrorSource, originalError: unknown, metadata?: {
|
|
26
|
+
code?: Code;
|
|
27
|
+
serverCode?: string;
|
|
28
|
+
status?: number;
|
|
29
|
+
authenticationChallenge?: AutharaAuthenticationChallenge;
|
|
30
|
+
reauthenticateUrl?: string;
|
|
31
|
+
recovery?: AutharaAccountRecoveryLink;
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export declare function toAutharaButtonError(error: unknown, fallback: string, defaultSource: AutharaButtonErrorSource): AutharaButtonError;
|
|
35
|
+
export declare function isAutharaButtonError(error: unknown): error is AutharaButtonError;
|
|
3
36
|
export declare function isAppleCancellation(error: unknown): boolean;
|