@brandlab-digital/site-next 3.9.0 → 3.10.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/README.md +33 -0
- package/dist/contact/attachments-client.d.ts +3 -0
- package/dist/contact/attachments-client.d.ts.map +1 -1
- package/dist/contact/attachments-client.js +31 -8
- package/dist/contact/attachments-client.js.map +1 -1
- package/dist/contact/client-entry.d.ts +1 -1
- package/dist/contact/client-entry.d.ts.map +1 -1
- package/dist/contact/client-entry.js.map +1 -1
- 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/email.d.ts.map +1 -1
- package/dist/contact/email.js +9 -0
- package/dist/contact/email.js.map +1 -1
- package/dist/contact/form-client.d.ts +4 -2
- package/dist/contact/form-client.d.ts.map +1 -1
- package/dist/contact/form-client.js +49 -13
- package/dist/contact/form-client.js.map +1 -1
- package/dist/contact/rate-limit.d.ts +59 -0
- package/dist/contact/rate-limit.d.ts.map +1 -0
- package/dist/contact/rate-limit.js +109 -0
- package/dist/contact/rate-limit.js.map +1 -0
- package/dist/contact/route-handler.d.ts +6 -0
- package/dist/contact/route-handler.d.ts.map +1 -1
- package/dist/contact/route-handler.js +4 -0
- package/dist/contact/route-handler.js.map +1 -1
- package/dist/contact/server-entry.d.ts +1 -1
- package/dist/contact/server-entry.d.ts.map +1 -1
- package/dist/contact/server-entry.js +1 -1
- package/dist/contact/server-entry.js.map +1 -1
- package/dist/contact/server.d.ts +9 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +71 -7
- package/dist/contact/server.js.map +1 -1
- package/dist/contact/shared.d.ts +11 -0
- package/dist/contact/shared.d.ts.map +1 -1
- package/dist/contact/shared.js +11 -0
- package/dist/contact/shared.js.map +1 -1
- package/dist/contact/testing.d.ts +5 -0
- package/dist/contact/testing.d.ts.map +1 -1
- package/dist/contact/testing.js +1 -0
- package/dist/contact/testing.js.map +1 -1
- package/dist/lead-reporting.d.ts +6 -0
- package/dist/lead-reporting.d.ts.map +1 -1
- package/dist/lead-reporting.js +13 -1
- package/dist/lead-reporting.js.map +1 -1
- package/dist/ui-kit/brandlab-skin.d.ts +12 -0
- package/dist/ui-kit/brandlab-skin.d.ts.map +1 -1
- package/dist/ui-kit/brandlab-skin.js.map +1 -1
- package/dist/ui-kit/form/copy.d.ts +3 -0
- package/dist/ui-kit/form/copy.d.ts.map +1 -0
- package/dist/ui-kit/form/copy.js +5 -0
- package/dist/ui-kit/form/copy.js.map +1 -0
- package/dist/ui-kit/form/dialog.d.ts +24 -0
- package/dist/ui-kit/form/dialog.d.ts.map +1 -0
- package/dist/ui-kit/form/dialog.js +17 -0
- package/dist/ui-kit/form/dialog.js.map +1 -0
- package/dist/ui-kit/form/field.d.ts +30 -0
- package/dist/ui-kit/form/field.d.ts.map +1 -0
- package/dist/ui-kit/form/field.js +11 -0
- package/dist/ui-kit/form/field.js.map +1 -0
- package/dist/ui-kit/form/index.d.ts +7 -0
- package/dist/ui-kit/form/index.d.ts.map +1 -0
- package/dist/ui-kit/form/index.js +7 -0
- package/dist/ui-kit/form/index.js.map +1 -0
- package/dist/ui-kit/form/photo-upload.d.ts +37 -0
- package/dist/ui-kit/form/photo-upload.d.ts.map +1 -0
- package/dist/ui-kit/form/photo-upload.js +19 -0
- package/dist/ui-kit/form/photo-upload.js.map +1 -0
- package/dist/ui-kit/form/quote-dialog.d.ts +15 -0
- package/dist/ui-kit/form/quote-dialog.d.ts.map +1 -0
- package/dist/ui-kit/form/quote-dialog.js +68 -0
- package/dist/ui-kit/form/quote-dialog.js.map +1 -0
- package/dist/ui-kit/form/quote-form.d.ts +165 -0
- package/dist/ui-kit/form/quote-form.d.ts.map +1 -0
- package/dist/ui-kit/form/quote-form.js +235 -0
- package/dist/ui-kit/form/quote-form.js.map +1 -0
- package/dist/ui-kit/form/thank-you.d.ts +37 -0
- package/dist/ui-kit/form/thank-you.d.ts.map +1 -0
- package/dist/ui-kit/form/thank-you.js +36 -0
- package/dist/ui-kit/form/thank-you.js.map +1 -0
- package/dist/ui-kit/structure.css +197 -0
- package/dist/ui.d.ts +10 -1
- package/dist/ui.d.ts.map +1 -1
- package/dist/ui.js +3 -3
- package/dist/ui.js.map +1 -1
- package/package.json +6 -2
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EAOL,KAAK,uBAAuB,EAI7B,MAAM,qCAAqC,CAAA;AAK5C,OAAO,EACL,mCAAmC,EACnC,KAAK,+BAA+B,EACrC,MAAM,eAAe,CAAA;AAGtB,OAAO,EAGL,KAAK,iBAAiB,EACvB,MAAM,aAAa,CAAA;AACpB,OAAO,
|
|
1
|
+
{"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"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"}
|
package/dist/contact/server.js
CHANGED
|
@@ -5,11 +5,13 @@ import { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes';
|
|
|
5
5
|
import { resolveBrandlabDeployment } from '@brandlab-digital/site-core/site';
|
|
6
6
|
import { normalizeContactAttributionSummary } from './attribution.js';
|
|
7
7
|
import { createContactDefinitionFromContract, } from './contract.js';
|
|
8
|
-
import { renderContactEmail } from './email.js';
|
|
8
|
+
import { renderContactEmail, sanitizeContactEmailSubject } from './email.js';
|
|
9
9
|
import { createBrandlabContactImageSanitizer } from './image-sanitizer.js';
|
|
10
|
+
import { createBrandlabContactRateLimiter, isBrandlabContactRateLimiter, } from './rate-limit.js';
|
|
10
11
|
import { RESEND_ERROR_CODES, createContractResendContactTransport, } from './resend.js';
|
|
11
|
-
import { CONTACT_CLIENT_SUBMISSION_ID_PATTERN, CONTACT_CONFIRMATION_ID_PATTERN, CONTACT_FORM_FIELDS, } from './shared.js';
|
|
12
|
+
import { BRANDLAB_CONTACT_TEST_MARKER, CONTACT_CLIENT_SUBMISSION_ID_PATTERN, CONTACT_CONFIRMATION_ID_PATTERN, CONTACT_FORM_FIELDS, } from './shared.js';
|
|
12
13
|
export { createBrandlabContactImageSanitizer } from './image-sanitizer.js';
|
|
14
|
+
export { BRANDLAB_CONTACT_RATE_LIMITS, createBrandlabContactRateLimiter, } from './rate-limit.js';
|
|
13
15
|
export { createResendSdkContactSend } from './resend.js';
|
|
14
16
|
export const BRANDLAB_CONTACT_RUNTIME = 'brandlab-contact-v4';
|
|
15
17
|
export const BRANDLAB_CONTACT_API_KEY_ENV = 'RESEND_API_KEY';
|
|
@@ -596,7 +598,27 @@ function statusForResult(result) {
|
|
|
596
598
|
return 503;
|
|
597
599
|
return 400;
|
|
598
600
|
}
|
|
599
|
-
|
|
601
|
+
const RATE_LIMITED_EVENT = 'brandlab_contact_rate_limited';
|
|
602
|
+
/**
|
|
603
|
+
* One JSON line on the server's error output for each refused enquiry, for the daily delivery monitor:
|
|
604
|
+
* `{"event":"brandlab_contact_rate_limited","rule":"ip","retryAfterSeconds":540}`. Never an address, IP or form value.
|
|
605
|
+
*/
|
|
606
|
+
function logRateLimited(rule, retryAfterSeconds) {
|
|
607
|
+
console.error(JSON.stringify({ event: RATE_LIMITED_EVENT, rule, retryAfterSeconds }));
|
|
608
|
+
}
|
|
609
|
+
/** A client IP as Vercel sets it: `x-real-ip`, else the first `x-forwarded-for` entry. */
|
|
610
|
+
function clientIp(request) {
|
|
611
|
+
const candidate = request.headers.get('x-real-ip')?.trim() ||
|
|
612
|
+
request.headers.get('x-forwarded-for')?.split(',', 1)[0]?.trim();
|
|
613
|
+
return candidate && candidate.length <= 64 && /^[0-9A-Fa-f:.]+$/.test(candidate) ? candidate : undefined;
|
|
614
|
+
}
|
|
615
|
+
async function rateLimitKey(kind, value) {
|
|
616
|
+
if (!value)
|
|
617
|
+
return undefined;
|
|
618
|
+
const digest = await globalThis.crypto.subtle.digest('SHA-256', new TextEncoder().encode(`brandlab-contact-${kind}:${value}`));
|
|
619
|
+
return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('');
|
|
620
|
+
}
|
|
621
|
+
async function handleSubmission(options, request, formData, outcome, ip) {
|
|
600
622
|
const now = options.now?.() ?? new Date();
|
|
601
623
|
if (!Number.isFinite(now.getTime()) || !validateFormShape(options.definition, formData)) {
|
|
602
624
|
return validationResult();
|
|
@@ -637,6 +659,32 @@ async function handleSubmission(options, request, formData) {
|
|
|
637
659
|
if (Object.keys(validated.fieldErrors).length > 0) {
|
|
638
660
|
return validationResult(validated.fieldErrors);
|
|
639
661
|
}
|
|
662
|
+
const mode = options.definition.deploymentMode ?? 'production';
|
|
663
|
+
if (options.rateLimiter && (mode === 'production' || mode === 'preview')) {
|
|
664
|
+
const emailField = options.definition.fields.find((field) => getFieldRole(field) === 'email');
|
|
665
|
+
let decision;
|
|
666
|
+
try {
|
|
667
|
+
const [ipKey, addressKey] = await Promise.all([
|
|
668
|
+
rateLimitKey('ip', ip),
|
|
669
|
+
rateLimitKey('address', emailField ? validated.values[emailField.name] : undefined),
|
|
670
|
+
]);
|
|
671
|
+
decision = options.rateLimiter.check({
|
|
672
|
+
...(ipKey ? { ipKey } : {}),
|
|
673
|
+
...(addressKey ? { addressKey } : {}),
|
|
674
|
+
submissionId: metadata.clientSubmissionId,
|
|
675
|
+
now: now.getTime(),
|
|
676
|
+
});
|
|
677
|
+
}
|
|
678
|
+
catch {
|
|
679
|
+
// A limiter fault never costs an enquiry.
|
|
680
|
+
decision = { ok: true };
|
|
681
|
+
}
|
|
682
|
+
if (!decision.ok) {
|
|
683
|
+
logRateLimited(decision.limit, decision.retryAfterSeconds);
|
|
684
|
+
outcome.retryAfterSeconds = decision.retryAfterSeconds;
|
|
685
|
+
return deliveryUnavailable(true);
|
|
686
|
+
}
|
|
687
|
+
}
|
|
640
688
|
let attachments;
|
|
641
689
|
try {
|
|
642
690
|
attachments = await readValidatedAttachments(options.definition, formData);
|
|
@@ -655,7 +703,6 @@ async function handleSubmission(options, request, formData) {
|
|
|
655
703
|
retryable: false,
|
|
656
704
|
};
|
|
657
705
|
}
|
|
658
|
-
const mode = options.definition.deploymentMode ?? 'production';
|
|
659
706
|
if (mode === 'development' || mode === 'test') {
|
|
660
707
|
return fakeSuccess();
|
|
661
708
|
}
|
|
@@ -673,11 +720,13 @@ async function handleSubmission(options, request, formData) {
|
|
|
673
720
|
confirmationId,
|
|
674
721
|
attachments,
|
|
675
722
|
});
|
|
723
|
+
// A Brandlab test enquiry: delivered like any other, flagged in the subject and never reported as a lead.
|
|
724
|
+
const testEnquiry = stringEntry(formData, CONTACT_FORM_FIELDS.testMarker).trim() === BRANDLAB_CONTACT_TEST_MARKER;
|
|
676
725
|
try {
|
|
677
726
|
const transportResult = await options.transport.send({
|
|
678
727
|
idempotencyKey: createIdempotencyKey(options.definition.projectId, metadata.clientSubmissionId),
|
|
679
728
|
confirmationId,
|
|
680
|
-
subject: rendered.subject,
|
|
729
|
+
subject: testEnquiry ? sanitizeContactEmailSubject(`[Test] ${rendered.subject}`) : rendered.subject,
|
|
681
730
|
html: rendered.html,
|
|
682
731
|
text: rendered.text,
|
|
683
732
|
...(rendered.replyTo ? { replyTo: rendered.replyTo } : {}),
|
|
@@ -700,7 +749,7 @@ async function handleSubmission(options, request, formData) {
|
|
|
700
749
|
logDeliveryFailure({ provider, code: 'provider_invalid_id' });
|
|
701
750
|
return deliveryUnavailable(true);
|
|
702
751
|
}
|
|
703
|
-
return acceptedResult(confirmationId);
|
|
752
|
+
return testEnquiry ? fakeSuccess() : acceptedResult(confirmationId);
|
|
704
753
|
}
|
|
705
754
|
catch {
|
|
706
755
|
logDeliveryFailure({ provider, code: 'transport_exception' });
|
|
@@ -716,6 +765,9 @@ export function createContactRouteHandler(options) {
|
|
|
716
765
|
if (options.botGuard && typeof options.botGuard.assess !== 'function') {
|
|
717
766
|
throw new Error('The optional contact bot guard is invalid.');
|
|
718
767
|
}
|
|
768
|
+
if (options.rateLimiter !== undefined && !isBrandlabContactRateLimiter(options.rateLimiter)) {
|
|
769
|
+
throw new Error('The contact rate limiter is invalid.');
|
|
770
|
+
}
|
|
719
771
|
const limits = getContactRequestLimits(options.definition);
|
|
720
772
|
return async (request) => {
|
|
721
773
|
if (!(request instanceof Request) || request.method.toUpperCase() !== 'POST') {
|
|
@@ -735,7 +787,13 @@ export function createContactRouteHandler(options) {
|
|
|
735
787
|
catch {
|
|
736
788
|
return jsonResult(validationResult(), 400);
|
|
737
789
|
}
|
|
738
|
-
const
|
|
790
|
+
const outcome = {};
|
|
791
|
+
const result = await handleSubmission(options, { origin }, formData, outcome, clientIp(request));
|
|
792
|
+
if (outcome.retryAfterSeconds !== undefined) {
|
|
793
|
+
const response = jsonResult(result, 429);
|
|
794
|
+
response.headers.set('retry-after', String(outcome.retryAfterSeconds));
|
|
795
|
+
return response;
|
|
796
|
+
}
|
|
739
797
|
return jsonResult(result, statusForResult(result));
|
|
740
798
|
};
|
|
741
799
|
}
|
|
@@ -774,6 +832,11 @@ export function createBrandlabContactRuntime(options) {
|
|
|
774
832
|
if (typeof options.createResendSend !== 'function') {
|
|
775
833
|
throw new TypeError('A lazy Resend send factory is required.');
|
|
776
834
|
}
|
|
835
|
+
const rateLimiter = options.rateLimit === false
|
|
836
|
+
? undefined
|
|
837
|
+
: isBrandlabContactRateLimiter(options.rateLimit)
|
|
838
|
+
? options.rateLimit
|
|
839
|
+
: createBrandlabContactRateLimiter(options.rateLimit);
|
|
777
840
|
const mode = options.deploymentMode ?? 'production';
|
|
778
841
|
if (!['production', 'preview', 'development', 'test'].includes(mode)) {
|
|
779
842
|
throw new Error('deploymentMode is invalid.');
|
|
@@ -793,6 +856,7 @@ export function createBrandlabContactRuntime(options) {
|
|
|
793
856
|
: {}),
|
|
794
857
|
...(options.botGuard ? { botGuard: options.botGuard } : {}),
|
|
795
858
|
...(options.now ? { now: options.now } : {}),
|
|
859
|
+
...(rateLimiter ? { rateLimiter } : {}),
|
|
796
860
|
});
|
|
797
861
|
return Object.freeze({
|
|
798
862
|
runtimeKind: BRANDLAB_CONTACT_RUNTIME,
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"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","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n deriveContactAttachmentTransportPolicy,\n detectContactTransportAttachmentType,\n createContactAttachmentFilename,\n defineContactContract,\n parseContactEmailRecipients,\n type BrandlabContactContract,\n type ContactActionResult,\n type ContactAttachmentMimeType,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport { isBrandlabCanonicalEntityId } from '@brandlab-digital/site-core/entity-id'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { resolveBrandlabDeployment } from '@brandlab-digital/site-core/site'\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 RESEND_ERROR_CODES,\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\n/**\n * Contact delivery follows the shared deployment gate on the server's own\n * VERCEL_ENV: production and Preview deliver, everything else (including a\n * local `next start`) accepts without sending. NODE_ENV=test adds test mode.\n */\nexport function detectBrandlabContactDeploymentMode(\n environment: Readonly<Record<string, string | undefined>>,\n): BrandlabContactDeploymentMode {\n const deployment = resolveBrandlabDeployment({\n VERCEL_ENV: environment.VERCEL_ENV,\n NODE_ENV: environment.NODE_ENV,\n })\n if (deployment.environment !== 'development') return deployment.environment\n return environment.NODE_ENV === 'test' ? 'test' : '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\n/**\n * A transport as the route reads it for the delivery-failure log (internal: the\n * public ContactTransport type is unchanged). The shared Resend transport names\n * itself and adds a failed send's documented provider code and HTTP status.\n */\ntype LoggedContactTransport = ContactTransport & { provider?: string }\n\ninterface ContactRouteHandlerOptions {\n definition: BrandlabContactDefinition\n transport?: LoggedContactTransport\n /** The provider the route delivers through, named in the delivery-failure log when it has no transport. */\n provider?: string\n attachmentProcessor?: ContactAttachmentProcessor\n botGuard?: ContactBotGuard\n now?: () => Date\n}\n\nconst DELIVERY_FAILED_EVENT = 'brandlab_contact_delivery_failed'\n\n/** The only values the delivery-failure log writes: anything else is written as `unknown`. */\nconst DELIVERY_LOG_PROVIDERS: ReadonlySet<string> = new Set(['resend'])\nconst DELIVERY_LOG_CODES: ReadonlySet<string> = new Set([\n // The shared Resend transport's own codes.\n 'provider_rejected',\n 'provider_missing_id',\n 'provider_exception',\n 'message_refused',\n // The route's.\n 'provider_invalid_id',\n 'transport_exception',\n 'not_configured',\n // Resend's documented error names.\n ...RESEND_ERROR_CODES,\n])\n\n/**\n * One JSON line on the server's error output for each enquiry the email provider\n * did not accept, for the daily delivery monitor (Vercel logs):\n * `{\"event\":\"brandlab_contact_delivery_failed\",\"provider\":\"resend\",\"status\":429,\"code\":\"rate_limit_exceeded\"}`.\n * Only the provider, its HTTP status and a bounded code are written; a form value,\n * address, name or message never is.\n */\nfunction logDeliveryFailure(failure: { provider?: string; status?: number; code: string }) {\n const known = (allowed: ReadonlySet<string>, value: string | undefined) =>\n value !== undefined && allowed.has(value) ? value : 'unknown'\n const status =\n typeof failure.status === 'number' && Number.isInteger(failure.status) && failure.status >= 100 && failure.status <= 599\n ? failure.status\n : null\n console.error(\n JSON.stringify({\n event: DELIVERY_FAILED_EVENT,\n provider: known(DELIVERY_LOG_PROVIDERS, failure.provider),\n status,\n code: known(DELIVERY_LOG_CODES, failure.code),\n }),\n )\n}\n\nfunction getFieldRole(field: BrandlabContactDefinition['fields'][number]) {\n if (field.role) return field.role\n if (field.name === 'suburb' || field.name === 'location') return 'location' as const\n if (['name', 'email', 'phone', 'message'].includes(field.name)) {\n return field.name as 'name' | 'email' | 'phone' | 'message'\n }\n return 'custom' as const\n}\n\nfunction normalizedHttpsOrigin(value: string) {\n try {\n const url = new URL(value)\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.pathname !== '/' && url.pathname !== '') ||\n value.trim().replace(/\\/$/, '') !== url.origin\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction assertDefinition(definition: BrandlabContactDefinition) {\n if (!isBrandlabCanonicalEntityId(definition.projectId)) {\n throw new Error('projectId must be a canonical Brandlab entity ID.')\n }\n if (\n !definition.brandName.trim() ||\n definition.brandName.trim() !== definition.brandName ||\n definition.brandName.length > 160 ||\n /[\\u0000-\\u001f\\u007f]/.test(definition.brandName)\n ) {\n throw new Error('brandName must contain bounded reviewed text.')\n }\n if (!normalizedHttpsOrigin(definition.siteUrl)) {\n throw new Error('siteUrl must be a canonical HTTPS origin.')\n }\n const mode = definition.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n if (!Array.isArray(definition.fields) || definition.fields.length < 4) {\n throw new Error('Contact fields are unavailable.')\n }\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n const reservedFields = new Set<string>(\n Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n )\n if (!FIELD_NAME_PATTERN.test(honeypotField) || reservedFields.has(honeypotField)) {\n throw new Error('The contact honeypot field is invalid.')\n }\n const fieldNames = new Set<string>()\n for (const field of definition.fields) {\n if (\n !FIELD_NAME_PATTERN.test(field.name) ||\n fieldNames.has(field.name) ||\n reservedFields.has(field.name) ||\n field.name === honeypotField ||\n !field.label.trim() ||\n field.label.length > 120\n ) {\n throw new Error(`Contact field \"${field.name}\" is invalid.`)\n }\n fieldNames.add(field.name)\n }\n for (const role of ['name', 'email', 'phone', 'message'] as const) {\n if (definition.fields.filter((field) => getFieldRole(field) === role).length !== 1) {\n throw new Error(`Contact definition requires exactly one \"${role}\" field.`)\n }\n }\n if (definition.fields.filter((field) => getFieldRole(field) === 'location').length > 1) {\n throw new Error('Contact definition allows at most one \"location\" field.')\n }\n if (definition.attachments) {\n const policy = attachmentPolicy(definition)\n if (\n !Number.isSafeInteger(policy.maxFiles) ||\n policy.maxFiles < 1 ||\n policy.maxFiles > 20 ||\n !Number.isSafeInteger(policy.maxFileSizeBytes) ||\n policy.maxFileSizeBytes < 1 ||\n !Number.isSafeInteger(policy.maxTotalSizeBytes) ||\n policy.maxTotalSizeBytes < policy.maxFileSizeBytes ||\n policy.maxTotalSizeBytes > BRANDLAB_CONTACT_MAX_REQUEST_BYTES ||\n policy.allowedTypes.length < 1 ||\n policy.allowedTypes.some((type) => !SUPPORTED_ATTACHMENT_MIME_TYPES.has(type))\n ) {\n throw new Error('The contact attachment policy is invalid.')\n }\n }\n if (\n definition.email?.style &&\n Object.values(definition.email.style).some(\n (value) => !EMAIL_COLOR_PATTERN.test(value),\n )\n ) {\n throw new Error('Contact email colours must use six-digit hexadecimal values.')\n }\n if (definition.email?.logo) {\n const { url, alt, width } = definition.email.logo\n let parsed: URL | undefined\n try {\n parsed = new URL(url)\n } catch {\n parsed = undefined\n }\n if (\n !parsed ||\n parsed.protocol !== 'https:' ||\n parsed.username ||\n parsed.password ||\n parsed.search ||\n parsed.hash ||\n !alt.trim() ||\n alt.length > 160 ||\n (width !== undefined && (!Number.isInteger(width) || width < 32 || width > 240))\n ) {\n throw new Error('The contact email logo must be a reviewed HTTPS asset.')\n }\n }\n}\n\nfunction attachmentPolicy(definition: BrandlabContactDefinition): ContactAttachmentPolicy {\n return deriveContactAttachmentTransportPolicy({\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n ...(definition.attachments || {}),\n })\n}\n\nexport function getContactRequestLimits(definition: BrandlabContactDefinition) {\n return {\n maxRequestBytes:\n definition.limits?.maxRequestBytes ?? BRANDLAB_CONTACT_MAX_REQUEST_BYTES,\n maxEntries: definition.limits?.maxEntries ?? DEFAULT_MAX_ENTRIES,\n maxStringBytes:\n definition.limits?.maxStringBytes ?? DEFAULT_MAX_STRING_BYTES,\n }\n}\n\nfunction isAttachmentField(definition: BrandlabContactDefinition, name: string) {\n if (!definition.attachments) return false\n const prefix = definition.attachments.fieldPrefix ?? 'attachments'\n return name === prefix || new RegExp(`^${prefix}\\\\[\\\\d{1,2}\\\\]$`).test(name)\n}\n\nfunction validateFormShape(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n const limits = getContactRequestLimits(definition)\n const allowedStrings = new Set([\n ...definition.fields.map((field) => field.name),\n ...Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot,\n ])\n const counts = new Map<string, number>()\n let estimatedBytes = 0\n const entries = Array.from(formData.entries())\n if (entries.length < 1 || entries.length > limits.maxEntries) return false\n for (const [name, value] of entries) {\n if (!FIELD_NAME_PATTERN.test(name.replace(/\\[\\d{1,2}\\]$/, ''))) return false\n counts.set(name, (counts.get(name) ?? 0) + 1)\n if (typeof value === 'string') {\n if (!allowedStrings.has(name) || (counts.get(name) ?? 0) > 1) return false\n const bytes = new TextEncoder().encode(value).byteLength\n if (bytes > limits.maxStringBytes) return false\n estimatedBytes += bytes\n } else {\n if (!isAttachmentField(definition, name) || value.size < 0) return false\n estimatedBytes += value.size\n }\n if (estimatedBytes > limits.maxRequestBytes) return false\n }\n return true\n}\n\nfunction stringEntry(formData: FormData, name: string) {\n const value = formData.get(name)\n return typeof value === 'string' ? value : ''\n}\n\nfunction validateFields(definition: BrandlabContactDefinition, formData: FormData) {\n const values: Record<string, string> = {}\n const fieldErrors: Record<string, string[]> = {}\n for (const field of definition.fields) {\n let value = stringEntry(formData, field.name).trim()\n try {\n value = field.normalize ? field.normalize(value) : value\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n continue\n }\n values[field.name] = value\n const role = getFieldRole(field)\n const required = field.required || role !== 'custom'\n if (required && !value) {\n fieldErrors[field.name] = [`${field.label} is required.`]\n continue\n }\n if (!value) continue\n const maximum = field.maxLength ?? (role === 'message' ? 5_000 : role === 'email' ? 254 : 200)\n if (value.length > maximum) {\n fieldErrors[field.name] = [`${field.label} is too long.`]\n continue\n }\n if ((field.kind === 'email' || role === 'email') && !EMAIL_PATTERN.test(value)) {\n fieldErrors[field.name] = ['Enter a valid email address.']\n continue\n }\n if (\n (field.kind === 'phone' || role === 'phone') &&\n !field.validate &&\n value.replace(/\\D/g, '').length < 6\n ) {\n fieldErrors[field.name] = ['Enter a valid phone number.']\n continue\n }\n if (field.options && !field.options.includes(value)) {\n fieldErrors[field.name] = [`Select a valid ${field.label.toLowerCase()}.`]\n continue\n }\n try {\n const issue = field.validate?.(value, values)\n if (issue) fieldErrors[field.name] = [issue]\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n }\n }\n return { values, fieldErrors }\n}\n\nconst EXTENSION_TYPES: Record<string, ContactAttachmentMimeType> = {\n pdf: 'application/pdf',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n heic: 'image/heic',\n heif: 'image/heif',\n}\n\nfunction normalizeMimeType(value: string) {\n const normalized = value.trim().toLowerCase()\n return normalized === 'image/jpg' ? 'image/jpeg' : normalized\n}\n\nasync function readValidatedAttachments(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n if (!definition.attachments) return []\n const policy = attachmentPolicy(definition)\n const allowed = new Set(policy.allowedTypes.map(normalizeMimeType))\n const files = Array.from(formData.entries())\n .filter(\n ([name, value]) =>\n isAttachmentField(definition, name) &&\n typeof value !== 'string' &&\n value.size > 0,\n )\n .map(([, value]) => value as File)\n if (definition.attachments.required && files.length === 0) return undefined\n if (files.length > policy.maxFiles) return undefined\n\n const attachments: ContactDeliveryAttachment[] = []\n let totalBytes = 0\n for (const [index, file] of files.entries()) {\n const extension = file.name.toLowerCase().split('.').pop() ?? ''\n const extensionType = EXTENSION_TYPES[extension]\n const declaredType = normalizeMimeType(file.type)\n if (\n !extensionType ||\n !declaredType ||\n !allowed.has(extensionType) ||\n !allowed.has(declaredType) ||\n normalizeMimeType(extensionType) !== declaredType ||\n file.size > policy.maxFileSizeBytes\n ) {\n return undefined\n }\n totalBytes += file.size\n if (totalBytes > policy.maxTotalSizeBytes) return undefined\n const content = new Uint8Array(await file.arrayBuffer())\n if (normalizeMimeType(detectContactTransportAttachmentType(content.slice(0, 64)) ?? '') !== declaredType) {\n return undefined\n }\n attachments.push({\n filename: createContactAttachmentFilename({ index, contentType: declaredType }),\n content,\n contentType: declaredType,\n })\n }\n return attachments\n}\n\nfunction validateProcessedAttachments(\n definition: BrandlabContactDefinition,\n attachments: readonly ContactDeliveryAttachment[],\n) {\n if (!definition.attachments) return attachments.length === 0\n const policy = attachmentPolicy(definition)\n let totalBytes = 0\n if (attachments.length > policy.maxFiles) return false\n return attachments.every((attachment, index) => {\n totalBytes += attachment.content.byteLength\n return (\n attachment.filename === createContactAttachmentFilename({ index, contentType: attachment.contentType }) &&\n (attachment.contentType === 'image/jpeg' || (attachment.contentType === 'application/pdf' && policy.allowedTypes.includes('application/pdf'))) &&\n attachment.content.byteLength > 0 &&\n attachment.content.byteLength <= policy.maxFileSizeBytes &&\n totalBytes <= policy.maxTotalSizeBytes &&\n detectContactTransportAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType\n )\n })\n}\n\nfunction validationResult(\n fieldErrors?: Record<string, string[]>,\n): ContactActionResult {\n return {\n ok: false,\n code: 'validation',\n retryable: false,\n ...(fieldErrors && Object.keys(fieldErrors).length > 0 ? { fieldErrors } : {}),\n }\n}\n\nfunction deliveryUnavailable(retryable: boolean): ContactActionResult {\n return { ok: false, code: 'delivery_unavailable', retryable }\n}\n\nfunction fakeSuccess(): ContactActionResult {\n return { ok: true, accepted: false, trackConversion: false }\n}\n\nfunction acceptedResult(confirmationId: string): ContactActionResult {\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId,\n }\n}\n\nfunction parseSubmissionMetadata(\n definition: BrandlabContactDefinition,\n formData: FormData,\n now: Date,\n): {\n clientSubmissionId: string\n submittedAt: string\n context: ContactPageContext\n} | undefined {\n const clientSubmissionId = stringEntry(\n formData,\n CONTACT_FORM_FIELDS.clientSubmissionId,\n )\n .trim()\n .toLowerCase()\n const submittedAt = stringEntry(formData, CONTACT_FORM_FIELDS.submittedAt).trim()\n if (\n !CONTACT_CLIENT_SUBMISSION_ID_PATTERN.test(clientSubmissionId) ||\n !ISO_TIMESTAMP_PATTERN.test(submittedAt)\n ) {\n return undefined\n }\n const submittedMs = Date.parse(submittedAt)\n const nowMs = now.getTime()\n if (\n !Number.isFinite(submittedMs) ||\n submittedMs > nowMs + MAX_CLOCK_SKEW_MS ||\n submittedMs < nowMs - MAX_SUBMISSION_AGE_MS\n ) {\n return undefined\n }\n try {\n const pagePath = normalizeBrandlabRoutePath(\n stringEntry(formData, CONTACT_FORM_FIELDS.pagePath),\n )\n const pageLabel = stringEntry(formData, CONTACT_FORM_FIELDS.pageLabel).trim()\n if (\n pageLabel &&\n (pageLabel.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(pageLabel))\n ) {\n return undefined\n }\n const attribution = normalizeContactAttributionSummary({\n initialLandingPath: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.initialLandingPath,\n ),\n visitSource: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSource,\n ) as Parameters<typeof normalizeContactAttributionSummary>[0]['visitSource'],\n ...(stringEntry(formData, CONTACT_FORM_FIELDS.visitSourceDetail).trim()\n ? {\n visitSourceDetail: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSourceDetail,\n ).trim(),\n }\n : {}),\n })\n return {\n clientSubmissionId,\n submittedAt,\n context: {\n pagePath,\n pageUrl: new URL(pagePath, definition.siteUrl).toString(),\n ...(pageLabel ? { pageLabel } : {}),\n ...attribution,\n },\n }\n } catch {\n return undefined\n }\n}\n\nasync function createConfirmationId(projectId: string, clientSubmissionId: string) {\n if (!globalThis.crypto?.subtle) {\n throw new Error('A secure digest implementation is required.')\n }\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(`${projectId}:${clientSubmissionId}`),\n )\n return Array.from(new Uint8Array(digest), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('')\n}\n\nfunction createIdempotencyKey(projectId: string, clientSubmissionId: string) {\n const projectKey = projectId.replaceAll('&', '-and-')\n return `brandlab/contact/${projectKey}/${clientSubmissionId}`\n}\n\nfunction defaultBotAssessment(\n definition: BrandlabContactDefinition,\n formData: FormData,\n): ContactBotAssessment {\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n return stringEntry(formData, honeypotField).trim()\n ? { status: 'accept-silently' }\n : { status: 'allow' }\n}\n\nfunction normalizedRequestOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash ||\n url.origin !== value\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction forwardedOrigin(request: Request) {\n const host = request.headers.get('x-forwarded-host')?.trim()\n const protocol = request.headers.get('x-forwarded-proto')?.trim()\n if (\n !host ||\n host.includes(',') ||\n host.length > 253 ||\n !/^[a-z0-9.-]+(?::\\d{1,5})?$/i.test(host) ||\n (protocol !== 'https' && protocol !== 'http')\n ) {\n return undefined\n }\n try {\n return new URL(`${protocol}://${host}`).origin\n } catch {\n return undefined\n }\n}\n\nfunction requestOriginCandidates(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n if (mode === 'production') {\n return new Set([normalizedHttpsOrigin(definition.siteUrl)])\n }\n const candidates = new Set<string>()\n try {\n candidates.add(new URL(request.url).origin)\n } catch {\n return undefined\n }\n const forwarded = forwardedOrigin(request)\n if (forwarded) candidates.add(forwarded)\n return candidates\n}\n\nfunction normalizedReferrerOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction sameOriginRequest(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n const candidates = requestOriginCandidates(request, definition)\n if (!candidates) return undefined\n\n const originHeader = request.headers.get('origin')\n if (originHeader !== null) {\n const origin = normalizedRequestOrigin(originHeader, mode)\n return origin && candidates.has(origin) ? origin : undefined\n }\n\n const fetchSite = request.headers.get('sec-fetch-site')\n if (fetchSite !== null && fetchSite !== 'same-origin') return undefined\n const referrerOrigin = normalizedReferrerOrigin(\n request.headers.get('referer'),\n mode,\n )\n return referrerOrigin && candidates.has(referrerOrigin)\n ? referrerOrigin\n : undefined\n}\n\nfunction contentTypeIsAllowed(value: string | null, uploadsEnabled: boolean) {\n if (!value || value.length > 256) return false\n const mediaType = value.split(';', 1)[0]?.trim().toLowerCase()\n if (uploadsEnabled && mediaType !== MULTIPART_FORM) return false\n if (mediaType === FORM_URLENCODED) return true\n return mediaType === MULTIPART_FORM && MULTIPART_BOUNDARY_PATTERN.test(value)\n}\n\nfunction contentLengthIsAllowed(value: string | null, maximum: number) {\n if (value === null) return true\n if (!/^\\d{1,16}$/.test(value)) return false\n const parsed = Number(value)\n return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= maximum\n}\n\nfunction jsonResult(result: ContactActionResult, status: number) {\n return Response.json(result, {\n status,\n headers: {\n 'cache-control': 'no-store, max-age=0',\n pragma: 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n}\n\nfunction statusForResult(result: ContactActionResult) {\n if (result.ok) return 200\n if (result.code === 'delivery_unavailable') return 503\n return 400\n}\n\nasync function handleSubmission(\n options: ContactRouteHandlerOptions,\n request: ContactRequestContext,\n formData: FormData,\n): Promise<ContactActionResult> {\n const now = options.now?.() ?? new Date()\n if (!Number.isFinite(now.getTime()) || !validateFormShape(options.definition, formData)) {\n return validationResult()\n }\n const metadata = parseSubmissionMetadata(options.definition, formData, now)\n if (!metadata) return validationResult()\n\n let confirmationId: string\n try {\n confirmationId = await createConfirmationId(\n options.definition.projectId,\n metadata.clientSubmissionId,\n )\n } catch {\n return deliveryUnavailable(true)\n }\n if (!CONTACT_CONFIRMATION_ID_PATTERN.test(confirmationId)) {\n return deliveryUnavailable(false)\n }\n\n if (defaultBotAssessment(options.definition, formData).status !== 'allow') {\n return fakeSuccess()\n }\n if (options.botGuard) {\n try {\n const result = await options.botGuard.assess({\n formData,\n request,\n projectId: options.definition.projectId,\n confirmationId,\n now: now.getTime(),\n })\n if (result.status !== 'allow') return fakeSuccess()\n } catch {\n return deliveryUnavailable(true)\n }\n }\n\n const validated = validateFields(options.definition, formData)\n if (Object.keys(validated.fieldErrors).length > 0) {\n return validationResult(validated.fieldErrors)\n }\n\n let attachments: readonly ContactDeliveryAttachment[] | undefined\n try {\n attachments = await readValidatedAttachments(options.definition, formData)\n if (attachments && options.attachmentProcessor) {\n const processed = await options.attachmentProcessor.process({ attachments })\n attachments = processed.ok ? processed.attachments : undefined\n }\n } catch {\n attachments = undefined\n }\n if (!attachments || !validateProcessedAttachments(options.definition, attachments)) {\n return {\n ok: false,\n code: 'attachment_rejected',\n retryable: false,\n }\n }\n\n const mode = options.definition.deploymentMode ?? 'production'\n if (mode === 'development' || mode === 'test') {\n return fakeSuccess()\n }\n if (!options.transport) {\n // Production or Preview without its email key or recipients: every enquiry fails until it is set.\n logDeliveryFailure({ provider: options.provider, code: 'not_configured' })\n return deliveryUnavailable(false)\n }\n const provider = options.transport.provider ?? options.provider\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 const detail = transportResult as { providerCode?: unknown; status?: unknown }\n logDeliveryFailure({\n provider,\n ...(typeof detail.status === 'number' ? { status: detail.status } : {}),\n code: (typeof detail.providerCode === 'string' ? detail.providerCode : undefined) ?? transportResult.code ?? 'provider_rejected',\n })\n return deliveryUnavailable(transportResult.retryable ?? true)\n }\n if (!SAFE_PROVIDER_MESSAGE_ID_PATTERN.test(transportResult.providerMessageId)) {\n logDeliveryFailure({ provider, code: 'provider_invalid_id' })\n return deliveryUnavailable(true)\n }\n return acceptedResult(confirmationId)\n } catch {\n logDeliveryFailure({ provider, code: 'transport_exception' })\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 provider: 'resend',\n ...(definition.attachments\n ? { attachmentProcessor: createBrandlabContactImageSanitizer() }\n : {}),\n ...(options.botGuard ? { botGuard: options.botGuard } : {}),\n ...(options.now ? { now: options.now } : {}),\n })\n\n return Object.freeze({\n runtimeKind: BRANDLAB_CONTACT_RUNTIME,\n definition,\n contactRouteHandler,\n })\n}\n"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"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","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n deriveContactAttachmentTransportPolicy,\n detectContactTransportAttachmentType,\n createContactAttachmentFilename,\n defineContactContract,\n parseContactEmailRecipients,\n type BrandlabContactContract,\n type ContactActionResult,\n type ContactAttachmentMimeType,\n type ContactAttachmentPolicy,\n} from '@brandlab-digital/site-core/contact'\nimport { isBrandlabCanonicalEntityId } from '@brandlab-digital/site-core/entity-id'\nimport { normalizeBrandlabRoutePath } from '@brandlab-digital/site-core/routes'\nimport { resolveBrandlabDeployment } from '@brandlab-digital/site-core/site'\nimport { normalizeContactAttributionSummary } from './attribution.js'\nimport {\n createContactDefinitionFromContract,\n type ContactRuntimeDefinitionOptions,\n} from './contract.js'\nimport { renderContactEmail, sanitizeContactEmailSubject } from './email.js'\nimport { createBrandlabContactImageSanitizer } from './image-sanitizer.js'\nimport {\n createBrandlabContactRateLimiter,\n isBrandlabContactRateLimiter,\n type BrandlabContactRateLimitOptions,\n type BrandlabContactRateLimiter,\n} from './rate-limit.js'\nimport {\n RESEND_ERROR_CODES,\n createContractResendContactTransport,\n type ResendContactSend,\n} from './resend.js'\nimport {\n BRANDLAB_CONTACT_TEST_MARKER,\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 {\n BRANDLAB_CONTACT_RATE_LIMITS,\n createBrandlabContactRateLimiter,\n type BrandlabContactRateLimitDecision,\n type BrandlabContactRateLimitInput,\n type BrandlabContactRateLimitOptions,\n type BrandlabContactRateLimitRule,\n type BrandlabContactRateLimiter,\n} from './rate-limit.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\n/**\n * Contact delivery follows the shared deployment gate on the server's own\n * VERCEL_ENV: production and Preview deliver, everything else (including a\n * local `next start`) accepts without sending. NODE_ENV=test adds test mode.\n */\nexport function detectBrandlabContactDeploymentMode(\n environment: Readonly<Record<string, string | undefined>>,\n): BrandlabContactDeploymentMode {\n const deployment = resolveBrandlabDeployment({\n VERCEL_ENV: environment.VERCEL_ENV,\n NODE_ENV: environment.NODE_ENV,\n })\n if (deployment.environment !== 'development') return deployment.environment\n return environment.NODE_ENV === 'test' ? 'test' : '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 * Abuse limits per client IP and per email address on deployments that deliver (production and Preview): the\n * defaults (BRANDLAB_CONTACT_RATE_LIMITS) when omitted, adjusted limits, a limiter shared across runtimes, or\n * `false` to turn them off. Create a runtime once per route module so its limits persist between requests.\n */\n rateLimit?: BrandlabContactRateLimitOptions | BrandlabContactRateLimiter | false\n}\n\nexport interface BrandlabContactRuntime {\n runtimeKind: typeof BRANDLAB_CONTACT_RUNTIME\n definition: ReturnType<typeof createContactDefinitionFromContract>\n contactRouteHandler: (request: Request) => Promise<Response>\n}\n\n/**\n * A transport as the route reads it for the delivery-failure log (internal: the\n * public ContactTransport type is unchanged). The shared Resend transport names\n * itself and adds a failed send's documented provider code and HTTP status.\n */\ntype LoggedContactTransport = ContactTransport & { provider?: string }\n\ninterface ContactRouteHandlerOptions {\n definition: BrandlabContactDefinition\n transport?: LoggedContactTransport\n /** The provider the route delivers through, named in the delivery-failure log when it has no transport. */\n provider?: string\n attachmentProcessor?: ContactAttachmentProcessor\n botGuard?: ContactBotGuard\n now?: () => Date\n rateLimiter?: BrandlabContactRateLimiter\n}\n\n/** What the route adds to the response beyond the result: the wait after a refused, rate-limited enquiry. */\ninterface SubmissionOutcome {\n retryAfterSeconds?: number\n}\n\nconst DELIVERY_FAILED_EVENT = 'brandlab_contact_delivery_failed'\n\n/** The only values the delivery-failure log writes: anything else is written as `unknown`. */\nconst DELIVERY_LOG_PROVIDERS: ReadonlySet<string> = new Set(['resend'])\nconst DELIVERY_LOG_CODES: ReadonlySet<string> = new Set([\n // The shared Resend transport's own codes.\n 'provider_rejected',\n 'provider_missing_id',\n 'provider_exception',\n 'message_refused',\n // The route's.\n 'provider_invalid_id',\n 'transport_exception',\n 'not_configured',\n // Resend's documented error names.\n ...RESEND_ERROR_CODES,\n])\n\n/**\n * One JSON line on the server's error output for each enquiry the email provider\n * did not accept, for the daily delivery monitor (Vercel logs):\n * `{\"event\":\"brandlab_contact_delivery_failed\",\"provider\":\"resend\",\"status\":429,\"code\":\"rate_limit_exceeded\"}`.\n * Only the provider, its HTTP status and a bounded code are written; a form value,\n * address, name or message never is.\n */\nfunction logDeliveryFailure(failure: { provider?: string; status?: number; code: string }) {\n const known = (allowed: ReadonlySet<string>, value: string | undefined) =>\n value !== undefined && allowed.has(value) ? value : 'unknown'\n const status =\n typeof failure.status === 'number' && Number.isInteger(failure.status) && failure.status >= 100 && failure.status <= 599\n ? failure.status\n : null\n console.error(\n JSON.stringify({\n event: DELIVERY_FAILED_EVENT,\n provider: known(DELIVERY_LOG_PROVIDERS, failure.provider),\n status,\n code: known(DELIVERY_LOG_CODES, failure.code),\n }),\n )\n}\n\nfunction getFieldRole(field: BrandlabContactDefinition['fields'][number]) {\n if (field.role) return field.role\n if (field.name === 'suburb' || field.name === 'location') return 'location' as const\n if (['name', 'email', 'phone', 'message'].includes(field.name)) {\n return field.name as 'name' | 'email' | 'phone' | 'message'\n }\n return 'custom' as const\n}\n\nfunction normalizedHttpsOrigin(value: string) {\n try {\n const url = new URL(value)\n if (\n url.protocol !== 'https:' ||\n url.username ||\n url.password ||\n url.search ||\n url.hash ||\n (url.pathname !== '/' && url.pathname !== '') ||\n value.trim().replace(/\\/$/, '') !== url.origin\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction assertDefinition(definition: BrandlabContactDefinition) {\n if (!isBrandlabCanonicalEntityId(definition.projectId)) {\n throw new Error('projectId must be a canonical Brandlab entity ID.')\n }\n if (\n !definition.brandName.trim() ||\n definition.brandName.trim() !== definition.brandName ||\n definition.brandName.length > 160 ||\n /[\\u0000-\\u001f\\u007f]/.test(definition.brandName)\n ) {\n throw new Error('brandName must contain bounded reviewed text.')\n }\n if (!normalizedHttpsOrigin(definition.siteUrl)) {\n throw new Error('siteUrl must be a canonical HTTPS origin.')\n }\n const mode = definition.deploymentMode ?? 'production'\n if (!['production', 'preview', 'development', 'test'].includes(mode)) {\n throw new Error('deploymentMode is invalid.')\n }\n if (!Array.isArray(definition.fields) || definition.fields.length < 4) {\n throw new Error('Contact fields are unavailable.')\n }\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n const reservedFields = new Set<string>(\n Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n )\n if (!FIELD_NAME_PATTERN.test(honeypotField) || reservedFields.has(honeypotField)) {\n throw new Error('The contact honeypot field is invalid.')\n }\n const fieldNames = new Set<string>()\n for (const field of definition.fields) {\n if (\n !FIELD_NAME_PATTERN.test(field.name) ||\n fieldNames.has(field.name) ||\n reservedFields.has(field.name) ||\n field.name === honeypotField ||\n !field.label.trim() ||\n field.label.length > 120\n ) {\n throw new Error(`Contact field \"${field.name}\" is invalid.`)\n }\n fieldNames.add(field.name)\n }\n for (const role of ['name', 'email', 'phone', 'message'] as const) {\n if (definition.fields.filter((field) => getFieldRole(field) === role).length !== 1) {\n throw new Error(`Contact definition requires exactly one \"${role}\" field.`)\n }\n }\n if (definition.fields.filter((field) => getFieldRole(field) === 'location').length > 1) {\n throw new Error('Contact definition allows at most one \"location\" field.')\n }\n if (definition.attachments) {\n const policy = attachmentPolicy(definition)\n if (\n !Number.isSafeInteger(policy.maxFiles) ||\n policy.maxFiles < 1 ||\n policy.maxFiles > 20 ||\n !Number.isSafeInteger(policy.maxFileSizeBytes) ||\n policy.maxFileSizeBytes < 1 ||\n !Number.isSafeInteger(policy.maxTotalSizeBytes) ||\n policy.maxTotalSizeBytes < policy.maxFileSizeBytes ||\n policy.maxTotalSizeBytes > BRANDLAB_CONTACT_MAX_REQUEST_BYTES ||\n policy.allowedTypes.length < 1 ||\n policy.allowedTypes.some((type) => !SUPPORTED_ATTACHMENT_MIME_TYPES.has(type))\n ) {\n throw new Error('The contact attachment policy is invalid.')\n }\n }\n if (\n definition.email?.style &&\n Object.values(definition.email.style).some(\n (value) => !EMAIL_COLOR_PATTERN.test(value),\n )\n ) {\n throw new Error('Contact email colours must use six-digit hexadecimal values.')\n }\n if (definition.email?.logo) {\n const { url, alt, width } = definition.email.logo\n let parsed: URL | undefined\n try {\n parsed = new URL(url)\n } catch {\n parsed = undefined\n }\n if (\n !parsed ||\n parsed.protocol !== 'https:' ||\n parsed.username ||\n parsed.password ||\n parsed.search ||\n parsed.hash ||\n !alt.trim() ||\n alt.length > 160 ||\n (width !== undefined && (!Number.isInteger(width) || width < 32 || width > 240))\n ) {\n throw new Error('The contact email logo must be a reviewed HTTPS asset.')\n }\n }\n}\n\nfunction attachmentPolicy(definition: BrandlabContactDefinition): ContactAttachmentPolicy {\n return deriveContactAttachmentTransportPolicy({\n ...DEFAULT_CONTACT_ATTACHMENT_POLICY,\n ...(definition.attachments || {}),\n })\n}\n\nexport function getContactRequestLimits(definition: BrandlabContactDefinition) {\n return {\n maxRequestBytes:\n definition.limits?.maxRequestBytes ?? BRANDLAB_CONTACT_MAX_REQUEST_BYTES,\n maxEntries: definition.limits?.maxEntries ?? DEFAULT_MAX_ENTRIES,\n maxStringBytes:\n definition.limits?.maxStringBytes ?? DEFAULT_MAX_STRING_BYTES,\n }\n}\n\nfunction isAttachmentField(definition: BrandlabContactDefinition, name: string) {\n if (!definition.attachments) return false\n const prefix = definition.attachments.fieldPrefix ?? 'attachments'\n return name === prefix || new RegExp(`^${prefix}\\\\[\\\\d{1,2}\\\\]$`).test(name)\n}\n\nfunction validateFormShape(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n const limits = getContactRequestLimits(definition)\n const allowedStrings = new Set([\n ...definition.fields.map((field) => field.name),\n ...Object.values(CONTACT_FORM_FIELDS).filter(\n (fieldName) => fieldName !== CONTACT_FORM_FIELDS.honeypot,\n ),\n definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot,\n ])\n const counts = new Map<string, number>()\n let estimatedBytes = 0\n const entries = Array.from(formData.entries())\n if (entries.length < 1 || entries.length > limits.maxEntries) return false\n for (const [name, value] of entries) {\n if (!FIELD_NAME_PATTERN.test(name.replace(/\\[\\d{1,2}\\]$/, ''))) return false\n counts.set(name, (counts.get(name) ?? 0) + 1)\n if (typeof value === 'string') {\n if (!allowedStrings.has(name) || (counts.get(name) ?? 0) > 1) return false\n const bytes = new TextEncoder().encode(value).byteLength\n if (bytes > limits.maxStringBytes) return false\n estimatedBytes += bytes\n } else {\n if (!isAttachmentField(definition, name) || value.size < 0) return false\n estimatedBytes += value.size\n }\n if (estimatedBytes > limits.maxRequestBytes) return false\n }\n return true\n}\n\nfunction stringEntry(formData: FormData, name: string) {\n const value = formData.get(name)\n return typeof value === 'string' ? value : ''\n}\n\nfunction validateFields(definition: BrandlabContactDefinition, formData: FormData) {\n const values: Record<string, string> = {}\n const fieldErrors: Record<string, string[]> = {}\n for (const field of definition.fields) {\n let value = stringEntry(formData, field.name).trim()\n try {\n value = field.normalize ? field.normalize(value) : value\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n continue\n }\n values[field.name] = value\n const role = getFieldRole(field)\n const required = field.required || role !== 'custom'\n if (required && !value) {\n fieldErrors[field.name] = [`${field.label} is required.`]\n continue\n }\n if (!value) continue\n const maximum = field.maxLength ?? (role === 'message' ? 5_000 : role === 'email' ? 254 : 200)\n if (value.length > maximum) {\n fieldErrors[field.name] = [`${field.label} is too long.`]\n continue\n }\n if ((field.kind === 'email' || role === 'email') && !EMAIL_PATTERN.test(value)) {\n fieldErrors[field.name] = ['Enter a valid email address.']\n continue\n }\n if (\n (field.kind === 'phone' || role === 'phone') &&\n !field.validate &&\n value.replace(/\\D/g, '').length < 6\n ) {\n fieldErrors[field.name] = ['Enter a valid phone number.']\n continue\n }\n if (field.options && !field.options.includes(value)) {\n fieldErrors[field.name] = [`Select a valid ${field.label.toLowerCase()}.`]\n continue\n }\n try {\n const issue = field.validate?.(value, values)\n if (issue) fieldErrors[field.name] = [issue]\n } catch {\n fieldErrors[field.name] = [`${field.label} is invalid.`]\n }\n }\n return { values, fieldErrors }\n}\n\nconst EXTENSION_TYPES: Record<string, ContactAttachmentMimeType> = {\n pdf: 'application/pdf',\n jpg: 'image/jpeg',\n jpeg: 'image/jpeg',\n png: 'image/png',\n gif: 'image/gif',\n webp: 'image/webp',\n heic: 'image/heic',\n heif: 'image/heif',\n}\n\nfunction normalizeMimeType(value: string) {\n const normalized = value.trim().toLowerCase()\n return normalized === 'image/jpg' ? 'image/jpeg' : normalized\n}\n\nasync function readValidatedAttachments(\n definition: BrandlabContactDefinition,\n formData: FormData,\n) {\n if (!definition.attachments) return []\n const policy = attachmentPolicy(definition)\n const allowed = new Set(policy.allowedTypes.map(normalizeMimeType))\n const files = Array.from(formData.entries())\n .filter(\n ([name, value]) =>\n isAttachmentField(definition, name) &&\n typeof value !== 'string' &&\n value.size > 0,\n )\n .map(([, value]) => value as File)\n if (definition.attachments.required && files.length === 0) return undefined\n if (files.length > policy.maxFiles) return undefined\n\n const attachments: ContactDeliveryAttachment[] = []\n let totalBytes = 0\n for (const [index, file] of files.entries()) {\n const extension = file.name.toLowerCase().split('.').pop() ?? ''\n const extensionType = EXTENSION_TYPES[extension]\n const declaredType = normalizeMimeType(file.type)\n if (\n !extensionType ||\n !declaredType ||\n !allowed.has(extensionType) ||\n !allowed.has(declaredType) ||\n normalizeMimeType(extensionType) !== declaredType ||\n file.size > policy.maxFileSizeBytes\n ) {\n return undefined\n }\n totalBytes += file.size\n if (totalBytes > policy.maxTotalSizeBytes) return undefined\n const content = new Uint8Array(await file.arrayBuffer())\n if (normalizeMimeType(detectContactTransportAttachmentType(content.slice(0, 64)) ?? '') !== declaredType) {\n return undefined\n }\n attachments.push({\n filename: createContactAttachmentFilename({ index, contentType: declaredType }),\n content,\n contentType: declaredType,\n })\n }\n return attachments\n}\n\nfunction validateProcessedAttachments(\n definition: BrandlabContactDefinition,\n attachments: readonly ContactDeliveryAttachment[],\n) {\n if (!definition.attachments) return attachments.length === 0\n const policy = attachmentPolicy(definition)\n let totalBytes = 0\n if (attachments.length > policy.maxFiles) return false\n return attachments.every((attachment, index) => {\n totalBytes += attachment.content.byteLength\n return (\n attachment.filename === createContactAttachmentFilename({ index, contentType: attachment.contentType }) &&\n (attachment.contentType === 'image/jpeg' || (attachment.contentType === 'application/pdf' && policy.allowedTypes.includes('application/pdf'))) &&\n attachment.content.byteLength > 0 &&\n attachment.content.byteLength <= policy.maxFileSizeBytes &&\n totalBytes <= policy.maxTotalSizeBytes &&\n detectContactTransportAttachmentType(attachment.content.slice(0, 64)) === attachment.contentType\n )\n })\n}\n\nfunction validationResult(\n fieldErrors?: Record<string, string[]>,\n): ContactActionResult {\n return {\n ok: false,\n code: 'validation',\n retryable: false,\n ...(fieldErrors && Object.keys(fieldErrors).length > 0 ? { fieldErrors } : {}),\n }\n}\n\nfunction deliveryUnavailable(retryable: boolean): ContactActionResult {\n return { ok: false, code: 'delivery_unavailable', retryable }\n}\n\nfunction fakeSuccess(): ContactActionResult {\n return { ok: true, accepted: false, trackConversion: false }\n}\n\nfunction acceptedResult(confirmationId: string): ContactActionResult {\n return {\n ok: true,\n accepted: true,\n trackConversion: true,\n confirmationId,\n }\n}\n\nfunction parseSubmissionMetadata(\n definition: BrandlabContactDefinition,\n formData: FormData,\n now: Date,\n): {\n clientSubmissionId: string\n submittedAt: string\n context: ContactPageContext\n} | undefined {\n const clientSubmissionId = stringEntry(\n formData,\n CONTACT_FORM_FIELDS.clientSubmissionId,\n )\n .trim()\n .toLowerCase()\n const submittedAt = stringEntry(formData, CONTACT_FORM_FIELDS.submittedAt).trim()\n if (\n !CONTACT_CLIENT_SUBMISSION_ID_PATTERN.test(clientSubmissionId) ||\n !ISO_TIMESTAMP_PATTERN.test(submittedAt)\n ) {\n return undefined\n }\n const submittedMs = Date.parse(submittedAt)\n const nowMs = now.getTime()\n if (\n !Number.isFinite(submittedMs) ||\n submittedMs > nowMs + MAX_CLOCK_SKEW_MS ||\n submittedMs < nowMs - MAX_SUBMISSION_AGE_MS\n ) {\n return undefined\n }\n try {\n const pagePath = normalizeBrandlabRoutePath(\n stringEntry(formData, CONTACT_FORM_FIELDS.pagePath),\n )\n const pageLabel = stringEntry(formData, CONTACT_FORM_FIELDS.pageLabel).trim()\n if (\n pageLabel &&\n (pageLabel.length > 160 || /[\\u0000-\\u001f\\u007f]/.test(pageLabel))\n ) {\n return undefined\n }\n const attribution = normalizeContactAttributionSummary({\n initialLandingPath: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.initialLandingPath,\n ),\n visitSource: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSource,\n ) as Parameters<typeof normalizeContactAttributionSummary>[0]['visitSource'],\n ...(stringEntry(formData, CONTACT_FORM_FIELDS.visitSourceDetail).trim()\n ? {\n visitSourceDetail: stringEntry(\n formData,\n CONTACT_FORM_FIELDS.visitSourceDetail,\n ).trim(),\n }\n : {}),\n })\n return {\n clientSubmissionId,\n submittedAt,\n context: {\n pagePath,\n pageUrl: new URL(pagePath, definition.siteUrl).toString(),\n ...(pageLabel ? { pageLabel } : {}),\n ...attribution,\n },\n }\n } catch {\n return undefined\n }\n}\n\nasync function createConfirmationId(projectId: string, clientSubmissionId: string) {\n if (!globalThis.crypto?.subtle) {\n throw new Error('A secure digest implementation is required.')\n }\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(`${projectId}:${clientSubmissionId}`),\n )\n return Array.from(new Uint8Array(digest), (byte) =>\n byte.toString(16).padStart(2, '0'),\n ).join('')\n}\n\nfunction createIdempotencyKey(projectId: string, clientSubmissionId: string) {\n const projectKey = projectId.replaceAll('&', '-and-')\n return `brandlab/contact/${projectKey}/${clientSubmissionId}`\n}\n\nfunction defaultBotAssessment(\n definition: BrandlabContactDefinition,\n formData: FormData,\n): ContactBotAssessment {\n const honeypotField = definition.bot?.honeypotField ?? CONTACT_FORM_FIELDS.honeypot\n return stringEntry(formData, honeypotField).trim()\n ? { status: 'accept-silently' }\n : { status: 'allow' }\n}\n\nfunction normalizedRequestOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password ||\n url.pathname !== '/' ||\n url.search ||\n url.hash ||\n url.origin !== value\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction forwardedOrigin(request: Request) {\n const host = request.headers.get('x-forwarded-host')?.trim()\n const protocol = request.headers.get('x-forwarded-proto')?.trim()\n if (\n !host ||\n host.includes(',') ||\n host.length > 253 ||\n !/^[a-z0-9.-]+(?::\\d{1,5})?$/i.test(host) ||\n (protocol !== 'https' && protocol !== 'http')\n ) {\n return undefined\n }\n try {\n return new URL(`${protocol}://${host}`).origin\n } catch {\n return undefined\n }\n}\n\nfunction requestOriginCandidates(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n if (mode === 'production') {\n return new Set([normalizedHttpsOrigin(definition.siteUrl)])\n }\n const candidates = new Set<string>()\n try {\n candidates.add(new URL(request.url).origin)\n } catch {\n return undefined\n }\n const forwarded = forwardedOrigin(request)\n if (forwarded) candidates.add(forwarded)\n return candidates\n}\n\nfunction normalizedReferrerOrigin(\n value: string | null,\n mode: BrandlabContactDeploymentMode,\n) {\n if (!value || value.length > 2_048) return undefined\n try {\n const url = new URL(value)\n const loopback =\n (mode === 'development' || mode === 'test') &&\n url.protocol === 'http:' &&\n (url.hostname === 'localhost' || url.hostname === '127.0.0.1')\n if (\n (url.protocol !== 'https:' && !loopback) ||\n url.username ||\n url.password\n ) {\n return undefined\n }\n return url.origin\n } catch {\n return undefined\n }\n}\n\nfunction sameOriginRequest(\n request: Request,\n definition: BrandlabContactDefinition,\n) {\n const mode = definition.deploymentMode ?? 'production'\n const candidates = requestOriginCandidates(request, definition)\n if (!candidates) return undefined\n\n const originHeader = request.headers.get('origin')\n if (originHeader !== null) {\n const origin = normalizedRequestOrigin(originHeader, mode)\n return origin && candidates.has(origin) ? origin : undefined\n }\n\n const fetchSite = request.headers.get('sec-fetch-site')\n if (fetchSite !== null && fetchSite !== 'same-origin') return undefined\n const referrerOrigin = normalizedReferrerOrigin(\n request.headers.get('referer'),\n mode,\n )\n return referrerOrigin && candidates.has(referrerOrigin)\n ? referrerOrigin\n : undefined\n}\n\nfunction contentTypeIsAllowed(value: string | null, uploadsEnabled: boolean) {\n if (!value || value.length > 256) return false\n const mediaType = value.split(';', 1)[0]?.trim().toLowerCase()\n if (uploadsEnabled && mediaType !== MULTIPART_FORM) return false\n if (mediaType === FORM_URLENCODED) return true\n return mediaType === MULTIPART_FORM && MULTIPART_BOUNDARY_PATTERN.test(value)\n}\n\nfunction contentLengthIsAllowed(value: string | null, maximum: number) {\n if (value === null) return true\n if (!/^\\d{1,16}$/.test(value)) return false\n const parsed = Number(value)\n return Number.isSafeInteger(parsed) && parsed > 0 && parsed <= maximum\n}\n\nfunction jsonResult(result: ContactActionResult, status: number) {\n return Response.json(result, {\n status,\n headers: {\n 'cache-control': 'no-store, max-age=0',\n pragma: 'no-cache',\n 'x-content-type-options': 'nosniff',\n },\n })\n}\n\nfunction statusForResult(result: ContactActionResult) {\n if (result.ok) return 200\n if (result.code === 'delivery_unavailable') return 503\n return 400\n}\n\nconst RATE_LIMITED_EVENT = 'brandlab_contact_rate_limited'\n\n/**\n * One JSON line on the server's error output for each refused enquiry, for the daily delivery monitor:\n * `{\"event\":\"brandlab_contact_rate_limited\",\"rule\":\"ip\",\"retryAfterSeconds\":540}`. Never an address, IP or form value.\n */\nfunction logRateLimited(rule: 'ip' | 'address', retryAfterSeconds: number) {\n console.error(JSON.stringify({ event: RATE_LIMITED_EVENT, rule, retryAfterSeconds }))\n}\n\n/** A client IP as Vercel sets it: `x-real-ip`, else the first `x-forwarded-for` entry. */\nfunction clientIp(request: Request) {\n const candidate =\n request.headers.get('x-real-ip')?.trim() ||\n request.headers.get('x-forwarded-for')?.split(',', 1)[0]?.trim()\n return candidate && candidate.length <= 64 && /^[0-9A-Fa-f:.]+$/.test(candidate) ? candidate : undefined\n}\n\nasync function rateLimitKey(kind: 'ip' | 'address', value: string | undefined) {\n if (!value) return undefined\n const digest = await globalThis.crypto.subtle.digest(\n 'SHA-256',\n new TextEncoder().encode(`brandlab-contact-${kind}:${value}`),\n )\n return Array.from(new Uint8Array(digest), (byte) => byte.toString(16).padStart(2, '0')).join('')\n}\n\nasync function handleSubmission(\n options: ContactRouteHandlerOptions,\n request: ContactRequestContext,\n formData: FormData,\n outcome: SubmissionOutcome,\n ip?: string,\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 const mode = options.definition.deploymentMode ?? 'production'\n if (options.rateLimiter && (mode === 'production' || mode === 'preview')) {\n const emailField = options.definition.fields.find((field) => getFieldRole(field) === 'email')\n let decision: ReturnType<BrandlabContactRateLimiter['check']>\n try {\n const [ipKey, addressKey] = await Promise.all([\n rateLimitKey('ip', ip),\n rateLimitKey('address', emailField ? validated.values[emailField.name] : undefined),\n ])\n decision = options.rateLimiter.check({\n ...(ipKey ? { ipKey } : {}),\n ...(addressKey ? { addressKey } : {}),\n submissionId: metadata.clientSubmissionId,\n now: now.getTime(),\n })\n } catch {\n // A limiter fault never costs an enquiry.\n decision = { ok: true }\n }\n if (!decision.ok) {\n logRateLimited(decision.limit, decision.retryAfterSeconds)\n outcome.retryAfterSeconds = decision.retryAfterSeconds\n return deliveryUnavailable(true)\n }\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 if (mode === 'development' || mode === 'test') {\n return fakeSuccess()\n }\n if (!options.transport) {\n // Production or Preview without its email key or recipients: every enquiry fails until it is set.\n logDeliveryFailure({ provider: options.provider, code: 'not_configured' })\n return deliveryUnavailable(false)\n }\n const provider = options.transport.provider ?? options.provider\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 // A Brandlab test enquiry: delivered like any other, flagged in the subject and never reported as a lead.\n const testEnquiry =\n stringEntry(formData, CONTACT_FORM_FIELDS.testMarker).trim() === BRANDLAB_CONTACT_TEST_MARKER\n try {\n const transportResult = await options.transport.send({\n idempotencyKey: createIdempotencyKey(\n options.definition.projectId,\n metadata.clientSubmissionId,\n ),\n confirmationId,\n subject: testEnquiry ? sanitizeContactEmailSubject(`[Test] ${rendered.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 const detail = transportResult as { providerCode?: unknown; status?: unknown }\n logDeliveryFailure({\n provider,\n ...(typeof detail.status === 'number' ? { status: detail.status } : {}),\n code: (typeof detail.providerCode === 'string' ? detail.providerCode : undefined) ?? transportResult.code ?? 'provider_rejected',\n })\n return deliveryUnavailable(transportResult.retryable ?? true)\n }\n if (!SAFE_PROVIDER_MESSAGE_ID_PATTERN.test(transportResult.providerMessageId)) {\n logDeliveryFailure({ provider, code: 'provider_invalid_id' })\n return deliveryUnavailable(true)\n }\n return testEnquiry ? fakeSuccess() : acceptedResult(confirmationId)\n } catch {\n logDeliveryFailure({ provider, code: 'transport_exception' })\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 if (options.rateLimiter !== undefined && !isBrandlabContactRateLimiter(options.rateLimiter)) {\n throw new Error('The contact rate limiter 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 outcome: SubmissionOutcome = {}\n const result = await handleSubmission(options, { origin }, formData, outcome, clientIp(request))\n if (outcome.retryAfterSeconds !== undefined) {\n const response = jsonResult(result, 429)\n response.headers.set('retry-after', String(outcome.retryAfterSeconds))\n return response\n }\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 rateLimiter =\n options.rateLimit === false\n ? undefined\n : isBrandlabContactRateLimiter(options.rateLimit)\n ? options.rateLimit\n : createBrandlabContactRateLimiter(options.rateLimit)\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 provider: 'resend',\n ...(definition.attachments\n ? { attachmentProcessor: createBrandlabContactImageSanitizer() }\n : {}),\n ...(options.botGuard ? { botGuard: options.botGuard } : {}),\n ...(options.now ? { now: options.now } : {}),\n ...(rateLimiter ? { rateLimiter } : {}),\n })\n\n return Object.freeze({\n runtimeKind: BRANDLAB_CONTACT_RUNTIME,\n definition,\n contactRouteHandler,\n })\n}\n"]}
|
package/dist/contact/shared.d.ts
CHANGED
|
@@ -8,7 +8,18 @@ export declare const CONTACT_FORM_FIELDS: {
|
|
|
8
8
|
readonly visitSource: "visitSource";
|
|
9
9
|
readonly visitSourceDetail: "visitSourceDetail";
|
|
10
10
|
readonly honeypot: "website";
|
|
11
|
+
/** Brandlab's test marker: `bl_test=1` on a test enquiry (see BRANDLAB_CONTACT_TEST_MARKER). */
|
|
12
|
+
readonly testMarker: "bl_test";
|
|
11
13
|
};
|
|
14
|
+
/**
|
|
15
|
+
* The value of the `bl_test` field on a Brandlab test enquiry (a launch proof or a canary). The server strips the
|
|
16
|
+
* marker: the enquiry is delivered to the configured recipient with "[Test]" in the subject, and is answered like a
|
|
17
|
+
* silent acceptance, so the browser never reports it as a lead (no `contact_form`, no Ads conversion). Any other
|
|
18
|
+
* value is ignored and the enquiry is treated as a real one.
|
|
19
|
+
*/
|
|
20
|
+
export declare const BRANDLAB_CONTACT_TEST_MARKER: "1";
|
|
21
|
+
/** The characters a phone value may contain: digits, +, brackets, spaces, dots and every dash autocorrect produces. */
|
|
22
|
+
export declare const CONTACT_PHONE_CHARACTERS: RegExp;
|
|
12
23
|
export declare const CONTACT_CLIENT_SUBMISSION_ID_PATTERN: RegExp;
|
|
13
24
|
export declare const CONTACT_CONFIRMATION_ID_PATTERN: RegExp;
|
|
14
25
|
export declare const CONTACT_IDEMPOTENCY_KEY_PATTERN: RegExp;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/contact/shared.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACV,yBAAyB,EACzB,uBAAuB,EACvB,gBAAgB,EACjB,MAAM,qCAAqC,CAAA;AAE5C,eAAO,MAAM,mBAAmB;;;;;;;;;
|
|
1
|
+
{"version":3,"file":"shared.d.ts","sourceRoot":"","sources":["../../src/contact/shared.ts"],"names":[],"mappings":"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"}
|
package/dist/contact/shared.js
CHANGED
|
@@ -7,7 +7,18 @@ export const CONTACT_FORM_FIELDS = {
|
|
|
7
7
|
visitSource: 'visitSource',
|
|
8
8
|
visitSourceDetail: 'visitSourceDetail',
|
|
9
9
|
honeypot: 'website',
|
|
10
|
+
/** Brandlab's test marker: `bl_test=1` on a test enquiry (see BRANDLAB_CONTACT_TEST_MARKER). */
|
|
11
|
+
testMarker: 'bl_test',
|
|
10
12
|
};
|
|
13
|
+
/**
|
|
14
|
+
* The value of the `bl_test` field on a Brandlab test enquiry (a launch proof or a canary). The server strips the
|
|
15
|
+
* marker: the enquiry is delivered to the configured recipient with "[Test]" in the subject, and is answered like a
|
|
16
|
+
* silent acceptance, so the browser never reports it as a lead (no `contact_form`, no Ads conversion). Any other
|
|
17
|
+
* value is ignored and the enquiry is treated as a real one.
|
|
18
|
+
*/
|
|
19
|
+
export const BRANDLAB_CONTACT_TEST_MARKER = '1';
|
|
20
|
+
/** The characters a phone value may contain: digits, +, brackets, spaces, dots and every dash autocorrect produces. */
|
|
21
|
+
export const CONTACT_PHONE_CHARACTERS = /^[+()\d\s.\-\u2010-\u2015\u2212]+$/;
|
|
11
22
|
export const CONTACT_CLIENT_SUBMISSION_ID_PATTERN = /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/;
|
|
12
23
|
export const CONTACT_CONFIRMATION_ID_PATTERN = /^[0-9a-f]{64}$/;
|
|
13
24
|
export const CONTACT_IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9/_-]{1,256}$/;
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/contact/shared.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,kBAAkB,EAAE,oBAAoB;IACxC,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,kBAAkB,EAAE,oBAAoB;IACxC,WAAW,EAAE,aAAa;IAC1B,iBAAiB,EAAE,mBAAmB;IACtC,QAAQ,EAAE,SAAS;
|
|
1
|
+
{"version":3,"file":"shared.js","sourceRoot":"","sources":["../../src/contact/shared.ts"],"names":[],"mappings":"AAMA,MAAM,CAAC,MAAM,mBAAmB,GAAG;IACjC,kBAAkB,EAAE,oBAAoB;IACxC,WAAW,EAAE,aAAa;IAC1B,QAAQ,EAAE,UAAU;IACpB,SAAS,EAAE,WAAW;IACtB,kBAAkB,EAAE,oBAAoB;IACxC,WAAW,EAAE,aAAa;IAC1B,iBAAiB,EAAE,mBAAmB;IACtC,QAAQ,EAAE,SAAS;IACnB,gGAAgG;IAChG,UAAU,EAAE,SAAS;CACb,CAAA;AAEV;;;;;GAKG;AACH,MAAM,CAAC,MAAM,4BAA4B,GAAG,GAAY,CAAA;AAExD,uHAAuH;AACvH,MAAM,CAAC,MAAM,wBAAwB,GAAG,oCAAoC,CAAA;AAE5E,MAAM,CAAC,MAAM,oCAAoC,GAC/C,uEAAuE,CAAA;AACzE,MAAM,CAAC,MAAM,+BAA+B,GAAG,gBAAgB,CAAA;AAC/D,MAAM,CAAC,MAAM,+BAA+B,GAAG,yBAAyB,CAAA;AA8ExE,MAAM,UAAU,qBAAqB,CACnC,UAAgD;IAEhD,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,MAAM,UAAU,yBAAyB;IACvC,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,UAAU,EAAE,CAAC;QACnC,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,OAAO,UAAU,CAAC,MAAM,CAAC,UAAU,EAAE,CAAC,WAAW,EAAE,CAAA;AACrD,CAAC","sourcesContent":["import type {\n ContactAttributionSummary,\n ContactAttachmentPolicy,\n ContactFieldRole,\n} from '@brandlab-digital/site-core/contact'\n\nexport const CONTACT_FORM_FIELDS = {\n clientSubmissionId: 'clientSubmissionId',\n submittedAt: 'submittedAt',\n pagePath: 'pagePath',\n pageLabel: 'pageLabel',\n initialLandingPath: 'initialLandingPath',\n visitSource: 'visitSource',\n visitSourceDetail: 'visitSourceDetail',\n honeypot: 'website',\n /** Brandlab's test marker: `bl_test=1` on a test enquiry (see BRANDLAB_CONTACT_TEST_MARKER). */\n testMarker: 'bl_test',\n} as const\n\n/**\n * The value of the `bl_test` field on a Brandlab test enquiry (a launch proof or a canary). The server strips the\n * marker: the enquiry is delivered to the configured recipient with \"[Test]\" in the subject, and is answered like a\n * silent acceptance, so the browser never reports it as a lead (no `contact_form`, no Ads conversion). Any other\n * value is ignored and the enquiry is treated as a real one.\n */\nexport const BRANDLAB_CONTACT_TEST_MARKER = '1' as const\n\n/** The characters a phone value may contain: digits, +, brackets, spaces, dots and every dash autocorrect produces. */\nexport const CONTACT_PHONE_CHARACTERS = /^[+()\\d\\s.\\-\\u2010-\\u2015\\u2212]+$/\n\nexport const CONTACT_CLIENT_SUBMISSION_ID_PATTERN =\n /^[0-9a-f]{8}-[0-9a-f]{4}-4[0-9a-f]{3}-[89ab][0-9a-f]{3}-[0-9a-f]{12}$/\nexport const CONTACT_CONFIRMATION_ID_PATTERN = /^[0-9a-f]{64}$/\nexport const CONTACT_IDEMPOTENCY_KEY_PATTERN = /^[A-Za-z0-9/_-]{1,256}$/\n\nexport type ContactFieldKind =\n | 'text'\n | 'email'\n | 'phone'\n | 'textarea'\n | 'select'\n | 'checkbox'\n\nexport interface ContactFieldDefinition<Name extends string = string> {\n name: Name\n label: string\n role?: ContactFieldRole\n kind?: ContactFieldKind\n required?: boolean\n maxLength?: number\n options?: readonly string[]\n normalize?: (value: string) => string\n validate?: (\n value: string,\n values: Readonly<Record<string, string>>,\n ) => string | undefined\n}\n\nexport interface ContactEmailStyle {\n accentColor?: string\n backgroundColor?: string\n surfaceColor?: string\n textColor?: string\n mutedTextColor?: string\n}\n\nexport interface ContactEmailLogo {\n url: string\n alt: string\n width?: number\n}\n\nexport interface ContactEmailConfig {\n style?: ContactEmailStyle\n logo?: ContactEmailLogo\n}\n\nexport type BrandlabContactDeploymentMode =\n | 'production'\n | 'preview'\n | 'development'\n | 'test'\n\nexport interface BrandlabContactDefinition<FieldName extends string = string> {\n projectId: string\n brandName: string\n siteUrl: string\n deploymentMode?: BrandlabContactDeploymentMode\n fields: readonly ContactFieldDefinition<FieldName>[]\n attachments?:\n | false\n | (Partial<ContactAttachmentPolicy> & {\n fieldPrefix?: string\n required?: boolean\n })\n email?: ContactEmailConfig\n limits?: {\n maxRequestBytes?: number\n maxEntries?: number\n maxStringBytes?: number\n }\n bot?: {\n honeypotField?: string\n }\n}\n\n/** The part of a contact definition that analytics reads: field names and roles. */\nexport interface BrandlabContactFieldRoles {\n fields: readonly Pick<ContactFieldDefinition, 'name' | 'role'>[]\n}\n\nexport function defineBrandlabContact<const FieldName extends string>(\n definition: BrandlabContactDefinition<FieldName>,\n) {\n return definition\n}\n\nexport function createContactSubmissionId() {\n if (!globalThis.crypto?.randomUUID) {\n throw new Error('A secure identifier generator is required.')\n }\n return globalThis.crypto.randomUUID().toLowerCase()\n}\n\nexport interface ContactPageContext extends ContactAttributionSummary {\n pageLabel?: string\n pagePath: string\n pageUrl: string\n}\n\nexport interface ContactRequestContext {\n origin: string\n}\n\nexport interface ContactDeliveryAttachment {\n filename: string\n content: Uint8Array\n contentType: string\n}\n\nexport interface ContactDeliveryMessage {\n idempotencyKey: string\n confirmationId: string\n subject: string\n html: string\n text: string\n replyTo?: string\n attachments: readonly ContactDeliveryAttachment[]\n providerMetadata: Readonly<{\n project_id: string\n submission_hash: string\n }>\n}\n\nexport type ContactTransportResult =\n | { ok: true; providerMessageId: string }\n | { ok: false; code?: string; retryable?: boolean }\n\nexport interface ContactTransport {\n send(message: ContactDeliveryMessage): Promise<ContactTransportResult>\n}\n\nexport type ContactBotAssessment =\n | { status: 'allow' }\n | { status: 'accept-silently' }\n | { status: 'reject' }\n\nexport interface ContactBotGuard {\n assess(input: {\n formData: FormData\n request: ContactRequestContext\n projectId: string\n confirmationId: string\n now: number\n }): Promise<ContactBotAssessment> | ContactBotAssessment\n}\n\nexport type ContactAttachmentResult =\n | { ok: true; attachments: readonly ContactDeliveryAttachment[] }\n | { ok: false }\n\nexport interface ContactAttachmentProcessor {\n capability: 'sanitizes-contact-images-v1'\n process(input: {\n attachments: readonly ContactDeliveryAttachment[]\n }): Promise<ContactAttachmentResult>\n}\n"]}
|
|
@@ -13,6 +13,11 @@ export interface RecordBrandlabContactLeadInput {
|
|
|
13
13
|
/** The provider confirmation ID (64 lowercase hex characters). */
|
|
14
14
|
confirmationId: string;
|
|
15
15
|
adUserDataConsent?: boolean;
|
|
16
|
+
/**
|
|
17
|
+
* Whether the enquiry carried photos. useBrandlabContactForm always sends contact_form's `has_photos`; pass this
|
|
18
|
+
* to record it too (omitted, the recorded event has no has_photos, as before 3.10.0).
|
|
19
|
+
*/
|
|
20
|
+
hasPhotos?: boolean;
|
|
16
21
|
}
|
|
17
22
|
export interface RecordedBrandlabContactLead {
|
|
18
23
|
/** Every gtag call, in order, that the accepted enquiry sends on the production deployment. */
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/contact/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AACzG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAKxD,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,8BAA8B;IAC7C,kDAAkD;IAClD,SAAS,EAAE,iBAAiB,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,EAAE,uBAAuB,CAAA;IACjC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,QAAQ,CAAA;IAClB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAA;
|
|
1
|
+
{"version":3,"file":"testing.d.ts","sourceRoot":"","sources":["../../src/contact/testing.ts"],"names":[],"mappings":"AAAA,OAAO,EAAyB,KAAK,uBAAuB,EAAE,MAAM,qCAAqC,CAAA;AACzG,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,iBAAiB,CAAA;AAKxD,OAAO,EACL,wBAAwB,EACxB,sBAAsB,EACtB,kBAAkB,EAClB,2BAA2B,EAC3B,KAAK,uBAAuB,EAC5B,KAAK,oBAAoB,GAC1B,MAAM,YAAY,CAAA;AAEnB,MAAM,WAAW,8BAA8B;IAC7C,kDAAkD;IAClD,SAAS,EAAE,iBAAiB,CAAA;IAC5B,yFAAyF;IACzF,QAAQ,EAAE,uBAAuB,CAAA;IACjC,kEAAkE;IAClE,QAAQ,EAAE,MAAM,CAAA;IAChB,4EAA4E;IAC5E,QAAQ,EAAE,QAAQ,CAAA;IAClB,kEAAkE;IAClE,cAAc,EAAE,MAAM,CAAA;IACtB,iBAAiB,CAAC,EAAE,OAAO,CAAA;IAC3B;;;OAGG;IACH,SAAS,CAAC,EAAE,OAAO,CAAA;CACpB;AAED,MAAM,WAAW,2BAA2B;IAC1C,+FAA+F;IAC/F,KAAK,EAAE,OAAO,EAAE,EAAE,CAAA;IAClB,OAAO,EAAE,OAAO,CAAA;IAChB,sBAAsB,EAAE,OAAO,CAAA;IAC/B,iBAAiB,EAAE,OAAO,CAAA;CAC3B;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CAAC,KAAK,EAAE,8BAA8B,GAAG,2BAA2B,CAqB5G"}
|