@sonordev/site-kit 7.0.1 → 7.1.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.
Files changed (147) hide show
  1. package/CHANGELOG.md +3606 -0
  2. package/README.md +12 -13
  3. package/agent-manifest.json +11 -5
  4. package/dist/{AnalyticsProvider-EMM2TKRE.js → AnalyticsProvider-ZMQUV33M.js} +4 -4
  5. package/dist/{ArticleViewTracker-RA64BGL6.js → ArticleViewTracker-V7NUXYBY.js} +3 -3
  6. package/dist/{BlocksPopup-D25RFNOV.js → BlocksPopup-52EU7OUY.js} +4 -4
  7. package/dist/{ChatWidget-RYI7BMJJ.js → ChatWidget-5BHMNR57.js} +5 -5
  8. package/dist/{EngageWidget-UKFCN33M.js → EngageWidget-PCGLX7SO.js} +4 -4
  9. package/dist/{FileField-MUHA7LZR.js → FileField-TSFGNAMY.js} +3 -3
  10. package/dist/{FormSpotlight-TCLPWPLL.js → FormSpotlight-XLBWEOTE.js} +1 -1
  11. package/dist/{FormStage-CNYLP6I6.js → FormStage-IJQ5Q2X6.js} +1 -1
  12. package/dist/{ManagedForm-7ZL5SKTO.js → ManagedForm-Z3PKOPIZ.js} +6 -6
  13. package/dist/{ManagedNewsletterForm-33B4JLX7.js → ManagedNewsletterForm-QAO3POLC.js} +4 -4
  14. package/dist/{SignalCore-L5FVDHFE.js → SignalCore-RBA3VDBL.js} +3 -3
  15. package/dist/{SiteDesignReporter-4JOFL4FP.js → SiteDesignReporter-C4LR5X2V.js} +5 -5
  16. package/dist/SitemapSync-XVMGKCF3.js +8 -0
  17. package/dist/_client/booking-widget.js +5 -5
  18. package/dist/affiliates/index.js +3 -3
  19. package/dist/analytics/index.js +4 -4
  20. package/dist/articles/index.js +1 -1
  21. package/dist/articles/server-ui.js +1 -1
  22. package/dist/chat/index.js +5 -5
  23. package/dist/{chunk-FYBZ5SNP.js → chunk-3G2SE2J4.js} +1 -1
  24. package/dist/{chunk-HGCK465A.js → chunk-3J2ERO3I.js} +1 -1
  25. package/dist/{chunk-KXPBMCFL.js → chunk-3QI26673.js} +3 -1
  26. package/dist/{chunk-BMO3VGMR.js → chunk-3XPJKZ6D.js} +30 -7
  27. package/dist/{chunk-QGHSMJKW.js → chunk-4JQQDCMO.js} +1 -1
  28. package/dist/{chunk-6HDT4G4A.js → chunk-4YTYGG2C.js} +2 -2
  29. package/dist/{chunk-N2UVOR3X.js → chunk-662ILEZ6.js} +2 -0
  30. package/dist/chunk-6G43IRWR.js +4 -0
  31. package/dist/{chunk-LVESVYCE.js → chunk-7MHHWZKC.js} +11 -117
  32. package/dist/{chunk-MV2MBTC3.js → chunk-7QTMMHUO.js} +1 -1
  33. package/dist/{chunk-KPAZG65P.js → chunk-CGWUXUYZ.js} +138 -46
  34. package/dist/{chunk-4IQ52CXL.js → chunk-DUAO4Q75.js} +2 -2
  35. package/dist/{chunk-4RMVXRBO.js → chunk-EIULXXUJ.js} +3 -3
  36. package/dist/{chunk-3KUUH2YP.js → chunk-EVFZ7KEW.js} +1 -1
  37. package/dist/{chunk-OFOAHPUV.js → chunk-F42R35NV.js} +1 -1
  38. package/dist/{chunk-QANVUXKH.js → chunk-FLR3EMK6.js} +1 -1
  39. package/dist/{chunk-P4GRY6QP.js → chunk-GIAOPEN6.js} +1 -1
  40. package/dist/{chunk-P5J7VMQ3.js → chunk-GWUKQ26F.js} +1 -1
  41. package/dist/{chunk-TT63HHIT.js → chunk-HAG4YIZY.js} +1 -1
  42. package/dist/{chunk-QZZIKMAT.js → chunk-HVH37YPX.js} +1 -1
  43. package/dist/{chunk-SSUQKA7L.js → chunk-J4D6ZXRW.js} +1 -1
  44. package/dist/{chunk-GYESATRY.js → chunk-L2DJD5Y4.js} +1 -1
  45. package/dist/{chunk-WATH55UY.js → chunk-LFXVE32I.js} +1 -1
  46. package/dist/chunk-LPH5FANE.js +169 -0
  47. package/dist/{chunk-V6LSQRTH.js → chunk-PLUP2KN5.js} +1 -1
  48. package/dist/chunk-RYVDGXC2.js +19 -0
  49. package/dist/{chunk-EGOD74PP.js → chunk-U35H2JIQ.js} +2 -2
  50. package/dist/chunk-VCJYLYJV.js +49 -0
  51. package/dist/{chunk-FL4EPUWA.js → chunk-W2CL2DB3.js} +2 -2
  52. package/dist/{chunk-UZN4ZYR2.js → chunk-XD3ZQET6.js} +1 -1
  53. package/dist/{chunk-CVTVNC2U.js → chunk-XNVSCQ2O.js} +2 -2
  54. package/dist/{chunk-T3MC4HOD.js → chunk-YLSEB32F.js} +1 -1
  55. package/dist/chunk-ZETJTCMV.js +118 -0
  56. package/dist/{chunk-5SEM2V4A.js → chunk-ZIMFQWGJ.js} +3 -3
  57. package/dist/client/index.js +3 -3
  58. package/dist/cms/CmsPage.d.ts +1 -0
  59. package/dist/cms/CmsPreview.d.ts +1 -0
  60. package/dist/cms/CmsSection.d.ts +1 -0
  61. package/dist/cms/index.d.ts +6 -0
  62. package/dist/cms/server-api.d.ts +3 -0
  63. package/dist/commerce/index.js +4 -4
  64. package/dist/config/index.js +1 -1
  65. package/dist/contracts/entries.d.ts +1 -1
  66. package/dist/contracts/site-cache.d.ts +55 -0
  67. package/dist/contracts/site-edit-param.d.ts +7 -0
  68. package/dist/contracts/site-edit.d.ts +77 -0
  69. package/dist/contracts/slot-content.d.ts +111 -0
  70. package/dist/contracts/slots.d.ts +39 -25
  71. package/dist/engage/index.js +6 -6
  72. package/dist/fleet/index.js +4 -4
  73. package/dist/forms/index.js +8 -8
  74. package/dist/forms/server.js +2 -2
  75. package/dist/forms/types.d.ts +3 -1
  76. package/dist/images/index.js +4 -4
  77. package/dist/index.js +1 -1
  78. package/dist/layout/client.js +8 -7
  79. package/dist/layout/index.js +9 -8
  80. package/dist/llms/index.js +4 -2
  81. package/dist/llms/seo-revalidate.d.ts +8 -1
  82. package/dist/maps/index.js +3 -3
  83. package/dist/mcp/sonor.js +6 -6
  84. package/dist/overlay-RXV6U6QC.js +353 -0
  85. package/dist/proxy/index.js +2 -2
  86. package/dist/proxy/securityHeaders.d.ts +4 -0
  87. package/dist/revalidate/index.d.ts +44 -0
  88. package/dist/revalidate/index.js +27 -0
  89. package/dist/seo/ManagedContent.d.ts +2 -0
  90. package/dist/seo/client.js +4 -4
  91. package/dist/seo/index.js +9 -8
  92. package/dist/seo/llms.js +4 -2
  93. package/dist/seo/register-sitemap-cli.js +1 -1
  94. package/dist/seo/server.js +3 -2
  95. package/dist/seo/sitemap.js +2 -2
  96. package/dist/server/index.js +2 -2
  97. package/dist/{server-api-GJJQZVG7.js → server-api-BVCBLJKL.js} +2 -1
  98. package/dist/shared/build-entries.d.ts +1 -0
  99. package/dist/shared/edit-bridge.d.ts +8 -0
  100. package/dist/shared/version.d.ts +1 -1
  101. package/dist/signal/index.js +2 -2
  102. package/dist/sitemap/index.js +2 -2
  103. package/dist/slots/ManagedLink.d.ts +31 -0
  104. package/dist/slots/ManagedList.d.ts +30 -0
  105. package/dist/slots/ManagedRichText.d.ts +31 -0
  106. package/dist/slots/contract.js +2 -1
  107. package/dist/slots/edit/locate.d.ts +30 -0
  108. package/dist/slots/edit/overlay.d.ts +18 -0
  109. package/dist/slots/index.d.ts +12 -4
  110. package/dist/slots/index.js +4 -2
  111. package/dist/slots/revalidate.d.ts +8 -3
  112. package/dist/slots/rich.d.ts +7 -0
  113. package/dist/slots/server-api.d.ts +6 -2
  114. package/dist/sync/index.js +5 -5
  115. package/dist/website/images.js +4 -4
  116. package/dist/website/index.js +5 -5
  117. package/dist/website/popups.js +4 -4
  118. package/dist/website/slots/contract.js +2 -1
  119. package/dist/website/slots.js +4 -2
  120. package/dist/{writeLLMsTxt-UMHKGNRR.js → writeLLMsTxt-QR23OQUE.js} +1 -1
  121. package/docs/MIGRATING-TO-7.md +146 -0
  122. package/docs.json +69 -0
  123. package/package.json +14 -4
  124. package/src/admin-auth/README.md +88 -0
  125. package/src/analytics/README.md +264 -0
  126. package/src/articles/README.md +325 -0
  127. package/src/commerce/README.md +109 -0
  128. package/src/cta-bar/README.md +154 -0
  129. package/src/engage/README.md +241 -0
  130. package/src/forms/README.md +219 -0
  131. package/src/images/README.md +74 -0
  132. package/src/layout/README.md +66 -0
  133. package/src/llms/README.md +723 -0
  134. package/src/mcp/README.md +376 -0
  135. package/src/motion/README.md +372 -0
  136. package/src/og/README.md +304 -0
  137. package/src/proxy/README.md +152 -0
  138. package/src/redirects/README.md +74 -0
  139. package/src/reputation/README.md +64 -0
  140. package/src/revalidate/README.md +82 -0
  141. package/src/seo/README.md +346 -0
  142. package/src/signal/README.md +115 -0
  143. package/src/sitemap/README.md +127 -0
  144. package/src/slots/README.md +168 -0
  145. package/src/sync/README.md +115 -0
  146. package/dist/SitemapSync-7WKY4HXI.js +0 -8
  147. package/dist/chunk-SS636UDN.js +0 -35
