next-api-layer 0.1.9 → 0.1.10
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 +18 -0
- package/dist/client.cjs +1 -1
- package/dist/client.cjs.map +1 -1
- package/dist/client.d.cts +32 -2
- package/dist/client.d.ts +32 -2
- package/dist/client.js +1 -1
- package/dist/client.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -729,6 +729,24 @@ React context provider for client-side auth state.
|
|
|
729
729
|
</AuthProvider>
|
|
730
730
|
```
|
|
731
731
|
|
|
732
|
+
#### Custom Auth Response Parsing
|
|
733
|
+
|
|
734
|
+
For backends with non-standard auth response formats, use `parseAuthResponse`:
|
|
735
|
+
|
|
736
|
+
```tsx
|
|
737
|
+
<AuthProvider
|
|
738
|
+
// Standard props...
|
|
739
|
+
parseAuthResponse={(json) => ({
|
|
740
|
+
success: json.ok === true, // Your success field
|
|
741
|
+
message: json.msg, // Your message field
|
|
742
|
+
user: json.result?.user, // User data (optional)
|
|
743
|
+
errors: json.validation_errors, // Error details (optional)
|
|
744
|
+
})}
|
|
745
|
+
>
|
|
746
|
+
{children}
|
|
747
|
+
</AuthProvider>
|
|
748
|
+
```
|
|
749
|
+
|
|
732
750
|
### useAuth()
|
|
733
751
|
|
|
734
752
|
Hook to access authentication state.
|
package/dist/client.cjs
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
'use strict';var react=require('react'),
|
|
2
|
+
'use strict';var react=require('react'),E=require('swr'),jsxRuntime=require('react/jsx-runtime'),navigation=require('next/navigation');function _interopDefault(e){return e&&e.__esModule?e:{default:e}}var E__default=/*#__PURE__*/_interopDefault(E);var w=react.createContext(void 0);function F(r){if(!r||typeof r!="object")return null;let e=r;return e.success&&e.data?e.data:e.user?e.user:"id"in e||"email"in e||"name"in e||"type"in e?e:null}function G(r){if(!r||typeof r!="object")return false;let e=r;return e.token_type==="guest"||e.type==="guest"}function q({children:r,initialUser:e,userEndpoint:f="/api/auth/me",loginEndpoint:o="/api/auth/login",registerEndpoint:m="/api/auth/register",logoutEndpoint:x="/api/auth/logout",logoutRedirect:U,isGuestFn:k=G,parseResponse:l=F,parseAuthResponse:d,swrConfig:b={},onLogin:h,onLogout:D,onError:c}){let V=react.useCallback(async n=>{let s=await fetch(n);if(!s.ok){if(s.status===401)return null;throw new Error("Failed to fetch user")}let a=await s.json();return l(a)},[l]),{data:g,error:P,isLoading:C,mutate:u}=E__default.default(f,V,{fallbackData:e??void 0,revalidateOnFocus:true,revalidateOnReconnect:true,revalidateOnMount:!e,refreshInterval:0,shouldRetryOnError:false,...b,onError:n=>{c?.(n);}}),R=react.useCallback(async n=>{try{let s=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)}),a=await s.json();if(d){let t=d(a);return t.success?(t.user?(await u(t.user,!1),h?.(t.user)):await u(),{success:!0,user:t.user??void 0,message:t.message}):{success:!1,message:t.message||"Login failed",errors:t.errors}}let i=a;if(s.ok&&i.success!==!1){let t=l(a);return t?(await u(t,!1),h?.(t)):await u(),{success:!0,user:t??void 0,message:i.message}}return {success:!1,message:i.message||"Login failed",errors:i.errors}}catch(s){let a=s instanceof Error?s:new Error("Login failed");return c?.(a),{success:false,message:a.message}}},[o,u,h,c,l,d]),v=react.useCallback(async n=>{try{let s=await fetch(m,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)}),a=await s.json();if(d){let t=d(a);return t.success?(t.user?(await u(t.user,!1),h?.(t.user)):await u(),{success:!0,user:t.user??void 0,message:t.message}):{success:!1,message:t.message||"Registration failed",errors:t.errors}}let i=a;if(s.ok&&i.success!==!1){let t=l(a);return t?(await u(t,!1),h?.(t)):await u(),{success:!0,user:t??void 0,message:i.message}}return {success:!1,message:i.message||"Registration failed",errors:i.errors}}catch(s){let a=s instanceof Error?s:new Error("Registration failed");return c?.(a),{success:false,message:a.message}}},[m,u,h,c,l,d]),O=react.useCallback(async()=>{try{await fetch(x,{method:"POST"}),await u(null,!1),D?.(),U&&typeof window<"u"&&(window.location.href=U);}catch(n){let s=n instanceof Error?n:new Error("Logout failed");throw c?.(s),s}},[x,U,u,D,c]),y=react.useCallback(async()=>{await u();},[u]),T=k(g??null),j=!!g&&!T,I=react.useMemo(()=>({user:g??null,isLoading:C,isAuthenticated:j,isGuest:T,error:P??null,login:R,register:v,logout:O,refresh:y,mutate:y}),[g,C,j,T,P,R,v,O,y]);return jsxRuntime.jsx(w.Provider,{value:I,children:r})}function A(r={}){let e=react.useContext(w),f=navigation.useRouter();if(!e)throw new Error("useAuth must be used within an AuthProvider. Wrap your app with <AuthProvider> from next-api-layer/client");let{redirectTo:o,redirectIfFound:m}=r;return e.isLoading||(o&&!e.isAuthenticated&&!e.isGuest&&typeof window<"u"&&f.replace(o),m&&e.isAuthenticated&&typeof window<"u"&&f.replace(m)),e}function W(){let{user:r,isLoading:e,isAuthenticated:f,isGuest:o}=A();return {user:r,isLoading:e,isAuthenticated:f,isGuest:o}}function _(r="/login"){let e=A({redirectTo:r});if(!e.isLoading&&!e.isAuthenticated)throw new Error("Authentication required");return e}function z(r="/"){return A({redirectIfFound:r})}exports.AuthContext=w;exports.AuthProvider=q;exports.useAuth=A;exports.useRedirectIfAuth=z;exports.useRequireAuth=_;exports.useUser=W;//# sourceMappingURL=client.cjs.map
|
|
3
3
|
//# sourceMappingURL=client.cjs.map
|
package/dist/client.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/AuthProvider.tsx","../src/client/useAuth.ts"],"names":["AuthContext","createContext","defaultParseResponse","response","res","defaultIsGuest","user","u","AuthProvider","children","initialUser","userEndpoint","loginEndpoint","registerEndpoint","logoutEndpoint","logoutRedirect","isGuestFn","parseResponse","swrConfig","onLogin","onLogout","onError","fetcher","useCallback","url","json","error","isLoading","mutate","useSWR","err","login","credentials","userData","errorResponse","register","data","logout","refresh","isGuest","isAuthenticated","contextValue","useMemo","jsx","useAuth","options","context","useContext","router","useRouter","redirectTo","redirectIfFound","useUser","useRequireAuth","auth","useRedirectIfAuth"],"mappings":"uPA8CO,IAAMA,CAAAA,CAAcC,oBAAiD,MAAS,EAKrF,SAASC,CAAAA,CAA4BC,EAAiC,CACpE,GAAI,CAACA,CAAAA,EAAY,OAAOA,CAAAA,EAAa,QAAA,CAAU,OAAO,IAAA,CAEtD,IAAMC,CAAAA,CAAMD,CAAAA,CAGZ,OAAIC,CAAAA,CAAI,OAAA,EAAWA,EAAI,IAAA,CACdA,CAAAA,CAAI,IAAA,CAITA,CAAAA,CAAI,KACCA,CAAAA,CAAI,IAAA,CAIT,IAAA,GAAQA,CAAAA,EAAO,UAAWA,CAAAA,EAAO,MAAA,GAAUA,CAAAA,EAAO,MAAA,GAAUA,EACvDA,CAAAA,CAGF,IACT,CAGA,SAASC,EAAsBC,CAAAA,CAA6B,CAC1D,GAAI,CAACA,GAAQ,OAAOA,CAAAA,EAAS,QAAA,CAAU,OAAO,OAE9C,IAAMC,CAAAA,CAAID,CAAAA,CAMV,OAHIC,EAAE,UAAA,GAAe,OAAA,EAGjBA,EAAE,IAAA,GAAS,OAGjB,CAIO,SAASC,CAAAA,CAAsC,CACpD,QAAA,CAAAC,EACA,WAAA,CAAAC,CAAAA,CACA,YAAA,CAAAC,CAAAA,CAAe,eACf,aAAA,CAAAC,CAAAA,CAAgB,iBAAA,CAChB,gBAAA,CAAAC,EAAmB,oBAAA,CACnB,cAAA,CAAAC,CAAAA,CAAiB,kBAAA,CACjB,eAAAC,CAAAA,CACA,SAAA,CAAAC,CAAAA,CAAYX,CAAAA,CACZ,cAAAY,CAAAA,CAAgBf,CAAAA,CAChB,SAAA,CAAAgB,CAAAA,CAAY,EAAC,CACb,OAAA,CAAAC,CAAAA,CACA,QAAA,CAAAC,EACA,OAAA,CAAAC,CACF,EAAiD,CAG/C,IAAMC,EAAUC,iBAAAA,CAAY,MAAOC,CAAAA,EAAuC,CACxE,IAAMpB,CAAAA,CAAM,MAAM,KAAA,CAAMoB,CAAG,EAE3B,GAAI,CAACpB,CAAAA,CAAI,EAAA,CAAI,CACX,GAAIA,CAAAA,CAAI,SAAW,GAAA,CACjB,OAAO,KAET,MAAM,IAAI,KAAA,CAAM,sBAAsB,CACxC,CAEA,IAAMqB,CAAAA,CAAO,MAAMrB,EAAI,IAAA,EAAK,CAC5B,OAAOa,CAAAA,CAAcQ,CAAI,CAC3B,CAAA,CAAG,CAACR,CAAa,CAAC,EAGZ,CACJ,IAAA,CAAMX,CAAAA,CACN,KAAA,CAAAoB,EACA,SAAA,CAAAC,CAAAA,CACA,MAAA,CAAAC,CACF,EAAIC,kBAAAA,CACFlB,CAAAA,CACAW,CAAAA,CACA,CACE,aAAcZ,CAAAA,EAAe,MAAA,CAC7B,iBAAA,CAAmB,IAAA,CACnB,sBAAuB,IAAA,CACvB,iBAAA,CAAmB,CAACA,CAAAA,CACpB,gBAAiB,CAAA,CACjB,kBAAA,CAAoB,KAAA,CACpB,GAAGQ,EACH,OAAA,CAAUY,CAAAA,EAAe,CACvBT,CAAAA,GAAUS,CAAG,EACf,CACF,CACF,CAAA,CAGMC,CAAAA,CAAQR,kBAAY,MAAOS,CAAAA,EAA8D,CAC7F,GAAI,CAOF,IAAMP,CAAAA,CAAO,KAAA,CAND,MAAM,MAAMb,CAAAA,CAAe,CACrC,MAAA,CAAQ,MAAA,CACR,QAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,KAAK,SAAA,CAAUoB,CAAW,CAClC,CAAC,GAEsB,IAAA,EAAK,CACtBC,CAAAA,CAAWhB,CAAAA,CAAcQ,CAAI,CAAA,CAEnC,GAAIQ,CAAAA,CACF,OAAA,MAAML,EAAOK,CAAAA,CAAU,CAAA,CAAK,EAC5Bd,CAAAA,GAAUc,CAAQ,EACX,CAAE,OAAA,CAAS,CAAA,CAAA,CAAM,IAAA,CAAMA,CAAS,CAAA,CAGzC,IAAMC,CAAAA,CAAgBT,CAAAA,CACtB,OAAO,CACL,OAAA,CAAS,CAAA,CAAA,CACT,OAAA,CAASS,EAAc,OAAA,EAAW,cAAA,CAClC,MAAA,CAAQA,CAAAA,CAAc,MACxB,CACF,CAAA,MAASJ,CAAAA,CAAK,CACZ,IAAMJ,CAAAA,CAAQI,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,KAAA,CAAM,cAAc,CAAA,CACnE,OAAAT,IAAUK,CAAK,CAAA,CACR,CAAE,OAAA,CAAS,KAAA,CAAO,QAASA,CAAAA,CAAM,OAAQ,CAClD,CACF,EAAG,CAACd,CAAAA,CAAegB,CAAAA,CAAQT,CAAAA,CAASE,EAASJ,CAAa,CAAC,CAAA,CAGrDkB,CAAAA,CAAWZ,kBAAY,MAAOa,CAAAA,EAAmD,CACrF,GAAI,CAOF,IAAMX,CAAAA,CAAO,KAAA,CAND,MAAM,KAAA,CAAMZ,EAAkB,CACxC,MAAA,CAAQ,MAAA,CACR,OAAA,CAAS,CAAE,cAAA,CAAgB,kBAAmB,CAAA,CAC9C,IAAA,CAAM,KAAK,SAAA,CAAUuB,CAAI,CAC3B,CAAC,CAAA,EAEsB,MAAK,CACtBH,CAAAA,CAAWhB,CAAAA,CAAcQ,CAAI,EAEnC,GAAIQ,CAAAA,CACF,OAAA,MAAML,CAAAA,CAAOK,EAAU,CAAA,CAAK,CAAA,CAC5Bd,CAAAA,GAAUc,CAAQ,EACX,CAAE,OAAA,CAAS,CAAA,CAAA,CAAM,IAAA,CAAMA,CAAS,CAAA,CAGzC,IAAMC,CAAAA,CAAgBT,CAAAA,CACtB,OAAO,CACL,OAAA,CAAS,CAAA,CAAA,CACT,OAAA,CAASS,EAAc,OAAA,EAAW,qBAAA,CAClC,MAAA,CAAQA,CAAAA,CAAc,MACxB,CACF,CAAA,MAASJ,EAAK,CACZ,IAAMJ,EAAQI,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,MAAM,qBAAqB,CAAA,CAC1E,OAAAT,CAAAA,GAAUK,CAAK,CAAA,CACR,CAAE,OAAA,CAAS,KAAA,CAAO,QAASA,CAAAA,CAAM,OAAQ,CAClD,CACF,CAAA,CAAG,CAACb,CAAAA,CAAkBe,CAAAA,CAAQT,CAAAA,CAASE,CAAAA,CAASJ,CAAa,CAAC,CAAA,CAGxDoB,CAAAA,CAASd,iBAAAA,CAAY,SAA2B,CACpD,GAAI,CACF,MAAM,MAAMT,CAAAA,CAAgB,CAAE,OAAQ,MAAO,CAAC,EAC9C,MAAMc,CAAAA,CAAO,IAAA,CAAM,CAAA,CAAK,EACxBR,CAAAA,IAAW,CAGPL,CAAAA,EAAkB,OAAO,OAAW,GAAA,GACtC,MAAA,CAAO,QAAA,CAAS,IAAA,CAAOA,GAE3B,CAAA,MAASe,CAAAA,CAAK,CACZ,IAAMJ,EAAQI,CAAAA,YAAe,KAAA,CAAQA,CAAAA,CAAM,IAAI,MAAM,eAAe,CAAA,CACpE,MAAAT,CAAAA,GAAUK,CAAK,CAAA,CACTA,CACR,CACF,CAAA,CAAG,CAACZ,CAAAA,CAAgBC,CAAAA,CAAgBa,EAAQR,CAAAA,CAAUC,CAAO,CAAC,CAAA,CAGxDiB,CAAAA,CAAUf,iBAAAA,CAAY,SAA2B,CACrD,MAAMK,CAAAA,GACR,CAAA,CAAG,CAACA,CAAM,CAAC,CAAA,CAGLW,CAAAA,CAAUvB,EAAUV,CAAAA,EAAQ,IAAI,EAChCkC,CAAAA,CAAkB,CAAC,CAAClC,CAAAA,EAAQ,CAACiC,CAAAA,CAG7BE,CAAAA,CAAeC,cAAiC,KAAO,CAC3D,IAAA,CAAMpC,CAAAA,EAAQ,KACd,SAAA,CAAAqB,CAAAA,CACA,eAAA,CAAAa,CAAAA,CACA,QAAAD,CAAAA,CACA,KAAA,CAAOb,GAAS,IAAA,CAChB,KAAA,CAAAK,EACA,QAAA,CAAAI,CAAAA,CACA,MAAA,CAAAE,CAAAA,CACA,QAAAC,CAAAA,CACA,MAAA,CAAQA,CACV,CAAA,CAAA,CAAI,CAAChC,CAAAA,CAAMqB,CAAAA,CAAWa,CAAAA,CAAiBD,CAAAA,CAASb,EAAOK,CAAAA,CAAOI,CAAAA,CAAUE,CAAAA,CAAQC,CAAO,CAAC,CAAA,CAExF,OACEK,cAAAA,CAAC3C,CAAAA,CAAY,SAAZ,CAAqB,KAAA,CAAOyC,CAAAA,CAC1B,QAAA,CAAAhC,EACH,CAEJ,CC7NO,SAASmC,CAAAA,CACdC,CAAAA,CAA0B,EAAC,CACF,CACzB,IAAMC,CAAAA,CAAUC,gBAAAA,CAAW/C,CAAW,EAChCgD,CAAAA,CAASC,oBAAAA,EAAU,CAEzB,GAAI,CAACH,CAAAA,CACH,MAAM,IAAI,KAAA,CACR,2GAEF,EAGF,GAAM,CAAE,UAAA,CAAAI,CAAAA,CAAY,gBAAAC,CAAgB,CAAA,CAAIN,CAAAA,CAGxC,OAAKC,EAAQ,SAAA,GACPI,CAAAA,EAAc,CAACJ,CAAAA,CAAQ,iBAAmB,CAACA,CAAAA,CAAQ,SACjD,OAAO,MAAA,CAAW,KACpBE,CAAAA,CAAO,OAAA,CAAQE,CAAU,CAAA,CAIzBC,GAAmBL,CAAAA,CAAQ,eAAA,EACzB,OAAO,MAAA,CAAW,KACpBE,CAAAA,CAAO,OAAA,CAAQG,CAAe,CAAA,CAAA,CAK7BL,CACT,CAOO,SAASM,CAAAA,EAAmC,CACjD,GAAM,CAAE,IAAA,CAAA9C,CAAAA,CAAM,SAAA,CAAAqB,EAAW,eAAA,CAAAa,CAAAA,CAAiB,OAAA,CAAAD,CAAQ,EAAIK,CAAAA,EAAe,CACrE,OAAO,CAAE,KAAAtC,CAAAA,CAAM,SAAA,CAAAqB,EAAW,eAAA,CAAAa,CAAAA,CAAiB,QAAAD,CAAQ,CACrD,CAOO,SAASc,EAAwCH,CAAAA,CAAa,QAAA,CAAU,CAC7E,IAAMI,EAAOV,CAAAA,CAAe,CAAE,UAAA,CAAAM,CAAW,CAAC,CAAA,CAE1C,GAAI,CAACI,CAAAA,CAAK,SAAA,EAAa,CAACA,CAAAA,CAAK,eAAA,CAC3B,MAAM,IAAI,MAAM,yBAAyB,CAAA,CAG3C,OAAOA,CACT,CAOO,SAASC,CAAAA,CAA2CL,CAAAA,CAAa,GAAA,CAAK,CAC3E,OAAON,CAAAA,CAAe,CAAE,eAAA,CAAiBM,CAAW,CAAC,CACvD","file":"client.cjs","sourcesContent":["'use client';\r\n\r\n/**\r\n * AuthProvider - Generic React context for any backend format\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * <AuthProvider>\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n * \r\n * @example With custom user type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; email: string; };\r\n * }\r\n * \r\n * <AuthProvider<MyUser>\r\n * initialUser={serverUser}\r\n * isGuestFn={(u) => u?.type === 'guest'}\r\n * parseResponse={(res) => res.data}\r\n * >\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useCallback, useMemo } from 'react';\r\nimport useSWR from 'swr';\r\nimport type { \r\n AuthContextValue, \r\n AuthProviderProps, \r\n LoginCredentials,\r\n RegisterData,\r\n AuthResult,\r\n DefaultUserData,\r\n ApiResponse,\r\n} from './types';\r\n\r\n// ==================== Context ====================\r\n\r\n// We use 'any' here because the context needs to work with any user type\r\n// The actual type safety comes from useAuth<TUser>() hook\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const AuthContext = createContext<AuthContextValue<any> | undefined>(undefined);\r\n\r\n// ==================== Default Functions ====================\r\n\r\n/** Default response parser - handles common API formats */\r\nfunction defaultParseResponse<TUser>(response: unknown): TUser | null {\r\n if (!response || typeof response !== 'object') return null;\r\n \r\n const res = response as Record<string, unknown>;\r\n \r\n // Format: { success: true, data: user }\r\n if (res.success && res.data) {\r\n return res.data as TUser;\r\n }\r\n \r\n // Format: { user: {...} }\r\n if (res.user) {\r\n return res.user as TUser;\r\n }\r\n \r\n // Format: user object directly\r\n if ('id' in res || 'email' in res || 'name' in res || 'type' in res) {\r\n return res as TUser;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/** Default guest check - handles common patterns */\r\nfunction defaultIsGuest<TUser>(user: TUser | null): boolean {\r\n if (!user || typeof user !== 'object') return false;\r\n \r\n const u = user as Record<string, unknown>;\r\n \r\n // Check token_type (flat structure)\r\n if (u.token_type === 'guest') return true;\r\n \r\n // Check type (nested structure)\r\n if (u.type === 'guest') return true;\r\n \r\n return false;\r\n}\r\n\r\n// ==================== Provider Component ====================\r\n\r\nexport function AuthProvider<TUser = DefaultUserData>({\r\n children,\r\n initialUser,\r\n userEndpoint = '/api/auth/me',\r\n loginEndpoint = '/api/auth/login',\r\n registerEndpoint = '/api/auth/register',\r\n logoutEndpoint = '/api/auth/logout',\r\n logoutRedirect,\r\n isGuestFn = defaultIsGuest,\r\n parseResponse = defaultParseResponse,\r\n swrConfig = {},\r\n onLogin,\r\n onLogout,\r\n onError,\r\n}: AuthProviderProps<TUser>): React.ReactElement {\r\n \r\n // Create fetcher with custom parser\r\n const fetcher = useCallback(async (url: string): Promise<TUser | null> => {\r\n const res = await fetch(url);\r\n \r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n return null;\r\n }\r\n throw new Error('Failed to fetch user');\r\n }\r\n \r\n const json = await res.json();\r\n return parseResponse(json);\r\n }, [parseResponse]);\r\n\r\n // Fetch user data with SWR\r\n const {\r\n data: user,\r\n error,\r\n isLoading,\r\n mutate,\r\n } = useSWR<TUser | null>(\r\n userEndpoint,\r\n fetcher,\r\n {\r\n fallbackData: initialUser ?? undefined,\r\n revalidateOnFocus: true,\r\n revalidateOnReconnect: true,\r\n revalidateOnMount: !initialUser,\r\n refreshInterval: 0,\r\n shouldRetryOnError: false,\r\n ...swrConfig,\r\n onError: (err: Error) => {\r\n onError?.(err);\r\n },\r\n }\r\n );\r\n\r\n // Login function\r\n const login = useCallback(async (credentials: LoginCredentials): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(loginEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(credentials),\r\n });\r\n\r\n const json = await res.json();\r\n const userData = parseResponse(json);\r\n\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n return { success: true, user: userData };\r\n }\r\n\r\n const errorResponse = json as ApiResponse;\r\n return {\r\n success: false,\r\n message: errorResponse.message || 'Login failed',\r\n errors: errorResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Login failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [loginEndpoint, mutate, onLogin, onError, parseResponse]);\r\n\r\n // Register function\r\n const register = useCallback(async (data: RegisterData): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(registerEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n const json = await res.json();\r\n const userData = parseResponse(json);\r\n\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n return { success: true, user: userData };\r\n }\r\n\r\n const errorResponse = json as ApiResponse;\r\n return {\r\n success: false,\r\n message: errorResponse.message || 'Registration failed',\r\n errors: errorResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Registration failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [registerEndpoint, mutate, onLogin, onError, parseResponse]);\r\n\r\n // Logout function\r\n const logout = useCallback(async (): Promise<void> => {\r\n try {\r\n await fetch(logoutEndpoint, { method: 'POST' });\r\n await mutate(null, false);\r\n onLogout?.();\r\n \r\n // Redirect after logout if configured\r\n if (logoutRedirect && typeof window !== 'undefined') {\r\n window.location.href = logoutRedirect;\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Logout failed');\r\n onError?.(error);\r\n throw error;\r\n }\r\n }, [logoutEndpoint, logoutRedirect, mutate, onLogout, onError]);\r\n\r\n // Refresh user data\r\n const refresh = useCallback(async (): Promise<void> => {\r\n await mutate();\r\n }, [mutate]);\r\n\r\n // Compute derived state using custom isGuestFn\r\n const isGuest = isGuestFn(user ?? null);\r\n const isAuthenticated = !!user && !isGuest;\r\n\r\n // Memoize context value\r\n const contextValue = useMemo<AuthContextValue<TUser>>(() => ({\r\n user: user ?? null,\r\n isLoading,\r\n isAuthenticated,\r\n isGuest,\r\n error: error ?? null,\r\n login,\r\n register,\r\n logout,\r\n refresh,\r\n mutate: refresh,\r\n }), [user, isLoading, isAuthenticated, isGuest, error, login, register, logout, refresh]);\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>\r\n {children}\r\n </AuthContext.Provider>\r\n );\r\n}\r\n","'use client';\r\n\r\n/**\r\n * useAuth Hook - Generic for any user type\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * const { user, isAuthenticated, logout } = useAuth();\r\n * ```\r\n * \r\n * @example With custom type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; };\r\n * }\r\n * \r\n * const { user } = useAuth<MyUser>();\r\n * // user is MyUser | null\r\n * ```\r\n */\r\n\r\nimport { useContext } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport { AuthContext } from './AuthProvider';\r\nimport type { AuthContextValue, UseAuthOptions, DefaultUserData } from './types';\r\n\r\n/**\r\n * Hook to access authentication state and methods\r\n * \r\n * @typeParam TUser - User data type (defaults to DefaultUserData)\r\n */\r\nexport function useAuth<TUser = DefaultUserData>(\r\n options: UseAuthOptions = {}\r\n): AuthContextValue<TUser> {\r\n const context = useContext(AuthContext) as AuthContextValue<TUser> | undefined;\r\n const router = useRouter();\r\n\r\n if (!context) {\r\n throw new Error(\r\n 'useAuth must be used within an AuthProvider. ' +\r\n 'Wrap your app with <AuthProvider> from next-api-layer/client'\r\n );\r\n }\r\n\r\n const { redirectTo, redirectIfFound } = options;\r\n\r\n // Handle redirects based on auth state\r\n if (!context.isLoading) {\r\n if (redirectTo && !context.isAuthenticated && !context.isGuest) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectTo);\r\n }\r\n }\r\n\r\n if (redirectIfFound && context.isAuthenticated) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectIfFound);\r\n }\r\n }\r\n }\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get only the user object\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useUser<TUser = DefaultUserData>() {\r\n const { user, isLoading, isAuthenticated, isGuest } = useAuth<TUser>();\r\n return { user, isLoading, isAuthenticated, isGuest };\r\n}\r\n\r\n/**\r\n * Hook for protected pages - redirects if not authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRequireAuth<TUser = DefaultUserData>(redirectTo = '/login') {\r\n const auth = useAuth<TUser>({ redirectTo });\r\n \r\n if (!auth.isLoading && !auth.isAuthenticated) {\r\n throw new Error('Authentication required');\r\n }\r\n \r\n return auth;\r\n}\r\n\r\n/**\r\n * Hook for auth pages - redirects if already authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo = '/') {\r\n return useAuth<TUser>({ redirectIfFound: redirectTo });\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/AuthProvider.tsx","../src/client/useAuth.ts"],"names":["AuthContext","createContext","defaultParseResponse","response","res","defaultIsGuest","user","u","AuthProvider","children","initialUser","userEndpoint","loginEndpoint","registerEndpoint","logoutEndpoint","logoutRedirect","isGuestFn","parseResponse","parseAuthResponse","swrConfig","onLogin","onLogout","onError","fetcher","useCallback","url","json","error","isLoading","mutate","useSWR","err","login","credentials","parsed","apiResponse","userData","register","data","logout","refresh","isGuest","isAuthenticated","contextValue","useMemo","jsx","useAuth","options","context","useContext","router","useRouter","redirectTo","redirectIfFound","useUser","useRequireAuth","auth","useRedirectIfAuth"],"mappings":"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","file":"client.cjs","sourcesContent":["'use client';\r\n\r\n/**\r\n * AuthProvider - Generic React context for any backend format\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * <AuthProvider>\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n * \r\n * @example With custom user type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; email: string; };\r\n * }\r\n * \r\n * <AuthProvider<MyUser>\r\n * initialUser={serverUser}\r\n * isGuestFn={(u) => u?.type === 'guest'}\r\n * parseResponse={(res) => res.data}\r\n * >\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useCallback, useMemo } from 'react';\r\nimport useSWR from 'swr';\r\nimport type { \r\n AuthContextValue, \r\n AuthProviderProps, \r\n LoginCredentials,\r\n RegisterData,\r\n AuthResult,\r\n DefaultUserData,\r\n ApiResponse,\r\n} from './types';\r\n\r\n// ==================== Context ====================\r\n\r\n// We use 'any' here because the context needs to work with any user type\r\n// The actual type safety comes from useAuth<TUser>() hook\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const AuthContext = createContext<AuthContextValue<any> | undefined>(undefined);\r\n\r\n// ==================== Default Functions ====================\r\n\r\n/** Default response parser - handles common API formats */\r\nfunction defaultParseResponse<TUser>(response: unknown): TUser | null {\r\n if (!response || typeof response !== 'object') return null;\r\n \r\n const res = response as Record<string, unknown>;\r\n \r\n // Format: { success: true, data: user }\r\n if (res.success && res.data) {\r\n return res.data as TUser;\r\n }\r\n \r\n // Format: { user: {...} }\r\n if (res.user) {\r\n return res.user as TUser;\r\n }\r\n \r\n // Format: user object directly\r\n if ('id' in res || 'email' in res || 'name' in res || 'type' in res) {\r\n return res as TUser;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/** Default guest check - handles common patterns */\r\nfunction defaultIsGuest<TUser>(user: TUser | null): boolean {\r\n if (!user || typeof user !== 'object') return false;\r\n \r\n const u = user as Record<string, unknown>;\r\n \r\n // Check token_type (flat structure)\r\n if (u.token_type === 'guest') return true;\r\n \r\n // Check type (nested structure)\r\n if (u.type === 'guest') return true;\r\n \r\n return false;\r\n}\r\n\r\n// ==================== Provider Component ====================\r\n\r\nexport function AuthProvider<TUser = DefaultUserData>({\r\n children,\r\n initialUser,\r\n userEndpoint = '/api/auth/me',\r\n loginEndpoint = '/api/auth/login',\r\n registerEndpoint = '/api/auth/register',\r\n logoutEndpoint = '/api/auth/logout',\r\n logoutRedirect,\r\n isGuestFn = defaultIsGuest,\r\n parseResponse = defaultParseResponse,\r\n parseAuthResponse,\r\n swrConfig = {},\r\n onLogin,\r\n onLogout,\r\n onError,\r\n}: AuthProviderProps<TUser>): React.ReactElement {\r\n \r\n // Create fetcher with custom parser\r\n const fetcher = useCallback(async (url: string): Promise<TUser | null> => {\r\n const res = await fetch(url);\r\n \r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n return null;\r\n }\r\n throw new Error('Failed to fetch user');\r\n }\r\n \r\n const json = await res.json();\r\n return parseResponse(json);\r\n }, [parseResponse]);\r\n\r\n // Fetch user data with SWR\r\n const {\r\n data: user,\r\n error,\r\n isLoading,\r\n mutate,\r\n } = useSWR<TUser | null>(\r\n userEndpoint,\r\n fetcher,\r\n {\r\n fallbackData: initialUser ?? undefined,\r\n revalidateOnFocus: true,\r\n revalidateOnReconnect: true,\r\n revalidateOnMount: !initialUser,\r\n refreshInterval: 0,\r\n shouldRetryOnError: false,\r\n ...swrConfig,\r\n onError: (err: Error) => {\r\n onError?.(err);\r\n },\r\n }\r\n );\r\n\r\n // Login function\r\n const login = useCallback(async (credentials: LoginCredentials): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(loginEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(credentials),\r\n });\r\n\r\n const json = await res.json();\r\n\r\n // Use custom parser if provided\r\n if (parseAuthResponse) {\r\n const parsed = parseAuthResponse(json);\r\n if (parsed.success) {\r\n if (parsed.user) {\r\n await mutate(parsed.user, false);\r\n onLogin?.(parsed.user);\r\n } else {\r\n // No user data, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: parsed.user ?? undefined, message: parsed.message };\r\n }\r\n return {\r\n success: false,\r\n message: parsed.message || 'Login failed',\r\n errors: parsed.errors,\r\n };\r\n }\r\n\r\n // Default behavior: check res.ok and json.success\r\n const apiResponse = json as ApiResponse;\r\n if (res.ok && apiResponse.success !== false) {\r\n // Try to extract user data using parseResponse\r\n const userData = parseResponse(json);\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n } else {\r\n // No user data in response, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: userData ?? undefined, message: apiResponse.message };\r\n }\r\n\r\n return {\r\n success: false,\r\n message: apiResponse.message || 'Login failed',\r\n errors: apiResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Login failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [loginEndpoint, mutate, onLogin, onError, parseResponse, parseAuthResponse]);\r\n\r\n // Register function\r\n const register = useCallback(async (data: RegisterData): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(registerEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n const json = await res.json();\r\n\r\n // Use custom parser if provided\r\n if (parseAuthResponse) {\r\n const parsed = parseAuthResponse(json);\r\n if (parsed.success) {\r\n if (parsed.user) {\r\n await mutate(parsed.user, false);\r\n onLogin?.(parsed.user);\r\n } else {\r\n // No user data, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: parsed.user ?? undefined, message: parsed.message };\r\n }\r\n return {\r\n success: false,\r\n message: parsed.message || 'Registration failed',\r\n errors: parsed.errors,\r\n };\r\n }\r\n\r\n // Default behavior: check res.ok and json.success\r\n const apiResponse = json as ApiResponse;\r\n if (res.ok && apiResponse.success !== false) {\r\n // Try to extract user data using parseResponse\r\n const userData = parseResponse(json);\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n } else {\r\n // No user data in response, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: userData ?? undefined, message: apiResponse.message };\r\n }\r\n\r\n return {\r\n success: false,\r\n message: apiResponse.message || 'Registration failed',\r\n errors: apiResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Registration failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [registerEndpoint, mutate, onLogin, onError, parseResponse, parseAuthResponse]);\r\n\r\n // Logout function\r\n const logout = useCallback(async (): Promise<void> => {\r\n try {\r\n await fetch(logoutEndpoint, { method: 'POST' });\r\n await mutate(null, false);\r\n onLogout?.();\r\n \r\n // Redirect after logout if configured\r\n if (logoutRedirect && typeof window !== 'undefined') {\r\n window.location.href = logoutRedirect;\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Logout failed');\r\n onError?.(error);\r\n throw error;\r\n }\r\n }, [logoutEndpoint, logoutRedirect, mutate, onLogout, onError]);\r\n\r\n // Refresh user data\r\n const refresh = useCallback(async (): Promise<void> => {\r\n await mutate();\r\n }, [mutate]);\r\n\r\n // Compute derived state using custom isGuestFn\r\n const isGuest = isGuestFn(user ?? null);\r\n const isAuthenticated = !!user && !isGuest;\r\n\r\n // Memoize context value\r\n const contextValue = useMemo<AuthContextValue<TUser>>(() => ({\r\n user: user ?? null,\r\n isLoading,\r\n isAuthenticated,\r\n isGuest,\r\n error: error ?? null,\r\n login,\r\n register,\r\n logout,\r\n refresh,\r\n mutate: refresh,\r\n }), [user, isLoading, isAuthenticated, isGuest, error, login, register, logout, refresh]);\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>\r\n {children}\r\n </AuthContext.Provider>\r\n );\r\n}\r\n","'use client';\r\n\r\n/**\r\n * useAuth Hook - Generic for any user type\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * const { user, isAuthenticated, logout } = useAuth();\r\n * ```\r\n * \r\n * @example With custom type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; };\r\n * }\r\n * \r\n * const { user } = useAuth<MyUser>();\r\n * // user is MyUser | null\r\n * ```\r\n */\r\n\r\nimport { useContext } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport { AuthContext } from './AuthProvider';\r\nimport type { AuthContextValue, UseAuthOptions, DefaultUserData } from './types';\r\n\r\n/**\r\n * Hook to access authentication state and methods\r\n * \r\n * @typeParam TUser - User data type (defaults to DefaultUserData)\r\n */\r\nexport function useAuth<TUser = DefaultUserData>(\r\n options: UseAuthOptions = {}\r\n): AuthContextValue<TUser> {\r\n const context = useContext(AuthContext) as AuthContextValue<TUser> | undefined;\r\n const router = useRouter();\r\n\r\n if (!context) {\r\n throw new Error(\r\n 'useAuth must be used within an AuthProvider. ' +\r\n 'Wrap your app with <AuthProvider> from next-api-layer/client'\r\n );\r\n }\r\n\r\n const { redirectTo, redirectIfFound } = options;\r\n\r\n // Handle redirects based on auth state\r\n if (!context.isLoading) {\r\n if (redirectTo && !context.isAuthenticated && !context.isGuest) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectTo);\r\n }\r\n }\r\n\r\n if (redirectIfFound && context.isAuthenticated) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectIfFound);\r\n }\r\n }\r\n }\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get only the user object\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useUser<TUser = DefaultUserData>() {\r\n const { user, isLoading, isAuthenticated, isGuest } = useAuth<TUser>();\r\n return { user, isLoading, isAuthenticated, isGuest };\r\n}\r\n\r\n/**\r\n * Hook for protected pages - redirects if not authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRequireAuth<TUser = DefaultUserData>(redirectTo = '/login') {\r\n const auth = useAuth<TUser>({ redirectTo });\r\n \r\n if (!auth.isLoading && !auth.isAuthenticated) {\r\n throw new Error('Authentication required');\r\n }\r\n \r\n return auth;\r\n}\r\n\r\n/**\r\n * Hook for auth pages - redirects if already authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo = '/') {\r\n return useAuth<TUser>({ redirectIfFound: redirectTo });\r\n}\r\n"]}
|
package/dist/client.d.cts
CHANGED
|
@@ -40,6 +40,20 @@ interface AuthResult<TUser = DefaultUserData> {
|
|
|
40
40
|
user?: TUser;
|
|
41
41
|
errors?: Record<string, unknown>;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Return type for parseAuthResponse function.
|
|
45
|
+
* Used to parse login/register responses from different backend formats.
|
|
46
|
+
*/
|
|
47
|
+
interface AuthResponseParsed<TUser = DefaultUserData> {
|
|
48
|
+
/** Whether the auth operation was successful */
|
|
49
|
+
success: boolean;
|
|
50
|
+
/** Optional message from the backend */
|
|
51
|
+
message?: string;
|
|
52
|
+
/** User data if available (optional - will be fetched from /me if not provided) */
|
|
53
|
+
user?: TUser | null;
|
|
54
|
+
/** Validation or other errors */
|
|
55
|
+
errors?: Record<string, unknown>;
|
|
56
|
+
}
|
|
43
57
|
interface AuthProviderProps<TUser = DefaultUserData> {
|
|
44
58
|
children: React.ReactNode;
|
|
45
59
|
/** Initial user data from server (SSR) */
|
|
@@ -61,9 +75,25 @@ interface AuthProviderProps<TUser = DefaultUserData> {
|
|
|
61
75
|
isGuestFn?: (user: TUser | null) => boolean;
|
|
62
76
|
/**
|
|
63
77
|
* Function to parse API response and extract user data
|
|
78
|
+
* Used for /me endpoint responses
|
|
64
79
|
* @default (response) => response.data || response.user || response
|
|
65
80
|
*/
|
|
66
81
|
parseResponse?: (response: unknown) => TUser | null;
|
|
82
|
+
/**
|
|
83
|
+
* Function to parse login/register responses.
|
|
84
|
+
* Use this when your backend has a non-standard auth response format.
|
|
85
|
+
* If not provided, uses smart default: res.ok && json.success !== false
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* parseAuthResponse={(json) => ({
|
|
90
|
+
* success: json.ok === true,
|
|
91
|
+
* user: json.result?.user,
|
|
92
|
+
* message: json.message,
|
|
93
|
+
* })}
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
parseAuthResponse?: (response: unknown) => AuthResponseParsed<TUser>;
|
|
67
97
|
/** SWR config overrides */
|
|
68
98
|
swrConfig?: {
|
|
69
99
|
refreshInterval?: number;
|
|
@@ -134,7 +164,7 @@ type UserData = DefaultUserData;
|
|
|
134
164
|
*/
|
|
135
165
|
|
|
136
166
|
declare const AuthContext: React$1.Context<AuthContextValue<any> | undefined>;
|
|
137
|
-
declare function AuthProvider<TUser = DefaultUserData>({ children, initialUser, userEndpoint, loginEndpoint, registerEndpoint, logoutEndpoint, logoutRedirect, isGuestFn, parseResponse, swrConfig, onLogin, onLogout, onError, }: AuthProviderProps<TUser>): React$1.ReactElement;
|
|
167
|
+
declare function AuthProvider<TUser = DefaultUserData>({ children, initialUser, userEndpoint, loginEndpoint, registerEndpoint, logoutEndpoint, logoutRedirect, isGuestFn, parseResponse, parseAuthResponse, swrConfig, onLogin, onLogout, onError, }: AuthProviderProps<TUser>): React$1.ReactElement;
|
|
138
168
|
|
|
139
169
|
/**
|
|
140
170
|
* Hook to access authentication state and methods
|
|
@@ -166,4 +196,4 @@ declare function useRequireAuth<TUser = DefaultUserData>(redirectTo?: string): A
|
|
|
166
196
|
*/
|
|
167
197
|
declare function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo?: string): AuthContextValue<TUser>;
|
|
168
198
|
|
|
169
|
-
export { type ApiResponse, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthResult, type DefaultUserData, type LoginCredentials, type RegisterData, type UseAuthOptions, type UserData, useAuth, useRedirectIfAuth, useRequireAuth, useUser };
|
|
199
|
+
export { type ApiResponse, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthResponseParsed, type AuthResult, type DefaultUserData, type LoginCredentials, type RegisterData, type UseAuthOptions, type UserData, useAuth, useRedirectIfAuth, useRequireAuth, useUser };
|
package/dist/client.d.ts
CHANGED
|
@@ -40,6 +40,20 @@ interface AuthResult<TUser = DefaultUserData> {
|
|
|
40
40
|
user?: TUser;
|
|
41
41
|
errors?: Record<string, unknown>;
|
|
42
42
|
}
|
|
43
|
+
/**
|
|
44
|
+
* Return type for parseAuthResponse function.
|
|
45
|
+
* Used to parse login/register responses from different backend formats.
|
|
46
|
+
*/
|
|
47
|
+
interface AuthResponseParsed<TUser = DefaultUserData> {
|
|
48
|
+
/** Whether the auth operation was successful */
|
|
49
|
+
success: boolean;
|
|
50
|
+
/** Optional message from the backend */
|
|
51
|
+
message?: string;
|
|
52
|
+
/** User data if available (optional - will be fetched from /me if not provided) */
|
|
53
|
+
user?: TUser | null;
|
|
54
|
+
/** Validation or other errors */
|
|
55
|
+
errors?: Record<string, unknown>;
|
|
56
|
+
}
|
|
43
57
|
interface AuthProviderProps<TUser = DefaultUserData> {
|
|
44
58
|
children: React.ReactNode;
|
|
45
59
|
/** Initial user data from server (SSR) */
|
|
@@ -61,9 +75,25 @@ interface AuthProviderProps<TUser = DefaultUserData> {
|
|
|
61
75
|
isGuestFn?: (user: TUser | null) => boolean;
|
|
62
76
|
/**
|
|
63
77
|
* Function to parse API response and extract user data
|
|
78
|
+
* Used for /me endpoint responses
|
|
64
79
|
* @default (response) => response.data || response.user || response
|
|
65
80
|
*/
|
|
66
81
|
parseResponse?: (response: unknown) => TUser | null;
|
|
82
|
+
/**
|
|
83
|
+
* Function to parse login/register responses.
|
|
84
|
+
* Use this when your backend has a non-standard auth response format.
|
|
85
|
+
* If not provided, uses smart default: res.ok && json.success !== false
|
|
86
|
+
*
|
|
87
|
+
* @example
|
|
88
|
+
* ```tsx
|
|
89
|
+
* parseAuthResponse={(json) => ({
|
|
90
|
+
* success: json.ok === true,
|
|
91
|
+
* user: json.result?.user,
|
|
92
|
+
* message: json.message,
|
|
93
|
+
* })}
|
|
94
|
+
* ```
|
|
95
|
+
*/
|
|
96
|
+
parseAuthResponse?: (response: unknown) => AuthResponseParsed<TUser>;
|
|
67
97
|
/** SWR config overrides */
|
|
68
98
|
swrConfig?: {
|
|
69
99
|
refreshInterval?: number;
|
|
@@ -134,7 +164,7 @@ type UserData = DefaultUserData;
|
|
|
134
164
|
*/
|
|
135
165
|
|
|
136
166
|
declare const AuthContext: React$1.Context<AuthContextValue<any> | undefined>;
|
|
137
|
-
declare function AuthProvider<TUser = DefaultUserData>({ children, initialUser, userEndpoint, loginEndpoint, registerEndpoint, logoutEndpoint, logoutRedirect, isGuestFn, parseResponse, swrConfig, onLogin, onLogout, onError, }: AuthProviderProps<TUser>): React$1.ReactElement;
|
|
167
|
+
declare function AuthProvider<TUser = DefaultUserData>({ children, initialUser, userEndpoint, loginEndpoint, registerEndpoint, logoutEndpoint, logoutRedirect, isGuestFn, parseResponse, parseAuthResponse, swrConfig, onLogin, onLogout, onError, }: AuthProviderProps<TUser>): React$1.ReactElement;
|
|
138
168
|
|
|
139
169
|
/**
|
|
140
170
|
* Hook to access authentication state and methods
|
|
@@ -166,4 +196,4 @@ declare function useRequireAuth<TUser = DefaultUserData>(redirectTo?: string): A
|
|
|
166
196
|
*/
|
|
167
197
|
declare function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo?: string): AuthContextValue<TUser>;
|
|
168
198
|
|
|
169
|
-
export { type ApiResponse, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthResult, type DefaultUserData, type LoginCredentials, type RegisterData, type UseAuthOptions, type UserData, useAuth, useRedirectIfAuth, useRequireAuth, useUser };
|
|
199
|
+
export { type ApiResponse, AuthContext, type AuthContextValue, AuthProvider, type AuthProviderProps, type AuthResponseParsed, type AuthResult, type DefaultUserData, type LoginCredentials, type RegisterData, type UseAuthOptions, type UserData, useAuth, useRedirectIfAuth, useRequireAuth, useUser };
|
package/dist/client.js
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
"use client";
|
|
2
|
-
import {createContext,useCallback,useMemo,useContext}from'react';import
|
|
2
|
+
import {createContext,useCallback,useMemo,useContext}from'react';import E from'swr';import {jsx}from'react/jsx-runtime';import {useRouter}from'next/navigation';var w=createContext(void 0);function F(r){if(!r||typeof r!="object")return null;let e=r;return e.success&&e.data?e.data:e.user?e.user:"id"in e||"email"in e||"name"in e||"type"in e?e:null}function G(r){if(!r||typeof r!="object")return false;let e=r;return e.token_type==="guest"||e.type==="guest"}function q({children:r,initialUser:e,userEndpoint:f="/api/auth/me",loginEndpoint:o="/api/auth/login",registerEndpoint:m="/api/auth/register",logoutEndpoint:x="/api/auth/logout",logoutRedirect:U,isGuestFn:k=G,parseResponse:l=F,parseAuthResponse:d,swrConfig:b={},onLogin:h,onLogout:D,onError:c}){let V=useCallback(async n=>{let s=await fetch(n);if(!s.ok){if(s.status===401)return null;throw new Error("Failed to fetch user")}let a=await s.json();return l(a)},[l]),{data:g,error:P,isLoading:C,mutate:u}=E(f,V,{fallbackData:e??void 0,revalidateOnFocus:true,revalidateOnReconnect:true,revalidateOnMount:!e,refreshInterval:0,shouldRetryOnError:false,...b,onError:n=>{c?.(n);}}),R=useCallback(async n=>{try{let s=await fetch(o,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)}),a=await s.json();if(d){let t=d(a);return t.success?(t.user?(await u(t.user,!1),h?.(t.user)):await u(),{success:!0,user:t.user??void 0,message:t.message}):{success:!1,message:t.message||"Login failed",errors:t.errors}}let i=a;if(s.ok&&i.success!==!1){let t=l(a);return t?(await u(t,!1),h?.(t)):await u(),{success:!0,user:t??void 0,message:i.message}}return {success:!1,message:i.message||"Login failed",errors:i.errors}}catch(s){let a=s instanceof Error?s:new Error("Login failed");return c?.(a),{success:false,message:a.message}}},[o,u,h,c,l,d]),v=useCallback(async n=>{try{let s=await fetch(m,{method:"POST",headers:{"Content-Type":"application/json"},body:JSON.stringify(n)}),a=await s.json();if(d){let t=d(a);return t.success?(t.user?(await u(t.user,!1),h?.(t.user)):await u(),{success:!0,user:t.user??void 0,message:t.message}):{success:!1,message:t.message||"Registration failed",errors:t.errors}}let i=a;if(s.ok&&i.success!==!1){let t=l(a);return t?(await u(t,!1),h?.(t)):await u(),{success:!0,user:t??void 0,message:i.message}}return {success:!1,message:i.message||"Registration failed",errors:i.errors}}catch(s){let a=s instanceof Error?s:new Error("Registration failed");return c?.(a),{success:false,message:a.message}}},[m,u,h,c,l,d]),O=useCallback(async()=>{try{await fetch(x,{method:"POST"}),await u(null,!1),D?.(),U&&typeof window<"u"&&(window.location.href=U);}catch(n){let s=n instanceof Error?n:new Error("Logout failed");throw c?.(s),s}},[x,U,u,D,c]),y=useCallback(async()=>{await u();},[u]),T=k(g??null),j=!!g&&!T,I=useMemo(()=>({user:g??null,isLoading:C,isAuthenticated:j,isGuest:T,error:P??null,login:R,register:v,logout:O,refresh:y,mutate:y}),[g,C,j,T,P,R,v,O,y]);return jsx(w.Provider,{value:I,children:r})}function A(r={}){let e=useContext(w),f=useRouter();if(!e)throw new Error("useAuth must be used within an AuthProvider. Wrap your app with <AuthProvider> from next-api-layer/client");let{redirectTo:o,redirectIfFound:m}=r;return e.isLoading||(o&&!e.isAuthenticated&&!e.isGuest&&typeof window<"u"&&f.replace(o),m&&e.isAuthenticated&&typeof window<"u"&&f.replace(m)),e}function W(){let{user:r,isLoading:e,isAuthenticated:f,isGuest:o}=A();return {user:r,isLoading:e,isAuthenticated:f,isGuest:o}}function _(r="/login"){let e=A({redirectTo:r});if(!e.isLoading&&!e.isAuthenticated)throw new Error("Authentication required");return e}function z(r="/"){return A({redirectIfFound:r})}export{w as AuthContext,q as AuthProvider,A as useAuth,z as useRedirectIfAuth,_ as useRequireAuth,W as useUser};//# sourceMappingURL=client.js.map
|
|
3
3
|
//# sourceMappingURL=client.js.map
|
package/dist/client.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/client/AuthProvider.tsx","../src/client/useAuth.ts"],"names":["AuthContext","createContext","defaultParseResponse","response","res","defaultIsGuest","user","u","AuthProvider","children","initialUser","userEndpoint","loginEndpoint","registerEndpoint","logoutEndpoint","logoutRedirect","isGuestFn","parseResponse","swrConfig","onLogin","onLogout","onError","fetcher","useCallback","url","json","error","isLoading","mutate","useSWR","err","login","credentials","userData","errorResponse","register","data","logout","refresh","isGuest","isAuthenticated","contextValue","useMemo","jsx","useAuth","options","context","useContext","router","useRouter","redirectTo","redirectIfFound","useUser","useRequireAuth","auth","useRedirectIfAuth"],"mappings":"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","file":"client.js","sourcesContent":["'use client';\r\n\r\n/**\r\n * AuthProvider - Generic React context for any backend format\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * <AuthProvider>\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n * \r\n * @example With custom user type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; email: string; };\r\n * }\r\n * \r\n * <AuthProvider<MyUser>\r\n * initialUser={serverUser}\r\n * isGuestFn={(u) => u?.type === 'guest'}\r\n * parseResponse={(res) => res.data}\r\n * >\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useCallback, useMemo } from 'react';\r\nimport useSWR from 'swr';\r\nimport type { \r\n AuthContextValue, \r\n AuthProviderProps, \r\n LoginCredentials,\r\n RegisterData,\r\n AuthResult,\r\n DefaultUserData,\r\n ApiResponse,\r\n} from './types';\r\n\r\n// ==================== Context ====================\r\n\r\n// We use 'any' here because the context needs to work with any user type\r\n// The actual type safety comes from useAuth<TUser>() hook\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const AuthContext = createContext<AuthContextValue<any> | undefined>(undefined);\r\n\r\n// ==================== Default Functions ====================\r\n\r\n/** Default response parser - handles common API formats */\r\nfunction defaultParseResponse<TUser>(response: unknown): TUser | null {\r\n if (!response || typeof response !== 'object') return null;\r\n \r\n const res = response as Record<string, unknown>;\r\n \r\n // Format: { success: true, data: user }\r\n if (res.success && res.data) {\r\n return res.data as TUser;\r\n }\r\n \r\n // Format: { user: {...} }\r\n if (res.user) {\r\n return res.user as TUser;\r\n }\r\n \r\n // Format: user object directly\r\n if ('id' in res || 'email' in res || 'name' in res || 'type' in res) {\r\n return res as TUser;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/** Default guest check - handles common patterns */\r\nfunction defaultIsGuest<TUser>(user: TUser | null): boolean {\r\n if (!user || typeof user !== 'object') return false;\r\n \r\n const u = user as Record<string, unknown>;\r\n \r\n // Check token_type (flat structure)\r\n if (u.token_type === 'guest') return true;\r\n \r\n // Check type (nested structure)\r\n if (u.type === 'guest') return true;\r\n \r\n return false;\r\n}\r\n\r\n// ==================== Provider Component ====================\r\n\r\nexport function AuthProvider<TUser = DefaultUserData>({\r\n children,\r\n initialUser,\r\n userEndpoint = '/api/auth/me',\r\n loginEndpoint = '/api/auth/login',\r\n registerEndpoint = '/api/auth/register',\r\n logoutEndpoint = '/api/auth/logout',\r\n logoutRedirect,\r\n isGuestFn = defaultIsGuest,\r\n parseResponse = defaultParseResponse,\r\n swrConfig = {},\r\n onLogin,\r\n onLogout,\r\n onError,\r\n}: AuthProviderProps<TUser>): React.ReactElement {\r\n \r\n // Create fetcher with custom parser\r\n const fetcher = useCallback(async (url: string): Promise<TUser | null> => {\r\n const res = await fetch(url);\r\n \r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n return null;\r\n }\r\n throw new Error('Failed to fetch user');\r\n }\r\n \r\n const json = await res.json();\r\n return parseResponse(json);\r\n }, [parseResponse]);\r\n\r\n // Fetch user data with SWR\r\n const {\r\n data: user,\r\n error,\r\n isLoading,\r\n mutate,\r\n } = useSWR<TUser | null>(\r\n userEndpoint,\r\n fetcher,\r\n {\r\n fallbackData: initialUser ?? undefined,\r\n revalidateOnFocus: true,\r\n revalidateOnReconnect: true,\r\n revalidateOnMount: !initialUser,\r\n refreshInterval: 0,\r\n shouldRetryOnError: false,\r\n ...swrConfig,\r\n onError: (err: Error) => {\r\n onError?.(err);\r\n },\r\n }\r\n );\r\n\r\n // Login function\r\n const login = useCallback(async (credentials: LoginCredentials): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(loginEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(credentials),\r\n });\r\n\r\n const json = await res.json();\r\n const userData = parseResponse(json);\r\n\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n return { success: true, user: userData };\r\n }\r\n\r\n const errorResponse = json as ApiResponse;\r\n return {\r\n success: false,\r\n message: errorResponse.message || 'Login failed',\r\n errors: errorResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Login failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [loginEndpoint, mutate, onLogin, onError, parseResponse]);\r\n\r\n // Register function\r\n const register = useCallback(async (data: RegisterData): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(registerEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n const json = await res.json();\r\n const userData = parseResponse(json);\r\n\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n return { success: true, user: userData };\r\n }\r\n\r\n const errorResponse = json as ApiResponse;\r\n return {\r\n success: false,\r\n message: errorResponse.message || 'Registration failed',\r\n errors: errorResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Registration failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [registerEndpoint, mutate, onLogin, onError, parseResponse]);\r\n\r\n // Logout function\r\n const logout = useCallback(async (): Promise<void> => {\r\n try {\r\n await fetch(logoutEndpoint, { method: 'POST' });\r\n await mutate(null, false);\r\n onLogout?.();\r\n \r\n // Redirect after logout if configured\r\n if (logoutRedirect && typeof window !== 'undefined') {\r\n window.location.href = logoutRedirect;\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Logout failed');\r\n onError?.(error);\r\n throw error;\r\n }\r\n }, [logoutEndpoint, logoutRedirect, mutate, onLogout, onError]);\r\n\r\n // Refresh user data\r\n const refresh = useCallback(async (): Promise<void> => {\r\n await mutate();\r\n }, [mutate]);\r\n\r\n // Compute derived state using custom isGuestFn\r\n const isGuest = isGuestFn(user ?? null);\r\n const isAuthenticated = !!user && !isGuest;\r\n\r\n // Memoize context value\r\n const contextValue = useMemo<AuthContextValue<TUser>>(() => ({\r\n user: user ?? null,\r\n isLoading,\r\n isAuthenticated,\r\n isGuest,\r\n error: error ?? null,\r\n login,\r\n register,\r\n logout,\r\n refresh,\r\n mutate: refresh,\r\n }), [user, isLoading, isAuthenticated, isGuest, error, login, register, logout, refresh]);\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>\r\n {children}\r\n </AuthContext.Provider>\r\n );\r\n}\r\n","'use client';\r\n\r\n/**\r\n * useAuth Hook - Generic for any user type\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * const { user, isAuthenticated, logout } = useAuth();\r\n * ```\r\n * \r\n * @example With custom type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; };\r\n * }\r\n * \r\n * const { user } = useAuth<MyUser>();\r\n * // user is MyUser | null\r\n * ```\r\n */\r\n\r\nimport { useContext } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport { AuthContext } from './AuthProvider';\r\nimport type { AuthContextValue, UseAuthOptions, DefaultUserData } from './types';\r\n\r\n/**\r\n * Hook to access authentication state and methods\r\n * \r\n * @typeParam TUser - User data type (defaults to DefaultUserData)\r\n */\r\nexport function useAuth<TUser = DefaultUserData>(\r\n options: UseAuthOptions = {}\r\n): AuthContextValue<TUser> {\r\n const context = useContext(AuthContext) as AuthContextValue<TUser> | undefined;\r\n const router = useRouter();\r\n\r\n if (!context) {\r\n throw new Error(\r\n 'useAuth must be used within an AuthProvider. ' +\r\n 'Wrap your app with <AuthProvider> from next-api-layer/client'\r\n );\r\n }\r\n\r\n const { redirectTo, redirectIfFound } = options;\r\n\r\n // Handle redirects based on auth state\r\n if (!context.isLoading) {\r\n if (redirectTo && !context.isAuthenticated && !context.isGuest) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectTo);\r\n }\r\n }\r\n\r\n if (redirectIfFound && context.isAuthenticated) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectIfFound);\r\n }\r\n }\r\n }\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get only the user object\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useUser<TUser = DefaultUserData>() {\r\n const { user, isLoading, isAuthenticated, isGuest } = useAuth<TUser>();\r\n return { user, isLoading, isAuthenticated, isGuest };\r\n}\r\n\r\n/**\r\n * Hook for protected pages - redirects if not authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRequireAuth<TUser = DefaultUserData>(redirectTo = '/login') {\r\n const auth = useAuth<TUser>({ redirectTo });\r\n \r\n if (!auth.isLoading && !auth.isAuthenticated) {\r\n throw new Error('Authentication required');\r\n }\r\n \r\n return auth;\r\n}\r\n\r\n/**\r\n * Hook for auth pages - redirects if already authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo = '/') {\r\n return useAuth<TUser>({ redirectIfFound: redirectTo });\r\n}\r\n"]}
|
|
1
|
+
{"version":3,"sources":["../src/client/AuthProvider.tsx","../src/client/useAuth.ts"],"names":["AuthContext","createContext","defaultParseResponse","response","res","defaultIsGuest","user","u","AuthProvider","children","initialUser","userEndpoint","loginEndpoint","registerEndpoint","logoutEndpoint","logoutRedirect","isGuestFn","parseResponse","parseAuthResponse","swrConfig","onLogin","onLogout","onError","fetcher","useCallback","url","json","error","isLoading","mutate","useSWR","err","login","credentials","parsed","apiResponse","userData","register","data","logout","refresh","isGuest","isAuthenticated","contextValue","useMemo","jsx","useAuth","options","context","useContext","router","useRouter","redirectTo","redirectIfFound","useUser","useRequireAuth","auth","useRedirectIfAuth"],"mappings":"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","file":"client.js","sourcesContent":["'use client';\r\n\r\n/**\r\n * AuthProvider - Generic React context for any backend format\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * <AuthProvider>\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n * \r\n * @example With custom user type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; email: string; };\r\n * }\r\n * \r\n * <AuthProvider<MyUser>\r\n * initialUser={serverUser}\r\n * isGuestFn={(u) => u?.type === 'guest'}\r\n * parseResponse={(res) => res.data}\r\n * >\r\n * {children}\r\n * </AuthProvider>\r\n * ```\r\n */\r\n\r\nimport React, { createContext, useCallback, useMemo } from 'react';\r\nimport useSWR from 'swr';\r\nimport type { \r\n AuthContextValue, \r\n AuthProviderProps, \r\n LoginCredentials,\r\n RegisterData,\r\n AuthResult,\r\n DefaultUserData,\r\n ApiResponse,\r\n} from './types';\r\n\r\n// ==================== Context ====================\r\n\r\n// We use 'any' here because the context needs to work with any user type\r\n// The actual type safety comes from useAuth<TUser>() hook\r\n// eslint-disable-next-line @typescript-eslint/no-explicit-any\r\nexport const AuthContext = createContext<AuthContextValue<any> | undefined>(undefined);\r\n\r\n// ==================== Default Functions ====================\r\n\r\n/** Default response parser - handles common API formats */\r\nfunction defaultParseResponse<TUser>(response: unknown): TUser | null {\r\n if (!response || typeof response !== 'object') return null;\r\n \r\n const res = response as Record<string, unknown>;\r\n \r\n // Format: { success: true, data: user }\r\n if (res.success && res.data) {\r\n return res.data as TUser;\r\n }\r\n \r\n // Format: { user: {...} }\r\n if (res.user) {\r\n return res.user as TUser;\r\n }\r\n \r\n // Format: user object directly\r\n if ('id' in res || 'email' in res || 'name' in res || 'type' in res) {\r\n return res as TUser;\r\n }\r\n \r\n return null;\r\n}\r\n\r\n/** Default guest check - handles common patterns */\r\nfunction defaultIsGuest<TUser>(user: TUser | null): boolean {\r\n if (!user || typeof user !== 'object') return false;\r\n \r\n const u = user as Record<string, unknown>;\r\n \r\n // Check token_type (flat structure)\r\n if (u.token_type === 'guest') return true;\r\n \r\n // Check type (nested structure)\r\n if (u.type === 'guest') return true;\r\n \r\n return false;\r\n}\r\n\r\n// ==================== Provider Component ====================\r\n\r\nexport function AuthProvider<TUser = DefaultUserData>({\r\n children,\r\n initialUser,\r\n userEndpoint = '/api/auth/me',\r\n loginEndpoint = '/api/auth/login',\r\n registerEndpoint = '/api/auth/register',\r\n logoutEndpoint = '/api/auth/logout',\r\n logoutRedirect,\r\n isGuestFn = defaultIsGuest,\r\n parseResponse = defaultParseResponse,\r\n parseAuthResponse,\r\n swrConfig = {},\r\n onLogin,\r\n onLogout,\r\n onError,\r\n}: AuthProviderProps<TUser>): React.ReactElement {\r\n \r\n // Create fetcher with custom parser\r\n const fetcher = useCallback(async (url: string): Promise<TUser | null> => {\r\n const res = await fetch(url);\r\n \r\n if (!res.ok) {\r\n if (res.status === 401) {\r\n return null;\r\n }\r\n throw new Error('Failed to fetch user');\r\n }\r\n \r\n const json = await res.json();\r\n return parseResponse(json);\r\n }, [parseResponse]);\r\n\r\n // Fetch user data with SWR\r\n const {\r\n data: user,\r\n error,\r\n isLoading,\r\n mutate,\r\n } = useSWR<TUser | null>(\r\n userEndpoint,\r\n fetcher,\r\n {\r\n fallbackData: initialUser ?? undefined,\r\n revalidateOnFocus: true,\r\n revalidateOnReconnect: true,\r\n revalidateOnMount: !initialUser,\r\n refreshInterval: 0,\r\n shouldRetryOnError: false,\r\n ...swrConfig,\r\n onError: (err: Error) => {\r\n onError?.(err);\r\n },\r\n }\r\n );\r\n\r\n // Login function\r\n const login = useCallback(async (credentials: LoginCredentials): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(loginEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(credentials),\r\n });\r\n\r\n const json = await res.json();\r\n\r\n // Use custom parser if provided\r\n if (parseAuthResponse) {\r\n const parsed = parseAuthResponse(json);\r\n if (parsed.success) {\r\n if (parsed.user) {\r\n await mutate(parsed.user, false);\r\n onLogin?.(parsed.user);\r\n } else {\r\n // No user data, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: parsed.user ?? undefined, message: parsed.message };\r\n }\r\n return {\r\n success: false,\r\n message: parsed.message || 'Login failed',\r\n errors: parsed.errors,\r\n };\r\n }\r\n\r\n // Default behavior: check res.ok and json.success\r\n const apiResponse = json as ApiResponse;\r\n if (res.ok && apiResponse.success !== false) {\r\n // Try to extract user data using parseResponse\r\n const userData = parseResponse(json);\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n } else {\r\n // No user data in response, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: userData ?? undefined, message: apiResponse.message };\r\n }\r\n\r\n return {\r\n success: false,\r\n message: apiResponse.message || 'Login failed',\r\n errors: apiResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Login failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [loginEndpoint, mutate, onLogin, onError, parseResponse, parseAuthResponse]);\r\n\r\n // Register function\r\n const register = useCallback(async (data: RegisterData): Promise<AuthResult<TUser>> => {\r\n try {\r\n const res = await fetch(registerEndpoint, {\r\n method: 'POST',\r\n headers: { 'Content-Type': 'application/json' },\r\n body: JSON.stringify(data),\r\n });\r\n\r\n const json = await res.json();\r\n\r\n // Use custom parser if provided\r\n if (parseAuthResponse) {\r\n const parsed = parseAuthResponse(json);\r\n if (parsed.success) {\r\n if (parsed.user) {\r\n await mutate(parsed.user, false);\r\n onLogin?.(parsed.user);\r\n } else {\r\n // No user data, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: parsed.user ?? undefined, message: parsed.message };\r\n }\r\n return {\r\n success: false,\r\n message: parsed.message || 'Registration failed',\r\n errors: parsed.errors,\r\n };\r\n }\r\n\r\n // Default behavior: check res.ok and json.success\r\n const apiResponse = json as ApiResponse;\r\n if (res.ok && apiResponse.success !== false) {\r\n // Try to extract user data using parseResponse\r\n const userData = parseResponse(json);\r\n if (userData) {\r\n await mutate(userData, false);\r\n onLogin?.(userData);\r\n } else {\r\n // No user data in response, revalidate from /me endpoint\r\n await mutate();\r\n }\r\n return { success: true, user: userData ?? undefined, message: apiResponse.message };\r\n }\r\n\r\n return {\r\n success: false,\r\n message: apiResponse.message || 'Registration failed',\r\n errors: apiResponse.errors,\r\n };\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Registration failed');\r\n onError?.(error);\r\n return { success: false, message: error.message };\r\n }\r\n }, [registerEndpoint, mutate, onLogin, onError, parseResponse, parseAuthResponse]);\r\n\r\n // Logout function\r\n const logout = useCallback(async (): Promise<void> => {\r\n try {\r\n await fetch(logoutEndpoint, { method: 'POST' });\r\n await mutate(null, false);\r\n onLogout?.();\r\n \r\n // Redirect after logout if configured\r\n if (logoutRedirect && typeof window !== 'undefined') {\r\n window.location.href = logoutRedirect;\r\n }\r\n } catch (err) {\r\n const error = err instanceof Error ? err : new Error('Logout failed');\r\n onError?.(error);\r\n throw error;\r\n }\r\n }, [logoutEndpoint, logoutRedirect, mutate, onLogout, onError]);\r\n\r\n // Refresh user data\r\n const refresh = useCallback(async (): Promise<void> => {\r\n await mutate();\r\n }, [mutate]);\r\n\r\n // Compute derived state using custom isGuestFn\r\n const isGuest = isGuestFn(user ?? null);\r\n const isAuthenticated = !!user && !isGuest;\r\n\r\n // Memoize context value\r\n const contextValue = useMemo<AuthContextValue<TUser>>(() => ({\r\n user: user ?? null,\r\n isLoading,\r\n isAuthenticated,\r\n isGuest,\r\n error: error ?? null,\r\n login,\r\n register,\r\n logout,\r\n refresh,\r\n mutate: refresh,\r\n }), [user, isLoading, isAuthenticated, isGuest, error, login, register, logout, refresh]);\r\n\r\n return (\r\n <AuthContext.Provider value={contextValue}>\r\n {children}\r\n </AuthContext.Provider>\r\n );\r\n}\r\n","'use client';\r\n\r\n/**\r\n * useAuth Hook - Generic for any user type\r\n * \r\n * @example Basic usage\r\n * ```tsx\r\n * const { user, isAuthenticated, logout } = useAuth();\r\n * ```\r\n * \r\n * @example With custom type\r\n * ```tsx\r\n * interface MyUser {\r\n * type: 'guest' | 'superadmin';\r\n * user?: { name: string; };\r\n * }\r\n * \r\n * const { user } = useAuth<MyUser>();\r\n * // user is MyUser | null\r\n * ```\r\n */\r\n\r\nimport { useContext } from 'react';\r\nimport { useRouter } from 'next/navigation';\r\nimport { AuthContext } from './AuthProvider';\r\nimport type { AuthContextValue, UseAuthOptions, DefaultUserData } from './types';\r\n\r\n/**\r\n * Hook to access authentication state and methods\r\n * \r\n * @typeParam TUser - User data type (defaults to DefaultUserData)\r\n */\r\nexport function useAuth<TUser = DefaultUserData>(\r\n options: UseAuthOptions = {}\r\n): AuthContextValue<TUser> {\r\n const context = useContext(AuthContext) as AuthContextValue<TUser> | undefined;\r\n const router = useRouter();\r\n\r\n if (!context) {\r\n throw new Error(\r\n 'useAuth must be used within an AuthProvider. ' +\r\n 'Wrap your app with <AuthProvider> from next-api-layer/client'\r\n );\r\n }\r\n\r\n const { redirectTo, redirectIfFound } = options;\r\n\r\n // Handle redirects based on auth state\r\n if (!context.isLoading) {\r\n if (redirectTo && !context.isAuthenticated && !context.isGuest) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectTo);\r\n }\r\n }\r\n\r\n if (redirectIfFound && context.isAuthenticated) {\r\n if (typeof window !== 'undefined') {\r\n router.replace(redirectIfFound);\r\n }\r\n }\r\n }\r\n\r\n return context;\r\n}\r\n\r\n/**\r\n * Hook to get only the user object\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useUser<TUser = DefaultUserData>() {\r\n const { user, isLoading, isAuthenticated, isGuest } = useAuth<TUser>();\r\n return { user, isLoading, isAuthenticated, isGuest };\r\n}\r\n\r\n/**\r\n * Hook for protected pages - redirects if not authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRequireAuth<TUser = DefaultUserData>(redirectTo = '/login') {\r\n const auth = useAuth<TUser>({ redirectTo });\r\n \r\n if (!auth.isLoading && !auth.isAuthenticated) {\r\n throw new Error('Authentication required');\r\n }\r\n \r\n return auth;\r\n}\r\n\r\n/**\r\n * Hook for auth pages - redirects if already authenticated\r\n * \r\n * @typeParam TUser - User data type\r\n */\r\nexport function useRedirectIfAuth<TUser = DefaultUserData>(redirectTo = '/') {\r\n return useAuth<TUser>({ redirectIfFound: redirectTo });\r\n}\r\n"]}
|