@coreiam/auth 1.0.15 → 1.0.391

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.
@@ -1,182 +1,49 @@
1
1
  "use strict";
2
2
  // // src/nextjs/provider.tsx
3
3
  // 'use client';
4
- // import React, { createContext, useContext, useEffect, useState, useCallback } from 'react';
5
- // import { useRouter } from 'next/navigation';
4
+ // import React, { createContext, useContext, useEffect, useState } from 'react';
5
+ // import { getSession } from './actions';
6
6
  // import type { CoreIAMIdentity } from '../core';
7
- // export interface CoreIAMRedirects {
8
- // afterLogin?: string;
9
- // afterLogout?: string;
10
- // }
11
- // interface LoginResult {
12
- // success?: boolean;
13
- // error?: string;
14
- // twoFactor?: boolean;
15
- // }
16
7
  // interface AuthContextType {
17
8
  // identity: CoreIAMIdentity | null;
18
9
  // isLoading: boolean;
19
10
  // isAuthenticated: boolean;
20
- // login: (values: { email: string; password: string }, callbackUrl?: string) => Promise<LoginResult>;
21
- // logout: () => Promise<void>;
22
- // register: (userData: Record<string, any>) => Promise<LoginResult>;
23
11
  // refetchIdentity: () => Promise<void>;
24
12
  // }
25
13
  // const AuthContext = createContext<AuthContextType>({
26
14
  // identity: null,
27
15
  // isLoading: true,
28
16
  // isAuthenticated: false,
29
- // login: async () => ({ error: 'CoreIAMProvider is not mounted' }),
30
- // logout: async () => {},
31
- // register: async () => ({ error: 'CoreIAMProvider is not mounted' }),
32
17
  // refetchIdentity: async () => {},
33
18
  // });
34
- // export function CoreIAMProvider({
35
- // children,
36
- // initialIdentity,
37
- // redirects = {},
38
- // }: {
39
- // children: React.ReactNode;
19
+ // export function CoreIAMProvider({
20
+ // children,
21
+ // initialIdentity
22
+ // }: {
23
+ // children: React.ReactNode;
40
24
  // initialIdentity?: CoreIAMIdentity | null;
41
- // redirects?: CoreIAMRedirects;
42
25
  // }) {
43
26
  // const [identity, setIdentity] = useState<CoreIAMIdentity | null>(initialIdentity ?? null);
44
27
  // const [isLoading, setIsLoading] = useState(initialIdentity === undefined);
45
- // const router = useRouter();
46
- // const refetchIdentity = useCallback(async () => {
28
+ // const refetchIdentity = async () => {
47
29
  // try {
48
- // // Call the Next.js API route, which securely calls CoreIAM
49
- // const res = await fetch('/api/auth/session', { credentials: 'include' });
50
- // setIdentity(res.ok ? await res.json() : null);
30
+ // const result = await getSession();
31
+ // setIdentity(result);
51
32
  // } catch {
52
33
  // setIdentity(null);
53
34
  // } finally {
54
35
  // setIsLoading(false);
55
36
  // }
56
- // }, []);
37
+ // };
57
38
  // useEffect(() => {
58
39
  // if (initialIdentity === undefined) {
59
40
  // refetchIdentity();
60
41
  // } else {
61
42
  // setIsLoading(false);
62
43
  // }
63
- // // eslint-disable-next-line react-hooks/exhaustive-deps
64
44
  // }, []);
