@brandlab-digital/site-next 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/attachments-client.d.ts.map +1 -1
- package/dist/contact/attachments-client.js +52 -36
- package/dist/contact/attachments-client.js.map +1 -1
- package/dist/contact/client.d.ts +2 -0
- package/dist/contact/client.d.ts.map +1 -1
- package/dist/contact/client.js +16 -1
- package/dist/contact/client.js.map +1 -1
- package/dist/contact/image-sanitizer.d.ts +1 -0
- package/dist/contact/image-sanitizer.d.ts.map +1 -1
- package/dist/contact/image-sanitizer.js +24 -3
- package/dist/contact/image-sanitizer.js.map +1 -1
- package/dist/contact/index.d.ts +1 -1
- package/dist/contact/index.d.ts.map +1 -1
- package/dist/contact/index.js +1 -1
- package/dist/contact/index.js.map +1 -1
- package/dist/contact/pdf-sanitizer.d.ts.map +1 -1
- package/dist/contact/pdf-sanitizer.js +3 -0
- package/dist/contact/pdf-sanitizer.js.map +1 -1
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +5 -38
- package/dist/contact/server.js.map +1 -1
- package/dist/image-runtime.d.ts +2 -0
- package/dist/image-runtime.d.ts.map +1 -0
- package/dist/image-runtime.js +22 -0
- package/dist/image-runtime.js.map +1 -0
- package/package.json +10 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments-client.d.ts","sourceRoot":"","sources":["../../src/contact/attachments-client.ts"],"names":[],"mappings":"AAEA,OAAO,
|
|
1
|
+
{"version":3,"file":"attachments-client.d.ts","sourceRoot":"","sources":["../../src/contact/attachments-client.ts"],"names":[],"mappings":"AAEA,OAAO,EAML,KAAK,uBAAuB,EAC7B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAKL,KAAK,WAAW,EAChB,KAAK,SAAS,EACf,MAAM,OAAO,CAAA;AAGd,MAAM,WAAW,gCAAgC;IAC/C,IAAI,EAAE,IAAI,CAAA;IACV,OAAO,EAAE,MAAM,CAAA;CAChB;AAED,MAAM,WAAW,oCAAoC;IACnD,MAAM,CAAC,EAAE,uBAAuB,CAAA;IAChC,aAAa,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC7C,eAAe,CAAC,EAAE,CAAC,IAAI,EAAE,IAAI,KAAK,MAAM,CAAA;IACxC,eAAe,CAAC,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,IAAI,CAAA;CACxC;AAED,MAAM,WAAW,mCAAmC;IAClD,MAAM,EAAE,gCAAgC,EAAE,CAAA;IAC1C,UAAU,EAAE,OAAO,CAAA;IACnB,YAAY,EAAE,OAAO,CAAA;IACrB,YAAY,EAAE,MAAM,GAAG,IAAI,CAAA;IAC3B,SAAS,EAAE,MAAM,CAAA;IACjB,QAAQ,EAAE,CAAC,KAAK,EAAE,SAAS,IAAI,EAAE,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACnD,iBAAiB,EAAE,MAAM,IAAI,CAAA;IAC7B,WAAW,EAAE,MAAM,IAAI,CAAA;IACvB,iBAAiB,EAAE,CAAC,KAAK,EAAE,WAAW,CAAC,gBAAgB,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC1E,eAAe,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;IAC3C,cAAc,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,IAAI,CAAA;IAC1C,UAAU,EAAE,CAAC,KAAK,EAAE,SAAS,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IAC/C,WAAW,EAAE,CAAC,KAAK,EAAE,MAAM,KAAK,IAAI,CAAA;CACrC;AAID,wBAAsB,4BAA4B,CAAC,IAAI,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAkC5E;AAWD,wBAAgB,6BAA6B,CAC3C,OAAO,GAAE,oCAAyC,GACjD,mCAAmC,CAiJrC"}
|
|
@@ -1,11 +1,12 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, contactAttachmentTypeLabel, resolveContactAttachmentType, validateContactAttachment, } from '@brandlab-digital/site-core/contact';
|
|
2
|
+
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, deriveContactAttachmentTransportPolicy, contactAttachmentTypeLabel, resolveContactAttachmentType, validateContactAttachment, } from '@brandlab-digital/site-core/contact';
|
|
3
3
|
import { useCallback, useEffect, useRef, useState, } from 'react';
|
|
4
|
-
import { normalizeContactUploadFile } from './client.js';
|
|
4
|
+
import { normalizeContactConvertedUploadFile, normalizeContactUploadFile } from './client.js';
|
|
5
5
|
const DEFAULT_COMPRESSED_IMAGE_SIZE_MB = 0.7;
|
|
6
6
|
export async function compressBrandlabContactImage(file) {
|
|
7
|
+
const contentType = resolveContactAttachmentType(file.name, file.type);
|
|
8
|
+
const needsConversion = contentType === 'image/heic' || contentType === 'image/heif';
|
|
7
9
|
try {
|
|
8
|
-
const contentType = resolveContactAttachmentType(file.name, file.type);
|
|
9
10
|
if (!contentType)
|
|
10
11
|
return file;
|
|
11
12
|
const imported = await import('browser-image-compression');
|
|
@@ -13,13 +14,20 @@ export async function compressBrandlabContactImage(file) {
|
|
|
13
14
|
const processed = await imageCompression(file, {
|
|
14
15
|
maxSizeMB: DEFAULT_COMPRESSED_IMAGE_SIZE_MB,
|
|
15
16
|
maxWidthOrHeight: 1920,
|
|
16
|
-
|
|
17
|
-
|
|
17
|
+
// Native browser image decoding is available on the main thread. Do not
|
|
18
|
+
// ask the dependency's remote worker fallback to decode HEIC.
|
|
19
|
+
useWebWorker: !needsConversion,
|
|
20
|
+
fileType: needsConversion ? 'image/jpeg' : contentType,
|
|
18
21
|
initialQuality: 0.7,
|
|
19
22
|
});
|
|
20
|
-
return
|
|
23
|
+
return needsConversion
|
|
24
|
+
? await normalizeContactConvertedUploadFile(file, processed)
|
|
25
|
+
: normalizeContactUploadFile(file, processed);
|
|
21
26
|
}
|
|
22
27
|
catch {
|
|
28
|
+
if (needsConversion) {
|
|
29
|
+
throw new Error('We could not prepare this photo. Please try adding it again, choose another photo, or continue without it.');
|
|
30
|
+
}
|
|
23
31
|
return file;
|
|
24
32
|
}
|
|
25
33
|
}
|
|
@@ -41,12 +49,16 @@ export function useBrandlabContactAttachments(options = {}) {
|
|
|
41
49
|
const [errorMessage, setErrorMessage] = useState(null);
|
|
42
50
|
const imagesRef = useRef([]);
|
|
43
51
|
const processingRef = useRef(false);
|
|
52
|
+
const selectionSequenceRef = useRef(0);
|
|
53
|
+
const revokeObjectUrlRef = useRef(revokeObjectUrl);
|
|
44
54
|
imagesRef.current = images;
|
|
55
|
+
revokeObjectUrlRef.current = revokeObjectUrl;
|
|
45
56
|
useEffect(() => {
|
|
46
57
|
return () => {
|
|
47
|
-
|
|
58
|
+
selectionSequenceRef.current += 1;
|
|
59
|
+
imagesRef.current.forEach((image) => revokeObjectUrlRef.current(image.preview));
|
|
48
60
|
};
|
|
49
|
-
}, [
|
|
61
|
+
}, []);
|
|
50
62
|
const addFiles = useCallback(async (files) => {
|
|
51
63
|
if (files.length === 0 || processingRef.current)
|
|
52
64
|
return;
|
|
@@ -55,47 +67,50 @@ export function useBrandlabContactAttachments(options = {}) {
|
|
|
55
67
|
setErrorMessage(maximumImagesMessage(policy));
|
|
56
68
|
return;
|
|
57
69
|
}
|
|
70
|
+
const sequence = selectionSequenceRef.current;
|
|
58
71
|
processingRef.current = true;
|
|
59
72
|
setIsProcessing(true);
|
|
60
73
|
setErrorMessage(null);
|
|
61
|
-
const
|
|
74
|
+
const transportPolicy = deriveContactAttachmentTransportPolicy(policy);
|
|
75
|
+
let firstError = null;
|
|
62
76
|
try {
|
|
63
77
|
const selectedFiles = files.slice(0, availableSlots);
|
|
64
78
|
for (const file of selectedFiles) {
|
|
65
|
-
|
|
66
|
-
|
|
79
|
+
try {
|
|
80
|
+
if (!resolveContactAttachmentType(file.name, file.type, policy)) {
|
|
81
|
+
throw new Error(`Please upload ${contactAttachmentTypeLabel(policy)} images only.`);
|
|
82
|
+
}
|
|
83
|
+
const processed = await compressImage(file);
|
|
84
|
+
if (sequence !== selectionSequenceRef.current)
|
|
85
|
+
return;
|
|
86
|
+
const validation = validateContactAttachment({ filename: processed.name, size: processed.size, type: processed.type }, transportPolicy);
|
|
87
|
+
if (!validation.ok)
|
|
88
|
+
throw new Error(validation.message);
|
|
89
|
+
const totalSize = imagesRef.current.reduce((total, image) => total + image.file.size, processed.size);
|
|
90
|
+
if (totalSize > policy.maxTotalSizeBytes)
|
|
91
|
+
throw new Error(maximumTotalSizeMessage(policy));
|
|
92
|
+
if (imagesRef.current.length >= policy.maxFiles)
|
|
93
|
+
throw new Error(maximumImagesMessage(policy));
|
|
94
|
+
const nextImages = [...imagesRef.current, {
|
|
95
|
+
file: processed,
|
|
96
|
+
preview: createObjectUrl(processed),
|
|
97
|
+
}];
|
|
98
|
+
imagesRef.current = nextImages;
|
|
99
|
+
setImages(nextImages);
|
|
100
|
+
}
|
|
101
|
+
catch (error) {
|
|
102
|
+
if (sequence !== selectionSequenceRef.current)
|
|
103
|
+
return;
|
|
104
|
+
firstError ??= error instanceof Error ? error.message : 'We could not prepare this photo. Please try again.';
|
|
67
105
|
}
|
|
68
|
-
const processed = await compressImage(file);
|
|
69
|
-
const validation = validateContactAttachment({ filename: processed.name, size: processed.size, type: processed.type }, policy);
|
|
70
|
-
if (!validation.ok)
|
|
71
|
-
throw new Error(validation.message);
|
|
72
|
-
prepared.push({
|
|
73
|
-
file: processed,
|
|
74
|
-
preview: createObjectUrl(processed),
|
|
75
|
-
});
|
|
76
|
-
}
|
|
77
|
-
const totalSize = [...imagesRef.current, ...prepared].reduce((total, image) => total + image.file.size, 0);
|
|
78
|
-
if (totalSize > policy.maxTotalSizeBytes) {
|
|
79
|
-
throw new Error(maximumTotalSizeMessage(policy));
|
|
80
|
-
}
|
|
81
|
-
const nextImages = [...imagesRef.current, ...prepared];
|
|
82
|
-
imagesRef.current = nextImages;
|
|
83
|
-
setImages(nextImages);
|
|
84
|
-
if (files.length > availableSlots) {
|
|
85
|
-
setErrorMessage(maximumImagesMessage(policy));
|
|
86
106
|
}
|
|
87
|
-
|
|
88
|
-
catch (error) {
|
|
89
|
-
prepared.forEach((image) => revokeObjectUrl(image.preview));
|
|
90
|
-
setErrorMessage(error instanceof Error
|
|
91
|
-
? error.message
|
|
92
|
-
: 'We could not prepare those images. Please try again.');
|
|
107
|
+
setErrorMessage(firstError ?? (files.length > availableSlots ? maximumImagesMessage(policy) : null));
|
|
93
108
|
}
|
|
94
109
|
finally {
|
|
95
110
|
processingRef.current = false;
|
|
96
111
|
setIsProcessing(false);
|
|
97
112
|
}
|
|
98
|
-
}, [compressImage, createObjectUrl, policy
|
|
113
|
+
}, [compressImage, createObjectUrl, policy]);
|
|
99
114
|
const handleImageChange = useCallback(async (event) => {
|
|
100
115
|
const files = event.target.files ? Array.from(event.target.files) : [];
|
|
101
116
|
await addFiles(files);
|
|
@@ -125,6 +140,7 @@ export function useBrandlabContactAttachments(options = {}) {
|
|
|
125
140
|
setErrorMessage(null);
|
|
126
141
|
}, [revokeObjectUrl]);
|
|
127
142
|
const clearImages = useCallback(() => {
|
|
143
|
+
selectionSequenceRef.current += 1;
|
|
128
144
|
imagesRef.current.forEach((image) => revokeObjectUrl(image.preview));
|
|
129
145
|
imagesRef.current = [];
|
|
130
146
|
setImages([]);
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"attachments-client.js","sourceRoot":"","sources":["../../src/contact/attachments-client.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n contactAttachmentTypeLabel,\n resolveContactAttachmentType,\n validateContactAttachment,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type DragEvent,\n} from 'react'\nimport { normalizeContactUploadFile } from './client.js'\n\nexport interface BrandlabContactAttachmentPreview {\n file: File\n preview: string\n}\n\nexport interface UseBrandlabContactAttachmentsOptions {\n policy?: ContactAttachmentPolicy\n compressImage?: (file: File) => Promise<File>\n createObjectUrl?: (file: File) => string\n revokeObjectUrl?: (url: string) => void\n}\n\nexport interface UseBrandlabContactAttachmentsResult {\n images: BrandlabContactAttachmentPreview[]\n isDragging: boolean\n isProcessing: boolean\n errorMessage: string | null\n maxImages: number\n addFiles: (files: readonly File[]) => Promise<void>\n clearErrorMessage: () => void\n clearImages: () => void\n handleImageChange: (event: ChangeEvent<HTMLInputElement>) => Promise<void>\n handleDragLeave: (event: DragEvent) => void\n handleDragOver: (event: DragEvent) => void\n handleDrop: (event: DragEvent) => Promise<void>\n removeImage: (index: number) => void\n}\n\nconst DEFAULT_COMPRESSED_IMAGE_SIZE_MB = 0.7\n\nexport async function compressBrandlabContactImage(file: File): Promise<File> {\n try {\n const contentType = resolveContactAttachmentType(file.name, file.type)\n if (!contentType) return file\n const imported = await import('browser-image-compression')\n const imageCompression = imported.default as unknown as (\n image: File,\n options: {\n maxSizeMB: number\n maxWidthOrHeight: number\n useWebWorker: boolean\n fileType: string\n initialQuality: number\n },\n ) => Promise<File>\n const processed = await imageCompression(file, {\n maxSizeMB: DEFAULT_COMPRESSED_IMAGE_SIZE_MB,\n maxWidthOrHeight: 1920,\n useWebWorker: true,\n fileType: contentType,\n initialQuality: 0.7,\n })\n return normalizeContactUploadFile(file, processed)\n } catch {\n return file\n }\n}\n\nfunction maximumImagesMessage(policy: ContactAttachmentPolicy) {\n return `You can add up to ${policy.maxFiles} images.`\n}\n\nfunction maximumTotalSizeMessage(policy: ContactAttachmentPolicy) {\n const maximumMegabytes = Math.round((policy.maxTotalSizeBytes / 1_000_000) * 10) / 10\n return `Your images are too large. Please use fewer images or keep the total under ${maximumMegabytes} MB.`\n}\n\nexport function useBrandlabContactAttachments(\n options: UseBrandlabContactAttachmentsOptions = {},\n): UseBrandlabContactAttachmentsResult {\n const policy = options.policy ?? DEFAULT_CONTACT_ATTACHMENT_POLICY\n const compressImage = options.compressImage ?? compressBrandlabContactImage\n const createObjectUrl = options.createObjectUrl ?? URL.createObjectURL\n const revokeObjectUrl = options.revokeObjectUrl ?? URL.revokeObjectURL\n const [images, setImages] = useState<BrandlabContactAttachmentPreview[]>([])\n const [isDragging, setIsDragging] = useState(false)\n const [isProcessing, setIsProcessing] = useState(false)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const imagesRef = useRef<BrandlabContactAttachmentPreview[]>([])\n const processingRef = useRef(false)\n\n imagesRef.current = images\n\n useEffect(() => {\n return () => {\n imagesRef.current.forEach((image) => revokeObjectUrl(image.preview))\n }\n }, [revokeObjectUrl])\n\n const addFiles = useCallback(\n async (files: readonly File[]) => {\n if (files.length === 0 || processingRef.current) return\n\n const availableSlots = policy.maxFiles - imagesRef.current.length\n if (availableSlots <= 0) {\n setErrorMessage(maximumImagesMessage(policy))\n return\n }\n\n processingRef.current = true\n setIsProcessing(true)\n setErrorMessage(null)\n const prepared: BrandlabContactAttachmentPreview[] = []\n\n try {\n const selectedFiles = files.slice(0, availableSlots)\n for (const file of selectedFiles) {\n if (!resolveContactAttachmentType(file.name, file.type, policy)) {\n throw new Error(\n `Please upload ${contactAttachmentTypeLabel(policy)} images only.`,\n )\n }\n\n const processed = await compressImage(file)\n const validation = validateContactAttachment(\n { filename: processed.name, size: processed.size, type: processed.type },\n policy,\n )\n if (!validation.ok) throw new Error(validation.message)\n\n prepared.push({\n file: processed,\n preview: createObjectUrl(processed),\n })\n }\n\n const totalSize = [...imagesRef.current, ...prepared].reduce(\n (total, image) => total + image.file.size,\n 0,\n )\n if (totalSize > policy.maxTotalSizeBytes) {\n throw new Error(maximumTotalSizeMessage(policy))\n }\n\n const nextImages = [...imagesRef.current, ...prepared]\n imagesRef.current = nextImages\n setImages(nextImages)\n if (files.length > availableSlots) {\n setErrorMessage(maximumImagesMessage(policy))\n }\n } catch (error) {\n prepared.forEach((image) => revokeObjectUrl(image.preview))\n setErrorMessage(\n error instanceof Error\n ? error.message\n : 'We could not prepare those images. Please try again.',\n )\n } finally {\n processingRef.current = false\n setIsProcessing(false)\n }\n },\n [compressImage, createObjectUrl, policy, revokeObjectUrl],\n )\n\n const handleImageChange = useCallback(\n async (event: ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files ? Array.from(event.target.files) : []\n await addFiles(files)\n event.target.value = ''\n },\n [addFiles],\n )\n\n const handleDragOver = useCallback((event: DragEvent) => {\n event.preventDefault()\n setIsDragging(true)\n }, [])\n\n const handleDragLeave = useCallback((event: DragEvent) => {\n event.preventDefault()\n setIsDragging(false)\n }, [])\n\n const handleDrop = useCallback(\n async (event: DragEvent) => {\n event.preventDefault()\n setIsDragging(false)\n await addFiles(Array.from(event.dataTransfer.files))\n },\n [addFiles],\n )\n\n const removeImage = useCallback(\n (index: number) => {\n const removed = imagesRef.current[index]\n if (!removed) return\n revokeObjectUrl(removed.preview)\n const nextImages = imagesRef.current.filter((_, imageIndex) => imageIndex !== index)\n imagesRef.current = nextImages\n setImages(nextImages)\n setErrorMessage(null)\n },\n [revokeObjectUrl],\n )\n\n const clearImages = useCallback(() => {\n imagesRef.current.forEach((image) => revokeObjectUrl(image.preview))\n imagesRef.current = []\n setImages([])\n setErrorMessage(null)\n }, [revokeObjectUrl])\n\n return {\n images,\n isDragging,\n isProcessing,\n errorMessage,\n maxImages: policy.maxFiles,\n addFiles,\n clearErrorMessage: () => setErrorMessage(null),\n clearImages,\n handleImageChange,\n handleDragLeave,\n handleDragOver,\n handleDrop,\n removeImage,\n }\n}\n"]}
|
|
1
|
+
{"version":3,"file":"attachments-client.js","sourceRoot":"","sources":["../../src/contact/attachments-client.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n deriveContactAttachmentTransportPolicy,\n contactAttachmentTypeLabel,\n resolveContactAttachmentType,\n validateContactAttachment,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport {\n useCallback,\n useEffect,\n useRef,\n useState,\n type ChangeEvent,\n type DragEvent,\n} from 'react'\nimport { normalizeContactConvertedUploadFile, normalizeContactUploadFile } from './client.js'\n\nexport interface BrandlabContactAttachmentPreview {\n file: File\n preview: string\n}\n\nexport interface UseBrandlabContactAttachmentsOptions {\n policy?: ContactAttachmentPolicy\n compressImage?: (file: File) => Promise<File>\n createObjectUrl?: (file: File) => string\n revokeObjectUrl?: (url: string) => void\n}\n\nexport interface UseBrandlabContactAttachmentsResult {\n images: BrandlabContactAttachmentPreview[]\n isDragging: boolean\n isProcessing: boolean\n errorMessage: string | null\n maxImages: number\n addFiles: (files: readonly File[]) => Promise<void>\n clearErrorMessage: () => void\n clearImages: () => void\n handleImageChange: (event: ChangeEvent<HTMLInputElement>) => Promise<void>\n handleDragLeave: (event: DragEvent) => void\n handleDragOver: (event: DragEvent) => void\n handleDrop: (event: DragEvent) => Promise<void>\n removeImage: (index: number) => void\n}\n\nconst DEFAULT_COMPRESSED_IMAGE_SIZE_MB = 0.7\n\nexport async function compressBrandlabContactImage(file: File): Promise<File> {\n const contentType = resolveContactAttachmentType(file.name, file.type)\n const needsConversion = contentType === 'image/heic' || contentType === 'image/heif'\n try {\n if (!contentType) return file\n const imported = await import('browser-image-compression')\n const imageCompression = imported.default as unknown as (\n image: File,\n options: {\n maxSizeMB: number\n maxWidthOrHeight: number\n useWebWorker: boolean\n fileType: string\n initialQuality: number\n },\n ) => Promise<File>\n const processed = await imageCompression(file, {\n maxSizeMB: DEFAULT_COMPRESSED_IMAGE_SIZE_MB,\n maxWidthOrHeight: 1920,\n // Native browser image decoding is available on the main thread. Do not\n // ask the dependency's remote worker fallback to decode HEIC.\n useWebWorker: !needsConversion,\n fileType: needsConversion ? 'image/jpeg' : contentType,\n initialQuality: 0.7,\n })\n return needsConversion\n ? await normalizeContactConvertedUploadFile(file, processed)\n : normalizeContactUploadFile(file, processed)\n } catch {\n if (needsConversion) {\n throw new Error('We could not prepare this photo. Please try adding it again, choose another photo, or continue without it.')\n }\n return file\n }\n}\n\nfunction maximumImagesMessage(policy: ContactAttachmentPolicy) {\n return `You can add up to ${policy.maxFiles} images.`\n}\n\nfunction maximumTotalSizeMessage(policy: ContactAttachmentPolicy) {\n const maximumMegabytes = Math.round((policy.maxTotalSizeBytes / 1_000_000) * 10) / 10\n return `Your images are too large. Please use fewer images or keep the total under ${maximumMegabytes} MB.`\n}\n\nexport function useBrandlabContactAttachments(\n options: UseBrandlabContactAttachmentsOptions = {},\n): UseBrandlabContactAttachmentsResult {\n const policy = options.policy ?? DEFAULT_CONTACT_ATTACHMENT_POLICY\n const compressImage = options.compressImage ?? compressBrandlabContactImage\n const createObjectUrl = options.createObjectUrl ?? URL.createObjectURL\n const revokeObjectUrl = options.revokeObjectUrl ?? URL.revokeObjectURL\n const [images, setImages] = useState<BrandlabContactAttachmentPreview[]>([])\n const [isDragging, setIsDragging] = useState(false)\n const [isProcessing, setIsProcessing] = useState(false)\n const [errorMessage, setErrorMessage] = useState<string | null>(null)\n const imagesRef = useRef<BrandlabContactAttachmentPreview[]>([])\n const processingRef = useRef(false)\n const selectionSequenceRef = useRef(0)\n const revokeObjectUrlRef = useRef(revokeObjectUrl)\n\n imagesRef.current = images\n revokeObjectUrlRef.current = revokeObjectUrl\n\n useEffect(() => {\n return () => {\n selectionSequenceRef.current += 1\n imagesRef.current.forEach((image) => revokeObjectUrlRef.current(image.preview))\n }\n }, [])\n\n const addFiles = useCallback(\n async (files: readonly File[]) => {\n if (files.length === 0 || processingRef.current) return\n\n const availableSlots = policy.maxFiles - imagesRef.current.length\n if (availableSlots <= 0) {\n setErrorMessage(maximumImagesMessage(policy))\n return\n }\n\n const sequence = selectionSequenceRef.current\n processingRef.current = true\n setIsProcessing(true)\n setErrorMessage(null)\n const transportPolicy = deriveContactAttachmentTransportPolicy(policy)\n let firstError: string | null = null\n\n try {\n const selectedFiles = files.slice(0, availableSlots)\n for (const file of selectedFiles) {\n try {\n if (!resolveContactAttachmentType(file.name, file.type, policy)) {\n throw new Error(\n `Please upload ${contactAttachmentTypeLabel(policy)} images only.`,\n )\n }\n\n const processed = await compressImage(file)\n if (sequence !== selectionSequenceRef.current) return\n const validation = validateContactAttachment(\n { filename: processed.name, size: processed.size, type: processed.type },\n transportPolicy,\n )\n if (!validation.ok) throw new Error(validation.message)\n const totalSize = imagesRef.current.reduce((total, image) => total + image.file.size, processed.size)\n if (totalSize > policy.maxTotalSizeBytes) throw new Error(maximumTotalSizeMessage(policy))\n if (imagesRef.current.length >= policy.maxFiles) throw new Error(maximumImagesMessage(policy))\n const nextImages = [...imagesRef.current, {\n file: processed,\n preview: createObjectUrl(processed),\n }]\n imagesRef.current = nextImages\n setImages(nextImages)\n } catch (error) {\n if (sequence !== selectionSequenceRef.current) return\n firstError ??= error instanceof Error ? error.message : 'We could not prepare this photo. Please try again.'\n }\n }\n setErrorMessage(firstError ?? (files.length > availableSlots ? maximumImagesMessage(policy) : null))\n } finally {\n processingRef.current = false\n setIsProcessing(false)\n }\n },\n [compressImage, createObjectUrl, policy],\n )\n\n const handleImageChange = useCallback(\n async (event: ChangeEvent<HTMLInputElement>) => {\n const files = event.target.files ? Array.from(event.target.files) : []\n await addFiles(files)\n event.target.value = ''\n },\n [addFiles],\n )\n\n const handleDragOver = useCallback((event: DragEvent) => {\n event.preventDefault()\n setIsDragging(true)\n }, [])\n\n const handleDragLeave = useCallback((event: DragEvent) => {\n event.preventDefault()\n setIsDragging(false)\n }, [])\n\n const handleDrop = useCallback(\n async (event: DragEvent) => {\n event.preventDefault()\n setIsDragging(false)\n await addFiles(Array.from(event.dataTransfer.files))\n },\n [addFiles],\n )\n\n const removeImage = useCallback(\n (index: number) => {\n const removed = imagesRef.current[index]\n if (!removed) return\n revokeObjectUrl(removed.preview)\n const nextImages = imagesRef.current.filter((_, imageIndex) => imageIndex !== index)\n imagesRef.current = nextImages\n setImages(nextImages)\n setErrorMessage(null)\n },\n [revokeObjectUrl],\n )\n\n const clearImages = useCallback(() => {\n selectionSequenceRef.current += 1\n imagesRef.current.forEach((image) => revokeObjectUrl(image.preview))\n imagesRef.current = []\n setImages([])\n setErrorMessage(null)\n }, [revokeObjectUrl])\n\n return {\n images,\n isDragging,\n isProcessing,\n errorMessage,\n maxImages: policy.maxFiles,\n addFiles,\n clearErrorMessage: () => setErrorMessage(null),\n clearImages,\n handleImageChange,\n handleDragLeave,\n handleDragOver,\n handleDrop,\n removeImage,\n }\n}\n"]}
|
package/dist/contact/client.d.ts
CHANGED
|
@@ -4,6 +4,8 @@ import { type SafeContactAdsParams, type SafeContactAnalyticsParams } from '../a
|
|
|
4
4
|
import { createContactSubmissionId, type BrandlabContactDefinition } from './shared.js';
|
|
5
5
|
export { createContactSubmissionId };
|
|
6
6
|
export declare function normalizeContactUploadFile(original: File, processed: Blob): File;
|
|
7
|
+
/** Explicit format-changing path; never relabel the original HEIC bytes as JPEG. */
|
|
8
|
+
export declare function normalizeContactConvertedUploadFile(original: File, processed: Blob): Promise<File>;
|
|
7
9
|
export declare function parseContactActionResult(value: unknown): ContactActionResult | undefined;
|
|
8
10
|
export type ContactSubmissionPhase = 'idle' | 'submitting' | 'accepted' | 'accepted-silently' | 'error';
|
|
9
11
|
export interface ContactSubmissionState {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAC1E,OAAO,
|
|
1
|
+
{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,uCAAuC,CAAA;AAC1E,OAAO,EAGL,KAAK,mBAAmB,EACzB,MAAM,qCAAqC,CAAA;AAG5C,OAAO,EAEL,KAAK,oBAAoB,EACzB,KAAK,0BAA0B,EAChC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAGL,yBAAyB,EACzB,KAAK,yBAAyB,EAC/B,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,yBAAyB,EAAE,CAAA;AAEpC,wBAAgB,0BAA0B,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,CAgBhF;AAED,oFAAoF;AACpF,wBAAsB,mCAAmC,CAAC,QAAQ,EAAE,IAAI,EAAE,SAAS,EAAE,IAAI,GAAG,OAAO,CAAC,IAAI,CAAC,CAexG;AA8CD,wBAAgB,wBAAwB,CAAC,KAAK,EAAE,OAAO,GAAG,mBAAmB,GAAG,SAAS,CA+CxF;AAED,MAAM,MAAM,sBAAsB,GAC9B,MAAM,GACN,YAAY,GACZ,UAAU,GACV,mBAAmB,GACnB,OAAO,CAAA;AAEX,MAAM,WAAW,sBAAsB;IACrC,KAAK,EAAE,sBAAsB,CAAA;IAC7B,OAAO,EAAE,OAAO,CAAA;IAChB,QAAQ,EAAE,OAAO,CAAA;IACjB,MAAM,CAAC,EAAE,mBAAmB,CAAA;CAC7B;AAED,MAAM,WAAW,sCAAsC;IACrD,QAAQ,EAAE,MAAM,CAAA;IAChB,SAAS,CAAC,EAAE,MAAM,CAAA;IAClB,eAAe,CAAC,EAAE,MAAM,CAAA;IACxB,OAAO,CAAC,EAAE,OAAO,KAAK,CAAA;IACtB,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;IAChB,SAAS,CAAC,EAAE,IAAI,CACd,UAAU,CAAC,OAAO,2BAA2B,CAAC,CAAC,CAAC,CAAC,EACjD,UAAU,CACX,CAAA;IACD,aAAa,CAAC,EAAE,CAAC,KAAK,EAAE,sBAAsB,KAAK,IAAI,CAAA;CACxD;AAED,MAAM,WAAW,2BAA2B;IAC1C,QAAQ,IAAI,sBAAsB,CAAA;IAClC,MAAM,CAAC,QAAQ,EAAE,QAAQ,GAAG,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACxD,KAAK,IAAI,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACrC,KAAK,IAAI,IAAI,CAAA;CACd;AAkFD,wBAAgB,qCAAqC,CACnD,OAAO,EAAE,sCAAsC,GAC9C,2BAA2B,CAwH7B;AAED,wBAAgB,wBAAwB,CACtC,MAAM,EAAE,mBAAmB,GAC1B,MAAM,IAAI,OAAO,CAAC,mBAAmB,EAAE;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,QAAQ,EAAE,IAAI,CAAA;CAAE,CAAC,CAEtE;AAED,wBAAgB,2BAA2B,CACzC,MAAM,EAAE,mBAAmB,EAC3B,OAAO,EAAE;IACP,QAAQ,EAAE,MAAM,CAAA;IAChB,UAAU,EAAE,yBAAyB,CAAA;IACrC,QAAQ,EAAE,QAAQ,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,0BAA0B,CAAC,EAAE,OAAO,CAAA;IACpC,iBAAiB,EAAE,OAAO,CAAA;IAC1B,aAAa,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IAC7B,qBAAqB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACrC,wBAAwB,CAAC,EAAE,MAAM,GAAG,IAAI,CAAA;IACxC,IAAI,CAAC,EAAE,aAAa,CAAA;IACpB,MAAM,CAAC,EAAE,0BAA0B,CAAA;IACnC,SAAS,CAAC,EAAE,oBAAoB,CAAA;CACjC,+EAmBF"}
|
package/dist/contact/client.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
'use client';
|
|
2
|
-
import { resolveContactAttachmentType, } from '@brandlab-digital/site-core/contact';
|
|
2
|
+
import { resolveContactAttachmentType, detectContactTransportAttachmentType, } from '@brandlab-digital/site-core/contact';
|
|
3
3
|
import { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes';
|
|
4
4
|
import { getInitialContactAttribution } from '../instrumentation-client.js';
|
|
5
5
|
import { trackDeliveredContactWithEnhancedConversions, } from '../analytics.js';
|
|
@@ -22,6 +22,21 @@ export function normalizeContactUploadFile(original, processed) {
|
|
|
22
22
|
lastModified: original.lastModified,
|
|
23
23
|
});
|
|
24
24
|
}
|
|
25
|
+
/** Explicit format-changing path; never relabel the original HEIC bytes as JPEG. */
|
|
26
|
+
export async function normalizeContactConvertedUploadFile(original, processed) {
|
|
27
|
+
if (!(original instanceof File) || !(processed instanceof Blob)) {
|
|
28
|
+
throw new TypeError('Contact image conversion requires browser File and Blob values.');
|
|
29
|
+
}
|
|
30
|
+
const selectedType = resolveContactAttachmentType(original.name, original.type);
|
|
31
|
+
if (!['image/heic', 'image/heif'].includes(selectedType ?? '') ||
|
|
32
|
+
processed.type !== 'image/jpeg' || processed.size === 0 ||
|
|
33
|
+
detectContactTransportAttachmentType(new Uint8Array(await processed.slice(0, 12).arrayBuffer())) !== 'image/jpeg') {
|
|
34
|
+
throw new TypeError('The converted contact image must contain JPEG bytes.');
|
|
35
|
+
}
|
|
36
|
+
return new File([processed], `${original.name.replace(/\.[^.]*$/, '') || 'photo'}.jpg`, {
|
|
37
|
+
type: 'image/jpeg', lastModified: original.lastModified,
|
|
38
|
+
});
|
|
39
|
+
}
|
|
25
40
|
const CONTACT_FIELD_ERROR_KEY_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/;
|
|
26
41
|
const CONTACT_ERROR_CODES = new Set([
|
|
27
42
|
'validation',
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"AAAA,YAAY,CAAA;AAGZ,OAAO,EACL,4BAA4B,GAE7B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,4BAA4B,EAAE,MAAM,8BAA8B,CAAA;AAC3E,OAAO,EACL,4CAA4C,GAG7C,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,+BAA+B,EAC/B,mBAAmB,EACnB,yBAAyB,GAE1B,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,yBAAyB,EAAE,CAAA;AAEpC,MAAM,UAAU,0BAA0B,CAAC,QAAc,EAAE,SAAe;IACxE,IAAI,CAAC,CAAC,QAAQ,YAAY,IAAI,CAAC,IAAI,CAAC,CAAC,SAAS,YAAY,IAAI,CAAC,EAAE,CAAC;QAChE,MAAM,IAAI,SAAS,CAAC,oEAAoE,CAAC,CAAA;IAC3F,CAAC;IACD,MAAM,WAAW,GAAG,SAAS,CAAC,IAAI,IAAI,QAAQ,CAAC,IAAI,CAAA;IACnD,MAAM,YAAY,GAAG,4BAA4B,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAA;IAChE,MAAM,aAAa,GAAG,4BAA4B,CAAC,EAAE,EAAE,WAAW,CAAC,CAAA;IACnE,MAAM,sBAAsB,GAAG,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAA;IACzF,MAAM,uBAAuB,GAAG,aAAa,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,aAAa,CAAA;IAC5F,IAAI,CAAC,sBAAsB,IAAI,sBAAsB,KAAK,uBAAuB,EAAE,CAAC;QAClF,MAAM,IAAI,SAAS,CAAC,mEAAmE,CAAC,CAAA;IAC1F,CAAC;IACD,OAAO,IAAI,IAAI,CAAC,CAAC,SAAS,CAAC,EAAE,QAAQ,CAAC,IAAI,EAAE;QAC1C,IAAI,EAAE,sBAAsB;QAC5B,YAAY,EAAE,QAAQ,CAAC,YAAY;KACpC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,+BAA+B,GAAG,yBAAyB,CAAA;AACjE,MAAM,mBAAmB,GAAG,IAAI,GAAG,CAAC;IAClC,YAAY;IACZ,qBAAqB;IACrB,sBAAsB;CACvB,CAAC,CAAA;AAEF,SAAS,YAAY,CAAC,KAAc;IAClC,OAAO,KAAK,IAAI,OAAO,KAAK,KAAK,QAAQ,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,KAAK,CAAC;QAChE,CAAC,CAAE,KAAiC;QACpC,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,WAAW,CAAC,MAA+B,EAAE,OAA0B;IAC9E,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,OAAO,CAAC,CAAA;IAC7B,OAAO,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC,CAAA;AAC1D,CAAC;AAED,SAAS,gBAAgB,CAAC,KAAc;IACtC,IAAI,KAAK,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IACzC,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IAClC,IAAI,CAAC,MAAM,IAAI,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,MAAM,GAAG,EAAE;QAAE,OAAO,SAAS,CAAA;IAChE,MAAM,MAAM,GAA6B,EAAE,CAAA;IAC3C,KAAK,MAAM,CAAC,KAAK,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QACvD,IACE,CAAC,+BAA+B,CAAC,IAAI,CAAC,KAAK,CAAC;YAC5C,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;YACxB,QAAQ,CAAC,MAAM,GAAG,CAAC;YACnB,QAAQ,CAAC,MAAM,GAAG,CAAC;YACnB,QAAQ,CAAC,IAAI,CACX,CAAC,OAAO,EAAE,EAAE,CACV,OAAO,OAAO,KAAK,QAAQ;gBAC3B,CAAC,OAAO,CAAC,IAAI,EAAE;gBACf,OAAO,CAAC,MAAM,GAAG,GAAG;gBACpB,uBAAuB,CAAC,IAAI,CAAC,OAAO,CAAC,CACxC,EACD,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,GAAG,QAAQ,CAAC,CAAA;IAC/B,CAAC;IACD,OAAO,MAAM,CAAA;AACf,CAAC;AAED,MAAM,UAAU,wBAAwB,CAAC,KAAc;IACrD,MAAM,MAAM,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;IAClC,IAAI,CAAC,MAAM,IAAI,OAAO,MAAM,CAAC,EAAE,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC/D,IAAI,MAAM,CAAC,EAAE,EAAE,CAAC;QACd,IAAI,MAAM,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;YAC7B,IACE,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,iBAAiB,EAAE,gBAAgB,CAAC,CAAC;gBAC7E,MAAM,CAAC,eAAe,KAAK,IAAI;gBAC/B,OAAO,MAAM,CAAC,cAAc,KAAK,QAAQ;gBACzC,CAAC,+BAA+B,CAAC,IAAI,CAAC,MAAM,CAAC,cAAc,CAAC,EAC5D,CAAC;gBACD,OAAO,SAAS,CAAA;YAClB,CAAC;YACD,OAAO;gBACL,EAAE,EAAE,IAAI;gBACR,QAAQ,EAAE,IAAI;gBACd,eAAe,EAAE,IAAI;gBACrB,cAAc,EAAE,MAAM,CAAC,cAAc;aACtC,CAAA;QACH,CAAC;QACD,IACE,MAAM,CAAC,QAAQ,KAAK,KAAK;YACzB,MAAM,CAAC,eAAe,KAAK,KAAK;YAChC,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,UAAU,EAAE,iBAAiB,CAAC,CAAC,EAC3D,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;IAC9D,CAAC;IAED,IACE,CAAC,WAAW,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,MAAM,EAAE,WAAW,EAAE,aAAa,CAAC,CAAC;QAChE,OAAO,MAAM,CAAC,IAAI,KAAK,QAAQ;QAC/B,CAAC,mBAAmB,CAAC,GAAG,CAAC,MAAM,CAAC,IAAI,CAAC;QACrC,OAAO,MAAM,CAAC,SAAS,KAAK,SAAS,EACrC,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,gBAAgB,CAAC,MAAM,CAAC,WAAW,CAAC,CAAA;IACxD,IAAI,MAAM,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,WAAW;QAAE,OAAO,SAAS,CAAA;IACtE,IAAI,MAAM,CAAC,IAAI,KAAK,YAAY,IAAI,WAAW;QAAE,OAAO,SAAS,CAAA;IACjE,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,MAAM,CAAC,IAA2D;QACxE,SAAS,EAAE,MAAM,CAAC,SAAS;QAC3B,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxC,CAAA;AACH,CAAC;AAoCD,SAAS,YAAY,CAAC,QAAkB;IACtC,IAAI,CAAC,QAAQ,IAAI,OAAO,QAAQ,CAAC,OAAO,KAAK,UAAU,EAAE,CAAC;QACxD,MAAM,IAAI,SAAS,CAAC,oCAAoC,CAAC,CAAA;IAC3D,CAAC;IACD,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAA;IAC3B,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE;QAAE,IAAI,CAAC,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,CAAA;IACxE,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAyB,EAAE,QAAgB;IACvE,MAAM,QAAQ,GAAG,KAAK,IAAI,QAAQ,CAAA;IAClC,IACE,CAAC,kBAAkB,CAAC,IAAI,CAAC,QAAQ,CAAC;QAClC,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC;QACvB,QAAQ,CAAC,QAAQ,CAAC,GAAG,CAAC,EACtB,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,0DAA0D,CAAC,CAAA;IACjF,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,KAAK,UAAU,WAAW,CAAC,QAAkB,EAAE,YAAoB;IACjE,MAAM,WAAW,GAAG,QAAQ,CAAC,OAAO;SACjC,GAAG,CAAC,cAAc,CAAC;QACpB,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC;QAClB,EAAE,IAAI,EAAE;SACP,WAAW,EAAE,CAAA;IAChB,IAAI,WAAW,KAAK,kBAAkB,EAAE,CAAC;QACvC,MAAM,IAAI,KAAK,CAAC,gEAAgE,CAAC,CAAA;IACnF,CAAC;IACD,MAAM,IAAI,GAAG,MAAM,QAAQ,CAAC,IAAI,EAAE,CAAA;IAClC,IAAI,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,UAAU,GAAG,YAAY,EAAE,CAAC;QAC7D,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,OAAO,IAAI,CAAC,KAAK,CAAC,IAAI,CAAY,CAAA;AACpC,CAAC;AAED,MAAM,wBAAwB,GAAwB;IACpD,EAAE,EAAE,KAAK;IACT,IAAI,EAAE,sBAAsB;IAC5B,SAAS,EAAE,IAAI;CAChB,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAyB;IAClD,MAAM,KAAK,GAAG,KAAK,EAAE,IAAI,EAAE,CAAA;IAC3B,IACE,KAAK,KAAK,SAAS;QACnB,CAAC,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,EACrE,CAAC;QACD,MAAM,IAAI,SAAS,CAAC,0CAA0C,CAAC,CAAA;IACjE,CAAC;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,SAAS,qBAAqB,CAC5B,QAAkB,EAClB,OAIC;IAED,MAAM,WAAW,GACf,OAAO,MAAM,KAAK,WAAW;QAC3B,CAAC,CAAC,EAAE,kBAAkB,EAAE,OAAO,CAAC,QAAQ,EAAE,WAAW,EAAE,mBAA4B,EAAE;QACrF,CAAC,CAAC,4BAA4B,CAAC,MAAM,CAAC,CAAA;IAC1C,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,yBAAyB,EAAE,CAAC,CAAA;IACjF,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,WAAW,EAAE,OAAO,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CAAA;IACxE,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,QAAQ,EAAE,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC5D,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;QACtB,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,SAAS,EAAE,OAAO,CAAC,SAAS,CAAC,CAAA;IAChE,CAAC;IACD,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,kBAAkB,EAAE,WAAW,CAAC,kBAAkB,CAAC,CAAA;IACpF,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,WAAW,EAAE,WAAW,CAAC,WAAW,CAAC,CAAA;IACtE,IAAI,WAAW,CAAC,iBAAiB,EAAE,CAAC;QAClC,QAAQ,CAAC,GAAG,CAAC,mBAAmB,CAAC,iBAAiB,EAAE,WAAW,CAAC,iBAAiB,CAAC,CAAA;IACpF,CAAC;IACD,OAAO,QAAQ,CAAA;AACjB,CAAC;AAED,MAAM,UAAU,qCAAqC,CACnD,OAA+C;IAE/C,MAAM,eAAe,GAAG,oBAAoB,CAAC,OAAO,CAAC,eAAe,EAAE,cAAc,CAAC,CAAA;IACrF,MAAM,QAAQ,GAAG,0BAA0B,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC7D,MAAM,SAAS,GAAG,iBAAiB,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IACtD,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,IAAI,KAAK,CAAA;IACxC,IAAI,OAAO,OAAO,KAAK,UAAU;QAAE,MAAM,IAAI,SAAS,CAAC,qCAAqC,CAAC,CAAA;IAC7F,IAAI,OAAO,CAAC,aAAa,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,aAAa,KAAK,UAAU,EAAE,CAAC;QACvF,MAAM,IAAI,SAAS,CAAC,mCAAmC,CAAC,CAAA;IAC1D,CAAC;IAED,MAAM,oBAAoB,GAAG,IAAI,GAAG,EAAU,CAAA;IAC9C,IAAI,OAA6B,CAAA;IACjC,IAAI,QAAkD,CAAA;IACtD,IAAI,KAAK,GAA2B;QAClC,KAAK,EAAE,MAAM;QACb,OAAO,EAAE,KAAK;QACd,QAAQ,EAAE,KAAK;KAChB,CAAA;IAED,MAAM,OAAO,GAAG,CAAC,IAA4B,EAAE,EAAE;QAC/C,KAAK,GAAG,MAAM,CAAC,MAAM,CAAC,EAAE,GAAG,IAAI,EAAE,CAAC,CAAA;QAClC,OAAO,CAAC,aAAa,EAAE,CAAC,KAAK,CAAC,CAAA;IAChC,CAAC,CAAA;IAED,MAAM,IAAI,GAAG,KAAK,EAAE,QAAkB,EAAE,EAAE;QACxC,OAAO,CAAC,EAAE,KAAK,EAAE,YAAY,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAChE,IAAI,MAA2B,CAAA;QAC/B,IAAI,CAAC;YACH,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,eAAe,EAAE;gBAC9C,MAAM,EAAE,MAAM;gBACd,WAAW,EAAE,aAAa;gBAC1B,KAAK,EAAE,UAAU;gBACjB,IAAI,EAAE,YAAY,CAAC,QAAQ,CAAC;aAC7B,CAAC,CAAA;YACF,MAAM;gBACJ,wBAAwB,CAAC,MAAM,WAAW,CAAC,QAAQ,EAAE,EAAE,GAAG,KAAK,CAAC,CAAC;oBACjE,wBAAwB,CAAA;QAC5B,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,wBAAwB,CAAA;QACnC,CAAC;QAED,IAAI,CAAC,MAAM,CAAC,EAAE,EAAE,CAAC;YACf,OAAO,CAAC;gBACN,KAAK,EAAE,OAAO;gBACd,OAAO,EAAE,KAAK;gBACd,QAAQ,EAAE,MAAM,CAAC,SAAS;gBAC1B,MAAM;aACP,CAAC,CAAA;YACF,OAAO,MAAM,CAAA;QACf,CAAC;QAED,IAAI,MAAM,CAAC,QAAQ,IAAI,CAAC,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,EAAE,CAAC;YACxE,oBAAoB,CAAC,GAAG,CAAC,MAAM,CAAC,cAAc,CAAC,CAAA;YAC/C,IAAI,CAAC;gBACH,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;oBACtB,2BAA2B,CAAC,MAAM,EAAE;wBAClC,GAAG,OAAO,CAAC,SAAS;wBACpB,QAAQ,EAAE,YAAY,CAAC,QAAQ,CAAC;qBACjC,CAAC,CAAA;gBACJ,CAAC;YACH,CAAC;YAAC,MAAM,CAAC;gBACP,uEAAuE;YACzE,CAAC;QACH,CAAC;QAED,OAAO,GAAG,SAAS,CAAA;QACnB,OAAO,CAAC;YACN,KAAK,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,mBAAmB;YACzD,OAAO,EAAE,KAAK;YACd,QAAQ,EAAE,KAAK;YACf,MAAM;SACP,CAAC,CAAA;QACF,OAAO,MAAM,CAAA;IACf,CAAC,CAAA;IAED,MAAM,GAAG,GAAG,CAAC,QAAkB,EAAE,EAAE;QACjC,IAAI,QAAQ;YAAE,OAAO,QAAQ,CAAA;QAC7B,IAAI,OAAqC,CAAA;QACzC,OAAO,GAAG,IAAI,CAAC,QAAQ,CAAC,CAAC,OAAO,CAAC,GAAG,EAAE;YACpC,IAAI,QAAQ,KAAK,OAAO;gBAAE,QAAQ,GAAG,SAAS,CAAA;QAChD,CAAC,CAAC,CAAA;QACF,QAAQ,GAAG,OAAO,CAAA;QAClB,OAAO,OAAO,CAAA;IAChB,CAAC,CAAA;IAED,OAAO;QACL,QAAQ,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,GAAG,KAAK,EAAE,CAAC;QAC9B,MAAM,CAAC,QAAQ;YACb,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAA;YAC7B,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAA;YACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC;gBACpC,OAAO,GAAG,SAAS,CAAA;gBACnB,OAAO,CAAC;oBACN,KAAK,EAAE,OAAO;oBACd,OAAO,EAAE,KAAK;oBACd,QAAQ,EAAE,KAAK;oBACf,MAAM,EAAE,wBAAwB;iBACjC,CAAC,CAAA;gBACF,OAAO,OAAO,CAAC,OAAO,CAAC,wBAAwB,CAAC,CAAA;YAClD,CAAC;YACD,OAAO,GAAG,qBAAqB,CAAC,YAAY,CAAC,QAAQ,CAAC,EAAE;gBACtD,QAAQ;gBACR,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG;aACJ,CAAC,CAAA;YACF,OAAO,GAAG,CAAC,OAAO,CAAC,CAAA;QACrB,CAAC;QACD,KAAK;YACH,IAAI,QAAQ;gBAAE,OAAO,QAAQ,CAAA;YAC7B,IAAI,CAAC,OAAO,IAAI,KAAK,CAAC,KAAK,KAAK,OAAO,IAAI,CAAC,KAAK,CAAC,QAAQ,EAAE,CAAC;gBAC3D,OAAO,OAAO,CAAC,MAAM,CAAC,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAC,CAAA;YACnF,CAAC;YACD,OAAO,GAAG,CAAC,OAAO,CAAC,CAAA;QACrB,CAAC;QACD,KAAK;YACH,IAAI,QAAQ;gBAAE,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;YAC9E,OAAO,GAAG,SAAS,CAAA;YACnB,OAAO,CAAC,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,EAAE,KAAK,EAAE,QAAQ,EAAE,KAAK,EAAE,CAAC,CAAA;QAC7D,CAAC;KACF,CAAA;AACH,CAAC;AAED,MAAM,UAAU,wBAAwB,CACtC,MAA2B;IAE3B,OAAO,MAAM,CAAC,EAAE,IAAI,MAAM,CAAC,QAAQ,IAAI,MAAM,CAAC,eAAe,CAAA;AAC/D,CAAC;AAED,MAAM,UAAU,2BAA2B,CACzC,MAA2B,EAC3B,OAaC;IAED,MAAM,EACJ,QAAQ,EACR,UAAU,EACV,QAAQ,EACR,iBAAiB,EACjB,MAAM,EACN,SAAS,EACT,GAAG,MAAM,EACV,GAAG,OAAO,CAAA;IACX,OAAO,4CAA4C,CAAC,MAAM,EAAE,MAAM,EAAE;QAClE,QAAQ;QACR,UAAU;QACV,QAAQ;QACR,iBAAiB;QACjB,MAAM;QACN,SAAS;KACV,CAAC,CAAA;AACJ,CAAC","sourcesContent":["'use client'\n\nimport type { GtagTransport } from '@brandlab-digital/site-core/analytics'\nimport {\n resolveContactAttachmentType,\n type ContactActionResult,\n} from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { getInitialContactAttribution } from '../instrumentation-client.js'\nimport {\n trackDeliveredContactWithEnhancedConversions,\n type SafeContactAdsParams,\n type SafeContactAnalyticsParams,\n} from '../analytics.js'\nimport {\n CONTACT_CONFIRMATION_ID_PATTERN,\n CONTACT_FORM_FIELDS,\n createContactSubmissionId,\n type BrandlabContactDefinition,\n} from './shared.js'\n\nexport { createContactSubmissionId }\n\nexport function normalizeContactUploadFile(original: File, processed: Blob): File {\n if (!(original instanceof File) || !(processed instanceof Blob)) {\n throw new TypeError('Contact image normalisation requires browser File and Blob values.')\n }\n const contentType = processed.type || original.type\n const filenameType = resolveContactAttachmentType(original.name)\n const processedType = resolveContactAttachmentType('', contentType)\n const normalizedFilenameType = filenameType === 'image/jpg' ? 'image/jpeg' : filenameType\n const normalizedProcessedType = processedType === 'image/jpg' ? 'image/jpeg' : processedType\n if (!normalizedFilenameType || normalizedFilenameType !== normalizedProcessedType) {\n throw new TypeError('The processed contact image does not match its reviewed filename.')\n }\n return new File([processed], original.name, {\n type: normalizedFilenameType,\n lastModified: original.lastModified,\n })\n}\n\nconst CONTACT_FIELD_ERROR_KEY_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/\nconst CONTACT_ERROR_CODES = new Set([\n 'validation',\n 'attachment_rejected',\n 'delivery_unavailable',\n])\n\nfunction objectRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction hasOnlyKeys(record: Record<string, unknown>, allowed: readonly string[]) {\n const keys = new Set(allowed)\n return Object.keys(record).every((key) => keys.has(key))\n}\n\nfunction parseFieldErrors(value: unknown) {\n if (value === undefined) return undefined\n const record = objectRecord(value)\n if (!record || Object.keys(record).length > 48) return undefined\n const result: Record<string, string[]> = {}\n for (const [field, messages] of Object.entries(record)) {\n if (\n !CONTACT_FIELD_ERROR_KEY_PATTERN.test(field) ||\n !Array.isArray(messages) ||\n messages.length < 1 ||\n messages.length > 5 ||\n messages.some(\n (message) =>\n typeof message !== 'string' ||\n !message.trim() ||\n message.length > 200 ||\n /[\\u0000-\\u001f\\u007f]/.test(message),\n )\n ) {\n return undefined\n }\n result[field] = [...messages]\n }\n return result\n}\n\nexport function parseContactActionResult(value: unknown): ContactActionResult | undefined {\n const record = objectRecord(value)\n if (!record || typeof record.ok !== 'boolean') return undefined\n if (record.ok) {\n if (record.accepted === true) {\n if (\n !hasOnlyKeys(record, ['ok', 'accepted', 'trackConversion', 'confirmationId']) ||\n record.trackConversion !== true ||\n typeof record.confirmationId !== 'string' ||\n !CONTACT_CONFIRMATION_ID_PATTERN.test(record.confirmationId)\n ) {\n return undefined\n }\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId: record.confirmationId,\n }\n }\n if (\n record.accepted !== false ||\n record.trackConversion !== false ||\n !hasOnlyKeys(record, ['ok', 'accepted', 'trackConversion'])\n ) {\n return undefined\n }\n return { ok: true, accepted: false, trackConversion: false }\n }\n\n if (\n !hasOnlyKeys(record, ['ok', 'code', 'retryable', 'fieldErrors']) ||\n typeof record.code !== 'string' ||\n !CONTACT_ERROR_CODES.has(record.code) ||\n typeof record.retryable !== 'boolean'\n ) {\n return undefined\n }\n const fieldErrors = parseFieldErrors(record.fieldErrors)\n if (record.fieldErrors !== undefined && !fieldErrors) return undefined\n if (record.code !== 'validation' && fieldErrors) return undefined\n return {\n ok: false,\n code: record.code as Extract<ContactActionResult, { ok: false }>['code'],\n retryable: record.retryable,\n ...(fieldErrors ? { fieldErrors } : {}),\n }\n}\n\nexport type ContactSubmissionPhase =\n | 'idle'\n | 'submitting'\n | 'accepted'\n | 'accepted-silently'\n | 'error'\n\nexport interface ContactSubmissionState {\n phase: ContactSubmissionPhase\n pending: boolean\n canRetry: boolean\n result?: ContactActionResult\n}\n\nexport interface ContactHttpSubmissionControllerOptions {\n pagePath: string\n pageLabel?: string\n contactEndpoint?: string\n fetcher?: typeof fetch\n now?: () => Date\n analytics?: Omit<\n Parameters<typeof trackDeliveredContactResult>[1],\n 'formData'\n >\n onStateChange?: (state: ContactSubmissionState) => void\n}\n\nexport interface ContactSubmissionController {\n getState(): ContactSubmissionState\n submit(formData: FormData): Promise<ContactActionResult>\n retry(): Promise<ContactActionResult>\n reset(): void\n}\n\nfunction copyFormData(formData: FormData) {\n if (!formData || typeof formData.entries !== 'function') {\n throw new TypeError('A FormData submission is required.')\n }\n const copy = new FormData()\n for (const [name, value] of formData.entries()) copy.append(name, value)\n return copy\n}\n\nfunction rootRelativeEndpoint(value: string | undefined, fallback: string) {\n const endpoint = value ?? fallback\n if (\n !/^\\/[a-z0-9/_-]+$/.test(endpoint) ||\n endpoint.includes('//') ||\n endpoint.endsWith('/')\n ) {\n throw new TypeError('Contact endpoints must be canonical root-relative paths.')\n }\n return endpoint\n}\n\nasync function boundedJson(response: Response, maximumBytes: number) {\n const contentType = response.headers\n .get('content-type')\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase()\n if (contentType !== 'application/json') {\n throw new Error('The contact response did not use the required JSON media type.')\n }\n const text = await response.text()\n if (new TextEncoder().encode(text).byteLength > maximumBytes) {\n throw new Error('The contact response exceeded its safe bound.')\n }\n return JSON.parse(text) as unknown\n}\n\nconst RETRYABLE_CLIENT_FAILURE: ContactActionResult = {\n ok: false,\n code: 'delivery_unavailable',\n retryable: true,\n}\n\nfunction reviewedPageLabel(value: string | undefined) {\n const label = value?.trim()\n if (\n label !== undefined &&\n (!label || label.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(label))\n ) {\n throw new TypeError('pageLabel must be bounded reviewed text.')\n }\n return label\n}\n\nfunction addSubmissionMetadata(\n formData: FormData,\n options: {\n pagePath: string\n pageLabel?: string\n now: Date\n },\n) {\n const attribution =\n typeof window === 'undefined'\n ? { initialLandingPath: options.pagePath, visitSource: 'direct-or-unknown' as const }\n : getInitialContactAttribution(window)\n formData.set(CONTACT_FORM_FIELDS.clientSubmissionId, createContactSubmissionId())\n formData.set(CONTACT_FORM_FIELDS.submittedAt, options.now.toISOString())\n formData.set(CONTACT_FORM_FIELDS.pagePath, options.pagePath)\n if (options.pageLabel) {\n formData.set(CONTACT_FORM_FIELDS.pageLabel, options.pageLabel)\n }\n formData.set(CONTACT_FORM_FIELDS.initialLandingPath, attribution.initialLandingPath)\n formData.set(CONTACT_FORM_FIELDS.visitSource, attribution.visitSource)\n if (attribution.visitSourceDetail) {\n formData.set(CONTACT_FORM_FIELDS.visitSourceDetail, attribution.visitSourceDetail)\n }\n return formData\n}\n\nexport function createContactHttpSubmissionController(\n options: ContactHttpSubmissionControllerOptions,\n): ContactSubmissionController {\n const contactEndpoint = rootRelativeEndpoint(options.contactEndpoint, '/api/contact')\n const pagePath = normalizeBrandlabRoutePath(options.pagePath)\n const pageLabel = reviewedPageLabel(options.pageLabel)\n const fetcher = options.fetcher ?? fetch\n if (typeof fetcher !== 'function') throw new TypeError('A fetch implementation is required.')\n if (options.onStateChange !== undefined && typeof options.onStateChange !== 'function') {\n throw new TypeError('onStateChange must be a function.')\n }\n\n const trackedConfirmations = new Set<string>()\n let attempt: FormData | undefined\n let inFlight: Promise<ContactActionResult> | undefined\n let state: ContactSubmissionState = {\n phase: 'idle',\n pending: false,\n canRetry: false,\n }\n\n const publish = (next: ContactSubmissionState) => {\n state = Object.freeze({ ...next })\n options.onStateChange?.(state)\n }\n\n const post = async (formData: FormData) => {\n publish({ phase: 'submitting', pending: true, canRetry: false })\n let result: ContactActionResult\n try {\n const response = await fetcher(contactEndpoint, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n body: copyFormData(formData),\n })\n result =\n parseContactActionResult(await boundedJson(response, 64 * 1_024)) ??\n RETRYABLE_CLIENT_FAILURE\n } catch {\n result = RETRYABLE_CLIENT_FAILURE\n }\n\n if (!result.ok) {\n publish({\n phase: 'error',\n pending: false,\n canRetry: result.retryable,\n result,\n })\n return result\n }\n\n if (result.accepted && !trackedConfirmations.has(result.confirmationId)) {\n trackedConfirmations.add(result.confirmationId)\n try {\n if (options.analytics) {\n trackDeliveredContactResult(result, {\n ...options.analytics,\n formData: copyFormData(formData),\n })\n }\n } catch {\n // Delivery has already succeeded; analytics cannot change that result.\n }\n }\n\n attempt = undefined\n publish({\n phase: result.accepted ? 'accepted' : 'accepted-silently',\n pending: false,\n canRetry: false,\n result,\n })\n return result\n }\n\n const run = (formData: FormData) => {\n if (inFlight) return inFlight\n let wrapped: Promise<ContactActionResult>\n wrapped = post(formData).finally(() => {\n if (inFlight === wrapped) inFlight = undefined\n })\n inFlight = wrapped\n return wrapped\n }\n\n return {\n getState: () => ({ ...state }),\n submit(formData) {\n if (inFlight) return inFlight\n const now = options.now?.() ?? new Date()\n if (!Number.isFinite(now.getTime())) {\n attempt = undefined\n publish({\n phase: 'error',\n pending: false,\n canRetry: false,\n result: RETRYABLE_CLIENT_FAILURE,\n })\n return Promise.resolve(RETRYABLE_CLIENT_FAILURE)\n }\n attempt = addSubmissionMetadata(copyFormData(formData), {\n pagePath,\n ...(pageLabel ? { pageLabel } : {}),\n now,\n })\n return run(attempt)\n },\n retry() {\n if (inFlight) return inFlight\n if (!attempt || state.phase !== 'error' || !state.canRetry) {\n return Promise.reject(new Error('No retryable contact submission is available.'))\n }\n return run(attempt)\n },\n reset() {\n if (inFlight) throw new Error('A pending contact submission cannot be reset.')\n attempt = undefined\n publish({ phase: 'idle', pending: false, canRetry: false })\n },\n }\n}\n\nexport function shouldTrackContactResult(\n result: ContactActionResult,\n): result is Extract<ContactActionResult, { ok: true; accepted: true }> {\n return result.ok && result.accepted && result.trackConversion\n}\n\nexport function trackDeliveredContactResult(\n result: ContactActionResult,\n options: {\n pagePath: string\n definition: BrandlabContactDefinition\n formData: FormData\n enabled: boolean\n enhancedConversionsEnabled?: boolean\n adUserDataConsent: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n) {\n const {\n pagePath,\n definition,\n formData,\n adUserDataConsent,\n params,\n adsParams,\n ...config\n } = options\n return trackDeliveredContactWithEnhancedConversions(result, config, {\n pagePath,\n definition,\n formData,\n adUserDataConsent,\n params,\n adsParams,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"client.js","sourceRoot":"","sources":["../../src/contact/client.ts"],"names":[],"mappings":"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","sourcesContent":["'use client'\n\nimport type { GtagTransport } from '@brandlab-digital/site-core/analytics'\nimport {\n resolveContactAttachmentType,\n detectContactTransportAttachmentType,\n type ContactActionResult,\n} from '@brandlab-digital/site-core/contact'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { getInitialContactAttribution } from '../instrumentation-client.js'\nimport {\n trackDeliveredContactWithEnhancedConversions,\n type SafeContactAdsParams,\n type SafeContactAnalyticsParams,\n} from '../analytics.js'\nimport {\n CONTACT_CONFIRMATION_ID_PATTERN,\n CONTACT_FORM_FIELDS,\n createContactSubmissionId,\n type BrandlabContactDefinition,\n} from './shared.js'\n\nexport { createContactSubmissionId }\n\nexport function normalizeContactUploadFile(original: File, processed: Blob): File {\n if (!(original instanceof File) || !(processed instanceof Blob)) {\n throw new TypeError('Contact image normalisation requires browser File and Blob values.')\n }\n const contentType = processed.type || original.type\n const filenameType = resolveContactAttachmentType(original.name)\n const processedType = resolveContactAttachmentType('', contentType)\n const normalizedFilenameType = filenameType === 'image/jpg' ? 'image/jpeg' : filenameType\n const normalizedProcessedType = processedType === 'image/jpg' ? 'image/jpeg' : processedType\n if (!normalizedFilenameType || normalizedFilenameType !== normalizedProcessedType) {\n throw new TypeError('The processed contact image does not match its reviewed filename.')\n }\n return new File([processed], original.name, {\n type: normalizedFilenameType,\n lastModified: original.lastModified,\n })\n}\n\n/** Explicit format-changing path; never relabel the original HEIC bytes as JPEG. */\nexport async function normalizeContactConvertedUploadFile(original: File, processed: Blob): Promise<File> {\n if (!(original instanceof File) || !(processed instanceof Blob)) {\n throw new TypeError('Contact image conversion requires browser File and Blob values.')\n }\n const selectedType = resolveContactAttachmentType(original.name, original.type)\n if (\n !['image/heic', 'image/heif'].includes(selectedType ?? '') ||\n processed.type !== 'image/jpeg' || processed.size === 0 ||\n detectContactTransportAttachmentType(new Uint8Array(await processed.slice(0, 12).arrayBuffer())) !== 'image/jpeg'\n ) {\n throw new TypeError('The converted contact image must contain JPEG bytes.')\n }\n return new File([processed], `${original.name.replace(/\\.[^.]*$/, '') || 'photo'}.jpg`, {\n type: 'image/jpeg', lastModified: original.lastModified,\n })\n}\n\nconst CONTACT_FIELD_ERROR_KEY_PATTERN = /^[a-z][a-z0-9_-]{0,63}$/\nconst CONTACT_ERROR_CODES = new Set([\n 'validation',\n 'attachment_rejected',\n 'delivery_unavailable',\n])\n\nfunction objectRecord(value: unknown): Record<string, unknown> | undefined {\n return value && typeof value === 'object' && !Array.isArray(value)\n ? (value as Record<string, unknown>)\n : undefined\n}\n\nfunction hasOnlyKeys(record: Record<string, unknown>, allowed: readonly string[]) {\n const keys = new Set(allowed)\n return Object.keys(record).every((key) => keys.has(key))\n}\n\nfunction parseFieldErrors(value: unknown) {\n if (value === undefined) return undefined\n const record = objectRecord(value)\n if (!record || Object.keys(record).length > 48) return undefined\n const result: Record<string, string[]> = {}\n for (const [field, messages] of Object.entries(record)) {\n if (\n !CONTACT_FIELD_ERROR_KEY_PATTERN.test(field) ||\n !Array.isArray(messages) ||\n messages.length < 1 ||\n messages.length > 5 ||\n messages.some(\n (message) =>\n typeof message !== 'string' ||\n !message.trim() ||\n message.length > 200 ||\n /[\\u0000-\\u001f\\u007f]/.test(message),\n )\n ) {\n return undefined\n }\n result[field] = [...messages]\n }\n return result\n}\n\nexport function parseContactActionResult(value: unknown): ContactActionResult | undefined {\n const record = objectRecord(value)\n if (!record || typeof record.ok !== 'boolean') return undefined\n if (record.ok) {\n if (record.accepted === true) {\n if (\n !hasOnlyKeys(record, ['ok', 'accepted', 'trackConversion', 'confirmationId']) ||\n record.trackConversion !== true ||\n typeof record.confirmationId !== 'string' ||\n !CONTACT_CONFIRMATION_ID_PATTERN.test(record.confirmationId)\n ) {\n return undefined\n }\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId: record.confirmationId,\n }\n }\n if (\n record.accepted !== false ||\n record.trackConversion !== false ||\n !hasOnlyKeys(record, ['ok', 'accepted', 'trackConversion'])\n ) {\n return undefined\n }\n return { ok: true, accepted: false, trackConversion: false }\n }\n\n if (\n !hasOnlyKeys(record, ['ok', 'code', 'retryable', 'fieldErrors']) ||\n typeof record.code !== 'string' ||\n !CONTACT_ERROR_CODES.has(record.code) ||\n typeof record.retryable !== 'boolean'\n ) {\n return undefined\n }\n const fieldErrors = parseFieldErrors(record.fieldErrors)\n if (record.fieldErrors !== undefined && !fieldErrors) return undefined\n if (record.code !== 'validation' && fieldErrors) return undefined\n return {\n ok: false,\n code: record.code as Extract<ContactActionResult, { ok: false }>['code'],\n retryable: record.retryable,\n ...(fieldErrors ? { fieldErrors } : {}),\n }\n}\n\nexport type ContactSubmissionPhase =\n | 'idle'\n | 'submitting'\n | 'accepted'\n | 'accepted-silently'\n | 'error'\n\nexport interface ContactSubmissionState {\n phase: ContactSubmissionPhase\n pending: boolean\n canRetry: boolean\n result?: ContactActionResult\n}\n\nexport interface ContactHttpSubmissionControllerOptions {\n pagePath: string\n pageLabel?: string\n contactEndpoint?: string\n fetcher?: typeof fetch\n now?: () => Date\n analytics?: Omit<\n Parameters<typeof trackDeliveredContactResult>[1],\n 'formData'\n >\n onStateChange?: (state: ContactSubmissionState) => void\n}\n\nexport interface ContactSubmissionController {\n getState(): ContactSubmissionState\n submit(formData: FormData): Promise<ContactActionResult>\n retry(): Promise<ContactActionResult>\n reset(): void\n}\n\nfunction copyFormData(formData: FormData) {\n if (!formData || typeof formData.entries !== 'function') {\n throw new TypeError('A FormData submission is required.')\n }\n const copy = new FormData()\n for (const [name, value] of formData.entries()) copy.append(name, value)\n return copy\n}\n\nfunction rootRelativeEndpoint(value: string | undefined, fallback: string) {\n const endpoint = value ?? fallback\n if (\n !/^\\/[a-z0-9/_-]+$/.test(endpoint) ||\n endpoint.includes('//') ||\n endpoint.endsWith('/')\n ) {\n throw new TypeError('Contact endpoints must be canonical root-relative paths.')\n }\n return endpoint\n}\n\nasync function boundedJson(response: Response, maximumBytes: number) {\n const contentType = response.headers\n .get('content-type')\n ?.split(';', 1)[0]\n ?.trim()\n .toLowerCase()\n if (contentType !== 'application/json') {\n throw new Error('The contact response did not use the required JSON media type.')\n }\n const text = await response.text()\n if (new TextEncoder().encode(text).byteLength > maximumBytes) {\n throw new Error('The contact response exceeded its safe bound.')\n }\n return JSON.parse(text) as unknown\n}\n\nconst RETRYABLE_CLIENT_FAILURE: ContactActionResult = {\n ok: false,\n code: 'delivery_unavailable',\n retryable: true,\n}\n\nfunction reviewedPageLabel(value: string | undefined) {\n const label = value?.trim()\n if (\n label !== undefined &&\n (!label || label.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(label))\n ) {\n throw new TypeError('pageLabel must be bounded reviewed text.')\n }\n return label\n}\n\nfunction addSubmissionMetadata(\n formData: FormData,\n options: {\n pagePath: string\n pageLabel?: string\n now: Date\n },\n) {\n const attribution =\n typeof window === 'undefined'\n ? { initialLandingPath: options.pagePath, visitSource: 'direct-or-unknown' as const }\n : getInitialContactAttribution(window)\n formData.set(CONTACT_FORM_FIELDS.clientSubmissionId, createContactSubmissionId())\n formData.set(CONTACT_FORM_FIELDS.submittedAt, options.now.toISOString())\n formData.set(CONTACT_FORM_FIELDS.pagePath, options.pagePath)\n if (options.pageLabel) {\n formData.set(CONTACT_FORM_FIELDS.pageLabel, options.pageLabel)\n }\n formData.set(CONTACT_FORM_FIELDS.initialLandingPath, attribution.initialLandingPath)\n formData.set(CONTACT_FORM_FIELDS.visitSource, attribution.visitSource)\n if (attribution.visitSourceDetail) {\n formData.set(CONTACT_FORM_FIELDS.visitSourceDetail, attribution.visitSourceDetail)\n }\n return formData\n}\n\nexport function createContactHttpSubmissionController(\n options: ContactHttpSubmissionControllerOptions,\n): ContactSubmissionController {\n const contactEndpoint = rootRelativeEndpoint(options.contactEndpoint, '/api/contact')\n const pagePath = normalizeBrandlabRoutePath(options.pagePath)\n const pageLabel = reviewedPageLabel(options.pageLabel)\n const fetcher = options.fetcher ?? fetch\n if (typeof fetcher !== 'function') throw new TypeError('A fetch implementation is required.')\n if (options.onStateChange !== undefined && typeof options.onStateChange !== 'function') {\n throw new TypeError('onStateChange must be a function.')\n }\n\n const trackedConfirmations = new Set<string>()\n let attempt: FormData | undefined\n let inFlight: Promise<ContactActionResult> | undefined\n let state: ContactSubmissionState = {\n phase: 'idle',\n pending: false,\n canRetry: false,\n }\n\n const publish = (next: ContactSubmissionState) => {\n state = Object.freeze({ ...next })\n options.onStateChange?.(state)\n }\n\n const post = async (formData: FormData) => {\n publish({ phase: 'submitting', pending: true, canRetry: false })\n let result: ContactActionResult\n try {\n const response = await fetcher(contactEndpoint, {\n method: 'POST',\n credentials: 'same-origin',\n cache: 'no-store',\n body: copyFormData(formData),\n })\n result =\n parseContactActionResult(await boundedJson(response, 64 * 1_024)) ??\n RETRYABLE_CLIENT_FAILURE\n } catch {\n result = RETRYABLE_CLIENT_FAILURE\n }\n\n if (!result.ok) {\n publish({\n phase: 'error',\n pending: false,\n canRetry: result.retryable,\n result,\n })\n return result\n }\n\n if (result.accepted && !trackedConfirmations.has(result.confirmationId)) {\n trackedConfirmations.add(result.confirmationId)\n try {\n if (options.analytics) {\n trackDeliveredContactResult(result, {\n ...options.analytics,\n formData: copyFormData(formData),\n })\n }\n } catch {\n // Delivery has already succeeded; analytics cannot change that result.\n }\n }\n\n attempt = undefined\n publish({\n phase: result.accepted ? 'accepted' : 'accepted-silently',\n pending: false,\n canRetry: false,\n result,\n })\n return result\n }\n\n const run = (formData: FormData) => {\n if (inFlight) return inFlight\n let wrapped: Promise<ContactActionResult>\n wrapped = post(formData).finally(() => {\n if (inFlight === wrapped) inFlight = undefined\n })\n inFlight = wrapped\n return wrapped\n }\n\n return {\n getState: () => ({ ...state }),\n submit(formData) {\n if (inFlight) return inFlight\n const now = options.now?.() ?? new Date()\n if (!Number.isFinite(now.getTime())) {\n attempt = undefined\n publish({\n phase: 'error',\n pending: false,\n canRetry: false,\n result: RETRYABLE_CLIENT_FAILURE,\n })\n return Promise.resolve(RETRYABLE_CLIENT_FAILURE)\n }\n attempt = addSubmissionMetadata(copyFormData(formData), {\n pagePath,\n ...(pageLabel ? { pageLabel } : {}),\n now,\n })\n return run(attempt)\n },\n retry() {\n if (inFlight) return inFlight\n if (!attempt || state.phase !== 'error' || !state.canRetry) {\n return Promise.reject(new Error('No retryable contact submission is available.'))\n }\n return run(attempt)\n },\n reset() {\n if (inFlight) throw new Error('A pending contact submission cannot be reset.')\n attempt = undefined\n publish({ phase: 'idle', pending: false, canRetry: false })\n },\n }\n}\n\nexport function shouldTrackContactResult(\n result: ContactActionResult,\n): result is Extract<ContactActionResult, { ok: true; accepted: true }> {\n return result.ok && result.accepted && result.trackConversion\n}\n\nexport function trackDeliveredContactResult(\n result: ContactActionResult,\n options: {\n pagePath: string\n definition: BrandlabContactDefinition\n formData: FormData\n enabled: boolean\n enhancedConversionsEnabled?: boolean\n adUserDataConsent: boolean\n measurementId?: string | null\n googleAdsConversionId?: string | null\n googleAdsConversionLabel?: string | null\n gtag?: GtagTransport\n params?: SafeContactAnalyticsParams\n adsParams?: SafeContactAdsParams\n },\n) {\n const {\n pagePath,\n definition,\n formData,\n adUserDataConsent,\n params,\n adsParams,\n ...config\n } = options\n return trackDeliveredContactWithEnhancedConversions(result, config, {\n pagePath,\n definition,\n formData,\n adUserDataConsent,\n params,\n adsParams,\n })\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-sanitizer.d.ts","sourceRoot":"","sources":["../../src/contact/image-sanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;
|
|
1
|
+
{"version":3,"file":"image-sanitizer.d.ts","sourceRoot":"","sources":["../../src/contact/image-sanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,qBAAqB,CAAA;AAI5B,OAAO,KAAK,EACV,0BAA0B,EAE3B,MAAM,aAAa,CAAA;AA2GpB;;;;GAIG;AACH,wBAAgB,mCAAmC,IAAI,0BAA0B,CA4BhF"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
|
+
import '../image-runtime.js';
|
|
2
3
|
import { sanitizeContactPdf } from './pdf-sanitizer.js';
|
|
3
4
|
import sharp, {} from 'sharp';
|
|
5
|
+
import { detectContactTransportAttachmentType } from '@brandlab-digital/site-core/contact';
|
|
6
|
+
sharp.block({ operation: ['VipsForeignLoadHeif'] });
|
|
4
7
|
const MAX_INPUT_PIXELS = 50_000_000;
|
|
5
8
|
const MAX_OUTPUT_DIMENSION = 4_096;
|
|
6
9
|
const PROCESSING_TIMEOUT_SECONDS = 5;
|
|
@@ -10,8 +13,6 @@ const INPUT_FORMAT_BY_MIME = Object.freeze({
|
|
|
10
13
|
'image/png': 'png',
|
|
11
14
|
'image/gif': 'gif',
|
|
12
15
|
'image/webp': 'webp',
|
|
13
|
-
'image/heic': 'heif',
|
|
14
|
-
'image/heif': 'heif',
|
|
15
16
|
});
|
|
16
17
|
function expectedInputFormat(contentType) {
|
|
17
18
|
return INPUT_FORMAT_BY_MIME[contentType.trim().toLowerCase()];
|
|
@@ -53,6 +54,12 @@ async function sanitizeOne(attachment) {
|
|
|
53
54
|
}
|
|
54
55
|
// Buffer.from(Uint8Array) copies untrusted request bytes before native work.
|
|
55
56
|
const input = Buffer.from(attachment.content);
|
|
57
|
+
const detected = detectContactTransportAttachmentType(input);
|
|
58
|
+
if (!detected || expectedInputFormat(detected) !== expectedFormat) {
|
|
59
|
+
throw new Error('The uploaded bytes do not match a supported image type.');
|
|
60
|
+
}
|
|
61
|
+
// Independent of Next's lazy optimizer initialization. Never unblock a loader.
|
|
62
|
+
sharp.block({ operation: ['VipsForeignLoadHeif'] });
|
|
56
63
|
const image = sharp(input, {
|
|
57
64
|
animated: false,
|
|
58
65
|
failOn: 'warning',
|
|
@@ -94,10 +101,24 @@ export function createBrandlabContactImageSanitizer() {
|
|
|
94
101
|
if (!Array.isArray(attachments))
|
|
95
102
|
return { ok: false };
|
|
96
103
|
try {
|
|
104
|
+
// Match the existing absolute request envelope; per-form limits are
|
|
105
|
+
// enforced by the server before and after processing.
|
|
106
|
+
if (attachments.length > 20)
|
|
107
|
+
return { ok: false };
|
|
108
|
+
let total = 0;
|
|
109
|
+
for (const attachment of attachments) {
|
|
110
|
+
if (!(attachment?.content instanceof Uint8Array))
|
|
111
|
+
return { ok: false };
|
|
112
|
+
total += attachment.content.byteLength;
|
|
113
|
+
if (attachment.content.byteLength < 1 || attachment.content.byteLength > 4_500_000 || total > 4_500_000)
|
|
114
|
+
return { ok: false };
|
|
115
|
+
}
|
|
97
116
|
const sanitized = [];
|
|
98
117
|
// Sequential processing bounds peak native memory for multiple photos.
|
|
99
118
|
for (const attachment of attachments) {
|
|
100
|
-
sanitized.push(attachment.contentType === 'application/pdf'
|
|
119
|
+
sanitized.push(attachment.contentType === 'application/pdf'
|
|
120
|
+
? await sanitizeContactPdf(attachment)
|
|
121
|
+
: await sanitizeOne(attachment));
|
|
101
122
|
}
|
|
102
123
|
return { ok: true, attachments: Object.freeze(sanitized) };
|
|
103
124
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-sanitizer.js","sourceRoot":"","sources":["../../src/contact/image-sanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAAE,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AACvD,OAAO,KAAK,EAAE,EAA6B,MAAM,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"image-sanitizer.js","sourceRoot":"","sources":["../../src/contact/image-sanitizer.ts"],"names":[],"mappings":"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","sourcesContent":["import 'server-only'\n\nimport '../image-runtime.js'\nimport { sanitizeContactPdf } from './pdf-sanitizer.js'\nimport sharp, { type Metadata, type Sharp } from 'sharp'\nimport { detectContactTransportAttachmentType } from '@brandlab-digital/site-core/contact'\nimport type {\n ContactAttachmentProcessor,\n ContactDeliveryAttachment,\n} from './shared.js'\n\nsharp.block({ operation: ['VipsForeignLoadHeif'] })\n\nconst MAX_INPUT_PIXELS = 50_000_000\nconst MAX_OUTPUT_DIMENSION = 4_096\nconst PROCESSING_TIMEOUT_SECONDS = 5\n\nconst INPUT_FORMAT_BY_MIME = Object.freeze({\n 'image/jpeg': 'jpeg',\n 'image/jpg': 'jpeg',\n 'image/png': 'png',\n 'image/gif': 'gif',\n 'image/webp': 'webp',\n} as const)\n\nfunction expectedInputFormat(contentType: string) {\n return INPUT_FORMAT_BY_MIME[\n contentType.trim().toLowerCase() as keyof typeof INPUT_FORMAT_BY_MIME\n ]\n}\n\nfunction assertSingleImage(metadata: Metadata, expectedFormat: string) {\n if (\n metadata.format !== expectedFormat ||\n !Number.isSafeInteger(metadata.width) ||\n !Number.isSafeInteger(metadata.height) ||\n !metadata.width ||\n !metadata.height ||\n (metadata.pages ?? 1) !== 1\n ) {\n throw new Error('The uploaded file is not one supported still image.')\n }\n}\n\nfunction outputFilename(filename: string) {\n const stem = filename.replace(/\\.[a-z0-9]+$/i, '')\n if (!/^[a-z0-9]+(?:-[a-z0-9]+)*$/.test(stem)) {\n throw new Error('The validated attachment filename is invalid.')\n }\n return `${stem}.jpg`\n}\n\nfunction outputPipeline(image: Sharp) {\n return image\n .autoOrient()\n .resize({\n width: MAX_OUTPUT_DIMENSION,\n height: MAX_OUTPUT_DIMENSION,\n fit: 'inside',\n withoutEnlargement: true,\n })\n .flatten({ background: '#ffffff' })\n .timeout({ seconds: PROCESSING_TIMEOUT_SECONDS })\n .jpeg({ quality: 85, progressive: true, mozjpeg: true })\n}\n\nasync function sanitizeOne(\n attachment: ContactDeliveryAttachment,\n): Promise<ContactDeliveryAttachment> {\n const expectedFormat = expectedInputFormat(attachment.contentType)\n if (!expectedFormat || !(attachment.content instanceof Uint8Array)) {\n throw new Error('The uploaded file type is unsupported.')\n }\n\n // Buffer.from(Uint8Array) copies untrusted request bytes before native work.\n const input = Buffer.from(attachment.content)\n const detected = detectContactTransportAttachmentType(input)\n if (!detected || expectedInputFormat(detected) !== expectedFormat) {\n throw new Error('The uploaded bytes do not match a supported image type.')\n }\n // Independent of Next's lazy optimizer initialization. Never unblock a loader.\n sharp.block({ operation: ['VipsForeignLoadHeif'] })\n const image = sharp(input, {\n animated: false,\n failOn: 'warning',\n limitInputPixels: MAX_INPUT_PIXELS,\n pages: 1,\n sequentialRead: true,\n unlimited: false,\n })\n const metadata = await image.metadata()\n assertSingleImage(metadata, expectedFormat)\n\n const { data, info } = await outputPipeline(image).toBuffer({\n resolveWithObject: true,\n })\n if (\n data.byteLength < 1 ||\n info.format !== 'jpeg' ||\n !Number.isSafeInteger(info.width) ||\n !Number.isSafeInteger(info.height) ||\n info.width < 1 ||\n info.height < 1 ||\n info.width > MAX_OUTPUT_DIMENSION ||\n info.height > MAX_OUTPUT_DIMENSION\n ) {\n throw new Error('The uploaded image could not be normalised safely.')\n }\n\n return Object.freeze({\n filename: outputFilename(attachment.filename),\n content: new Uint8Array(data),\n contentType: 'image/jpeg',\n })\n}\n\n/**\n * The production image boundary for Contact Contract v4. Every accepted image\n * is fully decoded, bounded, auto-oriented and re-encoded without source\n * metadata. Project code cannot replace this processor in production.\n */\nexport function createBrandlabContactImageSanitizer(): ContactAttachmentProcessor {\n return Object.freeze({\n capability: 'sanitizes-contact-images-v1' as const,\n async process({ attachments }: Parameters<ContactAttachmentProcessor['process']>[0]) {\n if (!Array.isArray(attachments)) return { ok: false as const }\n try {\n // Match the existing absolute request envelope; per-form limits are\n // enforced by the server before and after processing.\n if (attachments.length > 20) return { ok: false as const }\n let total = 0\n for (const attachment of attachments) {\n if (!(attachment?.content instanceof Uint8Array)) return { ok: false as const }\n total += attachment.content.byteLength\n if (attachment.content.byteLength < 1 || attachment.content.byteLength > 4_500_000 || total > 4_500_000) return { ok: false as const }\n }\n const sanitized: ContactDeliveryAttachment[] = []\n // Sequential processing bounds peak native memory for multiple photos.\n for (const attachment of attachments) {\n sanitized.push(attachment.contentType === 'application/pdf'\n ? await sanitizeContactPdf(attachment)\n : await sanitizeOne(attachment))\n }\n return { ok: true as const, attachments: Object.freeze(sanitized) }\n } catch {\n return { ok: false as const }\n }\n },\n })\n}\n"]}
|
package/dist/contact/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './shared.js';
|
|
2
2
|
export * from './contract.js';
|
|
3
|
-
export { createContactHttpSubmissionController, normalizeContactUploadFile, parseContactActionResult, shouldTrackContactResult, trackDeliveredContactResult, type ContactHttpSubmissionControllerOptions, type ContactSubmissionController, type ContactSubmissionPhase, type ContactSubmissionState, } from './client.js';
|
|
3
|
+
export { createContactHttpSubmissionController, normalizeContactUploadFile, normalizeContactConvertedUploadFile, parseContactActionResult, shouldTrackContactResult, trackDeliveredContactResult, type ContactHttpSubmissionControllerOptions, type ContactSubmissionController, type ContactSubmissionPhase, type ContactSubmissionState, } from './client.js';
|
|
4
4
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contact/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EACL,qCAAqC,EACrC,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,sCAAsC,EAC3C,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/contact/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EACL,qCAAqC,EACrC,0BAA0B,EAC1B,mCAAmC,EACnC,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,EAC3B,KAAK,sCAAsC,EAC3C,KAAK,2BAA2B,EAChC,KAAK,sBAAsB,EAC3B,KAAK,sBAAsB,GAC5B,MAAM,aAAa,CAAA"}
|
package/dist/contact/index.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
1
|
export * from './shared.js';
|
|
2
2
|
export * from './contract.js';
|
|
3
|
-
export { createContactHttpSubmissionController, normalizeContactUploadFile, parseContactActionResult, shouldTrackContactResult, trackDeliveredContactResult, } from './client.js';
|
|
3
|
+
export { createContactHttpSubmissionController, normalizeContactUploadFile, normalizeContactConvertedUploadFile, parseContactActionResult, shouldTrackContactResult, trackDeliveredContactResult, } from './client.js';
|
|
4
4
|
//# sourceMappingURL=index.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contact/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EACL,qCAAqC,EACrC,0BAA0B,EAC1B,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,GAK5B,MAAM,aAAa,CAAA","sourcesContent":["export * from './shared.js'\nexport * from './contract.js'\nexport {\n createContactHttpSubmissionController,\n normalizeContactUploadFile,\n parseContactActionResult,\n shouldTrackContactResult,\n trackDeliveredContactResult,\n type ContactHttpSubmissionControllerOptions,\n type ContactSubmissionController,\n type ContactSubmissionPhase,\n type ContactSubmissionState,\n} from './client.js'\n"]}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/contact/index.ts"],"names":[],"mappings":"AAAA,cAAc,aAAa,CAAA;AAC3B,cAAc,eAAe,CAAA;AAC7B,OAAO,EACL,qCAAqC,EACrC,0BAA0B,EAC1B,mCAAmC,EACnC,wBAAwB,EACxB,wBAAwB,EACxB,2BAA2B,GAK5B,MAAM,aAAa,CAAA","sourcesContent":["export * from './shared.js'\nexport * from './contract.js'\nexport {\n createContactHttpSubmissionController,\n normalizeContactUploadFile,\n normalizeContactConvertedUploadFile,\n parseContactActionResult,\n shouldTrackContactResult,\n trackDeliveredContactResult,\n type ContactHttpSubmissionControllerOptions,\n type ContactSubmissionController,\n type ContactSubmissionPhase,\n type ContactSubmissionState,\n} from './client.js'\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-sanitizer.d.ts","sourceRoot":"","sources":["../../src/contact/pdf-sanitizer.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"pdf-sanitizer.d.ts","sourceRoot":"","sources":["../../src/contact/pdf-sanitizer.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAG5D;qEACqE;AACrE,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAyBlH"}
|
|
@@ -1,8 +1,11 @@
|
|
|
1
1
|
import { PDFDocument, PDFDict, PDFName, PDFArray } from 'pdf-lib';
|
|
2
|
+
import { detectContactTransportAttachmentType } from '@brandlab-digital/site-core/contact';
|
|
2
3
|
const REJECTED_KEYS = new Set(['JS', 'JavaScript', 'AA', 'OpenAction', 'Launch', 'EmbeddedFiles', 'EmbeddedFile', 'XFA', 'RichMedia', 'SubmitForm', 'ImportData', 'GoToR', 'GoToE', 'AcroForm', 'AF']);
|
|
3
4
|
/** Accept bounded, static plans only. Rebuild page graphics without annotations,
|
|
4
5
|
* document actions, attachments, forms, links or source metadata. */
|
|
5
6
|
export async function sanitizeContactPdf(attachment) {
|
|
7
|
+
if (attachment.contentType !== 'application/pdf' || !(attachment.content instanceof Uint8Array) || detectContactTransportAttachmentType(attachment.content) !== 'application/pdf')
|
|
8
|
+
throw new Error('Invalid PDF signature or type.');
|
|
6
9
|
if (!(attachment.content instanceof Uint8Array) || attachment.content.byteLength > 4_000_000 || !/^document-\d+\.pdf$/.test(attachment.filename))
|
|
7
10
|
throw new Error('Invalid document attachment.');
|
|
8
11
|
const input = await PDFDocument.load(attachment.content, { ignoreEncryption: false, updateMetadata: false, throwOnInvalidObject: true });
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"pdf-sanitizer.js","sourceRoot":"","sources":["../../src/contact/pdf-sanitizer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,OAAO,EAAE,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAA;
|
|
1
|
+
{"version":3,"file":"pdf-sanitizer.js","sourceRoot":"","sources":["../../src/contact/pdf-sanitizer.ts"],"names":[],"mappings":"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","sourcesContent":["import { PDFDocument, PDFDict, PDFName, PDFArray } from 'pdf-lib'\nimport { detectContactTransportAttachmentType } from '@brandlab-digital/site-core/contact'\nimport type { ContactDeliveryAttachment } from './shared.js'\n\nconst REJECTED_KEYS = new Set(['JS','JavaScript','AA','OpenAction','Launch','EmbeddedFiles','EmbeddedFile','XFA','RichMedia','SubmitForm','ImportData','GoToR','GoToE','AcroForm','AF'])\n/** Accept bounded, static plans only. Rebuild page graphics without annotations,\n * document actions, attachments, forms, links or source metadata. */\nexport async function sanitizeContactPdf(attachment: ContactDeliveryAttachment): Promise<ContactDeliveryAttachment> {\n if (attachment.contentType !== 'application/pdf' || !(attachment.content instanceof Uint8Array) || detectContactTransportAttachmentType(attachment.content) !== 'application/pdf') throw new Error('Invalid PDF signature or type.')\n if (!(attachment.content instanceof Uint8Array) || attachment.content.byteLength > 4_000_000 || !/^document-\\d+\\.pdf$/.test(attachment.filename)) throw new Error('Invalid document attachment.')\n const input = await PDFDocument.load(attachment.content, { ignoreEncryption: false, updateMetadata: false, throwOnInvalidObject: true })\n if (input.isEncrypted || input.getPageCount() < 1 || input.getPageCount() > 100) throw new Error('Unsupported PDF document.')\n for (const [, object] of input.context.enumerateIndirectObjects()) {\n if (object instanceof PDFDict) {\n for (const [key, value] of object.entries()) {\n if (key.decodeText() === 'Annots') { const annotations = input.context.lookup(value); if (!(annotations instanceof PDFArray) || annotations.size() > 0) throw new Error('Annotated PDF documents must be flattened before upload.') }\n if (REJECTED_KEYS.has(key.decodeText()) || (value instanceof PDFName && REJECTED_KEYS.has(value.decodeText()))) throw new Error('Interactive PDF documents are not supported.')\n }\n }\n }\n const output = await PDFDocument.create({ updateMetadata: false })\n for (const page of input.getPages()) {\n const {width,height} = page.getSize()\n if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0 || width > 20_000 || height > 20_000) throw new Error('Unsupported PDF page dimensions.')\n const embedded = await output.embedPage(page)\n const copied = output.addPage([width,height])\n copied.drawPage(embedded)\n copied.setRotation(page.getRotation())\n }\n const content = await output.save({ useObjectStreams: true, addDefaultPage: false })\n if (!content.byteLength || content.byteLength > 4_000_000) throw new Error('PDF output exceeds the attachment limit.')\n return Object.freeze({filename:attachment.filename,content,contentType:'application/pdf'})\n}\n"]}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAOL,KAAK,uBAAuB,EAI7B,MAAM,qCAAqC,CAAA;AAI5C,OAAO,EACL,mCAAmC,EACnC,KAAK,+BAA+B,EACrC,MAAM,eAAe,CAAA;AAGtB,OAAO,EAEL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAA;AACpB,OAAO,EAIL,KAAK,yBAAyB,EAC9B,KAAK,6BAA6B,EAClC,KAAK,0BAA0B,EAE/B,KAAK,eAAe,EAIpB,KAAK,gBAAgB,EACtB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AACxD,YAAY,EAAE,iBAAiB,EAAE,sBAAsB,EAAE,MAAM,aAAa,CAAA;AAE5E,eAAO,MAAM,wBAAwB,EAAG,qBAA8B,CAAA;AACtE,eAAO,MAAM,4BAA4B,EAAG,gBAAyB,CAAA;AACrE,eAAO,MAAM,kCAAkC,UAAY,CAAA;AAE3D,wBAAgB,mCAAmC,CACjD,WAAW,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,GACxD,6BAA6B,CAK/B;AA2BD,MAAM,MAAM,uCAAuC,GAAG,IAAI,CACxD,+BAA+B,EAC/B,gBAAgB,CACjB,CAAA;AAED,MAAM,WAAW,6BAA6B;IAC5C,QAAQ,EAAE,uBAAuB,CAAA;IACjC,OAAO,EAAE,uCAAuC,CAAA;IAChD,WAAW,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,CAAC,CAAC,CAAA;IAC1D,cAAc,CAAC,EAAE,6BAA6B,CAAA;IAC9C,gBAAgB,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,iBAAiB,CAAA;IACvD,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB;AAED,MAAM,WAAW,sBAAsB;IACrC,WAAW,EAAE,OAAO,wBAAwB,CAAA;IAC5C,UAAU,EAAE,UAAU,CAAC,OAAO,mCAAmC,CAAC,CAAA;IAClE,mBAAmB,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;CAC7D;AAED,UAAU,0BAA0B;IAClC,UAAU,EAAE,yBAAyB,CAAA;IACrC,SAAS,CAAC,EAAE,gBAAgB,CAAA;IAC5B,mBAAmB,CAAC,EAAE,0BAA0B,CAAA;IAChD,QAAQ,CAAC,EAAE,eAAe,CAAA;IAC1B,GAAG,CAAC,EAAE,MAAM,IAAI,CAAA;CACjB;AA4ID,wBAAgB,uBAAuB,CAAC,UAAU,EAAE,yBAAyB;;;;EAQ5E;AAyjBD,wBAAgB,yBAAyB,CAAC,OAAO,EAAE,0BAA0B,IAa7D,SAAS,OAAO,KAAG,OAAO,CAAC,QAAQ,CAAC,CA6BnD;AAkCD,wBAAgB,4BAA4B,CAC1C,OAAO,EAAE,6BAA6B,GACrC,sBAAsB,CAmCxB"}
|
package/dist/contact/server.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
|
-
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, createContactAttachmentFilename, defineContactContract, parseContactEmailRecipients, } from '@brandlab-digital/site-core/contact';
|
|
2
|
+
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, deriveContactAttachmentTransportPolicy, detectContactTransportAttachmentType, createContactAttachmentFilename, defineContactContract, parseContactEmailRecipients, } from '@brandlab-digital/site-core/contact';
|
|
3
3
|
import { isBrandlabCanonicalEntityId } from '@brandlab-digital/site-core/entity-id';
|
|
4
4
|
import { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes';
|
|
5
5
|
import { normalizeContactAttributionSummary } from './attribution.js';
|
|
@@ -159,10 +159,10 @@ function assertDefinition(definition) {
|
|
|
159
159
|
}
|
|
160
160
|
}
|
|
161
161
|
function attachmentPolicy(definition) {
|
|
162
|
-
return {
|
|
162
|
+
return deriveContactAttachmentTransportPolicy({
|
|
163
163
|
...DEFAULT_CONTACT_ATTACHMENT_POLICY,
|
|
164
164
|
...(definition.attachments || {}),
|
|
165
|
-
};
|
|
165
|
+
});
|
|
166
166
|
}
|
|
167
167
|
export function getContactRequestLimits(definition) {
|
|
168
168
|
return {
|
|
@@ -280,39 +280,6 @@ function normalizeMimeType(value) {
|
|
|
280
280
|
const normalized = value.trim().toLowerCase();
|
|
281
281
|
return normalized === 'image/jpg' ? 'image/jpeg' : normalized;
|
|
282
282
|
}
|
|
283
|
-
function startsWithBytes(bytes, signature) {
|
|
284
|
-
return signature.every((byte, index) => bytes[index] === byte);
|
|
285
|
-
}
|
|
286
|
-
function ascii(bytes, start, length) {
|
|
287
|
-
return String.fromCharCode(...bytes.slice(start, start + length));
|
|
288
|
-
}
|
|
289
|
-
function detectAttachmentType(bytes) {
|
|
290
|
-
if (ascii(bytes, 0, 5) === '%PDF-')
|
|
291
|
-
return 'application/pdf';
|
|
292
|
-
if (startsWithBytes(bytes, [0xff, 0xd8, 0xff]))
|
|
293
|
-
return 'image/jpeg';
|
|
294
|
-
if (startsWithBytes(bytes, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) {
|
|
295
|
-
return 'image/png';
|
|
296
|
-
}
|
|
297
|
-
const gif = ascii(bytes, 0, 6);
|
|
298
|
-
if (gif === 'GIF87a' || gif === 'GIF89a')
|
|
299
|
-
return 'image/gif';
|
|
300
|
-
if (ascii(bytes, 0, 4) === 'RIFF' && ascii(bytes, 8, 4) === 'WEBP')
|
|
301
|
-
return 'image/webp';
|
|
302
|
-
if (ascii(bytes, 4, 4) === 'ftyp') {
|
|
303
|
-
const brands = new Set();
|
|
304
|
-
for (let offset = 8; offset + 4 <= Math.min(bytes.length, 64); offset += 4) {
|
|
305
|
-
brands.add(ascii(bytes, offset, 4));
|
|
306
|
-
}
|
|
307
|
-
if (['heic', 'heix', 'hevc', 'hevx'].some((brand) => brands.has(brand))) {
|
|
308
|
-
return 'image/heic';
|
|
309
|
-
}
|
|
310
|
-
if (['heif', 'mif1', 'msf1'].some((brand) => brands.has(brand))) {
|
|
311
|
-
return 'image/heif';
|
|
312
|
-
}
|
|
313
|
-
}
|
|
314
|
-
return undefined;
|
|
315
|
-
}
|
|
316
283
|
async function readValidatedAttachments(definition, formData) {
|
|
317
284
|
if (!definition.attachments)
|
|
318
285
|
return [];
|
|
@@ -345,7 +312,7 @@ async function readValidatedAttachments(definition, formData) {
|
|
|
345
312
|
if (totalBytes > policy.maxTotalSizeBytes)
|
|
346
313
|
return undefined;
|
|
347
314
|
const content = new Uint8Array(await file.arrayBuffer());
|
|
348
|
-
if (normalizeMimeType(
|
|
315
|
+
if (normalizeMimeType(detectContactTransportAttachmentType(content.slice(0, 64)) ?? '') !== declaredType) {
|
|
349
316
|
return undefined;
|
|
350
317
|
}
|
|
351
318
|
attachments.push({
|
|
@@ -370,7 +337,7 @@ function validateProcessedAttachments(definition, attachments) {
|
|
|
370
337
|
attachment.content.byteLength > 0 &&
|
|
371
338
|
attachment.content.byteLength <= policy.maxFileSizeBytes &&
|
|
372
339
|
totalBytes <= policy.maxTotalSizeBytes &&
|
|
373
|
-
|
|
340
|
+
detectContactTransportAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType);
|
|
374
341
|
});
|
|
375
342
|
}
|
|
376
343
|
function validationResult(fieldErrors) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"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","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n createContactAttachmentFilename,\n defineContactContract,\n parseContactEmailRecipients,\n type BrandlabContactContract,\n type ContactActionResult,\n type ContactAttachmentMimeType,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport { isBrandlabCanonicalEntityId } from '@brandlab-digital/site-core/entity-id'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { normalizeContactAttributionSummary } from './attribution.js'\nimport {\n createContactDefinitionFromContract,\n type ContactRuntimeDefinitionOptions,\n} from './contract.js'\nimport { renderContactEmail } from './email.js'\nimport { createBrandlabContactImageSanitizer } from './image-sanitizer.js'\nimport {\n createContractResendContactTransport,\n type ResendContactSend,\n} from './resend.js'\nimport {\n CONTACT_CLIENT_SUBMISSION_ID_PATTERN,\n CONTACT_CONFIRMATION_ID_PATTERN,\n CONTACT_FORM_FIELDS,\n type BrandlabContactDefinition,\n type BrandlabContactDeploymentMode,\n type ContactAttachmentProcessor,\n type ContactBotAssessment,\n type ContactBotGuard,\n type ContactDeliveryAttachment,\n type ContactPageContext,\n type ContactRequestContext,\n type ContactTransport,\n} from './shared.js'\n\nexport { createBrandlabContactImageSanitizer } from './image-sanitizer.js'\nexport { createResendSdkContactSend } from './resend.js'\nexport type { ResendContactSend, ResendSdkContactClient } from './resend.js'\n\nexport const BRANDLAB_CONTACT_RUNTIME = 'brandlab-contact-v4' as const\nexport const BRANDLAB_CONTACT_API_KEY_ENV = 'RESEND_API_KEY' as const\nexport const BRANDLAB_CONTACT_MAX_REQUEST_BYTES = 4_500_000\n\nexport function detectBrandlabContactDeploymentMode(\n environment: Readonly<Record<string, string | undefined>>,\n): BrandlabContactDeploymentMode {\n if (environment.VERCEL_ENV === 'production') return 'production'\n if (environment.VERCEL_ENV === 'preview') return 'preview'\n if (environment.NODE_ENV === 'test') return 'test'\n return 'development'\n}\n\nconst FORM_URLENCODED = 'application/x-www-form-urlencoded'\nconst MULTIPART_FORM = 'multipart/form-data'\nconst MULTIPART_BOUNDARY_PATTERN =\n /(?:^|;)\\s*boundary=(?:\"[0-9A-Za-z'()+_,.\\/:=?-]{1,70}\"|[0-9A-Za-z'()+_,.\\/:=?-]{1,70})(?:;|$)/i\nconst FIELD_NAME_PATTERN = /^[a-z][A-Za-z0-9_-]{0,63}$/\nconst SAFE_PROVIDER_MESSAGE_ID_PATTERN = /^[A-Za-z0-9._-]{1,256}$/\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst EMAIL_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/\nconst ISO_TIMESTAMP_PATTERN =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/\nconst MAX_SUBMISSION_AGE_MS = 24 * 60 * 60 * 1_000\nconst MAX_CLOCK_SKEW_MS = 5 * 60 * 1_000\nconst DEFAULT_MAX_ENTRIES = 64\nconst DEFAULT_MAX_STRING_BYTES = 64 * 1_024\nconst SUPPORTED_ATTACHMENT_MIME_TYPES = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/heic',\n 'image/heif',\n])\n\nexport type BrandlabContactRuntimeDefinitionOptions = Omit<\n ContactRuntimeDefinitionOptions,\n 'deploymentMode'\n>\n\nexport interface BrandlabContactRuntimeOptions {\n contract: BrandlabContactContract\n runtime: BrandlabContactRuntimeDefinitionOptions\n environment?: Readonly<Record<string, string | undefined>>\n deploymentMode?: BrandlabContactDeploymentMode\n createResendSend: (apiKey: string) => ResendContactSend\n botGuard?: ContactBotGuard\n now?: () => Date\n}\n\nexport interface BrandlabContactRuntime {\n runtimeKind: typeof BRANDLAB_CONTACT_RUNTIME\n definition: ReturnType<typeof createContactDefinitionFromContract>\n contactRouteHandler: (request: Request) => Promise<Response>\n}\n\ninterface ContactRouteHandlerOptions {\n definition: BrandlabContactDefinition\n transport?: ContactTransport\n attachmentProcessor?: ContactAttachmentProcessor\n botGuard?: ContactBotGuard\n now?: () => Date\n}\n\nfunction getFieldRole(field: BrandlabContactDefinition['fields'][number]) {\n if (field.role) return field.role\n if (field.name === 'suburb' || field.name === 'location') return 'location' as const\n if (['name', 'email', 'phone', 'message'].includes(field.name)) {\n return field.name as 'name' | 'email' | 'phone' | 'message'\n }\n return 'custom' as const\n}\n\nfunction normalizedHttpsOrigin(value: string) {\n try {\n const url = new URL(value)\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.pathname !== '/' && url.pathname !== '') ||\n value.trim().replace(/\\/$/, '') !== url.origin\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction assertDefinition(definition: BrandlabContactDefinition) {\n if (!isBrandlabCanonicalEntityId(definition.projectId)) {\n throw new Error('projectId must be a canonical Brandlab entity ID.')\n }\n if (\n !definition.brandName.trim() ||\n definition.brandName.trim() !== definition.brandName ||\n definition.brandName.length > 160 ||\n /[\\u0000-\\u001f\\u007f]/.test(definition.brandName)\n ) {\n throw new Error('brandName must contain bounded reviewed text.')\n }\n if (!normalizedHttpsOrigin(definition.siteUrl)) {\n throw new Error('siteUrl must be a canonical HTTPS origin.')\n }\n const mode = definition.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n if (!Array.isArray(definition.fields) || definition.fields.length < 4) {\n throw new Error('Contact fields are unavailable.')\n }\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n const reservedFields = new Set<string>(\n Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n )\n if (!FIELD_NAME_PATTERN.test(honeypotField) || reservedFields.has(honeypotField)) {\n throw new Error('The contact honeypot field is invalid.')\n }\n const fieldNames = new Set<string>()\n for (const field of definition.fields) {\n if (\n !FIELD_NAME_PATTERN.test(field.name) ||\n fieldNames.has(field.name) ||\n reservedFields.has(field.name) ||\n field.name === honeypotField ||\n !field.label.trim() ||\n field.label.length > 120\n ) {\n throw new Error(`Contact field \"${field.name}\" is invalid.`)\n }\n fieldNames.add(field.name)\n }\n for (const role of ['name', 'email', 'phone', 'message'] as const) {\n if (definition.fields.filter((field) => getFieldRole(field) === role).length !== 1) {\n throw new Error(`Contact definition requires exactly one \"${role}\" field.`)\n }\n }\n if (definition.fields.filter((field) => getFieldRole(field) === 'location').length > 1) {\n throw new Error('Contact definition allows at most one \"location\" field.')\n }\n if (definition.attachments) {\n const policy = attachmentPolicy(definition)\n if (\n !Number.isSafeInteger(policy.maxFiles) ||\n policy.maxFiles < 1 ||\n policy.maxFiles > 20 ||\n !Number.isSafeInteger(policy.maxFileSizeBytes) ||\n policy.maxFileSizeBytes < 1 ||\n !Number.isSafeInteger(policy.maxTotalSizeBytes) ||\n policy.maxTotalSizeBytes < policy.maxFileSizeBytes ||\n policy.maxTotalSizeBytes > BRANDLAB_CONTACT_MAX_REQUEST_BYTES ||\n policy.allowedTypes.length < 1 ||\n policy.allowedTypes.some((type) => !SUPPORTED_ATTACHMENT_MIME_TYPES.has(type))\n ) {\n throw new Error('The contact attachment policy is invalid.')\n }\n }\n if (\n definition.email?.style &&\n Object.values(definition.email.style).some(\n (value) => !EMAIL_COLOR_PATTERN.test(value),\n )\n ) {\n throw new Error('Contact email colours must use six-digit hexadecimal values.')\n }\n if (definition.email?.logo) {\n const { url, alt, width } = definition.email.logo\n let parsed: URL | undefined\n try {\n parsed = new URL(url)\n } catch {\n parsed = undefined\n }\n if (\n !parsed ||\n parsed.protocol !== 'https:' ||\n parsed.username ||\n parsed.password ||\n parsed.search ||\n parsed.hash ||\n !alt.trim() ||\n alt.length > 160 ||\n (width !== undefined && (!Number.isInteger(width) || width < 32 || width > 240))\n ) {\n throw new Error('The contact email logo must be a reviewed HTTPS asset.')\n }\n }\n}\n\nfunction attachmentPolicy(definition: BrandlabContactDefinition): ContactAttachmentPolicy {\n return {\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n ...(definition.attachments || {}),\n }\n}\n\nexport function getContactRequestLimits(definition: BrandlabContactDefinition) {\n return {\n maxRequestBytes:\n definition.limits?.maxRequestBytes ?? BRANDLAB_CONTACT_MAX_REQUEST_BYTES,\n maxEntries: definition.limits?.maxEntries ?? DEFAULT_MAX_ENTRIES,\n maxStringBytes:\n definition.limits?.maxStringBytes ?? DEFAULT_MAX_STRING_BYTES,\n }\n}\n\nfunction isAttachmentField(definition: BrandlabContactDefinition, name: string) {\n if (!definition.attachments) return false\n const prefix = definition.attachments.fieldPrefix ?? 'attachments'\n return name === prefix || new RegExp(`^${prefix}\\\\[\\\\d{1,2}\\\\]$`).test(name)\n}\n\nfunction validateFormShape(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n const limits = getContactRequestLimits(definition)\n const allowedStrings = new Set([\n ...definition.fields.map((field) => field.name),\n ...Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot,\n ])\n const counts = new Map<string, number>()\n let estimatedBytes = 0\n const entries = Array.from(formData.entries())\n if (entries.length < 1 || entries.length > limits.maxEntries) return false\n for (const [name, value] of entries) {\n if (!FIELD_NAME_PATTERN.test(name.replace(/\\[\\d{1,2}\\]$/, ''))) return false\n counts.set(name, (counts.get(name) ?? 0) + 1)\n if (typeof value === 'string') {\n if (!allowedStrings.has(name) || (counts.get(name) ?? 0) > 1) return false\n const bytes = new TextEncoder().encode(value).byteLength\n if (bytes > limits.maxStringBytes) return false\n estimatedBytes += bytes\n } else {\n if (!isAttachmentField(definition, name) || value.size < 0) return false\n estimatedBytes += value.size\n }\n if (estimatedBytes > limits.maxRequestBytes) return false\n }\n return true\n}\n\nfunction stringEntry(formData: FormData, name: string) {\n const value = formData.get(name)\n return typeof value === 'string' ? value : ''\n}\n\nfunction validateFields(definition: BrandlabContactDefinition, formData: FormData) {\n const values: Record<string, string> = {}\n const fieldErrors: Record<string, string[]> = {}\n for (const field of definition.fields) {\n let value = stringEntry(formData, field.name).trim()\n try {\n value = field.normalize ? field.normalize(value) : value\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n continue\n }\n values[field.name] = value\n const role = getFieldRole(field)\n const required = field.required || role !== 'custom'\n if (required && !value) {\n fieldErrors[field.name] = [`${field.label} is required.`]\n continue\n }\n if (!value) continue\n const maximum = field.maxLength ?? (role === 'message' ? 5_000 : role === 'email' ? 254 : 200)\n if (value.length > maximum) {\n fieldErrors[field.name] = [`${field.label} is too long.`]\n continue\n }\n if ((field.kind === 'email' || role === 'email') && !EMAIL_PATTERN.test(value)) {\n fieldErrors[field.name] = ['Enter a valid email address.']\n continue\n }\n if (\n (field.kind === 'phone' || role === 'phone') &&\n !field.validate &&\n value.replace(/\\D/g, '').length < 6\n ) {\n fieldErrors[field.name] = ['Enter a valid phone number.']\n continue\n }\n if (field.options && !field.options.includes(value)) {\n fieldErrors[field.name] = [`Select a valid ${field.label.toLowerCase()}.`]\n continue\n }\n try {\n const issue = field.validate?.(value, values)\n if (issue) fieldErrors[field.name] = [issue]\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n }\n }\n return { values, fieldErrors }\n}\n\nconst EXTENSION_TYPES: 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\nfunction normalizeMimeType(value: string) {\n const normalized = value.trim().toLowerCase()\n return normalized === 'image/jpg' ? 'image/jpeg' : normalized\n}\n\nfunction startsWithBytes(bytes: Uint8Array, signature: readonly number[]) {\n return signature.every((byte, index) => bytes[index] === byte)\n}\n\nfunction ascii(bytes: Uint8Array, start: number, length: number) {\n return String.fromCharCode(...bytes.slice(start, start + length))\n}\n\nfunction detectAttachmentType(bytes: Uint8Array): ContactAttachmentMimeType | undefined {\n if (ascii(bytes, 0, 5) === '%PDF-') return 'application/pdf'\n if (startsWithBytes(bytes, [0xff, 0xd8, 0xff])) return 'image/jpeg'\n if (startsWithBytes(bytes, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) {\n return 'image/png'\n }\n const gif = ascii(bytes, 0, 6)\n if (gif === 'GIF87a' || gif === 'GIF89a') return 'image/gif'\n if (ascii(bytes, 0, 4) === 'RIFF' && ascii(bytes, 8, 4) === 'WEBP') return 'image/webp'\n if (ascii(bytes, 4, 4) === 'ftyp') {\n const brands = new Set<string>()\n for (let offset = 8; offset + 4 <= Math.min(bytes.length, 64); offset += 4) {\n brands.add(ascii(bytes, offset, 4))\n }\n if (['heic', 'heix', 'hevc', 'hevx'].some((brand) => brands.has(brand))) {\n return 'image/heic'\n }\n if (['heif', 'mif1', 'msf1'].some((brand) => brands.has(brand))) {\n return 'image/heif'\n }\n }\n return undefined\n}\n\nasync function readValidatedAttachments(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n if (!definition.attachments) return []\n const policy = attachmentPolicy(definition)\n const allowed = new Set(policy.allowedTypes.map(normalizeMimeType))\n const files = Array.from(formData.entries())\n .filter(\n ([name, value]) =>\n isAttachmentField(definition, name) &&\n typeof value !== 'string' &&\n value.size > 0,\n )\n .map(([, value]) => value as File)\n if (definition.attachments.required && files.length === 0) return undefined\n if (files.length > policy.maxFiles) return undefined\n\n const attachments: ContactDeliveryAttachment[] = []\n let totalBytes = 0\n for (const [index, file] of files.entries()) {\n const extension = file.name.toLowerCase().split('.').pop() ?? ''\n const extensionType = EXTENSION_TYPES[extension]\n const declaredType = normalizeMimeType(file.type)\n if (\n !extensionType ||\n !declaredType ||\n !allowed.has(extensionType) ||\n !allowed.has(declaredType) ||\n normalizeMimeType(extensionType) !== declaredType ||\n file.size > policy.maxFileSizeBytes\n ) {\n return undefined\n }\n totalBytes += file.size\n if (totalBytes > policy.maxTotalSizeBytes) return undefined\n const content = new Uint8Array(await file.arrayBuffer())\n if (normalizeMimeType(detectAttachmentType(content.slice(0, 64)) ?? '') !== declaredType) {\n return undefined\n }\n attachments.push({\n filename: createContactAttachmentFilename({ index, contentType: declaredType }),\n content,\n contentType: declaredType,\n })\n }\n return attachments\n}\n\nfunction validateProcessedAttachments(\n definition: BrandlabContactDefinition,\n attachments: readonly ContactDeliveryAttachment[],\n) {\n if (!definition.attachments) return attachments.length === 0\n const policy = attachmentPolicy(definition)\n let totalBytes = 0\n if (attachments.length > policy.maxFiles) return false\n return attachments.every((attachment, index) => {\n totalBytes += attachment.content.byteLength\n return (\n attachment.filename === createContactAttachmentFilename({ index, contentType: attachment.contentType }) &&\n (attachment.contentType === 'image/jpeg' || (attachment.contentType === 'application/pdf' && policy.allowedTypes.includes('application/pdf'))) &&\n attachment.content.byteLength > 0 &&\n attachment.content.byteLength <= policy.maxFileSizeBytes &&\n totalBytes <= policy.maxTotalSizeBytes &&\n detectAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType\n )\n })\n}\n\nfunction validationResult(\n fieldErrors?: Record<string, string[]>,\n): ContactActionResult {\n return {\n ok: false,\n code: 'validation',\n retryable: false,\n ...(fieldErrors && Object.keys(fieldErrors).length > 0 ? { fieldErrors } : {}),\n }\n}\n\nfunction deliveryUnavailable(retryable: boolean): ContactActionResult {\n return { ok: false, code: 'delivery_unavailable', retryable }\n}\n\nfunction fakeSuccess(): ContactActionResult {\n return { ok: true, accepted: false, trackConversion: false }\n}\n\nfunction acceptedResult(confirmationId: string): ContactActionResult {\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId,\n }\n}\n\nfunction parseSubmissionMetadata(\n definition: BrandlabContactDefinition,\n formData: FormData,\n now: Date,\n): {\n clientSubmissionId: string\n submittedAt: string\n context: ContactPageContext\n} | undefined {\n const clientSubmissionId = stringEntry(\n formData,\n CONTACT_FORM_FIELDS.clientSubmissionId,\n )\n .trim()\n .toLowerCase()\n const submittedAt = stringEntry(formData, CONTACT_FORM_FIELDS.submittedAt).trim()\n if (\n !CONTACT_CLIENT_SUBMISSION_ID_PATTERN.test(clientSubmissionId) ||\n !ISO_TIMESTAMP_PATTERN.test(submittedAt)\n ) {\n return undefined\n }\n const submittedMs = Date.parse(submittedAt)\n const nowMs = now.getTime()\n if (\n !Number.isFinite(submittedMs) ||\n submittedMs > nowMs + MAX_CLOCK_SKEW_MS ||\n submittedMs < nowMs - MAX_SUBMISSION_AGE_MS\n ) {\n return undefined\n }\n try {\n const pagePath = normalizeBrandlabRoutePath(\n stringEntry(formData, CONTACT_FORM_FIELDS.pagePath),\n )\n const pageLabel = stringEntry(formData, CONTACT_FORM_FIELDS.pageLabel).trim()\n if (\n pageLabel &&\n (pageLabel.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(pageLabel))\n ) {\n return undefined\n }\n const attribution = normalizeContactAttributionSummary({\n initialLandingPath: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.initialLandingPath,\n ),\n visitSource: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSource,\n ) as Parameters<typeof normalizeContactAttributionSummary>[0]['visitSource'],\n ...(stringEntry(formData, CONTACT_FORM_FIELDS.visitSourceDetail).trim()\n ? {\n visitSourceDetail: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSourceDetail,\n ).trim(),\n }\n : {}),\n })\n return {\n clientSubmissionId,\n submittedAt,\n context: {\n pagePath,\n pageUrl: new URL(pagePath, definition.siteUrl).toString(),\n ...(pageLabel ? { pageLabel } : {}),\n ...attribution,\n },\n }\n } catch {\n return undefined\n }\n}\n\nasync function createConfirmationId(projectId: string, clientSubmissionId: string) {\n if (!globalThis.crypto?.subtle) {\n throw new Error('A secure digest implementation is required.')\n }\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(`${projectId}:${clientSubmissionId}`),\n )\n return Array.from(new Uint8Array(digest), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('')\n}\n\nfunction createIdempotencyKey(projectId: string, clientSubmissionId: string) {\n const projectKey = projectId.replaceAll('&', '-and-')\n return `brandlab/contact/${projectKey}/${clientSubmissionId}`\n}\n\nfunction defaultBotAssessment(\n definition: BrandlabContactDefinition,\n formData: FormData,\n): ContactBotAssessment {\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n return stringEntry(formData, honeypotField).trim()\n ? { status: 'accept-silently' }\n : { status: 'allow' }\n}\n\nfunction normalizedRequestOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash ||\n url.origin !== value\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction forwardedOrigin(request: Request) {\n const host = request.headers.get('x-forwarded-host')?.trim()\n const protocol = request.headers.get('x-forwarded-proto')?.trim()\n if (\n !host ||\n host.includes(',') ||\n host.length > 253 ||\n !/^[a-z0-9.-]+(?::\\d{1,5})?$/i.test(host) ||\n (protocol !== 'https' && protocol !== 'http')\n ) {\n return undefined\n }\n try {\n return new URL(`${protocol}://${host}`).origin\n } catch {\n return undefined\n }\n}\n\nfunction requestOriginCandidates(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n if (mode === 'production') {\n return new Set([normalizedHttpsOrigin(definition.siteUrl)])\n }\n const candidates = new Set<string>()\n try {\n candidates.add(new URL(request.url).origin)\n } catch {\n return undefined\n }\n const forwarded = forwardedOrigin(request)\n if (forwarded) candidates.add(forwarded)\n return candidates\n}\n\nfunction normalizedReferrerOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction sameOriginRequest(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n const candidates = requestOriginCandidates(request, definition)\n if (!candidates) return undefined\n\n const originHeader = request.headers.get('origin')\n if (originHeader !== null) {\n const origin = normalizedRequestOrigin(originHeader, mode)\n return origin && candidates.has(origin) ? origin : undefined\n }\n\n const fetchSite = request.headers.get('sec-fetch-site')\n if (fetchSite !== null && fetchSite !== 'same-origin') return undefined\n const referrerOrigin = normalizedReferrerOrigin(\n request.headers.get('referer'),\n mode,\n )\n return referrerOrigin && candidates.has(referrerOrigin)\n ? referrerOrigin\n : undefined\n}\n\nfunction contentTypeIsAllowed(value: string | null, uploadsEnabled: boolean) {\n if (!value || value.length > 256) return false\n const mediaType = value.split(';', 1)[0]?.trim().toLowerCase()\n if (uploadsEnabled && mediaType !== MULTIPART_FORM) return false\n if (mediaType === FORM_URLENCODED) return true\n return mediaType === MULTIPART_FORM && MULTIPART_BOUNDARY_PATTERN.test(value)\n}\n\nfunction contentLengthIsAllowed(value: string | null, maximum: number) {\n if (value === null) return true\n if (!/^\\d{1,16}$/.test(value)) return false\n const parsed = Number(value)\n return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= maximum\n}\n\nfunction jsonResult(result: ContactActionResult, status: number) {\n return Response.json(result, {\n status,\n headers: {\n 'cache-control': 'no-store, max-age=0',\n pragma: 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n}\n\nfunction statusForResult(result: ContactActionResult) {\n if (result.ok) return 200\n if (result.code === 'delivery_unavailable') return 503\n return 400\n}\n\nasync function handleSubmission(\n options: ContactRouteHandlerOptions,\n request: ContactRequestContext,\n formData: FormData,\n): Promise<ContactActionResult> {\n const now = options.now?.() ?? new Date()\n if (!Number.isFinite(now.getTime()) || !validateFormShape(options.definition, formData)) {\n return validationResult()\n }\n const metadata = parseSubmissionMetadata(options.definition, formData, now)\n if (!metadata) return validationResult()\n\n let confirmationId: string\n try {\n confirmationId = await createConfirmationId(\n options.definition.projectId,\n metadata.clientSubmissionId,\n )\n } catch {\n return deliveryUnavailable(true)\n }\n if (!CONTACT_CONFIRMATION_ID_PATTERN.test(confirmationId)) {\n return deliveryUnavailable(false)\n }\n\n if (defaultBotAssessment(options.definition, formData).status !== 'allow') {\n return fakeSuccess()\n }\n if (options.botGuard) {\n try {\n const result = await options.botGuard.assess({\n formData,\n request,\n projectId: options.definition.projectId,\n confirmationId,\n now: now.getTime(),\n })\n if (result.status !== 'allow') return fakeSuccess()\n } catch {\n return deliveryUnavailable(true)\n }\n }\n\n const validated = validateFields(options.definition, formData)\n if (Object.keys(validated.fieldErrors).length > 0) {\n return validationResult(validated.fieldErrors)\n }\n\n let attachments: readonly ContactDeliveryAttachment[] | undefined\n try {\n attachments = await readValidatedAttachments(options.definition, formData)\n if (attachments && options.attachmentProcessor) {\n const processed = await options.attachmentProcessor.process({ attachments })\n attachments = processed.ok ? processed.attachments : undefined\n }\n } catch {\n attachments = undefined\n }\n if (!attachments || !validateProcessedAttachments(options.definition, attachments)) {\n return {\n ok: false,\n code: 'attachment_rejected',\n retryable: false,\n }\n }\n\n const mode = options.definition.deploymentMode ?? 'production'\n if (mode === 'development' || mode === 'test') {\n return fakeSuccess()\n }\n if (!options.transport) return deliveryUnavailable(false)\n\n const rendered = renderContactEmail({\n definition: options.definition,\n values: validated.values,\n context: metadata.context,\n submittedAt: metadata.submittedAt,\n confirmationId,\n attachments,\n })\n try {\n const transportResult = await options.transport.send({\n idempotencyKey: createIdempotencyKey(\n options.definition.projectId,\n metadata.clientSubmissionId,\n ),\n confirmationId,\n subject: rendered.subject,\n html: rendered.html,\n text: rendered.text,\n ...(rendered.replyTo ? { replyTo: rendered.replyTo } : {}),\n attachments,\n providerMetadata: {\n project_id: options.definition.projectId,\n submission_hash: confirmationId,\n },\n })\n if (!transportResult.ok) {\n return deliveryUnavailable(transportResult.retryable ?? true)\n }\n if (!SAFE_PROVIDER_MESSAGE_ID_PATTERN.test(transportResult.providerMessageId)) {\n return deliveryUnavailable(true)\n }\n return acceptedResult(confirmationId)\n } catch {\n return deliveryUnavailable(true)\n }\n}\n\nexport function createContactRouteHandler(options: ContactRouteHandlerOptions) {\n assertDefinition(options.definition)\n if (\n options.definition.attachments &&\n options.attachmentProcessor?.capability !== 'sanitizes-contact-images-v1'\n ) {\n throw new Error('Upload-enabled contact routes require the shared image sanitizer.')\n }\n if (options.botGuard && typeof options.botGuard.assess !== 'function') {\n throw new Error('The optional contact bot guard is invalid.')\n }\n const limits = getContactRequestLimits(options.definition)\n\n return async (request: Request): Promise<Response> => {\n if (!(request instanceof Request) || request.method.toUpperCase() !== 'POST') {\n return jsonResult(validationResult(), 405)\n }\n const origin = sameOriginRequest(request, options.definition)\n if (\n !origin ||\n request.headers.has('transfer-encoding') ||\n !contentTypeIsAllowed(\n request.headers.get('content-type'),\n Boolean(options.definition.attachments),\n ) ||\n !contentLengthIsAllowed(\n request.headers.get('content-length'),\n limits.maxRequestBytes,\n )\n ) {\n return jsonResult(validationResult(), 400)\n }\n\n let formData: FormData\n try {\n formData = await request.formData()\n } catch {\n return jsonResult(validationResult(), 400)\n }\n const result = await handleSubmission(options, { origin }, formData)\n return jsonResult(result, statusForResult(result))\n }\n}\n\nfunction boundedSecret(value: string | undefined): value is string {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= 8_192 &&\n !/[\\u0000-\\u001f\\u007f]/.test(value)\n )\n}\n\nfunction createRuntimeTransport(\n options: BrandlabContactRuntimeOptions,\n contract: BrandlabContactContract,\n mode: BrandlabContactDeploymentMode,\n) {\n if (mode === 'development' || mode === 'test') return undefined\n const environment = options.environment ?? {}\n const apiKey = environment[BRANDLAB_CONTACT_API_KEY_ENV]\n try {\n const recipients = parseContactEmailRecipients(\n environment[contract.delivery.recipientEnv],\n )\n if (!boundedSecret(apiKey) || recipients.length === 0) return undefined\n return createContractResendContactTransport({\n contract,\n environment,\n send: options.createResendSend(apiKey),\n })\n } catch {\n return undefined\n }\n}\n\nexport function createBrandlabContactRuntime(\n options: BrandlabContactRuntimeOptions,\n): BrandlabContactRuntime {\n if (!options || typeof options !== 'object') {\n throw new TypeError('Contact runtime options are required.')\n }\n if (!options.runtime || typeof options.runtime !== 'object') {\n throw new TypeError('Contact runtime definition is required.')\n }\n if (typeof options.createResendSend !== 'function') {\n throw new TypeError('A lazy Resend send factory is required.')\n }\n const mode = options.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n const contract = defineContactContract(options.contract)\n const definition = createContactDefinitionFromContract(contract, {\n ...options.runtime,\n deploymentMode: mode,\n })\n assertDefinition(definition)\n const contactRouteHandler = createContactRouteHandler({\n definition,\n transport: createRuntimeTransport(options, contract, mode),\n ...(definition.attachments\n ? { attachmentProcessor: createBrandlabContactImageSanitizer() }\n : {}),\n ...(options.botGuard ? { botGuard: options.botGuard } : {}),\n ...(options.now ? { now: options.now } : {}),\n })\n\n return Object.freeze({\n runtimeKind: BRANDLAB_CONTACT_RUNTIME,\n definition,\n contactRouteHandler,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"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","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n deriveContactAttachmentTransportPolicy,\n detectContactTransportAttachmentType,\n createContactAttachmentFilename,\n defineContactContract,\n parseContactEmailRecipients,\n type BrandlabContactContract,\n type ContactActionResult,\n type ContactAttachmentMimeType,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport { isBrandlabCanonicalEntityId } from '@brandlab-digital/site-core/entity-id'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { normalizeContactAttributionSummary } from './attribution.js'\nimport {\n createContactDefinitionFromContract,\n type ContactRuntimeDefinitionOptions,\n} from './contract.js'\nimport { renderContactEmail } from './email.js'\nimport { createBrandlabContactImageSanitizer } from './image-sanitizer.js'\nimport {\n createContractResendContactTransport,\n type ResendContactSend,\n} from './resend.js'\nimport {\n CONTACT_CLIENT_SUBMISSION_ID_PATTERN,\n CONTACT_CONFIRMATION_ID_PATTERN,\n CONTACT_FORM_FIELDS,\n type BrandlabContactDefinition,\n type BrandlabContactDeploymentMode,\n type ContactAttachmentProcessor,\n type ContactBotAssessment,\n type ContactBotGuard,\n type ContactDeliveryAttachment,\n type ContactPageContext,\n type ContactRequestContext,\n type ContactTransport,\n} from './shared.js'\n\nexport { createBrandlabContactImageSanitizer } from './image-sanitizer.js'\nexport { createResendSdkContactSend } from './resend.js'\nexport type { ResendContactSend, ResendSdkContactClient } from './resend.js'\n\nexport const BRANDLAB_CONTACT_RUNTIME = 'brandlab-contact-v4' as const\nexport const BRANDLAB_CONTACT_API_KEY_ENV = 'RESEND_API_KEY' as const\nexport const BRANDLAB_CONTACT_MAX_REQUEST_BYTES = 4_500_000\n\nexport function detectBrandlabContactDeploymentMode(\n environment: Readonly<Record<string, string | undefined>>,\n): BrandlabContactDeploymentMode {\n if (environment.VERCEL_ENV === 'production') return 'production'\n if (environment.VERCEL_ENV === 'preview') return 'preview'\n if (environment.NODE_ENV === 'test') return 'test'\n return 'development'\n}\n\nconst FORM_URLENCODED = 'application/x-www-form-urlencoded'\nconst MULTIPART_FORM = 'multipart/form-data'\nconst MULTIPART_BOUNDARY_PATTERN =\n /(?:^|;)\\s*boundary=(?:\"[0-9A-Za-z'()+_,.\\/:=?-]{1,70}\"|[0-9A-Za-z'()+_,.\\/:=?-]{1,70})(?:;|$)/i\nconst FIELD_NAME_PATTERN = /^[a-z][A-Za-z0-9_-]{0,63}$/\nconst SAFE_PROVIDER_MESSAGE_ID_PATTERN = /^[A-Za-z0-9._-]{1,256}$/\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/\nconst EMAIL_COLOR_PATTERN = /^#[0-9a-fA-F]{6}$/\nconst ISO_TIMESTAMP_PATTERN =\n /^\\d{4}-\\d{2}-\\d{2}T\\d{2}:\\d{2}:\\d{2}\\.\\d{3}Z$/\nconst MAX_SUBMISSION_AGE_MS = 24 * 60 * 60 * 1_000\nconst MAX_CLOCK_SKEW_MS = 5 * 60 * 1_000\nconst DEFAULT_MAX_ENTRIES = 64\nconst DEFAULT_MAX_STRING_BYTES = 64 * 1_024\nconst SUPPORTED_ATTACHMENT_MIME_TYPES = new Set([\n 'application/pdf',\n 'image/jpeg',\n 'image/jpg',\n 'image/png',\n 'image/gif',\n 'image/webp',\n 'image/heic',\n 'image/heif',\n])\n\nexport type BrandlabContactRuntimeDefinitionOptions = Omit<\n ContactRuntimeDefinitionOptions,\n 'deploymentMode'\n>\n\nexport interface BrandlabContactRuntimeOptions {\n contract: BrandlabContactContract\n runtime: BrandlabContactRuntimeDefinitionOptions\n environment?: Readonly<Record<string, string | undefined>>\n deploymentMode?: BrandlabContactDeploymentMode\n createResendSend: (apiKey: string) => ResendContactSend\n botGuard?: ContactBotGuard\n now?: () => Date\n}\n\nexport interface BrandlabContactRuntime {\n runtimeKind: typeof BRANDLAB_CONTACT_RUNTIME\n definition: ReturnType<typeof createContactDefinitionFromContract>\n contactRouteHandler: (request: Request) => Promise<Response>\n}\n\ninterface ContactRouteHandlerOptions {\n definition: BrandlabContactDefinition\n transport?: ContactTransport\n attachmentProcessor?: ContactAttachmentProcessor\n botGuard?: ContactBotGuard\n now?: () => Date\n}\n\nfunction getFieldRole(field: BrandlabContactDefinition['fields'][number]) {\n if (field.role) return field.role\n if (field.name === 'suburb' || field.name === 'location') return 'location' as const\n if (['name', 'email', 'phone', 'message'].includes(field.name)) {\n return field.name as 'name' | 'email' | 'phone' | 'message'\n }\n return 'custom' as const\n}\n\nfunction normalizedHttpsOrigin(value: string) {\n try {\n const url = new URL(value)\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.pathname !== '/' && url.pathname !== '') ||\n value.trim().replace(/\\/$/, '') !== url.origin\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction assertDefinition(definition: BrandlabContactDefinition) {\n if (!isBrandlabCanonicalEntityId(definition.projectId)) {\n throw new Error('projectId must be a canonical Brandlab entity ID.')\n }\n if (\n !definition.brandName.trim() ||\n definition.brandName.trim() !== definition.brandName ||\n definition.brandName.length > 160 ||\n /[\\u0000-\\u001f\\u007f]/.test(definition.brandName)\n ) {\n throw new Error('brandName must contain bounded reviewed text.')\n }\n if (!normalizedHttpsOrigin(definition.siteUrl)) {\n throw new Error('siteUrl must be a canonical HTTPS origin.')\n }\n const mode = definition.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n if (!Array.isArray(definition.fields) || definition.fields.length < 4) {\n throw new Error('Contact fields are unavailable.')\n }\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n const reservedFields = new Set<string>(\n Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n )\n if (!FIELD_NAME_PATTERN.test(honeypotField) || reservedFields.has(honeypotField)) {\n throw new Error('The contact honeypot field is invalid.')\n }\n const fieldNames = new Set<string>()\n for (const field of definition.fields) {\n if (\n !FIELD_NAME_PATTERN.test(field.name) ||\n fieldNames.has(field.name) ||\n reservedFields.has(field.name) ||\n field.name === honeypotField ||\n !field.label.trim() ||\n field.label.length > 120\n ) {\n throw new Error(`Contact field \"${field.name}\" is invalid.`)\n }\n fieldNames.add(field.name)\n }\n for (const role of ['name', 'email', 'phone', 'message'] as const) {\n if (definition.fields.filter((field) => getFieldRole(field) === role).length !== 1) {\n throw new Error(`Contact definition requires exactly one \"${role}\" field.`)\n }\n }\n if (definition.fields.filter((field) => getFieldRole(field) === 'location').length > 1) {\n throw new Error('Contact definition allows at most one \"location\" field.')\n }\n if (definition.attachments) {\n const policy = attachmentPolicy(definition)\n if (\n !Number.isSafeInteger(policy.maxFiles) ||\n policy.maxFiles < 1 ||\n policy.maxFiles > 20 ||\n !Number.isSafeInteger(policy.maxFileSizeBytes) ||\n policy.maxFileSizeBytes < 1 ||\n !Number.isSafeInteger(policy.maxTotalSizeBytes) ||\n policy.maxTotalSizeBytes < policy.maxFileSizeBytes ||\n policy.maxTotalSizeBytes > BRANDLAB_CONTACT_MAX_REQUEST_BYTES ||\n policy.allowedTypes.length < 1 ||\n policy.allowedTypes.some((type) => !SUPPORTED_ATTACHMENT_MIME_TYPES.has(type))\n ) {\n throw new Error('The contact attachment policy is invalid.')\n }\n }\n if (\n definition.email?.style &&\n Object.values(definition.email.style).some(\n (value) => !EMAIL_COLOR_PATTERN.test(value),\n )\n ) {\n throw new Error('Contact email colours must use six-digit hexadecimal values.')\n }\n if (definition.email?.logo) {\n const { url, alt, width } = definition.email.logo\n let parsed: URL | undefined\n try {\n parsed = new URL(url)\n } catch {\n parsed = undefined\n }\n if (\n !parsed ||\n parsed.protocol !== 'https:' ||\n parsed.username ||\n parsed.password ||\n parsed.search ||\n parsed.hash ||\n !alt.trim() ||\n alt.length > 160 ||\n (width !== undefined && (!Number.isInteger(width) || width < 32 || width > 240))\n ) {\n throw new Error('The contact email logo must be a reviewed HTTPS asset.')\n }\n }\n}\n\nfunction attachmentPolicy(definition: BrandlabContactDefinition): ContactAttachmentPolicy {\n return deriveContactAttachmentTransportPolicy({\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n ...(definition.attachments || {}),\n })\n}\n\nexport function getContactRequestLimits(definition: BrandlabContactDefinition) {\n return {\n maxRequestBytes:\n definition.limits?.maxRequestBytes ?? BRANDLAB_CONTACT_MAX_REQUEST_BYTES,\n maxEntries: definition.limits?.maxEntries ?? DEFAULT_MAX_ENTRIES,\n maxStringBytes:\n definition.limits?.maxStringBytes ?? DEFAULT_MAX_STRING_BYTES,\n }\n}\n\nfunction isAttachmentField(definition: BrandlabContactDefinition, name: string) {\n if (!definition.attachments) return false\n const prefix = definition.attachments.fieldPrefix ?? 'attachments'\n return name === prefix || new RegExp(`^${prefix}\\\\[\\\\d{1,2}\\\\]$`).test(name)\n}\n\nfunction validateFormShape(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n const limits = getContactRequestLimits(definition)\n const allowedStrings = new Set([\n ...definition.fields.map((field) => field.name),\n ...Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot,\n ])\n const counts = new Map<string, number>()\n let estimatedBytes = 0\n const entries = Array.from(formData.entries())\n if (entries.length < 1 || entries.length > limits.maxEntries) return false\n for (const [name, value] of entries) {\n if (!FIELD_NAME_PATTERN.test(name.replace(/\\[\\d{1,2}\\]$/, ''))) return false\n counts.set(name, (counts.get(name) ?? 0) + 1)\n if (typeof value === 'string') {\n if (!allowedStrings.has(name) || (counts.get(name) ?? 0) > 1) return false\n const bytes = new TextEncoder().encode(value).byteLength\n if (bytes > limits.maxStringBytes) return false\n estimatedBytes += bytes\n } else {\n if (!isAttachmentField(definition, name) || value.size < 0) return false\n estimatedBytes += value.size\n }\n if (estimatedBytes > limits.maxRequestBytes) return false\n }\n return true\n}\n\nfunction stringEntry(formData: FormData, name: string) {\n const value = formData.get(name)\n return typeof value === 'string' ? value : ''\n}\n\nfunction validateFields(definition: BrandlabContactDefinition, formData: FormData) {\n const values: Record<string, string> = {}\n const fieldErrors: Record<string, string[]> = {}\n for (const field of definition.fields) {\n let value = stringEntry(formData, field.name).trim()\n try {\n value = field.normalize ? field.normalize(value) : value\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n continue\n }\n values[field.name] = value\n const role = getFieldRole(field)\n const required = field.required || role !== 'custom'\n if (required && !value) {\n fieldErrors[field.name] = [`${field.label} is required.`]\n continue\n }\n if (!value) continue\n const maximum = field.maxLength ?? (role === 'message' ? 5_000 : role === 'email' ? 254 : 200)\n if (value.length > maximum) {\n fieldErrors[field.name] = [`${field.label} is too long.`]\n continue\n }\n if ((field.kind === 'email' || role === 'email') && !EMAIL_PATTERN.test(value)) {\n fieldErrors[field.name] = ['Enter a valid email address.']\n continue\n }\n if (\n (field.kind === 'phone' || role === 'phone') &&\n !field.validate &&\n value.replace(/\\D/g, '').length < 6\n ) {\n fieldErrors[field.name] = ['Enter a valid phone number.']\n continue\n }\n if (field.options && !field.options.includes(value)) {\n fieldErrors[field.name] = [`Select a valid ${field.label.toLowerCase()}.`]\n continue\n }\n try {\n const issue = field.validate?.(value, values)\n if (issue) fieldErrors[field.name] = [issue]\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n }\n }\n return { values, fieldErrors }\n}\n\nconst EXTENSION_TYPES: 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\nfunction normalizeMimeType(value: string) {\n const normalized = value.trim().toLowerCase()\n return normalized === 'image/jpg' ? 'image/jpeg' : normalized\n}\n\nasync function readValidatedAttachments(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n if (!definition.attachments) return []\n const policy = attachmentPolicy(definition)\n const allowed = new Set(policy.allowedTypes.map(normalizeMimeType))\n const files = Array.from(formData.entries())\n .filter(\n ([name, value]) =>\n isAttachmentField(definition, name) &&\n typeof value !== 'string' &&\n value.size > 0,\n )\n .map(([, value]) => value as File)\n if (definition.attachments.required && files.length === 0) return undefined\n if (files.length > policy.maxFiles) return undefined\n\n const attachments: ContactDeliveryAttachment[] = []\n let totalBytes = 0\n for (const [index, file] of files.entries()) {\n const extension = file.name.toLowerCase().split('.').pop() ?? ''\n const extensionType = EXTENSION_TYPES[extension]\n const declaredType = normalizeMimeType(file.type)\n if (\n !extensionType ||\n !declaredType ||\n !allowed.has(extensionType) ||\n !allowed.has(declaredType) ||\n normalizeMimeType(extensionType) !== declaredType ||\n file.size > policy.maxFileSizeBytes\n ) {\n return undefined\n }\n totalBytes += file.size\n if (totalBytes > policy.maxTotalSizeBytes) return undefined\n const content = new Uint8Array(await file.arrayBuffer())\n if (normalizeMimeType(detectContactTransportAttachmentType(content.slice(0, 64)) ?? '') !== declaredType) {\n return undefined\n }\n attachments.push({\n filename: createContactAttachmentFilename({ index, contentType: declaredType }),\n content,\n contentType: declaredType,\n })\n }\n return attachments\n}\n\nfunction validateProcessedAttachments(\n definition: BrandlabContactDefinition,\n attachments: readonly ContactDeliveryAttachment[],\n) {\n if (!definition.attachments) return attachments.length === 0\n const policy = attachmentPolicy(definition)\n let totalBytes = 0\n if (attachments.length > policy.maxFiles) return false\n return attachments.every((attachment, index) => {\n totalBytes += attachment.content.byteLength\n return (\n attachment.filename === createContactAttachmentFilename({ index, contentType: attachment.contentType }) &&\n (attachment.contentType === 'image/jpeg' || (attachment.contentType === 'application/pdf' && policy.allowedTypes.includes('application/pdf'))) &&\n attachment.content.byteLength > 0 &&\n attachment.content.byteLength <= policy.maxFileSizeBytes &&\n totalBytes <= policy.maxTotalSizeBytes &&\n detectContactTransportAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType\n )\n })\n}\n\nfunction validationResult(\n fieldErrors?: Record<string, string[]>,\n): ContactActionResult {\n return {\n ok: false,\n code: 'validation',\n retryable: false,\n ...(fieldErrors && Object.keys(fieldErrors).length > 0 ? { fieldErrors } : {}),\n }\n}\n\nfunction deliveryUnavailable(retryable: boolean): ContactActionResult {\n return { ok: false, code: 'delivery_unavailable', retryable }\n}\n\nfunction fakeSuccess(): ContactActionResult {\n return { ok: true, accepted: false, trackConversion: false }\n}\n\nfunction acceptedResult(confirmationId: string): ContactActionResult {\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId,\n }\n}\n\nfunction parseSubmissionMetadata(\n definition: BrandlabContactDefinition,\n formData: FormData,\n now: Date,\n): {\n clientSubmissionId: string\n submittedAt: string\n context: ContactPageContext\n} | undefined {\n const clientSubmissionId = stringEntry(\n formData,\n CONTACT_FORM_FIELDS.clientSubmissionId,\n )\n .trim()\n .toLowerCase()\n const submittedAt = stringEntry(formData, CONTACT_FORM_FIELDS.submittedAt).trim()\n if (\n !CONTACT_CLIENT_SUBMISSION_ID_PATTERN.test(clientSubmissionId) ||\n !ISO_TIMESTAMP_PATTERN.test(submittedAt)\n ) {\n return undefined\n }\n const submittedMs = Date.parse(submittedAt)\n const nowMs = now.getTime()\n if (\n !Number.isFinite(submittedMs) ||\n submittedMs > nowMs + MAX_CLOCK_SKEW_MS ||\n submittedMs < nowMs - MAX_SUBMISSION_AGE_MS\n ) {\n return undefined\n }\n try {\n const pagePath = normalizeBrandlabRoutePath(\n stringEntry(formData, CONTACT_FORM_FIELDS.pagePath),\n )\n const pageLabel = stringEntry(formData, CONTACT_FORM_FIELDS.pageLabel).trim()\n if (\n pageLabel &&\n (pageLabel.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(pageLabel))\n ) {\n return undefined\n }\n const attribution = normalizeContactAttributionSummary({\n initialLandingPath: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.initialLandingPath,\n ),\n visitSource: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSource,\n ) as Parameters<typeof normalizeContactAttributionSummary>[0]['visitSource'],\n ...(stringEntry(formData, CONTACT_FORM_FIELDS.visitSourceDetail).trim()\n ? {\n visitSourceDetail: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSourceDetail,\n ).trim(),\n }\n : {}),\n })\n return {\n clientSubmissionId,\n submittedAt,\n context: {\n pagePath,\n pageUrl: new URL(pagePath, definition.siteUrl).toString(),\n ...(pageLabel ? { pageLabel } : {}),\n ...attribution,\n },\n }\n } catch {\n return undefined\n }\n}\n\nasync function createConfirmationId(projectId: string, clientSubmissionId: string) {\n if (!globalThis.crypto?.subtle) {\n throw new Error('A secure digest implementation is required.')\n }\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(`${projectId}:${clientSubmissionId}`),\n )\n return Array.from(new Uint8Array(digest), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('')\n}\n\nfunction createIdempotencyKey(projectId: string, clientSubmissionId: string) {\n const projectKey = projectId.replaceAll('&', '-and-')\n return `brandlab/contact/${projectKey}/${clientSubmissionId}`\n}\n\nfunction defaultBotAssessment(\n definition: BrandlabContactDefinition,\n formData: FormData,\n): ContactBotAssessment {\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n return stringEntry(formData, honeypotField).trim()\n ? { status: 'accept-silently' }\n : { status: 'allow' }\n}\n\nfunction normalizedRequestOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash ||\n url.origin !== value\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction forwardedOrigin(request: Request) {\n const host = request.headers.get('x-forwarded-host')?.trim()\n const protocol = request.headers.get('x-forwarded-proto')?.trim()\n if (\n !host ||\n host.includes(',') ||\n host.length > 253 ||\n !/^[a-z0-9.-]+(?::\\d{1,5})?$/i.test(host) ||\n (protocol !== 'https' && protocol !== 'http')\n ) {\n return undefined\n }\n try {\n return new URL(`${protocol}://${host}`).origin\n } catch {\n return undefined\n }\n}\n\nfunction requestOriginCandidates(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n if (mode === 'production') {\n return new Set([normalizedHttpsOrigin(definition.siteUrl)])\n }\n const candidates = new Set<string>()\n try {\n candidates.add(new URL(request.url).origin)\n } catch {\n return undefined\n }\n const forwarded = forwardedOrigin(request)\n if (forwarded) candidates.add(forwarded)\n return candidates\n}\n\nfunction normalizedReferrerOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction sameOriginRequest(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n const candidates = requestOriginCandidates(request, definition)\n if (!candidates) return undefined\n\n const originHeader = request.headers.get('origin')\n if (originHeader !== null) {\n const origin = normalizedRequestOrigin(originHeader, mode)\n return origin && candidates.has(origin) ? origin : undefined\n }\n\n const fetchSite = request.headers.get('sec-fetch-site')\n if (fetchSite !== null && fetchSite !== 'same-origin') return undefined\n const referrerOrigin = normalizedReferrerOrigin(\n request.headers.get('referer'),\n mode,\n )\n return referrerOrigin && candidates.has(referrerOrigin)\n ? referrerOrigin\n : undefined\n}\n\nfunction contentTypeIsAllowed(value: string | null, uploadsEnabled: boolean) {\n if (!value || value.length > 256) return false\n const mediaType = value.split(';', 1)[0]?.trim().toLowerCase()\n if (uploadsEnabled && mediaType !== MULTIPART_FORM) return false\n if (mediaType === FORM_URLENCODED) return true\n return mediaType === MULTIPART_FORM && MULTIPART_BOUNDARY_PATTERN.test(value)\n}\n\nfunction contentLengthIsAllowed(value: string | null, maximum: number) {\n if (value === null) return true\n if (!/^\\d{1,16}$/.test(value)) return false\n const parsed = Number(value)\n return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= maximum\n}\n\nfunction jsonResult(result: ContactActionResult, status: number) {\n return Response.json(result, {\n status,\n headers: {\n 'cache-control': 'no-store, max-age=0',\n pragma: 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n}\n\nfunction statusForResult(result: ContactActionResult) {\n if (result.ok) return 200\n if (result.code === 'delivery_unavailable') return 503\n return 400\n}\n\nasync function handleSubmission(\n options: ContactRouteHandlerOptions,\n request: ContactRequestContext,\n formData: FormData,\n): Promise<ContactActionResult> {\n const now = options.now?.() ?? new Date()\n if (!Number.isFinite(now.getTime()) || !validateFormShape(options.definition, formData)) {\n return validationResult()\n }\n const metadata = parseSubmissionMetadata(options.definition, formData, now)\n if (!metadata) return validationResult()\n\n let confirmationId: string\n try {\n confirmationId = await createConfirmationId(\n options.definition.projectId,\n metadata.clientSubmissionId,\n )\n } catch {\n return deliveryUnavailable(true)\n }\n if (!CONTACT_CONFIRMATION_ID_PATTERN.test(confirmationId)) {\n return deliveryUnavailable(false)\n }\n\n if (defaultBotAssessment(options.definition, formData).status !== 'allow') {\n return fakeSuccess()\n }\n if (options.botGuard) {\n try {\n const result = await options.botGuard.assess({\n formData,\n request,\n projectId: options.definition.projectId,\n confirmationId,\n now: now.getTime(),\n })\n if (result.status !== 'allow') return fakeSuccess()\n } catch {\n return deliveryUnavailable(true)\n }\n }\n\n const validated = validateFields(options.definition, formData)\n if (Object.keys(validated.fieldErrors).length > 0) {\n return validationResult(validated.fieldErrors)\n }\n\n let attachments: readonly ContactDeliveryAttachment[] | undefined\n try {\n attachments = await readValidatedAttachments(options.definition, formData)\n if (attachments && options.attachmentProcessor) {\n const processed = await options.attachmentProcessor.process({ attachments })\n attachments = processed.ok ? processed.attachments : undefined\n }\n } catch {\n attachments = undefined\n }\n if (!attachments || !validateProcessedAttachments(options.definition, attachments)) {\n return {\n ok: false,\n code: 'attachment_rejected',\n retryable: false,\n }\n }\n\n const mode = options.definition.deploymentMode ?? 'production'\n if (mode === 'development' || mode === 'test') {\n return fakeSuccess()\n }\n if (!options.transport) return deliveryUnavailable(false)\n\n const rendered = renderContactEmail({\n definition: options.definition,\n values: validated.values,\n context: metadata.context,\n submittedAt: metadata.submittedAt,\n confirmationId,\n attachments,\n })\n try {\n const transportResult = await options.transport.send({\n idempotencyKey: createIdempotencyKey(\n options.definition.projectId,\n metadata.clientSubmissionId,\n ),\n confirmationId,\n subject: rendered.subject,\n html: rendered.html,\n text: rendered.text,\n ...(rendered.replyTo ? { replyTo: rendered.replyTo } : {}),\n attachments,\n providerMetadata: {\n project_id: options.definition.projectId,\n submission_hash: confirmationId,\n },\n })\n if (!transportResult.ok) {\n return deliveryUnavailable(transportResult.retryable ?? true)\n }\n if (!SAFE_PROVIDER_MESSAGE_ID_PATTERN.test(transportResult.providerMessageId)) {\n return deliveryUnavailable(true)\n }\n return acceptedResult(confirmationId)\n } catch {\n return deliveryUnavailable(true)\n }\n}\n\nexport function createContactRouteHandler(options: ContactRouteHandlerOptions) {\n assertDefinition(options.definition)\n if (\n options.definition.attachments &&\n options.attachmentProcessor?.capability !== 'sanitizes-contact-images-v1'\n ) {\n throw new Error('Upload-enabled contact routes require the shared image sanitizer.')\n }\n if (options.botGuard && typeof options.botGuard.assess !== 'function') {\n throw new Error('The optional contact bot guard is invalid.')\n }\n const limits = getContactRequestLimits(options.definition)\n\n return async (request: Request): Promise<Response> => {\n if (!(request instanceof Request) || request.method.toUpperCase() !== 'POST') {\n return jsonResult(validationResult(), 405)\n }\n const origin = sameOriginRequest(request, options.definition)\n if (\n !origin ||\n request.headers.has('transfer-encoding') ||\n !contentTypeIsAllowed(\n request.headers.get('content-type'),\n Boolean(options.definition.attachments),\n ) ||\n !contentLengthIsAllowed(\n request.headers.get('content-length'),\n limits.maxRequestBytes,\n )\n ) {\n return jsonResult(validationResult(), 400)\n }\n\n let formData: FormData\n try {\n formData = await request.formData()\n } catch {\n return jsonResult(validationResult(), 400)\n }\n const result = await handleSubmission(options, { origin }, formData)\n return jsonResult(result, statusForResult(result))\n }\n}\n\nfunction boundedSecret(value: string | undefined): value is string {\n return (\n typeof value === 'string' &&\n value.length > 0 &&\n value.length <= 8_192 &&\n !/[\\u0000-\\u001f\\u007f]/.test(value)\n )\n}\n\nfunction createRuntimeTransport(\n options: BrandlabContactRuntimeOptions,\n contract: BrandlabContactContract,\n mode: BrandlabContactDeploymentMode,\n) {\n if (mode === 'development' || mode === 'test') return undefined\n const environment = options.environment ?? {}\n const apiKey = environment[BRANDLAB_CONTACT_API_KEY_ENV]\n try {\n const recipients = parseContactEmailRecipients(\n environment[contract.delivery.recipientEnv],\n )\n if (!boundedSecret(apiKey) || recipients.length === 0) return undefined\n return createContractResendContactTransport({\n contract,\n environment,\n send: options.createResendSend(apiKey),\n })\n } catch {\n return undefined\n }\n}\n\nexport function createBrandlabContactRuntime(\n options: BrandlabContactRuntimeOptions,\n): BrandlabContactRuntime {\n if (!options || typeof options !== 'object') {\n throw new TypeError('Contact runtime options are required.')\n }\n if (!options.runtime || typeof options.runtime !== 'object') {\n throw new TypeError('Contact runtime definition is required.')\n }\n if (typeof options.createResendSend !== 'function') {\n throw new TypeError('A lazy Resend send factory is required.')\n }\n const mode = options.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n const contract = defineContactContract(options.contract)\n const definition = createContactDefinitionFromContract(contract, {\n ...options.runtime,\n deploymentMode: mode,\n })\n assertDefinition(definition)\n const contactRouteHandler = createContactRouteHandler({\n definition,\n transport: createRuntimeTransport(options, contract, mode),\n ...(definition.attachments\n ? { attachmentProcessor: createBrandlabContactImageSanitizer() }\n : {}),\n ...(options.botGuard ? { botGuard: options.botGuard } : {}),\n ...(options.now ? { now: options.now } : {}),\n })\n\n return Object.freeze({\n runtimeKind: BRANDLAB_CONTACT_RUNTIME,\n definition,\n contactRouteHandler,\n })\n}\n"]}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-runtime.d.ts","sourceRoot":"","sources":["../src/image-runtime.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
import { createRequire } from 'node:module';
|
|
2
|
+
import sharp from 'sharp';
|
|
3
|
+
// Next lazily unblocks HEIF when its optimizer first acquires Sharp. Initialise
|
|
4
|
+
// that cache before applying our exclusion, without patching either library.
|
|
5
|
+
// This private Next entrypoint is covered by the exact runtime pin and packed
|
|
6
|
+
// startup-order tests. Remove this bridge when maintained native fixes ship.
|
|
7
|
+
const require = createRequire(import.meta.url);
|
|
8
|
+
let nextInstalled = false;
|
|
9
|
+
try {
|
|
10
|
+
require.resolve('next/package.json');
|
|
11
|
+
nextInstalled = true;
|
|
12
|
+
}
|
|
13
|
+
catch (error) {
|
|
14
|
+
if (error.code !== 'MODULE_NOT_FOUND')
|
|
15
|
+
throw error;
|
|
16
|
+
}
|
|
17
|
+
if (nextInstalled) {
|
|
18
|
+
const optimizer = require('next/dist/server/image-optimizer.js');
|
|
19
|
+
optimizer.getSharp();
|
|
20
|
+
}
|
|
21
|
+
sharp.block({ operation: ['VipsForeignLoadHeif'] });
|
|
22
|
+
//# sourceMappingURL=image-runtime.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"image-runtime.js","sourceRoot":"","sources":["../src/image-runtime.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,KAAK,MAAM,OAAO,CAAA;AAEzB,gFAAgF;AAChF,6EAA6E;AAC7E,8EAA8E;AAC9E,6EAA6E;AAC7E,MAAM,OAAO,GAAG,aAAa,CAAC,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAA;AAC9C,IAAI,aAAa,GAAG,KAAK,CAAA;AACzB,IAAI,CAAC;IACH,OAAO,CAAC,OAAO,CAAC,mBAAmB,CAAC,CAAA;IACpC,aAAa,GAAG,IAAI,CAAA;AACtB,CAAC;AAAC,OAAO,KAAK,EAAE,CAAC;IACf,IAAK,KAA+B,CAAC,IAAI,KAAK,kBAAkB;QAAE,MAAM,KAAK,CAAA;AAC/E,CAAC;AACD,IAAI,aAAa,EAAE,CAAC;IAClB,MAAM,SAAS,GAAG,OAAO,CAAC,qCAAqC,CAE9D,CAAA;IACD,SAAS,CAAC,QAAQ,EAAE,CAAA;AACtB,CAAC;AACD,KAAK,CAAC,KAAK,CAAC,EAAE,SAAS,EAAE,CAAC,qBAAqB,CAAC,EAAE,CAAC,CAAA","sourcesContent":["import { createRequire } from 'node:module'\nimport sharp from 'sharp'\n\n// Next lazily unblocks HEIF when its optimizer first acquires Sharp. Initialise\n// that cache before applying our exclusion, without patching either library.\n// This private Next entrypoint is covered by the exact runtime pin and packed\n// startup-order tests. Remove this bridge when maintained native fixes ship.\nconst require = createRequire(import.meta.url)\nlet nextInstalled = false\ntry {\n require.resolve('next/package.json')\n nextInstalled = true\n} catch (error) {\n if ((error as NodeJS.ErrnoException).code !== 'MODULE_NOT_FOUND') throw error\n}\nif (nextInstalled) {\n const optimizer = require('next/dist/server/image-optimizer.js') as {\n getSharp: () => typeof sharp\n }\n optimizer.getSharp()\n}\nsharp.block({ operation: ['VipsForeignLoadHeif'] })\n"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brandlab-digital/site-next",
|
|
3
|
-
"version": "1.3.
|
|
3
|
+
"version": "1.3.1",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/RomieDandan/brandlab.git",
|
|
@@ -8,7 +8,9 @@
|
|
|
8
8
|
},
|
|
9
9
|
"private": false,
|
|
10
10
|
"type": "module",
|
|
11
|
-
"sideEffects":
|
|
11
|
+
"sideEffects": [
|
|
12
|
+
"./dist/image-runtime.js"
|
|
13
|
+
],
|
|
12
14
|
"files": [
|
|
13
15
|
"dist"
|
|
14
16
|
],
|
|
@@ -18,7 +20,7 @@
|
|
|
18
20
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
19
21
|
},
|
|
20
22
|
"dependencies": {
|
|
21
|
-
"@brandlab-digital/site-core": "1.3.
|
|
23
|
+
"@brandlab-digital/site-core": "1.3.1",
|
|
22
24
|
"browser-image-compression": "2.0.2",
|
|
23
25
|
"pdf-lib": "1.17.1",
|
|
24
26
|
"server-only": "0.0.1",
|
|
@@ -121,6 +123,11 @@
|
|
|
121
123
|
"./google-reviews/ui": {
|
|
122
124
|
"types": "./dist/google-reviews-ui.d.ts",
|
|
123
125
|
"import": "./dist/google-reviews-ui.js"
|
|
126
|
+
},
|
|
127
|
+
"./image-runtime": {
|
|
128
|
+
"types": "./dist/image-runtime.d.ts",
|
|
129
|
+
"import": "./dist/image-runtime.js",
|
|
130
|
+
"require": "./dist/image-runtime.js"
|
|
124
131
|
}
|
|
125
132
|
}
|
|
126
133
|
}
|