import type { ActorContext } from '@devrunbook/application' import { cookies, headers } from 'next/headers' import { redirect } from 'next/navigation' import type { ReactNode } from 'react' import type { CommandPaletteItem } from '../../components/command-palette/command-palette' import { AppShell } from '../../components/shell/app-shell' import { isThemePreference } from '../../components/theme/theme-model' import { detectLocale, isPresentationMode, } from '../../components/presentation/presentation-model' import { getAuth } from '../../auth/auth' import { AuthenticatedWorkspaceContextError, resolveAuthenticatedWorkspaceContext, } from '../../server/authenticated-workspace-context' import { DrizzleWorkspaceSelectionLookup } from '@devrunbook/db' import { authenticatedCommands, buildAuthenticatedShellPresentation, buildLoginHref, commandsForWorkspaceRole, localizeAuthenticatedCommands, } from './authenticated-app-presentation' export interface AuthenticatedAppLayoutProps { readonly children: ReactNode readonly requestPath: string readonly loginReturnTo: string readonly activeNavigationId: string readonly commands?: readonly CommandPaletteItem[] readonly loadCommands?: ( actor: ActorContext, ) => Promise } export async function AuthenticatedAppLayout({ children, requestPath, loginReturnTo, activeNavigationId, commands = authenticatedCommands, loadCommands, }: AuthenticatedAppLayoutProps) { let actor: ActorContext const requestHeaders = await headers() try { actor = await resolveAuthenticatedWorkspaceContext( new Request(new URL(requestPath, 'http://devrunbook.local'), { headers: requestHeaders, }), ) } catch (error) { if ( error instanceof AuthenticatedWorkspaceContextError && error.code === 'authentication_required' ) { redirect(buildLoginHref(loginReturnTo)) } throw error } const cookieStore = await cookies() const themeCookie = cookieStore.get('devrunbook_theme')?.value const initialTheme = isThemePreference(themeCookie) ? themeCookie : 'system' const modeCookie = cookieStore.get('devrunbook_mode')?.value const mode = isPresentationMode(modeCookie) ? modeCookie : 'simple' const locale = detectLocale( cookieStore.get('devrunbook_locale')?.value, requestHeaders.get('accept-language'), ) const session = await getAuth().api.getSession({ headers: requestHeaders }) const workspaces = await new DrizzleWorkspaceSelectionLookup().listAuthorizedWorkspaces( actor.userId, ) const presentation = buildAuthenticatedShellPresentation({ ...actor, mode, locale, workspaces: workspaces.map(({ id, name, type }) => ({ id, name, type })), ...(session?.user.name ? { displayName: session.user.name } : {}), ...(session?.user.email ? { email: session.user.email } : {}), }) const resolvedCommands = localizeAuthenticatedCommands( commandsForWorkspaceRole( loadCommands ? await loadCommands(actor) : commands, actor.workspaceRole, ), locale, ) return ( {children} ) }