@ascendkit/nextjs 0.1.0 → 0.2.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/dist/client/provider.d.ts +7 -1
- package/dist/client/provider.d.ts.map +1 -1
- package/dist/client/provider.js +10 -4
- package/dist/client/use-analytics.d.ts.map +1 -1
- package/dist/client/use-analytics.js +3 -1
- package/dist/components/auth-card.d.ts.map +1 -1
- package/dist/components/auth-card.js +6 -1
- package/dist/components/branding-badge.d.ts.map +1 -1
- package/dist/components/branding-badge.js +15 -1
- package/dist/components/forgot-password.d.ts +3 -1
- package/dist/components/forgot-password.d.ts.map +1 -1
- package/dist/components/forgot-password.js +2 -2
- package/dist/components/login.d.ts +5 -1
- package/dist/components/login.d.ts.map +1 -1
- package/dist/components/login.js +142 -4
- package/dist/components/sign-in-button.d.ts +16 -2
- package/dist/components/sign-in-button.d.ts.map +1 -1
- package/dist/components/sign-in-button.js +13 -5
- package/dist/components/sign-up-button.d.ts +16 -2
- package/dist/components/sign-up-button.d.ts.map +1 -1
- package/dist/components/sign-up-button.js +13 -5
- package/dist/components/signup.d.ts +3 -1
- package/dist/components/signup.d.ts.map +1 -1
- package/dist/components/signup.js +167 -7
- package/dist/components/social-button.d.ts.map +1 -1
- package/dist/components/social-button.js +55 -2
- package/dist/server/access-token.d.ts +1 -1
- package/dist/server/access-token.d.ts.map +1 -1
- package/dist/server/access-token.js +2 -1
- package/dist/server/adapter.d.ts +1 -1
- package/dist/server/adapter.d.ts.map +1 -1
- package/dist/server/analytics.d.ts +7 -10
- package/dist/server/analytics.d.ts.map +1 -1
- package/dist/server/analytics.js +15 -10
- package/dist/server/ascendkit-auth.d.ts +5 -5
- package/dist/server/ascendkit-auth.d.ts.map +1 -1
- package/dist/server/ascendkit-auth.js +3 -2
- package/dist/server/auth-runtime.d.ts +1 -1
- package/dist/server/auth-runtime.d.ts.map +1 -1
- package/dist/server/auth-runtime.js +2 -1
- package/dist/server/oauth-proxy-plugin.js +1 -1
- package/dist/shared/constants.d.ts +2 -0
- package/dist/shared/constants.d.ts.map +1 -0
- package/dist/shared/constants.js +1 -0
- package/dist/shared/http-client.d.ts +1 -0
- package/dist/shared/http-client.d.ts.map +1 -1
- package/dist/shared/http-client.js +13 -0
- package/package.json +5 -4
|
@@ -29,6 +29,12 @@ interface AscendKitContextValue {
|
|
|
29
29
|
/** In-modal notification set by auth form actions (signup, login errors). */
|
|
30
30
|
authNotification: AuthNotification | null;
|
|
31
31
|
clearAuthNotification: () => void;
|
|
32
|
+
/** Whether the "forgot password" feature is enabled (settings-driven). */
|
|
33
|
+
passwordResetEnabled: boolean;
|
|
34
|
+
/** Whether email verification is enabled (settings-driven). */
|
|
35
|
+
emailVerificationEnabled: boolean;
|
|
36
|
+
/** Whether credentials (email + password) are enabled. */
|
|
37
|
+
credentialsEnabled: boolean;
|
|
32
38
|
}
|
|
33
39
|
export declare function useAscendKitContext(): AscendKitContextValue;
|
|
34
40
|
interface AscendKitProviderProps {
|
|
@@ -59,7 +65,7 @@ interface AscendKitProviderProps {
|
|
|
59
65
|
*
|
|
60
66
|
* Environment variables (set by `ascendkit init` + `ascendkit set-env`):
|
|
61
67
|
* - NEXT_PUBLIC_ASCENDKIT_ENV_KEY — public key (client-side)
|
|
62
|
-
* - NEXT_PUBLIC_ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.
|
|
68
|
+
* - NEXT_PUBLIC_ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.dev)
|
|
63
69
|
*/
|
|
64
70
|
export declare function AscendKitProvider({ publicKey, apiUrl, enabledProviders: overrideProviders, onFocusRefresh, basePath, viewPaths, children, }: AscendKitProviderProps): import("react/jsx-runtime").JSX.Element;
|
|
65
71
|
export {};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/client/provider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"provider.d.ts","sourceRoot":"","sources":["../../src/client/provider.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAC;AAGrD,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAItD,MAAM,MAAM,aAAa,GAAG,SAAS,GAAG,SAAS,CAAC;AAElD,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,OAAO,CAAC;IAChB,IAAI,EAAE,aAAa,CAAC;IACpB,IAAI,EAAE,CAAC,IAAI,CAAC,EAAE,aAAa,KAAK,IAAI,CAAC;IACrC,KAAK,EAAE,MAAM,IAAI,CAAC;CACnB;AAED,KAAK,YAAY,GAAG,SAAS,GAAG,SAAS,GAAG,OAAO,GAAG,MAAM,GAAG,SAAS,CAAC;AAEzE,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,YAAY,CAAC;IACtB,OAAO,EAAE,MAAM,CAAC;CACjB;AAED,UAAU,qBAAqB;IAC7B,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC;IAChD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,eAAe,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,CAAC;IACrC,uEAAuE;IACvE,cAAc,EAAE,OAAO,CAAC;IACxB,+EAA+E;IAC/E,aAAa,EAAE,MAAM,GAAG,IAAI,CAAC;IAC7B,QAAQ,EAAE,cAAc,CAAC;IACzB,KAAK,EAAE,cAAc,CAAC;IACtB,6FAA6F;IAC7F,eAAe,EAAE,MAAM,CAAC;IACxB,6EAA6E;IAC7E,gBAAgB,EAAE,gBAAgB,GAAG,IAAI,CAAC;IAC1C,qBAAqB,EAAE,MAAM,IAAI,CAAC;IAClC,0EAA0E;IAC1E,oBAAoB,EAAE,OAAO,CAAC;IAC9B,+DAA+D;IAC/D,wBAAwB,EAAE,OAAO,CAAC;IAClC,0DAA0D;IAC1D,kBAAkB,EAAE,OAAO,CAAC;CAC7B;AA2BD,wBAAgB,mBAAmB,0BAMlC;AAED,UAAU,sBAAsB;IAC9B,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,kEAAkE;IAClE,gBAAgB,CAAC,EAAE,MAAM,EAAE,CAAC;IAC5B,2EAA2E;IAC3E,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,mDAAmD;IACnD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,0FAA0F;IAC1F,SAAS,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;IACnC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAC;CAC3B;AAcD;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,iBAAiB,CAAC,EAChC,SAA2D,EAC3D,MAAqE,EACrE,gBAAgB,EAAE,iBAAiB,EACnC,cAAsB,EACtB,QAAQ,EACR,SAAS,EACT,QAAQ,GACT,EAAE,sBAAsB,2CA0SxB"}
|
package/dist/client/provider.js
CHANGED
|
@@ -3,6 +3,7 @@ import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
|
3
3
|
import { AuthUIProvider } from "@daveyplate/better-auth-ui";
|
|
4
4
|
import { createAuthClient } from "better-auth/react";
|
|
5
5
|
import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
|
|
6
|
+
import { DEFAULT_API_URL } from "../shared/constants";
|
|
6
7
|
import { AuthModal } from "../components/auth-modal";
|
|
7
8
|
const AscendKitContext = createContext(null);
|
|
8
9
|
const AUTH_MODES = new Set(["credentials", "magic-link"]);
|
|
@@ -50,13 +51,14 @@ export function useAscendKitContext() {
|
|
|
50
51
|
*
|
|
51
52
|
* Environment variables (set by `ascendkit init` + `ascendkit set-env`):
|
|
52
53
|
* - NEXT_PUBLIC_ASCENDKIT_ENV_KEY — public key (client-side)
|
|
53
|
-
* - NEXT_PUBLIC_ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.
|
|
54
|
+
* - NEXT_PUBLIC_ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.dev)
|
|
54
55
|
*/
|
|
55
|
-
export function AscendKitProvider({ publicKey = process.env.NEXT_PUBLIC_ASCENDKIT_ENV_KEY ?? "", apiUrl = process.env.NEXT_PUBLIC_ASCENDKIT_API_URL ||
|
|
56
|
+
export function AscendKitProvider({ publicKey = process.env.NEXT_PUBLIC_ASCENDKIT_ENV_KEY ?? "", apiUrl = process.env.NEXT_PUBLIC_ASCENDKIT_API_URL || DEFAULT_API_URL, enabledProviders: overrideProviders, onFocusRefresh = false, basePath, viewPaths, children, }) {
|
|
56
57
|
const [providers, setProviders] = useState(overrideProviders ?? []);
|
|
57
58
|
const [branding, setBranding] = useState({ showBadge: true });
|
|
58
59
|
const [environmentName, setEnvironmentName] = useState("");
|
|
59
60
|
const [emailVerificationEnabled, setEmailVerificationEnabled] = useState(false);
|
|
61
|
+
const [passwordResetEnabled, setPasswordResetEnabled] = useState(false);
|
|
60
62
|
const [authNotification, setAuthNotification] = useState(null);
|
|
61
63
|
const clearAuthNotification = useCallback(() => setAuthNotification(null), []);
|
|
62
64
|
const [settingsLoaded, setSettingsLoaded] = useState(!!overrideProviders);
|
|
@@ -156,6 +158,7 @@ export function AscendKitProvider({ publicKey = process.env.NEXT_PUBLIC_ASCENDKI
|
|
|
156
158
|
setBranding(json.data.branding);
|
|
157
159
|
setEnvironmentName(json.data?.environmentName ?? "");
|
|
158
160
|
setEmailVerificationEnabled(json.data?.features?.emailVerification === true);
|
|
161
|
+
setPasswordResetEnabled(json.data?.features?.passwordReset === true);
|
|
159
162
|
if (readyProviders.length === 0 && rawProviders.length > 0) {
|
|
160
163
|
setSettingsError("Sign-in providers are enabled but not yet configured. Please contact the app developer.");
|
|
161
164
|
}
|
|
@@ -264,7 +267,10 @@ export function AscendKitProvider({ publicKey = process.env.NEXT_PUBLIC_ASCENDKI
|
|
|
264
267
|
environmentName,
|
|
265
268
|
authNotification,
|
|
266
269
|
clearAuthNotification,
|
|
267
|
-
|
|
270
|
+
passwordResetEnabled,
|
|
271
|
+
emailVerificationEnabled,
|
|
272
|
+
credentialsEnabled,
|
|
273
|
+
}, children: _jsxs(AuthUIProvider, { authClient: authClient, credentials: credentialsEnabled ? { forgotPassword: passwordResetEnabled } : false, social: socialProviders.length > 0 ? { providers: socialProviders } : undefined, magicLink: magicLinkEnabled, emailVerification: emailVerificationEnabled, signUp: true, account: false, navigate: navigate, replace: navigate, Link: ModalAwareLink, toast: ({ variant = "default", message }) => {
|
|
268
274
|
if (message)
|
|
269
275
|
setAuthNotification({ variant, message });
|
|
270
276
|
}, localization: {
|
|
@@ -276,7 +282,7 @@ export function AscendKitProvider({ publicKey = process.env.NEXT_PUBLIC_ASCENDKI
|
|
|
276
282
|
: "Choose how you'd like to sign in",
|
|
277
283
|
SIGN_UP: environmentName ? `Sign up for ${environmentName}` : "Sign Up",
|
|
278
284
|
SIGN_UP_DESCRIPTION: "Enter your information to create an account",
|
|
279
|
-
SIGN_IN_WITH: "
|
|
285
|
+
SIGN_IN_WITH: "",
|
|
280
286
|
DISABLED_CREDENTIALS_DESCRIPTION: socialProviders.length === 1
|
|
281
287
|
? `Continue with ${socialProviders[0].charAt(0).toUpperCase() + socialProviders[0].slice(1)} to sign in`
|
|
282
288
|
: "Choose how you'd like to continue",
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"use-analytics.d.ts","sourceRoot":"","sources":["../../src/client/use-analytics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"use-analytics.d.ts","sourceRoot":"","sources":["../../src/client/use-analytics.ts"],"names":[],"mappings":"AAyCA;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,wBAAgB,YAAY;mBAkFhB,MAAM,eAAe,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;;EAsBvD"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { useCallback, useEffect, useRef } from "react";
|
|
3
3
|
import { useAscendKitContext } from "./provider";
|
|
4
4
|
import { useAscendKit } from "./hooks";
|
|
5
|
-
|
|
5
|
+
import { SDK_VERSION } from "../shared/http-client";
|
|
6
6
|
const FLUSH_INTERVAL_MS = 30_000;
|
|
7
7
|
const BATCH_SIZE = 10;
|
|
8
8
|
const MAX_RETRY_ATTEMPTS = 3;
|
|
@@ -55,6 +55,7 @@ export function useAnalytics() {
|
|
|
55
55
|
headers: {
|
|
56
56
|
"Content-Type": "application/json",
|
|
57
57
|
"X-AscendKit-Public-Key": publicKey,
|
|
58
|
+
"X-AscendKit-Client-Version": `js/${SDK_VERSION}`,
|
|
58
59
|
},
|
|
59
60
|
body: JSON.stringify({ batch }),
|
|
60
61
|
});
|
|
@@ -102,6 +103,7 @@ export function useAnalytics() {
|
|
|
102
103
|
headers: {
|
|
103
104
|
"Content-Type": "application/json",
|
|
104
105
|
"X-AscendKit-Public-Key": publicKey,
|
|
106
|
+
"X-AscendKit-Client-Version": `js/${SDK_VERSION}`,
|
|
105
107
|
},
|
|
106
108
|
body: JSON.stringify({ batch }),
|
|
107
109
|
keepalive: true,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-card.d.ts","sourceRoot":"","sources":["../../src/components/auth-card.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAK1E,UAAU,sBAAuB,SAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;IAClE,iDAAiD;IACjD,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,
|
|
1
|
+
{"version":3,"file":"auth-card.d.ts","sourceRoot":"","sources":["../../src/components/auth-card.tsx"],"names":[],"mappings":"AAGA,OAAO,EAAY,KAAK,aAAa,EAAE,MAAM,4BAA4B,CAAC;AAK1E,UAAU,sBAAuB,SAAQ,IAAI,CAAC,aAAa,EAAE,MAAM,CAAC;IAClE,iDAAiD;IACjD,IAAI,CAAC,EAAE,aAAa,CAAC,MAAM,CAAC,CAAC;CAC9B;AAED;;;;;;;;;;;GAWG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,EAAE,sBAAsB,2CA8J9D"}
|
|
@@ -124,5 +124,10 @@ export function AscendKitAuthCard(props) {
|
|
|
124
124
|
--ak-notif-info-border: rgba(59, 130, 246, 0.2);
|
|
125
125
|
}
|
|
126
126
|
}
|
|
127
|
-
` })] })), _jsx(AuthView, { ...props
|
|
127
|
+
` })] })), _jsx(AuthView, { ...props, socialLayout: props.socialLayout ?? "vertical", classNames: {
|
|
128
|
+
content: "overflow-x-hidden",
|
|
129
|
+
continueWith: "w-full min-w-0",
|
|
130
|
+
separator: "min-w-0 flex-1",
|
|
131
|
+
...props.classNames,
|
|
132
|
+
} }), _jsx(BrandingBadge, {})] }));
|
|
128
133
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"branding-badge.d.ts","sourceRoot":"","sources":["../../src/components/branding-badge.tsx"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,
|
|
1
|
+
{"version":3,"file":"branding-badge.d.ts","sourceRoot":"","sources":["../../src/components/branding-badge.tsx"],"names":[],"mappings":"AAIA,wBAAgB,aAAa,mDAgC5B"}
|
|
@@ -5,5 +5,19 @@ export function BrandingBadge() {
|
|
|
5
5
|
const { branding } = useAscendKitContext();
|
|
6
6
|
if (!branding.showBadge)
|
|
7
7
|
return null;
|
|
8
|
-
return (
|
|
8
|
+
return (_jsxs("div", { className: "ak-branding-badge", children: [_jsxs("a", { href: "https://ascendkit.dev?ref=auth", target: "_blank", rel: "noopener noreferrer", className: "ak-branding-link", children: ["Powered by ", _jsx("strong", { children: "AscendKit" })] }), _jsx("style", { children: `
|
|
9
|
+
.ak-branding-badge {
|
|
10
|
+
margin-top: 12px;
|
|
11
|
+
text-align: center;
|
|
12
|
+
font-size: 12px;
|
|
13
|
+
color: var(--ak-muted-color, #888);
|
|
14
|
+
}
|
|
15
|
+
.ak-branding-link {
|
|
16
|
+
color: inherit;
|
|
17
|
+
text-decoration: none;
|
|
18
|
+
}
|
|
19
|
+
.ak-branding-link:hover {
|
|
20
|
+
text-decoration: underline;
|
|
21
|
+
}
|
|
22
|
+
` })] }));
|
|
9
23
|
}
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
interface ForgotPasswordProps {
|
|
2
2
|
onSuccess?: () => void;
|
|
3
|
+
/** Called when user clicks "Back to sign in" link. */
|
|
4
|
+
onBackToLogin?: () => void;
|
|
3
5
|
}
|
|
4
|
-
export declare function ForgotPassword({ onSuccess }: ForgotPasswordProps): import("react/jsx-runtime").JSX.Element;
|
|
6
|
+
export declare function ForgotPassword({ onSuccess, onBackToLogin }: ForgotPasswordProps): import("react/jsx-runtime").JSX.Element;
|
|
5
7
|
export {};
|
|
6
8
|
//# sourceMappingURL=forgot-password.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"forgot-password.d.ts","sourceRoot":"","sources":["../../src/components/forgot-password.tsx"],"names":[],"mappings":"AAKA,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;
|
|
1
|
+
{"version":3,"file":"forgot-password.d.ts","sourceRoot":"","sources":["../../src/components/forgot-password.tsx"],"names":[],"mappings":"AAKA,UAAU,mBAAmB;IAC3B,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,sDAAsD;IACtD,aAAa,CAAC,EAAE,MAAM,IAAI,CAAC;CAC5B;AAED,wBAAgB,cAAc,CAAC,EAAE,SAAS,EAAE,aAAa,EAAE,EAAE,mBAAmB,2CAuE/E"}
|
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useState } from "react";
|
|
4
4
|
import { useAscendKitContext } from "../client/provider";
|
|
5
|
-
export function ForgotPassword({ onSuccess }) {
|
|
5
|
+
export function ForgotPassword({ onSuccess, onBackToLogin }) {
|
|
6
6
|
const { apiUrl, publicKey } = useAscendKitContext();
|
|
7
7
|
const [email, setEmail] = useState("");
|
|
8
8
|
const [loading, setLoading] = useState(false);
|
|
@@ -33,5 +33,5 @@ export function ForgotPassword({ onSuccess }) {
|
|
|
33
33
|
setLoading(false);
|
|
34
34
|
}
|
|
35
35
|
}
|
|
36
|
-
return (
|
|
36
|
+
return (_jsxs("div", { className: "ak-auth", children: [_jsxs("div", { className: "ak-auth-header", children: [_jsx("h2", { className: "ak-auth-title", children: "Reset Password" }), _jsx("p", { className: "ak-auth-description", children: "Enter your email address and we'll send you a reset link." })] }), _jsxs("form", { onSubmit: handleSubmit, className: "ak-form", children: [error && _jsx("div", { className: "ak-error", role: "alert", children: error }), message && _jsx("div", { className: "ak-success", role: "status", children: message }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-forgot-email", children: "Email" }), _jsx("input", { id: "ak-forgot-email", name: "email", type: "email", placeholder: "m@example.com", required: true, value: email, onChange: (e) => setEmail(e.target.value), className: "ak-input" })] }), _jsxs("button", { type: "submit", disabled: loading, className: "ak-button ak-button-primary", children: [loading && _jsx("span", { className: "ak-spinner-sm", "aria-hidden": "true" }), loading ? "Sending..." : "Send reset link"] })] }), onBackToLogin && (_jsx("p", { className: "ak-auth-footer", children: _jsx("button", { type: "button", onClick: onBackToLogin, className: "ak-link", children: "\u2190 Back to sign in" }) }))] }));
|
|
37
37
|
}
|
|
@@ -3,7 +3,11 @@ interface LoginProps {
|
|
|
3
3
|
onError?: (error: string) => void;
|
|
4
4
|
/** Redirect URL after social login completes. */
|
|
5
5
|
callbackURL?: string;
|
|
6
|
+
/** Called when user clicks "Sign up" link. */
|
|
7
|
+
onSwitchToSignUp?: () => void;
|
|
8
|
+
/** Called when user clicks "Forgot your password?" link. */
|
|
9
|
+
onForgotPassword?: () => void;
|
|
6
10
|
}
|
|
7
|
-
export declare function Login({ onSuccess, onError, callbackURL }: LoginProps): import("react/jsx-runtime").JSX.Element;
|
|
11
|
+
export declare function Login({ onSuccess, onError, callbackURL, onSwitchToSignUp, onForgotPassword }: LoginProps): import("react/jsx-runtime").JSX.Element;
|
|
8
12
|
export {};
|
|
9
13
|
//# sourceMappingURL=login.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/components/login.tsx"],"names":[],"mappings":"AAMA,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"login.d.ts","sourceRoot":"","sources":["../../src/components/login.tsx"],"names":[],"mappings":"AAMA,UAAU,UAAU;IAClB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;IAC9B,4DAA4D;IAC5D,gBAAgB,CAAC,EAAE,MAAM,IAAI,CAAC;CAC/B;AAED,wBAAgB,KAAK,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,gBAAgB,EAAE,gBAAgB,EAAE,EAAE,UAAU,2CAgRxG"}
|
package/dist/components/login.js
CHANGED
|
@@ -3,11 +3,11 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { useAscendKitContext } from "../client/provider";
|
|
5
5
|
import { SocialButton } from "./social-button";
|
|
6
|
-
export function Login({ onSuccess, onError, callbackURL }) {
|
|
7
|
-
const { authClient, enabledProviders, refreshSettings } = useAscendKitContext();
|
|
6
|
+
export function Login({ onSuccess, onError, callbackURL, onSwitchToSignUp, onForgotPassword }) {
|
|
7
|
+
const { authClient, enabledProviders, refreshSettings, environmentName, credentialsEnabled, passwordResetEnabled, } = useAscendKitContext();
|
|
8
8
|
const [error, setError] = useState(null);
|
|
9
9
|
const [loading, setLoading] = useState(false);
|
|
10
|
-
const socialProviders = enabledProviders.filter((p) => p !== "credentials");
|
|
10
|
+
const socialProviders = enabledProviders.filter((p) => p !== "credentials" && p !== "magic-link");
|
|
11
11
|
useEffect(() => {
|
|
12
12
|
void refreshSettings();
|
|
13
13
|
}, [refreshSettings]);
|
|
@@ -44,5 +44,143 @@ export function Login({ onSuccess, onError, callbackURL }) {
|
|
|
44
44
|
setLoading(false);
|
|
45
45
|
}
|
|
46
46
|
}
|
|
47
|
-
return (_jsxs("div", { className: "ak-auth", children: [_jsxs("
|
|
47
|
+
return (_jsxs("div", { className: "ak-auth", children: [_jsxs("div", { className: "ak-auth-header", children: [_jsx("h2", { className: "ak-auth-title", children: environmentName ? `Log in to ${environmentName}` : "Sign In" }), _jsx("p", { className: "ak-auth-description", children: credentialsEnabled
|
|
48
|
+
? "Enter your email below to login to your account"
|
|
49
|
+
: "Choose how you'd like to sign in" })] }), credentialsEnabled && (_jsxs("form", { onSubmit: handleSubmit, className: "ak-form", children: [error && _jsx("div", { className: "ak-error", role: "alert", children: error }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-login-email", children: "Email" }), _jsx("input", { id: "ak-login-email", name: "email", type: "email", placeholder: "m@example.com", required: true, className: "ak-input" })] }), _jsxs("div", { className: "ak-field", children: [_jsxs("div", { className: "ak-field-row", children: [_jsx("label", { htmlFor: "ak-login-password", children: "Password" }), passwordResetEnabled && onForgotPassword && (_jsx("button", { type: "button", onClick: onForgotPassword, className: "ak-link", children: "Forgot your password?" }))] }), _jsx("input", { id: "ak-login-password", name: "password", type: "password", placeholder: "Password", required: true, className: "ak-input" })] }), _jsxs("button", { type: "submit", disabled: loading, className: "ak-button ak-button-primary", children: [loading && _jsx("span", { className: "ak-spinner-sm", "aria-hidden": "true" }), loading ? "Logging in..." : "Login"] })] })), socialProviders.length > 0 && (_jsxs(_Fragment, { children: [credentialsEnabled && (_jsx("div", { className: "ak-divider", children: _jsx("span", { children: "Or continue with" }) })), _jsx("div", { className: "ak-social-buttons", children: socialProviders.map((provider) => (_jsx(SocialButton, { provider: provider, callbackURL: callbackURL }, provider))) })] })), onSwitchToSignUp && (_jsxs("p", { className: "ak-auth-footer", children: ["Don't have an account?", " ", _jsx("button", { type: "button", onClick: onSwitchToSignUp, className: "ak-link ak-link-bold", children: "Sign Up" })] })), _jsx("style", { children: `
|
|
50
|
+
.ak-auth { display: flex; flex-direction: column; gap: 20px; }
|
|
51
|
+
.ak-auth-header { text-align: left; }
|
|
52
|
+
.ak-auth-title {
|
|
53
|
+
font-size: 24px;
|
|
54
|
+
font-weight: 700;
|
|
55
|
+
margin: 0 0 4px;
|
|
56
|
+
color: var(--ak-text-color, inherit);
|
|
57
|
+
}
|
|
58
|
+
.ak-auth-description {
|
|
59
|
+
font-size: 14px;
|
|
60
|
+
color: var(--ak-muted-color, #64748b);
|
|
61
|
+
margin: 0;
|
|
62
|
+
}
|
|
63
|
+
.ak-form { display: flex; flex-direction: column; gap: 16px; }
|
|
64
|
+
.ak-field { display: flex; flex-direction: column; gap: 6px; }
|
|
65
|
+
.ak-field label {
|
|
66
|
+
font-size: 14px;
|
|
67
|
+
font-weight: 500;
|
|
68
|
+
color: var(--ak-text-color, inherit);
|
|
69
|
+
}
|
|
70
|
+
.ak-field-row {
|
|
71
|
+
display: flex;
|
|
72
|
+
justify-content: space-between;
|
|
73
|
+
align-items: center;
|
|
74
|
+
}
|
|
75
|
+
.ak-input {
|
|
76
|
+
width: 100%;
|
|
77
|
+
padding: 10px 12px;
|
|
78
|
+
border: 1px solid var(--ak-border, #e2e8f0);
|
|
79
|
+
border-radius: 8px;
|
|
80
|
+
font-size: 14px;
|
|
81
|
+
background: var(--ak-input-bg, transparent);
|
|
82
|
+
color: var(--ak-text-color, inherit);
|
|
83
|
+
outline: none;
|
|
84
|
+
transition: border-color 0.15s;
|
|
85
|
+
box-sizing: border-box;
|
|
86
|
+
}
|
|
87
|
+
.ak-input::placeholder { color: var(--ak-placeholder, #94a3b8); }
|
|
88
|
+
.ak-input:focus { border-color: var(--ak-focus-border, #3b82f6); }
|
|
89
|
+
.ak-button {
|
|
90
|
+
display: flex;
|
|
91
|
+
align-items: center;
|
|
92
|
+
justify-content: center;
|
|
93
|
+
gap: 8px;
|
|
94
|
+
width: 100%;
|
|
95
|
+
padding: 10px 16px;
|
|
96
|
+
border: none;
|
|
97
|
+
border-radius: 8px;
|
|
98
|
+
font-size: 14px;
|
|
99
|
+
font-weight: 500;
|
|
100
|
+
cursor: pointer;
|
|
101
|
+
transition: opacity 0.15s;
|
|
102
|
+
}
|
|
103
|
+
.ak-button:disabled { opacity: 0.7; cursor: not-allowed; }
|
|
104
|
+
.ak-button-primary {
|
|
105
|
+
background: var(--ak-primary-bg, #0f172a);
|
|
106
|
+
color: var(--ak-primary-color, #fff);
|
|
107
|
+
}
|
|
108
|
+
.ak-button-primary:hover:not(:disabled) { opacity: 0.9; }
|
|
109
|
+
.ak-error {
|
|
110
|
+
padding: 10px 14px;
|
|
111
|
+
border-radius: 8px;
|
|
112
|
+
font-size: 14px;
|
|
113
|
+
background: var(--ak-error-bg, #fef2f2);
|
|
114
|
+
color: var(--ak-error-color, #991b1b);
|
|
115
|
+
border: 1px solid var(--ak-error-border, #fecaca);
|
|
116
|
+
}
|
|
117
|
+
.ak-divider {
|
|
118
|
+
display: flex;
|
|
119
|
+
align-items: center;
|
|
120
|
+
gap: 12px;
|
|
121
|
+
font-size: 12px;
|
|
122
|
+
color: var(--ak-muted-color, #64748b);
|
|
123
|
+
text-transform: uppercase;
|
|
124
|
+
}
|
|
125
|
+
.ak-divider::before,
|
|
126
|
+
.ak-divider::after {
|
|
127
|
+
content: "";
|
|
128
|
+
flex: 1;
|
|
129
|
+
height: 1px;
|
|
130
|
+
background: var(--ak-border, #e2e8f0);
|
|
131
|
+
}
|
|
132
|
+
.ak-social-buttons { display: flex; flex-direction: column; gap: 8px; }
|
|
133
|
+
.ak-link {
|
|
134
|
+
background: none;
|
|
135
|
+
border: none;
|
|
136
|
+
padding: 0;
|
|
137
|
+
font-size: 14px;
|
|
138
|
+
color: var(--ak-muted-color, #64748b);
|
|
139
|
+
cursor: pointer;
|
|
140
|
+
text-decoration: none;
|
|
141
|
+
}
|
|
142
|
+
.ak-link:hover { text-decoration: underline; }
|
|
143
|
+
.ak-link-bold { font-weight: 600; color: var(--ak-text-color, inherit); }
|
|
144
|
+
.ak-auth-footer {
|
|
145
|
+
text-align: center;
|
|
146
|
+
font-size: 14px;
|
|
147
|
+
color: var(--ak-muted-color, #64748b);
|
|
148
|
+
margin: 0;
|
|
149
|
+
}
|
|
150
|
+
.ak-spinner-sm {
|
|
151
|
+
width: 14px;
|
|
152
|
+
height: 14px;
|
|
153
|
+
border: 2px solid rgba(255,255,255,0.3);
|
|
154
|
+
border-top-color: currentColor;
|
|
155
|
+
border-radius: 50%;
|
|
156
|
+
animation: ak-spin 0.6s linear infinite;
|
|
157
|
+
}
|
|
158
|
+
@keyframes ak-spin { to { transform: rotate(360deg); } }
|
|
159
|
+
|
|
160
|
+
:root.dark .ak-auth, html.dark .ak-auth {
|
|
161
|
+
--ak-border: rgba(255,255,255,0.15);
|
|
162
|
+
--ak-muted-color: #94a3b8;
|
|
163
|
+
--ak-input-bg: transparent;
|
|
164
|
+
--ak-placeholder: #64748b;
|
|
165
|
+
--ak-focus-border: #60a5fa;
|
|
166
|
+
--ak-primary-bg: #f8fafc;
|
|
167
|
+
--ak-primary-color: #0f172a;
|
|
168
|
+
--ak-error-bg: rgba(239,68,68,0.1);
|
|
169
|
+
--ak-error-color: #fca5a5;
|
|
170
|
+
--ak-error-border: rgba(239,68,68,0.2);
|
|
171
|
+
}
|
|
172
|
+
@media (prefers-color-scheme: dark) {
|
|
173
|
+
.ak-auth:not(.ak-light) {
|
|
174
|
+
--ak-border: rgba(255,255,255,0.15);
|
|
175
|
+
--ak-muted-color: #94a3b8;
|
|
176
|
+
--ak-placeholder: #64748b;
|
|
177
|
+
--ak-focus-border: #60a5fa;
|
|
178
|
+
--ak-primary-bg: #f8fafc;
|
|
179
|
+
--ak-primary-color: #0f172a;
|
|
180
|
+
--ak-error-bg: rgba(239,68,68,0.1);
|
|
181
|
+
--ak-error-color: #fca5a5;
|
|
182
|
+
--ak-error-border: rgba(239,68,68,0.2);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
` })] }));
|
|
48
186
|
}
|
|
@@ -3,17 +3,31 @@ interface SignInButtonProps {
|
|
|
3
3
|
mode?: "modal" | "redirect";
|
|
4
4
|
/** Custom redirect path for "redirect" mode (default: "/auth/sign-in"). */
|
|
5
5
|
redirectUrl?: string;
|
|
6
|
+
/**
|
|
7
|
+
* When true, delegates rendering to the child element instead of wrapping
|
|
8
|
+
* in a `<button>`. The child receives the `onClick` handler via cloneElement.
|
|
9
|
+
* Follows the Radix UI / Clerk `asChild` convention.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <SignInButton asChild>
|
|
14
|
+
* <MyCustomButton variant="ghost">Log in</MyCustomButton>
|
|
15
|
+
* </SignInButton>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
asChild?: boolean;
|
|
6
19
|
children?: React.ReactNode;
|
|
7
20
|
}
|
|
8
21
|
/**
|
|
9
22
|
* Button that opens the sign-in modal or redirects to the sign-in page.
|
|
10
23
|
*
|
|
11
|
-
*
|
|
24
|
+
* @example
|
|
12
25
|
* ```tsx
|
|
13
26
|
* <SignInButton />
|
|
14
27
|
* <SignInButton mode="modal">Log in</SignInButton>
|
|
28
|
+
* <SignInButton asChild><button className="custom">Sign in</button></SignInButton>
|
|
15
29
|
* ```
|
|
16
30
|
*/
|
|
17
|
-
export declare function SignInButton({ mode, redirectUrl, children, }: SignInButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function SignInButton({ mode, redirectUrl, asChild, children, }: SignInButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
18
32
|
export {};
|
|
19
33
|
//# sourceMappingURL=sign-in-button.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-in-button.d.ts","sourceRoot":"","sources":["../../src/components/sign-in-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sign-in-button.d.ts","sourceRoot":"","sources":["../../src/components/sign-in-button.tsx"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAc,EACd,WAA6B,EAC7B,OAAe,EACf,QAAQ,GACT,EAAE,iBAAiB,2CAyBnB"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement, isValidElement } from "react";
|
|
3
4
|
import { useAscendKitContext } from "../client/provider";
|
|
4
5
|
/**
|
|
5
6
|
* Button that opens the sign-in modal or redirects to the sign-in page.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* @example
|
|
8
9
|
* ```tsx
|
|
9
10
|
* <SignInButton />
|
|
10
11
|
* <SignInButton mode="modal">Log in</SignInButton>
|
|
12
|
+
* <SignInButton asChild><button className="custom">Sign in</button></SignInButton>
|
|
11
13
|
* ```
|
|
12
14
|
*/
|
|
13
|
-
export function SignInButton({ mode = "modal", redirectUrl = "/auth/sign-in", children, }) {
|
|
15
|
+
export function SignInButton({ mode = "modal", redirectUrl = "/auth/sign-in", asChild = false, children, }) {
|
|
14
16
|
const { modal } = useAscendKitContext();
|
|
15
17
|
function handleClick() {
|
|
16
18
|
if (mode === "modal") {
|
|
@@ -20,8 +22,14 @@ export function SignInButton({ mode = "modal", redirectUrl = "/auth/sign-in", ch
|
|
|
20
22
|
window.location.href = redirectUrl;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
|
-
if (children) {
|
|
24
|
-
return (
|
|
25
|
+
if (asChild && isValidElement(children)) {
|
|
26
|
+
return cloneElement(children, {
|
|
27
|
+
onClick: (e) => {
|
|
28
|
+
children.props.onClick?.(e);
|
|
29
|
+
if (!e.defaultPrevented)
|
|
30
|
+
handleClick();
|
|
31
|
+
},
|
|
32
|
+
});
|
|
25
33
|
}
|
|
26
|
-
return (_jsx("button", { type: "button", onClick: handleClick, className: "ak-sign-in-button", children: "Sign in" }));
|
|
34
|
+
return (_jsx("button", { type: "button", onClick: handleClick, className: "ak-sign-in-button", children: children ?? "Sign in" }));
|
|
27
35
|
}
|
|
@@ -3,17 +3,31 @@ interface SignUpButtonProps {
|
|
|
3
3
|
mode?: "modal" | "redirect";
|
|
4
4
|
/** Custom redirect path for "redirect" mode (default: "/auth/sign-up"). */
|
|
5
5
|
redirectUrl?: string;
|
|
6
|
+
/**
|
|
7
|
+
* When true, delegates rendering to the child element instead of wrapping
|
|
8
|
+
* in a `<button>`. The child receives the `onClick` handler via cloneElement.
|
|
9
|
+
* Follows the Radix UI / Clerk `asChild` convention.
|
|
10
|
+
*
|
|
11
|
+
* @example
|
|
12
|
+
* ```tsx
|
|
13
|
+
* <SignUpButton asChild>
|
|
14
|
+
* <MyCustomButton>Create account</MyCustomButton>
|
|
15
|
+
* </SignUpButton>
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
asChild?: boolean;
|
|
6
19
|
children?: React.ReactNode;
|
|
7
20
|
}
|
|
8
21
|
/**
|
|
9
22
|
* Button that opens the sign-up modal or redirects to the sign-up page.
|
|
10
23
|
*
|
|
11
|
-
*
|
|
24
|
+
* @example
|
|
12
25
|
* ```tsx
|
|
13
26
|
* <SignUpButton />
|
|
14
27
|
* <SignUpButton mode="modal">Create account</SignUpButton>
|
|
28
|
+
* <SignUpButton asChild><button className="custom">Join</button></SignUpButton>
|
|
15
29
|
* ```
|
|
16
30
|
*/
|
|
17
|
-
export declare function SignUpButton({ mode, redirectUrl, children, }: SignUpButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
31
|
+
export declare function SignUpButton({ mode, redirectUrl, asChild, children, }: SignUpButtonProps): import("react/jsx-runtime").JSX.Element;
|
|
18
32
|
export {};
|
|
19
33
|
//# sourceMappingURL=sign-up-button.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sign-up-button.d.ts","sourceRoot":"","sources":["../../src/components/sign-up-button.tsx"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"sign-up-button.d.ts","sourceRoot":"","sources":["../../src/components/sign-up-button.tsx"],"names":[],"mappings":"AAKA,UAAU,iBAAiB;IACzB,8EAA8E;IAC9E,IAAI,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC;IAC5B,2EAA2E;IAC3E,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,EAAE,OAAO,CAAC;IAClB,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAC;CAC5B;AAED;;;;;;;;;GASG;AACH,wBAAgB,YAAY,CAAC,EAC3B,IAAc,EACd,WAA6B,EAC7B,OAAe,EACf,QAAQ,GACT,EAAE,iBAAiB,2CAyBnB"}
|
|
@@ -1,16 +1,18 @@
|
|
|
1
1
|
"use client";
|
|
2
2
|
import { jsx as _jsx } from "react/jsx-runtime";
|
|
3
|
+
import { cloneElement, isValidElement } from "react";
|
|
3
4
|
import { useAscendKitContext } from "../client/provider";
|
|
4
5
|
/**
|
|
5
6
|
* Button that opens the sign-up modal or redirects to the sign-up page.
|
|
6
7
|
*
|
|
7
|
-
*
|
|
8
|
+
* @example
|
|
8
9
|
* ```tsx
|
|
9
10
|
* <SignUpButton />
|
|
10
11
|
* <SignUpButton mode="modal">Create account</SignUpButton>
|
|
12
|
+
* <SignUpButton asChild><button className="custom">Join</button></SignUpButton>
|
|
11
13
|
* ```
|
|
12
14
|
*/
|
|
13
|
-
export function SignUpButton({ mode = "modal", redirectUrl = "/auth/sign-up", children, }) {
|
|
15
|
+
export function SignUpButton({ mode = "modal", redirectUrl = "/auth/sign-up", asChild = false, children, }) {
|
|
14
16
|
const { modal } = useAscendKitContext();
|
|
15
17
|
function handleClick() {
|
|
16
18
|
if (mode === "modal") {
|
|
@@ -20,8 +22,14 @@ export function SignUpButton({ mode = "modal", redirectUrl = "/auth/sign-up", ch
|
|
|
20
22
|
window.location.href = redirectUrl;
|
|
21
23
|
}
|
|
22
24
|
}
|
|
23
|
-
if (children) {
|
|
24
|
-
return (
|
|
25
|
+
if (asChild && isValidElement(children)) {
|
|
26
|
+
return cloneElement(children, {
|
|
27
|
+
onClick: (e) => {
|
|
28
|
+
children.props.onClick?.(e);
|
|
29
|
+
if (!e.defaultPrevented)
|
|
30
|
+
handleClick();
|
|
31
|
+
},
|
|
32
|
+
});
|
|
25
33
|
}
|
|
26
|
-
return (_jsx("button", { type: "button", onClick: handleClick, className: "ak-sign-up-button", children: "Sign up" }));
|
|
34
|
+
return (_jsx("button", { type: "button", onClick: handleClick, className: "ak-sign-up-button", children: children ?? "Sign up" }));
|
|
27
35
|
}
|
|
@@ -3,7 +3,9 @@ interface SignUpProps {
|
|
|
3
3
|
onError?: (error: string) => void;
|
|
4
4
|
/** Redirect URL after social login completes. */
|
|
5
5
|
callbackURL?: string;
|
|
6
|
+
/** Called when user clicks "Sign in" link. */
|
|
7
|
+
onSwitchToLogin?: () => void;
|
|
6
8
|
}
|
|
7
|
-
export declare function SignUp({ onSuccess, onError, callbackURL }: SignUpProps): import("react/jsx-runtime").JSX.Element;
|
|
9
|
+
export declare function SignUp({ onSuccess, onError, callbackURL, onSwitchToLogin }: SignUpProps): import("react/jsx-runtime").JSX.Element;
|
|
8
10
|
export {};
|
|
9
11
|
//# sourceMappingURL=signup.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"signup.d.ts","sourceRoot":"","sources":["../../src/components/signup.tsx"],"names":[],"mappings":"AAMA,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"signup.d.ts","sourceRoot":"","sources":["../../src/components/signup.tsx"],"names":[],"mappings":"AAMA,UAAU,WAAW;IACnB,SAAS,CAAC,EAAE,MAAM,IAAI,CAAC;IACvB,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,iDAAiD;IACjD,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,8CAA8C;IAC9C,eAAe,CAAC,EAAE,MAAM,IAAI,CAAC;CAC9B;AAED,wBAAgB,MAAM,CAAC,EAAE,SAAS,EAAE,OAAO,EAAE,WAAW,EAAE,eAAe,EAAE,EAAE,WAAW,2CA+TvF"}
|
|
@@ -3,17 +3,19 @@ import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-run
|
|
|
3
3
|
import { useEffect, useState } from "react";
|
|
4
4
|
import { useAscendKitContext } from "../client/provider";
|
|
5
5
|
import { SocialButton } from "./social-button";
|
|
6
|
-
export function SignUp({ onSuccess, onError, callbackURL }) {
|
|
7
|
-
const { authClient, enabledProviders, refreshSettings } = useAscendKitContext();
|
|
6
|
+
export function SignUp({ onSuccess, onError, callbackURL, onSwitchToLogin }) {
|
|
7
|
+
const { authClient, enabledProviders, refreshSettings, environmentName, credentialsEnabled, emailVerificationEnabled, } = useAscendKitContext();
|
|
8
8
|
const [error, setError] = useState(null);
|
|
9
|
+
const [success, setSuccess] = useState(null);
|
|
9
10
|
const [loading, setLoading] = useState(false);
|
|
10
|
-
const socialProviders = enabledProviders.filter((p) => p !== "credentials");
|
|
11
|
+
const socialProviders = enabledProviders.filter((p) => p !== "credentials" && p !== "magic-link");
|
|
11
12
|
useEffect(() => {
|
|
12
13
|
void refreshSettings();
|
|
13
14
|
}, [refreshSettings]);
|
|
14
15
|
async function handleSubmit(e) {
|
|
15
16
|
e.preventDefault();
|
|
16
17
|
setError(null);
|
|
18
|
+
setSuccess(null);
|
|
17
19
|
setLoading(true);
|
|
18
20
|
const form = new FormData(e.currentTarget);
|
|
19
21
|
const name = form.get("name");
|
|
@@ -26,7 +28,6 @@ export function SignUp({ onSuccess, onError, callbackURL }) {
|
|
|
26
28
|
return;
|
|
27
29
|
}
|
|
28
30
|
try {
|
|
29
|
-
// Better Auth auto-signs in after signup (autoSignIn defaults to true)
|
|
30
31
|
const { error: err } = await authClient.signUp.email({
|
|
31
32
|
name,
|
|
32
33
|
email,
|
|
@@ -42,10 +43,22 @@ export function SignUp({ onSuccess, onError, callbackURL }) {
|
|
|
42
43
|
else if (lower.includes("rejected")) {
|
|
43
44
|
msg = "Your account application was not approved.";
|
|
44
45
|
}
|
|
45
|
-
|
|
46
|
-
|
|
46
|
+
else if (lower.includes("verify") || lower.includes("verification")) {
|
|
47
|
+
msg = raw;
|
|
48
|
+
}
|
|
49
|
+
// Waitlist and verification are "soft" successes — show as info, not error
|
|
50
|
+
if (lower.includes("pending approval") || lower.includes("waitlist") || lower.includes("verify")) {
|
|
51
|
+
setSuccess(msg);
|
|
52
|
+
}
|
|
53
|
+
else {
|
|
54
|
+
setError(msg);
|
|
55
|
+
onError?.(msg);
|
|
56
|
+
}
|
|
47
57
|
}
|
|
48
58
|
else {
|
|
59
|
+
if (emailVerificationEnabled) {
|
|
60
|
+
setSuccess("Account created! Please check your email to verify your account.");
|
|
61
|
+
}
|
|
49
62
|
onSuccess?.();
|
|
50
63
|
}
|
|
51
64
|
}
|
|
@@ -56,5 +69,152 @@ export function SignUp({ onSuccess, onError, callbackURL }) {
|
|
|
56
69
|
setLoading(false);
|
|
57
70
|
}
|
|
58
71
|
}
|
|
59
|
-
return (_jsxs("div", { className: "ak-auth", children: [_jsxs("
|
|
72
|
+
return (_jsxs("div", { className: "ak-auth", children: [_jsxs("div", { className: "ak-auth-header", children: [_jsx("h2", { className: "ak-auth-title", children: environmentName ? `Sign up for ${environmentName}` : "Sign Up" }), _jsx("p", { className: "ak-auth-description", children: credentialsEnabled
|
|
73
|
+
? "Enter your information to create an account"
|
|
74
|
+
: "Choose how you'd like to sign up" })] }), credentialsEnabled && (_jsxs("form", { onSubmit: handleSubmit, className: "ak-form", children: [error && _jsx("div", { className: "ak-error", role: "alert", children: error }), success && _jsx("div", { className: "ak-success", role: "status", children: success }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-name", children: "Name" }), _jsx("input", { id: "ak-name", name: "name", type: "text", placeholder: "John Doe", required: true, className: "ak-input" })] }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-email", children: "Email" }), _jsx("input", { id: "ak-email", name: "email", type: "email", placeholder: "m@example.com", required: true, className: "ak-input" })] }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-password", children: "Password" }), _jsx("input", { id: "ak-password", name: "password", type: "password", placeholder: "Password", minLength: 8, required: true, className: "ak-input" })] }), _jsxs("div", { className: "ak-field", children: [_jsx("label", { htmlFor: "ak-confirm", children: "Confirm password" }), _jsx("input", { id: "ak-confirm", name: "confirmPassword", type: "password", placeholder: "Confirm password", minLength: 8, required: true, className: "ak-input" })] }), _jsxs("button", { type: "submit", disabled: loading, className: "ak-button ak-button-primary", children: [loading && _jsx("span", { className: "ak-spinner-sm", "aria-hidden": "true" }), loading ? "Creating account..." : "Sign up"] })] })), socialProviders.length > 0 && (_jsxs(_Fragment, { children: [credentialsEnabled && (_jsx("div", { className: "ak-divider", children: _jsx("span", { children: "Or continue with" }) })), _jsx("div", { className: "ak-social-buttons", children: socialProviders.map((provider) => (_jsx(SocialButton, { provider: provider, callbackURL: callbackURL }, provider))) })] })), onSwitchToLogin && (_jsxs("p", { className: "ak-auth-footer", children: ["Already have an account?", " ", _jsx("button", { type: "button", onClick: onSwitchToLogin, className: "ak-link ak-link-bold", children: "Sign In" })] })), _jsx("style", { children: `
|
|
75
|
+
.ak-auth { display: flex; flex-direction: column; gap: 20px; }
|
|
76
|
+
.ak-auth-header { text-align: left; }
|
|
77
|
+
.ak-auth-title {
|
|
78
|
+
font-size: 24px;
|
|
79
|
+
font-weight: 700;
|
|
80
|
+
margin: 0 0 4px;
|
|
81
|
+
color: var(--ak-text-color, inherit);
|
|
82
|
+
}
|
|
83
|
+
.ak-auth-description {
|
|
84
|
+
font-size: 14px;
|
|
85
|
+
color: var(--ak-muted-color, #64748b);
|
|
86
|
+
margin: 0;
|
|
87
|
+
}
|
|
88
|
+
.ak-form { display: flex; flex-direction: column; gap: 16px; }
|
|
89
|
+
.ak-field { display: flex; flex-direction: column; gap: 6px; }
|
|
90
|
+
.ak-field label {
|
|
91
|
+
font-size: 14px;
|
|
92
|
+
font-weight: 500;
|
|
93
|
+
color: var(--ak-text-color, inherit);
|
|
94
|
+
}
|
|
95
|
+
.ak-input {
|
|
96
|
+
width: 100%;
|
|
97
|
+
padding: 10px 12px;
|
|
98
|
+
border: 1px solid var(--ak-border, #e2e8f0);
|
|
99
|
+
border-radius: 8px;
|
|
100
|
+
font-size: 14px;
|
|
101
|
+
background: var(--ak-input-bg, transparent);
|
|
102
|
+
color: var(--ak-text-color, inherit);
|
|
103
|
+
outline: none;
|
|
104
|
+
transition: border-color 0.15s;
|
|
105
|
+
box-sizing: border-box;
|
|
106
|
+
}
|
|
107
|
+
.ak-input::placeholder { color: var(--ak-placeholder, #94a3b8); }
|
|
108
|
+
.ak-input:focus { border-color: var(--ak-focus-border, #3b82f6); }
|
|
109
|
+
.ak-button {
|
|
110
|
+
display: flex;
|
|
111
|
+
align-items: center;
|
|
112
|
+
justify-content: center;
|
|
113
|
+
gap: 8px;
|
|
114
|
+
width: 100%;
|
|
115
|
+
padding: 10px 16px;
|
|
116
|
+
border: none;
|
|
117
|
+
border-radius: 8px;
|
|
118
|
+
font-size: 14px;
|
|
119
|
+
font-weight: 500;
|
|
120
|
+
cursor: pointer;
|
|
121
|
+
transition: opacity 0.15s;
|
|
122
|
+
}
|
|
123
|
+
.ak-button:disabled { opacity: 0.7; cursor: not-allowed; }
|
|
124
|
+
.ak-button-primary {
|
|
125
|
+
background: var(--ak-primary-bg, #0f172a);
|
|
126
|
+
color: var(--ak-primary-color, #fff);
|
|
127
|
+
}
|
|
128
|
+
.ak-button-primary:hover:not(:disabled) { opacity: 0.9; }
|
|
129
|
+
.ak-error {
|
|
130
|
+
padding: 10px 14px;
|
|
131
|
+
border-radius: 8px;
|
|
132
|
+
font-size: 14px;
|
|
133
|
+
background: var(--ak-error-bg, #fef2f2);
|
|
134
|
+
color: var(--ak-error-color, #991b1b);
|
|
135
|
+
border: 1px solid var(--ak-error-border, #fecaca);
|
|
136
|
+
}
|
|
137
|
+
.ak-success {
|
|
138
|
+
padding: 10px 14px;
|
|
139
|
+
border-radius: 8px;
|
|
140
|
+
font-size: 14px;
|
|
141
|
+
background: var(--ak-success-bg, #f0fdf4);
|
|
142
|
+
color: var(--ak-success-color, #166534);
|
|
143
|
+
border: 1px solid var(--ak-success-border, #bbf7d0);
|
|
144
|
+
}
|
|
145
|
+
.ak-divider {
|
|
146
|
+
display: flex;
|
|
147
|
+
align-items: center;
|
|
148
|
+
gap: 12px;
|
|
149
|
+
font-size: 12px;
|
|
150
|
+
color: var(--ak-muted-color, #64748b);
|
|
151
|
+
text-transform: uppercase;
|
|
152
|
+
}
|
|
153
|
+
.ak-divider::before,
|
|
154
|
+
.ak-divider::after {
|
|
155
|
+
content: "";
|
|
156
|
+
flex: 1;
|
|
157
|
+
height: 1px;
|
|
158
|
+
background: var(--ak-border, #e2e8f0);
|
|
159
|
+
}
|
|
160
|
+
.ak-social-buttons { display: flex; flex-direction: column; gap: 8px; }
|
|
161
|
+
.ak-link {
|
|
162
|
+
background: none;
|
|
163
|
+
border: none;
|
|
164
|
+
padding: 0;
|
|
165
|
+
font-size: 14px;
|
|
166
|
+
color: var(--ak-muted-color, #64748b);
|
|
167
|
+
cursor: pointer;
|
|
168
|
+
text-decoration: none;
|
|
169
|
+
}
|
|
170
|
+
.ak-link:hover { text-decoration: underline; }
|
|
171
|
+
.ak-link-bold { font-weight: 600; color: var(--ak-text-color, inherit); }
|
|
172
|
+
.ak-auth-footer {
|
|
173
|
+
text-align: center;
|
|
174
|
+
font-size: 14px;
|
|
175
|
+
color: var(--ak-muted-color, #64748b);
|
|
176
|
+
margin: 0;
|
|
177
|
+
}
|
|
178
|
+
.ak-spinner-sm {
|
|
179
|
+
width: 14px;
|
|
180
|
+
height: 14px;
|
|
181
|
+
border: 2px solid rgba(255,255,255,0.3);
|
|
182
|
+
border-top-color: currentColor;
|
|
183
|
+
border-radius: 50%;
|
|
184
|
+
animation: ak-spin 0.6s linear infinite;
|
|
185
|
+
}
|
|
186
|
+
@keyframes ak-spin { to { transform: rotate(360deg); } }
|
|
187
|
+
|
|
188
|
+
:root.dark .ak-auth, html.dark .ak-auth {
|
|
189
|
+
--ak-border: rgba(255,255,255,0.15);
|
|
190
|
+
--ak-muted-color: #94a3b8;
|
|
191
|
+
--ak-input-bg: transparent;
|
|
192
|
+
--ak-placeholder: #64748b;
|
|
193
|
+
--ak-focus-border: #60a5fa;
|
|
194
|
+
--ak-primary-bg: #f8fafc;
|
|
195
|
+
--ak-primary-color: #0f172a;
|
|
196
|
+
--ak-error-bg: rgba(239,68,68,0.1);
|
|
197
|
+
--ak-error-color: #fca5a5;
|
|
198
|
+
--ak-error-border: rgba(239,68,68,0.2);
|
|
199
|
+
--ak-success-bg: rgba(34,197,94,0.1);
|
|
200
|
+
--ak-success-color: #86efac;
|
|
201
|
+
--ak-success-border: rgba(34,197,94,0.2);
|
|
202
|
+
}
|
|
203
|
+
@media (prefers-color-scheme: dark) {
|
|
204
|
+
.ak-auth:not(.ak-light) {
|
|
205
|
+
--ak-border: rgba(255,255,255,0.15);
|
|
206
|
+
--ak-muted-color: #94a3b8;
|
|
207
|
+
--ak-placeholder: #64748b;
|
|
208
|
+
--ak-focus-border: #60a5fa;
|
|
209
|
+
--ak-primary-bg: #f8fafc;
|
|
210
|
+
--ak-primary-color: #0f172a;
|
|
211
|
+
--ak-error-bg: rgba(239,68,68,0.1);
|
|
212
|
+
--ak-error-color: #fca5a5;
|
|
213
|
+
--ak-error-border: rgba(239,68,68,0.2);
|
|
214
|
+
--ak-success-bg: rgba(34,197,94,0.1);
|
|
215
|
+
--ak-success-color: #86efac;
|
|
216
|
+
--ak-success-border: rgba(34,197,94,0.2);
|
|
217
|
+
}
|
|
218
|
+
}
|
|
219
|
+
` })] }));
|
|
60
220
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"social-button.d.ts","sourceRoot":"","sources":["../../src/components/social-button.tsx"],"names":[],"mappings":"AAIA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;
|
|
1
|
+
{"version":3,"file":"social-button.d.ts","sourceRoot":"","sources":["../../src/components/social-button.tsx"],"names":[],"mappings":"AAIA,UAAU,iBAAiB;IACzB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,WAAW,CAAC,EAAE,MAAM,CAAC;CACtB;AAaD,wBAAgB,YAAY,CAAC,EAAE,QAAQ,EAAE,KAAK,EAAE,WAAW,EAAE,EAAE,iBAAiB,2CAmE/E"}
|
|
@@ -1,10 +1,63 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import { jsx as _jsx } from "react/jsx-runtime";
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
3
|
import { useAscendKitContext } from "../client/provider";
|
|
4
|
+
const PROVIDER_ICONS = {
|
|
5
|
+
google: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M22.56 12.25c0-.78-.07-1.53-.2-2.25H12v4.26h5.92a5.06 5.06 0 0 1-2.2 3.32v2.77h3.57c2.08-1.92 3.28-4.74 3.28-8.1z" fill="#4285F4"/><path d="M12 23c2.97 0 5.46-.98 7.28-2.66l-3.57-2.77c-.98.66-2.23 1.06-3.71 1.06-2.86 0-5.29-1.93-6.16-4.53H2.18v2.84C3.99 20.53 7.7 23 12 23z" fill="#34A853"/><path d="M5.84 14.09c-.22-.66-.35-1.36-.35-2.09s.13-1.43.35-2.09V7.07H2.18A10.96 10.96 0 0 0 1 12c0 1.77.42 3.45 1.18 4.93l3.66-2.84z" fill="#FBBC05"/><path d="M12 5.38c1.62 0 3.06.56 4.21 1.64l3.15-3.15C17.45 2.09 14.97 1 12 1 7.7 1 3.99 3.47 2.18 7.07l3.66 2.84c.87-2.6 3.3-4.53 6.16-4.53z" fill="#EA4335"/></svg>`,
|
|
6
|
+
github: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M12 2C6.477 2 2 6.484 2 12.017c0 4.425 2.865 8.18 6.839 9.504.5.092.682-.217.682-.483 0-.237-.008-.868-.013-1.703-2.782.605-3.369-1.343-3.369-1.343-.454-1.158-1.11-1.466-1.11-1.466-.908-.62.069-.608.069-.608 1.003.07 1.531 1.032 1.531 1.032.892 1.53 2.341 1.088 2.91.832.092-.647.35-1.088.636-1.338-2.22-.253-4.555-1.113-4.555-4.951 0-1.093.39-1.988 1.029-2.688-.103-.253-.446-1.272.098-2.65 0 0 .84-.27 2.75 1.026A9.564 9.564 0 0 1 12 6.844a9.59 9.59 0 0 1 2.504.337c1.909-1.296 2.747-1.027 2.747-1.027.546 1.379.202 2.398.1 2.651.64.7 1.028 1.595 1.028 2.688 0 3.848-2.339 4.695-4.566 4.943.359.309.678.92.678 1.855 0 1.338-.012 2.419-.012 2.747 0 .268.18.58.688.482A10.02 10.02 0 0 0 22 12.017C22 6.484 17.522 2 12 2z" fill="currentColor"/></svg>`,
|
|
7
|
+
linkedin: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M20.447 20.452h-3.554v-5.569c0-1.328-.027-3.037-1.852-3.037-1.853 0-2.136 1.445-2.136 2.939v5.667H9.351V9h3.414v1.561h.046c.477-.9 1.637-1.85 3.37-1.85 3.601 0 4.267 2.37 4.267 5.455v6.286zM5.337 7.433a2.062 2.062 0 0 1-2.063-2.065 2.064 2.064 0 1 1 2.063 2.065zm1.782 13.019H3.555V9h3.564v11.452zM22.225 0H1.771C.792 0 0 .774 0 1.729v20.542C0 23.227.792 24 1.771 24h20.451C23.2 24 24 23.227 24 22.271V1.729C24 .774 23.2 0 22.222 0h.003z" fill="#0A66C2"/></svg>`,
|
|
8
|
+
apple: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M17.05 20.28c-.98.95-2.05.88-3.08.4-1.09-.5-2.08-.48-3.24 0-1.44.62-2.2.44-3.06-.4C2.79 15.25 3.51 7.59 9.05 7.31c1.35.07 2.29.74 3.08.8 1.18-.24 2.31-.93 3.57-.84 1.51.12 2.65.72 3.4 1.8-3.12 1.87-2.38 5.98.48 7.13-.57 1.5-1.31 2.99-2.54 4.09zM12.03 7.25c-.15-2.23 1.66-4.07 3.74-4.25.32 2.32-1.55 4.23-3.74 4.25z" fill="currentColor"/></svg>`,
|
|
9
|
+
microsoft: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M2 2h9.5v9.5H2z" fill="#F25022"/><path d="M12.5 2H22v9.5h-9.5z" fill="#7FBA00"/><path d="M2 12.5h9.5V22H2z" fill="#00A4EF"/><path d="M12.5 12.5H22V22h-9.5z" fill="#FFB900"/></svg>`,
|
|
10
|
+
discord: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M20.317 4.37a19.791 19.791 0 0 0-4.885-1.515.074.074 0 0 0-.079.037c-.21.375-.444.864-.608 1.25a18.27 18.27 0 0 0-5.487 0 12.64 12.64 0 0 0-.617-1.25.077.077 0 0 0-.079-.037A19.736 19.736 0 0 0 3.677 4.37a.07.07 0 0 0-.032.027C.533 9.046-.32 13.58.099 18.057a.082.082 0 0 0 .031.057 19.9 19.9 0 0 0 5.993 3.03.078.078 0 0 0 .084-.028c.462-.63.874-1.295 1.226-1.994a.076.076 0 0 0-.041-.106 13.107 13.107 0 0 1-1.872-.892.077.077 0 0 1-.008-.128 10.2 10.2 0 0 0 .372-.292.074.074 0 0 1 .077-.01c3.928 1.793 8.18 1.793 12.062 0a.074.074 0 0 1 .078.01c.12.098.246.198.373.292a.077.077 0 0 1-.006.127 12.299 12.299 0 0 1-1.873.892.077.077 0 0 0-.041.107c.36.698.772 1.362 1.225 1.993a.076.076 0 0 0 .084.028 19.839 19.839 0 0 0 6.002-3.03.077.077 0 0 0 .032-.054c.5-5.177-.838-9.674-3.549-13.66a.061.061 0 0 0-.031-.03zM8.02 15.33c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.956-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.956 2.418-2.157 2.418zm7.975 0c-1.183 0-2.157-1.085-2.157-2.419 0-1.333.955-2.419 2.157-2.419 1.21 0 2.176 1.096 2.157 2.42 0 1.333-.946 2.418-2.157 2.418z" fill="#5865F2"/></svg>`,
|
|
11
|
+
twitter: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M18.244 2.25h3.308l-7.227 8.26 8.502 11.24H16.17l-5.214-6.817L4.99 21.75H1.68l7.73-8.835L1.254 2.25H8.08l4.713 6.231zm-1.161 17.52h1.833L7.084 4.126H5.117z" fill="currentColor"/></svg>`,
|
|
12
|
+
facebook: `<svg viewBox="0 0 24 24" width="18" height="18" xmlns="http://www.w3.org/2000/svg"><path d="M24 12.073c0-6.627-5.373-12-12-12s-12 5.373-12 12c0 5.99 4.388 10.954 10.125 11.854v-8.385H7.078v-3.47h3.047V9.43c0-3.007 1.792-4.669 4.533-4.669 1.312 0 2.686.235 2.686.235v2.953H15.83c-1.491 0-1.956.925-1.956 1.874v2.25h3.328l-.532 3.47h-2.796v8.385C19.612 23.027 24 18.062 24 12.073z" fill="#1877F2"/></svg>`,
|
|
13
|
+
};
|
|
4
14
|
export function SocialButton({ provider, label, callbackURL }) {
|
|
5
15
|
const { authClient } = useAscendKitContext();
|
|
16
|
+
const icon = PROVIDER_ICONS[provider];
|
|
17
|
+
const displayName = label || provider.charAt(0).toUpperCase() + provider.slice(1);
|
|
6
18
|
function handleClick() {
|
|
7
19
|
authClient.signIn.social({ provider, callbackURL });
|
|
8
20
|
}
|
|
9
|
-
return (
|
|
21
|
+
return (_jsxs("button", { type: "button", onClick: handleClick, className: `ak-social-button ak-social-${provider}`, children: [icon && (_jsx("span", { className: "ak-social-icon", dangerouslySetInnerHTML: { __html: icon }, "aria-hidden": "true" })), _jsxs("span", { children: ["Continue with ", displayName] }), _jsx("style", { children: `
|
|
22
|
+
.ak-social-button {
|
|
23
|
+
display: flex;
|
|
24
|
+
align-items: center;
|
|
25
|
+
justify-content: center;
|
|
26
|
+
gap: 8px;
|
|
27
|
+
width: 100%;
|
|
28
|
+
padding: 10px 16px;
|
|
29
|
+
border: 1px solid var(--ak-border, #e2e8f0);
|
|
30
|
+
border-radius: 8px;
|
|
31
|
+
background: var(--ak-social-bg, transparent);
|
|
32
|
+
color: var(--ak-social-color, inherit);
|
|
33
|
+
font-size: 14px;
|
|
34
|
+
font-weight: 500;
|
|
35
|
+
cursor: pointer;
|
|
36
|
+
transition: background 0.15s, border-color 0.15s;
|
|
37
|
+
line-height: 1.4;
|
|
38
|
+
}
|
|
39
|
+
.ak-social-button:hover {
|
|
40
|
+
background: var(--ak-social-hover-bg, rgba(0, 0, 0, 0.03));
|
|
41
|
+
border-color: var(--ak-border-hover, #cbd5e1);
|
|
42
|
+
}
|
|
43
|
+
.ak-social-icon {
|
|
44
|
+
display: flex;
|
|
45
|
+
align-items: center;
|
|
46
|
+
flex-shrink: 0;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
:root.dark .ak-social-button,
|
|
50
|
+
html.dark .ak-social-button {
|
|
51
|
+
--ak-border: rgba(255, 255, 255, 0.15);
|
|
52
|
+
--ak-border-hover: rgba(255, 255, 255, 0.3);
|
|
53
|
+
--ak-social-hover-bg: rgba(255, 255, 255, 0.05);
|
|
54
|
+
}
|
|
55
|
+
@media (prefers-color-scheme: dark) {
|
|
56
|
+
.ak-social-button:not(.ak-light) {
|
|
57
|
+
--ak-border: rgba(255, 255, 255, 0.15);
|
|
58
|
+
--ak-border-hover: rgba(255, 255, 255, 0.3);
|
|
59
|
+
--ak-social-hover-bg: rgba(255, 255, 255, 0.05);
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
` })] }));
|
|
10
63
|
}
|
|
@@ -4,7 +4,7 @@ interface AccessTokenHandlerOptions {
|
|
|
4
4
|
authRuntime: AscendKitAuthRuntime;
|
|
5
5
|
/** AscendKit environment public key (default: ASCENDKIT_ENV_KEY env var). */
|
|
6
6
|
publicKey?: string;
|
|
7
|
-
/** AscendKit API URL (default: ASCENDKIT_API_URL env var, then https://api.ascendkit.
|
|
7
|
+
/** AscendKit API URL (default: ASCENDKIT_API_URL env var, then https://api.ascendkit.dev). */
|
|
8
8
|
apiUrl?: string;
|
|
9
9
|
}
|
|
10
10
|
/**
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"access-token.d.ts","sourceRoot":"","sources":["../../src/server/access-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;
|
|
1
|
+
{"version":3,"file":"access-token.d.ts","sourceRoot":"","sources":["../../src/server/access-token.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAG3D,UAAU,yBAAyB;IACjC,qEAAqE;IACrE,WAAW,EAAE,oBAAoB,CAAC;IAClC,6EAA6E;IAC7E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,8FAA8F;IAC9F,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAQD;;;;;;;;;;;;;;;;;;;;;;;;;;GA0BG;AACH,wBAAgB,wBAAwB,CAAC,OAAO,EAAE,yBAAyB,IAO/C,KAAK,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA+D3D"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_API_URL } from "../shared/constants";
|
|
1
2
|
/**
|
|
2
3
|
* Create a Next.js route handler that exchanges a Better Auth session
|
|
3
4
|
* for a short-lived RS256 access token.
|
|
@@ -26,7 +27,7 @@
|
|
|
26
27
|
* ```
|
|
27
28
|
*/
|
|
28
29
|
export function createAccessTokenHandler(options) {
|
|
29
|
-
const { authRuntime, publicKey = process.env.ASCENDKIT_ENV_KEY ?? "", apiUrl = process.env.ASCENDKIT_API_URL ||
|
|
30
|
+
const { authRuntime, publicKey = process.env.ASCENDKIT_ENV_KEY ?? "", apiUrl = process.env.ASCENDKIT_API_URL || DEFAULT_API_URL, } = options;
|
|
30
31
|
return async function GET(req) {
|
|
31
32
|
try {
|
|
32
33
|
if (!publicKey || publicKey === "undefined" || publicKey === "null") {
|
package/dist/server/adapter.d.ts
CHANGED
|
@@ -2,5 +2,5 @@
|
|
|
2
2
|
* Creates a Better Auth database adapter that routes all CRUD operations
|
|
3
3
|
* through the AscendKit backend API, scoped by public key.
|
|
4
4
|
*/
|
|
5
|
-
export declare function createAscendKitAdapter(publicKey: string, apiUrl: string): import("better-auth/adapters").AdapterFactory
|
|
5
|
+
export declare function createAscendKitAdapter(publicKey: string, apiUrl: string): import("better-auth/adapters").AdapterFactory<import("better-auth").BetterAuthOptions>;
|
|
6
6
|
//# sourceMappingURL=adapter.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/server/adapter.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,
|
|
1
|
+
{"version":3,"file":"adapter.d.ts","sourceRoot":"","sources":["../../src/server/adapter.ts"],"names":[],"mappings":"AAGA;;;GAGG;AACH,wBAAgB,sBAAsB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,0FA+DvE"}
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
interface AnalyticsOptions {
|
|
2
|
-
/** Your project's secret key (sk_prod_...). */
|
|
3
|
-
secretKey
|
|
4
|
-
/** Your project's public key. */
|
|
5
|
-
publicKey
|
|
6
|
-
/** AscendKit API base URL. Defaults to https://api.ascendkit.
|
|
2
|
+
/** Your project's secret key (sk_prod_...). Falls back to ASCENDKIT_SECRET_KEY env var. */
|
|
3
|
+
secretKey?: string;
|
|
4
|
+
/** Your project's public key. Falls back to ASCENDKIT_ENV_KEY env var. */
|
|
5
|
+
publicKey?: string;
|
|
6
|
+
/** AscendKit API base URL. Defaults to https://api.ascendkit.dev. */
|
|
7
7
|
apiUrl?: string;
|
|
8
8
|
/** Milliseconds between automatic flushes. Defaults to 30000. */
|
|
9
9
|
flushIntervalMs?: number;
|
|
@@ -20,10 +20,7 @@ interface AnalyticsOptions {
|
|
|
20
20
|
* ```ts
|
|
21
21
|
* import { Analytics } from "@ascendkit/nextjs/server";
|
|
22
22
|
*
|
|
23
|
-
* const analytics = new Analytics(
|
|
24
|
-
* secretKey: process.env.ASCENDKIT_SECRET_KEY!,
|
|
25
|
-
* publicKey: process.env.ASCENDKIT_ENV_KEY!,
|
|
26
|
-
* });
|
|
23
|
+
* const analytics = new Analytics();
|
|
27
24
|
*
|
|
28
25
|
* analytics.track("usr_456", "checkout.completed", { orderId: "ord_789" });
|
|
29
26
|
*
|
|
@@ -37,7 +34,7 @@ export declare class Analytics {
|
|
|
37
34
|
private batchSize;
|
|
38
35
|
private flushTimer;
|
|
39
36
|
private flushing;
|
|
40
|
-
constructor(options
|
|
37
|
+
constructor(options?: AnalyticsOptions);
|
|
41
38
|
/**
|
|
42
39
|
* Queue a server-side event for a user.
|
|
43
40
|
*
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/server/analytics.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../../src/server/analytics.ts"],"names":[],"mappings":"AAaA,UAAU,gBAAgB;IACxB,2FAA2F;IAC3F,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,0EAA0E;IAC1E,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,qEAAqE;IACrE,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,iEAAiE;IACjE,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,oDAAoD;IACpD,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED;;;;;;;;;;;;;;;;;GAiBG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,KAAK,CAAwB;IACrC,OAAO,CAAC,IAAI,CAAsC;IAClD,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,UAAU,CAAiC;IACnD,OAAO,CAAC,QAAQ,CAAS;gBAEb,OAAO,GAAE,gBAAqB;IAkC1C;;;;;;;;;;;OAWG;IACH,KAAK,CACH,MAAM,EAAE,MAAM,EACd,KAAK,EAAE,MAAM,EACb,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GACnC,IAAI;IAcP,sCAAsC;IAChC,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;IAgB5B,6EAA6E;IACvE,QAAQ,IAAI,OAAO,CAAC,IAAI,CAAC;YASjB,SAAS;CAuBxB"}
|
package/dist/server/analytics.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { createHttpClient } from "../shared/http-client";
|
|
2
|
-
|
|
1
|
+
import { createHttpClient, SDK_VERSION } from "../shared/http-client";
|
|
2
|
+
import { DEFAULT_API_URL } from "../shared/constants";
|
|
3
3
|
const DEFAULT_FLUSH_INTERVAL_MS = 30_000;
|
|
4
4
|
const DEFAULT_BATCH_SIZE = 10;
|
|
5
5
|
const MAX_RETRY_ATTEMPTS = 3;
|
|
@@ -13,10 +13,7 @@ const MAX_RETRY_ATTEMPTS = 3;
|
|
|
13
13
|
* ```ts
|
|
14
14
|
* import { Analytics } from "@ascendkit/nextjs/server";
|
|
15
15
|
*
|
|
16
|
-
* const analytics = new Analytics(
|
|
17
|
-
* secretKey: process.env.ASCENDKIT_SECRET_KEY!,
|
|
18
|
-
* publicKey: process.env.ASCENDKIT_ENV_KEY!,
|
|
19
|
-
* });
|
|
16
|
+
* const analytics = new Analytics();
|
|
20
17
|
*
|
|
21
18
|
* analytics.track("usr_456", "checkout.completed", { orderId: "ord_789" });
|
|
22
19
|
*
|
|
@@ -30,13 +27,21 @@ export class Analytics {
|
|
|
30
27
|
batchSize;
|
|
31
28
|
flushTimer;
|
|
32
29
|
flushing = false;
|
|
33
|
-
constructor(options) {
|
|
34
|
-
const
|
|
30
|
+
constructor(options = {}) {
|
|
31
|
+
const secretKey = options.secretKey ?? process.env.ASCENDKIT_SECRET_KEY;
|
|
32
|
+
const publicKey = options.publicKey ?? process.env.ASCENDKIT_ENV_KEY;
|
|
33
|
+
if (!secretKey) {
|
|
34
|
+
throw new Error("AscendKit Analytics: missing secret key. Pass secretKey in options or set ASCENDKIT_SECRET_KEY.");
|
|
35
|
+
}
|
|
36
|
+
if (!publicKey) {
|
|
37
|
+
throw new Error("AscendKit Analytics: missing public key. Pass publicKey in options or set ASCENDKIT_ENV_KEY.");
|
|
38
|
+
}
|
|
39
|
+
const apiUrl = options.apiUrl ?? DEFAULT_API_URL;
|
|
35
40
|
this.batchSize = options.batchSize ?? DEFAULT_BATCH_SIZE;
|
|
36
41
|
this.http = createHttpClient({
|
|
37
|
-
publicKey
|
|
42
|
+
publicKey,
|
|
38
43
|
apiUrl,
|
|
39
|
-
secretKey
|
|
44
|
+
secretKey,
|
|
40
45
|
});
|
|
41
46
|
this.flushTimer = setInterval(() => void this.flush(), options.flushIntervalMs ?? DEFAULT_FLUSH_INTERVAL_MS);
|
|
42
47
|
// Unref so the timer doesn't keep the process alive
|
|
@@ -21,7 +21,7 @@ import type { BetterAuthPlugin } from "better-auth";
|
|
|
21
21
|
* Environment variables (set by `ascendkit init` + `ascendkit set-env`):
|
|
22
22
|
* - ASCENDKIT_ENV_KEY — public key (server-side)
|
|
23
23
|
* - ASCENDKIT_SECRET_KEY — secret key (server-side)
|
|
24
|
-
* - ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.
|
|
24
|
+
* - ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.dev)
|
|
25
25
|
*
|
|
26
26
|
* ```ts
|
|
27
27
|
* // app/api/auth/[...all]/route.ts
|
|
@@ -31,7 +31,7 @@ import type { BetterAuthPlugin } from "better-auth";
|
|
|
31
31
|
* ```
|
|
32
32
|
*/
|
|
33
33
|
export declare function AscendKitAuth(options?: AscendKitAuthOptions): Promise<import("better-auth").Auth<{
|
|
34
|
-
database: import("better-auth/adapters").AdapterFactory
|
|
34
|
+
database: import("better-auth/adapters").AdapterFactory<import("better-auth").BetterAuthOptions>;
|
|
35
35
|
emailAndPassword: {
|
|
36
36
|
enabled: false;
|
|
37
37
|
};
|
|
@@ -58,7 +58,7 @@ export declare function AscendKitAuth(options?: AscendKitAuthOptions): Promise<i
|
|
|
58
58
|
}) => Promise<void>;
|
|
59
59
|
sendOnSignUp: boolean;
|
|
60
60
|
} | undefined;
|
|
61
|
-
database: import("better-auth/adapters").AdapterFactory
|
|
61
|
+
database: import("better-auth/adapters").AdapterFactory<import("better-auth").BetterAuthOptions>;
|
|
62
62
|
emailAndPassword: {
|
|
63
63
|
sendResetPassword?: ((data: {
|
|
64
64
|
user: {
|
|
@@ -72,7 +72,7 @@ export declare function AscendKitAuth(options?: AscendKitAuthOptions): Promise<i
|
|
|
72
72
|
};
|
|
73
73
|
}>>;
|
|
74
74
|
export declare function createDisabledAuth(publicKey: string, apiUrl: string): import("better-auth").Auth<{
|
|
75
|
-
database: import("better-auth/adapters").AdapterFactory
|
|
75
|
+
database: import("better-auth/adapters").AdapterFactory<import("better-auth").BetterAuthOptions>;
|
|
76
76
|
emailAndPassword: {
|
|
77
77
|
enabled: false;
|
|
78
78
|
};
|
|
@@ -106,7 +106,7 @@ export declare function buildAscendKitAuthFromConfig(args: {
|
|
|
106
106
|
}) => Promise<void>;
|
|
107
107
|
sendOnSignUp: boolean;
|
|
108
108
|
} | undefined;
|
|
109
|
-
database: import("better-auth/adapters").AdapterFactory
|
|
109
|
+
database: import("better-auth/adapters").AdapterFactory<import("better-auth").BetterAuthOptions>;
|
|
110
110
|
emailAndPassword: {
|
|
111
111
|
sendResetPassword?: ((data: {
|
|
112
112
|
user: {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"ascendkit-auth.d.ts","sourceRoot":"","sources":["../../src/server/ascendkit-auth.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"ascendkit-auth.d.ts","sourceRoot":"","sources":["../../src/server/ascendkit-auth.ts"],"names":[],"mappings":"AAMA,OAAO,KAAK,EAAE,oBAAoB,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAC;AAExE,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC;AAEpD;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,wBAAsB,aAAa,CAAC,OAAO,GAAE,oBAAyB;;;;;;;;;;;;;;;;;;;sCAuG1B;YAAE,IAAI,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE;;;;;oCARxD;YAAE,IAAI,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE;;;;IA1E/F;AAED,wBAAgB,kBAAkB,CAAC,SAAS,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;;;;;GAMnE;AAED,wBAAsB,4BAA4B,CAAC,IAAI,EAAE;IACvD,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,EAAE,UAAU,CAAC;IACnB,oBAAoB,CAAC,EAAE,MAAM,CAAC;IAC9B,oBAAoB,CAAC,EAAE,MAAM,CAAC;CAC/B;;;;;;;;;;;;;;sCAkE2C;YAAE,IAAI,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE;;;;;oCARxD;YAAE,IAAI,EAAE;gBAAE,IAAI,EAAE,MAAM,CAAC;gBAAC,KAAK,EAAE,MAAM,CAAA;aAAE,CAAC;YAAC,GAAG,EAAE,MAAM,CAAA;SAAE;;;;IAwB/F"}
|
|
@@ -4,6 +4,7 @@ import { fetchAuthConfig } from "./config-fetcher";
|
|
|
4
4
|
import { buildSocialProviders } from "./social-providers";
|
|
5
5
|
import { createEmailSender } from "./email-sender";
|
|
6
6
|
import { ascendkitOAuthProxyPlugin } from "./oauth-proxy-plugin";
|
|
7
|
+
import { DEFAULT_API_URL } from "../shared/constants";
|
|
7
8
|
/**
|
|
8
9
|
* Pre-configured Better Auth setup for AscendKit.
|
|
9
10
|
*
|
|
@@ -25,7 +26,7 @@ import { ascendkitOAuthProxyPlugin } from "./oauth-proxy-plugin";
|
|
|
25
26
|
* Environment variables (set by `ascendkit init` + `ascendkit set-env`):
|
|
26
27
|
* - ASCENDKIT_ENV_KEY — public key (server-side)
|
|
27
28
|
* - ASCENDKIT_SECRET_KEY — secret key (server-side)
|
|
28
|
-
* - ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.
|
|
29
|
+
* - ASCENDKIT_API_URL — backend URL (default: https://api.ascendkit.dev)
|
|
29
30
|
*
|
|
30
31
|
* ```ts
|
|
31
32
|
* // app/api/auth/[...all]/route.ts
|
|
@@ -37,7 +38,7 @@ import { ascendkitOAuthProxyPlugin } from "./oauth-proxy-plugin";
|
|
|
37
38
|
export async function AscendKitAuth(options = {}) {
|
|
38
39
|
const publicKey = options.publicKey || process.env.ASCENDKIT_ENV_KEY || "";
|
|
39
40
|
const secretKey = options.secretKey || process.env.ASCENDKIT_SECRET_KEY || "";
|
|
40
|
-
const apiUrl = options.apiUrl || process.env.ASCENDKIT_API_URL ||
|
|
41
|
+
const apiUrl = options.apiUrl || process.env.ASCENDKIT_API_URL || DEFAULT_API_URL;
|
|
41
42
|
let config;
|
|
42
43
|
try {
|
|
43
44
|
config = await fetchAuthConfig(publicKey, secretKey, apiUrl);
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { betterAuth } from "better-auth";
|
|
2
2
|
import type { AscendKitAuthOptions } from "../shared/types";
|
|
3
|
-
type BetterAuthInstance = ReturnType<typeof betterAuth
|
|
3
|
+
type BetterAuthInstance = ReturnType<typeof betterAuth<any>>;
|
|
4
4
|
type SessionResult = Awaited<ReturnType<BetterAuthInstance["api"]["getSession"]>>;
|
|
5
5
|
export interface AscendKitAuthRuntime {
|
|
6
6
|
handler: (request: Request) => Promise<Response>;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"auth-runtime.d.ts","sourceRoot":"","sources":["../../src/server/auth-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;
|
|
1
|
+
{"version":3,"file":"auth-runtime.d.ts","sourceRoot":"","sources":["../../src/server/auth-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,aAAa,CAAC;AAEzC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAM5D,KAAK,kBAAkB,GAAG,UAAU,CAAC,OAAO,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC;AAC7D,KAAK,aAAa,GAAG,OAAO,CAAC,UAAU,CAAC,kBAAkB,CAAC,KAAK,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;AAOlF,MAAM,WAAW,oBAAoB;IACnC,OAAO,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAC;IACjD,UAAU,EAAE,CAAC,OAAO,EAAE,WAAW,KAAK,OAAO,CAAC,aAAa,CAAC,CAAC;IAC7D,OAAO,EAAE,MAAM,OAAO,CAAC,kBAAkB,CAAC,CAAC;CAC5C;AA8BD,wBAAgB,0BAA0B,CAAC,OAAO,GAAE,oBAAyB,GAAG,oBAAoB,CA0HnG"}
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { DEFAULT_API_URL } from "../shared/constants";
|
|
1
2
|
import { buildAscendKitAuthFromConfig, createDisabledAuth } from "./ascendkit-auth";
|
|
2
3
|
import { fetchAuthConfigConditional } from "./config-fetcher";
|
|
3
4
|
function isCallbackPath(request) {
|
|
@@ -26,7 +27,7 @@ async function shouldRetryWithPrevious(response) {
|
|
|
26
27
|
export function createAscendKitAuthRuntime(options = {}) {
|
|
27
28
|
const publicKey = options.publicKey || process.env.ASCENDKIT_ENV_KEY || "";
|
|
28
29
|
const secretKey = options.secretKey || process.env.ASCENDKIT_SECRET_KEY || "";
|
|
29
|
-
const apiUrl = options.apiUrl || process.env.ASCENDKIT_API_URL ||
|
|
30
|
+
const apiUrl = options.apiUrl || process.env.ASCENDKIT_API_URL || DEFAULT_API_URL;
|
|
30
31
|
const callbackGraceMs = 5 * 60 * 1000;
|
|
31
32
|
const minRefreshIntervalMs = 10 * 1000;
|
|
32
33
|
let currentAuth = null;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/
|
|
1
|
+
import { createAuthEndpoint, createAuthMiddleware } from "better-auth/api";
|
|
2
2
|
import { APIError } from "better-call";
|
|
3
3
|
import * as z from "zod";
|
|
4
4
|
const proxyCallbackQuerySchema = z.object({
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../../src/shared/constants.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,eAAe,8BAA8B,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export const DEFAULT_API_URL = "https://api.ascendkit.dev";
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/shared/http-client.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;
|
|
1
|
+
{"version":3,"file":"http-client.d.ts","sourceRoot":"","sources":["../../src/shared/http-client.ts"],"names":[],"mappings":"AAAA,eAAO,MAAM,WAAW,UAAU,CAAC;AAEnC,MAAM,WAAW,iBAAiB;IAChC,SAAS,EAAE,MAAM,CAAC;IAClB,MAAM,EAAE,MAAM,CAAC;IACf,SAAS,CAAC,EAAE,MAAM,CAAC;CACpB;AAED,MAAM,WAAW,oBAAoB,CAAC,CAAC;IACrC,WAAW,EAAE,OAAO,CAAC;IACrB,IAAI,CAAC,EAAE,CAAC,CAAC;IACT,IAAI,CAAC,EAAE,MAAM,CAAC;CACf;AAgBD,wBAAgB,gBAAgB,CAAC,EAAE,SAAS,EAAE,MAAM,EAAE,SAAS,EAAE,EAAE,iBAAiB;WAkB9D,CAAC,cAAc,MAAM,QAAQ,OAAO,KAAG,OAAO,CAAC,CAAC,CAAC;UASlD,CAAC,cAAc,MAAM,KAAG,OAAO,CAAC,CAAC,CAAC;qBAOvB,CAAC,cAAc,MAAM,SAAS,MAAM,KAAG,OAAO,CAAC,oBAAoB,CAAC,CAAC,CAAC,CAAC;EA0BtG;AAED,MAAM,MAAM,UAAU,GAAG,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAC"}
|
|
@@ -1,11 +1,24 @@
|
|
|
1
|
+
export const SDK_VERSION = "0.1.0";
|
|
2
|
+
let upgradeWarned = false;
|
|
3
|
+
function checkUpgradeHeader(res) {
|
|
4
|
+
const upgrade = res.headers.get("X-AscendKit-Upgrade");
|
|
5
|
+
if (upgrade === "recommended" && !upgradeWarned) {
|
|
6
|
+
const latest = res.headers.get("X-AscendKit-Latest-Version") ?? "latest";
|
|
7
|
+
console.warn(`[ascendkit] A newer SDK version (v${latest}) is available. ` +
|
|
8
|
+
`You are running v${SDK_VERSION}. Run "npm update @ascendkit/nextjs" to upgrade.`);
|
|
9
|
+
upgradeWarned = true;
|
|
10
|
+
}
|
|
11
|
+
}
|
|
1
12
|
export function createHttpClient({ publicKey, apiUrl, secretKey }) {
|
|
2
13
|
const baseHeaders = {
|
|
3
14
|
"X-AscendKit-Public-Key": publicKey,
|
|
15
|
+
"X-AscendKit-Client-Version": `js/${SDK_VERSION}`,
|
|
4
16
|
};
|
|
5
17
|
if (secretKey) {
|
|
6
18
|
baseHeaders["X-AscendKit-Secret-Key"] = secretKey;
|
|
7
19
|
}
|
|
8
20
|
async function handleResponse(res) {
|
|
21
|
+
checkUpgradeHeader(res);
|
|
9
22
|
const json = await res.json();
|
|
10
23
|
if (!res.ok) {
|
|
11
24
|
throw new Error(json.error || json.detail || `Request failed: ${res.status}`);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ascendkit/nextjs",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.2.0",
|
|
4
4
|
"description": "AscendKit SDK for Next.js and React",
|
|
5
5
|
"author": "ascendkit.dev",
|
|
6
6
|
"license": "MIT",
|
|
@@ -33,16 +33,17 @@
|
|
|
33
33
|
"typecheck": "tsc --noEmit"
|
|
34
34
|
},
|
|
35
35
|
"dependencies": {
|
|
36
|
-
"@daveyplate/better-auth-ui": "^3.3.15"
|
|
37
|
-
"better-auth": "^1.0.0",
|
|
38
|
-
"better-call": "^1.1.8"
|
|
36
|
+
"@daveyplate/better-auth-ui": "^3.3.15"
|
|
39
37
|
},
|
|
40
38
|
"peerDependencies": {
|
|
39
|
+
"better-auth": ">=1.4.0",
|
|
40
|
+
"better-call": "^1.1.8",
|
|
41
41
|
"next": ">=14",
|
|
42
42
|
"react": ">=18",
|
|
43
43
|
"react-dom": ">=18"
|
|
44
44
|
},
|
|
45
45
|
"devDependencies": {
|
|
46
|
+
"@types/node": "^22",
|
|
46
47
|
"@types/react": "^19",
|
|
47
48
|
"typescript": "^5"
|
|
48
49
|
}
|