@sonordev/site-kit 7.1.2 → 7.3.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 +1 -1
- package/CHANGELOG.md +60 -0
- package/README.md +9 -8
- package/agent-manifest.json +17 -7
- package/dist/{AnalyticsProvider-ZB33W6MC.js → AnalyticsProvider-DJQA66AG.js} +4 -4
- package/dist/{ArticleViewTracker-GMHYLLLZ.js → ArticleViewTracker-GFOAXFV7.js} +3 -3
- package/dist/{BlocksPopup-EA6LYL25.js → BlocksPopup-AHDU34TL.js} +5 -5
- package/dist/ChatWidget-FHBAHFZX.js +17 -0
- package/dist/{FileField-QKA3JB2Q.js → FileField-J5W5MIAZ.js} +3 -3
- package/dist/{FormSpotlight-AQTIA5TP.js → FormSpotlight-PE5YZBFZ.js} +20 -6
- package/dist/{FormStage-FDTLTP3B.js → FormStage-OOPQC27J.js} +27 -7
- package/dist/ManagedForm-JRZAJ7SZ.js +16 -0
- package/dist/{ManagedNewsletterForm-J6QSAGGP.js → ManagedNewsletterForm-TC5542ZG.js} +7 -5
- package/dist/{SignalCore-JZNXOLNT.js → SignalCore-2YP5FCAS.js} +3 -3
- package/dist/SiteChat-EGEZJJVV.js +5 -0
- package/dist/{SiteDesignReporter-W4EJUSTE.js → SiteDesignReporter-YEEWJKWN.js} +5 -5
- package/dist/SitePopups-LQBIXIFV.js +10 -0
- package/dist/SitemapSync-LSZ2EYOF.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/analytics/send-gate.d.ts +1 -1
- package/dist/articles/index.js +2 -2
- package/dist/articles/server-ui.js +3 -2
- package/dist/articles/server.js +2 -1
- package/dist/{engage → chat}/ChatWidget.d.ts +7 -6
- package/dist/{engage → chat}/EchoUiActions.d.ts +1 -1
- package/dist/chat/SiteChat.d.ts +25 -0
- package/dist/{engage → chat}/brand-color.d.ts +1 -1
- package/dist/{engage → chat}/chat-messages.d.ts +1 -1
- package/dist/{engage → chat}/echo-config.d.ts +1 -1
- package/dist/chat/index.d.ts +10 -6
- package/dist/chat/index.js +14 -8
- package/dist/{engage → chat}/launcher-placement.d.ts +1 -7
- package/dist/{engage → chat}/socket-loader.d.ts +2 -2
- package/dist/chat/types.d.ts +136 -0
- package/dist/chunk-27FISYK4.js +4 -0
- package/dist/{chunk-HF57LG73.js → chunk-2AD3CDRR.js} +43 -29
- package/dist/{chunk-M3YEPKP7.js → chunk-2ECWEUHP.js} +1 -1
- package/dist/{chunk-LUXVWITO.js → chunk-4NTBQNHA.js} +247 -78
- package/dist/{chunk-AH5Q262S.js → chunk-56KNHB4U.js} +1 -1
- package/dist/{chunk-GLHQ3LRO.js → chunk-6U3VLV2C.js} +1 -1
- package/dist/{chunk-3SDOQUUF.js → chunk-BEBR4OJD.js} +2 -2
- package/dist/{chunk-JSZN6LDZ.js → chunk-BF7TZYC3.js} +38 -31
- package/dist/{chunk-AQSNPZY4.js → chunk-C2FZBUSS.js} +80 -1
- package/dist/{chunk-PHYMNUJU.js → chunk-CYUFBKJQ.js} +1 -1
- package/dist/{chunk-6WIQCXOO.js → chunk-DNPNYWVL.js} +1 -1
- package/dist/{chunk-V6FDQLR7.js → chunk-EPT6FJUY.js} +53 -21
- package/dist/chunk-HODO5BX5.js +28 -0
- package/dist/chunk-HW7B43E5.js +14 -0
- package/dist/{chunk-PGMVL4AB.js → chunk-I2YX3HVD.js} +2 -2
- package/dist/{chunk-JTU2GOM4.js → chunk-L7U23XI2.js} +18 -6
- package/dist/{chunk-YEMPUQVU.js → chunk-MKMD2HJW.js} +2 -2
- package/dist/{chunk-Q4W23JYM.js → chunk-MRQ2U4LZ.js} +1 -1
- package/dist/chunk-MVR4FY5R.js +187 -0
- package/dist/{chunk-VGH4MDTU.js → chunk-NI2XNEMR.js} +1 -1
- package/dist/{chunk-4Y5FWDPM.js → chunk-NZ4RXN3G.js} +55 -7
- package/dist/{chunk-RHNWA34F.js → chunk-O5RGXTWU.js} +41 -7
- package/dist/{chunk-TXBAOEKG.js → chunk-PKGN32AU.js} +5 -4
- package/dist/chunk-Q6E4OPGG.js +40 -0
- package/dist/chunk-RDPW4D33.js +45 -0
- package/dist/{chunk-UXOGCKL6.js → chunk-T4DLETKR.js} +1 -1
- package/dist/{chunk-NK4CSJNP.js → chunk-UPRSH6Q4.js} +2 -2
- package/dist/{chunk-ERXXITG4.js → chunk-VF4F5WXZ.js} +1 -1
- package/dist/chunk-VWWITFWM.js +300 -0
- package/dist/{chunk-WWSHFRDL.js → chunk-WDQB4OXY.js} +7 -3
- package/dist/{chunk-VDF5DFWT.js → chunk-WGG6GTKW.js} +1 -1
- package/dist/{chunk-CSTQDNGK.js → chunk-WGIDC6QP.js} +43 -24
- package/dist/{chunk-V3PUVBME.js → chunk-XLSQTTUE.js} +2 -4
- package/dist/{chunk-JBE46QJZ.js → chunk-Y6LP36UW.js} +1 -1
- package/dist/chunk-YJLS6JBI.js +370 -0
- package/dist/{chunk-QEDHRBAT.js → chunk-Z65DHMTW.js} +26 -9
- package/dist/{chunk-ILU5I6RW.js → chunk-ZHS2XFLV.js} +1 -1
- package/dist/{chunk-D5EC5KVO.js → chunk-ZKHI4E2B.js} +2 -2
- package/dist/{chunk-CIG5UL2S.js → chunk-ZTLMPUO6.js} +3 -2
- package/dist/client/index.js +3 -3
- package/dist/commerce/index.js +4 -4
- package/dist/contracts/color.d.ts +1 -1
- package/dist/contracts/entries.d.ts +1 -1
- package/dist/contracts/error-page.d.ts +183 -0
- package/dist/contracts/llms.d.ts +1 -0
- package/dist/contracts/proposal-sitemap.d.ts +130 -0
- package/dist/contracts/schema-placeholders.d.ts +87 -0
- package/dist/engage/EngageWidget.d.ts +13 -12
- package/dist/engage/index.d.ts +10 -9
- package/dist/engage/index.js +31 -35
- package/dist/engage/types.d.ts +19 -244
- package/dist/fleet/FleetHeartbeat.d.ts +1 -1
- package/dist/fleet/index.js +4 -4
- package/dist/forms/FormEnhancer.d.ts +25 -12
- package/dist/forms/ServerForm.d.ts +11 -10
- package/dist/forms/StaticForm.d.ts +3 -1
- package/dist/forms/field-autocomplete.d.ts +28 -0
- package/dist/forms/form-dom-values.d.ts +42 -0
- package/dist/forms/index.js +11 -9
- package/dist/forms/server.js +6 -4
- package/dist/forms/static.js +3 -2
- package/dist/forms/submitForm.d.ts +8 -1
- package/dist/forms/types.d.ts +41 -2
- package/dist/forms/useForm.d.ts +21 -4
- package/dist/forms/webmcp.d.ts +38 -0
- package/dist/images/index.js +4 -4
- package/dist/index.d.ts +4 -1
- package/dist/index.js +1 -1
- package/dist/layout/SiteKitClientProviders.d.ts +3 -3
- package/dist/layout/SiteKitLayout.d.ts +4 -4
- package/dist/layout/client.d.ts +3 -3
- package/dist/layout/client.js +7 -7
- package/dist/layout/index.js +8 -8
- package/dist/layout/types.d.ts +5 -4
- package/dist/llms/agent-access.d.ts +4 -0
- package/dist/llms/contract.js +1 -1
- package/dist/llms/index.js +6 -6
- package/dist/maps/index.js +3 -3
- package/dist/mcp/WebMcpTools.d.ts +5 -4
- package/dist/mcp/client.js +14 -7
- package/dist/mcp/discovery.d.ts +48 -0
- package/dist/mcp/handlers.d.ts +13 -7
- package/dist/mcp/index.d.ts +5 -3
- package/dist/mcp/index.js +62 -30
- package/dist/mcp/serverCard.d.ts +6 -7
- package/dist/mcp/sonor.js +14 -11
- package/dist/revalidate/index.js +2 -2
- package/dist/seo/client.js +4 -4
- package/dist/seo/index.js +15 -8
- package/dist/seo/llms/contract.js +1 -1
- package/dist/seo/llms.js +6 -6
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/sitemap.js +4 -4
- package/dist/server/index.js +2 -2
- package/dist/shared/dialog.d.ts +27 -0
- package/dist/shared/identity.d.ts +1 -1
- package/dist/shared/layers.d.ts +7 -0
- package/dist/shared/mid-form.d.ts +53 -0
- package/dist/shared/reporting-gate.d.ts +1 -1
- package/dist/shared/version.d.ts +1 -1
- package/dist/shared/visual-viewport-gap.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/signal/types.d.ts +1 -1
- package/dist/sitemap/index.js +4 -4
- package/dist/{socket-loader-R24ZSRSQ.js → socket-loader-CGIPEG74.js} +1 -1
- package/dist/sync/index.js +5 -5
- package/dist/types.d.ts +3 -1
- package/dist/{web-vitals.attribution-GD6LGLVF.js → web-vitals.attribution-N2PCCF4Q.js} +1 -1
- package/dist/website/BlocksPopup.d.ts +1 -1
- package/dist/website/PopupBlocks.d.ts +5 -2
- package/dist/website/SitePopups.d.ts +25 -0
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +6 -6
- package/dist/website/popup-rules.d.ts +46 -0
- package/dist/website/popup-types.d.ts +113 -0
- package/dist/website/popups.d.ts +2 -6
- package/dist/website/popups.js +6 -14
- package/dist/{writeLLMsTxt-G3JBNBC5.js → writeLLMsTxt-2NQVDGYI.js} +3 -3
- package/docs/MIGRATING-TO-7.md +41 -9
- package/docs.json +2 -1
- package/package.json +2 -2
- package/src/analytics/README.md +2 -2
- package/src/articles/README.md +4 -1
- package/src/{engage → chat}/README.md +63 -62
- package/src/forms/README.md +49 -3
- package/src/layout/README.md +8 -5
- package/src/llms/README.md +69 -0
- package/src/mcp/README.md +50 -16
- package/src/seo/README.md +3 -1
- package/src/sync/README.md +10 -0
- package/src/website/README.md +133 -0
- package/dist/ChatWidget-UCDWMWCW.js +0 -15
- package/dist/EngageWidget-7ZYSK4GE.js +0 -11
- package/dist/ManagedForm-H7BVAH2W.js +0 -14
- package/dist/SitemapSync-XBANGKHZ.js +0 -8
- package/dist/chunk-NDF4A5JM.js +0 -37
- package/dist/chunk-VLARKWZU.js +0 -100
- package/dist/chunk-YCJT4JJG.js +0 -837
- package/dist/engage/DesignRenderer.d.ts +0 -57
- package/dist/engage/element-rules.d.ts +0 -38
|
@@ -0,0 +1,370 @@
|
|
|
1
|
+
'use client';
|
|
2
|
+
import { DEFAULT_WIDGET_Z_INDEX } from './chunk-27FISYK4.js';
|
|
3
|
+
import { getOrCreateVisitorId } from './chunk-24QZEO3Q.js';
|
|
4
|
+
import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
|
|
5
|
+
import { sonorFetch } from './chunk-BEBR4OJD.js';
|
|
6
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
7
|
+
import ReactDOM from 'react-dom';
|
|
8
|
+
import dynamic from 'next/dynamic';
|
|
9
|
+
import { usePathname } from 'next/navigation';
|
|
10
|
+
import { jsx, Fragment } from 'react/jsx-runtime';
|
|
11
|
+
|
|
12
|
+
// src/shared/mid-form.ts
|
|
13
|
+
var BUTTON_TYPES = /* @__PURE__ */ new Set(["button", "submit", "reset", "image"]);
|
|
14
|
+
var UNREACHABLE = '[inert],[aria-hidden="true"],[data-sk-honeypot]';
|
|
15
|
+
var typedInto = /* @__PURE__ */ new WeakSet();
|
|
16
|
+
var watched = /* @__PURE__ */ new WeakSet();
|
|
17
|
+
function watchFormInput(doc = document) {
|
|
18
|
+
if (watched.has(doc)) return;
|
|
19
|
+
watched.add(doc);
|
|
20
|
+
const note = (e) => {
|
|
21
|
+
const target = e.composedPath?.()[0] ?? e.target;
|
|
22
|
+
if (target) typedInto.add(target);
|
|
23
|
+
};
|
|
24
|
+
doc.addEventListener("input", note, true);
|
|
25
|
+
doc.addEventListener("change", note, true);
|
|
26
|
+
}
|
|
27
|
+
function isFillable(el) {
|
|
28
|
+
if (!el) return false;
|
|
29
|
+
const tag = el.tagName;
|
|
30
|
+
if (tag !== "INPUT" && tag !== "TEXTAREA" && tag !== "SELECT") return false;
|
|
31
|
+
if (tag === "INPUT") {
|
|
32
|
+
const type = el.type;
|
|
33
|
+
if (type === "hidden" || BUTTON_TYPES.has(type)) return false;
|
|
34
|
+
}
|
|
35
|
+
return !el.closest(UNREACHABLE);
|
|
36
|
+
}
|
|
37
|
+
function belongsToForm(el) {
|
|
38
|
+
return Boolean(el.form ?? el.closest("form"));
|
|
39
|
+
}
|
|
40
|
+
function focused(doc) {
|
|
41
|
+
let el = doc.activeElement;
|
|
42
|
+
while (el?.shadowRoot?.activeElement) el = el.shadowRoot.activeElement;
|
|
43
|
+
return el;
|
|
44
|
+
}
|
|
45
|
+
function renderedSelected(option) {
|
|
46
|
+
return option.defaultSelected || option.hasAttribute("selected");
|
|
47
|
+
}
|
|
48
|
+
function selectChanged(select) {
|
|
49
|
+
const options = Array.from(select.options);
|
|
50
|
+
if (select.multiple) return options.some((o) => o.selected !== renderedSelected(o));
|
|
51
|
+
if (!select.value) return false;
|
|
52
|
+
const initial = [...options].reverse().find(renderedSelected) ?? options.find((o) => !o.disabled);
|
|
53
|
+
return select.options[select.selectedIndex] !== initial;
|
|
54
|
+
}
|
|
55
|
+
function isFilled(el) {
|
|
56
|
+
if (!isFillable(el)) return false;
|
|
57
|
+
const typed = typedInto.has(el);
|
|
58
|
+
if (!typed && (el.disabled || el.tagName !== "SELECT" && el.readOnly)) return false;
|
|
59
|
+
if (el.tagName === "SELECT") return selectChanged(el);
|
|
60
|
+
const field = el;
|
|
61
|
+
if (field.type === "checkbox" || field.type === "radio") {
|
|
62
|
+
const box = field;
|
|
63
|
+
return box.checked !== box.defaultChecked;
|
|
64
|
+
}
|
|
65
|
+
return field.value.trim() !== "" && (typed || field.value !== field.defaultValue);
|
|
66
|
+
}
|
|
67
|
+
function isVisitorMidForm(doc = document) {
|
|
68
|
+
if (doc.querySelector('[data-sk-state="submitting"]')) return true;
|
|
69
|
+
if (doc.querySelector('[data-sk-form-mount][data-sk-carried="true"] form')) return true;
|
|
70
|
+
const active = focused(doc);
|
|
71
|
+
if (active && belongsToForm(active) && (isFillable(active) || active.tagName === "IFRAME")) return true;
|
|
72
|
+
for (const form of Array.from(doc.forms)) {
|
|
73
|
+
for (const el of Array.from(form.elements)) if (isFilled(el)) return true;
|
|
74
|
+
}
|
|
75
|
+
return false;
|
|
76
|
+
}
|
|
77
|
+
function whenNotMidForm(open, options = {}) {
|
|
78
|
+
const { doc = document, settleMs = 1500, pollMs = 5e3 } = options;
|
|
79
|
+
if (!isVisitorMidForm(doc)) {
|
|
80
|
+
open();
|
|
81
|
+
return () => {
|
|
82
|
+
};
|
|
83
|
+
}
|
|
84
|
+
let done = false;
|
|
85
|
+
let settle;
|
|
86
|
+
const stop = () => {
|
|
87
|
+
done = true;
|
|
88
|
+
clearTimeout(settle);
|
|
89
|
+
clearInterval(poll);
|
|
90
|
+
doc.removeEventListener("focusout", onFocusOut, true);
|
|
91
|
+
};
|
|
92
|
+
const check = () => {
|
|
93
|
+
if (done || isVisitorMidForm(doc)) return;
|
|
94
|
+
stop();
|
|
95
|
+
open();
|
|
96
|
+
};
|
|
97
|
+
const onFocusOut = () => {
|
|
98
|
+
clearTimeout(settle);
|
|
99
|
+
settle = setTimeout(check, settleMs);
|
|
100
|
+
};
|
|
101
|
+
const poll = setInterval(check, pollMs);
|
|
102
|
+
doc.addEventListener("focusout", onFocusOut, true);
|
|
103
|
+
return stop;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
// src/website/popup-rules.ts
|
|
107
|
+
function matchPath(pathname, pattern) {
|
|
108
|
+
if (pattern.endsWith("*")) return pathname.startsWith(pattern.slice(0, -1));
|
|
109
|
+
return pathname === pattern;
|
|
110
|
+
}
|
|
111
|
+
function deviceFromUserAgent(ua) {
|
|
112
|
+
if (/tablet|ipad|playbook|silk/i.test(ua)) return "tablet";
|
|
113
|
+
if (/mobile|iphone|ipod|android|blackberry|opera mini|iemobile/i.test(ua)) return "mobile";
|
|
114
|
+
return "desktop";
|
|
115
|
+
}
|
|
116
|
+
function seenKey(popupId) {
|
|
117
|
+
return `_engage_${popupId}`;
|
|
118
|
+
}
|
|
119
|
+
function isEligible(popup, pathname, device, store, now = Date.now()) {
|
|
120
|
+
const pages = popup.targeting?.pages;
|
|
121
|
+
if (pages) {
|
|
122
|
+
if (pages.exclude?.some((p) => matchPath(pathname, p))) return false;
|
|
123
|
+
if (pages.include && !pages.include.some((p) => matchPath(pathname, p))) return false;
|
|
124
|
+
}
|
|
125
|
+
if (popup.targeting?.devices && !popup.targeting.devices.includes(device)) return false;
|
|
126
|
+
const frequency = popup.trigger?.frequency;
|
|
127
|
+
if (frequency) {
|
|
128
|
+
const key = seenKey(popup.id);
|
|
129
|
+
if (frequency.type === "once") {
|
|
130
|
+
if (store.local?.getItem(key)) return false;
|
|
131
|
+
} else if (frequency.type === "once-per-session") {
|
|
132
|
+
if (store.session?.getItem(key)) return false;
|
|
133
|
+
} else if (frequency.type === "every-n-days" && frequency.days) {
|
|
134
|
+
const last = store.local?.getItem(key);
|
|
135
|
+
if (last && now - parseInt(last, 10) < frequency.days * 864e5) return false;
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
return true;
|
|
139
|
+
}
|
|
140
|
+
var PLACEMENT = {
|
|
141
|
+
popup: "popup",
|
|
142
|
+
bar: "bar",
|
|
143
|
+
nudge: "slide-in",
|
|
144
|
+
"slide-in": "slide-in"
|
|
145
|
+
};
|
|
146
|
+
function popupPlacement(popup) {
|
|
147
|
+
if (!popup.blocks?.length) return void 0;
|
|
148
|
+
return popup.layout?.placement ?? PLACEMENT[popup.type] ?? "popup";
|
|
149
|
+
}
|
|
150
|
+
function waitsForForms(popup) {
|
|
151
|
+
return popupPlacement(popup) !== "bar";
|
|
152
|
+
}
|
|
153
|
+
function activatePopup(active, id, popups) {
|
|
154
|
+
if (active.includes(id)) return active;
|
|
155
|
+
const isPopup = (popupId) => {
|
|
156
|
+
const popup = popups.find((p) => p.id === popupId);
|
|
157
|
+
return popup ? popupPlacement(popup) === "popup" : false;
|
|
158
|
+
};
|
|
159
|
+
if (isPopup(id) && active.some(isPopup)) return active;
|
|
160
|
+
return [...active, id];
|
|
161
|
+
}
|
|
162
|
+
var LazyBlocksPopup = dynamic(
|
|
163
|
+
() => import('./BlocksPopup-AHDU34TL.js').then((m) => ({ default: m.BlocksPopup })),
|
|
164
|
+
{ ssr: false }
|
|
165
|
+
);
|
|
166
|
+
function SitePopups(props) {
|
|
167
|
+
const target = resolveAnalyticsTarget(props);
|
|
168
|
+
if (!target) return null;
|
|
169
|
+
return /* @__PURE__ */ jsx(AllowedSitePopups, { ...props, ...target });
|
|
170
|
+
}
|
|
171
|
+
function AllowedSitePopups({
|
|
172
|
+
apiUrl,
|
|
173
|
+
apiKey,
|
|
174
|
+
zIndex = DEFAULT_WIDGET_Z_INDEX,
|
|
175
|
+
debug = false
|
|
176
|
+
}) {
|
|
177
|
+
const pathname = usePathname();
|
|
178
|
+
const [popups, setPopups] = useState([]);
|
|
179
|
+
const [active, setActive] = useState([]);
|
|
180
|
+
const [dismissed, setDismissed] = useState(/* @__PURE__ */ new Set());
|
|
181
|
+
useEffect(() => {
|
|
182
|
+
let cancelled = false;
|
|
183
|
+
async function load() {
|
|
184
|
+
const visitorId = getOrCreateVisitorId();
|
|
185
|
+
const url = typeof window !== "undefined" ? window.location.href : "";
|
|
186
|
+
try {
|
|
187
|
+
const response = await sonorFetch(
|
|
188
|
+
`${apiUrl.replace(/\/$/, "")}/engage/widget/elements?url=${encodeURIComponent(url)}&visitorId=${encodeURIComponent(visitorId)}&deviceType=${getDeviceType()}`,
|
|
189
|
+
{},
|
|
190
|
+
{ apiKey }
|
|
191
|
+
);
|
|
192
|
+
if (!response.ok) {
|
|
193
|
+
if (debug) console.error("[SitePopups] Error loading popups:", response.statusText);
|
|
194
|
+
return;
|
|
195
|
+
}
|
|
196
|
+
const json = await response.json();
|
|
197
|
+
const list = json.data?.elements ?? json.elements ?? [];
|
|
198
|
+
const drawable = list.filter((popup) => popupPlacement(popup) !== void 0);
|
|
199
|
+
if (debug) console.log("[SitePopups] Loaded popups:", drawable);
|
|
200
|
+
if (!cancelled) setPopups(drawable);
|
|
201
|
+
} catch (error) {
|
|
202
|
+
if (debug) console.error("[SitePopups] Error loading popups:", error);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
load();
|
|
206
|
+
return () => {
|
|
207
|
+
cancelled = true;
|
|
208
|
+
};
|
|
209
|
+
}, [apiUrl, apiKey, debug]);
|
|
210
|
+
useEffect(() => {
|
|
211
|
+
watchFormInput();
|
|
212
|
+
}, []);
|
|
213
|
+
useEffect(() => {
|
|
214
|
+
if (!popups.length) return;
|
|
215
|
+
const store = { local: storageOrNull("local"), session: storageOrNull("session") };
|
|
216
|
+
const device = getDeviceType();
|
|
217
|
+
const eligible = popups.filter((popup) => !dismissed.has(popup.id) && isEligible(popup, pathname, device, store));
|
|
218
|
+
if (debug) console.log("[SitePopups] Eligible popups:", eligible);
|
|
219
|
+
const eligibleIds = new Set(eligible.map((p) => p.id));
|
|
220
|
+
setActive((prev) => {
|
|
221
|
+
const kept = prev.filter((id) => eligibleIds.has(id));
|
|
222
|
+
return kept.length === prev.length ? prev : kept;
|
|
223
|
+
});
|
|
224
|
+
const cleanups = [];
|
|
225
|
+
const activate = (popup) => {
|
|
226
|
+
const show = () => setActive((prev) => activatePopup(prev, popup.id, popups));
|
|
227
|
+
if (waitsForForms(popup)) cleanups.push(whenNotMidForm(show));
|
|
228
|
+
else show();
|
|
229
|
+
};
|
|
230
|
+
eligible.forEach((popup) => {
|
|
231
|
+
const trigger = popup.trigger;
|
|
232
|
+
if (trigger?.type === "immediate" || !trigger?.type) {
|
|
233
|
+
activate(popup);
|
|
234
|
+
} else if (trigger.type === "delay" && trigger.delay) {
|
|
235
|
+
const timer = setTimeout(() => activate(popup), trigger.delay * 1e3);
|
|
236
|
+
cleanups.push(() => clearTimeout(timer));
|
|
237
|
+
} else if (trigger.type === "exit-intent") {
|
|
238
|
+
const handleMouseLeave = (e) => {
|
|
239
|
+
if (e.clientY < 10) {
|
|
240
|
+
activate(popup);
|
|
241
|
+
document.removeEventListener("mouseleave", handleMouseLeave);
|
|
242
|
+
}
|
|
243
|
+
};
|
|
244
|
+
document.addEventListener("mouseleave", handleMouseLeave);
|
|
245
|
+
cleanups.push(() => document.removeEventListener("mouseleave", handleMouseLeave));
|
|
246
|
+
} else if (trigger.type === "scroll" && trigger.scrollPercentage) {
|
|
247
|
+
const handleScroll = () => {
|
|
248
|
+
const scrollPercent = window.scrollY / (document.body.scrollHeight - window.innerHeight) * 100;
|
|
249
|
+
if (scrollPercent >= (trigger.scrollPercentage || 50)) {
|
|
250
|
+
activate(popup);
|
|
251
|
+
window.removeEventListener("scroll", handleScroll);
|
|
252
|
+
}
|
|
253
|
+
};
|
|
254
|
+
window.addEventListener("scroll", handleScroll, { passive: true });
|
|
255
|
+
cleanups.push(() => window.removeEventListener("scroll", handleScroll));
|
|
256
|
+
}
|
|
257
|
+
});
|
|
258
|
+
return () => {
|
|
259
|
+
cleanups.forEach((fn) => fn());
|
|
260
|
+
};
|
|
261
|
+
}, [popups, pathname, dismissed, debug]);
|
|
262
|
+
const recordSeen = useCallback((popupId) => {
|
|
263
|
+
const popup = popups.find((p) => p.id === popupId);
|
|
264
|
+
if (!popup?.trigger?.frequency) return;
|
|
265
|
+
try {
|
|
266
|
+
if (popup.trigger.frequency.type === "once-per-session") {
|
|
267
|
+
sessionStorage.setItem(seenKey(popupId), "true");
|
|
268
|
+
} else {
|
|
269
|
+
localStorage.setItem(seenKey(popupId), Date.now().toString());
|
|
270
|
+
}
|
|
271
|
+
} catch {
|
|
272
|
+
}
|
|
273
|
+
}, [popups]);
|
|
274
|
+
const handleDismiss = useCallback((popupId) => {
|
|
275
|
+
setDismissed((prev) => /* @__PURE__ */ new Set([...prev, popupId]));
|
|
276
|
+
setActive((prev) => prev.filter((id) => id !== popupId));
|
|
277
|
+
recordSeen(popupId);
|
|
278
|
+
}, [recordSeen]);
|
|
279
|
+
if (typeof document === "undefined" || !active.length) return null;
|
|
280
|
+
return ReactDOM.createPortal(
|
|
281
|
+
/* @__PURE__ */ jsx(Fragment, { children: active.map((popupId) => {
|
|
282
|
+
const popup = popups.find((p) => p.id === popupId);
|
|
283
|
+
if (!popup) return null;
|
|
284
|
+
return /* @__PURE__ */ jsx(
|
|
285
|
+
PopupView,
|
|
286
|
+
{
|
|
287
|
+
popup,
|
|
288
|
+
onDismiss: () => handleDismiss(popup.id),
|
|
289
|
+
onEngaged: () => recordSeen(popup.id),
|
|
290
|
+
zIndex,
|
|
291
|
+
apiUrl,
|
|
292
|
+
apiKey
|
|
293
|
+
},
|
|
294
|
+
popup.id
|
|
295
|
+
);
|
|
296
|
+
}) }),
|
|
297
|
+
document.body
|
|
298
|
+
);
|
|
299
|
+
}
|
|
300
|
+
function PopupView({
|
|
301
|
+
popup,
|
|
302
|
+
onDismiss,
|
|
303
|
+
onEngaged,
|
|
304
|
+
zIndex,
|
|
305
|
+
apiUrl,
|
|
306
|
+
apiKey
|
|
307
|
+
}) {
|
|
308
|
+
const rootRef = useRef(null);
|
|
309
|
+
const counted = useRef(false);
|
|
310
|
+
useEffect(() => {
|
|
311
|
+
const el = rootRef.current;
|
|
312
|
+
if (!el || counted.current) return;
|
|
313
|
+
const observer = new IntersectionObserver(
|
|
314
|
+
([entry]) => {
|
|
315
|
+
if (entry.isIntersecting && !counted.current) {
|
|
316
|
+
counted.current = true;
|
|
317
|
+
trackPopupEvent(apiUrl, apiKey, "impression", { elementId: popup.id });
|
|
318
|
+
observer.disconnect();
|
|
319
|
+
}
|
|
320
|
+
},
|
|
321
|
+
{ threshold: 0.5 }
|
|
322
|
+
);
|
|
323
|
+
observer.observe(el);
|
|
324
|
+
return () => observer.disconnect();
|
|
325
|
+
}, [apiUrl, apiKey, popup.id]);
|
|
326
|
+
const layout = popup.layout;
|
|
327
|
+
const position = layout?.corner ?? popup.config?.position;
|
|
328
|
+
const corner = position === "bottom-left" || position === "top-left" || position === "top-right" ? position : "bottom-right";
|
|
329
|
+
return /* @__PURE__ */ jsx(
|
|
330
|
+
LazyBlocksPopup,
|
|
331
|
+
{
|
|
332
|
+
blocks: popup.blocks,
|
|
333
|
+
placement: popupPlacement(popup) ?? "popup",
|
|
334
|
+
edge: layout?.edge,
|
|
335
|
+
accent: layout?.accent,
|
|
336
|
+
corner,
|
|
337
|
+
zIndex,
|
|
338
|
+
rootRef,
|
|
339
|
+
elementId: popup.id,
|
|
340
|
+
onClose: onDismiss,
|
|
341
|
+
onButton: (url) => {
|
|
342
|
+
onEngaged();
|
|
343
|
+
trackPopupEvent(apiUrl, apiKey, "click", { elementId: popup.id, action: "navigate", url });
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
);
|
|
347
|
+
}
|
|
348
|
+
function trackPopupEvent(apiUrl, apiKey, endpoint, data) {
|
|
349
|
+
const visitorId = typeof localStorage !== "undefined" ? localStorage.getItem("_sk_vid") : null;
|
|
350
|
+
sonorFetch(`${apiUrl.replace(/\/$/, "")}/engage/widget/${endpoint}`, {
|
|
351
|
+
method: "POST",
|
|
352
|
+
headers: { "Content-Type": "application/json" },
|
|
353
|
+
body: JSON.stringify({ ...data, visitorId, pageUrl: window.location.href }),
|
|
354
|
+
keepalive: true
|
|
355
|
+
}, { apiKey, retries: 0 }).catch(() => {
|
|
356
|
+
});
|
|
357
|
+
}
|
|
358
|
+
function getDeviceType() {
|
|
359
|
+
if (typeof navigator === "undefined") return "desktop";
|
|
360
|
+
return deviceFromUserAgent(navigator.userAgent);
|
|
361
|
+
}
|
|
362
|
+
function storageOrNull(kind) {
|
|
363
|
+
try {
|
|
364
|
+
return kind === "local" ? window.localStorage : window.sessionStorage;
|
|
365
|
+
} catch {
|
|
366
|
+
return null;
|
|
367
|
+
}
|
|
368
|
+
}
|
|
369
|
+
|
|
370
|
+
export { SitePopups };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
|
-
import { getLLMsData, getOptimizedLLMsTxt } from './chunk-
|
|
1
|
+
import { getLLMsData, getOptimizedLLMsTxt } from './chunk-6U3VLV2C.js';
|
|
2
2
|
import { linkClassificationHost } from './chunk-L5UOHS6E.js';
|
|
3
3
|
import { resolveArticleUrl } from './chunk-WMVK77ND.js';
|
|
4
4
|
import { freshFetch } from './chunk-VX5CMNMM.js';
|
|
5
|
-
import { LLM_GEO_CONTRACT_VERSION, sanitizePrimaryLanguageTag, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary } from './chunk-
|
|
5
|
+
import { LLM_GEO_CONTRACT_VERSION, sanitizePrimaryLanguageTag, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary } from './chunk-NZ4RXN3G.js';
|
|
6
6
|
import { resolveTrailingSlash, applyTrailingSlash } from './chunk-YVKRYQRG.js';
|
|
7
7
|
import { resolveSiteHost } from './chunk-FESKKJAS.js';
|
|
8
8
|
import { readFileSync, existsSync, mkdirSync, writeFileSync, renameSync, unlinkSync, readdirSync } from 'fs';
|
|
@@ -19,24 +19,39 @@ function formatAgentAccessSection(baseUrl, options = {}) {
|
|
|
19
19
|
return [
|
|
20
20
|
AGENT_ACCESS_HEADING,
|
|
21
21
|
"",
|
|
22
|
-
"
|
|
22
|
+
"AI assistants can use this site\u2019s Model Context Protocol tools to look up information and, with the user\u2019s approval, take supported actions.",
|
|
23
23
|
"",
|
|
24
24
|
`- [MCP endpoint](${endpoint}): Streamable HTTP. Call tools/list for the current tools.`,
|
|
25
25
|
`- [Server card](${card}): what the server is and how to connect.`,
|
|
26
|
+
...options.catalog ? [`- [AI catalog](${absolute(baseUrl, options.catalog)}): experimental domain discovery.`] : [],
|
|
26
27
|
...tools.length ? ["", `Tools include ${tools.map((t) => `\`${t}\``).join(", ")}.`] : []
|
|
27
28
|
].join("\n");
|
|
28
29
|
}
|
|
29
30
|
function appendAgentAccessSection(markdown, baseUrl, options = {}) {
|
|
30
31
|
if (!baseUrl || describesMcp(markdown)) return markdown;
|
|
32
|
+
const section = formatAgentAccessSection(baseUrl, options);
|
|
33
|
+
if (options.position === "after-intro") {
|
|
34
|
+
const firstSection = /^## /m.exec(markdown);
|
|
35
|
+
if (firstSection) {
|
|
36
|
+
const intro = markdown.slice(0, firstSection.index).trimEnd().replace(/\n---$/, "").trimEnd();
|
|
37
|
+
return `${intro}
|
|
38
|
+
|
|
39
|
+
${section}
|
|
40
|
+
|
|
41
|
+
---
|
|
42
|
+
|
|
43
|
+
${markdown.slice(firstSection.index)}`;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
31
46
|
return `${markdown.trimEnd()}
|
|
32
47
|
|
|
33
48
|
---
|
|
34
49
|
|
|
35
|
-
${
|
|
50
|
+
${section}
|
|
36
51
|
`;
|
|
37
52
|
}
|
|
38
53
|
function describesMcp(markdown) {
|
|
39
|
-
return markdown.includes(AGENT_ACCESS_HEADING) || markdown.includes("/.well-known/mcp-server-card") || markdown.includes("/.well-known/mcp.json");
|
|
54
|
+
return markdown.includes(AGENT_ACCESS_HEADING) || markdown.includes("/.well-known/mcp-server-card") || markdown.includes("/.well-known/mcp.json") || markdown.includes("/api/mcp/server-card");
|
|
40
55
|
}
|
|
41
56
|
var MCP_ROUTE_FILES = ["route.ts", "route.tsx", "route.js", "route.jsx", "route.mjs"];
|
|
42
57
|
var SERVER_CARD_DIRS = ["mcp-server-card", "mcp.json"];
|
|
@@ -362,16 +377,18 @@ async function generateLLMsTxt(options) {
|
|
|
362
377
|
}
|
|
363
378
|
}
|
|
364
379
|
}
|
|
365
|
-
if (options.mcp && baseUrl) {
|
|
366
|
-
sections.push(formatAgentAccessSection(baseUrl, options.mcp === true ? {} : options.mcp));
|
|
367
|
-
sectionNames.push("agent-access");
|
|
368
|
-
}
|
|
369
380
|
for (const custom of customSections) {
|
|
370
381
|
sections.push(`## ${custom.title}
|
|
371
382
|
|
|
372
383
|
${custom.content}`);
|
|
373
384
|
sectionNames.push(custom.title.toLowerCase().replace(/\s+/g, "-"));
|
|
374
385
|
}
|
|
386
|
+
if (options.mcp && baseUrl) {
|
|
387
|
+
const agentOptions = options.mcp === true ? {} : options.mcp;
|
|
388
|
+
const index = agentOptions.position === "after-intro" ? sectionNames[0] === "header" ? 1 : 0 : sections.length;
|
|
389
|
+
sections.splice(index, 0, formatAgentAccessSection(baseUrl, agentOptions));
|
|
390
|
+
sectionNames.splice(index, 0, "agent-access");
|
|
391
|
+
}
|
|
375
392
|
return {
|
|
376
393
|
// Every own-site link (pages, clusters, portfolio, custom sections) takes
|
|
377
394
|
// the site's trailing-slash shape in one pass.
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { isEmptyValue, isDisplayOnly } from './chunk-
|
|
2
|
+
import { isEmptyValue, isDisplayOnly } from './chunk-C2FZBUSS.js';
|
|
3
3
|
import { useMemo, useState, useRef, useEffect } from 'react';
|
|
4
4
|
|
|
5
5
|
var NO_CONTROLS = {};
|
|
@@ -26,7 +26,7 @@ function useFieldControls(fields) {
|
|
|
26
26
|
}
|
|
27
27
|
if (needsFile && !requested.current.file) {
|
|
28
28
|
requested.current.file = true;
|
|
29
|
-
import('./FileField-
|
|
29
|
+
import('./FileField-J5W5MIAZ.js').then((m) => {
|
|
30
30
|
if (!cancelled) setControls((prev) => ({ ...prev, File: m.FileField }));
|
|
31
31
|
}).catch(() => {
|
|
32
32
|
requested.current.file = false;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { HoneypotField } from './chunk-DXO6SBMD.js';
|
|
2
|
-
import { FormField } from './chunk-
|
|
2
|
+
import { FormField } from './chunk-4NTBQNHA.js';
|
|
3
3
|
import { normalizeFormConfig } from './chunk-5SQK3D53.js';
|
|
4
4
|
import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
|
|
5
5
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
@@ -31,7 +31,8 @@ function StaticForm({ config: raw, className }) {
|
|
|
31
31
|
},
|
|
32
32
|
field.id || field.slug
|
|
33
33
|
)) }) }),
|
|
34
|
-
/* @__PURE__ */ jsx("div", { className: "sk-form__actions", style: { justifyContent: "flex-end" }, children: /* @__PURE__ */ jsx("button", { type: "submit", className: "sk-form__btn sk-form__btn--submit", children: config.submit_button_text || "Submit" }) }),
|
|
34
|
+
/* @__PURE__ */ jsx("div", { className: "sk-form__actions", style: { justifyContent: "flex-end" }, children: /* @__PURE__ */ jsx("button", { type: "submit", className: "sk-form__btn sk-form__btn--submit", disabled: true, "data-sk-shell-submit": "", children: config.submit_button_text || "Submit" }) }),
|
|
35
|
+
/* @__PURE__ */ jsx("noscript", { children: /* @__PURE__ */ jsx("p", { className: "sk-form__noscript", children: "This form needs JavaScript to send. Turn it on and reload the page." }) }),
|
|
35
36
|
config.honeypot_enabled && /* @__PURE__ */ jsx(HoneypotField, { name: honeypotFieldName })
|
|
36
37
|
]
|
|
37
38
|
}
|
package/dist/client/index.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { publishSiteCredential } from '../chunk-
|
|
2
|
+
import { publishSiteCredential } from '../chunk-VF4F5WXZ.js';
|
|
3
3
|
export { useDeferredActivation } from '../chunk-YC7ELZS3.js';
|
|
4
4
|
import '../chunk-FESKKJAS.js';
|
|
5
5
|
import '../chunk-A4CC4ZG3.js';
|
|
@@ -7,8 +7,8 @@ export { trackConversion, trackEvent } from '../chunk-LCDVPAMR.js';
|
|
|
7
7
|
export { VISUAL_VIEWPORT_GAP_PROPERTY, VisualViewportGap, useVisualViewportGap } from '../chunk-6T6CQVNL.js';
|
|
8
8
|
export { getOrCreateSessionId, getOrCreateVisitorId, useSiteKitIdentity } from '../chunk-24QZEO3Q.js';
|
|
9
9
|
import '../chunk-GJWI74ZZ.js';
|
|
10
|
-
import '../chunk-
|
|
11
|
-
import '../chunk-
|
|
10
|
+
import '../chunk-WGG6GTKW.js';
|
|
11
|
+
import '../chunk-56KNHB4U.js';
|
|
12
12
|
import '../chunk-PKBMQBKP.js';
|
|
13
13
|
|
|
14
14
|
// src/client/SiteKitCredential.tsx
|
package/dist/commerce/index.js
CHANGED
|
@@ -1,15 +1,15 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import '../chunk-P5GB6NEO.js';
|
|
3
|
-
import { useAnalyticsOptional } from '../chunk-
|
|
3
|
+
import { useAnalyticsOptional } from '../chunk-MKMD2HJW.js';
|
|
4
4
|
import '../chunk-LCDVPAMR.js';
|
|
5
5
|
import '../chunk-24QZEO3Q.js';
|
|
6
6
|
import '../chunk-L2V5PUFN.js';
|
|
7
7
|
import '../chunk-GJWI74ZZ.js';
|
|
8
8
|
import '../chunk-43OCZ3JA.js';
|
|
9
9
|
import '../chunk-EKBEOXTH.js';
|
|
10
|
-
import { sonorFetch } from '../chunk-
|
|
11
|
-
import '../chunk-
|
|
12
|
-
import '../chunk-
|
|
10
|
+
import { sonorFetch } from '../chunk-BEBR4OJD.js';
|
|
11
|
+
import '../chunk-WGG6GTKW.js';
|
|
12
|
+
import '../chunk-56KNHB4U.js';
|
|
13
13
|
import '../chunk-PKBMQBKP.js';
|
|
14
14
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
15
15
|
import React5, { useState, useEffect, useMemo, useRef, useCallback } from 'react';
|
|
@@ -4,7 +4,7 @@
|
|
|
4
4
|
* Single source of truth for turning a CSS colour string into something the
|
|
5
5
|
* kit can reason about. Used at build time by the brand-profile extractor
|
|
6
6
|
* (`src/brand/extract-brand-profile.ts`, theme detection) and in the browser
|
|
7
|
-
* by Echo (`src/
|
|
7
|
+
* by Echo (`src/chat/brand-color.ts`, brand text contrast). Pure, no
|
|
8
8
|
* imports, safe in both.
|
|
9
9
|
*/
|
|
10
10
|
export type Rgb = {
|
|
@@ -4,5 +4,5 @@
|
|
|
4
4
|
* tsup config, its package.json check and the boundary test, so a new
|
|
5
5
|
* contract is added in one place.
|
|
6
6
|
*/
|
|
7
|
-
export declare const CONTRACT_ENTRIES: readonly ['forms', 'llms', 'slots', 'slot-content', 'site-cache', 'site-edit', 'website', 'color', 'fleet', 'sites', 'seo-pages', 'seo-meta', 'portfolio', 'voice'];
|
|
7
|
+
export declare const CONTRACT_ENTRIES: readonly ['forms', 'llms', 'slots', 'slot-content', 'site-cache', 'site-edit', 'website', 'color', 'fleet', 'sites', 'seo-pages', 'seo-meta', 'portfolio', 'voice', 'proposal-sitemap', 'error-page', 'schema-placeholders'];
|
|
8
8
|
export type ContractEntry = (typeof CONTRACT_ENTRIES)[number];
|