@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/src/proxy/README.md
CHANGED
|
@@ -2,10 +2,11 @@
|
|
|
2
2
|
|
|
3
3
|
Composable Next.js Proxy factory. Zero-config redirects + security headers. Opt-in AI discovery headers.
|
|
4
4
|
|
|
5
|
-
Next 16 renamed the `middleware` file convention to `proxy`.
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
5
|
+
Next 16 renamed the `middleware` file convention to `proxy`. This module is
|
|
6
|
+
also served on `@sonordev/site-kit/middleware`, with `createMiddleware` as an
|
|
7
|
+
alias of `createProxy`. Both are deprecated and still work in 8; they'll go in a
|
|
8
|
+
later major, so move off them when you next touch the file.
|
|
9
|
+
`npx sonor-setup codemod --write` moves a site over (the file too).
|
|
9
10
|
|
|
10
11
|
## Usage
|
|
11
12
|
|
package/src/revalidate/README.md
CHANGED
|
@@ -15,7 +15,7 @@ tells you when it's missing.
|
|
|
15
15
|
|
|
16
16
|
Everything site-kit fetches from Sonor is cached, and pages built from those
|
|
17
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),
|
|
18
|
+
(managed copy, a page's title or description, an article, a portfolio item, a product or event),
|
|
19
19
|
Sonor sends this route the paths and cache tags that changed. The route checks
|
|
20
20
|
the call was signed with your project's API key, then expires only those
|
|
21
21
|
pages and tags. The next visitor gets the new version, and every other page
|
|
@@ -60,7 +60,7 @@ A POST with `Authorization: Bearer <SONOR_API_KEY>` and a JSON body:
|
|
|
60
60
|
| Field | Meaning |
|
|
61
61
|
|---|---|
|
|
62
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 `
|
|
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`, `portfolio` and `commerce` (products, services, events and membership plans, from [commerce-kit](https://sonor.dev/commerce-kit)). |
|
|
64
64
|
| `revalidateAll` | Regenerate every page. |
|
|
65
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
66
|
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
# Runtime
|
|
2
|
+
|
|
3
|
+
`@sonordev/site-kit/runtime` is how a package that builds on site-kit talks to Sonor from the browser, so it never needs a transport of its own. [commerce-kit](https://sonor.dev/commerce-kit) is built on it.
|
|
4
|
+
|
|
5
|
+
Building a site? You don't need this entry. Forms, analytics, articles and the rest of site-kit already use the same transport.
|
|
6
|
+
|
|
7
|
+
## What it gives a kit
|
|
8
|
+
|
|
9
|
+
| Export | Use it to |
|
|
10
|
+
|---|---|
|
|
11
|
+
| `sonorFetch(url, init?, options?)` | Call the Sonor API from the browser. It sends the site credential you pass as `apiKey`, retries transient failures with a timeout, refreshes an expired site token once, and pauses for a few minutes after an authentication failure, so a misconfigured site doesn't hammer the API. |
|
|
12
|
+
| `getClientApiConfig(options?)` | Find the API origin and credential. In the browser that's what `SiteKitLayout` published. During server rendering it's the server's `SONOR_API_URL`, and with `{ serverKey: true }` its `SONOR_API_KEY`. |
|
|
13
|
+
| `readPublishedApiConfig()` | Exactly what `SiteKitLayout` published, with no fallbacks. For code that must stay quiet on a page without the layout. |
|
|
14
|
+
| `DEFAULT_SONOR_API_URL` | `https://api.sonor.io`. |
|
|
15
|
+
| `readAnalyticsIdentity()` | Get the visitor's analytics ids, `{ sessionId, visitorId }`, so what you send to Sonor ties to the visit analytics recorded. It only reads: either id is `null` during server rendering and before analytics has started a session in the tab. It never throws, including when the browser blocks site storage. |
|
|
16
|
+
|
|
17
|
+
The types `SonorFetchOptions`, `FetchRetryOptions`, `ClientApiConfigOptions` and `AnalyticsIdentity` come with them.
|
|
18
|
+
|
|
19
|
+
```ts
|
|
20
|
+
import { getClientApiConfig, sonorFetch } from '@sonordev/site-kit/runtime'
|
|
21
|
+
|
|
22
|
+
export async function startCheckout(payload: unknown) {
|
|
23
|
+
const { apiUrl, apiKey } = getClientApiConfig()
|
|
24
|
+
// Anything that isn't safe to repeat (checkout, payments, uploads) passes retries: 0.
|
|
25
|
+
const response = await sonorFetch(
|
|
26
|
+
`${apiUrl}/api/public/example/checkout`,
|
|
27
|
+
{ method: 'POST', headers: { 'Content-Type': 'application/json' }, body: JSON.stringify(payload) },
|
|
28
|
+
{ apiKey, retries: 0 },
|
|
29
|
+
)
|
|
30
|
+
return response.json()
|
|
31
|
+
}
|
|
32
|
+
```
|
|
33
|
+
|
|
34
|
+
Pass `apiKey` from `getClientApiConfig()` and `sonorFetch` sets the `x-api-key` header itself, using the site's freshest token when the site uses one. Don't set `x-api-key` or `Authorization` yourself: on a site that uses tokens, a stale header you set is replaced by the fresh one.
|
|
35
|
+
|
|
36
|
+
## Rules for kits
|
|
37
|
+
|
|
38
|
+
- **Use this entry for browser calls.** Don't read `window.__SITE_KIT_*` and don't call `fetch` on the Sonor API directly. A second transport is a second copy of the credential, retry and breaker logic, and it drifts.
|
|
39
|
+
- **Get the visitor's ids from `readAnalyticsIdentity()`.** Where site-kit keeps them is its own business and can change.
|
|
40
|
+
- **Server data goes through `@sonordev/site-kit/server`.** `serverApiFetch` sends the key, bounds each call in time and retries transient failures. Tag what you fetch with your content's entry in `SITE_CACHE_TAGS` so an edit in Sonor refreshes it, and if you catch errors around your own server calls, rethrow the ones `isNextControlFlow` recognizes: they're Next steering the render (a page turning dynamic, `redirect()`, `notFound()`), not failures.
|
|
41
|
+
- **Events go through `trackEvent` and `trackConversion`** from `@sonordev/site-kit/analytics` (`@sonordev/site-kit/client` exports them too). They wait for the analytics provider, which mounts after the page. Don't use the `useAnalytics` hooks in a kit: under `SiteKitLayout` your components sit outside the provider, so the hooks have nothing to return.
|
|
42
|
+
- **Lead capture goes through `ManagedForm`** from `@sonordev/site-kit/forms`.
|
|
43
|
+
- **List site-kit as a peer dependency** and mark it external in your bundler, so every kit shares the site's one copy.
|
|
44
|
+
|
|
45
|
+
## Why it's its own entry
|
|
46
|
+
|
|
47
|
+
`@sonordev/site-kit/client` is stamped `'use client'`. A function imported from a stamped module into a server component becomes a client reference there and can't be called, and `getClientApiConfig` is built to run during server rendering. So `runtime` isn't stamped, imports neither React nor Next, and works the same from a server component, a route handler or a client component.
|
|
48
|
+
|
|
49
|
+
## Stability
|
|
50
|
+
|
|
51
|
+
This entry is public API under semver. New exports arrive in minor releases; nothing in the list above is removed or changed in a minor or patch release.
|
package/src/seo/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# SEO: `@sonordev/site-kit/seo`
|
|
2
2
|
|
|
3
|
-
Server Components and server helpers that render what you manage in the SEO module at [app.sonor.io](https://app.sonor.io): page metadata, JSON-LD, FAQs, internal links,
|
|
3
|
+
Server Components and server helpers that render what you manage in the SEO module at [app.sonor.io](https://app.sonor.io): page metadata, JSON-LD, FAQs, internal links, redirects and robots directives.
|
|
4
4
|
|
|
5
5
|
The project comes from `SONOR_API_KEY`. Nothing in this module takes a project ID. A few option types and props still carry an optional `projectId` from older versions; it's ignored, so leave it out.
|
|
6
6
|
|
|
@@ -55,6 +55,7 @@ export async function generateMetadata({ params }: { params: Promise<{ slug: str
|
|
|
55
55
|
| `fallback` | `Metadata` | Fills any field Sonor has no managed value for. Used in full when the page isn't in Sonor at all. |
|
|
56
56
|
| `overrides` | `Partial<Metadata>` | Applied last, so it wins over managed values. |
|
|
57
57
|
| `favicon` | `'metadata' \| 'component'` | `'metadata'` (default) adds `icons` from the project logo. Pass `'component'` when your layout already renders the favicon, which `SiteKitLayout` does by default, so icons aren't emitted twice. |
|
|
58
|
+
| `scope` | `'page' \| 'layout'` | `'page'` (default) applies Sonor's managed canonical and hreflang for `path`. Pass `'layout'` when you call this from a root or shared layout, whose metadata every route beneath it inherits. See [Canonical URLs](#canonical-urls). |
|
|
58
59
|
|
|
59
60
|
It returns a Next.js `Metadata` object with two extra flags, `_managed` and `_source`. Managed fields map like this:
|
|
60
61
|
|
|
@@ -70,6 +71,27 @@ It returns a Next.js `Metadata` object with two extra flags, `_managed` and `_so
|
|
|
70
71
|
|
|
71
72
|
When the page exists in Sonor but has neither a title nor a description, the call asks Signal to write them in the background and returns your fallback for now. The generated copy shows up once the cached response refreshes (see [Caching](#caching)).
|
|
72
73
|
|
|
74
|
+
### Canonical URLs
|
|
75
|
+
|
|
76
|
+
Every page gets a canonical, so you never have to set one by hand. When Sonor has no `managed_canonical` for the page, `getManagedMetadata` returns `alternates.canonical: './'`. Next resolves that against your `metadataBase` and the route being rendered, so each page names itself (`https://example.com/about` for `/about`). Without a `metadataBase`, Next emits the path alone (`/about`), which is still valid. Set `metadataBase` in your root layout for absolute URLs.
|
|
77
|
+
|
|
78
|
+
The order, lowest to highest: the self-referencing default, then Sonor's managed canonical and hreflang, then your `fallback`, then your `overrides`. `alternates` merges key by key, so passing only `languages` keeps the canonical, and `canonical: null` opts out.
|
|
79
|
+
|
|
80
|
+
**Calling it from a layout.** A layout's metadata is inherited by every page under it. If your root layout calls `getManagedMetadata({ path: '/' })`, pass `scope: 'layout'`. Otherwise a managed canonical set for the homepage in Sonor is stamped on every page without its own, and each one tells search engines it's a copy of the homepage:
|
|
81
|
+
|
|
82
|
+
```tsx
|
|
83
|
+
// app/layout.tsx
|
|
84
|
+
export async function generateMetadata() {
|
|
85
|
+
return getManagedMetadata({
|
|
86
|
+
path: '/',
|
|
87
|
+
scope: 'layout',
|
|
88
|
+
fallback: { title: 'Example Co', description: 'Plumbing in Cincinnati.' },
|
|
89
|
+
})
|
|
90
|
+
}
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
Don't set an absolute `alternates.canonical` in a layout for the same reason. Use `'./'`, or leave it to this helper.
|
|
94
|
+
|
|
73
95
|
**Title templates.** The managed title comes back as a plain string, so a root-layout `title.template` still applies to it. If your managed titles already include the brand, you'll get it twice. Mark the title absolute:
|
|
74
96
|
|
|
75
97
|
```ts
|
|
@@ -100,7 +122,7 @@ export const generateMetadata = withManagedMetadata('/about', async () => ({
|
|
|
100
122
|
}))
|
|
101
123
|
```
|
|
102
124
|
|
|
103
|
-
Whatever `pageMetadata` returns wins over Sonor's values. `openGraph` and `
|
|
125
|
+
Whatever `pageMetadata` returns wins over Sonor's values. `openGraph`, `twitter` and `alternates` merge one level deep, so a page that returns only `alternates.languages` keeps its canonical. It calls `getManagedMetadata` with the default `favicon: 'metadata'`.
|
|
104
126
|
|
|
105
127
|
### A/B-tested titles and descriptions
|
|
106
128
|
|
|
@@ -221,10 +243,6 @@ Renders the internal links Sonor has for `path` at that position, or nothing whe
|
|
|
221
243
|
|
|
222
244
|
`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)).
|
|
223
245
|
|
|
224
|
-
## Content blocks: `<ManagedContent>` (deprecated)
|
|
225
|
-
|
|
226
|
-
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`.
|
|
227
|
-
|
|
228
246
|
## Multi-site projects
|
|
229
247
|
|
|
230
248
|
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.
|
|
@@ -235,7 +253,6 @@ The host resolves from `NEXT_PUBLIC_SITE_URL`, which every microsite already set
|
|
|
235
253
|
<ManagedFAQ path="/contact" site="charlotte.example.com" />
|
|
236
254
|
await getFAQData('/contact', 'charlotte.example.com')
|
|
237
255
|
await getInternalLinks('/contact', { position: 'bottom', site: 'charlotte.example.com' })
|
|
238
|
-
await getContentBlock('/contact', 'hero', 'charlotte.example.com')
|
|
239
256
|
```
|
|
240
257
|
|
|
241
258
|
When no host resolves, `site` is left off and the API answers for the project's primary domain. Single-site projects and older API servers ignore it.
|
|
@@ -288,7 +305,6 @@ Every component above is built on these. They're server-only, take paths rather
|
|
|
288
305
|
| `getSchemaMarkups(path, { includeTypes?, excludeTypes? })` | Schema rows (`schema_type`, `schema_json`, ...). `excludeTypes` also prunes matching nodes inside each row. |
|
|
289
306
|
| `getFAQData(path, site?)` | The FAQ (`title`, `description`, `items`, `include_schema`), or `null` |
|
|
290
307
|
| `getInternalLinks(path, { position?, limit?, site? })` | Link rows |
|
|
291
|
-
| `getContentBlock(path, section, site?)` | The content block, or `null` |
|
|
292
308
|
| `getABTest(path, field)` | The running test for that field, or `null` |
|
|
293
309
|
| `recordABImpression(testId, variant, sessionId?)` | `void` |
|
|
294
310
|
| `getRedirectData(path)` | The raw redirect row, or `null` |
|
package/src/sync/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
# Sync (Booking)
|
|
1
|
+
# Sync (Booking): `@sonordev/site-kit/sync`
|
|
2
2
|
|
|
3
|
-
Embeddable booking/scheduling widget
|
|
3
|
+
Embeddable booking/scheduling widget, like Calendly, built into Sonor. Appointments, consultations, classes.
|
|
4
4
|
|
|
5
5
|
## Usage
|
|
6
6
|
|
package/src/website/README.md
CHANGED
|
@@ -129,5 +129,6 @@ import { PopupBlocks } from '@sonordev/site-kit/website/popups'
|
|
|
129
129
|
Engage was retired in Sonor, and its popups with it. Popups made in Engage
|
|
130
130
|
Studio (a `design_json` without blocks) aren't drawn by site-kit 7.2 or later;
|
|
131
131
|
make them again in Website → Popups & Banners. `@sonordev/site-kit/engage`
|
|
132
|
-
|
|
133
|
-
|
|
132
|
+
was removed in site-kit 8: `SiteKitLayout` mounts `SitePopups` and the website
|
|
133
|
+
chat for you, and `npx sonor-setup codemod --write` moves the names that have
|
|
134
|
+
a home.
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { AnalyticsProvider, useAnalytics, useAnalyticsOptional, useTrackEvent } from './chunk-CKW4HFJG.js';
|
|
2
|
-
import './chunk-LCDVPAMR.js';
|
|
3
|
-
import './chunk-24QZEO3Q.js';
|
|
4
|
-
import './chunk-L2V5PUFN.js';
|
|
5
|
-
import './chunk-GJWI74ZZ.js';
|
|
6
|
-
import './chunk-43OCZ3JA.js';
|
|
7
|
-
import './chunk-EKBEOXTH.js';
|
|
8
|
-
import './chunk-3E3PPSNR.js';
|
|
9
|
-
import './chunk-GK7TV7EK.js';
|
|
10
|
-
import './chunk-KHQ5GD6T.js';
|
|
11
|
-
import './chunk-PKBMQBKP.js';
|
|
@@ -1,16 +0,0 @@
|
|
|
1
|
-
export { ManagedForm } from './chunk-MDP7EB4J.js';
|
|
2
|
-
import './chunk-ATE6IFVK.js';
|
|
3
|
-
import './chunk-DXO6SBMD.js';
|
|
4
|
-
import './chunk-4NTBQNHA.js';
|
|
5
|
-
import './chunk-CSN45MHO.js';
|
|
6
|
-
import './chunk-Q6E4OPGG.js';
|
|
7
|
-
import './chunk-C2FZBUSS.js';
|
|
8
|
-
import './chunk-5SQK3D53.js';
|
|
9
|
-
import './chunk-HW7B43E5.js';
|
|
10
|
-
import './chunk-NJCTQH2P.js';
|
|
11
|
-
import './chunk-L2V5PUFN.js';
|
|
12
|
-
import './chunk-GJWI74ZZ.js';
|
|
13
|
-
import './chunk-3E3PPSNR.js';
|
|
14
|
-
import './chunk-GK7TV7EK.js';
|
|
15
|
-
import './chunk-KHQ5GD6T.js';
|
|
16
|
-
import './chunk-PKBMQBKP.js';
|
|
@@ -1,11 +0,0 @@
|
|
|
1
|
-
export { SiteDesignReporter } from './chunk-PQDJNIHR.js';
|
|
2
|
-
import './chunk-CG4ETW5Y.js';
|
|
3
|
-
import './chunk-IHG36STL.js';
|
|
4
|
-
import './chunk-YC7ELZS3.js';
|
|
5
|
-
import './chunk-S22FSH7C.js';
|
|
6
|
-
import './chunk-43OCZ3JA.js';
|
|
7
|
-
import './chunk-EKBEOXTH.js';
|
|
8
|
-
import './chunk-3E3PPSNR.js';
|
|
9
|
-
import './chunk-GK7TV7EK.js';
|
|
10
|
-
import './chunk-KHQ5GD6T.js';
|
|
11
|
-
import './chunk-PKBMQBKP.js';
|
|
@@ -1,10 +0,0 @@
|
|
|
1
|
-
export { SitePopups } from './chunk-6LLTLLEJ.js';
|
|
2
|
-
import './chunk-27FISYK4.js';
|
|
3
|
-
import './chunk-24QZEO3Q.js';
|
|
4
|
-
import './chunk-GJWI74ZZ.js';
|
|
5
|
-
import './chunk-43OCZ3JA.js';
|
|
6
|
-
import './chunk-EKBEOXTH.js';
|
|
7
|
-
import './chunk-3E3PPSNR.js';
|
|
8
|
-
import './chunk-GK7TV7EK.js';
|
|
9
|
-
import './chunk-KHQ5GD6T.js';
|
|
10
|
-
import './chunk-PKBMQBKP.js';
|
|
@@ -1,8 +0,0 @@
|
|
|
1
|
-
export { SitemapSync } from './chunk-D2RGEWHS.js';
|
|
2
|
-
import './chunk-YVKRYQRG.js';
|
|
3
|
-
import './chunk-43OCZ3JA.js';
|
|
4
|
-
import './chunk-EKBEOXTH.js';
|
|
5
|
-
import './chunk-3E3PPSNR.js';
|
|
6
|
-
import './chunk-GK7TV7EK.js';
|
|
7
|
-
import './chunk-KHQ5GD6T.js';
|
|
8
|
-
import './chunk-PKBMQBKP.js';
|
package/dist/chunk-24QZEO3Q.js
DELETED
|
@@ -1,41 +0,0 @@
|
|
|
1
|
-
'use client';
|
|
2
|
-
import { uuid } from './chunk-GJWI74ZZ.js';
|
|
3
|
-
import { useState } from 'react';
|
|
4
|
-
|
|
5
|
-
function getOrCreateVisitorId() {
|
|
6
|
-
if (typeof window === "undefined") return "";
|
|
7
|
-
let visitorId = localStorage.getItem("_sk_vid");
|
|
8
|
-
if (!visitorId) {
|
|
9
|
-
visitorId = uuid();
|
|
10
|
-
}
|
|
11
|
-
localStorage.setItem("_sk_vid", visitorId);
|
|
12
|
-
return visitorId;
|
|
13
|
-
}
|
|
14
|
-
function getOrCreateSessionId(timeoutMinutes = 30) {
|
|
15
|
-
if (typeof window === "undefined") return "";
|
|
16
|
-
const now = Date.now();
|
|
17
|
-
const timeoutMs = timeoutMinutes * 60 * 1e3;
|
|
18
|
-
const existingSession = sessionStorage.getItem("_sk_sid");
|
|
19
|
-
const lastActivity = sessionStorage.getItem("_sk_stime");
|
|
20
|
-
if (existingSession && lastActivity) {
|
|
21
|
-
const elapsed = now - parseInt(lastActivity, 10);
|
|
22
|
-
if (elapsed < timeoutMs) {
|
|
23
|
-
sessionStorage.setItem("_sk_stime", now.toString());
|
|
24
|
-
sessionStorage.setItem("_sk_sid", existingSession);
|
|
25
|
-
return existingSession;
|
|
26
|
-
}
|
|
27
|
-
}
|
|
28
|
-
const newSession = uuid();
|
|
29
|
-
sessionStorage.setItem("_sk_sid", newSession);
|
|
30
|
-
sessionStorage.setItem("_sk_stime", now.toString());
|
|
31
|
-
return newSession;
|
|
32
|
-
}
|
|
33
|
-
function useSiteKitIdentity() {
|
|
34
|
-
const [identity] = useState(() => ({
|
|
35
|
-
visitorId: getOrCreateVisitorId(),
|
|
36
|
-
sessionId: getOrCreateSessionId()
|
|
37
|
-
}));
|
|
38
|
-
return identity;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
export { getOrCreateSessionId, getOrCreateVisitorId, useSiteKitIdentity };
|
package/dist/chunk-BU66S5B7.js
DELETED
|
@@ -1 +0,0 @@
|
|
|
1
|
-
|
package/dist/chunk-G3NHWMP5.js
DELETED
|
@@ -1,233 +0,0 @@
|
|
|
1
|
-
// src/commerce/server.ts
|
|
2
|
-
function isFrameworkSignal(err) {
|
|
3
|
-
const digest = err?.digest;
|
|
4
|
-
return typeof digest === "string" && (digest === "DYNAMIC_SERVER_USAGE" || digest.startsWith("NEXT_"));
|
|
5
|
-
}
|
|
6
|
-
async function apiFetch(config, endpoint) {
|
|
7
|
-
try {
|
|
8
|
-
const response = await fetch(`${config.apiUrl}${endpoint}`, {
|
|
9
|
-
headers: {
|
|
10
|
-
"X-API-Key": config.apiKey,
|
|
11
|
-
"X-Project-ID": config.projectId,
|
|
12
|
-
"Content-Type": "application/json"
|
|
13
|
-
}
|
|
14
|
-
});
|
|
15
|
-
if (!response.ok) {
|
|
16
|
-
console.error(`[site-kit/commerce] GET ${endpoint} failed: ${response.status}`);
|
|
17
|
-
return { ok: false, data: null };
|
|
18
|
-
}
|
|
19
|
-
return { ok: true, data: await response.json() };
|
|
20
|
-
} catch (error) {
|
|
21
|
-
if (isFrameworkSignal(error)) throw error;
|
|
22
|
-
console.error(`[site-kit/commerce] GET ${endpoint} failed:`, error);
|
|
23
|
-
return { ok: false, data: null };
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
async function apiPost(config, endpoint, body) {
|
|
27
|
-
try {
|
|
28
|
-
const response = await fetch(`${config.apiUrl}${endpoint}`, {
|
|
29
|
-
method: "POST",
|
|
30
|
-
headers: {
|
|
31
|
-
"X-API-Key": config.apiKey,
|
|
32
|
-
"X-Project-ID": config.projectId,
|
|
33
|
-
"Content-Type": "application/json"
|
|
34
|
-
},
|
|
35
|
-
body: JSON.stringify(body)
|
|
36
|
-
});
|
|
37
|
-
if (!response.ok) {
|
|
38
|
-
console.error(`[site-kit/commerce] POST ${endpoint} failed: ${response.status}`);
|
|
39
|
-
return { ok: false, data: null };
|
|
40
|
-
}
|
|
41
|
-
return { ok: true, data: await response.json() };
|
|
42
|
-
} catch (error) {
|
|
43
|
-
if (isFrameworkSignal(error)) throw error;
|
|
44
|
-
console.error(`[site-kit/commerce] POST ${endpoint} failed:`, error);
|
|
45
|
-
return { ok: false, data: null };
|
|
46
|
-
}
|
|
47
|
-
}
|
|
48
|
-
function transformOffering(data) {
|
|
49
|
-
return {
|
|
50
|
-
id: data.id,
|
|
51
|
-
project_id: data.project_id,
|
|
52
|
-
type: data.type,
|
|
53
|
-
status: data.status,
|
|
54
|
-
name: data.name,
|
|
55
|
-
slug: data.slug,
|
|
56
|
-
description: data.description,
|
|
57
|
-
short_description: data.short_description,
|
|
58
|
-
long_description: data.long_description,
|
|
59
|
-
featured_image_url: data.featured_image_url,
|
|
60
|
-
gallery_images: data.gallery_image_urls || [],
|
|
61
|
-
price_type: data.price_type || "fixed",
|
|
62
|
-
price: data.price,
|
|
63
|
-
compare_at_price: data.compare_at_price,
|
|
64
|
-
currency: data.currency || "USD",
|
|
65
|
-
price_is_public: data.price_is_public ?? true,
|
|
66
|
-
billing_period: data.billing_period,
|
|
67
|
-
track_inventory: data.track_inventory,
|
|
68
|
-
inventory_count: data.inventory_count,
|
|
69
|
-
allow_backorder: data.allow_backorder,
|
|
70
|
-
duration_minutes: data.duration_minutes,
|
|
71
|
-
capacity: data.capacity,
|
|
72
|
-
location: data.location,
|
|
73
|
-
is_virtual: data.is_virtual,
|
|
74
|
-
virtual_meeting_url: data.virtual_meeting_url,
|
|
75
|
-
requires_booking: data.requires_booking,
|
|
76
|
-
booking_lead_time_hours: data.booking_lead_time_hours,
|
|
77
|
-
category: data.category,
|
|
78
|
-
category_id: data.category_id,
|
|
79
|
-
tags: data.tags || [],
|
|
80
|
-
seo_title: data.seo_title,
|
|
81
|
-
seo_description: data.seo_description,
|
|
82
|
-
features: data.features || [],
|
|
83
|
-
specifications: data.specifications || {},
|
|
84
|
-
schedules: data.schedules || [],
|
|
85
|
-
variants: data.variants || [],
|
|
86
|
-
created_at: data.created_at,
|
|
87
|
-
updated_at: data.updated_at
|
|
88
|
-
};
|
|
89
|
-
}
|
|
90
|
-
async function getProductPaths(config) {
|
|
91
|
-
const { ok, data } = await apiFetch(
|
|
92
|
-
config,
|
|
93
|
-
`/api/public/commerce/offerings?type=product&status=active&fields=slug`
|
|
94
|
-
);
|
|
95
|
-
if (!ok) console.error("[site-kit/commerce] getProductPaths failed \u2014 0 product pages will be prerendered");
|
|
96
|
-
if (!data?.offerings) return [];
|
|
97
|
-
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
98
|
-
}
|
|
99
|
-
async function getEventPaths(config) {
|
|
100
|
-
const { ok, data } = await apiFetch(
|
|
101
|
-
config,
|
|
102
|
-
`/api/public/commerce/offerings?type=event&status=active&fields=slug`
|
|
103
|
-
);
|
|
104
|
-
if (!ok) console.error("[site-kit/commerce] getEventPaths failed \u2014 0 event pages will be prerendered");
|
|
105
|
-
if (!data?.offerings) return [];
|
|
106
|
-
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
107
|
-
}
|
|
108
|
-
async function getOfferingPaths(config, type) {
|
|
109
|
-
let typeParam = "";
|
|
110
|
-
if (type) {
|
|
111
|
-
if (Array.isArray(type)) {
|
|
112
|
-
typeParam = `&type=${type.join(",")}`;
|
|
113
|
-
} else {
|
|
114
|
-
typeParam = `&type=${type}`;
|
|
115
|
-
}
|
|
116
|
-
}
|
|
117
|
-
const { ok, data } = await apiFetch(
|
|
118
|
-
config,
|
|
119
|
-
`/api/public/commerce/offerings?status=active&fields=slug${typeParam}`
|
|
120
|
-
);
|
|
121
|
-
if (!ok) console.error("[site-kit/commerce] getOfferingPaths failed \u2014 0 pages will be prerendered");
|
|
122
|
-
if (!data?.offerings) return [];
|
|
123
|
-
return data.offerings.map((item) => ({ params: { slug: item.slug } }));
|
|
124
|
-
}
|
|
125
|
-
async function getOfferingBySlug(config, slug) {
|
|
126
|
-
return (await getOfferingBySlugResult(config, slug)).data;
|
|
127
|
-
}
|
|
128
|
-
async function getOfferingBySlugResult(config, slug) {
|
|
129
|
-
const { ok, data } = await apiFetch(
|
|
130
|
-
config,
|
|
131
|
-
`/api/public/commerce/offerings/${slug}`
|
|
132
|
-
);
|
|
133
|
-
if (!data?.offering) return { ok, data: null };
|
|
134
|
-
return { ok: true, data: transformOffering(data.offering) };
|
|
135
|
-
}
|
|
136
|
-
async function getOfferings(config, options = {}) {
|
|
137
|
-
return (await getOfferingsResult(config, options)).data;
|
|
138
|
-
}
|
|
139
|
-
async function getOfferingsResult(config, options = {}) {
|
|
140
|
-
const params = new URLSearchParams();
|
|
141
|
-
params.set("status", options.status || "active");
|
|
142
|
-
if (options.type) {
|
|
143
|
-
if (Array.isArray(options.type)) {
|
|
144
|
-
params.set("type", options.type.join(","));
|
|
145
|
-
} else {
|
|
146
|
-
params.set("type", options.type);
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
if (options.category) {
|
|
150
|
-
params.set("category", options.category);
|
|
151
|
-
}
|
|
152
|
-
if (options.limit) {
|
|
153
|
-
params.set("limit", options.limit.toString());
|
|
154
|
-
}
|
|
155
|
-
const { ok, data } = await apiFetch(
|
|
156
|
-
config,
|
|
157
|
-
`/api/public/commerce/offerings?${params.toString()}`
|
|
158
|
-
);
|
|
159
|
-
if (!data?.offerings) return { ok, data: [] };
|
|
160
|
-
return { ok: true, data: data.offerings.map(transformOffering) };
|
|
161
|
-
}
|
|
162
|
-
async function getUpcomingEvents(config, options = {}) {
|
|
163
|
-
return (await getUpcomingEventsResult(config, options)).data;
|
|
164
|
-
}
|
|
165
|
-
async function getUpcomingEventsResult(config, options = {}) {
|
|
166
|
-
const primary = await apiPost(
|
|
167
|
-
config,
|
|
168
|
-
"/api/public/commerce/events",
|
|
169
|
-
{
|
|
170
|
-
type: "event",
|
|
171
|
-
category: options.category,
|
|
172
|
-
limit: options.limit,
|
|
173
|
-
includePast: false
|
|
174
|
-
}
|
|
175
|
-
);
|
|
176
|
-
if (primary.ok && primary.data?.events) {
|
|
177
|
-
return { ok: true, data: primary.data.events.map(transformOffering) };
|
|
178
|
-
}
|
|
179
|
-
const params = new URLSearchParams();
|
|
180
|
-
params.set("type", "event");
|
|
181
|
-
params.set("status", "active");
|
|
182
|
-
params.set("upcoming", "true");
|
|
183
|
-
if (options.category) {
|
|
184
|
-
params.set("category", options.category);
|
|
185
|
-
}
|
|
186
|
-
if (options.limit) {
|
|
187
|
-
params.set("limit", options.limit.toString());
|
|
188
|
-
}
|
|
189
|
-
const legacy = await apiFetch(
|
|
190
|
-
config,
|
|
191
|
-
`/api/public/commerce/offerings?${params.toString()}`
|
|
192
|
-
);
|
|
193
|
-
if (legacy.ok && legacy.data?.offerings) {
|
|
194
|
-
return { ok: true, data: legacy.data.offerings.map(transformOffering) };
|
|
195
|
-
}
|
|
196
|
-
return { ok: primary.ok || legacy.ok, data: [] };
|
|
197
|
-
}
|
|
198
|
-
async function getNextEvent(config, category) {
|
|
199
|
-
return (await getNextEventResult(config, category)).data;
|
|
200
|
-
}
|
|
201
|
-
async function getNextEventResult(config, category) {
|
|
202
|
-
const { ok, data } = await getUpcomingEventsResult(config, { limit: 1, category });
|
|
203
|
-
return { ok, data: data[0] || null };
|
|
204
|
-
}
|
|
205
|
-
function generateOfferingMetadata(offering, siteUrl) {
|
|
206
|
-
if (!offering) return null;
|
|
207
|
-
const title = offering.seo_title || offering.name;
|
|
208
|
-
const description = offering.seo_description || offering.short_description || offering.description || "";
|
|
209
|
-
const images = offering.featured_image_url ? [offering.featured_image_url] : [];
|
|
210
|
-
const typeMap = {
|
|
211
|
-
product: "product",
|
|
212
|
-
service: "website",
|
|
213
|
-
event: "website",
|
|
214
|
-
class: "website",
|
|
215
|
-
subscription: "product"
|
|
216
|
-
};
|
|
217
|
-
return {
|
|
218
|
-
title,
|
|
219
|
-
description,
|
|
220
|
-
openGraph: {
|
|
221
|
-
title,
|
|
222
|
-
description,
|
|
223
|
-
images,
|
|
224
|
-
type: typeMap[offering.type] || "website",
|
|
225
|
-
url: `${siteUrl}/${offering.type}s/${offering.slug}`
|
|
226
|
-
}
|
|
227
|
-
};
|
|
228
|
-
}
|
|
229
|
-
function createServerConfig(apiUrl, apiKey, projectId) {
|
|
230
|
-
return { apiUrl, apiKey, projectId };
|
|
231
|
-
}
|
|
232
|
-
|
|
233
|
-
export { createServerConfig, generateOfferingMetadata, getEventPaths, getNextEvent, getNextEventResult, getOfferingBySlug, getOfferingBySlugResult, getOfferingPaths, getOfferings, getOfferingsResult, getProductPaths, getUpcomingEvents, getUpcomingEventsResult };
|
package/dist/chunk-HODO5BX5.js
DELETED
|
@@ -1,28 +0,0 @@
|
|
|
1
|
-
// src/chat/echo-config.ts
|
|
2
|
-
var SONOR_PUBLIC_ECHO_DEFAULTS = {
|
|
3
|
-
signalUrl: "https://signal.sonor.io",
|
|
4
|
-
welcomeMessage: "Hi! I'm Echo, Sonor's AI assistant. I can answer questions about our platform, help you understand pricing, or get you started with a demo. What would you like to know?",
|
|
5
|
-
suggestedQuestions: [
|
|
6
|
-
"What does Sonor do?",
|
|
7
|
-
"How does Signal AI work?",
|
|
8
|
-
"What are the pricing plans?",
|
|
9
|
-
"Can I migrate from HubSpot?",
|
|
10
|
-
"How does the SEO module work?"
|
|
11
|
-
],
|
|
12
|
-
brandColor: "#2563eb",
|
|
13
|
-
// blue-600 (~5.2:1 on white, AA); overridden by --sk-primary CSS var or API brand_primary
|
|
14
|
-
assistantName: "Echo"
|
|
15
|
-
};
|
|
16
|
-
function getEchoWidgetProps(config = SONOR_PUBLIC_ECHO_DEFAULTS) {
|
|
17
|
-
return {
|
|
18
|
-
signal_enabled: true,
|
|
19
|
-
signal_url: config.signalUrl || SONOR_PUBLIC_ECHO_DEFAULTS.signalUrl,
|
|
20
|
-
welcome_message: config.welcomeMessage || SONOR_PUBLIC_ECHO_DEFAULTS.welcomeMessage,
|
|
21
|
-
suggested_questions: config.suggestedQuestions || SONOR_PUBLIC_ECHO_DEFAULTS.suggestedQuestions,
|
|
22
|
-
brand_color: config.brandColor || SONOR_PUBLIC_ECHO_DEFAULTS.brandColor,
|
|
23
|
-
assistant_name: config.assistantName || SONOR_PUBLIC_ECHO_DEFAULTS.assistantName,
|
|
24
|
-
assistant_avatar: config.assistantAvatar
|
|
25
|
-
};
|
|
26
|
-
}
|
|
27
|
-
|
|
28
|
-
export { SONOR_PUBLIC_ECHO_DEFAULTS, getEchoWidgetProps };
|