Skip to content

Refactor auth client to use official better-auth createAuthClient#1061

Merged
hotlong merged 3 commits intomainfrom
copilot/refactor-auth-client-to-better-auth
Mar 10, 2026
Merged

Refactor auth client to use official better-auth createAuthClient#1061
hotlong merged 3 commits intomainfrom
copilot/refactor-auth-client-to-better-auth

Conversation

Copy link
Contributor

Copilot AI commented Mar 10, 2026

Replace the custom HTTP-based createAuthClient with the official better-auth/client createAuthClient, eliminating manual request handling and type mismatches while unlocking the full better-auth feature set (OAuth, magic links, session hooks, plugins).

Core change

createAuthClient now delegates to better-auth/client internally via an adapter that preserves the existing AuthClient interface — all consumers (AuthProvider, AuthGuard, useAuth, forms, createAuthenticatedFetch) are unchanged.

// Before: manual fetch calls per endpoint
async function request<T>(path: string, options?: RequestInit): Promise<T> {
  const response = await fetchFn(`${baseURL}${path}`, { ...options, credentials: 'include' });
  // ...manual error handling
}

// After: delegates to official better-auth client
const betterAuth = createBetterAuthClient({ baseURL: origin, basePath, ... });
const { data, error } = await betterAuth.signIn.email({ email, password });

Changes

  • packages/auth/src/createAuthClient.ts — Rewrote to wrap better-auth/client createAuthClient, with resolveAuthURL() to support both relative (/api/v1/auth) and absolute URLs
  • packages/auth/package.json — Added better-auth dependency
  • apps/console/src/mocks/authHandlers.ts — Updated endpoint from /forgot-password/forget-password (better-auth convention)
  • Tests & docs — Updated createAuthClient.test.ts, authHandlers.test.ts, README, ROADMAP

Notes

  • better-auth TS types are narrower than runtime responses (e.g. session not in signIn type but present at runtime), so controlled unknown casts bridge between type systems
  • forgetPassword (better-auth spelling) exists at runtime but not in default TS types — accessed via a typed cast
Original prompt

This section details on the original issue you should resolve

<issue_title>Refactor auth client to use official better-auth createAuthClient</issue_title>
<issue_description>## Problem
Current client implementation uses a custom createAuthClient instead of the official better-auth client, leading to several integration bugs:

  • Client does not leverage the full feature set of official better-auth client (OAuth, magic links, session hooks, etc.)
  • Type mismatches and manual request handling increase maintenance burden and introduce hard-to-debug edge cases

Recommended Fix

Priority refactor:

  1. Replace custom createAuthClient with official better-auth/react or better-auth/client (createAuthClient) and migrate usage accordingly.</issue_description>

Comments on the Issue (you are @copilot in this section)


💡 You can make Copilot smarter by setting up custom instructions, customizing its development environment and configuring Model Context Protocol (MCP) servers. Learn more Copilot coding agent tips in the docs.

Copilot AI self-assigned this Mar 10, 2026
@vercel
Copy link

vercel bot commented Mar 10, 2026

The latest updates on your projects. Learn more about Vercel for GitHub.

Project Deployment Actions Updated (UTC)
objectui Error Error Mar 10, 2026 6:01am
objectui-demo Ready Ready Preview, Comment Mar 10, 2026 6:01am
objectui-storybook Ready Ready Preview, Comment Mar 10, 2026 6:01am

Request Review

…lient

- Install better-auth as dependency in @object-ui/auth
- Rewrite createAuthClient.ts to delegate to better-auth/client createAuthClient
- Add resolveAuthURL helper to support both relative and absolute baseURLs
- Update MSW authHandlers to use better-auth endpoint name (forget-password)
- Update createAuthClient tests for new better-auth backed implementation
- All 81 existing tests pass, TypeScript compiles cleanly

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
- Simplify window origin detection into separate getWindowOrigin helper
- Define proper ForgetPasswordFn type for better-auth method access
- Throw error instead of returning empty AuthUser on updateUser failure
- Replace nested ternary with if-else in test URL extraction

Co-authored-by: hotlong <50353452+hotlong@users.noreply.github.com>
Copilot AI changed the title [WIP] Refactor auth client to use official better-auth createAuthClient Refactor auth client to use official better-auth createAuthClient Mar 10, 2026
@hotlong
Copy link
Contributor

hotlong commented Mar 10, 2026

