# Layout — `@sonordev/site-kit/layout`

RSC-compatible master layout that auto-composes all site-kit features.

## Usage

```tsx
// app/layout.tsx
import { SiteKitLayout } from '@sonordev/site-kit/layout'

export default function RootLayout({ children }: { children: React.ReactNode }) {
  return (
    <html lang="en">
      <body>
        <SiteKitLayout>{children}</SiteKitLayout>
      </body>
    </html>
  )
}
```

Zero-config: reads `SONOR_API_KEY` from env, injects it into client modules automatically.

## Props

```ts
interface SiteKitLayoutProps {
  children: React.ReactNode
  apiKey?: string                         // Defaults to SONOR_API_KEY env var
  apiUrl?: string                         // Defaults to SONOR_API_URL, then https://api.sonor.io
  projectId?: string                      // For chat routing (auto-resolved if omitted)
  analytics?: boolean | AnalyticsConfig   // Default: true
  chat?: boolean | ChatLayoutConfig       // Default: true (website chat; config = launcher placement)
  popups?: boolean                        // Default: true (Website → Popups & Banners)
  engage?: boolean | EngageConfig         // Deprecated: false turns chat and popups off; an object configures the launcher
  signal?: boolean | SignalConfig         // Default: false
  sitemapSync?: boolean                   // Default: false (build-time + server reconciler own this)
  fleet?: boolean                         // Default: true (once-per-session kit version heartbeat)
  defer?: boolean                         // Default: true (client modules wait for load + idle)
  favicon?: boolean                       // Default: true
  managedScripts?: boolean                // Default: true
  debug?: boolean                         // Default: false
  showLlmsTxtFooterLink?: boolean         // Default: false (prefer middleware discovery headers)
  speculation?: boolean | { mode?: 'prerender' | 'prefetch'; exclude?: string[] } // Default: false
}
```

Module options live with each module: [Analytics](https://sonor.dev/site-kit/analytics) (`trackPageViews`, `excludePaths`, `site`, `allowInFrame`, `allowLocalhost`) [Website chat](https://sonor.dev/site-kit/chat) (`position`, `offsetBottom`, `zIndex`, `allowInFrame`) and [Popups and banners](https://sonor.dev/site-kit/popups).

## What It Composes

**Server-side (RSC):**

- `ManagedFavicon` — Sonor logo as `<link>` tags
- `ManagedScripts` — tracking pixels/analytics tags in `<head>` and body-end positions
- API preconnect/dns-prefetch hints

**Client-side (lazy-loaded island):**

- `AnalyticsProvider` — page views, scroll depth, heatmap clicks, Web Vitals
- `SitePopups` — popups, banners and toasts
- `SiteChat` — website chat (Echo)
- `SignalBridge` — A/B experiments, behavior tracking (opt-in)
- `SitemapSync` — parses `/sitemap.xml` and syncs to Sonor (opt-in)
- `FleetHeartbeat` — reports the kit version and enabled modules once per session

Since 4.0.0 none of these wrap your page. `{children}` renders first and every module mounts after it as a childless sibling, so `SiteKitLayout` never pushes a route to client rendering. Analytics, chat, popups, SitemapSync and the heartbeat also wait for window load + idle (or the first interaction) unless you pass `defer={false}`. `SignalBridge` isn't deferred, so experiment variants apply early. Visitor and session IDs come from a shared storage singleton rather than a provider.

## Note

`SiteKitProvider` was **removed in 4.0.0**. It wrapped the whole tree client-side, which broke RSC. Migrate an older layout with `npx sonor-setup codemod --only provider-to-layout --write`.