@@ -0,0 +1,30 @@
1
+ import * as React from 'react';
2
+ import { type SlotListItem } from './contract';
3
+ import type { SlotResolveOptions } from './server-api';
4
+ export interface ManagedListProps extends Omit<SlotResolveOptions, 'fallback' | 'type' | 'fallbackValue'> {
5
+ /** Stable slot id, e.g. "home-services" or "gallery". */
6
+ id: string;
7
+ /** The static items: `{ title?, body?, href?, image?: { src, alt, width?, height? } }`. */
8
+ items: SlotListItem[];
9
+ /** Draw the items. Called with the managed items, or `items` when nothing's managed. */
10
+ children: (items: SlotListItem[]) => React.ReactNode;
11
+ }
12
+ /**
13
+ * ManagedList — a list the owner edits in Sonor: services, team, FAQs, a
14
+ * gallery. You keep the markup; Sonor manages the items. Each item has an
15
+ * optional title, plain-text body, link and image (https only).
16
+ *
17
+ * Server component, fallback-first and signature-verified like ManagedSlot.
18
+ *
19
+ * @example
20
+ * ```tsx
21
+ * <ManagedList id="home-services" items={SERVICES}>
22
+ * {(items) => (
23
+ * <ul className="grid">
24
+ * {items.map((s) => <li key={s.title}><a href={s.href}>{s.title}</a><p>{s.body}</p></li>)}
25
+ * </ul>
26
+ * )}
27
+ * </ManagedList>
28
+ * ```
29
+ */
30
+ export declare function ManagedList({ id, items, children, site, revalidate, page, }: ManagedListProps): Promise<React.ReactElement>;
@@ -0,0 +1,31 @@
1
+ import * as React from 'react';
2
+ import type { SlotResolveOptions } from './server-api';
3
+ export interface ManagedRichTextProps extends Omit<SlotResolveOptions, 'fallback' | 'type' | 'fallbackValue'> {
4
+ /** Stable slot id, lowercase, page-scoped by convention (e.g. "about-intro"). */
5
+ id: string;
6
+ /**
7
+ * The static content. A string is read as the rich-text subset (so the
8
+ * fallback and the managed copy render the same way); JSX renders as is.
9
+ */
10
+ children: React.ReactNode;
11
+ }
12
+ /**
13
+ * ManagedRichText — a Sonor-managed block of formatted copy: paragraphs,
14
+ * line breaks, bold, italic, links and lists. Renders a fragment of `<p>`,
15
+ * `<ul>`/`<ol>`, `<strong>`, `<em>`, `<a>` and `<br>`; wrap it in your own
16
+ * element for styling.
17
+ *
18
+ * Server component, fallback-first and signature-verified like ManagedSlot.
19
+ * Managed content is parsed by the contract's rich-text parser and rendered
20
+ * as elements, never as HTML.
21
+ *
22
+ * @example
23
+ * ```tsx
24
+ * <div className="prose">
25
+ * <ManagedRichText id="about-intro" page="/about">
26
+ * {`We've built homes in **Cincinnati** since 1998.\n\n- Custom builds\n- Remodels`}
27
+ * </ManagedRichText>
28
+ * </div>
29
+ * ```
30
+ */
31
+ export declare function ManagedRichText({ id, children, site, revalidate, page, }: ManagedRichTextProps): Promise<React.ReactElement>;
@@ -1,2 +1,3 @@
1
- export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-SS636UDN.js';
1
+ export { SLOTS_CONTRACT_VERSION, SUPPORTED_SLOTS_CONTRACT_VERSIONS, canonicalJson, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-VCJYLYJV.js';
2
+ export { SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_FIELD_MAX_LENGTH, SLOT_HREF_MAX_LENGTH, SLOT_ID_PATTERN, SLOT_LIST_MAX_ITEMS, SLOT_V1_CONTENT_TYPES, isSafeSlotHref, isSafeSlotImageSrc, isSlotContentType, isValidSlotId, normalizeSlotValue, parseSlotRichText, slotListPlainText } from '../chunk-LPH5FANE.js';
2
3
  import '../chunk-PKBMQBKP.js';
@@ -0,0 +1,30 @@
1
+ /**
2
+ * Find managed copy on a rendered page by what it says.
3
+ *
4
+ * The slot components render plain text: no wrapper element, no attribute,
5
+ * so a site's markup and CSS are exactly what it wrote (a marker element would
6
+ * shift `:first-child`, `h2 + p` and Tailwind's `space-y-*` for every visitor
7
+ * to serve one editor). The edit overlay finds each slot the way a person
8
+ * would, by its visible text, using the needles from `slotNeedles`.
9
+ */
10
+ import { type EditableSlot } from '../../contracts/site-edit';
11
+ export interface LocatedSlot {
12
+ key: string;
13
+ /** The element to outline and click. */
14
+ element: HTMLElement;
15
+ /** For a text slot rendered as one text node: the node, so a preview can swap just it. */
16
+ textNode?: Text;
17
+ }
18
+ /**
19
+ * The deepest unclaimed element whose whole visible text is `needle`: first a
20
+ * single text node, then an element whose text is split across inline tags
21
+ * (`Fast <em>and</em> local`).
22
+ */
23
+ export declare function findByText(root: Element, needle: string, claimed: Set<Element>): {
24
+ element: HTMLElement;
25
+ textNode?: Text;
26
+ } | null;
27
+ /** Locate one slot, or null when its text isn't on this page. */
28
+ export declare function locateSlot(root: Element, slot: EditableSlot, claimed: Set<Element>): LocatedSlot | null;
29
+ /** Locate every slot on the page; each element belongs to at most one slot. */
30
+ export declare function locateSlots(root: Element, slots: EditableSlot[]): LocatedSlot[];
@@ -0,0 +1,18 @@
1
+ /**
2
+ * The edit overlay: what a site shows inside Sonor's "Edit on page".
3
+ *
4
+ * Loaded only when the page is framed cross-origin with `?sonor_edit`
5
+ * (`shared/edit-bridge.ts`), and it only acts for the Sonor dashboard
6
+ * (`isSonorAppOrigin`). It outlines the managed copy it can find, reports a
7
+ * click as a selection, shows a draft in place, and reloads on request. It
8
+ * never writes anything: the dashboard saves with the person's own session.
9
+ *
10
+ * Plain DOM, no React, so it adds nothing to a visitor's bundle; the bridge
11
+ * imports it on demand.
12
+ */
13
+ /** The dashboard's origin, from the browser's own record of who framed us. */
14
+ export declare function framingOrigin(win: Window): string | null;
15
+ /** The same URL with the edit parameter, so the overlay starts again after a navigation. */
16
+ export declare function withEditParam(href: string, base: string): string | null;
17
+ /** Start the overlay. Returns a function that removes every trace of it. */
18
+ export declare function startEditOverlay(win?: Window): () => void;
@@ -1,14 +1,22 @@
1
1
  /**
2
- * @sonordev/site-kit/slots — Managed Slots (3.0 spine, Pillar 1)
2
+ * @sonordev/site-kit/website/slots — Managed Slots (3.0 spine, Pillar 1)
3
3
  *
4
- * Named, Sonor-managed text regions inside developer-owned markup.
4
+ * Named, Sonor-managed copy inside developer-owned markup: text, rich text,
5
+ * links and lists (the Website CMS; docs/WEBSITE-CMS.md).
5
6
  * Static-safe, fallback-first, signature-verified.
6
7
  * See docs/SITE-KIT-3.0-SPEC-SLOTS.md.
7
8
  */
8
9
  export { ManagedSlot, default } from './ManagedSlot';
9
10
  export type { ManagedSlotProps } from './ManagedSlot';
11
+ export { ManagedRichText } from './ManagedRichText';
12
+ export type { ManagedRichTextProps } from './ManagedRichText';
13
+ export { ManagedLink } from './ManagedLink';
14
+ export type { ManagedLinkProps } from './ManagedLink';
15
+ export { ManagedList } from './ManagedList';
16
+ export type { ManagedListProps } from './ManagedList';
17
+ export { renderSlotRichText } from './rich';
10
18
  export { getSlot, resolveSlots } from './server-api';
11
19
  export type { SlotResolveOptions } from './server-api';
12
20
  export { createSlotsRevalidateHandler, SLOTS_CACHE_TAG } from './revalidate';
13
- export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, slotSigningPayload, signSlotContent, verifySlotContent, } from './contract';
14
- export type { SlotContent, SlotContentType, SlotsResolveRequest, SlotsResolveResponse, } from './contract';
21
+ export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, SLOT_LIST_MAX_ITEMS, isSafeSlotHref, isValidSlotId, normalizeSlotValue, parseSlotRichText, slotSigningPayload, signSlotContent, verifySlotContent, } from './contract';
22
+ export type { SlotContent, SlotContentType, SlotLinkValue, SlotListImage, SlotListItem, SlotListValue, SlotRichBlock, SlotRichInline, SlotValue, SlotsResolveRequest, SlotsResolveResponse, } from './contract';
@@ -1,5 +1,7 @@
1
- export { ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, resolveSlots } from '../chunk-KPAZG65P.js';
2
- export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-SS636UDN.js';
1
+ export { ManagedLink, ManagedList, ManagedRichText, ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, renderSlotRichText, resolveSlots } from '../chunk-CGWUXUYZ.js';
2
+ export { SLOTS_CONTRACT_VERSION, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-VCJYLYJV.js';
3
+ export { SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, SLOT_LIST_MAX_ITEMS, isSafeSlotHref, isValidSlotId, normalizeSlotValue, parseSlotRichText } from '../chunk-LPH5FANE.js';
4
+ import '../chunk-RYVDGXC2.js';
3
5
  import '../chunk-X6F6SO4S.js';
4
6
  import '../chunk-MH2DSGC6.js';
5
7
  import '../chunk-PKBMQBKP.js';
@@ -1,20 +1,25 @@
1
1
  /**
2
- * @sonordev/site-kit/slots — On-demand Revalidation
2
+ * @sonordev/site-kit/website/slots — On-demand Revalidation
3
3
  *
4
4
  * Sonor calls this when slot content changes (owner edit or approved Signal
5
5
  * proposal) so the change is live in seconds instead of at the next ISR
6
6
  * window. Mirrors the llms revalidation handler pattern.
7
7
  *
8
+ * Sonor sends slot edits to the site's one revalidation route
9
+ * (`@sonordev/site-kit/revalidate`), which expires this tag too. Use this
10
+ * handler only for a separate slots-only route.
11
+ *
8
12
  * @example
9
13
  * ```ts
10
14
  * // app/api/revalidate-slots/route.ts
11
- * import { createSlotsRevalidateHandler } from '@sonordev/site-kit/slots'
15
+ * import { createSlotsRevalidateHandler } from '@sonordev/site-kit/website/slots'
12
16
  *
13
17
  * export const POST = createSlotsRevalidateHandler(process.env.REVALIDATION_SECRET!)
14
18
  * ```
15
19
  */
16
20
  type RevalidateTagFn = (tag: string) => void;
17
- export declare const SLOTS_CACHE_TAG = "sonor-slots";
21
+ /** The tag every slot fetch carries (SITE_CACHE_TAGS.slots, @sonordev/contracts/site-cache). */
22
+ export declare const SLOTS_CACHE_TAG: "sonor-slots";
18
23
  /**
19
24
  * Create a POST handler that busts the slots data cache.
20
25
  * Protected by a shared secret. (POST handlers are never statically
@@ -0,0 +1,7 @@
1
+ import * as React from 'react';
2
+ /**
3
+ * Render the rich-text subset (see parseSlotRichText in the slots contract)
4
+ * as React elements. There's no HTML path: every node maps to one element,
5
+ * and text is React text, so managed rich content can't inject markup.
6
+ */
7
+ export declare function renderSlotRichText(markdown: string): React.ReactNode;
@@ -1,5 +1,5 @@
1
1
  /**
2
- * @sonordev/site-kit/slots — Server-Only Resolution
2
+ * @sonordev/site-kit/website/slots — Server-Only Resolution
3
3
  *
4
4
  * SECURITY: uses the private SONOR_API_KEY. Import only in server code
5
5
  * (RSC, route handlers, server actions).
@@ -12,7 +12,7 @@
12
12
  * - Signed: unsigned/tampered payloads are dropped with a warning.
13
13
  */
14
14
  import 'server-only';
15
- import { type SlotContent } from './contract';
15
+ import { type SlotContent, type SlotContentType, type SlotValue } from './contract';
16
16
  export interface SlotResolveOptions {
17
17
  /** Multi-site sub-dimension: normalized lowercase host. */
18
18
  site?: string;
@@ -29,6 +29,10 @@ export interface SlotResolveOptions {
29
29
  * the Copy Evidence Loop's slot↔page mapping.
30
30
  */
31
31
  page?: string;
32
+ /** What this slot renders as (default 'text'). The component sets it. */
33
+ type?: SlotContentType;
34
+ /** The structured fallback (link or list), reported so the editor starts from it. */
35
+ fallbackValue?: SlotValue;
32
36
  }
33
37
  /** Resolve one slot. Null on any failure → caller renders fallback. */
34
38
  export declare function getSlot(id: string, options?: SlotResolveOptions): Promise<SlotContent | null>;
@@ -1,6 +1,6 @@
1
- export { BookingWidget } from '../chunk-FYBZ5SNP.js';
2
- export { createBooking, createSlotHold, detectTimezone, fetchAvailability, fetchAvailableDates, fetchBookingTypeDetails, fetchBookingTypes, formatDate, formatDuration, formatTime, prepareMeeting, releaseSlotHold } from '../chunk-MV2MBTC3.js';
3
- import '../chunk-EGOD74PP.js';
4
- import '../chunk-3KUUH2YP.js';
5
- import '../chunk-QGHSMJKW.js';
1
+ export { BookingWidget } from '../chunk-3G2SE2J4.js';
2
+ export { createBooking, createSlotHold, detectTimezone, fetchAvailability, fetchAvailableDates, fetchBookingTypeDetails, fetchBookingTypes, formatDate, formatDuration, formatTime, prepareMeeting, releaseSlotHold } from '../chunk-7QTMMHUO.js';
3
+ import '../chunk-U35H2JIQ.js';
4
+ import '../chunk-EVFZ7KEW.js';
5
+ import '../chunk-4JQQDCMO.js';
6
6
  import '../chunk-PKBMQBKP.js';
@@ -1,6 +1,6 @@
1
- export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage } from '../chunk-P5J7VMQ3.js';
1
+ export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage } from '../chunk-GWUKQ26F.js';
2
2
  export { ManagedFavicon, getManagedFaviconUrl } from '../chunk-GW7GSBO7.js';
