@beamarco/auth-sdk 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 (41) hide show
  1. package/README.md +163 -0
  2. package/dist/client.d.ts +59 -0
  3. package/dist/client.d.ts.map +1 -0
  4. package/dist/client.js +149 -0
  5. package/dist/components/ProtectedRoute.d.ts +13 -0
  6. package/dist/components/ProtectedRoute.d.ts.map +1 -0
  7. package/dist/components/ProtectedRoute.js +21 -0
  8. package/dist/components/SignIn.d.ts +87 -0
  9. package/dist/components/SignIn.d.ts.map +1 -0
  10. package/dist/components/SignIn.js +149 -0
  11. package/dist/components/SignInButton.d.ts +13 -0
  12. package/dist/components/SignInButton.d.ts.map +1 -0
  13. package/dist/components/SignInButton.js +14 -0
  14. package/dist/components/SignUp.d.ts +79 -0
  15. package/dist/components/SignUp.d.ts.map +1 -0
  16. package/dist/components/SignUp.js +143 -0
  17. package/dist/components/SignUpButton.d.ts +13 -0
  18. package/dist/components/SignUpButton.d.ts.map +1 -0
  19. package/dist/components/SignUpButton.js +14 -0
  20. package/dist/components/SignedIn.d.ts +9 -0
  21. package/dist/components/SignedIn.d.ts.map +1 -0
  22. package/dist/components/SignedIn.js +13 -0
  23. package/dist/components/SignedOut.d.ts +9 -0
  24. package/dist/components/SignedOut.d.ts.map +1 -0
  25. package/dist/components/SignedOut.js +13 -0
  26. package/dist/components/UserButton.d.ts +13 -0
  27. package/dist/components/UserButton.d.ts.map +1 -0
  28. package/dist/components/UserButton.js +64 -0
  29. package/dist/context.d.ts +29 -0
  30. package/dist/context.d.ts.map +1 -0
  31. package/dist/context.js +88 -0
  32. package/dist/hooks.d.ts +13 -0
  33. package/dist/hooks.d.ts.map +1 -0
  34. package/dist/hooks.js +22 -0
  35. package/dist/index.d.ts +48 -0
  36. package/dist/index.d.ts.map +1 -0
  37. package/dist/index.js +46 -0
  38. package/dist/types.d.ts +61 -0
  39. package/dist/types.d.ts.map +1 -0
  40. package/dist/types.js +8 -0
  41. package/package.json +56 -0
