@sonordev/site-kit 7.4.0 → 8.0.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.
- package/AGENTS.md +40 -12
- package/CHANGELOG.md +67 -0
- package/README.md +44 -18
- package/agent-manifest.json +111 -56
- package/dist/AnalyticsProvider-LYFDQRRJ.js +13 -0
- package/dist/{ArticleViewTracker-3DH53RSB.js → ArticleViewTracker-HG7IIRJY.js} +6 -5
- package/dist/{BlocksPopup-FGWYVHCH.js → BlocksPopup-GFX3GZIK.js} +6 -5
- package/dist/{ChatWidget-CDQZCLVH.js → ChatWidget-DVS7MLBN.js} +8 -5
- package/dist/{FileField-IPJ7L2W6.js → FileField-DVN7NUBI.js} +5 -5
- package/dist/{FormSpotlight-CQI2DBWI.js → FormSpotlight-W4SXKKO6.js} +3 -3
- package/dist/{FormStage-4WHD6ED4.js → FormStage-JTEE5MZD.js} +3 -3
- package/dist/ManagedForm-ZAUHIHGP.js +19 -0
- package/dist/{ManagedNewsletterForm-3D2BK3KQ.js → ManagedNewsletterForm-DQIB5Z4Y.js} +9 -6
- package/dist/{SignalCore-HEQYITTM.js → SignalCore-W5PYYMGX.js} +7 -7
- package/dist/SiteChat-MY2GATWC.js +6 -0
- package/dist/SiteDesignReporter-ICZWEGCY.js +12 -0
- package/dist/SitePopups-TGULLAER.js +13 -0
- package/dist/SitemapSync-AN2OBJE6.js +9 -0
- package/dist/_client/booking-widget.js +6 -5
- package/dist/_client/testimonial-section.js +3 -2
- package/dist/affiliates/index.js +6 -6
- package/dist/analytics/index.js +73 -7
- package/dist/articles/index.js +2 -2
- package/dist/articles/server-ui.js +3 -3
- package/dist/articles/server.js +2 -2
- package/dist/brand.css +1 -1
- package/dist/chat/index.d.ts +1 -1
- package/dist/chat/index.js +39 -8
- package/dist/chunk-3G7YABRA.js +25 -0
- package/dist/{chunk-CGWUXUYZ.js → chunk-3RDJKIYO.js} +2 -2
- package/dist/{chunk-J4FSB4OG.js → chunk-3YKQLC7J.js} +5 -2
- package/dist/{chunk-3E3PPSNR.js → chunk-56VDS2RP.js} +2 -2
- package/dist/chunk-5ROTTMBL.js +19 -0
- package/dist/{chunk-KHQ5GD6T.js → chunk-5S2XDG5O.js} +1 -1
- package/dist/chunk-5TM3WPCI.js +7 -0
- package/dist/{chunk-7HPZSWS4.js → chunk-6CJGZFOU.js} +1 -1
- package/dist/{chunk-RYVDGXC2.js → chunk-6KU7STM3.js} +3 -1
- package/dist/{chunk-FUQTV5O6.js → chunk-6QFINXLH.js} +3 -3
- package/dist/{chunk-AH4AXO4P.js → chunk-6ZXJ3SXR.js} +1 -1
- package/dist/{chunk-XA2BNW5M.js → chunk-7YEEOIWI.js} +1 -1
- package/dist/{chunk-IE5SSOCN.js → chunk-BQ2CXKTQ.js} +3 -11
- package/dist/{chunk-X6F6SO4S.js → chunk-C7TLGL3R.js} +21 -1
- package/dist/{chunk-43OCZ3JA.js → chunk-CAH4Y4PY.js} +4 -2
- package/dist/{chunk-PXKIGZ2F.js → chunk-EATJPSTS.js} +1 -1
- package/dist/{chunk-OOD6GMT4.js → chunk-GNSXOTIK.js} +6 -4
- package/dist/{chunk-EHR4NIMX.js → chunk-ICAVVF6D.js} +3 -3
- package/dist/{chunk-MHGAZ3LL.js → chunk-IJQ767JS.js} +3 -5
- package/dist/{chunk-CKW4HFJG.js → chunk-J65N34YM.js} +3 -3
- package/dist/{chunk-4BHRA7TI.js → chunk-JIH32RH2.js} +3 -3
- package/dist/{chunk-D2RGEWHS.js → chunk-K22OLAPC.js} +2 -2
- package/dist/{chunk-CG4ETW5Y.js → chunk-KRBBH64S.js} +3 -3
- package/dist/{chunk-JRCNUUNG.js → chunk-LBIQ5LTC.js} +1 -1
- package/dist/{chunk-MDP7EB4J.js → chunk-LKH44GI3.js} +5 -5
- package/dist/{chunk-ZTLMPUO6.js → chunk-LNSF6BJC.js} +1 -1
- package/dist/{chunk-5O62CER4.js → chunk-M62U7TJF.js} +1 -1
- package/dist/{chunk-EDYHROQ7.js → chunk-NFRJTOTB.js} +3 -3
- package/dist/{chunk-4DJMJ4V5.js → chunk-OE3NXEOF.js} +1 -1
- package/dist/{chunk-AV4QAK5F.js → chunk-OGK7OL3T.js} +5 -4
- package/dist/{chunk-YCFW2OQO.js → chunk-PD7K54EQ.js} +2 -2
- package/dist/{chunk-PF64OEXC.js → chunk-PIX7FAMX.js} +2 -2
- package/dist/{chunk-XEMHGJEG.js → chunk-ROAOI6GG.js} +10 -10
- package/dist/{chunk-6LLTLLEJ.js → chunk-S7SSYGUJ.js} +6 -5
- package/dist/{chunk-ATE6IFVK.js → chunk-SBPAXWLF.js} +1 -1
- package/dist/{chunk-DA5XC7Y6.js → chunk-TOSZGJEQ.js} +1 -1
- package/dist/{chunk-4NTBQNHA.js → chunk-TYAVHRWH.js} +80 -81
- package/dist/{chunk-ZTLU3BSW.js → chunk-TZ5RTANX.js} +2 -2
- package/dist/{chunk-4YTYGG2C.js → chunk-URJN75ZG.js} +29 -16
- package/dist/{chunk-CSN45MHO.js → chunk-UUWUAMUC.js} +13 -16
- package/dist/{chunk-PKGN32AU.js → chunk-XPTJRVL2.js} +1 -1
- package/dist/{chunk-662ILEZ6.js → chunk-Y35BWW2C.js} +3 -7
- package/dist/{chunk-PQDJNIHR.js → chunk-ZHNQFNO3.js} +2 -2
- package/dist/chunk-ZKADJNR2.js +52 -0
- package/dist/{chunk-GK7TV7EK.js → chunk-ZLFGXKLG.js} +1 -1
- package/dist/client/index.js +6 -5
- package/dist/contracts/entries.d.ts +1 -1
- package/dist/contracts/sentences.d.ts +46 -0
- package/dist/contracts/site-cache.d.ts +2 -0
- package/dist/cta-bar/index.js +1 -1
- package/dist/fleet/index.js +6 -5
- package/dist/forms/field-autocomplete.d.ts +16 -8
- package/dist/forms/index.d.ts +5 -0
- package/dist/forms/index.js +17 -17
- package/dist/forms/server.js +7 -7
- package/dist/forms/static.js +2 -2
- package/dist/forms/submitForm.d.ts +5 -0
- package/dist/images/index.js +4 -4
- package/dist/index.d.ts +3 -7
- package/dist/index.js +1 -1
- package/dist/layout/SiteKitLayout.d.ts +2 -1
- package/dist/layout/client.js +11 -9
- package/dist/layout/index.js +13 -11
- package/dist/llms/index.js +7 -6
- package/dist/maps/index.js +6 -6
- package/dist/mcp/sonor.d.ts +47 -3
- package/dist/mcp/sonor.js +30 -20
- package/dist/proxy/index.d.ts +3 -3
- package/dist/proxy/index.js +1 -1
- package/dist/reputation/index.js +3 -2
- package/dist/reputation/server.js +2 -1
- package/dist/revalidate/index.js +3 -3
- package/dist/robots/indexnow.js +2 -2
- package/dist/runtime/index.d.ts +32 -0
- package/dist/runtime/index.js +7 -0
- package/dist/seo/api.d.ts +0 -4
- package/dist/seo/client.js +6 -5
- package/dist/seo/getManagedMetadata.d.ts +24 -0
- package/dist/seo/index.d.ts +2 -3
- package/dist/seo/index.js +14 -132
- package/dist/seo/indexnow.js +2 -2
- package/dist/seo/llms.js +7 -6
- package/dist/seo/register-sitemap-cli.js +2 -2
- package/dist/seo/server-api.d.ts +0 -6
- package/dist/seo/server.d.ts +1 -1
- package/dist/seo/server.js +4 -4
- package/dist/seo/sitemap.js +4 -3
- package/dist/seo/types.d.ts +9 -30
- package/dist/server/index.d.ts +8 -1
- package/dist/server/index.js +4 -3
- package/dist/server/mint-site-token.d.ts +0 -11
- package/dist/server/server-fetch.d.ts +19 -0
- package/dist/server-api-EGOKC7Q3.js +9 -0
- package/dist/shared/build-entries.d.ts +21 -9
- package/dist/shared/clientApiConfig.d.ts +56 -0
- package/dist/shared/identity-reader.d.ts +26 -0
- package/dist/shared/identity-storage.d.ts +30 -0
- package/dist/shared/identity.d.ts +13 -13
- package/dist/shared/import-specifiers.d.ts +26 -0
- package/dist/shared/sonorFetch.d.ts +4 -3
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/sitemap/index.js +4 -3
- package/dist/slots/index.js +3 -3
- package/dist/sync/index.js +6 -5
- package/dist/types.d.ts +0 -1
- package/dist/website/cta-bar.js +1 -1
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +7 -6
- package/dist/website/popups.js +10 -7
- package/dist/website/slots.js +3 -3
- package/dist/{writeLLMsTxt-OL4KQERZ.js → writeLLMsTxt-UZGN6IBU.js} +3 -2
- package/docs/MIGRATING-TO-7.md +5 -2
- package/docs/MIGRATING-TO-8.md +183 -0
- package/docs.json +4 -8
- package/package.json +15 -44
- package/skills/site-kit/SKILL.md +41 -11
- package/src/analytics/README.md +14 -14
- package/src/chat/README.md +7 -7
- package/src/forms/README.md +61 -6
- package/src/mcp/README.md +61 -20
- package/src/proxy/README.md +5 -4
- package/src/revalidate/README.md +2 -2
- package/src/runtime/README.md +51 -0
- package/src/seo/README.md +24 -8
- package/src/sync/README.md +2 -2
- package/src/website/README.md +3 -2
- package/dist/AnalyticsProvider-BQXV3ZF3.js +0 -11
- package/dist/ManagedForm-7FZNH4L2.js +0 -16
- package/dist/SiteChat-DMPDXY3W.js +0 -5
- package/dist/SiteDesignReporter-Y2IOJE52.js +0 -11
- package/dist/SitePopups-HD2LDKVU.js +0 -10
- package/dist/SitemapSync-OKPZHRX6.js +0 -8
- package/dist/chunk-24QZEO3Q.js +0 -41
- package/dist/chunk-BU66S5B7.js +0 -1
- package/dist/chunk-G3NHWMP5.js +0 -233
- package/dist/chunk-HODO5BX5.js +0 -28
- package/dist/chunk-L3AQCDCY.js +0 -386
- package/dist/chunk-P5GB6NEO.js +0 -66
- package/dist/chunk-SWKE6FWH.js +0 -47
- package/dist/cms/CmsPage.d.ts +0 -17
- package/dist/cms/CmsPreview.d.ts +0 -37
- package/dist/cms/CmsSection.d.ts +0 -8
- package/dist/cms/PortableTextRenderer.d.ts +0 -7
- package/dist/cms/index.d.ts +0 -37
- package/dist/cms/index.js +0 -5
- package/dist/cms/sanity-image.d.ts +0 -47
- package/dist/cms/sections/CtaSection.d.ts +0 -3
- package/dist/cms/sections/CustomSection.d.ts +0 -7
- package/dist/cms/sections/FaqSection.d.ts +0 -3
- package/dist/cms/sections/FormSection.d.ts +0 -8
- package/dist/cms/sections/GallerySection.d.ts +0 -3
- package/dist/cms/sections/HeroSection.d.ts +0 -3
- package/dist/cms/sections/RichTextSection.d.ts +0 -3
- package/dist/cms/sections/TestimonialsSection.d.ts +0 -3
- package/dist/cms/sections/index.d.ts +0 -8
- package/dist/cms/server-api.d.ts +0 -49
- package/dist/cms/server.d.ts +0 -1
- package/dist/cms/server.js +0 -5
- package/dist/cms/types.d.ts +0 -104
- package/dist/commerce/CalendarView.d.ts +0 -43
- package/dist/commerce/CheckoutForm.d.ts +0 -11
- package/dist/commerce/EventCalendar.d.ts +0 -26
- package/dist/commerce/EventCheckout.d.ts +0 -42
- package/dist/commerce/EventEmbed.d.ts +0 -11
- package/dist/commerce/EventModal.d.ts +0 -43
- package/dist/commerce/EventTile.d.ts +0 -10
- package/dist/commerce/EventsAgenda.d.ts +0 -38
- package/dist/commerce/EventsWidget.d.ts +0 -84
- package/dist/commerce/OfferingCard.d.ts +0 -9
- package/dist/commerce/OfferingList.d.ts +0 -9
- package/dist/commerce/ProductDetail.d.ts +0 -38
- package/dist/commerce/ProductEmbed.d.ts +0 -11
- package/dist/commerce/ProductGrid.d.ts +0 -41
- package/dist/commerce/ProductPage.d.ts +0 -39
- package/dist/commerce/RegistrationForm.d.ts +0 -9
- package/dist/commerce/SizeChart.d.ts +0 -8
- package/dist/commerce/UpcomingEvents.d.ts +0 -9
- package/dist/commerce/api.d.ts +0 -179
- package/dist/commerce/events-extras.d.ts +0 -60
- package/dist/commerce/index.d.ts +0 -33
- package/dist/commerce/index.js +0 -8022
- package/dist/commerce/server.d.ts +0 -161
- package/dist/commerce/server.js +0 -2
- package/dist/commerce/types.d.ts +0 -340
- package/dist/commerce/useEventModal.d.ts +0 -20
- package/dist/commerce/utils.d.ts +0 -17
- package/dist/engage/EngageWidget.d.ts +0 -21
- package/dist/engage/index.d.ts +0 -14
- package/dist/engage/index.js +0 -45
- package/dist/engage/types.d.ts +0 -33
- package/dist/seo/ManagedContent.d.ts +0 -14
- package/dist/server-api-BVCBLJKL.js +0 -9
- package/dist/website/cms/server.d.ts +0 -2
- package/dist/website/cms/server.js +0 -5
- package/dist/website/cms-server.d.ts +0 -2
- package/dist/website/cms.d.ts +0 -2
- package/dist/website/cms.js +0 -5
- package/src/commerce/README.md +0 -109
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@sonordev/site-kit",
|
|
3
|
-
"version": "
|
|
3
|
+
"version": "8.0.0",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"packageManager": "pnpm@11.5.3",
|
|
6
|
-
"description": "
|
|
6
|
+
"description": "The Sonor modules a Next.js site needs, from one package and one API key: SEO, analytics, forms, articles, chat, booking, AI visibility and agent tools. Selling online? Add @sonordev/commerce-kit.",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"repository": {
|
|
9
9
|
"type": "git",
|
|
@@ -13,7 +13,7 @@
|
|
|
13
13
|
"**/*.css"
|
|
14
14
|
],
|
|
15
15
|
"main": "./dist/index.js",
|
|
16
|
-
"module": "./dist/index.
|
|
16
|
+
"module": "./dist/index.js",
|
|
17
17
|
"types": "./dist/index.d.ts",
|
|
18
18
|
"bin": {
|
|
19
19
|
"sonor-register-sitemap": "dist/seo/register-sitemap-cli.js"
|
|
@@ -43,10 +43,6 @@
|
|
|
43
43
|
"types": "./dist/analytics/index.d.ts",
|
|
44
44
|
"default": "./dist/analytics/index.js"
|
|
45
45
|
},
|
|
46
|
-
"./engage": {
|
|
47
|
-
"types": "./dist/engage/index.d.ts",
|
|
48
|
-
"default": "./dist/engage/index.js"
|
|
49
|
-
},
|
|
50
46
|
"./signal": {
|
|
51
47
|
"types": "./dist/signal/index.d.ts",
|
|
52
48
|
"default": "./dist/signal/index.js"
|
|
@@ -75,14 +71,6 @@
|
|
|
75
71
|
"types": "./dist/articles/server-ui.d.ts",
|
|
76
72
|
"default": "./dist/articles/server-ui.js"
|
|
77
73
|
},
|
|
78
|
-
"./commerce": {
|
|
79
|
-
"types": "./dist/commerce/index.d.ts",
|
|
80
|
-
"default": "./dist/commerce/index.js"
|
|
81
|
-
},
|
|
82
|
-
"./commerce/server": {
|
|
83
|
-
"types": "./dist/commerce/server.d.ts",
|
|
84
|
-
"default": "./dist/commerce/server.js"
|
|
85
|
-
},
|
|
86
74
|
"./sync": {
|
|
87
75
|
"types": "./dist/sync/index.d.ts",
|
|
88
76
|
"default": "./dist/sync/index.js"
|
|
@@ -207,14 +195,6 @@
|
|
|
207
195
|
"types": "./dist/website/slots/contract.d.ts",
|
|
208
196
|
"default": "./dist/website/slots/contract.js"
|
|
209
197
|
},
|
|
210
|
-
"./website/cms": {
|
|
211
|
-
"types": "./dist/website/cms.d.ts",
|
|
212
|
-
"default": "./dist/website/cms.js"
|
|
213
|
-
},
|
|
214
|
-
"./website/cms/server": {
|
|
215
|
-
"types": "./dist/website/cms/server.d.ts",
|
|
216
|
-
"default": "./dist/website/cms/server.js"
|
|
217
|
-
},
|
|
218
198
|
"./website/landing": {
|
|
219
199
|
"types": "./dist/website/landing.d.ts",
|
|
220
200
|
"default": "./dist/website/landing.js"
|
|
@@ -323,14 +303,6 @@
|
|
|
323
303
|
"types": "./dist/config/index.d.ts",
|
|
324
304
|
"default": "./dist/config/index.js"
|
|
325
305
|
},
|
|
326
|
-
"./cms": {
|
|
327
|
-
"types": "./dist/cms/index.d.ts",
|
|
328
|
-
"default": "./dist/cms/index.js"
|
|
329
|
-
},
|
|
330
|
-
"./cms/server": {
|
|
331
|
-
"types": "./dist/cms/server.d.ts",
|
|
332
|
-
"default": "./dist/cms/server.js"
|
|
333
|
-
},
|
|
334
306
|
"./maps": {
|
|
335
307
|
"types": "./dist/maps/index.d.ts",
|
|
336
308
|
"default": "./dist/maps/index.js"
|
|
@@ -355,6 +327,10 @@
|
|
|
355
327
|
"types": "./dist/client/index.d.ts",
|
|
356
328
|
"default": "./dist/client/index.js"
|
|
357
329
|
},
|
|
330
|
+
"./runtime": {
|
|
331
|
+
"types": "./dist/runtime/index.d.ts",
|
|
332
|
+
"default": "./dist/runtime/index.js"
|
|
333
|
+
},
|
|
358
334
|
"./brand.css": "./dist/brand.css",
|
|
359
335
|
"./forms/styles.css": "./dist/forms/styles.css",
|
|
360
336
|
"./forms/static": {
|
|
@@ -375,6 +351,7 @@
|
|
|
375
351
|
"docs.json",
|
|
376
352
|
"CHANGELOG.md",
|
|
377
353
|
"docs/MIGRATING-TO-7.md",
|
|
354
|
+
"docs/MIGRATING-TO-8.md",
|
|
378
355
|
"src/*/README.md"
|
|
379
356
|
],
|
|
380
357
|
"scripts": {
|
|
@@ -395,13 +372,15 @@
|
|
|
395
372
|
"typecheck": "tsc --noEmit",
|
|
396
373
|
"typecheck:setup": "tsc --noEmit -p packages/sonor-setup/tsconfig.json",
|
|
397
374
|
"version": "node scripts/sync-version.cjs && node scripts/gen-agent-manifest.cjs && git add src/shared/version.ts agent-manifest.json",
|
|
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",
|
|
375
|
+
"prepublishOnly": "vitest run && tsc --noEmit -p packages/commerce-kit/tsconfig.json && 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/verify-no-local-paths.cjs dist agent-manifest.json && node scripts/prepublish-integration.cjs && node scripts/audit-as-consumer.cjs && node scripts/verify-docs.cjs",
|
|
399
376
|
"build:types": "tsc -p tsconfig.build.json --emitDeclarationOnly --noEmit false && node scripts/alias-dts.cjs",
|
|
400
|
-
"verify:docs": "node scripts/verify-docs.cjs"
|
|
377
|
+
"verify:docs": "node scripts/verify-docs.cjs",
|
|
378
|
+
"build:commerce": "node scripts/check-kit-build-order.cjs && NODE_OPTIONS=--max-old-space-size=8192 tsup --config packages/commerce-kit/tsup.config.ts && tsc -p packages/commerce-kit/tsconfig.build.json && node packages/commerce-kit/scripts/verify-dist.cjs && node packages/commerce-kit/scripts/verify-against-site-kit.cjs",
|
|
379
|
+
"test:commerce": "vitest run packages/commerce-kit && tsc --noEmit -p packages/commerce-kit/tsconfig.json",
|
|
380
|
+
"typecheck:commerce": "tsc --noEmit -p packages/commerce-kit/tsconfig.json",
|
|
381
|
+
"verify:docs:commerce": "node scripts/verify-docs.cjs packages/commerce-kit"
|
|
401
382
|
},
|
|
402
383
|
"peerDependencies": {
|
|
403
|
-
"@portabletext/react": "^8.0.0",
|
|
404
|
-
"@sanity/image-url": "^2.1.1",
|
|
405
384
|
"@vis.gl/react-google-maps": ">=1.0.0",
|
|
406
385
|
"gsap": "^3.13.0",
|
|
407
386
|
"next": "^16.0.0",
|
|
@@ -422,12 +401,6 @@
|
|
|
422
401
|
"@vis.gl/react-google-maps": {
|
|
423
402
|
"optional": true
|
|
424
403
|
},
|
|
425
|
-
"@portabletext/react": {
|
|
426
|
-
"optional": true
|
|
427
|
-
},
|
|
428
|
-
"@sanity/image-url": {
|
|
429
|
-
"optional": true
|
|
430
|
-
},
|
|
431
404
|
"gsap": {
|
|
432
405
|
"optional": true
|
|
433
406
|
},
|
|
@@ -446,8 +419,6 @@
|
|
|
446
419
|
"@babel/parser": "^8.0.4",
|
|
447
420
|
"@babel/traverse": "^8.0.4",
|
|
448
421
|
"@babel/types": "^8.0.4",
|
|
449
|
-
"@portabletext/react": "^8.0.0",
|
|
450
|
-
"@sanity/image-url": "^2.1.1",
|
|
451
422
|
"@types/babel__generator": "^7.27.0",
|
|
452
423
|
"@types/babel__traverse": "^7.28.0",
|
|
453
424
|
"@types/inquirer": "^9.0.10",
|
|
@@ -480,7 +451,7 @@
|
|
|
480
451
|
"seo",
|
|
481
452
|
"analytics",
|
|
482
453
|
"forms",
|
|
483
|
-
"
|
|
454
|
+
"chat",
|
|
484
455
|
"articles",
|
|
485
456
|
"publishing",
|
|
486
457
|
"nextjs",
|
package/skills/site-kit/SKILL.md
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: site-kit
|
|
3
|
-
description: Integrate, upgrade, or debug a Next.js site's Sonor integration via @sonordev/site-kit. Use when wiring a site to Sonor, migrating a 2.x integration to 3.x, or diagnosing SSR/analytics/key issues on a site that installs @sonordev/site-kit. Trigger on "wire up Sonor", "connect this site to Sonor", "site-kit", "sonor-setup", "SiteKitLayout", "analytics bailout / CSR", or a failing `sonor-setup verify`.
|
|
3
|
+
description: Integrate, upgrade, or debug a Next.js site's Sonor integration via @sonordev/site-kit. Use when wiring a site to Sonor, migrating a 2.x integration to 3.x, or diagnosing SSR/analytics/key issues on a site that installs @sonordev/site-kit. Also use when moving a site to site-kit 8, or when adding commerce, events or memberships through @sonordev/commerce-kit. Trigger on "wire up Sonor", "connect this site to Sonor", "site-kit", "sonor-setup", "SiteKitLayout", "commerce-kit", "analytics bailout / CSR", or a failing `sonor-setup verify`.
|
|
4
4
|
---
|
|
5
5
|
|
|
6
|
-
# @sonordev/site-kit
|
|
6
|
+
# @sonordev/site-kit: integration skill
|
|
7
7
|
|
|
8
8
|
You are integrating a Next.js site with Sonor using `@sonordev/site-kit`. The
|
|
9
9
|
package ships its own machine-readable contract; use it instead of guessing.
|
|
@@ -16,7 +16,7 @@ package ships its own machine-readable contract; use it instead of guessing.
|
|
|
16
16
|
(`verify`, `doctor`, `codemod`, `manifest`, `init`, `install`, `upgrade`)
|
|
17
17
|
prints ONE JSON envelope to stdout. Parse it; branch on `exitCode`/`checks`.
|
|
18
18
|
3. **Never let a command prompt.** Pass `--yes` (and `--api-key` to `init`) so it
|
|
19
|
-
runs non-interactively. Exit `3` means you're missing a flag
|
|
19
|
+
runs non-interactively. Exit `3` means you're missing a flag; the error's
|
|
20
20
|
`fix` names it.
|
|
21
21
|
4. **One env var: `SONOR_API_KEY`** (server-side, no `NEXT_PUBLIC_` prefix). Never
|
|
22
22
|
add `UPTRADE_*`, `NEXT_PUBLIC_SONOR_API_KEY`, or `SONOR_PROJECT_ID`.
|
|
@@ -25,7 +25,7 @@ package ships its own machine-readable contract; use it instead of guessing.
|
|
|
25
25
|
anywhere below the fold; `./motion/gsap` and `./motion/three` need their
|
|
26
26
|
peer installed first (`npm i gsap` / `npm i three`). Never wrap page
|
|
27
27
|
content in a `dynamic(ssr:false)` component and never animate the hero
|
|
28
|
-
in
|
|
28
|
+
in; the server HTML must stay fully visible. See `src/motion/README.md`.
|
|
29
29
|
6. **The sticky mobile CTA bar comes from `@sonordev/site-kit/cta-bar`, never a
|
|
30
30
|
per-site `MobileCTABar`.** Render `<CtaBar>` once per page (the layout root
|
|
31
31
|
for a site-wide bar, inside the page for a page-specific one), with
|
|
@@ -33,8 +33,17 @@ package ships its own machine-readable contract; use it instead of guessing.
|
|
|
33
33
|
own bar, its body `padding-bottom`, and any `--sk-echo-offset-bottom` rule
|
|
34
34
|
written for it: the kit reserves the space and lifts the Echo launcher.
|
|
35
35
|
See `src/cta-bar/README.md`.
|
|
36
|
-
|
|
37
|
-
|
|
36
|
+
7. **Commerce, events and memberships come from `@sonordev/commerce-kit`, not
|
|
37
|
+
site-kit (since site-kit 8).** Install it beside site-kit with
|
|
38
|
+
`npm i @sonordev/commerce-kit` and import from
|
|
39
|
+
`@sonordev/commerce-kit/commerce`, `/commerce/server`, `/memberships` or
|
|
40
|
+
`/memberships/server`. The old site-kit commerce entries are gone, and
|
|
41
|
+
`npx sonor-setup manifest --json` lists every moved subpath under
|
|
42
|
+
`relocated`, the root types that moved under `relocatedTypes`, and what was
|
|
43
|
+
retired for good (Engage, the CMS, content blocks) under `removed`.
|
|
44
|
+
Docs: https://sonor.dev/commerce-kit.
|
|
45
|
+
|
|
46
|
+
## First step: discover, don't assume
|
|
38
47
|
|
|
39
48
|
```bash
|
|
40
49
|
cat node_modules/@sonordev/site-kit/AGENTS.md # human-skimmable guide
|
|
@@ -55,7 +64,7 @@ npx sonor-setup verify --json
|
|
|
55
64
|
|
|
56
65
|
```bash
|
|
57
66
|
npx sonor-setup codemod --check --json # exit 1 ⇒ work pending
|
|
58
|
-
npx sonor-setup codemod --write --json # apply (idempotent;
|
|
67
|
+
npx sonor-setup codemod --write --json # apply (idempotent; originals go to a temp folder). Review the diff.
|
|
59
68
|
next build # a bump you didn't build is a guess
|
|
60
69
|
npx sonor-setup verify --json
|
|
61
70
|
```
|
|
@@ -69,22 +78,43 @@ Codemod transforms: `provider-to-layout` (SiteKitProvider→SiteKitLayout),
|
|
|
69
78
|
(flags an `<AnalyticsProvider>` wrapped around `{children}`; remove it by hand.
|
|
70
79
|
A plain `<SiteKitLayout>{children}</SiteKitLayout>` is correct and isn't flagged).
|
|
71
80
|
|
|
81
|
+
## Move a 7.x site that sells to site-kit 8
|
|
82
|
+
|
|
83
|
+
Commerce left site-kit in 8.0 (memberships is new, and ships only in
|
|
84
|
+
commerce-kit). A site that doesn't use commerce needs nothing but the version bump.
|
|
85
|
+
|
|
86
|
+
```bash
|
|
87
|
+
npm i @sonordev/site-kit@^8 @sonordev/commerce-kit
|
|
88
|
+
npx sonor-setup codemod --only site-kit-8 --check --json # exit 1 ⇒ imports still to move
|
|
89
|
+
npx sonor-setup codemod --only site-kit-8 --write --json # swaps the package name in each import
|
|
90
|
+
next build
|
|
91
|
+
npx sonor-setup verify --json
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
It rewrites the imports, adds `@sonordev/commerce-kit` to package.json, raises
|
|
95
|
+
site-kit's range to `^8.0.0` and flags what it can't rewrite. A site that passes
|
|
96
|
+
`offerings` to `sonorMcpServer` also needs `read: getOfferingsResult`, imported from
|
|
97
|
+
`@sonordev/commerce-kit/commerce/server`. See `docs/MIGRATING-TO-8.md`.
|
|
98
|
+
|
|
72
99
|
## Debug a red integration
|
|
73
100
|
|
|
74
101
|
Run `npx sonor-setup doctor --online --json` (or `verify`). Each `checks[]`
|
|
75
102
|
finding has a stable `id`, a `fix`, and often a `fixCommand`. Highest-signal ids:
|
|
76
103
|
|
|
77
|
-
- `ssr.render
|
|
104
|
+
- `ssr.render`: page bailed to client rendering. On site-kit ≥3.0.2 a plain
|
|
78
105
|
`SiteKitLayout` is never the cause: it already mounts analytics as a
|
|
79
106
|
deferred, childless sibling, so don't reach for `analytics={false}`. Find
|
|
80
107
|
what else wraps `{children}` (usually a `next/dynamic({ ssr: false })`
|
|
81
108
|
component, often the site's own Providers) and import it statically or mount
|
|
82
109
|
it as a childless sibling. On <3.0.2, upgrade. Confirm with
|
|
83
110
|
`verify --url <url>`.
|
|
84
|
-
- `key.valid
|
|
111
|
+
- `key.valid`: key rejected/stale. Put the current `sonor_` key in `.env.local`
|
|
85
112
|
and redeploy (hosts don't pick up env changes without a redeploy).
|
|
86
|
-
- `middleware.netlify
|
|
113
|
+
- `middleware.netlify`: `middleware.ts` sets `runtime: 'nodejs'`, which
|
|
87
114
|
`proxy.ts` rejects. Remove the export, then run the codemod to move it.
|
|
88
|
-
- `layout.sitekit
|
|
115
|
+
- `layout.sitekit`: deprecated `SiteKitProvider`; run the codemod.
|
|
116
|
+
- A build that can't resolve a site-kit commerce path: the site is on site-kit 8,
|
|
117
|
+
where commerce moved to `@sonordev/commerce-kit`. Run the site-kit 8 steps
|
|
118
|
+
above.
|
|
89
119
|
|
|
90
120
|
Apply fixes, then re-run `verify --json`. Done when it exits 0.
|
package/src/analytics/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Analytics
|
|
1
|
+
# Analytics: `@sonordev/site-kit/analytics`
|
|
2
2
|
|
|
3
3
|
Automatic page view tracking, custom events, conversions, scroll depth, heatmap clicks, and Core Web Vitals. All data flows through the Sonor API.
|
|
4
4
|
|
|
@@ -157,22 +157,22 @@ interface AnalyticsConfig {
|
|
|
157
157
|
trackScrollDepth?: boolean // Default: true
|
|
158
158
|
sessionTimeout?: number // Minutes (default: 30)
|
|
159
159
|
excludePaths?: string[] // Don't track these paths
|
|
160
|
-
allowInFrame?: boolean // Default: false
|
|
161
|
-
allowLocalhost?: boolean // Default: false
|
|
160
|
+
allowInFrame?: boolean // Default: false (see below)
|
|
161
|
+
allowLocalhost?: boolean // Default: false (local builds report nothing)
|
|
162
162
|
debug?: boolean // Log events to console
|
|
163
163
|
}
|
|
164
164
|
```
|
|
165
165
|
|
|
166
166
|
## What Gets Tracked Automatically
|
|
167
167
|
|
|
168
|
-
- **Page views
|
|
169
|
-
- **Web Vitals
|
|
170
|
-
- **Contact clicks
|
|
171
|
-
- **DOM metadata
|
|
168
|
+
- **Page views**: on every route change (path, URL, title, referrer, UTM params, device/browser/OS)
|
|
169
|
+
- **Web Vitals**: LCP, CLS, TTFB, INP, FCP with good/needs-improvement/poor ratings
|
|
170
|
+
- **Contact clicks**: `tel:` and `mailto:` links tracked as conversions, once `<ContactTracking />` is mounted (it isn't by default)
|
|
171
|
+
- **DOM metadata**: full snapshot per page view (meta tags, H1, word count, links, content, FAQs)
|
|
172
172
|
|
|
173
173
|
## Embedded pages report nothing (`analytics.allowInFrame`)
|
|
174
174
|
|
|
175
|
-
When this site is loaded inside a **cross-origin iframe**, nothing is sent
|
|
175
|
+
When this site is loaded inside a **cross-origin iframe**, nothing is sent:
|
|
176
176
|
no page views, journey/session rows, scroll depth, heatmap clicks, web vitals,
|
|
177
177
|
events or conversions. The visitor is on whoever framed the page, not on this
|
|
178
178
|
site, so every metric the frame produces is phantom traffic in the analytics
|
|
@@ -189,8 +189,8 @@ the pixels, not the JavaScript.
|
|
|
189
189
|
a print view, an on-domain booking frame) has a real visitor really on that
|
|
190
190
|
site and no other tenant to pollute.
|
|
191
191
|
|
|
192
|
-
Opt back in only when the frame IS the product
|
|
193
|
-
page deliberately distributed as an embed:
|
|
192
|
+
Opt back in only when the frame IS the product (a widget or partner-hosted
|
|
193
|
+
page deliberately distributed as an embed):
|
|
194
194
|
|
|
195
195
|
```tsx
|
|
196
196
|
<SiteKitLayout analytics={{ allowInFrame: true }}>…</SiteKitLayout>
|
|
@@ -199,7 +199,7 @@ page deliberately distributed as an embed:
|
|
|
199
199
|
There is deliberately no env var or window global for this. A silent switch
|
|
200
200
|
that turns cross-tenant tracking back on is the failure mode, not the feature.
|
|
201
201
|
|
|
202
|
-
The decision lives in one place
|
|
202
|
+
The decision lives in one place, `shared/reporting-gate.ts`, over the frame
|
|
203
203
|
primitive in `shared/frame.ts`. Every send in the module routes through it, and
|
|
204
204
|
`send-gate.test.ts` fails the build if a new one does not. `isCrossOriginFrame()`
|
|
205
205
|
is exported from `@sonordev/site-kit/analytics` if a site needs the same answer
|
|
@@ -229,8 +229,8 @@ Neither option bypasses authentication. No environment variable or global
|
|
|
229
229
|
silently enables local reporting.
|
|
230
230
|
|
|
231
231
|
This is a browser gate: build-time `createSitemap` and Node fleet reporting
|
|
232
|
-
still run. It doesn't disable forms,
|
|
233
|
-
modules locally, point them at a test API as well.
|
|
232
|
+
still run. It doesn't disable forms, Signal, or [commerce-kit](https://sonor.dev/commerce-kit).
|
|
233
|
+
When verifying those modules locally, point them at a test API as well.
|
|
234
234
|
|
|
235
235
|
## Environment
|
|
236
236
|
|
|
@@ -257,6 +257,6 @@ site without forcing each microsite into its own Sonor project.
|
|
|
257
257
|
</SiteKitLayout>
|
|
258
258
|
```
|
|
259
259
|
|
|
260
|
-
Most projects leave it implicit
|
|
260
|
+
Most projects leave it implicit: `NEXT_PUBLIC_SITE_URL` is already set per
|
|
261
261
|
microsite, so the dimension fills in automatically. The dashboard shows a
|
|
262
262
|
"Site" picker + a "Sites" tab as soon as ≥2 distinct hosts are detected.
|
package/src/chat/README.md
CHANGED
|
@@ -46,7 +46,7 @@ interface SiteChatProps {
|
|
|
46
46
|
```
|
|
47
47
|
|
|
48
48
|
Through `SiteKitLayout`, the placement options go in `chat={{ ... }}`. The
|
|
49
|
-
deprecated `engage={{ ... }}` still works
|
|
49
|
+
deprecated `engage={{ ... }}` still works; it goes in a later major.
|
|
50
50
|
|
|
51
51
|
## The chat switch
|
|
52
52
|
|
|
@@ -233,10 +233,10 @@ interface ChatConfig {
|
|
|
233
233
|
Popups, banners and toasts are their own module now:
|
|
234
234
|
[Popups and banners](../website/README.md) (`@sonordev/site-kit/website/popups`).
|
|
235
235
|
|
|
236
|
-
##
|
|
236
|
+
## Engage (retired)
|
|
237
237
|
|
|
238
|
-
Engage was retired in Sonor
|
|
239
|
-
|
|
240
|
-
|
|
241
|
-
(`DesignRenderer`) is gone; popups render from blocks.
|
|
242
|
-
|
|
238
|
+
Engage was retired in Sonor, and `@sonordev/site-kit/engage` was removed in
|
|
239
|
+
site-kit 8. `ChatWidget` and the chat types are here, popups are in
|
|
240
|
+
`@sonordev/site-kit/website/popups`, and `SiteKitLayout` mounts both for you.
|
|
241
|
+
Engage Studio's renderer (`DesignRenderer`) is gone; popups render from blocks.
|
|
242
|
+
`npx sonor-setup codemod --write` moves the names that have a home.
|
package/src/forms/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# Forms
|
|
1
|
+
# Forms: `@sonordev/site-kit/forms`
|
|
2
2
|
|
|
3
3
|
Sonor-managed forms with multi-step support, conditional logic, validation, anti-bot protection, and automatic CRM routing.
|
|
4
4
|
|
|
@@ -21,7 +21,7 @@ Fetches form config from Sonor, renders fields, handles submission, routes to CR
|
|
|
21
21
|
Since 4.0 that one line gets you the **spotlight** experience by default: the
|
|
22
22
|
familiar layout, alive. A glowing ring visits the field you're in, completed
|
|
23
23
|
fields earn a check, and each finished row collapses into a sentence the form
|
|
24
|
-
says back
|
|
24
|
+
says back ("Nice to meet you, Jordan." or "We'll follow up at jordan@…"), with
|
|
25
25
|
an edit control to reopen it.
|
|
26
26
|
|
|
27
27
|
| Experience | What it is | How to get it |
|
|
@@ -36,7 +36,7 @@ an edit control to reopen it.
|
|
|
36
36
|
<ManagedForm formId="contact-form" experience="classic" /> // opt out
|
|
37
37
|
```
|
|
38
38
|
|
|
39
|
-
Sonor can decide instead of the site, with no deploy on either side
|
|
39
|
+
Sonor can decide instead of the site, with no deploy on either side: set the
|
|
40
40
|
form's `layout` to `classic`, `stage`, or `spotlight`. An explicit
|
|
41
41
|
`experience` prop always wins over the config.
|
|
42
42
|
|
|
@@ -68,7 +68,7 @@ Welcome aboard, {first_name}. We'll reach you at {email}.
|
|
|
68
68
|
```
|
|
69
69
|
|
|
70
70
|
Leave it empty to keep the built-in sentence. Unknown or unanswered tokens
|
|
71
|
-
render as nothing
|
|
71
|
+
render as nothing, never raw braces.
|
|
72
72
|
|
|
73
73
|
### Option 2: Headless Hook (full UI control)
|
|
74
74
|
|
|
@@ -101,6 +101,59 @@ export function ContactForm() {
|
|
|
101
101
|
}
|
|
102
102
|
```
|
|
103
103
|
|
|
104
|
+
#### Autocomplete on your own controls
|
|
105
|
+
|
|
106
|
+
`ManagedForm` puts the right `autocomplete` token on each field that has one, so
|
|
107
|
+
browser autofill, password managers and AI assistants know what the field wants.
|
|
108
|
+
When you draw the controls yourself, with `useForm` or the render prop below, ask
|
|
109
|
+
for the same token with `autocompleteFor` (since 8.0.0) and pass it to
|
|
110
|
+
`autoComplete`:
|
|
111
|
+
|
|
112
|
+
```tsx
|
|
113
|
+
'use client'
|
|
114
|
+
import { useForm, autocompleteFor } from '@sonordev/site-kit/forms'
|
|
115
|
+
|
|
116
|
+
export function QuoteForm() {
|
|
117
|
+
const { fields, values, setFieldValue, handleSubmit, toolAttributes } = useForm('quote-request')
|
|
118
|
+
|
|
119
|
+
return (
|
|
120
|
+
<form {...toolAttributes} onSubmit={handleSubmit}>
|
|
121
|
+
{fields.map(field => (
|
|
122
|
+
<label key={field.slug}>
|
|
123
|
+
{field.label}
|
|
124
|
+
<input
|
|
125
|
+
name={field.slug}
|
|
126
|
+
autoComplete={autocompleteFor(field)}
|
|
127
|
+
value={String(values[field.slug] || '')}
|
|
128
|
+
onChange={(e) => setFieldValue(field.slug, e.target.value)}
|
|
129
|
+
/>
|
|
130
|
+
</label>
|
|
131
|
+
))}
|
|
132
|
+
<button type="submit">Request a quote</button>
|
|
133
|
+
</form>
|
|
134
|
+
)
|
|
135
|
+
}
|
|
136
|
+
```
|
|
137
|
+
|
|
138
|
+
It returns a token such as `given-name`, `email`, `tel`, `organization` or
|
|
139
|
+
`postal-code`, or `undefined` when a field has no confident match, and React
|
|
140
|
+
leaves the attribute off for `undefined`. Only text, email and phone fields and
|
|
141
|
+
selects get a token, so a message box, a number, a date or a checkbox gets
|
|
142
|
+
`undefined`. To stay short, the example draws every field as a text input and
|
|
143
|
+
leaves out error messages and steps; draw each field with the control it calls
|
|
144
|
+
for and pass the same `autoComplete={autocompleteFor(field)}` to all of them.
|
|
145
|
+
|
|
146
|
+
Use it instead of typing tokens per field. It works the token out from the
|
|
147
|
+
field's type, slug and label, so your markup doesn't keep a list of its own that
|
|
148
|
+
can drift. `@sonordev/site-kit/forms` is a client module, like `useForm`, so call
|
|
149
|
+
`autocompleteFor` from a client component (a file that starts with
|
|
150
|
+
`'use client'`). Calling it in a Server Component fails the build.
|
|
151
|
+
|
|
152
|
+
To type a field you pass around, use `UseFormReturn['fields'][number]`, or
|
|
153
|
+
`AutocompleteField` for a helper that only needs the token. Don't use the
|
|
154
|
+
`FormField` this entry exports: that's the shape `formsApi` takes (camelCase keys
|
|
155
|
+
such as `fieldType`), not what `useForm` returns.
|
|
156
|
+
|
|
104
157
|
### Option 3: Render Prop
|
|
105
158
|
|
|
106
159
|
```tsx
|
|
@@ -228,7 +281,8 @@ nothing to configure.
|
|
|
228
281
|
fields carry the right `autocomplete` token (`given-name`, `email`, `tel`,
|
|
229
282
|
`organization`, `url`, `postal-code`, ...), read from the field's CRM
|
|
230
283
|
destination in Sonor, then its type, slug and label. Browser autofill and
|
|
231
|
-
password managers use the same tokens.
|
|
284
|
+
password managers use the same tokens. A headless form adds them with
|
|
285
|
+
`autocompleteFor` (see [Autocomplete on your own controls](#autocomplete-on-your-own-controls)).
|
|
232
286
|
- **Accessible wiring.** Error and help text are tied to their control
|
|
233
287
|
(`aria-describedby`), an errored control says so (`aria-invalid`), radio and
|
|
234
288
|
checkbox groups are named by their question, and rating stars by their
|
|
@@ -252,7 +306,8 @@ nothing to configure.
|
|
|
252
306
|
until the page can catch the click.
|
|
253
307
|
|
|
254
308
|
With `useForm`, spread `toolAttributes` on your `<form>` and use
|
|
255
|
-
`handleSubmit` as its `onSubmit` to get the
|
|
309
|
+
`handleSubmit` as its `onSubmit` to get the WebMCP behavior and the agent-sent
|
|
310
|
+
tag, and add `autocompleteFor` to your controls for the autofill tokens.
|
|
256
311
|
|
|
257
312
|
`ServerForm`'s `enhance` prop is ignored since 7.2.0. Only the interactive
|
|
258
313
|
form can send a managed form, so `enhance={false}` only ever produced a form
|
package/src/mcp/README.md
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
# `@sonordev/site-kit/mcp
|
|
1
|
+
# `@sonordev/site-kit/mcp`: WebMCP & Model Context Protocol
|
|
2
2
|
|
|
3
3
|
Make a marketing site something an AI agent can **use**, not just read.
|
|
4
4
|
|
|
@@ -8,12 +8,12 @@ definitions:
|
|
|
8
8
|
|
|
9
9
|
| Surface | Who uses it | Entry point |
|
|
10
10
|
|---|---|---|
|
|
11
|
-
| Remote MCP endpoint (Streamable HTTP) | Off-browser agents
|
|
11
|
+
| Remote MCP endpoint (Streamable HTTP) | Off-browser agents: Claude, Cursor, any MCP client | `createMcpHandler` |
|
|
12
12
|
| Server card and experimental AI catalog | Crawlers and clients discovering the endpoint | `createMcpServerCardHandler`, `createMcpAiCatalogHandler` |
|
|
13
13
|
| In-page WebMCP | Browser-driving agents | `<WebMcpTools>`, `declarativeToolForm` |
|
|
14
14
|
|
|
15
|
-
One definition feeding all three is the point. The alternative
|
|
16
|
-
the endpoint and a separate one for the page
|
|
15
|
+
One definition feeding all three is the point. The alternative, a tool list for
|
|
16
|
+
the endpoint and a separate one for the page, drifts, and a stale tool
|
|
17
17
|
definition is worse than none, because the agent believes it.
|
|
18
18
|
|
|
19
19
|
---
|
|
@@ -36,7 +36,7 @@ site's pages use, so an agent gets what a visitor gets.
|
|
|
36
36
|
| `find_pages` | The page that covers a topic |
|
|
37
37
|
| `list_articles`, `get_article` | Its articles (`articles: false` drops them) |
|
|
38
38
|
| `get_reviews` | Reviews verbatim, with who wrote them, and the rating |
|
|
39
|
-
| `list_offerings` | Priced products, services, events (opt-in: `offerings: { path }
|
|
39
|
+
| `list_offerings` | Priced products, services, events (opt-in: `offerings: { path, read }`, see below); private prices are left out |
|
|
40
40
|
| `check_availability` | Open appointment times, read only (opt-in: `booking: { path }`) |
|
|
41
41
|
| `get_inquiry_form`, `send_inquiry` | An inquiry for a person (opt-in: `inquiry: { form }`) |
|
|
42
42
|
|
|
@@ -63,6 +63,47 @@ export const { POST, GET, DELETE, OPTIONS } = createMcpHandler({
|
|
|
63
63
|
})
|
|
64
64
|
```
|
|
65
65
|
|
|
66
|
+
**`list_offerings` needs a reader (8.0).** The catalog it lists belongs to
|
|
67
|
+
[commerce-kit](https://sonor.dev/commerce-kit), so you hand the tool commerce-kit's
|
|
68
|
+
fetcher instead of site-kit importing it:
|
|
69
|
+
|
|
70
|
+
```ts
|
|
71
|
+
// lib/mcp.ts
|
|
72
|
+
import 'server-only'
|
|
73
|
+
import { sonorMcpServer } from '@sonordev/site-kit/mcp/sonor'
|
|
74
|
+
import { getOfferingsResult } from '@sonordev/commerce-kit/commerce/server'
|
|
75
|
+
|
|
76
|
+
export const mcpServer = sonorMcpServer({
|
|
77
|
+
businessName: 'Example Studio',
|
|
78
|
+
offerings: { path: '/shop', read: getOfferingsResult },
|
|
79
|
+
})
|
|
80
|
+
```
|
|
81
|
+
|
|
82
|
+
`read` is required and is `getOfferingsResult` from
|
|
83
|
+
`@sonordev/commerce-kit/commerce/server`, so the site needs commerce-kit installed
|
|
84
|
+
(`npm install @sonordev/commerce-kit`). When a request fails it tells the agent the
|
|
85
|
+
catalog is unavailable; the plain `getOfferings` from the same entry also works, but
|
|
86
|
+
it reads an outage as an empty catalog. The other tools, `list_services` included,
|
|
87
|
+
don't. `path` is where the offerings' pages live: each offering links to
|
|
88
|
+
`<path>/<slug>` on the site, and `path` defaults to `/shop`. An agent can narrow the
|
|
89
|
+
list with `type` (`product`, `service` or `event`), search it with `query`, and cap
|
|
90
|
+
it with `limit` (at most 20). The tool, how it ranks a query, and its rule that a
|
|
91
|
+
price the business keeps private is never shown all stay in site-kit.
|
|
92
|
+
|
|
93
|
+
`read` is typed `McpOfferingsReader`, and what it returns is a list of `McpOffering`s
|
|
94
|
+
(a name, type, slug, descriptions and a price), or `{ ok, data }` around that list. Both
|
|
95
|
+
types are exported from `@sonordev/site-kit/mcp/sonor`. commerce-kit's fetchers satisfy
|
|
96
|
+
them as they are, so you only meet the types if you supply the catalog from somewhere
|
|
97
|
+
else: write a function that takes `({ apiUrl, apiKey, projectId }, { type, limit })` and
|
|
98
|
+
returns the offerings, and answer `{ ok: false, data: [] }` when the request fails, so
|
|
99
|
+
the agent hears "unavailable" instead of "nothing for sale".
|
|
100
|
+
|
|
101
|
+
Without `read`, `sonorMcpServer` throws when the server is built, with a message that
|
|
102
|
+
names the fix. `npx sonor-setup mcp --offerings /shop` writes this wiring for a new
|
|
103
|
+
site, import included, and tells you to install commerce-kit. Before 8.0 the option
|
|
104
|
+
was `offerings: { path }`; see
|
|
105
|
+
[Moving a site to site-kit 8](../../docs/MIGRATING-TO-8.md#the-mcp-change).
|
|
106
|
+
|
|
66
107
|
**`send_inquiry` has a person behind it.** It refuses unless
|
|
67
108
|
`person_confirmed` is true (the person asked to be contacted and agreed to
|
|
68
109
|
share their details), files through Sonor's agent-inquiry door with the
|
|
@@ -205,7 +246,7 @@ aliases for clients that already use them. The card handler's default remains
|
|
|
205
246
|
### 4. Register in-page (optional, for browser agents)
|
|
206
247
|
|
|
207
248
|
```tsx
|
|
208
|
-
// app/layout.tsx
|
|
249
|
+
// app/layout.tsx: a CHILDLESS SIBLING, never a wrapper
|
|
209
250
|
<SiteKitLayout>{children}</SiteKitLayout>
|
|
210
251
|
<WebMcpTools endpoint="/api/mcp" />
|
|
211
252
|
```
|
|
@@ -290,13 +331,13 @@ The header and label default to `x-site-mcp-transport` and
|
|
|
290
331
|
`{ header, label }` to all three factories (for example
|
|
291
332
|
`x-example-mcp-transport` / `example-mcp-transport-v1`). This entry is Node
|
|
292
333
|
only and imports no `server-only`, so the plain-Node function can load it. It
|
|
293
|
-
|
|
334
|
+
isn't re-exported from `@sonordev/site-kit/mcp`, which stays runtime-neutral.
|
|
294
335
|
|
|
295
336
|
---
|
|
296
337
|
|
|
297
338
|
## Design notes
|
|
298
339
|
|
|
299
|
-
### The card
|
|
340
|
+
### The card doesn't list tools, on purpose
|
|
300
341
|
|
|
301
342
|
The card's discovery shape omits primitives: what a server exposes can
|
|
302
343
|
vary with auth state and configuration, so the authoritative list is whatever
|
|
@@ -306,8 +347,8 @@ source of truth that goes stale silently.
|
|
|
306
347
|
We still publish a **summary** (name + description + read-only flag) under
|
|
307
348
|
`_meta['io.sonor.site-kit/tools']`. `_meta` is the spec's sanctioned extension
|
|
308
349
|
point and requires a reverse-DNS prefix, so the hint rides along without
|
|
309
|
-
pretending to be standard
|
|
310
|
-
connect.
|
|
350
|
+
pretending to be standard. That's useful for crawlers that index the card and
|
|
351
|
+
never connect.
|
|
311
352
|
|
|
312
353
|
### Experimental discovery and compatibility paths
|
|
313
354
|
|
|
@@ -323,21 +364,21 @@ URLs working while adding the catalog.
|
|
|
323
364
|
|
|
324
365
|
`dispatch()` answers both protocol eras on one endpoint:
|
|
325
366
|
|
|
326
|
-
- **Modern (`2026-07-28`)
|
|
367
|
+
- **Modern (`2026-07-28`)**: stateless, per-request `_meta` carrying the
|
|
327
368
|
protocol version, mirrored into `MCP-Protocol-Version`. `server/discover`
|
|
328
369
|
replaces the handshake. No sessions, no GET stream (both return `405`).
|
|
329
|
-
- **Legacy (`≤ 2025-11-25`)
|
|
370
|
+
- **Legacy (`≤ 2025-11-25`)**: the `initialize` handshake, which is what most
|
|
330
371
|
shipped clients and SDKs still speak.
|
|
331
372
|
|
|
332
373
|
Supporting only the current revision would be spec-correct and unusable today.
|
|
333
374
|
|
|
334
|
-
### Header mirroring: mismatch is fatal, absence
|
|
375
|
+
### Header mirroring: mismatch is fatal, absence isn't
|
|
335
376
|
|
|
336
377
|
The modern revision mirrors `method` and `params.name` into `Mcp-Method` and
|
|
337
378
|
`Mcp-Name` so intermediaries can route without parsing bodies, and requires
|
|
338
379
|
servers to reject disagreements (`-32020`).
|
|
339
380
|
|
|
340
|
-
We always reject a **mismatch
|
|
381
|
+
We always reject a **mismatch**; that's the real security property, stopping
|
|
341
382
|
a load balancer and the server from acting on different values. A merely
|
|
342
383
|
**absent** header is tolerated unless you set `strictHeaders: true`, because a
|
|
343
384
|
public marketing endpoint exists to be reachable and today's clients frequently
|
|
@@ -360,13 +401,13 @@ one or the other makes you invisible to a large slice of the ecosystem.
|
|
|
360
401
|
|
|
361
402
|
`<WebMcpTools>` does nothing at all unless `document.modelContext` exists. That
|
|
362
403
|
gate comes before the `tools/list` fetch, so the cost for a human visitor is a
|
|
363
|
-
single property check
|
|
404
|
+
single property check: not a request, and not a byte of page weight.
|
|
364
405
|
|
|
365
406
|
### In-page tools are proxied, not re-implemented
|
|
366
407
|
|
|
367
408
|
`<WebMcpTools>` registers thin wrappers that POST `tools/call` to this site's
|
|
368
409
|
own endpoint, so the in-page tool and the remote tool run the same server-side
|
|
369
|
-
handler. It also keeps `SONOR_API_KEY` out of the client bundle
|
|
410
|
+
handler. It also keeps `SONOR_API_KEY` out of the client bundle: registering
|
|
370
411
|
real handlers client-side would pull server code, and the key with it, into a
|
|
371
412
|
`'use client'` graph and a public chunk.
|
|
372
413
|
|
|
@@ -376,13 +417,13 @@ Tools that genuinely need live DOM state go in `localTools` and run in-page.
|
|
|
376
417
|
|
|
377
418
|
`<WebMcpTools>` waits for the page to go quiet (`useDeferredActivation`) before
|
|
378
419
|
touching `document.modelContext`. Agents poll or listen for `toolchange`, so a
|
|
379
|
-
few hundred milliseconds costs nothing
|
|
420
|
+
few hundred milliseconds costs nothing, while a blocked LCP costs a lot.
|
|
380
421
|
|
|
381
422
|
---
|
|
382
423
|
|
|
383
424
|
## Writing good tools
|
|
384
425
|
|
|
385
|
-
The `description` is the highest-leverage field in this module. It
|
|
426
|
+
The `description` is the highest-leverage field in this module. It's the only
|
|
386
427
|
thing a model reads when deciding whether to call the tool.
|
|
387
428
|
|
|
388
429
|
- **Verb-led `snake_case` names**: `get_services`, `request_site_audit`.
|
|
@@ -391,10 +432,10 @@ thing a model reads when deciding whether to call the tool.
|
|
|
391
432
|
- **Set `annotations` honestly.** `readOnlyHint` on lookups; `destructiveHint`
|
|
392
433
|
on anything creating a record. Good agents use these to decide what needs a
|
|
393
434
|
human.
|
|
394
|
-
- **Never `toolautosubmit` a lead form.** That
|
|
435
|
+
- **Never `toolautosubmit` a lead form.** That's how an agent files fifty
|
|
395
436
|
audit requests by accident.
|
|
396
437
|
- **Return the caveat with the data.** A pricing tool should return the ranges
|
|
397
|
-
*and* the fact that they
|
|
438
|
+
*and* the fact that they're ranges; otherwise the model quotes a number as
|
|
398
439
|
a commitment.
|
|
399
440
|
|
|
400
441
|
## Testing an endpoint by hand
|