3
- import '../chunk-EGOD74PP.js';
4
- import '../chunk-3KUUH2YP.js';
5
- import '../chunk-QGHSMJKW.js';
3
+ import '../chunk-U35H2JIQ.js';
4
+ import '../chunk-EVFZ7KEW.js';
5
+ import '../chunk-4JQQDCMO.js';
6
6
  import '../chunk-PKBMQBKP.js';
@@ -1,13 +1,13 @@
1
1
  'use client';
2
- export { SiteDesignReporter } from '../chunk-P4GRY6QP.js';
3
- export { SITE_DESIGN_PATH, cleanFontStack, colorToHex, getSiteDesignTokens, measureSiteDesign, readDeclaredDesign, sendSiteDesign } from '../chunk-FL4EPUWA.js';
2
+ export { SiteDesignReporter } from '../chunk-GIAOPEN6.js';
3
+ export { SITE_DESIGN_PATH, cleanFontStack, colorToHex, getSiteDesignTokens, measureSiteDesign, readDeclaredDesign, sendSiteDesign } from '../chunk-W2CL2DB3.js';
4
4
  export { DEFAULT_POPUP_TOKENS, PopupBlocks } from '../chunk-JSZN6LDZ.js';
5
5
  import '../chunk-IHG36STL.js';
