@object-ui/auth 3.1.2 → 3.1.3

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/README.md CHANGED
@@ -8,7 +8,7 @@ Authentication system for Object UI — AuthProvider, guards, login/register for
8
8
  - 🛡️ **AuthGuard** - Protect routes and components from unauthenticated access
9
9
  - 📝 **Pre-built Forms** - LoginForm, RegisterForm, and ForgotPasswordForm ready to use
10
10
  - 👤 **UserMenu** - Display authenticated user info with sign-out support
11
- - 🔑 **Auth Client Factory** - `createAuthClient` for pluggable backend integration
11
+ - 🔑 **Auth Client Factory** - `createAuthClient` powered by official [better-auth](https://better-auth.com) client
12
12
  - 🌐 **Authenticated Fetch** - `createAuthenticatedFetch` for automatic token injection
13
13
  - 👀 **Preview Mode** - Auto-login with simulated identity for marketplace demos and app showcases
14
14
  - 🎯 **Type-Safe** - Full TypeScript support with exported types
@@ -30,8 +30,7 @@ import { AuthProvider, useAuth, AuthGuard } from '@object-ui/auth';
30
30
  import { createAuthClient } from '@object-ui/auth';
31
31
 
32
32
  const authClient = createAuthClient({
33
- provider: 'custom',
34
- apiUrl: 'https://api.example.com/auth',
33
+ baseURL: 'https://api.example.com/auth',
35
34
  });
36
35
 
37
36
  function App() {
@@ -7,11 +7,12 @@
7
7
  */
8
8
  import type { AuthClient, AuthClientConfig } from './types';
9
9
  /**
10
- * Create an auth client instance.
10
+ * Create an auth client instance backed by the official better-auth client.
11
11
  *
12
- * This factory creates an abstraction layer over the authentication provider.
13
- * It is designed to work with better-auth but can be adapted to any auth backend
14
- * that exposes standard REST endpoints for sign-in, sign-up, sign-out, and session management.
12
+ * Internally delegates to `createAuthClient` from `better-auth/client`,
13
+ * exposing the same {@link AuthClient} interface so that AuthProvider,
14
+ * createAuthenticatedFetch, and all downstream consumers continue to work
15
+ * without changes.
15
16
  *
16
17
  * @example
17
18
  * ```ts
@@ -1 +1 @@
1
- {"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAwD,MAAM,SAAS,CAAC;AAElH;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CA4ErE"}
1
+ {"version":3,"file":"createAuthClient.d.ts","sourceRoot":"","sources":["../src/createAuthClient.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAGH,OAAO,KAAK,EAAE,UAAU,EAAE,gBAAgB,EAAwD,MAAM,SAAS,CAAC;AAiClH;;;;;;;;;;;;;GAaG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,gBAAgB,GAAG,UAAU,CAwFrE"}
@@ -5,12 +5,45 @@
5
5
  * This source code is licensed under the MIT license found in the
6
6
  * LICENSE file in the root directory of this source tree.
7
7
  */
8
+ import { createAuthClient as createBetterAuthClient } from 'better-auth/client';
8
9
  /**
9
- * Create an auth client instance.
10
+ * Resolve a baseURL (which may be relative or absolute) into the
11
+ * `{ origin, basePath }` pair required by the better-auth client.
10
12
  *
11
- * This factory creates an abstraction layer over the authentication provider.
12
- * It is designed to work with better-auth but can be adapted to any auth backend
13
- * that exposes standard REST endpoints for sign-in, sign-up, sign-out, and session management.
13
+ * - Absolute URLs (e.g. `http://localhost:3000/api/auth`) are split into origin + pathname.
14
+ * - Relative paths (e.g. `/api/v1/auth`) use `window.location.origin` in
15
+ * browser environments, falling back to `http://localhost` elsewhere.
16
+ */
17
+ function resolveAuthURL(baseURL) {
18
+ try {
19
+ const url = new URL(baseURL);
20
+ return { origin: url.origin, basePath: url.pathname.replace(/\/$/, '') };
21
+ }
22
+ catch {
23
+ // Relative URL – resolve against the current origin when available
24
+ const origin = getWindowOrigin() ?? 'http://localhost';
25
+ return { origin, basePath: baseURL.replace(/\/$/, '') };
26
+ }
27
+ }
28
+ /** Safely read window.location.origin when available (browser environments). */
29
+ function getWindowOrigin() {
30
+ try {
31
+ if (typeof window !== 'undefined' && window.location?.origin) {
32
+ return window.location.origin;
33
+ }
34
+ }
35
+ catch {
36
+ // window may be defined but accessing location can throw in some SSR environments
37
+ }
38
+ return undefined;
39
+ }
40
+ /**
41
+ * Create an auth client instance backed by the official better-auth client.
42
+ *
43
+ * Internally delegates to `createAuthClient` from `better-auth/client`,
44
+ * exposing the same {@link AuthClient} interface so that AuthProvider,
45
+ * createAuthenticatedFetch, and all downstream consumers continue to work
46
+ * without changes.
14
47
  *
15
48
  * @example
16
49
  * ```ts
@@ -19,70 +52,79 @@
19
52
  * ```
20
53
  */
21
54
  export function createAuthClient(config) {
22
- const { baseURL, fetchFn = fetch } = config;
23
- async function request(path, options) {
24
- const url = `${baseURL}${path}`;
25
- const response = await fetchFn(url, {
26
- ...options,
27
- headers: {
28
- 'Content-Type': 'application/json',
29
- ...options?.headers,
30
- },
31
- credentials: 'include',
32
- });
33
- if (!response.ok) {
34
- const body = await response.json().catch(() => null);
35
- const message = (body && typeof body === 'object' && 'message' in body)
36
- ? String(body.message)
37
- : `Auth request failed with status ${response.status}`;
38
- throw new Error(message);
39
- }
40
- return response.json();
41
- }
55
+ const { baseURL, fetchFn } = config;
56
+ const { origin, basePath } = resolveAuthURL(baseURL);
57
+ const betterAuth = createBetterAuthClient({
58
+ baseURL: origin,
59
+ basePath,
60
+ disableDefaultFetchPlugins: true,
61
+ fetchOptions: fetchFn ? { customFetchImpl: fetchFn } : undefined,
62
+ });
63
+ // The better-auth client exposes methods whose TS return types are narrower
64
+ // than the runtime JSON the server actually sends (e.g. `session` on signIn).
65
+ // We deliberately cast through `unknown` to bridge from better-auth types
66
+ // to the ObjectUI AuthClient contract.
42
67
  return {
43
68
  async signIn(credentials) {
44
- return request('/sign-in/email', {
45
- method: 'POST',
46
- body: JSON.stringify(credentials),
69
+ const { data, error } = await betterAuth.signIn.email({
70
+ email: credentials.email,
71
+ password: credentials.password,
47
72
  });
73
+ if (error) {
74
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
75
+ }
76
+ const payload = data;
77
+ return { user: payload.user, session: payload.session };
48
78
  },
49
- async signUp(data) {
50
- return request('/sign-up/email', {
51
- method: 'POST',
52
- body: JSON.stringify(data),
79
+ async signUp(signUpData) {
80
+ const { data, error } = await betterAuth.signUp.email({
81
+ email: signUpData.email,
82
+ password: signUpData.password,
83
+ name: signUpData.name,
53
84
  });
85
+ if (error) {
86
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
87
+ }
88
+ const payload = data;
89
+ return { user: payload.user, session: payload.session };
54
90
  },
55
91
  async signOut() {
56
- await request('/sign-out', { method: 'POST' });
92
+ const { error } = await betterAuth.signOut();
93
+ if (error) {
94
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
95
+ }
57
96
  },
58
97
  async getSession() {
59
- try {
60
- return await request('/get-session', {
61
- method: 'GET',
62
- });
63
- }
64
- catch {
98
+ const { data, error } = await betterAuth.getSession();
99
+ if (error || !data)
65
100
  return null;
66
- }
101
+ const payload = data;
102
+ return { user: payload.user, session: payload.session };
67
103
  },
68
104
  async forgotPassword(email) {
69
- await request('/forgot-password', {
70
- method: 'POST',
71
- body: JSON.stringify({ email }),
72
- });
105
+ const forgetPw = betterAuth.forgetPassword;
106
+ const { error } = await forgetPw({ email, redirectTo: '/' });
107
+ if (error) {
108
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
109
+ }
73
110
  },
74
111
  async resetPassword(token, newPassword) {
75
- await request('/reset-password', {
76
- method: 'POST',
77
- body: JSON.stringify({ token, newPassword }),
78
- });
112
+ const { error } = await betterAuth.resetPassword({ token, newPassword });
113
+ if (error) {
114
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
115
+ }
79
116
  },
80
- async updateUser(data) {
81
- const result = await request('/update-user', {
82
- method: 'POST',
83
- body: JSON.stringify(data),
84
- });
85
- return result.user;
117
+ async updateUser(userData) {
118
+ const { data, error } = await betterAuth.updateUser(userData);
119
+ if (error) {
120
+ throw new Error(error.message ?? `Auth request failed with status ${error.status}`);
121
+ }
122
+ if (!data) {
123
+ throw new Error('Update user returned no data');
124
+ }
125
+ // The server response may wrap the user in a `user` key or return it directly
126
+ const raw = data;
127
+ return (raw && typeof raw === 'object' && 'user' in raw ? raw.user : raw);
86
128
  },
87
129
  };
88
130
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@object-ui/auth",
3
- "version": "3.1.2",
3
+ "version": "3.1.3",
4
4
  "type": "module",
5
5
  "license": "MIT",
6
6
  "description": "Authentication system for Object UI with AuthProvider, useAuth hook, AuthGuard, and form components.",
@@ -27,7 +27,8 @@
27
27
  "react": "^18.0.0 || ^19.0.0"
28
28
  },
29
29
  "dependencies": {
30
- "@object-ui/types": "3.1.2"
30
+ "better-auth": "^1.5.4",
31
+ "@object-ui/types": "3.1.3"
31
32
  },
32
33
  "devDependencies": {
33
34
  "@types/react": "19.2.14",