@brandlab-digital/site-next 3.13.0 → 3.14.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 +79 -0
- package/dist/contact/delivery.d.ts +81 -0
- package/dist/contact/delivery.d.ts.map +1 -0
- package/dist/contact/delivery.js +138 -0
- package/dist/contact/delivery.js.map +1 -0
- package/dist/contact/resend-webhook.d.ts +72 -0
- package/dist/contact/resend-webhook.d.ts.map +1 -0
- package/dist/contact/resend-webhook.js +300 -0
- package/dist/contact/resend-webhook.js.map +1 -0
- package/dist/contact/route-handler.d.ts +16 -0
- package/dist/contact/route-handler.d.ts.map +1 -1
- package/dist/contact/route-handler.js +8 -0
- package/dist/contact/route-handler.js.map +1 -1
- package/dist/contact/server-entry.d.ts +2 -0
- package/dist/contact/server-entry.d.ts.map +1 -1
- package/dist/contact/server-entry.js +2 -0
- package/dist/contact/server-entry.js.map +1 -1
- package/dist/contact/server.d.ts +26 -0
- package/dist/contact/server.d.ts.map +1 -1
- package/dist/contact/server.js +48 -3
- package/dist/contact/server.js.map +1 -1
- package/dist/next-config.d.ts +17 -1
- package/dist/next-config.d.ts.map +1 -1
- package/dist/next-config.js +36 -2
- package/dist/next-config.js.map +1 -1
- package/dist/ui-kit/brandlab-skin.d.ts +24 -1
- 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/photo-upload.d.ts +4 -1
- package/dist/ui-kit/form/photo-upload.d.ts.map +1 -1
- package/dist/ui-kit/form/photo-upload.js +4 -4
- package/dist/ui-kit/form/photo-upload.js.map +1 -1
- package/dist/ui-kit/form/quote-form.d.ts +4 -1
- package/dist/ui-kit/form/quote-form.d.ts.map +1 -1
- package/dist/ui-kit/form/quote-form.js.map +1 -1
- package/dist/ui-kit/form/thank-you.d.ts +4 -1
- package/dist/ui-kit/form/thank-you.d.ts.map +1 -1
- package/dist/ui-kit/form/thank-you.js +2 -2
- package/dist/ui-kit/form/thank-you.js.map +1 -1
- package/dist/ui-kit/icon-glyphs.d.ts +41 -0
- package/dist/ui-kit/icon-glyphs.d.ts.map +1 -0
- package/dist/ui-kit/icon-glyphs.js +138 -0
- package/dist/ui-kit/icon-glyphs.js.map +1 -0
- package/dist/ui-kit/icon-sprite.d.ts +19 -0
- package/dist/ui-kit/icon-sprite.d.ts.map +1 -0
- package/dist/ui-kit/icon-sprite.js +44 -0
- package/dist/ui-kit/icon-sprite.js.map +1 -0
- package/dist/ui-kit/icons.d.ts +38 -3
- package/dist/ui-kit/icons.d.ts.map +1 -1
- package/dist/ui-kit/icons.js +47 -64
- package/dist/ui-kit/icons.js.map +1 -1
- package/dist/ui-kit/primitives/badge.d.ts +25 -0
- package/dist/ui-kit/primitives/badge.d.ts.map +1 -0
- package/dist/ui-kit/primitives/badge.js +21 -0
- package/dist/ui-kit/primitives/badge.js.map +1 -0
- package/dist/ui-kit/primitives/breadcrumbs.d.ts +27 -0
- package/dist/ui-kit/primitives/breadcrumbs.d.ts.map +1 -0
- package/dist/ui-kit/primitives/breadcrumbs.js +40 -0
- package/dist/ui-kit/primitives/breadcrumbs.js.map +1 -0
- package/dist/ui-kit/primitives/button.d.ts +32 -0
- package/dist/ui-kit/primitives/button.d.ts.map +1 -0
- package/dist/ui-kit/primitives/button.js +8 -0
- package/dist/ui-kit/primitives/button.js.map +1 -0
- package/dist/ui-kit/primitives/card.d.ts +40 -0
- package/dist/ui-kit/primitives/card.d.ts.map +1 -0
- package/dist/ui-kit/primitives/card.js +8 -0
- package/dist/ui-kit/primitives/card.js.map +1 -0
- package/dist/ui-kit/primitives/index.d.ts +11 -2
- package/dist/ui-kit/primitives/index.d.ts.map +1 -1
- package/dist/ui-kit/primitives/index.js +11 -2
- package/dist/ui-kit/primitives/index.js.map +1 -1
- package/dist/ui-kit/primitives/layout.d.ts +12 -0
- package/dist/ui-kit/primitives/layout.d.ts.map +1 -1
- package/dist/ui-kit/primitives/layout.js +20 -2
- package/dist/ui-kit/primitives/layout.js.map +1 -1
- package/dist/ui-kit/primitives/links.d.ts +15 -0
- package/dist/ui-kit/primitives/links.d.ts.map +1 -1
- package/dist/ui-kit/primitives/links.js +5 -1
- package/dist/ui-kit/primitives/links.js.map +1 -1
- package/dist/ui-kit/primitives/lists.d.ts +43 -0
- package/dist/ui-kit/primitives/lists.d.ts.map +1 -0
- package/dist/ui-kit/primitives/lists.js +34 -0
- package/dist/ui-kit/primitives/lists.js.map +1 -0
- package/dist/ui-kit/primitives/media-frame.d.ts +28 -0
- package/dist/ui-kit/primitives/media-frame.d.ts.map +1 -0
- package/dist/ui-kit/primitives/media-frame.js +58 -0
- package/dist/ui-kit/primitives/media-frame.js.map +1 -0
- package/dist/ui-kit/primitives/media.d.ts +38 -0
- package/dist/ui-kit/primitives/media.d.ts.map +1 -0
- package/dist/ui-kit/primitives/media.js +9 -0
- package/dist/ui-kit/primitives/media.js.map +1 -0
- package/dist/ui-kit/primitives/stat.d.ts +25 -0
- package/dist/ui-kit/primitives/stat.d.ts.map +1 -0
- package/dist/ui-kit/primitives/stat.js +7 -0
- package/dist/ui-kit/primitives/stat.js.map +1 -0
- package/dist/ui-kit/repeated-slots.d.ts +121 -0
- package/dist/ui-kit/repeated-slots.d.ts.map +1 -0
- package/dist/ui-kit/repeated-slots.js +81 -0
- package/dist/ui-kit/repeated-slots.js.map +1 -0
- package/dist/ui-kit/sections/accordion.d.ts +4 -1
- package/dist/ui-kit/sections/accordion.d.ts.map +1 -1
- package/dist/ui-kit/sections/accordion.js +2 -2
- package/dist/ui-kit/sections/accordion.js.map +1 -1
- package/dist/ui-kit/sections/contact-block.d.ts +4 -1
- package/dist/ui-kit/sections/contact-block.d.ts.map +1 -1
- package/dist/ui-kit/sections/contact-block.js +3 -3
- package/dist/ui-kit/sections/contact-block.js.map +1 -1
- package/dist/ui-kit/sections/faqs.d.ts +4 -1
- package/dist/ui-kit/sections/faqs.d.ts.map +1 -1
- package/dist/ui-kit/sections/faqs.js +4 -5
- package/dist/ui-kit/sections/faqs.js.map +1 -1
- package/dist/ui-kit/sections/hero.d.ts +113 -0
- package/dist/ui-kit/sections/hero.d.ts.map +1 -0
- package/dist/ui-kit/sections/hero.js +58 -0
- package/dist/ui-kit/sections/hero.js.map +1 -0
- package/dist/ui-kit/sections/index.d.ts +2 -0
- package/dist/ui-kit/sections/index.d.ts.map +1 -1
- package/dist/ui-kit/sections/index.js +2 -0
- package/dist/ui-kit/sections/index.js.map +1 -1
- package/dist/ui-kit/sections/price-guide.d.ts +4 -1
- package/dist/ui-kit/sections/price-guide.d.ts.map +1 -1
- package/dist/ui-kit/sections/price-guide.js +3 -3
- package/dist/ui-kit/sections/price-guide.js.map +1 -1
- package/dist/ui-kit/sections/price-table.d.ts +7 -9
- package/dist/ui-kit/sections/price-table.d.ts.map +1 -1
- package/dist/ui-kit/sections/price-table.js +8 -8
- package/dist/ui-kit/sections/price-table.js.map +1 -1
- package/dist/ui-kit/sections/proof-strip.d.ts +4 -1
- package/dist/ui-kit/sections/proof-strip.d.ts.map +1 -1
- package/dist/ui-kit/sections/proof-strip.js +2 -2
- package/dist/ui-kit/sections/proof-strip.js.map +1 -1
- package/dist/ui-kit/sections/reviews-band.d.ts +5 -2
- package/dist/ui-kit/sections/reviews-band.d.ts.map +1 -1
- package/dist/ui-kit/sections/reviews-band.js +2 -2
- package/dist/ui-kit/sections/reviews-band.js.map +1 -1
- package/dist/ui-kit/sections/services-grid.d.ts +82 -0
- package/dist/ui-kit/sections/services-grid.d.ts.map +1 -0
- package/dist/ui-kit/sections/services-grid.js +90 -0
- package/dist/ui-kit/sections/services-grid.js.map +1 -0
- package/dist/ui-kit/sections/site-footer.d.ts +4 -1
- package/dist/ui-kit/sections/site-footer.d.ts.map +1 -1
- package/dist/ui-kit/sections/site-footer.js +6 -6
- package/dist/ui-kit/sections/site-footer.js.map +1 -1
- package/dist/ui-kit/shell/mobile-drawer.d.ts +7 -3
- package/dist/ui-kit/shell/mobile-drawer.d.ts.map +1 -1
- package/dist/ui-kit/shell/mobile-drawer.js +20 -4
- package/dist/ui-kit/shell/mobile-drawer.js.map +1 -1
- package/dist/ui-kit/shell/site-header.d.ts +4 -1
- package/dist/ui-kit/shell/site-header.d.ts.map +1 -1
- package/dist/ui-kit/shell/site-header.js +8 -8
- package/dist/ui-kit/shell/site-header.js.map +1 -1
- package/dist/ui-kit/shell/social-links.d.ts +1 -2
- package/dist/ui-kit/shell/social-links.d.ts.map +1 -1
- package/dist/ui-kit/shell/social-links.js +6 -3
- package/dist/ui-kit/shell/social-links.js.map +1 -1
- package/dist/ui-kit/shell/utility-bar.d.ts +4 -1
- package/dist/ui-kit/shell/utility-bar.d.ts.map +1 -1
- package/dist/ui-kit/shell/utility-bar.js +2 -2
- package/dist/ui-kit/shell/utility-bar.js.map +1 -1
- package/dist/ui-kit/skin-index.d.ts +2 -1
- package/dist/ui-kit/skin-index.d.ts.map +1 -1
- package/dist/ui-kit/skin-index.js +2 -1
- package/dist/ui-kit/skin-index.js.map +1 -1
- package/dist/ui-kit/skin.d.ts +21 -4
- package/dist/ui-kit/skin.d.ts.map +1 -1
- package/dist/ui-kit/skin.js +14 -1
- package/dist/ui-kit/skin.js.map +1 -1
- package/dist/ui-kit/structure.css +383 -3
- package/package.json +6 -2
package/dist/contact/server.js
CHANGED
|
@@ -5,6 +5,7 @@ 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 { BRANDLAB_CONTACT_DELIVERY_FAILED_EVENT, BRANDLAB_CONTACT_LOOKUP_API_KEY_ENV, reportContactDeliveryFailure, } from './delivery.js';
|
|
8
9
|
import { renderContactEmail, sanitizeContactEmailSubject } from './email.js';
|
|
9
10
|
import { createBrandlabContactImageSanitizer } from './image-sanitizer.js';
|
|
10
11
|
import { createBrandlabContactRateLimiter, isBrandlabContactRateLimiter, } from './rate-limit.js';
|
|
@@ -52,7 +53,7 @@ const SUPPORTED_ATTACHMENT_MIME_TYPES = new Set([
|
|
|
52
53
|
'image/heic',
|
|
53
54
|
'image/heif',
|
|
54
55
|
]);
|
|
55
|
-
const DELIVERY_FAILED_EVENT =
|
|
56
|
+
const DELIVERY_FAILED_EVENT = BRANDLAB_CONTACT_DELIVERY_FAILED_EVENT;
|
|
56
57
|
/** The only values the delivery-failure log writes: anything else is written as `unknown`. */
|
|
57
58
|
const DELIVERY_LOG_PROVIDERS = new Set(['resend']);
|
|
58
59
|
const DELIVERY_LOG_CODES = new Set([
|
|
@@ -397,6 +398,12 @@ function deliveryUnavailable(retryable) {
|
|
|
397
398
|
function fakeSuccess() {
|
|
398
399
|
return { ok: true, accepted: false, trackConversion: false };
|
|
399
400
|
}
|
|
401
|
+
/**
|
|
402
|
+
* Resend accepted the enquiry: it is queued for delivery, not yet delivered. `trackConversion` (and so `contact_form`)
|
|
403
|
+
* keeps its analytics-v4 meaning, provider acceptance. Whether the business inbox actually received it is tracked
|
|
404
|
+
* separately: the pre-send suppression check and the Resend webhook route (`brandlab_contact_delivery_failed`,
|
|
405
|
+
* `brandlab_contact_delivery_status`).
|
|
406
|
+
*/
|
|
400
407
|
function acceptedResult(confirmationId) {
|
|
401
408
|
return {
|
|
402
409
|
ok: true,
|
|
@@ -712,6 +719,27 @@ async function handleSubmission(options, request, formData, outcome, ip) {
|
|
|
712
719
|
return deliveryUnavailable(false);
|
|
713
720
|
}
|
|
714
721
|
const provider = options.transport.provider ?? options.provider;
|
|
722
|
+
if (options.recipientCheck && options.recipientCheck.recipients.length > 0) {
|
|
723
|
+
const { recipients, check } = options.recipientCheck;
|
|
724
|
+
const statuses = await Promise.all(recipients.map((address) => Promise.resolve()
|
|
725
|
+
.then(() => check(address))
|
|
726
|
+
.catch(() => 'unknown')));
|
|
727
|
+
const suppressed = statuses.filter((status) => status === 'suppressed').length;
|
|
728
|
+
if (suppressed > 0) {
|
|
729
|
+
await reportContactDeliveryFailure({
|
|
730
|
+
event: BRANDLAB_CONTACT_DELIVERY_FAILED_EVENT,
|
|
731
|
+
provider: 'resend',
|
|
732
|
+
code: 'recipient_suppressed',
|
|
733
|
+
source: 'pre-send',
|
|
734
|
+
recipients: suppressed === recipients.length ? 'all' : 'some',
|
|
735
|
+
submission: confirmationId.slice(0, 16),
|
|
736
|
+
at: now.toISOString(),
|
|
737
|
+
}, options.onDeliveryFailure);
|
|
738
|
+
// Record and alert only: the client keeps their own inbox deliverable. A site may opt in to refusing instead.
|
|
739
|
+
if (suppressed === recipients.length && options.refuseWhenAllSuppressed === true)
|
|
740
|
+
return deliveryUnavailable(false);
|
|
741
|
+
}
|
|
742
|
+
}
|
|
715
743
|
const rendered = renderContactEmail({
|
|
716
744
|
definition: options.definition,
|
|
717
745
|
values: validated.values,
|
|
@@ -812,11 +840,18 @@ function createRuntimeTransport(options, contract, mode) {
|
|
|
812
840
|
const recipients = parseContactEmailRecipients(environment[contract.delivery.recipientEnv]);
|
|
813
841
|
if (!boundedSecret(apiKey) || recipients.length === 0)
|
|
814
842
|
return undefined;
|
|
815
|
-
|
|
843
|
+
const transport = createContractResendContactTransport({
|
|
816
844
|
contract,
|
|
817
845
|
environment,
|
|
818
846
|
send: options.createResendSend(apiKey),
|
|
819
847
|
});
|
|
848
|
+
const suppressionCheck = options.suppressionCheck;
|
|
849
|
+
const lookupKey = environment[BRANDLAB_CONTACT_LOOKUP_API_KEY_ENV];
|
|
850
|
+
const lookupApiKey = boundedSecret(lookupKey) ? lookupKey : apiKey;
|
|
851
|
+
const recipientCheck = suppressionCheck
|
|
852
|
+
? { recipients, check: (address) => suppressionCheck.check(address, { apiKey: lookupApiKey }) }
|
|
853
|
+
: undefined;
|
|
854
|
+
return { transport, recipientCheck };
|
|
820
855
|
}
|
|
821
856
|
catch {
|
|
822
857
|
return undefined;
|
|
@@ -847,9 +882,19 @@ export function createBrandlabContactRuntime(options) {
|
|
|
847
882
|
deploymentMode: mode,
|
|
848
883
|
});
|
|
849
884
|
assertDefinition(definition);
|
|
885
|
+
if (options.suppressionCheck !== undefined && typeof options.suppressionCheck?.check !== 'function') {
|
|
886
|
+
throw new TypeError('The contact suppression check is invalid.');
|
|
887
|
+
}
|
|
888
|
+
if (options.onDeliveryFailure !== undefined && typeof options.onDeliveryFailure !== 'function') {
|
|
889
|
+
throw new TypeError('onDeliveryFailure must be a function.');
|
|
890
|
+
}
|
|
891
|
+
const delivery = createRuntimeTransport(options, contract, mode);
|
|
850
892
|
const contactRouteHandler = createContactRouteHandler({
|
|
851
893
|
definition,
|
|
852
|
-
transport:
|
|
894
|
+
...(delivery ? { transport: delivery.transport } : {}),
|
|
895
|
+
...(delivery?.recipientCheck ? { recipientCheck: delivery.recipientCheck } : {}),
|
|
896
|
+
...(options.onDeliveryFailure ? { onDeliveryFailure: options.onDeliveryFailure } : {}),
|
|
897
|
+
...(options.refuseWhenAllSuppressed === true ? { refuseWhenAllSuppressed: true } : {}),
|
|
853
898
|
provider: 'resend',
|
|
854
899
|
...(definition.attachments
|
|
855
900
|
? { attachmentProcessor: createBrandlabContactImageSanitizer() }
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EACL,iCAAiC,EACjC,sCAAsC,EACtC,oCAAoC,EACpC,+BAA+B,EAC/B,qBAAqB,EACrB,2BAA2B,GAK5B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAA;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AAC5E,OAAO,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACL,mCAAmC,GAEpC,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EACL,gCAAgC,EAChC,4BAA4B,GAG7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,kBAAkB,EAClB,oCAAoC,GAErC,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,4BAA4B,EAC5B,oCAAoC,EACpC,+BAA+B,EAC/B,mBAAmB,GAUpB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,GAMjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAA8B,CAAA;AACtE,MAAM,CAAC,MAAM,4BAA4B,GAAG,gBAAyB,CAAA;AACrE,MAAM,CAAC,MAAM,kCAAkC,GAAG,SAAS,CAAA;AAE3D;;;;GAIG;AACH,MAAM,UAAU,mCAAmC,CACjD,WAAyD;IAEzD,MAAM,UAAU,GAAG,yBAAyB,CAAC;QAC3C,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,QAAQ,EAAE,WAAW,CAAC,QAAQ;KAC/B,CAAC,CAAA;IACF,IAAI,UAAU,CAAC,WAAW,KAAK,aAAa;QAAE,OAAO,UAAU,CAAC,WAAW,CAAA;IAC3E,OAAO,WAAW,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAA;AACjE,CAAC;AAED,MAAM,eAAe,GAAG,mCAAmC,CAAA;AAC3D,MAAM,cAAc,GAAG,qBAAqB,CAAA;AAC5C,MAAM,0BAA0B,GAC9B,gGAAgG,CAAA;AAClG,MAAM,kBAAkB,GAAG,4BAA4B,CAAA;AACvD,MAAM,gCAAgC,GAAG,yBAAyB,CAAA;AAClE,MAAM,aAAa,GAAG,4BAA4B,CAAA;AAClD,MAAM,mBAAmB,GAAG,mBAAmB,CAAA;AAC/C,MAAM,qBAAqB,GACzB,+CAA+C,CAAA;AACjD,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;AAClD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAC9B,MAAM,wBAAwB,GAAG,EAAE,GAAG,KAAK,CAAA;AAC3C,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC;IAC9C,iBAAiB;IACjB,YAAY;IACZ,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,YAAY;CACb,CAAC,CAAA;AAoDF,MAAM,qBAAqB,GAAG,kCAAkC,CAAA;AAEhE,8FAA8F;AAC9F,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AACvE,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IACtD,2CAA2C;IAC3C,mBAAmB;IACnB,qBAAqB;IACrB,oBAAoB;IACpB,iBAAiB;IACjB,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,mCAAmC;IACnC,GAAG,kBAAkB;CACtB,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,OAA6D;IACvF,MAAM,KAAK,GAAG,CAAC,OAA4B,EAAE,KAAyB,EAAE,EAAE,CACxE,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/D,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG;QACtH,CAAC,CAAC,OAAO,CAAC,MAAM;QAChB,CAAC,CAAC,IAAI,CAAA;IACV,OAAO,CAAC,KAAK,CACX,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,QAAQ,CAAC;QACzD,MAAM;QACN,IAAI,EAAE,KAAK,CAAC,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC;KAC9C,CAAC,CACH,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAkD;IACtE,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,CAAA;IACjC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,UAAmB,CAAA;IACpF,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC,IAA8C,CAAA;IAC7D,CAAC;IACD,OAAO,QAAiB,CAAA;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,IACE,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACzB,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,EAC9C,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,IAAI,CAAC,2BAA2B,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,IACE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE;QAC5B,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,UAAU,CAAC,SAAS;QACpD,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG;QACjC,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAClD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CACvC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D,CACF,CAAA;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IACE,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACpC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1B,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC9B,KAAK,CAAC,IAAI,KAAK,aAAa;YAC5B,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;YACnB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,EACxB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,eAAe,CAAC,CAAA;QAC9D,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAU,EAAE,CAAC;QAClE,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,UAAU,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvF,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;QAC3C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACtC,MAAM,CAAC,QAAQ,GAAG,CAAC;YACnB,MAAM,CAAC,QAAQ,GAAG,EAAE;YACpB,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC9C,MAAM,CAAC,gBAAgB,GAAG,CAAC;YAC3B,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,iBAAiB,CAAC;YAC/C,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,gBAAgB;YAClD,MAAM,CAAC,iBAAiB,GAAG,kCAAkC;YAC7D,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAC9B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAC9E,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC;IACD,IACE,UAAU,CAAC,KAAK,EAAE,KAAK;QACvB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CACxC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAC5C,EACD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;IACjF,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAA;QACjD,IAAI,MAAuB,CAAA;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,SAAS,CAAA;QACpB,CAAC;QACD,IACE,CAAC,MAAM;YACP,MAAM,CAAC,QAAQ,KAAK,QAAQ;YAC5B,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,MAAM;YACb,MAAM,CAAC,IAAI;YACX,CAAC,GAAG,CAAC,IAAI,EAAE;YACX,GAAG,CAAC,MAAM,GAAG,GAAG;YAChB,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,EAChF,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAA;QAC3E,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,OAAO,sCAAsC,CAAC;QAC5C,GAAG,iCAAiC;QACpC,GAAG,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;KAClC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,UAAqC;IAC3E,OAAO;QACL,eAAe,EACb,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI,kCAAkC;QAC1E,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,mBAAmB;QAChE,cAAc,EACZ,UAAU,CAAC,MAAM,EAAE,cAAc,IAAI,wBAAwB;KAChE,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAqC,EAAE,IAAY;IAC5E,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,WAAW,IAAI,aAAa,CAAA;IAClE,OAAO,IAAI,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,iBAAiB,CACxB,UAAqC,EACrC,QAAkB;IAElB,MAAM,MAAM,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAA;IAClD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;QAC7B,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/C,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAC1C,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D;QACD,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ;KAC9D,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU;QAAE,OAAO,KAAK,CAAA;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QAC5E,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC1E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAA;YACxD,IAAI,KAAK,GAAG,MAAM,CAAC,cAAc;gBAAE,OAAO,KAAK,CAAA;YAC/C,cAAc,IAAI,KAAK,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YACxE,cAAc,IAAI,KAAK,CAAC,IAAI,CAAA;QAC9B,CAAC;QACD,IAAI,cAAc,GAAG,MAAM,CAAC,eAAe;YAAE,OAAO,KAAK,CAAA;IAC3D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,WAAW,CAAC,QAAkB,EAAE,IAAY;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;AAC/C,CAAC;AAED,SAAS,cAAc,CAAC,UAAqC,EAAE,QAAkB;IAC/E,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,MAAM,WAAW,GAA6B,EAAE,CAAA;IAChD,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IAAI,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;QACpD,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;YACxD,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,KAAK,QAAQ,CAAA;QACpD,IAAI,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACvB,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC9F,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YAC3B,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/E,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;YAC1D,SAAQ;QACV,CAAC;QACD,IACE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;YAC5C,CAAC,KAAK,CAAC,QAAQ;YACf,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EACnC,CAAC;YACD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;YAC1E,SAAQ;QACV,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAC7C,IAAI,KAAK;gBAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AAChC,CAAC;AAED,MAAM,eAAe,GAA8C;IACjE,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;CACnB,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC7C,OAAO,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,UAAqC,EACrC,QAAkB;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,EAAE,CAAA;IACtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACnE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;SACzC,MAAM,CACL,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAChB,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC;QACnC,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,IAAI,GAAG,CAAC,CACjB;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAa,CAAC,CAAA;IACpC,IAAI,UAAU,CAAC,WAAW,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAEpD,MAAM,WAAW,GAAgC,EAAE,CAAA;IACnD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;QAChE,MAAM,aAAa,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;QAChD,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjD,IACE,CAAC,aAAa;YACd,CAAC,YAAY;YACb,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAC3B,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;YAC1B,iBAAiB,CAAC,aAAa,CAAC,KAAK,YAAY;YACjD,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,gBAAgB,EACnC,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,UAAU,IAAI,IAAI,CAAC,IAAI,CAAA;QACvB,IAAI,UAAU,GAAG,MAAM,CAAC,iBAAiB;YAAE,OAAO,SAAS,CAAA;QAC3D,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACxD,IAAI,iBAAiB,CAAC,oCAAoC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,EAAE,CAAC;YACzG,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,+BAA+B,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;YAC/E,OAAO;YACP,WAAW,EAAE,YAAY;SAC1B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,SAAS,4BAA4B,CACnC,UAAqC,EACrC,WAAiD;IAEjD,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,WAAW,CAAC,MAAM,KAAK,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IACtD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;QAC7C,UAAU,IAAI,UAAU,CAAC,OAAO,CAAC,UAAU,CAAA;QAC3C,OAAO,CACL,UAAU,CAAC,QAAQ,KAAK,+BAA+B,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC;YACvG,CAAC,UAAU,CAAC,WAAW,KAAK,YAAY,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,iBAAiB,IAAI,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC9I,UAAU,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC;YACjC,UAAU,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,gBAAgB;YACxD,UAAU,IAAI,MAAM,CAAC,iBAAiB;YACtC,oCAAoC,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,WAAW,CACjG,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,WAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,KAAK;QAChB,GAAG,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,SAAkB;IAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;AAC9D,CAAC;AAED,SAAS,cAAc,CAAC,cAAsB;IAC5C,OAAO;QACL,EAAE,EAAE,IAAI;QACR,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,cAAc;KACf,CAAA;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,UAAqC,EACrC,QAAkB,EAClB,GAAS;IAMT,MAAM,kBAAkB,GAAG,WAAW,CACpC,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;SACE,IAAI,EAAE;SACN,WAAW,EAAE,CAAA;IAChB,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAA;IACjF,IACE,CAAC,oCAAoC,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC9D,CAAC,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,EACxC,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC3B,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC7B,WAAW,GAAG,KAAK,GAAG,iBAAiB;QACvC,WAAW,GAAG,KAAK,GAAG,qBAAqB,EAC3C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,0BAA0B,CACzC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CACpD,CAAA;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7E,IACE,SAAS;YACT,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EACnE,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,WAAW,GAAG,kCAAkC,CAAC;YACrD,kBAAkB,EAAE,WAAW,CAC7B,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;YACD,WAAW,EAAE,WAAW,CACtB,QAAQ,EACR,mBAAmB,CAAC,WAAW,CAC2C;YAC5E,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE;gBACrE,CAAC,CAAC;oBACE,iBAAiB,EAAE,WAAW,CAC5B,QAAQ,EACR,mBAAmB,CAAC,iBAAiB,CACtC,CAAC,IAAI,EAAE;iBACT;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;QACF,OAAO;YACL,kBAAkB;YAClB,WAAW;YACX,OAAO,EAAE;gBACP,QAAQ;gBACR,OAAO,EAAE,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;gBACzD,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG,WAAW;aACf;SACF,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IAC/E,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAClD,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,kBAAkB,EAAE,CAAC,CAC/D,CAAA;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACjD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CACnC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACZ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IACzE,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,oBAAoB,UAAU,IAAI,kBAAkB,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,oBAAoB,CAC3B,UAAqC,EACrC,QAAkB;IAElB,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,OAAO,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,IAAI,EAAE;QAChD,CAAC,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE;QAC/B,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AACzB,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,KAAK,GAAG;YACpB,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,GAAG,CAAC,MAAM,KAAK,KAAK,EACpB,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,OAAgB;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAA;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAA;IACjE,IACE,CAAC,IAAI;QACL,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,GAAG;QACjB,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,CAAC,EAC7C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,GAAG,CAAC,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,SAAS;QAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACxC,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,EACZ,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC/D,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAA;IAEjC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,uBAAuB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QAC1D,OAAO,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IACvD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,aAAa;QAAE,OAAO,SAAS,CAAA;IACvE,MAAM,cAAc,GAAG,wBAAwB,CAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAC9B,IAAI,CACL,CAAA;IACD,OAAO,cAAc,IAAI,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC;QACrD,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAoB,EAAE,cAAuB;IACzE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC9D,IAAI,cAAc,IAAI,SAAS,KAAK,cAAc;QAAE,OAAO,KAAK,CAAA;IAChE,IAAI,SAAS,KAAK,eAAe;QAAE,OAAO,IAAI,CAAA;IAC9C,OAAO,SAAS,KAAK,cAAc,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/E,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAoB,EAAE,OAAe;IACnE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,OAAO,CAAA;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,MAA2B,EAAE,MAAc;IAC7D,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE;QAC3B,MAAM;QACN,OAAO,EAAE;YACP,eAAe,EAAE,qBAAqB;YACtC,MAAM,EAAE,UAAU;YAClB,wBAAwB,EAAE,SAAS;SACpC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAA2B;IAClD,IAAI,MAAM,CAAC,EAAE;QAAE,OAAO,GAAG,CAAA;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,GAAG,CAAA;IACtD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,kBAAkB,GAAG,+BAA+B,CAAA;AAE1D;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAsB,EAAE,iBAAyB;IACvE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;AACvF,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,OAAgB;IAChC,MAAM,SAAS,GACb,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE;QACxC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;IAClE,OAAO,SAAS,IAAI,SAAS,CAAC,MAAM,IAAI,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;AAC1G,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAsB,EAAE,KAAyB;IAC3E,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAClD,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,oBAAoB,IAAI,IAAI,KAAK,EAAE,CAAC,CAC9D,CAAA;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAClG,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAmC,EACnC,OAA8B,EAC9B,QAAkB,EAClB,OAA0B,EAC1B,EAAW;IAEX,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAA;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;QACxF,OAAO,gBAAgB,EAAE,CAAA;IAC3B,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC3E,IAAI,CAAC,QAAQ;QAAE,OAAO,gBAAgB,EAAE,CAAA;IAExC,IAAI,cAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,oBAAoB,CACzC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1D,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,oBAAoB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC1E,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC3C,QAAQ;gBACR,OAAO;gBACP,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACvC,cAAc;gBACd,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;aACnB,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,WAAW,EAAE,CAAA;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAC9D,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAChD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IAC9D,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;QACzE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAA;QAC7F,IAAI,QAAyD,CAAA;QAC7D,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC5C,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtB,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;aACpF,CAAC,CAAA;YACF,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;gBACnC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrC,YAAY,EAAE,QAAQ,CAAC,kBAAkB;gBACzC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;aACnB,CAAC,CAAA;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,QAAQ,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;QACzB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAA;YAC1D,OAAO,CAAC,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAA;YACtD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,IAAI,WAA6D,CAAA;IACjE,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC1E,IAAI,WAAW,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;YAC5E,WAAW,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,SAAS,CAAA;IACzB,CAAC;IACD,IAAI,CAAC,WAAW,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QACnF,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,qBAAqB;YAC3B,SAAS,EAAE,KAAK;SACjB,CAAA;IACH,CAAC;IAED,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9C,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,kGAAkG;QAClG,kBAAkB,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAC1E,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAA;IAE/D,MAAM,QAAQ,GAAG,kBAAkB,CAAC;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,cAAc;QACd,WAAW;KACZ,CAAC,CAAA;IACF,0GAA0G;IAC1G,MAAM,WAAW,GACf,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,KAAK,4BAA4B,CAAA;IAC/F,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;YACnD,cAAc,EAAE,oBAAoB,CAClC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B;YACD,cAAc;YACd,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,2BAA2B,CAAC,UAAU,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO;YACnG,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,WAAW;YACX,gBAAgB,EAAE;gBAChB,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACxC,eAAe,EAAE,cAAc;aAChC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,eAA+D,CAAA;YAC9E,kBAAkB,CAAC;gBACjB,QAAQ;gBACR,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,IAAI,EAAE,CAAC,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,eAAe,CAAC,IAAI,IAAI,mBAAmB;aACjI,CAAC,CAAA;YACF,OAAO,mBAAmB,CAAC,eAAe,CAAC,SAAS,IAAI,IAAI,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC9E,kBAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAA;YAC7D,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAA;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAA;QAC7D,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAmC;IAC3E,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACpC,IACE,OAAO,CAAC,UAAU,CAAC,WAAW;QAC9B,OAAO,CAAC,mBAAmB,EAAE,UAAU,KAAK,6BAA6B,EACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;IACtF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;IACzD,CAAC;IACD,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE1D,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC,CAAC,OAAO,YAAY,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YAC7E,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QAC7D,IACE,CAAC,MAAM;YACP,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACxC,CAAC,oBAAoB,CACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EACnC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CACxC;YACD,CAAC,sBAAsB,CACrB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EACrC,MAAM,CAAC,eAAe,CACvB,EACD,CAAC;YACD,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QAED,IAAI,QAAkB,CAAA;QACtB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,OAAO,GAAsB,EAAE,CAAA;QACrC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;QAChG,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;YACxC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAA;YACtE,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;IACpD,CAAC,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,MAAM,IAAI,KAAK;QACrB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACrC,CAAA;AACH,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAsC,EACtC,QAAiC,EACjC,IAAmC;IAEnC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAA;IAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAA;IAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,4BAA4B,CAAC,CAAA;IACxD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,2BAA2B,CAC5C,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAC5C,CAAA;QACD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACvE,OAAO,oCAAoC,CAAC;YAC1C,QAAQ;YACR,WAAW;YACX,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC;SACvC,CAAC,CAAA;IACJ,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAsC;IAEtC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;IAC9D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACnD,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,WAAW,GACf,OAAO,CAAC,SAAS,KAAK,KAAK;QACzB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,SAAS,CAAC;YAC/C,CAAC,CAAC,OAAO,CAAC,SAAS;YACnB,CAAC,CAAC,gCAAgC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,IAAI,YAAY,CAAA;IACnD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxD,MAAM,UAAU,GAAG,mCAAmC,CAAC,QAAQ,EAAE;QAC/D,GAAG,OAAO,CAAC,OAAO;QAClB,cAAc,EAAE,IAAI;KACrB,CAAC,CAAA;IACF,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC5B,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;QACpD,UAAU;QACV,SAAS,EAAE,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC;QAC1D,QAAQ,EAAE,QAAQ;QAClB,GAAG,CAAC,UAAU,CAAC,WAAW;YACxB,CAAC,CAAC,EAAE,mBAAmB,EAAE,mCAAmC,EAAE,EAAE;YAChE,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,wBAAwB;QACrC,UAAU;QACV,mBAAmB;KACpB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n 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"]}
|
|
1
|
+
{"version":3,"file":"server.js","sourceRoot":"","sources":["../../src/contact/server.ts"],"names":[],"mappings":"AAAA,OAAO,aAAa,CAAA;AAEpB,OAAO,EACL,iCAAiC,EACjC,sCAAsC,EACtC,oCAAoC,EACpC,+BAA+B,EAC/B,qBAAqB,EACrB,2BAA2B,GAK5B,MAAM,qCAAqC,CAAA;AAC5C,OAAO,EAAE,2BAA2B,EAAE,MAAM,uCAAuC,CAAA;AACnF,OAAO,EAAE,0BAA0B,EAAE,MAAM,oCAAoC,CAAA;AAC/E,OAAO,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AAC5E,OAAO,EAAE,kCAAkC,EAAE,MAAM,kBAAkB,CAAA;AACrE,OAAO,EACL,mCAAmC,GAEpC,MAAM,eAAe,CAAA;AACtB,OAAO,EACL,sCAAsC,EACtC,mCAAmC,EACnC,4BAA4B,GAI7B,MAAM,eAAe,CAAA;AACtB,OAAO,EAAE,kBAAkB,EAAE,2BAA2B,EAAE,MAAM,YAAY,CAAA;AAC5E,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EACL,gCAAgC,EAChC,4BAA4B,GAG7B,MAAM,iBAAiB,CAAA;AACxB,OAAO,EACL,kBAAkB,EAClB,oCAAoC,GAErC,MAAM,aAAa,CAAA;AACpB,OAAO,EACL,4BAA4B,EAC5B,oCAAoC,EACpC,+BAA+B,EAC/B,mBAAmB,GAUpB,MAAM,aAAa,CAAA;AAEpB,OAAO,EAAE,mCAAmC,EAAE,MAAM,sBAAsB,CAAA;AAC1E,OAAO,EACL,4BAA4B,EAC5B,gCAAgC,GAMjC,MAAM,iBAAiB,CAAA;AACxB,OAAO,EAAE,0BAA0B,EAAE,MAAM,aAAa,CAAA;AAGxD,MAAM,CAAC,MAAM,wBAAwB,GAAG,qBAA8B,CAAA;AACtE,MAAM,CAAC,MAAM,4BAA4B,GAAG,gBAAyB,CAAA;AACrE,MAAM,CAAC,MAAM,kCAAkC,GAAG,SAAS,CAAA;AAE3D;;;;GAIG;AACH,MAAM,UAAU,mCAAmC,CACjD,WAAyD;IAEzD,MAAM,UAAU,GAAG,yBAAyB,CAAC;QAC3C,UAAU,EAAE,WAAW,CAAC,UAAU;QAClC,QAAQ,EAAE,WAAW,CAAC,QAAQ;KAC/B,CAAC,CAAA;IACF,IAAI,UAAU,CAAC,WAAW,KAAK,aAAa;QAAE,OAAO,UAAU,CAAC,WAAW,CAAA;IAC3E,OAAO,WAAW,CAAC,QAAQ,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,aAAa,CAAA;AACjE,CAAC;AAED,MAAM,eAAe,GAAG,mCAAmC,CAAA;AAC3D,MAAM,cAAc,GAAG,qBAAqB,CAAA;AAC5C,MAAM,0BAA0B,GAC9B,gGAAgG,CAAA;AAClG,MAAM,kBAAkB,GAAG,4BAA4B,CAAA;AACvD,MAAM,gCAAgC,GAAG,yBAAyB,CAAA;AAClE,MAAM,aAAa,GAAG,4BAA4B,CAAA;AAClD,MAAM,mBAAmB,GAAG,mBAAmB,CAAA;AAC/C,MAAM,qBAAqB,GACzB,+CAA+C,CAAA;AACjD,MAAM,qBAAqB,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,KAAK,CAAA;AAClD,MAAM,iBAAiB,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAA;AACxC,MAAM,mBAAmB,GAAG,EAAE,CAAA;AAC9B,MAAM,wBAAwB,GAAG,EAAE,GAAG,KAAK,CAAA;AAC3C,MAAM,+BAA+B,GAAG,IAAI,GAAG,CAAC;IAC9C,iBAAiB;IACjB,YAAY;IACZ,WAAW;IACX,WAAW;IACX,WAAW;IACX,YAAY;IACZ,YAAY;IACZ,YAAY;CACb,CAAC,CAAA;AA8EF,MAAM,qBAAqB,GAAG,sCAAsC,CAAA;AAEpE,8FAA8F;AAC9F,MAAM,sBAAsB,GAAwB,IAAI,GAAG,CAAC,CAAC,QAAQ,CAAC,CAAC,CAAA;AACvE,MAAM,kBAAkB,GAAwB,IAAI,GAAG,CAAC;IACtD,2CAA2C;IAC3C,mBAAmB;IACnB,qBAAqB;IACrB,oBAAoB;IACpB,iBAAiB;IACjB,eAAe;IACf,qBAAqB;IACrB,qBAAqB;IACrB,gBAAgB;IAChB,mCAAmC;IACnC,GAAG,kBAAkB;CACtB,CAAC,CAAA;AAEF;;;;;;GAMG;AACH,SAAS,kBAAkB,CAAC,OAA6D;IACvF,MAAM,KAAK,GAAG,CAAC,OAA4B,EAAE,KAAyB,EAAE,EAAE,CACxE,KAAK,KAAK,SAAS,IAAI,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,CAAA;IAC/D,MAAM,MAAM,GACV,OAAO,OAAO,CAAC,MAAM,KAAK,QAAQ,IAAI,MAAM,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG,IAAI,OAAO,CAAC,MAAM,IAAI,GAAG;QACtH,CAAC,CAAC,OAAO,CAAC,MAAM;QAChB,CAAC,CAAC,IAAI,CAAA;IACV,OAAO,CAAC,KAAK,CACX,IAAI,CAAC,SAAS,CAAC;QACb,KAAK,EAAE,qBAAqB;QAC5B,QAAQ,EAAE,KAAK,CAAC,sBAAsB,EAAE,OAAO,CAAC,QAAQ,CAAC;QACzD,MAAM;QACN,IAAI,EAAE,KAAK,CAAC,kBAAkB,EAAE,OAAO,CAAC,IAAI,CAAC;KAC9C,CAAC,CACH,CAAA;AACH,CAAC;AAED,SAAS,YAAY,CAAC,KAAkD;IACtE,IAAI,KAAK,CAAC,IAAI;QAAE,OAAO,KAAK,CAAC,IAAI,CAAA;IACjC,IAAI,KAAK,CAAC,IAAI,KAAK,QAAQ,IAAI,KAAK,CAAC,IAAI,KAAK,UAAU;QAAE,OAAO,UAAmB,CAAA;IACpF,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAC,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QAC/D,OAAO,KAAK,CAAC,IAA8C,CAAA;IAC7D,CAAC;IACD,OAAO,QAAiB,CAAA;AAC1B,CAAC;AAED,SAAS,qBAAqB,CAAC,KAAa;IAC1C,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,IACE,GAAG,CAAC,QAAQ,KAAK,QAAQ;YACzB,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,CAAC,GAAG,CAAC,QAAQ,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,KAAK,EAAE,CAAC;YAC7C,KAAK,CAAC,IAAI,EAAE,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,GAAG,CAAC,MAAM,EAC9C,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,IAAI,CAAC,2BAA2B,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACvD,MAAM,IAAI,KAAK,CAAC,mDAAmD,CAAC,CAAA;IACtE,CAAC;IACD,IACE,CAAC,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE;QAC5B,UAAU,CAAC,SAAS,CAAC,IAAI,EAAE,KAAK,UAAU,CAAC,SAAS;QACpD,UAAU,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG;QACjC,uBAAuB,CAAC,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAClD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,+CAA+C,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,EAAE,CAAC;QAC/C,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,iCAAiC,CAAC,CAAA;IACpD,CAAC;IACD,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,MAAM,cAAc,GAAG,IAAI,GAAG,CAC5B,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CACvC,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D,CACF,CAAA;IACD,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,cAAc,CAAC,GAAG,CAAC,aAAa,CAAC,EAAE,CAAC;QACjF,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAA;IAC3D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IACE,CAAC,kBAAkB,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,CAAC;YACpC,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC1B,cAAc,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC;YAC9B,KAAK,CAAC,IAAI,KAAK,aAAa;YAC5B,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,EAAE;YACnB,KAAK,CAAC,KAAK,CAAC,MAAM,GAAG,GAAG,EACxB,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,kBAAkB,KAAK,CAAC,IAAI,eAAe,CAAC,CAAA;QAC9D,CAAC;QACD,UAAU,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAA;IAC5B,CAAC;IACD,KAAK,MAAM,IAAI,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,OAAO,EAAE,SAAS,CAAU,EAAE,CAAC;QAClE,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YACnF,MAAM,IAAI,KAAK,CAAC,4CAA4C,IAAI,UAAU,CAAC,CAAA;QAC7E,CAAC;IACH,CAAC;IACD,IAAI,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,UAAU,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACvF,MAAM,IAAI,KAAK,CAAC,yDAAyD,CAAC,CAAA;IAC5E,CAAC;IACD,IAAI,UAAU,CAAC,WAAW,EAAE,CAAC;QAC3B,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;QAC3C,IACE,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,QAAQ,CAAC;YACtC,MAAM,CAAC,QAAQ,GAAG,CAAC;YACnB,MAAM,CAAC,QAAQ,GAAG,EAAE;YACpB,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,gBAAgB,CAAC;YAC9C,MAAM,CAAC,gBAAgB,GAAG,CAAC;YAC3B,CAAC,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,iBAAiB,CAAC;YAC/C,MAAM,CAAC,iBAAiB,GAAG,MAAM,CAAC,gBAAgB;YAClD,MAAM,CAAC,iBAAiB,GAAG,kCAAkC;YAC7D,MAAM,CAAC,YAAY,CAAC,MAAM,GAAG,CAAC;YAC9B,MAAM,CAAC,YAAY,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC,+BAA+B,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC,EAC9E,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAA;QAC9D,CAAC;IACH,CAAC;IACD,IACE,UAAU,CAAC,KAAK,EAAE,KAAK;QACvB,MAAM,CAAC,MAAM,CAAC,UAAU,CAAC,KAAK,CAAC,KAAK,CAAC,CAAC,IAAI,CACxC,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,mBAAmB,CAAC,IAAI,CAAC,KAAK,CAAC,CAC5C,EACD,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,8DAA8D,CAAC,CAAA;IACjF,CAAC;IACD,IAAI,UAAU,CAAC,KAAK,EAAE,IAAI,EAAE,CAAC;QAC3B,MAAM,EAAE,GAAG,EAAE,GAAG,EAAE,KAAK,EAAE,GAAG,UAAU,CAAC,KAAK,CAAC,IAAI,CAAA;QACjD,IAAI,MAAuB,CAAA;QAC3B,IAAI,CAAC;YACH,MAAM,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,CAAA;QACvB,CAAC;QAAC,MAAM,CAAC;YACP,MAAM,GAAG,SAAS,CAAA;QACpB,CAAC;QACD,IACE,CAAC,MAAM;YACP,MAAM,CAAC,QAAQ,KAAK,QAAQ;YAC5B,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,QAAQ;YACf,MAAM,CAAC,MAAM;YACb,MAAM,CAAC,IAAI;YACX,CAAC,GAAG,CAAC,IAAI,EAAE;YACX,GAAG,CAAC,MAAM,GAAG,GAAG;YAChB,CAAC,KAAK,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,KAAK,CAAC,IAAI,KAAK,GAAG,EAAE,IAAI,KAAK,GAAG,GAAG,CAAC,CAAC,EAChF,CAAC;YACD,MAAM,IAAI,KAAK,CAAC,wDAAwD,CAAC,CAAA;QAC3E,CAAC;IACH,CAAC;AACH,CAAC;AAED,SAAS,gBAAgB,CAAC,UAAqC;IAC7D,OAAO,sCAAsC,CAAC;QAC5C,GAAG,iCAAiC;QACpC,GAAG,CAAC,UAAU,CAAC,WAAW,IAAI,EAAE,CAAC;KAClC,CAAC,CAAA;AACJ,CAAC;AAED,MAAM,UAAU,uBAAuB,CAAC,UAAqC;IAC3E,OAAO;QACL,eAAe,EACb,UAAU,CAAC,MAAM,EAAE,eAAe,IAAI,kCAAkC;QAC1E,UAAU,EAAE,UAAU,CAAC,MAAM,EAAE,UAAU,IAAI,mBAAmB;QAChE,cAAc,EACZ,UAAU,CAAC,MAAM,EAAE,cAAc,IAAI,wBAAwB;KAChE,CAAA;AACH,CAAC;AAED,SAAS,iBAAiB,CAAC,UAAqC,EAAE,IAAY;IAC5E,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,KAAK,CAAA;IACzC,MAAM,MAAM,GAAG,UAAU,CAAC,WAAW,CAAC,WAAW,IAAI,aAAa,CAAA;IAClE,OAAO,IAAI,KAAK,MAAM,IAAI,IAAI,MAAM,CAAC,IAAI,MAAM,iBAAiB,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;AAC9E,CAAC;AAED,SAAS,iBAAiB,CACxB,UAAqC,EACrC,QAAkB;IAElB,MAAM,MAAM,GAAG,uBAAuB,CAAC,UAAU,CAAC,CAAA;IAClD,MAAM,cAAc,GAAG,IAAI,GAAG,CAAC;QAC7B,GAAG,UAAU,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,KAAK,CAAC,IAAI,CAAC;QAC/C,GAAG,MAAM,CAAC,MAAM,CAAC,mBAAmB,CAAC,CAAC,MAAM,CAC1C,CAAC,SAAS,EAAE,EAAE,CAAC,SAAS,KAAK,mBAAmB,CAAC,QAAQ,CAC1D;QACD,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ;KAC9D,CAAC,CAAA;IACF,MAAM,MAAM,GAAG,IAAI,GAAG,EAAkB,CAAA;IACxC,IAAI,cAAc,GAAG,CAAC,CAAA;IACtB,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAA;IAC9C,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,IAAI,OAAO,CAAC,MAAM,GAAG,MAAM,CAAC,UAAU;QAAE,OAAO,KAAK,CAAA;IAC1E,KAAK,MAAM,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,OAAO,EAAE,CAAC;QACpC,IAAI,CAAC,kBAAkB,CAAC,IAAI,CAAC,IAAI,CAAC,OAAO,CAAC,cAAc,EAAE,EAAE,CAAC,CAAC;YAAE,OAAO,KAAK,CAAA;QAC5E,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC,CAAC,CAAA;QAC7C,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;YAC9B,IAAI,CAAC,cAAc,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YAC1E,MAAM,KAAK,GAAG,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,UAAU,CAAA;YACxD,IAAI,KAAK,GAAG,MAAM,CAAC,cAAc;gBAAE,OAAO,KAAK,CAAA;YAC/C,cAAc,IAAI,KAAK,CAAA;QACzB,CAAC;aAAM,CAAC;YACN,IAAI,CAAC,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,IAAI,GAAG,CAAC;gBAAE,OAAO,KAAK,CAAA;YACxE,cAAc,IAAI,KAAK,CAAC,IAAI,CAAA;QAC9B,CAAC;QACD,IAAI,cAAc,GAAG,MAAM,CAAC,eAAe;YAAE,OAAO,KAAK,CAAA;IAC3D,CAAC;IACD,OAAO,IAAI,CAAA;AACb,CAAC;AAED,SAAS,WAAW,CAAC,QAAkB,EAAE,IAAY;IACnD,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,IAAI,CAAC,CAAA;IAChC,OAAO,OAAO,KAAK,KAAK,QAAQ,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,CAAA;AAC/C,CAAC;AAED,SAAS,cAAc,CAAC,UAAqC,EAAE,QAAkB;IAC/E,MAAM,MAAM,GAA2B,EAAE,CAAA;IACzC,MAAM,WAAW,GAA6B,EAAE,CAAA;IAChD,KAAK,MAAM,KAAK,IAAI,UAAU,CAAC,MAAM,EAAE,CAAC;QACtC,IAAI,KAAK,GAAG,WAAW,CAAC,QAAQ,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,EAAE,CAAA;QACpD,IAAI,CAAC;YACH,KAAK,GAAG,KAAK,CAAC,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,KAAK,CAAA;QAC1D,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;YACxD,SAAQ;QACV,CAAC;QACD,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,KAAK,CAAA;QAC1B,MAAM,IAAI,GAAG,YAAY,CAAC,KAAK,CAAC,CAAA;QAChC,MAAM,QAAQ,GAAG,KAAK,CAAC,QAAQ,IAAI,IAAI,KAAK,QAAQ,CAAA;QACpD,IAAI,QAAQ,IAAI,CAAC,KAAK,EAAE,CAAC;YACvB,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK;YAAE,SAAQ;QACpB,MAAM,OAAO,GAAG,KAAK,CAAC,SAAS,IAAI,CAAC,IAAI,KAAK,SAAS,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,IAAI,KAAK,OAAO,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,CAAA;QAC9F,IAAI,KAAK,CAAC,MAAM,GAAG,OAAO,EAAE,CAAC;YAC3B,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,eAAe,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;YAC/E,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAA;YAC1D,SAAQ;QACV,CAAC;QACD,IACE,CAAC,KAAK,CAAC,IAAI,KAAK,OAAO,IAAI,IAAI,KAAK,OAAO,CAAC;YAC5C,CAAC,KAAK,CAAC,QAAQ;YACf,KAAK,CAAC,OAAO,CAAC,KAAK,EAAE,EAAE,CAAC,CAAC,MAAM,GAAG,CAAC,EACnC,CAAC;YACD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAA;YACzD,SAAQ;QACV,CAAC;QACD,IAAI,KAAK,CAAC,OAAO,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;YACpD,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,kBAAkB,KAAK,CAAC,KAAK,CAAC,WAAW,EAAE,GAAG,CAAC,CAAA;YAC1E,SAAQ;QACV,CAAC;QACD,IAAI,CAAC;YACH,MAAM,KAAK,GAAG,KAAK,CAAC,QAAQ,EAAE,CAAC,KAAK,EAAE,MAAM,CAAC,CAAA;YAC7C,IAAI,KAAK;gBAAE,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,KAAK,CAAC,CAAA;QAC9C,CAAC;QAAC,MAAM,CAAC;YACP,WAAW,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,KAAK,CAAC,KAAK,cAAc,CAAC,CAAA;QAC1D,CAAC;IACH,CAAC;IACD,OAAO,EAAE,MAAM,EAAE,WAAW,EAAE,CAAA;AAChC,CAAC;AAED,MAAM,eAAe,GAA8C;IACjE,GAAG,EAAE,iBAAiB;IACtB,GAAG,EAAE,YAAY;IACjB,IAAI,EAAE,YAAY;IAClB,GAAG,EAAE,WAAW;IAChB,GAAG,EAAE,WAAW;IAChB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;IAClB,IAAI,EAAE,YAAY;CACnB,CAAA;AAED,SAAS,iBAAiB,CAAC,KAAa;IACtC,MAAM,UAAU,GAAG,KAAK,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC7C,OAAO,UAAU,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,UAAU,CAAA;AAC/D,CAAC;AAED,KAAK,UAAU,wBAAwB,CACrC,UAAqC,EACrC,QAAkB;IAElB,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,EAAE,CAAA;IACtC,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,MAAM,CAAC,YAAY,CAAC,GAAG,CAAC,iBAAiB,CAAC,CAAC,CAAA;IACnE,MAAM,KAAK,GAAG,KAAK,CAAC,IAAI,CAAC,QAAQ,CAAC,OAAO,EAAE,CAAC;SACzC,MAAM,CACL,CAAC,CAAC,IAAI,EAAE,KAAK,CAAC,EAAE,EAAE,CAChB,iBAAiB,CAAC,UAAU,EAAE,IAAI,CAAC;QACnC,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,IAAI,GAAG,CAAC,CACjB;SACA,GAAG,CAAC,CAAC,CAAC,EAAE,KAAK,CAAC,EAAE,EAAE,CAAC,KAAa,CAAC,CAAA;IACpC,IAAI,UAAU,CAAC,WAAW,CAAC,QAAQ,IAAI,KAAK,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,SAAS,CAAA;IAC3E,IAAI,KAAK,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,SAAS,CAAA;IAEpD,MAAM,WAAW,GAAgC,EAAE,CAAA;IACnD,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,KAAK,MAAM,CAAC,KAAK,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,EAAE,EAAE,CAAC;QAC5C,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,GAAG,EAAE,IAAI,EAAE,CAAA;QAChE,MAAM,aAAa,GAAG,eAAe,CAAC,SAAS,CAAC,CAAA;QAChD,MAAM,YAAY,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAA;QACjD,IACE,CAAC,aAAa;YACd,CAAC,YAAY;YACb,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,CAAC;YAC3B,CAAC,OAAO,CAAC,GAAG,CAAC,YAAY,CAAC;YAC1B,iBAAiB,CAAC,aAAa,CAAC,KAAK,YAAY;YACjD,IAAI,CAAC,IAAI,GAAG,MAAM,CAAC,gBAAgB,EACnC,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,UAAU,IAAI,IAAI,CAAC,IAAI,CAAA;QACvB,IAAI,UAAU,GAAG,MAAM,CAAC,iBAAiB;YAAE,OAAO,SAAS,CAAA;QAC3D,MAAM,OAAO,GAAG,IAAI,UAAU,CAAC,MAAM,IAAI,CAAC,WAAW,EAAE,CAAC,CAAA;QACxD,IAAI,iBAAiB,CAAC,oCAAoC,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,YAAY,EAAE,CAAC;YACzG,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,WAAW,CAAC,IAAI,CAAC;YACf,QAAQ,EAAE,+BAA+B,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,YAAY,EAAE,CAAC;YAC/E,OAAO;YACP,WAAW,EAAE,YAAY;SAC1B,CAAC,CAAA;IACJ,CAAC;IACD,OAAO,WAAW,CAAA;AACpB,CAAC;AAED,SAAS,4BAA4B,CACnC,UAAqC,EACrC,WAAiD;IAEjD,IAAI,CAAC,UAAU,CAAC,WAAW;QAAE,OAAO,WAAW,CAAC,MAAM,KAAK,CAAC,CAAA;IAC5D,MAAM,MAAM,GAAG,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC3C,IAAI,UAAU,GAAG,CAAC,CAAA;IAClB,IAAI,WAAW,CAAC,MAAM,GAAG,MAAM,CAAC,QAAQ;QAAE,OAAO,KAAK,CAAA;IACtD,OAAO,WAAW,CAAC,KAAK,CAAC,CAAC,UAAU,EAAE,KAAK,EAAE,EAAE;QAC7C,UAAU,IAAI,UAAU,CAAC,OAAO,CAAC,UAAU,CAAA;QAC3C,OAAO,CACL,UAAU,CAAC,QAAQ,KAAK,+BAA+B,CAAC,EAAE,KAAK,EAAE,WAAW,EAAE,UAAU,CAAC,WAAW,EAAE,CAAC;YACvG,CAAC,UAAU,CAAC,WAAW,KAAK,YAAY,IAAI,CAAC,UAAU,CAAC,WAAW,KAAK,iBAAiB,IAAI,MAAM,CAAC,YAAY,CAAC,QAAQ,CAAC,iBAAiB,CAAC,CAAC,CAAC;YAC9I,UAAU,CAAC,OAAO,CAAC,UAAU,GAAG,CAAC;YACjC,UAAU,CAAC,OAAO,CAAC,UAAU,IAAI,MAAM,CAAC,gBAAgB;YACxD,UAAU,IAAI,MAAM,CAAC,iBAAiB;YACtC,oCAAoC,CAAC,UAAU,CAAC,OAAO,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,KAAK,UAAU,CAAC,WAAW,CACjG,CAAA;IACH,CAAC,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,gBAAgB,CACvB,WAAsC;IAEtC,OAAO;QACL,EAAE,EAAE,KAAK;QACT,IAAI,EAAE,YAAY;QAClB,SAAS,EAAE,KAAK;QAChB,GAAG,CAAC,WAAW,IAAI,MAAM,CAAC,IAAI,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KAC/E,CAAA;AACH,CAAC;AAED,SAAS,mBAAmB,CAAC,SAAkB;IAC7C,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,sBAAsB,EAAE,SAAS,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,WAAW;IAClB,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,KAAK,EAAE,eAAe,EAAE,KAAK,EAAE,CAAA;AAC9D,CAAC;AAED;;;;;GAKG;AACH,SAAS,cAAc,CAAC,cAAsB;IAC5C,OAAO;QACL,EAAE,EAAE,IAAI;QACR,QAAQ,EAAE,IAAI;QACd,eAAe,EAAE,IAAI;QACrB,cAAc;KACf,CAAA;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,UAAqC,EACrC,QAAkB,EAClB,GAAS;IAMT,MAAM,kBAAkB,GAAG,WAAW,CACpC,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;SACE,IAAI,EAAE;SACN,WAAW,EAAE,CAAA;IAChB,MAAM,WAAW,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,WAAW,CAAC,CAAC,IAAI,EAAE,CAAA;IACjF,IACE,CAAC,oCAAoC,CAAC,IAAI,CAAC,kBAAkB,CAAC;QAC9D,CAAC,qBAAqB,CAAC,IAAI,CAAC,WAAW,CAAC,EACxC,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,WAAW,GAAG,IAAI,CAAC,KAAK,CAAC,WAAW,CAAC,CAAA;IAC3C,MAAM,KAAK,GAAG,GAAG,CAAC,OAAO,EAAE,CAAA;IAC3B,IACE,CAAC,MAAM,CAAC,QAAQ,CAAC,WAAW,CAAC;QAC7B,WAAW,GAAG,KAAK,GAAG,iBAAiB;QACvC,WAAW,GAAG,KAAK,GAAG,qBAAqB,EAC3C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,MAAM,QAAQ,GAAG,0BAA0B,CACzC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,QAAQ,CAAC,CACpD,CAAA;QACD,MAAM,SAAS,GAAG,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,SAAS,CAAC,CAAC,IAAI,EAAE,CAAA;QAC7E,IACE,SAAS;YACT,CAAC,SAAS,CAAC,MAAM,GAAG,GAAG,IAAI,uBAAuB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,EACnE,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,MAAM,WAAW,GAAG,kCAAkC,CAAC;YACrD,kBAAkB,EAAE,WAAW,CAC7B,QAAQ,EACR,mBAAmB,CAAC,kBAAkB,CACvC;YACD,WAAW,EAAE,WAAW,CACtB,QAAQ,EACR,mBAAmB,CAAC,WAAW,CAC2C;YAC5E,GAAG,CAAC,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,iBAAiB,CAAC,CAAC,IAAI,EAAE;gBACrE,CAAC,CAAC;oBACE,iBAAiB,EAAE,WAAW,CAC5B,QAAQ,EACR,mBAAmB,CAAC,iBAAiB,CACtC,CAAC,IAAI,EAAE;iBACT;gBACH,CAAC,CAAC,EAAE,CAAC;SACR,CAAC,CAAA;QACF,OAAO;YACL,kBAAkB;YAClB,WAAW;YACX,OAAO,EAAE;gBACP,QAAQ;gBACR,OAAO,EAAE,IAAI,GAAG,CAAC,QAAQ,EAAE,UAAU,CAAC,OAAO,CAAC,CAAC,QAAQ,EAAE;gBACzD,GAAG,CAAC,SAAS,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACnC,GAAG,WAAW;aACf;SACF,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,KAAK,UAAU,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IAC/E,IAAI,CAAC,UAAU,CAAC,MAAM,EAAE,MAAM,EAAE,CAAC;QAC/B,MAAM,IAAI,KAAK,CAAC,6CAA6C,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAClD,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,GAAG,SAAS,IAAI,kBAAkB,EAAE,CAAC,CAC/D,CAAA;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CACjD,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CACnC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AACZ,CAAC;AAED,SAAS,oBAAoB,CAAC,SAAiB,EAAE,kBAA0B;IACzE,MAAM,UAAU,GAAG,SAAS,CAAC,UAAU,CAAC,GAAG,EAAE,OAAO,CAAC,CAAA;IACrD,OAAO,oBAAoB,UAAU,IAAI,kBAAkB,EAAE,CAAA;AAC/D,CAAC;AAED,SAAS,oBAAoB,CAC3B,UAAqC,EACrC,QAAkB;IAElB,MAAM,aAAa,GAAG,UAAU,CAAC,GAAG,EAAE,aAAa,IAAI,mBAAmB,CAAC,QAAQ,CAAA;IACnF,OAAO,WAAW,CAAC,QAAQ,EAAE,aAAa,CAAC,CAAC,IAAI,EAAE;QAChD,CAAC,CAAC,EAAE,MAAM,EAAE,iBAAiB,EAAE;QAC/B,CAAC,CAAC,EAAE,MAAM,EAAE,OAAO,EAAE,CAAA;AACzB,CAAC;AAED,SAAS,uBAAuB,CAC9B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,KAAK,GAAG;YACpB,GAAG,CAAC,MAAM;YACV,GAAG,CAAC,IAAI;YACR,GAAG,CAAC,MAAM,KAAK,KAAK,EACpB,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,eAAe,CAAC,OAAgB;IACvC,MAAM,IAAI,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,kBAAkB,CAAC,EAAE,IAAI,EAAE,CAAA;IAC5D,MAAM,QAAQ,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC,EAAE,IAAI,EAAE,CAAA;IACjE,IACE,CAAC,IAAI;QACL,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC;QAClB,IAAI,CAAC,MAAM,GAAG,GAAG;QACjB,CAAC,6BAA6B,CAAC,IAAI,CAAC,IAAI,CAAC;QACzC,CAAC,QAAQ,KAAK,OAAO,IAAI,QAAQ,KAAK,MAAM,CAAC,EAC7C,CAAC;QACD,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,IAAI,CAAC;QACH,OAAO,IAAI,GAAG,CAAC,GAAG,QAAQ,MAAM,IAAI,EAAE,CAAC,CAAC,MAAM,CAAA;IAChD,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,uBAAuB,CAC9B,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,IAAI,IAAI,KAAK,YAAY,EAAE,CAAC;QAC1B,OAAO,IAAI,GAAG,CAAC,CAAC,qBAAqB,CAAC,UAAU,CAAC,OAAO,CAAC,CAAC,CAAC,CAAA;IAC7D,CAAC;IACD,MAAM,UAAU,GAAG,IAAI,GAAG,EAAU,CAAA;IACpC,IAAI,CAAC;QACH,UAAU,CAAC,GAAG,CAAC,IAAI,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAA;IAC7C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;IACD,MAAM,SAAS,GAAG,eAAe,CAAC,OAAO,CAAC,CAAA;IAC1C,IAAI,SAAS;QAAE,UAAU,CAAC,GAAG,CAAC,SAAS,CAAC,CAAA;IACxC,OAAO,UAAU,CAAA;AACnB,CAAC;AAED,SAAS,wBAAwB,CAC/B,KAAoB,EACpB,IAAmC;IAEnC,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,KAAK;QAAE,OAAO,SAAS,CAAA;IACpD,IAAI,CAAC;QACH,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,CAAA;QAC1B,MAAM,QAAQ,GACZ,CAAC,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,CAAC;YAC3C,GAAG,CAAC,QAAQ,KAAK,OAAO;YACxB,CAAC,GAAG,CAAC,QAAQ,KAAK,WAAW,IAAI,GAAG,CAAC,QAAQ,KAAK,WAAW,CAAC,CAAA;QAChE,IACE,CAAC,GAAG,CAAC,QAAQ,KAAK,QAAQ,IAAI,CAAC,QAAQ,CAAC;YACxC,GAAG,CAAC,QAAQ;YACZ,GAAG,CAAC,QAAQ,EACZ,CAAC;YACD,OAAO,SAAS,CAAA;QAClB,CAAC;QACD,OAAO,GAAG,CAAC,MAAM,CAAA;IACnB,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,SAAS,iBAAiB,CACxB,OAAgB,EAChB,UAAqC;IAErC,MAAM,IAAI,GAAG,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IACtD,MAAM,UAAU,GAAG,uBAAuB,CAAC,OAAO,EAAE,UAAU,CAAC,CAAA;IAC/D,IAAI,CAAC,UAAU;QAAE,OAAO,SAAS,CAAA;IAEjC,MAAM,YAAY,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;IAClD,IAAI,YAAY,KAAK,IAAI,EAAE,CAAC;QAC1B,MAAM,MAAM,GAAG,uBAAuB,CAAC,YAAY,EAAE,IAAI,CAAC,CAAA;QAC1D,OAAO,MAAM,IAAI,UAAU,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,SAAS,CAAA;IAC9D,CAAC;IAED,MAAM,SAAS,GAAG,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,CAAA;IACvD,IAAI,SAAS,KAAK,IAAI,IAAI,SAAS,KAAK,aAAa;QAAE,OAAO,SAAS,CAAA;IACvE,MAAM,cAAc,GAAG,wBAAwB,CAC7C,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,EAC9B,IAAI,CACL,CAAA;IACD,OAAO,cAAc,IAAI,UAAU,CAAC,GAAG,CAAC,cAAc,CAAC;QACrD,CAAC,CAAC,cAAc;QAChB,CAAC,CAAC,SAAS,CAAA;AACf,CAAC;AAED,SAAS,oBAAoB,CAAC,KAAoB,EAAE,cAAuB;IACzE,IAAI,CAAC,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,GAAG;QAAE,OAAO,KAAK,CAAA;IAC9C,MAAM,SAAS,GAAG,KAAK,CAAC,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAC,WAAW,EAAE,CAAA;IAC9D,IAAI,cAAc,IAAI,SAAS,KAAK,cAAc;QAAE,OAAO,KAAK,CAAA;IAChE,IAAI,SAAS,KAAK,eAAe;QAAE,OAAO,IAAI,CAAA;IAC9C,OAAO,SAAS,KAAK,cAAc,IAAI,0BAA0B,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;AAC/E,CAAC;AAED,SAAS,sBAAsB,CAAC,KAAoB,EAAE,OAAe;IACnE,IAAI,KAAK,KAAK,IAAI;QAAE,OAAO,IAAI,CAAA;IAC/B,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,KAAK,CAAC;QAAE,OAAO,KAAK,CAAA;IAC3C,MAAM,MAAM,GAAG,MAAM,CAAC,KAAK,CAAC,CAAA;IAC5B,OAAO,MAAM,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,MAAM,GAAG,CAAC,IAAI,MAAM,IAAI,OAAO,CAAA;AACxE,CAAC;AAED,SAAS,UAAU,CAAC,MAA2B,EAAE,MAAc;IAC7D,OAAO,QAAQ,CAAC,IAAI,CAAC,MAAM,EAAE;QAC3B,MAAM;QACN,OAAO,EAAE;YACP,eAAe,EAAE,qBAAqB;YACtC,MAAM,EAAE,UAAU;YAClB,wBAAwB,EAAE,SAAS;SACpC;KACF,CAAC,CAAA;AACJ,CAAC;AAED,SAAS,eAAe,CAAC,MAA2B;IAClD,IAAI,MAAM,CAAC,EAAE;QAAE,OAAO,GAAG,CAAA;IACzB,IAAI,MAAM,CAAC,IAAI,KAAK,sBAAsB;QAAE,OAAO,GAAG,CAAA;IACtD,OAAO,GAAG,CAAA;AACZ,CAAC;AAED,MAAM,kBAAkB,GAAG,+BAA+B,CAAA;AAE1D;;;GAGG;AACH,SAAS,cAAc,CAAC,IAAsB,EAAE,iBAAyB;IACvE,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,SAAS,CAAC,EAAE,KAAK,EAAE,kBAAkB,EAAE,IAAI,EAAE,iBAAiB,EAAE,CAAC,CAAC,CAAA;AACvF,CAAC;AAED,0FAA0F;AAC1F,SAAS,QAAQ,CAAC,OAAgB;IAChC,MAAM,SAAS,GACb,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,WAAW,CAAC,EAAE,IAAI,EAAE;QACxC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,CAAA;IAClE,OAAO,SAAS,IAAI,SAAS,CAAC,MAAM,IAAI,EAAE,IAAI,kBAAkB,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,SAAS,CAAA;AAC1G,CAAC;AAED,KAAK,UAAU,YAAY,CAAC,IAAsB,EAAE,KAAyB;IAC3E,IAAI,CAAC,KAAK;QAAE,OAAO,SAAS,CAAA;IAC5B,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,MAAM,CAAC,MAAM,CAAC,MAAM,CAClD,SAAS,EACT,IAAI,WAAW,EAAE,CAAC,MAAM,CAAC,oBAAoB,IAAI,IAAI,KAAK,EAAE,CAAC,CAC9D,CAAA;IACD,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,EAAE,CAAC,IAAI,EAAE,EAAE,CAAC,IAAI,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAA;AAClG,CAAC;AAED,KAAK,UAAU,gBAAgB,CAC7B,OAAmC,EACnC,OAA8B,EAC9B,QAAkB,EAClB,OAA0B,EAC1B,EAAW;IAEX,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,EAAE,IAAI,IAAI,IAAI,EAAE,CAAA;IACzC,IAAI,CAAC,MAAM,CAAC,QAAQ,CAAC,GAAG,CAAC,OAAO,EAAE,CAAC,IAAI,CAAC,iBAAiB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,EAAE,CAAC;QACxF,OAAO,gBAAgB,EAAE,CAAA;IAC3B,CAAC;IACD,MAAM,QAAQ,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,EAAE,GAAG,CAAC,CAAA;IAC3E,IAAI,CAAC,QAAQ;QAAE,OAAO,gBAAgB,EAAE,CAAA;IAExC,IAAI,cAAsB,CAAA;IAC1B,IAAI,CAAC;QACH,cAAc,GAAG,MAAM,oBAAoB,CACzC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B,CAAA;IACH,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;IACD,IAAI,CAAC,+BAA+B,CAAC,IAAI,CAAC,cAAc,CAAC,EAAE,CAAC;QAC1D,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IAED,IAAI,oBAAoB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAC,MAAM,KAAK,OAAO,EAAE,CAAC;QAC1E,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,EAAE,CAAC;QACrB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,MAAM,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAC;gBAC3C,QAAQ;gBACR,OAAO;gBACP,SAAS,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACvC,cAAc;gBACd,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;aACnB,CAAC,CAAA;YACF,IAAI,MAAM,CAAC,MAAM,KAAK,OAAO;gBAAE,OAAO,WAAW,EAAE,CAAA;QACrD,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,MAAM,SAAS,GAAG,cAAc,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;IAC9D,IAAI,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAClD,OAAO,gBAAgB,CAAC,SAAS,CAAC,WAAW,CAAC,CAAA;IAChD,CAAC;IAED,MAAM,IAAI,GAAG,OAAO,CAAC,UAAU,CAAC,cAAc,IAAI,YAAY,CAAA;IAC9D,IAAI,OAAO,CAAC,WAAW,IAAI,CAAC,IAAI,KAAK,YAAY,IAAI,IAAI,KAAK,SAAS,CAAC,EAAE,CAAC;QACzE,MAAM,UAAU,GAAG,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC,KAAK,EAAE,EAAE,CAAC,YAAY,CAAC,KAAK,CAAC,KAAK,OAAO,CAAC,CAAA;QAC7F,IAAI,QAAyD,CAAA;QAC7D,IAAI,CAAC;YACH,MAAM,CAAC,KAAK,EAAE,UAAU,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;gBAC5C,YAAY,CAAC,IAAI,EAAE,EAAE,CAAC;gBACtB,YAAY,CAAC,SAAS,EAAE,UAAU,CAAC,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC;aACpF,CAAC,CAAA;YACF,QAAQ,GAAG,OAAO,CAAC,WAAW,CAAC,KAAK,CAAC;gBACnC,GAAG,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBAC3B,GAAG,CAAC,UAAU,CAAC,CAAC,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACrC,YAAY,EAAE,QAAQ,CAAC,kBAAkB;gBACzC,GAAG,EAAE,GAAG,CAAC,OAAO,EAAE;aACnB,CAAC,CAAA;QACJ,CAAC;QAAC,MAAM,CAAC;YACP,0CAA0C;YAC1C,QAAQ,GAAG,EAAE,EAAE,EAAE,IAAI,EAAE,CAAA;QACzB,CAAC;QACD,IAAI,CAAC,QAAQ,CAAC,EAAE,EAAE,CAAC;YACjB,cAAc,CAAC,QAAQ,CAAC,KAAK,EAAE,QAAQ,CAAC,iBAAiB,CAAC,CAAA;YAC1D,OAAO,CAAC,iBAAiB,GAAG,QAAQ,CAAC,iBAAiB,CAAA;YACtD,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;IACH,CAAC;IAED,IAAI,WAA6D,CAAA;IACjE,IAAI,CAAC;QACH,WAAW,GAAG,MAAM,wBAAwB,CAAC,OAAO,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAC1E,IAAI,WAAW,IAAI,OAAO,CAAC,mBAAmB,EAAE,CAAC;YAC/C,MAAM,SAAS,GAAG,MAAM,OAAO,CAAC,mBAAmB,CAAC,OAAO,CAAC,EAAE,WAAW,EAAE,CAAC,CAAA;YAC5E,WAAW,GAAG,SAAS,CAAC,EAAE,CAAC,CAAC,CAAC,SAAS,CAAC,WAAW,CAAC,CAAC,CAAC,SAAS,CAAA;QAChE,CAAC;IACH,CAAC;IAAC,MAAM,CAAC;QACP,WAAW,GAAG,SAAS,CAAA;IACzB,CAAC;IACD,IAAI,CAAC,WAAW,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,UAAU,EAAE,WAAW,CAAC,EAAE,CAAC;QACnF,OAAO;YACL,EAAE,EAAE,KAAK;YACT,IAAI,EAAE,qBAAqB;YAC3B,SAAS,EAAE,KAAK;SACjB,CAAA;IACH,CAAC;IAED,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM,EAAE,CAAC;QAC9C,OAAO,WAAW,EAAE,CAAA;IACtB,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,SAAS,EAAE,CAAC;QACvB,kGAAkG;QAClG,kBAAkB,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,IAAI,EAAE,gBAAgB,EAAE,CAAC,CAAA;QAC1E,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;IACnC,CAAC;IACD,MAAM,QAAQ,GAAG,OAAO,CAAC,SAAS,CAAC,QAAQ,IAAI,OAAO,CAAC,QAAQ,CAAA;IAE/D,IAAI,OAAO,CAAC,cAAc,IAAI,OAAO,CAAC,cAAc,CAAC,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC3E,MAAM,EAAE,UAAU,EAAE,KAAK,EAAE,GAAG,OAAO,CAAC,cAAc,CAAA;QACpD,MAAM,QAAQ,GAAG,MAAM,OAAO,CAAC,GAAG,CAChC,UAAU,CAAC,GAAG,CAAC,CAAC,OAAO,EAAE,EAAE,CACzB,OAAO,CAAC,OAAO,EAAE;aACd,IAAI,CAAC,GAAG,EAAE,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;aAC1B,KAAK,CAAC,GAAqC,EAAE,CAAC,SAAS,CAAC,CAC5D,CACF,CAAA;QACD,MAAM,UAAU,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,MAAM,KAAK,YAAY,CAAC,CAAC,MAAM,CAAA;QAC9E,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,MAAM,4BAA4B,CAChC;gBACE,KAAK,EAAE,sCAAsC;gBAC7C,QAAQ,EAAE,QAAQ;gBAClB,IAAI,EAAE,sBAAsB;gBAC5B,MAAM,EAAE,UAAU;gBAClB,UAAU,EAAE,UAAU,KAAK,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM;gBAC7D,UAAU,EAAE,cAAc,CAAC,KAAK,CAAC,CAAC,EAAE,EAAE,CAAC;gBACvC,EAAE,EAAE,GAAG,CAAC,WAAW,EAAE;aACtB,EACD,OAAO,CAAC,iBAAiB,CAC1B,CAAA;YACD,8GAA8G;YAC9G,IAAI,UAAU,KAAK,UAAU,CAAC,MAAM,IAAI,OAAO,CAAC,uBAAuB,KAAK,IAAI;gBAAE,OAAO,mBAAmB,CAAC,KAAK,CAAC,CAAA;QACrH,CAAC;IACH,CAAC;IAED,MAAM,QAAQ,GAAG,kBAAkB,CAAC;QAClC,UAAU,EAAE,OAAO,CAAC,UAAU;QAC9B,MAAM,EAAE,SAAS,CAAC,MAAM;QACxB,OAAO,EAAE,QAAQ,CAAC,OAAO;QACzB,WAAW,EAAE,QAAQ,CAAC,WAAW;QACjC,cAAc;QACd,WAAW;KACZ,CAAC,CAAA;IACF,0GAA0G;IAC1G,MAAM,WAAW,GACf,WAAW,CAAC,QAAQ,EAAE,mBAAmB,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,KAAK,4BAA4B,CAAA;IAC/F,IAAI,CAAC;QACH,MAAM,eAAe,GAAG,MAAM,OAAO,CAAC,SAAS,CAAC,IAAI,CAAC;YACnD,cAAc,EAAE,oBAAoB,CAClC,OAAO,CAAC,UAAU,CAAC,SAAS,EAC5B,QAAQ,CAAC,kBAAkB,CAC5B;YACD,cAAc;YACd,OAAO,EAAE,WAAW,CAAC,CAAC,CAAC,2BAA2B,CAAC,UAAU,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,CAAC,QAAQ,CAAC,OAAO;YACnG,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,IAAI,EAAE,QAAQ,CAAC,IAAI;YACnB,GAAG,CAAC,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAC,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;YAC1D,WAAW;YACX,gBAAgB,EAAE;gBAChB,UAAU,EAAE,OAAO,CAAC,UAAU,CAAC,SAAS;gBACxC,eAAe,EAAE,cAAc;aAChC;SACF,CAAC,CAAA;QACF,IAAI,CAAC,eAAe,CAAC,EAAE,EAAE,CAAC;YACxB,MAAM,MAAM,GAAG,eAA+D,CAAA;YAC9E,kBAAkB,CAAC;gBACjB,QAAQ;gBACR,GAAG,CAAC,OAAO,MAAM,CAAC,MAAM,KAAK,QAAQ,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;gBACvE,IAAI,EAAE,CAAC,OAAO,MAAM,CAAC,YAAY,KAAK,QAAQ,CAAC,CAAC,CAAC,MAAM,CAAC,YAAY,CAAC,CAAC,CAAC,SAAS,CAAC,IAAI,eAAe,CAAC,IAAI,IAAI,mBAAmB;aACjI,CAAC,CAAA;YACF,OAAO,mBAAmB,CAAC,eAAe,CAAC,SAAS,IAAI,IAAI,CAAC,CAAA;QAC/D,CAAC;QACD,IAAI,CAAC,gCAAgC,CAAC,IAAI,CAAC,eAAe,CAAC,iBAAiB,CAAC,EAAE,CAAC;YAC9E,kBAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAA;YAC7D,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;QAClC,CAAC;QACD,OAAO,WAAW,CAAC,CAAC,CAAC,WAAW,EAAE,CAAC,CAAC,CAAC,cAAc,CAAC,cAAc,CAAC,CAAA;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,kBAAkB,CAAC,EAAE,QAAQ,EAAE,IAAI,EAAE,qBAAqB,EAAE,CAAC,CAAA;QAC7D,OAAO,mBAAmB,CAAC,IAAI,CAAC,CAAA;IAClC,CAAC;AACH,CAAC;AAED,MAAM,UAAU,yBAAyB,CAAC,OAAmC;IAC3E,gBAAgB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IACpC,IACE,OAAO,CAAC,UAAU,CAAC,WAAW;QAC9B,OAAO,CAAC,mBAAmB,EAAE,UAAU,KAAK,6BAA6B,EACzE,CAAC;QACD,MAAM,IAAI,KAAK,CAAC,mEAAmE,CAAC,CAAA;IACtF,CAAC;IACD,IAAI,OAAO,CAAC,QAAQ,IAAI,OAAO,OAAO,CAAC,QAAQ,CAAC,MAAM,KAAK,UAAU,EAAE,CAAC;QACtE,MAAM,IAAI,KAAK,CAAC,4CAA4C,CAAC,CAAA;IAC/D,CAAC;IACD,IAAI,OAAO,CAAC,WAAW,KAAK,SAAS,IAAI,CAAC,4BAA4B,CAAC,OAAO,CAAC,WAAW,CAAC,EAAE,CAAC;QAC5F,MAAM,IAAI,KAAK,CAAC,sCAAsC,CAAC,CAAA;IACzD,CAAC;IACD,MAAM,MAAM,GAAG,uBAAuB,CAAC,OAAO,CAAC,UAAU,CAAC,CAAA;IAE1D,OAAO,KAAK,EAAE,OAAgB,EAAqB,EAAE;QACnD,IAAI,CAAC,CAAC,OAAO,YAAY,OAAO,CAAC,IAAI,OAAO,CAAC,MAAM,CAAC,WAAW,EAAE,KAAK,MAAM,EAAE,CAAC;YAC7E,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,MAAM,GAAG,iBAAiB,CAAC,OAAO,EAAE,OAAO,CAAC,UAAU,CAAC,CAAA;QAC7D,IACE,CAAC,MAAM;YACP,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,mBAAmB,CAAC;YACxC,CAAC,oBAAoB,CACnB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,cAAc,CAAC,EACnC,OAAO,CAAC,OAAO,CAAC,UAAU,CAAC,WAAW,CAAC,CACxC;YACD,CAAC,sBAAsB,CACrB,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC,gBAAgB,CAAC,EACrC,MAAM,CAAC,eAAe,CACvB,EACD,CAAC;YACD,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QAED,IAAI,QAAkB,CAAA;QACtB,IAAI,CAAC;YACH,QAAQ,GAAG,MAAM,OAAO,CAAC,QAAQ,EAAE,CAAA;QACrC,CAAC;QAAC,MAAM,CAAC;YACP,OAAO,UAAU,CAAC,gBAAgB,EAAE,EAAE,GAAG,CAAC,CAAA;QAC5C,CAAC;QACD,MAAM,OAAO,GAAsB,EAAE,CAAA;QACrC,MAAM,MAAM,GAAG,MAAM,gBAAgB,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,CAAC,OAAO,CAAC,CAAC,CAAA;QAChG,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,EAAE,CAAC;YAC5C,MAAM,QAAQ,GAAG,UAAU,CAAC,MAAM,EAAE,GAAG,CAAC,CAAA;YACxC,QAAQ,CAAC,OAAO,CAAC,GAAG,CAAC,aAAa,EAAE,MAAM,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAA;YACtE,OAAO,QAAQ,CAAA;QACjB,CAAC;QACD,OAAO,UAAU,CAAC,MAAM,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAA;IACpD,CAAC,CAAA;AACH,CAAC;AAED,SAAS,aAAa,CAAC,KAAyB;IAC9C,OAAO,CACL,OAAO,KAAK,KAAK,QAAQ;QACzB,KAAK,CAAC,MAAM,GAAG,CAAC;QAChB,KAAK,CAAC,MAAM,IAAI,KAAK;QACrB,CAAC,uBAAuB,CAAC,IAAI,CAAC,KAAK,CAAC,CACrC,CAAA;AACH,CAAC;AAED,SAAS,sBAAsB,CAC7B,OAAsC,EACtC,QAAiC,EACjC,IAAmC;IAEnC,IAAI,IAAI,KAAK,aAAa,IAAI,IAAI,KAAK,MAAM;QAAE,OAAO,SAAS,CAAA;IAC/D,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,EAAE,CAAA;IAC7C,MAAM,MAAM,GAAG,WAAW,CAAC,4BAA4B,CAAC,CAAA;IACxD,IAAI,CAAC;QACH,MAAM,UAAU,GAAG,2BAA2B,CAC5C,WAAW,CAAC,QAAQ,CAAC,QAAQ,CAAC,YAAY,CAAC,CAC5C,CAAA;QACD,IAAI,CAAC,aAAa,CAAC,MAAM,CAAC,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;YAAE,OAAO,SAAS,CAAA;QACvE,MAAM,SAAS,GAAG,oCAAoC,CAAC;YACrD,QAAQ;YACR,WAAW;YACX,IAAI,EAAE,OAAO,CAAC,gBAAgB,CAAC,MAAM,CAAC;SACvC,CAAC,CAAA;QACF,MAAM,gBAAgB,GAAG,OAAO,CAAC,gBAAgB,CAAA;QACjD,MAAM,SAAS,GAAG,WAAW,CAAC,mCAAmC,CAAC,CAAA;QAClE,MAAM,YAAY,GAAG,aAAa,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,MAAM,CAAA;QAClE,MAAM,cAAc,GAA+B,gBAAgB;YACjE,CAAC,CAAC,EAAE,UAAU,EAAE,KAAK,EAAE,CAAC,OAAO,EAAE,EAAE,CAAC,gBAAgB,CAAC,KAAK,CAAC,OAAO,EAAE,EAAE,MAAM,EAAE,YAAY,EAAE,CAAC,EAAE;YAC/F,CAAC,CAAC,SAAS,CAAA;QACb,OAAO,EAAE,SAAS,EAAE,cAAc,EAAE,CAAA;IACtC,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,SAAS,CAAA;IAClB,CAAC;AACH,CAAC;AAED,MAAM,UAAU,4BAA4B,CAC1C,OAAsC;IAEtC,IAAI,CAAC,OAAO,IAAI,OAAO,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5C,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;IAC9D,CAAC;IACD,IAAI,CAAC,OAAO,CAAC,OAAO,IAAI,OAAO,OAAO,CAAC,OAAO,KAAK,QAAQ,EAAE,CAAC;QAC5D,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,IAAI,OAAO,OAAO,CAAC,gBAAgB,KAAK,UAAU,EAAE,CAAC;QACnD,MAAM,IAAI,SAAS,CAAC,yCAAyC,CAAC,CAAA;IAChE,CAAC;IACD,MAAM,WAAW,GACf,OAAO,CAAC,SAAS,KAAK,KAAK;QACzB,CAAC,CAAC,SAAS;QACX,CAAC,CAAC,4BAA4B,CAAC,OAAO,CAAC,SAAS,CAAC;YAC/C,CAAC,CAAC,OAAO,CAAC,SAAS;YACnB,CAAC,CAAC,gCAAgC,CAAC,OAAO,CAAC,SAAS,CAAC,CAAA;IAC3D,MAAM,IAAI,GAAG,OAAO,CAAC,cAAc,IAAI,YAAY,CAAA;IACnD,IAAI,CAAC,CAAC,YAAY,EAAE,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC,CAAC,QAAQ,CAAC,IAAI,CAAC,EAAE,CAAC;QACrE,MAAM,IAAI,KAAK,CAAC,4BAA4B,CAAC,CAAA;IAC/C,CAAC;IACD,MAAM,QAAQ,GAAG,qBAAqB,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAA;IACxD,MAAM,UAAU,GAAG,mCAAmC,CAAC,QAAQ,EAAE;QAC/D,GAAG,OAAO,CAAC,OAAO;QAClB,cAAc,EAAE,IAAI;KACrB,CAAC,CAAA;IACF,gBAAgB,CAAC,UAAU,CAAC,CAAA;IAC5B,IAAI,OAAO,CAAC,gBAAgB,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,gBAAgB,EAAE,KAAK,KAAK,UAAU,EAAE,CAAC;QACpG,MAAM,IAAI,SAAS,CAAC,2CAA2C,CAAC,CAAA;IAClE,CAAC;IACD,IAAI,OAAO,CAAC,iBAAiB,KAAK,SAAS,IAAI,OAAO,OAAO,CAAC,iBAAiB,KAAK,UAAU,EAAE,CAAC;QAC/F,MAAM,IAAI,SAAS,CAAC,uCAAuC,CAAC,CAAA;IAC9D,CAAC;IACD,MAAM,QAAQ,GAAG,sBAAsB,CAAC,OAAO,EAAE,QAAQ,EAAE,IAAI,CAAC,CAAA;IAChE,MAAM,mBAAmB,GAAG,yBAAyB,CAAC;QACpD,UAAU;QACV,GAAG,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,SAAS,EAAE,QAAQ,CAAC,SAAS,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtD,GAAG,CAAC,QAAQ,EAAE,cAAc,CAAC,CAAC,CAAC,EAAE,cAAc,EAAE,QAAQ,CAAC,cAAc,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAChF,GAAG,CAAC,OAAO,CAAC,iBAAiB,CAAC,CAAC,CAAC,EAAE,iBAAiB,EAAE,OAAO,CAAC,iBAAiB,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,GAAG,CAAC,OAAO,CAAC,uBAAuB,KAAK,IAAI,CAAC,CAAC,CAAC,EAAE,uBAAuB,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QACtF,QAAQ,EAAE,QAAQ;QAClB,GAAG,CAAC,UAAU,CAAC,WAAW;YACxB,CAAC,CAAC,EAAE,mBAAmB,EAAE,mCAAmC,EAAE,EAAE;YAChE,CAAC,CAAC,EAAE,CAAC;QACP,GAAG,CAAC,OAAO,CAAC,QAAQ,CAAC,CAAC,CAAC,EAAE,QAAQ,EAAE,OAAO,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC3D,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,GAAG,EAAE,OAAO,CAAC,GAAG,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;QAC5C,GAAG,CAAC,WAAW,CAAC,CAAC,CAAC,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC;KACxC,CAAC,CAAA;IAEF,OAAO,MAAM,CAAC,MAAM,CAAC;QACnB,WAAW,EAAE,wBAAwB;QACrC,UAAU;QACV,mBAAmB;KACpB,CAAC,CAAA;AACJ,CAAC","sourcesContent":["import 'server-only'\n\nimport {\n DEFAULT_CONTACT_ATTACHMENT_POLICY,\n 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 {\n BRANDLAB_CONTACT_DELIVERY_FAILED_EVENT,\n BRANDLAB_CONTACT_LOOKUP_API_KEY_ENV,\n reportContactDeliveryFailure,\n type BrandlabContactDeliveryAlert,\n type BrandlabContactSuppressionCheck,\n type BrandlabContactSuppressionStatus,\n} from './delivery.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 * Checks each business inbox against Resend's suppression list before sending (3.14.0), with the runtime's\n * `RESEND_API_KEY`. Pass one check shared across runtimes so its cache outlives each request\n * (`createBrandlabContactRouteHandler` does). The check only records and alerts: when any inbox is suppressed a\n * `recipient_suppressed` failure is logged and alerted, and the enquiry is still sent to the client's own inboxes with\n * the normal sent result. It never blocks a send unless the site opts in with `refuseWhenAllSuppressed: true`.\n * The lookup uses `RESEND_LOOKUP_API_KEY` (full access) when set, otherwise `RESEND_API_KEY`.\n */\n suppressionCheck?: BrandlabContactSuppressionCheck\n /**\n * Opt-in only (default `false`): when every business inbox is suppressed, refuse the enquiry with the non-retryable\n * `delivery_unavailable` answer (the form's call-us fallback) and track no conversion. By default the enquiry is sent\n * to the client's own inboxes as normal, still logging and alerting `recipient_suppressed`.\n */\n refuseWhenAllSuppressed?: boolean\n /** The same-day alert for a delivery failure the route finds before sending (3.14.0). */\n onDeliveryFailure?: BrandlabContactDeliveryAlert\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\n/** The pre-send suppression check as the route reads it: the business inboxes and a lookup bound to the API key. */\ninterface RecipientCheck {\n recipients: readonly string[]\n check(address: string): Promise<BrandlabContactSuppressionStatus>\n}\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 recipientCheck?: RecipientCheck\n onDeliveryFailure?: BrandlabContactDeliveryAlert\n refuseWhenAllSuppressed?: boolean\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_EVENT\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\n/**\n * Resend accepted the enquiry: it is queued for delivery, not yet delivered. `trackConversion` (and so `contact_form`)\n * keeps its analytics-v4 meaning, provider acceptance. Whether the business inbox actually received it is tracked\n * separately: the pre-send suppression check and the Resend webhook route (`brandlab_contact_delivery_failed`,\n * `brandlab_contact_delivery_status`).\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 if (options.recipientCheck && options.recipientCheck.recipients.length > 0) {\n const { recipients, check } = options.recipientCheck\n const statuses = await Promise.all(\n recipients.map((address) =>\n Promise.resolve()\n .then(() => check(address))\n .catch((): BrandlabContactSuppressionStatus => 'unknown'),\n ),\n )\n const suppressed = statuses.filter((status) => status === 'suppressed').length\n if (suppressed > 0) {\n await reportContactDeliveryFailure(\n {\n event: BRANDLAB_CONTACT_DELIVERY_FAILED_EVENT,\n provider: 'resend',\n code: 'recipient_suppressed',\n source: 'pre-send',\n recipients: suppressed === recipients.length ? 'all' : 'some',\n submission: confirmationId.slice(0, 16),\n at: now.toISOString(),\n },\n options.onDeliveryFailure,\n )\n // Record and alert only: the client keeps their own inbox deliverable. A site may opt in to refusing instead.\n if (suppressed === recipients.length && options.refuseWhenAllSuppressed === true) return deliveryUnavailable(false)\n }\n }\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 const transport = createContractResendContactTransport({\n contract,\n environment,\n send: options.createResendSend(apiKey),\n })\n const suppressionCheck = options.suppressionCheck\n const lookupKey = environment[BRANDLAB_CONTACT_LOOKUP_API_KEY_ENV]\n const lookupApiKey = boundedSecret(lookupKey) ? lookupKey : apiKey\n const recipientCheck: RecipientCheck | undefined = suppressionCheck\n ? { recipients, check: (address) => suppressionCheck.check(address, { apiKey: lookupApiKey }) }\n : undefined\n return { transport, recipientCheck }\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 if (options.suppressionCheck !== undefined && typeof options.suppressionCheck?.check !== 'function') {\n throw new TypeError('The contact suppression check is invalid.')\n }\n if (options.onDeliveryFailure !== undefined && typeof options.onDeliveryFailure !== 'function') {\n throw new TypeError('onDeliveryFailure must be a function.')\n }\n const delivery = createRuntimeTransport(options, contract, mode)\n const contactRouteHandler = createContactRouteHandler({\n definition,\n ...(delivery ? { transport: delivery.transport } : {}),\n ...(delivery?.recipientCheck ? { recipientCheck: delivery.recipientCheck } : {}),\n ...(options.onDeliveryFailure ? { onDeliveryFailure: options.onDeliveryFailure } : {}),\n ...(options.refuseWhenAllSuppressed === true ? { refuseWhenAllSuppressed: true } : {}),\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/next-config.d.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { type BrandlabRedirectTable } from '@brandlab-digital/site-core/redirects';
|
|
2
2
|
import { type BrandlabDeploymentEnvironment, type BrandlabEnvironment, type BrandlabSite } from '@brandlab-digital/site-core/site';
|
|
3
3
|
import { type BrandlabContentSecurityPolicyExtensions, type BrandlabHeader, type BrandlabHeaderRule, type BrandlabHstsExpansion } from './headers.js';
|
|
4
|
+
import { type SiteIconSet } from './ui-kit/icon-glyphs.js';
|
|
4
5
|
/** Next redirect records: 308 stays `permanent: true`, 301 stays `statusCode: 301`. */
|
|
5
6
|
export type BrandlabNextRedirect = {
|
|
6
7
|
source: string;
|
|
@@ -56,6 +57,8 @@ export interface BrandlabNextConfig {
|
|
|
56
57
|
skipTrailingSlashRedirect: true;
|
|
57
58
|
env: {
|
|
58
59
|
NEXT_PUBLIC_VERCEL_ENV: BrandlabDeploymentEnvironment;
|
|
60
|
+
/** The icon sprite's path (3.14.0), set when `icons` is declared. */
|
|
61
|
+
NEXT_PUBLIC_BL_ICON_SPRITE?: string;
|
|
59
62
|
};
|
|
60
63
|
outputFileTracingIncludes: Record<string, string[]>;
|
|
61
64
|
images: BrandlabNextImagesConfig;
|
|
@@ -91,11 +94,24 @@ export interface BrandlabNextConfigOptions {
|
|
|
91
94
|
* no route under `src/app` or `app` may answer below it.
|
|
92
95
|
*/
|
|
93
96
|
staticAssetCache?: readonly string[];
|
|
97
|
+
/**
|
|
98
|
+
* The ui-kit icon sprite (3.14.0). When declared, loading the config writes `public/_bl/icons.<hash>.svg` (every
|
|
99
|
+
* library icon plus `site`, the set from `defineSiteIcons`), removes older sprites there and sets
|
|
100
|
+
* `NEXT_PUBLIC_BL_ICON_SPRITE`, so every `Icon` renders a `<use>` into the sprite instead of an inline glyph.
|
|
101
|
+
* Production builds serve the file with `public, max-age=31536000, immutable`. Add `public/_bl/` to `.gitignore`.
|
|
102
|
+
*/
|
|
103
|
+
icons?: BrandlabIconsOptions;
|
|
94
104
|
/** Defaults to process.env; tests supply a fixed environment. */
|
|
95
105
|
environment?: BrandlabEnvironment;
|
|
96
|
-
/** The project root for the staticAssetCache checks; defaults to process.cwd(). */
|
|
106
|
+
/** The project root for the staticAssetCache checks and the icon sprite; defaults to process.cwd(). */
|
|
97
107
|
projectRoot?: string;
|
|
98
108
|
}
|
|
109
|
+
export interface BrandlabIconsOptions {
|
|
110
|
+
/** The site's own icons, from `defineSiteIcons` (`src/site/icons.ts`). */
|
|
111
|
+
site?: SiteIconSet;
|
|
112
|
+
}
|
|
113
|
+
/** The sprite's cache rule: content-hashed names only, so a stale name never reaches a page. */
|
|
114
|
+
export declare const BRANDLAB_ICON_SPRITE_SOURCE = "/_bl/:file(icons\\.[0-9a-f]+\\.svg)";
|
|
99
115
|
/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */
|
|
100
116
|
export declare const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING: Readonly<{
|
|
101
117
|
'/api/contact': readonly string[];
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"AAEA,OAAO,EAAmB,KAAK,qBAAqB,EAAE,MAAM,uCAAuC,CAAA;AACnG,OAAO,EAGL,KAAK,6BAA6B,EAClC,KAAK,mBAAmB,EACxB,KAAK,YAAY,EAClB,MAAM,kCAAkC,CAAA;AACzC,OAAO,
|
|
1
|
+
{"version":3,"file":"next-config.d.ts","sourceRoot":"","sources":["../src/next-config.ts"],"names":[],"mappings":"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"}
|
package/dist/next-config.js
CHANGED
|
@@ -2,7 +2,11 @@ import { readdirSync, statSync } from 'node:fs';
|
|
|
2
2
|
import { join, posix } from 'node:path';
|
|
3
3
|
import { defineRedirects } from '@brandlab-digital/site-core/redirects';
|
|
4
4
|
import { assertBrandlabAliasHosts, resolveBrandlabDeployment, } from '@brandlab-digital/site-core/site';
|
|
5
|
-
import { buildBrandlabHeaderRules, parseBrandlabStaticAssetCache, } from './headers.js';
|
|
5
|
+
import { BRANDLAB_STATIC_ASSET_CACHE_CONTROL, buildBrandlabHeaderRules, parseBrandlabStaticAssetCache, } from './headers.js';
|
|
6
|
+
import { defineSiteIcons, ICON_SPRITE_ENV } from './ui-kit/icon-glyphs.js';
|
|
7
|
+
import { writeIconSprite } from './ui-kit/icon-sprite.js';
|
|
8
|
+
/** The sprite's cache rule: content-hashed names only, so a stale name never reaches a page. */
|
|
9
|
+
export const BRANDLAB_ICON_SPRITE_SOURCE = '/_bl/:file(icons\\.[0-9a-f]+\\.svg)';
|
|
6
10
|
/** Sharp's Linux binaries must travel with the contact route's image sanitiser. */
|
|
7
11
|
export const BRANDLAB_CONTACT_OUTPUT_FILE_TRACING = Object.freeze({
|
|
8
12
|
'/api/contact': Object.freeze([
|
|
@@ -23,6 +27,7 @@ const OPTION_KEYS = new Set([
|
|
|
23
27
|
'extraHeaders',
|
|
24
28
|
'staticAssetCache',
|
|
25
29
|
'mdx',
|
|
30
|
+
'icons',
|
|
26
31
|
'environment',
|
|
27
32
|
'projectRoot',
|
|
28
33
|
]);
|
|
@@ -241,6 +246,16 @@ function assertStaticAssetFolders(folders, root) {
|
|
|
241
246
|
}
|
|
242
247
|
}
|
|
243
248
|
}
|
|
249
|
+
/** A site icon set, checked again here: the config may be handed an object that never went through defineSiteIcons. */
|
|
250
|
+
function siteIconSet(site) {
|
|
251
|
+
if (site === undefined)
|
|
252
|
+
return undefined;
|
|
253
|
+
const set = site;
|
|
254
|
+
if (!set || typeof set !== 'object' || !Array.isArray(set.names) || !set.glyphs || typeof set.glyphs !== 'object') {
|
|
255
|
+
throw new Error('icons.site must come from defineSiteIcons.');
|
|
256
|
+
}
|
|
257
|
+
return defineSiteIcons(Object.fromEntries(set.names.map((name) => [name, set.glyphs[name]])));
|
|
258
|
+
}
|
|
244
259
|
/**
|
|
245
260
|
* Converts the redirect table to Next redirects: each entry keeps its 301 or
|
|
246
261
|
* 308 status (Next forwards the query string), gains a single-hop
|
|
@@ -315,6 +330,22 @@ export function defineBrandlabNextConfig(options) {
|
|
|
315
330
|
...(options.extraHeaders ? { extraHeaders: options.extraHeaders } : {}),
|
|
316
331
|
...(options.staticAssetCache ? { staticAssetCache: options.staticAssetCache } : {}),
|
|
317
332
|
});
|
|
333
|
+
if (options.icons !== undefined) {
|
|
334
|
+
if (!options.icons || typeof options.icons !== 'object' || Array.isArray(options.icons)) {
|
|
335
|
+
throw new Error('icons must be { site?: defineSiteIcons(...) } ({} for the library icons only).');
|
|
336
|
+
}
|
|
337
|
+
assertKnownKeys(options.icons, new Set(['site']), 'icons');
|
|
338
|
+
}
|
|
339
|
+
const sprite = options.icons === undefined ? undefined : writeIconSprite(options.projectRoot ?? process.cwd(), siteIconSet(options.icons.site));
|
|
340
|
+
// The same production-only rule as staticAssetCache: Previews keep private, no-store.
|
|
341
|
+
if (sprite && deployment.productionBuild && deployment.environment !== 'preview') {
|
|
342
|
+
// After the static folders, before the non-canonical host rule.
|
|
343
|
+
const at = headerRules.findIndex((rule) => rule.missing !== undefined);
|
|
344
|
+
headerRules.splice(at === -1 ? headerRules.length : at, 0, {
|
|
345
|
+
source: BRANDLAB_ICON_SPRITE_SOURCE,
|
|
346
|
+
headers: [{ key: 'Cache-Control', value: BRANDLAB_STATIC_ASSET_CACHE_CONTROL }],
|
|
347
|
+
});
|
|
348
|
+
}
|
|
318
349
|
const redirects = buildBrandlabRedirects({
|
|
319
350
|
site: options.site,
|
|
320
351
|
redirects: options.redirects,
|
|
@@ -323,7 +354,10 @@ export function defineBrandlabNextConfig(options) {
|
|
|
323
354
|
const config = {
|
|
324
355
|
poweredByHeader: false,
|
|
325
356
|
skipTrailingSlashRedirect: true,
|
|
326
|
-
env: {
|
|
357
|
+
env: {
|
|
358
|
+
NEXT_PUBLIC_VERCEL_ENV: deployment.environment,
|
|
359
|
+
...(sprite ? { [ICON_SPRITE_ENV]: sprite.href } : {}),
|
|
360
|
+
},
|
|
327
361
|
outputFileTracingIncludes: Object.fromEntries(Object.entries(BRANDLAB_CONTACT_OUTPUT_FILE_TRACING).map(([route, globs]) => [route, [...globs]])),
|
|
328
362
|
// A Vercel build (preview or production) is checked like any production build, whatever NODE_ENV says.
|
|
329
363
|
images: buildImagesConfig(options.images, deployment.productionBuild || deployment.environment !== 'development'),
|