6
6
  import '../chunk-YC7ELZS3.js';
7
7
  import '../chunk-S22FSH7C.js';
8
8
  import '../chunk-43OCZ3JA.js';
9
9
  import '../chunk-EKBEOXTH.js';
10
- import '../chunk-EGOD74PP.js';
11
- import '../chunk-3KUUH2YP.js';
12
- import '../chunk-QGHSMJKW.js';
10
+ import '../chunk-U35H2JIQ.js';
11
+ import '../chunk-EVFZ7KEW.js';
12
+ import '../chunk-4JQQDCMO.js';
13
13
  import '../chunk-PKBMQBKP.js';
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  export { DEFAULT_POPUP_TOKENS, PopupBlocks } from '../chunk-JSZN6LDZ.js';
3
3
  import '../chunk-IHG36STL.js';
4
- import { EngageWidget } from '../chunk-5SEM2V4A.js';
4
+ import { EngageWidget } from '../chunk-ZIMFQWGJ.js';
5
5
  import '../chunk-NDF4A5JM.js';
6
6
  import '../chunk-6T6CQVNL.js';
7
7
  import '../chunk-S22FSH7C.js';
@@ -9,9 +9,9 @@ import '../chunk-24QZEO3Q.js';
9
9
  import '../chunk-GJWI74ZZ.js';
