# @sonordev/site-kit

All-in-one integration kit for [Sonor](https://sonor.io)-powered Next.js sites. One package, one env var, every module: SEO, Analytics, Forms, Articles, Commerce, Website chat, Popups, GEO/AEO, Booking, Reputation, A/B Testing, and more — all managed from the Sonor dashboard at [app.sonor.io](https://app.sonor.io).

## Install

```bash
npm install @sonordev/site-kit
```

## What's new in 7.0

- **Agents can use the site.** `npx sonor-setup mcp` serves the built-in
  Sonor tools over MCP (business profile, services, FAQ, pages, articles,
  reviews, and inquiries when you turn them on), and Sonor's AI Visibility
  tab shows which agents called them. See [src/mcp/README.md](https://sonor.dev/site-kit/mcp).
- **Organised the way Sonor's dashboard is**: one entry per module
  (`./website/*`, `./seo/*`, `./chat`), a types-only root entry, and the
  setup CLI in its own package, [`sonor-setup`](https://sonor.dev/cli).
- **ESM only, Next 16 only, 0.6 MB** (from 4 MB), with no react-markdown in
  your install and support for Cache Components.

Move a site when you next touch it: `npx sonor-setup codemod --write`, then
build. See [docs/MIGRATING-TO-7.md](https://sonor.dev/site-kit/migrating-to-7).

## Setup

**One environment variable:**

```bash
# .env.local
SONOR_API_KEY=sonor_xxxxxxxx_xxxxx
```

Copy the key from [app.sonor.io](https://app.sonor.io): **Projects → your project → Settings → API Keys**. Keys start with `sonor_`. Keep it server-side, with no `NEXT_PUBLIC_` prefix.

**One layout component:**

```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>
  )
}
```

`SiteKitLayout` is an RSC-compatible async Server Component that auto-composes: analytics tracking, website chat, popups, favicons, and managed scripts. No client-side provider wrapping needed: client modules mount as deferred siblings after `{children}`, so the page stays server-rendered. Props and module options: [src/layout/README.md](https://sonor.dev/site-kit/layout).

**Proxy (optional but recommended):**

```ts
// proxy.ts
import { createProxy } from '@sonordev/site-kit/proxy'

export default createProxy()

// Inlined on purpose: Next statically parses `config.matcher` at build time
// and rejects an imported value. `siteKitMatcher` is a reference value to
// copy from, never a binding to export.
export const config = {
  matcher: [
    '/((?!_next/static|_next/image|favicon\\.ico|.*\\.(?:ico|png|jpg|jpeg|gif|webp|svg|woff2?)$).*)',
  ],
}
```

Handles Sonor-managed redirects, security headers, and AI discovery headers.

**CLI (optional — scaffolds everything):**

```bash
npx sonor-setup init
npx sonor-setup scaffold   # sitemap, robots, llms.txt, middleware, manifest
npx sonor-setup status     # health check
```

***

## Modules

Every module has its own README in `src/<module>/README.md` with full API docs, types, and examples.

### Core (every site)

| Module        | Import                             | Purpose                                                                         | Docs                                           |
| ------------- | ---------------------------------- | ------------------------------------------------------------------------------- | ---------------------------------------------- |
| **Layout**    | `@sonordev/site-kit/layout`        | RSC layout that composes all features                                           | [README](https://sonor.dev/site-kit/layout)    |
| **SEO**       | `@sonordev/site-kit/seo`           | Managed metadata, schemas, FAQs, internal links                                 | [README](https://sonor.dev/site-kit/seo)       |
| **Analytics** | `@sonordev/site-kit/analytics`     | Page views, events, conversions, Web Vitals                                     | [README](https://sonor.dev/site-kit/analytics) |
| **Sitemap**   | `@sonordev/site-kit/seo/sitemap`   | Auto-generated sitemap with Sonor sync. URLs follow next.config `trailingSlash` | [README](https://sonor.dev/site-kit/sitemap)   |
| **Proxy**     | `@sonordev/site-kit/proxy`         | Redirects, security headers, AI discovery (`./middleware` is its 7.x alias)     | [README](https://sonor.dev/site-kit/proxy)     |
| **Redirects** | `@sonordev/site-kit/seo/redirects` | Sonor-managed 301/302 redirect rules                                            | [README](https://sonor.dev/site-kit/redirects) |

### Content

| Module         | Import                              | Purpose                                                  | Docs                                            |
| -------------- | ----------------------------------- | -------------------------------------------------------- | ----------------------------------------------- |
| **Articles**   | `@sonordev/site-kit/articles`       | Sonor-managed articles with SSG, topic clusters, E-E-A-T | [README](https://sonor.dev/site-kit/articles)   |
| **Images**     | `@sonordev/site-kit/website/images` | Managed image slots with dev-mode editing                | [README](https://sonor.dev/site-kit/images)     |
| **Reputation** | `@sonordev/site-kit/reputation`     | Reviews, testimonials, rating stats                      | [README](https://sonor.dev/site-kit/reputation) |

### Engagement

| Module               | Import                              | Purpose                                                                         | Docs                                        |
| -------------------- | ----------------------------------- | ------------------------------------------------------------------------------- | ------------------------------------------- |
| **Website chat**     | `@sonordev/site-kit/chat`           | The chat launcher and Echo (Sonor → Messages)                                   | [README](https://sonor.dev/site-kit/chat)   |
| **Popups & Banners** | `@sonordev/site-kit/website/popups` | Popups, banners and toasts from Sonor → Website, drawn in the site's own design | [README](https://sonor.dev/site-kit/popups) |
| **Forms**            | `@sonordev/site-kit/forms`          | Managed forms with CRM routing, multi-step, validation                          | [README](https://sonor.dev/site-kit/forms)  |
| **Signal**           | `@sonordev/site-kit/signal`         | A/B experiments, behavior tracking, real-time config                            | [README](https://sonor.dev/site-kit/signal) |

### Commerce

| Module       | Import                        | Purpose                                   | Docs                                          |
| ------------ | ----------------------------- | ----------------------------------------- | --------------------------------------------- |
| **Commerce** | `@sonordev/site-kit/commerce` | Products, services, events, checkout      | [README](https://sonor.dev/site-kit/commerce) |
| **Sync**     | `@sonordev/site-kit/sync`     | Booking/scheduling widget (Calendly-like) | [README](https://sonor.dev/site-kit/booking)  |

### GEO / AEO (AI Visibility)

| Module              | Import                                 | Purpose                                                                          | Docs                                      |
| ------------------- | -------------------------------------- | -------------------------------------------------------------------------------- | ----------------------------------------- |
| **LLMs**            | `@sonordev/site-kit/seo/llms`          | llms.txt, AEO components, Speakable schema                                       | [README](https://sonor.dev/site-kit/llms) |
| **LLMs Contract**   | `@sonordev/site-kit/seo/llms/contract` | Shared types/sanitizers (the APIs use `@sonordev/contracts/llms`, the same code) | README                                    |
| **MCP**             | `@sonordev/site-kit/mcp`               | MCP endpoint, server card, in-page WebMCP tools                                  | [README](https://sonor.dev/site-kit/mcp)  |
| **Sonor MCP tools** | `@sonordev/site-kit/mcp/sonor`         | The built-in tools (`sonorMcpServer`) and tool-call reporting to Sonor           | [README](https://sonor.dev/site-kit/mcp)  |

### Motion

Three tiers as three subpaths — a site only installs and ships what it imports. Server HTML always stays visible; above-the-fold content is never animated in.

| Module             | Import                            | Purpose                                                                            | Docs                                        |
| ------------------ | --------------------------------- | ---------------------------------------------------------------------------------- | ------------------------------------------- |
| **Motion**         | `@sonordev/site-kit/motion`       | `<Reveal>`, `<Parallax>`, `<ScrollScene>` and the scroll engine — zero deps, \~2KB | [README](https://sonor.dev/site-kit/motion) |
| **Motion / GSAP**  | `@sonordev/site-kit/motion/gsap`  | Lazy-loaded GSAP timelines (`useGsap`) — optional peer `gsap`                      | [README](https://sonor.dev/site-kit/motion) |
| **Motion / three** | `@sonordev/site-kit/motion/three` | WebGL stages on the engine (`useThreeStage`) — optional peer `three`               | [README](https://sonor.dev/site-kit/motion) |

### Liquid Glass chrome

| Module      | Import                               | Purpose                                                                                                                                                                                   | Docs                                         |
| ----------- | ------------------------------------ | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | -------------------------------------------- |
| **CTA bar** | `@sonordev/site-kit/website/cta-bar` | `<CtaBar>` + `<CtaBarAction>`: the floating glass mobile CTA bar. Hides over its form and while typing, compacts on scroll, lifts the Echo launcher, emits `cta_click`. Server component. | [README](https://sonor.dev/site-kit/cta-bar) |

Echo's launcher and chat window use the same glass recipe; see [Website chat](https://sonor.dev/site-kit/chat#liquid-glass-610).

***

## How It Works

```
SONOR_API_KEY in .env.local
       │
       ▼
SiteKitLayout (RSC server component)
├── Server-side:
│   ├── ManagedFavicon         (Sonor logo → <link> tags)
│   ├── ManagedScripts         (tracking pixels, analytics tags)
│   └── API preconnect hints
│
├── Client-side (childless siblings after {children}, deferred to idle):
│   ├── AnalyticsProvider      (page views, scroll depth, Web Vitals)
│   ├── SitePopups             (popups, banners, toasts)
│   ├── SiteChat               (website chat: Echo)
│   ├── SignalBridge           (A/B experiments, opt-in, not deferred)
│   ├── SitemapSync            (browser sitemap fallback, opt-in)
│   └── FleetHeartbeat         (kit version + modules, once per session)
│
└── Middleware (separate):
    ├── Redirects              (Sonor-managed 301/302)
    ├── Security headers       (CSP frame-ancestors, nosniff, etc.)
    └── AI discovery           (Link: rel="describedby" → /llms.txt)
```

All data flows through the Sonor API (`api.sonor.io`) authenticated by your API key. No direct database access, no Supabase keys exposed to the client.

***

## Import Paths

```ts
// Core
import { SiteKitLayout } from '@sonordev/site-kit/layout'
import { createProxy, siteKitMatcher } from '@sonordev/site-kit/proxy'   // in proxy.ts

// SEO
import { getManagedMetadata, ManagedSchema, ManagedFAQ } from '@sonordev/site-kit/seo'

// Analytics
import { AnalyticsProvider, useAnalytics, WebVitals } from '@sonordev/site-kit/analytics'

// Forms
import { ManagedForm, useForm, formsApi, field } from '@sonordev/site-kit/forms'

// Articles (server components — keeps server-only data helpers out of client bundles)
import { Article, ArticleList, ClusterLandingPage } from '@sonordev/site-kit/articles/server-ui'
import { getArticle, generateArticleStaticParams } from '@sonordev/site-kit/articles/server'

// Commerce
import { OfferingCard, ProductPage, EventCalendar } from '@sonordev/site-kit/commerce'

// Booking
import { BookingWidget } from '@sonordev/site-kit/sync'

// Website chat, and popups (SiteKitLayout mounts both; its `chat` and `popups` props turn them off)
import { SiteChat, ChatWidget } from '@sonordev/site-kit/chat'
import { SitePopups, PopupBlocks } from '@sonordev/site-kit/website/popups'

// Signal (A/B)
import { SignalBridge, SignalExperiment, useSignal } from '@sonordev/site-kit/signal'

// GEO / AEO
import { createLLMsTxtHandler, buildAiDiscoveryHeaders } from '@sonordev/site-kit/seo/llms'
import { AEOBlock, AEOSummary, AEOSteps, SpeakableSchema } from '@sonordev/site-kit/seo/llms'

// Agent tools (MCP): see src/mcp/README.md, or run `npx sonor-setup mcp`
import { createMcpHandler, createMcpServerCardHandler } from '@sonordev/site-kit/mcp'
import { sonorMcpServer, reportToolCallsToSonor } from '@sonordev/site-kit/mcp/sonor'
import { WebMcpTools } from '@sonordev/site-kit/mcp/client'

// Sitemap
import { createSitemap } from '@sonordev/site-kit/seo/sitemap'

// Images
import { ManagedImage } from '@sonordev/site-kit/website/images'

// Reputation
import { TestimonialSection, fetchReviews } from '@sonordev/site-kit/reputation'

// Redirects
import { handleManagedRedirects } from '@sonordev/site-kit/seo/redirects'

// Robots (the AI crawler helpers live in /llms; /robots re-exports them)
import { createRobots, buildAiCrawlerRules, createRobotsTxtHandler } from '@sonordev/site-kit/seo/robots'

// Motion (tier 0, zero deps) — tiers 1/2 need `npm i gsap` / `npm i three`
import { Reveal, Parallax, ScrollScene, registerScene } from '@sonordev/site-kit/motion'
import { useGsap } from '@sonordev/site-kit/motion/gsap'
import { useThreeStage, canRunWebGL } from '@sonordev/site-kit/motion/three'

// Liquid Glass mobile CTA bar (server component; pass Next Link via `as`)
import { CtaBar, CtaBarAction } from '@sonordev/site-kit/website/cta-bar'

// Styles (optional)
import '@sonordev/site-kit/brand.css'
import '@sonordev/site-kit/forms/styles.css'
```

***

## Environment Variables

```bash
# Required (server-only — SiteKitLayout injects into client automatically):
SONOR_API_KEY=sonor_xxxxxxxx_xxxxx

# Optional:
SONOR_API_URL=https://api.sonor.io              # Sonor API (default)
NEXT_PUBLIC_SITE_URL=https://example.com         # For CLI status checks + sitemap
REVALIDATION_SECRET=your_secret                  # On-demand ISR for llms.txt
MCP_TRANSPORT_SECRET=...                         # Netlify MCP relay (npx sonor-setup mcp writes it)
```

Uptrade-era variables (`UPTRADE_API_KEY`, `NEXT_PUBLIC_UPTRADE_API_KEY`) aren't read, and `uptrade_` keys aren't accepted. A site that only sets those runs with no key. Move it to `SONOR_API_KEY` with `npx sonor-setup codemod --only uptrade-to-sonor --write`.

***

## CLI

The setup CLI is its own package since 7.0, [`sonor-setup`](https://sonor.dev/cli).
`npx` fetches it; a site that runs it from package.json scripts adds it as a
dev dependency. (`sonor-register-sitemap`, the postbuild step, stays here.)

```bash
npx sonor-setup <command>

Commands:
  init           Initialize site-kit in a Next.js project
  scaffold       Scaffold sitemap, robots, llms.txt, proxy, manifest
  mcp            Give agents the site's tools (MCP endpoint, server card, relay)
  setup          AI-powered SEO setup (metadata, schemas, FAQs)
  scan           Scan codebase for integration opportunities
  migrate        Migrate detected components to site-kit
  sync           Sync local content to Sonor
  status         Health check (API, llms.txt, sitemap, layout)
  geo            Check GEO/llms.txt wiring
  images         Scan, upload, and manage images
  locations      Generate location pages
  faqs           Sync ManagedFAQ paths
  api-routes     Generate API proxy routes
  install        Install @sonordev/site-kit
  upgrade        Upgrade to latest version
  codemod        Move an older site to the current site-kit (--check, --write)
  next16         Move middleware.ts to proxy.ts
  verify         Exit 0 when the integration is done
```

***

## TypeScript

Fully typed. All types are exported from their respective module paths:

```ts
import type { LLMsDataResponse, GenerateLLMSTxtOptions } from '@sonordev/site-kit/seo/llms'
import type { ManagedFormConfig, UseFormReturn } from '@sonordev/site-kit/forms'
import type { Article, TopicCluster } from '@sonordev/site-kit/articles'
import type { CommerceOffering, SizeChart } from '@sonordev/site-kit/commerce'
import type { SiteKitLayoutProps } from '@sonordev/site-kit/layout'
```

***

## Architecture Note

`@sonordev/site-kit` is the client bridge between Next.js marketing sites and the Sonor platform. All persistent data (forms, articles, SEO config, analytics) lives in Sonor — site-kit fetches, renders, and tracks.

- **Server components** (SEO, Articles, Images): Import directly, RSC-compatible, no provider needed
- **Client modules** (Analytics, chat, popups, Signal): Lazy-loaded via `SiteKitLayout`, tree-shaken
- **Build-time** (Sitemap, llms.txt): Run during `next build`, sync to Sonor
- **Middleware** (Redirects, Security, AI Discovery): Runs on every request edge

Full docs for every module: [sonor.dev](https://sonor.dev).
