@brandlab-digital/site-next 3.2.0 → 3.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/analytics.d.ts +2 -0
- package/dist/analytics.d.ts.map +1 -1
- package/dist/analytics.js +5 -1
- package/dist/analytics.js.map +1 -1
- package/dist/contact/form-client.d.ts +1 -1
- package/dist/contact/form-client.d.ts.map +1 -1
- package/dist/contact/form-client.js +1 -1
- package/dist/contact/form-client.js.map +1 -1
- package/dist/contact/resend.d.ts +25 -3
- package/dist/contact/resend.d.ts.map +1 -1
- package/dist/contact/resend.js +54 -8
- package/dist/contact/resend.js.map +1 -1
- package/dist/contact/server.d.ts +11 -1
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +50 -2
- package/dist/contact/server.js.map +1 -1
- package/dist/contact/testing.js +1 -1
- package/dist/contact/testing.js.map +1 -1
- package/dist/google-reviews-client.d.ts +9 -4
- package/dist/google-reviews-client.d.ts.map +1 -1
- package/dist/google-reviews-client.js +60 -13
- package/dist/google-reviews-client.js.map +1 -1
- package/dist/google-reviews-server.d.ts +11 -2
- package/dist/google-reviews-server.d.ts.map +1 -1
- package/dist/google-reviews-server.js +52 -18
- package/dist/google-reviews-server.js.map +1 -1
- package/dist/google-tag-plan.d.ts +5 -0
- package/dist/google-tag-plan.d.ts.map +1 -1
- package/dist/google-tag-plan.js +16 -1
- package/dist/google-tag-plan.js.map +1 -1
- package/dist/headers.d.ts +22 -1
- package/dist/headers.d.ts.map +1 -1
- package/dist/headers.js +34 -1
- package/dist/headers.js.map +1 -1
- package/dist/lead-registry.d.ts +2 -0
- package/dist/lead-registry.d.ts.map +1 -1
- package/dist/lead-registry.js.map +1 -1
- package/dist/lead-reporting.d.ts +7 -3
- package/dist/lead-reporting.d.ts.map +1 -1
- package/dist/lead-reporting.js +5 -2
- package/dist/lead-reporting.js.map +1 -1
- package/dist/next-config.d.ts +15 -0
- package/dist/next-config.d.ts.map +1 -1
- package/dist/next-config.js +29 -4
- package/dist/next-config.js.map +1 -1
- package/dist/robots.d.ts +4 -2
- package/dist/robots.d.ts.map +1 -1
- package/dist/robots.js +12 -2
- package/dist/robots.js.map +1 -1
- package/dist/user-interaction.d.ts +14 -0
- package/dist/user-interaction.d.ts.map +1 -0
- package/dist/user-interaction.js +53 -0
- package/dist/user-interaction.js.map +1 -0
- package/package.json +2 -2
package/dist/analytics.d.ts
CHANGED
|
@@ -6,6 +6,8 @@ export interface BrandlabBrowserAnalyticsConfig {
|
|
|
6
6
|
enabled: boolean;
|
|
7
7
|
leadDiagnosticsEnabled?: boolean;
|
|
8
8
|
enhancedConversionsEnabled?: boolean;
|
|
9
|
+
/** Disclosed Enhanced Conversions: ad_user_data is granted by default. */
|
|
10
|
+
adUserDataGrantedByDefault?: boolean;
|
|
9
11
|
measurementId?: string | null;
|
|
10
12
|
googleAdsConversionId?: string | null;
|
|
11
13
|
googleAdsConversionLabel?: string | null;
|
package/dist/analytics.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"analytics.d.ts","sourceRoot":"","sources":["../src/analytics.ts"],"names":[],"mappings":"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"}
|
package/dist/analytics.js
CHANGED
|
@@ -362,11 +362,14 @@ export function defineBrandlabAnalytics(options) {
|
|
|
362
362
|
.environment === 'production';
|
|
363
363
|
const measurementId = publicValue(values.measurementId);
|
|
364
364
|
const googleAdsConversionId = contract.googleAds ? publicValue(values.googleAdsConversionId) : undefined;
|
|
365
|
+
const enhancedConversionsMode = contract.googleAds?.enhancedConversions?.mode;
|
|
366
|
+
const adUserDataGrantedByDefault = enhancedConversionsMode === 'disclosed';
|
|
365
367
|
const config = Object.freeze({
|
|
366
368
|
enabled,
|
|
367
369
|
// Privacy-safe lead_form_start / lead_form_error diagnostics are on for every site.
|
|
368
370
|
leadDiagnosticsEnabled: true,
|
|
369
|
-
enhancedConversionsEnabled:
|
|
371
|
+
enhancedConversionsEnabled: enhancedConversionsMode === 'consent-required' || enhancedConversionsMode === 'disclosed',
|
|
372
|
+
adUserDataGrantedByDefault,
|
|
370
373
|
measurementId,
|
|
371
374
|
googleAdsConversionId,
|
|
372
375
|
googleAdsConversionLabel: contract.googleAds
|
|
@@ -380,6 +383,7 @@ export function defineBrandlabAnalytics(options) {
|
|
|
380
383
|
googleAdsWebsiteCallConversionLabel: contract.googleAds?.websiteCalls
|
|
381
384
|
? publicValue(values.googleAdsWebsiteCallConversionLabel)
|
|
382
385
|
: undefined,
|
|
386
|
+
adUserData: adUserDataGrantedByDefault ? 'granted' : 'denied',
|
|
383
387
|
});
|
|
384
388
|
const pageParams = (pagePath) => {
|
|
385
389
|
const parts = pathSegments(pagePath);
|
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":["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"]}
|
|
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 /** Disclosed Enhanced Conversions: ad_user_data is granted by default. */\n adUserDataGrantedByDefault?: 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 enhancedConversionsMode = contract.googleAds?.enhancedConversions?.mode\n const adUserDataGrantedByDefault = enhancedConversionsMode === 'disclosed'\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 enhancedConversionsMode === 'consent-required' || enhancedConversionsMode === 'disclosed',\n adUserDataGrantedByDefault,\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 adUserData: adUserDataGrantedByDefault ? 'granted' : 'denied',\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"]}
|
|
@@ -67,7 +67,7 @@ export interface UseBrandlabContactFormOptions {
|
|
|
67
67
|
attachments?: UseBrandlabContactAttachmentsOptions;
|
|
68
68
|
/** Multipart field prefix for prepared files (default `attachments`, sent as `attachments[0]` …). */
|
|
69
69
|
attachmentFieldPrefix?: string;
|
|
70
|
-
/** Live Consent Mode decision for ad_user_data; Enhanced Conversions stay off
|
|
70
|
+
/** Live Consent Mode decision for ad_user_data; without it Enhanced Conversions stay off, unless the analytics contract's mode is `disclosed`. */
|
|
71
71
|
adUserDataConsent?: boolean;
|
|
72
72
|
contactEndpoint?: string;
|
|
73
73
|
fetcher?: typeof fetch;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-client.d.ts","sourceRoot":"","sources":["../../src/contact/form-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAIL,KAAK,uBAAuB,EAC5B,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAA;AAE5C,OAAO,EAOL,KAAK,SAAS,EACd,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AACd,OAAO,KAAK,EAAE,iBAAiB,EAAsB,MAAM,iBAAiB,CAAA;AAG5E,OAAO,EAEL,KAAK,oCAAoC,EACzC,KAAK,mCAAmC,EACzC,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAEL,KAAK,sBAAsB,EAE5B,MAAM,aAAa,CAAA;AAEpB,iGAAiG;AACjG,MAAM,MAAM,6BAA6B,GAAG,OAAO,CAAC,mBAAmB,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,CAAA;AACtF,MAAM,MAAM,2BAA2B,GAAG,OAAO,CAAC,mBAAmB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,CAAA;AAErF,MAAM,WAAW,0BAA0B;IACzC,IAAI,EAAE,eAAe,CAAA;IACrB;;;OAGG;IACH,QAAQ,EAAE,QAAQ,CAAA;CACnB;AAED,MAAM,WAAW,6BAA6B;IAC5C,uDAAuD;IACvD,QAAQ,EAAE,uBAAuB,CAAA;IACjC,wHAAwH;IACxH,SAAS,CAAC,EAAE,iBAAiB,CAAA;IAC7B,yDAAyD;IACzD,QAAQ,EAAE,MAAM,CAAA;IAChB,uDAAuD;IACvD,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB;;;;;;OAMG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IACf,+FAA+F;IAC/F,UAAU,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC1B,qFAAqF;IACrF,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;IACjC,sFAAsF;IACtF,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB;;;;;OAKG;IACH,aAAa,CAAC,EAAE,CAAC,UAAU,EAAE,0BAA0B,KAAK,IAAI,GAAG,KAAK,CAAA;IACxE;;;OAGG;IACH,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,mBAAmB,KAAK,IAAI,CAAA;IACjD,4FAA4F;IAC5F,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,6BAA6B,KAAK,IAAI,CAAA;IAC5D,8EAA8E;IAC9E,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,2BAA2B,KAAK,IAAI,CAAA;IACxD;;;;OAIG;IACH,gBAAgB,CAAC,EAAE,UAAU,GAAG,QAAQ,CAAA;IACxC,+FAA+F;IAC/F,WAAW,CAAC,EAAE,oCAAoC,CAAA;IAClD,qGAAqG;IACrG,qBAAqB,CAAC,EAAE,MAAM,CAAA;IAC9B,
|
|
1
|
+
{"version":3,"file":"form-client.d.ts","sourceRoot":"","sources":["../../src/contact/form-client.ts"],"names":[],"mappings":"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"}
|
|
@@ -118,7 +118,7 @@ export function useBrandlabContactForm(options) {
|
|
|
118
118
|
pagePath: rawPagePath,
|
|
119
119
|
formData,
|
|
120
120
|
fieldRoles: roles,
|
|
121
|
-
adUserDataConsent
|
|
121
|
+
...(adUserDataConsent !== undefined ? { adUserDataConsent } : {}),
|
|
122
122
|
});
|
|
123
123
|
},
|
|
124
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"form-client.js","sourceRoot":"","sources":["../../src/contact/form-client.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n DOCUMENT_CONTACT_ATTACHMENT_POLICY,\n defineContactContract,\n type BrandlabContactContract,\n type ContactActionResult,\n} from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type FormEvent,\n type RefObject,\n} from 'react'\nimport type { BrandlabAnalytics, LeadFormErrorStage } from '../analytics.js'\nimport { leadBindingFor, safeSlug } from '../lead-registry.js'\nimport { reportAcceptedLead } from '../lead-reporting.js'\nimport {\n useBrandlabContactAttachments,\n type UseBrandlabContactAttachmentsOptions,\n type UseBrandlabContactAttachmentsResult,\n} from './attachments-client.js'\nimport {\n createContactHttpSubmissionController,\n type ContactSubmissionPhase,\n type ContactSubmissionState,\n} from './client.js'\n\n/** An accepted enquiry, or a silently accepted spam-protected submission (`accepted: false`). */\nexport type BrandlabContactAcceptedResult = Extract<ContactActionResult, { ok: true }>\nexport type BrandlabContactFailedResult = Extract<ContactActionResult, { ok: false }>\n\nexport interface BrandlabContactSubmitStart {\n form: HTMLFormElement\n /**\n * The fields about to be sent, read from the form. Add or replace entries\n * here (for example `service_interest`); prepared photos are appended after.\n */\n formData: FormData\n}\n\nexport interface UseBrandlabContactFormOptions {\n /** The contact contract from src/config/contact.ts. */\n contract: BrandlabContactContract\n /** The site's defineBrandlabAnalytics binding: the declared lead after each accepted enquiry, plus lead diagnostics. */\n analytics?: BrandlabAnalytics\n /** The current pathname, for example `usePathname()`. */\n pagePath: string\n /** Reviewed label for the enquiry email's page row. */\n pageLabel?: string\n /**\n * The form element's id and the lead diagnostics' form_id. Without it the form\n * gets no id (the hook never takes a React id, so the form's own ids are\n * unchanged), diagnostics use `contact-form` and error ids start `contact-form-`.\n * The element keeps the id exactly as given; diagnostics report it as a slug\n * (React `useId()` parts removed, see `contactFormSlug`).\n */\n formId?: string\n /** Page to open after an accepted enquiry; `null` or omitted keeps the visitor on the page. */\n redirectTo?: string | null\n /** Client navigation such as `router.push`; defaults to `window.location.assign`. */\n navigate?: (href: string) => void\n /** Delay before the redirect, in milliseconds (default 1500); 0 navigates at once. */\n redirectDelayMs?: number\n /**\n * Runs when the visitor submits, before anything is sent: clear the form's\n * own notices, adjust `formData`, or return `false` to cancel (for example\n * after `form.reportValidity()`). An unchanged resubmission runs it too;\n * `retry()` does not.\n */\n onSubmitStart?: (submission: BrandlabContactSubmitStart) => void | false\n /**\n * Runs after every attempt, before onAccepted or onFailed: an accepted\n * enquiry, a silently accepted submission (even when ignored) or a failure.\n */\n onSettled?: (result: ContactActionResult) => void\n /** Runs after an accepted enquiry, once the form has been reset and before any redirect. */\n onAccepted?: (result: BrandlabContactAcceptedResult) => void\n /** Runs after a failed attempt; typed values and prepared photos are kept. */\n onFailed?: (result: BrandlabContactFailedResult) => void\n /**\n * A silently accepted submission (spam protection): `complete` (default)\n * resets, runs onAccepted and redirects like an accepted enquiry; `ignore`\n * leaves the form as it is and runs only onSettled.\n */\n silentAcceptance?: 'complete' | 'ignore'\n /** Photo preparation options; the policy follows the contract's attachment mode by default. */\n attachments?: UseBrandlabContactAttachmentsOptions\n /** Multipart field prefix for prepared files (default `attachments`, sent as `attachments[0]` …). */\n attachmentFieldPrefix?: string\n /** Live Consent Mode decision for ad_user_data; Enhanced Conversions stay off without it. */\n adUserDataConsent?: boolean\n contactEndpoint?: string\n fetcher?: typeof fetch\n}\n\n/**\n * Spread onto the `<form>`: `method=\"post\"` with no `action` or `encType`, so a\n * submission before hydration posts back to the page and never puts fields in\n * a URL; the hook submits through fetch. `id` only when `formId` is given.\n */\nexport interface BrandlabContactFormProps {\n id?: string\n ref: RefObject<HTMLFormElement | null>\n method: 'post'\n 'aria-busy': boolean\n onSubmit: (event: FormEvent<HTMLFormElement>) => void\n onFocusCapture: () => void\n}\n\n/** Spread onto the submit button: disabled until hydration, while sending or preparing photos. */\nexport interface BrandlabContactSubmitProps {\n type: 'submit'\n disabled: boolean\n}\n\nexport interface UseBrandlabContactFormResult {\n /** The `formId` option, or `contact-form` when none was given. */\n formId: string\n formProps: BrandlabContactFormProps\n submitProps: BrandlabContactSubmitProps\n /** False during server rendering and hydration. */\n hydrated: boolean\n /** The submit button's `disabled` (also in submitProps): until hydration, while sending or preparing photos. */\n submitDisabled: boolean\n pending: boolean\n phase: ContactSubmissionPhase\n result: ContactActionResult | undefined\n /** An accepted enquiry (a silently accepted spam-protected submission looks the same). */\n succeeded: boolean\n /** A retryable failure: retry(), or submitting the same fields again, reuses its submission ID. */\n canRetry: boolean\n fieldErrors: Readonly<Record<string, readonly string[]>>\n fieldError(name: string): string | undefined\n /** Id for a field's error message element: `${formId}-${name}-error`. */\n errorId(name: string): string\n /** Attach to the status element; it receives focus when an error has no invalid field. */\n statusRef: RefObject<HTMLElement | null>\n /** Resends the failed enquiry with the same submission ID. */\n retry(): Promise<ContactActionResult | undefined>\n attachments: UseBrandlabContactAttachmentsResult\n /** Contract field keys accepted by contactFieldProps. */\n fieldNames: ReadonlySet<string>\n}\n\nconst INITIAL_STATE: ContactSubmissionState = {\n phase: 'idle',\n pending: false,\n canRetry: false,\n}\nconst DEFAULT_REDIRECT_DELAY_MS = 1_500\nconst FOCUSABLE_INVALID_FIELD = [\n 'input[aria-invalid=\"true\"]:not([disabled]):not([type=\"hidden\"])',\n 'select[aria-invalid=\"true\"]:not([disabled])',\n 'textarea[aria-invalid=\"true\"]:not([disabled])',\n 'button[aria-invalid=\"true\"]:not([disabled])',\n '[aria-invalid=\"true\"][tabindex]:not([aria-disabled=\"true\"])',\n].join(',')\n\nconst subscribeToNothing = () => () => undefined\nconst getClientSnapshot = () => true\nconst getServerSnapshot = () => false\n\n/** React `useId()` values: `_R_1a_`/`_r_1a_` (19.2), `«r1a»` (19.0 and 19.1), `:r1a:` (18). */\nconst REACT_ID = /_[rR]_[0-9A-Za-z]*_|«[rR][0-9A-Za-z]*»|:[rR][0-9A-Za-z]*:/g\n\n/**\n * The lead diagnostics' form_id for any formId. A valid slug is kept (trimmed and\n * lowercased). Otherwise React `useId()` parts are removed, so an id made unique for\n * the page still reports as one stable form, every run of other characters becomes\n * one hyphen, and the result is at most 80 characters; `contact-form` when nothing\n * is left. Without this, a formId such as `contact-form-_R_5e35f9db_` silently\n * dropped lead_form_start and lead_form_error.\n */\nexport function contactFormSlug(formId: string): string {\n const slug = safeSlug(String(formId))\n if (slug) return slug\n const derived = String(formId)\n .replace(REACT_ID, '-')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+/, '')\n .slice(0, 80)\n .replace(/-+$/, '')\n return derived || 'contact-form'\n}\n\nfunction safePagePath(pagePath: string) {\n try {\n return normalizeBrandlabRoutePath(pagePath.split(/[?#]/, 1)[0] || '/')\n } catch {\n return '/'\n }\n}\n\nfunction errorStage(result: BrandlabContactFailedResult): LeadFormErrorStage {\n return result.code === 'validation' ? 'validation' : 'delivery'\n}\n\nfunction assertLifecycleOptions(options: UseBrandlabContactFormOptions) {\n const delay = options.redirectDelayMs\n if (delay !== undefined && (!Number.isInteger(delay) || delay < 0 || delay > 60_000)) {\n throw new TypeError('redirectDelayMs must be a whole number of milliseconds from 0 to 60000.')\n }\n if (options.silentAcceptance !== undefined && !['complete', 'ignore'].includes(options.silentAcceptance)) {\n throw new TypeError('silentAcceptance must be \"complete\" or \"ignore\".')\n }\n if (options.analytics !== undefined && !leadBindingFor(options.analytics)) {\n throw new TypeError('analytics must be the binding returned by defineBrandlabAnalytics.')\n }\n}\n\n/**\n * Contact form behaviour for project-owned markup and copy. The form posts\n * through fetch with FormData; before hydration the submit button stays\n * disabled. Typed values (uncontrolled fields) and prepared photos are kept\n * after any failure, retry() and an unchanged resubmission reuse the same\n * submission ID (so a resend cannot duplicate the email), the first invalid\n * field is focused, and an accepted enquiry resets the form and redirects.\n * The lead is reported exactly as the site's defineBrandlabAnalytics binding\n * declares, once per accepted enquiry. Browser validation is left exactly as\n * the form's own markup declares it.\n */\nexport function useBrandlabContactForm(options: UseBrandlabContactFormOptions): UseBrandlabContactFormResult {\n const contract = useMemo(() => defineContactContract(options.contract), [options.contract])\n assertLifecycleOptions(options)\n const hydrated = useSyncExternalStore(subscribeToNothing, getClientSnapshot, getServerSnapshot)\n const formId = options.formId ?? 'contact-form'\n const diagnosticsFormId = contactFormSlug(formId)\n const rawPagePath = options.pagePath\n const pagePath = safePagePath(rawPagePath)\n const formRef = useRef<HTMLFormElement>(null)\n const statusRef = useRef<HTMLElement>(null)\n const [state, setState] = useState<ContactSubmissionState>(INITIAL_STATE)\n const lockRef = useRef(false)\n const startedRef = useRef(false)\n const redirectTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const latest = useRef(options)\n latest.current = options\n\n const policy = options.attachments?.policy ??\n (contract.attachments.mode === 'images-and-pdfs-optional'\n ? DOCUMENT_CONTACT_ATTACHMENT_POLICY\n : DEFAULT_CONTACT_ATTACHMENT_POLICY)\n const attachments = useBrandlabContactAttachments({ ...options.attachments, policy })\n const attachmentPrefix = options.attachmentFieldPrefix ?? 'attachments'\n\n const fieldNames = useMemo(() => new Set(contract.fields.map((field) => field.key)), [contract])\n const roles = useMemo(\n () => ({ fields: contract.fields.map((field) => ({ name: field.key, role: field.role })) }),\n [contract],\n )\n const { analytics, pageLabel, contactEndpoint, fetcher, adUserDataConsent } = options\n const controller = useMemo(() => {\n const lead = leadBindingFor(analytics)\n return createContactHttpSubmissionController({\n pagePath,\n ...(pageLabel ? { pageLabel } : {}),\n ...(contactEndpoint ? { contactEndpoint } : {}),\n ...(fetcher ? { fetcher } : {}),\n ...(lead\n ? {\n reportAccepted: (result, formData) => {\n reportAcceptedLead(lead, result, {\n pagePath: rawPagePath,\n formData,\n fieldRoles: roles,\n adUserDataConsent: adUserDataConsent === true,\n })\n },\n }\n : {}),\n onStateChange: setState,\n })\n }, [adUserDataConsent, analytics, contactEndpoint, fetcher, pageLabel, pagePath, rawPagePath, roles])\n\n useEffect(() => () => clearTimeout(redirectTimerRef.current), [])\n\n useEffect(() => {\n if (state.phase !== 'error') return\n const invalid = formRef.current?.querySelector<HTMLElement>(FOCUSABLE_INVALID_FIELD)\n ;(invalid ?? statusRef.current)?.focus()\n }, [state])\n\n const trackStart = useCallback(() => {\n if (startedRef.current) return\n startedRef.current = true\n latest.current.analytics?.trackLeadFormStart({ pagePath: rawPagePath, formId: diagnosticsFormId })\n }, [diagnosticsFormId, rawPagePath])\n\n const handleResult = useCallback(\n (result: ContactActionResult) => {\n const current = latest.current\n current.onSettled?.(result)\n if (!result.ok) {\n current.analytics?.trackLeadFormError({\n pagePath: rawPagePath,\n formId: diagnosticsFormId,\n stage: errorStage(result),\n errorCount: result.code === 'validation'\n ? Math.min(50, Math.max(1, Object.keys(result.fieldErrors ?? {}).length))\n : 1,\n })\n current.onFailed?.(result)\n return\n }\n if (!result.accepted && current.silentAcceptance === 'ignore') return\n formRef.current?.reset()\n attachments.clearImages()\n current.onAccepted?.(result)\n const redirectTo = current.redirectTo\n if (!redirectTo) return\n const navigate = current.navigate ?? ((href: string) => window.location.assign(href))\n const delay = current.redirectDelayMs ?? DEFAULT_REDIRECT_DELAY_MS\n clearTimeout(redirectTimerRef.current)\n if (delay === 0) {\n navigate(redirectTo)\n return\n }\n redirectTimerRef.current = setTimeout(() => navigate(redirectTo), delay)\n },\n [attachments, diagnosticsFormId, rawPagePath],\n )\n\n const send = useCallback(\n async (attempt: () => Promise<ContactActionResult>) => {\n lockRef.current = true\n try {\n const result = await attempt()\n handleResult(result)\n return result\n } finally {\n lockRef.current = false\n }\n },\n [handleResult],\n )\n\n const onSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n if (lockRef.current || attachments.isProcessing) return\n const form = event.currentTarget\n const formData = new FormData(form)\n if (latest.current.onSubmitStart?.({ form, formData }) === false) return\n trackStart()\n attachments.clearErrorMessage()\n attachments.images.forEach((image, index) => {\n formData.append(`${attachmentPrefix}[${index}]`, image.file)\n })\n // The controller reports every failure as a result; nothing is left to handle here.\n send(() => controller.submit(formData)).catch(() => undefined)\n },\n [attachmentPrefix, attachments, controller, send, trackStart],\n )\n\n const retry = useCallback(async () => {\n if (lockRef.current || !controller.getState().canRetry) return undefined\n return send(() => controller.retry())\n }, [controller, send])\n\n const fieldErrors = state.result && !state.result.ok && state.result.code === 'validation'\n ? state.result.fieldErrors ?? {}\n : {}\n\n const submitDisabled = !hydrated || state.pending || attachments.isProcessing\n return {\n formId,\n formProps: {\n ...(options.formId ? { id: options.formId } : {}),\n ref: formRef,\n method: 'post',\n 'aria-busy': state.pending || attachments.isProcessing,\n onSubmit,\n onFocusCapture: trackStart,\n },\n submitProps: { type: 'submit', disabled: submitDisabled },\n hydrated,\n submitDisabled,\n pending: state.pending,\n phase: state.phase,\n result: state.result,\n succeeded: state.result?.ok === true,\n canRetry: state.canRetry,\n fieldErrors,\n fieldError: (name: string) => fieldErrors[name]?.[0],\n errorId: (name: string) => `${formId}-${name}-error`,\n statusRef,\n retry,\n attachments,\n fieldNames,\n }\n}\n\nexport interface ContactFieldPropsOptions {\n /** Ids of help text already describing the field; the error id is appended. */\n describedBy?: string\n /** Defaults to disabled while an enquiry is sending. */\n disabled?: boolean\n}\n\n/**\n * Props for one uncontrolled contract field: name, disabled while sending and\n * the error relationship. It never adds value, required or length attributes,\n * so the form's existing validation is unchanged.\n */\nexport function contactFieldProps(\n form: UseBrandlabContactFormResult,\n name: string,\n options: ContactFieldPropsOptions = {},\n) {\n if (!form.fieldNames.has(name)) {\n throw new Error(`\"${name}\" is not a field in the contact contract.`)\n }\n const error = form.fieldError(name)\n const describedBy = [options.describedBy, error ? form.errorId(name) : undefined]\n .filter(Boolean)\n .join(' ')\n return {\n name,\n disabled: options.disabled ?? form.pending,\n 'aria-invalid': error ? (true as const) : undefined,\n 'aria-describedby': describedBy || undefined,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"form-client.js","sourceRoot":"","sources":["../../src/contact/form-client.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n DOCUMENT_CONTACT_ATTACHMENT_POLICY,\n defineContactContract,\n type BrandlabContactContract,\n type ContactActionResult,\n} from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport {\n useCallback,\n useEffect,\n useMemo,\n useRef,\n useState,\n useSyncExternalStore,\n type FormEvent,\n type RefObject,\n} from 'react'\nimport type { BrandlabAnalytics, LeadFormErrorStage } from '../analytics.js'\nimport { leadBindingFor, safeSlug } from '../lead-registry.js'\nimport { reportAcceptedLead } from '../lead-reporting.js'\nimport {\n useBrandlabContactAttachments,\n type UseBrandlabContactAttachmentsOptions,\n type UseBrandlabContactAttachmentsResult,\n} from './attachments-client.js'\nimport {\n createContactHttpSubmissionController,\n type ContactSubmissionPhase,\n type ContactSubmissionState,\n} from './client.js'\n\n/** An accepted enquiry, or a silently accepted spam-protected submission (`accepted: false`). */\nexport type BrandlabContactAcceptedResult = Extract<ContactActionResult, { ok: true }>\nexport type BrandlabContactFailedResult = Extract<ContactActionResult, { ok: false }>\n\nexport interface BrandlabContactSubmitStart {\n form: HTMLFormElement\n /**\n * The fields about to be sent, read from the form. Add or replace entries\n * here (for example `service_interest`); prepared photos are appended after.\n */\n formData: FormData\n}\n\nexport interface UseBrandlabContactFormOptions {\n /** The contact contract from src/config/contact.ts. */\n contract: BrandlabContactContract\n /** The site's defineBrandlabAnalytics binding: the declared lead after each accepted enquiry, plus lead diagnostics. */\n analytics?: BrandlabAnalytics\n /** The current pathname, for example `usePathname()`. */\n pagePath: string\n /** Reviewed label for the enquiry email's page row. */\n pageLabel?: string\n /**\n * The form element's id and the lead diagnostics' form_id. Without it the form\n * gets no id (the hook never takes a React id, so the form's own ids are\n * unchanged), diagnostics use `contact-form` and error ids start `contact-form-`.\n * The element keeps the id exactly as given; diagnostics report it as a slug\n * (React `useId()` parts removed, see `contactFormSlug`).\n */\n formId?: string\n /** Page to open after an accepted enquiry; `null` or omitted keeps the visitor on the page. */\n redirectTo?: string | null\n /** Client navigation such as `router.push`; defaults to `window.location.assign`. */\n navigate?: (href: string) => void\n /** Delay before the redirect, in milliseconds (default 1500); 0 navigates at once. */\n redirectDelayMs?: number\n /**\n * Runs when the visitor submits, before anything is sent: clear the form's\n * own notices, adjust `formData`, or return `false` to cancel (for example\n * after `form.reportValidity()`). An unchanged resubmission runs it too;\n * `retry()` does not.\n */\n onSubmitStart?: (submission: BrandlabContactSubmitStart) => void | false\n /**\n * Runs after every attempt, before onAccepted or onFailed: an accepted\n * enquiry, a silently accepted submission (even when ignored) or a failure.\n */\n onSettled?: (result: ContactActionResult) => void\n /** Runs after an accepted enquiry, once the form has been reset and before any redirect. */\n onAccepted?: (result: BrandlabContactAcceptedResult) => void\n /** Runs after a failed attempt; typed values and prepared photos are kept. */\n onFailed?: (result: BrandlabContactFailedResult) => void\n /**\n * A silently accepted submission (spam protection): `complete` (default)\n * resets, runs onAccepted and redirects like an accepted enquiry; `ignore`\n * leaves the form as it is and runs only onSettled.\n */\n silentAcceptance?: 'complete' | 'ignore'\n /** Photo preparation options; the policy follows the contract's attachment mode by default. */\n attachments?: UseBrandlabContactAttachmentsOptions\n /** Multipart field prefix for prepared files (default `attachments`, sent as `attachments[0]` …). */\n attachmentFieldPrefix?: string\n /** Live Consent Mode decision for ad_user_data; without it Enhanced Conversions stay off, unless the analytics contract's mode is `disclosed`. */\n adUserDataConsent?: boolean\n contactEndpoint?: string\n fetcher?: typeof fetch\n}\n\n/**\n * Spread onto the `<form>`: `method=\"post\"` with no `action` or `encType`, so a\n * submission before hydration posts back to the page and never puts fields in\n * a URL; the hook submits through fetch. `id` only when `formId` is given.\n */\nexport interface BrandlabContactFormProps {\n id?: string\n ref: RefObject<HTMLFormElement | null>\n method: 'post'\n 'aria-busy': boolean\n onSubmit: (event: FormEvent<HTMLFormElement>) => void\n onFocusCapture: () => void\n}\n\n/** Spread onto the submit button: disabled until hydration, while sending or preparing photos. */\nexport interface BrandlabContactSubmitProps {\n type: 'submit'\n disabled: boolean\n}\n\nexport interface UseBrandlabContactFormResult {\n /** The `formId` option, or `contact-form` when none was given. */\n formId: string\n formProps: BrandlabContactFormProps\n submitProps: BrandlabContactSubmitProps\n /** False during server rendering and hydration. */\n hydrated: boolean\n /** The submit button's `disabled` (also in submitProps): until hydration, while sending or preparing photos. */\n submitDisabled: boolean\n pending: boolean\n phase: ContactSubmissionPhase\n result: ContactActionResult | undefined\n /** An accepted enquiry (a silently accepted spam-protected submission looks the same). */\n succeeded: boolean\n /** A retryable failure: retry(), or submitting the same fields again, reuses its submission ID. */\n canRetry: boolean\n fieldErrors: Readonly<Record<string, readonly string[]>>\n fieldError(name: string): string | undefined\n /** Id for a field's error message element: `${formId}-${name}-error`. */\n errorId(name: string): string\n /** Attach to the status element; it receives focus when an error has no invalid field. */\n statusRef: RefObject<HTMLElement | null>\n /** Resends the failed enquiry with the same submission ID. */\n retry(): Promise<ContactActionResult | undefined>\n attachments: UseBrandlabContactAttachmentsResult\n /** Contract field keys accepted by contactFieldProps. */\n fieldNames: ReadonlySet<string>\n}\n\nconst INITIAL_STATE: ContactSubmissionState = {\n phase: 'idle',\n pending: false,\n canRetry: false,\n}\nconst DEFAULT_REDIRECT_DELAY_MS = 1_500\nconst FOCUSABLE_INVALID_FIELD = [\n 'input[aria-invalid=\"true\"]:not([disabled]):not([type=\"hidden\"])',\n 'select[aria-invalid=\"true\"]:not([disabled])',\n 'textarea[aria-invalid=\"true\"]:not([disabled])',\n 'button[aria-invalid=\"true\"]:not([disabled])',\n '[aria-invalid=\"true\"][tabindex]:not([aria-disabled=\"true\"])',\n].join(',')\n\nconst subscribeToNothing = () => () => undefined\nconst getClientSnapshot = () => true\nconst getServerSnapshot = () => false\n\n/** React `useId()` values: `_R_1a_`/`_r_1a_` (19.2), `«r1a»` (19.0 and 19.1), `:r1a:` (18). */\nconst REACT_ID = /_[rR]_[0-9A-Za-z]*_|«[rR][0-9A-Za-z]*»|:[rR][0-9A-Za-z]*:/g\n\n/**\n * The lead diagnostics' form_id for any formId. A valid slug is kept (trimmed and\n * lowercased). Otherwise React `useId()` parts are removed, so an id made unique for\n * the page still reports as one stable form, every run of other characters becomes\n * one hyphen, and the result is at most 80 characters; `contact-form` when nothing\n * is left. Without this, a formId such as `contact-form-_R_5e35f9db_` silently\n * dropped lead_form_start and lead_form_error.\n */\nexport function contactFormSlug(formId: string): string {\n const slug = safeSlug(String(formId))\n if (slug) return slug\n const derived = String(formId)\n .replace(REACT_ID, '-')\n .toLowerCase()\n .replace(/[^a-z0-9]+/g, '-')\n .replace(/^-+/, '')\n .slice(0, 80)\n .replace(/-+$/, '')\n return derived || 'contact-form'\n}\n\nfunction safePagePath(pagePath: string) {\n try {\n return normalizeBrandlabRoutePath(pagePath.split(/[?#]/, 1)[0] || '/')\n } catch {\n return '/'\n }\n}\n\nfunction errorStage(result: BrandlabContactFailedResult): LeadFormErrorStage {\n return result.code === 'validation' ? 'validation' : 'delivery'\n}\n\nfunction assertLifecycleOptions(options: UseBrandlabContactFormOptions) {\n const delay = options.redirectDelayMs\n if (delay !== undefined && (!Number.isInteger(delay) || delay < 0 || delay > 60_000)) {\n throw new TypeError('redirectDelayMs must be a whole number of milliseconds from 0 to 60000.')\n }\n if (options.silentAcceptance !== undefined && !['complete', 'ignore'].includes(options.silentAcceptance)) {\n throw new TypeError('silentAcceptance must be \"complete\" or \"ignore\".')\n }\n if (options.analytics !== undefined && !leadBindingFor(options.analytics)) {\n throw new TypeError('analytics must be the binding returned by defineBrandlabAnalytics.')\n }\n}\n\n/**\n * Contact form behaviour for project-owned markup and copy. The form posts\n * through fetch with FormData; before hydration the submit button stays\n * disabled. Typed values (uncontrolled fields) and prepared photos are kept\n * after any failure, retry() and an unchanged resubmission reuse the same\n * submission ID (so a resend cannot duplicate the email), the first invalid\n * field is focused, and an accepted enquiry resets the form and redirects.\n * The lead is reported exactly as the site's defineBrandlabAnalytics binding\n * declares, once per accepted enquiry. Browser validation is left exactly as\n * the form's own markup declares it.\n */\nexport function useBrandlabContactForm(options: UseBrandlabContactFormOptions): UseBrandlabContactFormResult {\n const contract = useMemo(() => defineContactContract(options.contract), [options.contract])\n assertLifecycleOptions(options)\n const hydrated = useSyncExternalStore(subscribeToNothing, getClientSnapshot, getServerSnapshot)\n const formId = options.formId ?? 'contact-form'\n const diagnosticsFormId = contactFormSlug(formId)\n const rawPagePath = options.pagePath\n const pagePath = safePagePath(rawPagePath)\n const formRef = useRef<HTMLFormElement>(null)\n const statusRef = useRef<HTMLElement>(null)\n const [state, setState] = useState<ContactSubmissionState>(INITIAL_STATE)\n const lockRef = useRef(false)\n const startedRef = useRef(false)\n const redirectTimerRef = useRef<ReturnType<typeof setTimeout> | undefined>(undefined)\n const latest = useRef(options)\n latest.current = options\n\n const policy = options.attachments?.policy ??\n (contract.attachments.mode === 'images-and-pdfs-optional'\n ? DOCUMENT_CONTACT_ATTACHMENT_POLICY\n : DEFAULT_CONTACT_ATTACHMENT_POLICY)\n const attachments = useBrandlabContactAttachments({ ...options.attachments, policy })\n const attachmentPrefix = options.attachmentFieldPrefix ?? 'attachments'\n\n const fieldNames = useMemo(() => new Set(contract.fields.map((field) => field.key)), [contract])\n const roles = useMemo(\n () => ({ fields: contract.fields.map((field) => ({ name: field.key, role: field.role })) }),\n [contract],\n )\n const { analytics, pageLabel, contactEndpoint, fetcher, adUserDataConsent } = options\n const controller = useMemo(() => {\n const lead = leadBindingFor(analytics)\n return createContactHttpSubmissionController({\n pagePath,\n ...(pageLabel ? { pageLabel } : {}),\n ...(contactEndpoint ? { contactEndpoint } : {}),\n ...(fetcher ? { fetcher } : {}),\n ...(lead\n ? {\n reportAccepted: (result, formData) => {\n reportAcceptedLead(lead, result, {\n pagePath: rawPagePath,\n formData,\n fieldRoles: roles,\n ...(adUserDataConsent !== undefined ? { adUserDataConsent } : {}),\n })\n },\n }\n : {}),\n onStateChange: setState,\n })\n }, [adUserDataConsent, analytics, contactEndpoint, fetcher, pageLabel, pagePath, rawPagePath, roles])\n\n useEffect(() => () => clearTimeout(redirectTimerRef.current), [])\n\n useEffect(() => {\n if (state.phase !== 'error') return\n const invalid = formRef.current?.querySelector<HTMLElement>(FOCUSABLE_INVALID_FIELD)\n ;(invalid ?? statusRef.current)?.focus()\n }, [state])\n\n const trackStart = useCallback(() => {\n if (startedRef.current) return\n startedRef.current = true\n latest.current.analytics?.trackLeadFormStart({ pagePath: rawPagePath, formId: diagnosticsFormId })\n }, [diagnosticsFormId, rawPagePath])\n\n const handleResult = useCallback(\n (result: ContactActionResult) => {\n const current = latest.current\n current.onSettled?.(result)\n if (!result.ok) {\n current.analytics?.trackLeadFormError({\n pagePath: rawPagePath,\n formId: diagnosticsFormId,\n stage: errorStage(result),\n errorCount: result.code === 'validation'\n ? Math.min(50, Math.max(1, Object.keys(result.fieldErrors ?? {}).length))\n : 1,\n })\n current.onFailed?.(result)\n return\n }\n if (!result.accepted && current.silentAcceptance === 'ignore') return\n formRef.current?.reset()\n attachments.clearImages()\n current.onAccepted?.(result)\n const redirectTo = current.redirectTo\n if (!redirectTo) return\n const navigate = current.navigate ?? ((href: string) => window.location.assign(href))\n const delay = current.redirectDelayMs ?? DEFAULT_REDIRECT_DELAY_MS\n clearTimeout(redirectTimerRef.current)\n if (delay === 0) {\n navigate(redirectTo)\n return\n }\n redirectTimerRef.current = setTimeout(() => navigate(redirectTo), delay)\n },\n [attachments, diagnosticsFormId, rawPagePath],\n )\n\n const send = useCallback(\n async (attempt: () => Promise<ContactActionResult>) => {\n lockRef.current = true\n try {\n const result = await attempt()\n handleResult(result)\n return result\n } finally {\n lockRef.current = false\n }\n },\n [handleResult],\n )\n\n const onSubmit = useCallback(\n (event: FormEvent<HTMLFormElement>) => {\n event.preventDefault()\n if (lockRef.current || attachments.isProcessing) return\n const form = event.currentTarget\n const formData = new FormData(form)\n if (latest.current.onSubmitStart?.({ form, formData }) === false) return\n trackStart()\n attachments.clearErrorMessage()\n attachments.images.forEach((image, index) => {\n formData.append(`${attachmentPrefix}[${index}]`, image.file)\n })\n // The controller reports every failure as a result; nothing is left to handle here.\n send(() => controller.submit(formData)).catch(() => undefined)\n },\n [attachmentPrefix, attachments, controller, send, trackStart],\n )\n\n const retry = useCallback(async () => {\n if (lockRef.current || !controller.getState().canRetry) return undefined\n return send(() => controller.retry())\n }, [controller, send])\n\n const fieldErrors = state.result && !state.result.ok && state.result.code === 'validation'\n ? state.result.fieldErrors ?? {}\n : {}\n\n const submitDisabled = !hydrated || state.pending || attachments.isProcessing\n return {\n formId,\n formProps: {\n ...(options.formId ? { id: options.formId } : {}),\n ref: formRef,\n method: 'post',\n 'aria-busy': state.pending || attachments.isProcessing,\n onSubmit,\n onFocusCapture: trackStart,\n },\n submitProps: { type: 'submit', disabled: submitDisabled },\n hydrated,\n submitDisabled,\n pending: state.pending,\n phase: state.phase,\n result: state.result,\n succeeded: state.result?.ok === true,\n canRetry: state.canRetry,\n fieldErrors,\n fieldError: (name: string) => fieldErrors[name]?.[0],\n errorId: (name: string) => `${formId}-${name}-error`,\n statusRef,\n retry,\n attachments,\n fieldNames,\n }\n}\n\nexport interface ContactFieldPropsOptions {\n /** Ids of help text already describing the field; the error id is appended. */\n describedBy?: string\n /** Defaults to disabled while an enquiry is sending. */\n disabled?: boolean\n}\n\n/**\n * Props for one uncontrolled contract field: name, disabled while sending and\n * the error relationship. It never adds value, required or length attributes,\n * so the form's existing validation is unchanged.\n */\nexport function contactFieldProps(\n form: UseBrandlabContactFormResult,\n name: string,\n options: ContactFieldPropsOptions = {},\n) {\n if (!form.fieldNames.has(name)) {\n throw new Error(`\"${name}\" is not a field in the contact contract.`)\n }\n const error = form.fieldError(name)\n const describedBy = [options.describedBy, error ? form.errorId(name) : undefined]\n .filter(Boolean)\n .join(' ')\n return {\n name,\n disabled: options.disabled ?? form.pending,\n 'aria-invalid': error ? (true as const) : undefined,\n 'aria-describedby': describedBy || undefined,\n }\n}\n"]}
|
package/dist/contact/resend.d.ts
CHANGED
|
@@ -1,6 +1,22 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
2
|
import { type BrandlabContactContract } from '@brandlab-digital/site-core/contact';
|
|
3
|
-
import { type ContactTransport } from './shared.js';
|
|
3
|
+
import { type ContactDeliveryMessage, type ContactTransport, type ContactTransportResult } from './shared.js';
|
|
4
|
+
/** A send's result as the shared transport reports it: a failure also names what the delivery-failure log may say. */
|
|
5
|
+
export type ResendContactTransportResult = Extract<ContactTransportResult, {
|
|
6
|
+
ok: true;
|
|
7
|
+
}> | (Extract<ContactTransportResult, {
|
|
8
|
+
ok: false;
|
|
9
|
+
}> & {
|
|
10
|
+
/** Resend's documented error name, when it gave one. */
|
|
11
|
+
providerCode?: string;
|
|
12
|
+
/** Resend's HTTP status, when it gave one. */
|
|
13
|
+
status?: number;
|
|
14
|
+
});
|
|
15
|
+
/** The shared Resend transport (internal): a ContactTransport that names itself for the delivery-failure log. */
|
|
16
|
+
export interface ResendContactTransport extends ContactTransport {
|
|
17
|
+
provider: 'resend';
|
|
18
|
+
send(message: ContactDeliveryMessage): Promise<ResendContactTransportResult>;
|
|
19
|
+
}
|
|
4
20
|
export interface ResendContactPayload {
|
|
5
21
|
from: string;
|
|
6
22
|
to: readonly string[];
|
|
@@ -52,7 +68,13 @@ export declare function createResendSdkContactSend(client: ResendSdkContactClien
|
|
|
52
68
|
* underscore, so `_26_` is a reversible, collision-free transport encoding.
|
|
53
69
|
*/
|
|
54
70
|
export declare function encodeBrandlabEntityIdForResendTag(projectId: string): string;
|
|
55
|
-
|
|
71
|
+
/**
|
|
72
|
+
* Resend's documented error names (`RESEND_ERROR_CODE_KEY` in resend 6): the only
|
|
73
|
+
* provider text the delivery-failure log may carry. A returned error's message can
|
|
74
|
+
* quote submitted values, so it is never read.
|
|
75
|
+
*/
|
|
76
|
+
export declare const RESEND_ERROR_CODES: ReadonlySet<string>;
|
|
77
|
+
export declare function createResendContactTransport(options: ResendContactTransportOptions): ResendContactTransport;
|
|
56
78
|
/** Resolves the recipient env and reviewed non-secret sender from Contact Contract v4. */
|
|
57
|
-
export declare function createContractResendContactTransport(options: ContractResendContactTransportOptions):
|
|
79
|
+
export declare function createContractResendContactTransport(options: ContractResendContactTransportOptions): ResendContactTransport;
|
|
58
80
|
//# sourceMappingURL=resend.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/contact/resend.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qCAAqC,CAAA;AAE5C,OAAO,EAGL,KAAK,gBAAgB,
|
|
1
|
+
{"version":3,"file":"resend.d.ts","sourceRoot":"","sources":["../../src/contact/resend.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAGpB,OAAO,EAGL,KAAK,uBAAuB,EAC7B,MAAM,qCAAqC,CAAA;AAE5C,OAAO,EAGL,KAAK,sBAAsB,EAC3B,KAAK,gBAAgB,EACrB,KAAK,sBAAsB,EAC5B,MAAM,aAAa,CAAA;AAEpB,sHAAsH;AACtH,MAAM,MAAM,4BAA4B,GACpC,OAAO,CAAC,sBAAsB,EAAE;IAAE,EAAE,EAAE,IAAI,CAAA;CAAE,CAAC,GAC7C,CAAC,OAAO,CAAC,sBAAsB,EAAE;IAAE,EAAE,EAAE,KAAK,CAAA;CAAE,CAAC,GAAG;IAChD,wDAAwD;IACxD,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,8CAA8C;IAC9C,MAAM,CAAC,EAAE,MAAM,CAAA;CAChB,CAAC,CAAA;AAEN,iHAAiH;AACjH,MAAM,WAAW,sBAAuB,SAAQ,gBAAgB;IAC9D,QAAQ,EAAE,QAAQ,CAAA;IAClB,IAAI,CAAC,OAAO,EAAE,sBAAsB,GAAG,OAAO,CAAC,4BAA4B,CAAC,CAAA;CAC7E;AAKD,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;IACrB,OAAO,EAAE,MAAM,CAAA;IACf,IAAI,EAAE,MAAM,CAAA;IACZ,IAAI,EAAE,MAAM,CAAA;IACZ,OAAO,CAAC,EAAE,MAAM,CAAA;IAChB,WAAW,EAAE,SAAS;QACpB,QAAQ,EAAE,MAAM,CAAA;QAChB,OAAO,EAAE,UAAU,CAAA;QACnB,WAAW,EAAE,MAAM,CAAA;KACpB,EAAE,CAAA;IACH,IAAI,EAAE,SAAS;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,MAAM,CAAA;KAAE,EAAE,CAAA;CACjD;AAED,MAAM,WAAW,wBAAwB;IACvC,cAAc,EAAE,MAAM,CAAA;CACvB;AAED,MAAM,MAAM,iBAAiB,GAAG,CAC9B,OAAO,EAAE,oBAAoB,EAC7B,OAAO,EAAE,wBAAwB,KAC9B,OAAO,CAAC;IACX,IAAI,CAAC,EAAE;QAAE,EAAE,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;KAAE,GAAG,IAAI,CAAA;IACpC,KAAK,CAAC,EAAE,OAAO,CAAA;CAChB,CAAC,CAAA;AAEF,MAAM,WAAW,sBAAsB;IACrC,MAAM,EAAE,MAAM,CAAA;CACf;AAED,MAAM,WAAW,6BAA6B;IAC5C,IAAI,EAAE,MAAM,CAAA;IACZ,EAAE,EAAE,SAAS,MAAM,EAAE,CAAA;IACrB,iGAAiG;IACjG,IAAI,EAAE,iBAAiB,CAAA;CACxB;AAED,MAAM,WAAW,qCAAqC;IACpD,QAAQ,EAAE,uBAAuB,CAAA;IACjC,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IACzD,IAAI,EAAE,iBAAiB,CAAA;CACxB;AAED;;;;GAIG;AACH,wBAAgB,0BAA0B,CACxC,MAAM,EAAE,sBAAsB,GAC7B,iBAAiB,CA+CnB;AAED;;;GAGG;AACH,wBAAgB,kCAAkC,CAAC,SAAS,EAAE,MAAM,UASnE;AAgBD;;;;GAIG;AACH,eAAO,MAAM,kBAAkB,EAAE,WAAW,CAAC,MAAM,CAsBjD,CAAA;AAyDF,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,sBAAsB,CAqExB;AAED,0FAA0F;AAC1F,wBAAgB,oCAAoC,CAClD,OAAO,EAAE,qCAAqC,GAC7C,sBAAsB,CASxB"}
|
package/dist/contact/resend.js
CHANGED
|
@@ -60,16 +60,60 @@ function isSafeMailboxValue(value) {
|
|
|
60
60
|
display[2] &&
|
|
61
61
|
MAILBOX_ADDRESS_PATTERN.test(display[2].trim()));
|
|
62
62
|
}
|
|
63
|
+
/**
|
|
64
|
+
* Resend's documented error names (`RESEND_ERROR_CODE_KEY` in resend 6): the only
|
|
65
|
+
* provider text the delivery-failure log may carry. A returned error's message can
|
|
66
|
+
* quote submitted values, so it is never read.
|
|
67
|
+
*/
|
|
68
|
+
export const RESEND_ERROR_CODES = new Set([
|
|
69
|
+
'invalid_idempotency_key',
|
|
70
|
+
'validation_error',
|
|
71
|
+
'missing_api_key',
|
|
72
|
+
'restricted_api_key',
|
|
73
|
+
'invalid_api_key',
|
|
74
|
+
'not_found',
|
|
75
|
+
'method_not_allowed',
|
|
76
|
+
'invalid_idempotent_request',
|
|
77
|
+
'concurrent_idempotent_requests',
|
|
78
|
+
'invalid_attachment',
|
|
79
|
+
'invalid_from_address',
|
|
80
|
+
'invalid_access',
|
|
81
|
+
'invalid_parameter',
|
|
82
|
+
'invalid_region',
|
|
83
|
+
'missing_required_field',
|
|
84
|
+
'monthly_quota_exceeded',
|
|
85
|
+
'daily_quota_exceeded',
|
|
86
|
+
'rate_limit_exceeded',
|
|
87
|
+
'security_error',
|
|
88
|
+
'application_error',
|
|
89
|
+
'internal_server_error',
|
|
90
|
+
]);
|
|
91
|
+
function resendErrorStatus(error) {
|
|
92
|
+
const candidate = error.statusCode ?? error.status;
|
|
93
|
+
const status = typeof candidate === 'number'
|
|
94
|
+
? candidate
|
|
95
|
+
: typeof candidate === 'string' && /^\d{3}$/.test(candidate)
|
|
96
|
+
? Number(candidate)
|
|
97
|
+
: undefined;
|
|
98
|
+
return status !== undefined && Number.isInteger(status) && status >= 100 && status <= 599 ? status : undefined;
|
|
99
|
+
}
|
|
100
|
+
/** A returned Resend error as the delivery-failure log may name it: its documented name and HTTP status only. */
|
|
101
|
+
function resendErrorDetail(value) {
|
|
102
|
+
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
103
|
+
return {};
|
|
104
|
+
const error = value;
|
|
105
|
+
const name = typeof error.name === 'string' ? error.name.trim().toLowerCase() : '';
|
|
106
|
+
const status = resendErrorStatus(error);
|
|
107
|
+
return {
|
|
108
|
+
...(RESEND_ERROR_CODES.has(name) ? { providerCode: name } : {}),
|
|
109
|
+
...(status !== undefined ? { status } : {}),
|
|
110
|
+
};
|
|
111
|
+
}
|
|
63
112
|
function resendErrorRetryable(value) {
|
|
64
113
|
if (!value || typeof value !== 'object' || Array.isArray(value))
|
|
65
114
|
return true;
|
|
66
115
|
const error = value;
|
|
67
|
-
const
|
|
68
|
-
const status = typeof statusCandidate === 'number'
|
|
69
|
-
? statusCandidate
|
|
70
|
-
: typeof statusCandidate === 'string' && /^\d{3}$/.test(statusCandidate)
|
|
71
|
-
? Number(statusCandidate)
|
|
72
|
-
: undefined;
|
|
116
|
+
const status = resendErrorStatus(error);
|
|
73
117
|
const name = typeof error.name === 'string' ? error.name.trim().toLowerCase() : '';
|
|
74
118
|
if (name === 'concurrent_idempotent_requests' ||
|
|
75
119
|
name === 'rate_limit_exceeded' ||
|
|
@@ -104,19 +148,20 @@ export function createResendContactTransport(options) {
|
|
|
104
148
|
throw new Error('Resend contact transport configuration is invalid.');
|
|
105
149
|
}
|
|
106
150
|
return {
|
|
151
|
+
provider: 'resend',
|
|
107
152
|
async send(message) {
|
|
108
153
|
let providerProjectId;
|
|
109
154
|
try {
|
|
110
155
|
providerProjectId = encodeBrandlabEntityIdForResendTag(message.providerMetadata.project_id);
|
|
111
156
|
}
|
|
112
157
|
catch {
|
|
113
|
-
return { ok: false, code: '
|
|
158
|
+
return { ok: false, code: 'message_refused', retryable: false };
|
|
114
159
|
}
|
|
115
160
|
if (!CONTACT_IDEMPOTENCY_KEY_PATTERN.test(message.idempotencyKey) ||
|
|
116
161
|
!CONTACT_CONFIRMATION_ID_PATTERN.test(message.confirmationId) ||
|
|
117
162
|
message.providerMetadata.submission_hash !== message.confirmationId ||
|
|
118
163
|
(message.replyTo !== undefined && !isSafeMailboxValue(message.replyTo))) {
|
|
119
|
-
return { ok: false, code: '
|
|
164
|
+
return { ok: false, code: 'message_refused', retryable: false };
|
|
120
165
|
}
|
|
121
166
|
try {
|
|
122
167
|
const result = await options.send({
|
|
@@ -141,6 +186,7 @@ export function createResendContactTransport(options) {
|
|
|
141
186
|
ok: false,
|
|
142
187
|
code: 'provider_rejected',
|
|
143
188
|
retryable: resendErrorRetryable(result.error),
|
|
189
|
+
...resendErrorDetail(result.error),
|
|
144
190
|
};
|
|
145
191
|
}
|
|
146
192
|
const providerMessageId = result.data?.id?.trim();
|