@brandlab-digital/site-next 1.1.0 → 1.2.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/contact/contract.d.ts.map +1 -1
- package/dist/contact/contract.js +2 -2
- package/dist/contact/contract.js.map +1 -1
- package/dist/contact/image-sanitizer.d.ts.map +1 -1
- package/dist/contact/image-sanitizer.js +2 -1
- package/dist/contact/image-sanitizer.js.map +1 -1
- package/dist/contact/pdf-sanitizer.d.ts +5 -0
- package/dist/contact/pdf-sanitizer.d.ts.map +1 -0
- package/dist/contact/pdf-sanitizer.js +39 -0
- package/dist/contact/pdf-sanitizer.js.map +1 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +8 -4
- package/dist/contact/server.js.map +1 -1
- package/package.json +4 -3
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/contact/contract.ts"],"names":[],"mappings":"AAAA,OAAO,
|
|
1
|
+
{"version":3,"file":"contract.d.ts","sourceRoot":"","sources":["../../src/contact/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EAML,KAAK,uBAAuB,EAC5B,KAAK,uBAAuB,EAE7B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAEL,KAAK,yBAAyB,EAE/B,MAAM,aAAa,CAAA;AAEpB,MAAM,MAAM,+BAA+B,GAAG,IAAI,CAChD,yBAAyB,EACzB,WAAW,GAAG,SAAS,GAAG,gBAAgB,GAAG,KAAK,CACnD,GAAG;IACF,MAAM,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC,CAAA;IACxC,UAAU,CAAC,EAAE,OAAO,CAAC,uBAAuB,CAAC,GAAG;QAAE,WAAW,CAAC,EAAE,MAAM,CAAA;KAAE,CAAA;IACxE,KAAK,CAAC,EAAE,WAAW,CAAC,yBAAyB,CAAC,OAAO,CAAC,CAAC,CAAA;CACxD,CAAA;AAuBD,wBAAgB,mCAAmC,CACjD,QAAQ,EAAE,uBAAuB,EACjC,OAAO,EAAE,+BAA+B,qCAgDzC"}
|
package/dist/contact/contract.js
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, defineContactContract, isValidAustralianPhoneNumber, normalizeAustralianPhoneDigits, } from '@brandlab-digital/site-core/contact';
|
|
1
|
+
import { DEFAULT_CONTACT_ATTACHMENT_POLICY, DOCUMENT_CONTACT_ATTACHMENT_POLICY, defineContactContract, isValidAustralianPhoneNumber, normalizeAustralianPhoneDigits, } from '@brandlab-digital/site-core/contact';
|
|
2
2
|
import { defineBrandlabContact, } from './shared.js';
|
|
3
3
|
const KIND_MAP = {
|
|
4
4
|
text: 'text',
|
|
@@ -52,7 +52,7 @@ export function createContactDefinitionFromContract(contract, options) {
|
|
|
52
52
|
const attachments = contract.attachments.mode === 'none'
|
|
53
53
|
? false
|
|
54
54
|
: {
|
|
55
|
-
...DEFAULT_CONTACT_ATTACHMENT_POLICY,
|
|
55
|
+
...(contract.attachments.mode === 'images-and-pdfs-optional' ? DOCUMENT_CONTACT_ATTACHMENT_POLICY : DEFAULT_CONTACT_ATTACHMENT_POLICY),
|
|
56
56
|
...attachment,
|
|
57
57
|
required: contract.attachments.mode === 'images-required',
|
|
58
58
|
};
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/contact/contract.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,iCAAiC,EACjC,qBAAqB,EACrB,4BAA4B,EAC5B,8BAA8B,GAI/B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EACL,qBAAqB,GAGtB,MAAM,aAAa,CAAA;AAWpB,MAAM,QAAQ,GAAgF;IAC5F,IAAI,EAAE,MAAM;IACZ,KAAK,EAAE,OAAO;IACd,GAAG,EAAE,OAAO;IACZ,QAAQ,EAAE,UAAU;IACpB,MAAM,EAAE,QAAQ;IAChB,QAAQ,EAAE,UAAU;CACrB,CAAA;AAED,SAAS,+BAA+B,CAAC,KAAa;IACpD,IAAI,CAAC,gBAAgB,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,kDAAkD,CAAC,CAAA;IACrE,CAAC;IACD,OAAO,8BAA8B,CAAC,KAAK,CAAC,CAAA;AAC9C,CAAC;AAED,MAAM,WAAW,GAAiE;IAChF,SAAS,EAAE,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,WAAW,EAAE;IACzC,yBAAyB,EAAE,+BAA+B;CAC3D,CAAA;AAED,MAAM,UAAU,mCAAmC,CACjD,QAAiC,EACjC,OAAwC;IAExC,qBAAqB,CAAC,QAAQ,CAAC,CAAA;IAC/B,MAAM,EAAE,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,GAAG,OAAO,CAAA;IACzD,MAAM,MAAM,GAAG,QAAQ,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE;QAC3C,MAAM,KAAK,GAAG,MAAM,CAAC,KAAK,CAAC,GAAG,CAAC,EAAE,IAAI,EAAE,CAAA;QACvC,IAAI,CAAC,KAAK;YAAE,MAAM,IAAI,KAAK,CAAC,0DAA0D,KAAK,CAAC,GAAG,IAAI,CAAC,CAAA;QACpG,OAAO;YACL,IAAI,EAAE,KAAK,CAAC,GAAG;YACf,KAAK;YACL,IAAI,EAAE,KAAK,CAAC,IAAI;YAChB,IAAI,EAAE,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1B,QAAQ,EAAE,KAAK,CAAC,QAAQ;YACxB,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,KAAK,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YACxE,GAAG,CAAC,KAAK,CAAC,IAAI,KAAK,UAAU;gBAC3B,CAAC,CAAC,EAAE,OAAO,EAAE,CAAC,KAAK,CAAC,YAAa,CAAC,EAAE;gBACpC,CAAC,CAAC,KAAK,CAAC,OAAO;oBACb,CAAC,CAAC,EAAE,OAAO,EAAE,KAAK,CAAC,OAAO,EAAE;oBAC5B,CAAC,CAAC,EAAE,CAAC;YACT,GAAG,CAAC,KAAK,CAAC,aAAa;gBACrB,CAAC,CAAC,EAAE,SAAS,EAAE,WAAW,CAAC,KAAK,CAAC,aAAa,CAAC,EAAE;gBACjD,CAAC,CAAC,EAAE,CAAC;YACP,GAAG,CAAC,KAAK,CAAC,SAAS,KAAK,YAAY;gBAClC,CAAC,CAAC;oBACE,QAAQ,EAAE,CAAC,KAAa,EAAE,EAAE,CAC1B,4BAA4B,CAAC,KAAK,CAAC;wBACjC,CAAC,CAAC,SAAS;wBACX,CAAC,CAAC,wCAAwC;iBAC/C;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAA;IACH,CAAC,CAAC,CAAA;IACF,MAAM,WAAW,GACf,QAAQ,CAAC,WAAW,CAAC,IAAI,KAAK,MAAM;QAClC,CAAC,CAAC,KAAK;QACP,CAAC,CAAC;YACE,GAAG,iCAAiC;
|
|
1
|
+
{"version":3,"file":"contract.js","sourceRoot":"","sources":["../../src/contact/contract.ts"],"names":[],"mappings":"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","sourcesContent":["import {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n DOCUMENT_CONTACT_ATTACHMENT_POLICY,\n defineContactContract,\n isValidAustralianPhoneNumber,\n normalizeAustralianPhoneDigits,\n type BrandlabContactContract,\n type ContactAttachmentPolicy,\n type ContactFieldNormalization,\n} from '@brandlab-digital/site-core/contact'\nimport {\n defineBrandlabContact,\n type BrandlabContactDefinition,\n type ContactFieldKind,\n} from './shared.js'\n\nexport type ContactRuntimeDefinitionOptions = Pick<\n BrandlabContactDefinition,\n 'brandName' | 'siteUrl' | 'deploymentMode' | 'bot'\n> & {\n labels: Readonly<Record<string, string>>\n attachment?: Partial<ContactAttachmentPolicy> & { fieldPrefix?: string }\n email?: NonNullable<BrandlabContactDefinition['email']>\n}\n\nconst KIND_MAP: Record<BrandlabContactContract['fields'][number]['kind'], ContactFieldKind> = {\n text: 'text',\n email: 'email',\n tel: 'phone',\n textarea: 'textarea',\n select: 'select',\n checkbox: 'checkbox',\n}\n\nfunction normalizeAustralianContactPhone(value: string) {\n if (!/^[+()\\d\\s.-]+$/.test(value)) {\n throw new Error('The phone value contains unsupported characters.')\n }\n return normalizeAustralianPhoneDigits(value)\n}\n\nconst NORMALIZERS: Record<ContactFieldNormalization, (value: string) => string> = {\n lowercase: (value) => value.toLowerCase(),\n 'australian-phone-digits': normalizeAustralianContactPhone,\n}\n\nexport function createContactDefinitionFromContract(\n contract: BrandlabContactContract,\n options: ContactRuntimeDefinitionOptions,\n) {\n defineContactContract(contract)\n const { labels, attachment, email, ...runtime } = options\n const fields = contract.fields.map((field) => {\n const label = labels[field.key]?.trim()\n if (!label) throw new Error(`A customer-facing label is required for contact field \"${field.key}\".`)\n return {\n name: field.key,\n label,\n role: field.role,\n kind: KIND_MAP[field.kind],\n required: field.required,\n ...(field.maxLength !== undefined ? { maxLength: field.maxLength } : {}),\n ...(field.kind === 'checkbox'\n ? { options: [field.checkedValue!] }\n : field.options\n ? { options: field.options }\n : {}),\n ...(field.normalization\n ? { normalize: NORMALIZERS[field.normalization] }\n : {}),\n ...(field.phoneRule === 'australian'\n ? {\n validate: (value: string) =>\n isValidAustralianPhoneNumber(value)\n ? undefined\n : 'Enter a valid Australian phone number.',\n }\n : {}),\n }\n })\n const attachments =\n contract.attachments.mode === 'none'\n ? false\n : {\n ...(contract.attachments.mode === 'images-and-pdfs-optional' ? DOCUMENT_CONTACT_ATTACHMENT_POLICY : DEFAULT_CONTACT_ATTACHMENT_POLICY),\n ...attachment,\n required: contract.attachments.mode === 'images-required',\n }\n\n return defineBrandlabContact({\n ...runtime,\n projectId: contract.projectId,\n fields,\n attachments,\n ...(email ? { email } : {}),\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;AAIpB,OAAO,KAAK,EACV,0BAA0B,EAE3B,MAAM,aAAa,CAAA;AAqGpB;;;;GAIG;AACH,wBAAgB,mCAAmC,IAAI,0BAA0B,CAiBhF"}
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import 'server-only';
|
|
2
|
+
import { sanitizeContactPdf } from './pdf-sanitizer.js';
|
|
2
3
|
import sharp, {} from 'sharp';
|
|
3
4
|
const MAX_INPUT_PIXELS = 50_000_000;
|
|
4
5
|
const MAX_OUTPUT_DIMENSION = 4_096;
|
|
@@ -96,7 +97,7 @@ export function createBrandlabContactImageSanitizer() {
|
|
|
96
97
|
const sanitized = [];
|
|
97
98
|
// Sequential processing bounds peak native memory for multiple photos.
|
|
98
99
|
for (const attachment of attachments) {
|
|
99
|
-
sanitized.push(await sanitizeOne(attachment));
|
|
100
|
+
sanitized.push(attachment.contentType === 'application/pdf' ? await sanitizeContactPdf(attachment) : await sanitizeOne(attachment));
|
|
100
101
|
}
|
|
101
102
|
return { ok: true, attachments: Object.freeze(sanitized) };
|
|
102
103
|
}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"image-sanitizer.js","sourceRoot":"","sources":["../../src/contact/image-sanitizer.ts"],"names":[],"mappings":"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
|
|
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 { sanitizeContactPdf } from './pdf-sanitizer.js'\nimport sharp, { type Metadata, type Sharp } from 'sharp'\nimport type {\n ContactAttachmentProcessor,\n ContactDeliveryAttachment,\n} from './shared.js'\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 'image/heic': 'heif',\n 'image/heif': 'heif',\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 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 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' ? await sanitizeContactPdf(attachment) : 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"]}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import type { ContactDeliveryAttachment } from './shared.js';
|
|
2
|
+
/** Accept bounded, static plans only. Rebuild page graphics without annotations,
|
|
3
|
+
* document actions, attachments, forms, links or source metadata. */
|
|
4
|
+
export declare function sanitizeContactPdf(attachment: ContactDeliveryAttachment): Promise<ContactDeliveryAttachment>;
|
|
5
|
+
//# sourceMappingURL=pdf-sanitizer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"pdf-sanitizer.d.ts","sourceRoot":"","sources":["../../src/contact/pdf-sanitizer.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,yBAAyB,EAAE,MAAM,aAAa,CAAA;AAG5D;qEACqE;AACrE,wBAAsB,kBAAkB,CAAC,UAAU,EAAE,yBAAyB,GAAG,OAAO,CAAC,yBAAyB,CAAC,CAwBlH"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { PDFDocument, PDFDict, PDFName, PDFArray } from 'pdf-lib';
|
|
2
|
+
const REJECTED_KEYS = new Set(['JS', 'JavaScript', 'AA', 'OpenAction', 'Launch', 'EmbeddedFiles', 'EmbeddedFile', 'XFA', 'RichMedia', 'SubmitForm', 'ImportData', 'GoToR', 'GoToE', 'AcroForm', 'AF']);
|
|
3
|
+
/** Accept bounded, static plans only. Rebuild page graphics without annotations,
|
|
4
|
+
* document actions, attachments, forms, links or source metadata. */
|
|
5
|
+
export async function sanitizeContactPdf(attachment) {
|
|
6
|
+
if (!(attachment.content instanceof Uint8Array) || attachment.content.byteLength > 4_000_000 || !/^document-\d+\.pdf$/.test(attachment.filename))
|
|
7
|
+
throw new Error('Invalid document attachment.');
|
|
8
|
+
const input = await PDFDocument.load(attachment.content, { ignoreEncryption: false, updateMetadata: false, throwOnInvalidObject: true });
|
|
9
|
+
if (input.isEncrypted || input.getPageCount() < 1 || input.getPageCount() > 100)
|
|
10
|
+
throw new Error('Unsupported PDF document.');
|
|
11
|
+
for (const [, object] of input.context.enumerateIndirectObjects()) {
|
|
12
|
+
if (object instanceof PDFDict) {
|
|
13
|
+
for (const [key, value] of object.entries()) {
|
|
14
|
+
if (key.decodeText() === 'Annots') {
|
|
15
|
+
const annotations = input.context.lookup(value);
|
|
16
|
+
if (!(annotations instanceof PDFArray) || annotations.size() > 0)
|
|
17
|
+
throw new Error('Annotated PDF documents must be flattened before upload.');
|
|
18
|
+
}
|
|
19
|
+
if (REJECTED_KEYS.has(key.decodeText()) || (value instanceof PDFName && REJECTED_KEYS.has(value.decodeText())))
|
|
20
|
+
throw new Error('Interactive PDF documents are not supported.');
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
const output = await PDFDocument.create({ updateMetadata: false });
|
|
25
|
+
for (const page of input.getPages()) {
|
|
26
|
+
const { width, height } = page.getSize();
|
|
27
|
+
if (!Number.isFinite(width) || !Number.isFinite(height) || width <= 0 || height <= 0 || width > 20_000 || height > 20_000)
|
|
28
|
+
throw new Error('Unsupported PDF page dimensions.');
|
|
29
|
+
const embedded = await output.embedPage(page);
|
|
30
|
+
const copied = output.addPage([width, height]);
|
|
31
|
+
copied.drawPage(embedded);
|
|
32
|
+
copied.setRotation(page.getRotation());
|
|
33
|
+
}
|
|
34
|
+
const content = await output.save({ useObjectStreams: true, addDefaultPage: false });
|
|
35
|
+
if (!content.byteLength || content.byteLength > 4_000_000)
|
|
36
|
+
throw new Error('PDF output exceeds the attachment limit.');
|
|
37
|
+
return Object.freeze({ filename: attachment.filename, content, contentType: 'application/pdf' });
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=pdf-sanitizer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
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 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.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,EAKL,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;
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAKL,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;AAylBD,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
|
@@ -35,6 +35,7 @@ const MAX_CLOCK_SKEW_MS = 5 * 60 * 1_000;
|
|
|
35
35
|
const DEFAULT_MAX_ENTRIES = 64;
|
|
36
36
|
const DEFAULT_MAX_STRING_BYTES = 64 * 1_024;
|
|
37
37
|
const SUPPORTED_ATTACHMENT_MIME_TYPES = new Set([
|
|
38
|
+
'application/pdf',
|
|
38
39
|
'image/jpeg',
|
|
39
40
|
'image/jpg',
|
|
40
41
|
'image/png',
|
|
@@ -266,6 +267,7 @@ function validateFields(definition, formData) {
|
|
|
266
267
|
return { values, fieldErrors };
|
|
267
268
|
}
|
|
268
269
|
const EXTENSION_TYPES = {
|
|
270
|
+
pdf: 'application/pdf',
|
|
269
271
|
jpg: 'image/jpeg',
|
|
270
272
|
jpeg: 'image/jpeg',
|
|
271
273
|
png: 'image/png',
|
|
@@ -285,6 +287,8 @@ function ascii(bytes, start, length) {
|
|
|
285
287
|
return String.fromCharCode(...bytes.slice(start, start + length));
|
|
286
288
|
}
|
|
287
289
|
function detectAttachmentType(bytes) {
|
|
290
|
+
if (ascii(bytes, 0, 5) === '%PDF-')
|
|
291
|
+
return 'application/pdf';
|
|
288
292
|
if (startsWithBytes(bytes, [0xff, 0xd8, 0xff]))
|
|
289
293
|
return 'image/jpeg';
|
|
290
294
|
if (startsWithBytes(bytes, [0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a])) {
|
|
@@ -345,7 +349,7 @@ async function readValidatedAttachments(definition, formData) {
|
|
|
345
349
|
return undefined;
|
|
346
350
|
}
|
|
347
351
|
attachments.push({
|
|
348
|
-
filename: createContactAttachmentFilename({ index }),
|
|
352
|
+
filename: createContactAttachmentFilename({ index, contentType: declaredType }),
|
|
349
353
|
content,
|
|
350
354
|
contentType: declaredType,
|
|
351
355
|
});
|
|
@@ -361,12 +365,12 @@ function validateProcessedAttachments(definition, attachments) {
|
|
|
361
365
|
return false;
|
|
362
366
|
return attachments.every((attachment, index) => {
|
|
363
367
|
totalBytes += attachment.content.byteLength;
|
|
364
|
-
return (attachment.filename === createContactAttachmentFilename({ index }) &&
|
|
365
|
-
attachment.contentType === 'image/jpeg' &&
|
|
368
|
+
return (attachment.filename === createContactAttachmentFilename({ index, contentType: attachment.contentType }) &&
|
|
369
|
+
(attachment.contentType === 'image/jpeg' || (attachment.contentType === 'application/pdf' && policy.allowedTypes.includes('application/pdf'))) &&
|
|
366
370
|
attachment.content.byteLength > 0 &&
|
|
367
371
|
attachment.content.byteLength <= policy.maxFileSizeBytes &&
|
|
368
372
|
totalBytes <= policy.maxTotalSizeBytes &&
|
|
369
|
-
detectAttachmentType(attachment.content.slice(0, 64)) ===
|
|
373
|
+
detectAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType);
|
|
370
374
|
});
|
|
371
375
|
}
|
|
372
376
|
function validationResult(fieldErrors) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EACL,iCAAiC,EACjC,+BAA+B,EAC/B,qBAAqB,EACrB,2BAA2B,GAK5B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAA;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACL,mCAAmC,GAEpC,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,kBAAkB,EAAE,MAAM,YAAY,CAAA;AAC/C,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EACL,oCAAoC,GAErC,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,oCAAoC,EACpC,+BAA+B,EAC/B,mBAAmB,GAUpB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAA8B,CAAA;AACtE,MAAM,CAAC,MAAM,4BAA4B,GAAG,gBAAyB,CAAA;AACrE,MAAM,CAAC,MAAM,kCAAkC,GAAG,SAAS,CAAA;AAE3D,MAAM,UAAU,mCAAmC,CACjD,WAAyD;IAEzD,IAAI,WAAW,CAAC,UAAU,KAAK,YAAY;QAAE,OAAO,YAAY,CAAA;IAChE,IAAI,WAAW,CAAC,UAAU,KAAK,SAAS;QAAE,OAAO,SAAS,CAAA;IAC1D,IAAI,WAAW,CAAC,QAAQ,KAAK,MAAM;QAAE,OAAO,MAAM,CAAA;IAClD,OAAO,aAAa,CAAA;AACtB,CAAC;AAED,MAAM,eAAe,GAAG,mCAAmC,CAAA;AAC3D,MAAM,cAAc,GAAG,qBAAqB,CAAA;AAC5C,MAAM,0BAA0B,GAC9B,gGAAgG,CAAA;AAClG,MAAM,kBAAkB,GAAG,4BAA4B,CAAA;AACvD,MAAM,gCAAgC,GAAG,yBAAyB,CAAA;AAClE,MAAM,aAAa,GAAG,4BAA4B,CAAA;AAClD,MAAM,mBAAmB,GAAG,mBAAmB,CAAA;AAC/C,MAAM,qBAAqB,GACzB,+CAA+C,CAAA;AACjD,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;AAClD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAC9B,MAAM,wBAAwB,GAAG,EAAE,GAAG,KAAK,CAAA;AAC3C,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC;IAC9C,YAAY;IACZ,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,YAAY;CACb,CAAC,CAAA;AA+BF,SAAS,YAAY,CAAC,KAAkD;IACtE,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,CAAA;IACjC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,UAAmB,CAAA;IACpF,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC,IAA8C,CAAA;IAC7D,CAAC;IACD,OAAO,QAAiB,CAAA;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,IACE,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACzB,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,EAC9C,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,IAAI,CAAC,2BAA2B,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,IACE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE;QAC5B,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,UAAU,CAAC,SAAS;QACpD,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG;QACjC,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAClD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CACvC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D,CACF,CAAA;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IACE,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACpC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1B,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC9B,KAAK,CAAC,IAAI,KAAK,aAAa;YAC5B,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;YACnB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,EACxB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,eAAe,CAAC,CAAA;QAC9D,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAU,EAAE,CAAC;QAClE,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,UAAU,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvF,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;QAC3C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACtC,MAAM,CAAC,QAAQ,GAAG,CAAC;YACnB,MAAM,CAAC,QAAQ,GAAG,EAAE;YACpB,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC9C,MAAM,CAAC,gBAAgB,GAAG,CAAC;YAC3B,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,iBAAiB,CAAC;YAC/C,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,gBAAgB;YAClD,MAAM,CAAC,iBAAiB,GAAG,kCAAkC;YAC7D,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAC9B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAC9E,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC;IACD,IACE,UAAU,CAAC,KAAK,EAAE,KAAK;QACvB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CACxC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAC5C,EACD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;IACjF,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAA;QACjD,IAAI,MAAuB,CAAA;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,SAAS,CAAA;QACpB,CAAC;QACD,IACE,CAAC,MAAM;YACP,MAAM,CAAC,QAAQ,KAAK,QAAQ;YAC5B,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,MAAM;YACb,MAAM,CAAC,IAAI;YACX,CAAC,GAAG,CAAC,IAAI,EAAE;YACX,GAAG,CAAC,MAAM,GAAG,GAAG;YAChB,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,EAChF,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAA;QAC3E,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,OAAO;QACL,GAAG,iCAAiC;QACpC,GAAG,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;KAClC,CAAA;AACH,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,UAAqC;IAC3E,OAAO;QACL,eAAe,EACb,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI,kCAAkC;QAC1E,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,mBAAmB;QAChE,cAAc,EACZ,UAAU,CAAC,MAAM,EAAE,cAAc,IAAI,wBAAwB;KAChE,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAqC,EAAE,IAAY;IAC5E,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,WAAW,IAAI,aAAa,CAAA;IAClE,OAAO,IAAI,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,iBAAiB,CACxB,UAAqC,EACrC,QAAkB;IAElB,MAAM,MAAM,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAA;IAClD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;QAC7B,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/C,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAC1C,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D;QACD,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ;KAC9D,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU;QAAE,OAAO,KAAK,CAAA;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QAC5E,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC1E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAA;YACxD,IAAI,KAAK,GAAG,MAAM,CAAC,cAAc;gBAAE,OAAO,KAAK,CAAA;YAC/C,cAAc,IAAI,KAAK,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YACxE,cAAc,IAAI,KAAK,CAAC,IAAI,CAAA;QAC9B,CAAC;QACD,IAAI,cAAc,GAAG,MAAM,CAAC,eAAe;YAAE,OAAO,KAAK,CAAA;IAC3D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,WAAW,CAAC,QAAkB,EAAE,IAAY;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;AAC/C,CAAC;AAED,SAAS,cAAc,CAAC,UAAqC,EAAE,QAAkB;IAC/E,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,MAAM,WAAW,GAA6B,EAAE,CAAA;IAChD,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IAAI,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;QACpD,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;YACxD,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,KAAK,QAAQ,CAAA;QACpD,IAAI,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACvB,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC9F,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YAC3B,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/E,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;YAC1D,SAAQ;QACV,CAAC;QACD,IACE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;YAC5C,CAAC,KAAK,CAAC,QAAQ;YACf,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EACnC,CAAC;YACD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;YAC1E,SAAQ;QACV,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAC7C,IAAI,KAAK;gBAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AAChC,CAAC;AAED,MAAM,eAAe,GAA8C;IACjE,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;CACnB,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC7C,OAAO,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAA;AAC/D,CAAC;AAED,SAAS,eAAe,CAAC,KAAiB,EAAE,SAA4B;IACtE,OAAO,SAAS,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAA;AAChE,CAAC;AAED,SAAS,KAAK,CAAC,KAAiB,EAAE,KAAa,EAAE,MAAc;IAC7D,OAAO,MAAM,CAAC,YAAY,CAAC,GAAG,KAAK,CAAC,KAAK,CAAC,KAAK,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC,CAAA;AACnE,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAiB;IAC7C,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QAAE,OAAO,YAAY,CAAA;IACnE,IAAI,eAAe,CAAC,KAAK,EAAE,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,EAAE,CAAC;QAC7E,OAAO,WAAW,CAAA;IACpB,CAAC;IACD,MAAM,GAAG,GAAG,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,CAAA;IAC9B,IAAI,GAAG,KAAK,QAAQ,IAAI,GAAG,KAAK,QAAQ;QAAE,OAAO,WAAW,CAAA;IAC5D,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM;QAAE,OAAO,YAAY,CAAA;IACvF,IAAI,KAAK,CAAC,KAAK,EAAE,CAAC,EAAE,CAAC,CAAC,KAAK,MAAM,EAAE,CAAC;QAClC,MAAM,MAAM,GAAG,IAAI,GAAG,EAAU,CAAA;QAChC,KAAK,IAAI,MAAM,GAAG,CAAC,EAAE,MAAM,GAAG,CAAC,IAAI,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,EAAE,EAAE,CAAC,EAAE,MAAM,IAAI,CAAC,EAAE,CAAC;YAC3E,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,KAAK,EAAE,MAAM,EAAE,CAAC,CAAC,CAAC,CAAA;QACrC,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YACxE,OAAO,YAAY,CAAA;QACrB,CAAC;QACD,IAAI,CAAC,MAAM,EAAE,MAAM,EAAE,MAAM,CAAC,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC;YAChE,OAAO,YAAY,CAAA;QACrB,CAAC;IACH,CAAC;IACD,OAAO,SAAS,CAAA;AAClB,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,UAAqC,EACrC,QAAkB;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,EAAE,CAAA;IACtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACnE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;SACzC,MAAM,CACL,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAChB,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC;QACnC,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,IAAI,GAAG,CAAC,CACjB;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAa,CAAC,CAAA;IACpC,IAAI,UAAU,CAAC,WAAW,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAEpD,MAAM,WAAW,GAAgC,EAAE,CAAA;IACnD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;QAChE,MAAM,aAAa,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;QAChD,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjD,IACE,CAAC,aAAa;YACd,CAAC,YAAY;YACb,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAC3B,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;YAC1B,iBAAiB,CAAC,aAAa,CAAC,KAAK,YAAY;YACjD,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,gBAAgB,EACnC,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,UAAU,IAAI,IAAI,CAAC,IAAI,CAAA;QACvB,IAAI,UAAU,GAAG,MAAM,CAAC,iBAAiB;YAAE,OAAO,SAAS,CAAA;QAC3D,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACxD,IAAI,iBAAiB,CAAC,oBAAoB,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,EAAE,CAAC;YACzF,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,+BAA+B,CAAC,EAAE,KAAK,EAAE,CAAC;YACpD,OAAO;YACP,WAAW,EAAE,YAAY;SAC1B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,SAAS,4BAA4B,CACnC,UAAqC,EACrC,WAAiD;IAEjD,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,WAAW,CAAC,MAAM,KAAK,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IACtD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;QAC7C,UAAU,IAAI,UAAU,CAAC,OAAO,CAAC,UAAU,CAAA;QAC3C,OAAO,CACL,UAAU,CAAC,QAAQ,KAAK,+BAA+B,CAAC,EAAE,KAAK,EAAE,CAAC;YAClE,UAAU,CAAC,WAAW,KAAK,YAAY;YACvC,UAAU,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC;YACjC,UAAU,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,gBAAgB;YACxD,UAAU,IAAI,MAAM,CAAC,iBAAiB;YACtC,oBAAoB,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,YAAY,CACvE,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,WAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,KAAK;QAChB,GAAG,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,SAAkB;IAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;AAC9D,CAAC;AAED,SAAS,cAAc,CAAC,cAAsB;IAC5C,OAAO;QACL,EAAE,EAAE,IAAI;QACR,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,cAAc;KACf,CAAA;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,UAAqC,EACrC,QAAkB,EAClB,GAAS;IAMT,MAAM,kBAAkB,GAAG,WAAW,CACpC,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;SACE,IAAI,EAAE;SACN,WAAW,EAAE,CAAA;IAChB,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAA;IACjF,IACE,CAAC,oCAAoC,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC9D,CAAC,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,EACxC,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC3B,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC7B,WAAW,GAAG,KAAK,GAAG,iBAAiB;QACvC,WAAW,GAAG,KAAK,GAAG,qBAAqB,EAC3C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,0BAA0B,CACzC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CACpD,CAAA;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7E,IACE,SAAS;YACT,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EACnE,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,WAAW,GAAG,kCAAkC,CAAC;YACrD,kBAAkB,EAAE,WAAW,CAC7B,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;YACD,WAAW,EAAE,WAAW,CACtB,QAAQ,EACR,mBAAmB,CAAC,WAAW,CAC2C;YAC5E,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE;gBACrE,CAAC,CAAC;oBACE,iBAAiB,EAAE,WAAW,CAC5B,QAAQ,EACR,mBAAmB,CAAC,iBAAiB,CACtC,CAAC,IAAI,EAAE;iBACT;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;QACF,OAAO;YACL,kBAAkB;YAClB,WAAW;YACX,OAAO,EAAE;gBACP,QAAQ;gBACR,OAAO,EAAE,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;gBACzD,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG,WAAW;aACf;SACF,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IAC/E,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAClD,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,kBAAkB,EAAE,CAAC,CAC/D,CAAA;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACjD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CACnC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACZ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IACzE,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,oBAAoB,UAAU,IAAI,kBAAkB,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,oBAAoB,CAC3B,UAAqC,EACrC,QAAkB;IAElB,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,OAAO,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,IAAI,EAAE;QAChD,CAAC,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE;QAC/B,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AACzB,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,KAAK,GAAG;YACpB,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,GAAG,CAAC,MAAM,KAAK,KAAK,EACpB,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,OAAgB;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAA;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAA;IACjE,IACE,CAAC,IAAI;QACL,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,GAAG;QACjB,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,CAAC,EAC7C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,GAAG,CAAC,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,SAAS;QAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACxC,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,EACZ,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC/D,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAA;IAEjC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,uBAAuB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QAC1D,OAAO,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IACvD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,aAAa;QAAE,OAAO,SAAS,CAAA;IACvE,MAAM,cAAc,GAAG,wBAAwB,CAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAC9B,IAAI,CACL,CAAA;IACD,OAAO,cAAc,IAAI,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC;QACrD,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAoB,EAAE,cAAuB;IACzE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC9D,IAAI,cAAc,IAAI,SAAS,KAAK,cAAc;QAAE,OAAO,KAAK,CAAA;IAChE,IAAI,SAAS,KAAK,eAAe;QAAE,OAAO,IAAI,CAAA;IAC9C,OAAO,SAAS,KAAK,cAAc,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/E,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAoB,EAAE,OAAe;IACnE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,OAAO,CAAA;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,MAA2B,EAAE,MAAc;IAC7D,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE;QAC3B,MAAM;QACN,OAAO,EAAE;YACP,eAAe,EAAE,qBAAqB;YACtC,MAAM,EAAE,UAAU;YAClB,wBAAwB,EAAE,SAAS;SACpC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAA2B;IAClD,IAAI,MAAM,CAAC,EAAE;QAAE,OAAO,GAAG,CAAA;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,GAAG,CAAA;IACtD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAmC,EACnC,OAA8B,EAC9B,QAAkB;IAElB,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAA;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;QACxF,OAAO,gBAAgB,EAAE,CAAA;IAC3B,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC3E,IAAI,CAAC,QAAQ;QAAE,OAAO,gBAAgB,EAAE,CAAA;IAExC,IAAI,cAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,oBAAoB,CACzC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1D,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,oBAAoB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC1E,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC3C,QAAQ;gBACR,OAAO;gBACP,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACvC,cAAc;gBACd,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;aACnB,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,WAAW,EAAE,CAAA;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAC9D,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAChD,CAAC;IAED,IAAI,WAA6D,CAAA;IACjE,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC1E,IAAI,WAAW,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;YAC5E,WAAW,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,SAAS,CAAA;IACzB,CAAC;IACD,IAAI,CAAC,WAAW,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QACnF,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,qBAAqB;YAC3B,SAAS,EAAE,KAAK;SACjB,CAAA;IACH,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IAC9D,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9C,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,SAAS;QAAE,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IAEzD,MAAM,QAAQ,GAAG,kBAAkB,CAAC;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,cAAc;QACd,WAAW;KACZ,CAAC,CAAA;IACF,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;YACnD,cAAc,EAAE,oBAAoB,CAClC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B;YACD,cAAc;YACd,OAAO,EAAE,QAAQ,CAAC,OAAO;YACzB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,WAAW;YACX,gBAAgB,EAAE;gBAChB,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACxC,eAAe,EAAE,cAAc;aAChC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;YACxB,OAAO,mBAAmB,CAAC,eAAe,CAAC,SAAS,IAAI,IAAI,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC9E,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,cAAc,CAAC,cAAc,CAAC,CAAA;IACvC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAmC;IAC3E,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACpC,IACE,OAAO,CAAC,UAAU,CAAC,WAAW;QAC9B,OAAO,CAAC,mBAAmB,EAAE,UAAU,KAAK,6BAA6B,EACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;IACtF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE1D,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC,CAAC,OAAO,YAAY,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YAC7E,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QAC7D,IACE,CAAC,MAAM;YACP,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACxC,CAAC,oBAAoB,CACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EACnC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CACxC;YACD,CAAC,sBAAsB,CACrB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EACrC,MAAM,CAAC,eAAe,CACvB,EACD,CAAC;YACD,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QAED,IAAI,QAAkB,CAAA;QACtB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,CAAC,CAAA;QACpE,OAAO,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;IACpD,CAAC,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,MAAM,IAAI,KAAK;QACrB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACrC,CAAA;AACH,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAsC,EACtC,QAAiC,EACjC,IAAmC;IAEnC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAA;IAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAA;IAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,4BAA4B,CAAC,CAAA;IACxD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,2BAA2B,CAC5C,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAC5C,CAAA;QACD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACvE,OAAO,oCAAoC,CAAC;YAC1C,QAAQ;YACR,WAAW;YACX,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC;SACvC,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAsC;IAEtC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;IAC9D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACnD,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,IAAI,YAAY,CAAA;IACnD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxD,MAAM,UAAU,GAAG,mCAAmC,CAAC,QAAQ,EAAE;QAC/D,GAAG,OAAO,CAAC,OAAO;QAClB,cAAc,EAAE,IAAI;KACrB,CAAC,CAAA;IACF,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC5B,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;QACpD,UAAU;QACV,SAAS,EAAE,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC;QAC1D,GAAG,CAAC,UAAU,CAAC,WAAW;YACxB,CAAC,CAAC,EAAE,mBAAmB,EAAE,mCAAmC,EAAE,EAAE;YAChE,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7C,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,wBAAwB;QACrC,UAAU;QACV,mBAAmB;KACpB,CAAC,CAAA;AACJ,CAAC","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 '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 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 (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 }),\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 }) &&\n attachment.contentType === 'image/jpeg' &&\n attachment.content.byteLength > 0 &&\n attachment.content.byteLength <= policy.maxFileSizeBytes &&\n totalBytes <= policy.maxTotalSizeBytes &&\n detectAttachmentType(attachment.content.slice(0, 64)) === 'image/jpeg'\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 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"]}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@brandlab-digital/site-next",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
4
4
|
"repository": {
|
|
5
5
|
"type": "git",
|
|
6
6
|
"url": "git+https://github.com/RomieDandan/brandlab.git",
|
|
@@ -18,10 +18,11 @@
|
|
|
18
18
|
"typecheck": "tsc --noEmit -p tsconfig.json"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
|
-
"@brandlab-digital/site-core": "1.
|
|
21
|
+
"@brandlab-digital/site-core": "1.2.0",
|
|
22
22
|
"browser-image-compression": "2.0.2",
|
|
23
|
+
"pdf-lib": "1.17.1",
|
|
23
24
|
"server-only": "0.0.1",
|
|
24
|
-
"sharp": "0.35.
|
|
25
|
+
"sharp": "0.35.4"
|
|
25
26
|
},
|
|
26
27
|
"peerDependencies": {
|
|
27
28
|
"next": ">=16",
|