@sonordev/site-kit 7.0.2 → 7.1.1
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.
- package/CHANGELOG.md +71 -0
- package/agent-manifest.json +11 -5
- package/dist/{AnalyticsProvider-XXWTFKJH.js → AnalyticsProvider-3MI5RCTL.js} +4 -4
- package/dist/{ArticleViewTracker-V4KZB6QN.js → ArticleViewTracker-CMBSJR3N.js} +3 -3
- package/dist/{BlocksPopup-JHGHB6XW.js → BlocksPopup-X3OAAK2L.js} +4 -4
- package/dist/{ChatWidget-CG32POI3.js → ChatWidget-JMFBXJ75.js} +5 -5
- package/dist/{EngageWidget-LQMR4LEX.js → EngageWidget-A3QKZ3SU.js} +4 -4
- package/dist/{FileField-KUG3CKXG.js → FileField-QRSEGO6D.js} +3 -3
- package/dist/{FormSpotlight-FVNPOCU3.js → FormSpotlight-XKV7VTN4.js} +1 -1
- package/dist/{FormStage-C7VKRURJ.js → FormStage-C3YGYAUZ.js} +1 -1
- package/dist/{ManagedForm-VLNJKV65.js → ManagedForm-2GSSDJPP.js} +6 -6
- package/dist/{ManagedNewsletterForm-KJEU23BV.js → ManagedNewsletterForm-LPIKGJF4.js} +4 -4
- package/dist/{SignalCore-K2O46QG7.js → SignalCore-ICXXZBYI.js} +3 -3
- package/dist/{SiteDesignReporter-D7MD66GI.js → SiteDesignReporter-A7MS2CIP.js} +5 -5
- package/dist/SitemapSync-4U654SEA.js +8 -0
- package/dist/_client/booking-widget.js +5 -5
- package/dist/affiliates/index.js +3 -3
- package/dist/analytics/index.js +4 -4
- package/dist/articles/index.js +1 -1
- package/dist/articles/server-ui.js +1 -1
- package/dist/chat/index.js +5 -5
- package/dist/{chunk-KXPBMCFL.js → chunk-3QI26673.js} +3 -1
- package/dist/{chunk-6HDT4G4A.js → chunk-4YTYGG2C.js} +2 -2
- package/dist/{chunk-O52CH273.js → chunk-542MIHNP.js} +1 -1
- package/dist/{chunk-N2UVOR3X.js → chunk-662ILEZ6.js} +2 -0
- package/dist/chunk-6G43IRWR.js +4 -0
- package/dist/{chunk-B6RZ2NRH.js → chunk-6OL23QYD.js} +1 -1
- package/dist/{chunk-GGD4P7UW.js → chunk-7FWA3I6A.js} +1 -1
- package/dist/{chunk-T4SY3FMN.js → chunk-B73QPZPH.js} +3 -3
- package/dist/{chunk-KPAZG65P.js → chunk-CGWUXUYZ.js} +138 -46
- package/dist/{chunk-56JNI463.js → chunk-DUQMSNF2.js} +1 -1
- package/dist/{chunk-5FBY2ZIH.js → chunk-EFPS56JA.js} +1 -1
- package/dist/{chunk-P72ZJRSX.js → chunk-EQBZ24VH.js} +3 -3
- package/dist/{chunk-K5WZX776.js → chunk-H42PZKVC.js} +2 -2
- package/dist/{chunk-TT63HHIT.js → chunk-HAG4YIZY.js} +1 -1
- package/dist/{chunk-ZRE4ZYEG.js → chunk-ICFRH2ED.js} +1 -1
- package/dist/{chunk-7JIKGKWD.js → chunk-ILAW3XKD.js} +30 -7
- package/dist/{chunk-SSUQKA7L.js → chunk-J4D6ZXRW.js} +1 -1
- package/dist/{chunk-SWP36NCB.js → chunk-JC7KXNNM.js} +1 -1
- package/dist/{chunk-LVESVYCE.js → chunk-JIL5VY2R.js} +11 -117
- package/dist/{chunk-BS7FWUOY.js → chunk-KOPVJQ2P.js} +1 -1
- package/dist/chunk-LPH5FANE.js +169 -0
- package/dist/{chunk-ZSLRAMCK.js → chunk-NEKEH4CK.js} +1 -1
- package/dist/{chunk-DKTSGYLM.js → chunk-ODADQM6Z.js} +2 -2
- package/dist/{chunk-OIETJKIL.js → chunk-OUNRFXDC.js} +1 -1
- package/dist/{chunk-RU2RMTGT.js → chunk-PXZ7LAOY.js} +2 -2
- package/dist/{chunk-SAUTJMK6.js → chunk-Q3S26EQA.js} +1 -1
- package/dist/{chunk-BEL7YFMC.js → chunk-R3VKF43H.js} +1 -1
- package/dist/{chunk-P2GIIQH5.js → chunk-RK7GF7PQ.js} +1 -1
- package/dist/{chunk-42OXY4JV.js → chunk-RTMMHTEQ.js} +1 -1
- package/dist/chunk-RYVDGXC2.js +19 -0
- package/dist/{chunk-LJZ3SUET.js → chunk-V4HUSHZO.js} +2 -2
- package/dist/chunk-VCJYLYJV.js +49 -0
- package/dist/{chunk-GYY6ETGB.js → chunk-ZAWANWUS.js} +9 -5
- package/dist/chunk-ZETJTCMV.js +118 -0
- package/dist/client/index.js +3 -3
- package/dist/cms/CmsPage.d.ts +1 -0
- package/dist/cms/CmsPreview.d.ts +1 -0
- package/dist/cms/CmsSection.d.ts +1 -0
- package/dist/cms/index.d.ts +6 -0
- package/dist/cms/server-api.d.ts +3 -0
- package/dist/commerce/index.js +4 -4
- package/dist/config/index.js +1 -1
- package/dist/contracts/entries.d.ts +1 -1
- package/dist/contracts/site-cache.d.ts +55 -0
- package/dist/contracts/site-edit-param.d.ts +7 -0
- package/dist/contracts/site-edit.d.ts +77 -0
- package/dist/contracts/slot-content.d.ts +111 -0
- package/dist/contracts/slots.d.ts +39 -25
- package/dist/engage/index.js +6 -6
- package/dist/fleet/index.js +4 -4
- package/dist/forms/index.js +8 -8
- package/dist/forms/server.js +2 -2
- package/dist/images/index.js +4 -4
- package/dist/index.js +1 -1
- package/dist/layout/client.js +8 -7
- package/dist/layout/index.js +9 -8
- package/dist/llms/index.js +4 -2
- package/dist/llms/seo-revalidate.d.ts +8 -1
- package/dist/maps/index.js +3 -3
- package/dist/mcp/sonor.js +6 -6
- package/dist/overlay-RXV6U6QC.js +353 -0
- package/dist/proxy/index.js +2 -2
- package/dist/proxy/securityHeaders.d.ts +4 -0
- package/dist/revalidate/index.d.ts +44 -0
- package/dist/revalidate/index.js +27 -0
- package/dist/seo/ManagedContent.d.ts +2 -0
- package/dist/seo/client.js +4 -4
- package/dist/seo/index.js +9 -8
- package/dist/seo/llms.js +4 -2
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/server.js +3 -2
- package/dist/seo/sitemap.js +2 -2
- package/dist/server/index.js +2 -2
- package/dist/{server-api-GJJQZVG7.js → server-api-BVCBLJKL.js} +2 -1
- package/dist/shared/build-entries.d.ts +1 -0
- package/dist/shared/edit-bridge.d.ts +8 -0
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/sitemap/index.js +2 -2
- package/dist/slots/ManagedLink.d.ts +31 -0
- package/dist/slots/ManagedList.d.ts +30 -0
- package/dist/slots/ManagedRichText.d.ts +31 -0
- package/dist/slots/contract.js +2 -1
- package/dist/slots/edit/locate.d.ts +30 -0
- package/dist/slots/edit/overlay.d.ts +18 -0
- package/dist/slots/index.d.ts +12 -4
- package/dist/slots/index.js +4 -2
- package/dist/slots/revalidate.d.ts +8 -3
- package/dist/slots/rich.d.ts +7 -0
- package/dist/slots/server-api.d.ts +6 -2
- package/dist/sync/index.js +5 -5
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +5 -5
- package/dist/website/popups.js +4 -4
- package/dist/website/slots/contract.js +2 -1
- package/dist/website/slots.js +4 -2
- package/dist/{writeLLMsTxt-UMHKGNRR.js → writeLLMsTxt-QR23OQUE.js} +1 -1
- package/docs.json +2 -0
- package/package.json +6 -1
- package/src/revalidate/README.md +82 -0
- package/src/seo/README.md +4 -17
- package/src/slots/README.md +168 -0
- package/src/sync/README.md +1 -1
- package/dist/SitemapSync-NMXGMPCQ.js +0 -8
- 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>;
|
package/dist/slots/contract.js
CHANGED
|
@@ -1,2 +1,3 @@
|
|
|
1
|
-
export { SLOTS_CONTRACT_VERSION,
|
|
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;
|
package/dist/slots/index.d.ts
CHANGED
|
@@ -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
|
|
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';
|
package/dist/slots/index.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, resolveSlots } from '../chunk-
|
|
2
|
-
export { SLOTS_CONTRACT_VERSION,
|
|
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
|
-
|
|
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>;
|
package/dist/sync/index.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { BookingWidget } from '../chunk-
|
|
2
|
-
export { createBooking, createSlotHold, detectTimezone, fetchAvailability, fetchAvailableDates, fetchBookingTypeDetails, fetchBookingTypes, formatDate, formatDuration, formatTime, prepareMeeting, releaseSlotHold } from '../chunk-
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
5
|
-
import '../chunk-
|
|
1
|
+
export { BookingWidget } from '../chunk-ZAWANWUS.js';
|
|
2
|
+
export { createBooking, createSlotHold, detectTimezone, fetchAvailability, fetchAvailableDates, fetchBookingTypeDetails, fetchBookingTypes, formatDate, formatDuration, formatTime, prepareMeeting, releaseSlotHold } from '../chunk-EFPS56JA.js';
|
|
3
|
+
import '../chunk-PXZ7LAOY.js';
|
|
4
|
+
import '../chunk-OUNRFXDC.js';
|
|
5
|
+
import '../chunk-6OL23QYD.js';
|
|
6
6
|
import '../chunk-PKBMQBKP.js';
|
package/dist/website/images.js
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage } from '../chunk-
|
|
1
|
+
export { ManagedImage, assignImageToSlot, clearImageSlot, fetchManagedImage, fetchManagedImages, listImageFiles, uploadImage } from '../chunk-542MIHNP.js';
|
|
2
2
|
export { ManagedFavicon, getManagedFaviconUrl } from '../chunk-GW7GSBO7.js';
|
|
3
|
-
import '../chunk-
|
|
4
|
-
import '../chunk-
|
|
5
|
-
import '../chunk-
|
|
3
|
+
import '../chunk-PXZ7LAOY.js';
|
|
4
|
+
import '../chunk-OUNRFXDC.js';
|
|
5
|
+
import '../chunk-6OL23QYD.js';
|
|
6
6
|
import '../chunk-PKBMQBKP.js';
|
package/dist/website/index.js
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { SiteDesignReporter } from '../chunk-
|
|
3
|
-
export { SITE_DESIGN_PATH, cleanFontStack, colorToHex, getSiteDesignTokens, measureSiteDesign, readDeclaredDesign, sendSiteDesign } from '../chunk-
|
|
2
|
+
export { SiteDesignReporter } from '../chunk-ICFRH2ED.js';
|
|
3
|
+
export { SITE_DESIGN_PATH, cleanFontStack, colorToHex, getSiteDesignTokens, measureSiteDesign, readDeclaredDesign, sendSiteDesign } from '../chunk-ODADQM6Z.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-
|
|
11
|
-
import '../chunk-
|
|
12
|
-
import '../chunk-
|
|
10
|
+
import '../chunk-PXZ7LAOY.js';
|
|
11
|
+
import '../chunk-OUNRFXDC.js';
|
|
12
|
+
import '../chunk-6OL23QYD.js';
|
|
13
13
|
import '../chunk-PKBMQBKP.js';
|
package/dist/website/popups.js
CHANGED
|
@@ -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-
|
|
4
|
+
import { EngageWidget } from '../chunk-B73QPZPH.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-
|
|
13
|
-
import '../chunk-
|
|
14
|
-
import '../chunk-
|
|
12
|
+
import '../chunk-PXZ7LAOY.js';
|
|
13
|
+
import '../chunk-OUNRFXDC.js';
|
|
14
|
+
import '../chunk-6OL23QYD.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,
|
|
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';
|
package/dist/website/slots.js
CHANGED
|
@@ -1,5 +1,7 @@
|
|
|
1
|
-
export { ManagedSlot, SLOTS_CACHE_TAG, createSlotsRevalidateHandler, ManagedSlot_default as default, getSlot, resolveSlots } from '../chunk-
|
|
2
|
-
export { SLOTS_CONTRACT_VERSION,
|
|
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';
|
package/docs.json
CHANGED
|
@@ -16,6 +16,7 @@
|
|
|
16
16
|
"title": "Core",
|
|
17
17
|
"pages": [
|
|
18
18
|
{ "slug": "layout", "title": "Layout", "file": "src/layout/README.md" },
|
|
19
|
+
{ "slug": "live-updates", "title": "Live updates", "file": "src/revalidate/README.md" },
|
|
19
20
|
{ "slug": "seo", "title": "SEO", "file": "src/seo/README.md" },
|
|
20
21
|
{ "slug": "analytics", "title": "Analytics", "file": "src/analytics/README.md" },
|
|
21
22
|
{ "slug": "sitemap", "title": "Sitemap", "file": "src/sitemap/README.md" },
|
|
@@ -27,6 +28,7 @@
|
|
|
27
28
|
{
|
|
28
29
|
"title": "Content",
|
|
29
30
|
"pages": [
|
|
31
|
+
{ "slug": "copy", "title": "Managed copy", "file": "src/slots/README.md" },
|
|
30
32
|
{ "slug": "articles", "title": "Articles", "file": "src/articles/README.md" },
|
|
31
33
|
{ "slug": "images", "title": "Images", "file": "src/images/README.md" },
|
|
32
34
|
{ "slug": "reputation", "title": "Reputation", "file": "src/reputation/README.md" }
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sonordev/site-kit",
|
|
3
|
-
"version": "7.
|
|
3
|
+
"version": "7.1.1",
|
|
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"
|
|
@@ -455,6 +459,7 @@
|
|
|
455
459
|
"commander": "^15.0.0",
|
|
456
460
|
"glob": "^13.0.6",
|
|
457
461
|
"gsap": "^3.15.0",
|
|
462
|
+
"happy-dom": "^20.14.5",
|
|
458
463
|
"inquirer": "^14.0.2",
|
|
459
464
|
"next": "16.3.6",
|
|
460
465
|
"open": "11.0.0",
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
# Live updates
|
|
2
|
+
|
|
3
|
+
Your pages stay cached, and when someone changes content in Sonor, the pages
|
|
4
|
+
that use it refresh within seconds. It takes one route file:
|
|
5
|
+
|
|
6
|
+
```ts
|
|
7
|
+
// app/api/seo-revalidate/route.ts
|
|
8
|
+
export { POST } from '@sonordev/site-kit/revalidate'
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
`npx sonor-setup scaffold` writes it for you, and `npx sonor-setup doctor`
|
|
12
|
+
tells you when it's missing.
|
|
13
|
+
|
|
14
|
+
## How it works
|
|
15
|
+
|
|
16
|
+
Everything site-kit fetches from Sonor is cached, and pages built from those
|
|
17
|
+
fetches are served from your host's CDN. When content changes in Sonor
|
|
18
|
+
(managed copy, a page's title or description, an article, a portfolio item),
|
|
19
|
+
Sonor sends this route the paths and cache tags that changed. The route checks
|
|
20
|
+
the call was signed with your project's API key, then expires only those
|
|
21
|
+
pages and tags. The next visitor gets the new version, and every other page
|
|
22
|
+
stays cached.
|
|
23
|
+
|
|
24
|
+
It's the same `SONOR_API_KEY` the rest of site-kit reads, so there's no
|
|
25
|
+
extra secret to set. Sonor finds the route on its own: the first sitemap sync
|
|
26
|
+
after a deploy registers `https://your-domain/api/seo-revalidate` and checks
|
|
27
|
+
that it answers.
|
|
28
|
+
|
|
29
|
+
Without the route, nothing breaks. Edits still show up, but only once each
|
|
30
|
+
cached fetch ages out: about five minutes for managed copy, up to a day for
|
|
31
|
+
metadata.
|
|
32
|
+
|
|
33
|
+
## Sites with a publication
|
|
34
|
+
|
|
35
|
+
If your site publishes articles, tell the route where they live so the index
|
|
36
|
+
and feeds refresh with each article:
|
|
37
|
+
|
|
38
|
+
```ts
|
|
39
|
+
// app/api/seo-revalidate/route.ts
|
|
40
|
+
import { createRevalidateRoute } from '@sonordev/site-kit/revalidate'
|
|
41
|
+
|
|
42
|
+
export const POST = createRevalidateRoute({ publicationBasePath: '/insights' })
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
| Option | What it does |
|
|
46
|
+
|---|---|
|
|
47
|
+
| `publicationBasePath` | Where your articles live, e.g. `/insights`. The index and its RSS and Atom feeds refresh on every call. |
|
|
48
|
+
| `extraPaths` | Local paths to refresh on every call, e.g. a hub page like `/work`. |
|
|
49
|
+
| `extendPayload` | Map extra fields Sonor sends to more paths or tags. The result is validated again, so it can't widen what a caller may refresh. |
|
|
50
|
+
| `secret` | The key calls are signed with. Defaults to `SONOR_API_KEY`, read on every call. |
|
|
51
|
+
|
|
52
|
+
## What Sonor sends
|
|
53
|
+
|
|
54
|
+
A POST with `Authorization: Bearer <SONOR_API_KEY>` and a JSON body:
|
|
55
|
+
|
|
56
|
+
```json
|
|
57
|
+
{ "paths": ["/services/roofing"], "tags": ["sonor-slots"] }
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
| Field | Meaning |
|
|
61
|
+
|---|---|
|
|
62
|
+
| `paths` | Local paths to regenerate. `/sitemap.xml`, `/llms.txt` and `/llms-full.txt` are always refreshed too. |
|
|
63
|
+
| `tags` | Cache tags to expire. The ones Sonor uses are `SITE_CACHE_TAGS`: `sonor-slots` (managed copy), `seo` (metadata, schema, FAQs), `blog` (articles), `editorial-taxonomy` and `portfolio`. |
|
|
64
|
+
| `revalidateAll` | Regenerate every page. |
|
|
65
|
+
| `ping` | `{ "ping": true }` on its own regenerates nothing and answers `{ "ok": true, "ping": true, "version": "…" }`. Sonor uses it to confirm the route is installed. |
|
|
66
|
+
|
|
67
|
+
The route refuses a bad key (401), a body over 16 KB (413) and any path that
|
|
68
|
+
isn't a plain local path or any malformed tag (400). A refused call refreshes
|
|
69
|
+
nothing.
|
|
70
|
+
|
|
71
|
+
## Checking it
|
|
72
|
+
|
|
73
|
+
```bash
|
|
74
|
+
curl -s -X POST https://your-domain/api/seo-revalidate \
|
|
75
|
+
-H "Authorization: Bearer $SONOR_API_KEY" \
|
|
76
|
+
-H "Content-Type: application/json" \
|
|
77
|
+
-d '{"ping":true}'
|
|
78
|
+
```
|
|
79
|
+
|
|
80
|
+
`{"ok":true,"ping":true,...}` means Sonor's edits will go live in seconds. A
|
|
81
|
+
404 means the route isn't deployed. A 401 means the key on the site doesn't
|
|
82
|
+
match the project's key.
|
package/src/seo/README.md
CHANGED
|
@@ -219,26 +219,13 @@ Renders the internal links Sonor has for `path` at that position, or nothing whe
|
|
|
219
219
|
|
|
220
220
|
`limit` defaults to 5. `renderLink(link)` replaces the default `<a>`, and `className` replaces the default `sk-internal-links sk-internal-links--{position}`. `site` pins the sub-site host (see [Multi-site projects](#multi-site-projects)).
|
|
221
221
|
|
|
222
|
-
## Content blocks: `<ManagedContent>`
|
|
222
|
+
## Content blocks: `<ManagedContent>` (deprecated)
|
|
223
223
|
|
|
224
|
-
|
|
225
|
-
import { ManagedContent } from '@sonordev/site-kit/seo'
|
|
226
|
-
|
|
227
|
-
<ManagedContent path="/services/plumbing" section="hero" fallback={<DefaultHero />} />
|
|
228
|
-
```
|
|
229
|
-
|
|
230
|
-
Renders the block Sonor has for that path and section, by its content type:
|
|
231
|
-
|
|
232
|
-
- `html`: injected as-is
|
|
233
|
-
- `markdown`: a basic conversion (headings, bold, italic, links, paragraphs). For anything richer, fetch the raw block with `getManagedContentData(path, section)` and use your own parser.
|
|
234
|
-
- `json`: renders `title`, `subtitle`, `content` (as HTML) and `items`
|
|
235
|
-
- `react`: `{ component, props }`, looked up by name in the `components` prop
|
|
236
|
-
|
|
237
|
-
It renders `fallback` (or nothing) when there's no block. `injectEntityAnnotations` depends on the entity graph and changes nothing today. `site` pins the sub-site host, and `getManagedContentData(path, section, site?)` takes it too.
|
|
224
|
+
Deprecated in 7.1 and removed in 8.0. Page copy is [managed copy](../slots/README.md) now: wrap the text in `<ManagedSlot>` or `<ManagedRichText>` and edit it in Sonor under Website → Content, with drafts, history and Edit on page. Sonor no longer creates content blocks, so `ManagedContent` renders its `fallback`.
|
|
238
225
|
|
|
239
226
|
## Multi-site projects
|
|
240
227
|
|
|
241
|
-
One Sonor project can serve many domains (example.com plus its city microsites). Managed FAQs
|
|
228
|
+
One Sonor project can serve many domains (example.com plus its city microsites). Managed FAQs and internal links can be project-wide (every host) or tagged with one host (that host only). `ManagedFAQ` and `ManagedInternalLinks` send the site host with every read, so each microsite gets its own rows plus the project-wide ones, never a sibling's.
|
|
242
229
|
|
|
243
230
|
The host resolves from `NEXT_PUBLIC_SITE_URL`, which every microsite already sets, so most sites change nothing. To pin one, pass `site`:
|
|
244
231
|
|
|
@@ -311,7 +298,7 @@ Every component above is built on these. They're server-only, take paths rather
|
|
|
311
298
|
|
|
312
299
|
## Entity graph and AI visibility
|
|
313
300
|
|
|
314
|
-
`getEntities`, `getPrimaryEntity`, `getEntityEnhancedSchema`, `getVisibilityScore` and `getVisibilitySummary` are exported, but called from a site they currently return empty results (`[]` or `null`): the Signal endpoints behind them don't accept a site key yet. That's also why `ManagedSchema`'s `includeEntityGraph`
|
|
301
|
+
`getEntities`, `getPrimaryEntity`, `getEntityEnhancedSchema`, `getVisibilityScore` and `getVisibilitySummary` are exported, but called from a site they currently return empty results (`[]` or `null`): the Signal endpoints behind them don't accept a site key yet. That's also why `ManagedSchema`'s `includeEntityGraph` has no effect. Don't build on them until that changes.
|
|
315
302
|
|
|
316
303
|
## Caching
|
|
317
304
|
|