10
10
  import '../chunk-43OCZ3JA.js';
11
11
  import '../chunk-EKBEOXTH.js';
12
- import '../chunk-EGOD74PP.js';
13
- import '../chunk-3KUUH2YP.js';
14
- import '../chunk-QGHSMJKW.js';
12
+ import '../chunk-U35H2JIQ.js';
13
+ import '../chunk-EVFZ7KEW.js';
14
+ import '../chunk-4JQQDCMO.js';
15
15
  import '../chunk-PKBMQBKP.js';
16
16
  import { jsx } from 'react/jsx-runtime';
17
17
 
@@ -1,2 +1,3 @@
1
- export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from '../../chunk-SS636UDN.js';
1
+ export { SLOTS_CONTRACT_VERSION, SUPPORTED_SLOTS_CONTRACT_VERSIONS, canonicalJson, signSlotContent, slotSigningPayload, verifySlotContent } from '../../chunk-VCJYLYJV.js';
2
+ export { SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_FIELD_MAX_LENGTH, SLOT_HREF_MAX_LENGTH, SLOT_ID_PATTERN, SLOT_LIST_MAX_ITEMS, SLOT_V1_CONTENT_TYPES, isSafeSlotHref, isSafeSlotImageSrc, isSlotContentType, isValidSlotId, normalizeSlotValue, parseSlotRichText, slotListPlainText } from '../../chunk-LPH5FANE.js';
2
3
  import '../../chunk-PKBMQBKP.js';
