@brandlab-digital/site-next 2.1.0 → 3.0.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/dist/analytics.d.ts +111 -52
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +281 -153
- package/dist/analytics.js.map +1 -1
- package/dist/blog.d.ts +4 -2
- package/dist/blog.d.ts.map +1 -1
- package/dist/blog.js +7 -7
- package/dist/blog.js.map +1 -1
- package/dist/contact/client-entry.d.ts +2 -0
- package/dist/contact/client-entry.d.ts.map +1 -1
- package/dist/contact/client-entry.js +1 -0
- package/dist/contact/client-entry.js.map +1 -1
- package/dist/contact/client.d.ts +12 -22
- package/dist/contact/client.d.ts.map +1 -1
- package/dist/contact/client.js +28 -21
- package/dist/contact/client.js.map +1 -1
- package/dist/contact/form-client.d.ts +148 -0
- package/dist/contact/form-client.d.ts.map +1 -0
- package/dist/contact/form-client.js +234 -0
- package/dist/contact/form-client.js.map +1 -0
- package/dist/contact/index.d.ts +1 -1
- package/dist/contact/index.d.ts.map +1 -1
- package/dist/contact/index.js +1 -1
- package/dist/contact/index.js.map +1 -1
- package/dist/contact/route-handler.d.ts +32 -0
- package/dist/contact/route-handler.d.ts.map +1 -0
- package/dist/contact/route-handler.js +44 -0
- package/dist/contact/route-handler.js.map +1 -0
- package/dist/contact/server-entry.d.ts +1 -0
- package/dist/contact/server-entry.d.ts.map +1 -1
- package/dist/contact/server-entry.js +1 -0
- package/dist/contact/server-entry.js.map +1 -1
- package/dist/contact/server.d.ts +5 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +13 -7
- package/dist/contact/server.js.map +1 -1
- package/dist/contact/shared.d.ts +4 -0
- package/dist/contact/shared.d.ts.map +1 -1
- package/dist/contact/shared.js.map +1 -1
- package/dist/contact/testing.d.ts +29 -0
- package/dist/contact/testing.d.ts.map +1 -1
- package/dist/contact/testing.js +27 -0
- package/dist/contact/testing.js.map +1 -1
- package/dist/google-tag-plan.d.ts +1 -4
- package/dist/google-tag-plan.d.ts.map +1 -1
- package/dist/google-tag-plan.js +1 -14
- package/dist/google-tag-plan.js.map +1 -1
- package/dist/google-tag.d.ts +5 -4
- package/dist/google-tag.d.ts.map +1 -1
- package/dist/google-tag.js +5 -4
- package/dist/google-tag.js.map +1 -1
- package/dist/headers.d.ts +21 -28
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +62 -51
- package/dist/headers.js.map +1 -1
- package/dist/instrumentation-client.d.ts +21 -1
- package/dist/instrumentation-client.d.ts.map +1 -1
- package/dist/instrumentation-client.js +62 -7
- package/dist/instrumentation-client.js.map +1 -1
- package/dist/lead-registry.d.ts +34 -0
- package/dist/lead-registry.d.ts.map +1 -0
- package/dist/lead-registry.js +30 -0
- package/dist/lead-registry.js.map +1 -0
- package/dist/lead-reporting.d.ts +37 -0
- package/dist/lead-reporting.d.ts.map +1 -0
- package/dist/lead-reporting.js +74 -0
- package/dist/lead-reporting.js.map +1 -0
- package/dist/metadata.d.ts +10 -11
- package/dist/metadata.d.ts.map +1 -1
- package/dist/metadata.js +17 -19
- package/dist/metadata.js.map +1 -1
- package/dist/next-config.d.ts +102 -0
- package/dist/next-config.d.ts.map +1 -0
- package/dist/next-config.js +140 -0
- package/dist/next-config.js.map +1 -0
- package/dist/robots.d.ts +14 -6
- package/dist/robots.d.ts.map +1 -1
- package/dist/robots.js +26 -17
- package/dist/robots.js.map +1 -1
- package/dist/sitemaps.d.ts +34 -0
- package/dist/sitemaps.d.ts.map +1 -1
- package/dist/sitemaps.js +66 -1
- package/dist/sitemaps.js.map +1 -1
- package/dist/testing/server-only.d.ts +8 -0
- package/dist/testing/server-only.d.ts.map +1 -0
- package/dist/testing/server-only.js +8 -0
- package/dist/testing/server-only.js.map +1 -0
- package/dist/ui-client.d.ts +1 -12
- package/dist/ui-client.d.ts.map +1 -1
- package/dist/ui-client.js +0 -17
- package/dist/ui-client.js.map +1 -1
- package/dist/ui.d.ts +22 -2
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +67 -6
- package/dist/ui.js.map +1 -1
- package/package.json +16 -3
package/dist/analytics.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n defineAnalyticsContract,\n normalizeEnhancedConversionEmail,\n normalizeEnhancedConversionPhone,\n sendBrandlabAnalyticsEvent,\n sendContactFormConversion,\n type BrandlabAnalyticsContract,\n type ContactFormConversionResult,\n type GtagTransport,\n} from '@brandlab-digital/site-core/analytics'\nimport type { ContactActionResult } from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport type { BrandlabContactDefinition } from './contact/shared.js'\n\nexport interface BrandlabBrowserAnalyticsConfig {\n enabled: boolean\n webVitalsEnabled?: boolean\n leadDiagnosticsEnabled?: boolean\n enhancedConversionsEnabled?: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n}\n\n/**\n * Public analytics values that a client bundle must bind through direct,\n * statically analyzable `process.env.NEXT_PUBLIC_*` property access.\n */\nexport interface BrandlabBrowserAnalyticsPublicValues {\n measurementId: string | null | undefined\n googleAdsConversionId: string | null | undefined\n googleAdsConversionLabel: string | null | undefined\n}\n\nexport interface SafeContactAnalyticsParams {\n page_template?: string\n service_slug?: string\n location_slug?: string\n}\n\nexport interface SafeContactAdsParams {\n currency?: string\n value?: number\n}\n\nexport const PHONE_CALL_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'cta',\n 'fab',\n 'contact',\n 'location',\n 'page',\n] as const\n\nexport type PhoneCallPlacement = (typeof PHONE_CALL_PLACEMENTS)[number]\n\nexport function resolveBrowserAnalyticsConfig(\n contract: BrandlabAnalyticsContract,\n publicValues: BrandlabBrowserAnalyticsPublicValues,\n options: { enabled: boolean; gtag?: GtagTransport },\n): BrandlabBrowserAnalyticsConfig {\n defineAnalyticsContract(contract)\n return {\n enabled: options.enabled,\n webVitalsEnabled: contract.webVitals,\n leadDiagnosticsEnabled: contract.leadDiagnostics?.enabled === true,\n enhancedConversionsEnabled:\n contract.googleAds?.enhancedConversions?.mode === 'consent-required',\n measurementId: publicValues.measurementId,\n googleAdsConversionId: contract.googleAds\n ? publicValues.googleAdsConversionId\n : undefined,\n googleAdsConversionLabel: contract.googleAds\n ? publicValues.googleAdsConversionLabel\n : undefined,\n gtag: options.gtag,\n }\n}\n\nexport type BrandlabWebVitalName = 'CLS' | 'FCP' | 'INP' | 'LCP' | 'TTFB'\nexport type BrandlabWebVitalRating = 'good' | 'needs-improvement' | 'poor'\n\nexport interface BrandlabWebVitalMetric {\n name: BrandlabWebVitalName\n value: number\n delta: number\n rating: BrandlabWebVitalRating\n navigationType?: string\n}\n\nconst WEB_VITAL_NAMES = new Set<BrandlabWebVitalName>(['CLS', 'FCP', 'INP', 'LCP', 'TTFB'])\nconst WEB_VITAL_RATINGS = new Set<BrandlabWebVitalRating>([\n 'good',\n 'needs-improvement',\n 'poor',\n])\nconst WEB_VITAL_NAVIGATION_TYPES = new Set([\n 'navigate',\n 'reload',\n 'back-forward',\n 'back-forward-cache',\n 'prerender',\n 'restore',\n])\n\n/** Privacy-safe callback for Next's useReportWebVitals hook. */\nexport function reportBrandlabWebVital(\n metric: BrandlabWebVitalMetric,\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n if (\n !WEB_VITAL_NAMES.has(metric.name) ||\n !WEB_VITAL_RATINGS.has(metric.rating) ||\n !Number.isFinite(metric.value) ||\n metric.value < 0 ||\n !Number.isFinite(metric.delta)\n ) {\n return false\n }\n const navigationType = WEB_VITAL_NAVIGATION_TYPES.has(metric.navigationType ?? '')\n ? metric.navigationType\n : undefined\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.webVitalsEnabled !== false,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'web_vital',\n params: {\n metric_name: metric.name,\n metric_value: metric.value,\n metric_delta: metric.delta,\n metric_rating: metric.rating,\n ...(navigationType ? { navigation_type: navigationType } : {}),\n },\n })\n}\n\nexport function createBrandlabWebVitalsReporter(\n config: Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'webVitalsEnabled' | 'measurementId' | 'gtag'\n >,\n) {\n return (metric: BrandlabWebVitalMetric) => reportBrandlabWebVital(metric, config)\n}\n\nexport function getBrowserGtag(win: Window = window): GtagTransport | undefined {\n const candidate = (win as Window & { gtag?: GtagTransport }).gtag\n return typeof candidate === 'function' ? candidate : undefined\n}\n\nfunction safePagePath(value: string) {\n const path = value.trim().split(/[?#]/, 1)[0]\n if (!path || path.length > 500) return '/'\n try {\n return normalizeBrandlabRoutePath(path)\n } catch {\n return '/'\n }\n}\n\nfunction safeSlug(value: string | undefined) {\n const normalized = value?.trim().toLowerCase()\n return normalized && /^[a-z0-9]+(?:[-_][a-z0-9]+)*$/.test(normalized) && normalized.length <= 80\n ? normalized\n : undefined\n}\n\nfunction sanitizeContactParams(params: SafeContactAnalyticsParams | undefined) {\n return {\n ...(safeSlug(params?.page_template)\n ? { page_template: safeSlug(params?.page_template) }\n : {}),\n ...(safeSlug(params?.service_slug)\n ? { service_slug: safeSlug(params?.service_slug) }\n : {}),\n ...(safeSlug(params?.location_slug)\n ? { location_slug: safeSlug(params?.location_slug) }\n : {}),\n }\n}\n\nfunction sanitizeAdsParams(params: SafeContactAdsParams | undefined) {\n return {\n ...(params?.currency && /^[A-Z]{3}$/.test(params.currency)\n ? { currency: params.currency }\n : {}),\n ...(typeof params?.value === 'number' && Number.isFinite(params.value) && params.value >= 0\n ? { value: params.value }\n : {}),\n }\n}\n\nexport function isTrackableContactActionResult(\n result: ContactActionResult,\n): result is Extract<ContactActionResult, { ok: true; accepted: true }> {\n return result.ok && result.accepted && result.trackConversion\n}\n\nexport function trackDeliveredContact(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n })\n}\n\nfunction explicitRoleValue(\n definition: BrandlabContactDefinition,\n formData: FormData,\n role: 'email' | 'phone',\n) {\n const field = definition.fields.find((candidate) => candidate.role === role)\n if (!field) return undefined\n const value = formData.get(field.name)\n return typeof value === 'string' ? value : undefined\n}\n\n/**\n * Sends Enhanced Conversions only after provider acceptance. Email and phone may\n * only be sourced from fields with explicit declarative roles; they never enter\n * the GA4 parameter object.\n */\nexport function trackDeliveredContactWithEnhancedConversions(\n result: ContactActionResult,\n config: BrandlabBrowserAnalyticsConfig,\n options: {\n pagePath: string\n definition: BrandlabContactDefinition\n formData: FormData\n /** Live Consent Mode decision for ad_user_data; absence is deny. */\n adUserDataConsent: boolean\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n): ContactFormConversionResult {\n if (!isTrackableContactActionResult(result)) {\n return { ga4Sent: false, enhancedConversionSent: false, adsConversionSent: false }\n }\n const email = normalizeEnhancedConversionEmail(\n explicitRoleValue(options.definition, options.formData, 'email'),\n )\n const phone = normalizeEnhancedConversionPhone(\n explicitRoleValue(options.definition, options.formData, 'phone'),\n )\n return sendContactFormConversion({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n pagePath: safePagePath(options.pagePath),\n submissionId: result.confirmationId,\n params: sanitizeContactParams(options.params),\n adsParams: sanitizeAdsParams(options.adsParams),\n enhancedConversionsEnabled: config.enhancedConversionsEnabled === true,\n adUserDataConsent: options.adUserDataConsent === true,\n ...((email || phone) ? { enhancedConversion: { email, phone } } : {}),\n })\n}\n\nexport function trackPhoneLinkClick(\n input: { pagePath: string; placement: PhoneCallPlacement },\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>,\n) {\n if (!PHONE_CALL_PLACEMENTS.includes(input.placement)) return false\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'phone_link_click',\n params: {\n event_category: 'contact_interaction',\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n },\n })\n}\n\nexport const LEAD_FORM_ERROR_STAGES = [\n 'validation',\n 'submission',\n 'delivery',\n 'unknown',\n] as const\nexport type LeadFormErrorStage = (typeof LEAD_FORM_ERROR_STAGES)[number]\n\nexport const LEAD_CTA_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'section',\n 'navigation',\n 'floating',\n 'page',\n] as const\nexport type LeadCtaPlacement = (typeof LEAD_CTA_PLACEMENTS)[number]\n\ntype LeadDiagnosticConfig = Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'leadDiagnosticsEnabled' | 'measurementId' | 'gtag'\n>\n\nexport function trackLeadFormStart(\n input: { pagePath: string; formId: string; pageTemplate?: string },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (!formId) return false\n return sendLeadDiagnosticEvent('lead_form_start', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n ...(safeSlug(input.pageTemplate) ? { page_template: safeSlug(input.pageTemplate) } : {}),\n }, config)\n}\n\nexport function trackLeadFormError(\n input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (\n !formId ||\n !LEAD_FORM_ERROR_STAGES.includes(input.stage) ||\n !Number.isInteger(input.errorCount) ||\n input.errorCount < 1 ||\n input.errorCount > 50\n ) {\n return false\n }\n return sendLeadDiagnosticEvent('lead_form_error', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n error_stage: input.stage,\n error_count: input.errorCount,\n }, config)\n}\n\nexport function trackLeadCtaClick(\n input: {\n pagePath: string\n ctaId: string\n placement: LeadCtaPlacement\n },\n config: LeadDiagnosticConfig,\n) {\n const ctaId = safeSlug(input.ctaId)\n if (!ctaId || !LEAD_CTA_PLACEMENTS.includes(input.placement)) return false\n return sendLeadDiagnosticEvent('lead_cta_click', {\n cta_id: ctaId,\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n }, config)\n}\n\nfunction sendLeadDiagnosticEvent(\n eventName: 'lead_form_start' | 'lead_form_error' | 'lead_cta_click',\n params: Record<string, unknown>,\n config: LeadDiagnosticConfig,\n) {\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.leadDiagnosticsEnabled === true,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params,\n })\n}\n\nfunction safeAdditionalEventValue(\n value: unknown,\n policy: NonNullable<BrandlabAnalyticsContract['additionalEvents']>[number]['parameters'][number],\n) {\n if (policy.type === 'boolean') return typeof value === 'boolean' ? value : undefined\n if (policy.type === 'count') {\n const minimum = policy.minimum ?? 0\n const maximum = policy.maximum ?? 100_000\n return typeof value === 'number' && Number.isInteger(value) && value >= minimum && value <= maximum\n ? value\n : undefined\n }\n if (typeof value !== 'string') return undefined\n const normalized = value.trim()\n if (policy.type === 'enum') return policy.values.includes(normalized) ? normalized : undefined\n if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized) || normalized.length > 80) {\n return undefined\n }\n const digits = normalized.replace(/\\D/g, '')\n return digits.length >= 4 || /^[a-f0-9]{24,}$/.test(normalized)\n ? undefined\n : normalized\n}\n\nexport function trackBrandlabBrowserEvent(\n eventName: string,\n params: Record<string, unknown>,\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'> & {\n contract: BrandlabAnalyticsContract\n },\n) {\n defineAnalyticsContract(config.contract)\n const event = config.contract.additionalEvents?.find(\n (candidate) => candidate.name === eventName,\n )\n if (!event) return false\n const safeParams = Object.fromEntries(\n Object.entries(params).flatMap(([key, value]) => {\n const policy = event.parameters.find((candidate) => candidate.key === key)\n if (!policy) return []\n const safeValue = safeAdditionalEventValue(value, policy)\n return safeValue === undefined ? [] : [[key, safeValue]]\n }),\n )\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params: safeParams,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"analytics.js","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineAnalyticsContract,\n sendBrandlabAnalyticsEvent,\n type BrandlabAnalyticsContract,\n type GtagTransport,\n} from '@brandlab-digital/site-core/analytics'\nimport { resolveBrandlabDeployment } from '@brandlab-digital/site-core/site'\nimport type { BrandlabGoogleTagConfig } from './google-tag-plan.js'\nimport {\n getBrowserGtag,\n registerLeadBinding,\n safePagePath,\n safeSlug,\n type LeadAdsParams,\n} from './lead-registry.js'\n\nexport { getBrowserGtag }\n\nexport interface BrandlabBrowserAnalyticsConfig {\n enabled: boolean\n leadDiagnosticsEnabled?: boolean\n enhancedConversionsEnabled?: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n}\n\n/**\n * Public analytics values that a client bundle must bind through direct,\n * statically analysable `process.env.NEXT_PUBLIC_*` property access. Ads keys\n * are bound only when the contract declares Google Ads (and website calls).\n */\nexport interface BrandlabBrowserAnalyticsPublicValues {\n /** `process.env.NEXT_PUBLIC_VERCEL_ENV`, inlined by defineBrandlabNextConfig. */\n deploymentEnvironment: string | null | undefined\n measurementId: string | null | undefined\n googleAdsConversionId?: string | null | undefined\n googleAdsConversionLabel?: string | null | undefined\n googleAdsWebsiteCallConversionLabel?: string | null | undefined\n}\n\nexport interface SafeContactAnalyticsParams {\n page_template?: string\n service_slug?: string\n location_slug?: string\n}\n\nexport const PHONE_CALL_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'cta',\n 'fab',\n 'contact',\n 'location',\n 'page',\n] as const\n\nexport type PhoneCallPlacement = (typeof PHONE_CALL_PLACEMENTS)[number]\n\nexport function trackPhoneLinkClick(\n input: { pagePath: string; placement: PhoneCallPlacement },\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'>,\n) {\n if (!PHONE_CALL_PLACEMENTS.includes(input.placement)) return false\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName: 'phone_link_click',\n params: {\n event_category: 'contact_interaction',\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n },\n })\n}\n\nexport const LEAD_FORM_ERROR_STAGES = [\n 'validation',\n 'submission',\n 'delivery',\n 'unknown',\n] as const\nexport type LeadFormErrorStage = (typeof LEAD_FORM_ERROR_STAGES)[number]\n\nexport const LEAD_CTA_PLACEMENTS = [\n 'header',\n 'footer',\n 'hero',\n 'section',\n 'navigation',\n 'floating',\n 'page',\n] as const\nexport type LeadCtaPlacement = (typeof LEAD_CTA_PLACEMENTS)[number]\n\ntype LeadDiagnosticConfig = Pick<\n BrandlabBrowserAnalyticsConfig,\n 'enabled' | 'leadDiagnosticsEnabled' | 'measurementId' | 'gtag'\n>\n\nexport function trackLeadFormStart(\n input: { pagePath: string; formId: string; pageTemplate?: string },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (!formId) return false\n return sendLeadDiagnosticEvent('lead_form_start', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n ...(safeSlug(input.pageTemplate) ? { page_template: safeSlug(input.pageTemplate) } : {}),\n }, config)\n}\n\nexport function trackLeadFormError(\n input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n },\n config: LeadDiagnosticConfig,\n) {\n const formId = safeSlug(input.formId)\n if (\n !formId ||\n !LEAD_FORM_ERROR_STAGES.includes(input.stage) ||\n !Number.isInteger(input.errorCount) ||\n input.errorCount < 1 ||\n input.errorCount > 50\n ) {\n return false\n }\n return sendLeadDiagnosticEvent('lead_form_error', {\n form_id: formId,\n page_path: safePagePath(input.pagePath),\n error_stage: input.stage,\n error_count: input.errorCount,\n }, config)\n}\n\nexport function trackLeadCtaClick(\n input: {\n pagePath: string\n ctaId: string\n placement: LeadCtaPlacement\n },\n config: LeadDiagnosticConfig,\n) {\n const ctaId = safeSlug(input.ctaId)\n if (!ctaId || !LEAD_CTA_PLACEMENTS.includes(input.placement)) return false\n return sendLeadDiagnosticEvent('lead_cta_click', {\n cta_id: ctaId,\n page_path: safePagePath(input.pagePath),\n placement: input.placement,\n }, config)\n}\n\nfunction sendLeadDiagnosticEvent(\n eventName: 'lead_form_start' | 'lead_form_error' | 'lead_cta_click',\n params: Record<string, unknown>,\n config: LeadDiagnosticConfig,\n) {\n return sendBrandlabAnalyticsEvent({\n enabled: config.enabled && config.leadDiagnosticsEnabled === true,\n measurementId: config.measurementId,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params,\n })\n}\n\nfunction safeAdditionalEventValue(\n value: unknown,\n policy: NonNullable<BrandlabAnalyticsContract['additionalEvents']>[number]['parameters'][number],\n) {\n if (policy.type === 'boolean') return typeof value === 'boolean' ? value : undefined\n if (policy.type === 'count') {\n const minimum = policy.minimum ?? 0\n const maximum = policy.maximum ?? 100_000\n return typeof value === 'number' && Number.isInteger(value) && value >= minimum && value <= maximum\n ? value\n : undefined\n }\n if (typeof value !== 'string') return undefined\n const normalized = value.trim()\n if (policy.type === 'enum') return policy.values.includes(normalized) ? normalized : undefined\n if (!/^[a-z][a-z0-9]*(?:[-_][a-z0-9]+)*$/.test(normalized) || normalized.length > 80) {\n return undefined\n }\n const digits = normalized.replace(/\\D/g, '')\n return digits.length >= 4 || /^[a-f0-9]{24,}$/.test(normalized)\n ? undefined\n : normalized\n}\n\nexport function trackBrandlabBrowserEvent(\n eventName: string,\n params: Record<string, unknown>,\n config: Pick<BrandlabBrowserAnalyticsConfig, 'enabled' | 'measurementId' | 'gtag'> & {\n contract: BrandlabAnalyticsContract\n },\n) {\n defineAnalyticsContract(config.contract)\n const event = config.contract.additionalEvents?.find(\n (candidate) => candidate.name === eventName,\n )\n if (!event) return false\n const safeParams = Object.fromEntries(\n Object.entries(params).flatMap(([key, value]) => {\n const policy = event.parameters.find((candidate) => candidate.key === key)\n if (!policy) return []\n const safeValue = safeAdditionalEventValue(value, policy)\n return safeValue === undefined ? [] : [[key, safeValue]]\n }),\n )\n return sendBrandlabAnalyticsEvent({\n ...config,\n gtag: config.gtag ?? getBrowserGtag(),\n eventName,\n params: safeParams,\n })\n}\n\n// ---------------------------------------------------------------------------\n// Project binding: src/config/analytics.ts\n// ---------------------------------------------------------------------------\n\ntype PageDimension = 'service_slug' | 'location_slug'\n\nconst PAGE_DIMENSIONS: readonly PageDimension[] = ['service_slug', 'location_slug']\nconst MAX_PAGE_TEMPLATE_ROWS = 5_000\n\n/**\n * One row of the page-template table. Rows are tried in order against the\n * page path's segments (query, hash, empty and trailing segments ignored) and\n * the first match wins; no match reports no page dimensions.\n *\n * `path` segments: a literal matches itself; `:name` matches any one segment,\n * and `:service_slug` / `:location_slug` also report it (lowercased, or\n * omitted when it is not a safe slug, without failing the row); `**` matches\n * zero or more segments and may appear once, anywhere.\n */\nexport interface BrandlabAnalyticsPageTemplate {\n path: string\n template: string\n /** Constant dimensions for every page the row matches. */\n params?: Readonly<Partial<Record<PageDimension, string>>>\n /**\n * Constraints on `:name` segments, tested against the segment exactly as it\n * appears in the path: a list of allowed values or a regular expression. A\n * segment that fails its constraint skips the row.\n */\n values?: Readonly<Record<string, readonly string[] | RegExp>>\n}\n\ntype PageTemplateSegment =\n | { kind: 'literal'; value: string }\n | {\n kind: 'parameter'\n name: string\n dimension?: PageDimension\n allowed?: ReadonlySet<string> | RegExp\n }\n\ninterface CompiledPageTemplate {\n head: readonly PageTemplateSegment[]\n /** Segments after `**`; undefined when the row has no `**`. */\n tail?: readonly PageTemplateSegment[]\n template: string\n params: SafeContactAnalyticsParams\n}\n\nfunction compilePageTemplate(row: BrandlabAnalyticsPageTemplate, index: number): CompiledPageTemplate {\n const field = `pageTemplates[${index}]`\n if (!row || typeof row !== 'object') throw new Error(`${field} must be a page-template row.`)\n const unsupported = Object.keys(row).filter((key) => !['path', 'template', 'params', 'values'].includes(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.`)\n }\n if (typeof row.path !== 'string' || !row.path.startsWith('/') || row.path.includes('//')) {\n throw new Error(`${field}.path must be a root-relative pattern.`)\n }\n const template = safeSlug(row.template)\n if (!template || template !== row.template) {\n throw new Error(`${field}.template must be a lowercase slug.`)\n }\n const parts = row.path === '/' ? [] : row.path.replace(/\\/$/, '').slice(1).split('/')\n if (parts.filter((part) => part === '**').length > 1) {\n throw new Error(`${field}.path may use ** only once.`)\n }\n const names = new Set<string>()\n const segments = parts.map((part): PageTemplateSegment | '**' => {\n if (part === '**') return '**'\n if (part.startsWith(':')) {\n const name = part.slice(1)\n if (!/^[a-z_][a-z0-9_]*$/.test(name)) throw new Error(`${field}.path has an invalid parameter \"${part}\".`)\n if (names.has(name)) throw new Error(`${field}.path repeats ${part}.`)\n names.add(name)\n return PAGE_DIMENSIONS.includes(name as PageDimension)\n ? { kind: 'parameter', name, dimension: name as PageDimension }\n : { kind: 'parameter', name }\n }\n if (!/^[A-Za-z0-9._~-]+$/.test(part)) throw new Error(`${field}.path has an invalid segment \"${part}\".`)\n return { kind: 'literal', value: part }\n })\n const params: SafeContactAnalyticsParams = {}\n for (const [key, value] of Object.entries(row.params ?? {})) {\n const dimension = key as PageDimension\n if (!PAGE_DIMENSIONS.includes(dimension) || names.has(dimension)) {\n throw new Error(`${field}.params.${key} is not an uncaptured page dimension.`)\n }\n if (typeof value !== 'string' || safeSlug(value) !== value) {\n throw new Error(`${field}.params.${key} must be a lowercase slug.`)\n }\n params[dimension] = value\n }\n for (const [name, allowed] of Object.entries(row.values ?? {})) {\n if (!names.has(name)) throw new Error(`${field}.values.${name} needs :${name} in the path.`)\n let constraint: ReadonlySet<string> | RegExp\n if (allowed instanceof RegExp) {\n if (allowed.global || allowed.sticky) {\n throw new Error(`${field}.values.${name} must be a regular expression without the g or y flag.`)\n }\n constraint = allowed\n } else if (Array.isArray(allowed) && allowed.every((value) => typeof value === 'string' && value.length > 0)) {\n constraint = new Set(allowed)\n } else {\n throw new Error(`${field}.values.${name} must list segment values or be a regular expression.`)\n }\n for (const segment of segments) {\n if (segment !== '**' && segment.kind === 'parameter' && segment.name === name) segment.allowed = constraint\n }\n }\n const rest = segments.indexOf('**')\n const compiled = segments.filter((segment): segment is PageTemplateSegment => segment !== '**')\n return {\n head: rest === -1 ? compiled : compiled.slice(0, rest),\n ...(rest === -1 ? {} : { tail: compiled.slice(rest) }),\n template,\n params,\n }\n}\n\nfunction pathSegments(pagePath: string) {\n return String(pagePath).split(/[?#]/, 1)[0]!.split('/').filter(Boolean)\n}\n\nfunction matchSegment(\n segment: PageTemplateSegment,\n part: string,\n params: SafeContactAnalyticsParams,\n) {\n if (segment.kind === 'literal') return segment.value === part\n const { allowed } = segment\n if (allowed && !(allowed instanceof RegExp ? allowed.test(part) : allowed.has(part))) return false\n if (segment.dimension) {\n const value = safeSlug(part)\n if (value) params[segment.dimension] = value\n }\n return true\n}\n\nfunction matchPageTemplate(row: CompiledPageTemplate, parts: readonly string[]) {\n const fixed = row.head.length + (row.tail?.length ?? 0)\n if (row.tail ? parts.length < fixed : parts.length !== fixed) return undefined\n const params: SafeContactAnalyticsParams = { page_template: row.template, ...row.params }\n for (let index = 0; index < row.head.length; index += 1) {\n if (!matchSegment(row.head[index]!, parts[index]!, params)) return undefined\n }\n const offset = parts.length - (row.tail?.length ?? 0)\n for (let index = 0; index < (row.tail?.length ?? 0); index += 1) {\n if (!matchSegment(row.tail![index]!, parts[offset + index]!, params)) return undefined\n }\n return params\n}\n\n/** What a declared lead value sees for one accepted enquiry. */\nexport interface BrandlabLeadContext {\n /** The form's page path, as useBrandlabContactForm received it. */\n readonly pagePath: string\n /** The page's contact_form dimensions from the page-template table. */\n readonly pageParams: SafeContactAnalyticsParams\n /** The accepted enquiry's fields; they are never sent to analytics. */\n readonly formData: FormData\n}\n\nexport interface BrandlabGoogleAdsLeadConversion {\n /**\n * Conversion value: a number, or a function evaluated for each accepted\n * enquiry. A function that throws or returns anything but a finite,\n * non-negative number sends the conversion without a value.\n */\n value?: number | ((lead: BrandlabLeadContext) => number | undefined)\n /** ISO 4217 currency code, for example `AUD`. */\n currency?: string\n}\n\n/**\n * How the site reports an accepted enquiry, declared once. Every accepted\n * enquiry sends one GA4 `contact_form` (page dimensions from the page-template\n * table) and, when the contract declares Google Ads, one form conversion with\n * `send_to` and `transaction_id` plus the value and currency declared here.\n */\nexport interface BrandlabLeadReporting {\n googleAdsConversion?: BrandlabGoogleAdsLeadConversion\n}\n\nfunction compileLeadReporting(\n contract: BrandlabAnalyticsContract,\n leads: BrandlabLeadReporting | undefined,\n): (lead: BrandlabLeadContext) => LeadAdsParams {\n if (leads === undefined) return () => ({})\n if (!leads || typeof leads !== 'object' || Array.isArray(leads)) {\n throw new Error('leads must be a lead-reporting declaration.')\n }\n const unsupported = Object.keys(leads).filter((key) => key !== 'googleAdsConversion')\n if (unsupported.length > 0) throw new Error(`leads contains unsupported keys: ${unsupported.join(', ')}.`)\n const conversion = leads.googleAdsConversion\n if (conversion === undefined) return () => ({})\n if (!conversion || typeof conversion !== 'object' || Array.isArray(conversion)) {\n throw new Error('leads.googleAdsConversion must declare value and/or currency.')\n }\n if (!contract.googleAds) {\n throw new Error('leads.googleAdsConversion needs googleAds in the analytics contract.')\n }\n const unsupportedConversion = Object.keys(conversion).filter((key) => key !== 'value' && key !== 'currency')\n if (unsupportedConversion.length > 0) {\n throw new Error(`leads.googleAdsConversion contains unsupported keys: ${unsupportedConversion.join(', ')}.`)\n }\n const { value, currency } = conversion\n if (currency !== undefined && (typeof currency !== 'string' || !/^[A-Z]{3}$/.test(currency))) {\n throw new Error('leads.googleAdsConversion.currency must be an ISO 4217 code such as AUD.')\n }\n if (\n value !== undefined &&\n typeof value !== 'function' &&\n (typeof value !== 'number' || !Number.isFinite(value) || value < 0)\n ) {\n throw new Error('leads.googleAdsConversion.value must be a non-negative number or a function.')\n }\n return (lead) => {\n let resolved: unknown = value\n if (typeof value === 'function') {\n try {\n resolved = value(lead)\n } catch {\n resolved = undefined\n }\n }\n return {\n ...(currency ? { currency } : {}),\n ...(typeof resolved === 'number' ? { value: resolved } : {}),\n }\n }\n}\n\nexport interface DefineBrandlabAnalyticsOptions {\n contract: BrandlabAnalyticsContract\n publicValues: BrandlabBrowserAnalyticsPublicValues\n /** Classifies page paths for contact_form and lead_form_start dimensions. */\n pageTemplates: readonly BrandlabAnalyticsPageTemplate[]\n /** The Google Ads form-conversion value and currency, if the site sends them. */\n leads?: BrandlabLeadReporting\n}\n\nexport interface BrandlabAnalytics {\n readonly contract: BrandlabAnalyticsContract\n /** True only on the Vercel production deployment. */\n readonly enabled: boolean\n /** Props for the single `<BrandlabGoogleTag {...analytics.googleTag} />` in the root layout. */\n readonly googleTag: BrandlabGoogleTagConfig\n /** Tracking configuration; the page's gtag function is resolved when an event is sent. */\n readonly config: BrandlabBrowserAnalyticsConfig\n /** Privacy-safe page_template, service_slug and location_slug for a path. */\n pageParams(pagePath: string): SafeContactAnalyticsParams\n trackPhoneLinkClick(input: { pagePath: string; placement: PhoneCallPlacement }): boolean\n trackLeadFormStart(input: { pagePath: string; formId: string }): boolean\n trackLeadFormError(input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n }): boolean\n trackLeadCtaClick(input: { pagePath: string; ctaId: string; placement: LeadCtaPlacement }): boolean\n /** Sends an event declared in the contract's additionalEvents, filtered by its parameter policy. */\n trackEvent(eventName: string, params: Record<string, unknown>): boolean\n}\n\nconst PUBLIC_VALUE_KEYS = [\n 'deploymentEnvironment',\n 'measurementId',\n 'googleAdsConversionId',\n 'googleAdsConversionLabel',\n 'googleAdsWebsiteCallConversionLabel',\n] as const\n\nfunction assertPublicValues(\n contract: BrandlabAnalyticsContract,\n publicValues: BrandlabBrowserAnalyticsPublicValues,\n) {\n if (!publicValues || typeof publicValues !== 'object' || Array.isArray(publicValues)) {\n throw new Error('publicValues must bind the NEXT_PUBLIC_* analytics values.')\n }\n const required = new Set<string>(['deploymentEnvironment', 'measurementId'])\n if (contract.googleAds) {\n required.add('googleAdsConversionId')\n required.add('googleAdsConversionLabel')\n if (contract.googleAds.websiteCalls) required.add('googleAdsWebsiteCallConversionLabel')\n }\n for (const key of Object.keys(publicValues)) {\n if (!(PUBLIC_VALUE_KEYS as readonly string[]).includes(key)) {\n throw new Error(`publicValues contains unsupported key \"${key}\".`)\n }\n if (!required.has(key)) {\n throw new Error(`publicValues.${key} is bound but the analytics contract does not declare it.`)\n }\n }\n for (const key of required) {\n if (!Object.hasOwn(publicValues, key)) {\n throw new Error(`publicValues.${key} must be bound with literal process.env property access.`)\n }\n const value = (publicValues as unknown as Record<string, unknown>)[key]\n if (value !== undefined && value !== null && typeof value !== 'string') {\n throw new Error(`publicValues.${key} must be a string or undefined.`)\n }\n }\n const browserEnvKeys = [\n contract.measurementIdEnv,\n contract.googleAds?.conversionIdEnv,\n contract.googleAds?.contactConversionLabelEnv,\n contract.googleAds?.websiteCalls?.conversionLabelEnv,\n ].filter((key): key is string => Boolean(key))\n const privateKey = browserEnvKeys.find((key) => !key.startsWith('NEXT_PUBLIC_'))\n if (privateKey) {\n throw new Error(`${privateKey} is read in the browser and must be a NEXT_PUBLIC_ variable.`)\n }\n}\n\nfunction publicValue(value: string | null | undefined) {\n const trimmed = value?.trim()\n return trimmed || undefined\n}\n\n/**\n * The project's single analytics binding (`src/config/analytics.ts`). It is\n * safe in server and browser code: the root layout renders\n * `analytics.googleTag`, `src/instrumentation-client.ts` installs the phone\n * listener, and `useBrandlabContactForm` reports each accepted enquiry exactly\n * as `pageTemplates` and `leads` declare, plus the lead diagnostics. Analytics\n * runs only on the Vercel production deployment.\n */\nexport function defineBrandlabAnalytics(options: DefineBrandlabAnalyticsOptions): BrandlabAnalytics {\n if (!options || typeof options !== 'object') {\n throw new TypeError('defineBrandlabAnalytics requires contract, publicValues and pageTemplates.')\n }\n const contract = defineAnalyticsContract(options.contract)\n assertPublicValues(contract, options.publicValues)\n if (!Array.isArray(options.pageTemplates) || options.pageTemplates.length > MAX_PAGE_TEMPLATE_ROWS) {\n throw new Error(`pageTemplates must list at most ${MAX_PAGE_TEMPLATE_ROWS} rows.`)\n }\n const pageTemplates = options.pageTemplates.map(compilePageTemplate)\n const leadAdsParams = compileLeadReporting(contract, options.leads)\n const values = options.publicValues\n const enabled =\n resolveBrandlabDeployment({ NEXT_PUBLIC_VERCEL_ENV: publicValue(values.deploymentEnvironment) })\n .environment === 'production'\n const measurementId = publicValue(values.measurementId)\n const googleAdsConversionId = contract.googleAds ? publicValue(values.googleAdsConversionId) : undefined\n const config: BrandlabBrowserAnalyticsConfig = Object.freeze({\n enabled,\n // Privacy-safe lead_form_start / lead_form_error diagnostics are on for every site.\n leadDiagnosticsEnabled: true,\n enhancedConversionsEnabled:\n contract.googleAds?.enhancedConversions?.mode === 'consent-required',\n measurementId,\n googleAdsConversionId,\n googleAdsConversionLabel: contract.googleAds\n ? publicValue(values.googleAdsConversionLabel)\n : undefined,\n })\n const googleTag: BrandlabGoogleTagConfig = Object.freeze({\n enabled,\n measurementId,\n googleAdsConversionId,\n googleAdsWebsiteCallConversionLabel: contract.googleAds?.websiteCalls\n ? publicValue(values.googleAdsWebsiteCallConversionLabel)\n : undefined,\n })\n const pageParams = (pagePath: string): SafeContactAnalyticsParams => {\n const parts = pathSegments(pagePath)\n for (const row of pageTemplates) {\n const params = matchPageTemplate(row, parts)\n if (params) return params\n }\n return {}\n }\n\n const binding: BrandlabAnalytics = Object.freeze({\n contract,\n enabled,\n googleTag,\n config,\n pageParams,\n trackPhoneLinkClick: (input: { pagePath: string; placement: PhoneCallPlacement }) =>\n trackPhoneLinkClick(input, config),\n trackLeadFormStart: (input: { pagePath: string; formId: string }) =>\n trackLeadFormStart({ ...input, pageTemplate: pageParams(input.pagePath).page_template }, config),\n trackLeadFormError: (input: {\n pagePath: string\n formId: string\n stage: LeadFormErrorStage\n errorCount: number\n }) => trackLeadFormError(input, config),\n trackLeadCtaClick: (input: { pagePath: string; ctaId: string; placement: LeadCtaPlacement }) =>\n trackLeadCtaClick(input, config),\n trackEvent: (eventName: string, params: Record<string, unknown>) =>\n trackBrandlabBrowserEvent(eventName, params, { ...config, contract }),\n })\n registerLeadBinding(binding, { config, pageParams, adsParams: leadAdsParams })\n return binding\n}\n"]}
|
package/dist/blog.d.ts
CHANGED
|
@@ -1,11 +1,13 @@
|
|
|
1
1
|
import { type BrandlabBlogAdapter, type BrandlabBlogPost } from '@brandlab-digital/site-core/blog';
|
|
2
2
|
import { type BrandlabRouteCatalog } from '@brandlab-digital/site-core/routes';
|
|
3
|
+
import type { BrandlabSite } from '@brandlab-digital/site-core/site';
|
|
3
4
|
import { type SitemapEntry } from '@brandlab-digital/site-core/sitemaps';
|
|
4
|
-
import { type
|
|
5
|
+
import { type NextCompatibleMetadata } from './metadata.js';
|
|
5
6
|
export interface BrandlabBlogAdapterOptions<Content> {
|
|
6
7
|
adapter: BrandlabBlogAdapter;
|
|
7
8
|
posts: readonly BrandlabBlogPost[];
|
|
8
|
-
metadata
|
|
9
|
+
/** The site identity from defineBrandlabSite; supplies canonical URLs and metadata defaults. */
|
|
10
|
+
site: BrandlabSite;
|
|
9
11
|
publisherId: string;
|
|
10
12
|
resolveContent: (post: BrandlabBlogPost) => Content | Promise<Content>;
|
|
11
13
|
now?: () => Date;
|
package/dist/blog.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../src/blog.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAA;AAEzC,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,oCAAoC,CAAA;AAE3C,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,sCAAsC,CAAA;AACnF,OAAO,EAEL,KAAK,
|
|
1
|
+
{"version":3,"file":"blog.d.ts","sourceRoot":"","sources":["../src/blog.ts"],"names":[],"mappings":"AAAA,OAAO,EAIL,KAAK,mBAAmB,EACxB,KAAK,gBAAgB,EACtB,MAAM,kCAAkC,CAAA;AAEzC,OAAO,EAGL,KAAK,oBAAoB,EAC1B,MAAM,oCAAoC,CAAA;AAE3C,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,kCAAkC,CAAA;AACpE,OAAO,EAAa,KAAK,YAAY,EAAE,MAAM,sCAAsC,CAAA;AACnF,OAAO,EAEL,KAAK,sBAAsB,EAC5B,MAAM,eAAe,CAAA;AAEtB,MAAM,WAAW,0BAA0B,CAAC,OAAO;IACjD,OAAO,EAAE,mBAAmB,CAAA;IAC5B,KAAK,EAAE,SAAS,gBAAgB,EAAE,CAAA;IAClC,gGAAgG;IAChG,IAAI,EAAE,YAAY,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;IACnB,cAAc,EAAE,CAAC,IAAI,EAAE,gBAAgB,KAAK,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,CAAA;IACtE,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,MAAM,EAAE,oBAAoB,CAAA;IAC5B,GAAG,CAAC,EAAE;QACJ,KAAK,EAAE,MAAM,CAAA;QACb,WAAW,EAAE,MAAM,CAAA;QACnB,IAAI,CAAC,EAAE,MAAM,CAAA;KACd,CAAA;CACF;AAwKD,MAAM,MAAM,oCAAoC,CAAC,OAAO,IAAI,IAAI,CAC9D,0BAA0B,CAAC,OAAO,CAAC,EACnC,SAAS,GAAG,QAAQ,CACrB,GAAG;IAAE,MAAM,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAEpC,wBAAgB,8BAA8B,CAAC,OAAO,EACpD,OAAO,EAAE,oCAAoC,CAAC,OAAO,CAAC;;;;;wBAtIhC,MAAM;;;;;;;2BAMH,MAAM,GAAG,sBAAsB,GAAG,SAAS;yBAkB7C,MAAM;yBAuBN,YAAY,EAAE;0BAcb,MAAM;;;;;kBA+CR,MAAM;;;;;;;EA6B7B;AAED,wBAAgB,qCAAqC,CAAC,OAAO,EAC3D,OAAO,EAAE,oCAAoC,CAAC,OAAO,CAAC;;;;;wBA5IhC,MAAM;;;;;;;2BAMH,MAAM,GAAG,sBAAsB,GAAG,SAAS;yBAkB7C,MAAM;yBAuBN,YAAY,EAAE;0BAcb,MAAM;;;;;kBA+CR,MAAM;;;;;;;EAmC7B"}
|
package/dist/blog.js
CHANGED
|
@@ -13,7 +13,7 @@ function createBrandlabBlogAdapter(options) {
|
|
|
13
13
|
}
|
|
14
14
|
const eligiblePosts = options.posts.filter((post) => post.adapter === options.adapter);
|
|
15
15
|
const published = () => getPublishedBlogPosts(eligiblePosts, options.now?.() ?? new Date());
|
|
16
|
-
const routeMetadata = createRouteMetadataBuilder(options.
|
|
16
|
+
const routeMetadata = createRouteMetadataBuilder(options.site, options.routes);
|
|
17
17
|
const validationTime = options.now?.() ?? new Date();
|
|
18
18
|
eligiblePosts.forEach((post) => {
|
|
19
19
|
const route = getBlogRoute(post, options.routes);
|
|
@@ -61,7 +61,7 @@ function createBrandlabBlogAdapter(options) {
|
|
|
61
61
|
if (!post)
|
|
62
62
|
return undefined;
|
|
63
63
|
const route = getBlogRoute(post, options.routes);
|
|
64
|
-
const url = getAbsoluteUrl(options.
|
|
64
|
+
const url = getAbsoluteUrl(options.site.canonicalUrl, route.canonicalPath ?? route.path);
|
|
65
65
|
return buildBlogPostingSchema({
|
|
66
66
|
id: `${url}#article`,
|
|
67
67
|
url,
|
|
@@ -72,7 +72,7 @@ function createBrandlabBlogAdapter(options) {
|
|
|
72
72
|
authorNames: post.authors.map((author) => author.name),
|
|
73
73
|
publisherId: options.publisherId,
|
|
74
74
|
...(post.image
|
|
75
|
-
? { imageUrls: [resolveBlogAssetUrl(options.
|
|
75
|
+
? { imageUrls: [resolveBlogAssetUrl(options.site.canonicalUrl, post.image.url)] }
|
|
76
76
|
: {}),
|
|
77
77
|
mainEntityOfPageId: url,
|
|
78
78
|
});
|
|
@@ -83,7 +83,7 @@ function createBrandlabBlogAdapter(options) {
|
|
|
83
83
|
if (route.indexing !== 'index')
|
|
84
84
|
return [];
|
|
85
85
|
return [{
|
|
86
|
-
url: getAbsoluteUrl(options.
|
|
86
|
+
url: getAbsoluteUrl(options.site.canonicalUrl, route.canonicalPath ?? route.path),
|
|
87
87
|
lastModified: route.lastSignificantChange ?? post.modifiedAt ?? post.publishedAt,
|
|
88
88
|
}];
|
|
89
89
|
});
|
|
@@ -103,14 +103,14 @@ function createBrandlabBlogAdapter(options) {
|
|
|
103
103
|
renderRss() {
|
|
104
104
|
if (!options.rss)
|
|
105
105
|
return undefined;
|
|
106
|
-
const feedUrl = getAbsoluteUrl(options.
|
|
107
|
-
const siteUrl = getAbsoluteUrl(options.
|
|
106
|
+
const feedUrl = getAbsoluteUrl(options.site.canonicalUrl, options.rss.path ?? '/rss.xml');
|
|
107
|
+
const siteUrl = getAbsoluteUrl(options.site.canonicalUrl, '/');
|
|
108
108
|
const items = published()
|
|
109
109
|
.map((post) => {
|
|
110
110
|
const route = getBlogRoute(post, options.routes);
|
|
111
111
|
if (route.indexing !== 'index')
|
|
112
112
|
return '';
|
|
113
|
-
const url = getAbsoluteUrl(options.
|
|
113
|
+
const url = getAbsoluteUrl(options.site.canonicalUrl, route.canonicalPath ?? route.path);
|
|
114
114
|
return [
|
|
115
115
|
' <item>',
|
|
116
116
|
` <title>${escapeXml(post.headline)}</title>`,
|
package/dist/blog.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"blog.js","sourceRoot":"","sources":["../src/blog.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineBlogPost,\n getPublishedBlogPosts,\n isPublishedBlogPost,\n type BrandlabBlogAdapter,\n type BrandlabBlogPost,\n} from '@brandlab-digital/site-core/blog'\nimport { getAbsoluteUrl } from '@brandlab-digital/site-core/metadata'\nimport {\n getRouteByPath,\n type BrandlabRoute,\n type BrandlabRouteCatalog,\n} from '@brandlab-digital/site-core/routes'\nimport { buildBlogPostingSchema } from '@brandlab-digital/site-core/schema'\nimport { escapeXml, type SitemapEntry } from '@brandlab-digital/site-core/sitemaps'\nimport {\n createRouteMetadataBuilder,\n type BrandlabMetadataDefaults,\n type NextCompatibleMetadata,\n} from './metadata.js'\n\nexport interface BrandlabBlogAdapterOptions<Content> {\n adapter: BrandlabBlogAdapter\n posts: readonly BrandlabBlogPost[]\n metadata: BrandlabMetadataDefaults\n publisherId: string\n resolveContent: (post: BrandlabBlogPost) => Content | Promise<Content>\n now?: () => Date\n routes: BrandlabRouteCatalog\n rss?: {\n title: string\n description: string\n path?: string\n }\n}\n\nfunction createBrandlabBlogAdapter<Content>(\n options: BrandlabBlogAdapterOptions<Content>,\n) {\n options.posts.forEach(defineBlogPost)\n assertUniquePosts(options.posts)\n const mismatchedAdapter = options.posts.find((post) => post.adapter !== options.adapter)\n if (mismatchedAdapter) {\n throw new Error(\n `Blog post \"${mismatchedAdapter.id}\" uses adapter \"${mismatchedAdapter.adapter}\" instead of \"${options.adapter}\".`,\n )\n }\n const eligiblePosts = options.posts.filter((post) => post.adapter === options.adapter)\n const published = () => getPublishedBlogPosts(eligiblePosts, options.now?.() ?? new Date())\n const routeMetadata = createRouteMetadataBuilder(options.metadata, options.routes)\n const validationTime = options.now?.() ?? new Date()\n eligiblePosts.forEach((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.kind !== 'blog-post') {\n throw new Error(`Blog post \"${post.id}\" must reference a blog-post route.`)\n }\n if (!isPublishedBlogPost(post, validationTime) && route.indexing === 'index') {\n throw new Error(\n `Unpublished blog post \"${post.id}\" must not use an indexable route.`,\n )\n }\n })\n const postPaths = new Set(eligiblePosts.map((post) => post.path))\n const routeWithoutPost = options.routes.find(\n (route) => route.kind === 'blog-post' && !postPaths.has(route.path),\n )\n if (routeWithoutPost) {\n throw new Error(\n `Blog-post route \"${routeWithoutPost.id}\" has no matching ${options.adapter} content record.`,\n )\n }\n\n return {\n getPublishedPosts: published,\n getPostBySlug(slug: string) {\n return published().find((post) => post.slug === slug)\n },\n generateStaticParams() {\n return published().map((post) => ({ slug: post.slug }))\n },\n generateMetadata(slug: string): NextCompatibleMetadata | undefined {\n const post = published().find((candidate) => candidate.slug === slug)\n if (!post) return undefined\n const metadataTitle = post.seo?.title ?? post.headline\n const route = getBlogRoute(post, options.routes)\n return routeMetadata({\n routeId: route.id,\n title: metadataTitle,\n description: post.description,\n ...(post.seo?.titleMode ? { titleMode: post.seo.titleMode } : {}),\n article: {\n publishedTime: post.publishedAt,\n ...(post.modifiedAt ? { modifiedTime: post.modifiedAt } : {}),\n authors: post.authors.map((author) => author.name),\n },\n ...(post.image ? { socialImage: post.image } : {}),\n })\n },\n generateSchema(slug: string) {\n const post = published().find((candidate) => candidate.slug === slug)\n if (!post) return undefined\n const route = getBlogRoute(post, options.routes)\n const url = getAbsoluteUrl(\n options.metadata.siteUrl,\n route.canonicalPath ?? route.path,\n )\n return buildBlogPostingSchema({\n id: `${url}#article`,\n url,\n headline: post.headline,\n description: post.description,\n datePublished: post.publishedAt,\n ...(post.modifiedAt ? { dateModified: post.modifiedAt } : {}),\n authorNames: post.authors.map((author) => author.name),\n publisherId: options.publisherId,\n ...(post.image\n ? { imageUrls: [resolveBlogAssetUrl(options.metadata.siteUrl, post.image.url)] }\n : {}),\n mainEntityOfPageId: url,\n })\n },\n getSitemapEntries(): SitemapEntry[] {\n return published().flatMap((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.indexing !== 'index') return []\n return [{\n url: getAbsoluteUrl(\n options.metadata.siteUrl,\n route.canonicalPath ?? route.path,\n ),\n lastModified:\n route.lastSignificantChange ?? post.modifiedAt ?? post.publishedAt,\n }]\n })\n },\n getRelatedPosts(slug: string, limit = 3) {\n const source = published().find((post) => post.slug === slug)\n if (!source || limit < 1) return []\n return published()\n .filter((post) => post.slug !== slug)\n .map((post) => ({ post, score: relatedScore(source, post) }))\n .filter((candidate) => candidate.score > 0)\n .sort((left, right) => right.score - left.score || right.post.headline.localeCompare(left.post.headline))\n .slice(0, limit)\n .map((candidate) => candidate.post)\n },\n renderRss() {\n if (!options.rss) return undefined\n const feedUrl = getAbsoluteUrl(options.metadata.siteUrl, options.rss.path ?? '/rss.xml')\n const siteUrl = getAbsoluteUrl(options.metadata.siteUrl, '/')\n const items = published()\n .map((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.indexing !== 'index') return ''\n const url = getAbsoluteUrl(\n options.metadata.siteUrl,\n route.canonicalPath ?? route.path,\n )\n return [\n ' <item>',\n ` <title>${escapeXml(post.headline)}</title>`,\n ` <link>${escapeXml(url)}</link>`,\n ` <guid isPermaLink=\"true\">${escapeXml(url)}</guid>`,\n ` <description>${escapeXml(post.description)}</description>`,\n ` <pubDate>${new Date(post.publishedAt).toUTCString()}</pubDate>`,\n ' </item>',\n ].join('\\n')\n })\n .join('\\n')\n return [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<rss version=\"2.0\">',\n ' <channel>',\n ` <title>${escapeXml(options.rss.title)}</title>`,\n ` <link>${escapeXml(siteUrl)}</link>`,\n ` <description>${escapeXml(options.rss.description)}</description>`,\n ` <atom:link xmlns:atom=\"http://www.w3.org/2005/Atom\" href=\"${escapeXml(feedUrl)}\" rel=\"self\" type=\"application/rss+xml\"/>`,\n items,\n ' </channel>',\n '</rss>',\n ].filter(Boolean).join('\\n')\n },\n async resolve(slug: string) {\n const post = published().find((candidate) => candidate.slug === slug)\n return post ? { post, content: await options.resolveContent(post) } : undefined\n },\n }\n}\n\nfunction resolveBlogAssetUrl(siteUrl: string, value: string) {\n let resolved: URL\n try {\n resolved = new URL(value, getAbsoluteUrl(siteUrl, '/'))\n } catch {\n throw new Error('Blog image URL must resolve to absolute HTTPS.')\n }\n if (resolved.protocol !== 'https:' || resolved.username || resolved.password) {\n throw new Error('Blog image URL must resolve to absolute HTTPS.')\n }\n return resolved.href\n}\n\nexport type BrandlabRouteAwareBlogAdapterOptions<Content> = Omit<\n BrandlabBlogAdapterOptions<Content>,\n 'adapter' | 'routes'\n> & { routes: BrandlabRouteCatalog }\n\nexport function createRouteAwareMdxBlogAdapter<Content>(\n options: BrandlabRouteAwareBlogAdapterOptions<Content>,\n) {\n return createBrandlabBlogAdapter({ ...options, adapter: 'mdx' })\n}\n\nexport function createRouteAwareStructuredBlogAdapter<Content>(\n options: BrandlabRouteAwareBlogAdapterOptions<Content>,\n) {\n return createBrandlabBlogAdapter({ ...options, adapter: 'structured' })\n}\n\nfunction getBlogRoute(post: BrandlabBlogPost, routes: BrandlabRouteCatalog): BrandlabRoute {\n const route = getRouteByPath(routes, post.path)\n if (!route) throw new Error(`Blog post \"${post.id}\" has no route-catalog record for \"${post.path}\".`)\n return route\n}\n\nfunction assertUniquePosts(posts: readonly BrandlabBlogPost[]) {\n for (const field of ['id', 'slug', 'path'] as const) {\n const values = posts.map((post) => post[field])\n const duplicate = values.find((value, index) => values.indexOf(value) !== index)\n if (duplicate) throw new Error(`Blog posts contain duplicate ${field} \"${duplicate}\".`)\n }\n}\n\nfunction relatedScore(source: BrandlabBlogPost, candidate: BrandlabBlogPost) {\n const categories = new Set(source.categories ?? [])\n const tags = new Set(source.tags ?? [])\n return (\n (candidate.categories ?? []).filter((category) => categories.has(category)).length * 2 +\n (candidate.tags ?? []).filter((tag) => tags.has(tag)).length\n )\n}\n"]}
|
|
1
|
+
{"version":3,"file":"blog.js","sourceRoot":"","sources":["../src/blog.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n defineBlogPost,\n getPublishedBlogPosts,\n isPublishedBlogPost,\n type BrandlabBlogAdapter,\n type BrandlabBlogPost,\n} from '@brandlab-digital/site-core/blog'\nimport { getAbsoluteUrl } from '@brandlab-digital/site-core/metadata'\nimport {\n getRouteByPath,\n type BrandlabRoute,\n type BrandlabRouteCatalog,\n} from '@brandlab-digital/site-core/routes'\nimport { buildBlogPostingSchema } from '@brandlab-digital/site-core/schema'\nimport type { BrandlabSite } from '@brandlab-digital/site-core/site'\nimport { escapeXml, type SitemapEntry } from '@brandlab-digital/site-core/sitemaps'\nimport {\n createRouteMetadataBuilder,\n type NextCompatibleMetadata,\n} from './metadata.js'\n\nexport interface BrandlabBlogAdapterOptions<Content> {\n adapter: BrandlabBlogAdapter\n posts: readonly BrandlabBlogPost[]\n /** The site identity from defineBrandlabSite; supplies canonical URLs and metadata defaults. */\n site: BrandlabSite\n publisherId: string\n resolveContent: (post: BrandlabBlogPost) => Content | Promise<Content>\n now?: () => Date\n routes: BrandlabRouteCatalog\n rss?: {\n title: string\n description: string\n path?: string\n }\n}\n\nfunction createBrandlabBlogAdapter<Content>(\n options: BrandlabBlogAdapterOptions<Content>,\n) {\n options.posts.forEach(defineBlogPost)\n assertUniquePosts(options.posts)\n const mismatchedAdapter = options.posts.find((post) => post.adapter !== options.adapter)\n if (mismatchedAdapter) {\n throw new Error(\n `Blog post \"${mismatchedAdapter.id}\" uses adapter \"${mismatchedAdapter.adapter}\" instead of \"${options.adapter}\".`,\n )\n }\n const eligiblePosts = options.posts.filter((post) => post.adapter === options.adapter)\n const published = () => getPublishedBlogPosts(eligiblePosts, options.now?.() ?? new Date())\n const routeMetadata = createRouteMetadataBuilder(options.site, options.routes)\n const validationTime = options.now?.() ?? new Date()\n eligiblePosts.forEach((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.kind !== 'blog-post') {\n throw new Error(`Blog post \"${post.id}\" must reference a blog-post route.`)\n }\n if (!isPublishedBlogPost(post, validationTime) && route.indexing === 'index') {\n throw new Error(\n `Unpublished blog post \"${post.id}\" must not use an indexable route.`,\n )\n }\n })\n const postPaths = new Set(eligiblePosts.map((post) => post.path))\n const routeWithoutPost = options.routes.find(\n (route) => route.kind === 'blog-post' && !postPaths.has(route.path),\n )\n if (routeWithoutPost) {\n throw new Error(\n `Blog-post route \"${routeWithoutPost.id}\" has no matching ${options.adapter} content record.`,\n )\n }\n\n return {\n getPublishedPosts: published,\n getPostBySlug(slug: string) {\n return published().find((post) => post.slug === slug)\n },\n generateStaticParams() {\n return published().map((post) => ({ slug: post.slug }))\n },\n generateMetadata(slug: string): NextCompatibleMetadata | undefined {\n const post = published().find((candidate) => candidate.slug === slug)\n if (!post) return undefined\n const metadataTitle = post.seo?.title ?? post.headline\n const route = getBlogRoute(post, options.routes)\n return routeMetadata({\n routeId: route.id,\n title: metadataTitle,\n description: post.description,\n ...(post.seo?.titleMode ? { titleMode: post.seo.titleMode } : {}),\n article: {\n publishedTime: post.publishedAt,\n ...(post.modifiedAt ? { modifiedTime: post.modifiedAt } : {}),\n authors: post.authors.map((author) => author.name),\n },\n ...(post.image ? { socialImage: post.image } : {}),\n })\n },\n generateSchema(slug: string) {\n const post = published().find((candidate) => candidate.slug === slug)\n if (!post) return undefined\n const route = getBlogRoute(post, options.routes)\n const url = getAbsoluteUrl(\n options.site.canonicalUrl,\n route.canonicalPath ?? route.path,\n )\n return buildBlogPostingSchema({\n id: `${url}#article`,\n url,\n headline: post.headline,\n description: post.description,\n datePublished: post.publishedAt,\n ...(post.modifiedAt ? { dateModified: post.modifiedAt } : {}),\n authorNames: post.authors.map((author) => author.name),\n publisherId: options.publisherId,\n ...(post.image\n ? { imageUrls: [resolveBlogAssetUrl(options.site.canonicalUrl, post.image.url)] }\n : {}),\n mainEntityOfPageId: url,\n })\n },\n getSitemapEntries(): SitemapEntry[] {\n return published().flatMap((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.indexing !== 'index') return []\n return [{\n url: getAbsoluteUrl(\n options.site.canonicalUrl,\n route.canonicalPath ?? route.path,\n ),\n lastModified:\n route.lastSignificantChange ?? post.modifiedAt ?? post.publishedAt,\n }]\n })\n },\n getRelatedPosts(slug: string, limit = 3) {\n const source = published().find((post) => post.slug === slug)\n if (!source || limit < 1) return []\n return published()\n .filter((post) => post.slug !== slug)\n .map((post) => ({ post, score: relatedScore(source, post) }))\n .filter((candidate) => candidate.score > 0)\n .sort((left, right) => right.score - left.score || right.post.headline.localeCompare(left.post.headline))\n .slice(0, limit)\n .map((candidate) => candidate.post)\n },\n renderRss() {\n if (!options.rss) return undefined\n const feedUrl = getAbsoluteUrl(options.site.canonicalUrl, options.rss.path ?? '/rss.xml')\n const siteUrl = getAbsoluteUrl(options.site.canonicalUrl, '/')\n const items = published()\n .map((post) => {\n const route = getBlogRoute(post, options.routes)\n if (route.indexing !== 'index') return ''\n const url = getAbsoluteUrl(\n options.site.canonicalUrl,\n route.canonicalPath ?? route.path,\n )\n return [\n ' <item>',\n ` <title>${escapeXml(post.headline)}</title>`,\n ` <link>${escapeXml(url)}</link>`,\n ` <guid isPermaLink=\"true\">${escapeXml(url)}</guid>`,\n ` <description>${escapeXml(post.description)}</description>`,\n ` <pubDate>${new Date(post.publishedAt).toUTCString()}</pubDate>`,\n ' </item>',\n ].join('\\n')\n })\n .join('\\n')\n return [\n '<?xml version=\"1.0\" encoding=\"UTF-8\"?>',\n '<rss version=\"2.0\">',\n ' <channel>',\n ` <title>${escapeXml(options.rss.title)}</title>`,\n ` <link>${escapeXml(siteUrl)}</link>`,\n ` <description>${escapeXml(options.rss.description)}</description>`,\n ` <atom:link xmlns:atom=\"http://www.w3.org/2005/Atom\" href=\"${escapeXml(feedUrl)}\" rel=\"self\" type=\"application/rss+xml\"/>`,\n items,\n ' </channel>',\n '</rss>',\n ].filter(Boolean).join('\\n')\n },\n async resolve(slug: string) {\n const post = published().find((candidate) => candidate.slug === slug)\n return post ? { post, content: await options.resolveContent(post) } : undefined\n },\n }\n}\n\nfunction resolveBlogAssetUrl(siteUrl: string, value: string) {\n let resolved: URL\n try {\n resolved = new URL(value, getAbsoluteUrl(siteUrl, '/'))\n } catch {\n throw new Error('Blog image URL must resolve to absolute HTTPS.')\n }\n if (resolved.protocol !== 'https:' || resolved.username || resolved.password) {\n throw new Error('Blog image URL must resolve to absolute HTTPS.')\n }\n return resolved.href\n}\n\nexport type BrandlabRouteAwareBlogAdapterOptions<Content> = Omit<\n BrandlabBlogAdapterOptions<Content>,\n 'adapter' | 'routes'\n> & { routes: BrandlabRouteCatalog }\n\nexport function createRouteAwareMdxBlogAdapter<Content>(\n options: BrandlabRouteAwareBlogAdapterOptions<Content>,\n) {\n return createBrandlabBlogAdapter({ ...options, adapter: 'mdx' })\n}\n\nexport function createRouteAwareStructuredBlogAdapter<Content>(\n options: BrandlabRouteAwareBlogAdapterOptions<Content>,\n) {\n return createBrandlabBlogAdapter({ ...options, adapter: 'structured' })\n}\n\nfunction getBlogRoute(post: BrandlabBlogPost, routes: BrandlabRouteCatalog): BrandlabRoute {\n const route = getRouteByPath(routes, post.path)\n if (!route) throw new Error(`Blog post \"${post.id}\" has no route-catalog record for \"${post.path}\".`)\n return route\n}\n\nfunction assertUniquePosts(posts: readonly BrandlabBlogPost[]) {\n for (const field of ['id', 'slug', 'path'] as const) {\n const values = posts.map((post) => post[field])\n const duplicate = values.find((value, index) => values.indexOf(value) !== index)\n if (duplicate) throw new Error(`Blog posts contain duplicate ${field} \"${duplicate}\".`)\n }\n}\n\nfunction relatedScore(source: BrandlabBlogPost, candidate: BrandlabBlogPost) {\n const categories = new Set(source.categories ?? [])\n const tags = new Set(source.tags ?? [])\n return (\n (candidate.categories ?? []).filter((category) => categories.has(category)).length * 2 +\n (candidate.tags ?? []).filter((tag) => tags.has(tag)).length\n )\n}\n"]}
|
|
@@ -1,2 +1,4 @@
|
|
|
1
1
|
export { compressBrandlabContactImage, useBrandlabContactAttachments, type BrandlabContactAttachmentPreview, type UseBrandlabContactAttachmentsOptions, type UseBrandlabContactAttachmentsResult, } from './attachments-client.js';
|
|
2
|
+
export { contactFieldProps, useBrandlabContactForm, type BrandlabContactAcceptedResult, type BrandlabContactFailedResult, type BrandlabContactFormProps, type BrandlabContactSubmitProps, type BrandlabContactSubmitStart, type ContactFieldPropsOptions, type UseBrandlabContactFormOptions, type UseBrandlabContactFormResult, } from './form-client.js';
|
|
3
|
+
export type { ContactSubmissionPhase } from './client.js';
|
|
2
4
|
//# sourceMappingURL=client-entry.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../../src/contact/client-entry.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,GACzC,MAAM,yBAAyB,CAAA"}
|
|
1
|
+
{"version":3,"file":"client-entry.d.ts","sourceRoot":"","sources":["../../src/contact/client-entry.ts"],"names":[],"mappings":"AAEA,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,EAC7B,KAAK,gCAAgC,EACrC,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,GACzC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,EACtB,KAAK,6BAA6B,EAClC,KAAK,2BAA2B,EAChC,KAAK,wBAAwB,EAC7B,KAAK,0BAA0B,EAC/B,KAAK,0BAA0B,EAC/B,KAAK,wBAAwB,EAC7B,KAAK,6BAA6B,EAClC,KAAK,4BAA4B,GAClC,MAAM,kBAAkB,CAAA;AACzB,YAAY,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client-entry.js","sourceRoot":"","sources":["../../src/contact/client-entry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,GAI9B,MAAM,yBAAyB,CAAA","sourcesContent":["'use client'\n\nexport {\n compressBrandlabContactImage,\n useBrandlabContactAttachments,\n type BrandlabContactAttachmentPreview,\n type UseBrandlabContactAttachmentsOptions,\n type UseBrandlabContactAttachmentsResult,\n} from './attachments-client.js'\n"]}
|
|
1
|
+
{"version":3,"file":"client-entry.js","sourceRoot":"","sources":["../../src/contact/client-entry.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAEZ,OAAO,EACL,4BAA4B,EAC5B,6BAA6B,GAI9B,MAAM,yBAAyB,CAAA;AAChC,OAAO,EACL,iBAAiB,EACjB,sBAAsB,GASvB,MAAM,kBAAkB,CAAA","sourcesContent":["'use client'\n\nexport {\n compressBrandlabContactImage,\n useBrandlabContactAttachments,\n type BrandlabContactAttachmentPreview,\n type UseBrandlabContactAttachmentsOptions,\n type UseBrandlabContactAttachmentsResult,\n} from './attachments-client.js'\nexport {\n contactFieldProps,\n useBrandlabContactForm,\n type BrandlabContactAcceptedResult,\n type BrandlabContactFailedResult,\n type BrandlabContactFormProps,\n type BrandlabContactSubmitProps,\n type BrandlabContactSubmitStart,\n type ContactFieldPropsOptions,\n type UseBrandlabContactFormOptions,\n type UseBrandlabContactFormResult,\n} from './form-client.js'\nexport type { ContactSubmissionPhase } from './client.js'\n"]}
|
package/dist/contact/client.d.ts
CHANGED
|
@@ -1,7 +1,5 @@
|
|
|
1
|
-
import type { GtagTransport } from '@brandlab-digital/site-core/analytics';
|
|
2
1
|
import { type ContactActionResult } from '@brandlab-digital/site-core/contact';
|
|
3
|
-
import {
|
|
4
|
-
import { createContactSubmissionId, type BrandlabContactDefinition } from './shared.js';
|
|
2
|
+
import { createContactSubmissionId } from './shared.js';
|
|
5
3
|
export { createContactSubmissionId };
|
|
6
4
|
export declare function normalizeContactUploadFile(original: File, processed: Blob): File;
|
|
7
5
|
/** Explicit format-changing path; never relabel the original HEIC bytes as JPEG. */
|
|
@@ -20,32 +18,24 @@ export interface ContactHttpSubmissionControllerOptions {
|
|
|
20
18
|
contactEndpoint?: string;
|
|
21
19
|
fetcher?: typeof fetch;
|
|
22
20
|
now?: () => Date;
|
|
23
|
-
|
|
21
|
+
/** Reports an accepted enquiry, once per confirmation ID, with the attempt's fields. */
|
|
22
|
+
reportAccepted?: (result: Extract<ContactActionResult, {
|
|
23
|
+
ok: true;
|
|
24
|
+
accepted: true;
|
|
25
|
+
}>, formData: FormData) => void;
|
|
24
26
|
onStateChange?: (state: ContactSubmissionState) => void;
|
|
25
27
|
}
|
|
26
28
|
export interface ContactSubmissionController {
|
|
27
29
|
getState(): ContactSubmissionState;
|
|
30
|
+
/**
|
|
31
|
+
* Sends the fields. After a retryable failure, fields identical to the failed
|
|
32
|
+
* attempt resend that attempt with its submission ID; changed fields start a
|
|
33
|
+
* new submission.
|
|
34
|
+
*/
|
|
28
35
|
submit(formData: FormData): Promise<ContactActionResult>;
|
|
36
|
+
/** Resends the failed attempt with its submission ID. */
|
|
29
37
|
retry(): Promise<ContactActionResult>;
|
|
30
38
|
reset(): void;
|
|
31
39
|
}
|
|
32
40
|
export declare function createContactHttpSubmissionController(options: ContactHttpSubmissionControllerOptions): ContactSubmissionController;
|
|
33
|
-
export declare function shouldTrackContactResult(result: ContactActionResult): result is Extract<ContactActionResult, {
|
|
34
|
-
ok: true;
|
|
35
|
-
accepted: true;
|
|
36
|
-
}>;
|
|
37
|
-
export declare function trackDeliveredContactResult(result: ContactActionResult, options: {
|
|
38
|
-
pagePath: string;
|
|
39
|
-
definition: BrandlabContactDefinition;
|
|
40
|
-
formData: FormData;
|
|
41
|
-
enabled: boolean;
|
|
42
|
-
enhancedConversionsEnabled?: boolean;
|
|
43
|
-
adUserDataConsent: boolean;
|
|
44
|
-
measurementId?: string | null;
|
|
45
|
-
googleAdsConversionId?: string | null;
|
|
46
|
-
googleAdsConversionLabel?: string | null;
|
|
47
|
-
gtag?: GtagTransport;
|
|
48
|
-
params?: SafeContactAnalyticsParams;
|
|
49
|
-
adsParams?: SafeContactAdsParams;
|
|
50
|
-
}): import("@brandlab-digital/site-core/analytics").ContactFormConversionResult;
|
|
51
41
|
//# sourceMappingURL=client.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"AAEA,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAA;AAG5C,OAAO,EAGL,yBAAyB,EAC1B,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,yBAAyB,EAAE,CAAA;AAEpC,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAgBhF;AAED,oFAAoF;AACpF,wBAAsB,mCAAmC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAexG;AA8CD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,SAAS,CA+CxF;AAED,MAAM,MAAM,sBAAsB,GAC9B,MAAM,GACN,YAAY,GACZ,UAAU,GACV,mBAAmB,GACnB,OAAO,CAAA;AAEX,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,sBAAsB,CAAA;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,mBAAmB,CAAA;CAC7B;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;IACtB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,wFAAwF;IACxF,cAAc,CAAC,EAAE,CACf,MAAM,EAAE,OAAO,CAAC,mBAAmB,EAAE;QAAE,EAAE,EAAE,IAAI,CAAC;QAAC,QAAQ,EAAE,IAAI,CAAA;KAAE,CAAC,EAClE,QAAQ,EAAE,QAAQ,KACf,IAAI,CAAA;IACT,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAA;CACxD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,IAAI,sBAAsB,CAAA;IAClC;;;;OAIG;IACH,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACxD,yDAAyD;IACzD,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACrC,KAAK,IAAI,IAAI,CAAA;CACd;AAmGD,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,sCAAsC,GAC9C,2BAA2B,CAqI7B"}
|
package/dist/contact/client.js
CHANGED
|
@@ -2,7 +2,6 @@
|
|
|
2
2
|
import { resolveContactAttachmentType, detectContactTransportAttachmentType, } from '@brandlab-digital/site-core/contact';
|
|
3
3
|
import { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes';
|
|
4
4
|
import { getInitialContactAttribution } from '../instrumentation-client.js';
|
|
5
|
-
import { trackDeliveredContactWithEnhancedConversions, } from '../analytics.js';
|
|
6
5
|
import { CONTACT_CONFIRMATION_ID_PATTERN, CONTACT_FORM_FIELDS, createContactSubmissionId, } from './shared.js';
|
|
7
6
|
export { createContactSubmissionId };
|
|
8
7
|
export function normalizeContactUploadFile(original, processed) {
|
|
@@ -118,6 +117,17 @@ export function parseContactActionResult(value) {
|
|
|
118
117
|
...(fieldErrors ? { fieldErrors } : {}),
|
|
119
118
|
};
|
|
120
119
|
}
|
|
120
|
+
function sameEntryValue(left, right) {
|
|
121
|
+
if (typeof left === 'string' || typeof right === 'string')
|
|
122
|
+
return left === right;
|
|
123
|
+
return left === right || (left.name === right.name &&
|
|
124
|
+
left.size === right.size &&
|
|
125
|
+
left.type === right.type &&
|
|
126
|
+
left.lastModified === right.lastModified);
|
|
127
|
+
}
|
|
128
|
+
function sameFields(left, right) {
|
|
129
|
+
return left.length === right.length && left.every(([name, value], index) => name === right[index][0] && sameEntryValue(value, right[index][1]));
|
|
130
|
+
}
|
|
121
131
|
function copyFormData(formData) {
|
|
122
132
|
if (!formData || typeof formData.entries !== 'function') {
|
|
123
133
|
throw new TypeError('A FormData submission is required.');
|
|
@@ -191,8 +201,12 @@ export function createContactHttpSubmissionController(options) {
|
|
|
191
201
|
if (options.onStateChange !== undefined && typeof options.onStateChange !== 'function') {
|
|
192
202
|
throw new TypeError('onStateChange must be a function.');
|
|
193
203
|
}
|
|
204
|
+
if (options.reportAccepted !== undefined && typeof options.reportAccepted !== 'function') {
|
|
205
|
+
throw new TypeError('reportAccepted must be a function.');
|
|
206
|
+
}
|
|
194
207
|
const trackedConfirmations = new Set();
|
|
195
208
|
let attempt;
|
|
209
|
+
let attemptFields;
|
|
196
210
|
let inFlight;
|
|
197
211
|
let state = {
|
|
198
212
|
phase: 'idle',
|
|
@@ -232,18 +246,14 @@ export function createContactHttpSubmissionController(options) {
|
|
|
232
246
|
if (result.accepted && !trackedConfirmations.has(result.confirmationId)) {
|
|
233
247
|
trackedConfirmations.add(result.confirmationId);
|
|
234
248
|
try {
|
|
235
|
-
|
|
236
|
-
trackDeliveredContactResult(result, {
|
|
237
|
-
...options.analytics,
|
|
238
|
-
formData: copyFormData(formData),
|
|
239
|
-
});
|
|
240
|
-
}
|
|
249
|
+
options.reportAccepted?.(result, copyFormData(formData));
|
|
241
250
|
}
|
|
242
251
|
catch {
|
|
243
252
|
// Delivery has already succeeded; analytics cannot change that result.
|
|
244
253
|
}
|
|
245
254
|
}
|
|
246
255
|
attempt = undefined;
|
|
256
|
+
attemptFields = undefined;
|
|
247
257
|
publish({
|
|
248
258
|
phase: result.accepted ? 'accepted' : 'accepted-silently',
|
|
249
259
|
pending: false,
|
|
@@ -268,9 +278,18 @@ export function createContactHttpSubmissionController(options) {
|
|
|
268
278
|
submit(formData) {
|
|
269
279
|
if (inFlight)
|
|
270
280
|
return inFlight;
|
|
281
|
+
const fields = [...copyFormData(formData).entries()];
|
|
282
|
+
if (attempt &&
|
|
283
|
+
attemptFields &&
|
|
284
|
+
state.phase === 'error' &&
|
|
285
|
+
state.canRetry &&
|
|
286
|
+
sameFields(attemptFields, fields)) {
|
|
287
|
+
return run(attempt);
|
|
288
|
+
}
|
|
271
289
|
const now = options.now?.() ?? new Date();
|
|
272
290
|
if (!Number.isFinite(now.getTime())) {
|
|
273
291
|
attempt = undefined;
|
|
292
|
+
attemptFields = undefined;
|
|
274
293
|
publish({
|
|
275
294
|
phase: 'error',
|
|
276
295
|
pending: false,
|
|
@@ -279,6 +298,7 @@ export function createContactHttpSubmissionController(options) {
|
|
|
279
298
|
});
|
|
280
299
|
return Promise.resolve(RETRYABLE_CLIENT_FAILURE);
|
|
281
300
|
}
|
|
301
|
+
attemptFields = fields;
|
|
282
302
|
attempt = addSubmissionMetadata(copyFormData(formData), {
|
|
283
303
|
pagePath,
|
|
284
304
|
...(pageLabel ? { pageLabel } : {}),
|
|
@@ -298,22 +318,9 @@ export function createContactHttpSubmissionController(options) {
|
|
|
298
318
|
if (inFlight)
|
|
299
319
|
throw new Error('A pending contact submission cannot be reset.');
|
|
300
320
|
attempt = undefined;
|
|
321
|
+
attemptFields = undefined;
|
|
301
322
|
publish({ phase: 'idle', pending: false, canRetry: false });
|
|
302
323
|
},
|
|
303
324
|
};
|
|
304
325
|
}
|
|
305
|
-
export function shouldTrackContactResult(result) {
|
|
306
|
-
return result.ok && result.accepted && result.trackConversion;
|
|
307
|
-
}
|
|
308
|
-
export function trackDeliveredContactResult(result, options) {
|
|
309
|
-
const { pagePath, definition, formData, adUserDataConsent, params, adsParams, ...config } = options;
|
|
310
|
-
return trackDeliveredContactWithEnhancedConversions(result, config, {
|
|
311
|
-
pagePath,
|
|
312
|
-
definition,
|
|
313
|
-
formData,
|
|
314
|
-
adUserDataConsent,
|
|
315
|
-
params,
|
|
316
|
-
adsParams,
|
|
317
|
-
});
|
|
318
|
-
}
|
|
319
326
|
//# sourceMappingURL=client.js.map
|