@insforge/nextjs 0.11.1 → 0.11.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md
CHANGED
|
@@ -29,6 +29,7 @@ Wrap your app with `InsforgeProvider` in the root layout:
|
|
|
29
29
|
```tsx
|
|
30
30
|
// app/layout.tsx
|
|
31
31
|
import { InsforgeProvider } from '@insforge/nextjs';
|
|
32
|
+
import '@insforge/nextjs/styles.css';
|
|
32
33
|
|
|
33
34
|
export default function RootLayout({ children }: { children: React.ReactNode }) {
|
|
34
35
|
return (
|
|
@@ -46,7 +47,7 @@ export default function RootLayout({ children }: { children: React.ReactNode })
|
|
|
46
47
|
}
|
|
47
48
|
```
|
|
48
49
|
|
|
49
|
-
> **
|
|
50
|
+
> **Important**: Import the CSS file in your root layout to ensure styles are loaded during SSR and prevent flash of unstyled content (FOUC).
|
|
50
51
|
|
|
51
52
|
### 2. Create API Route
|
|
52
53
|
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../../../src/server/InsforgeProvider.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ClientInsforgeProvider } from '../client/provider';\nimport type { InsforgeProviderProps } from '@insforge/react';\nimport { cookies } from 'next/headers';\nimport type { InitialAuthState } from '@insforge/react';\n\nexport interface InsforgeProviderServerProps extends Omit<InsforgeProviderProps, 'initialState'> {\n children: ReactNode;\n /**\n * Opt into dynamic rendering to read auth state from cookies during SSR.\n *\n * - When true: Reads cookies on server, prevents content flashing, opts into dynamic rendering\n * - When false: Static rendering, may see brief content flash during hydration\n *\n * Following Clerk's pattern: dynamic prop controls server-side auth state access\n *\n * @default false\n *\n * @example\n * ```tsx\n * <InsforgeProvider baseUrl={...} dynamic>\n * {children}\n * </InsforgeProvider>\n * ```\n */\n dynamic?: boolean;\n}\n\n/**\n * Get initial auth state from cookies (server-side)\n *\n * This helper reads the authentication state from cookies set by the SDK.\n * Use this in Server Components or Server Actions to get the initial auth state\n * and pass it to the InsforgeProvider via initialState prop.\n *\n * This prevents hydration mismatches by ensuring SSR and client render have the same state.\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { InsforgeProvider } from '@insforge/nextjs';\n * import { getAuthFromCookies } from '@insforge/nextjs/api/auth-helpers';\n *\n * export default async function RootLayout({ children }) {\n * const initialAuth = await getAuthFromCookies();\n *\n * return (\n * <html>\n * <body>\n * <InsforgeProvider\n * baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}\n * initialState={initialAuth}\n * >\n * {children}\n * </InsforgeProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n *\n * @returns Initial auth state with user and userId, or empty object if not authenticated\n */\nexport async function getAuthFromCookies(): Promise<InitialAuthState> {\n try {\n const cookieStore = await cookies();\n\n // Read session token from cookie (set by middleware or /api/auth route)\n const sessionToken = cookieStore.get('insforge-session')?.value;\n\n if (!sessionToken) {\n // Not authenticated - return null to indicate signed out\n return {\n user: null,\n userId: null,\n };\n }\n\n // Read user identity from cookie (set by middleware or /api/auth route)\n const userCookie = cookieStore.get('insforge-user')?.value;\n\n if (!userCookie) {\n // Have session token but no user info - this shouldn't happen\n // but return null to be safe\n return {\n user: null,\n userId: null,\n };\n }\n\n try {\n const user = JSON.parse(userCookie) as { id: string; email: string; name?: string };\n\n // Return basic user info from cookie\n // This is lightweight data for SSR hydration only\n // Full profile will be loaded by SDK's getCurrentUser() after hydration\n return {\n user: {\n id: user.id,\n email: user.email,\n name: user.name || '',\n },\n userId: user.id,\n };\n } catch {\n // Invalid user data in cookie\n return {\n user: null,\n userId: null,\n };\n }\n } catch (error) {\n // Error reading cookies (might be in middleware or edge runtime)\n console.error('[Insforge] Error reading cookies:', error);\n return {\n user: null,\n userId: null,\n };\n }\n}\n\n/**\n * Synchronous version for use in middleware or edge runtime\n *\n * @param request - Next.js request object\n * @returns Initial auth state\n */\nexport function getAuthFromRequest(request: Request): InitialAuthState {\n try {\n // Parse cookies from request headers\n const cookieHeader = request.headers.get('cookie') || '';\n const cookies = Object.fromEntries(\n cookieHeader.split('; ').map((c) => {\n const [key, ...v] = c.split('=');\n return [key, v.join('=')];\n })\n );\n\n const sessionToken = cookies['insforge-session'];\n\n if (!sessionToken) {\n // Not authenticated\n return {\n user: null,\n userId: null,\n };\n }\n\n const userCookie = cookies['insforge-user'];\n\n if (!userCookie) {\n // Have session but no user info\n return {\n user: null,\n userId: null,\n };\n }\n\n try {\n const user = JSON.parse(decodeURIComponent(userCookie)) as {\n id: string;\n email: string;\n name?: string;\n };\n\n // Return basic user info from cookie\n // This is lightweight data for SSR hydration only\n return {\n user: {\n id: user.id,\n email: user.email,\n name: user.name || '',\n },\n userId: user.id,\n };\n } catch {\n return {\n user: null,\n userId: null,\n };\n }\n } catch (error) {\n console.error('[Insforge] Error reading cookies from request:', error);\n return {\n user: null,\n userId: null,\n };\n }\n}\n\n/**\n * Server Component Provider for Insforge\n *\n * This is a Server Component (no 'use client') that:\n * 1. Optionally reads auth state from cookies on the server (when dynamic=true)\n * 2. Passes initialState to the Client Provider\n * 3. Ensures SSR and client hydration match perfectly\n *\n * Following Clerk's pattern: packages/nextjs/src/app-router/server/ClerkProvider.tsx\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { InsforgeProvider } from '@insforge/nextjs';\n *\n * export default async function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * <InsforgeProvider\n * baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}\n * dynamic // 👈 Enable dynamic rendering for SSR auth\n * >\n * {children}\n * </InsforgeProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport async function InsforgeProvider(props: InsforgeProviderServerProps) {\n const { children, dynamic = true, ...restProps } = props;\n\n // Only read cookies if dynamic=true (opts into dynamic rendering)\n // When dynamic=false, Next.js can statically generate the page\n const initialAuth = dynamic ? await getAuthFromCookies() : { user: null, userId: null };\n\n // Pass initialState to Client Provider\n return (\n <ClientInsforgeProvider {...restProps} initialState={initialAuth}>\n {children}\n </ClientInsforgeProvider>\n );\n}\n"],"mappings":"
|
|
1
|
+
{"version":3,"sources":["../../../src/server/InsforgeProvider.tsx"],"sourcesContent":["import type { ReactNode } from 'react';\nimport { ClientInsforgeProvider } from '../client/provider';\nimport type { InsforgeProviderProps } from '@insforge/react';\nimport { cookies } from 'next/headers';\nimport type { InitialAuthState } from '@insforge/react';\n\nexport interface InsforgeProviderServerProps extends Omit<InsforgeProviderProps, 'initialState'> {\n children: ReactNode;\n /**\n * Opt into dynamic rendering to read auth state from cookies during SSR.\n *\n * - When true: Reads cookies on server, prevents content flashing, opts into dynamic rendering\n * - When false: Static rendering, may see brief content flash during hydration\n *\n * Following Clerk's pattern: dynamic prop controls server-side auth state access\n *\n * @default false\n *\n * @example\n * ```tsx\n * <InsforgeProvider baseUrl={...} dynamic>\n * {children}\n * </InsforgeProvider>\n * ```\n */\n dynamic?: boolean;\n}\n\n/**\n * Get initial auth state from cookies (server-side)\n *\n * This helper reads the authentication state from cookies set by the SDK.\n * Use this in Server Components or Server Actions to get the initial auth state\n * and pass it to the InsforgeProvider via initialState prop.\n *\n * This prevents hydration mismatches by ensuring SSR and client render have the same state.\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { InsforgeProvider } from '@insforge/nextjs';\n * import { getAuthFromCookies } from '@insforge/nextjs/api/auth-helpers';\n * import '@insforge/nextjs/styles.css';\n *\n * export default async function RootLayout({ children }) {\n * const initialAuth = await getAuthFromCookies();\n *\n * return (\n * <html>\n * <body>\n * <InsforgeProvider\n * baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}\n * initialState={initialAuth}\n * >\n * {children}\n * </InsforgeProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n *\n * @returns Initial auth state with user and userId, or empty object if not authenticated\n */\nexport async function getAuthFromCookies(): Promise<InitialAuthState> {\n try {\n const cookieStore = await cookies();\n\n // Read session token from cookie (set by middleware or /api/auth route)\n const sessionToken = cookieStore.get('insforge-session')?.value;\n\n if (!sessionToken) {\n // Not authenticated - return null to indicate signed out\n return {\n user: null,\n userId: null,\n };\n }\n\n // Read user identity from cookie (set by middleware or /api/auth route)\n const userCookie = cookieStore.get('insforge-user')?.value;\n\n if (!userCookie) {\n // Have session token but no user info - this shouldn't happen\n // but return null to be safe\n return {\n user: null,\n userId: null,\n };\n }\n\n try {\n const user = JSON.parse(userCookie) as { id: string; email: string; name?: string };\n\n // Return basic user info from cookie\n // This is lightweight data for SSR hydration only\n // Full profile will be loaded by SDK's getCurrentUser() after hydration\n return {\n user: {\n id: user.id,\n email: user.email,\n name: user.name || '',\n },\n userId: user.id,\n };\n } catch {\n // Invalid user data in cookie\n return {\n user: null,\n userId: null,\n };\n }\n } catch (error) {\n // Error reading cookies (might be in middleware or edge runtime)\n console.error('[Insforge] Error reading cookies:', error);\n return {\n user: null,\n userId: null,\n };\n }\n}\n\n/**\n * Synchronous version for use in middleware or edge runtime\n *\n * @param request - Next.js request object\n * @returns Initial auth state\n */\nexport function getAuthFromRequest(request: Request): InitialAuthState {\n try {\n // Parse cookies from request headers\n const cookieHeader = request.headers.get('cookie') || '';\n const cookies = Object.fromEntries(\n cookieHeader.split('; ').map((c) => {\n const [key, ...v] = c.split('=');\n return [key, v.join('=')];\n })\n );\n\n const sessionToken = cookies['insforge-session'];\n\n if (!sessionToken) {\n // Not authenticated\n return {\n user: null,\n userId: null,\n };\n }\n\n const userCookie = cookies['insforge-user'];\n\n if (!userCookie) {\n // Have session but no user info\n return {\n user: null,\n userId: null,\n };\n }\n\n try {\n const user = JSON.parse(decodeURIComponent(userCookie)) as {\n id: string;\n email: string;\n name?: string;\n };\n\n // Return basic user info from cookie\n // This is lightweight data for SSR hydration only\n return {\n user: {\n id: user.id,\n email: user.email,\n name: user.name || '',\n },\n userId: user.id,\n };\n } catch {\n return {\n user: null,\n userId: null,\n };\n }\n } catch (error) {\n console.error('[Insforge] Error reading cookies from request:', error);\n return {\n user: null,\n userId: null,\n };\n }\n}\n\n/**\n * Server Component Provider for Insforge\n *\n * This is a Server Component (no 'use client') that:\n * 1. Optionally reads auth state from cookies on the server (when dynamic=true)\n * 2. Passes initialState to the Client Provider\n * 3. Ensures SSR and client hydration match perfectly\n *\n * Following Clerk's pattern: packages/nextjs/src/app-router/server/ClerkProvider.tsx\n *\n * @example\n * ```tsx\n * // app/layout.tsx (Server Component)\n * import { InsforgeProvider } from '@insforge/nextjs';\n * import '@insforge/nextjs/styles.css';\n *\n * export default async function RootLayout({ children }) {\n * return (\n * <html>\n * <body>\n * <InsforgeProvider\n * baseUrl={process.env.NEXT_PUBLIC_INSFORGE_BASE_URL!}\n * dynamic // 👈 Enable dynamic rendering for SSR auth\n * >\n * {children}\n * </InsforgeProvider>\n * </body>\n * </html>\n * );\n * }\n * ```\n */\nexport async function InsforgeProvider(props: InsforgeProviderServerProps) {\n const { children, dynamic = true, ...restProps } = props;\n\n // Only read cookies if dynamic=true (opts into dynamic rendering)\n // When dynamic=false, Next.js can statically generate the page\n const initialAuth = dynamic ? await getAuthFromCookies() : { user: null, userId: null };\n\n // Pass initialState to Client Provider\n return (\n <ClientInsforgeProvider {...restProps} initialState={initialAuth}>\n {children}\n </ClientInsforgeProvider>\n );\n}\n"],"mappings":"AAwOI;AAvOJ,SAAS,8BAA8B;AAEvC,SAAS,eAAe;AA6DxB,eAAsB,qBAAgD;AACpE,MAAI;AACF,UAAM,cAAc,MAAM,QAAQ;AAGlC,UAAM,eAAe,YAAY,IAAI,kBAAkB,GAAG;AAE1D,QAAI,CAAC,cAAc;AAEjB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAGA,UAAM,aAAa,YAAY,IAAI,eAAe,GAAG;AAErD,QAAI,CAAC,YAAY;AAGf,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,UAAU;AAKlC,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK,QAAQ;AAAA,QACrB;AAAA,QACA,QAAQ,KAAK;AAAA,MACf;AAAA,IACF,QAAQ;AAEN,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AAEd,YAAQ,MAAM,qCAAqC,KAAK;AACxD,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAQO,SAAS,mBAAmB,SAAoC;AACrE,MAAI;AAEF,UAAM,eAAe,QAAQ,QAAQ,IAAI,QAAQ,KAAK;AACtD,UAAMA,WAAU,OAAO;AAAA,MACrB,aAAa,MAAM,IAAI,EAAE,IAAI,CAAC,MAAM;AAClC,cAAM,CAAC,KAAK,GAAG,CAAC,IAAI,EAAE,MAAM,GAAG;AAC/B,eAAO,CAAC,KAAK,EAAE,KAAK,GAAG,CAAC;AAAA,MAC1B,CAAC;AAAA,IACH;AAEA,UAAM,eAAeA,SAAQ,kBAAkB;AAE/C,QAAI,CAAC,cAAc;AAEjB,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,UAAM,aAAaA,SAAQ,eAAe;AAE1C,QAAI,CAAC,YAAY;AAEf,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAEA,QAAI;AACF,YAAM,OAAO,KAAK,MAAM,mBAAmB,UAAU,CAAC;AAQtD,aAAO;AAAA,QACL,MAAM;AAAA,UACJ,IAAI,KAAK;AAAA,UACT,OAAO,KAAK;AAAA,UACZ,MAAM,KAAK,QAAQ;AAAA,QACrB;AAAA,QACA,QAAQ,KAAK;AAAA,MACf;AAAA,IACF,QAAQ;AACN,aAAO;AAAA,QACL,MAAM;AAAA,QACN,QAAQ;AAAA,MACV;AAAA,IACF;AAAA,EACF,SAAS,OAAO;AACd,YAAQ,MAAM,kDAAkD,KAAK;AACrE,WAAO;AAAA,MACL,MAAM;AAAA,MACN,QAAQ;AAAA,IACV;AAAA,EACF;AACF;AAkCA,eAAsB,iBAAiB,OAAoC;AACzE,QAAM,EAAE,UAAU,UAAU,MAAM,GAAG,UAAU,IAAI;AAInD,QAAM,cAAc,UAAU,MAAM,mBAAmB,IAAI,EAAE,MAAM,MAAM,QAAQ,KAAK;AAGtF,SACE,oBAAC,0BAAwB,GAAG,WAAW,cAAc,aAClD,UACH;AAEJ;","names":["cookies"]}
|
|
@@ -37,6 +37,7 @@ interface InsforgeProviderServerProps extends Omit<InsforgeProviderProps, 'initi
|
|
|
37
37
|
* // app/layout.tsx (Server Component)
|
|
38
38
|
* import { InsforgeProvider } from '@insforge/nextjs';
|
|
39
39
|
* import { getAuthFromCookies } from '@insforge/nextjs/api/auth-helpers';
|
|
40
|
+
* import '@insforge/nextjs/styles.css';
|
|
40
41
|
*
|
|
41
42
|
* export default async function RootLayout({ children }) {
|
|
42
43
|
* const initialAuth = await getAuthFromCookies();
|
|
@@ -80,6 +81,7 @@ declare function getAuthFromRequest(request: Request): InitialAuthState;
|
|
|
80
81
|
* ```tsx
|
|
81
82
|
* // app/layout.tsx (Server Component)
|
|
82
83
|
* import { InsforgeProvider } from '@insforge/nextjs';
|
|
84
|
+
* import '@insforge/nextjs/styles.css';
|
|
83
85
|
*
|
|
84
86
|
* export default async function RootLayout({ children }) {
|
|
85
87
|
* return (
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@insforge/nextjs",
|
|
3
|
-
"version": "0.11.
|
|
3
|
+
"version": "0.11.2",
|
|
4
4
|
"description": "Pre-built authentication UI components for Next.js with Insforge backend - zero configuration required",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"types": "./dist/index.d.ts",
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"author": "Insforge",
|
|
46
46
|
"license": "MIT",
|
|
47
47
|
"dependencies": {
|
|
48
|
-
"@insforge/react": "^0.6.
|
|
48
|
+
"@insforge/react": "^0.6.9",
|
|
49
49
|
"@insforge/sdk": "^0.0.58",
|
|
50
50
|
"@insforge/shared": "^0.1.5",
|
|
51
51
|
"@insforge/shared-schemas": "^1.1.19"
|