@opensaas/stack-auth 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/.turbo/turbo-build.log +4 -0
- package/INTEGRATION_SUMMARY.md +425 -0
- package/README.md +445 -0
- package/dist/client/index.d.ts +38 -0
- package/dist/client/index.d.ts.map +1 -0
- package/dist/client/index.js +23 -0
- package/dist/client/index.js.map +1 -0
- package/dist/config/index.d.ts +50 -0
- package/dist/config/index.d.ts.map +1 -0
- package/dist/config/index.js +115 -0
- package/dist/config/index.js.map +1 -0
- package/dist/config/types.d.ts +160 -0
- package/dist/config/types.d.ts.map +1 -0
- package/dist/config/types.js +2 -0
- package/dist/config/types.js.map +1 -0
- package/dist/index.d.ts +35 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +34 -0
- package/dist/index.js.map +1 -0
- package/dist/lists/index.d.ts +46 -0
- package/dist/lists/index.d.ts.map +1 -0
- package/dist/lists/index.js +227 -0
- package/dist/lists/index.js.map +1 -0
- package/dist/server/index.d.ts +27 -0
- package/dist/server/index.d.ts.map +1 -0
- package/dist/server/index.js +90 -0
- package/dist/server/index.js.map +1 -0
- package/dist/ui/components/ForgotPasswordForm.d.ts +36 -0
- package/dist/ui/components/ForgotPasswordForm.d.ts.map +1 -0
- package/dist/ui/components/ForgotPasswordForm.js +50 -0
- package/dist/ui/components/ForgotPasswordForm.js.map +1 -0
- package/dist/ui/components/SignInForm.d.ts +52 -0
- package/dist/ui/components/SignInForm.d.ts.map +1 -0
- package/dist/ui/components/SignInForm.js +66 -0
- package/dist/ui/components/SignInForm.js.map +1 -0
- package/dist/ui/components/SignUpForm.d.ts +56 -0
- package/dist/ui/components/SignUpForm.d.ts.map +1 -0
- package/dist/ui/components/SignUpForm.js +74 -0
- package/dist/ui/components/SignUpForm.js.map +1 -0
- package/dist/ui/index.d.ts +7 -0
- package/dist/ui/index.d.ts.map +1 -0
- package/dist/ui/index.js +4 -0
- package/dist/ui/index.js.map +1 -0
- package/package.json +55 -0
- package/src/client/index.ts +44 -0
- package/src/config/index.ts +140 -0
- package/src/config/types.ts +166 -0
- package/src/index.ts +44 -0
- package/src/lists/index.ts +245 -0
- package/src/server/index.ts +120 -0
- package/src/ui/components/ForgotPasswordForm.tsx +120 -0
- package/src/ui/components/SignInForm.tsx +191 -0
- package/src/ui/components/SignUpForm.tsx +238 -0
- package/src/ui/index.ts +7 -0
- package/tsconfig.json +14 -0
- package/tsconfig.tsbuildinfo +1 -0
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { createAuthClient } from 'better-auth/react';
|
|
2
|
+
export type ForgotPasswordFormProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Better-auth client instance
|
|
5
|
+
* Created with createAuthClient from better-auth/react
|
|
6
|
+
*/
|
|
7
|
+
authClient: ReturnType<typeof createAuthClient>;
|
|
8
|
+
/**
|
|
9
|
+
* Custom CSS class for the form container
|
|
10
|
+
*/
|
|
11
|
+
className?: string;
|
|
12
|
+
/**
|
|
13
|
+
* Callback when reset email is sent successfully
|
|
14
|
+
*/
|
|
15
|
+
onSuccess?: () => void;
|
|
16
|
+
/**
|
|
17
|
+
* Callback when reset fails
|
|
18
|
+
*/
|
|
19
|
+
onError?: (error: Error) => void;
|
|
20
|
+
};
|
|
21
|
+
/**
|
|
22
|
+
* Forgot password form component
|
|
23
|
+
* Allows users to request a password reset email
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* ```typescript
|
|
27
|
+
* import { ForgotPasswordForm } from '@opensaas/stack-auth/ui'
|
|
28
|
+
* import { authClient } from '@/lib/auth-client'
|
|
29
|
+
*
|
|
30
|
+
* export default function ForgotPasswordPage() {
|
|
31
|
+
* return <ForgotPasswordForm authClient={authClient} />
|
|
32
|
+
* }
|
|
33
|
+
* ```
|
|
34
|
+
*/
|
|
35
|
+
export declare function ForgotPasswordForm({ authClient, className, onSuccess, onError, }: ForgotPasswordFormProps): import("react/jsx-runtime").JSX.Element;
|
|
36
|
+
//# sourceMappingURL=ForgotPasswordForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForgotPasswordForm.d.ts","sourceRoot":"","sources":["../../../src/ui/components/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,MAAM,MAAM,uBAAuB,GAAG;IACpC;;;OAGG;IACH,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;IAC/C;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,kBAAkB,CAAC,EACjC,UAAU,EACV,SAAc,EACd,SAAS,EACT,OAAO,GACR,EAAE,uBAAuB,2CA2EzB"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Forgot password form component
|
|
6
|
+
* Allows users to request a password reset email
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { ForgotPasswordForm } from '@opensaas/stack-auth/ui'
|
|
11
|
+
* import { authClient } from '@/lib/auth-client'
|
|
12
|
+
*
|
|
13
|
+
* export default function ForgotPasswordPage() {
|
|
14
|
+
* return <ForgotPasswordForm authClient={authClient} />
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function ForgotPasswordForm({ authClient, className = '', onSuccess, onError, }) {
|
|
19
|
+
const [email, setEmail] = useState('');
|
|
20
|
+
const [error, setError] = useState('');
|
|
21
|
+
const [success, setSuccess] = useState(false);
|
|
22
|
+
const [loading, setLoading] = useState(false);
|
|
23
|
+
const handleSubmit = async (e) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
setError('');
|
|
26
|
+
setSuccess(false);
|
|
27
|
+
setLoading(true);
|
|
28
|
+
try {
|
|
29
|
+
const result = await authClient.forgetPassword({
|
|
30
|
+
email,
|
|
31
|
+
redirectTo: '/reset-password',
|
|
32
|
+
});
|
|
33
|
+
if (result.error) {
|
|
34
|
+
throw new Error(result.error.message);
|
|
35
|
+
}
|
|
36
|
+
setSuccess(true);
|
|
37
|
+
onSuccess?.();
|
|
38
|
+
}
|
|
39
|
+
catch (err) {
|
|
40
|
+
const message = err instanceof Error ? err.message : 'Failed to send reset email';
|
|
41
|
+
setError(message);
|
|
42
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
43
|
+
}
|
|
44
|
+
finally {
|
|
45
|
+
setLoading(false);
|
|
46
|
+
}
|
|
47
|
+
};
|
|
48
|
+
return (_jsxs("div", { className: `w-full max-w-md mx-auto p-6 ${className}`, children: [_jsx("h2", { className: "text-2xl font-bold mb-6", children: "Forgot Password" }), error && (_jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4", children: error })), success && (_jsx("div", { className: "bg-green-50 border border-green-200 text-green-700 px-4 py-3 rounded mb-4", children: "Password reset email sent! Check your inbox for instructions." })), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "email", className: "block text-sm font-medium mb-2", children: "Email" }), _jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading || success })] }), _jsx("button", { type: "submit", disabled: loading || success, className: "w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed", children: loading ? 'Sending...' : success ? 'Email Sent' : 'Send Reset Link' })] })] }));
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=ForgotPasswordForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ForgotPasswordForm.js","sourceRoot":"","sources":["../../../src/ui/components/ForgotPasswordForm.tsx"],"names":[],"mappings":"AAAA,YAAY,CAAA;;AAEZ,OAAc,EAAE,QAAQ,EAAE,MAAM,OAAO,CAAA;AAuBvC;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,kBAAkB,CAAC,EACjC,UAAU,EACV,SAAS,GAAG,EAAE,EACd,SAAS,EACT,OAAO,GACiB;IACxB,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,GAAG,QAAQ,CAAC,EAAE,CAAC,CAAA;IACtC,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAC7C,MAAM,CAAC,OAAO,EAAE,UAAU,CAAC,GAAG,QAAQ,CAAC,KAAK,CAAC,CAAA;IAE7C,MAAM,YAAY,GAAG,KAAK,EAAE,CAAkB,EAAE,EAAE;QAChD,CAAC,CAAC,cAAc,EAAE,CAAA;QAClB,QAAQ,CAAC,EAAE,CAAC,CAAA;QACZ,UAAU,CAAC,KAAK,CAAC,CAAA;QACjB,UAAU,CAAC,IAAI,CAAC,CAAA;QAEhB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,cAAc,CAAC;gBAC7C,KAAK;gBACL,UAAU,EAAE,iBAAiB;aAC9B,CAAC,CAAA;YAEF,IAAI,MAAM,CAAC,KAAK,EAAE,CAAC;gBACjB,MAAM,IAAI,KAAK,CAAC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAA;YACvC,CAAC;YAED,UAAU,CAAC,IAAI,CAAC,CAAA;YAChB,SAAS,EAAE,EAAE,CAAA;QACf,CAAC;QAAC,OAAO,GAAG,EAAE,CAAC;YACb,MAAM,OAAO,GAAG,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,OAAO,CAAC,CAAC,CAAC,4BAA4B,CAAA;YACjF,QAAQ,CAAC,OAAO,CAAC,CAAA;YACjB,OAAO,EAAE,CAAC,GAAG,YAAY,KAAK,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC,CAAC,CAAA;QAC5D,CAAC;gBAAS,CAAC;YACT,UAAU,CAAC,KAAK,CAAC,CAAA;QACnB,CAAC;IACH,CAAC,CAAA;IAED,OAAO,CACL,eAAK,SAAS,EAAE,+BAA+B,SAAS,EAAE,aACxD,aAAI,SAAS,EAAC,yBAAyB,gCAAqB,EAE3D,KAAK,IAAI,CACR,cAAK,SAAS,EAAC,qEAAqE,YACjF,KAAK,GACF,CACP,EAEA,OAAO,IAAI,CACV,cAAK,SAAS,EAAC,2EAA2E,8EAEpF,CACP,EAED,gBAAM,QAAQ,EAAE,YAAY,EAAE,SAAS,EAAC,WAAW,aACjD,0BACE,gBAAO,OAAO,EAAC,OAAO,EAAC,SAAS,EAAC,gCAAgC,sBAEzD,EACR,gBACE,EAAE,EAAC,OAAO,EACV,IAAI,EAAC,OAAO,EACZ,KAAK,EAAE,KAAK,EACZ,QAAQ,EAAE,CAAC,CAAC,EAAE,EAAE,CAAC,QAAQ,CAAE,CAAC,CAAC,MAA2B,CAAC,KAAK,CAAC,EAC/D,QAAQ,QACR,SAAS,EAAC,wGAAwG,EAClH,QAAQ,EAAE,OAAO,IAAI,OAAO,GAC5B,IACE,EAEN,iBACE,IAAI,EAAC,QAAQ,EACb,QAAQ,EAAE,OAAO,IAAI,OAAO,EAC5B,SAAS,EAAC,uHAAuH,YAEhI,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,iBAAiB,GAC7D,IACJ,IACH,CACP,CAAA;AACH,CAAC"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import type { createAuthClient } from 'better-auth/react';
|
|
2
|
+
export type SignInFormProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Better-auth client instance
|
|
5
|
+
* Created with createAuthClient from better-auth/react
|
|
6
|
+
* Pass your client from lib/auth-client.ts
|
|
7
|
+
*/
|
|
8
|
+
authClient: ReturnType<typeof createAuthClient>;
|
|
9
|
+
/**
|
|
10
|
+
* URL to redirect to after successful sign in
|
|
11
|
+
* @default '/'
|
|
12
|
+
*/
|
|
13
|
+
redirectTo?: string;
|
|
14
|
+
/**
|
|
15
|
+
* Show OAuth provider buttons
|
|
16
|
+
* @default true
|
|
17
|
+
*/
|
|
18
|
+
showSocialProviders?: boolean;
|
|
19
|
+
/**
|
|
20
|
+
* Which OAuth providers to show
|
|
21
|
+
* @default ['github', 'google']
|
|
22
|
+
*/
|
|
23
|
+
socialProviders?: string[];
|
|
24
|
+
/**
|
|
25
|
+
* Custom CSS class for the form container
|
|
26
|
+
*/
|
|
27
|
+
className?: string;
|
|
28
|
+
/**
|
|
29
|
+
* Callback when sign in is successful
|
|
30
|
+
*/
|
|
31
|
+
onSuccess?: () => void;
|
|
32
|
+
/**
|
|
33
|
+
* Callback when sign in fails
|
|
34
|
+
*/
|
|
35
|
+
onError?: (error: Error) => void;
|
|
36
|
+
};
|
|
37
|
+
/**
|
|
38
|
+
* Sign in form component
|
|
39
|
+
* Provides email/password sign in and OAuth provider buttons
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* ```typescript
|
|
43
|
+
* import { SignInForm } from '@opensaas/stack-auth/ui'
|
|
44
|
+
* import { authClient } from '@/lib/auth-client'
|
|
45
|
+
*
|
|
46
|
+
* export default function SignInPage() {
|
|
47
|
+
* return <SignInForm authClient={authClient} redirectTo="/admin" />
|
|
48
|
+
* }
|
|
49
|
+
* ```
|
|
50
|
+
*/
|
|
51
|
+
export declare function SignInForm({ authClient, redirectTo, showSocialProviders, socialProviders, className, onSuccess, onError, }: SignInFormProps): import("react/jsx-runtime").JSX.Element;
|
|
52
|
+
//# sourceMappingURL=SignInForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignInForm.d.ts","sourceRoot":"","sources":["../../../src/ui/components/SignInForm.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B;;;;OAIG;IACH,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;IAC/C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,EACzB,UAAU,EACV,UAAgB,EAChB,mBAA0B,EAC1B,eAAsC,EACtC,SAAc,EACd,SAAS,EACT,OAAO,GACR,EAAE,eAAe,2CA+HjB"}
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Sign in form component
|
|
6
|
+
* Provides email/password sign in and OAuth provider buttons
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { SignInForm } from '@opensaas/stack-auth/ui'
|
|
11
|
+
* import { authClient } from '@/lib/auth-client'
|
|
12
|
+
*
|
|
13
|
+
* export default function SignInPage() {
|
|
14
|
+
* return <SignInForm authClient={authClient} redirectTo="/admin" />
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function SignInForm({ authClient, redirectTo = '/', showSocialProviders = true, socialProviders = ['github', 'google'], className = '', onSuccess, onError, }) {
|
|
19
|
+
const [email, setEmail] = useState('');
|
|
20
|
+
const [password, setPassword] = useState('');
|
|
21
|
+
const [error, setError] = useState('');
|
|
22
|
+
const [loading, setLoading] = useState(false);
|
|
23
|
+
const handleSubmit = async (e) => {
|
|
24
|
+
e.preventDefault();
|
|
25
|
+
setError('');
|
|
26
|
+
setLoading(true);
|
|
27
|
+
try {
|
|
28
|
+
const result = await authClient.signIn.email({
|
|
29
|
+
email,
|
|
30
|
+
password,
|
|
31
|
+
callbackURL: redirectTo,
|
|
32
|
+
});
|
|
33
|
+
if (result.error) {
|
|
34
|
+
throw new Error(result.error.message);
|
|
35
|
+
}
|
|
36
|
+
onSuccess?.();
|
|
37
|
+
}
|
|
38
|
+
catch (err) {
|
|
39
|
+
const message = err instanceof Error ? err.message : 'Sign in failed';
|
|
40
|
+
setError(message);
|
|
41
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
42
|
+
}
|
|
43
|
+
finally {
|
|
44
|
+
setLoading(false);
|
|
45
|
+
}
|
|
46
|
+
};
|
|
47
|
+
const handleSocialSignIn = async (provider) => {
|
|
48
|
+
setError('');
|
|
49
|
+
setLoading(true);
|
|
50
|
+
try {
|
|
51
|
+
await authClient.signIn.social({
|
|
52
|
+
provider,
|
|
53
|
+
callbackURL: redirectTo,
|
|
54
|
+
});
|
|
55
|
+
onSuccess?.();
|
|
56
|
+
}
|
|
57
|
+
catch (err) {
|
|
58
|
+
const message = err instanceof Error ? err.message : 'Sign in failed';
|
|
59
|
+
setError(message);
|
|
60
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
61
|
+
setLoading(false);
|
|
62
|
+
}
|
|
63
|
+
};
|
|
64
|
+
return (_jsxs("div", { className: `w-full max-w-md mx-auto p-6 ${className}`, children: [_jsx("h2", { className: "text-2xl font-bold mb-6", children: "Sign In" }), error && (_jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4", children: error })), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "email", className: "block text-sm font-medium mb-2", children: "Email" }), _jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "password", className: "block text-sm font-medium mb-2", children: "Password" }), _jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] }), _jsx("button", { type: "submit", disabled: loading, className: "w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed", children: loading ? 'Signing in...' : 'Sign In' })] }), showSocialProviders && socialProviders.length > 0 && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative my-6", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full border-t border-gray-300" }) }), _jsx("div", { className: "relative flex justify-center text-sm", children: _jsx("span", { className: "px-2 bg-white text-gray-500", children: "Or continue with" }) })] }), _jsx("div", { className: "space-y-2", children: socialProviders.map((provider) => (_jsxs("button", { onClick: () => handleSocialSignIn(provider), disabled: loading, className: "w-full bg-white border border-gray-300 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-50 disabled:bg-gray-100 disabled:cursor-not-allowed", children: ["Sign in with ", provider.charAt(0).toUpperCase() + provider.slice(1)] }, provider))) })] }))] }));
|
|
65
|
+
}
|
|
66
|
+
//# sourceMappingURL=SignInForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignInForm.js","sourceRoot":"","sources":["../../../src/ui/components/SignInForm.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { createAuthClient } from 'better-auth/react';
|
|
2
|
+
export type SignUpFormProps = {
|
|
3
|
+
/**
|
|
4
|
+
* Better-auth client instance
|
|
5
|
+
* Created with createAuthClient from better-auth/react
|
|
6
|
+
*/
|
|
7
|
+
authClient: ReturnType<typeof createAuthClient>;
|
|
8
|
+
/**
|
|
9
|
+
* URL to redirect to after successful sign up
|
|
10
|
+
* @default '/'
|
|
11
|
+
*/
|
|
12
|
+
redirectTo?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Show OAuth provider buttons
|
|
15
|
+
* @default true
|
|
16
|
+
*/
|
|
17
|
+
showSocialProviders?: boolean;
|
|
18
|
+
/**
|
|
19
|
+
* Which OAuth providers to show
|
|
20
|
+
* @default ['github', 'google']
|
|
21
|
+
*/
|
|
22
|
+
socialProviders?: string[];
|
|
23
|
+
/**
|
|
24
|
+
* Require password confirmation
|
|
25
|
+
* @default true
|
|
26
|
+
*/
|
|
27
|
+
requirePasswordConfirmation?: boolean;
|
|
28
|
+
/**
|
|
29
|
+
* Custom CSS class for the form container
|
|
30
|
+
*/
|
|
31
|
+
className?: string;
|
|
32
|
+
/**
|
|
33
|
+
* Callback when sign up is successful
|
|
34
|
+
*/
|
|
35
|
+
onSuccess?: () => void;
|
|
36
|
+
/**
|
|
37
|
+
* Callback when sign up fails
|
|
38
|
+
*/
|
|
39
|
+
onError?: (error: Error) => void;
|
|
40
|
+
};
|
|
41
|
+
/**
|
|
42
|
+
* Sign up form component
|
|
43
|
+
* Provides email/password registration and OAuth provider buttons
|
|
44
|
+
*
|
|
45
|
+
* @example
|
|
46
|
+
* ```typescript
|
|
47
|
+
* import { SignUpForm } from '@opensaas/stack-auth/ui'
|
|
48
|
+
* import { authClient } from '@/lib/auth-client'
|
|
49
|
+
*
|
|
50
|
+
* export default function SignUpPage() {
|
|
51
|
+
* return <SignUpForm authClient={authClient} redirectTo="/admin" />
|
|
52
|
+
* }
|
|
53
|
+
* ```
|
|
54
|
+
*/
|
|
55
|
+
export declare function SignUpForm({ authClient, redirectTo, showSocialProviders, socialProviders, requirePasswordConfirmation, className, onSuccess, onError, }: SignUpFormProps): import("react/jsx-runtime").JSX.Element;
|
|
56
|
+
//# sourceMappingURL=SignUpForm.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignUpForm.d.ts","sourceRoot":"","sources":["../../../src/ui/components/SignUpForm.tsx"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,mBAAmB,CAAA;AAEzD,MAAM,MAAM,eAAe,GAAG;IAC5B;;;OAGG;IACH,UAAU,EAAE,UAAU,CAAC,OAAO,gBAAgB,CAAC,CAAA;IAC/C;;;OAGG;IACH,UAAU,CAAC,EAAE,MAAM,CAAA;IACnB;;;OAGG;IACH,mBAAmB,CAAC,EAAE,OAAO,CAAA;IAC7B;;;OAGG;IACH,eAAe,CAAC,EAAE,MAAM,EAAE,CAAA;IAC1B;;;OAGG;IACH,2BAA2B,CAAC,EAAE,OAAO,CAAA;IACrC;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;OAEG;IACH,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB;;OAEG;IACH,OAAO,CAAC,EAAE,CAAC,KAAK,EAAE,KAAK,KAAK,IAAI,CAAA;CACjC,CAAA;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAgB,UAAU,CAAC,EACzB,UAAU,EACV,UAAgB,EAChB,mBAA0B,EAC1B,eAAsC,EACtC,2BAAkC,EAClC,SAAc,EACd,SAAS,EACT,OAAO,GACR,EAAE,eAAe,2CAyKjB"}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { jsx as _jsx, jsxs as _jsxs, Fragment as _Fragment } from "react/jsx-runtime";
|
|
3
|
+
import { useState } from 'react';
|
|
4
|
+
/**
|
|
5
|
+
* Sign up form component
|
|
6
|
+
* Provides email/password registration and OAuth provider buttons
|
|
7
|
+
*
|
|
8
|
+
* @example
|
|
9
|
+
* ```typescript
|
|
10
|
+
* import { SignUpForm } from '@opensaas/stack-auth/ui'
|
|
11
|
+
* import { authClient } from '@/lib/auth-client'
|
|
12
|
+
*
|
|
13
|
+
* export default function SignUpPage() {
|
|
14
|
+
* return <SignUpForm authClient={authClient} redirectTo="/admin" />
|
|
15
|
+
* }
|
|
16
|
+
* ```
|
|
17
|
+
*/
|
|
18
|
+
export function SignUpForm({ authClient, redirectTo = '/', showSocialProviders = true, socialProviders = ['github', 'google'], requirePasswordConfirmation = true, className = '', onSuccess, onError, }) {
|
|
19
|
+
const [name, setName] = useState('');
|
|
20
|
+
const [email, setEmail] = useState('');
|
|
21
|
+
const [password, setPassword] = useState('');
|
|
22
|
+
const [confirmPassword, setConfirmPassword] = useState('');
|
|
23
|
+
const [error, setError] = useState('');
|
|
24
|
+
const [loading, setLoading] = useState(false);
|
|
25
|
+
const handleSubmit = async (e) => {
|
|
26
|
+
e.preventDefault();
|
|
27
|
+
setError('');
|
|
28
|
+
// Validate password confirmation
|
|
29
|
+
if (requirePasswordConfirmation && password !== confirmPassword) {
|
|
30
|
+
setError('Passwords do not match');
|
|
31
|
+
return;
|
|
32
|
+
}
|
|
33
|
+
setLoading(true);
|
|
34
|
+
try {
|
|
35
|
+
const result = await authClient.signUp.email({
|
|
36
|
+
email,
|
|
37
|
+
password,
|
|
38
|
+
name,
|
|
39
|
+
callbackURL: redirectTo,
|
|
40
|
+
});
|
|
41
|
+
if (result.error) {
|
|
42
|
+
throw new Error(result.error.message);
|
|
43
|
+
}
|
|
44
|
+
onSuccess?.();
|
|
45
|
+
}
|
|
46
|
+
catch (err) {
|
|
47
|
+
const message = err instanceof Error ? err.message : 'Sign up failed';
|
|
48
|
+
setError(message);
|
|
49
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
50
|
+
}
|
|
51
|
+
finally {
|
|
52
|
+
setLoading(false);
|
|
53
|
+
}
|
|
54
|
+
};
|
|
55
|
+
const handleSocialSignUp = async (provider) => {
|
|
56
|
+
setError('');
|
|
57
|
+
setLoading(true);
|
|
58
|
+
try {
|
|
59
|
+
await authClient.signIn.social({
|
|
60
|
+
provider,
|
|
61
|
+
callbackURL: redirectTo,
|
|
62
|
+
});
|
|
63
|
+
onSuccess?.();
|
|
64
|
+
}
|
|
65
|
+
catch (err) {
|
|
66
|
+
const message = err instanceof Error ? err.message : 'Sign up failed';
|
|
67
|
+
setError(message);
|
|
68
|
+
onError?.(err instanceof Error ? err : new Error(message));
|
|
69
|
+
setLoading(false);
|
|
70
|
+
}
|
|
71
|
+
};
|
|
72
|
+
return (_jsxs("div", { className: `w-full max-w-md mx-auto p-6 ${className}`, children: [_jsx("h2", { className: "text-2xl font-bold mb-6", children: "Sign Up" }), error && (_jsx("div", { className: "bg-red-50 border border-red-200 text-red-700 px-4 py-3 rounded mb-4", children: error })), _jsxs("form", { onSubmit: handleSubmit, className: "space-y-4", children: [_jsxs("div", { children: [_jsx("label", { htmlFor: "name", className: "block text-sm font-medium mb-2", children: "Name" }), _jsx("input", { id: "name", type: "text", value: name, onChange: (e) => setName(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "email", className: "block text-sm font-medium mb-2", children: "Email" }), _jsx("input", { id: "email", type: "email", value: email, onChange: (e) => setEmail(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] }), _jsxs("div", { children: [_jsx("label", { htmlFor: "password", className: "block text-sm font-medium mb-2", children: "Password" }), _jsx("input", { id: "password", type: "password", value: password, onChange: (e) => setPassword(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] }), requirePasswordConfirmation && (_jsxs("div", { children: [_jsx("label", { htmlFor: "confirmPassword", className: "block text-sm font-medium mb-2", children: "Confirm Password" }), _jsx("input", { id: "confirmPassword", type: "password", value: confirmPassword, onChange: (e) => setConfirmPassword(e.target.value), required: true, className: "w-full px-3 py-2 border border-gray-300 rounded-md focus:outline-none focus:ring-2 focus:ring-blue-500", disabled: loading })] })), _jsx("button", { type: "submit", disabled: loading, className: "w-full bg-blue-600 text-white py-2 px-4 rounded-md hover:bg-blue-700 disabled:bg-gray-400 disabled:cursor-not-allowed", children: loading ? 'Creating account...' : 'Sign Up' })] }), showSocialProviders && socialProviders.length > 0 && (_jsxs(_Fragment, { children: [_jsxs("div", { className: "relative my-6", children: [_jsx("div", { className: "absolute inset-0 flex items-center", children: _jsx("div", { className: "w-full border-t border-gray-300" }) }), _jsx("div", { className: "relative flex justify-center text-sm", children: _jsx("span", { className: "px-2 bg-white text-gray-500", children: "Or continue with" }) })] }), _jsx("div", { className: "space-y-2", children: socialProviders.map((provider) => (_jsxs("button", { onClick: () => handleSocialSignUp(provider), disabled: loading, className: "w-full bg-white border border-gray-300 text-gray-700 py-2 px-4 rounded-md hover:bg-gray-50 disabled:bg-gray-100 disabled:cursor-not-allowed", children: ["Sign up with ", provider.charAt(0).toUpperCase() + provider.slice(1)] }, provider))) })] }))] }));
|
|
73
|
+
}
|
|
74
|
+
//# sourceMappingURL=SignUpForm.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"SignUpForm.js","sourceRoot":"","sources":["../../../src/ui/components/SignUpForm.tsx"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
export { SignInForm } from './components/SignInForm.js';
|
|
2
|
+
export { SignUpForm } from './components/SignUpForm.js';
|
|
3
|
+
export { ForgotPasswordForm } from './components/ForgotPasswordForm.js';
|
|
4
|
+
export type { SignInFormProps } from './components/SignInForm.js';
|
|
5
|
+
export type { SignUpFormProps } from './components/SignUpForm.js';
|
|
6
|
+
export type { ForgotPasswordFormProps } from './components/ForgotPasswordForm.js';
|
|
7
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA;AAEvE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,YAAY,EAAE,eAAe,EAAE,MAAM,4BAA4B,CAAA;AACjE,YAAY,EAAE,uBAAuB,EAAE,MAAM,oCAAoC,CAAA"}
|
package/dist/ui/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/ui/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,UAAU,EAAE,MAAM,4BAA4B,CAAA;AACvD,OAAO,EAAE,kBAAkB,EAAE,MAAM,oCAAoC,CAAA"}
|
package/package.json
ADDED
|
@@ -0,0 +1,55 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@opensaas/stack-auth",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Better-auth integration for OpenSaas Stack",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "./dist/index.js",
|
|
7
|
+
"types": "./dist/index.d.ts",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": {
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"default": "./dist/index.js"
|
|
12
|
+
},
|
|
13
|
+
"./server": {
|
|
14
|
+
"types": "./dist/server/index.d.ts",
|
|
15
|
+
"default": "./dist/server/index.js"
|
|
16
|
+
},
|
|
17
|
+
"./client": {
|
|
18
|
+
"types": "./dist/client/index.d.ts",
|
|
19
|
+
"default": "./dist/client/index.js"
|
|
20
|
+
},
|
|
21
|
+
"./ui": {
|
|
22
|
+
"types": "./dist/ui/index.d.ts",
|
|
23
|
+
"default": "./dist/ui/index.js"
|
|
24
|
+
}
|
|
25
|
+
},
|
|
26
|
+
"keywords": [
|
|
27
|
+
"opensaas",
|
|
28
|
+
"better-auth",
|
|
29
|
+
"authentication",
|
|
30
|
+
"nextjs"
|
|
31
|
+
],
|
|
32
|
+
"author": "",
|
|
33
|
+
"license": "MIT",
|
|
34
|
+
"peerDependencies": {
|
|
35
|
+
"better-auth": "^1.3.29",
|
|
36
|
+
"react": "^18.0.0 || ^19.0.0",
|
|
37
|
+
"next": "^15.0.0 || ^16.0.0",
|
|
38
|
+
"@opensaas/stack-core": "0.1.0"
|
|
39
|
+
},
|
|
40
|
+
"dependencies": {},
|
|
41
|
+
"devDependencies": {
|
|
42
|
+
"@types/node": "^24.7.2",
|
|
43
|
+
"@types/react": "^19.2.2",
|
|
44
|
+
"better-auth": "^1.3.29",
|
|
45
|
+
"next": "^16.0.0",
|
|
46
|
+
"react": "^19.2.0",
|
|
47
|
+
"typescript": "^5.9.3",
|
|
48
|
+
"@opensaas/stack-core": "0.1.0"
|
|
49
|
+
},
|
|
50
|
+
"scripts": {
|
|
51
|
+
"build": "tsc",
|
|
52
|
+
"dev": "tsc --watch",
|
|
53
|
+
"clean": "rm -rf .turbo dist tsconfig.tsbuildinfo"
|
|
54
|
+
}
|
|
55
|
+
}
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
import { createAuthClient } from 'better-auth/react'
|
|
4
|
+
import type { Session } from 'better-auth/types'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Create a better-auth client for use in React components
|
|
8
|
+
* This should be called once and the result exported
|
|
9
|
+
*
|
|
10
|
+
* @example
|
|
11
|
+
* ```typescript
|
|
12
|
+
* // lib/auth-client.ts
|
|
13
|
+
* 'use client'
|
|
14
|
+
* import { createClient } from '@opensaas/stack-auth/client'
|
|
15
|
+
*
|
|
16
|
+
* export const authClient = createClient({
|
|
17
|
+
* baseURL: process.env.NEXT_PUBLIC_APP_URL || 'http://localhost:3000'
|
|
18
|
+
* })
|
|
19
|
+
* ```
|
|
20
|
+
*/
|
|
21
|
+
export function createClient(options: { baseURL: string }): ReturnType<typeof createAuthClient> {
|
|
22
|
+
return createAuthClient({
|
|
23
|
+
baseURL: options.baseURL,
|
|
24
|
+
})
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/**
|
|
28
|
+
* Re-export useful types from better-auth
|
|
29
|
+
*/
|
|
30
|
+
export type { Session }
|
|
31
|
+
|
|
32
|
+
/**
|
|
33
|
+
* Note: React hooks (useSession, etc.) are accessed from the client instance
|
|
34
|
+
*
|
|
35
|
+
* @example
|
|
36
|
+
* ```typescript
|
|
37
|
+
* import { authClient } from '@/lib/auth-client'
|
|
38
|
+
*
|
|
39
|
+
* function MyComponent() {
|
|
40
|
+
* const { data: session } = authClient.useSession()
|
|
41
|
+
* // ...
|
|
42
|
+
* }
|
|
43
|
+
* ```
|
|
44
|
+
*/
|
|
@@ -0,0 +1,140 @@
|
|
|
1
|
+
import type { OpenSaasConfig } from '@opensaas/stack-core'
|
|
2
|
+
import type {
|
|
3
|
+
AuthConfig,
|
|
4
|
+
NormalizedAuthConfig,
|
|
5
|
+
EmailPasswordConfig,
|
|
6
|
+
EmailVerificationConfig,
|
|
7
|
+
PasswordResetConfig,
|
|
8
|
+
} from './types.js'
|
|
9
|
+
import { getAuthLists } from '../lists/index.js'
|
|
10
|
+
|
|
11
|
+
/**
|
|
12
|
+
* Normalize auth configuration with defaults
|
|
13
|
+
*/
|
|
14
|
+
export function normalizeAuthConfig(config: AuthConfig): NormalizedAuthConfig {
|
|
15
|
+
// Email and password defaults
|
|
16
|
+
const emailAndPassword = config.emailAndPassword?.enabled
|
|
17
|
+
? {
|
|
18
|
+
enabled: true as const,
|
|
19
|
+
minPasswordLength: (config.emailAndPassword as EmailPasswordConfig).minPasswordLength ?? 8,
|
|
20
|
+
requireConfirmation:
|
|
21
|
+
(config.emailAndPassword as EmailPasswordConfig).requireConfirmation ?? true,
|
|
22
|
+
}
|
|
23
|
+
: { enabled: false as const, minPasswordLength: 8, requireConfirmation: true }
|
|
24
|
+
|
|
25
|
+
// Email verification defaults
|
|
26
|
+
const emailVerification = config.emailVerification?.enabled
|
|
27
|
+
? {
|
|
28
|
+
enabled: true as const,
|
|
29
|
+
sendOnSignUp: (config.emailVerification as EmailVerificationConfig).sendOnSignUp ?? true,
|
|
30
|
+
tokenExpiration:
|
|
31
|
+
(config.emailVerification as EmailVerificationConfig).tokenExpiration ?? 86400,
|
|
32
|
+
}
|
|
33
|
+
: { enabled: false as const, sendOnSignUp: true, tokenExpiration: 86400 }
|
|
34
|
+
|
|
35
|
+
// Password reset defaults
|
|
36
|
+
const passwordReset = config.passwordReset?.enabled
|
|
37
|
+
? {
|
|
38
|
+
enabled: true as const,
|
|
39
|
+
tokenExpiration: (config.passwordReset as PasswordResetConfig).tokenExpiration ?? 3600,
|
|
40
|
+
}
|
|
41
|
+
: { enabled: false as const, tokenExpiration: 3600 }
|
|
42
|
+
|
|
43
|
+
// Session defaults
|
|
44
|
+
const session = {
|
|
45
|
+
expiresIn: config.session?.expiresIn || 604800, // 7 days
|
|
46
|
+
updateAge: config.session?.updateAge ?? true,
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
// Session fields defaults
|
|
50
|
+
const sessionFields = config.sessionFields || ['userId', 'email', 'name']
|
|
51
|
+
|
|
52
|
+
return {
|
|
53
|
+
emailAndPassword,
|
|
54
|
+
emailVerification,
|
|
55
|
+
passwordReset,
|
|
56
|
+
socialProviders: config.socialProviders || {},
|
|
57
|
+
session,
|
|
58
|
+
sessionFields,
|
|
59
|
+
extendUserList: config.extendUserList || {},
|
|
60
|
+
sendEmail:
|
|
61
|
+
config.sendEmail ||
|
|
62
|
+
(async ({ to, subject, html }) => {
|
|
63
|
+
console.log('[Auth] Email not sent (no sendEmail configured):')
|
|
64
|
+
console.log(`To: ${to}`)
|
|
65
|
+
console.log(`Subject: ${subject}`)
|
|
66
|
+
console.log(`Body: ${html}`)
|
|
67
|
+
}),
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Auth configuration builder
|
|
73
|
+
* Use this to create an auth configuration object
|
|
74
|
+
*
|
|
75
|
+
* @example
|
|
76
|
+
* ```typescript
|
|
77
|
+
* import { authConfig } from '@opensaas/stack-auth'
|
|
78
|
+
*
|
|
79
|
+
* const auth = authConfig({
|
|
80
|
+
* emailAndPassword: { enabled: true },
|
|
81
|
+
* emailVerification: { enabled: true },
|
|
82
|
+
* socialProviders: {
|
|
83
|
+
* github: { clientId: '...', clientSecret: '...' }
|
|
84
|
+
* }
|
|
85
|
+
* })
|
|
86
|
+
* ```
|
|
87
|
+
*/
|
|
88
|
+
export function authConfig(config: AuthConfig): AuthConfig {
|
|
89
|
+
return config
|
|
90
|
+
}
|
|
91
|
+
|
|
92
|
+
/**
|
|
93
|
+
* Wrap an OpenSaas config with better-auth integration
|
|
94
|
+
* This merges the auth lists into the user's config and sets up session handling
|
|
95
|
+
*
|
|
96
|
+
* @example
|
|
97
|
+
* ```typescript
|
|
98
|
+
* import { config } from '@opensaas/stack-core'
|
|
99
|
+
* import { withAuth, authConfig } from '@opensaas/stack-auth'
|
|
100
|
+
*
|
|
101
|
+
* export default withAuth(
|
|
102
|
+
* config({
|
|
103
|
+
* db: { provider: 'sqlite', url: 'file:./dev.db' },
|
|
104
|
+
* lists: {
|
|
105
|
+
* Post: list({ ... })
|
|
106
|
+
* }
|
|
107
|
+
* }),
|
|
108
|
+
* authConfig({
|
|
109
|
+
* emailAndPassword: { enabled: true }
|
|
110
|
+
* })
|
|
111
|
+
* )
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export function withAuth(opensaasConfig: OpenSaasConfig, authConfig: AuthConfig): OpenSaasConfig {
|
|
115
|
+
const normalized = normalizeAuthConfig(authConfig)
|
|
116
|
+
|
|
117
|
+
// Get auth lists with user extensions
|
|
118
|
+
const authLists = getAuthLists(normalized.extendUserList)
|
|
119
|
+
|
|
120
|
+
// Merge auth lists with user lists (auth lists take priority)
|
|
121
|
+
const mergedLists = {
|
|
122
|
+
...opensaasConfig.lists,
|
|
123
|
+
...authLists,
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
// Return merged config with auth config attached
|
|
127
|
+
// Note: Session integration happens in the generator/context
|
|
128
|
+
const result: OpenSaasConfig & { __authConfig?: NormalizedAuthConfig } = {
|
|
129
|
+
...opensaasConfig,
|
|
130
|
+
lists: mergedLists,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// Store auth config for internal use
|
|
134
|
+
result.__authConfig = normalized
|
|
135
|
+
|
|
136
|
+
return result
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
export type { AuthConfig, NormalizedAuthConfig }
|
|
140
|
+
export * from './types.js'
|