@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.
Files changed (176) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +60 -0
  3. package/README.md +9 -8
  4. package/agent-manifest.json +17 -7
  5. package/dist/{AnalyticsProvider-ZB33W6MC.js → AnalyticsProvider-DJQA66AG.js} +4 -4
  6. package/dist/{ArticleViewTracker-GMHYLLLZ.js → ArticleViewTracker-GFOAXFV7.js} +3 -3
  7. package/dist/{BlocksPopup-EA6LYL25.js → BlocksPopup-AHDU34TL.js} +5 -5
  8. package/dist/ChatWidget-FHBAHFZX.js +17 -0
  9. package/dist/{FileField-QKA3JB2Q.js → FileField-J5W5MIAZ.js} +3 -3
  10. package/dist/{FormSpotlight-AQTIA5TP.js → FormSpotlight-PE5YZBFZ.js} +20 -6
  11. package/dist/{FormStage-FDTLTP3B.js → FormStage-OOPQC27J.js} +27 -7
  12. package/dist/ManagedForm-JRZAJ7SZ.js +16 -0
  13. package/dist/{ManagedNewsletterForm-J6QSAGGP.js → ManagedNewsletterForm-TC5542ZG.js} +7 -5
  14. package/dist/{SignalCore-JZNXOLNT.js → SignalCore-2YP5FCAS.js} +3 -3
  15. package/dist/SiteChat-EGEZJJVV.js +5 -0
  16. package/dist/{SiteDesignReporter-W4EJUSTE.js → SiteDesignReporter-YEEWJKWN.js} +5 -5
  17. package/dist/SitePopups-LQBIXIFV.js +10 -0
  18. package/dist/SitemapSync-LSZ2EYOF.js +8 -0
  19. package/dist/_client/booking-widget.js +5 -5
  20. package/dist/affiliates/index.js +3 -3
  21. package/dist/analytics/index.js +4 -4
  22. package/dist/analytics/send-gate.d.ts +1 -1
  23. package/dist/articles/index.js +2 -2
  24. package/dist/articles/server-ui.js +3 -2
  25. package/dist/articles/server.js +2 -1
  26. package/dist/{engage → chat}/ChatWidget.d.ts +7 -6
  27. package/dist/{engage → chat}/EchoUiActions.d.ts +1 -1
  28. package/dist/chat/SiteChat.d.ts +25 -0
  29. package/dist/{engage → chat}/brand-color.d.ts +1 -1
  30. package/dist/{engage → chat}/chat-messages.d.ts +1 -1
  31. package/dist/{engage → chat}/echo-config.d.ts +1 -1
  32. package/dist/chat/index.d.ts +10 -6
  33. package/dist/chat/index.js +14 -8
  34. package/dist/{engage → chat}/launcher-placement.d.ts +1 -7
  35. package/dist/{engage → chat}/socket-loader.d.ts +2 -2
  36. package/dist/chat/types.d.ts +136 -0
  37. package/dist/chunk-27FISYK4.js +4 -0
  38. package/dist/{chunk-HF57LG73.js → chunk-2AD3CDRR.js} +43 -29
  39. package/dist/{chunk-M3YEPKP7.js → chunk-2ECWEUHP.js} +1 -1
  40. package/dist/{chunk-LUXVWITO.js → chunk-4NTBQNHA.js} +247 -78
  41. package/dist/{chunk-AH5Q262S.js → chunk-56KNHB4U.js} +1 -1
  42. package/dist/{chunk-GLHQ3LRO.js → chunk-6U3VLV2C.js} +1 -1
  43. package/dist/{chunk-3SDOQUUF.js → chunk-BEBR4OJD.js} +2 -2
  44. package/dist/{chunk-JSZN6LDZ.js → chunk-BF7TZYC3.js} +38 -31
  45. package/dist/{chunk-AQSNPZY4.js → chunk-C2FZBUSS.js} +80 -1
  46. package/dist/{chunk-PHYMNUJU.js → chunk-CYUFBKJQ.js} +1 -1
  47. package/dist/{chunk-6WIQCXOO.js → chunk-DNPNYWVL.js} +1 -1
  48. package/dist/{chunk-V6FDQLR7.js → chunk-EPT6FJUY.js} +53 -21
  49. package/dist/chunk-HODO5BX5.js +28 -0
  50. package/dist/chunk-HW7B43E5.js +14 -0
  51. package/dist/{chunk-PGMVL4AB.js → chunk-I2YX3HVD.js} +2 -2
  52. package/dist/{chunk-JTU2GOM4.js → chunk-L7U23XI2.js} +18 -6
  53. package/dist/{chunk-YEMPUQVU.js → chunk-MKMD2HJW.js} +2 -2
  54. package/dist/{chunk-Q4W23JYM.js → chunk-MRQ2U4LZ.js} +1 -1
  55. package/dist/chunk-MVR4FY5R.js +187 -0
  56. package/dist/{chunk-VGH4MDTU.js → chunk-NI2XNEMR.js} +1 -1
  57. package/dist/{chunk-4Y5FWDPM.js → chunk-NZ4RXN3G.js} +55 -7
  58. package/dist/{chunk-RHNWA34F.js → chunk-O5RGXTWU.js} +41 -7
  59. package/dist/{chunk-TXBAOEKG.js → chunk-PKGN32AU.js} +5 -4
  60. package/dist/chunk-Q6E4OPGG.js +40 -0
  61. package/dist/chunk-RDPW4D33.js +45 -0
  62. package/dist/{chunk-UXOGCKL6.js → chunk-T4DLETKR.js} +1 -1
  63. package/dist/{chunk-NK4CSJNP.js → chunk-UPRSH6Q4.js} +2 -2
  64. package/dist/{chunk-ERXXITG4.js → chunk-VF4F5WXZ.js} +1 -1
  65. package/dist/chunk-VWWITFWM.js +300 -0
  66. package/dist/{chunk-WWSHFRDL.js → chunk-WDQB4OXY.js} +7 -3
  67. package/dist/{chunk-VDF5DFWT.js → chunk-WGG6GTKW.js} +1 -1
  68. package/dist/{chunk-CSTQDNGK.js → chunk-WGIDC6QP.js} +43 -24
  69. package/dist/{chunk-V3PUVBME.js → chunk-XLSQTTUE.js} +2 -4
  70. package/dist/{chunk-JBE46QJZ.js → chunk-Y6LP36UW.js} +1 -1
  71. package/dist/chunk-YJLS6JBI.js +370 -0
  72. package/dist/{chunk-QEDHRBAT.js → chunk-Z65DHMTW.js} +26 -9
  73. package/dist/{chunk-ILU5I6RW.js → chunk-ZHS2XFLV.js} +1 -1
  74. package/dist/{chunk-D5EC5KVO.js → chunk-ZKHI4E2B.js} +2 -2
  75. package/dist/{chunk-CIG5UL2S.js → chunk-ZTLMPUO6.js} +3 -2
  76. package/dist/client/index.js +3 -3
  77. package/dist/commerce/index.js +4 -4
  78. package/dist/contracts/color.d.ts +1 -1
  79. package/dist/contracts/entries.d.ts +1 -1
  80. package/dist/contracts/error-page.d.ts +183 -0
  81. package/dist/contracts/llms.d.ts +1 -0
  82. package/dist/contracts/proposal-sitemap.d.ts +130 -0
  83. package/dist/contracts/schema-placeholders.d.ts +87 -0
  84. package/dist/engage/EngageWidget.d.ts +13 -12
  85. package/dist/engage/index.d.ts +10 -9
  86. package/dist/engage/index.js +31 -35
  87. package/dist/engage/types.d.ts +19 -244
  88. package/dist/fleet/FleetHeartbeat.d.ts +1 -1
  89. package/dist/fleet/index.js +4 -4
  90. package/dist/forms/FormEnhancer.d.ts +25 -12
  91. package/dist/forms/ServerForm.d.ts +11 -10
  92. package/dist/forms/StaticForm.d.ts +3 -1
  93. package/dist/forms/field-autocomplete.d.ts +28 -0
  94. package/dist/forms/form-dom-values.d.ts +42 -0
  95. package/dist/forms/index.js +11 -9
  96. package/dist/forms/server.js +6 -4
  97. package/dist/forms/static.js +3 -2
  98. package/dist/forms/submitForm.d.ts +8 -1
  99. package/dist/forms/types.d.ts +41 -2
  100. package/dist/forms/useForm.d.ts +21 -4
  101. package/dist/forms/webmcp.d.ts +38 -0
  102. package/dist/images/index.js +4 -4
  103. package/dist/index.d.ts +4 -1
  104. package/dist/index.js +1 -1
  105. package/dist/layout/SiteKitClientProviders.d.ts +3 -3
  106. package/dist/layout/SiteKitLayout.d.ts +4 -4
  107. package/dist/layout/client.d.ts +3 -3
  108. package/dist/layout/client.js +7 -7
  109. package/dist/layout/index.js +8 -8
  110. package/dist/layout/types.d.ts +5 -4
  111. package/dist/llms/agent-access.d.ts +4 -0
  112. package/dist/llms/contract.js +1 -1
  113. package/dist/llms/index.js +6 -6
  114. package/dist/maps/index.js +3 -3
  115. package/dist/mcp/WebMcpTools.d.ts +5 -4
  116. package/dist/mcp/client.js +14 -7
  117. package/dist/mcp/discovery.d.ts +48 -0
  118. package/dist/mcp/handlers.d.ts +13 -7
  119. package/dist/mcp/index.d.ts +5 -3
  120. package/dist/mcp/index.js +62 -30
  121. package/dist/mcp/serverCard.d.ts +6 -7
  122. package/dist/mcp/sonor.js +14 -11
  123. package/dist/revalidate/index.js +2 -2
  124. package/dist/seo/client.js +4 -4
  125. package/dist/seo/index.js +15 -8
  126. package/dist/seo/llms/contract.js +1 -1
  127. package/dist/seo/llms.js +6 -6
  128. package/dist/seo/register-sitemap-cli.js +1 -1
  129. package/dist/seo/sitemap.js +4 -4
  130. package/dist/server/index.js +2 -2
  131. package/dist/shared/dialog.d.ts +27 -0
  132. package/dist/shared/identity.d.ts +1 -1
  133. package/dist/shared/layers.d.ts +7 -0
  134. package/dist/shared/mid-form.d.ts +53 -0
  135. package/dist/shared/reporting-gate.d.ts +1 -1
  136. package/dist/shared/version.d.ts +1 -1
  137. package/dist/shared/visual-viewport-gap.d.ts +1 -1
  138. package/dist/signal/index.js +2 -2
  139. package/dist/signal/types.d.ts +1 -1
  140. package/dist/sitemap/index.js +4 -4
  141. package/dist/{socket-loader-R24ZSRSQ.js → socket-loader-CGIPEG74.js} +1 -1
  142. package/dist/sync/index.js +5 -5
  143. package/dist/types.d.ts +3 -1
  144. package/dist/{web-vitals.attribution-GD6LGLVF.js → web-vitals.attribution-N2PCCF4Q.js} +1 -1
  145. package/dist/website/BlocksPopup.d.ts +1 -1
  146. package/dist/website/PopupBlocks.d.ts +5 -2
  147. package/dist/website/SitePopups.d.ts +25 -0
  148. package/dist/website/images.js +4 -4
  149. package/dist/website/index.js +6 -6
  150. package/dist/website/popup-rules.d.ts +46 -0
  151. package/dist/website/popup-types.d.ts +113 -0
  152. package/dist/website/popups.d.ts +2 -6
  153. package/dist/website/popups.js +6 -14
  154. package/dist/{writeLLMsTxt-G3JBNBC5.js → writeLLMsTxt-2NQVDGYI.js} +3 -3
  155. package/docs/MIGRATING-TO-7.md +41 -9
  156. package/docs.json +2 -1
  157. package/package.json +2 -2
  158. package/src/analytics/README.md +2 -2
  159. package/src/articles/README.md +4 -1
  160. package/src/{engage → chat}/README.md +63 -62
  161. package/src/forms/README.md +49 -3
  162. package/src/layout/README.md +8 -5
  163. package/src/llms/README.md +69 -0
  164. package/src/mcp/README.md +50 -16
  165. package/src/seo/README.md +3 -1
  166. package/src/sync/README.md +10 -0
  167. package/src/website/README.md +133 -0
  168. package/dist/ChatWidget-UCDWMWCW.js +0 -15
  169. package/dist/EngageWidget-7ZYSK4GE.js +0 -11
  170. package/dist/ManagedForm-H7BVAH2W.js +0 -14
  171. package/dist/SitemapSync-XBANGKHZ.js +0 -8
  172. package/dist/chunk-NDF4A5JM.js +0 -37
  173. package/dist/chunk-VLARKWZU.js +0 -100
  174. package/dist/chunk-YCJT4JJG.js +0 -837
  175. package/dist/engage/DesignRenderer.d.ts +0 -57
  176. package/dist/engage/element-rules.d.ts +0 -38