package/README.md ADDED
@@ -0,0 +1,163 @@
1
+ # @beamarco/auth-sdk
2
+
3
+ Embed authentication like Clerk in your React apps. Works with the Beamar auth-service backend.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ npm install @beamarco/auth-sdk
9
+ ```
10
+
11
+ ## Quick Start
12
+
13
+ ### 1. Wrap your app with BeamarAuthProvider
14
+
15
+ ```tsx
16
+ import { BeamarAuthProvider } from '@beamarco/auth-sdk'
17
+
18
+ const config = {
19
+ apiUrl: 'https://auth.creztu.com', // or your auth-service URL
20
+ appName: 'my-app', // e.g. GOMEDI, developers-portal
21
+ googleClientId: 'xxx.apps.googleusercontent.com', // optional, for Google Sign In
22
+ }
23
+
24
+ function App() {
25
+ return (
26
+ <BeamarAuthProvider config={config}>
27
+ <YourApp />
28
+ </BeamarAuthProvider>
29
+ )
30
+ }
31
+ ```
32
+
33
+ ### 2. Use SignedIn / SignedOut for conditional rendering
34
+
35
+ ```tsx
36
+ import { SignedIn, SignedOut, SignIn, SignUp } from '@beamarco/auth-sdk'
37
+
38
+ function App() {
39
+ return (
40
+ <>
41
+ <SignedIn>
42
+ <Dashboard />
43
+ </SignedIn>
44
+ <SignedOut>
45
+ <SignIn signUpUrl="/sign-up" />
46
+ </SignedOut>
47
+ </>
48
+ )
49
+ }
50
+ ```
51
+
52
+ ### 3. Add routes (e.g. with React Router)
53
+
54
+ ```tsx
55
+ import { Routes, Route, Navigate } from 'react-router-dom'
56
+ import {
57
+ BeamarAuthProvider,
58
+ SignIn,
59
+ SignUp,
60
+ SignedIn,
61
+ SignedOut,
62
+ useAuth,
63
+ } from '@beamarco/auth-sdk'
64
+
65
+ function ProtectedRoute({ children }) {
66
+ const { isLoaded, isSignedIn } = useAuth()
67
+ if (!isLoaded) return <Spinner />
68
+ if (!isSignedIn) return <Navigate to="/sign-in" replace />
69
+ return children
70
+ }
71
+
72
+ function AuthRoute({ children }) {
73
+ const { isLoaded, isSignedIn } = useAuth()
74
+ if (!isLoaded) return <Spinner />
75
+ if (isSignedIn) return <Navigate to="/" replace />
76
+ return children
77
+ }
78
+
79
+ function App() {
80
+ return (
81
+ <BeamarAuthProvider config={config}>
82
+ <Routes>
83
+ <Route path="/" element={
84
+ <ProtectedRoute><Home /></ProtectedRoute>
85
+ } />
86
+ <Route path="/sign-in" element={
87
+ <AuthRoute><SignIn /></AuthRoute>
88
+ } />
89
+ <Route path="/sign-up" element={
90
+ <AuthRoute><SignUp /></AuthRoute>
91
+ } />
92
+ </Routes>
93
+ </BeamarAuthProvider>
94
+ )
95
+ }
96
+ ```
97
+
98
+ ## API
99
+
100
+ ### Components
101
+
102
+ | Component | Description |
103
+ |-----------|-------------|
104
+ | `BeamarAuthProvider` | Wrap your app; provides auth context |
105
+ | `SignIn` | Email/password + Google sign-in form |
106
+ | `SignUp` | Email/password + Google sign-up form |
107
+ | `SignedIn` | Renders children only when signed in |
108
+ | `SignedOut` | Renders children only when signed out |
109
+ | `SignInButton` | Link/button to sign-in page |
110
+ | `SignUpButton` | Link/button to sign-up page |
111
+ | `UserButton` | User avatar/menu with sign out |
112
+ | `ProtectedRoute` | Redirects to sign-in when not authenticated |
113
+
114
+ ### Hooks
115
+
116
+ | Hook | Description |
117
+ |------|-------------|
118
+ | `useAuth()` | Full auth context (signIn, signOut, user, etc.) |
119
+ | `useUser()` | Current user and loading state |
120
+
121
+ ### Config
122
+
123
+ ```ts
124
+ interface BeamarAuthConfig {
125
+ apiUrl: string // auth-service base URL
126
+ appName: string // application name (multi-tenant)
127
+ googleClientId?: string // for Google OAuth
128
+ parentUrl?: string // for password reset redirect
129
+ }
130
+ ```
131
+
132
+ ## CORS & Cookies
133
+
134
+ The auth-service uses **httpOnly cookies** for sessions. Ensure:
135
+
136
+ 1. **Same origin** or **CORS with credentials**: Your frontend and auth-service must allow `credentials: 'include'`.
137
+ 2. **auth-service CORS**: Set `APP_CORS` env var to include your frontend origin(s).
138
+ 3. **Cookie domain**: In production, auth-service may set `domain` for cross-subdomain cookies (e.g. `.creztu.com`).
139
+
140
+ ## Developers Portal & Creztu
141
+
142
+ To protect developers-portal or embed auth in the Creztu portal:
143
+
144
+ ```tsx
145
+ // developers-portal - replace Clerk with Beamar Auth
146
+ import { BeamarAuthProvider, SignIn, SignedIn, SignedOut, UserButton } from '@beamarco/auth-sdk'
147
+
148
+ const config = {
149
+ apiUrl: process.env.VITE_AUTH_API_URL,
150
+ appName: 'developers-portal',
151
+ googleClientId: process.env.VITE_GOOGLE_CLIENT_ID,
152
+ }
153
+
154
+ <BeamarAuthProvider config={config}>
155
+ <SignedIn>
156
+ <UserButton />
157
+ <MainContent />
158
+ </SignedIn>
159
+ <SignedOut>
160
+ <SignIn />
161
+ </SignedOut>
162
+ </BeamarAuthProvider>
163
+ ```
@@ -0,0 +1,59 @@
1
+ import type { User, LoginCredentials, RegisterCredentials, GoogleCredential } from './types';
2
+ export interface BeamarAuthClientOptions {
3
+ apiUrl: string;
4
+ appName: string;
5
+ parentUrl?: string;
6
+ }
7
+ /**
8
+ * Low-level client for Beamar auth-service API.
9
+ * Uses credentials: 'include' for cookie-based sessions.
10
+ */
11
+ export declare class BeamarAuthClient {
12
+ private apiUrl;
13
+ private appName;
14
+ private parentUrl;
15
+ constructor(options: BeamarAuthClientOptions);
16
+ private request;
17
+ /**
18
+ * Login with email and password (Basic auth)
19
+ */
20
+ login(credentials: LoginCredentials): Promise<User>;
21
+ /**
22
+ * Register new account with email and password
23
+ */
24
+ register(credentials: RegisterCredentials): Promise<{
25
+ message: string;
26
+ }>;
27
+ /**
28
+ * Logout (clears session cookie)
29
+ */
30
+ logout(): Promise<void>;
31
+ /**
32
+ * Check if email exists
33
+ */
34
+ validateEmail(loginId: string): Promise<boolean>;
35
+ /**
36
+ * Get current session - returns user if logged in
37
+ * Uses GET /user/preference which returns user info when cookie is valid
38
+ */
39
+ getSession(): Promise<User | null>;
40
+ /**
41
+ * Login with Google OAuth credential
42
+ */
43
+ loginWithGoogle(credential: GoogleCredential): Promise<User>;
44
+ /**
45
+ * Register with Google OAuth credential
46
+ */
47
+ registerWithGoogle(credential: GoogleCredential): Promise<{
48
+ message: string;
49
+ }>;
50
+ /**
51
+ * Request password reset email
52
+ */
53
+ requestPasswordReset(loginId: string): Promise<void>;
54
+ /**
55
+ * Update password with reset token
56
+ */
57
+ updatePassword(key: string, password: string): Promise<void>;
58
+ }
59
+ //# sourceMappingURL=client.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,IAAI,EAAE,gBAAgB,EAAE,mBAAmB,EAAE,gBAAgB,EAAE,MAAM,SAAS,CAAA;AAG5F,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAA;IACd,OAAO,EAAE,MAAM,CAAA;IACf,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;;GAGG;AACH,qBAAa,gBAAgB;IAC3B,OAAO,CAAC,MAAM,CAAQ;IACtB,OAAO,CAAC,OAAO,CAAQ;IACvB,OAAO,CAAC,SAAS,CAAQ;gBAEb,OAAO,EAAE,uBAAuB;YAM9B,OAAO;IAoCrB;;OAEG;IACG,KAAK,CAAC,WAAW,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWzD;;OAEG;IACG,QAAQ,CAAC,WAAW,EAAE,mBAAmB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAW9E;;OAEG;IACG,MAAM,IAAI,OAAO,CAAC,IAAI,CAAC;IAI7B;;OAEG;IACG,aAAa,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,OAAO,CAAC;IAQtD;;;OAGG;IACG,UAAU,IAAI,OAAO,CAAC,IAAI,GAAG,IAAI,CAAC;IAwBxC;;OAEG;IACG,eAAe,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAWlE;;OAEG;IACG,kBAAkB,CAAC,UAAU,EAAE,gBAAgB,GAAG,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;IAYpF;;OAEG;IACG,oBAAoB,CAAC,OAAO,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;IAQ1D;;OAEG;IACG,cAAc,CAAC,GAAG,EAAE,MAAM,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC;CAMnE"}
package/dist/client.js ADDED
@@ -0,0 +1,149 @@
1
+ import { AuthError } from './types';
2
+ /**
3
+ * Low-level client for Beamar auth-service API.
4
+ * Uses credentials: 'include' for cookie-based sessions.
5
+ */
6
+ export class BeamarAuthClient {
7
+ constructor(options) {
8
+ this.apiUrl = options.apiUrl.replace(/\/$/, '');
9
+ this.appName = options.appName;
10
+ this.parentUrl = options.parentUrl ?? (typeof window !== 'undefined' ? window.location.origin : '');
11
+ }
12
+ async request(path, options = {}) {
13
+ const { params, ...fetchOptions } = options;
14
+ const url = new URL(`${this.apiUrl}${path}`);
15
+ if (params) {
16
+ Object.entries(params).forEach(([k, v]) => url.searchParams.set(k, v));
17
+ }
18
+ const res = await fetch(url.toString(), {
19
+ ...fetchOptions,
20
+ credentials: 'include',
21
+ headers: {
22
+ 'Content-Type': 'application/json',
23
+ ...fetchOptions.headers,
24
+ },
25
+ });
26
+ if (!res.ok) {
27
+ const body = await res.json().catch(() => ({}));
28
+ const message = body?.message ??
29
+ body?.error ??
30
+ res.statusText ??
31
+ 'Request failed';
32
+ throw new AuthError(message, res.status, body?.code);
33
+ }
34
+ if (res.status === 204 || res.headers.get('content-length') === '0') {
35
+ return {};
36
+ }
37
+ return res.json();
38
+ }
39
+ /**
40
+ * Login with email and password (Basic auth)
41
+ */
42
+ async login(credentials) {
43
+ const basic = btoa(`${credentials.email}:${credentials.password}`);
44
+ return this.request('/auth/login', {
45
+ method: 'POST',
46
+ params: { appName: this.appName },
47
+ headers: {
48
+ Authorization: `Basic ${basic}`,
49
+ },
50
+ });
51
+ }
52
+ /**
53
+ * Register new account with email and password
54
+ */
55
+ async register(credentials) {
56
+ const res = await this.request('/auth/register', {
57
+ method: 'POST',
58
+ body: JSON.stringify({
59
+ email: credentials.email,
60
+ password: credentials.password,
61
+ }),
62
+ });
63
+ return { message: res.message ?? 'Account created' };
64
+ }
65
+ /**
66
+ * Logout (clears session cookie)
67
+ */
68
+ async logout() {
69
+ await this.request('/auth/logout', { method: 'GET' });
70
+ }
71
+ /**
72
+ * Check if email exists
73
+ */
74
+ async validateEmail(loginId) {
75
+ const res = await this.request('/auth/validate', {
76
+ method: 'POST',
77
+ body: JSON.stringify({ loginId }),
78
+ });
79
+ return res === true;
80
+ }
81
+ /**
82
+ * Get current session - returns user if logged in
83
+ * Uses GET /user/preference which returns user info when cookie is valid
84
+ */
85
+ async getSession() {
86
+ try {
87
+ const res = await this.request('/user/preference', { method: 'GET' });
88
+ if (!res || !res.email)
89
+ return null;
90
+ return {
91
+ id: res.id ?? '',
92
+ loginId: res.email,
93
+ displayName: res.displayName,
94
+ imageUrl: res.imageUrl,
95
+ cellphone: res.cellphone,
96
+ tenants: [],
97
+ };
98
+ }
99
+ catch {
100
+ return null;
101
+ }
102
+ }
103
+ /**
104
+ * Login with Google OAuth credential
105
+ */
106
+ async loginWithGoogle(credential) {
107
+ return this.request('/goauth/login', {
108
+ method: 'POST',
109
+ params: { appName: this.appName },
110
+ body: JSON.stringify({
111
+ tokenId: credential.credential,
112
+ googleId: credential.clientId,
113
+ }),
114
+ });
115
+ }
116
+ /**
117
+ * Register with Google OAuth credential
118
+ */
119
+ async registerWithGoogle(credential) {
120
+ const res = await this.request('/goauth/register', {
121
+ method: 'POST',
122
+ params: { appName: this.appName },
123
+ body: JSON.stringify({
124
+ tokenId: credential.credential,
125
+ googleId: credential.clientId,
126
+ }),
127
+ });
128
+ return { message: res.message ?? 'Account created' };
129
+ }
130
+ /**
131
+ * Request password reset email
132
+ */
133
+ async requestPasswordReset(loginId) {
134
+ await this.request('/auth/password-request', {
135
+ method: 'POST',
136
+ params: { parentUrl: this.parentUrl, appName: this.appName },
137
+ body: JSON.stringify({ loginId }),
138
+ });
139
+ }
140
+ /**
141
+ * Update password with reset token
142
+ */
143
+ async updatePassword(key, password) {
144
+ await this.request('/auth/password-request', {
145
+ method: 'PUT',
146
+ body: JSON.stringify({ key, password }),
147
+ });
148
+ }
149
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ export interface ProtectedRouteProps {
3
+ children: React.ReactNode;
4
+ /** Redirect to this path when not signed in */
5
+ fallbackRedirectUrl?: string;
6
+ /** Custom loading component */
7
+ loading?: React.ReactNode;
8
+ }
9
+ /**
10
+ * Protects routes - redirects to sign-in when not authenticated
11
+ */
12
+ export declare function ProtectedRoute({ children, fallbackRedirectUrl, loading, }: ProtectedRouteProps): import("react/jsx-runtime").JSX.Element | null;
13
+ //# sourceMappingURL=ProtectedRoute.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"ProtectedRoute.d.ts","sourceRoot":"","sources":["../../src/components/ProtectedRoute.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,WAAW,mBAAmB;IAClC,QAAQ,EAAE,KAAK,CAAC,SAAS,CAAA;IACzB,+CAA+C;IAC/C,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,+BAA+B;IAC/B,OAAO,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;CAC1B;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,EAC7B,QAAQ,EACR,mBAAgC,EAChC,OAAO,GACR,EAAE,mBAAmB,kDAqBrB"}
@@ -0,0 +1,21 @@
1
+ import { Fragment as _Fragment, jsx as _jsx } from "react/jsx-runtime";
2
+ import { useBeamarAuth } from '../hooks';
3
+ /**
4
+ * Protects routes - redirects to sign-in when not authenticated
5
+ */
6
+ export function ProtectedRoute({ children, fallbackRedirectUrl = '/sign-in', loading, }) {
7
+ const { isLoaded, isSignedIn } = useBeamarAuth();
8
+ if (!isLoaded) {
9
+ if (loading)
10
+ return _jsx(_Fragment, { children: loading });
11
+ return (_jsx("div", { style: { display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px' }, children: "Loading..." }));
12
+ }
13
+ if (!isSignedIn) {
14
+ const to = fallbackRedirectUrl
15
+ ? `${fallbackRedirectUrl}?redirect_url=${encodeURIComponent(window.location.pathname + window.location.search)}`
16
+ : fallbackRedirectUrl;
17
+ window.location.href = to;
18
+ return null;
19
+ }
20
+ return _jsx(_Fragment, { children: children });
21
+ }
@@ -0,0 +1,87 @@
1
+ import React from 'react';
2
+ import type { LoginCredentials } from '../types';
3
+ declare const defaultStyles: {
4
+ container: {
5
+ display: string;
6
+ flexDirection: "column";
7
+ gap: string;
8
+ maxWidth: string;
9
+ padding: string;
10
+ fontFamily: string;
11
+ };
12
+ input: {
13
+ padding: string;
14
+ fontSize: string;
15
+ border: string;
16
+ borderRadius: string;
17
+ width: string;
18
+ boxSizing: "border-box";
19
+ };
20
+ button: {
21
+ padding: string;
22
+ fontSize: string;
23
+ fontWeight: number;
24
+ border: string;
25
+ borderRadius: string;
26
+ cursor: string;
27
+ backgroundColor: string;
28
+ color: string;
29
+ };
30
+ buttonGoogle: {
31
+ padding: string;
32
+ fontSize: string;
33
+ border: string;
34
+ borderRadius: string;
35
+ cursor: string;
36
+ backgroundColor: string;
37
+ color: string;
38
+ };
39
+ error: {
40
+ color: string;
41
+ fontSize: string;
42
+ };
43
+ link: {
44
+ color: string;
45
+ cursor: string;
46
+ textDecoration: string;
47
+ };
48
+ divider: {
49
+ display: string;
50
+ alignItems: string;
51
+ gap: string;
52
+ color: string;
53
+ };
54
+ dividerLine: {
55
+ flex: number;
56
+ height: number;
57
+ backgroundColor: string;
58
+ };
59
+ };
60
+ export interface SignInProps {
61
+ /** Redirect path after sign in (optional - caller handles navigation) */
62
+ afterSignInUrl?: string;
63
+ /** Custom styles */
64
+ styles?: Partial<typeof defaultStyles>;
65
+ /** Show Google sign in button */
66
+ showGoogle?: boolean;
67
+ /** Link to sign up - e.g. /sign-up */
68
+ signUpUrl?: string;
69
+ /** Link to forgot password - e.g. /forgot-password */
70
+ forgotPasswordUrl?: string;
71
+ /** Called after successful sign in */
72
+ onSuccess?: () => void;
73
+ /** Render prop for custom layout */
74
+ children?: (props: SignInRenderProps) => React.ReactNode;
75
+ }
76
+ export interface SignInRenderProps {
77
+ signIn: (credentials: LoginCredentials) => Promise<void>;
78
+ signInWithGoogle: (credential: {
79
+ credential: string;
80
+ clientId: string;
81
+ }) => Promise<void>;
82
+ error: string | null;
83
+ isLoading: boolean;
84
+ }
85
+ export declare function SignIn({ afterSignInUrl, styles: customStyles, showGoogle, signUpUrl, forgotPasswordUrl, onSuccess, children, }: SignInProps): import("react/jsx-runtime").JSX.Element;
86
+ export {};
87
+ //# sourceMappingURL=SignIn.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignIn.d.ts","sourceRoot":"","sources":["../../src/components/SignIn.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAmB,MAAM,OAAO,CAAA;AAEvC,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,UAAU,CAAA;AAEhD,QAAA,MAAM,aAAa;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAwDlB,CAAA;AAED,MAAM,WAAW,WAAW;IAC1B,yEAAyE;IACzE,cAAc,CAAC,EAAE,MAAM,CAAA;IACvB,oBAAoB;IACpB,MAAM,CAAC,EAAE,OAAO,CAAC,OAAO,aAAa,CAAC,CAAA;IACtC,iCAAiC;IACjC,UAAU,CAAC,EAAE,OAAO,CAAA;IACpB,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,sDAAsD;IACtD,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAC1B,sCAAsC;IACtC,SAAS,CAAC,EAAE,MAAM,IAAI,CAAA;IACtB,oCAAoC;IACpC,QAAQ,CAAC,EAAE,CAAC,KAAK,EAAE,iBAAiB,KAAK,KAAK,CAAC,SAAS,CAAA;CACzD;AAED,MAAM,WAAW,iBAAiB;IAChC,MAAM,EAAE,CAAC,WAAW,EAAE,gBAAgB,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxD,gBAAgB,EAAE,CAAC,UAAU,EAAE;QAAE,UAAU,EAAE,MAAM,CAAC;QAAC,QAAQ,EAAE,MAAM,CAAA;KAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACzF,KAAK,EAAE,MAAM,GAAG,IAAI,CAAA;IACpB,SAAS,EAAE,OAAO,CAAA;CACnB;AAED,wBAAgB,MAAM,CAAC,EACrB,cAAc,EACd,MAAM,EAAE,YAAiB,EACzB,UAAiB,EACjB,SAAsB,EACtB,iBAAiB,EACjB,SAAS,EACT,QAAQ,GACT,EAAE,WAAW,2CAoHb"}
@@ -0,0 +1,149 @@
1
+ import { Fragment as _Fragment, jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
+ import React, { useState } from 'react';
3
+ import { useBeamarAuth } from '../hooks';
4
+ const defaultStyles = {
5
+ container: {
6
+ display: 'flex',
7
+ flexDirection: 'column',
8
+ gap: '16px',
9
+ maxWidth: '400px',
10
+ padding: '24px',
11
+ fontFamily: 'system-ui, sans-serif',
12
+ },
13
+ input: {
14
+ padding: '10px 12px',
15
+ fontSize: '16px',
16
+ border: '1px solid #ccc',
17
+ borderRadius: '6px',
18
+ width: '100%',
19
+ boxSizing: 'border-box',
20
+ },
21
+ button: {
22
+ padding: '12px 24px',
23
+ fontSize: '16px',
24
+ fontWeight: 600,
25
+ border: 'none',
26
+ borderRadius: '6px',
27
+ cursor: 'pointer',
28
+ backgroundColor: '#0066cc',
29
+ color: 'white',
30
+ },
31
+ buttonGoogle: {
32
+ padding: '12px 24px',
33
+ fontSize: '16px',
34
+ border: '1px solid #ccc',
35
+ borderRadius: '6px',
36
+ cursor: 'pointer',
37
+ backgroundColor: 'white',
38
+ color: '#333',
39
+ },
40
+ error: {
41
+ color: '#c00',
42
+ fontSize: '14px',
43
+ },
44
+ link: {
45
+ color: '#0066cc',
46
+ cursor: 'pointer',
47
+ textDecoration: 'none',
48
+ },
49
+ divider: {
50
+ display: 'flex',
51
+ alignItems: 'center',
52
+ gap: '12px',
53
+ color: '#666',
54
+ },
55
+ dividerLine: {
56
+ flex: 1,
57
+ height: 1,
58
+ backgroundColor: '#ddd',
59
+ },
60
+ };
61
+ export function SignIn({ afterSignInUrl, styles: customStyles = {}, showGoogle = true, signUpUrl = '/sign-up', forgotPasswordUrl, onSuccess, children, }) {
62
+ const { signIn, signInWithGoogle, googleClientId } = useBeamarAuth();
63
+ const [email, setEmail] = useState('');
64
+ const [password, setPassword] = useState('');
65
+ const [error, setError] = useState(null);
66
+ const [isLoading, setIsLoading] = useState(false);
67
+ const styles = { ...defaultStyles, ...customStyles };
68
+ const handleSubmit = async (e) => {
69
+ e.preventDefault();
70
+ setError(null);
71
+ setIsLoading(true);
72
+ try {
73
+ await signIn({ email, password });
74
+ onSuccess?.();
75
+ if (afterSignInUrl) {
76
+ window.location.href = afterSignInUrl;
77
+ }
78
+ }
79
+ catch (err) {
80
+ setError(err instanceof Error ? err.message : 'Sign in failed');
81
+ }
82
+ finally {
83
+ setIsLoading(false);
84
+ }
85
+ };
86
+ const handleGoogleSuccess = async (credential) => {
87
+ setError(null);
88
+ setIsLoading(true);
89
+ try {
90
+ await signInWithGoogle(credential);
91
+ onSuccess?.();
92
+ if (afterSignInUrl) {
93
+ window.location.href = afterSignInUrl;
94
+ }
95
+ }
96
+ catch (err) {
97
+ setError(err instanceof Error ? err.message : 'Sign in with Google failed');
98
+ }
99
+ finally {
100
+ setIsLoading(false);
101
+ }
102
+ };
103
+ if (children) {
104
+ return (_jsx(_Fragment, { children: children({
105
+ signIn: async (creds) => {
106
+ setError(null);
107
+ setIsLoading(true);
108
+ try {
109
+ await signIn(creds);
110
+ onSuccess?.();
111
+ if (afterSignInUrl)
112
+ window.location.href = afterSignInUrl;
113
+ }
114
+ catch (err) {
115
+ setError(err instanceof Error ? err.message : 'Sign in failed');
116
+ throw err;
117
+ }
118
+ finally {
119
+ setIsLoading(false);
120
+ }
121
+ },
122
+ signInWithGoogle: handleGoogleSuccess,
123
+ error,
124
+ isLoading,
125
+ }) }));
126
+ }
127
+ return (_jsxs("form", { onSubmit: handleSubmit, style: styles.container, children: [error && _jsx("div", { style: styles.error, children: error }), _jsx("input", { type: "email", placeholder: "Email", value: email, onChange: (e) => setEmail(e.target.value), required: true, disabled: isLoading, style: styles.input }), _jsx("input", { type: "password", placeholder: "Password", value: password, onChange: (e) => setPassword(e.target.value), required: true, disabled: isLoading, style: styles.input }), forgotPasswordUrl && (_jsx("a", { href: forgotPasswordUrl, style: styles.link, children: "Forgot password?" })), _jsx("button", { type: "submit", disabled: isLoading, style: styles.button, children: isLoading ? 'Signing in...' : 'Sign in' }), showGoogle && (_jsxs(_Fragment, { children: [_jsxs("div", { style: styles.divider, children: [_jsx("span", { style: styles.dividerLine }), _jsx("span", { children: "or" }), _jsx("span", { style: styles.dividerLine })] }), _jsx(GoogleSignInButton, { onSuccess: handleGoogleSuccess, disabled: isLoading, clientId: googleClientId })] })), _jsxs("p", { children: ["Don't have an account? ", _jsx("a", { href: signUpUrl, style: styles.link, children: "Sign up" })] })] }));
128
+ }
129
+ /**
130
+ * Google Sign In button - requires GoogleOAuthProvider wrapper with clientId from config
131
+ */
132
+ function GoogleSignInButton({ onSuccess, disabled, clientId, }) {
133
+ const [GoogleLogin, setGoogleLogin] = useState(null);
134
+ React.useEffect(() => {
135
+ import('@react-oauth/google').then((mod) => {
136
+ setGoogleLogin(() => mod.GoogleLogin);
137
+ });
138
+ }, []);
139
+ if (!clientId)
140
+ return null;
141
+ if (!GoogleLogin) {
142
+ return (_jsx("button", { type: "button", disabled: true, style: { ...defaultStyles.buttonGoogle, opacity: 0.7 }, children: "Loading..." }));
143
+ }
144
+ return (_jsx(GoogleLogin, { onSuccess: (res) => {
145
+ if (res.credential && res.clientId) {
146
+ onSuccess({ credential: res.credential, clientId: res.clientId });
147
+ }
148
+ }, onError: () => { }, useOneTap: false }));
149
+ }
@@ -0,0 +1,13 @@
1
+ import React from 'react';
2
+ export interface SignInButtonProps {
3
+ children?: React.ReactNode;
4
+ fallbackRedirectUrl?: string;
5
+ signInUrl?: string;
6
+ style?: React.CSSProperties;
7
+ className?: string;
8
+ }
9
+ /**
10
+ * Button that redirects to sign-in page (Clerk-style)
11
+ */
12
+ export declare function SignInButton({ children, signInUrl, fallbackRedirectUrl, style, className, }: SignInButtonProps): import("react/jsx-runtime").JSX.Element | null;
13
+ //# sourceMappingURL=SignInButton.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"SignInButton.d.ts","sourceRoot":"","sources":["../../src/components/SignInButton.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAK,MAAM,OAAO,CAAA;AAGzB,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,EAAE,KAAK,CAAC,SAAS,CAAA;IAC1B,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,KAAK,CAAC,EAAE,KAAK,CAAC,aAAa,CAAA;IAC3B,SAAS,CAAC,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,EAC3B,QAAoB,EACpB,SAAsB,EACtB,mBAAmB,EACnB,KAAK,EACL,SAAS,GACV,EAAE,iBAAiB,kDAanB"}
@@ -0,0 +1,14 @@
1
+ import { jsx as _jsx } from "react/jsx-runtime";
2
+ import { useBeamarAuth } from '../hooks';
3
+ /**
4
+ * Button that redirects to sign-in page (Clerk-style)
5
+ */
6
+ export function SignInButton({ children = 'Sign in', signInUrl = '/sign-in', fallbackRedirectUrl, style, className, }) {
7
+ const { isSignedIn } = useBeamarAuth();
8
+ const to = fallbackRedirectUrl
9
+ ? `${signInUrl}?redirect_url=${encodeURIComponent(fallbackRedirectUrl)}`
10
+ : signInUrl;
11
+ if (isSignedIn)
12
+ return null;
13
+ return (_jsx("a", { href: to, style: style, className: className, children: children }));
14
+ }