@sonordev/site-kit 8.6.0 → 8.8.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 +17 -0
- package/agent-manifest.json +1 -1
- package/dist/{AnalyticsProvider-GVJYL6XY.js → AnalyticsProvider-7SBJ27SI.js} +6 -6
- package/dist/{ArticleViewTracker-AOJXEBYM.js → ArticleViewTracker-PV2RD3P6.js} +5 -5
- package/dist/{BlocksPopup-AJ3CKVQG.js → BlocksPopup-NEEFV2L3.js} +9 -8
- package/dist/{ChatWidget-EYBVB5SZ.js → ChatWidget-V46UBDOM.js} +5 -5
- package/dist/{FileField-UEQYIFRO.js → FileField-MJ3RCNFJ.js} +3 -3
- package/dist/{FormSpotlight-H73ZZ66T.js → FormSpotlight-NQPQFZS7.js} +1 -1
- package/dist/{FormStage-2PLWWYBW.js → FormStage-4T5PJR5K.js} +1 -1
- package/dist/{ManagedForm-ZQOFXEWS.js → ManagedForm-DDDVMKLJ.js} +6 -6
- package/dist/{ManagedNewsletterForm-5TE47YZD.js → ManagedNewsletterForm-TUYGN6O3.js} +9 -9
- package/dist/{SignalCore-FEFNMNYN.js → SignalCore-OW3YIH6M.js} +5 -5
- package/dist/SiteChat-XMKHBSEK.js +6 -0
- package/dist/SiteDesignReporter-BRH7ORQS.js +13 -0
- package/dist/{SitePopups-C44YTQ3Q.js → SitePopups-VU2C3Z6B.js} +6 -6
- package/dist/SitemapSync-C4H3HF3L.js +9 -0
- package/dist/_client/booking-widget.js +5 -5
- package/dist/admin-auth/index.d.ts +2 -2
- package/dist/admin-auth/session.d.ts +2 -2
- 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-KTMHRXDT.js → chunk-2WM4TNDF.js} +1 -1
- package/dist/chunk-3MJNBOUO.js +8 -0
- package/dist/{chunk-BF7TZYC3.js → chunk-52KO4LKD.js} +1 -1
- package/dist/chunk-64XODP7M.js +7 -0
- package/dist/{chunk-DSD3XZQQ.js → chunk-6BFQI3ZE.js} +3 -3
- package/dist/{chunk-QNOJSSQT.js → chunk-6DXQHNZK.js} +1 -1
- package/dist/{chunk-5D7ZISUP.js → chunk-7DYMM6SS.js} +11 -6
- package/dist/{chunk-QQT2T6JQ.js → chunk-7HW4TZB5.js} +1 -1
- package/dist/{chunk-E4PTMORJ.js → chunk-AL5UCWLI.js} +23 -8
- package/dist/chunk-AYQEIMGS.js +390 -0
- package/dist/{chunk-L6QTERSH.js → chunk-DYROJGI2.js} +1 -1
- package/dist/{chunk-XA7Q2VQA.js → chunk-EK7P62DT.js} +1 -1
- package/dist/{chunk-BUE3Z32O.js → chunk-F6WLHVMQ.js} +1 -1
- package/dist/{chunk-IYCSDFPN.js → chunk-FLOJUMFR.js} +2 -2
- package/dist/{chunk-7R2STOVD.js → chunk-G7BRCSV6.js} +3 -3
- package/dist/{chunk-NI6ZTP3D.js → chunk-GQN4BGK6.js} +1 -1
- package/dist/{chunk-GFY3E7EQ.js → chunk-GXWM5KNS.js} +15 -7
- package/dist/{chunk-U34O6I7W.js → chunk-HN7GVGWC.js} +3 -3
- package/dist/{chunk-6KU7STM3.js → chunk-HY7ZEU2C.js} +3 -1
- package/dist/chunk-IBHBEUZV.js +27 -0
- package/dist/{chunk-ZZSAWXWD.js → chunk-IDC5CVBR.js} +1 -1
- package/dist/{chunk-HMTPRBYJ.js → chunk-IWNJCRXW.js} +1 -1
- package/dist/chunk-JESLPEST.js +14 -0
- package/dist/{chunk-BC7JMY4Z.js → chunk-JG53YJLM.js} +58 -1
- package/dist/{chunk-RI2N2EBI.js → chunk-JYITKUUB.js} +13 -5
- package/dist/{chunk-V67OD7RW.js → chunk-KG5IEV7I.js} +113 -93
- package/dist/chunk-KIYACQW3.js +1 -0
- package/dist/{chunk-JSW42BHL.js → chunk-M5JIHQ42.js} +1 -1
- package/dist/{chunk-YJH6WE76.js → chunk-NFGAXWCN.js} +9 -9
- package/dist/{chunk-Y35BWW2C.js → chunk-ODOV76VW.js} +1 -1
- package/dist/{chunk-VA6IJ55K.js → chunk-OPUY4RS6.js} +1 -1
- package/dist/{chunk-6NXFA7HE.js → chunk-OWZWRP7Y.js} +2 -2
- package/dist/{chunk-JJ4JS3LD.js → chunk-PAYCK7FC.js} +1 -1
- package/dist/{chunk-72F44HKL.js → chunk-PSS6M4CG.js} +1 -1
- package/dist/{chunk-O3Z5HHFP.js → chunk-SBPUFTMP.js} +2 -2
- package/dist/{chunk-OFSV5TZY.js → chunk-SHAUX2MQ.js} +1 -1
- package/dist/{chunk-OWO3RFEX.js → chunk-SLFYTELD.js} +1 -1
- package/dist/{chunk-CMUD37WV.js → chunk-SVHPILS3.js} +1 -1
- package/dist/{chunk-YNBRVVTX.js → chunk-THXELZTQ.js} +1 -1
- package/dist/{chunk-IGAIQ2B3.js → chunk-TP32MRXV.js} +2 -2
- package/dist/{chunk-NUXXFCIT.js → chunk-URLTBVRX.js} +4 -4
- package/dist/chunk-XAZC2TUD.js +1119 -0
- package/dist/{chunk-URJN75ZG.js → chunk-XIDWNXZN.js} +3 -3
- package/dist/chunk-XLAHRN4B.js +1 -0
- package/dist/chunk-XS2ORMUG.js +32 -0
- package/dist/{chunk-6AWIUO2Z.js → chunk-Y6SHFILE.js} +1 -1
- package/dist/{chunk-FTSEP7Q3.js → chunk-YEX5RAEU.js} +3 -3
- package/dist/{chunk-AJG74ZZV.js → chunk-YRQS7VAH.js} +1 -1
- package/dist/{chunk-DLM4FFNH.js → chunk-ZQSCMYZO.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/frame-ready.d.ts +23 -0
- 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 +361 -8
- 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 +20 -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/og/pages.d.ts +3 -3
- package/dist/portfolio/contract.js +705 -1
- package/dist/press-kit/articles/article-body.d.ts +12 -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/frame.d.ts +1 -1
- package/dist/shared/markdown.d.ts +7 -6
- package/dist/shared/source-graph.d.ts +5 -5
- package/dist/shared/version.d.ts +1 -1
- package/dist/signal/index.js +2 -2
- package/dist/sitemap/index.js +7 -5
- package/dist/sitemap/shared.d.ts +1 -2
- 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 +20 -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-4HHUAOA6.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
package/dist/articles/server.js
CHANGED
|
@@ -1,21 +1,22 @@
|
|
|
1
|
-
export { ArticleUnavailableError, FEED_DEFAULT_ITEMS, NEWS_SITEMAP_MAX_URLS, NEWS_SITEMAP_WINDOW_MS, PUBLICATION_PREVIEW_COOKIE, PUBLICATION_PREVIEW_HEADERS, SEO_LIMITS, buildNewsSitemapXml, cdata, createPublicationPreviewHandler, 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 } from '../chunk-
|
|
1
|
+
export { ArticleUnavailableError, FEED_DEFAULT_ITEMS, NEWS_SITEMAP_MAX_URLS, NEWS_SITEMAP_WINDOW_MS, PUBLICATION_PREVIEW_COOKIE, PUBLICATION_PREVIEW_HEADERS, SEO_LIMITS, buildNewsSitemapXml, cdata, createPublicationPreviewHandler, 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 } from '../chunk-JYITKUUB.js';
|
|
2
2
|
export { articlePhotoCss, insertArticlePhotos } from '../chunk-WHPCGQHC.js';
|
|
3
|
-
export { articleTableCss, wrapArticleTables } from '../chunk-
|
|
3
|
+
export { articleTableCss, wrapArticleTables } from '../chunk-AL5UCWLI.js';
|
|
4
4
|
export { articleImageSchema, authorEntityId, generateArticleAuthorNode, generateAuthorPersonSchema, generateAuthorSchema, resolveArticleArtwork, resolveRepresentativeImage, withArticleAuthorIdentity } from '../chunk-UVYUTBT4.js';
|
|
5
5
|
import '../chunk-H72ZFO3F.js';
|
|
6
|
+
import '../chunk-IBHBEUZV.js';
|
|
6
7
|
export { articleCategorySlug, createPublicationRoutes, resolveArticleUrl, resolvePublicationUrl } from '../chunk-4K735O3J.js';
|
|
7
8
|
import '../chunk-34ZYJTQR.js';
|
|
8
|
-
import '../chunk-
|
|
9
|
+
import '../chunk-M5JIHQ42.js';
|
|
9
10
|
import '../chunk-UAYAJPEP.js';
|
|
10
11
|
import '../chunk-VWWITFWM.js';
|
|
11
12
|
import '../chunk-4KZ6W3ZH.js';
|
|
12
13
|
import '../chunk-MJP63SSS.js';
|
|
13
|
-
import '../chunk-
|
|
14
|
+
import '../chunk-HY7ZEU2C.js';
|
|
14
15
|
import '../chunk-C7TLGL3R.js';
|
|
15
16
|
import '../chunk-MH2DSGC6.js';
|
|
16
17
|
import '../chunk-YVKRYQRG.js';
|
|
17
18
|
import '../chunk-FESKKJAS.js';
|
|
18
19
|
import '../chunk-A4CC4ZG3.js';
|
|
19
20
|
import '../chunk-W7OPEMGJ.js';
|
|
20
|
-
import '../chunk-
|
|
21
|
+
import '../chunk-F6WLHVMQ.js';
|
|
21
22
|
import '../chunk-PKBMQBKP.js';
|
package/dist/chat/index.js
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
export { ChatWidget, DEFAULT_LAUNCHER_OFFSET_BOTTOM, EchoChat, chatLauncherStyles, isChatEnabled } from '../chunk-
|
|
3
|
-
export { SiteChat } from '../chunk-
|
|
2
|
+
export { ChatWidget, DEFAULT_LAUNCHER_OFFSET_BOTTOM, EchoChat, chatLauncherStyles, isChatEnabled } from '../chunk-TP32MRXV.js';
|
|
3
|
+
export { SiteChat } from '../chunk-SBPUFTMP.js';
|
|
4
4
|
import '../chunk-6T6CQVNL.js';
|
|
5
5
|
import '../chunk-JE4A5S4F.js';
|
|
6
6
|
import '../chunk-27FISYK4.js';
|
|
7
|
-
import '../chunk-
|
|
7
|
+
import '../chunk-IWNJCRXW.js';
|
|
8
8
|
import '../chunk-Q6E4OPGG.js';
|
|
9
9
|
import '../chunk-5ROTTMBL.js';
|
|
10
10
|
import '../chunk-C2FZBUSS.js';
|
|
@@ -15,12 +15,12 @@ import '../chunk-S22FSH7C.js';
|
|
|
15
15
|
import '../chunk-L2V5PUFN.js';
|
|
16
16
|
import '../chunk-GJWI74ZZ.js';
|
|
17
17
|
import '../chunk-5TM3WPCI.js';
|
|
18
|
-
import '../chunk-
|
|
19
|
-
import '../chunk-
|
|
20
|
-
import '../chunk-
|
|
21
|
-
import '../chunk-
|
|
18
|
+
import '../chunk-ZQSCMYZO.js';
|
|
19
|
+
import '../chunk-64XODP7M.js';
|
|
20
|
+
import '../chunk-FLOJUMFR.js';
|
|
21
|
+
import '../chunk-7HW4TZB5.js';
|
|
22
22
|
import '../chunk-W7OPEMGJ.js';
|
|
23
|
-
import '../chunk-
|
|
23
|
+
import '../chunk-F6WLHVMQ.js';
|
|
24
24
|
import '../chunk-PKBMQBKP.js';
|
|
25
25
|
|
|
26
26
|
// src/chat/echo-config.ts
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import { SLOTS_CONTRACT_VERSION, verifySlotContent, canonicalJson } from './chunk-VCJYLYJV.js';
|
|
2
2
|
import { isValidSlotId, SLOT_CONTENT_MAX_LENGTH, parseSlotRichText, normalizeSlotValue } from './chunk-LPH5FANE.js';
|
|
3
|
-
import { SITE_CACHE_TAGS } from './chunk-
|
|
3
|
+
import { SITE_CACHE_TAGS } from './chunk-HY7ZEU2C.js';
|
|
4
4
|
import { resolveServerApiConfig } from './chunk-C7TLGL3R.js';
|
|
5
5
|
import 'server-only';
|
|
6
6
|
import * as React from 'react';
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { generateLLMsTxt, generateLLMsFullTxt, appendAgentAccessSection } from './chunk-
|
|
1
|
+
import { generateLLMsTxt, generateLLMsFullTxt, appendAgentAccessSection } from './chunk-KG5IEV7I.js';
|
|
2
2
|
import { createHash } from 'crypto';
|
|
3
3
|
import { existsSync, readFileSync } from 'fs';
|
|
4
4
|
import { join } from 'path';
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
// src/contracts/campaign-normalize.ts
|
|
2
|
+
function normalizeCampaignSlug(input) {
|
|
3
|
+
if (!input || typeof input !== "string") return null;
|
|
4
|
+
const slug = input.trim().toLowerCase().replace(/[\s_]+/g, "-").replace(/[^a-z0-9-]/g, "").replace(/-{2,}/g, "-").replace(/^-+|-+$/g, "").slice(0, 80);
|
|
5
|
+
return slug || null;
|
|
6
|
+
}
|
|
7
|
+
|
|
8
|
+
export { normalizeCampaignSlug };
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { normalizeDesignTokens, designTokenCssVars, sanitizePopupHtml, isSafePopupUrl } from './chunk-
|
|
2
|
+
import { normalizeDesignTokens, designTokenCssVars, sanitizePopupHtml, isSafePopupUrl } from './chunk-XHYE24HU.js';
|
|
3
3
|
import { useId, useRef, useEffect } from 'react';
|
|
4
4
|
import { jsxs, jsx } from 'react/jsx-runtime';
|
|
5
5
|
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
// src/contracts/frame-ready.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
|
+
|
|
7
|
+
export { FRAME_READY_MESSAGE, isFrameReadyMessage };
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-
|
|
3
|
-
import { designTokensHash } from './chunk-
|
|
2
|
+
import { getSiteDesignTokens, tokensForReport, shouldReportDesign, sendSiteDesign } from './chunk-URLTBVRX.js';
|
|
3
|
+
import { designTokensHash } from './chunk-XHYE24HU.js';
|
|
4
4
|
import { useDeferredActivation } from './chunk-YC7ELZS3.js';
|
|
5
|
-
import { resolveAnalyticsTarget } from './chunk-
|
|
5
|
+
import { resolveAnalyticsTarget } from './chunk-ZQSCMYZO.js';
|
|
6
6
|
import { useRef, useEffect } from 'react';
|
|
7
7
|
|
|
8
8
|
var STAMP_KEY = (site) => `_sk_design_sent:${site}`;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-
|
|
2
|
+
import { detectTimezone, releaseSlotHold, fetchBookingTypeDetails, fetchBookingTypes, fetchAvailability, createSlotHold, createBooking, formatDuration, formatDate, formatTime, prepareMeeting } from './chunk-PSS6M4CG.js';
|
|
3
3
|
import { readPublishedApiConfig, DEFAULT_SONOR_API_URL } from './chunk-W7OPEMGJ.js';
|
|
4
4
|
import { useState, useRef, useMemo, useCallback, useEffect, useId } from 'react';
|
|
5
5
|
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { htmlTags, isClosingTag, htmlTagName, openTagAttributes } from './chunk-IBHBEUZV.js';
|
|
2
|
+
|
|
1
3
|
// packages/press-kit/src/articles/processArticleHtml.ts
|
|
2
4
|
function linkClassificationHost(siteUrl) {
|
|
3
5
|
try {
|
|
@@ -24,20 +26,23 @@ function addExternalLinkTargets(html, siteUrl) {
|
|
|
24
26
|
if (!html || !siteUrl) return html;
|
|
25
27
|
const siteHost = linkClassificationHost(siteUrl);
|
|
26
28
|
if (!siteHost) return html;
|
|
27
|
-
return html.replace(
|
|
29
|
+
return html.replace(htmlTags(), (tag) => {
|
|
30
|
+
if (isClosingTag(tag) || htmlTagName(tag) !== "a") return tag;
|
|
31
|
+
const attrs = openTagAttributes(tag);
|
|
32
|
+
const unchanged = `<a${attrs}>`;
|
|
28
33
|
const hrefMatch = attrs.match(/\bhref\s*=\s*(["'])([^"']*)\1/i);
|
|
29
|
-
if (!hrefMatch) return
|
|
34
|
+
if (!hrefMatch) return unchanged;
|
|
30
35
|
const href = hrefMatch[2].trim();
|
|
31
|
-
if (!/^https?:\/\//i.test(href)) return
|
|
36
|
+
if (!/^https?:\/\//i.test(href)) return unchanged;
|
|
32
37
|
try {
|
|
33
38
|
const url = new URL(href);
|
|
34
39
|
const linkHost = url.hostname.replace(/^www\./i, "").toLowerCase();
|
|
35
|
-
if (linkHost === siteHost) return
|
|
36
|
-
if (/\btarget\s*=/i.test(attrs)) return
|
|
40
|
+
if (linkHost === siteHost) return unchanged;
|
|
41
|
+
if (/\btarget\s*=/i.test(attrs)) return unchanged;
|
|
37
42
|
const trimmed = attrs.trim();
|
|
38
43
|
return `<a ${trimmed} target="_blank" rel="noopener noreferrer">`;
|
|
39
44
|
} catch {
|
|
40
|
-
return
|
|
45
|
+
return unchanged;
|
|
41
46
|
}
|
|
42
47
|
});
|
|
43
48
|
}
|
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { htmlTags, htmlTagName, isClosingTag } from './chunk-IBHBEUZV.js';
|
|
2
|
+
|
|
1
3
|
// packages/press-kit/src/articles/article-tables.ts
|
|
2
4
|
var tableScrollClass = "sk-article-table-scroll";
|
|
3
5
|
var legacyTableScrollClass = "sk-blog-table-scroll";
|
|
@@ -18,9 +20,6 @@ var voidElements = /* @__PURE__ */ new Set([
|
|
|
18
20
|
"wbr"
|
|
19
21
|
]);
|
|
20
22
|
var preservedElements = /* @__PURE__ */ new Set(["pre", "code", "script", "style", "textarea", "xmp", "template"]);
|
|
21
|
-
function htmlTags() {
|
|
22
|
-
return /<!--[\s\S]*?(?:-->|$)|<\/?[a-z][\w:-]*(?=[\s/>])(?:[^"'<>]|"[^"]*"|'[^']*')*>/gi;
|
|
23
|
-
}
|
|
24
23
|
function hasScrollClass(tag) {
|
|
25
24
|
const attributes = tag.replace(/^<[\w:-]+/, "").replace(/\/?>$/, "");
|
|
26
25
|
const pattern = /([^\s=/>]+)(?:\s*=\s*(?:"([^"]*)"|'([^']*)'|([^\s"'=<>`]+)))?/g;
|
|
@@ -31,14 +30,30 @@ function hasScrollClass(tag) {
|
|
|
31
30
|
return false;
|
|
32
31
|
}
|
|
33
32
|
function labelText(html) {
|
|
34
|
-
return html.replace(
|
|
33
|
+
return html.replace(htmlTags(), (token) => token.startsWith("<!--") ? "" : " ").replace(/\s+/g, " ").trim();
|
|
35
34
|
}
|
|
36
35
|
function escapeLabel(text) {
|
|
37
36
|
return text.replace(/&(?!(?:#\d+|#x[\da-f]+|[a-z][\da-z]+);)/gi, "&").replace(/"/g, """).replace(/</g, "<").replace(/>/g, ">");
|
|
38
37
|
}
|
|
38
|
+
function elementContents(table, name) {
|
|
39
|
+
const tags = htmlTags();
|
|
40
|
+
const contents = [];
|
|
41
|
+
let from = -1;
|
|
42
|
+
let token;
|
|
43
|
+
while (token = tags.exec(table)) {
|
|
44
|
+
if (htmlTagName(token[0]) !== name) continue;
|
|
45
|
+
if (!isClosingTag(token[0])) {
|
|
46
|
+
if (from < 0) from = tags.lastIndex;
|
|
47
|
+
} else if (from >= 0) {
|
|
48
|
+
contents.push(table.slice(from, token.index));
|
|
49
|
+
from = -1;
|
|
50
|
+
}
|
|
51
|
+
}
|
|
52
|
+
return contents;
|
|
53
|
+
}
|
|
39
54
|
function tableLabel(table, number) {
|
|
40
|
-
const caption = table
|
|
41
|
-
const headers =
|
|
55
|
+
const caption = elementContents(table, "caption")[0];
|
|
56
|
+
const headers = elementContents(table, "th").slice(0, 4).map(labelText).filter(Boolean).join(", ");
|
|
42
57
|
const summary = labelText(caption || headers).slice(0, 180);
|
|
43
58
|
return escapeLabel(`Table ${number}${summary ? `: ${summary}` : ""}`);
|
|
44
59
|
}
|
|
@@ -50,8 +65,8 @@ function wrapArticleTables(html) {
|
|
|
50
65
|
let token;
|
|
51
66
|
while (token = tags.exec(html)) {
|
|
52
67
|
const tag = token[0];
|
|
53
|
-
|
|
54
|
-
|
|
68
|
+
const tagName = htmlTagName(tag);
|
|
69
|
+
if (!tagName) continue;
|
|
55
70
|
if (tag.startsWith("</")) {
|
|
56
71
|
const index = stack.map((frame3) => frame3.tag).lastIndexOf(tagName);
|
|
57
72
|
if (index < 0) continue;
|
|
@@ -0,0 +1,390 @@
|
|
|
1
|
+
import { isBlockedPublicUrlHost } from './chunk-XS2ORMUG.js';
|
|
2
|
+
import { LandingPage } from './chunk-PAYCK7FC.js';
|
|
3
|
+
import { normalizeCampaignSlug } from './chunk-3MJNBOUO.js';
|
|
4
|
+
import { landingPageMetadata } from './chunk-JESLPEST.js';
|
|
5
|
+
import { ServerForm } from './chunk-YRQS7VAH.js';
|
|
6
|
+
import { serverApiFetch } from './chunk-C7TLGL3R.js';
|
|
7
|
+
import { normalizeSiteHost } from './chunk-A4CC4ZG3.js';
|
|
8
|
+
import 'server-only';
|
|
9
|
+
import { jsxs, jsx, Fragment } from 'react/jsx-runtime';
|
|
10
|
+
|
|
11
|
+
// src/contracts/publication-branding.ts
|
|
12
|
+
var PUBLICATION_COLOR_FIELDS = ["primary", "secondary", "accent", "background", "surface", "text", "muted", "border"];
|
|
13
|
+
var GENERIC_FONT_FAMILIES = /* @__PURE__ */ new Set(["serif", "sans-serif", "monospace", "system-ui", "cursive", "fantasy", "ui-serif", "ui-sans-serif", "ui-monospace"]);
|
|
14
|
+
function containsControlCharacters(value) {
|
|
15
|
+
for (const character of value) {
|
|
16
|
+
const code = character.charCodeAt(0);
|
|
17
|
+
if (code <= 31 || code === 127) return true;
|
|
18
|
+
}
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
function safeFontStack(value) {
|
|
22
|
+
if (typeof value !== "string" || value.length > 512 || containsControlCharacters(value) || /[;{}<>\\]|(?:var|url|expression)\s*\(/i.test(value)) return void 0;
|
|
23
|
+
const names = value.split(",").map((v) => v.trim().replace(/^(['"])(.*)\1$/, "$2")).filter(Boolean).filter((v) => !/^(?:heading|body|mono)$/i.test(v));
|
|
24
|
+
if (!names.length || names.some((v) => !/^[\p{L}\p{N} _.-]+$/u.test(v))) return void 0;
|
|
25
|
+
return names.map((v) => GENERIC_FONT_FAMILIES.has(v.toLowerCase()) ? v.toLowerCase() : `'${v}'`).join(",");
|
|
26
|
+
}
|
|
27
|
+
|
|
28
|
+
// src/contracts/funnels.ts
|
|
29
|
+
var MANAGED_FUNNEL_PATH_PREFIX = "/f";
|
|
30
|
+
var FUNNEL_TEMPLATES = ["newsletter", "requested_guide", "inquiry"];
|
|
31
|
+
var string = (maxLength, minLength = 1) => ({ type: "string", minLength, maxLength });
|
|
32
|
+
var literal = (value) => ({ const: value });
|
|
33
|
+
var enumeration = (...values) => ({ type: "string", enum: values });
|
|
34
|
+
var object = (properties, required = Object.keys(properties)) => ({ type: "object", properties, required, additionalProperties: false });
|
|
35
|
+
var array = (items, maxItems, minItems = 0) => ({ type: "array", items, maxItems, minItems });
|
|
36
|
+
var integer = (minimum, maximum = Number.MAX_SAFE_INTEGER) => ({ type: "integer", minimum, maximum });
|
|
37
|
+
var nullable = (shape) => ({ oneOf: [shape, { type: "null" }] });
|
|
38
|
+
var isoDate = { type: "string", pattern: "^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}(?:\\.\\d{1,3})?Z$" };
|
|
39
|
+
var uuid = { type: "string", pattern: "^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$" };
|
|
40
|
+
var slug = { ...string(80), pattern: "^[a-z0-9]+(?:-[a-z0-9]+)*$" };
|
|
41
|
+
var fieldSlug = { ...string(80), pattern: "^[a-zA-Z0-9_-]+$" };
|
|
42
|
+
var path = { ...string(512), pattern: "^/(?!/)[a-zA-Z0-9/_-]*$" };
|
|
43
|
+
var site = { ...string(253), pattern: "^[a-z0-9](?:[a-z0-9-]*[a-z0-9])?(?:\\.[a-z0-9](?:[a-z0-9-]*[a-z0-9])?)+$" };
|
|
44
|
+
var color = { ...string(9), pattern: "^#[a-fA-F0-9]{6}$" };
|
|
45
|
+
var colors = object(Object.fromEntries(PUBLICATION_COLOR_FIELDS.map((key) => [key, color])));
|
|
46
|
+
var typography = object({ headingFamily: string(200), bodyFamily: string(200) });
|
|
47
|
+
var override = object({
|
|
48
|
+
displayName: nullable(string(120)),
|
|
49
|
+
tagline: nullable(string(300, 0)),
|
|
50
|
+
fullLogoAssetId: nullable(uuid),
|
|
51
|
+
squareLogoAssetId: nullable(uuid),
|
|
52
|
+
colors: object(Object.fromEntries(PUBLICATION_COLOR_FIELDS.map((key) => [key, nullable(color)])), []),
|
|
53
|
+
typography: object({ headingFamily: nullable(string(200)), bodyFamily: nullable(string(200)) }, [])
|
|
54
|
+
}, []);
|
|
55
|
+
var bodyBlock = { oneOf: [object({ type: literal("paragraph"), text: string(2e3) }), object({ type: literal("bullets"), items: array(string(500), 8, 1) })] };
|
|
56
|
+
var body = array(bodyBlock, 12);
|
|
57
|
+
var publicBrand = object({ displayName: string(120), tagline: string(300, 0), fullLogoUrl: nullable(string(2048)), squareLogoUrl: nullable(string(2048)), colors, typography, scheme: enumeration("light", "dark") });
|
|
58
|
+
var step = { oneOf: [
|
|
59
|
+
object({ id: uuid, type: literal("wait"), durationSeconds: integer(60, 2592e3) }),
|
|
60
|
+
object({ id: uuid, type: literal("send_email"), templateId: uuid, purpose: enumeration("requested_fulfillment", "marketing"), guideAssetId: nullable(uuid) }, ["id", "type", "templateId", "purpose"]),
|
|
61
|
+
object({ id: uuid, type: literal("add_tag"), target: literal("subscriber"), tag: string(80) }),
|
|
62
|
+
object({ id: uuid, type: literal("create_task"), ownerContactId: uuid, title: string(160), dueAfterSeconds: integer(0, 2592e3) })
|
|
63
|
+
] };
|
|
64
|
+
var definitionShape = object({
|
|
65
|
+
schemaVersion: literal(1),
|
|
66
|
+
name: string(120),
|
|
67
|
+
template: enumeration(...FUNNEL_TEMPLATES),
|
|
68
|
+
site,
|
|
69
|
+
entry: object({ formId: uuid, mode: literal("future_accepted_form_only") }),
|
|
70
|
+
goal: object({ type: enumeration("newsletter_confirmed", "guide_requested", "inquiry_received", "booking_confirmed"), bookingTypeId: nullable(uuid) }, ["type"]),
|
|
71
|
+
page: object({ mode: enumeration("existing", "managed"), path, slug: nullable(slug), headline: string(160, 0), body, formId: uuid, offerAssetId: nullable(uuid) }, ["mode", "path", "headline", "body", "formId"]),
|
|
72
|
+
permission: object({ mode: enumeration("requested_only", "marketing_opt_in"), optInFieldSlug: nullable(fieldSlug) }, ["mode"]),
|
|
73
|
+
brandOverride: override,
|
|
74
|
+
steps: array(step, 8),
|
|
75
|
+
exits: object({ unsubscribe: literal(true), manualStop: literal(true), confirmedBooking: object({ enabled: { type: "boolean" }, bookingTypeId: nullable(uuid) }) }, ["unsubscribe", "manualStop"])
|
|
76
|
+
}, ["schemaVersion", "name", "template", "site", "entry", "goal", "page", "permission", "steps", "exits"]);
|
|
77
|
+
var draftDefinitionShape = JSON.parse(JSON.stringify(definitionShape));
|
|
78
|
+
var draftProps = draftDefinitionShape.properties;
|
|
79
|
+
draftProps.name = string(120, 0);
|
|
80
|
+
draftProps.site = nullable(site);
|
|
81
|
+
draftProps.entry.properties.formId = nullable(uuid);
|
|
82
|
+
draftProps.page.properties.path = nullable(path);
|
|
83
|
+
draftProps.page.properties.formId = nullable(uuid);
|
|
84
|
+
draftProps.permission.properties.optInFieldSlug = nullable(fieldSlug);
|
|
85
|
+
draftProps.steps.items.oneOf = draftProps.steps.items.oneOf.map((item) => {
|
|
86
|
+
const fields = item.properties;
|
|
87
|
+
if (fields.templateId) fields.templateId = nullable(uuid);
|
|
88
|
+
if (fields.guideAssetId) fields.guideAssetId = nullable(uuid);
|
|
89
|
+
if (fields.ownerContactId) fields.ownerContactId = nullable(uuid);
|
|
90
|
+
if (fields.title) fields.title = string(160, 0);
|
|
91
|
+
if (fields.tag) fields.tag = string(80, 0);
|
|
92
|
+
return item;
|
|
93
|
+
});
|
|
94
|
+
draftProps.page.properties.body = array({ oneOf: [object({ type: literal("paragraph"), text: string(2e3, 0) }), object({ type: literal("bullets"), items: array(string(500, 0), 8, 1) })] }, 12);
|
|
95
|
+
var FUNNEL_DRAFT_DEFINITION_JSON_SCHEMA = { $schema: "http://json-schema.org/draft-07/schema#", ...draftDefinitionShape };
|
|
96
|
+
var FUNNEL_DEFINITION_JSON_SCHEMA = { $schema: "http://json-schema.org/draft-07/schema#", ...definitionShape };
|
|
97
|
+
var publishedShape = object({
|
|
98
|
+
schemaVersion: literal(1),
|
|
99
|
+
id: uuid,
|
|
100
|
+
versionId: uuid,
|
|
101
|
+
revision: integer(1),
|
|
102
|
+
site,
|
|
103
|
+
path,
|
|
104
|
+
content: object({ headline: string(160), body, offer: object({ label: string(120), href: string(2048) }) }, ["headline", "body"]),
|
|
105
|
+
brand: publicBrand,
|
|
106
|
+
conversion: object({ formSlug: fieldSlug }),
|
|
107
|
+
tracking: object({ campaignSlug: slug })
|
|
108
|
+
});
|
|
109
|
+
var PUBLISHED_FUNNEL_PAGE_JSON_SCHEMA = { $schema: "http://json-schema.org/draft-07/schema#", ...publishedShape };
|
|
110
|
+
var FUNNEL_LAUNCH_JSON_SCHEMA = object({ expectedRevision: integer(1), previewId: uuid, idempotencyKey: string(200), confirm: literal(true) });
|
|
111
|
+
var FUNNEL_LIFECYCLE_JSON_SCHEMA = object({ expectedActiveVersionId: uuid, idempotencyKey: string(200), confirm: literal(true) });
|
|
112
|
+
var FUNNEL_ROLLBACK_JSON_SCHEMA = object({ expectedActiveVersionId: uuid, targetVersionId: uuid, idempotencyKey: string(200), confirm: literal(true) });
|
|
113
|
+
var FunnelValidationError = class extends Error {
|
|
114
|
+
constructor(path2, reason) {
|
|
115
|
+
super(`${path2}: ${reason}`);
|
|
116
|
+
this.path = path2;
|
|
117
|
+
this.name = "FunnelValidationError";
|
|
118
|
+
}
|
|
119
|
+
};
|
|
120
|
+
function fail(path2, reason) {
|
|
121
|
+
throw new FunnelValidationError(path2, reason);
|
|
122
|
+
}
|
|
123
|
+
function check(value, shape, at) {
|
|
124
|
+
if (shape.oneOf) {
|
|
125
|
+
let matches = 0;
|
|
126
|
+
for (const candidate of shape.oneOf) {
|
|
127
|
+
try {
|
|
128
|
+
check(value, candidate, at);
|
|
129
|
+
matches++;
|
|
130
|
+
} catch (error) {
|
|
131
|
+
if (!(error instanceof FunnelValidationError)) throw error;
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
if (matches !== 1) fail(at, "must match one supported shape");
|
|
135
|
+
return;
|
|
136
|
+
}
|
|
137
|
+
if ("const" in shape && value !== shape.const) fail(at, "unexpected value");
|
|
138
|
+
if (shape.enum && !shape.enum.includes(value)) fail(at, "unsupported value");
|
|
139
|
+
if (shape.type === "null" && value !== null) fail(at, "must be null");
|
|
140
|
+
if (shape.type === "boolean" && typeof value !== "boolean") fail(at, "must be boolean");
|
|
141
|
+
if (shape.type === "string") {
|
|
142
|
+
if (typeof value !== "string") fail(at, "must be a string");
|
|
143
|
+
if (value.length < (shape.minLength ?? 0) || value.length > (shape.maxLength ?? Infinity) || (shape.minLength ?? 0) > 0 && !value.trim() || /[\x00-\x08\x0b\x0c\x0e-\x1f\x7f]/.test(value)) fail(at, "invalid string length or control character");
|
|
144
|
+
if (shape.pattern) {
|
|
145
|
+
const match = new RegExp(shape.pattern).exec(value);
|
|
146
|
+
if (!match || match[0] !== value) fail(at, "invalid format");
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
if (shape.type === "integer" && (typeof value !== "number" || !Number.isSafeInteger(value) || value < (shape.minimum ?? -Infinity) || value > (shape.maximum ?? Infinity))) fail(at, "invalid integer");
|
|
150
|
+
if (shape.type === "array") {
|
|
151
|
+
if (!Array.isArray(value) || value.length < (shape.minItems ?? 0) || value.length > (shape.maxItems ?? Infinity)) fail(at, "invalid array length");
|
|
152
|
+
value.forEach((item, i) => check(item, shape.items, `${at}[${i}]`));
|
|
153
|
+
}
|
|
154
|
+
if (shape.type === "object") {
|
|
155
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) fail(at, "must be an object");
|
|
156
|
+
const row = value;
|
|
157
|
+
if (![Object.prototype, null].includes(Object.getPrototypeOf(row))) fail(at, "must be plain JSON");
|
|
158
|
+
for (const key of shape.required ?? []) if (!Object.prototype.hasOwnProperty.call(row, key)) fail(`${at}.${key}`, "required");
|
|
159
|
+
for (const key of Object.keys(row)) {
|
|
160
|
+
if (!Object.prototype.hasOwnProperty.call(shape.properties, key)) fail(`${at}.${key}`, "unknown field");
|
|
161
|
+
check(row[key], shape.properties[key], `${at}.${key}`);
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
}
|
|
165
|
+
function isSafeFunnelPublicUrl(value) {
|
|
166
|
+
try {
|
|
167
|
+
const url = new URL(value);
|
|
168
|
+
return value.startsWith("https://") && url.protocol === "https:" && !url.username && !url.password && (!url.port || url.port === "443") && !isBlockedPublicUrlHost(url.hostname) && !/[\s\x00-\x1f\\]/.test(value);
|
|
169
|
+
} catch {
|
|
170
|
+
return false;
|
|
171
|
+
}
|
|
172
|
+
}
|
|
173
|
+
function managedFunnelPath(value) {
|
|
174
|
+
check(value, slug, "slug");
|
|
175
|
+
if (normalizeCampaignSlug(value) !== value) fail("slug", "must be canonical");
|
|
176
|
+
return `${MANAGED_FUNNEL_PATH_PREFIX}/${value}`;
|
|
177
|
+
}
|
|
178
|
+
function checkFonts(value, at) {
|
|
179
|
+
for (const [key, font] of Object.entries(value.typography ?? {})) if (font !== null && safeFontStack(font) === void 0) fail(`${at}.typography.${key}`, "unsafe font stack");
|
|
180
|
+
}
|
|
181
|
+
function checkBody(blocks, at) {
|
|
182
|
+
if (blocks.reduce((total, block) => total + (block.type === "paragraph" ? block.text.length : block.items.join("").length), 0) > 12e3) fail(at, "total text exceeds 12000 characters");
|
|
183
|
+
}
|
|
184
|
+
function parsePublishedFunnelPage(value) {
|
|
185
|
+
check(value, publishedShape, "page");
|
|
186
|
+
const result = JSON.parse(JSON.stringify(value));
|
|
187
|
+
const suffix = result.path.slice(MANAGED_FUNNEL_PATH_PREFIX.length + 1);
|
|
188
|
+
if (managedFunnelPath(suffix) !== result.path) fail("page.path", "invalid managed route");
|
|
189
|
+
for (const key of ["fullLogoUrl", "squareLogoUrl"]) if (result.brand[key] && !isSafeFunnelPublicUrl(result.brand[key])) fail(`page.brand.${key}`, "unsafe public URL");
|
|
190
|
+
checkFonts(result.brand, "page.brand");
|
|
191
|
+
checkBody(result.content.body, "page.content.body");
|
|
192
|
+
if (result.content.offer && !isSafeFunnelPublicUrl(result.content.offer.href)) fail("page.content.offer.href", "unsafe public URL");
|
|
193
|
+
return result;
|
|
194
|
+
}
|
|
195
|
+
var FUNNEL_CREATE_JSON_SCHEMA = object({ idempotencyKey: string(200), definition: draftDefinitionShape });
|
|
196
|
+
var FUNNEL_UPDATE_JSON_SCHEMA = object({ expectedRevision: integer(1), idempotencyKey: string(200), definition: draftDefinitionShape });
|
|
197
|
+
var FUNNEL_REVISION_JSON_SCHEMA = object({ expectedRevision: integer(1) });
|
|
198
|
+
var FUNNEL_RETRY_JSON_SCHEMA = object({ expectedAttempt: integer(0, 100), idempotencyKey: string(200), confirm: literal(true) });
|
|
199
|
+
var FUNNEL_DRAFT_JSON_SCHEMAS = { create: FUNNEL_CREATE_JSON_SCHEMA, update: FUNNEL_UPDATE_JSON_SCHEMA };
|
|
200
|
+
var fingerprint = { type: "string", pattern: "^[a-f0-9]{64}$" };
|
|
201
|
+
var issue = object({ code: { ...string(80), pattern: "^[A-Z][A-Z0-9_]*$" }, path: string(300), message: string(500), fixRef: object({ section: string(80), field: string(80), resourceId: uuid }, ["section"]) }, ["code", "path", "message"]);
|
|
202
|
+
var FUNNEL_READINESS_JSON_SCHEMA = object({ definitionRevision: integer(1), brandFingerprint: fingerprint, resourceFingerprint: fingerprint, ready: { type: "boolean" }, blockers: array(issue, 50), warnings: array(issue, 50), capabilities: object({ managedPage: { type: "boolean" } }) });
|
|
203
|
+
var funnelDetailShape = object({ id: uuid, revision: integer(1), definition: draftDefinitionShape, activeVersionId: nullable(uuid), lifecycle: enumeration("draft", "active", "paused"), health: enumeration("healthy", "waiting", "needs_attention", "unknown"), hasDraftChanges: { type: "boolean" }, readiness: FUNNEL_READINESS_JSON_SCHEMA });
|
|
204
|
+
var FUNNEL_DETAIL_JSON_SCHEMA = funnelDetailShape;
|
|
205
|
+
var FUNNEL_OPERATION_RECEIPT_JSON_SCHEMA = object({
|
|
206
|
+
operationId: uuid,
|
|
207
|
+
projectId: uuid,
|
|
208
|
+
orgId: uuid,
|
|
209
|
+
funnelId: uuid,
|
|
210
|
+
operation: enumeration("create", "update", "launch", "pause", "resume", "retry", "rollback"),
|
|
211
|
+
idempotencyKey: string(200),
|
|
212
|
+
requestDigest: fingerprint,
|
|
213
|
+
versionId: nullable(uuid),
|
|
214
|
+
lifecycle: enumeration("draft", "active", "paused"),
|
|
215
|
+
replayed: { type: "boolean" },
|
|
216
|
+
armedFutureEntrantsOnly: literal(true),
|
|
217
|
+
enrolledExisting: literal(0),
|
|
218
|
+
messagesSent: literal(0),
|
|
219
|
+
pagePublication: enumeration("not_requested", "published", "revalidation_pending"),
|
|
220
|
+
health: enumeration("healthy", "waiting", "needs_attention", "unknown"),
|
|
221
|
+
revision: integer(1),
|
|
222
|
+
commandState: literal("committed"),
|
|
223
|
+
funnel: nullable(funnelDetailShape),
|
|
224
|
+
actor: string(200),
|
|
225
|
+
armedAt: nullable(isoDate),
|
|
226
|
+
effectScope: enumeration("configuration_only", "safe_retry_armed"),
|
|
227
|
+
target: object({ funnelId: nullable(uuid), enrollmentId: nullable(uuid), executionId: nullable(uuid), targetVersionId: nullable(uuid) }),
|
|
228
|
+
ledgerProposalId: uuid
|
|
229
|
+
});
|
|
230
|
+
var provenancePaths = ["displayName", "tagline", "fullLogoUrl", "squareLogoUrl", "scheme", ...PUBLICATION_COLOR_FIELDS.map((key) => `colors.${key}`), "typography.headingFamily", "typography.bodyFamily"];
|
|
231
|
+
var brandSnapshotShape = object({
|
|
232
|
+
page: publicBrand,
|
|
233
|
+
email: publicBrand,
|
|
234
|
+
provenance: object(Object.fromEntries(["page", "email"].flatMap((channel) => provenancePaths.map((key) => [`${channel}.${key}`, enumeration("project", "brand_profile", "site_design", "publication_branding", "platforms.publication", "platforms.email", "funnel_override", "default")]))), []),
|
|
235
|
+
assetRefs: array(object({ id: nullable(uuid), version: nullable(string(128)) }), 32),
|
|
236
|
+
capturedAt: isoDate,
|
|
237
|
+
fingerprint
|
|
238
|
+
});
|
|
239
|
+
var FUNNEL_BRAND_SNAPSHOT_JSON_SCHEMA = brandSnapshotShape;
|
|
240
|
+
var choicePage = (item) => object({ items: array(item, 100), nextCursor: nullable(string(500)) });
|
|
241
|
+
var choiceFields = { id: uuid, label: string(120) };
|
|
242
|
+
var catalogShape = object({
|
|
243
|
+
templates: array(object({ id: enumeration(...FUNNEL_TEMPLATES), label: string(120), defaults: draftDefinitionShape }), 3),
|
|
244
|
+
sites: array(object({ host: site, label: string(200) }), 200),
|
|
245
|
+
brand: nullable(brandSnapshotShape),
|
|
246
|
+
choices: object({
|
|
247
|
+
forms: choicePage(object({ ...choiceFields, slug: string(120), site: nullable(site), formType: enumeration("prospect", "contact", "support", "feedback", "newsletter", "custom"), active: { type: "boolean" }, newsletterListIds: array(uuid, 20), fields: array(object({ slug: fieldSlug, type: string(80), label: string(120), required: { type: "boolean" } }), 100) })),
|
|
248
|
+
lists: choicePage(object({ ...choiceFields, active: { type: "boolean" }, doubleOptIn: { type: "boolean" } })),
|
|
249
|
+
emailTemplates: choicePage(object({ ...choiceFields, subject: string(998, 0), updatedAt: nullable(isoDate) })),
|
|
250
|
+
assets: choicePage(object({ ...choiceFields, label: string(160), mimeType: string(100), sizeBytes: integer(0, 52428800), visibility: literal("public"), publicUrl: string(2048), version: nullable(string(200)) })),
|
|
251
|
+
owners: choicePage(object({ ...choiceFields, active: literal(true) })),
|
|
252
|
+
bookingTypes: choicePage(object({ ...choiceFields, site: nullable(site), active: literal(true), requiresConfirmation: { type: "boolean" } }))
|
|
253
|
+
}, []),
|
|
254
|
+
capabilities: object({ managedPage: { type: "boolean" } })
|
|
255
|
+
});
|
|
256
|
+
var FUNNEL_CATALOG_JSON_SCHEMA = catalogShape;
|
|
257
|
+
var launchEvidenceShape = object({ projectId: uuid, orgId: uuid, funnelId: uuid, previewId: uuid, versionId: uuid, definitionRevision: integer(1), definitionDigest: fingerprint, brandFingerprint: fingerprint, resourceFingerprint: fingerprint, entryDigest: fingerprint, permissionDigest: fingerprint, expiresAt: isoDate });
|
|
258
|
+
var FUNNEL_LAUNCH_EVIDENCE_JSON_SCHEMA = launchEvidenceShape;
|
|
259
|
+
var FUNNEL_ROLLBACK_EVIDENCE_JSON_SCHEMA = object({ orgId: uuid, projectId: uuid, funnelId: uuid, targetVersionId: uuid, definitionRevision: integer(1), definitionDigest: fingerprint, brandFingerprint: fingerprint, resourceFingerprint: fingerprint });
|
|
260
|
+
var FUNNEL_PREVIEW_JSON_SCHEMA = object({
|
|
261
|
+
previewId: uuid,
|
|
262
|
+
versionId: uuid,
|
|
263
|
+
expiresAt: isoDate,
|
|
264
|
+
definitionRevision: integer(1),
|
|
265
|
+
brand: brandSnapshotShape,
|
|
266
|
+
readiness: FUNNEL_READINESS_JSON_SCHEMA,
|
|
267
|
+
page: nullable(publishedShape),
|
|
268
|
+
launchEvidence: launchEvidenceShape,
|
|
269
|
+
emailPreviews: array(object({ stepId: uuid, ready: { type: "boolean" }, subject: nullable(string(998, 0)), contentHtml: nullable(string(2e5, 0)), issues: array(issue, 50) }), 8)
|
|
270
|
+
});
|
|
271
|
+
var summaryShape = object({
|
|
272
|
+
id: uuid,
|
|
273
|
+
name: string(120, 0),
|
|
274
|
+
template: enumeration(...FUNNEL_TEMPLATES),
|
|
275
|
+
site: nullable(site),
|
|
276
|
+
revision: integer(1),
|
|
277
|
+
activeVersionId: nullable(uuid),
|
|
278
|
+
lifecycle: enumeration("draft", "active", "paused"),
|
|
279
|
+
health: enumeration("healthy", "waiting", "needs_attention", "unknown"),
|
|
280
|
+
hasDraftChanges: { type: "boolean" },
|
|
281
|
+
counts: object({ entered: integer(0), waiting: integer(0), running: integer(0), completed: integer(0), exited: integer(0), needsAttention: integer(0) }),
|
|
282
|
+
countsBasis: literal("all_versions_all_time"),
|
|
283
|
+
lastEventAt: nullable(isoDate)
|
|
284
|
+
});
|
|
285
|
+
var FUNNEL_SUMMARY_JSON_SCHEMA = summaryShape;
|
|
286
|
+
var FUNNEL_ENROLLMENT_JSON_SCHEMA = object({
|
|
287
|
+
id: uuid,
|
|
288
|
+
versionId: uuid,
|
|
289
|
+
state: enumeration("waiting", "running", "completed", "exited", "needs_attention"),
|
|
290
|
+
effectiveStatus: enumeration("paused", "waiting", "running", "completed", "exited", "needs_attention"),
|
|
291
|
+
source: object({ submissionId: uuid, acceptedAt: isoDate }),
|
|
292
|
+
subject: object({ kind: enumeration("subscriber", "contact", "submission"), id: uuid, displayLabel: string(200) }),
|
|
293
|
+
enteredAt: isoDate,
|
|
294
|
+
nextRunAt: nullable(isoDate),
|
|
295
|
+
exitCode: nullable(string(80)),
|
|
296
|
+
stepsCompleted: integer(0, 8),
|
|
297
|
+
stepsTotal: integer(0, 8),
|
|
298
|
+
lastReceiptAt: nullable(isoDate)
|
|
299
|
+
});
|
|
300
|
+
var FUNNEL_TIMELINE_JSON_SCHEMA = object({
|
|
301
|
+
items: array(object({ executionId: uuid, stepId: uuid, type: enumeration("wait", "send_email", "add_tag", "create_task"), state: enumeration("pending", "claimed", "queued", "admitted", "succeeded", "skipped", "uncertain", "failed"), dueAt: nullable(isoDate), occurredAt: nullable(isoDate), attempt: integer(0, 100), reasonCode: nullable(string(80)), message: string(500, 0), receipt: nullable(object({ domain: enumeration("campaign_send", "subscriber_tag", "crm_task", "wait"), id: nullable(uuid), state: string(80) })), canRetry: { type: "boolean" } }), 100),
|
|
302
|
+
nextCursor: nullable(string(500)),
|
|
303
|
+
exit: nullable(object({ code: string(80), sourceType: string(80), sourceId: nullable(uuid), occurredAt: isoDate }))
|
|
304
|
+
});
|
|
305
|
+
function freezeSchema(value) {
|
|
306
|
+
if (!value || typeof value !== "object" || Object.isFrozen(value)) return;
|
|
307
|
+
for (const child of Object.values(value)) freezeSchema(child);
|
|
308
|
+
Object.freeze(value);
|
|
309
|
+
}
|
|
310
|
+
for (const schema of [FUNNEL_DEFINITION_JSON_SCHEMA, FUNNEL_DRAFT_DEFINITION_JSON_SCHEMA, PUBLISHED_FUNNEL_PAGE_JSON_SCHEMA, FUNNEL_LAUNCH_JSON_SCHEMA, FUNNEL_LIFECYCLE_JSON_SCHEMA, FUNNEL_ROLLBACK_JSON_SCHEMA, FUNNEL_CREATE_JSON_SCHEMA, FUNNEL_UPDATE_JSON_SCHEMA, FUNNEL_REVISION_JSON_SCHEMA, FUNNEL_RETRY_JSON_SCHEMA, FUNNEL_DRAFT_JSON_SCHEMAS, FUNNEL_READINESS_JSON_SCHEMA, FUNNEL_DETAIL_JSON_SCHEMA, FUNNEL_OPERATION_RECEIPT_JSON_SCHEMA, FUNNEL_BRAND_SNAPSHOT_JSON_SCHEMA, FUNNEL_CATALOG_JSON_SCHEMA, FUNNEL_PREVIEW_JSON_SCHEMA, FUNNEL_SUMMARY_JSON_SCHEMA, FUNNEL_ENROLLMENT_JSON_SCHEMA, FUNNEL_TIMELINE_JSON_SCHEMA]) freezeSchema(schema);
|
|
311
|
+
var FUNNEL_VERSION_JSON_SCHEMA = object({ versionId: uuid, definitionRevision: integer(1), publishedAt: isoDate, brandFingerprint: fingerprint, resourceFingerprint: fingerprint, active: { type: "boolean" } });
|
|
312
|
+
var FUNNEL_VERSION_DETAIL_JSON_SCHEMA = object({ ...FUNNEL_VERSION_JSON_SCHEMA.properties, rollbackEvidence: FUNNEL_ROLLBACK_EVIDENCE_JSON_SCHEMA });
|
|
313
|
+
for (const schema of [FUNNEL_LAUNCH_EVIDENCE_JSON_SCHEMA, FUNNEL_ROLLBACK_EVIDENCE_JSON_SCHEMA, FUNNEL_VERSION_JSON_SCHEMA, FUNNEL_VERSION_DETAIL_JSON_SCHEMA]) freezeSchema(schema);
|
|
314
|
+
function FunnelPageContent({ page: input, conversion, preview = false }) {
|
|
315
|
+
const page = parsePublishedFunnelPage(input);
|
|
316
|
+
const { brand, content } = page;
|
|
317
|
+
const tokens = {
|
|
318
|
+
"--sk-primary": brand.colors.primary,
|
|
319
|
+
"--sk-secondary": brand.colors.secondary,
|
|
320
|
+
"--sk-bg": brand.colors.background,
|
|
321
|
+
"--sk-surface": brand.colors.surface,
|
|
322
|
+
"--sk-text-primary": brand.colors.text,
|
|
323
|
+
"--sk-text-secondary": brand.colors.muted,
|
|
324
|
+
"--sk-border": brand.colors.border,
|
|
325
|
+
"--sk-font": brand.typography.bodyFamily,
|
|
326
|
+
colorScheme: brand.scheme,
|
|
327
|
+
color: "var(--sk-text-primary)",
|
|
328
|
+
background: "var(--sk-bg)",
|
|
329
|
+
fontFamily: "var(--sk-font)",
|
|
330
|
+
overflowWrap: "anywhere"
|
|
331
|
+
};
|
|
332
|
+
return /* @__PURE__ */ jsxs("article", { className: "sk-funnel", style: tokens, "data-sk-private-preview": preview ? "" : void 0, "data-sk-funnel-revision": page.revision, children: [
|
|
333
|
+
preview && /* @__PURE__ */ jsx("meta", { name: "robots", content: "noindex, nofollow" }),
|
|
334
|
+
/* @__PURE__ */ jsx("style", { children: `.sk-funnel{padding:clamp(1rem,5vw,4rem);line-height:1.65}.sk-funnel-inner{max-width:68rem;margin-inline:auto}.sk-funnel-brand{display:flex;align-items:center;gap:1rem;margin-bottom:2rem}.sk-funnel-brand img{max-width:min(16rem,60vw);height:auto;max-height:5rem;object-fit:contain}.sk-funnel-grid{display:grid;grid-template-columns:repeat(auto-fit,minmax(min(100%,24rem),1fr));gap:clamp(1.5rem,5vw,4rem);align-items:start}.sk-funnel h1{font-size:clamp(2rem,5vw,3.5rem);line-height:1.12;margin:0 0 1.5rem}.sk-funnel p,.sk-funnel li{max-width:65ch}.sk-funnel-conversion{padding:clamp(1rem,3vw,2rem);border:1px solid var(--sk-border);border-radius:var(--sk-radius-lg);background:var(--sk-surface)}.sk-funnel a{color:var(--sk-primary);text-decoration:underline}.sk-funnel a:focus-visible{outline:3px solid var(--sk-primary);outline-offset:4px}.sk-funnel-preview{font-weight:600}.sk-funnel ul{padding-inline-start:1.25rem}` }),
|
|
335
|
+
/* @__PURE__ */ jsxs("div", { className: "sk-funnel-inner", children: [
|
|
336
|
+
/* @__PURE__ */ jsxs("header", { className: "sk-funnel-brand", children: [
|
|
337
|
+
brand.fullLogoUrl && /* @__PURE__ */ jsx("img", { src: brand.fullLogoUrl, alt: brand.displayName, width: 256, height: 80, fetchPriority: "high" }),
|
|
338
|
+
/* @__PURE__ */ jsxs("div", { children: [
|
|
339
|
+
!brand.fullLogoUrl && /* @__PURE__ */ jsx("strong", { children: brand.displayName }),
|
|
340
|
+
brand.tagline && /* @__PURE__ */ jsx("p", { children: brand.tagline })
|
|
341
|
+
] })
|
|
342
|
+
] }),
|
|
343
|
+
/* @__PURE__ */ jsxs("div", { className: "sk-funnel-grid", children: [
|
|
344
|
+
/* @__PURE__ */ jsxs("section", { "aria-label": content.headline, children: [
|
|
345
|
+
/* @__PURE__ */ jsx("h1", { style: { fontFamily: brand.typography.headingFamily }, children: content.headline }),
|
|
346
|
+
content.body.map((block, index) => block.type === "paragraph" ? /* @__PURE__ */ jsx("p", { children: block.text }, index) : /* @__PURE__ */ jsx("ul", { children: block.items.map((item, i) => /* @__PURE__ */ jsx("li", { children: item }, i)) }, index)),
|
|
347
|
+
content.offer && (preview ? /* @__PURE__ */ jsx("p", { children: content.offer.label }) : /* @__PURE__ */ jsx("p", { children: /* @__PURE__ */ jsx("a", { href: content.offer.href, rel: "noopener noreferrer", children: content.offer.label }) }))
|
|
348
|
+
] }),
|
|
349
|
+
/* @__PURE__ */ jsx("section", { className: "sk-funnel-conversion", "aria-label": "Response form", children: preview ? /* @__PURE__ */ jsx("p", { className: "sk-funnel-preview", role: "status", children: "Form preview. Submissions are disabled." }) : conversion })
|
|
350
|
+
] })
|
|
351
|
+
] })
|
|
352
|
+
] });
|
|
353
|
+
}
|
|
354
|
+
async function getPublishedFunnelPage(slug2, options) {
|
|
355
|
+
let path2;
|
|
356
|
+
try {
|
|
357
|
+
path2 = managedFunnelPath(slug2);
|
|
358
|
+
} catch (error) {
|
|
359
|
+
if (error instanceof FunnelValidationError) return null;
|
|
360
|
+
throw error;
|
|
361
|
+
}
|
|
362
|
+
const site2 = normalizeSiteHost(options.site);
|
|
363
|
+
if (!site2 || !/^[a-z0-9](?:[a-z0-9.-]*[a-z0-9])?$/.test(site2)) throw new Error("An explicit canonical registered site is required");
|
|
364
|
+
const data = await serverApiFetch(`/api/public/funnels/${encodeURIComponent(slug2)}?site=${encodeURIComponent(site2)}`, {
|
|
365
|
+
apiKey: options.apiKey,
|
|
366
|
+
apiUrl: options.apiUrl,
|
|
367
|
+
revalidate: 0,
|
|
368
|
+
init: { cache: "no-store" },
|
|
369
|
+
logPrefix: "@sonordev/site-kit/landing"
|
|
370
|
+
});
|
|
371
|
+
if (data === null) return null;
|
|
372
|
+
const page = parsePublishedFunnelPage(data);
|
|
373
|
+
if (page.site !== site2 || page.path !== path2) throw new Error("Published funnel page scope mismatch");
|
|
374
|
+
return page;
|
|
375
|
+
}
|
|
376
|
+
function managedFunnelMetadata(page) {
|
|
377
|
+
const safe = parsePublishedFunnelPage(page);
|
|
378
|
+
return landingPageMetadata({ title: safe.content.headline, alternates: { canonical: `https://${safe.site}${safe.path}` } });
|
|
379
|
+
}
|
|
380
|
+
async function ManagedFunnelPage({ page: input, preview = false, configOptions }) {
|
|
381
|
+
const page = parsePublishedFunnelPage(input);
|
|
382
|
+
if (preview) return /* @__PURE__ */ jsx(FunnelPageContent, { page, preview: true });
|
|
383
|
+
const form = await ServerForm({ formId: page.conversion.formSlug, defer: false, enter: "none", configOptions });
|
|
384
|
+
return /* @__PURE__ */ jsxs(Fragment, { children: [
|
|
385
|
+
/* @__PURE__ */ jsx(LandingPage, { campaign: page.tracking.campaignSlug, robotsMeta: false }),
|
|
386
|
+
/* @__PURE__ */ jsx(FunnelPageContent, { page, conversion: form })
|
|
387
|
+
] });
|
|
388
|
+
}
|
|
389
|
+
|
|
390
|
+
export { FunnelPageContent, ManagedFunnelPage, getPublishedFunnelPage, managedFunnelMetadata };
|