@brandlab-digital/site-core 1.3.0 → 1.3.1
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/contact.d.ts +5 -0
- package/dist/contact.d.ts.map +1 -1
- package/dist/contact.js +26 -0
- package/dist/contact.js.map +1 -1
- package/package.json +1 -1
package/dist/contact.d.ts
CHANGED
|
@@ -17,6 +17,11 @@ export declare const DOCUMENT_CONTACT_ATTACHMENT_POLICY: {
|
|
|
17
17
|
readonly maxFileSizeBytes: 4000000;
|
|
18
18
|
readonly maxTotalSizeBytes: 4000000;
|
|
19
19
|
};
|
|
20
|
+
export type ContactTransportAttachmentMimeType = 'application/pdf' | 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif';
|
|
21
|
+
/** Selection stays compatible; HEIC/HEIF must be prepared as JPEG in the browser. */
|
|
22
|
+
export declare function deriveContactAttachmentTransportPolicy(selection?: ContactAttachmentPolicy): ContactAttachmentPolicy;
|
|
23
|
+
/** Positive raw-byte allowlist. No ISO-BMFF/HEIF-family input reaches native decoding. */
|
|
24
|
+
export declare function detectContactTransportAttachmentType(bytes: Uint8Array): ContactTransportAttachmentMimeType | undefined;
|
|
20
25
|
export declare function contactAttachmentAccept(policy?: ContactAttachmentPolicy): string;
|
|
21
26
|
export declare function contactAttachmentTypeLabel(policy?: ContactAttachmentPolicy): string;
|
|
22
27
|
export declare function isAllowedContactAttachmentType(value: string, policy?: ContactAttachmentPolicy): value is ContactAttachmentMimeType;
|
package/dist/contact.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"contact.d.ts","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"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"}
|
package/dist/contact.js
CHANGED
|
@@ -28,6 +28,32 @@ const EXTENSION_TO_MIME = {
|
|
|
28
28
|
heic: 'image/heic',
|
|
29
29
|
heif: 'image/heif',
|
|
30
30
|
};
|
|
31
|
+
/** Selection stays compatible; HEIC/HEIF must be prepared as JPEG in the browser. */
|
|
32
|
+
export function deriveContactAttachmentTransportPolicy(selection = DEFAULT_CONTACT_ATTACHMENT_POLICY) {
|
|
33
|
+
const allowedTypes = selection.allowedTypes.flatMap((type) => {
|
|
34
|
+
if (['image/jpg', 'image/heic', 'image/heif'].includes(type))
|
|
35
|
+
return ['image/jpeg'];
|
|
36
|
+
return ['application/pdf', 'image/jpeg', 'image/png', 'image/webp', 'image/gif'].includes(type)
|
|
37
|
+
? [type] : [];
|
|
38
|
+
});
|
|
39
|
+
return { ...selection, allowedTypes: [...new Set(allowedTypes)] };
|
|
40
|
+
}
|
|
41
|
+
/** Positive raw-byte allowlist. No ISO-BMFF/HEIF-family input reaches native decoding. */
|
|
42
|
+
export function detectContactTransportAttachmentType(bytes) {
|
|
43
|
+
const starts = (signature) => signature.every((byte, index) => bytes[index] === byte);
|
|
44
|
+
const ascii = (start, length) => String.fromCharCode(...bytes.slice(start, start + length));
|
|
45
|
+
if (ascii(0, 5) === '%PDF-')
|
|
46
|
+
return 'application/pdf';
|
|
47
|
+
if (starts([0xff, 0xd8, 0xff]))
|
|
48
|
+
return 'image/jpeg';
|
|
49
|
+
if (starts([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))
|
|
50
|
+
return 'image/png';
|
|
51
|
+
if (['GIF87a', 'GIF89a'].includes(ascii(0, 6)))
|
|
52
|
+
return 'image/gif';
|
|
53
|
+
if (ascii(0, 4) === 'RIFF' && ascii(8, 4) === 'WEBP')
|
|
54
|
+
return 'image/webp';
|
|
55
|
+
return undefined;
|
|
56
|
+
}
|
|
31
57
|
export function contactAttachmentAccept(policy = DEFAULT_CONTACT_ATTACHMENT_POLICY) {
|
|
32
58
|
return [...new Set(policy.allowedTypes)].join(',');
|
|
33
59
|
}
|
package/dist/contact.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contact.js","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"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","sourcesContent":["import { normalizeBrandlabRoutePath } from './routes.js'\nimport { assertBrandlabCanonicalEntityId } from './entity-id.js'\n\nexport interface ContactAttachmentPolicy {\n maxFiles: number\n maxFileSizeBytes: number\n maxTotalSizeBytes: number\n allowedTypes: readonly ContactAttachmentMimeType[]\n}\n\nexport type ContactAttachmentMimeType =\n | 'application/pdf'\n | 'image/jpeg'\n | 'image/jpg'\n | 'image/png'\n | 'image/webp'\n | 'image/gif'\n | 'image/heic'\n | 'image/heif'\n\nexport const DEFAULT_CONTACT_ATTACHMENT_POLICY = {\n maxFiles: 5,\n maxFileSizeBytes: 4_000_000,\n maxTotalSizeBytes: 4_000_000,\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/webp',\n 'image/gif',\n 'image/heic',\n 'image/heif',\n ],\n} as const satisfies ContactAttachmentPolicy\n\nexport const DOCUMENT_CONTACT_ATTACHMENT_POLICY = {\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n allowedTypes: [...DEFAULT_CONTACT_ATTACHMENT_POLICY.allowedTypes, 'application/pdf'],\n} as const satisfies ContactAttachmentPolicy\n\nconst EXTENSION_TO_MIME: Record<string, ContactAttachmentMimeType> = {\n pdf: 'application/pdf',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n heic: 'image/heic',\n heif: 'image/heif',\n}\n\nexport function contactAttachmentAccept(\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n) {\n return [...new Set(policy.allowedTypes)].join(',')\n}\n\nexport function contactAttachmentTypeLabel(\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n) {\n const labels = policy.allowedTypes\n .map((type) => {\n const subtype = type.split('/')[1] ?? type\n if (subtype === 'jpeg' || subtype === 'jpg') return 'JPG'\n if (subtype === 'webp') return 'WebP'\n return subtype.toUpperCase()\n })\n .filter((label, index, labels) => labels.indexOf(label) === index)\n\n if (labels.length <= 1) return labels[0] ?? ''\n return `${labels.slice(0, -1).join(', ')}, or ${labels[labels.length - 1]}`\n}\n\nexport function isAllowedContactAttachmentType(\n value: string,\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n): value is ContactAttachmentMimeType {\n return policy.allowedTypes.includes(value as ContactAttachmentMimeType)\n}\n\nexport function resolveContactAttachmentType(\n filename: string,\n fileType?: string,\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n): ContactAttachmentMimeType | null {\n const normalizedType = fileType?.trim().toLowerCase()\n\n if (normalizedType && isAllowedContactAttachmentType(normalizedType, policy)) {\n return normalizedType\n }\n\n const extension = filename.toLowerCase().split('.').pop()\n if (!extension) return null\n\n const mappedType = EXTENSION_TO_MIME[extension]\n return mappedType && isAllowedContactAttachmentType(mappedType, policy) ? mappedType : null\n}\n\nexport function createContactAttachmentFilename(options: {\n index: number\n contentType?: string\n}) {\n if (options.contentType === 'application/pdf') return `document-${options.index + 1}.pdf`\n return `image-${options.index + 1}.jpg`\n}\n\nexport function validateContactAttachment(\n file: { filename: string; size: number; type?: string },\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n):\n | { ok: true; contentType: ContactAttachmentMimeType }\n | { ok: false; message: string } {\n const contentType = resolveContactAttachmentType(file.filename, file.type, policy)\n\n if (!contentType) {\n return {\n ok: false,\n message: `\"${file.filename}\" is not a supported image type. Please upload ${contactAttachmentTypeLabel(\n policy,\n )} files.`,\n }\n }\n\n if (file.size > policy.maxFileSizeBytes) {\n const maximumMegabytes = Math.round((policy.maxFileSizeBytes / (1024 * 1024)) * 10) / 10\n return {\n ok: false,\n message: `Image \"${file.filename}\" is too large. Maximum size is ${maximumMegabytes} MB per image.`,\n }\n }\n\n return { ok: true, contentType }\n}\n\nexport type AdClickIds = {\n gclid?: string\n gbraid?: string\n wbraid?: string\n gadParams?: Record<string, string>\n}\n\nconst AD_CLICK_ID_FIELDS = [\n ['gclid', 'Google Click ID'],\n ['gbraid', 'GBRAID'],\n ['wbraid', 'WBRAID'],\n] as const\n\nexport function resolveTrackingSearchParams(queryParams: string, pageUrl = '') {\n const trimmedQueryParams = queryParams.trim()\n\n if (trimmedQueryParams) {\n return new URLSearchParams(\n trimmedQueryParams.startsWith('?') ? trimmedQueryParams : `?${trimmedQueryParams}`,\n )\n }\n\n if (pageUrl) {\n try {\n return new URL(pageUrl).searchParams\n } catch {\n return new URLSearchParams()\n }\n }\n\n return new URLSearchParams()\n}\n\nexport function resolveAdClickIds(queryParams: string, pageUrl = ''): AdClickIds {\n const params = resolveTrackingSearchParams(queryParams, pageUrl)\n const clickIds = AD_CLICK_ID_FIELDS.reduce<AdClickIds>((ids, [field]) => {\n const value = params.get(field)?.trim()\n\n if (value) {\n ids[field] = value\n }\n\n return ids\n }, {})\n const gadParams: Record<string, string> = {}\n\n params.forEach((value, key) => {\n const trimmedValue = value.trim()\n const normalizedKey = key.toLowerCase()\n\n if (trimmedValue && (normalizedKey === 'gad_source' || normalizedKey.startsWith('gad_'))) {\n gadParams[key] = trimmedValue\n }\n })\n\n return Object.keys(gadParams).length > 0 ? { ...clickIds, gadParams } : clickIds\n}\n\nexport function hasAdClickIds(adClickIds: AdClickIds) {\n return (\n AD_CLICK_ID_FIELDS.some(([field]) => Boolean(adClickIds[field])) ||\n Object.keys(adClickIds.gadParams ?? {}).length > 0\n )\n}\n\nexport function hasGoogleAdsClickId(queryParams: string, pageUrl = '') {\n return hasAdClickIds(resolveAdClickIds(queryParams, pageUrl))\n}\n\nfunction formatGadLabel(key: string) {\n return key\n .replace(/^gad_/, 'GAD ')\n .replace(/_/g, ' ')\n .replace(/campaignid\\b/i, 'campaign ID')\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase())\n}\n\nexport function getAdClickIdRows(adClickIds: AdClickIds | undefined) {\n if (!adClickIds) return []\n\n const directRows = AD_CLICK_ID_FIELDS.flatMap(([field, label]) => {\n const value = adClickIds[field]\n return value ? [{ field, label, value }] : []\n })\n\n const gadRows = Object.entries(adClickIds.gadParams ?? {})\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([field, value]) => ({\n field,\n label: formatGadLabel(field),\n value,\n }))\n\n return [...directRows, ...gadRows]\n}\n\nexport function formatAdClickIdsForEmailText(adClickIds: AdClickIds) {\n return getAdClickIdRows(adClickIds)\n .map(({ label, value }) => `${label}: ${value}`)\n .join('\\n')\n}\n\nexport function parseContactEmailRecipients(value: string | undefined) {\n const recipients = value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n const unique = recipients.filter((recipient, index) => {\n const address = recipient.match(/<([^<>]+)>$/)?.[1]?.trim() ?? recipient\n return recipients.findIndex((candidate) => {\n const candidateAddress = candidate.match(/<([^<>]+)>$/)?.[1]?.trim() ?? candidate\n return candidateAddress.toLowerCase() === address.toLowerCase()\n }) === index\n })\n if (unique.length > 5) {\n throw new Error('Contact delivery supports no more than five unique recipients.')\n }\n return unique\n}\n\nexport interface ContactFormEmailBaseData {\n name: string\n email: string\n phone: string\n message: string\n submittedAt: string\n submissionId: string\n pageLabel: string\n pagePath: string\n pageUrl: string\n trafficSource?: string\n initialLandingPath?: string\n initialLandingUrl?: string\n adClickIds?: AdClickIds\n attachmentCount?: number\n attachments?: readonly ContactFormEmailAttachmentSummary[]\n}\n\nexport type ContactFormEmailData = ContactFormEmailBaseData &\n ({ suburb: string; location?: string } | { location: string; suburb?: string })\n\nexport interface ContactFormEmailAttachmentSummary {\n filename: string\n contentType?: string\n sizeBytes?: number\n}\n\nexport interface ContactFormEmailRow {\n field: string\n label: string\n value: string\n}\n\nexport interface ContactFormEmailDataIssue {\n field: string\n message: string\n}\n\ntype ContactFormEmailValidationData = Partial<\n ContactFormEmailBaseData & {\n suburb: string\n location: string\n }\n>\n\nconst REQUIRED_CONTACT_FORM_EMAIL_LEAD_FIELDS = [\n 'name',\n 'email',\n 'phone',\n] as const\n\nconst REQUIRED_CONTACT_FORM_EMAIL_CONTEXT_FIELDS = [\n 'message',\n 'submittedAt',\n 'submissionId',\n 'pageLabel',\n 'pagePath',\n 'pageUrl',\n] as const\n\nfunction hasContactEmailValue(value: unknown) {\n return typeof value === 'string' ? value.trim().length > 0 : value != null\n}\n\nfunction contactEmailRow(field: string, label: string, value: unknown): ContactFormEmailRow[] {\n return hasContactEmailValue(value) ? [{ field, label, value: String(value) }] : []\n}\n\nexport function getContactFormEmailLocationValue(\n data: Pick<ContactFormEmailValidationData, 'location' | 'suburb'>,\n) {\n return data.suburb?.trim() || data.location?.trim() || ''\n}\n\nexport function validateContactFormEmailData(data: ContactFormEmailValidationData) {\n const issues: ContactFormEmailDataIssue[] = []\n\n REQUIRED_CONTACT_FORM_EMAIL_LEAD_FIELDS.forEach((field) => {\n if (!hasContactEmailValue(data[field])) {\n issues.push({ field, message: `Contact email data requires ${field}.` })\n }\n })\n\n if (!getContactFormEmailLocationValue(data)) {\n issues.push({\n field: 'suburbOrLocation',\n message: 'Contact email data requires a suburb or location.',\n })\n }\n\n REQUIRED_CONTACT_FORM_EMAIL_CONTEXT_FIELDS.forEach((field) => {\n if (!hasContactEmailValue(data[field])) {\n issues.push({ field, message: `Contact email data requires ${field}.` })\n }\n })\n\n return issues\n}\n\nexport function getContactFormEmailLeadRows(data: ContactFormEmailData) {\n const locationField = data.suburb ? 'suburb' : 'location'\n\n return [\n ...contactEmailRow('name', 'Name', data.name),\n ...contactEmailRow('email', 'Email', data.email),\n ...contactEmailRow('phone', 'Phone', data.phone),\n ...contactEmailRow(locationField, 'Location', getContactFormEmailLocationValue(data)),\n ...contactEmailRow('message', 'Message', data.message),\n ...contactEmailRow('submittedAt', 'Submitted at', data.submittedAt),\n ...contactEmailRow('submissionId', 'Submission ID', data.submissionId),\n ]\n}\n\nexport function formatContactFormEmailAttachmentSummary(\n data: Pick<ContactFormEmailBaseData, 'attachmentCount' | 'attachments'>,\n) {\n const attachments = data.attachments ?? []\n const attachmentCount = data.attachmentCount ?? attachments.length\n\n if (!attachmentCount) {\n return undefined\n }\n\n const countLabel = attachmentCount === 1 ? '1 file' : `${attachmentCount} files`\n // Original filenames may contain a person's name, address or device data.\n // Shared context rows retain only the operationally useful count.\n return countLabel\n}\n\nfunction privacySafeContextLabel(value: string | undefined) {\n const normalized = value?.trim()\n return normalized && normalized.length <= 160 && !/[\\u0000-\\u001f\\u007f]/.test(normalized)\n ? normalized\n : undefined\n}\n\nfunction privacySafeContextPath(value: string | undefined) {\n if (!value) return undefined\n try {\n return normalizeBrandlabRoutePath(value.split(/[?#]/, 1)[0] ?? '')\n } catch {\n return undefined\n }\n}\n\nfunction privacySafeContextUrl(value: string | undefined) {\n if (!value) return undefined\n try {\n const parsed = new URL(value)\n if (parsed.protocol !== 'https:' || parsed.username || parsed.password) return undefined\n const path = privacySafeContextPath(parsed.pathname)\n return path ? new URL(path, parsed.origin).toString() : undefined\n } catch {\n return undefined\n }\n}\n\nexport function getContactFormEmailContextRows(data: ContactFormEmailData) {\n const attachmentSummary = formatContactFormEmailAttachmentSummary(data)\n\n return [\n ...contactEmailRow('pageLabel', 'Page', privacySafeContextLabel(data.pageLabel)),\n ...contactEmailRow('pagePath', 'Page path', privacySafeContextPath(data.pagePath)),\n ...contactEmailRow('pageUrl', 'Page URL', privacySafeContextUrl(data.pageUrl)),\n ...contactEmailRow('attachments', 'Attachments', attachmentSummary),\n ]\n}\n\nconst AUSTRALIAN_PHONE_DIGITS = /^(?:0[23478]\\d{8}|61[23478]\\d{8})$/\n\nexport function normalizeAustralianPhoneDigits(phone: string) {\n return phone.replace(/[^\\d]/g, '')\n}\n\nexport function isValidAustralianPhoneNumber(phone: string) {\n return AUSTRALIAN_PHONE_DIGITS.test(normalizeAustralianPhoneDigits(phone))\n}\n\nexport const BRANDLAB_CONTACT_CONTRACT_VERSION = '4' as const\n\nexport const CONTACT_VISIT_SOURCES = [\n 'google-ads',\n 'google-business-profile',\n 'organic-search',\n 'referral',\n 'social',\n 'email-campaign',\n 'direct-or-unknown',\n] as const\n\nexport type ContactVisitSource = (typeof CONTACT_VISIT_SOURCES)[number]\n\nexport interface ContactAttributionSummary {\n initialLandingPath: string\n visitSource: ContactVisitSource\n visitSourceDetail?: string\n}\n\nexport function isContactVisitSource(value: unknown): value is ContactVisitSource {\n return CONTACT_VISIT_SOURCES.includes(value as ContactVisitSource)\n}\n\nexport function contactVisitSourceLabel(source: ContactVisitSource, detail?: string) {\n const labels: Record<ContactVisitSource, string> = {\n 'google-ads': 'Google Ads',\n 'google-business-profile': 'Google Business Profile',\n 'organic-search': 'Organic search',\n referral: 'Referral',\n social: 'Social',\n 'email-campaign': 'Email campaign',\n 'direct-or-unknown': 'Direct or unknown',\n }\n const label = labels[source]\n return detail && (source === 'referral' || source === 'social')\n ? `${label} — ${detail}`\n : label\n}\n\nexport type ContactFieldRole =\n | 'name'\n | 'email'\n | 'phone'\n | 'location'\n | 'message'\n | 'custom'\n\nexport type ContactFieldKind =\n | 'text'\n | 'email'\n | 'tel'\n | 'textarea'\n | 'select'\n | 'checkbox'\n\nexport type ContactFieldNormalization =\n | 'lowercase'\n | 'australian-phone-digits'\n\nexport type ContactPhoneRule = 'australian'\n\nexport interface ContactFieldContract {\n key: string\n role: ContactFieldRole\n kind: ContactFieldKind\n required: boolean\n /** Declarative limits remain shared instead of being recreated in projects. */\n maxLength?: number\n /** Required for select fields and prohibited for other field kinds. */\n options?: readonly string[]\n normalization?: ContactFieldNormalization\n /** Required for telephone fields so server validation has explicit semantics. */\n phoneRule?: ContactPhoneRule\n /** Required for checkbox fields; browsers submit this exact value when checked. */\n checkedValue?: string\n}\n\nexport interface BrandlabContactContract {\n projectId: string\n fieldProfile: string\n fields: readonly ContactFieldContract[]\n attachments: {\n mode: 'none' | 'images-optional' | 'images-required' | 'images-and-pdfs-optional'\n }\n delivery: {\n recipientEnv: string\n /** Reviewed non-secret sender identity, for example Brand <noreply@example.com>. */\n sender: string\n }\n}\n\nexport type ContactActionResult =\n | {\n ok: true\n accepted: true\n trackConversion: true\n confirmationId: string\n }\n | {\n ok: true\n accepted: false\n trackConversion: false\n }\n | {\n ok: false\n code: 'validation' | 'attachment_rejected' | 'delivery_unavailable'\n retryable: boolean\n fieldErrors?: Record<string, string[]>\n }\n\nconst CONTACT_REQUIRED_ROLES = ['name', 'email', 'phone', 'message'] as const\nconst CONTACT_SINGLETON_ROLES = ['location'] as const\nconst ENV_KEY_PATTERN = /^[A-Z][A-Z0-9_]*$/\nconst CONTACT_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst CONTACT_FIELD_KEY_PATTERN = /^[a-z][A-Za-z0-9_-]{0,63}$/\nconst CONTACT_SENDER_PATTERN =\n /^(?:[^<>\\r\\n]{1,120}<)?[^\\s<>,@]+@[^\\s<>,@]+\\.[^\\s<>,@]+>?$/\nconst CONTACT_FIELD_ROLES = new Set<ContactFieldRole>([\n 'name', 'email', 'phone', 'location', 'message', 'custom',\n])\nconst CONTACT_FIELD_KINDS = new Set<ContactFieldKind>([\n 'text', 'email', 'tel', 'textarea', 'select', 'checkbox',\n])\nfunction assertContractText(value: string, field: string) {\n if (!value.trim()) throw new Error(`${field} cannot be empty.`)\n}\n\nfunction assertContactContractKeys(\n value: object,\n allowedKeys: readonly string[],\n field: string,\n) {\n const allowed = new Set(allowedKeys)\n const unsupported = Object.keys(value).filter((key) => !allowed.has(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.`)\n }\n}\n\nexport function defineContactContract<const T extends BrandlabContactContract>(contract: T): T {\n if (!contract || typeof contract !== 'object' || Array.isArray(contract)) {\n throw new Error('Contact contract must be an object.')\n }\n if (!Array.isArray(contract.fields)) {\n throw new Error('Contact contract fields must be an array.')\n }\n assertContactContractKeys(\n contract,\n ['projectId', 'fieldProfile', 'fields', 'attachments', 'delivery'],\n 'Contact contract',\n )\n if (\n !contract.attachments ||\n typeof contract.attachments !== 'object' ||\n !['none', 'images-optional', 'images-required', 'images-and-pdfs-optional'].includes(contract.attachments.mode)\n ) {\n throw new Error('Contact contract attachment mode is invalid.')\n }\n assertContactContractKeys(contract.attachments, ['mode'], 'Contact contract attachments')\n if (\n !contract.delivery ||\n typeof contract.delivery !== 'object' ||\n Array.isArray(contract.delivery)\n ) {\n throw new Error('Contact contract delivery environment is invalid.')\n }\n assertContactContractKeys(\n contract.delivery,\n ['recipientEnv', 'sender'],\n 'Contact contract delivery',\n )\n assertContractText(contract.projectId, 'projectId')\n assertContractText(contract.fieldProfile, 'fieldProfile')\n assertBrandlabCanonicalEntityId(contract.projectId)\n if (!CONTACT_ID_PATTERN.test(contract.fieldProfile)) {\n throw new Error('fieldProfile must be lowercase kebab-case.')\n }\n if (contract.fields.length < CONTACT_REQUIRED_ROLES.length || contract.fields.length > 20) {\n throw new Error('Contact contract must define between 4 and 20 fields.')\n }\n\n const duplicateKey = contract.fields.find((field, index) =>\n contract.fields.slice(0, index).some((candidate) => candidate.key === field.key),\n )\n if (duplicateKey) throw new Error(`Contact contract contains duplicate field key \"${duplicateKey.key}\".`)\n\n contract.fields.forEach((field, index) => {\n assertContactContractKeys(\n field,\n [\n 'key',\n 'role',\n 'kind',\n 'required',\n 'maxLength',\n 'options',\n 'normalization',\n 'phoneRule',\n 'checkedValue',\n ],\n `fields[${index}]`,\n )\n assertContractText(field.key, `fields[${index}].key`)\n if (!CONTACT_FIELD_KEY_PATTERN.test(field.key)) {\n throw new Error(`fields[${index}].key is invalid.`)\n }\n if (!CONTACT_FIELD_ROLES.has(field.role)) {\n throw new Error(`fields[${index}].role is invalid.`)\n }\n if (!CONTACT_FIELD_KINDS.has(field.kind)) {\n throw new Error(`fields[${index}].kind is invalid.`)\n }\n if (typeof field.required !== 'boolean') {\n throw new Error(`fields[${index}].required must be boolean.`)\n }\n if (\n field.maxLength !== undefined &&\n (!Number.isSafeInteger(field.maxLength) || field.maxLength < 1 || field.maxLength > 10_000)\n ) {\n throw new Error(`fields[${index}].maxLength is invalid.`)\n }\n if (field.kind === 'select') {\n if (\n !Array.isArray(field.options) ||\n field.options.length === 0 ||\n field.options.length > 100 ||\n field.options.some(\n (option: unknown) =>\n typeof option !== 'string' ||\n option.trim() !== option ||\n !option ||\n option.length > 200,\n ) ||\n new Set(field.options).size !== field.options.length\n ) {\n throw new Error(`fields[${index}].options must be a bounded unique select allowlist.`)\n }\n } else if (field.options !== undefined) {\n throw new Error(`fields[${index}].options is supported only for select fields.`)\n }\n if (\n field.normalization !== undefined &&\n !['lowercase', 'australian-phone-digits'].includes(field.normalization)\n ) {\n throw new Error(`fields[${index}].normalization is unsupported.`)\n }\n if (\n field.normalization === 'australian-phone-digits' &&\n field.kind !== 'tel'\n ) {\n throw new Error(`fields[${index}] uses phone normalization without a tel kind.`)\n }\n if (field.kind === 'tel') {\n if (field.phoneRule !== 'australian') {\n throw new Error(`fields[${index}].phoneRule must declare Australian phone semantics.`)\n }\n if (field.normalization !== 'australian-phone-digits') {\n throw new Error(`fields[${index}].normalization must use Australian phone digits.`)\n }\n } else if (field.phoneRule !== undefined) {\n throw new Error(`fields[${index}].phoneRule is supported only for tel fields.`)\n }\n if (field.kind === 'email' && field.normalization !== 'lowercase') {\n throw new Error(`fields[${index}].normalization must lowercase email values.`)\n }\n if (field.kind === 'checkbox') {\n if (\n typeof field.checkedValue !== 'string' ||\n !field.checkedValue ||\n field.checkedValue.trim() !== field.checkedValue ||\n field.checkedValue.length > 100\n ) {\n throw new Error(`fields[${index}].checkedValue is required for checkbox fields.`)\n }\n } else if (field.checkedValue !== undefined) {\n throw new Error(`fields[${index}].checkedValue is supported only for checkbox fields.`)\n }\n })\n\n CONTACT_REQUIRED_ROLES.forEach((role) => {\n const matches = contract.fields.filter((field) => field.role === role)\n if (matches.length !== 1 || !matches[0]?.required) {\n throw new Error(`Contact contract requires exactly one required \"${role}\" field.`)\n }\n })\n CONTACT_SINGLETON_ROLES.forEach((role) => {\n if (contract.fields.filter((field) => field.role === role).length > 1) {\n throw new Error(`Contact contract allows at most one \"${role}\" field.`)\n }\n })\n\n const roleKinds: Partial<Record<ContactFieldRole, readonly ContactFieldKind[]>> = {\n name: ['text'],\n email: ['email'],\n phone: ['tel'],\n location: ['text', 'select'],\n message: ['textarea'],\n }\n contract.fields.forEach((field) => {\n const role = field.role as ContactFieldRole\n const kind = field.kind as ContactFieldKind\n const allowedKinds = roleKinds[role]\n if (allowedKinds && !allowedKinds.includes(kind)) {\n throw new Error(`Contact field \"${field.key}\" has an invalid kind for role \"${field.role}\".`)\n }\n })\n\n if (!ENV_KEY_PATTERN.test(contract.delivery.recipientEnv)) {\n throw new Error('delivery.recipientEnv must be an environment variable key.')\n }\n if (\n !CONTACT_SENDER_PATTERN.test(contract.delivery.sender) ||\n contract.delivery.sender.length > 320 ||\n /[\\u0000-\\u001f\\u007f]/.test(contract.delivery.sender)\n ) {\n throw new Error('delivery.sender must be a reviewed email sender.')\n }\n\n return contract\n}\n"]}
|
|
1
|
+
{"version":3,"file":"contact.js","sourceRoot":"","sources":["../src/contact.ts"],"names":[],"mappings":"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","sourcesContent":["import { normalizeBrandlabRoutePath } from './routes.js'\nimport { assertBrandlabCanonicalEntityId } from './entity-id.js'\n\nexport interface ContactAttachmentPolicy {\n maxFiles: number\n maxFileSizeBytes: number\n maxTotalSizeBytes: number\n allowedTypes: readonly ContactAttachmentMimeType[]\n}\n\nexport type ContactAttachmentMimeType =\n | 'application/pdf'\n | 'image/jpeg'\n | 'image/jpg'\n | 'image/png'\n | 'image/webp'\n | 'image/gif'\n | 'image/heic'\n | 'image/heif'\n\nexport const DEFAULT_CONTACT_ATTACHMENT_POLICY = {\n maxFiles: 5,\n maxFileSizeBytes: 4_000_000,\n maxTotalSizeBytes: 4_000_000,\n allowedTypes: [\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/webp',\n 'image/gif',\n 'image/heic',\n 'image/heif',\n ],\n} as const satisfies ContactAttachmentPolicy\n\nexport const DOCUMENT_CONTACT_ATTACHMENT_POLICY = {\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n allowedTypes: [...DEFAULT_CONTACT_ATTACHMENT_POLICY.allowedTypes, 'application/pdf'],\n} as const satisfies ContactAttachmentPolicy\n\nconst EXTENSION_TO_MIME: Record<string, ContactAttachmentMimeType> = {\n pdf: 'application/pdf',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n heic: 'image/heic',\n heif: 'image/heif',\n}\n\nexport type ContactTransportAttachmentMimeType =\n | 'application/pdf' | 'image/jpeg' | 'image/png' | 'image/webp' | 'image/gif'\n\n/** Selection stays compatible; HEIC/HEIF must be prepared as JPEG in the browser. */\nexport function deriveContactAttachmentTransportPolicy(\n selection: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n): ContactAttachmentPolicy {\n const allowedTypes = selection.allowedTypes.flatMap((type) => {\n if (['image/jpg', 'image/heic', 'image/heif'].includes(type)) return ['image/jpeg' as const]\n return ['application/pdf', 'image/jpeg', 'image/png', 'image/webp', 'image/gif'].includes(type)\n ? [type] : []\n })\n return { ...selection, allowedTypes: [...new Set(allowedTypes)] }\n}\n\n/** Positive raw-byte allowlist. No ISO-BMFF/HEIF-family input reaches native decoding. */\nexport function detectContactTransportAttachmentType(\n bytes: Uint8Array,\n): ContactTransportAttachmentMimeType | undefined {\n const starts = (signature: readonly number[]) =>\n signature.every((byte, index) => bytes[index] === byte)\n const ascii = (start: number, length: number) =>\n String.fromCharCode(...bytes.slice(start, start + length))\n if (ascii(0, 5) === '%PDF-') return 'application/pdf'\n if (starts([0xff, 0xd8, 0xff])) return 'image/jpeg'\n if (starts([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) return 'image/png'\n if (['GIF87a', 'GIF89a'].includes(ascii(0, 6))) return 'image/gif'\n if (ascii(0, 4) === 'RIFF' && ascii(8, 4) === 'WEBP') return 'image/webp'\n return undefined\n}\n\nexport function contactAttachmentAccept(\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n) {\n return [...new Set(policy.allowedTypes)].join(',')\n}\n\nexport function contactAttachmentTypeLabel(\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n) {\n const labels = policy.allowedTypes\n .map((type) => {\n const subtype = type.split('/')[1] ?? type\n if (subtype === 'jpeg' || subtype === 'jpg') return 'JPG'\n if (subtype === 'webp') return 'WebP'\n return subtype.toUpperCase()\n })\n .filter((label, index, labels) => labels.indexOf(label) === index)\n\n if (labels.length <= 1) return labels[0] ?? ''\n return `${labels.slice(0, -1).join(', ')}, or ${labels[labels.length - 1]}`\n}\n\nexport function isAllowedContactAttachmentType(\n value: string,\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n): value is ContactAttachmentMimeType {\n return policy.allowedTypes.includes(value as ContactAttachmentMimeType)\n}\n\nexport function resolveContactAttachmentType(\n filename: string,\n fileType?: string,\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n): ContactAttachmentMimeType | null {\n const normalizedType = fileType?.trim().toLowerCase()\n\n if (normalizedType && isAllowedContactAttachmentType(normalizedType, policy)) {\n return normalizedType\n }\n\n const extension = filename.toLowerCase().split('.').pop()\n if (!extension) return null\n\n const mappedType = EXTENSION_TO_MIME[extension]\n return mappedType && isAllowedContactAttachmentType(mappedType, policy) ? mappedType : null\n}\n\nexport function createContactAttachmentFilename(options: {\n index: number\n contentType?: string\n}) {\n if (options.contentType === 'application/pdf') return `document-${options.index + 1}.pdf`\n return `image-${options.index + 1}.jpg`\n}\n\nexport function validateContactAttachment(\n file: { filename: string; size: number; type?: string },\n policy: ContactAttachmentPolicy = DEFAULT_CONTACT_ATTACHMENT_POLICY,\n):\n | { ok: true; contentType: ContactAttachmentMimeType }\n | { ok: false; message: string } {\n const contentType = resolveContactAttachmentType(file.filename, file.type, policy)\n\n if (!contentType) {\n return {\n ok: false,\n message: `\"${file.filename}\" is not a supported image type. Please upload ${contactAttachmentTypeLabel(\n policy,\n )} files.`,\n }\n }\n\n if (file.size > policy.maxFileSizeBytes) {\n const maximumMegabytes = Math.round((policy.maxFileSizeBytes / (1024 * 1024)) * 10) / 10\n return {\n ok: false,\n message: `Image \"${file.filename}\" is too large. Maximum size is ${maximumMegabytes} MB per image.`,\n }\n }\n\n return { ok: true, contentType }\n}\n\nexport type AdClickIds = {\n gclid?: string\n gbraid?: string\n wbraid?: string\n gadParams?: Record<string, string>\n}\n\nconst AD_CLICK_ID_FIELDS = [\n ['gclid', 'Google Click ID'],\n ['gbraid', 'GBRAID'],\n ['wbraid', 'WBRAID'],\n] as const\n\nexport function resolveTrackingSearchParams(queryParams: string, pageUrl = '') {\n const trimmedQueryParams = queryParams.trim()\n\n if (trimmedQueryParams) {\n return new URLSearchParams(\n trimmedQueryParams.startsWith('?') ? trimmedQueryParams : `?${trimmedQueryParams}`,\n )\n }\n\n if (pageUrl) {\n try {\n return new URL(pageUrl).searchParams\n } catch {\n return new URLSearchParams()\n }\n }\n\n return new URLSearchParams()\n}\n\nexport function resolveAdClickIds(queryParams: string, pageUrl = ''): AdClickIds {\n const params = resolveTrackingSearchParams(queryParams, pageUrl)\n const clickIds = AD_CLICK_ID_FIELDS.reduce<AdClickIds>((ids, [field]) => {\n const value = params.get(field)?.trim()\n\n if (value) {\n ids[field] = value\n }\n\n return ids\n }, {})\n const gadParams: Record<string, string> = {}\n\n params.forEach((value, key) => {\n const trimmedValue = value.trim()\n const normalizedKey = key.toLowerCase()\n\n if (trimmedValue && (normalizedKey === 'gad_source' || normalizedKey.startsWith('gad_'))) {\n gadParams[key] = trimmedValue\n }\n })\n\n return Object.keys(gadParams).length > 0 ? { ...clickIds, gadParams } : clickIds\n}\n\nexport function hasAdClickIds(adClickIds: AdClickIds) {\n return (\n AD_CLICK_ID_FIELDS.some(([field]) => Boolean(adClickIds[field])) ||\n Object.keys(adClickIds.gadParams ?? {}).length > 0\n )\n}\n\nexport function hasGoogleAdsClickId(queryParams: string, pageUrl = '') {\n return hasAdClickIds(resolveAdClickIds(queryParams, pageUrl))\n}\n\nfunction formatGadLabel(key: string) {\n return key\n .replace(/^gad_/, 'GAD ')\n .replace(/_/g, ' ')\n .replace(/campaignid\\b/i, 'campaign ID')\n .replace(/\\b\\w/g, (letter) => letter.toUpperCase())\n}\n\nexport function getAdClickIdRows(adClickIds: AdClickIds | undefined) {\n if (!adClickIds) return []\n\n const directRows = AD_CLICK_ID_FIELDS.flatMap(([field, label]) => {\n const value = adClickIds[field]\n return value ? [{ field, label, value }] : []\n })\n\n const gadRows = Object.entries(adClickIds.gadParams ?? {})\n .sort(([left], [right]) => left.localeCompare(right))\n .map(([field, value]) => ({\n field,\n label: formatGadLabel(field),\n value,\n }))\n\n return [...directRows, ...gadRows]\n}\n\nexport function formatAdClickIdsForEmailText(adClickIds: AdClickIds) {\n return getAdClickIdRows(adClickIds)\n .map(({ label, value }) => `${label}: ${value}`)\n .join('\\n')\n}\n\nexport function parseContactEmailRecipients(value: string | undefined) {\n const recipients = value\n ?.split(',')\n .map((item) => item.trim())\n .filter(Boolean) ?? []\n const unique = recipients.filter((recipient, index) => {\n const address = recipient.match(/<([^<>]+)>$/)?.[1]?.trim() ?? recipient\n return recipients.findIndex((candidate) => {\n const candidateAddress = candidate.match(/<([^<>]+)>$/)?.[1]?.trim() ?? candidate\n return candidateAddress.toLowerCase() === address.toLowerCase()\n }) === index\n })\n if (unique.length > 5) {\n throw new Error('Contact delivery supports no more than five unique recipients.')\n }\n return unique\n}\n\nexport interface ContactFormEmailBaseData {\n name: string\n email: string\n phone: string\n message: string\n submittedAt: string\n submissionId: string\n pageLabel: string\n pagePath: string\n pageUrl: string\n trafficSource?: string\n initialLandingPath?: string\n initialLandingUrl?: string\n adClickIds?: AdClickIds\n attachmentCount?: number\n attachments?: readonly ContactFormEmailAttachmentSummary[]\n}\n\nexport type ContactFormEmailData = ContactFormEmailBaseData &\n ({ suburb: string; location?: string } | { location: string; suburb?: string })\n\nexport interface ContactFormEmailAttachmentSummary {\n filename: string\n contentType?: string\n sizeBytes?: number\n}\n\nexport interface ContactFormEmailRow {\n field: string\n label: string\n value: string\n}\n\nexport interface ContactFormEmailDataIssue {\n field: string\n message: string\n}\n\ntype ContactFormEmailValidationData = Partial<\n ContactFormEmailBaseData & {\n suburb: string\n location: string\n }\n>\n\nconst REQUIRED_CONTACT_FORM_EMAIL_LEAD_FIELDS = [\n 'name',\n 'email',\n 'phone',\n] as const\n\nconst REQUIRED_CONTACT_FORM_EMAIL_CONTEXT_FIELDS = [\n 'message',\n 'submittedAt',\n 'submissionId',\n 'pageLabel',\n 'pagePath',\n 'pageUrl',\n] as const\n\nfunction hasContactEmailValue(value: unknown) {\n return typeof value === 'string' ? value.trim().length > 0 : value != null\n}\n\nfunction contactEmailRow(field: string, label: string, value: unknown): ContactFormEmailRow[] {\n return hasContactEmailValue(value) ? [{ field, label, value: String(value) }] : []\n}\n\nexport function getContactFormEmailLocationValue(\n data: Pick<ContactFormEmailValidationData, 'location' | 'suburb'>,\n) {\n return data.suburb?.trim() || data.location?.trim() || ''\n}\n\nexport function validateContactFormEmailData(data: ContactFormEmailValidationData) {\n const issues: ContactFormEmailDataIssue[] = []\n\n REQUIRED_CONTACT_FORM_EMAIL_LEAD_FIELDS.forEach((field) => {\n if (!hasContactEmailValue(data[field])) {\n issues.push({ field, message: `Contact email data requires ${field}.` })\n }\n })\n\n if (!getContactFormEmailLocationValue(data)) {\n issues.push({\n field: 'suburbOrLocation',\n message: 'Contact email data requires a suburb or location.',\n })\n }\n\n REQUIRED_CONTACT_FORM_EMAIL_CONTEXT_FIELDS.forEach((field) => {\n if (!hasContactEmailValue(data[field])) {\n issues.push({ field, message: `Contact email data requires ${field}.` })\n }\n })\n\n return issues\n}\n\nexport function getContactFormEmailLeadRows(data: ContactFormEmailData) {\n const locationField = data.suburb ? 'suburb' : 'location'\n\n return [\n ...contactEmailRow('name', 'Name', data.name),\n ...contactEmailRow('email', 'Email', data.email),\n ...contactEmailRow('phone', 'Phone', data.phone),\n ...contactEmailRow(locationField, 'Location', getContactFormEmailLocationValue(data)),\n ...contactEmailRow('message', 'Message', data.message),\n ...contactEmailRow('submittedAt', 'Submitted at', data.submittedAt),\n ...contactEmailRow('submissionId', 'Submission ID', data.submissionId),\n ]\n}\n\nexport function formatContactFormEmailAttachmentSummary(\n data: Pick<ContactFormEmailBaseData, 'attachmentCount' | 'attachments'>,\n) {\n const attachments = data.attachments ?? []\n const attachmentCount = data.attachmentCount ?? attachments.length\n\n if (!attachmentCount) {\n return undefined\n }\n\n const countLabel = attachmentCount === 1 ? '1 file' : `${attachmentCount} files`\n // Original filenames may contain a person's name, address or device data.\n // Shared context rows retain only the operationally useful count.\n return countLabel\n}\n\nfunction privacySafeContextLabel(value: string | undefined) {\n const normalized = value?.trim()\n return normalized && normalized.length <= 160 && !/[\\u0000-\\u001f\\u007f]/.test(normalized)\n ? normalized\n : undefined\n}\n\nfunction privacySafeContextPath(value: string | undefined) {\n if (!value) return undefined\n try {\n return normalizeBrandlabRoutePath(value.split(/[?#]/, 1)[0] ?? '')\n } catch {\n return undefined\n }\n}\n\nfunction privacySafeContextUrl(value: string | undefined) {\n if (!value) return undefined\n try {\n const parsed = new URL(value)\n if (parsed.protocol !== 'https:' || parsed.username || parsed.password) return undefined\n const path = privacySafeContextPath(parsed.pathname)\n return path ? new URL(path, parsed.origin).toString() : undefined\n } catch {\n return undefined\n }\n}\n\nexport function getContactFormEmailContextRows(data: ContactFormEmailData) {\n const attachmentSummary = formatContactFormEmailAttachmentSummary(data)\n\n return [\n ...contactEmailRow('pageLabel', 'Page', privacySafeContextLabel(data.pageLabel)),\n ...contactEmailRow('pagePath', 'Page path', privacySafeContextPath(data.pagePath)),\n ...contactEmailRow('pageUrl', 'Page URL', privacySafeContextUrl(data.pageUrl)),\n ...contactEmailRow('attachments', 'Attachments', attachmentSummary),\n ]\n}\n\nconst AUSTRALIAN_PHONE_DIGITS = /^(?:0[23478]\\d{8}|61[23478]\\d{8})$/\n\nexport function normalizeAustralianPhoneDigits(phone: string) {\n return phone.replace(/[^\\d]/g, '')\n}\n\nexport function isValidAustralianPhoneNumber(phone: string) {\n return AUSTRALIAN_PHONE_DIGITS.test(normalizeAustralianPhoneDigits(phone))\n}\n\nexport const BRANDLAB_CONTACT_CONTRACT_VERSION = '4' as const\n\nexport const CONTACT_VISIT_SOURCES = [\n 'google-ads',\n 'google-business-profile',\n 'organic-search',\n 'referral',\n 'social',\n 'email-campaign',\n 'direct-or-unknown',\n] as const\n\nexport type ContactVisitSource = (typeof CONTACT_VISIT_SOURCES)[number]\n\nexport interface ContactAttributionSummary {\n initialLandingPath: string\n visitSource: ContactVisitSource\n visitSourceDetail?: string\n}\n\nexport function isContactVisitSource(value: unknown): value is ContactVisitSource {\n return CONTACT_VISIT_SOURCES.includes(value as ContactVisitSource)\n}\n\nexport function contactVisitSourceLabel(source: ContactVisitSource, detail?: string) {\n const labels: Record<ContactVisitSource, string> = {\n 'google-ads': 'Google Ads',\n 'google-business-profile': 'Google Business Profile',\n 'organic-search': 'Organic search',\n referral: 'Referral',\n social: 'Social',\n 'email-campaign': 'Email campaign',\n 'direct-or-unknown': 'Direct or unknown',\n }\n const label = labels[source]\n return detail && (source === 'referral' || source === 'social')\n ? `${label} — ${detail}`\n : label\n}\n\nexport type ContactFieldRole =\n | 'name'\n | 'email'\n | 'phone'\n | 'location'\n | 'message'\n | 'custom'\n\nexport type ContactFieldKind =\n | 'text'\n | 'email'\n | 'tel'\n | 'textarea'\n | 'select'\n | 'checkbox'\n\nexport type ContactFieldNormalization =\n | 'lowercase'\n | 'australian-phone-digits'\n\nexport type ContactPhoneRule = 'australian'\n\nexport interface ContactFieldContract {\n key: string\n role: ContactFieldRole\n kind: ContactFieldKind\n required: boolean\n /** Declarative limits remain shared instead of being recreated in projects. */\n maxLength?: number\n /** Required for select fields and prohibited for other field kinds. */\n options?: readonly string[]\n normalization?: ContactFieldNormalization\n /** Required for telephone fields so server validation has explicit semantics. */\n phoneRule?: ContactPhoneRule\n /** Required for checkbox fields; browsers submit this exact value when checked. */\n checkedValue?: string\n}\n\nexport interface BrandlabContactContract {\n projectId: string\n fieldProfile: string\n fields: readonly ContactFieldContract[]\n attachments: {\n mode: 'none' | 'images-optional' | 'images-required' | 'images-and-pdfs-optional'\n }\n delivery: {\n recipientEnv: string\n /** Reviewed non-secret sender identity, for example Brand <noreply@example.com>. */\n sender: string\n }\n}\n\nexport type ContactActionResult =\n | {\n ok: true\n accepted: true\n trackConversion: true\n confirmationId: string\n }\n | {\n ok: true\n accepted: false\n trackConversion: false\n }\n | {\n ok: false\n code: 'validation' | 'attachment_rejected' | 'delivery_unavailable'\n retryable: boolean\n fieldErrors?: Record<string, string[]>\n }\n\nconst CONTACT_REQUIRED_ROLES = ['name', 'email', 'phone', 'message'] as const\nconst CONTACT_SINGLETON_ROLES = ['location'] as const\nconst ENV_KEY_PATTERN = /^[A-Z][A-Z0-9_]*$/\nconst CONTACT_ID_PATTERN = /^[a-z0-9]+(?:-[a-z0-9]+)*$/\nconst CONTACT_FIELD_KEY_PATTERN = /^[a-z][A-Za-z0-9_-]{0,63}$/\nconst CONTACT_SENDER_PATTERN =\n /^(?:[^<>\\r\\n]{1,120}<)?[^\\s<>,@]+@[^\\s<>,@]+\\.[^\\s<>,@]+>?$/\nconst CONTACT_FIELD_ROLES = new Set<ContactFieldRole>([\n 'name', 'email', 'phone', 'location', 'message', 'custom',\n])\nconst CONTACT_FIELD_KINDS = new Set<ContactFieldKind>([\n 'text', 'email', 'tel', 'textarea', 'select', 'checkbox',\n])\nfunction assertContractText(value: string, field: string) {\n if (!value.trim()) throw new Error(`${field} cannot be empty.`)\n}\n\nfunction assertContactContractKeys(\n value: object,\n allowedKeys: readonly string[],\n field: string,\n) {\n const allowed = new Set(allowedKeys)\n const unsupported = Object.keys(value).filter((key) => !allowed.has(key))\n if (unsupported.length > 0) {\n throw new Error(`${field} contains unsupported keys: ${unsupported.join(', ')}.`)\n }\n}\n\nexport function defineContactContract<const T extends BrandlabContactContract>(contract: T): T {\n if (!contract || typeof contract !== 'object' || Array.isArray(contract)) {\n throw new Error('Contact contract must be an object.')\n }\n if (!Array.isArray(contract.fields)) {\n throw new Error('Contact contract fields must be an array.')\n }\n assertContactContractKeys(\n contract,\n ['projectId', 'fieldProfile', 'fields', 'attachments', 'delivery'],\n 'Contact contract',\n )\n if (\n !contract.attachments ||\n typeof contract.attachments !== 'object' ||\n !['none', 'images-optional', 'images-required', 'images-and-pdfs-optional'].includes(contract.attachments.mode)\n ) {\n throw new Error('Contact contract attachment mode is invalid.')\n }\n assertContactContractKeys(contract.attachments, ['mode'], 'Contact contract attachments')\n if (\n !contract.delivery ||\n typeof contract.delivery !== 'object' ||\n Array.isArray(contract.delivery)\n ) {\n throw new Error('Contact contract delivery environment is invalid.')\n }\n assertContactContractKeys(\n contract.delivery,\n ['recipientEnv', 'sender'],\n 'Contact contract delivery',\n )\n assertContractText(contract.projectId, 'projectId')\n assertContractText(contract.fieldProfile, 'fieldProfile')\n assertBrandlabCanonicalEntityId(contract.projectId)\n if (!CONTACT_ID_PATTERN.test(contract.fieldProfile)) {\n throw new Error('fieldProfile must be lowercase kebab-case.')\n }\n if (contract.fields.length < CONTACT_REQUIRED_ROLES.length || contract.fields.length > 20) {\n throw new Error('Contact contract must define between 4 and 20 fields.')\n }\n\n const duplicateKey = contract.fields.find((field, index) =>\n contract.fields.slice(0, index).some((candidate) => candidate.key === field.key),\n )\n if (duplicateKey) throw new Error(`Contact contract contains duplicate field key \"${duplicateKey.key}\".`)\n\n contract.fields.forEach((field, index) => {\n assertContactContractKeys(\n field,\n [\n 'key',\n 'role',\n 'kind',\n 'required',\n 'maxLength',\n 'options',\n 'normalization',\n 'phoneRule',\n 'checkedValue',\n ],\n `fields[${index}]`,\n )\n assertContractText(field.key, `fields[${index}].key`)\n if (!CONTACT_FIELD_KEY_PATTERN.test(field.key)) {\n throw new Error(`fields[${index}].key is invalid.`)\n }\n if (!CONTACT_FIELD_ROLES.has(field.role)) {\n throw new Error(`fields[${index}].role is invalid.`)\n }\n if (!CONTACT_FIELD_KINDS.has(field.kind)) {\n throw new Error(`fields[${index}].kind is invalid.`)\n }\n if (typeof field.required !== 'boolean') {\n throw new Error(`fields[${index}].required must be boolean.`)\n }\n if (\n field.maxLength !== undefined &&\n (!Number.isSafeInteger(field.maxLength) || field.maxLength < 1 || field.maxLength > 10_000)\n ) {\n throw new Error(`fields[${index}].maxLength is invalid.`)\n }\n if (field.kind === 'select') {\n if (\n !Array.isArray(field.options) ||\n field.options.length === 0 ||\n field.options.length > 100 ||\n field.options.some(\n (option: unknown) =>\n typeof option !== 'string' ||\n option.trim() !== option ||\n !option ||\n option.length > 200,\n ) ||\n new Set(field.options).size !== field.options.length\n ) {\n throw new Error(`fields[${index}].options must be a bounded unique select allowlist.`)\n }\n } else if (field.options !== undefined) {\n throw new Error(`fields[${index}].options is supported only for select fields.`)\n }\n if (\n field.normalization !== undefined &&\n !['lowercase', 'australian-phone-digits'].includes(field.normalization)\n ) {\n throw new Error(`fields[${index}].normalization is unsupported.`)\n }\n if (\n field.normalization === 'australian-phone-digits' &&\n field.kind !== 'tel'\n ) {\n throw new Error(`fields[${index}] uses phone normalization without a tel kind.`)\n }\n if (field.kind === 'tel') {\n if (field.phoneRule !== 'australian') {\n throw new Error(`fields[${index}].phoneRule must declare Australian phone semantics.`)\n }\n if (field.normalization !== 'australian-phone-digits') {\n throw new Error(`fields[${index}].normalization must use Australian phone digits.`)\n }\n } else if (field.phoneRule !== undefined) {\n throw new Error(`fields[${index}].phoneRule is supported only for tel fields.`)\n }\n if (field.kind === 'email' && field.normalization !== 'lowercase') {\n throw new Error(`fields[${index}].normalization must lowercase email values.`)\n }\n if (field.kind === 'checkbox') {\n if (\n typeof field.checkedValue !== 'string' ||\n !field.checkedValue ||\n field.checkedValue.trim() !== field.checkedValue ||\n field.checkedValue.length > 100\n ) {\n throw new Error(`fields[${index}].checkedValue is required for checkbox fields.`)\n }\n } else if (field.checkedValue !== undefined) {\n throw new Error(`fields[${index}].checkedValue is supported only for checkbox fields.`)\n }\n })\n\n CONTACT_REQUIRED_ROLES.forEach((role) => {\n const matches = contract.fields.filter((field) => field.role === role)\n if (matches.length !== 1 || !matches[0]?.required) {\n throw new Error(`Contact contract requires exactly one required \"${role}\" field.`)\n }\n })\n CONTACT_SINGLETON_ROLES.forEach((role) => {\n if (contract.fields.filter((field) => field.role === role).length > 1) {\n throw new Error(`Contact contract allows at most one \"${role}\" field.`)\n }\n })\n\n const roleKinds: Partial<Record<ContactFieldRole, readonly ContactFieldKind[]>> = {\n name: ['text'],\n email: ['email'],\n phone: ['tel'],\n location: ['text', 'select'],\n message: ['textarea'],\n }\n contract.fields.forEach((field) => {\n const role = field.role as ContactFieldRole\n const kind = field.kind as ContactFieldKind\n const allowedKinds = roleKinds[role]\n if (allowedKinds && !allowedKinds.includes(kind)) {\n throw new Error(`Contact field \"${field.key}\" has an invalid kind for role \"${field.role}\".`)\n }\n })\n\n if (!ENV_KEY_PATTERN.test(contract.delivery.recipientEnv)) {\n throw new Error('delivery.recipientEnv must be an environment variable key.')\n }\n if (\n !CONTACT_SENDER_PATTERN.test(contract.delivery.sender) ||\n contract.delivery.sender.length > 320 ||\n /[\\u0000-\\u001f\\u007f]/.test(contract.delivery.sender)\n ) {\n throw new Error('delivery.sender must be a reviewed email sender.')\n }\n\n return contract\n}\n"]}
|