@logickernel/bridge 0.9.9 → 0.10.0

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.
@@ -89,7 +89,7 @@ async function fetchUserRoles(options) {
89
89
  const cookieName = getCookieName(isSecure);
90
90
  try {
91
91
  const response = await fetchFn(
92
- `${kernelUrl}/api/user/organizations/${organizationId}/roles`,
92
+ `${kernelUrl}/core/api/user/organizations/${organizationId}/roles`,
93
93
  {
94
94
  headers: {
95
95
  Cookie: `${cookieName}=${sessionToken}`
@@ -129,7 +129,7 @@ function findMatchingProtectedRoute(pathname, protectedRoutes) {
129
129
  }
130
130
  function buildSignInUrl(callbackUrl) {
131
131
  const authUrl = getAuthUrl();
132
- const url = new URL("/auth/signin", authUrl);
132
+ const url = new URL("/core/auth/signin", authUrl);
133
133
  if (callbackUrl) {
134
134
  url.searchParams.set("callbackUrl", callbackUrl);
135
135
  }
@@ -196,7 +196,7 @@ async function checkPageAuth(options = {}) {
196
196
  if (!session) {
197
197
  return {
198
198
  authenticated: false,
199
- redirectUrl: `${baseUrl}/auth/signin`
199
+ redirectUrl: `${baseUrl}/core/auth/signin`
200
200
  };
201
201
  }
202
202
  if (requiredRoles.length === 0) {
@@ -210,7 +210,7 @@ async function checkPageAuth(options = {}) {
210
210
  console.error("[bridge] Organization ID required for role checking");
211
211
  return {
212
212
  authenticated: false,
213
- redirectUrl: `${baseUrl}/auth/signin`
213
+ redirectUrl: `${baseUrl}/core/auth/signin`
214
214
  };
215
215
  }
216
216
  const roles = await getUserRoles(organizationId);
@@ -233,7 +233,7 @@ async function requireAuth() {
233
233
  if (!session) {
234
234
  const baseUrl = getBaseUrl();
235
235
  const error = new Error("Authentication required");
236
- error.redirectUrl = `${baseUrl}/auth/signin`;
236
+ error.redirectUrl = `${baseUrl}/core/auth/signin`;
237
237
  throw error;
238
238
  }
239
239
  return session;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/jwt.ts","../../src/roles.ts","../../src/routes.ts","../../src/next/session.ts","../../src/next/page.ts","../../src/next/api.ts","../../src/next/proxy.ts"],"names":["decode","cookies","NextResponse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for AuthJS/NextAuth tokens\n */\n\nimport { decode } from \"@auth/core/jwt\"\nimport type { Session, SessionCookie, DecodeResult, DecodedToken } from \"./types\"\n\n/**\n * Get the base cookie name from AUTH_COOKIE env var or default to authjs.session-token\n * Strips __Secure- prefix if present, as it will be added automatically for secure cookies\n */\nfunction getBaseCookieName(): string {\n const cookieName = process.env.AUTH_COOKIE || \"authjs.session-token\"\n // Remove __Secure- prefix if present, as we'll add it back for secure cookies\n return cookieName.startsWith(\"__Secure-\") ? cookieName.slice(10) : cookieName\n}\n\n/**\n * Cookie names used by AuthJS/NextAuth\n * Defaults to authjs.session-token, can be overridden via AUTH_COOKIE env var\n */\nexport const COOKIE_NAMES = {\n get secure(): string {\n const baseName = getBaseCookieName()\n // Secure cookies must start with __Secure- prefix\n return `__Secure-${baseName}`\n },\n get dev(): string {\n return getBaseCookieName()\n },\n} as const\n\n/**\n * Get the AUTH_URL from environment variables\n * This is used internally for API calls to the kernel\n */\nexport function getAuthUrl(): string {\n return process.env.AUTH_URL || process.env.BASE_URL || \"http://localhost:3000\"\n}\n\n/**\n * Get the appropriate salt for JWT decoding based on cookie type\n */\nexport function getSalt(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Get the cookie name based on security mode\n */\nexport function getCookieName(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Check if a token is expired\n */\nexport function isTokenExpired(decoded: DecodedToken): boolean {\n if (!decoded.exp) return false\n return decoded.exp * 1000 < Date.now()\n}\n\n/**\n * Map decoded JWT payload to Session structure\n */\nexport function mapToSession(decoded: DecodedToken): Session {\n return {\n user: {\n id: decoded.sub as string,\n email: decoded.email as string,\n name: (decoded.name as string) || null,\n image: (decoded.picture as string) || null,\n },\n expires: decoded.exp\n ? new Date(decoded.exp * 1000).toISOString()\n : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // Default 30 days\n }\n}\n\n/**\n * Decode and validate a session token\n *\n * This is the core function - framework-agnostic JWT decoding.\n * The caller is responsible for extracting the token from their framework's\n * cookie/header mechanism.\n *\n * @param token - The JWT session token\n * @param secret - The AUTH_SECRET used to sign the token\n * @param isSecure - Whether the token came from a secure cookie\n * @returns DecodeResult with session data or error\n *\n * @example\n * ```typescript\n * const result = await decodeSessionToken(token, process.env.AUTH_SECRET, isSecure)\n * if (result.success) {\n * console.log(result.session.user.email)\n * } else {\n * console.error(result.error)\n * }\n * ```\n */\nexport async function decodeSessionToken(\n token: string | undefined,\n secret: string | undefined,\n isSecure: boolean = false\n): Promise<DecodeResult> {\n if (!token) {\n return { success: false, error: \"missing_token\" }\n }\n\n if (!secret) {\n return { success: false, error: \"missing_secret\" }\n }\n\n try {\n const salt = getSalt(isSecure)\n const decoded = await decode({ token, secret, salt })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n if (isTokenExpired(decoded as DecodedToken)) {\n return { success: false, error: \"expired\" }\n }\n\n const session = mapToSession(decoded as DecodedToken)\n return {\n success: true,\n session,\n decoded: decoded as DecodedToken,\n }\n } catch {\n return { success: false, error: \"decode_error\" }\n }\n}\n\n/**\n * Extract session cookie from a cookies object (generic interface)\n *\n * This works with any object that has a `get(name)` method returning\n * `{ value: string } | undefined`, like Next.js cookies() or similar.\n *\n * @param cookies - Object with get(name) method\n * @returns SessionCookie or undefined if no session cookie found\n */\nexport function extractSessionCookie(cookies: {\n get(name: string): { value: string } | undefined\n}): SessionCookie | undefined {\n // Try secure cookie first (production with HTTPS)\n const secureCookie = cookies.get(COOKIE_NAMES.secure)\n if (secureCookie?.value) {\n return { value: secureCookie.value, isSecure: true }\n }\n\n // Fall back to non-secure cookie (development)\n const devCookie = cookies.get(COOKIE_NAMES.dev)\n if (devCookie?.value) {\n return { value: devCookie.value, isSecure: false }\n }\n\n return undefined\n}\n","/**\n * Kernel Bridge Roles\n * Role checking and permission utilities\n */\n\nimport { getCookieName, getAuthUrl } from \"./jwt\"\n\n/**\n * Options for fetching user roles from the kernel\n */\nexport interface FetchRolesOptions {\n /**\n * Organization ID to fetch roles in\n */\n organizationId: string\n\n /**\n * Session token for authentication (user ID is determined from the token)\n */\n sessionToken: string\n\n /**\n * Whether using secure cookie\n * Defaults to NODE_ENV === \"production\" if not provided\n */\n isSecure?: boolean\n\n /**\n * Custom fetch function (optional, for testing or SSR)\n */\n fetchFn?: typeof fetch\n}\n\n/**\n * Result of role fetching operation\n */\nexport type FetchRolesResult =\n | { success: true; roles: string[] }\n | { success: false; error: string }\n\n/**\n * Fetch user roles from the kernel API\n *\n * This is a framework-agnostic function that makes a fetch request\n * to the kernel's roles endpoint. Uses AUTH_URL environment variable internally.\n * The user ID is determined from the session token.\n *\n * @param options - Configuration for fetching roles\n * @returns Promise with roles array or error\n *\n * @example\n * ```typescript\n * const result = await fetchUserRoles({\n * organizationId: \"org-123\",\n * sessionToken: token,\n * // isSecure defaults to NODE_ENV === \"production\"\n * })\n * if (result.success) {\n * console.log(result.roles)\n * }\n * ```\n */\nexport async function fetchUserRoles(\n options: FetchRolesOptions\n): Promise<FetchRolesResult> {\n const { organizationId, sessionToken, fetchFn = fetch } = options\n // Default isSecure to production mode\n const isSecure = options.isSecure ?? (process.env.NODE_ENV === \"production\")\n const kernelUrl = getAuthUrl()\n const cookieName = getCookieName(isSecure)\n\n try {\n const response = await fetchFn(\n `${kernelUrl}/api/user/organizations/${organizationId}/roles`,\n {\n headers: {\n Cookie: `${cookieName}=${sessionToken}`,\n },\n cache: \"no-store\",\n }\n )\n\n if (!response.ok) {\n return {\n success: false,\n error: `Failed to fetch roles: ${response.status}`,\n }\n }\n\n const data = await response.json()\n const roles = data.roles?.map((r: { roleName: string }) => r.roleName) || []\n\n return { success: true, roles }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n }\n }\n}\n\n/**\n * Check if user has at least one of the required roles\n */\nexport function hasAnyRole(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true // No roles required = any authenticated user\n return requiredRoles.some((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has all of the required roles\n */\nexport function hasAllRoles(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true\n return requiredRoles.every((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has a specific role\n */\nexport function hasRole(userRoles: string[], role: string): boolean {\n return userRoles.includes(role)\n}\n\n","/**\n * Kernel Bridge Routes\n * Route matching and protection utilities\n */\n\nimport { getAuthUrl } from \"./jwt\"\nimport type { RouteConfig, RouteMatch, MicroFrontendConfig } from \"./types\"\n\n/**\n * Check if a pathname matches any route in the list\n */\nexport function matchesAnyRoute(pathname: string, routes: string[]): boolean {\n return routes.some((route) => pathname.startsWith(route))\n}\n\n/**\n * Find the first matching protected route for a pathname\n */\nexport function findMatchingProtectedRoute(\n pathname: string,\n protectedRoutes: RouteConfig\n): { route: string; requiredRoles: string[] } | undefined {\n for (const [route, roles] of Object.entries(protectedRoutes)) {\n if (pathname.startsWith(route)) {\n return { route, requiredRoles: roles }\n }\n }\n return undefined\n}\n\n/**\n * Match a pathname against route configuration\n *\n * @param pathname - The URL pathname to match\n * @param config - Micro-frontend configuration\n * @returns RouteMatch indicating the type of route\n *\n * @example\n * ```typescript\n * const match = matchRoute(\"/dashboard\", {\n * publicRoutes: [\"/\", \"/api/health\"],\n * protectedRoutes: { \"/dashboard\": [], \"/admin\": [\"organization.owner\"] },\n * })\n * // Returns: { type: \"protected\", requiredRoles: [] }\n * ```\n */\nexport function matchRoute(\n pathname: string,\n config: Pick<MicroFrontendConfig, \"publicRoutes\" | \"protectedRoutes\">\n): RouteMatch {\n // Check public routes first (if specified)\n if (config.publicRoutes && matchesAnyRoute(pathname, config.publicRoutes)) {\n return { type: \"public\" }\n }\n\n // Check protected routes\n const match = findMatchingProtectedRoute(pathname, config.protectedRoutes)\n if (match) {\n return { type: \"protected\", requiredRoles: match.requiredRoles }\n }\n\n // Not explicitly configured = unprotected\n return { type: \"unprotected\" }\n}\n\n/**\n * Create a default configuration for a micro-frontend\n */\nexport function createConfig(\n options: Partial<MicroFrontendConfig> & Pick<MicroFrontendConfig, \"basePath\">\n): MicroFrontendConfig {\n return {\n basePath: options.basePath,\n protectedRoutes: options.protectedRoutes || {\n \"/dashboard\": [],\n \"/admin\": [\"organization.owner\"],\n },\n publicRoutes: options.publicRoutes || [],\n }\n}\n\n/**\n * Build a sign-in redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-in\n */\nexport function buildSignInUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/auth/signin\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n/**\n * Build a sign-out redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-out\n */\nexport function buildSignOutUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/auth/signout\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n","/**\n * Kernel Bridge Next.js Session\n * Server-side session utilities for Next.js\n */\n\nimport { cookies } from \"next/headers\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n} from \"../index\"\nimport type { Session, SessionCookie } from \"../types\"\n\n/**\n * Get the session cookie from Next.js cookies\n */\nexport async function getSessionCookie(): Promise<SessionCookie | undefined> {\n const cookieStore = await cookies()\n return extractSessionCookie(cookieStore)\n}\n\n/**\n * Get the session token value from cookies\n */\nexport async function getSessionToken(): Promise<string | undefined> {\n const cookie = await getSessionCookie()\n return cookie?.value\n}\n\n/**\n * Check if secure cookie is being used\n */\nexport async function isSecureCookie(): Promise<boolean> {\n const cookie = await getSessionCookie()\n return cookie?.isSecure ?? false\n}\n\n/**\n * Get the current session from cookies\n *\n * This reads the NextAuth session cookie and decodes the JWT.\n * Use this in Server Components, Server Actions, or API routes.\n *\n * @returns Session object or null if not authenticated\n *\n * @example\n * ```typescript\n * import { getSession } from \"@logickernel/bridge/next\"\n *\n * export default async function Page() {\n * const session = await getSession()\n * if (!session) {\n * redirect(\"/auth/signin\")\n * }\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function getSession(): Promise<Session | null> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return null\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return null\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n if (result.error !== \"missing_token\") {\n console.error(\"[bridge] Session decode failed:\", result.error)\n }\n return null\n }\n\n return result.session\n}\n\n/**\n * Get the base URL (facade/load balancer) for user-facing links and redirects\n * \n * This is the URL that users access through the facade/load balancer.\n * Use this for:\n * - Sign-in redirect URLs\n * - User-facing links to the kernel\n * - Any URLs that users will see or click\n */\nexport function getBaseUrl(): string {\n return process.env.BASE_URL || \"http://localhost:7001\"\n}\n\n/**\n * Get user roles in an organization\n *\n * Fetches roles from the kernel API using the current session.\n * The user ID is determined from the session token.\n *\n * @param organizationId - Organization ID to fetch roles in\n * @returns Array of role names (empty if error or no roles)\n *\n * @example\n * ```typescript\n * import { getUserRoles } from \"@logickernel/bridge/next\"\n *\n * const roles = await getUserRoles(\"org-123\")\n * const isOwner = roles.includes(\"organization.owner\")\n * ```\n */\nexport async function getUserRoles(\n organizationId: string\n): Promise<string[]> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return []\n }\n\n const result = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!result.success) {\n console.error(\"[bridge] Failed to fetch user roles:\", result.error)\n return []\n }\n\n return result.roles\n}\n\n","/**\n * Kernel Bridge Next.js Page\n * Authentication utilities for pages/server components\n */\n\nimport { getSession, getUserRoles, getBaseUrl } from \"./session\"\nimport { hasAnyRole } from \"../index\"\nimport type { Session } from \"../types\"\nimport type { PageAuthOptions, PageAuthResult } from \"./types\"\n\n// Re-export session utilities for convenience\nexport { getSession, getUserRoles, getBaseUrl } from \"./session\"\n\n/**\n * Check authentication and optionally roles for a page\n *\n * This is a helper for pages that need both auth and role checking.\n * For simple auth-only checks, use getSession() directly.\n *\n * @param options - Authentication options\n * @returns Auth result with session/roles or redirect URL\n *\n * @example\n * ```typescript\n * import { checkPageAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function AdminPage({ params }) {\n * const { organization_id } = await params\n *\n * const auth = await checkPageAuth({\n * requiredRoles: [\"organization.owner\"],\n * organizationId: organization_id,\n * })\n *\n * if (!auth.authenticated) {\n * redirect(auth.redirectUrl)\n * }\n *\n * return <div>Welcome {auth.session.user.email}</div>\n * }\n * ```\n */\nexport async function checkPageAuth(\n options: PageAuthOptions = {}\n): Promise<PageAuthResult> {\n const { requiredRoles = [], organizationId } = options\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n\n // Get session\n const session = await getSession()\n\n if (!session) {\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/auth/signin`,\n }\n }\n\n // If no roles required, just return session\n if (requiredRoles.length === 0) {\n return {\n authenticated: true,\n session,\n roles: [],\n }\n }\n\n // Roles required - need organization ID\n if (!organizationId) {\n console.error(\"[bridge] Organization ID required for role checking\")\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/auth/signin`,\n }\n }\n\n // Fetch user roles\n const roles = await getUserRoles(organizationId)\n\n // Check if user has required role\n if (!hasAnyRole(roles, requiredRoles)) {\n return {\n authenticated: true, // User is authenticated but lacks roles\n session,\n roles,\n }\n }\n\n return {\n authenticated: true,\n session,\n roles,\n }\n}\n\n/**\n * Require authentication for a page\n *\n * This is a simpler helper that throws if not authenticated.\n * Use with redirect() in the catch block.\n *\n * @returns Session if authenticated\n * @throws RedirectInfo if not authenticated\n *\n * @example\n * ```typescript\n * import { requireAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function DashboardPage() {\n * const session = await requireAuth()\n * // If we get here, user is authenticated\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function requireAuth(): Promise<Session> {\n const session = await getSession()\n\n if (!session) {\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n // We can't use redirect() here because it's a Next.js function\n // Instead, throw an error that the caller can catch\n const error = new Error(\"Authentication required\")\n ;(error as Error & { redirectUrl: string }).redirectUrl = `${baseUrl}/auth/signin`\n throw error\n }\n\n return session\n}\n\n/**\n * Check if user has any of the required roles\n *\n * The user ID is determined from the session token in cookies.\n *\n * @param organizationId - Organization to check roles in\n * @param requiredRoles - Roles to check for\n * @returns True if user has at least one required role\n *\n * @example\n * ```typescript\n * const hasAccess = await hasRequiredRole(\n * \"org-123\",\n * [\"organization.owner\", \"organization.editor\"]\n * )\n * ```\n */\nexport async function hasRequiredRole(\n organizationId: string,\n requiredRoles: string[]\n): Promise<boolean> {\n if (requiredRoles.length === 0) {\n return true // No roles required\n }\n\n const roles = await getUserRoles(organizationId)\n return hasAnyRole(roles, requiredRoles)\n}\n\n","/**\n * Kernel Bridge Next.js API\n * Authentication utilities for API routes\n */\n\nimport { NextRequest, NextResponse } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n hasAnyRole,\n} from \"../index\"\nimport type { Session } from \"../types\"\nimport type { AuthContext, AuthenticatedHandler, WithAuthOptions } from \"./types\"\n\n/**\n * Validate session from request cookies\n */\nasync function validateSession(\n request: NextRequest\n): Promise<{ success: true; session: Session; cookie: { value: string; isSecure: boolean } } | { success: false; error: string }> {\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n return { success: false, error: \"No session cookie\" }\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return { success: false, error: \"Server configuration error\" }\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n return { success: false, error: result.error }\n }\n\n return { success: true, session: result.session, cookie }\n}\n\n/**\n * Wrap an API route handler with authentication\n *\n * This handles JWT validation and optionally role checking.\n * The handler receives the session and can focus on business logic.\n *\n * @param handler - The authenticated handler function\n * @param options - Authentication options\n * @returns A Next.js route handler\n *\n * @example\n * ```typescript\n * // Any authenticated user\n * export const GET = withAuth(async (request, { session }) => {\n * return NextResponse.json({ user: session.user })\n * })\n *\n * // With role requirement\n * export const DELETE = withAuth(\n * async (request, { session }) => {\n * return NextResponse.json({ deleted: true })\n * },\n * { requiredRoles: [\"organization.owner\"] }\n * )\n * ```\n */\nexport function withAuth(\n handler: AuthenticatedHandler,\n options: WithAuthOptions = {}\n): (request: NextRequest, context?: { params?: Promise<Record<string, string>> }) => Promise<Response> {\n return async (\n request: NextRequest,\n context?: { params?: Promise<Record<string, string>> }\n ): Promise<Response> => {\n // Validate session\n const validation = await validateSession(request)\n\n if (!validation.success) {\n return NextResponse.json(\n { error: \"Unauthorized\" },\n { status: 401 }\n )\n }\n\n const { session, cookie } = validation\n\n // Get route params if available\n const params = context?.params ? await context.params : undefined\n\n // Check roles if required\n if (options.requiredRoles && options.requiredRoles.length > 0) {\n // Determine organization ID from params or headers\n const organizationId =\n (options.organizationId && params?.[options.organizationId]) ||\n params?.organization_id ||\n request.headers.get(\"x-organization-id\")\n\n if (!organizationId) {\n return NextResponse.json(\n { error: \"Organization ID required for role-based access\" },\n { status: 400 }\n )\n }\n\n // Fetch user roles\n const rolesResult = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!rolesResult.success) {\n console.error(\"[bridge] Failed to fetch roles:\", rolesResult.error)\n return NextResponse.json(\n { error: \"Failed to verify permissions\" },\n { status: 500 }\n )\n }\n\n if (!hasAnyRole(rolesResult.roles, options.requiredRoles)) {\n return NextResponse.json(\n { error: \"Forbidden\" },\n { status: 403 }\n )\n }\n }\n\n // Call the handler with auth context\n const authContext: AuthContext = {\n session,\n params,\n }\n\n return handler(request, authContext)\n }\n}\n\n/**\n * Get session from a request (for manual handling)\n *\n * Use this when you need more control than withAuth provides.\n *\n * @param request - The Next.js request\n * @returns Session or null\n *\n * @example\n * ```typescript\n * export async function GET(request: NextRequest) {\n * const session = await getSessionFromRequest(request)\n * if (!session) {\n * return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 })\n * }\n * // Custom logic...\n * }\n * ```\n */\nexport async function getSessionFromRequest(\n request: NextRequest\n): Promise<Session | null> {\n const validation = await validateSession(request)\n return validation.success ? validation.session : null\n}\n\n","/**\n * Kernel Bridge Next.js Proxy\n * Middleware/proxy utilities for Next.js\n */\n\nimport { NextResponse } from \"next/server\"\nimport type { NextRequest } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n findMatchingProtectedRoute,\n buildSignInUrl,\n} from \"../index\"\nimport type { ProxyOptions, DynamicRoutePattern, DynamicRouteMatch } from \"./types\"\n\n/**\n * Parse a dynamic route pattern and match against pathname\n *\n * @example\n * matchDynamicRoute(\"/abc123/admin\", \"/[organization_id]/admin\")\n * // Returns: { matched: true, params: { organization_id: \"abc123\" } }\n */\nfunction matchDynamicRoute(\n pathname: string,\n pattern: string,\n basePath: string\n): Omit<DynamicRouteMatch, \"requiredRoles\"> {\n // Remove basePath from pathname\n const relativePath = pathname.replace(basePath, \"\") || \"/\"\n\n // Convert pattern to regex\n // e.g., \"/[organization_id]/admin\" -> /^\\/([^/]+)\\/admin/\n const paramNames: string[] = []\n const regexPattern = pattern.replace(/\\[([^\\]]+)\\]/g, (_, paramName) => {\n paramNames.push(paramName)\n return \"([^/]+)\"\n })\n\n const regex = new RegExp(`^${regexPattern}(?:/.*)?$`)\n const match = relativePath.match(regex)\n\n if (!match) {\n return { matched: false, params: {} }\n }\n\n // Extract params from match groups\n const params: Record<string, string> = {}\n paramNames.forEach((name, index) => {\n const value = match[index + 1]\n if (value !== undefined) {\n params[name] = value\n }\n })\n\n return { matched: true, params }\n}\n\n/**\n * Find matching dynamic route pattern\n */\nfunction findDynamicRouteMatch(\n pathname: string,\n patterns: DynamicRoutePattern[],\n basePath: string\n): DynamicRouteMatch | null {\n for (const pattern of patterns) {\n const result = matchDynamicRoute(pathname, pattern.pattern, basePath)\n if (result.matched) {\n return { ...result, requiredRoles: pattern.requiredRoles }\n }\n }\n return null\n}\n\n/**\n * Create a proxy/middleware handler function for Next.js\n *\n * This creates a fully configured middleware handler that:\n * - Validates authentication for protected routes\n * - Handles dynamic routes with organization IDs\n * - Redirects unauthenticated users to sign in\n * - Adds user info to request headers for downstream use\n *\n * Note: The `config` export must be defined statically in your proxy.ts file\n * for Next.js to analyze it at compile time.\n *\n * @param options - Proxy configuration\n * @returns A Next.js proxy handler function\n *\n * @example\n * ```typescript\n * // src/proxy.ts\n * import { createProxyHandler, type ProxyOptions } from \"@logickernel/bridge/next\"\n *\n * const proxyConfig: ProxyOptions = {\n * basePath: \"/aura\",\n * protectedRoutes: { \"/dashboard\": [] },\n * dynamicRoutes: [\n * { pattern: \"/[organization_id]/admin\", requiredRoles: [\"organization.owner\"] },\n * ],\n * }\n *\n * export const proxy = createProxyHandler(proxyConfig)\n *\n * // Config must be static for Next.js\n * export const config = {\n * matcher: [\"/((?!_next/static|_next/image|favicon.ico|public).*)\"],\n * }\n * ```\n */\nexport function createProxyHandler(\n options: ProxyOptions\n): (request: NextRequest) => Promise<Response> {\n const {\n basePath,\n protectedRoutes,\n dynamicRoutes = [],\n errorPath,\n } = options\n\n async function proxy(request: NextRequest): Promise<Response> {\n const { pathname } = request.nextUrl\n\n // Check dynamic route patterns first\n const dynamicMatch = findDynamicRouteMatch(\n pathname,\n dynamicRoutes,\n basePath\n )\n\n // Check if route matches protected routes\n const staticProtectedMatch = findMatchingProtectedRoute(pathname, protectedRoutes)\n\n // If route is not in protectedRoutes or dynamicRoutes, it's public (no auth needed)\n const isProtected = staticProtectedMatch !== undefined || dynamicMatch?.matched === true\n\n if (!isProtected) {\n return NextResponse.next()\n }\n\n // Protected routes - validate session\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n const signInUrl = buildSignInUrl(request.url)\n return NextResponse.redirect(signInUrl)\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n const errorUrl = errorPath\n ? new URL(errorPath, request.url)\n : new URL(\"/error?code=config\", request.url)\n return NextResponse.redirect(errorUrl)\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n const signInUrl = buildSignInUrl()\n return NextResponse.redirect(signInUrl)\n }\n\n // Add user info to headers for downstream use\n const requestHeaders = new Headers(request.headers)\n requestHeaders.set(\"x-user-id\", result.session.user.id)\n requestHeaders.set(\"x-user-email\", result.session.user.email)\n\n // Add organization ID if from dynamic route\n if (dynamicMatch?.matched && dynamicMatch.params.organization_id) {\n requestHeaders.set(\"x-organization-id\", dynamicMatch.params.organization_id)\n }\n\n // Add any other dynamic params\n if (dynamicMatch?.matched) {\n for (const [key, value] of Object.entries(dynamicMatch.params)) {\n requestHeaders.set(`x-param-${key}`, value)\n }\n }\n\n return NextResponse.next({\n request: {\n headers: requestHeaders,\n },\n })\n }\n\n return proxy\n}\n\n/**\n * Default matcher config for proxy\n * Can be used if you don't want to define your own config\n */\nexport const defaultProxyConfig = {\n matcher: [\n /*\n * Match all request paths except:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public files (public folder)\n */\n \"/((?!_next/static|_next/image|favicon.ico|public).*)\",\n ],\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/jwt.ts","../../src/roles.ts","../../src/routes.ts","../../src/next/session.ts","../../src/next/page.ts","../../src/next/api.ts","../../src/next/proxy.ts"],"names":["decode","cookies","NextResponse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for AuthJS/NextAuth tokens\n */\n\nimport { decode } from \"@auth/core/jwt\"\nimport type { Session, SessionCookie, DecodeResult, DecodedToken } from \"./types\"\n\n/**\n * Get the base cookie name from AUTH_COOKIE env var or default to authjs.session-token\n * Strips __Secure- prefix if present, as it will be added automatically for secure cookies\n */\nfunction getBaseCookieName(): string {\n const cookieName = process.env.AUTH_COOKIE || \"authjs.session-token\"\n // Remove __Secure- prefix if present, as we'll add it back for secure cookies\n return cookieName.startsWith(\"__Secure-\") ? cookieName.slice(10) : cookieName\n}\n\n/**\n * Cookie names used by AuthJS/NextAuth\n * Defaults to authjs.session-token, can be overridden via AUTH_COOKIE env var\n */\nexport const COOKIE_NAMES = {\n get secure(): string {\n const baseName = getBaseCookieName()\n // Secure cookies must start with __Secure- prefix\n return `__Secure-${baseName}`\n },\n get dev(): string {\n return getBaseCookieName()\n },\n} as const\n\n/**\n * Get the AUTH_URL from environment variables\n * This is used internally for API calls to the kernel\n */\nexport function getAuthUrl(): string {\n return process.env.AUTH_URL || process.env.BASE_URL || \"http://localhost:3000\"\n}\n\n/**\n * Get the appropriate salt for JWT decoding based on cookie type\n */\nexport function getSalt(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Get the cookie name based on security mode\n */\nexport function getCookieName(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Check if a token is expired\n */\nexport function isTokenExpired(decoded: DecodedToken): boolean {\n if (!decoded.exp) return false\n return decoded.exp * 1000 < Date.now()\n}\n\n/**\n * Map decoded JWT payload to Session structure\n */\nexport function mapToSession(decoded: DecodedToken): Session {\n return {\n user: {\n id: decoded.sub as string,\n email: decoded.email as string,\n name: (decoded.name as string) || null,\n image: (decoded.picture as string) || null,\n },\n expires: decoded.exp\n ? new Date(decoded.exp * 1000).toISOString()\n : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // Default 30 days\n }\n}\n\n/**\n * Decode and validate a session token\n *\n * This is the core function - framework-agnostic JWT decoding.\n * The caller is responsible for extracting the token from their framework's\n * cookie/header mechanism.\n *\n * @param token - The JWT session token\n * @param secret - The AUTH_SECRET used to sign the token\n * @param isSecure - Whether the token came from a secure cookie\n * @returns DecodeResult with session data or error\n *\n * @example\n * ```typescript\n * const result = await decodeSessionToken(token, process.env.AUTH_SECRET, isSecure)\n * if (result.success) {\n * console.log(result.session.user.email)\n * } else {\n * console.error(result.error)\n * }\n * ```\n */\nexport async function decodeSessionToken(\n token: string | undefined,\n secret: string | undefined,\n isSecure: boolean = false\n): Promise<DecodeResult> {\n if (!token) {\n return { success: false, error: \"missing_token\" }\n }\n\n if (!secret) {\n return { success: false, error: \"missing_secret\" }\n }\n\n try {\n const salt = getSalt(isSecure)\n const decoded = await decode({ token, secret, salt })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n if (isTokenExpired(decoded as DecodedToken)) {\n return { success: false, error: \"expired\" }\n }\n\n const session = mapToSession(decoded as DecodedToken)\n return {\n success: true,\n session,\n decoded: decoded as DecodedToken,\n }\n } catch {\n return { success: false, error: \"decode_error\" }\n }\n}\n\n/**\n * Extract session cookie from a cookies object (generic interface)\n *\n * This works with any object that has a `get(name)` method returning\n * `{ value: string } | undefined`, like Next.js cookies() or similar.\n *\n * @param cookies - Object with get(name) method\n * @returns SessionCookie or undefined if no session cookie found\n */\nexport function extractSessionCookie(cookies: {\n get(name: string): { value: string } | undefined\n}): SessionCookie | undefined {\n // Try secure cookie first (production with HTTPS)\n const secureCookie = cookies.get(COOKIE_NAMES.secure)\n if (secureCookie?.value) {\n return { value: secureCookie.value, isSecure: true }\n }\n\n // Fall back to non-secure cookie (development)\n const devCookie = cookies.get(COOKIE_NAMES.dev)\n if (devCookie?.value) {\n return { value: devCookie.value, isSecure: false }\n }\n\n return undefined\n}\n","/**\n * Kernel Bridge Roles\n * Role checking and permission utilities\n */\n\nimport { getCookieName, getAuthUrl } from \"./jwt\"\n\n/**\n * Options for fetching user roles from the kernel\n */\nexport interface FetchRolesOptions {\n /**\n * Organization ID to fetch roles in\n */\n organizationId: string\n\n /**\n * Session token for authentication (user ID is determined from the token)\n */\n sessionToken: string\n\n /**\n * Whether using secure cookie\n * Defaults to NODE_ENV === \"production\" if not provided\n */\n isSecure?: boolean\n\n /**\n * Custom fetch function (optional, for testing or SSR)\n */\n fetchFn?: typeof fetch\n}\n\n/**\n * Result of role fetching operation\n */\nexport type FetchRolesResult =\n | { success: true; roles: string[] }\n | { success: false; error: string }\n\n/**\n * Fetch user roles from the kernel API\n *\n * This is a framework-agnostic function that makes a fetch request\n * to the kernel's roles endpoint. Uses AUTH_URL environment variable internally.\n * The user ID is determined from the session token.\n *\n * @param options - Configuration for fetching roles\n * @returns Promise with roles array or error\n *\n * @example\n * ```typescript\n * const result = await fetchUserRoles({\n * organizationId: \"org-123\",\n * sessionToken: token,\n * // isSecure defaults to NODE_ENV === \"production\"\n * })\n * if (result.success) {\n * console.log(result.roles)\n * }\n * ```\n */\nexport async function fetchUserRoles(\n options: FetchRolesOptions\n): Promise<FetchRolesResult> {\n const { organizationId, sessionToken, fetchFn = fetch } = options\n // Default isSecure to production mode\n const isSecure = options.isSecure ?? (process.env.NODE_ENV === \"production\")\n const kernelUrl = getAuthUrl()\n const cookieName = getCookieName(isSecure)\n\n try {\n const response = await fetchFn(\n `${kernelUrl}/core/api/user/organizations/${organizationId}/roles`,\n {\n headers: {\n Cookie: `${cookieName}=${sessionToken}`,\n },\n cache: \"no-store\",\n }\n )\n\n if (!response.ok) {\n return {\n success: false,\n error: `Failed to fetch roles: ${response.status}`,\n }\n }\n\n const data = await response.json()\n const roles = data.roles?.map((r: { roleName: string }) => r.roleName) || []\n\n return { success: true, roles }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n }\n }\n}\n\n/**\n * Check if user has at least one of the required roles\n */\nexport function hasAnyRole(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true // No roles required = any authenticated user\n return requiredRoles.some((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has all of the required roles\n */\nexport function hasAllRoles(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true\n return requiredRoles.every((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has a specific role\n */\nexport function hasRole(userRoles: string[], role: string): boolean {\n return userRoles.includes(role)\n}\n\n","/**\n * Kernel Bridge Routes\n * Route matching and protection utilities\n */\n\nimport { getAuthUrl } from \"./jwt\"\nimport type { RouteConfig, RouteMatch, MicroFrontendConfig } from \"./types\"\n\n/**\n * Check if a pathname matches any route in the list\n */\nexport function matchesAnyRoute(pathname: string, routes: string[]): boolean {\n return routes.some((route) => pathname.startsWith(route))\n}\n\n/**\n * Find the first matching protected route for a pathname\n */\nexport function findMatchingProtectedRoute(\n pathname: string,\n protectedRoutes: RouteConfig\n): { route: string; requiredRoles: string[] } | undefined {\n for (const [route, roles] of Object.entries(protectedRoutes)) {\n if (pathname.startsWith(route)) {\n return { route, requiredRoles: roles }\n }\n }\n return undefined\n}\n\n/**\n * Match a pathname against route configuration\n *\n * @param pathname - The URL pathname to match\n * @param config - Micro-frontend configuration\n * @returns RouteMatch indicating the type of route\n *\n * @example\n * ```typescript\n * const match = matchRoute(\"/dashboard\", {\n * publicRoutes: [\"/\", \"/api/health\"],\n * protectedRoutes: { \"/dashboard\": [], \"/admin\": [\"organization.owner\"] },\n * })\n * // Returns: { type: \"protected\", requiredRoles: [] }\n * ```\n */\nexport function matchRoute(\n pathname: string,\n config: Pick<MicroFrontendConfig, \"publicRoutes\" | \"protectedRoutes\">\n): RouteMatch {\n // Check public routes first (if specified)\n if (config.publicRoutes && matchesAnyRoute(pathname, config.publicRoutes)) {\n return { type: \"public\" }\n }\n\n // Check protected routes\n const match = findMatchingProtectedRoute(pathname, config.protectedRoutes)\n if (match) {\n return { type: \"protected\", requiredRoles: match.requiredRoles }\n }\n\n // Not explicitly configured = unprotected\n return { type: \"unprotected\" }\n}\n\n/**\n * Create a default configuration for a micro-frontend\n */\nexport function createConfig(\n options: Partial<MicroFrontendConfig> & Pick<MicroFrontendConfig, \"basePath\">\n): MicroFrontendConfig {\n return {\n basePath: options.basePath,\n protectedRoutes: options.protectedRoutes || {\n \"/dashboard\": [],\n \"/admin\": [\"organization.owner\"],\n },\n publicRoutes: options.publicRoutes || [],\n }\n}\n\n/**\n * Build a sign-in redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-in\n */\nexport function buildSignInUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/core/auth/signin\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n/**\n * Build a sign-out redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-out\n */\nexport function buildSignOutUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/core/auth/signout\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n","/**\n * Kernel Bridge Next.js Session\n * Server-side session utilities for Next.js\n */\n\nimport { cookies } from \"next/headers\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n} from \"../index\"\nimport type { Session, SessionCookie } from \"../types\"\n\n/**\n * Get the session cookie from Next.js cookies\n */\nexport async function getSessionCookie(): Promise<SessionCookie | undefined> {\n const cookieStore = await cookies()\n return extractSessionCookie(cookieStore)\n}\n\n/**\n * Get the session token value from cookies\n */\nexport async function getSessionToken(): Promise<string | undefined> {\n const cookie = await getSessionCookie()\n return cookie?.value\n}\n\n/**\n * Check if secure cookie is being used\n */\nexport async function isSecureCookie(): Promise<boolean> {\n const cookie = await getSessionCookie()\n return cookie?.isSecure ?? false\n}\n\n/**\n * Get the current session from cookies\n *\n * This reads the NextAuth session cookie and decodes the JWT.\n * Use this in Server Components, Server Actions, or API routes.\n *\n * @returns Session object or null if not authenticated\n *\n * @example\n * ```typescript\n * import { getSession } from \"@logickernel/bridge/next\"\n *\n * export default async function Page() {\n * const session = await getSession()\n * if (!session) {\n * redirect(\"/auth/signin\")\n * }\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function getSession(): Promise<Session | null> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return null\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return null\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n if (result.error !== \"missing_token\") {\n console.error(\"[bridge] Session decode failed:\", result.error)\n }\n return null\n }\n\n return result.session\n}\n\n/**\n * Get the base URL (facade/load balancer) for user-facing links and redirects\n * \n * This is the URL that users access through the facade/load balancer.\n * Use this for:\n * - Sign-in redirect URLs\n * - User-facing links to the kernel\n * - Any URLs that users will see or click\n */\nexport function getBaseUrl(): string {\n return process.env.BASE_URL || \"http://localhost:7001\"\n}\n\n/**\n * Get user roles in an organization\n *\n * Fetches roles from the kernel API using the current session.\n * The user ID is determined from the session token.\n *\n * @param organizationId - Organization ID to fetch roles in\n * @returns Array of role names (empty if error or no roles)\n *\n * @example\n * ```typescript\n * import { getUserRoles } from \"@logickernel/bridge/next\"\n *\n * const roles = await getUserRoles(\"org-123\")\n * const isOwner = roles.includes(\"organization.owner\")\n * ```\n */\nexport async function getUserRoles(\n organizationId: string\n): Promise<string[]> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return []\n }\n\n const result = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!result.success) {\n console.error(\"[bridge] Failed to fetch user roles:\", result.error)\n return []\n }\n\n return result.roles\n}\n\n","/**\n * Kernel Bridge Next.js Page\n * Authentication utilities for pages/server components\n */\n\nimport { getSession, getUserRoles, getBaseUrl } from \"./session\"\nimport { hasAnyRole } from \"../index\"\nimport type { Session } from \"../types\"\nimport type { PageAuthOptions, PageAuthResult } from \"./types\"\n\n// Re-export session utilities for convenience\nexport { getSession, getUserRoles, getBaseUrl } from \"./session\"\n\n/**\n * Check authentication and optionally roles for a page\n *\n * This is a helper for pages that need both auth and role checking.\n * For simple auth-only checks, use getSession() directly.\n *\n * @param options - Authentication options\n * @returns Auth result with session/roles or redirect URL\n *\n * @example\n * ```typescript\n * import { checkPageAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function AdminPage({ params }) {\n * const { organization_id } = await params\n *\n * const auth = await checkPageAuth({\n * requiredRoles: [\"organization.owner\"],\n * organizationId: organization_id,\n * })\n *\n * if (!auth.authenticated) {\n * redirect(auth.redirectUrl)\n * }\n *\n * return <div>Welcome {auth.session.user.email}</div>\n * }\n * ```\n */\nexport async function checkPageAuth(\n options: PageAuthOptions = {}\n): Promise<PageAuthResult> {\n const { requiredRoles = [], organizationId } = options\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n\n // Get session\n const session = await getSession()\n\n if (!session) {\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/core/auth/signin`,\n }\n }\n\n // If no roles required, just return session\n if (requiredRoles.length === 0) {\n return {\n authenticated: true,\n session,\n roles: [],\n }\n }\n\n // Roles required - need organization ID\n if (!organizationId) {\n console.error(\"[bridge] Organization ID required for role checking\")\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/core/auth/signin`,\n }\n }\n\n // Fetch user roles\n const roles = await getUserRoles(organizationId)\n\n // Check if user has required role\n if (!hasAnyRole(roles, requiredRoles)) {\n return {\n authenticated: true, // User is authenticated but lacks roles\n session,\n roles,\n }\n }\n\n return {\n authenticated: true,\n session,\n roles,\n }\n}\n\n/**\n * Require authentication for a page\n *\n * This is a simpler helper that throws if not authenticated.\n * Use with redirect() in the catch block.\n *\n * @returns Session if authenticated\n * @throws RedirectInfo if not authenticated\n *\n * @example\n * ```typescript\n * import { requireAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function DashboardPage() {\n * const session = await requireAuth()\n * // If we get here, user is authenticated\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function requireAuth(): Promise<Session> {\n const session = await getSession()\n\n if (!session) {\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n // We can't use redirect() here because it's a Next.js function\n // Instead, throw an error that the caller can catch\n const error = new Error(\"Authentication required\")\n ;(error as Error & { redirectUrl: string }).redirectUrl = `${baseUrl}/core/auth/signin`\n throw error\n }\n\n return session\n}\n\n/**\n * Check if user has any of the required roles\n *\n * The user ID is determined from the session token in cookies.\n *\n * @param organizationId - Organization to check roles in\n * @param requiredRoles - Roles to check for\n * @returns True if user has at least one required role\n *\n * @example\n * ```typescript\n * const hasAccess = await hasRequiredRole(\n * \"org-123\",\n * [\"organization.owner\", \"organization.editor\"]\n * )\n * ```\n */\nexport async function hasRequiredRole(\n organizationId: string,\n requiredRoles: string[]\n): Promise<boolean> {\n if (requiredRoles.length === 0) {\n return true // No roles required\n }\n\n const roles = await getUserRoles(organizationId)\n return hasAnyRole(roles, requiredRoles)\n}\n\n","/**\n * Kernel Bridge Next.js API\n * Authentication utilities for API routes\n */\n\nimport { NextRequest, NextResponse } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n hasAnyRole,\n} from \"../index\"\nimport type { Session } from \"../types\"\nimport type { AuthContext, AuthenticatedHandler, WithAuthOptions } from \"./types\"\n\n/**\n * Validate session from request cookies\n */\nasync function validateSession(\n request: NextRequest\n): Promise<{ success: true; session: Session; cookie: { value: string; isSecure: boolean } } | { success: false; error: string }> {\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n return { success: false, error: \"No session cookie\" }\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return { success: false, error: \"Server configuration error\" }\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n return { success: false, error: result.error }\n }\n\n return { success: true, session: result.session, cookie }\n}\n\n/**\n * Wrap an API route handler with authentication\n *\n * This handles JWT validation and optionally role checking.\n * The handler receives the session and can focus on business logic.\n *\n * @param handler - The authenticated handler function\n * @param options - Authentication options\n * @returns A Next.js route handler\n *\n * @example\n * ```typescript\n * // Any authenticated user\n * export const GET = withAuth(async (request, { session }) => {\n * return NextResponse.json({ user: session.user })\n * })\n *\n * // With role requirement\n * export const DELETE = withAuth(\n * async (request, { session }) => {\n * return NextResponse.json({ deleted: true })\n * },\n * { requiredRoles: [\"organization.owner\"] }\n * )\n * ```\n */\nexport function withAuth(\n handler: AuthenticatedHandler,\n options: WithAuthOptions = {}\n): (request: NextRequest, context?: { params?: Promise<Record<string, string>> }) => Promise<Response> {\n return async (\n request: NextRequest,\n context?: { params?: Promise<Record<string, string>> }\n ): Promise<Response> => {\n // Validate session\n const validation = await validateSession(request)\n\n if (!validation.success) {\n return NextResponse.json(\n { error: \"Unauthorized\" },\n { status: 401 }\n )\n }\n\n const { session, cookie } = validation\n\n // Get route params if available\n const params = context?.params ? await context.params : undefined\n\n // Check roles if required\n if (options.requiredRoles && options.requiredRoles.length > 0) {\n // Determine organization ID from params or headers\n const organizationId =\n (options.organizationId && params?.[options.organizationId]) ||\n params?.organization_id ||\n request.headers.get(\"x-organization-id\")\n\n if (!organizationId) {\n return NextResponse.json(\n { error: \"Organization ID required for role-based access\" },\n { status: 400 }\n )\n }\n\n // Fetch user roles\n const rolesResult = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!rolesResult.success) {\n console.error(\"[bridge] Failed to fetch roles:\", rolesResult.error)\n return NextResponse.json(\n { error: \"Failed to verify permissions\" },\n { status: 500 }\n )\n }\n\n if (!hasAnyRole(rolesResult.roles, options.requiredRoles)) {\n return NextResponse.json(\n { error: \"Forbidden\" },\n { status: 403 }\n )\n }\n }\n\n // Call the handler with auth context\n const authContext: AuthContext = {\n session,\n params,\n }\n\n return handler(request, authContext)\n }\n}\n\n/**\n * Get session from a request (for manual handling)\n *\n * Use this when you need more control than withAuth provides.\n *\n * @param request - The Next.js request\n * @returns Session or null\n *\n * @example\n * ```typescript\n * export async function GET(request: NextRequest) {\n * const session = await getSessionFromRequest(request)\n * if (!session) {\n * return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 })\n * }\n * // Custom logic...\n * }\n * ```\n */\nexport async function getSessionFromRequest(\n request: NextRequest\n): Promise<Session | null> {\n const validation = await validateSession(request)\n return validation.success ? validation.session : null\n}\n\n","/**\n * Kernel Bridge Next.js Proxy\n * Middleware/proxy utilities for Next.js\n */\n\nimport { NextResponse } from \"next/server\"\nimport type { NextRequest } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n findMatchingProtectedRoute,\n buildSignInUrl,\n} from \"../index\"\nimport type { ProxyOptions, DynamicRoutePattern, DynamicRouteMatch } from \"./types\"\n\n/**\n * Parse a dynamic route pattern and match against pathname\n *\n * @example\n * matchDynamicRoute(\"/abc123/admin\", \"/[organization_id]/admin\")\n * // Returns: { matched: true, params: { organization_id: \"abc123\" } }\n */\nfunction matchDynamicRoute(\n pathname: string,\n pattern: string,\n basePath: string\n): Omit<DynamicRouteMatch, \"requiredRoles\"> {\n // Remove basePath from pathname\n const relativePath = pathname.replace(basePath, \"\") || \"/\"\n\n // Convert pattern to regex\n // e.g., \"/[organization_id]/admin\" -> /^\\/([^/]+)\\/admin/\n const paramNames: string[] = []\n const regexPattern = pattern.replace(/\\[([^\\]]+)\\]/g, (_, paramName) => {\n paramNames.push(paramName)\n return \"([^/]+)\"\n })\n\n const regex = new RegExp(`^${regexPattern}(?:/.*)?$`)\n const match = relativePath.match(regex)\n\n if (!match) {\n return { matched: false, params: {} }\n }\n\n // Extract params from match groups\n const params: Record<string, string> = {}\n paramNames.forEach((name, index) => {\n const value = match[index + 1]\n if (value !== undefined) {\n params[name] = value\n }\n })\n\n return { matched: true, params }\n}\n\n/**\n * Find matching dynamic route pattern\n */\nfunction findDynamicRouteMatch(\n pathname: string,\n patterns: DynamicRoutePattern[],\n basePath: string\n): DynamicRouteMatch | null {\n for (const pattern of patterns) {\n const result = matchDynamicRoute(pathname, pattern.pattern, basePath)\n if (result.matched) {\n return { ...result, requiredRoles: pattern.requiredRoles }\n }\n }\n return null\n}\n\n/**\n * Create a proxy/middleware handler function for Next.js\n *\n * This creates a fully configured middleware handler that:\n * - Validates authentication for protected routes\n * - Handles dynamic routes with organization IDs\n * - Redirects unauthenticated users to sign in\n * - Adds user info to request headers for downstream use\n *\n * Note: The `config` export must be defined statically in your proxy.ts file\n * for Next.js to analyze it at compile time.\n *\n * @param options - Proxy configuration\n * @returns A Next.js proxy handler function\n *\n * @example\n * ```typescript\n * // src/proxy.ts\n * import { createProxyHandler, type ProxyOptions } from \"@logickernel/bridge/next\"\n *\n * const proxyConfig: ProxyOptions = {\n * basePath: \"/aura\",\n * protectedRoutes: { \"/dashboard\": [] },\n * dynamicRoutes: [\n * { pattern: \"/[organization_id]/admin\", requiredRoles: [\"organization.owner\"] },\n * ],\n * }\n *\n * export const proxy = createProxyHandler(proxyConfig)\n *\n * // Config must be static for Next.js\n * export const config = {\n * matcher: [\"/((?!_next/static|_next/image|favicon.ico|public).*)\"],\n * }\n * ```\n */\nexport function createProxyHandler(\n options: ProxyOptions\n): (request: NextRequest) => Promise<Response> {\n const {\n basePath,\n protectedRoutes,\n dynamicRoutes = [],\n errorPath,\n } = options\n\n async function proxy(request: NextRequest): Promise<Response> {\n const { pathname } = request.nextUrl\n\n // Check dynamic route patterns first\n const dynamicMatch = findDynamicRouteMatch(\n pathname,\n dynamicRoutes,\n basePath\n )\n\n // Check if route matches protected routes\n const staticProtectedMatch = findMatchingProtectedRoute(pathname, protectedRoutes)\n\n // If route is not in protectedRoutes or dynamicRoutes, it's public (no auth needed)\n const isProtected = staticProtectedMatch !== undefined || dynamicMatch?.matched === true\n\n if (!isProtected) {\n return NextResponse.next()\n }\n\n // Protected routes - validate session\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n const signInUrl = buildSignInUrl(request.url)\n return NextResponse.redirect(signInUrl)\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n const errorUrl = errorPath\n ? new URL(errorPath, request.url)\n : new URL(\"/error?code=config\", request.url)\n return NextResponse.redirect(errorUrl)\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n const signInUrl = buildSignInUrl()\n return NextResponse.redirect(signInUrl)\n }\n\n // Add user info to headers for downstream use\n const requestHeaders = new Headers(request.headers)\n requestHeaders.set(\"x-user-id\", result.session.user.id)\n requestHeaders.set(\"x-user-email\", result.session.user.email)\n\n // Add organization ID if from dynamic route\n if (dynamicMatch?.matched && dynamicMatch.params.organization_id) {\n requestHeaders.set(\"x-organization-id\", dynamicMatch.params.organization_id)\n }\n\n // Add any other dynamic params\n if (dynamicMatch?.matched) {\n for (const [key, value] of Object.entries(dynamicMatch.params)) {\n requestHeaders.set(`x-param-${key}`, value)\n }\n }\n\n return NextResponse.next({\n request: {\n headers: requestHeaders,\n },\n })\n }\n\n return proxy\n}\n\n/**\n * Default matcher config for proxy\n * Can be used if you don't want to define your own config\n */\nexport const defaultProxyConfig = {\n matcher: [\n /*\n * Match all request paths except:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public files (public folder)\n */\n \"/((?!_next/static|_next/image|favicon.ico|public).*)\",\n ],\n}\n\n"]}
@@ -87,7 +87,7 @@ async function fetchUserRoles(options) {
87
87
  const cookieName = getCookieName(isSecure);
88
88
  try {
89
89
  const response = await fetchFn(
90
- `${kernelUrl}/api/user/organizations/${organizationId}/roles`,
90
+ `${kernelUrl}/core/api/user/organizations/${organizationId}/roles`,
91
91
  {
92
92
  headers: {
93
93
  Cookie: `${cookieName}=${sessionToken}`
@@ -127,7 +127,7 @@ function findMatchingProtectedRoute(pathname, protectedRoutes) {
127
127
  }
128
128
  function buildSignInUrl(callbackUrl) {
129
129
  const authUrl = getAuthUrl();
130
- const url = new URL("/auth/signin", authUrl);
130
+ const url = new URL("/core/auth/signin", authUrl);
131
131
  if (callbackUrl) {
132
132
  url.searchParams.set("callbackUrl", callbackUrl);
133
133
  }
@@ -194,7 +194,7 @@ async function checkPageAuth(options = {}) {
194
194
  if (!session) {
195
195
  return {
196
196
  authenticated: false,
197
- redirectUrl: `${baseUrl}/auth/signin`
197
+ redirectUrl: `${baseUrl}/core/auth/signin`
198
198
  };
199
199
  }
200
200
  if (requiredRoles.length === 0) {
@@ -208,7 +208,7 @@ async function checkPageAuth(options = {}) {
208
208
  console.error("[bridge] Organization ID required for role checking");
209
209
  return {
210
210
  authenticated: false,
211
- redirectUrl: `${baseUrl}/auth/signin`
211
+ redirectUrl: `${baseUrl}/core/auth/signin`
212
212
  };
213
213
  }
214
214
  const roles = await getUserRoles(organizationId);
@@ -231,7 +231,7 @@ async function requireAuth() {
231
231
  if (!session) {
232
232
  const baseUrl = getBaseUrl();
233
233
  const error = new Error("Authentication required");
234
- error.redirectUrl = `${baseUrl}/auth/signin`;
234
+ error.redirectUrl = `${baseUrl}/core/auth/signin`;
235
235
  throw error;
236
236
  }
237
237
  return session;
@@ -1 +1 @@
1
- {"version":3,"sources":["../../src/jwt.ts","../../src/roles.ts","../../src/routes.ts","../../src/next/session.ts","../../src/next/page.ts","../../src/next/api.ts","../../src/next/proxy.ts"],"names":["cookies","NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for AuthJS/NextAuth tokens\n */\n\nimport { decode } from \"@auth/core/jwt\"\nimport type { Session, SessionCookie, DecodeResult, DecodedToken } from \"./types\"\n\n/**\n * Get the base cookie name from AUTH_COOKIE env var or default to authjs.session-token\n * Strips __Secure- prefix if present, as it will be added automatically for secure cookies\n */\nfunction getBaseCookieName(): string {\n const cookieName = process.env.AUTH_COOKIE || \"authjs.session-token\"\n // Remove __Secure- prefix if present, as we'll add it back for secure cookies\n return cookieName.startsWith(\"__Secure-\") ? cookieName.slice(10) : cookieName\n}\n\n/**\n * Cookie names used by AuthJS/NextAuth\n * Defaults to authjs.session-token, can be overridden via AUTH_COOKIE env var\n */\nexport const COOKIE_NAMES = {\n get secure(): string {\n const baseName = getBaseCookieName()\n // Secure cookies must start with __Secure- prefix\n return `__Secure-${baseName}`\n },\n get dev(): string {\n return getBaseCookieName()\n },\n} as const\n\n/**\n * Get the AUTH_URL from environment variables\n * This is used internally for API calls to the kernel\n */\nexport function getAuthUrl(): string {\n return process.env.AUTH_URL || process.env.BASE_URL || \"http://localhost:3000\"\n}\n\n/**\n * Get the appropriate salt for JWT decoding based on cookie type\n */\nexport function getSalt(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Get the cookie name based on security mode\n */\nexport function getCookieName(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Check if a token is expired\n */\nexport function isTokenExpired(decoded: DecodedToken): boolean {\n if (!decoded.exp) return false\n return decoded.exp * 1000 < Date.now()\n}\n\n/**\n * Map decoded JWT payload to Session structure\n */\nexport function mapToSession(decoded: DecodedToken): Session {\n return {\n user: {\n id: decoded.sub as string,\n email: decoded.email as string,\n name: (decoded.name as string) || null,\n image: (decoded.picture as string) || null,\n },\n expires: decoded.exp\n ? new Date(decoded.exp * 1000).toISOString()\n : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // Default 30 days\n }\n}\n\n/**\n * Decode and validate a session token\n *\n * This is the core function - framework-agnostic JWT decoding.\n * The caller is responsible for extracting the token from their framework's\n * cookie/header mechanism.\n *\n * @param token - The JWT session token\n * @param secret - The AUTH_SECRET used to sign the token\n * @param isSecure - Whether the token came from a secure cookie\n * @returns DecodeResult with session data or error\n *\n * @example\n * ```typescript\n * const result = await decodeSessionToken(token, process.env.AUTH_SECRET, isSecure)\n * if (result.success) {\n * console.log(result.session.user.email)\n * } else {\n * console.error(result.error)\n * }\n * ```\n */\nexport async function decodeSessionToken(\n token: string | undefined,\n secret: string | undefined,\n isSecure: boolean = false\n): Promise<DecodeResult> {\n if (!token) {\n return { success: false, error: \"missing_token\" }\n }\n\n if (!secret) {\n return { success: false, error: \"missing_secret\" }\n }\n\n try {\n const salt = getSalt(isSecure)\n const decoded = await decode({ token, secret, salt })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n if (isTokenExpired(decoded as DecodedToken)) {\n return { success: false, error: \"expired\" }\n }\n\n const session = mapToSession(decoded as DecodedToken)\n return {\n success: true,\n session,\n decoded: decoded as DecodedToken,\n }\n } catch {\n return { success: false, error: \"decode_error\" }\n }\n}\n\n/**\n * Extract session cookie from a cookies object (generic interface)\n *\n * This works with any object that has a `get(name)` method returning\n * `{ value: string } | undefined`, like Next.js cookies() or similar.\n *\n * @param cookies - Object with get(name) method\n * @returns SessionCookie or undefined if no session cookie found\n */\nexport function extractSessionCookie(cookies: {\n get(name: string): { value: string } | undefined\n}): SessionCookie | undefined {\n // Try secure cookie first (production with HTTPS)\n const secureCookie = cookies.get(COOKIE_NAMES.secure)\n if (secureCookie?.value) {\n return { value: secureCookie.value, isSecure: true }\n }\n\n // Fall back to non-secure cookie (development)\n const devCookie = cookies.get(COOKIE_NAMES.dev)\n if (devCookie?.value) {\n return { value: devCookie.value, isSecure: false }\n }\n\n return undefined\n}\n","/**\n * Kernel Bridge Roles\n * Role checking and permission utilities\n */\n\nimport { getCookieName, getAuthUrl } from \"./jwt\"\n\n/**\n * Options for fetching user roles from the kernel\n */\nexport interface FetchRolesOptions {\n /**\n * Organization ID to fetch roles in\n */\n organizationId: string\n\n /**\n * Session token for authentication (user ID is determined from the token)\n */\n sessionToken: string\n\n /**\n * Whether using secure cookie\n * Defaults to NODE_ENV === \"production\" if not provided\n */\n isSecure?: boolean\n\n /**\n * Custom fetch function (optional, for testing or SSR)\n */\n fetchFn?: typeof fetch\n}\n\n/**\n * Result of role fetching operation\n */\nexport type FetchRolesResult =\n | { success: true; roles: string[] }\n | { success: false; error: string }\n\n/**\n * Fetch user roles from the kernel API\n *\n * This is a framework-agnostic function that makes a fetch request\n * to the kernel's roles endpoint. Uses AUTH_URL environment variable internally.\n * The user ID is determined from the session token.\n *\n * @param options - Configuration for fetching roles\n * @returns Promise with roles array or error\n *\n * @example\n * ```typescript\n * const result = await fetchUserRoles({\n * organizationId: \"org-123\",\n * sessionToken: token,\n * // isSecure defaults to NODE_ENV === \"production\"\n * })\n * if (result.success) {\n * console.log(result.roles)\n * }\n * ```\n */\nexport async function fetchUserRoles(\n options: FetchRolesOptions\n): Promise<FetchRolesResult> {\n const { organizationId, sessionToken, fetchFn = fetch } = options\n // Default isSecure to production mode\n const isSecure = options.isSecure ?? (process.env.NODE_ENV === \"production\")\n const kernelUrl = getAuthUrl()\n const cookieName = getCookieName(isSecure)\n\n try {\n const response = await fetchFn(\n `${kernelUrl}/api/user/organizations/${organizationId}/roles`,\n {\n headers: {\n Cookie: `${cookieName}=${sessionToken}`,\n },\n cache: \"no-store\",\n }\n )\n\n if (!response.ok) {\n return {\n success: false,\n error: `Failed to fetch roles: ${response.status}`,\n }\n }\n\n const data = await response.json()\n const roles = data.roles?.map((r: { roleName: string }) => r.roleName) || []\n\n return { success: true, roles }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n }\n }\n}\n\n/**\n * Check if user has at least one of the required roles\n */\nexport function hasAnyRole(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true // No roles required = any authenticated user\n return requiredRoles.some((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has all of the required roles\n */\nexport function hasAllRoles(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true\n return requiredRoles.every((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has a specific role\n */\nexport function hasRole(userRoles: string[], role: string): boolean {\n return userRoles.includes(role)\n}\n\n","/**\n * Kernel Bridge Routes\n * Route matching and protection utilities\n */\n\nimport { getAuthUrl } from \"./jwt\"\nimport type { RouteConfig, RouteMatch, MicroFrontendConfig } from \"./types\"\n\n/**\n * Check if a pathname matches any route in the list\n */\nexport function matchesAnyRoute(pathname: string, routes: string[]): boolean {\n return routes.some((route) => pathname.startsWith(route))\n}\n\n/**\n * Find the first matching protected route for a pathname\n */\nexport function findMatchingProtectedRoute(\n pathname: string,\n protectedRoutes: RouteConfig\n): { route: string; requiredRoles: string[] } | undefined {\n for (const [route, roles] of Object.entries(protectedRoutes)) {\n if (pathname.startsWith(route)) {\n return { route, requiredRoles: roles }\n }\n }\n return undefined\n}\n\n/**\n * Match a pathname against route configuration\n *\n * @param pathname - The URL pathname to match\n * @param config - Micro-frontend configuration\n * @returns RouteMatch indicating the type of route\n *\n * @example\n * ```typescript\n * const match = matchRoute(\"/dashboard\", {\n * publicRoutes: [\"/\", \"/api/health\"],\n * protectedRoutes: { \"/dashboard\": [], \"/admin\": [\"organization.owner\"] },\n * })\n * // Returns: { type: \"protected\", requiredRoles: [] }\n * ```\n */\nexport function matchRoute(\n pathname: string,\n config: Pick<MicroFrontendConfig, \"publicRoutes\" | \"protectedRoutes\">\n): RouteMatch {\n // Check public routes first (if specified)\n if (config.publicRoutes && matchesAnyRoute(pathname, config.publicRoutes)) {\n return { type: \"public\" }\n }\n\n // Check protected routes\n const match = findMatchingProtectedRoute(pathname, config.protectedRoutes)\n if (match) {\n return { type: \"protected\", requiredRoles: match.requiredRoles }\n }\n\n // Not explicitly configured = unprotected\n return { type: \"unprotected\" }\n}\n\n/**\n * Create a default configuration for a micro-frontend\n */\nexport function createConfig(\n options: Partial<MicroFrontendConfig> & Pick<MicroFrontendConfig, \"basePath\">\n): MicroFrontendConfig {\n return {\n basePath: options.basePath,\n protectedRoutes: options.protectedRoutes || {\n \"/dashboard\": [],\n \"/admin\": [\"organization.owner\"],\n },\n publicRoutes: options.publicRoutes || [],\n }\n}\n\n/**\n * Build a sign-in redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-in\n */\nexport function buildSignInUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/auth/signin\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n/**\n * Build a sign-out redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-out\n */\nexport function buildSignOutUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/auth/signout\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n","/**\n * Kernel Bridge Next.js Session\n * Server-side session utilities for Next.js\n */\n\nimport { cookies } from \"next/headers\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n} from \"../index\"\nimport type { Session, SessionCookie } from \"../types\"\n\n/**\n * Get the session cookie from Next.js cookies\n */\nexport async function getSessionCookie(): Promise<SessionCookie | undefined> {\n const cookieStore = await cookies()\n return extractSessionCookie(cookieStore)\n}\n\n/**\n * Get the session token value from cookies\n */\nexport async function getSessionToken(): Promise<string | undefined> {\n const cookie = await getSessionCookie()\n return cookie?.value\n}\n\n/**\n * Check if secure cookie is being used\n */\nexport async function isSecureCookie(): Promise<boolean> {\n const cookie = await getSessionCookie()\n return cookie?.isSecure ?? false\n}\n\n/**\n * Get the current session from cookies\n *\n * This reads the NextAuth session cookie and decodes the JWT.\n * Use this in Server Components, Server Actions, or API routes.\n *\n * @returns Session object or null if not authenticated\n *\n * @example\n * ```typescript\n * import { getSession } from \"@logickernel/bridge/next\"\n *\n * export default async function Page() {\n * const session = await getSession()\n * if (!session) {\n * redirect(\"/auth/signin\")\n * }\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function getSession(): Promise<Session | null> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return null\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return null\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n if (result.error !== \"missing_token\") {\n console.error(\"[bridge] Session decode failed:\", result.error)\n }\n return null\n }\n\n return result.session\n}\n\n/**\n * Get the base URL (facade/load balancer) for user-facing links and redirects\n * \n * This is the URL that users access through the facade/load balancer.\n * Use this for:\n * - Sign-in redirect URLs\n * - User-facing links to the kernel\n * - Any URLs that users will see or click\n */\nexport function getBaseUrl(): string {\n return process.env.BASE_URL || \"http://localhost:7001\"\n}\n\n/**\n * Get user roles in an organization\n *\n * Fetches roles from the kernel API using the current session.\n * The user ID is determined from the session token.\n *\n * @param organizationId - Organization ID to fetch roles in\n * @returns Array of role names (empty if error or no roles)\n *\n * @example\n * ```typescript\n * import { getUserRoles } from \"@logickernel/bridge/next\"\n *\n * const roles = await getUserRoles(\"org-123\")\n * const isOwner = roles.includes(\"organization.owner\")\n * ```\n */\nexport async function getUserRoles(\n organizationId: string\n): Promise<string[]> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return []\n }\n\n const result = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!result.success) {\n console.error(\"[bridge] Failed to fetch user roles:\", result.error)\n return []\n }\n\n return result.roles\n}\n\n","/**\n * Kernel Bridge Next.js Page\n * Authentication utilities for pages/server components\n */\n\nimport { getSession, getUserRoles, getBaseUrl } from \"./session\"\nimport { hasAnyRole } from \"../index\"\nimport type { Session } from \"../types\"\nimport type { PageAuthOptions, PageAuthResult } from \"./types\"\n\n// Re-export session utilities for convenience\nexport { getSession, getUserRoles, getBaseUrl } from \"./session\"\n\n/**\n * Check authentication and optionally roles for a page\n *\n * This is a helper for pages that need both auth and role checking.\n * For simple auth-only checks, use getSession() directly.\n *\n * @param options - Authentication options\n * @returns Auth result with session/roles or redirect URL\n *\n * @example\n * ```typescript\n * import { checkPageAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function AdminPage({ params }) {\n * const { organization_id } = await params\n *\n * const auth = await checkPageAuth({\n * requiredRoles: [\"organization.owner\"],\n * organizationId: organization_id,\n * })\n *\n * if (!auth.authenticated) {\n * redirect(auth.redirectUrl)\n * }\n *\n * return <div>Welcome {auth.session.user.email}</div>\n * }\n * ```\n */\nexport async function checkPageAuth(\n options: PageAuthOptions = {}\n): Promise<PageAuthResult> {\n const { requiredRoles = [], organizationId } = options\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n\n // Get session\n const session = await getSession()\n\n if (!session) {\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/auth/signin`,\n }\n }\n\n // If no roles required, just return session\n if (requiredRoles.length === 0) {\n return {\n authenticated: true,\n session,\n roles: [],\n }\n }\n\n // Roles required - need organization ID\n if (!organizationId) {\n console.error(\"[bridge] Organization ID required for role checking\")\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/auth/signin`,\n }\n }\n\n // Fetch user roles\n const roles = await getUserRoles(organizationId)\n\n // Check if user has required role\n if (!hasAnyRole(roles, requiredRoles)) {\n return {\n authenticated: true, // User is authenticated but lacks roles\n session,\n roles,\n }\n }\n\n return {\n authenticated: true,\n session,\n roles,\n }\n}\n\n/**\n * Require authentication for a page\n *\n * This is a simpler helper that throws if not authenticated.\n * Use with redirect() in the catch block.\n *\n * @returns Session if authenticated\n * @throws RedirectInfo if not authenticated\n *\n * @example\n * ```typescript\n * import { requireAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function DashboardPage() {\n * const session = await requireAuth()\n * // If we get here, user is authenticated\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function requireAuth(): Promise<Session> {\n const session = await getSession()\n\n if (!session) {\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n // We can't use redirect() here because it's a Next.js function\n // Instead, throw an error that the caller can catch\n const error = new Error(\"Authentication required\")\n ;(error as Error & { redirectUrl: string }).redirectUrl = `${baseUrl}/auth/signin`\n throw error\n }\n\n return session\n}\n\n/**\n * Check if user has any of the required roles\n *\n * The user ID is determined from the session token in cookies.\n *\n * @param organizationId - Organization to check roles in\n * @param requiredRoles - Roles to check for\n * @returns True if user has at least one required role\n *\n * @example\n * ```typescript\n * const hasAccess = await hasRequiredRole(\n * \"org-123\",\n * [\"organization.owner\", \"organization.editor\"]\n * )\n * ```\n */\nexport async function hasRequiredRole(\n organizationId: string,\n requiredRoles: string[]\n): Promise<boolean> {\n if (requiredRoles.length === 0) {\n return true // No roles required\n }\n\n const roles = await getUserRoles(organizationId)\n return hasAnyRole(roles, requiredRoles)\n}\n\n","/**\n * Kernel Bridge Next.js API\n * Authentication utilities for API routes\n */\n\nimport { NextRequest, NextResponse } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n hasAnyRole,\n} from \"../index\"\nimport type { Session } from \"../types\"\nimport type { AuthContext, AuthenticatedHandler, WithAuthOptions } from \"./types\"\n\n/**\n * Validate session from request cookies\n */\nasync function validateSession(\n request: NextRequest\n): Promise<{ success: true; session: Session; cookie: { value: string; isSecure: boolean } } | { success: false; error: string }> {\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n return { success: false, error: \"No session cookie\" }\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return { success: false, error: \"Server configuration error\" }\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n return { success: false, error: result.error }\n }\n\n return { success: true, session: result.session, cookie }\n}\n\n/**\n * Wrap an API route handler with authentication\n *\n * This handles JWT validation and optionally role checking.\n * The handler receives the session and can focus on business logic.\n *\n * @param handler - The authenticated handler function\n * @param options - Authentication options\n * @returns A Next.js route handler\n *\n * @example\n * ```typescript\n * // Any authenticated user\n * export const GET = withAuth(async (request, { session }) => {\n * return NextResponse.json({ user: session.user })\n * })\n *\n * // With role requirement\n * export const DELETE = withAuth(\n * async (request, { session }) => {\n * return NextResponse.json({ deleted: true })\n * },\n * { requiredRoles: [\"organization.owner\"] }\n * )\n * ```\n */\nexport function withAuth(\n handler: AuthenticatedHandler,\n options: WithAuthOptions = {}\n): (request: NextRequest, context?: { params?: Promise<Record<string, string>> }) => Promise<Response> {\n return async (\n request: NextRequest,\n context?: { params?: Promise<Record<string, string>> }\n ): Promise<Response> => {\n // Validate session\n const validation = await validateSession(request)\n\n if (!validation.success) {\n return NextResponse.json(\n { error: \"Unauthorized\" },\n { status: 401 }\n )\n }\n\n const { session, cookie } = validation\n\n // Get route params if available\n const params = context?.params ? await context.params : undefined\n\n // Check roles if required\n if (options.requiredRoles && options.requiredRoles.length > 0) {\n // Determine organization ID from params or headers\n const organizationId =\n (options.organizationId && params?.[options.organizationId]) ||\n params?.organization_id ||\n request.headers.get(\"x-organization-id\")\n\n if (!organizationId) {\n return NextResponse.json(\n { error: \"Organization ID required for role-based access\" },\n { status: 400 }\n )\n }\n\n // Fetch user roles\n const rolesResult = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!rolesResult.success) {\n console.error(\"[bridge] Failed to fetch roles:\", rolesResult.error)\n return NextResponse.json(\n { error: \"Failed to verify permissions\" },\n { status: 500 }\n )\n }\n\n if (!hasAnyRole(rolesResult.roles, options.requiredRoles)) {\n return NextResponse.json(\n { error: \"Forbidden\" },\n { status: 403 }\n )\n }\n }\n\n // Call the handler with auth context\n const authContext: AuthContext = {\n session,\n params,\n }\n\n return handler(request, authContext)\n }\n}\n\n/**\n * Get session from a request (for manual handling)\n *\n * Use this when you need more control than withAuth provides.\n *\n * @param request - The Next.js request\n * @returns Session or null\n *\n * @example\n * ```typescript\n * export async function GET(request: NextRequest) {\n * const session = await getSessionFromRequest(request)\n * if (!session) {\n * return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 })\n * }\n * // Custom logic...\n * }\n * ```\n */\nexport async function getSessionFromRequest(\n request: NextRequest\n): Promise<Session | null> {\n const validation = await validateSession(request)\n return validation.success ? validation.session : null\n}\n\n","/**\n * Kernel Bridge Next.js Proxy\n * Middleware/proxy utilities for Next.js\n */\n\nimport { NextResponse } from \"next/server\"\nimport type { NextRequest } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n findMatchingProtectedRoute,\n buildSignInUrl,\n} from \"../index\"\nimport type { ProxyOptions, DynamicRoutePattern, DynamicRouteMatch } from \"./types\"\n\n/**\n * Parse a dynamic route pattern and match against pathname\n *\n * @example\n * matchDynamicRoute(\"/abc123/admin\", \"/[organization_id]/admin\")\n * // Returns: { matched: true, params: { organization_id: \"abc123\" } }\n */\nfunction matchDynamicRoute(\n pathname: string,\n pattern: string,\n basePath: string\n): Omit<DynamicRouteMatch, \"requiredRoles\"> {\n // Remove basePath from pathname\n const relativePath = pathname.replace(basePath, \"\") || \"/\"\n\n // Convert pattern to regex\n // e.g., \"/[organization_id]/admin\" -> /^\\/([^/]+)\\/admin/\n const paramNames: string[] = []\n const regexPattern = pattern.replace(/\\[([^\\]]+)\\]/g, (_, paramName) => {\n paramNames.push(paramName)\n return \"([^/]+)\"\n })\n\n const regex = new RegExp(`^${regexPattern}(?:/.*)?$`)\n const match = relativePath.match(regex)\n\n if (!match) {\n return { matched: false, params: {} }\n }\n\n // Extract params from match groups\n const params: Record<string, string> = {}\n paramNames.forEach((name, index) => {\n const value = match[index + 1]\n if (value !== undefined) {\n params[name] = value\n }\n })\n\n return { matched: true, params }\n}\n\n/**\n * Find matching dynamic route pattern\n */\nfunction findDynamicRouteMatch(\n pathname: string,\n patterns: DynamicRoutePattern[],\n basePath: string\n): DynamicRouteMatch | null {\n for (const pattern of patterns) {\n const result = matchDynamicRoute(pathname, pattern.pattern, basePath)\n if (result.matched) {\n return { ...result, requiredRoles: pattern.requiredRoles }\n }\n }\n return null\n}\n\n/**\n * Create a proxy/middleware handler function for Next.js\n *\n * This creates a fully configured middleware handler that:\n * - Validates authentication for protected routes\n * - Handles dynamic routes with organization IDs\n * - Redirects unauthenticated users to sign in\n * - Adds user info to request headers for downstream use\n *\n * Note: The `config` export must be defined statically in your proxy.ts file\n * for Next.js to analyze it at compile time.\n *\n * @param options - Proxy configuration\n * @returns A Next.js proxy handler function\n *\n * @example\n * ```typescript\n * // src/proxy.ts\n * import { createProxyHandler, type ProxyOptions } from \"@logickernel/bridge/next\"\n *\n * const proxyConfig: ProxyOptions = {\n * basePath: \"/aura\",\n * protectedRoutes: { \"/dashboard\": [] },\n * dynamicRoutes: [\n * { pattern: \"/[organization_id]/admin\", requiredRoles: [\"organization.owner\"] },\n * ],\n * }\n *\n * export const proxy = createProxyHandler(proxyConfig)\n *\n * // Config must be static for Next.js\n * export const config = {\n * matcher: [\"/((?!_next/static|_next/image|favicon.ico|public).*)\"],\n * }\n * ```\n */\nexport function createProxyHandler(\n options: ProxyOptions\n): (request: NextRequest) => Promise<Response> {\n const {\n basePath,\n protectedRoutes,\n dynamicRoutes = [],\n errorPath,\n } = options\n\n async function proxy(request: NextRequest): Promise<Response> {\n const { pathname } = request.nextUrl\n\n // Check dynamic route patterns first\n const dynamicMatch = findDynamicRouteMatch(\n pathname,\n dynamicRoutes,\n basePath\n )\n\n // Check if route matches protected routes\n const staticProtectedMatch = findMatchingProtectedRoute(pathname, protectedRoutes)\n\n // If route is not in protectedRoutes or dynamicRoutes, it's public (no auth needed)\n const isProtected = staticProtectedMatch !== undefined || dynamicMatch?.matched === true\n\n if (!isProtected) {\n return NextResponse.next()\n }\n\n // Protected routes - validate session\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n const signInUrl = buildSignInUrl(request.url)\n return NextResponse.redirect(signInUrl)\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n const errorUrl = errorPath\n ? new URL(errorPath, request.url)\n : new URL(\"/error?code=config\", request.url)\n return NextResponse.redirect(errorUrl)\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n const signInUrl = buildSignInUrl()\n return NextResponse.redirect(signInUrl)\n }\n\n // Add user info to headers for downstream use\n const requestHeaders = new Headers(request.headers)\n requestHeaders.set(\"x-user-id\", result.session.user.id)\n requestHeaders.set(\"x-user-email\", result.session.user.email)\n\n // Add organization ID if from dynamic route\n if (dynamicMatch?.matched && dynamicMatch.params.organization_id) {\n requestHeaders.set(\"x-organization-id\", dynamicMatch.params.organization_id)\n }\n\n // Add any other dynamic params\n if (dynamicMatch?.matched) {\n for (const [key, value] of Object.entries(dynamicMatch.params)) {\n requestHeaders.set(`x-param-${key}`, value)\n }\n }\n\n return NextResponse.next({\n request: {\n headers: requestHeaders,\n },\n })\n }\n\n return proxy\n}\n\n/**\n * Default matcher config for proxy\n * Can be used if you don't want to define your own config\n */\nexport const defaultProxyConfig = {\n matcher: [\n /*\n * Match all request paths except:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public files (public folder)\n */\n \"/((?!_next/static|_next/image|favicon.ico|public).*)\",\n ],\n}\n\n"]}
1
+ {"version":3,"sources":["../../src/jwt.ts","../../src/roles.ts","../../src/routes.ts","../../src/next/session.ts","../../src/next/page.ts","../../src/next/api.ts","../../src/next/proxy.ts"],"names":["cookies","NextResponse"],"mappings":"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","file":"index.js","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for AuthJS/NextAuth tokens\n */\n\nimport { decode } from \"@auth/core/jwt\"\nimport type { Session, SessionCookie, DecodeResult, DecodedToken } from \"./types\"\n\n/**\n * Get the base cookie name from AUTH_COOKIE env var or default to authjs.session-token\n * Strips __Secure- prefix if present, as it will be added automatically for secure cookies\n */\nfunction getBaseCookieName(): string {\n const cookieName = process.env.AUTH_COOKIE || \"authjs.session-token\"\n // Remove __Secure- prefix if present, as we'll add it back for secure cookies\n return cookieName.startsWith(\"__Secure-\") ? cookieName.slice(10) : cookieName\n}\n\n/**\n * Cookie names used by AuthJS/NextAuth\n * Defaults to authjs.session-token, can be overridden via AUTH_COOKIE env var\n */\nexport const COOKIE_NAMES = {\n get secure(): string {\n const baseName = getBaseCookieName()\n // Secure cookies must start with __Secure- prefix\n return `__Secure-${baseName}`\n },\n get dev(): string {\n return getBaseCookieName()\n },\n} as const\n\n/**\n * Get the AUTH_URL from environment variables\n * This is used internally for API calls to the kernel\n */\nexport function getAuthUrl(): string {\n return process.env.AUTH_URL || process.env.BASE_URL || \"http://localhost:3000\"\n}\n\n/**\n * Get the appropriate salt for JWT decoding based on cookie type\n */\nexport function getSalt(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Get the cookie name based on security mode\n */\nexport function getCookieName(isSecure: boolean): string {\n return isSecure ? COOKIE_NAMES.secure : COOKIE_NAMES.dev\n}\n\n/**\n * Check if a token is expired\n */\nexport function isTokenExpired(decoded: DecodedToken): boolean {\n if (!decoded.exp) return false\n return decoded.exp * 1000 < Date.now()\n}\n\n/**\n * Map decoded JWT payload to Session structure\n */\nexport function mapToSession(decoded: DecodedToken): Session {\n return {\n user: {\n id: decoded.sub as string,\n email: decoded.email as string,\n name: (decoded.name as string) || null,\n image: (decoded.picture as string) || null,\n },\n expires: decoded.exp\n ? new Date(decoded.exp * 1000).toISOString()\n : new Date(Date.now() + 30 * 24 * 60 * 60 * 1000).toISOString(), // Default 30 days\n }\n}\n\n/**\n * Decode and validate a session token\n *\n * This is the core function - framework-agnostic JWT decoding.\n * The caller is responsible for extracting the token from their framework's\n * cookie/header mechanism.\n *\n * @param token - The JWT session token\n * @param secret - The AUTH_SECRET used to sign the token\n * @param isSecure - Whether the token came from a secure cookie\n * @returns DecodeResult with session data or error\n *\n * @example\n * ```typescript\n * const result = await decodeSessionToken(token, process.env.AUTH_SECRET, isSecure)\n * if (result.success) {\n * console.log(result.session.user.email)\n * } else {\n * console.error(result.error)\n * }\n * ```\n */\nexport async function decodeSessionToken(\n token: string | undefined,\n secret: string | undefined,\n isSecure: boolean = false\n): Promise<DecodeResult> {\n if (!token) {\n return { success: false, error: \"missing_token\" }\n }\n\n if (!secret) {\n return { success: false, error: \"missing_secret\" }\n }\n\n try {\n const salt = getSalt(isSecure)\n const decoded = await decode({ token, secret, salt })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n if (isTokenExpired(decoded as DecodedToken)) {\n return { success: false, error: \"expired\" }\n }\n\n const session = mapToSession(decoded as DecodedToken)\n return {\n success: true,\n session,\n decoded: decoded as DecodedToken,\n }\n } catch {\n return { success: false, error: \"decode_error\" }\n }\n}\n\n/**\n * Extract session cookie from a cookies object (generic interface)\n *\n * This works with any object that has a `get(name)` method returning\n * `{ value: string } | undefined`, like Next.js cookies() or similar.\n *\n * @param cookies - Object with get(name) method\n * @returns SessionCookie or undefined if no session cookie found\n */\nexport function extractSessionCookie(cookies: {\n get(name: string): { value: string } | undefined\n}): SessionCookie | undefined {\n // Try secure cookie first (production with HTTPS)\n const secureCookie = cookies.get(COOKIE_NAMES.secure)\n if (secureCookie?.value) {\n return { value: secureCookie.value, isSecure: true }\n }\n\n // Fall back to non-secure cookie (development)\n const devCookie = cookies.get(COOKIE_NAMES.dev)\n if (devCookie?.value) {\n return { value: devCookie.value, isSecure: false }\n }\n\n return undefined\n}\n","/**\n * Kernel Bridge Roles\n * Role checking and permission utilities\n */\n\nimport { getCookieName, getAuthUrl } from \"./jwt\"\n\n/**\n * Options for fetching user roles from the kernel\n */\nexport interface FetchRolesOptions {\n /**\n * Organization ID to fetch roles in\n */\n organizationId: string\n\n /**\n * Session token for authentication (user ID is determined from the token)\n */\n sessionToken: string\n\n /**\n * Whether using secure cookie\n * Defaults to NODE_ENV === \"production\" if not provided\n */\n isSecure?: boolean\n\n /**\n * Custom fetch function (optional, for testing or SSR)\n */\n fetchFn?: typeof fetch\n}\n\n/**\n * Result of role fetching operation\n */\nexport type FetchRolesResult =\n | { success: true; roles: string[] }\n | { success: false; error: string }\n\n/**\n * Fetch user roles from the kernel API\n *\n * This is a framework-agnostic function that makes a fetch request\n * to the kernel's roles endpoint. Uses AUTH_URL environment variable internally.\n * The user ID is determined from the session token.\n *\n * @param options - Configuration for fetching roles\n * @returns Promise with roles array or error\n *\n * @example\n * ```typescript\n * const result = await fetchUserRoles({\n * organizationId: \"org-123\",\n * sessionToken: token,\n * // isSecure defaults to NODE_ENV === \"production\"\n * })\n * if (result.success) {\n * console.log(result.roles)\n * }\n * ```\n */\nexport async function fetchUserRoles(\n options: FetchRolesOptions\n): Promise<FetchRolesResult> {\n const { organizationId, sessionToken, fetchFn = fetch } = options\n // Default isSecure to production mode\n const isSecure = options.isSecure ?? (process.env.NODE_ENV === \"production\")\n const kernelUrl = getAuthUrl()\n const cookieName = getCookieName(isSecure)\n\n try {\n const response = await fetchFn(\n `${kernelUrl}/core/api/user/organizations/${organizationId}/roles`,\n {\n headers: {\n Cookie: `${cookieName}=${sessionToken}`,\n },\n cache: \"no-store\",\n }\n )\n\n if (!response.ok) {\n return {\n success: false,\n error: `Failed to fetch roles: ${response.status}`,\n }\n }\n\n const data = await response.json()\n const roles = data.roles?.map((r: { roleName: string }) => r.roleName) || []\n\n return { success: true, roles }\n } catch (error) {\n return {\n success: false,\n error: error instanceof Error ? error.message : \"Unknown error\",\n }\n }\n}\n\n/**\n * Check if user has at least one of the required roles\n */\nexport function hasAnyRole(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true // No roles required = any authenticated user\n return requiredRoles.some((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has all of the required roles\n */\nexport function hasAllRoles(userRoles: string[], requiredRoles: string[]): boolean {\n if (requiredRoles.length === 0) return true\n return requiredRoles.every((role) => userRoles.includes(role))\n}\n\n/**\n * Check if user has a specific role\n */\nexport function hasRole(userRoles: string[], role: string): boolean {\n return userRoles.includes(role)\n}\n\n","/**\n * Kernel Bridge Routes\n * Route matching and protection utilities\n */\n\nimport { getAuthUrl } from \"./jwt\"\nimport type { RouteConfig, RouteMatch, MicroFrontendConfig } from \"./types\"\n\n/**\n * Check if a pathname matches any route in the list\n */\nexport function matchesAnyRoute(pathname: string, routes: string[]): boolean {\n return routes.some((route) => pathname.startsWith(route))\n}\n\n/**\n * Find the first matching protected route for a pathname\n */\nexport function findMatchingProtectedRoute(\n pathname: string,\n protectedRoutes: RouteConfig\n): { route: string; requiredRoles: string[] } | undefined {\n for (const [route, roles] of Object.entries(protectedRoutes)) {\n if (pathname.startsWith(route)) {\n return { route, requiredRoles: roles }\n }\n }\n return undefined\n}\n\n/**\n * Match a pathname against route configuration\n *\n * @param pathname - The URL pathname to match\n * @param config - Micro-frontend configuration\n * @returns RouteMatch indicating the type of route\n *\n * @example\n * ```typescript\n * const match = matchRoute(\"/dashboard\", {\n * publicRoutes: [\"/\", \"/api/health\"],\n * protectedRoutes: { \"/dashboard\": [], \"/admin\": [\"organization.owner\"] },\n * })\n * // Returns: { type: \"protected\", requiredRoles: [] }\n * ```\n */\nexport function matchRoute(\n pathname: string,\n config: Pick<MicroFrontendConfig, \"publicRoutes\" | \"protectedRoutes\">\n): RouteMatch {\n // Check public routes first (if specified)\n if (config.publicRoutes && matchesAnyRoute(pathname, config.publicRoutes)) {\n return { type: \"public\" }\n }\n\n // Check protected routes\n const match = findMatchingProtectedRoute(pathname, config.protectedRoutes)\n if (match) {\n return { type: \"protected\", requiredRoles: match.requiredRoles }\n }\n\n // Not explicitly configured = unprotected\n return { type: \"unprotected\" }\n}\n\n/**\n * Create a default configuration for a micro-frontend\n */\nexport function createConfig(\n options: Partial<MicroFrontendConfig> & Pick<MicroFrontendConfig, \"basePath\">\n): MicroFrontendConfig {\n return {\n basePath: options.basePath,\n protectedRoutes: options.protectedRoutes || {\n \"/dashboard\": [],\n \"/admin\": [\"organization.owner\"],\n },\n publicRoutes: options.publicRoutes || [],\n }\n}\n\n/**\n * Build a sign-in redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-in\n */\nexport function buildSignInUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/core/auth/signin\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n/**\n * Build a sign-out redirect URL\n * Uses AUTH_URL environment variable internally.\n * \n * @param callbackUrl - Optional callback URL to return to after sign-out\n */\nexport function buildSignOutUrl(callbackUrl?: string): URL {\n const authUrl = getAuthUrl()\n const url = new URL(\"/core/auth/signout\", authUrl)\n if (callbackUrl) {\n url.searchParams.set(\"callbackUrl\", callbackUrl)\n }\n return url\n}\n\n","/**\n * Kernel Bridge Next.js Session\n * Server-side session utilities for Next.js\n */\n\nimport { cookies } from \"next/headers\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n} from \"../index\"\nimport type { Session, SessionCookie } from \"../types\"\n\n/**\n * Get the session cookie from Next.js cookies\n */\nexport async function getSessionCookie(): Promise<SessionCookie | undefined> {\n const cookieStore = await cookies()\n return extractSessionCookie(cookieStore)\n}\n\n/**\n * Get the session token value from cookies\n */\nexport async function getSessionToken(): Promise<string | undefined> {\n const cookie = await getSessionCookie()\n return cookie?.value\n}\n\n/**\n * Check if secure cookie is being used\n */\nexport async function isSecureCookie(): Promise<boolean> {\n const cookie = await getSessionCookie()\n return cookie?.isSecure ?? false\n}\n\n/**\n * Get the current session from cookies\n *\n * This reads the NextAuth session cookie and decodes the JWT.\n * Use this in Server Components, Server Actions, or API routes.\n *\n * @returns Session object or null if not authenticated\n *\n * @example\n * ```typescript\n * import { getSession } from \"@logickernel/bridge/next\"\n *\n * export default async function Page() {\n * const session = await getSession()\n * if (!session) {\n * redirect(\"/auth/signin\")\n * }\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function getSession(): Promise<Session | null> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return null\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return null\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n if (result.error !== \"missing_token\") {\n console.error(\"[bridge] Session decode failed:\", result.error)\n }\n return null\n }\n\n return result.session\n}\n\n/**\n * Get the base URL (facade/load balancer) for user-facing links and redirects\n * \n * This is the URL that users access through the facade/load balancer.\n * Use this for:\n * - Sign-in redirect URLs\n * - User-facing links to the kernel\n * - Any URLs that users will see or click\n */\nexport function getBaseUrl(): string {\n return process.env.BASE_URL || \"http://localhost:7001\"\n}\n\n/**\n * Get user roles in an organization\n *\n * Fetches roles from the kernel API using the current session.\n * The user ID is determined from the session token.\n *\n * @param organizationId - Organization ID to fetch roles in\n * @returns Array of role names (empty if error or no roles)\n *\n * @example\n * ```typescript\n * import { getUserRoles } from \"@logickernel/bridge/next\"\n *\n * const roles = await getUserRoles(\"org-123\")\n * const isOwner = roles.includes(\"organization.owner\")\n * ```\n */\nexport async function getUserRoles(\n organizationId: string\n): Promise<string[]> {\n const cookie = await getSessionCookie()\n\n if (!cookie) {\n return []\n }\n\n const result = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!result.success) {\n console.error(\"[bridge] Failed to fetch user roles:\", result.error)\n return []\n }\n\n return result.roles\n}\n\n","/**\n * Kernel Bridge Next.js Page\n * Authentication utilities for pages/server components\n */\n\nimport { getSession, getUserRoles, getBaseUrl } from \"./session\"\nimport { hasAnyRole } from \"../index\"\nimport type { Session } from \"../types\"\nimport type { PageAuthOptions, PageAuthResult } from \"./types\"\n\n// Re-export session utilities for convenience\nexport { getSession, getUserRoles, getBaseUrl } from \"./session\"\n\n/**\n * Check authentication and optionally roles for a page\n *\n * This is a helper for pages that need both auth and role checking.\n * For simple auth-only checks, use getSession() directly.\n *\n * @param options - Authentication options\n * @returns Auth result with session/roles or redirect URL\n *\n * @example\n * ```typescript\n * import { checkPageAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function AdminPage({ params }) {\n * const { organization_id } = await params\n *\n * const auth = await checkPageAuth({\n * requiredRoles: [\"organization.owner\"],\n * organizationId: organization_id,\n * })\n *\n * if (!auth.authenticated) {\n * redirect(auth.redirectUrl)\n * }\n *\n * return <div>Welcome {auth.session.user.email}</div>\n * }\n * ```\n */\nexport async function checkPageAuth(\n options: PageAuthOptions = {}\n): Promise<PageAuthResult> {\n const { requiredRoles = [], organizationId } = options\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n\n // Get session\n const session = await getSession()\n\n if (!session) {\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/core/auth/signin`,\n }\n }\n\n // If no roles required, just return session\n if (requiredRoles.length === 0) {\n return {\n authenticated: true,\n session,\n roles: [],\n }\n }\n\n // Roles required - need organization ID\n if (!organizationId) {\n console.error(\"[bridge] Organization ID required for role checking\")\n return {\n authenticated: false,\n redirectUrl: `${baseUrl}/core/auth/signin`,\n }\n }\n\n // Fetch user roles\n const roles = await getUserRoles(organizationId)\n\n // Check if user has required role\n if (!hasAnyRole(roles, requiredRoles)) {\n return {\n authenticated: true, // User is authenticated but lacks roles\n session,\n roles,\n }\n }\n\n return {\n authenticated: true,\n session,\n roles,\n }\n}\n\n/**\n * Require authentication for a page\n *\n * This is a simpler helper that throws if not authenticated.\n * Use with redirect() in the catch block.\n *\n * @returns Session if authenticated\n * @throws RedirectInfo if not authenticated\n *\n * @example\n * ```typescript\n * import { requireAuth } from \"@logickernel/bridge/next\"\n * import { redirect } from \"next/navigation\"\n *\n * export default async function DashboardPage() {\n * const session = await requireAuth()\n * // If we get here, user is authenticated\n * return <div>Hello {session.user.email}</div>\n * }\n * ```\n */\nexport async function requireAuth(): Promise<Session> {\n const session = await getSession()\n\n if (!session) {\n // Use base URL (facade) for user-facing redirects, not kernel URL (direct microservice)\n const baseUrl = getBaseUrl()\n // We can't use redirect() here because it's a Next.js function\n // Instead, throw an error that the caller can catch\n const error = new Error(\"Authentication required\")\n ;(error as Error & { redirectUrl: string }).redirectUrl = `${baseUrl}/core/auth/signin`\n throw error\n }\n\n return session\n}\n\n/**\n * Check if user has any of the required roles\n *\n * The user ID is determined from the session token in cookies.\n *\n * @param organizationId - Organization to check roles in\n * @param requiredRoles - Roles to check for\n * @returns True if user has at least one required role\n *\n * @example\n * ```typescript\n * const hasAccess = await hasRequiredRole(\n * \"org-123\",\n * [\"organization.owner\", \"organization.editor\"]\n * )\n * ```\n */\nexport async function hasRequiredRole(\n organizationId: string,\n requiredRoles: string[]\n): Promise<boolean> {\n if (requiredRoles.length === 0) {\n return true // No roles required\n }\n\n const roles = await getUserRoles(organizationId)\n return hasAnyRole(roles, requiredRoles)\n}\n\n","/**\n * Kernel Bridge Next.js API\n * Authentication utilities for API routes\n */\n\nimport { NextRequest, NextResponse } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n fetchUserRoles,\n hasAnyRole,\n} from \"../index\"\nimport type { Session } from \"../types\"\nimport type { AuthContext, AuthenticatedHandler, WithAuthOptions } from \"./types\"\n\n/**\n * Validate session from request cookies\n */\nasync function validateSession(\n request: NextRequest\n): Promise<{ success: true; session: Session; cookie: { value: string; isSecure: boolean } } | { success: false; error: string }> {\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n return { success: false, error: \"No session cookie\" }\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n return { success: false, error: \"Server configuration error\" }\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n return { success: false, error: result.error }\n }\n\n return { success: true, session: result.session, cookie }\n}\n\n/**\n * Wrap an API route handler with authentication\n *\n * This handles JWT validation and optionally role checking.\n * The handler receives the session and can focus on business logic.\n *\n * @param handler - The authenticated handler function\n * @param options - Authentication options\n * @returns A Next.js route handler\n *\n * @example\n * ```typescript\n * // Any authenticated user\n * export const GET = withAuth(async (request, { session }) => {\n * return NextResponse.json({ user: session.user })\n * })\n *\n * // With role requirement\n * export const DELETE = withAuth(\n * async (request, { session }) => {\n * return NextResponse.json({ deleted: true })\n * },\n * { requiredRoles: [\"organization.owner\"] }\n * )\n * ```\n */\nexport function withAuth(\n handler: AuthenticatedHandler,\n options: WithAuthOptions = {}\n): (request: NextRequest, context?: { params?: Promise<Record<string, string>> }) => Promise<Response> {\n return async (\n request: NextRequest,\n context?: { params?: Promise<Record<string, string>> }\n ): Promise<Response> => {\n // Validate session\n const validation = await validateSession(request)\n\n if (!validation.success) {\n return NextResponse.json(\n { error: \"Unauthorized\" },\n { status: 401 }\n )\n }\n\n const { session, cookie } = validation\n\n // Get route params if available\n const params = context?.params ? await context.params : undefined\n\n // Check roles if required\n if (options.requiredRoles && options.requiredRoles.length > 0) {\n // Determine organization ID from params or headers\n const organizationId =\n (options.organizationId && params?.[options.organizationId]) ||\n params?.organization_id ||\n request.headers.get(\"x-organization-id\")\n\n if (!organizationId) {\n return NextResponse.json(\n { error: \"Organization ID required for role-based access\" },\n { status: 400 }\n )\n }\n\n // Fetch user roles\n const rolesResult = await fetchUserRoles({\n organizationId,\n sessionToken: cookie.value,\n isSecure: cookie.isSecure,\n })\n\n if (!rolesResult.success) {\n console.error(\"[bridge] Failed to fetch roles:\", rolesResult.error)\n return NextResponse.json(\n { error: \"Failed to verify permissions\" },\n { status: 500 }\n )\n }\n\n if (!hasAnyRole(rolesResult.roles, options.requiredRoles)) {\n return NextResponse.json(\n { error: \"Forbidden\" },\n { status: 403 }\n )\n }\n }\n\n // Call the handler with auth context\n const authContext: AuthContext = {\n session,\n params,\n }\n\n return handler(request, authContext)\n }\n}\n\n/**\n * Get session from a request (for manual handling)\n *\n * Use this when you need more control than withAuth provides.\n *\n * @param request - The Next.js request\n * @returns Session or null\n *\n * @example\n * ```typescript\n * export async function GET(request: NextRequest) {\n * const session = await getSessionFromRequest(request)\n * if (!session) {\n * return NextResponse.json({ error: \"Unauthorized\" }, { status: 401 })\n * }\n * // Custom logic...\n * }\n * ```\n */\nexport async function getSessionFromRequest(\n request: NextRequest\n): Promise<Session | null> {\n const validation = await validateSession(request)\n return validation.success ? validation.session : null\n}\n\n","/**\n * Kernel Bridge Next.js Proxy\n * Middleware/proxy utilities for Next.js\n */\n\nimport { NextResponse } from \"next/server\"\nimport type { NextRequest } from \"next/server\"\nimport {\n decodeSessionToken,\n extractSessionCookie,\n findMatchingProtectedRoute,\n buildSignInUrl,\n} from \"../index\"\nimport type { ProxyOptions, DynamicRoutePattern, DynamicRouteMatch } from \"./types\"\n\n/**\n * Parse a dynamic route pattern and match against pathname\n *\n * @example\n * matchDynamicRoute(\"/abc123/admin\", \"/[organization_id]/admin\")\n * // Returns: { matched: true, params: { organization_id: \"abc123\" } }\n */\nfunction matchDynamicRoute(\n pathname: string,\n pattern: string,\n basePath: string\n): Omit<DynamicRouteMatch, \"requiredRoles\"> {\n // Remove basePath from pathname\n const relativePath = pathname.replace(basePath, \"\") || \"/\"\n\n // Convert pattern to regex\n // e.g., \"/[organization_id]/admin\" -> /^\\/([^/]+)\\/admin/\n const paramNames: string[] = []\n const regexPattern = pattern.replace(/\\[([^\\]]+)\\]/g, (_, paramName) => {\n paramNames.push(paramName)\n return \"([^/]+)\"\n })\n\n const regex = new RegExp(`^${regexPattern}(?:/.*)?$`)\n const match = relativePath.match(regex)\n\n if (!match) {\n return { matched: false, params: {} }\n }\n\n // Extract params from match groups\n const params: Record<string, string> = {}\n paramNames.forEach((name, index) => {\n const value = match[index + 1]\n if (value !== undefined) {\n params[name] = value\n }\n })\n\n return { matched: true, params }\n}\n\n/**\n * Find matching dynamic route pattern\n */\nfunction findDynamicRouteMatch(\n pathname: string,\n patterns: DynamicRoutePattern[],\n basePath: string\n): DynamicRouteMatch | null {\n for (const pattern of patterns) {\n const result = matchDynamicRoute(pathname, pattern.pattern, basePath)\n if (result.matched) {\n return { ...result, requiredRoles: pattern.requiredRoles }\n }\n }\n return null\n}\n\n/**\n * Create a proxy/middleware handler function for Next.js\n *\n * This creates a fully configured middleware handler that:\n * - Validates authentication for protected routes\n * - Handles dynamic routes with organization IDs\n * - Redirects unauthenticated users to sign in\n * - Adds user info to request headers for downstream use\n *\n * Note: The `config` export must be defined statically in your proxy.ts file\n * for Next.js to analyze it at compile time.\n *\n * @param options - Proxy configuration\n * @returns A Next.js proxy handler function\n *\n * @example\n * ```typescript\n * // src/proxy.ts\n * import { createProxyHandler, type ProxyOptions } from \"@logickernel/bridge/next\"\n *\n * const proxyConfig: ProxyOptions = {\n * basePath: \"/aura\",\n * protectedRoutes: { \"/dashboard\": [] },\n * dynamicRoutes: [\n * { pattern: \"/[organization_id]/admin\", requiredRoles: [\"organization.owner\"] },\n * ],\n * }\n *\n * export const proxy = createProxyHandler(proxyConfig)\n *\n * // Config must be static for Next.js\n * export const config = {\n * matcher: [\"/((?!_next/static|_next/image|favicon.ico|public).*)\"],\n * }\n * ```\n */\nexport function createProxyHandler(\n options: ProxyOptions\n): (request: NextRequest) => Promise<Response> {\n const {\n basePath,\n protectedRoutes,\n dynamicRoutes = [],\n errorPath,\n } = options\n\n async function proxy(request: NextRequest): Promise<Response> {\n const { pathname } = request.nextUrl\n\n // Check dynamic route patterns first\n const dynamicMatch = findDynamicRouteMatch(\n pathname,\n dynamicRoutes,\n basePath\n )\n\n // Check if route matches protected routes\n const staticProtectedMatch = findMatchingProtectedRoute(pathname, protectedRoutes)\n\n // If route is not in protectedRoutes or dynamicRoutes, it's public (no auth needed)\n const isProtected = staticProtectedMatch !== undefined || dynamicMatch?.matched === true\n\n if (!isProtected) {\n return NextResponse.next()\n }\n\n // Protected routes - validate session\n const cookie = extractSessionCookie(request.cookies)\n\n if (!cookie) {\n const signInUrl = buildSignInUrl(request.url)\n return NextResponse.redirect(signInUrl)\n }\n\n const secret = process.env.AUTH_SECRET\n if (!secret) {\n console.error(\"[bridge] AUTH_SECRET is not configured\")\n const errorUrl = errorPath\n ? new URL(errorPath, request.url)\n : new URL(\"/error?code=config\", request.url)\n return NextResponse.redirect(errorUrl)\n }\n\n const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure)\n\n if (!result.success) {\n const signInUrl = buildSignInUrl()\n return NextResponse.redirect(signInUrl)\n }\n\n // Add user info to headers for downstream use\n const requestHeaders = new Headers(request.headers)\n requestHeaders.set(\"x-user-id\", result.session.user.id)\n requestHeaders.set(\"x-user-email\", result.session.user.email)\n\n // Add organization ID if from dynamic route\n if (dynamicMatch?.matched && dynamicMatch.params.organization_id) {\n requestHeaders.set(\"x-organization-id\", dynamicMatch.params.organization_id)\n }\n\n // Add any other dynamic params\n if (dynamicMatch?.matched) {\n for (const [key, value] of Object.entries(dynamicMatch.params)) {\n requestHeaders.set(`x-param-${key}`, value)\n }\n }\n\n return NextResponse.next({\n request: {\n headers: requestHeaders,\n },\n })\n }\n\n return proxy\n}\n\n/**\n * Default matcher config for proxy\n * Can be used if you don't want to define your own config\n */\nexport const defaultProxyConfig = {\n matcher: [\n /*\n * Match all request paths except:\n * - _next/static (static files)\n * - _next/image (image optimization files)\n * - favicon.ico (favicon file)\n * - public files (public folder)\n */\n \"/((?!_next/static|_next/image|favicon.ico|public).*)\",\n ],\n}\n\n"]}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@logickernel/bridge",
3
- "version": "0.9.9",
3
+ "version": "0.10.0",
4
4
  "description": "Framework-agnostic micro-frontend authentication library for AuthJS/NextAuth JWT tokens",
5
5
  "author": "Victor",
6
6
  "license": "MIT",