65
- // // const login = async (values: { email: string; password: string }, callbackUrl?: string): Promise<LoginResult> => {
66
- // // setIsLoading(true);
67
- // // try {
68
- // // // Fetch CSRF token first
69
- // // const csrfRes = await fetch('/api/auth/csrf', { credentials: 'include' });
70
- // // if (!csrfRes.ok) return { error: 'Failed to get CSRF token' };
71
- // // const { csrfToken } = await csrfRes.json();
72
- // // // Call login API route
73
- // // const loginRes = await fetch('/api/auth/login', {
74
- // // method: 'POST',
75
- // // headers: {
76
- // // 'Content-Type': 'application/json',
77
- // // 'x-csrf-token': csrfToken,
78
- // // },
79
- // // credentials: 'include',
80
- // // body: JSON.stringify(values),
81
- // // });
82
- // // const data = await loginRes.json();
83
- // // if (!loginRes.ok) {
84
- // // return { error: data.message || data.error || 'Invalid credentials' };
85
- // // }
86
- // // if (data.twoFactor) {
87
- // // return { twoFactor: true };
88
- // // }
89
- // // await refetchIdentity();
90
- // // const target = callbackUrl || redirects.afterLogin;
91
- // // if (target) router.push(target);
92
- // // return { success: true };
93
- // // } catch {
94
- // // return { error: 'Something went wrong' };
95
- // // } finally {
96
- // // setIsLoading(false);
97
- // // }
98
- // // };
99
- // const login = async (values: { email: string; password: string }, callbackUrl?: string): Promise<LoginResult> => {
100
- // setIsLoading(true);
101
- // try {
102
- // // Fetch CSRF token first
103
- // const csrfRes = await fetch('/api/auth/csrf', { credentials: 'include' });
104
- // if (!csrfRes.ok) return { error: 'Failed to get CSRF token' };
105
- // const { csrfToken } = await csrfRes.json();
106
- // // FIX: Map 'email' to 'identifier' for the CoreIAM backend
107
- // const loginPayload = {
108
- // identifier: values.email,
109
- // password: values.password,
110
- // };
111
- // // Call login API route
112
- // const loginRes = await fetch('/api/auth/login', {
113
- // method: 'POST',
114
- // headers: {
115
- // 'Content-Type': 'application/json',
116
- // 'x-csrf-token': csrfToken,
117
- // },
118
- // credentials: 'include',
119
- // body: JSON.stringify(loginPayload), // Send the mapped payload
120
- // });
121
- // const data = await loginRes.json();
122
- // if (!loginRes.ok) {
123
- // return { error: data.message || data.error || 'Invalid credentials' };
124
- // }
125
- // if (data.twoFactor) {
126
- // return { twoFactor: true };
127
- // }
128
- // await refetchIdentity();
129
- // const target = callbackUrl || redirects.afterLogin;
130
- // if (target) router.push(target);
131
- // return { success: true };
132
- // } catch {
133
- // return { error: 'Something went wrong' };
134
- // } finally {
135
- // setIsLoading(false);
136
- // }
137
- // };
138
- // const logout = async () => {
139
- // try {
140
- // await fetch('/api/auth/logout', {
141
- // method: 'POST',
142
- // credentials: 'include',
143
- // });
144
- // } finally {
145
- // setIdentity(null);
146
- // if (redirects.afterLogout) router.push(redirects.afterLogout);
147
- // }
148
- // };
149
- // const register = async (userData: Record<string, any>): Promise<LoginResult> => {
150
- // setIsLoading(true);
151
- // try {
152
- // const csrfRes = await fetch('/api/auth/csrf', { credentials: 'include' });
153
- // if (!csrfRes.ok) return { error: 'Failed to get CSRF token' };
154
- // const { csrfToken } = await csrfRes.json();
155
- // const registerRes = await fetch('/api/auth/register', {
156
- // method: 'POST',
157
- // headers: {
158
- // 'Content-Type': 'application/json',
159
- // 'x-csrf-token': csrfToken,
160
- // },
161
- // credentials: 'include',
162
- // body: JSON.stringify(userData),
163
- // });
164
- // if (!registerRes.ok) {
165
- // const error = await registerRes.json();
166
- // return { error: error.message || error.error || 'Registration failed' };
167
- // }
168
- // // Auto-login after registration
169
- // return await login({ email: userData.email, password: userData.password });
170
- // } catch {
171
- // return { error: 'Something went wrong' };
172
- // } finally {
173
- // setIsLoading(false);
174
- // }
175
- // };
176
45
  // return (
177
- // <AuthContext.Provider
178
- // value={{ identity, isLoading, isAuthenticated: !!identity, login, logout, register, refetchIdentity }}
179
- // >
46
+ // <AuthContext.Provider value={{ identity, isLoading, isAuthenticated: !!identity, refetchIdentity }}>
180
47
  // {children}
181
48
  // </AuthContext.Provider>
182
49
  // );
@@ -184,6 +51,7 @@
184
51
  // export function useAuth() {