@copilot 13:57:10.313 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m27�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerTrigger' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.314 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m31�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerClose' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.315 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m33�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerOverlay' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.315 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m45�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerContent' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.315 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m88�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerTitle' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.315 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m103�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerDescription' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.316 ../../packages/components build: �[96msrc/ui/sidebar.tsx�[0m:�[93m475�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'SidebarSeparator' cannot be named without a reference to '.pnpm/@radix-ui+react-separator@1.1.7_@types+react-dom@19.2.3_@types+react@19.2.14__@types+re_708d1054dbf5e38a292cb79d1c79b4a1/node_modules/@radix-ui/react-separator'. This is likely not portable. A type annotation is necessary.
13:57:10.316 ../../packages/components build: �[96msrc/ui/chart.tsx�[0m:�[93m117�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'payload' does not exist on type 'Omit<Omit<Props<ValueType, NameType>, PropertiesReadFromContext> & { active?: boolean | undefined; allowEscapeViewBox?: AllowInDimension | undefined; ... 24 more ...; wrapperStyle?: CSSProperties | undefined; } & ClassAttributes<...> & HTMLAttributes<...> & { ...; }, "ref">'.
13:57:10.316 ../../packages/components build: �[96msrc/ui/chart.tsx�[0m:�[93m122�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'label' does not exist on type 'Omit<Omit<Props<ValueType, NameType>, PropertiesReadFromContext> & { active?: boolean | undefined; allowEscapeViewBox?: AllowInDimension | undefined; ... 24 more ...; wrapperStyle?: CSSProperties | undefined; } & ClassAttributes<...> & HTMLAttributes<...> & { ...; }, "ref">'.
13:57:10.316 ../../packages/components build: �[96msrc/ui/chart.tsx�[0m:�[93m264�[0m:�[93m41�[0m - �[91merror�[0m�[90m TS2344: �[0mType '"payload" | "verticalAlign"' does not satisfy the constraint '"string" | "filter" | "fill" | "values" | "className" | "color" | "slot" | "style" | "children" | "content" | "clipPath" | "mask" | "path" | "key" | "suppressHydrationWarning" | ... 435 more ... | "onBBoxUpdate"'.
13:57:10.317 ../../packages/components build: �[96msrc/ui/chart.tsx�[0m:�[93m275�[0m:�[93m19�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'length' does not exist on type '{}'.
13:57:10.317 ../../packages/components build: �[96msrc/ui/chart.tsx�[0m:�[93m289�[0m:�[93m12�[0m - �[91merror�[0m�[90m TS2339: �[0mProperty 'filter' does not exist on type '{}'.
13:57:10.318 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m27�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerTrigger' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.318 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m31�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerClose' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.318 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m33�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerOverlay' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.319 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m45�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerContent' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.319 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m88�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerTitle' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.320 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m103�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerDescription' cannot be named without a reference to '.pnpm/@radix-ui+react-dialog@1.1.15_@types+react-dom@19.2.3_@types+react@19.2.14__@types+reac_779045218dc2799d336e7197abef9d38/node_modules/@radix-ui/react-dialog'. This is likely not portable. A type annotation is necessary.
13:57:10.320 ../../packages/components build: �[96msrc/ui/sidebar.tsx�[0m:�[93m475�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'SidebarSeparator' cannot be named without a reference to '.pnpm/@radix-ui+react-separator@1.1.7_@types+react-dom@19.2.3_@types+react@19.2.14__@types+re_708d1054dbf5e38a292cb79d1c79b4a1/node_modules/@radix-ui/react-separator'. This is likely not portable. A type annotation is necessary.
13:57:26.848 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m26�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'Sidebar'.
13:57:26.848 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m27�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarHeader'.
13:57:26.849 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m28�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarContent'.
13:57:26.850 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m29�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarFooter'.
13:57:26.850 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m30�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenu'.
13:57:26.851 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m31�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuItem'.
13:57:26.852 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m32�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuButton'.
13:57:26.852 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m33�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroup'.
13:57:26.859 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m34�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupLabel'.
13:57:26.861 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m35�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupContent'.
13:57:26.864 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m36�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarInput'.
13:57:26.864 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m37�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'useSidebar'.
13:57:26.865 ../../packages/layout build: �[96msrc/AppSchemaRenderer.tsx�[0m:�[93m307�[0m:�[93m24�[0m - �[91merror�[0m�[90m TS7006: �[0mParameter 'e' implicitly has an 'any' type.
13:57:26.866 ../../packages/layout build: �[96msrc/AppShell.tsx�[0m:�[93m3�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarProvider'.
13:57:26.866 ../../packages/layout build: �[96msrc/AppShell.tsx�[0m:�[93m4�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarTrigger'.
13:57:26.868 ../../packages/layout build: �[96msrc/AppShell.tsx�[0m:�[93m5�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarInset'.
13:57:26.868 ../../packages/layout build: �[96msrc/AppShell.tsx�[0m:�[93m6�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'Sidebar'.
13:57:26.869 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m45�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroup'.
13:57:26.870 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m46�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupLabel'.
13:57:26.871 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m47�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupContent'.
13:57:26.871 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m48�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenu'.
13:57:26.872 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m49�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuItem'.
13:57:26.873 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m50�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuButton'.
13:57:26.874 ../../packages/layout build: �[96msrc/NavigationRenderer.tsx�[0m:�[93m51�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuAction'.
13:57:26.874 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m4�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'Sidebar'.
13:57:26.876 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m5�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarContent'.
13:57:26.877 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m6�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroup'.
13:57:26.877 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m7�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupLabel'.
13:57:26.878 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m8�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarGroupContent'.
13:57:26.879 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m9�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenu'.
13:57:26.879 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m10�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuItem'.
13:57:26.883 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m11�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuButton'.
13:57:26.884 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m12�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuSub'.
13:57:26.885 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m13�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuSubItem'.
13:57:26.886 ../../packages/layout build: �[96msrc/SidebarNav.tsx�[0m:�[93m14�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'SidebarMenuSubButton'.
13:59:08.374 ../../packages/plugin-view build: �[96msrc/FilterUI.tsx�[0m:�[93m14�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'Drawer'.
13:59:08.375 ../../packages/plugin-view build: �[96msrc/FilterUI.tsx�[0m:�[93m15�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerContent'.
13:59:08.375 ../../packages/plugin-view build: �[96msrc/FilterUI.tsx�[0m:�[93m16�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2724: �[0m'"@object-ui/components"' has no exported member named 'DrawerDescription'. Did you mean 'AlertDescription'?
13:59:08.375 ../../packages/plugin-view build: �[96msrc/FilterUI.tsx�[0m:�[93m17�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerHeader'.
13:59:08.375 ../../packages/plugin-view build: �[96msrc/FilterUI.tsx�[0m:�[93m18�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerTitle'.
13:59:08.376 ../../packages/plugin-view build: �[96msrc/ObjectView.tsx�[0m:�[93m47�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'Drawer'.
13:59:08.377 ../../packages/plugin-view build: �[96msrc/ObjectView.tsx�[0m:�[93m48�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerContent'.
13:59:08.377 ../../packages/plugin-view build: �[96msrc/ObjectView.tsx�[0m:�[93m49�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerHeader'.
13:59:08.377 ../../packages/plugin-view build: �[96msrc/ObjectView.tsx�[0m:�[93m50�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2305: �[0mModule '"@object-ui/components"' has no exported member 'DrawerTitle'.
13:59:08.377 ../../packages/plugin-view build: �[96msrc/ObjectView.tsx�[0m:�[93m51�[0m:�[93m3�[0m - �[91merror�[0m�[90m TS2724: �[0m'"@object-ui/components"' has no exported member named 'DrawerDescription'. Did you mean 'AlertDescription'?
13:59:49.823 Module not found: Can't resolve '@object-ui/react'
13:59:49.823 �[0m �[90m 603 |�[39m �[36mlet�[39m rt �[33m=�[39m xr�[33m;�[39m
13:59:49.823 �[90m 604 |�[39m �[36mtry�[39m {
13:59:49.824 �[31m�[1m>�[22m�[39m�[90m 605 |�[39m �[36mconst�[39m e �[33m=�[39m require(�[32m"@object-ui/react"�[39m)�[33m;�[39m
13:59:49.824 �[90m |�[39m �[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m�[31m�[1m^�[22m�[39m
13:59:49.824 �[90m 606 |�[39m e�[33m.�[39m�[33mSchemaRendererContext�[39m �[33m&&�[39m (rt �[33m=�[39m e�[33m.�[39m�[33mSchemaRendererContext�[39m)�[33m;�[39m
13:59:49.824 �[90m 607 |�[39m } �[36mcatch�[39m {
13:59:49.824 �[90m 608 |�[39m }�[0m
13:59:55.786 Failed to compile.
13:59:55.787 Type error: Module '"@object-ui/components"' has no exported member 'SidebarProvider'.
13:59:55.787 �[0m �[90m 3 |�[39m �[36mimport�[39m �[33mReact�[39m�[33m,�[39m { useMemo } �[36mfrom�[39m �[32m'react'�[39m�[33m;�[39m
13:59:55.787 �[90m 4 |�[39m �[36mimport�[39m { �[33mSchemaRenderer�[39m�[33m,�[39m �[33mSchemaRendererContext�[39m } �[36mfrom�[39m �[32m'@object-ui/react'�[39m�[33m;�[39m
13:59:55.787 �[31m�[1m>�[22m�[39m�[90m 5 |�[39m �[36mimport�[39m { �[33mSidebarProvider�[39m } �[36mfrom�[39m �[32m'@object-ui/components'�[39m�[33m;�[39m
13:59:55.787 �[90m |�[39m �[31m�[1m^�[22m�[39m
13:59:55.787 �[90m 6 |�[39m �[36mimport�[39m type { �[33mSchemaNode�[39m } �[36mfrom�[39m �[32m'@object-ui/core'�[39m�[33m;�[39m
13:59:55.787 �[90m 7 |�[39m �[36mimport�[39m { �[33mTabs�[39m�[33m,�[39m �[33mTab�[39m } �[36mfrom�[39m �[32m'fumadocs-ui/components/tabs'�[39m�[33m;�[39m
13:59:55.787 �[90m 8 |�[39m �[36mimport�[39m { �[33mCodeBlock�[39m�[33m,�[39m �[33mPre�[39m } �[36mfrom�[39m �[32m'fumadocs-ui/components/codeblock'�[39m�[33m;�[39m�[0m
13:59:55.965  ELIFECYCLE  Command failed with exit code 1.
13:59:56.002 Error: Command "pnpm --filter '../../packages/*' -r build && pnpm build" exited with 1

Copy link
Contributor Author

Copilot AI commented Mar 10, 2026

@copilot 13:57:10.313 ../../packages/components build: �[96msrc/ui/drawer.tsx�[0m:�[93m27�[0m:�[93m7�[0m - �[91merror�[0m�[90m TS2742: �[0mThe inferred type of 'DrawerTrigger' cannot be named without ...

These TS2742 (drawer.tsx, sidebar.tsx) and TS2339 (chart.tsx) errors are pre-existing in packages/components and not introduced by this PR. I verified by reverting to the base branch lockfile/deps and running tsc — the identical errors appear. The lockfile diff for this PR is only 3 lines (adding the better-auth entry), with no changes to @radix-ui, vaul, or recharts versions.

The @object-ui/auth package type-checks cleanly and all 81 tests + 11 console authHandler tests pass.

@hotlong hotlong marked this pull request as ready for review March 10, 2026 06:50
Copilot AI review requested due to automatic review settings March 10, 2026 06:50
@hotlong hotlong merged commit 8a63bad into main Mar 10, 2026
6 of 7 checks passed
Copy link
Contributor

Copilot AI left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Pull request overview

This PR replaces the custom HTTP-based createAuthClient in the @object-ui/auth package with a thin adapter wrapping the official better-auth/client createAuthClient. The existing AuthClient interface is preserved, so all downstream consumers (AuthProvider, AuthGuard, useAuth, forms, createAuthenticatedFetch) require no changes. A companion change renames the mock MSW handler's forgot-password route to forget-password to match the better-auth convention.

Changes:

  • createAuthClient now delegates to better-auth/client, with a resolveAuthURL helper to split a base URL into the origin/basePath pair required by the official client.
  • The forgot-password MSW mock handler and related tests are renamed to forget-password to match better-auth's convention.
  • better-auth is added as an explicit dependency in packages/auth/package.json and the lock file is updated accordingly.

Reviewed changes

Copilot reviewed 7 out of 8 changed files in this pull request and generated 4 comments.

Show a summary per file
File Description
packages/auth/src/createAuthClient.ts Core rewrite: delegates all auth methods to better-auth/client via adapter, adds resolveAuthURL/getWindowOrigin helpers
packages/auth/src/__tests__/createAuthClient.test.ts Tests updated with a routing-aware createMockFetch helper; each test creates its own client instance
packages/auth/package.json Adds better-auth ^1.5.4 as a runtime dependency
pnpm-lock.yaml Lock file updated to include the new better-auth dependency
apps/console/src/mocks/authHandlers.ts Renames /forgot-password handler to /forget-password to match better-auth convention
apps/console/src/__tests__/authHandlers.test.ts Test updated to call /forget-password
packages/auth/README.md Updates Quick Start example to use baseURL (removing old provider/apiUrl config)
ROADMAP.md Updates entry to reflect the forget-password endpoint name
Files not reviewed (1)
  • pnpm-lock.yaml: Language not supported

// exists at runtime but is not present in the default TS types.
type ForgetPasswordFn = (opts: { email: string; redirectTo: string }) =>
Promise<{ error: { message?: string; status: number } | null }>;
const forgetPw = (betterAuth as unknown as { forgetPassword: ForgetPasswordFn }).forgetPassword;
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The forgetPw variable (extracted from the cast betterAuth object) is called directly on line 119 without checking whether it is actually defined. If betterAuth.forgetPassword does not exist at runtime (e.g., on a version of better-auth that doesn't expose this method, or before the email plugin is configured), calling forgetPw(...) will throw a TypeError: forgetPw is not a function instead of a proper auth error. A null/undefined guard should be added: if forgetPw is falsy, throw an explicit Error('forgotPassword is not available in the current better-auth configuration') before attempting the call.

Suggested change
const forgetPw = (betterAuth as unknown as { forgetPassword: ForgetPasswordFn }).forgetPassword;
const forgetPw = (betterAuth as unknown as { forgetPassword?: ForgetPasswordFn }).forgetPassword;
if (!forgetPw || typeof forgetPw !== 'function') {
throw new Error('forgotPassword is not available in the current better-auth configuration');
}

Copilot uses AI. Check for mistakes.
type ForgetPasswordFn = (opts: { email: string; redirectTo: string }) =>
Promise<{ error: { message?: string; status: number } | null }>;
const forgetPw = (betterAuth as unknown as { forgetPassword: ForgetPasswordFn }).forgetPassword;
const { error } = await forgetPw({ email, redirectTo: '/' });
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The redirectTo value sent to the better-auth forgetPassword endpoint is hardcoded as '/'. This URL is embedded by the server into the password-reset email link (e.g. https://your-app.com/?token=...), which means users clicking the link will be directed to the root page instead of the actual reset-password route (e.g. /reset-password). The forgotPassword method's signature in AuthClient only accepts email, so there is no way for consumers to provide the correct redirect URL. Either the forgotPassword signature should be extended to accept an optional redirectTo parameter, or a sensible default (e.g. /reset-password) should be used rather than '/'.

Suggested change
const { error } = await forgetPw({ email, redirectTo: '/' });
const { error } = await forgetPw({ email, redirectTo: '/reset-password' });

Copilot uses AI. Check for mistakes.
Comment on lines 5 to 7
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createAuthClient } from '../createAuthClient';
import type { AuthClient } from '../types';
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

beforeEach and the AuthClient type are imported but never used in this test file after the refactor. The beforeEach was previously used to share client and mockFetch setup, but now each test creates its own local variables. These unused imports should be removed to keep the file clean and avoid TypeScript/linter warnings.

Suggested change
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { createAuthClient } from '../createAuthClient';
import type { AuthClient } from '../types';
import { describe, it, expect, vi } from 'vitest';
import { createAuthClient } from '../createAuthClient';

Copilot uses AI. Check for mistakes.
Comment on lines 42 to +44
it('creates a client with all expected methods', () => {
const { mockFn } = createMockFetch({});
const client = createAuthClient({ baseURL: 'http://localhost/api/auth', fetchFn: mockFn });
Copy link

Copilot AI Mar 10, 2026

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The resolveAuthURL function contains a non-trivial branch for handling relative URLs (falling back to window.location.origin in browsers and http://localhost in other environments), but this behavior is not covered by any test. The existing tests all use an absolute URL (http://localhost/api/auth), so the relative-URL path is never exercised. A test using a relative base URL (e.g. '/api/v1/auth') should be added to verify that the function correctly assembles the origin and basePath in a browser-like environment.

Copilot uses AI. Check for mistakes.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Refactor auth client to use official better-auth createAuthClient

3 participants