@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.
Files changed (56) hide show
  1. package/.turbo/turbo-build.log +4 -0
  2. package/INTEGRATION_SUMMARY.md +425 -0
  3. package/README.md +445 -0
  4. package/dist/client/index.d.ts +38 -0
  5. package/dist/client/index.d.ts.map +1 -0
  6. package/dist/client/index.js +23 -0
  7. package/dist/client/index.js.map +1 -0
  8. package/dist/config/index.d.ts +50 -0
  9. package/dist/config/index.d.ts.map +1 -0
  10. package/dist/config/index.js +115 -0
  11. package/dist/config/index.js.map +1 -0
  12. package/dist/config/types.d.ts +160 -0
  13. package/dist/config/types.d.ts.map +1 -0
  14. package/dist/config/types.js +2 -0
  15. package/dist/config/types.js.map +1 -0
  16. package/dist/index.d.ts +35 -0
  17. package/dist/index.d.ts.map +1 -0
  18. package/dist/index.js +34 -0
  19. package/dist/index.js.map +1 -0
  20. package/dist/lists/index.d.ts +46 -0
  21. package/dist/lists/index.d.ts.map +1 -0
  22. package/dist/lists/index.js +227 -0
  23. package/dist/lists/index.js.map +1 -0
  24. package/dist/server/index.d.ts +27 -0
  25. package/dist/server/index.d.ts.map +1 -0
  26. package/dist/server/index.js +90 -0
  27. package/dist/server/index.js.map +1 -0
  28. package/dist/ui/components/ForgotPasswordForm.d.ts +36 -0
  29. package/dist/ui/components/ForgotPasswordForm.d.ts.map +1 -0
  30. package/dist/ui/components/ForgotPasswordForm.js +50 -0
  31. package/dist/ui/components/ForgotPasswordForm.js.map +1 -0
  32. package/dist/ui/components/SignInForm.d.ts +52 -0
  33. package/dist/ui/components/SignInForm.d.ts.map +1 -0
  34. package/dist/ui/components/SignInForm.js +66 -0
  35. package/dist/ui/components/SignInForm.js.map +1 -0
  36. package/dist/ui/components/SignUpForm.d.ts +56 -0
  37. package/dist/ui/components/SignUpForm.d.ts.map +1 -0
  38. package/dist/ui/components/SignUpForm.js +74 -0
  39. package/dist/ui/components/SignUpForm.js.map +1 -0
  40. package/dist/ui/index.d.ts +7 -0
  41. package/dist/ui/index.d.ts.map +1 -0
  42. package/dist/ui/index.js +4 -0
  43. package/dist/ui/index.js.map +1 -0
  44. package/package.json +55 -0
  45. package/src/client/index.ts +44 -0
  46. package/src/config/index.ts +140 -0
  47. package/src/config/types.ts +166 -0
  48. package/src/index.ts +44 -0
  49. package/src/lists/index.ts +245 -0
  50. package/src/server/index.ts +120 -0
  51. package/src/ui/components/ForgotPasswordForm.tsx +120 -0
  52. package/src/ui/components/SignInForm.tsx +191 -0
  53. package/src/ui/components/SignUpForm.tsx +238 -0
  54. package/src/ui/index.ts +7 -0
  55. package/tsconfig.json +14 -0
  56. 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"}
@@ -0,0 +1,4 @@
1
+ export { SignInForm } from './components/SignInForm.js';
2
+ export { SignUpForm } from './components/SignUpForm.js';
3
+ export { ForgotPasswordForm } from './components/ForgotPasswordForm.js';
4
+ //# sourceMappingURL=index.js.map
@@ -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'