185
52
  // return useContext(AuthContext);
186
53
  // }
54
+ // src/nextjs/provider.tsx
187
55
  'use client';
188
56
  Object.defineProperty(exports, "__esModule", { value: true });
189
57
  exports.CoreIAMProvider = CoreIAMProvider;
@@ -196,20 +64,17 @@ const AuthContext = (0, react_1.createContext)({
196
64
  identity: null,
197
65
  isLoading: true,
198
66
  isAuthenticated: false,
199
- login: async () => ({ error: 'CoreIAMProvider is not mounted' }),
67
+ login: async () => ({ error: 'Not mounted' }),
200
68
  logout: async () => { },
201
- register: async () => ({ error: 'CoreIAMProvider is not mounted' }),
69
+ register: async () => ({ error: 'Not mounted' }),
70
+ verifyMfa: async () => ({ error: 'Not mounted' }),
202
71
  refetchIdentity: async () => { },
203
72
  });
204
- function CoreIAMProvider({ children, initialIdentity, redirects = {}, }) {
73
+ function CoreIAMProvider({ children, initialIdentity }) {
205
74
  const [identity, setIdentity] = (0, react_1.useState)(initialIdentity ?? null);
206
75
  const [isLoading, setIsLoading] = (0, react_1.useState)(initialIdentity === undefined);
207
76
  const router = (0, navigation_1.useRouter)();
208
77
  const refetchIdentity = async () => {
209
- // DEBUG_TRACE: browser console — tags who called this (mount effect vs.
210
- // an explicit login/logout/register call). Temporary, remove once
211
- // settled.
212
- console.log(`[DEBUG_TRACE][CoreIAMProvider] refetchIdentity() called @ ${new Date().toISOString()}`);
213
78
  try {
214
79
  const result = await (0, actions_1.getSession)();
215
80
  setIdentity(result);
@@ -222,37 +87,71 @@ function CoreIAMProvider({ children, initialIdentity, redirects = {}, }) {
222
87
  }
223
88
  };
224
89
  (0, react_1.useEffect)(() => {
225
- // FIX: was `initialIdentity === null`, which can't tell "SSR ran and
226
- // confirmed you're logged out" (a correct, final null) apart from "no
227
- // SSR value was ever provided" (a real undefined). Since layout.tsx
228
- // always calls getSession() and passes its result — even when that
229
- // result legitimately is null — every logged-out page view was
230
- // treated as "no SSR value, fetch again," firing a second, wholly
231
- // redundant /auth/profile call for something SSR had already
232
- // determined. undefined (the prop genuinely omitted) is the only case
233
- // that should trigger this fallback fetch.
234
- console.log(`[DEBUG_TRACE][CoreIAMProvider] mount effect ran, initialIdentity=${initialIdentity === undefined ? 'undefined' : JSON.stringify(initialIdentity)} @ ${new Date().toISOString()}`);
235
90
  if (initialIdentity === undefined) {
236
91
  refetchIdentity();
237
92
  }
238
93
  else {
239
94
  setIsLoading(false);
240
95
  }
241
- // Intentionally only on mount — initialIdentity is a one-time SSR seed,
242
- // not something we want to re-run this effect for if it changes identity.
243
- // eslint-disable-next-line react-hooks/exhaustive-deps
244
96
  }, []);
97
+ const getCsrfToken = async () => {
98
+ const res = await fetch('/api/auth/csrf-token', {
99
+ method: 'POST',
100
+ credentials: 'include'
101
+ });
102
+ if (!res.ok)
103
+ throw new Error('Failed to get CSRF token');
104
+ const { csrfToken } = await res.json();
105
+ return csrfToken;
106
+ };
107
+ const verifyMfa = async (tempToken, code) => {
108
+ setIsLoading(true);
109
+ try {
110
+ const res = await fetch('/api/auth/mfa/login', {
111
+ method: 'POST',
112
+ headers: { 'Content-Type': 'application/json' },
113
+ credentials: 'include',
114
+ body: JSON.stringify({ tempToken, code }),
115
+ });
116
+ const data = await res.json();
117
+ if (!res.ok) {
118
+ return { error: data.message || 'Invalid 2FA code.' };
119
+ }
120
+ // Success! Hard refresh to let the server re-render with new cookies
121
+ window.location.href = '/';
122
+ return { success: true };
123
+ }
124
+ catch {
125
+ return { error: 'Something went wrong' };
126
+ }
127
+ finally {
128
+ setIsLoading(false);
129
+ }
130
+ };
245
131
  const login = async (values, callbackUrl) => {
246
132
  setIsLoading(true);
247
133
  try {
248
- const result = await (0, actions_1.loginActionSdk)(values.email, values.password);
249
- if (!result.ok) {
250
- return { error: result.data?.message || result.data?.error || 'Invalid credentials' };
134
+ // 1. Fetch CSRF token
135
+ const csrfToken = await getCsrfToken();
136
+ // 2. Call login API route
137
+ const res = await fetch('/api/auth/login', {
138
+ method: 'POST',
139
+ headers: {
140
+ 'Content-Type': 'application/json',
141
+ 'x-csrf-token': csrfToken,
142
+ },
143
+ credentials: 'include',
144
+ body: JSON.stringify({ identifier: values.email, password: values.password }),
145
+ });
146
+ const data = await res.json();
147
+ if (!res.ok)
148
+ return { error: data.message || 'Invalid credentials' };
149
+ if (data.twoFactorRequired) {
150
+ // Return the twoFactor flag and the tempToken to the form
151
+ return { twoFactor: true, tempToken: data.tempToken };
251
152
  }
252
- await refetchIdentity();
253
- const target = callbackUrl || redirects.afterLogin;
254
- if (target)
255
- router.push(target);
153
+ // Hard refresh to let server re-render with new cookies
154
+ window.location.href = callbackUrl || '/';
256
155
  return { success: true };
257
156
  }
258
157
  catch {
@@ -263,31 +162,52 @@ function CoreIAMProvider({ children, initialIdentity, redirects = {}, }) {
263
162
  }
264
163
  };
265
164
  const logout = async () => {
165
+ setIsLoading(true);
266
166
  try {
267
- await (0, actions_1.logoutActionSdk)();
167
+ await fetch('/api/auth/logout', { method: 'POST', credentials: 'include' });
168
+ setIdentity(null);
169
+ window.location.href = '/auth/login';
268
170
  }
269
171
  finally {
270
- setIdentity(null);
271
- if (redirects.afterLogout)
272
- router.push(redirects.afterLogout);
172
+ setIsLoading(false);
273
173
  }
274
174
  };
275
175
  const register = async (userData) => {
276
176
  setIsLoading(true);
277
177
  try {
278
- const result = await (0, actions_1.registerActionSdk)(userData);
279
- if (!result.ok) {
280
- return { error: result.data?.message || result.data?.error || 'Registration failed' };
178
+ // 1. Fetch CSRF token
179
+ const csrfToken = await getCsrfToken();
180
+ // 2. Call register API route
181
+ const res = await fetch('/api/auth/register', {
182
+ method: 'POST',
183
+ headers: {
184
+ 'Content-Type': 'application/json',
185
+ 'x-csrf-token': csrfToken,
186
+ },
187
+ credentials: 'include',
188
+ body: JSON.stringify(userData),
189
+ });
190
+ const data = await res.json();
191
+ // 3. FIX: Check for the "OAuth Required" signal
192
+ if (!res.ok) {
193
+ if (data.code === 'OAUTH_ACCOUNT_EXISTS') {
194
+ // Automatically redirect to the OAuth provider!
195
+ window.location.href = `/api/auth/oauth/${data.provider}`;
196
+ return { success: true };
197
+ }
198
+ return { error: data.message || 'Registration failed' };
281
199
  }
282
- // Registration on the backend doesn't auto-issue a session — log in
283
- // immediately after, same as the flow this replaces did.
284
- return await login({ email: userData.email, password: userData.password });
200
+ // Auto-login after standard registration
201
+ return login({ email: userData.email, password: userData.password });
202
+ }
203
+ catch {
204
+ return { error: 'Something went wrong' };
285
205
  }
286
206
  finally {
287
207
  setIsLoading(false);
288
208
  }
289
209
  };
290
- return ((0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: { identity, isLoading, isAuthenticated: !!identity, login, logout, register, refetchIdentity }, children: children }));
210
+ return ((0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: { identity, isLoading, isAuthenticated: !!identity, login, logout, register, verifyMfa, refetchIdentity }, children: children }));
291
211
  }
292
212
  function useAuth() {
293
213
  return (0, react_1.useContext)(AuthContext);
@@ -1,6 +1,7 @@
1
1
  import React from 'react';
2
+ import type { CoreIAMIdentity } from '../core';
2
3
  interface AuthContextType {
3
- user: any | null;
4
+ user: CoreIAMIdentity | null;
4
5
  isLoading: boolean;
5
6
  }
6
7
  export declare function CoreIAMProvider({ children, sessionUrl }: {
@@ -1,25 +1,72 @@
1
1
  "use strict";
2
2
  // src/react/provider.tsx
3
+ /**
4
+ 'use client';
5
+
6
+ import React, { createContext, useContext, useEffect, useState } from 'react';
7
+
8
+ interface AuthContextType {
9
+ user: any | null;
10
+ isLoading: boolean;
11
+ }
12
+
13
+ const AuthContext = createContext<AuthContextType>({
14
+ user: null,
15
+ isLoading: true,
16
+ });
17
+
18
+ export function CoreIAMProvider({
19
+ children,
20
+ sessionUrl = '/api/auth/session'
21
+ }: {
22
+ children: React.ReactNode;
23
+ sessionUrl?: string;
24
+ }) {
25
+ const [user, setUser] = useState<any | null>(null);
26
+ const [isLoading, setIsLoading] = useState(true);
27
+
28
+ useEffect(() => {
29
+ fetch(sessionUrl, { credentials: 'include' })
30
+ .then(res => res.ok ? res.json() : null)
31
+ .then(data => setUser(data))
32
+ .finally(() => setIsLoading(false));
33
+ }, [sessionUrl]);
34
+
35
+ return (
36
+ <AuthContext.Provider value={{ user, isLoading }}>
37
+ {children}
38
+ </AuthContext.Provider>
39
+ );
40
+ }
41
+
42
+ export function useAuth() {
43
+ return useContext(AuthContext);
44
+ }
45
+
46
+ */
3
47
  'use client';
4
48
  Object.defineProperty(exports, "__esModule", { value: true });
5
49
  exports.CoreIAMProvider = CoreIAMProvider;
6
50
  exports.useAuth = useAuth;
7
51
  const jsx_runtime_1 = require("react/jsx-runtime");
8
52
  const react_1 = require("react");
9
- const AuthContext = (0, react_1.createContext)({
10
- user: null,
11
- isLoading: true,
12
- });
53
+ const AuthContext = (0, react_1.createContext)({ user: null, isLoading: true });
13
54
  function CoreIAMProvider({ children, sessionUrl = '/api/auth/session' }) {
14
55
  const [user, setUser] = (0, react_1.useState)(null);
15
56
  const [isLoading, setIsLoading] = (0, react_1.useState)(true);
16
57
  (0, react_1.useEffect)(() => {
58
+ let cancelled = false;
17
59
  fetch(sessionUrl, { credentials: 'include' })
18
- .then(res => res.ok ? res.json() : null)
19
- .then(data => setUser(data))
20
- .finally(() => setIsLoading(false));
60
+ .then(res => (res.ok ? res.json() : null))
61
+ .then(data => { if (!cancelled)
62
+ setUser(data); })
63
+ .catch(() => { if (!cancelled)
64
+ setUser(null); }) // NEW: network failure no longer leaves an unhandled rejection
65
+ .finally(() => { if (!cancelled)
66
+ setIsLoading(false); });
67
+ return () => { cancelled = true; }; // NEW: no state updates after unmount
21
68
  }, [sessionUrl]);
22
- return ((0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: { user, isLoading }, children: children }));
69
+ return (0, jsx_runtime_1.jsx)(AuthContext.Provider, { value: { user, isLoading }, children: children });
23
70
  }
24
71
  function useAuth() {
25
72
  return (0, react_1.useContext)(AuthContext);
@@ -0,0 +1,45 @@
1
+ import React from 'react';
2
+ export interface SignInButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
3
+ /** If true, renders child directly via Radix Slot instead of a <button> */
4
+ asChild?: boolean;
5
+ /** Destination route on click */
6
+ redirectTo?: string;
7
+ }
8
+ /**
9
+ * Renders a sign-in button or merges click behavior onto a child element (asChild).
10
+ */
11
+ export declare function SignInButton({ asChild, redirectTo, onClick, children, ...props }: SignInButtonProps): import("react/jsx-runtime").JSX.Element;
12
+ export interface SignUpButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
13
+ asChild?: boolean;
14
+ redirectTo?: string;
15
+ }
16
+ /**
17
+ * Renders a sign-up button or merges click behavior onto a child element (asChild).
18
+ */
19
+ export declare function SignUpButton({ asChild, redirectTo, onClick, children, ...props }: SignUpButtonProps): import("react/jsx-runtime").JSX.Element;
20
+ export interface OAuthButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
21
+ asChild?: boolean;
22
+ provider: 'google' | 'github' | 'microsoft' | 'apple' | string;
23
+ }
24
+ /**
25
+ * Renders an OAuth provider button or merges click behavior onto a child element (asChild).
26
+ */
27
+ export declare function OAuthButton({ asChild, provider, onClick, children, ...props }: OAuthButtonProps): import("react/jsx-runtime").JSX.Element;
28
+ export interface SignOutButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
29
+ asChild?: boolean;
30
+ /** Destination route after signing out */
31
+ redirectTo?: string;
32
+ }
33
+ /**
34
+ * Renders a sign-out button or merges click behavior onto a child element (asChild).
35
+ */
36
+ export declare function SignOutButton({ asChild, redirectTo, onClick, children, ...props }: SignOutButtonProps): import("react/jsx-runtime").JSX.Element;
37
+ export interface UserButtonProps extends React.ButtonHTMLAttributes<HTMLButtonElement> {
38
+ asChild?: boolean;
39
+ /** Destination route for the user's account/profile page */
40
+ redirectTo?: string;
41
+ }
42
+ /**
43
+ * Renders a user profile button or merges click behavior onto a child element (asChild).
44
+ */
45
+ export declare function UserButton({ asChild, redirectTo, onClick, children, ...props }: UserButtonProps): import("react/jsx-runtime").JSX.Element;
@@ -0,0 +1,76 @@
1
+ "use strict";
2
+ 'use client';
3
+ Object.defineProperty(exports, "__esModule", { value: true });
4
+ exports.SignInButton = SignInButton;
5
+ exports.SignUpButton = SignUpButton;
6
+ exports.OAuthButton = OAuthButton;
7
+ exports.SignOutButton = SignOutButton;
8
+ exports.UserButton = UserButton;
9
+ const jsx_runtime_1 = require("react/jsx-runtime");
10
+ const react_slot_1 = require("@radix-ui/react-slot");
11
+ /**
12
+ * Renders a sign-in button or merges click behavior onto a child element (asChild).
13
+ */
14
+ function SignInButton({ asChild = false, redirectTo = '/auth/login', onClick, children, ...props }) {
15
+ const Component = asChild ? react_slot_1.Slot : 'button';
16
+ const handleClick = (e) => {
17
+ onClick?.(e); // Run original onClick prop if passed
18
+ if (!e.defaultPrevented) {
19
+ window.location.href = redirectTo;
20
+ }
21
+ };
22
+ return ((0, jsx_runtime_1.jsx)(Component, { ...props, onClick: handleClick, children: children ?? 'Sign In' }));
23
+ }
24
+ /**
25
+ * Renders a sign-up button or merges click behavior onto a child element (asChild).
26
+ */
27
+ function SignUpButton({ asChild = false, redirectTo = '/auth/register', onClick, children, ...props }) {
28
+ const Component = asChild ? react_slot_1.Slot : 'button';
29
+ const handleClick = (e) => {
30
+ onClick?.(e);
31
+ if (!e.defaultPrevented) {
32
+ window.location.href = redirectTo;
33
+ }
34
+ };
35
+ return ((0, jsx_runtime_1.jsx)(Component, { ...props, onClick: handleClick, children: children ?? 'Sign Up' }));
36
+ }
37
+ /**
38
+ * Renders an OAuth provider button or merges click behavior onto a child element (asChild).
39
+ */
40
+ function OAuthButton({ asChild = false, provider, onClick, children, ...props }) {
41
+ const Component = asChild ? react_slot_1.Slot : 'button';
42
+ const handleClick = (e) => {
43
+ onClick?.(e);
44
+ if (!e.defaultPrevented) {
45
+ window.location.href = `/api/auth/oauth/${provider}`;
46
+ }
47
+ };
48
+ return ((0, jsx_runtime_1.jsx)(Component, { ...props, onClick: handleClick, children: children ?? `Continue with ${provider}` }));
49
+ }
50
+ /**
51
+ * Renders a sign-out button or merges click behavior onto a child element (asChild).
52
+ */
53
+ function SignOutButton({ asChild = false, redirectTo = '/', onClick, children, ...props }) {
54
+ const Component = asChild ? react_slot_1.Slot : 'button';
55
+ const handleClick = (e) => {
56
+ onClick?.(e);
57
+ if (!e.defaultPrevented) {
58
+ // Direct to your framework's sign-out endpoint, passing the redirect URL
59
+ window.location.href = `/api/auth/signout?callbackUrl=${encodeURIComponent(redirectTo)}`;
60
+ }
61
+ };
62
+ return ((0, jsx_runtime_1.jsx)(Component, { ...props, onClick: handleClick, children: children ?? 'Sign Out' }));
63
+ }
64
+ /**
65
+ * Renders a user profile button or merges click behavior onto a child element (asChild).
66
+ */
67
+ function UserButton({ asChild = false, redirectTo = '/account', onClick, children, ...props }) {
68
+ const Component = asChild ? react_slot_1.Slot : 'button';
69
+ const handleClick = (e) => {
70
+ onClick?.(e);
71
+ if (!e.defaultPrevented) {
72
+ window.location.href = redirectTo;
73
+ }
74
+ };
75
+ return ((0, jsx_runtime_1.jsx)(Component, { ...props, onClick: handleClick, children: children ?? 'My Account' }));
76
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@coreiam/auth",
3
- "version": "1.0.15",
3
+ "version": "1.0.391",
4
4
  "main": "./dist/core/index.js",
5
5
  "types": "./dist/core/index.d.ts",
6
6
  "exports": {
@@ -18,13 +18,19 @@
18
18
  "types": "./dist/react/index.d.ts",
19
19
  "import": "./dist/react/index.js",
20
20
  "require": "./dist/react/index.js"
21
+ },
22
+ "./express": {
23
+ "types": "./dist/express/index.d.ts",
24
+ "import": "./dist/express/index.js",
25
+ "require": "./dist/express/index.js"
21
26
  }
22
27
  },
23
28
  "files": [
24
29
  "dist"
25
30
  ],
26
31
  "scripts": {
27
- "build": "tsc"
32
+ "build": "tsc",
33
+ "test": "vitest run"
28
34
  },
29
35
  "keywords": [
30
36
  "coreiam",
@@ -39,6 +45,7 @@
39
45
  "access": "public"
40
46
  },
41
47
  "peerDependencies": {
48
+ "express": "^4.0.0 || ^5.0.0",
42
49
  "next": ">=14",
43
50
  "react": ">=18"
44
51
  },
@@ -48,15 +55,25 @@
48
55
  },
49
56
  "react": {
50
57
  "optional": true
58
+ },
59
+ "express": {
60
+ "optional": true
51
61
  }
52
62
  },
53
63
  "devDependencies": {
64
+ "@types/express": "^5.0.6",
54
65
  "@types/react": "^19.2.7",
66
+ "@types/supertest": "^7.2.1",
67
+ "express": "^5.2.1",
55
68
  "next": "^16.2.11",
56
69
  "react": "^19.2.7",
57
- "typescript": "^5.0.0"
70
+ "supertest": "^7.3.0",
71
+ "typescript": "^5.0.0",
72
+ "vitest": "^3.2.7"
58
73
  },
59
74
  "dependencies": {
75
+ "@radix-ui/react-slot": "^1.3.3",
76
+ "jose": "^6.2.7",
60
77
  "jwt-decode": "^4.0.0"
61
78
  }
62
- }
79
+ }