@@ -1,5 +1,7 @@
1
- export { ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, resolveSlots } from '../chunk-KPAZG65P.js';
2
- export { SLOTS_CONTRACT_VERSION, SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, isValidSlotId, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-SS636UDN.js';
1
+ export { ManagedLink, ManagedList, ManagedRichText, ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, renderSlotRichText, resolveSlots } from '../chunk-CGWUXUYZ.js';
2
+ export { SLOTS_CONTRACT_VERSION, signSlotContent, slotSigningPayload, verifySlotContent } from '../chunk-VCJYLYJV.js';
3
+ export { SLOT_CONTENT_MAX_LENGTH, SLOT_CONTENT_TYPES, SLOT_ID_PATTERN, SLOT_LIST_MAX_ITEMS, isSafeSlotHref, isValidSlotId, normalizeSlotValue, parseSlotRichText } from '../chunk-LPH5FANE.js';
4
+ import '../chunk-RYVDGXC2.js';
3
5
  import '../chunk-X6F6SO4S.js';
4
6
  import '../chunk-MH2DSGC6.js';
5
7
  import '../chunk-PKBMQBKP.js';
@@ -1,4 +1,4 @@
1
- export { writeLLMsTxtToPublic } from './chunk-SSUQKA7L.js';
1
+ export { writeLLMsTxtToPublic } from './chunk-J4D6ZXRW.js';
2
2
  import './chunk-GLHQ3LRO.js';
3
3
  import './chunk-L5UOHS6E.js';
4
4
  import './chunk-WMVK77ND.js';
@@ -0,0 +1,146 @@
1
+ # Moving a site to site-kit 7
2
+
3
+ site-kit 7 is organised the way Sonor's dashboard is: one entry per module.
4
+ Most sites need no changes at all. Move a site when you next touch it
5
+ ("touch a site, update its deps"); nothing forces it before then, because a
6
+ site's `^6` range never picks up 7.
7
+
8
+ ## The short version
9
+
10
+ ```bash
11
+ pnpm add @sonordev/site-kit@^7
12
+ npx sonor-setup codemod --check # lists what needs moving (writes nothing)
13
+ npx sonor-setup codemod --write # moves it
14
+ pnpm build # a bump you didn't build is a guess
15
+ ```
16
+
17
+ Run the codemod in each app or workspace package that imports site-kit (in a
18
+ monorepo, inside each workspace package too). It's
19
+ idempotent: running it twice changes nothing the second time. It works from
20
+ any 2.x-6.x site: copies of sites on 4.2, 5.8 and 6.5 were migrated with it
21
+ and built.
22
+
23
+ Requirements: Next 16 (every fleet site is on it) and Node 20.19+ or 22.12+
24
+ (Netlify's default is 22).
25
+
26
+ ## What changed, and what the codemod does about it
27
+
28
+ ### 1. The root entry is types-only
29
+
30
+ `@sonordev/site-kit` exports types and `SITE_KIT_VERSION`, nothing that runs.
31
+ A stray root import used to be able to pull commerce, signal or redirect code
32
+ into a page's bundle.
33
+
34
+ | Was | Now |
35
+ |---|---|
36
+ | `import { BookingWidget } from '@sonordev/site-kit'` | `@sonordev/site-kit/sync` |
37
+ | `import { AffiliatesWidget, useAffiliates } from '@sonordev/site-kit'` | `@sonordev/site-kit/affiliates` (new entry) |
38
+ | commerce components and fetchers | `@sonordev/site-kit/commerce` |
39
+ | `ManagedImage` and the image helpers | `@sonordev/site-kit/website/images` |
40
+ | `SignalBridge`, experiments, `useSignal*` | `@sonordev/site-kit/signal` |
41
+ | `TestimonialSection`, `fetchReviews` | `@sonordev/site-kit/reputation` |
42
+ | `handleManagedRedirects` and friends | `@sonordev/site-kit/seo/redirects` |
43
+ | `LandingPage`, `landingPageMetadata` | `@sonordev/site-kit/website/landing` |
44
+ | `formatBookingTime`, `formatBookingDate` | `formatTime`, `formatDate` from `@sonordev/site-kit/sync` |
45
+
46
+ **The codemod rewrites these imports**, including the two renamed ones, and
47
+ keeps type imports on the root. It flags, rather than rewrites, a namespace
48
+ import (`import * as SK`), a `require`, or a re-export from the root. The full
49
+ list is `src/shared/module-map.json` (`rootRuntime`).
50
+
51
+ Across our own sites on 2026-09-26 this touched three repos: one for
52
+ `affiliates`, two for `BookingWidget`.
53
+
54
+ ### 2. The setup CLI is its own package: `sonor-setup`
55
+
56
+ The CLI (init, scaffold, codemods, OG cards, GEO wiring, verify) was 3 MB of
57
+ every site's install and forced a site-kit release for every setup-only fix.
58
+ It's now [`sonor-setup`](../packages/sonor-setup).
59
+
60
+ - **`npx sonor-setup …` keeps working unchanged:** npx fetches the package.
61
+ - **A site whose package.json scripts run `sonor-setup`** (wirsch-law's OG
62
+ step, `sonor-setup og`) needs it as a dev dependency. The codemod adds
63
+ `"sonor-setup": "^7.0.0"` for you.
64
+ - **`sonor-register-sitemap` stays in site-kit**, since 11 sites run it from
65
+ their postbuild. Nothing to change.
66
+ - The `site-kit` bin alias for the CLI is gone (no site used it).
67
+
68
+ ### 3. One entry per Sonor module (old paths still work)
69
+
70
+ New homes, each the same module as before:
71
+
72
+ - Website: `./website/{popups,images,slots,cms,landing,cta-bar}`
73
+ - SEO: `./seo/{sitemap,robots,indexnow,redirects,og,og/route,llms,llms/client,llms/contract,meta/contract,pages/contract}`
74
+ - Website chat: `./chat` (out of `./engage`)
75
+
76
+ **The old paths keep working through 7.x** and are removed in 8.0. The
77
+ codemod moves them anyway, so a touched site is done in one pass.
78
+ `SiteKitLayout` gains `chat` and `popups` props; `engage` is an alias
79
+ (`engage={false}` still turns both off).
80
+
81
+ ### 4. ESM only, Next 16 only
82
+
83
+ site-kit ships ES modules alone (`"type": "module"`). Next, Turbopack and the
84
+ kits don't notice. Node 20.19+/22.12+ can `require()` it too, so a
85
+ `next.config.ts` that imports `@sonordev/site-kit/config` keeps working. A
86
+ site-side script that `require()`s site-kit on an older Node would break; none
87
+ in the fleet does.
88
+
89
+ The `next` peer is `^16`. Next 16 renamed `middleware.ts` to `proxy.ts`, and
90
+ **the codemod moves it**: the file, a named `middleware` export (to `proxy`),
91
+ and `createMiddleware` from `@sonordev/site-kit/middleware` (to `createProxy`
92
+ from `/proxy`). The old names work through 7.x. It won't move a file that
93
+ sets `runtime` (a proxy file can't; the build throws), and says so: remove
94
+ the export, check the logic still runs on your host, rerun. It never moves
95
+ onto an existing `proxy.ts`. `npx sonor-setup next16` runs just this part.
96
+
97
+ ### 5. Removed (no site in the fleet used them)
98
+
99
+ - `@sonordev/site-kit/search` and `/search/contract`
100
+ - `@sonordev/site-kit/redirects/not-found` (`resolveManagedRedirect`), and
101
+ with it the `x-sk-path` request header the proxy stamped for it and the
102
+ `SK_PATH_HEADER` export. Managed redirects run in the proxy.
103
+ - The postinstall GEO bootstrap (`SITE_KIT_AUTO_GEO=1`). Run
104
+ `npx sonor-setup geo` instead. site-kit no longer runs anything at install.
105
+ - `@sonordev/site-kit/setup` (an empty stub since 2.0), `LocationPageContent`
106
+ and `getLocationSection` (they sent a `project_id`), `identifyTopicClusters`
107
+ (use `getTopicCluster`), `formatContentSignals`, and the `SiteKitConfig`
108
+ type (not `withSiteKitConfig`, which stays).
109
+ - Source maps. The package no longer ships `.map` files (7.3 of 6.x's 11 MB).
110
+
111
+ Still accepted and ignored until 8.0, because sites pass them:
112
+ `contentSignals` on `createRobotsTxtHandler`, `nativeReturnTo` on forms, and
113
+ `<ManagedScripts />`.
114
+
115
+ ### 6. Behavior worth knowing
116
+
117
+ - **react-markdown is no longer installed with site-kit.** The chat widget
118
+ renders markdown with `marked`, already a dependency. A site that imports
119
+ `react-markdown` itself without listing it (it only worked because npm
120
+ hoisted site-kit's copy) must add it.
121
+ - **`sonor-register-sitemap` reads .env files the way Next does**: a variable
122
+ the host set wins over every file, then `.env.production.local`,
123
+ `.env.local`, `.env.production`, `.env`. It used to let `.env.local` beat
124
+ the host.
125
+
126
+ ## Optional, and new in 7.0
127
+
128
+ - **Cache Components.** `cacheComponents: true` in next.config works with
129
+ site-kit now (it failed every page through 6.x). Remove route segment
130
+ configs (`dynamic`, `revalidate`) when you turn it on; Next rejects them.
131
+ - **Agent tools.** `npx sonor-setup mcp` gives the site an MCP endpoint with
132
+ the built-in Sonor tools (business profile, services, FAQ, pages, articles,
133
+ reviews; inquiries, availability and offerings when you ask), the server
134
+ card, and on Netlify the rate-limited relay. Sonor's AI Visibility tab then
135
+ shows which agents used them. A site that already runs its own MCP server
136
+ (upforge.io and the other hand-written ones) is left exactly as it is:
137
+ nothing in 7.0 turns anything on for it. To have Sonor see its calls, add
138
+ `onToolCall: reportToolCallsToSonor()` to its `createMcpHandler`.
139
+ - **`@sonordev/contracts`** is for the APIs and the dashboard; sites keep
140
+ importing `@sonordev/site-kit/*/contract`, which is the same code.
141
+
142
+ ## Kits built on site-kit
143
+
144
+ agency-site-kit and re-site-kit import only entries 7 keeps unchanged
145
+ (`/client`, `/server`, `/llms`, `/forms`, `/mcp`, `/portfolio/contract`),
146
+ so their `>=` peer ranges already accept 7.
package/docs.json ADDED
@@ -0,0 +1,69 @@
1
+ {
2
+ "$comment": "What sonor.dev renders for this package, in nav order. sonor.dev reads this file from the published tarball (latest on npm), so a release IS the docs deploy: add a page here and ship it in package.json `files`. scripts/verify-docs.cjs fails the publish if a listed file is missing from the pack.",
3
+ "schemaVersion": 1,
4
+ "title": "site-kit",
5
+ "summary": "One package, one env var, every Sonor module on a Next.js site: SEO, analytics, forms, articles, commerce, chat, AI visibility, agent tools and motion.",
6
+ "groups": [
7
+ {
8
+ "title": "Start here",
9
+ "pages": [
10
+ { "slug": "", "title": "Overview", "file": "README.md" },
11
+ { "slug": "migrating-to-7", "title": "Migrating to 7", "file": "docs/MIGRATING-TO-7.md" },
12
+ { "slug": "agents", "title": "For coding agents", "file": "AGENTS.md" }
13
+ ]
14
+ },
15
+ {
16
+ "title": "Core",
17
+ "pages": [
18
+ { "slug": "layout", "title": "Layout", "file": "src/layout/README.md" },
19
+ { "slug": "live-updates", "title": "Live updates", "file": "src/revalidate/README.md" },
20
+ { "slug": "seo", "title": "SEO", "file": "src/seo/README.md" },
21
+ { "slug": "analytics", "title": "Analytics", "file": "src/analytics/README.md" },
22
+ { "slug": "sitemap", "title": "Sitemap", "file": "src/sitemap/README.md" },
23
+ { "slug": "proxy", "title": "Proxy", "file": "src/proxy/README.md" },
24
+ { "slug": "redirects", "title": "Redirects", "file": "src/redirects/README.md" },
25
+ { "slug": "og", "title": "OG cards", "file": "src/og/README.md" }
26
+ ]
27
+ },
28
+ {
29
+ "title": "Content",
30
+ "pages": [
31
+ { "slug": "copy", "title": "Managed copy", "file": "src/slots/README.md" },
32
+ { "slug": "articles", "title": "Articles", "file": "src/articles/README.md" },
33
+ { "slug": "images", "title": "Images", "file": "src/images/README.md" },
34
+ { "slug": "reputation", "title": "Reputation", "file": "src/reputation/README.md" }
35
+ ]
36
+ },
37
+ {
38
+ "title": "Engagement",
39
+ "pages": [
40
+ { "slug": "forms", "title": "Forms", "file": "src/forms/README.md" },
41
+ { "slug": "chat", "title": "Website chat", "file": "src/engage/README.md" },
42
+ { "slug": "cta-bar", "title": "CTA bar", "file": "src/cta-bar/README.md" },
43
+ { "slug": "signal", "title": "Signal (A/B)", "file": "src/signal/README.md" }
44
+ ]
45
+ },
46
+ {
47
+ "title": "Commerce",
48
+ "pages": [
49
+ { "slug": "commerce", "title": "Commerce", "file": "src/commerce/README.md" },
50
+ { "slug": "booking", "title": "Booking", "file": "src/sync/README.md" }
51
+ ]
52
+ },
53
+ {
54
+ "title": "AI visibility",
55
+ "pages": [
56
+ { "slug": "llms", "title": "llms.txt and AEO", "file": "src/llms/README.md" },
57
+ { "slug": "mcp", "title": "MCP and agent tools", "file": "src/mcp/README.md" }
58
+ ]
59
+ },
60
+ {
61
+ "title": "More",
62
+ "pages": [
63
+ { "slug": "motion", "title": "Motion", "file": "src/motion/README.md" },
64
+ { "slug": "admin-auth", "title": "Sign in with Sonor", "file": "src/admin-auth/README.md" }
65
+ ]
66
+ }
67
+ ],
68
+ "changelog": { "file": "CHANGELOG.md", "since": "7.0.0" }
69
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@sonordev/site-kit",
3
- "version": "7.0.1",
3
+ "version": "7.1.0",
4
4
  "type": "module",
5
5
  "packageManager": "pnpm@11.5.3",
6
6
  "description": "Complete client-side integration kit for Sonor - SEO, Analytics, Engage, Forms, Blog",
@@ -155,6 +155,10 @@
155
155
  "types": "./dist/slots/contract.d.ts",
156
156
  "default": "./dist/slots/contract.js"
157
157
  },
158
+ "./revalidate": {
159
+ "types": "./dist/revalidate/index.d.ts",
160
+ "default": "./dist/revalidate/index.js"
161
+ },
158
162
  "./sites/contract": {
159
163
  "types": "./dist/sites/contract.d.ts",
160
164
  "default": "./dist/sites/contract.js"
@@ -367,7 +371,11 @@
367
371
  "README.md",
368
372
  "AGENTS.md",
369
373
  "agent-manifest.json",
370
- "skills"
374
+ "skills",
375
+ "docs.json",
376
+ "CHANGELOG.md",
377
+ "docs/MIGRATING-TO-7.md",
378
+ "src/*/README.md"
371
379
  ],
372
380
  "scripts": {
373
381
  "build": "NODE_OPTIONS=--max-old-space-size=8192 tsup && pnpm build:types && node scripts/gen-agent-manifest.cjs",
@@ -387,8 +395,9 @@
387
395
  "typecheck": "tsc --noEmit",
388
396
  "typecheck:setup": "tsc --noEmit -p packages/sonor-setup/tsconfig.json",
389
397
  "version": "node scripts/sync-version.cjs && node scripts/gen-agent-manifest.cjs && git add src/shared/version.ts agent-manifest.json",
390
- "prepublishOnly": "rm -rf dist && NODE_OPTIONS=--max-old-space-size=8192 tsup && pnpm build:types && node scripts/gen-agent-manifest.cjs && node scripts/verify-dts.cjs && node scripts/prepublish-integration.cjs && node scripts/audit-as-consumer.cjs",
391
- "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --noEmit false && node scripts/alias-dts.cjs"
398
+ "prepublishOnly": "rm -rf dist && NODE_OPTIONS=--max-old-space-size=8192 tsup && pnpm build:types && node scripts/gen-agent-manifest.cjs && node scripts/verify-dts.cjs && node scripts/prepublish-integration.cjs && node scripts/audit-as-consumer.cjs && node scripts/verify-docs.cjs",
399
+ "build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --noEmit false && node scripts/alias-dts.cjs",
400
+ "verify:docs": "node scripts/verify-docs.cjs"
392
401
  },
393
402
  "peerDependencies": {
394
403
  "@portabletext/react": "^8.0.0",
@@ -450,6 +459,7 @@
450
459
  "commander": "^15.0.0",
451
460
  "glob": "^13.0.6",
452
461
  "gsap": "^3.15.0",
462
+ "happy-dom": "^20.14.5",
453
463
  "inquirer": "^14.0.2",
454
464
  "next": "16.3.6",
455
465
  "open": "11.0.0",