@sonordev/site-kit 8.6.0 → 8.7.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/CHANGELOG.md +11 -0
- package/agent-manifest.json +1 -1
- package/dist/{AnalyticsProvider-GVJYL6XY.js → AnalyticsProvider-3UIQMIRW.js} +6 -6
- package/dist/{ArticleViewTracker-AOJXEBYM.js → ArticleViewTracker-KNXP2DXL.js} +5 -5
- package/dist/{BlocksPopup-AJ3CKVQG.js → BlocksPopup-DFE32GPX.js} +9 -8
- package/dist/{ChatWidget-EYBVB5SZ.js → ChatWidget-L74L4YAD.js} +5 -5
- package/dist/{FileField-UEQYIFRO.js → FileField-P3PLEAON.js} +3 -3
- package/dist/{FormSpotlight-H73ZZ66T.js → FormSpotlight-DNBSBRIE.js} +1 -1
- package/dist/{FormStage-2PLWWYBW.js → FormStage-I4JGLT57.js} +1 -1
- package/dist/{ManagedForm-ZQOFXEWS.js → ManagedForm-GJRGBM6W.js} +6 -6
- package/dist/{ManagedNewsletterForm-5TE47YZD.js → ManagedNewsletterForm-AUZ6YB7G.js} +9 -9
- package/dist/{SignalCore-FEFNMNYN.js → SignalCore-UV7K7PT4.js} +5 -5
- package/dist/SiteChat-6UWE545R.js +6 -0
- package/dist/SiteDesignReporter-ZSU76DZJ.js +13 -0
- package/dist/{SitePopups-C44YTQ3Q.js → SitePopups-XHWU7GNF.js} +6 -6
- package/dist/SitemapSync-ELWV6W7Y.js +9 -0
- package/dist/_client/booking-widget.js +5 -5
- package/dist/affiliates/index.js +3 -3
- package/dist/analytics/content-text.d.ts +17 -0
- package/dist/analytics/index.js +6 -6
- package/dist/{article-styles-VASFBYA3.js → article-styles-D7VCDXMG.js} +2 -1
- package/dist/article-tables-W45BE353.js +3 -0
- package/dist/articles/index.js +7 -20
- package/dist/articles/server-ui.js +29 -55
- package/dist/articles/server.js +6 -5
- package/dist/chat/index.js +8 -8
- package/dist/{chunk-3RDJKIYO.js → chunk-2WDWQI7K.js} +1 -1
- package/dist/{chunk-NI6ZTP3D.js → chunk-36ZMNBXZ.js} +1 -1
- package/dist/chunk-3MJNBOUO.js +8 -0
- package/dist/{chunk-ZZSAWXWD.js → chunk-3MLWIBHX.js} +1 -1
- package/dist/{chunk-BF7TZYC3.js → chunk-52KO4LKD.js} +1 -1
- package/dist/{chunk-U34O6I7W.js → chunk-5WHBYQJ4.js} +3 -3
- package/dist/{chunk-5D7ZISUP.js → chunk-7DYMM6SS.js} +11 -6
- package/dist/{chunk-GFY3E7EQ.js → chunk-7YB3QA4P.js} +15 -7
- package/dist/{chunk-6AWIUO2Z.js → chunk-A2MDVP47.js} +1 -1
- package/dist/{chunk-E4PTMORJ.js → chunk-AL5UCWLI.js} +23 -8
- package/dist/{chunk-O3Z5HHFP.js → chunk-BAJUXQTH.js} +2 -2
- package/dist/{chunk-IGAIQ2B3.js → chunk-BJYX6SFI.js} +2 -2
- package/dist/{chunk-72F44HKL.js → chunk-DJIGFX33.js} +1 -1
- package/dist/{chunk-AJG74ZZV.js → chunk-DPYGC7WE.js} +1 -1
- package/dist/{chunk-XA7Q2VQA.js → chunk-EK7P62DT.js} +1 -1
- package/dist/chunk-FXR5PJDL.js +420 -0
- package/dist/{chunk-OWO3RFEX.js → chunk-G5FD7UXK.js} +1 -1
- package/dist/{chunk-KTMHRXDT.js → chunk-HM7CDWFK.js} +1 -1
- package/dist/{chunk-CMUD37WV.js → chunk-HWQPCZOX.js} +1 -1
- package/dist/{chunk-6KU7STM3.js → chunk-HY7ZEU2C.js} +3 -1
- package/dist/chunk-IBHBEUZV.js +27 -0
- package/dist/{chunk-NUXXFCIT.js → chunk-IXZBOOAD.js} +4 -4
- package/dist/chunk-JESLPEST.js +14 -0
- package/dist/{chunk-BC7JMY4Z.js → chunk-JG53YJLM.js} +58 -1
- package/dist/{chunk-VA6IJ55K.js → chunk-JWCCY72G.js} +1 -1
- package/dist/{chunk-RI2N2EBI.js → chunk-JYITKUUB.js} +13 -5
- package/dist/chunk-KIYACQW3.js +1 -0
- package/dist/{chunk-OFSV5TZY.js → chunk-KLIDCNML.js} +1 -1
- package/dist/{chunk-7R2STOVD.js → chunk-L2KSHJS2.js} +3 -3
- package/dist/{chunk-HMTPRBYJ.js → chunk-LGWN6KCN.js} +1 -1
- package/dist/{chunk-YNBRVVTX.js → chunk-MJW6YIDJ.js} +1 -1
- package/dist/{chunk-BUE3Z32O.js → chunk-MNORERMF.js} +1 -1
- package/dist/{chunk-Y35BWW2C.js → chunk-ODOV76VW.js} +1 -1
- package/dist/{chunk-6NXFA7HE.js → chunk-OHLCE4GC.js} +2 -2
- package/dist/{chunk-QQT2T6JQ.js → chunk-P5PRR2BB.js} +1 -1
- package/dist/{chunk-JJ4JS3LD.js → chunk-PAYCK7FC.js} +1 -1
- package/dist/{chunk-DLM4FFNH.js → chunk-QTBAKOCZ.js} +1 -1
- package/dist/{chunk-L6QTERSH.js → chunk-RHT7OZNF.js} +1 -1
- package/dist/{chunk-YJH6WE76.js → chunk-RWWSOYJO.js} +9 -9
- package/dist/{chunk-JSW42BHL.js → chunk-T6TWPKBL.js} +1 -1
- package/dist/{chunk-FTSEP7Q3.js → chunk-U4OQJQK6.js} +3 -3
- package/dist/{chunk-IYCSDFPN.js → chunk-UYOE3HA4.js} +2 -2
- package/dist/chunk-VEJD5EJ2.js +344 -0
- package/dist/chunk-XAZC2TUD.js +1119 -0
- package/dist/{chunk-DSD3XZQQ.js → chunk-XC2TWYDV.js} +3 -3
- package/dist/{chunk-URJN75ZG.js → chunk-XIDWNXZN.js} +3 -3
- package/dist/chunk-XLAHRN4B.js +1 -0
- package/dist/{chunk-V67OD7RW.js → chunk-XZFOQ2V4.js} +113 -93
- package/dist/{chunk-QNOJSSQT.js → chunk-YYPYLYZM.js} +1 -1
- package/dist/client/index.js +4 -4
- package/dist/contracts/campaign-normalize.d.ts +2 -0
- package/dist/contracts/entries.d.ts +1 -1
- package/dist/contracts/funnels.d.ts +576 -0
- package/dist/contracts/inbox.d.ts +42 -0
- package/dist/contracts/llms.d.ts +200 -0
- package/dist/contracts/portfolio.d.ts +170 -0
- package/dist/contracts/publication-branding.d.ts +10 -2
- package/dist/contracts/site-cache.d.ts +2 -0
- package/dist/fleet/index.js +6 -6
- package/dist/forms/index.js +9 -9
- package/dist/forms/server.js +2 -2
- package/dist/images/index.js +4 -4
- package/dist/index.js +1 -1
- package/dist/landing/contract.d.ts +2 -13
- package/dist/landing/contract.js +2 -0
- package/dist/landing/index.js +4 -2
- package/dist/landing/managed-server.d.ts +21 -0
- package/dist/landing/managed.d.ts +11 -0
- package/dist/landing/metadata.js +2 -0
- package/dist/landing/server.d.ts +5 -0
- package/dist/landing/server.js +19 -2
- package/dist/layout/client.js +9 -9
- package/dist/layout/index.js +10 -10
- package/dist/llms/contract.js +2 -1
- package/dist/llms/index.js +9 -7
- package/dist/llms/merge.d.ts +29 -0
- package/dist/maps/index.js +3 -3
- package/dist/mcp/sonor.js +9 -8
- package/dist/portfolio/contract.js +1 -1
- package/dist/press-kit/articles/article-body.d.ts +13 -0
- package/dist/press-kit/articles/article-heading-ids.d.ts +7 -0
- package/dist/press-kit/articles/article-headings.d.ts +61 -0
- package/dist/press-kit/articles/html-tags.d.ts +46 -0
- package/dist/press-kit/articles/types.d.ts +2 -0
- package/dist/revalidate/index.js +3 -3
- package/dist/runtime/index.js +3 -3
- package/dist/seo/client.js +6 -6
- package/dist/seo/index.js +14 -13
- package/dist/seo/llms/contract.js +2 -1
- package/dist/seo/llms.js +9 -7
- package/dist/seo/meta/contract.js +2 -1
- package/dist/seo/register-sitemap-cli.js +1 -1
- package/dist/seo/server.js +5 -4
- package/dist/seo/sitemap.js +7 -5
- package/dist/seo-meta/contract.js +2 -1
- package/dist/server/index.js +3 -3
- package/dist/{server-api-EGOKC7Q3.js → server-api-XIKDWSNO.js} +2 -2
- package/dist/shared/build-entries.d.ts +3 -1
- package/dist/shared/markdown.d.ts +7 -6
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/sitemap/index.js +7 -5
- package/dist/slots/index.js +2 -2
- package/dist/sync/index.js +5 -5
- package/dist/website/contract.js +2 -1
- package/dist/website/images.js +4 -4
- package/dist/website/index.js +10 -9
- package/dist/website/landing/server.js +19 -2
- package/dist/website/landing.js +4 -2
- package/dist/website/popups.js +9 -8
- package/dist/website/slots.js +2 -2
- package/dist/{writeLLMsTxt-KHVHNSDM.js → writeLLMsTxt-QN2HIVT4.js} +6 -4
- package/docs.json +5 -0
- package/package.json +1 -1
- package/src/analytics/README.md +1 -1
- package/src/landing/README.md +64 -0
- package/src/llms/README.md +52 -20
- package/dist/SiteChat-3MKYL2XM.js +0 -6
- package/dist/SiteDesignReporter-AJDIBNHI.js +0 -12
- package/dist/SitemapSync-UJA6JVPW.js +0 -9
- package/dist/article-tables-6XHVULPU.js +0 -2
- package/dist/chunk-EKBEOXTH.js +0 -114
- package/dist/chunk-NZ4RXN3G.js +0 -145
- package/dist/chunk-OSYCOC3K.js +0 -21
- /package/dist/{chunk-7ZWO5HDQ.js → chunk-BTHEQDN4.js} +0 -0
- /package/dist/{chunk-BQR4IPBW.js → chunk-ISRBSTB7.js} +0 -0
- /package/dist/{chunk-IHG36STL.js → chunk-XHYE24HU.js} +0 -0
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { insertArticlePhotos } from './chunk-WHPCGQHC.js';
|
|
2
2
|
import { resolveRepresentativeImage, generateArticleAuthorNode, articleImageSchema, resolveArticleArtwork, withArticleAuthorIdentity } from './chunk-UVYUTBT4.js';
|
|
3
|
+
import { stripHtmlTags } from './chunk-IBHBEUZV.js';
|
|
3
4
|
import { resolveArticleUrl, createPublicationRoutes, resolvePublicationUrl, articleCategorySlug } from './chunk-4K735O3J.js';
|
|
4
5
|
import { withoutSchemaPlaceholders } from './chunk-VWWITFWM.js';
|
|
5
6
|
import { withSiteParam, withSiteBody } from './chunk-MJP63SSS.js';
|
|
@@ -208,6 +209,13 @@ function createPublicationPreviewHandler(options) {
|
|
|
208
209
|
} });
|
|
209
210
|
};
|
|
210
211
|
}
|
|
212
|
+
|
|
213
|
+
// packages/press-kit/src/articles/article-body.ts
|
|
214
|
+
function articleBodyHtml(post) {
|
|
215
|
+
return typeof post.content_html === "string" ? post.content_html : "";
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// packages/press-kit/src/articles/server-core.ts
|
|
211
219
|
async function getArticleResult(slug, options) {
|
|
212
220
|
const config = resolveServerApiConfig();
|
|
213
221
|
return config ? readArticleBySlug({ ...config, site: options?.site }, slug) : { state: "unavailable" };
|
|
@@ -631,7 +639,7 @@ async function getAllArticles(options = {}) {
|
|
|
631
639
|
return posts.slice(0, maxPosts);
|
|
632
640
|
}
|
|
633
641
|
function stripHtml(html) {
|
|
634
|
-
return html.replace(
|
|
642
|
+
return stripHtmlTags(html).replace(/</g, "<").replace(/>/g, ">").trim();
|
|
635
643
|
}
|
|
636
644
|
async function generateRssFeed(options) {
|
|
637
645
|
const {
|
|
@@ -683,7 +691,7 @@ async function generateRssFeed(options) {
|
|
|
683
691
|
const postUrl = resolveArticleUrl(post, { ...options, siteUrl });
|
|
684
692
|
const pubDate = post.published_at ? new Date(post.published_at).toUTCString() : now;
|
|
685
693
|
const author = typeof post.author === "string" ? post.author : post.author?.name || "Unknown";
|
|
686
|
-
const fullContent = insertArticlePhotos(post
|
|
694
|
+
const fullContent = insertArticlePhotos(articleBodyHtml(post), post.editorial_photos);
|
|
687
695
|
const description2 = sanitizeExcerpt(post.excerpt, 300) || stripHtml(fullContent).substring(0, 300) + "...";
|
|
688
696
|
rss += ` <item>
|
|
689
697
|
<title>${escapeXml(post.title)}</title>
|
|
@@ -707,7 +715,7 @@ async function generateRssFeed(options) {
|
|
|
707
715
|
}
|
|
708
716
|
}
|
|
709
717
|
if (post.featured_image) {
|
|
710
|
-
rss += ` <enclosure url="${post.featured_image}" type="image/jpeg"/>
|
|
718
|
+
rss += ` <enclosure url="${escapeXml(post.featured_image)}" type="image/jpeg"/>
|
|
711
719
|
`;
|
|
712
720
|
}
|
|
713
721
|
rss += ` </item>
|
|
@@ -746,7 +754,7 @@ async function generateAtomFeed(options) {
|
|
|
746
754
|
const updated = post.updated_at || post.published_at || now;
|
|
747
755
|
const published = post.published_at || now;
|
|
748
756
|
const author = typeof post.author === "string" ? post.author : post.author?.name || "Unknown";
|
|
749
|
-
const fullContent = insertArticlePhotos(post
|
|
757
|
+
const fullContent = insertArticlePhotos(articleBodyHtml(post), post.editorial_photos);
|
|
750
758
|
atom += ` <entry>
|
|
751
759
|
<title>${escapeXml(post.title)}</title>
|
|
752
760
|
<link href="${escapeXml(postUrl)}"/>
|
|
@@ -1164,4 +1172,4 @@ function generateAuthorPageMetadata(author, options = {}) {
|
|
|
1164
1172
|
};
|
|
1165
1173
|
}
|
|
1166
1174
|
|
|
1167
|
-
export { ArticleUnavailableError, FEED_DEFAULT_ITEMS, NEWS_SITEMAP_MAX_URLS, NEWS_SITEMAP_WINDOW_MS, PUBLICATION_PREVIEW_COOKIE, PUBLICATION_PREVIEW_HEADERS, SEO_LIMITS, buildNewsSitemapXml, cdata, createPublicationPreviewHandler, fetchArticleBySlug, fetchArticleCategories, fetchRelatedArticles, generateAllArticleSchemas, generateArticleCategoryMetadata, generateArticleListSchema, generateArticleMetadata, generateArticleSchema, generateArticleSitemap, generateArticleStaticParams, generateAtomFeed, generateAuthorPageMetadata, generateAuthorStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateNewsSitemap, generatePublicationMetadata, generateRssFeed, getAllArticleSlugs, getAllArticles, getAllAuthorSlugs, getArticle, getArticleCategories, getArticlePreview, getArticleResult, getAuthorBySlug, getAuthorPosts, getClusterNavigation, getPostsByCategory, getPublicationIssue, getPublicationIssues, getRelatedInsights, getTopicCluster, getTopicClusters, recentNewsPosts, requireArticle, sanitizeExcerpt, validateArticleSeo, validateMetaDescription, validateSeoTitle };
|
|
1175
|
+
export { ArticleUnavailableError, FEED_DEFAULT_ITEMS, NEWS_SITEMAP_MAX_URLS, NEWS_SITEMAP_WINDOW_MS, PUBLICATION_PREVIEW_COOKIE, PUBLICATION_PREVIEW_HEADERS, SEO_LIMITS, articleBodyHtml, buildNewsSitemapXml, cdata, createPublicationPreviewHandler, fetchArticleBySlug, fetchArticleCategories, fetchRelatedArticles, generateAllArticleSchemas, generateArticleCategoryMetadata, generateArticleListSchema, generateArticleMetadata, generateArticleSchema, generateArticleSitemap, generateArticleStaticParams, generateAtomFeed, generateAuthorPageMetadata, generateAuthorStaticParams, generateBreadcrumbSchema, generateCategoryStaticParams, generateClusterArticleSchema, generateClusterBreadcrumbSchema, generateClusterItemListSchema, generateClusterLandingSchema, generateClusterPageMetadata, generateFaqSchema, generateHowToSchema, generateNewsSitemap, generatePublicationMetadata, generateRssFeed, getAllArticleSlugs, getAllArticles, getAllAuthorSlugs, getArticle, getArticleCategories, getArticlePreview, getArticleResult, getAuthorBySlug, getAuthorPosts, getClusterNavigation, getPostsByCategory, getPublicationIssue, getPublicationIssues, getRelatedInsights, getTopicCluster, getTopicClusters, recentNewsPosts, requireArticle, sanitizeExcerpt, validateArticleSeo, validateMetaDescription, validateSeoTitle };
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
|
|
@@ -54,7 +54,7 @@ function useSignal() {
|
|
|
54
54
|
return useSyncExternalStore(subscribe, getSnapshot, getServerSnapshot);
|
|
55
55
|
}
|
|
56
56
|
var LazySignalCore = dynamic(
|
|
57
|
-
() => import('./SignalCore-
|
|
57
|
+
() => import('./SignalCore-UV7K7PT4.js').then((m) => ({ default: m.SignalCore })),
|
|
58
58
|
{ ssr: false }
|
|
59
59
|
);
|
|
60
60
|
function SignalBridge({
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { countStageViews, countStageQuestions, useFieldControls } from './chunk-
|
|
3
|
-
import { useFormLoadedAt, useFormTracking, submitForm, useRecaptchaWarmup, useForm } from './chunk-
|
|
2
|
+
import { countStageViews, countStageQuestions, useFieldControls } from './chunk-36ZMNBXZ.js';
|
|
3
|
+
import { useFormLoadedAt, useFormTracking, submitForm, useRecaptchaWarmup, useForm } from './chunk-LGWN6KCN.js';
|
|
4
4
|
import { readAgentSubmit, formToolAttributes } from './chunk-Q6E4OPGG.js';
|
|
5
5
|
import { isFieldVisible, validateField, isFieldComplete, isDisplayOnly, unseenControlValues } from './chunk-C2FZBUSS.js';
|
|
6
6
|
import { HoneypotField } from './chunk-DXO6SBMD.js';
|
|
@@ -63,7 +63,7 @@ function FormClient({
|
|
|
63
63
|
return;
|
|
64
64
|
}
|
|
65
65
|
let cancelled = false;
|
|
66
|
-
const load = resolvedExperience === "stage" ? import('./FormStage-
|
|
66
|
+
const load = resolvedExperience === "stage" ? import('./FormStage-I4JGLT57.js').then((m) => m.FormStage) : import('./FormSpotlight-DNBSBRIE.js').then((m) => m.FormSpotlight);
|
|
67
67
|
load.then((Component) => {
|
|
68
68
|
if (!cancelled) setExperience(() => Component);
|
|
69
69
|
}).catch((err) => {
|
|
@@ -6,7 +6,7 @@ import { normalizeFormConfig, DEFAULT_FORM_SUCCESS_MESSAGE } from './chunk-TYSIA
|
|
|
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 { sonorFetch, sonorBeacon } from './chunk-
|
|
9
|
+
import { sonorFetch, sonorBeacon } from './chunk-UYOE3HA4.js';
|
|
10
10
|
import { readPublishedApiConfig, getClientApiConfig } from './chunk-W7OPEMGJ.js';
|
|
11
11
|
import { useRef, useCallback, useEffect, useState, useMemo } from 'react';
|
|
12
12
|
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { secretsMatch, readCappedBody } from './chunk-XTRZGXB2.js';
|
|
2
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
2
|
+
import { SITE_KIT_VERSION } from './chunk-MNORERMF.js';
|
|
3
3
|
|
|
4
4
|
// src/llms/revalidate.ts
|
|
5
5
|
function createLlmsRevalidateHandler(secret, options) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { withSiteBody } from './chunk-MJP63SSS.js';
|
|
2
|
-
import { SITE_CACHE_TAGS } from './chunk-
|
|
2
|
+
import { SITE_CACHE_TAGS } from './chunk-HY7ZEU2C.js';
|
|
3
3
|
import { serverApiFetch, requireServerApiConfig } from './chunk-C7TLGL3R.js';
|
|
4
4
|
import { postRegisterSitemap, resolveSyncSite } from './chunk-DIKNRN34.js';
|
|
5
5
|
import { cache } from 'react';
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { locToPath, isMalformedSitemapPath, inferPageType } from './chunk-YVKRYQRG.js';
|
|
3
|
-
import { resolveAnalyticsTarget } from './chunk-
|
|
4
|
-
import { sonorFetch } from './chunk-
|
|
3
|
+
import { resolveAnalyticsTarget } from './chunk-QTBAKOCZ.js';
|
|
4
|
+
import { sonorFetch } from './chunk-UYOE3HA4.js';
|
|
5
5
|
import { useRef, useEffect } from 'react';
|
|
6
6
|
|
|
7
7
|
var SYNC_STAMP_KEY = "_sk_sitemap_synced_at";
|
|
@@ -1,12 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
2
|
import { SITE_EDIT_PARAM } from './chunk-6G43IRWR.js';
|
|
3
|
-
import { publishSiteCredential } from './chunk-
|
|
4
|
-
import { FleetHeartbeat } from './chunk-
|
|
3
|
+
import { publishSiteCredential } from './chunk-JWCCY72G.js';
|
|
4
|
+
import { FleetHeartbeat } from './chunk-5WHBYQJ4.js';
|
|
5
5
|
import { useDeferredActivation } from './chunk-YC7ELZS3.js';
|
|
6
6
|
import { resolveSiteHost } from './chunk-FESKKJAS.js';
|
|
7
7
|
import { getOrCreateVisitorId, getOrCreateSessionId } from './chunk-IPQKQEWI.js';
|
|
8
|
-
import { announceFrameReady, isPrivatePreview, isCrossOriginFrame } from './chunk-
|
|
9
|
-
import { SignalBridge } from './chunk-
|
|
8
|
+
import { announceFrameReady, isPrivatePreview, isCrossOriginFrame } from './chunk-QTBAKOCZ.js';
|
|
9
|
+
import { SignalBridge } from './chunk-KLIDCNML.js';
|
|
10
10
|
import React, { useState, useRef, useCallback, useEffect, Suspense } from 'react';
|
|
11
11
|
import dynamic from 'next/dynamic';
|
|
12
12
|
import { jsx, Fragment, jsxs } from 'react/jsx-runtime';
|
|
@@ -33,23 +33,23 @@ function startEditBridge() {
|
|
|
33
33
|
};
|
|
34
34
|
}
|
|
35
35
|
var LazyAnalyticsProvider = dynamic(
|
|
36
|
-
() => import('./AnalyticsProvider-
|
|
36
|
+
() => import('./AnalyticsProvider-3UIQMIRW.js').then((m) => ({ default: m.AnalyticsProvider })),
|
|
37
37
|
{ ssr: false }
|
|
38
38
|
);
|
|
39
39
|
var LazySiteChat = dynamic(
|
|
40
|
-
() => import('./SiteChat-
|
|
40
|
+
() => import('./SiteChat-6UWE545R.js').then((m) => ({ default: m.SiteChat })),
|
|
41
41
|
{ ssr: false }
|
|
42
42
|
);
|
|
43
43
|
var LazySitePopups = dynamic(
|
|
44
|
-
() => import('./SitePopups-
|
|
44
|
+
() => import('./SitePopups-XHWU7GNF.js').then((m) => ({ default: m.SitePopups })),
|
|
45
45
|
{ ssr: false }
|
|
46
46
|
);
|
|
47
47
|
var LazySiteDesignReporter = dynamic(
|
|
48
|
-
() => import('./SiteDesignReporter-
|
|
48
|
+
() => import('./SiteDesignReporter-ZSU76DZJ.js').then((m) => ({ default: m.SiteDesignReporter })),
|
|
49
49
|
{ ssr: false }
|
|
50
50
|
);
|
|
51
51
|
var LazySitemapSync = dynamic(
|
|
52
|
-
() => import('./SitemapSync-
|
|
52
|
+
() => import('./SitemapSync-ELWV6W7Y.js').then((m) => ({ default: m.SitemapSync })),
|
|
53
53
|
{ ssr: false }
|
|
54
54
|
);
|
|
55
55
|
function SiteKitClientProviders({
|
|
@@ -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-
|
|
4
|
+
import { SITE_KIT_VERSION } from './chunk-MNORERMF.js';
|
|
5
5
|
import 'server-only';
|
|
6
6
|
|
|
7
7
|
var MINT_PATH = "/api/public/site-token";
|
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
import { DEFAULT_WIDGET_Z_INDEX } from './chunk-27FISYK4.js';
|
|
3
3
|
import { readAnalyticsIdentity } from './chunk-5ROTTMBL.js';
|
|
4
4
|
import { getOrCreateVisitorId } from './chunk-IPQKQEWI.js';
|
|
5
|
-
import { resolveAnalyticsTarget } from './chunk-
|
|
6
|
-
import { sonorFetch } from './chunk-
|
|
5
|
+
import { resolveAnalyticsTarget } from './chunk-QTBAKOCZ.js';
|
|
6
|
+
import { sonorFetch } from './chunk-UYOE3HA4.js';
|
|
7
7
|
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
8
8
|
import ReactDOM from 'react-dom';
|
|
9
9
|
import dynamic from 'next/dynamic';
|
|
@@ -161,7 +161,7 @@ function activatePopup(active, id, popups) {
|
|
|
161
161
|
return [...active, id];
|
|
162
162
|
}
|
|
163
163
|
var LazyBlocksPopup = dynamic(
|
|
164
|
-
() => import('./BlocksPopup-
|
|
164
|
+
() => import('./BlocksPopup-DFE32GPX.js').then((m) => ({ default: m.BlocksPopup })),
|
|
165
165
|
{ ssr: false }
|
|
166
166
|
);
|
|
167
167
|
function SitePopups(props) {
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-
|
|
2
|
-
import { SITE_KIT_VERSION } from './chunk-
|
|
1
|
+
import { isTokenMode, getFreshCredential, isSiteToken, refreshSiteToken, currentCredential, credentialBreakerId } from './chunk-P5PRR2BB.js';
|
|
2
|
+
import { SITE_KIT_VERSION } from './chunk-MNORERMF.js';
|
|
3
3
|
|
|
4
4
|
// src/shared/fetchWithRetry.ts
|
|
5
5
|
function backoffDelay(attempt, response) {
|
|
@@ -0,0 +1,344 @@
|
|
|
1
|
+
// src/contracts/portfolio.ts
|
|
2
|
+
var FRAME_READY_MESSAGE = "sonor:frame-ready";
|
|
3
|
+
function isFrameReadyMessage(data) {
|
|
4
|
+
return !!data && typeof data === "object" && data.type === FRAME_READY_MESSAGE && data.v === 1;
|
|
5
|
+
}
|
|
6
|
+
var PORTFOLIO_CONTRACT_VERSION = 1;
|
|
7
|
+
var CASE_STUDY_STAGES = ["problem", "build", "proof", "outcome"];
|
|
8
|
+
var CASE_STUDY_STAGE_COPY = {
|
|
9
|
+
problem: { name: "The problem", question: "What did the client come in with, and what was in the way?" },
|
|
10
|
+
build: { name: "The build", question: "What did we plan and make, and out of what?" },
|
|
11
|
+
proof: { name: "The proof", question: "How does the finished build hold up when measured?" },
|
|
12
|
+
outcome: { name: "The outcome", question: "What is the work doing for the client now?" }
|
|
13
|
+
};
|
|
14
|
+
var STAGE_NAME_MAX_CHARS = 24;
|
|
15
|
+
function stageNamesProblems(names) {
|
|
16
|
+
if (names === void 0 || names === null) return [];
|
|
17
|
+
if (typeof names !== "object" || Array.isArray(names)) return ["stageNames must be an object"];
|
|
18
|
+
const problems = [];
|
|
19
|
+
for (const [stage, name] of Object.entries(names)) {
|
|
20
|
+
if (!CASE_STUDY_STAGES.includes(stage)) problems.push(`stageNames.${stage} is not a stage`);
|
|
21
|
+
else if (name === void 0 || name === null) continue;
|
|
22
|
+
else if (typeof name !== "string") problems.push(`stageNames.${stage} must be text`);
|
|
23
|
+
else if (name.trim().length > STAGE_NAME_MAX_CHARS)
|
|
24
|
+
problems.push(`stageNames.${stage} is over ${STAGE_NAME_MAX_CHARS} characters`);
|
|
25
|
+
}
|
|
26
|
+
return problems;
|
|
27
|
+
}
|
|
28
|
+
function stageName(names, stage) {
|
|
29
|
+
const own = names?.[stage]?.trim();
|
|
30
|
+
return own || CASE_STUDY_STAGE_COPY[stage].name;
|
|
31
|
+
}
|
|
32
|
+
var PORTFOLIO_SECTION_TYPES = [
|
|
33
|
+
"portfolioHero",
|
|
34
|
+
// problem
|
|
35
|
+
"portfolioChallenges",
|
|
36
|
+
"portfolioBeforeAfter",
|
|
37
|
+
// build
|
|
38
|
+
"portfolioStrategy",
|
|
39
|
+
"portfolioSiteArchitecture",
|
|
40
|
+
"portfolioDesignSystem",
|
|
41
|
+
"portfolioFeatureSpotlight",
|
|
42
|
+
"portfolioGallery",
|
|
43
|
+
"portfolioVideo",
|
|
44
|
+
"portfolioTechStack",
|
|
45
|
+
// proof
|
|
46
|
+
"portfolioPerformance",
|
|
47
|
+
"portfolioSpeedComparison",
|
|
48
|
+
// outcome
|
|
49
|
+
"portfolioResults",
|
|
50
|
+
"portfolioMetricsTimeline",
|
|
51
|
+
"portfolioConversionFunnel",
|
|
52
|
+
"portfolioServices",
|
|
53
|
+
"portfolioTeam",
|
|
54
|
+
"portfolioTestimonial",
|
|
55
|
+
"portfolioDetails",
|
|
56
|
+
// outside the story
|
|
57
|
+
"portfolioSeo",
|
|
58
|
+
"portfolioCTA"
|
|
59
|
+
];
|
|
60
|
+
function isPortfolioSectionType(value) {
|
|
61
|
+
return typeof value === "string" && PORTFOLIO_SECTION_TYPES.includes(value);
|
|
62
|
+
}
|
|
63
|
+
var SECTION_STAGE = {
|
|
64
|
+
portfolioHero: null,
|
|
65
|
+
portfolioChallenges: "problem",
|
|
66
|
+
portfolioBeforeAfter: "problem",
|
|
67
|
+
portfolioStrategy: "build",
|
|
68
|
+
portfolioSiteArchitecture: "build",
|
|
69
|
+
portfolioDesignSystem: "build",
|
|
70
|
+
portfolioFeatureSpotlight: "build",
|
|
71
|
+
portfolioGallery: "build",
|
|
72
|
+
portfolioVideo: "build",
|
|
73
|
+
portfolioTechStack: "build",
|
|
74
|
+
portfolioPerformance: "proof",
|
|
75
|
+
portfolioSpeedComparison: "proof",
|
|
76
|
+
portfolioResults: "outcome",
|
|
77
|
+
portfolioMetricsTimeline: "outcome",
|
|
78
|
+
portfolioConversionFunnel: "outcome",
|
|
79
|
+
portfolioServices: "outcome",
|
|
80
|
+
portfolioTeam: "outcome",
|
|
81
|
+
portfolioTestimonial: "outcome",
|
|
82
|
+
portfolioDetails: "outcome",
|
|
83
|
+
portfolioSeo: null,
|
|
84
|
+
portfolioCTA: null
|
|
85
|
+
};
|
|
86
|
+
function sectionStage(type) {
|
|
87
|
+
return isPortfolioSectionType(type) ? SECTION_STAGE[type] : null;
|
|
88
|
+
}
|
|
89
|
+
var STAGE_CORE_SECTION = {
|
|
90
|
+
problem: "portfolioChallenges",
|
|
91
|
+
build: "portfolioStrategy",
|
|
92
|
+
proof: "portfolioPerformance",
|
|
93
|
+
outcome: "portfolioResults"
|
|
94
|
+
};
|
|
95
|
+
var PORTFOLIO_SECTION_ORDER = Object.fromEntries(
|
|
96
|
+
PORTFOLIO_SECTION_TYPES.map((type, i) => [type, i])
|
|
97
|
+
);
|
|
98
|
+
var UNKNOWN_SECTION_ORDER = PORTFOLIO_SECTION_TYPES.length;
|
|
99
|
+
function sectionOrder(type) {
|
|
100
|
+
return isPortfolioSectionType(type) ? PORTFOLIO_SECTION_ORDER[type] : UNKNOWN_SECTION_ORDER;
|
|
101
|
+
}
|
|
102
|
+
function stageOrder(type) {
|
|
103
|
+
if (type === "portfolioHero") return -1;
|
|
104
|
+
const stage = sectionStage(type);
|
|
105
|
+
return stage ? CASE_STUDY_STAGES.indexOf(stage) : CASE_STUDY_STAGES.length;
|
|
106
|
+
}
|
|
107
|
+
function orderSections(sections, options = {}) {
|
|
108
|
+
const list = [...sections ?? []];
|
|
109
|
+
const byStage = list.map((section, index) => ({ section, index }));
|
|
110
|
+
byStage.sort((a, b) => {
|
|
111
|
+
const stage = stageOrder(a.section.sectionType) - stageOrder(b.section.sectionType);
|
|
112
|
+
if (stage !== 0) return stage;
|
|
113
|
+
if (options.sectionsOrdered) return a.index - b.index;
|
|
114
|
+
const order = sectionOrder(a.section.sectionType) - sectionOrder(b.section.sectionType);
|
|
115
|
+
return order !== 0 ? order : a.index - b.index;
|
|
116
|
+
});
|
|
117
|
+
return byStage.map((s) => s.section);
|
|
118
|
+
}
|
|
119
|
+
function groupSectionsByStage(sections, options = {}) {
|
|
120
|
+
const ordered = orderSections(sections, options);
|
|
121
|
+
const groups = [];
|
|
122
|
+
for (const stage of CASE_STUDY_STAGES) {
|
|
123
|
+
const own = ordered.filter((s) => sectionStage(s.sectionType) === stage);
|
|
124
|
+
if (own.length) groups.push({ stage, index: groups.length + 1, sections: own });
|
|
125
|
+
}
|
|
126
|
+
return groups;
|
|
127
|
+
}
|
|
128
|
+
var STAGE_MISSING_COPY = {
|
|
129
|
+
problem: {
|
|
130
|
+
empty: "Nothing says what the client came in with. Add the challenges.",
|
|
131
|
+
noCore: "The problem is pictured but not stated. Add the challenges."
|
|
132
|
+
},
|
|
133
|
+
build: {
|
|
134
|
+
empty: "Nothing says what was planned or built. Add the strategy.",
|
|
135
|
+
noCore: "The build is shown but the plan behind it is missing. Add the strategy."
|
|
136
|
+
},
|
|
137
|
+
proof: {
|
|
138
|
+
empty: "Nothing measures the finished build. Add a performance measurement.",
|
|
139
|
+
noCore: "The old site is compared but the finished build has no measurement of its own. Add a performance measurement."
|
|
140
|
+
},
|
|
141
|
+
outcome: {
|
|
142
|
+
empty: "Nothing says what the work is doing for the client. Add the results.",
|
|
143
|
+
noCore: "The outcome has supporting sections but no results. Add the results."
|
|
144
|
+
}
|
|
145
|
+
};
|
|
146
|
+
function caseStudyStageStatus(sections) {
|
|
147
|
+
const ordered = orderSections(sections);
|
|
148
|
+
return CASE_STUDY_STAGES.map((stage) => {
|
|
149
|
+
const present = ordered.map((s) => s.sectionType).filter((t) => isPortfolioSectionType(t) && SECTION_STAGE[t] === stage);
|
|
150
|
+
const complete = present.includes(STAGE_CORE_SECTION[stage]);
|
|
151
|
+
const copy = STAGE_MISSING_COPY[stage];
|
|
152
|
+
return {
|
|
153
|
+
stage,
|
|
154
|
+
present,
|
|
155
|
+
complete,
|
|
156
|
+
missing: complete ? null : present.length ? copy.noCore : copy.empty
|
|
157
|
+
};
|
|
158
|
+
});
|
|
159
|
+
}
|
|
160
|
+
var NARRATIVE_MAX_CHARS = 320;
|
|
161
|
+
function narrativeProblems(narrative) {
|
|
162
|
+
if (narrative === void 0 || narrative === null) return [];
|
|
163
|
+
if (typeof narrative !== "object") return ["narrative must be an object"];
|
|
164
|
+
const problems = [];
|
|
165
|
+
const n = narrative;
|
|
166
|
+
if (typeof n.thesis !== "string" || !n.thesis.trim()) problems.push("narrative.thesis is required");
|
|
167
|
+
else if (n.thesis.length > NARRATIVE_MAX_CHARS) problems.push(`narrative.thesis is over ${NARRATIVE_MAX_CHARS} characters`);
|
|
168
|
+
if (n.stages === void 0 || n.stages === null) return problems;
|
|
169
|
+
if (typeof n.stages !== "object") return [...problems, "narrative.stages must be an object"];
|
|
170
|
+
for (const [stage, lede] of Object.entries(n.stages)) {
|
|
171
|
+
if (!CASE_STUDY_STAGES.includes(stage)) {
|
|
172
|
+
problems.push(`narrative.stages.${stage} is not a stage (${CASE_STUDY_STAGES.join(", ")})`);
|
|
173
|
+
continue;
|
|
174
|
+
}
|
|
175
|
+
if (lede === void 0 || lede === null) continue;
|
|
176
|
+
if (typeof lede !== "string") problems.push(`narrative.stages.${stage} must be text`);
|
|
177
|
+
else if (lede.length > NARRATIVE_MAX_CHARS) problems.push(`narrative.stages.${stage} is over ${NARRATIVE_MAX_CHARS} characters`);
|
|
178
|
+
}
|
|
179
|
+
return problems;
|
|
180
|
+
}
|
|
181
|
+
var CASE_STUDY_NARRATIVE_JSON_SCHEMA = {
|
|
182
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
183
|
+
$id: "https://sonor.io/schemas/case-study-narrative.v1.json",
|
|
184
|
+
title: "CaseStudyNarrative",
|
|
185
|
+
description: "The thesis of a case study and the lede that opens each of its four stages.",
|
|
186
|
+
type: "object",
|
|
187
|
+
required: ["thesis"],
|
|
188
|
+
properties: {
|
|
189
|
+
thesis: { type: "string", minLength: 1, maxLength: NARRATIVE_MAX_CHARS },
|
|
190
|
+
stages: {
|
|
191
|
+
type: "object",
|
|
192
|
+
properties: Object.fromEntries(
|
|
193
|
+
CASE_STUDY_STAGES.map((stage) => [stage, { type: "string", maxLength: NARRATIVE_MAX_CHARS }])
|
|
194
|
+
),
|
|
195
|
+
additionalProperties: false
|
|
196
|
+
}
|
|
197
|
+
},
|
|
198
|
+
additionalProperties: false
|
|
199
|
+
};
|
|
200
|
+
function challengeId(position) {
|
|
201
|
+
return `c${position}`;
|
|
202
|
+
}
|
|
203
|
+
function caseStudyFlowProblems(input) {
|
|
204
|
+
const challenges = input.challenges ?? [];
|
|
205
|
+
const ids = challenges.map((c) => typeof c.id === "string" && c.id.trim() ? c.id.trim() : null);
|
|
206
|
+
if (!ids.some(Boolean)) return [];
|
|
207
|
+
const problems = [];
|
|
208
|
+
const known = new Set(ids.filter((id) => !!id));
|
|
209
|
+
if (known.size !== ids.filter(Boolean).length) problems.push("two challenges share an id");
|
|
210
|
+
ids.forEach((id, i) => {
|
|
211
|
+
if (!id) problems.push(`challenge ${i + 1} has no id while the others do`);
|
|
212
|
+
});
|
|
213
|
+
const resolved = /* @__PURE__ */ new Set();
|
|
214
|
+
const proven = /* @__PURE__ */ new Set();
|
|
215
|
+
for (const phase of input.phases ?? []) {
|
|
216
|
+
for (const ref of phase.resolves ?? []) {
|
|
217
|
+
if (!known.has(ref)) problems.push(`a strategy phase resolves "${ref}", which is not a challenge`);
|
|
218
|
+
else resolved.add(ref);
|
|
219
|
+
}
|
|
220
|
+
}
|
|
221
|
+
for (const result of input.results ?? []) {
|
|
222
|
+
for (const ref of result.proves ?? []) {
|
|
223
|
+
if (!known.has(ref)) problems.push(`a result proves "${ref}", which is not a challenge`);
|
|
224
|
+
else proven.add(ref);
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
const nameOf = (id) => {
|
|
228
|
+
const c = challenges.find((x) => x.id === id);
|
|
229
|
+
return c?.title?.trim() ? `"${c.title.trim()}"` : id;
|
|
230
|
+
};
|
|
231
|
+
for (const id of known) {
|
|
232
|
+
if (!resolved.has(id)) problems.push(`no strategy phase resolves challenge ${nameOf(id)}`);
|
|
233
|
+
if (!proven.has(id)) problems.push(`no result proves challenge ${nameOf(id)}`);
|
|
234
|
+
}
|
|
235
|
+
return problems;
|
|
236
|
+
}
|
|
237
|
+
var LIGHTHOUSE_RE = /lighthouse/i;
|
|
238
|
+
function isLighthouseKpi(kpi) {
|
|
239
|
+
return LIGHTHOUSE_RE.test(kpi.label || "");
|
|
240
|
+
}
|
|
241
|
+
function curateHeroKpis(kpis) {
|
|
242
|
+
const business = kpis.filter((k) => !isLighthouseKpi(k));
|
|
243
|
+
const lighthouse = kpis.filter(isLighthouseKpi);
|
|
244
|
+
if (lighthouse.length <= 1) return kpis;
|
|
245
|
+
const allPerfect = lighthouse.length >= 4 && lighthouse.every((k) => k.value === 100);
|
|
246
|
+
const summary = allPerfect ? {
|
|
247
|
+
...lighthouse[0],
|
|
248
|
+
label: "Lighthouse, all 4 categories",
|
|
249
|
+
description: "Perfect scores across performance, SEO, accessibility, and best practices."
|
|
250
|
+
} : lighthouse.find((k) => /performance/i.test(k.label)) ?? lighthouse[0];
|
|
251
|
+
return [...business, summary];
|
|
252
|
+
}
|
|
253
|
+
var PORTFOLIO_KPI_JSON_SCHEMA = {
|
|
254
|
+
$schema: "http://json-schema.org/draft-07/schema#",
|
|
255
|
+
$id: "https://sonor.io/schemas/portfolio-kpi.v1.json",
|
|
256
|
+
title: "KpiLike",
|
|
257
|
+
description: "The subset of a portfolio KPI tile the Lighthouse-collapse policy reads.",
|
|
258
|
+
type: "object",
|
|
259
|
+
required: ["label", "value"],
|
|
260
|
+
properties: {
|
|
261
|
+
label: { type: "string" },
|
|
262
|
+
value: { type: "number" },
|
|
263
|
+
description: { type: "string" },
|
|
264
|
+
source: { enum: ["measured", "reported", "estimated"] },
|
|
265
|
+
reportedBy: {
|
|
266
|
+
type: "object",
|
|
267
|
+
required: ["name", "organization", "date"],
|
|
268
|
+
properties: {
|
|
269
|
+
name: { type: "string", minLength: 1 },
|
|
270
|
+
role: { type: "string" },
|
|
271
|
+
organization: { type: "string", minLength: 1 },
|
|
272
|
+
date: { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}$" }
|
|
273
|
+
}
|
|
274
|
+
}
|
|
275
|
+
},
|
|
276
|
+
// A reported number is only valid with someone named behind it.
|
|
277
|
+
if: { properties: { source: { const: "reported" } }, required: ["source"] },
|
|
278
|
+
then: { required: ["reportedBy"] },
|
|
279
|
+
additionalProperties: true
|
|
280
|
+
};
|
|
281
|
+
var METRIC_SOURCES = ["measured", "reported", "estimated"];
|
|
282
|
+
var ISO_DAY_RE = /^\d{4}-\d{2}-\d{2}$/;
|
|
283
|
+
var MONTHS = [
|
|
284
|
+
"January",
|
|
285
|
+
"February",
|
|
286
|
+
"March",
|
|
287
|
+
"April",
|
|
288
|
+
"May",
|
|
289
|
+
"June",
|
|
290
|
+
"July",
|
|
291
|
+
"August",
|
|
292
|
+
"September",
|
|
293
|
+
"October",
|
|
294
|
+
"November",
|
|
295
|
+
"December"
|
|
296
|
+
];
|
|
297
|
+
function isMetricSource(value) {
|
|
298
|
+
return typeof value === "string" && METRIC_SOURCES.includes(value);
|
|
299
|
+
}
|
|
300
|
+
function metricSourceProblem(metric) {
|
|
301
|
+
if (metric.source === void 0 || metric.source === null) return null;
|
|
302
|
+
if (!isMetricSource(metric.source)) return `source must be one of ${METRIC_SOURCES.join(", ")}`;
|
|
303
|
+
if (metric.source !== "reported") return null;
|
|
304
|
+
const by = metric.reportedBy;
|
|
305
|
+
if (!by || typeof by !== "object") {
|
|
306
|
+
return "a reported number needs reportedBy: who reported it, where they work, and when";
|
|
307
|
+
}
|
|
308
|
+
if (typeof by.name !== "string" || !by.name.trim()) return "reportedBy.name is required";
|
|
309
|
+
if (typeof by.organization !== "string" || !by.organization.trim()) {
|
|
310
|
+
return "reportedBy.organization is required";
|
|
311
|
+
}
|
|
312
|
+
if (typeof by.date !== "string" || !ISO_DAY_RE.test(by.date) || Number.isNaN(Date.parse(by.date))) {
|
|
313
|
+
return "reportedBy.date must be a real day, YYYY-MM-DD";
|
|
314
|
+
}
|
|
315
|
+
if (by.role !== void 0 && typeof by.role !== "string") return "reportedBy.role must be text";
|
|
316
|
+
return null;
|
|
317
|
+
}
|
|
318
|
+
function isHeadlineMetric(metric) {
|
|
319
|
+
if (metric.source === "measured") return true;
|
|
320
|
+
return metric.source === "reported" && metricSourceProblem(metric) === null;
|
|
321
|
+
}
|
|
322
|
+
function metricSourceLabel(source) {
|
|
323
|
+
if (source === "measured") return "Measured";
|
|
324
|
+
if (source === "reported") return "Client-reported";
|
|
325
|
+
if (source === "estimated") return "Estimated";
|
|
326
|
+
return null;
|
|
327
|
+
}
|
|
328
|
+
function formatAttribution(by) {
|
|
329
|
+
const [year, month, day] = by.date.split("-").map(Number);
|
|
330
|
+
const when = MONTHS[month - 1] ? `${MONTHS[month - 1]} ${day}, ${year}` : by.date;
|
|
331
|
+
return [`Reported by ${by.name.trim()}`, by.role?.trim(), by.organization.trim(), when].filter(Boolean).join(", ");
|
|
332
|
+
}
|
|
333
|
+
function shortAttribution(by) {
|
|
334
|
+
return `per ${by.organization.trim()}`;
|
|
335
|
+
}
|
|
336
|
+
function carryReportedMetrics(previous, next, keyOf) {
|
|
337
|
+
const norm = (metric) => String(keyOf(metric) ?? "").trim().toLowerCase();
|
|
338
|
+
const reported = (previous ?? []).filter((m) => m?.source === "reported");
|
|
339
|
+
const taken = new Set(reported.map(norm));
|
|
340
|
+
const generated = (next ?? []).filter((m) => m && m.source !== "reported" && !taken.has(norm(m)));
|
|
341
|
+
return [...reported, ...generated];
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
export { CASE_STUDY_NARRATIVE_JSON_SCHEMA, CASE_STUDY_STAGES, CASE_STUDY_STAGE_COPY, FRAME_READY_MESSAGE, METRIC_SOURCES, NARRATIVE_MAX_CHARS, PORTFOLIO_CONTRACT_VERSION, PORTFOLIO_KPI_JSON_SCHEMA, PORTFOLIO_SECTION_ORDER, PORTFOLIO_SECTION_TYPES, SECTION_STAGE, STAGE_CORE_SECTION, STAGE_NAME_MAX_CHARS, carryReportedMetrics, caseStudyFlowProblems, caseStudyStageStatus, challengeId, curateHeroKpis, formatAttribution, groupSectionsByStage, isFrameReadyMessage, isHeadlineMetric, isLighthouseKpi, isMetricSource, isPortfolioSectionType, metricSourceLabel, metricSourceProblem, narrativeProblems, orderSections, sectionStage, shortAttribution, stageName, stageNamesProblems };
|