@sonordev/site-kit 8.1.0 → 8.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 (194) hide show
  1. package/AGENTS.md +13 -1
  2. package/CHANGELOG.md +11 -0
  3. package/README.md +9 -5
  4. package/agent-manifest.json +47 -8
  5. package/dist/{AnalyticsProvider-UWTCE5UO.js → AnalyticsProvider-QXO33JUF.js} +6 -6
  6. package/dist/{ArticleFaqSection-3Q26DP7P.js → ArticleFaqSection-DEWE5B4Q.js} +1 -1
  7. package/dist/{ArticleViewTracker-MYD6SGNH.js → ArticleViewTracker-KN6ENIRS.js} +17 -6
  8. package/dist/{BlocksPopup-OY5G3EFH.js → BlocksPopup-3RPN6YVJ.js} +6 -6
  9. package/dist/{ChatWidget-BTR5VERC.js → ChatWidget-D2X445PO.js} +6 -6
  10. package/dist/{FileField-DEHVYXAO.js → FileField-UNGSNGJ5.js} +4 -4
  11. package/dist/{FormSpotlight-VGC4CZL4.js → FormSpotlight-JFH2ENKQ.js} +1 -1
  12. package/dist/{FormStage-CJUSCSAL.js → FormStage-RC3WHHXP.js} +1 -1
  13. package/dist/{ManagedForm-JCI2KPMO.js → ManagedForm-FOQZ2IYG.js} +7 -7
  14. package/dist/{ManagedNewsletterForm-DTE4KKXV.js → ManagedNewsletterForm-NFNF33V3.js} +16 -7
  15. package/dist/{SignalCore-LGCBQDEH.js → SignalCore-5KABGX5C.js} +4 -4
  16. package/dist/SiteChat-JQ46ZIJ4.js +6 -0
  17. package/dist/SiteDesignReporter-N7L6DR4J.js +12 -0
  18. package/dist/{SitePopups-T6YPHAVY.js → SitePopups-WZBKX5Q3.js} +6 -6
  19. package/dist/SitemapSync-GY6UADRI.js +9 -0
  20. package/dist/_client/booking-widget.js +6 -6
  21. package/dist/_client/testimonial-section.js +3 -3
  22. package/dist/affiliates/index.js +4 -4
  23. package/dist/analytics/index.js +6 -6
  24. package/dist/{article-styles-GGZOQG5X.js → article-styles-7QONZJR5.js} +3 -3
  25. package/dist/article-tables-6XHVULPU.js +2 -0
  26. package/dist/articles/Article.d.ts +2 -89
  27. package/dist/articles/ArticleFAQ.d.ts +2 -41
  28. package/dist/articles/ArticleFaqSection.d.ts +2 -2
  29. package/dist/articles/ArticleList.d.ts +2 -79
  30. package/dist/articles/ArticleViewTracker.d.ts +2 -15
  31. package/dist/articles/AuthorCard.d.ts +2 -10
  32. package/dist/articles/AuthorPage.d.ts +2 -8
  33. package/dist/articles/ClusterLandingPage.d.ts +2 -40
  34. package/dist/articles/ClusterNavigation.d.ts +2 -37
  35. package/dist/articles/ManagedNewsletterForm.d.ts +3 -12
  36. package/dist/articles/NewsletterShell.d.ts +2 -17
  37. package/dist/articles/NewsletterWidget.d.ts +2 -30
  38. package/dist/articles/PublicationLayout.d.ts +2 -67
  39. package/dist/articles/PublicationSidebar.d.ts +2 -36
  40. package/dist/articles/RelatedPosts.d.ts +2 -22
  41. package/dist/articles/ServiceCallout.d.ts +2 -56
  42. package/dist/articles/TableOfContents.d.ts +2 -6
  43. package/dist/articles/article-photos.d.ts +2 -9
  44. package/dist/articles/article-styles.d.ts +2 -21
  45. package/dist/articles/article-tables.d.ts +2 -12
  46. package/dist/articles/artwork.d.ts +2 -13
  47. package/dist/articles/author-schema.d.ts +2 -72
  48. package/dist/articles/author-social.d.ts +2 -14
  49. package/dist/articles/excerpt.d.ts +2 -17
  50. package/dist/articles/index.d.ts +2 -79
  51. package/dist/articles/index.js +16 -11
  52. package/dist/articles/news-sitemap.d.ts +2 -46
  53. package/dist/articles/processArticleHtml.d.ts +2 -34
  54. package/dist/articles/public-reads.d.ts +2 -26
  55. package/dist/articles/reading-time.d.ts +2 -9
  56. package/dist/articles/routes.d.ts +2 -52
  57. package/dist/articles/server-core.d.ts +2 -461
  58. package/dist/articles/server-ui.d.ts +2 -30
  59. package/dist/articles/server-ui.js +26 -17
  60. package/dist/articles/server.d.ts +2 -461
  61. package/dist/articles/server.js +14 -5
  62. package/dist/articles/types.d.ts +2 -315
  63. package/dist/articles/widget-styles.d.ts +2 -8
  64. package/dist/chat/index.js +8 -8
  65. package/dist/{chunk-AIDIEVPZ.js → chunk-2JMCBJM5.js} +1 -1
  66. package/dist/chunk-34ZYJTQR.js +1 -0
  67. package/dist/{chunk-ADI6IYFH.js → chunk-3OY52UFM.js} +1 -1
  68. package/dist/{chunk-WMVK77ND.js → chunk-4K735O3J.js} +1 -1
  69. package/dist/{chunk-55GHBRCN.js → chunk-4PVMUPC6.js} +2 -2
  70. package/dist/{chunk-L5UOHS6E.js → chunk-5D7ZISUP.js} +1 -1
  71. package/dist/{chunk-JT52KYHQ.js → chunk-5RYSTKVU.js} +1 -1
  72. package/dist/{chunk-6CJGZFOU.js → chunk-A4MPHIVP.js} +1 -1
  73. package/dist/chunk-B7T2SFUF.js +1 -0
  74. package/dist/{chunk-FV2VD7WM.js → chunk-BC7JMY4Z.js} +3 -3
  75. package/dist/{chunk-255NCCPB.js → chunk-BOCYBDKV.js} +1 -1
  76. package/dist/{chunk-NFRJTOTB.js → chunk-BSQP6PRA.js} +1 -1
  77. package/dist/{chunk-GKGSXUVQ.js → chunk-BVB5FBAA.js} +1 -1
  78. package/dist/{chunk-NWVB75ER.js → chunk-C2UROFGZ.js} +1 -1
  79. package/dist/{chunk-F2VYN3QL.js → chunk-C4AFNZT2.js} +1 -1
  80. package/dist/{chunk-GC2QWXJ3.js → chunk-D6ZIQMHB.js} +3 -3
  81. package/dist/{chunk-GYF2ULVO.js → chunk-DJAYFHVF.js} +1 -1
  82. package/dist/{chunk-XUCU3LX4.js → chunk-DPSNMOMZ.js} +1 -1
  83. package/dist/{chunk-A3EU6HB5.js → chunk-E3UR37RX.js} +2 -2
  84. package/dist/{chunk-Y3INC4QJ.js → chunk-E4PTMORJ.js} +1 -1
  85. package/dist/{chunk-TAO6BVA2.js → chunk-EA6FZMYA.js} +2 -2
  86. package/dist/{chunk-V56RZH7J.js → chunk-FHUTOXS7.js} +1 -1
  87. package/dist/{chunk-LLW5HKEE.js → chunk-GKJVSZ7H.js} +3 -3
  88. package/dist/chunk-H72ZFO3F.js +1 -0
  89. package/dist/{chunk-CSTC6HZO.js → chunk-HND6BDXC.js} +3 -3
  90. package/dist/chunk-IEGDPRQB.js +14 -0
  91. package/dist/{chunk-CAH4Y4PY.js → chunk-JO76F5WP.js} +1 -1
  92. package/dist/{chunk-4Z3DI2EL.js → chunk-KJVUOJMW.js} +58 -58
  93. package/dist/{chunk-SC4MZGWZ.js → chunk-LBDWAXAO.js} +1 -1
  94. package/dist/{chunk-RSBMQFZW.js → chunk-LPKKSYKX.js} +3 -3
  95. package/dist/{chunk-2UO4HPGE.js → chunk-M5SF7NCC.js} +73 -51
  96. package/dist/{chunk-S6IGQYHW.js → chunk-MQ4REMTH.js} +2 -2
  97. package/dist/{chunk-O4DETQJI.js → chunk-NA4Z4CQG.js} +1 -1
  98. package/dist/{chunk-WPOFTCKL.js → chunk-OIWFXUVD.js} +2 -2
  99. package/dist/{chunk-G2HCCWZQ.js → chunk-QBCWVT2S.js} +2 -2
  100. package/dist/{chunk-DZV3KPVF.js → chunk-QCZHYO5M.js} +1 -1
  101. package/dist/{chunk-DOMBP3FW.js → chunk-QDILCQBL.js} +9 -9
  102. package/dist/{chunk-IAYGTQJD.js → chunk-SCTVADDL.js} +2 -2
  103. package/dist/{chunk-QXMIKDOL.js → chunk-SNRE3ZVZ.js} +3 -3
  104. package/dist/{chunk-DSNCU2E3.js → chunk-TT4JZDKM.js} +3 -3
  105. package/dist/{chunk-6VHDCJIZ.js → chunk-U7Y3QG3A.js} +1 -1
  106. package/dist/{chunk-3G7YABRA.js → chunk-W7OPEMGJ.js} +4 -1
  107. package/dist/{chunk-2JEUDTL6.js → chunk-WBUG7XRL.js} +2 -2
  108. package/dist/{chunk-47VB5INH.js → chunk-WSOZ3FQN.js} +1 -1
  109. package/dist/chunk-X4IJS7LV.js +319 -0
  110. package/dist/{chunk-JIH32RH2.js → chunk-XA7Q2VQA.js} +1 -1
  111. package/dist/{chunk-5L467Z5Q.js → chunk-XLAXYPTK.js} +3 -3
  112. package/dist/client/index.js +4 -16
  113. package/dist/contracts/editorial-media.d.ts +39 -0
  114. package/dist/contracts/entries.d.ts +1 -1
  115. package/dist/fleet/index.js +6 -6
  116. package/dist/forms/index.js +9 -325
  117. package/dist/forms/server.js +2 -2
  118. package/dist/images/index.js +4 -4
  119. package/dist/index.js +1 -1
  120. package/dist/layout/client.js +9 -9
  121. package/dist/layout/index.js +10 -10
  122. package/dist/llms/index.js +8 -8
  123. package/dist/maps/index.js +4 -4
  124. package/dist/mcp/sonor.d.ts +42 -3
  125. package/dist/mcp/sonor.js +25 -20
  126. package/dist/mcp/transport.d.ts +1 -1
  127. package/dist/press-kit/articles/Article.d.ts +89 -0
  128. package/dist/press-kit/articles/ArticleFAQ.d.ts +41 -0
  129. package/dist/press-kit/articles/ArticleFaqSection.d.ts +2 -0
  130. package/dist/press-kit/articles/ArticleList.d.ts +79 -0
  131. package/dist/press-kit/articles/ArticleViewTracker.d.ts +15 -0
  132. package/dist/press-kit/articles/AuthorCard.d.ts +10 -0
  133. package/dist/press-kit/articles/AuthorPage.d.ts +8 -0
  134. package/dist/press-kit/articles/ClusterLandingPage.d.ts +40 -0
  135. package/dist/press-kit/articles/ClusterNavigation.d.ts +37 -0
  136. package/dist/press-kit/articles/ManagedNewsletterForm.d.ts +12 -0
  137. package/dist/press-kit/articles/NewsletterShell.d.ts +17 -0
  138. package/dist/press-kit/articles/NewsletterWidget.d.ts +30 -0
  139. package/dist/press-kit/articles/PublicationLayout.d.ts +67 -0
  140. package/dist/press-kit/articles/PublicationSidebar.d.ts +36 -0
  141. package/dist/press-kit/articles/RelatedPosts.d.ts +22 -0
  142. package/dist/press-kit/articles/ServiceCallout.d.ts +56 -0
  143. package/dist/press-kit/articles/TableOfContents.d.ts +6 -0
  144. package/dist/press-kit/articles/article-photos.d.ts +9 -0
  145. package/dist/press-kit/articles/article-styles.d.ts +21 -0
  146. package/dist/press-kit/articles/article-tables.d.ts +12 -0
  147. package/dist/press-kit/articles/artwork.d.ts +13 -0
  148. package/dist/press-kit/articles/author-schema.d.ts +72 -0
  149. package/dist/press-kit/articles/author-social.d.ts +14 -0
  150. package/dist/press-kit/articles/excerpt.d.ts +17 -0
  151. package/dist/press-kit/articles/index.d.ts +79 -0
  152. package/dist/press-kit/articles/news-sitemap.d.ts +46 -0
  153. package/dist/press-kit/articles/processArticleHtml.d.ts +34 -0
  154. package/dist/press-kit/articles/public-reads.d.ts +26 -0
  155. package/dist/press-kit/articles/reading-time.d.ts +9 -0
  156. package/dist/press-kit/articles/routes.d.ts +52 -0
  157. package/dist/press-kit/articles/server-core.d.ts +461 -0
  158. package/dist/press-kit/articles/server-ui.d.ts +31 -0
  159. package/dist/press-kit/articles/types.d.ts +316 -0
  160. package/dist/press-kit/articles/widget-styles.d.ts +8 -0
  161. package/dist/reputation/index.js +3 -3
  162. package/dist/reputation/server.js +2 -2
  163. package/dist/revalidate/index.js +2 -2
  164. package/dist/runtime/index.js +5 -4
  165. package/dist/seo/client.js +6 -6
  166. package/dist/seo/index.js +7 -7
  167. package/dist/seo/llms.js +8 -8
  168. package/dist/seo/register-sitemap-cli.js +1 -1
  169. package/dist/seo/sitemap.js +6 -6
  170. package/dist/server/index.js +3 -2
  171. package/dist/shared/build-entries.d.ts +2 -1
  172. package/dist/shared/clientApiConfig.d.ts +2 -0
  173. package/dist/shared/import-specifiers.d.ts +1 -1
  174. package/dist/shared/index.d.ts +6 -0
  175. package/dist/shared/index.js +8 -0
  176. package/dist/shared/version.d.ts +1 -1
  177. package/dist/signal/index.js +2 -2
  178. package/dist/sitemap/index.js +6 -6
  179. package/dist/sync/index.js +6 -6
  180. package/dist/website/images.js +4 -4
  181. package/dist/website/index.js +7 -7
  182. package/dist/website/popups.js +6 -6
  183. package/dist/{writeLLMsTxt-OS2WBSLM.js → writeLLMsTxt-VKHCM5IS.js} +5 -5
  184. package/docs/MIGRATING-TO-PRESS-KIT.md +83 -0
  185. package/docs.json +145 -29
  186. package/package.json +15 -5
  187. package/src/articles/README.md +5 -360
  188. package/src/mcp/README.md +16 -0
  189. package/src/og/README.md +1 -1
  190. package/src/runtime/README.md +4 -0
  191. package/dist/SiteChat-6SF7PVUT.js +0 -6
  192. package/dist/SiteDesignReporter-VISQZ5NQ.js +0 -12
  193. package/dist/SitemapSync-VKMVRPZL.js +0 -9
  194. package/dist/article-tables-AXSZOGNW.js +0 -2
