@logickernel/bridge 0.13.2 → 0.14.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.
@@ -117,24 +117,6 @@ function hasAnyRole(userRoles, requiredRoles) {
117
117
  return requiredRoles.some((role) => userRoles.includes(role));
118
118
  }
119
119
 
120
- // src/routes.ts
121
- function findMatchingProtectedRoute(pathname, protectedRoutes) {
122
- for (const [route, roles] of Object.entries(protectedRoutes)) {
123
- if (pathname.startsWith(route)) {
124
- return { route, requiredRoles: roles };
125
- }
126
- }
127
- return void 0;
128
- }
129
- function buildSignInUrl(callbackUrl) {
130
- const authUrl = getAuthUrl();
131
- const url = new URL("/core/auth/signin", authUrl);
132
- if (callbackUrl) {
133
- url.searchParams.set("callbackUrl", callbackUrl);
134
- }
135
- return url;
136
- }
137
-
138
120
  // src/next/session.ts
139
121
  async function getSessionCookie() {
140
122
  const cookieStore = await headers.cookies();
@@ -309,8 +291,12 @@ async function getSessionFromRequest(request) {
309
291
  const validation = await validateSession(request);
310
292
  return validation.success ? validation.session : null;
311
293
  }
312
- function matchDynamicRoute(pathname, pattern, basePath) {
313
- const relativePath = pathname.replace(basePath, "") || "/";
294
+
295
+ // src/routes.ts
296
+ function isDynamicRoute(route) {
297
+ return route.includes("[") && route.includes("]");
298
+ }
299
+ function matchDynamicRoutePattern(relativePath, pattern) {
314
300
  const paramNames = [];
315
301
  const regexPattern = pattern.replace(/\[([^\]]+)\]/g, (_, paramName) => {
316
302
  paramNames.push(paramName);
@@ -319,7 +305,7 @@ function matchDynamicRoute(pathname, pattern, basePath) {
319
305
  const regex = new RegExp(`^${regexPattern}(?:/.*)?$`);
320
306
  const match = relativePath.match(regex);
321
307
  if (!match) {
322
- return { matched: false, params: {} };
308
+ return null;
323
309
  }
324
310
  const params = {};
325
311
  paramNames.forEach((name, index) => {
@@ -328,39 +314,46 @@ function matchDynamicRoute(pathname, pattern, basePath) {
328
314
  params[name] = value;
329
315
  }
330
316
  });
331
- return { matched: true, params };
317
+ return { params };
332
318
  }
333
- function findDynamicRouteMatch(pathname, patterns, basePath) {
334
- for (const pattern of patterns) {
335
- const result = matchDynamicRoute(pathname, pattern.pattern, basePath);
336
- if (result.matched) {
337
- return { ...result, requiredRoles: pattern.requiredRoles };
319
+ function findMatchingRoute(pathname, routes, basePath) {
320
+ if (!pathname.startsWith(basePath)) {
321
+ return void 0;
322
+ }
323
+ const relativePath = pathname.replace(basePath, "") || "/";
324
+ for (const [route, requiredRoles] of Object.entries(routes)) {
325
+ if (isDynamicRoute(route)) {
326
+ const match = matchDynamicRoutePattern(relativePath, route);
327
+ if (match) {
328
+ return { route, requiredRoles, params: match.params };
329
+ }
330
+ } else {
331
+ if (relativePath.startsWith(route)) {
332
+ return { route, requiredRoles };
333
+ }
338
334
  }
339
335
  }
340
- return null;
336
+ return void 0;
341
337
  }
338
+
339
+ // src/next/proxy.ts
342
340
  function createProxyHandler(options) {
343
341
  const {
344
342
  basePath,
345
- protectedRoutes,
346
- dynamicRoutes = [],
343
+ routes,
347
344
  errorPath
348
345
  } = options;
349
346
  async function proxy(request) {
350
347
  const { pathname } = request.nextUrl;
351
- const dynamicMatch = findDynamicRouteMatch(
352
- pathname,
353
- dynamicRoutes,
354
- basePath
355
- );
356
- const staticProtectedMatch = findMatchingProtectedRoute(pathname, protectedRoutes);
357
- const isProtected = staticProtectedMatch !== void 0 || dynamicMatch?.matched === true;
348
+ const routeMatch = findMatchingRoute(pathname, routes, basePath);
349
+ const isProtected = routeMatch !== void 0;
358
350
  if (!isProtected) {
359
351
  return server.NextResponse.next();
360
352
  }
361
353
  const cookie = extractSessionCookie(request.cookies);
362
354
  if (!cookie) {
363
- const signInUrl = buildSignInUrl(request.url);
355
+ const signInUrl = new URL("/core/auth/signin", request.nextUrl.origin);
356
+ signInUrl.searchParams.set("callbackUrl", request.url);
364
357
  return server.NextResponse.redirect(signInUrl);
365
358
  }
366
359
  const secret = process.env.AUTH_SECRET;
@@ -371,17 +364,42 @@ function createProxyHandler(options) {
371
364
  }
372
365
  const result = await decodeSessionToken(cookie.value, secret, cookie.isSecure);
373
366
  if (!result.success) {
374
- const signInUrl = buildSignInUrl();
367
+ const signInUrl = new URL("/core/auth/signin", request.nextUrl.origin);
375
368
  return server.NextResponse.redirect(signInUrl);
376
369
  }
370
+ const requiredRoles = routeMatch?.requiredRoles || [];
371
+ if (requiredRoles.length > 0) {
372
+ const organizationId = routeMatch?.params?.organization_id || request.headers.get("x-organization-id");
373
+ if (!organizationId) {
374
+ const signInUrl = new URL("/core/auth/signin", request.nextUrl.origin);
375
+ signInUrl.searchParams.set("callbackUrl", request.url);
376
+ return server.NextResponse.redirect(signInUrl);
377
+ }
378
+ const rolesResult = await fetchUserRoles({
379
+ organizationId,
380
+ sessionToken: cookie.value,
381
+ isSecure: cookie.isSecure
382
+ });
383
+ if (!rolesResult.success) {
384
+ console.error("[bridge] Failed to fetch roles:", rolesResult.error);
385
+ const signInUrl = new URL("/core/auth/signin", request.nextUrl.origin);
386
+ signInUrl.searchParams.set("callbackUrl", request.url);
387
+ return server.NextResponse.redirect(signInUrl);
388
+ }
389
+ if (!hasAnyRole(rolesResult.roles, requiredRoles)) {
390
+ const signInUrl = new URL("/core/auth/signin", request.nextUrl.origin);
391
+ signInUrl.searchParams.set("callbackUrl", request.url);
392
+ return server.NextResponse.redirect(signInUrl);
393
+ }
394
+ }
377
395
  const requestHeaders = new Headers(request.headers);
378
396
  requestHeaders.set("x-user-id", result.session.user.id);
379
397
  requestHeaders.set("x-user-email", result.session.user.email);
380
- if (dynamicMatch?.matched && dynamicMatch.params.organization_id) {
381
- requestHeaders.set("x-organization-id", dynamicMatch.params.organization_id);
398
+ if (routeMatch?.params?.organization_id) {
399
+ requestHeaders.set("x-organization-id", routeMatch.params.organization_id);
382
400
  }
383
- if (dynamicMatch?.matched) {
384
- for (const [key, value] of Object.entries(dynamicMatch.params)) {
401
+ if (routeMatch?.params) {
402
+ for (const [key, value] of Object.entries(routeMatch.params)) {
385
403
  requestHeaders.set(`x-param-${key}`, value);
386
404
  }
387
405
  }
@@ -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":["nextAuthDecode","cookies","NextResponse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for NextAuth v4 tokens\n * Uses NextAuth's internal decode function for guaranteed compatibility\n */\n\nimport { decode as nextAuthDecode } from \"next-auth/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 next-auth.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 || \"next-auth.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 NextAuth v4\n * Defaults to next-auth.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 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 // Use NextAuth's decode function directly for session tokens\n // For session tokens, NextAuth uses an empty salt (\"\")\n const decoded = await nextAuthDecode({\n token,\n secret,\n salt: \"\", // Empty salt means session token in NextAuth\n })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n // Check if token is expired\n if (decoded.exp && typeof decoded.exp === \"number\" && decoded.exp * 1000 < Date.now()) {\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 (error) {\n // Log the actual error for debugging\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(\"[bridge] JWT decode error:\", errorMessage)\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"]}
1
+ {"version":3,"sources":["../../src/jwt.ts","../../src/roles.ts","../../src/next/session.ts","../../src/next/page.ts","../../src/next/api.ts","../../src/routes.ts","../../src/next/proxy.ts"],"names":["nextAuthDecode","cookies","NextResponse"],"mappings":"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","file":"index.cjs","sourcesContent":["/**\n * Kernel Bridge JWT\n * Framework-agnostic JWT decoding for NextAuth v4 tokens\n * Uses NextAuth's internal decode function for guaranteed compatibility\n */\n\nimport { decode as nextAuthDecode } from \"next-auth/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 next-auth.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 || \"next-auth.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 NextAuth v4\n * Defaults to next-auth.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 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 // Use NextAuth's decode function directly for session tokens\n // For session tokens, NextAuth uses an empty salt (\"\")\n const decoded = await nextAuthDecode({\n token,\n secret,\n salt: \"\", // Empty salt means session token in NextAuth\n })\n\n if (!decoded) {\n return { success: false, error: \"decode_error\" }\n }\n\n // Check if token is expired\n if (decoded.exp && typeof decoded.exp === \"number\" && decoded.exp * 1000 < Date.now()) {\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 (error) {\n // Log the actual error for debugging\n const errorMessage = error instanceof Error ? error.message : String(error)\n console.error(\"[bridge] JWT decode error:\", errorMessage)\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 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 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 * @deprecated Use findMatchingRoute instead, which supports basePath-relative routes\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 * Check if a route pattern is dynamic (contains [param] syntax)\n */\nfunction isDynamicRoute(route: string): boolean {\n return route.includes(\"[\") && route.includes(\"]\")\n}\n\n/**\n * Match a dynamic route pattern against a relative pathname\n * @param relativePath - Path relative to basePath (e.g., \"/abc123/admin\")\n * @param pattern - Route pattern with [param] syntax (e.g., \"/[organization_id]/admin\")\n * @returns Match result with params if matched, null otherwise\n */\nfunction matchDynamicRoutePattern(\n relativePath: string,\n pattern: string\n): { params: Record<string, string> } | null {\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 null\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 { params }\n}\n\n/**\n * Find the first matching route for a pathname (supports both static and dynamic routes)\n * Routes are relative to basePath, and basePath is prepended during matching\n * \n * @param pathname - Full pathname (e.g., \"/app/dashboard\")\n * @param routes - Route configuration (routes are relative to basePath)\n * @param basePath - Base path for the micro-frontend (e.g., \"/app\")\n * @returns Match result with route, requiredRoles, and params (if dynamic), or undefined\n */\nexport function findMatchingRoute(\n pathname: string,\n routes: RouteConfig,\n basePath: string\n): { route: string; requiredRoles: string[]; params?: Record<string, string> } | undefined {\n // Check if pathname starts with basePath\n if (!pathname.startsWith(basePath)) {\n return undefined\n }\n\n // Extract relative path (remove basePath)\n const relativePath = pathname.replace(basePath, \"\") || \"/\"\n\n // Check each route\n for (const [route, requiredRoles] of Object.entries(routes)) {\n if (isDynamicRoute(route)) {\n // Dynamic route: match pattern\n const match = matchDynamicRoutePattern(relativePath, route)\n if (match) {\n return { route, requiredRoles, params: match.params }\n }\n } else {\n // Static route: prefix matching\n if (relativePath.startsWith(route)) {\n return { route, requiredRoles }\n }\n }\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(\"/app/dashboard\", {\n * basePath: \"/app\",\n * publicRoutes: [\"/\", \"/api/health\"],\n * routes: { \"/dashboard\": [], \"/admin\": [\"organization.owner\"] },\n * })\n * // Returns: { type: \"protected\", requiredRoles: [] }\n * ```\n */\nexport function matchRoute(\n pathname: string,\n config: Pick<MicroFrontendConfig, \"basePath\" | \"publicRoutes\" | \"routes\">\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 routes (relative to basePath)\n const match = findMatchingRoute(pathname, config.routes, config.basePath)\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 routes: options.routes || {\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 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 fetchUserRoles,\n hasAnyRole,\n} from \"../index\"\nimport {\n findMatchingRoute,\n} from \"../routes\"\nimport type { ProxyOptions } from \"./types\"\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: \"/app\",\n * routes: {\n * \"/dashboard\": [],\n * \"/[organization_id]/admin\": [\"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 routes,\n errorPath,\n } = options\n\n async function proxy(request: NextRequest): Promise<Response> {\n const { pathname } = request.nextUrl\n\n // Check if route matches any configured route (static or dynamic)\n const routeMatch = findMatchingRoute(pathname, routes, basePath)\n\n // If route is not in routes, it's public (no auth needed)\n const isProtected = routeMatch !== undefined\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 // Use simple absolute-relative path since all apps share the same hostname\n const signInUrl = new URL(\"/core/auth/signin\", request.nextUrl.origin)\n signInUrl.searchParams.set(\"callbackUrl\", 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 // Use simple absolute-relative path since all apps share the same hostname\n const signInUrl = new URL(\"/core/auth/signin\", request.nextUrl.origin)\n return NextResponse.redirect(signInUrl)\n }\n\n // Check roles if required\n const requiredRoles = routeMatch?.requiredRoles || []\n \n if (requiredRoles.length > 0) {\n // Need organization ID for role checking\n const organizationId = routeMatch?.params?.organization_id || \n request.headers.get(\"x-organization-id\")\n \n if (!organizationId) {\n // Can't check roles without organization ID\n const signInUrl = new URL(\"/core/auth/signin\", request.nextUrl.origin)\n signInUrl.searchParams.set(\"callbackUrl\", request.url)\n return NextResponse.redirect(signInUrl)\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 const signInUrl = new URL(\"/core/auth/signin\", request.nextUrl.origin)\n signInUrl.searchParams.set(\"callbackUrl\", request.url)\n return NextResponse.redirect(signInUrl)\n }\n\n // Check if user has any of the required roles\n if (!hasAnyRole(rolesResult.roles, requiredRoles)) {\n // User doesn't have required role\n const signInUrl = new URL(\"/core/auth/signin\", request.nextUrl.origin)\n signInUrl.searchParams.set(\"callbackUrl\", request.url)\n return NextResponse.redirect(signInUrl)\n }\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 route params\n if (routeMatch?.params?.organization_id) {\n requestHeaders.set(\"x-organization-id\", routeMatch.params.organization_id)\n }\n\n // Add any other route params\n if (routeMatch?.params) {\n for (const [key, value] of Object.entries(routeMatch.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,5 +1,5 @@
1
- import { b as Session, S as SessionCookie, M as MicroFrontendConfig } from '../types-YvOY9KNP.cjs';
2
- export { d as SessionUser } from '../types-YvOY9KNP.cjs';
1
+ import { b as Session, S as SessionCookie, M as MicroFrontendConfig } from '../types-CyxNdDrk.cjs';
2
+ export { c as SessionUser } from '../types-CyxNdDrk.cjs';
3
3
  import { NextRequest } from 'next/server';
4
4
 
5
5
  /**
@@ -79,38 +79,11 @@ declare function getUserRoles(organizationId: string): Promise<string[]>;
79
79
  * Options for the proxy factory
80
80
  */
81
81
  interface ProxyOptions extends MicroFrontendConfig {
82
- /**
83
- * Dynamic route patterns that contain organization IDs
84
- * e.g., "/[organization_id]/admin" matches "/abc123/admin"
85
- */
86
- dynamicRoutes?: DynamicRoutePattern[];
87
82
  /**
88
83
  * Custom error page path (defaults to showing error in redirect)
89
84
  */
90
85
  errorPath?: string;
91
86
  }
92
- /**
93
- * Dynamic route pattern configuration
94
- */
95
- interface DynamicRoutePattern {
96
- /**
97
- * Pattern to match (e.g., "/[organization_id]/admin")
98
- * Use [param] syntax for dynamic segments
99
- */
100
- pattern: string;
101
- /**
102
- * Required roles for this route (empty = any authenticated user)
103
- */
104
- requiredRoles: string[];
105
- }
106
- /**
107
- * Result from parsing a dynamic route
108
- */
109
- interface DynamicRouteMatch {
110
- matched: boolean;
111
- params: Record<string, string>;
112
- requiredRoles: string[];
113
- }
114
87
  /**
115
88
  * API route handler with auth context
116
89
  */
@@ -318,11 +291,11 @@ declare function getSessionFromRequest(request: NextRequest): Promise<Session |
318
291
  * import { createProxyHandler, type ProxyOptions } from "@logickernel/bridge/next"
319
292
  *
320
293
  * const proxyConfig: ProxyOptions = {
321
- * basePath: "/aura",
322
- * protectedRoutes: { "/dashboard": [] },
323
- * dynamicRoutes: [
324
- * { pattern: "/[organization_id]/admin", requiredRoles: ["organization.owner"] },
325
- * ],
294
+ * basePath: "/app",
295
+ * routes: {
296
+ * "/dashboard": [],
297
+ * "/[organization_id]/admin": ["organization.owner"],
298
+ * },
326
299
  * }
327
300
  *
328
301
  * export const proxy = createProxyHandler(proxyConfig)
@@ -342,4 +315,4 @@ declare const defaultProxyConfig: {
342
315
  matcher: string[];
343
316
  };
344
317
 
345
- export { type AuthContext, type AuthenticatedHandler, type DynamicRouteMatch, type DynamicRoutePattern, type PageAuthOptions, type PageAuthResult, type ProxyOptions, Session, SessionCookie, type WithAuthOptions, checkPageAuth, createProxyHandler, defaultProxyConfig, getBaseUrl, getSession, getSessionCookie, getSessionFromRequest, getSessionToken, getUserRoles, hasRequiredRole, isSecureCookie, requireAuth, withAuth };
318
+ export { type AuthContext, type AuthenticatedHandler, type PageAuthOptions, type PageAuthResult, type ProxyOptions, Session, SessionCookie, type WithAuthOptions, checkPageAuth, createProxyHandler, defaultProxyConfig, getBaseUrl, getSession, getSessionCookie, getSessionFromRequest, getSessionToken, getUserRoles, hasRequiredRole, isSecureCookie, requireAuth, withAuth };
@@ -1,5 +1,5 @@
1
- import { b as Session, S as SessionCookie, M as MicroFrontendConfig } from '../types-YvOY9KNP.js';
2
- export { d as SessionUser } from '../types-YvOY9KNP.js';
1
+ import { b as Session, S as SessionCookie, M as MicroFrontendConfig } from '../types-CyxNdDrk.js';
2
+ export { c as SessionUser } from '../types-CyxNdDrk.js';
3
3
  import { NextRequest } from 'next/server';
4
4
 
5
5
  /**
@@ -79,38 +79,11 @@ declare function getUserRoles(organizationId: string): Promise<string[]>;
79
79
  * Options for the proxy factory
80
80
  */
81
81
  interface ProxyOptions extends MicroFrontendConfig {
82
- /**
83
- * Dynamic route patterns that contain organization IDs
84
- * e.g., "/[organization_id]/admin" matches "/abc123/admin"
85
- */
86
- dynamicRoutes?: DynamicRoutePattern[];
87
82
  /**
88
83
  * Custom error page path (defaults to showing error in redirect)
89
84
  */
90
85
  errorPath?: string;
91
86
  }
92
- /**
93
- * Dynamic route pattern configuration
94
- */
95
- interface DynamicRoutePattern {
96
- /**
97
- * Pattern to match (e.g., "/[organization_id]/admin")
98
- * Use [param] syntax for dynamic segments
99
- */
100
- pattern: string;
101
- /**
102
- * Required roles for this route (empty = any authenticated user)
103
- */
104
- requiredRoles: string[];
105
- }
106
- /**
107
- * Result from parsing a dynamic route
108
- */
109
- interface DynamicRouteMatch {
110
- matched: boolean;
111
- params: Record<string, string>;
112
- requiredRoles: string[];
113
- }
114
87
  /**
115
88
  * API route handler with auth context
116
89
  */
@@ -318,11 +291,11 @@ declare function getSessionFromRequest(request: NextRequest): Promise<Session |
318
291
  * import { createProxyHandler, type ProxyOptions } from "@logickernel/bridge/next"
319
292
  *
320
293
  * const proxyConfig: ProxyOptions = {
321
- * basePath: "/aura",
322
- * protectedRoutes: { "/dashboard": [] },
323
- * dynamicRoutes: [
324
- * { pattern: "/[organization_id]/admin", requiredRoles: ["organization.owner"] },
325
- * ],
294
+ * basePath: "/app",
295
+ * routes: {
296
+ * "/dashboard": [],
297
+ * "/[organization_id]/admin": ["organization.owner"],
298
+ * },
326
299
  * }
327
300
  *
328
301
  * export const proxy = createProxyHandler(proxyConfig)
@@ -342,4 +315,4 @@ declare const defaultProxyConfig: {
342
315
  matcher: string[];
343
316
  };
344
317
 
345
- export { type AuthContext, type AuthenticatedHandler, type DynamicRouteMatch, type DynamicRoutePattern, type PageAuthOptions, type PageAuthResult, type ProxyOptions, Session, SessionCookie, type WithAuthOptions, checkPageAuth, createProxyHandler, defaultProxyConfig, getBaseUrl, getSession, getSessionCookie, getSessionFromRequest, getSessionToken, getUserRoles, hasRequiredRole, isSecureCookie, requireAuth, withAuth };
318
+ export { type AuthContext, type AuthenticatedHandler, type PageAuthOptions, type PageAuthResult, type ProxyOptions, Session, SessionCookie, type WithAuthOptions, checkPageAuth, createProxyHandler, defaultProxyConfig, getBaseUrl, getSession, getSessionCookie, getSessionFromRequest, getSessionToken, getUserRoles, hasRequiredRole, isSecureCookie, requireAuth, withAuth };