@@ -1,10 +1,11 @@
1
1
  'use client';
2
- import { isFieldVisible, validateField, isFieldComplete } from './chunk-AQSNPZY4.js';
3
- import { normalizeFormConfig } from './chunk-5SQK3D53.js';
2
+ import { readAgentSubmit, formToolAttributes } from './chunk-Q6E4OPGG.js';
3
+ import { isFieldVisible, validateField, isFieldComplete, unseenControlValues } from './chunk-C2FZBUSS.js';
4
+ import { normalizeFormConfig, DEFAULT_FORM_SUCCESS_MESSAGE } from './chunk-5SQK3D53.js';
4
5
  import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
5
6
  import { onPageLeave } from './chunk-L2V5PUFN.js';
6
7
  import { uuid } from './chunk-GJWI74ZZ.js';
7
- import { sonorFetch, sonorBeacon } from './chunk-3SDOQUUF.js';
8
+ import { sonorFetch, sonorBeacon } from './chunk-BEBR4OJD.js';
8
9
  import { useRef, useCallback, useEffect, useState, useMemo } from 'react';
9
10
 
10
11
  // src/forms/field-interactions.ts
@@ -567,7 +568,8 @@ async function submitForm({
567
568
  config,
568
569
  values,
569
570
  honeypotValue,
570
- formLoadedAt
571
+ formLoadedAt,
572
+ agentInvoked
571
573
  }) {
572
574
  const { apiUrl, apiKey } = getApiConfig();
573
575
  if (!apiKey) {
@@ -606,7 +608,8 @@ async function submitForm({
606
608
  // Sub-site host — preserved on form_submissions for lead attribution
607
609
  // across multi-site projects. Resolved by SiteKitClientProviders.
608
610
  site: typeof window !== "undefined" ? window.__SITE_KIT_SITE__ || window.location.host : void 0,
609
- _formLoadedAt: formLoadedAt
611
+ _formLoadedAt: formLoadedAt,
612
+ ...agentInvoked ? { agentInvoked: true } : {}
610
613
  }
611
614
  };
612
615
  const response = await sonorFetch(
@@ -800,23 +803,24 @@ function useForm(formIdOrSlug, options = {}) {
800
803
  setErrors(newErrors);
801
804
  return Object.keys(newErrors).length === 0;
802
805
  }, [fields, validateField2]);
803
- const validateAll = useCallback(() => {
806
+ const validateAllFor = useCallback((vals) => {
807
+ const visible = (field) => isFieldVisible(field, vals);
804
808
  const newErrors = {};
805
809
  for (const field of allFields) {
806
- const error = validateField2(field);
810
+ const error = validateField(field, vals, visible);
807
811
  if (error) newErrors[field.slug] = error;
808
812
  }
809
813
  setErrors(newErrors);
810
- return Object.keys(newErrors).length === 0;
811
- }, [allFields, validateField2]);
812
- const buildVisibleValues = useCallback(() => {
814
+ return newErrors;
815
+ }, [allFields]);
816
+ const buildVisibleValues = useCallback((vals) => {
813
817
  const out = {};
814
818
  for (const field of allFields) {
815
- if (!isFieldVisible2(field)) continue;
816
- if (field.slug in values) out[field.slug] = values[field.slug];
819
+ if (!isFieldVisible(field, vals)) continue;
820
+ if (field.slug in vals) out[field.slug] = vals[field.slug];
817
821
  }
818
822
  return out;
819
- }, [allFields, values, isFieldVisible2]);
823
+ }, [allFields]);
820
824
  const setFieldValue = useCallback((key, value) => {
821
825
  setValuesState((prev) => ({ ...prev, [key]: value }));
822
826
  trackFieldChange(key);
@@ -862,19 +866,25 @@ function useForm(formIdOrSlug, options = {}) {
862
866
  trackStepChange(targetStep);
863
867
  }
864
868
  }, [totalSteps, trackStepChange]);
865
- const submit = useCallback(async () => {
866
- if (!form) return;
867
- if (isSubmittingRef.current) return;
868
- if (!validateAll()) return;
869
+ const submit = useCallback(async (options2) => {
870
+ if (!form) return { status: "failed", message: "The form is still loading." };
871
+ if (isSubmittingRef.current) return { status: "busy" };
872
+ const domFills = options2 && typeof options2 === "object" && options2.domFills && typeof options2.domFills === "object" ? options2.domFills : null;
873
+ const agentInvoked = !!options2 && typeof options2 === "object" && options2.agentInvoked === true;
874
+ const vals = domFills && Object.keys(domFills).length > 0 ? { ...values, ...domFills } : values;
875
+ if (vals !== values) setValuesState(vals);
876
+ const invalid = validateAllFor(vals);
877
+ if (Object.keys(invalid).length > 0) return { status: "invalid", errors: invalid };
869
878
  isSubmittingRef.current = true;
870
879
  setIsSubmitting(true);
871
880
  setSubmitError(null);
872
881
  try {
873
882
  const data = await submitForm({
874
883
  config: form,
875
- values: buildVisibleValues(),
884
+ values: buildVisibleValues(vals),
876
885
  honeypotValue: "",
877
- formLoadedAt: formLoadedAt()
886
+ formLoadedAt: formLoadedAt(),
887
+ agentInvoked
878
888
  });
879
889
  trackComplete();
880
890
  setIsComplete(true);
@@ -883,15 +893,35 @@ function useForm(formIdOrSlug, options = {}) {
883
893
  if (finalRedirect) {
884
894
  window.location.href = finalRedirect;
885
895
  }
896
+ const confirmation = typeof form.success_message === "string" && form.success_message.trim() ? form.success_message.trim() : DEFAULT_FORM_SUCCESS_MESSAGE;
897
+ return { status: "sent", message: confirmation, submissionId: data.submissionId || void 0 };
886
898
  } catch (error) {
887
899
  console.error("[useForm] Submission error:", error);
888
- setSubmitError("Something went wrong sending your submission. Please try again.");
900
+ const message = "Something went wrong sending your submission. Please try again.";
901
+ setSubmitError(message);
889
902
  onError?.(error);
903
+ return { status: "failed", message };
890
904
  } finally {
891
905
  isSubmittingRef.current = false;
892
906
  setIsSubmitting(false);
893
907
  }
894
- }, [form, validateAll, buildVisibleValues, trackComplete, onSuccess, onError, redirectUrl]);
908
+ }, [form, values, validateAllFor, buildVisibleValues, trackComplete, onSuccess, onError, redirectUrl]);
909
+ const handleSubmit = useCallback((event) => {
910
+ event.preventDefault();
911
+ const agent = readAgentSubmit(event.nativeEvent);
912
+ if (form?.is_multi_step && step < totalSteps) {
913
+ const moved = nextStep();
914
+ agent.respond(
915
+ Promise.resolve(
916
+ moved ? { status: "next_step", step: step + 1, totalSteps } : { status: "invalid", errors: {} }
917
+ )
918
+ );
919
+ return;
920
+ }
921
+ const domFills = unseenControlValues(event.currentTarget, allFields, "", values);
922
+ agent.respond(submit({ agentInvoked: agent.invoked, domFills }));
923
+ }, [form, step, totalSteps, nextStep, allFields, values, submit]);
924
+ const toolAttributes = useMemo(() => form ? formToolAttributes(form) : null, [form]);
895
925
  const reset = useCallback(() => {
896
926
  setValuesState(initialValues);
897
927
  setErrors({});
@@ -926,6 +956,8 @@ function useForm(formIdOrSlug, options = {}) {
926
956
  validateField: validateField2,
927
957
  isFieldVisible: isFieldVisible2,
928
958
  submit,
959
+ handleSubmit,
960
+ toolAttributes,
929
961
  isSubmitting,
930
962
  isComplete,
931
963
  reset,
@@ -0,0 +1,28 @@
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 };
@@ -0,0 +1,14 @@
1
+ // src/mcp/declarative.ts
2
+ function declarativeToolForm(options) {
3
+ const attributes = {
4
+ toolname: options.name,
5
+ tooldescription: options.description
6
+ };
7
+ if (options.autoSubmit) attributes.toolautosubmit = "";
8
+ return attributes;
9
+ }
10
+ function declarativeToolField(description) {
11
+ return { toolparamdescription: description };
12
+ }
13
+
14
+ export { declarativeToolField, declarativeToolForm };
@@ -1,8 +1,8 @@
1
1
  import { toHexColor, normalizeDesignTokens, designTokensHash } from './chunk-IHG36STL.js';
2
2
  import { contrastRatio, parseColor, relativeLuminance } from './chunk-S22FSH7C.js';
3
3
  import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
4
- import { sonorFetch } from './chunk-3SDOQUUF.js';
5
- import { SITE_KIT_VERSION } from './chunk-AH5Q262S.js';
4
+ import { sonorFetch } from './chunk-BEBR4OJD.js';
5
+ import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
6
6
 
7
7
  // src/website/design.ts
8
8
  var SITE_DESIGN_PATH = "/api/public/site/design";
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-M3YEPKP7.js';
2
+ import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-2ECWEUHP.js';
3
3
  import { useState, useRef, useMemo, useCallback, useEffect, useId } from 'react';
4
4
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
5
5
 
@@ -163,6 +163,12 @@ function toLocalDateStr(d) {
163
163
  const day = String(d.getDate()).padStart(2, "0");
164
164
  return `${y}-${m}-${day}`;
165
165
  }
166
+ function dayLabel(d) {
167
+ return d.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric", year: "numeric" });
168
+ }
169
+ function slotLabel(slot, timezone) {
170
+ return `${formatTime(slot.start, timezone)}, ${formatDate(slot.start, timezone)}`;
171
+ }
166
172
  function ChevronLeft() {
167
173
  return /* @__PURE__ */ jsx("svg", { width: "20", height: "20", viewBox: "0 0 20 20", fill: "none", xmlns: "http://www.w3.org/2000/svg", children: /* @__PURE__ */ jsx("path", { d: "M12.5 15L7.5 10L12.5 5", stroke: "currentColor", strokeWidth: "1.5", strokeLinecap: "round", strokeLinejoin: "round" }) });
168
174
  }
@@ -706,8 +712,8 @@ function BookingWidget({
706
712
  if (!disabled && !busyRef.current) setSelectedDate(date);
707
713
  },
708
714
  disabled,
709
- "aria-label": date.toLocaleDateString("en-US", { weekday: "long", month: "long", day: "numeric" }),
710
- "aria-pressed": sel || void 0,
715
+ "aria-label": dayLabel(date),
716
+ "aria-pressed": Boolean(sel),
711
717
  children: date.getDate()
712
718
  },
713
719
  date.toISOString()
@@ -965,13 +971,15 @@ function TimeButton({
965
971
  timezone,
966
972
  loading
967
973
  }) {
974
+ const time = formatTime(slot.start, timezone);
975
+ const label = slotLabel(slot, timezone);
968
976
  if (selected && !confirmed) {
969
977
  return /* @__PURE__ */ jsxs("div", { className: "bw-time-btn-wrap selected", children: [
970
- /* @__PURE__ */ jsx("span", { className: "bw-time-text", children: formatTime(slot.start, timezone) }),
971
- /* @__PURE__ */ jsx("button", { className: "bw-time-confirm", onClick: onConfirm, disabled: loading, children: loading ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : "Confirm" })
978
+ /* @__PURE__ */ jsx("button", { type: "button", className: "bw-time-text", "aria-label": label, "aria-pressed": "true", onClick, disabled: loading, children: time }),
979
+ /* @__PURE__ */ jsx("button", { type: "button", className: "bw-time-confirm", "aria-label": `Confirm ${label}`, onClick: onConfirm, disabled: loading, children: loading ? /* @__PURE__ */ jsx(SpinnerIcon, {}) : "Confirm" })
972
980
  ] });
973
981
  }
974
- return /* @__PURE__ */ jsx("button", { className: `bw-time-btn${selected ? " selected" : ""}`, onClick, disabled: loading, children: formatTime(slot.start, timezone) });
982
+ return /* @__PURE__ */ jsx("button", { type: "button", className: `bw-time-btn${selected ? " selected" : ""}`, "aria-label": label, "aria-pressed": selected, onClick, disabled: loading, children: time });
975
983
  }
976
984
  var WIDGET_CSS = `
977
985
  /* \u2500\u2500 Base \u2500\u2500 */
@@ -1159,7 +1167,11 @@ var WIDGET_CSS = `
1159
1167
  .bw-time-btn-wrap .bw-time-text {
1160
1168
  flex: 1; padding: 10px 12px; font-size: 0.875rem; font-weight: 500; color: var(--sk-text-primary); text-align: center;
1161
1169
  background: var(--sk-primary-light);
1170
+ -webkit-appearance: none; appearance: none; border: none; border-radius: 0; margin: 0;
1171
+ font-family: inherit; line-height: inherit; letter-spacing: inherit; cursor: default;
1162
1172
  }
1173
+ /* The wrap clips its children, so focus rings go inside, in the text color. */
1174
+ .bw-time-btn-wrap button:focus-visible { outline-color: currentColor; outline-offset: -2px; }
1163
1175
  .bw-time-confirm {
1164
1176
  display: inline-flex; align-items: center; justify-content: center; gap: 4px;
1165
1177
  min-height: 44px; padding: 10px 16px; border: none;
@@ -3,7 +3,7 @@ import { registerAnalyticsDispatcher } from './chunk-LCDVPAMR.js';
3
3
  import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-24QZEO3Q.js';
4
4
  import { onPageLeave } from './chunk-L2V5PUFN.js';
5
5
  import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
6
- import { sonorFetch, sonorBeacon } from './chunk-3SDOQUUF.js';
6
+ import { sonorFetch, sonorBeacon } from './chunk-BEBR4OJD.js';
7
7
  import { createContext, useRef, useEffect, useState, useMemo, useCallback, useContext } from 'react';
8
8
  import { usePathname } from 'next/navigation';
9
9
  import { jsxs, jsx } from 'react/jsx-runtime';
@@ -157,7 +157,7 @@ function WebVitals({
157
157
  useEffect(() => {
158
158
  let cancelled = false;
159
159
  let teardown;
160
- import('./web-vitals.attribution-GD6LGLVF.js').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {
160
+ import('./web-vitals.attribution-N2PCCF4Q.js').then(({ onCLS, onLCP, onTTFB, onINP, onFCP }) => {
161
161
  if (cancelled) return;
162
162
  const { propApiUrl: propApiUrl2, propApiKey: propApiKey2, propSite: propSite2, allowInFrame: allowInFrame2, allowLocalhost: allowLocalhost2, debug: debug2, visitorId: visitorId2, sessionId: sessionId2, sessionTimeout: sessionTimeout2 } = propsRef.current;
163
163
  const sent = /* @__PURE__ */ new Map();
@@ -1,5 +1,5 @@
1
1
  'use client';
2
- import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-PGMVL4AB.js';
2
+ import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-I2YX3HVD.js';
3
3
  import { designTokensHash } from './chunk-IHG36STL.js';
4
4
  import { useDeferredActivation } from './chunk-YC7ELZS3.js';
5
5
  import { resolveAnalyticsTarget } from './chunk-43OCZ3JA.js';
@@ -0,0 +1,187 @@
1
+ 'use client';
2
+ import { useDeferredActivation } from './chunk-YC7ELZS3.js';
3
+ import { shellValuesToCarry } from './chunk-C2FZBUSS.js';
4
+ import { normalizeFormConfig } from './chunk-5SQK3D53.js';
5
+ import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
6
+ import React, { useRef, useEffect, useState, useMemo, useCallback } from 'react';
7
+ import { jsx, jsxs } from 'react/jsx-runtime';
8
+
9
+ var loadInteractiveForm = () => import('./ManagedForm-JRZAJ7SZ.js').then((m) => m.ManagedForm);
10
+ var REPLAY_WAIT_MS = 8e3;
11
+ function FormEnhancer({
12
+ formId,
13
+ initialConfig,
14
+ className,
15
+ experience,
16
+ defaultValues,
17
+ onSuccess,
18
+ onError,
19
+ enter = "fade",
20
+ defer = true,
21
+ children
22
+ }) {
23
+ const idle = useDeferredActivation(defer);
24
+ const [engaged, setEngaged] = useState(false);
25
+ const hostRef = useRef(null);
26
+ const [Interactive, setInteractive] = useState(null);
27
+ const [carried, setCarried] = useState(null);
28
+ const pendingSubmitRef = useRef(false);
29
+ const [enhanced, setEnhanced] = useState(false);
30
+ const fields = useMemo(() => {
31
+ if (!initialConfig) return void 0;
32
+ try {
33
+ return normalizeFormConfig(initialConfig).fields;
34
+ } catch {
35
+ return void 0;
36
+ }
37
+ }, [initialConfig]);
38
+ const honeypotName = initialConfig && typeof initialConfig.honeypot_field === "string" && initialConfig.honeypot_field || DEFAULT_HONEYPOT_FIELD;
39
+ useEffect(() => {
40
+ if (Interactive) return;
41
+ const form = hostRef.current?.querySelector("form");
42
+ if (!form) return;
43
+ const onSubmit = (event) => {
44
+ event.preventDefault();
45
+ pendingSubmitRef.current = true;
46
+ setEngaged(true);
47
+ };
48
+ const onEngage = () => setEngaged(true);
49
+ form.addEventListener("submit", onSubmit);
50
+ form.addEventListener("focusin", onEngage);
51
+ form.addEventListener("input", onEngage);
52
+ form.addEventListener("change", onEngage);
53
+ for (const button of Array.from(form.querySelectorAll("button[data-sk-shell-submit]"))) {
54
+ button.disabled = false;
55
+ }
56
+ return () => {
57
+ form.removeEventListener("submit", onSubmit);
58
+ form.removeEventListener("focusin", onEngage);
59
+ form.removeEventListener("input", onEngage);
60
+ form.removeEventListener("change", onEngage);
61
+ };
62
+ }, [Interactive]);
63
+ useEffect(() => {
64
+ if (Interactive || !(idle || engaged)) return;
65
+ let cancelled = false;
66
+ loadInteractiveForm().then((Component) => {
67
+ if (cancelled) return;
68
+ const form = hostRef.current?.querySelector("form") ?? null;
69
+ const active = typeof document !== "undefined" ? document.activeElement : null;
70
+ const focusName = form && active && form.contains(active) ? active.name || null : null;
71
+ setCarried({ values: shellValuesToCarry(form, fields, honeypotName), focusName });
72
+ setInteractive(() => Component);
73
+ }).catch((err) => {
74
+ console.error("[Forms] Enhancement failed to load; keeping the form as rendered:", err);
75
+ });
76
+ return () => {
77
+ cancelled = true;
78
+ };
79
+ }, [Interactive, idle, engaged, fields, honeypotName]);
80
+ const onEnhancedMount = useCallback(() => {
81
+ setEnhanced(true);
82
+ const host = hostRef.current;
83
+ if (!host) return;
84
+ const focusName = carried?.focusName;
85
+ if (focusName) {
86
+ const target = Array.from(host.querySelectorAll("input, select, textarea")).find(
87
+ (el) => el.name === focusName
88
+ );
89
+ target?.focus({ preventScroll: true });
90
+ }
91
+ if (!pendingSubmitRef.current) return;
92
+ pendingSubmitRef.current = false;
93
+ const started = Date.now();
94
+ const tryReplay = () => {
95
+ const form = hostRef.current?.querySelector("form");
96
+ if (form) {
97
+ form.requestSubmit();
98
+ return;
99
+ }
100
+ if (Date.now() - started < REPLAY_WAIT_MS) requestAnimationFrame(tryReplay);
101
+ };
102
+ requestAnimationFrame(tryReplay);
103
+ }, [carried]);
104
+ const seededValues = useMemo(
105
+ () => carried && Object.keys(carried.values).length > 0 ? { ...defaultValues || {}, ...carried.values } : defaultValues,
106
+ [carried, defaultValues]
107
+ );
108
+ return /* @__PURE__ */ jsxs(
109
+ "div",
110
+ {
111
+ ref: hostRef,
112
+ "data-sk-form-mount": enhanced ? "enhanced" : "shell",
113
+ "data-sk-part": "form-mount",
114
+ "data-sk-carried": carried && Object.keys(carried.values).length > 0 ? "true" : void 0,
115
+ style: enter === "fade" ? FADE_HOST : void 0,
116
+ children: [
117
+ enter === "fade" && /* @__PURE__ */ jsx(EnterStyles, {}),
118
+ Interactive ? /* @__PURE__ */ jsx(Enhanced, { onMount: onEnhancedMount, fallback: children, children: /* @__PURE__ */ jsx(
119
+ Interactive,
120
+ {
121
+ formId,
122
+ initialConfig,
123
+ className,
124
+ experience,
125
+ defaultValues: seededValues,
126
+ onSuccess,
127
+ onError
128
+ }
129
+ ) }) : children
130
+ ]
131
+ }
132
+ );
133
+ }
134
+ var Enhanced = class extends React.Component {
135
+ constructor() {
136
+ super(...arguments);
137
+ this.state = { failed: false };
138
+ }
139
+ static getDerivedStateFromError() {
140
+ return { failed: true };
141
+ }
142
+ componentDidCatch(err) {
143
+ console.error("[Forms] Enhancement failed; keeping the native form:", err);
144
+ }
145
+ componentDidMount() {
146
+ if (!this.state.failed) this.props.onMount();
147
+ }
148
+ render() {
149
+ if (this.state.failed) return this.props.fallback;
150
+ return /* @__PURE__ */ jsx(FrameTag, { children: this.props.children });
151
+ }
152
+ };
153
+ function FrameTag({ children }) {
154
+ const ref = useRef(null);
155
+ useEffect(() => {
156
+ const el = ref.current;
157
+ if (!el) return;
158
+ el.setAttribute("data-sk-enter", "");
159
+ const id = requestAnimationFrame(() => el.removeAttribute("data-sk-enter"));
160
+ return () => cancelAnimationFrame(id);
161
+ }, []);
162
+ return /* @__PURE__ */ jsx("div", { ref, style: { display: "contents" }, children });
163
+ }
164
+ var FADE_HOST = {
165
+ transition: "opacity var(--sk-form-enter-duration, 320ms) var(--sk-form-enter-easing, cubic-bezier(.22,1,.36,1))"
166
+ };
167
+ function EnterStyles() {
168
+ return /* @__PURE__ */ jsx(
169
+ "style",
170
+ {
171
+ dangerouslySetInnerHTML: {
172
+ __html: `
173
+ [data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:.55}
174
+ [data-sk-part="form-mount"][data-sk-form-mount="enhanced"]{opacity:1}
175
+ [data-sk-part="form-mount"] [data-sk-enter]{opacity:0;transform:translateY(var(--sk-form-enter-distance,6px))}
176
+ [data-sk-part="form-mount"] [data-sk-enter] *{transition:none!important}
177
+ @media (prefers-reduced-motion: reduce){
178
+ [data-sk-part="form-mount"]{transition:none!important}
179
+ [data-sk-part="form-mount"][data-sk-form-mount="shell"]{opacity:1}
180
+ [data-sk-part="form-mount"] [data-sk-enter]{opacity:1;transform:none}
181
+ }`
182
+ }
183
+ }
184
+ );
185
+ }
186
+
187
+ export { FormEnhancer };
@@ -1,5 +1,5 @@
1
1
  import { secretsMatch, readCappedBody } from './chunk-XTRZGXB2.js';
2
- import { SITE_KIT_VERSION } from './chunk-AH5Q262S.js';
2
+ import { SITE_KIT_VERSION } from './chunk-56KNHB4U.js';
3
3
 
4
4
  // src/llms/revalidate.ts
5
5
  function createLlmsRevalidateHandler(secret, options) {
@@ -16,14 +16,64 @@ var MANAGED_LLM_SCHEMA_KNOWN_KEYS = /* @__PURE__ */ new Set([
16
16
  "speakable",
17
17
  "additionalType"
18
18
  ]);
19
+ var SENTENCE_SHARE = 0.4;
20
+ var ELLIPSIS = "\u2026";
21
+ var CLOSERS = /* @__PURE__ */ new Set(['"', "'", ")", "]", "\u201D", "\u2019", "\xBB"]);
22
+ var ABBREVIATIONS = /* @__PURE__ */ new Set([
23
+ "mr",
24
+ "mrs",
25
+ "ms",
26
+ "dr",
27
+ "prof",
28
+ "st",
29
+ "mt",
30
+ "ft",
31
+ "jr",
32
+ "sr",
33
+ "inc",
34
+ "ltd",
35
+ "co",
36
+ "corp",
37
+ "vs",
38
+ "no"
39
+ ]);
40
+ var TRAILING_SEPARATORS = /[\s.,;:\-\u2013\u2014/&([{]+$/;
41
+ function clipAtWordBoundary(text, max) {
42
+ const flat = text.replace(/\s+/g, " ").trim();
43
+ if (flat.length <= max) return flat;
44
+ if (max < 2) return flat.slice(0, Math.max(0, max));
45
+ const floor = Math.floor(max * (1 - SENTENCE_SHARE));
46
+ for (let end = max; end > floor; end--) {
47
+ if (endsSentence(flat, end)) return flat.slice(0, end);
48
+ }
49
+ const room = max - 1;
50
+ const space = flat.lastIndexOf(" ", room);
51
+ if (space <= 0) return `${flat.slice(0, room)}${ELLIPSIS}`;
52
+ if (endsSentence(flat, space)) return flat.slice(0, space);
53
+ const head = flat.slice(0, space).replace(TRAILING_SEPARATORS, "");
54
+ return `${head || flat.slice(0, room)}${ELLIPSIS}`;
55
+ }
56
+ function endsSentence(flat, end) {
57
+ if (flat[end] !== " ") return false;
58
+ let i = end - 1;
59
+ while (i > 0 && CLOSERS.has(flat[i])) i--;
60
+ const terminator = flat[i];
61
+ if (terminator === "!" || terminator === "?") return true;
62
+ return terminator === "." && !isAbbreviation(flat, i);
63
+ }
64
+ function isAbbreviation(flat, dot) {
65
+ let start = dot;
66
+ while (start > 0 && flat[start - 1] !== " ") start--;
67
+ const token = flat.slice(start, dot).replace(/^[("'[\u201c\u2018]+/, "").toLowerCase();
68
+ if (token.includes(".") || /^[a-z]$/.test(token)) return true;
69
+ return ABBREVIATIONS.has(token);
70
+ }
19
71
  function sanitizeLlmsPublicSummary(raw) {
20
72
  if (raw === null || raw === void 0) return null;
21
73
  if (typeof raw !== "string") return null;
22
74
  let s = raw.trim().replace(/\s+/g, " ");
23
75
  s = s.replace(/[\[\]\r\n]/g, " ").replace(/\s+/g, " ").trim();
24
- if (s.length > LLMS_PUBLIC_SUMMARY_MAX_LENGTH) {
25
- s = `${s.slice(0, LLMS_PUBLIC_SUMMARY_MAX_LENGTH - 1).trimEnd()}\u2026`;
26
- }
76
+ s = clipAtWordBoundary(s, LLMS_PUBLIC_SUMMARY_MAX_LENGTH);
27
77
  if (/\b[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}\b/.test(s)) return null;
28
78
  if (/\b\+?\d[\d\s().-]{8,}\b/.test(s)) return null;
29
79
  if (s.length < 8) return null;
@@ -34,9 +84,7 @@ function sanitizeLlmsDisclaimerLine(raw) {
34
84
  if (typeof raw !== "string") return null;
35
85
  let s = raw.trim().replace(/\s+/g, " ");
36
86
  s = s.replace(/[\[\]\r\n]/g, " ").replace(/\s+/g, " ").trim();
37
- if (s.length > LLMS_DISCLAIMER_MAX_LENGTH) {
38
- s = `${s.slice(0, LLMS_DISCLAIMER_MAX_LENGTH - 1).trimEnd()}\u2026`;
39
- }
87
+ s = clipAtWordBoundary(s, LLMS_DISCLAIMER_MAX_LENGTH);
40
88
  if (/\b[\w.%+-]+@[\w.-]+\.[A-Za-z]{2,}\b/.test(s)) return null;
41
89
  if (/\b\+?\d[\d\s().-]{8,}\b/.test(s)) return null;
42
90
  if (s.length < 3) return null;
@@ -94,4 +142,4 @@ function pickManagedLlmSchemaForJsonLd(schema) {
94
142
  return Object.keys(out).length ? out : null;
95
143
  }
96
144
 
97
- export { LLMS_DISCLAIMER_MAX_LENGTH, LLMS_PUBLIC_SUMMARY_MAX_LENGTH, LLM_GEO_CONTRACT_VERSION, MANAGED_LLM_SCHEMA_KNOWN_KEYS, isEmittableReviewNode, pickManagedLlmSchemaForJsonLd, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary, sanitizePrimaryLanguageTag };
145
+ export { LLMS_DISCLAIMER_MAX_LENGTH, LLMS_PUBLIC_SUMMARY_MAX_LENGTH, LLM_GEO_CONTRACT_VERSION, MANAGED_LLM_SCHEMA_KNOWN_KEYS, clipAtWordBoundary, isEmittableReviewNode, pickManagedLlmSchemaForJsonLd, sanitizeLlmsDisclaimerLine, sanitizeLlmsPublicSummary, sanitizePrimaryLanguageTag };
@@ -1,9 +1,10 @@
1
1
  'use client';
2
+ import { VISUAL_VIEWPORT_GAP_PROPERTY } from './chunk-6T6CQVNL.js';
2
3
  import { GlassStyles } from './chunk-JE4A5S4F.js';
3
- import { chatLauncherStyles } from './chunk-NDF4A5JM.js';
4
- import { useForm } from './chunk-V6FDQLR7.js';
4
+ import { DEFAULT_WIDGET_Z_INDEX } from './chunk-27FISYK4.js';
5
+ import { useForm } from './chunk-EPT6FJUY.js';
5
6
  import { parseColor, relativeLuminance, DARK_LUMINANCE, contrastRatio } from './chunk-S22FSH7C.js';
6
- import { sonorFetch } from './chunk-3SDOQUUF.js';
7
+ import { sonorFetch } from './chunk-BEBR4OJD.js';
7
8
  import { useState, useEffect, useRef, useLayoutEffect, useCallback, Fragment as Fragment$1 } from 'react';
8
9
  import { lexer } from 'marked';
9
10
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -144,7 +145,7 @@ function Markdown({ children, components }) {
144
145
  return /* @__PURE__ */ jsx(Fragment, { children: blocks(lexer(children, { gfm: true }), components) });
145
146
  }
146
147
 
147
- // src/engage/brand-color.ts
148
+ // src/chat/brand-color.ts
148
149
  var TEXT_CONTRAST = 4.5;
149
150
  var RESTING_TINT = 0.082;
150
151
  var UNREADABLE_BRAND_SHARE = 40;
@@ -454,7 +455,40 @@ function EchoUiActions({ actions, primaryColor, primaryRgb, brandText, onSuggest
454
455
  ] });
455
456
  }
456
457
 
457
- // src/engage/chat-messages.ts
458
+ // src/chat/launcher-placement.ts
459
+ var DEFAULT_LAUNCHER_OFFSET_BOTTOM = "20px";
460
+ var LAUNCHER_OFFSET_PROPERTY = "--sk-echo-offset-bottom";
461
+ var SIDE_GUTTER = "20px";
462
+ var POPUP_ABOVE_LAUNCHER = "70px";
463
+ var POPUP_VERTICAL_RESERVE = "100px";
464
+ function toCssLength(value) {
465
+ if (typeof value === "number") return Number.isFinite(value) ? `${value}px` : void 0;
466
+ const trimmed = value?.trim();
467
+ return trimmed ? trimmed : void 0;
468
+ }
469
+ function chatLauncherStyles({ position, offsetBottom, zIndex } = {}) {
470
+ const side = position === "bottom-left" ? { left: SIDE_GUTTER } : { right: SIDE_GUTTER };
471
+ const offset = toCssLength(offsetBottom) ?? DEFAULT_LAUNCHER_OFFSET_BOTTOM;
472
+ const layer = typeof zIndex === "number" && Number.isFinite(zIndex) ? zIndex : DEFAULT_WIDGET_Z_INDEX;
473
+ const clearance = `var(${LAUNCHER_OFFSET_PROPERTY}, ${offset}) + env(safe-area-inset-bottom, 0px) + var(${VISUAL_VIEWPORT_GAP_PROPERTY}, 0px)`;
474
+ return {
475
+ launcher: {
476
+ ...side,
477
+ bottom: `calc(${clearance})`
478
+ },
479
+ popup: {
480
+ ...side,
481
+ bottom: `calc(${clearance} + ${POPUP_ABOVE_LAUNCHER})`,
482
+ maxHeight: `calc(100dvh - (${clearance}) - ${POPUP_VERTICAL_RESERVE})`
483
+ },
484
+ // One beneath the launcher. At 0 or below, the same layer instead: -1
485
+ // would paint the popup behind the page's own content, and at a shared
486
+ // layer the launcher, which renders after the popup, still paints on top.
487
+ zIndex: { launcher: layer, popup: layer > 0 ? layer - 1 : layer }
488
+ };
489
+ }
490
+
491
+ // src/chat/chat-messages.ts
458
492
  function userRequestedHandoff(text) {
459
493
  const lower = text.toLowerCase().trim();
460
494
  const patterns = [
@@ -839,7 +873,7 @@ function EchoChat({ projectId, widgetConfig, config, apiUrl: propApiUrl, signalU
839
873
  socketRef.current.disconnect();
840
874
  socketRef.current = null;
841
875
  }
842
- const { createSocket } = await import('./socket-loader-R24ZSRSQ.js');
876
+ const { createSocket } = await import('./socket-loader-CGIPEG74.js');
843
877
  const namespaceUrl = `${baseUrl.replace(/\/$/, "")}/engage/chat`;
844
878
  const socket = await createSocket(namespaceUrl, {
845
879
  query: { projectId, visitorId, sessionId: currentSessionId },
@@ -1800,4 +1834,4 @@ function EchoChat({ projectId, widgetConfig, config, apiUrl: propApiUrl, signalU
1800
1834
  ] });
1801
1835
  }
1802
1836
 
1803
- export { ChatWidget, EchoChat, isChatEnabled };
1837
+ export { ChatWidget, DEFAULT_LAUNCHER_OFFSET_BOTTOM, EchoChat, chatLauncherStyles, isChatEnabled };