@@ -1,64 +1,12 @@
1
- import { insertArticlePhotos } from './chunk-2UO4HPGE.js';
2
- import { generateArticleAuthorNode, resolveArticleArtwork, withArticleAuthorIdentity } from './chunk-QXMIKDOL.js';
3
- import { resolveArticleUrl, createPublicationRoutes, resolvePublicationUrl, articleCategorySlug } from './chunk-WMVK77ND.js';
1
+ import { insertArticlePhotos } from './chunk-M5SF7NCC.js';
2
+ import { generateArticleAuthorNode, resolveArticleArtwork, withArticleAuthorIdentity } from './chunk-SNRE3ZVZ.js';
3
+ import { resolveArticleUrl, createPublicationRoutes, resolvePublicationUrl, articleCategorySlug } from './chunk-4K735O3J.js';
4
4
  import { withoutSchemaPlaceholders } from './chunk-VWWITFWM.js';
5
5
  import { withSiteParam, withSiteBody } from './chunk-MJP63SSS.js';
6
6
  import { resolveServerApiConfig } from './chunk-C7TLGL3R.js';
7
7
  import { notFound } from 'next/navigation';
8
8
 
9
- // src/articles/public-reads.ts
10
- async function fetchArticleBySlug({ apiUrl, apiKey, site }, slug) {
11
- try {
12
- const response = await fetch(withSiteParam(`${apiUrl}/public/articles/posts/${slug}`, site), {
13
- headers: { "x-api-key": apiKey },
14
- next: { revalidate: 60 }
15
- });
16
- if (!response.ok) {
17
- if (response.status !== 404) console.error("[Articles] Failed to fetch post:", response.statusText);
18
- return null;
19
- }
20
- const data = await response.json();
21
- return data.post || null;
22
- } catch (error) {
23
- console.error("[Articles] Error fetching post:", error);
24
- return null;
25
- }
26
- }
27
- async function fetchArticleCategories({ apiUrl, apiKey, site }) {
28
- try {
29
- const response = await fetch(withSiteParam(`${apiUrl}/public/articles/categories`, site), {
30
- headers: { "x-api-key": apiKey },
31
- next: { revalidate: 300 }
32
- });
33
- if (!response.ok) return [];
34
- const data = await response.json();
35
- return data.categories || [];
36
- } catch (error) {
37
- console.error("[Articles] Error fetching categories:", error);
38
- return [];
39
- }
40
- }
41
- async function fetchRelatedArticles({ apiUrl, apiKey, site }, currentPostId, limit, cache = {}) {
42
- try {
43
- const response = await fetch(`${apiUrl}/public/articles/related`, {
44
- method: "POST",
45
- headers: { "Content-Type": "application/json", "x-api-key": apiKey },
46
- body: JSON.stringify(withSiteBody({ current_post_id: currentPostId, limit }, site)),
47
- ...cache.revalidate !== void 0 ? { next: { revalidate: cache.revalidate } } : {}
48
- });
49
- if (!response.ok) {
50
- console.error("[Articles] Failed to fetch related posts:", response.statusText);
51
- return [];
52
- }
53
- const data = await response.json();
54
- return data.posts || [];
55
- } catch (error) {
56
- console.error("[Articles] Error fetching related posts:", error);
57
- return [];
58
- }
59
- }
60
-
61
- // src/articles/excerpt.ts
9
+ // packages/press-kit/src/articles/excerpt.ts
62
10
  function sanitizeExcerpt(raw, maxLength = 160) {
63
11
  if (!raw) return "";
64
12
  let text = String(raw).trim();
@@ -90,7 +38,7 @@ function sanitizeExcerpt(raw, maxLength = 160) {
90
38
  return `${(lastSpace > maxLength * 0.6 ? cut.slice(0, lastSpace) : cut).replace(/[\s,;:—–-]+$/, "")}\u2026`;
91
39
  }
92
40
 
93
- // src/articles/news-sitemap.ts
41
+ // packages/press-kit/src/articles/news-sitemap.ts
94
42
  var NEWS_SITEMAP_WINDOW_MS = 2 * 24 * 60 * 60 * 1e3;
95
43
  var NEWS_SITEMAP_MAX_URLS = 1e3;
96
44
  var FEED_DEFAULT_ITEMS = 20;
@@ -128,7 +76,59 @@ function buildNewsSitemapXml(posts, options, now = /* @__PURE__ */ new Date()) {
128
76
  ${items.join("\n")}${items.length ? "\n" : ""}</urlset>`;
129
77
  }
130
78
 
131
- // src/articles/server-core.ts
79
+ // packages/press-kit/src/articles/public-reads.ts
80
+ async function fetchArticleBySlug({ apiUrl, apiKey, site }, slug) {
81
+ try {
82
+ const response = await fetch(withSiteParam(`${apiUrl}/public/articles/posts/${slug}`, site), {
83
+ headers: { "x-api-key": apiKey },
84
+ next: { revalidate: 60 }
85
+ });
86
+ if (!response.ok) {
87
+ if (response.status !== 404) console.error("[Articles] Failed to fetch post:", response.statusText);
88
+ return null;
89
+ }
90
+ const data = await response.json();
91
+ return data.post || null;
92
+ } catch (error) {
93
+ console.error("[Articles] Error fetching post:", error);
94
+ return null;
95
+ }
96
+ }
97
+ async function fetchArticleCategories({ apiUrl, apiKey, site }) {
98
+ try {
99
+ const response = await fetch(withSiteParam(`${apiUrl}/public/articles/categories`, site), {
100
+ headers: { "x-api-key": apiKey },
101
+ next: { revalidate: 300 }
102
+ });
103
+ if (!response.ok) return [];
104
+ const data = await response.json();
105
+ return data.categories || [];
106
+ } catch (error) {
107
+ console.error("[Articles] Error fetching categories:", error);
108
+ return [];
109
+ }
110
+ }
111
+ async function fetchRelatedArticles({ apiUrl, apiKey, site }, currentPostId, limit, cache = {}) {
112
+ try {
113
+ const response = await fetch(`${apiUrl}/public/articles/related`, {
114
+ method: "POST",
115
+ headers: { "Content-Type": "application/json", "x-api-key": apiKey },
116
+ body: JSON.stringify(withSiteBody({ current_post_id: currentPostId, limit }, site)),
117
+ ...cache.revalidate !== void 0 ? { next: { revalidate: cache.revalidate } } : {}
118
+ });
119
+ if (!response.ok) {
120
+ console.error("[Articles] Failed to fetch related posts:", response.statusText);
121
+ return [];
122
+ }
123
+ const data = await response.json();
124
+ return data.posts || [];
125
+ } catch (error) {
126
+ console.error("[Articles] Error fetching related posts:", error);
127
+ return [];
128
+ }
129
+ }
130
+
131
+ // packages/press-kit/src/articles/server-core.ts
132
132
  var SEO_LIMITS = {
133
133
  title: { min: 30, max: 60, recommended: 55 },
134
134
  metaDescription: { min: 120, max: 160, recommended: 155 },
@@ -1,4 +1,4 @@
1
- import { widgetStyle, widgetTitleStyle } from './chunk-GYF2ULVO.js';
1
+ import { widgetStyle, widgetTitleStyle } from './chunk-DJAYFHVF.js';
2
2
  import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
3
3
 
4
4
  function NewsletterShell({
@@ -1,9 +1,9 @@
1
1
  'use client';
2
2
  import { sanitizeFleetVersion, buildFleetHeartbeatPayload } from './chunk-ZTZQPYP6.js';
3
3
  import { useDeferredActivation } from './chunk-YC7ELZS3.js';
4
- import { resolveAnalyticsTarget } from './chunk-CAH4Y4PY.js';
5
- import { sonorFetch } from './chunk-WPOFTCKL.js';
6
- import { SITE_KIT_VERSION } from './chunk-NWVB75ER.js';
4
+ import { resolveAnalyticsTarget } from './chunk-JO76F5WP.js';
5
+ import { sonorFetch } from './chunk-OIWFXUVD.js';
6
+ import { SITE_KIT_VERSION } from './chunk-C2UROFGZ.js';
7
7
  import { useRef, useEffect } from 'react';
8
8
 
9
9
  // src/fleet/heartbeat.ts
@@ -1,10 +1,9 @@
1
- // src/articles/article-photos.ts
1
+ // src/contracts/editorial-media.ts
2
2
  var voidElements = /* @__PURE__ */ new Set(["area", "base", "br", "col", "embed", "hr", "img", "input", "link", "meta", "param", "source", "track", "wbr"]);
3
3
  var rawElements = /* @__PURE__ */ new Set(["pre", "code", "script", "style", "textarea", "xmp", "template"]);
4
4
  var excludedAncestors = /* @__PURE__ */ new Set(["figure", "table", "ul", "ol", "blockquote", "aside", "nav", "header", "footer"]);
5
5
  var tags = () => /<!--[\s\S]*?(?:-->|$)|<\/?[a-z][\w:-]*(?=[\s/>])(?:[^"'<>]|"[^"]*"|'[^']*')*>/gi;
6
- var escape = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
7
- function headingText(value) {
6
+ function editorialPlainText(value) {
8
7
  const entities = { amp: "&", lt: "<", gt: ">", quot: '"', apos: "'", nbsp: " ", rsquo: "\u2019", lsquo: "\u2018", ldquo: "\u201C", rdquo: "\u201D", ndash: "\u2013", mdash: "\u2014" };
9
8
  return value.replace(/<!--[\s\S]*?-->/g, "").replace(tags(), "").replace(/&(#x[\da-f]+|#\d+|[a-z]+);/gi, (full, entity) => {
10
9
  if (!entity.startsWith("#")) return entities[entity.toLowerCase()] ?? full;
@@ -12,31 +11,24 @@ function headingText(value) {
12
11
  return number > 0 && number <= 1114111 ? String.fromCodePoint(number) : full;
13
12
  }).replace(/\s+/g, " ").trim();
14
13
  }
15
- function photoUrl(value) {
16
- if (typeof value !== "string" || value.length > 2e3 || /[\s\\]/.test(value)) return null;
17
- try {
18
- const url = new URL(value);
19
- if (url.protocol !== "https:" || url.username || url.password || /\/Blog\/(Cards|Carousel)\//i.test(decodeURIComponent(url.pathname))) return null;
20
- return url.href;
21
- } catch {
22
- return null;
23
- }
14
+ function editorialTextId(kind, text) {
15
+ const normalized = editorialPlainText(text);
16
+ let hash = 2166136261;
17
+ for (let i = 0; i < normalized.length; i++) hash = Math.imul(hash ^ normalized.charCodeAt(i), 16777619);
18
+ return `${kind}-${(hash >>> 0).toString(16).padStart(8, "0")}-${normalized.length}`;
24
19
  }
25
- function figure(photo, index) {
26
- const url = photoUrl(photo.url);
27
- if (!url || typeof photo.alt !== "string" || !photo.alt.trim() || photo.alt.length > 300) return null;
28
- if (![photo.width, photo.height].every((n) => Number.isInteger(n) && n > 0 && n <= 2400)) return null;
29
- const caption = typeof photo.caption === "string" && photo.caption.trim() ? `<figcaption>${escape(photo.caption.slice(0, 300))}</figcaption>` : "";
30
- return `<figure class="sk-article-photo" data-sk-editorial-photo="${index}"><img src="${escape(url)}" alt="${escape(photo.alt)}" width="${photo.width}" height="${photo.height}" loading="lazy" decoding="async" style="display:block;max-width:100%;height:auto" />${caption}</figure>`;
20
+ function attributes(tag) {
21
+ const out = /* @__PURE__ */ new Map();
22
+ const body = tag.replace(/^<[^\s>]+/, "").replace(/\/?\s*>$/, "");
23
+ for (const match of body.matchAll(/([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s>]+)))?/g)) out.set(match[1].toLowerCase(), editorialPlainText(match[2] ?? match[3] ?? match[4] ?? ""));
24
+ return out;
31
25
  }
32
- function insertArticlePhotos(html, photos) {
33
- if (!html || !Array.isArray(photos) || !photos.length) return html;
26
+ function resolveArticlePhotoPlacements(html, photos = []) {
34
27
  const pattern = tags();
35
28
  const stack = [];
36
29
  const headings = [];
37
30
  const paragraphs = [];
38
- const existing = /* @__PURE__ */ new Set();
39
- const existingSlots = /* @__PURE__ */ new Set();
31
+ const existing = /* @__PURE__ */ new Set(), existingSlots = /* @__PURE__ */ new Set();
40
32
  let token;
41
33
  while (token = pattern.exec(html)) {
42
34
  const tag = token[0];
@@ -47,8 +39,9 @@ function insertArticlePhotos(html, photos) {
47
39
  if (at < 0) continue;
48
40
  const frame = stack[at];
49
41
  if (frame.eligible) {
50
- if (/^h[1-6]$/.test(name)) headings.push({ text: headingText(html.slice(frame.inner, token.index)), start: frame.start, end: pattern.lastIndex, level: Number(name[1]) });
51
- if (name === "p" && headingText(html.slice(frame.inner, token.index))) paragraphs.push({ start: frame.start, end: pattern.lastIndex });
42
+ const text = editorialPlainText(html.slice(frame.inner, token.index));
43
+ if (/^h[1-6]$/.test(name)) headings.push({ id: frame.id || editorialTextId("section", text), text, level: Number(name[1]), start: frame.start, end: pattern.lastIndex, eligible: false });
44
+ if (name === "p" && text) paragraphs.push({ start: frame.start, end: pattern.lastIndex });
52
45
  }
53
46
  stack.length = at;
54
47
  continue;
@@ -60,39 +53,68 @@ function insertArticlePhotos(html, photos) {
60
53
  pattern.lastIndex = closing.lastIndex;
61
54
  continue;
62
55
  }
63
- const attrs = tag.replace(/^<[\w:-]+/, "").replace(/\/?>$/, "");
64
- for (const match of attrs.matchAll(/([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g)) {
65
- const key = match[1].toLowerCase(), value = match[2] ?? match[3] ?? match[4] ?? "";
66
- if (name === "img" && key === "src") existing.add(headingText(value));
67
- if (name === "figure" && key === "data-sk-editorial-photo" && /^\d+$/.test(value)) existingSlots.add(Number(value));
68
- }
56
+ const attrs = attributes(tag);
57
+ if (name === "img" && attrs.has("src")) existing.add(attrs.get("src"));
58
+ if (name === "figure" && /^\d+$/.test(attrs.get("data-sk-editorial-photo") ?? "")) existingSlots.add(Number(attrs.get("data-sk-editorial-photo")));
69
59
  if (voidElements.has(name) || /\/\s*>$/.test(tag)) continue;
70
- stack.push({ name, start: token.index, inner: pattern.lastIndex, eligible: !stack.some((frame) => excludedAncestors.has(frame.name)) });
60
+ stack.push({ name, start: token.index, inner: pattern.lastIndex, id: attrs.get("id"), eligible: !stack.some((frame) => excludedAncestors.has(frame.name)) });
71
61
  }
72
- const additions = /* @__PURE__ */ new Map();
73
- photos.slice(0, 8).forEach((photo, index) => {
74
- if (!photo || existingSlots.has(index)) return;
75
- const rendered = figure(photo, index);
76
- const url = photoUrl(photo.url);
77
- if (!rendered || !url || existing.has(url)) return;
62
+ const paragraphFor = (heading) => {
63
+ const next = headings.find((item) => item.start > heading.start);
64
+ return paragraphs.find((p) => p.start >= heading.end && (!next || p.end < next.start));
65
+ };
66
+ for (const heading of headings) heading.eligible = !!paragraphFor(heading);
67
+ const placements = photos.map((photo, index) => {
68
+ if (existingSlots.has(index) || photo.url && existing.has(photo.url)) return { index, status: "already_present" };
78
69
  let paragraph;
79
70
  if (photo.placement?.kind === "after_intro") {
80
- const firstSection = headings.find((heading) => heading.level > 1);
71
+ const firstSection = headings.find((h) => h.level > 1);
81
72
  paragraph = paragraphs.find((p) => !firstSection || p.start < firstSection.start);
82
- } else if (photo.placement?.kind === "after_heading" && typeof photo.placement.heading === "string") {
83
- const expectedHeading = headingText(photo.placement.heading);
84
- const matches = headings.filter((heading2) => heading2.text === expectedHeading);
85
- if (matches.length !== 1) return;
86
- const heading = matches[0];
87
- const next = headings.find((item) => item.start > heading.start);
88
- paragraph = paragraphs.find((p) => p.start >= heading.end && (!next || p.end < next.start));
89
- }
90
- if (!paragraph) return;
91
- const images = additions.get(paragraph.end) || [];
92
- images.push(rendered);
93
- additions.set(paragraph.end, images);
94
- existing.add(url);
73
+ } else if (photo.placement?.kind === "after_heading") {
74
+ const placement = photo.placement;
75
+ const matches = headings.filter((h) => placement.headingId ? h.id === placement.headingId : h.text === editorialPlainText(placement.heading));
76
+ if (matches.length !== 1) return { index, status: matches.length ? "ambiguous_heading" : "missing_heading" };
77
+ paragraph = paragraphFor(matches[0]);
78
+ } else return { index, status: "unassigned" };
79
+ if (!paragraph) return { index, status: "no_paragraph" };
80
+ if (photo.url) existing.add(photo.url);
81
+ return { index, status: "placed", offset: paragraph.end };
95
82
  });
83
+ return { headings: headings.map(({ start: _start, end: _end, ...heading }) => heading), placements };
84
+ }
85
+
86
+ // packages/press-kit/src/articles/article-photos.ts
87
+ var escape = (value) => value.replace(/&/g, "&amp;").replace(/</g, "&lt;").replace(/>/g, "&gt;").replace(/"/g, "&quot;").replace(/'/g, "&#39;");
88
+ function photoUrl(value) {
89
+ if (typeof value !== "string" || value.length > 2e3 || /[\s\\]/.test(value)) return null;
90
+ try {
91
+ const url = new URL(value);
92
+ if (url.protocol !== "https:" || url.username || url.password || /\/Blog\/(Cards|Carousel)\//i.test(decodeURIComponent(url.pathname))) return null;
93
+ return url.href;
94
+ } catch {
95
+ return null;
96
+ }
97
+ }
98
+ function figure(photo, index) {
99
+ const url = photoUrl(photo.url);
100
+ if (!url || typeof photo.alt !== "string" || !photo.alt.trim() || photo.alt.length > 300) return null;
101
+ if (![photo.width, photo.height].every((n) => Number.isInteger(n) && n > 0 && n <= 2400)) return null;
102
+ const caption = typeof photo.caption === "string" && photo.caption.trim() ? `<figcaption>${escape(photo.caption.slice(0, 300))}</figcaption>` : "";
103
+ return `<figure class="sk-article-photo" data-sk-editorial-photo="${index}"><img src="${escape(url)}" alt="${escape(photo.alt)}" width="${photo.width}" height="${photo.height}" loading="lazy" decoding="async" style="display:block;max-width:100%;height:auto" />${caption}</figure>`;
104
+ }
105
+ function insertArticlePhotos(html, photos) {
106
+ if (!html || !Array.isArray(photos) || !photos.length) return html;
107
+ const candidates = photos.slice(0, 8);
108
+ const { placements } = resolveArticlePhotoPlacements(html, candidates);
109
+ const additions = /* @__PURE__ */ new Map();
110
+ for (const { index, status, offset } of placements) {
111
+ if (status !== "placed" || offset === void 0) continue;
112
+ const rendered = figure(candidates[index], index);
113
+ if (!rendered) continue;
114
+ const images = additions.get(offset) || [];
115
+ images.push(rendered);
116
+ additions.set(offset, images);
117
+ }
96
118
  let result = html;
97
119
  for (const [offset, images] of [...additions].sort(([a], [b]) => b - a)) result = result.slice(0, offset) + images.join("") + result.slice(offset);
98
120
  return result;
@@ -6,8 +6,8 @@ import { normalizeFormConfig, DEFAULT_FORM_SUCCESS_MESSAGE } from './chunk-5SQK3
6
6
  import { DEFAULT_HONEYPOT_FIELD } from './chunk-NJCTQH2P.js';
7
7
  import { onPageLeave } from './chunk-L2V5PUFN.js';
8
8
  import { uuid } from './chunk-GJWI74ZZ.js';
9
- import { readPublishedApiConfig, getClientApiConfig } from './chunk-3G7YABRA.js';
10
- import { sonorFetch, sonorBeacon } from './chunk-WPOFTCKL.js';
9
+ import { sonorFetch, sonorBeacon } from './chunk-OIWFXUVD.js';
10
+ import { readPublishedApiConfig, getClientApiConfig } from './chunk-W7OPEMGJ.js';
11
11
  import { useRef, useCallback, useEffect, useState, useMemo } from 'react';
12
12
 
13
13
  // src/forms/field-interactions.ts
@@ -1,4 +1,4 @@
1
- import { FormEnhancer } from './chunk-JT52KYHQ.js';
1
+ import { FormEnhancer } from './chunk-5RYSTKVU.js';
2
2
  import { StaticForm } from './chunk-LNSF6BJC.js';
3
3
  import { serverApiFetch } from './chunk-C7TLGL3R.js';
4
4
  import { jsx } from 'react/jsx-runtime';
@@ -1,5 +1,5 @@
1
- import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-F2VYN3QL.js';
2
- import { SITE_KIT_VERSION } from './chunk-NWVB75ER.js';
1
+ import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-C4AFNZT2.js';
2
+ import { SITE_KIT_VERSION } from './chunk-C2UROFGZ.js';
3
3
 
4
4
  // src/shared/fetchWithRetry.ts
5
5
  function backoffDelay(attempt, response) {
@@ -1,8 +1,8 @@
1
1
  'use client';
2
- import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-DSNCU2E3.js';
2
+ import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-TT4JZDKM.js';
3
3
  import { designTokensHash } from './chunk-IHG36STL.js';
4
4
  import { useDeferredActivation } from './chunk-YC7ELZS3.js';
5
- import { resolveAnalyticsTarget } from './chunk-CAH4Y4PY.js';
5
+ import { resolveAnalyticsTarget } from './chunk-JO76F5WP.js';
6
6
  import { useRef, useEffect } from 'react';
7
7
 
8
8
  var STAMP_KEY = (site) => `_sk_design_sent:${site}`;
@@ -54,7 +54,7 @@ function useSignal() {
54
54
  return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
55
55
  }
56
56
  var LazySignalCore = dynamic(
57
- () => import('./SignalCore-LGCBQDEH.js').then((m) => ({ default: m.SignalCore })),
57
+ () => import('./SignalCore-5KABGX5C.js').then((m) => ({ default: m.SignalCore })),
58
58
  { ssr: false }
59
59
  );
60
60
  function SignalBridge({
@@ -1,12 +1,12 @@
1
1
  'use client';
2
2
  import { SITE_EDIT_PARAM } from './chunk-6G43IRWR.js';
3
- import { publishSiteCredential } from './chunk-6VHDCJIZ.js';
4
- import { FleetHeartbeat } from './chunk-RSBMQFZW.js';
3
+ import { publishSiteCredential } from './chunk-U7Y3QG3A.js';
4
+ import { FleetHeartbeat } from './chunk-LPKKSYKX.js';
5
5
  import { useDeferredActivation } from './chunk-YC7ELZS3.js';
6
6
  import { resolveSiteHost } from './chunk-FESKKJAS.js';
7
7
  import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-ZKADJNR2.js';
8
- import { announceFrameReady, isCrossOriginFrame } from './chunk-CAH4Y4PY.js';
9
- import { SignalBridge } from './chunk-DZV3KPVF.js';
8
+ import { announceFrameReady, isCrossOriginFrame } from './chunk-JO76F5WP.js';
9
+ import { SignalBridge } from './chunk-QCZHYO5M.js';
10
10
  import React, { useState, useRef, useCallback, useEffect, Suspense } from 'react';
11
11
  import dynamic from 'next/dynamic';
12
12
  import { jsx, jsxs, Fragment } from 'react/jsx-runtime';
@@ -33,23 +33,23 @@ function startEditBridge() {
33
33
  };
34
34
  }
35
35
  var LazyAnalyticsProvider = dynamic(
36
- () => import('./AnalyticsProvider-UWTCE5UO.js').then((m) => ({ default: m.AnalyticsProvider })),
36
+ () => import('./AnalyticsProvider-QXO33JUF.js').then((m) => ({ default: m.AnalyticsProvider })),
37
37
  { ssr: false }
38
38
  );
39
39
  var LazySiteChat = dynamic(
40
- () => import('./SiteChat-6SF7PVUT.js').then((m) => ({ default: m.SiteChat })),
40
+ () => import('./SiteChat-JQ46ZIJ4.js').then((m) => ({ default: m.SiteChat })),
41
41
  { ssr: false }
42
42
  );
43
43
  var LazySitePopups = dynamic(
44
- () => import('./SitePopups-T6YPHAVY.js').then((m) => ({ default: m.SitePopups })),
44
+ () => import('./SitePopups-WZBKX5Q3.js').then((m) => ({ default: m.SitePopups })),
45
45
  { ssr: false }
46
46
  );
47
47
  var LazySiteDesignReporter = dynamic(
48
- () => import('./SiteDesignReporter-VISQZ5NQ.js').then((m) => ({ default: m.SiteDesignReporter })),
48
+ () => import('./SiteDesignReporter-N7L6DR4J.js').then((m) => ({ default: m.SiteDesignReporter })),
49
49
  { ssr: false }
50
50
  );
51
51
  var LazySitemapSync = dynamic(
52
- () => import('./SitemapSync-VKMVRPZL.js').then((m) => ({ default: m.SitemapSync })),
52
+ () => import('./SitemapSync-GY6UADRI.js').then((m) => ({ default: m.SitemapSync })),
53
53
  { ssr: false }
54
54
  );
55
55
  function SiteKitClientProviders({
@@ -1,7 +1,7 @@
1
1
  'use client';
2
2
  import { locToPath, isMalformedSitemapPath, inferPageType } from './chunk-YVKRYQRG.js';
3
- import { resolveAnalyticsTarget } from './chunk-CAH4Y4PY.js';
4
- import { sonorFetch } from './chunk-WPOFTCKL.js';
3
+ import { resolveAnalyticsTarget } from './chunk-JO76F5WP.js';
4
+ import { sonorFetch } from './chunk-OIWFXUVD.js';
5
5
  import { useRef, useEffect } from 'react';
6
6
 
7
7
  var SYNC_STAMP_KEY = "_sk_sitemap_synced_at";
@@ -1,6 +1,6 @@
1
- import { resolvePublicationUrl, createPublicationRoutes } from './chunk-WMVK77ND.js';
1
+ import { resolvePublicationUrl, createPublicationRoutes } from './chunk-4K735O3J.js';
2
2
 
3
- // src/articles/artwork.ts
3
+ // packages/press-kit/src/articles/artwork.ts
4
4
  function resolveArticleArtwork(post, placement = "card") {
5
5
  const editorial = placement === "article" && !!post.editorial_image;
6
6
  const src = (editorial ? post.editorial_image : post.featured_image) || void 0;
@@ -18,7 +18,7 @@ function articleArtworkImageStyle(artwork) {
18
18
  return artwork.composed ? { display: "block", height: "auto", maxHeight: "none", objectFit: "contain", transform: "none" } : void 0;
19
19
  }
20
20
 
21
- // src/articles/author-schema.ts
21
+ // packages/press-kit/src/articles/author-schema.ts
22
22
  var ARTICLE_TYPES = /* @__PURE__ */ new Set(["Article", "BlogPosting", "NewsArticle", "TechArticle", "Report", "ScholarlyArticle"]);
23
23
  function isAbsoluteUrl(value) {
24
24
  return /^https?:\/\//i.test(value);
@@ -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
- import { resolveAnalyticsTarget } from './chunk-CAH4Y4PY.js';
4
- import { sonorFetch } from './chunk-WPOFTCKL.js';
5
- import { SITE_KIT_VERSION } from './chunk-NWVB75ER.js';
3
+ import { resolveAnalyticsTarget } from './chunk-JO76F5WP.js';
4
+ import { sonorFetch } from './chunk-OIWFXUVD.js';
5
+ import { SITE_KIT_VERSION } from './chunk-C2UROFGZ.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
  import { resolveSiteHost } from './chunk-FESKKJAS.js';
2
- import { configureSiteCredential, currentCredential } from './chunk-F2VYN3QL.js';
2
+ import { configureSiteCredential, currentCredential } from './chunk-C4AFNZT2.js';
3
3
 
4
4
  // src/shared/publishCredential.ts
5
5
  function publishSiteCredential({
@@ -21,5 +21,8 @@ function getClientApiConfig(options = {}) {
21
21
  const published = readPublishedApiConfig();
22
22
  return { apiUrl: published.apiUrl || DEFAULT_SONOR_API_URL, apiKey: published.apiKey };
23
23
  }
24
+ function readPublishedSite() {
25
+ return siteKitWindow()?.__SITE_KIT_SITE__ || void 0;
26
+ }
24
27
 
25
- export { DEFAULT_SONOR_API_URL, getClientApiConfig, readPublishedApiConfig };
28
+ export { DEFAULT_SONOR_API_URL, getClientApiConfig, readPublishedApiConfig, readPublishedSite };
@@ -1,5 +1,5 @@
1
- import { getClientApiConfig } from './chunk-3G7YABRA.js';
2
- import { sonorFetch } from './chunk-WPOFTCKL.js';
1
+ import { sonorFetch } from './chunk-OIWFXUVD.js';
2
+ import { getClientApiConfig } from './chunk-W7OPEMGJ.js';
3
3
 
4
4
  // src/sync/api.ts
5
5
  function getApiConfig() {
@@ -1,7 +1,7 @@
1
1
  import { trackedFreshFetch } from './chunk-UAYAJPEP.js';
2
2
  import { isNextControlFlow } from './chunk-C7TLGL3R.js';
3
3
  import { monotonicMs } from './chunk-MH2DSGC6.js';
4
- import { SITE_KIT_VERSION } from './chunk-NWVB75ER.js';
4
+ import { SITE_KIT_VERSION } from './chunk-C2UROFGZ.js';
5
5
  import 'server-only';
6
6
 
7
7
  var MINT_PATH = "/api/public/site-token";