feat(forms): gate Form A production embedding

This commit is contained in:
DeCentN2Madness committed 2026-10-28 18:29:32 -07:00
1 parent 1a56cd7603
commit 0eb3fcc3f6
17 files changed
+284 -47

No files matched your search

+2 -2
View File
@@ -20,8 +20,8 @@ if (!config.enabled || !config.url || !config.title || !config.fallbackText || !
role="group"
aria-labelledby="jotform-iframe-heading"
data-jotform-form-a
data-form-mode="isolated-test"
data-form-environment="isolated-test"
data-form-mode={config.mode}
data-form-environment={config.environmentRole}
data-logical-form="general"
data-form-context={config.context}
data-jotform-source="approved-form-a"
@@ -26,6 +26,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
route: campaignRoute,
@@ -6,6 +6,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
route: '/lp/early-intervention',
@@ -38,7 +39,7 @@ const formAIframe = resolveFormAIframe({
</div>
</section>
<div class="qr-process-band">
<section class="qr-section qr-contact-section" aria-label="Contact AIA about early intervention"><div id="consultation" class="lead-form" aria-labelledby="consultation-heading" role="group" data-forms-mode={formAIframe.enabled ? 'isolated-test' : 'off'}>
<section class="qr-section qr-contact-section" aria-label="Contact AIA about early intervention"><div id="consultation" class="lead-form" aria-labelledby="consultation-heading" role="group" data-forms-mode={formAIframe.enabled ? formAIframe.mode : 'off'}>
<div class="form-heading">
<h2 id="consultation-heading">Contact AIA about early intervention</h2>
@@ -19,6 +19,7 @@ const formAIframe = resolveFormAIframe({
rawMode: import.meta.env.PUBLIC_AIA_FORMS_MODE,
liveApproved: import.meta.env.PUBLIC_AIA_FORMS_LIVE_APPROVED,
isolatedTestApproved: import.meta.env.PUBLIC_AIA_FORMS_ISOLATED_TEST_APPROVED,
productionApproved: import.meta.env.PUBLIC_AIA_FORM_A_PRODUCTION_APPROVED,
environmentRole: import.meta.env.PUBLIC_AIA_FORMS_ENVIRONMENT,
allowIndexing: import.meta.env.PUBLIC_ALLOW_INDEXING,
route,
+34 -11
View File
@@ -25,9 +25,10 @@ export function formModeForRuntime(config: FormModeConfig): 'off' | 'mock' {
export type FormAIframeReason =
| 'enabled'
| 'mode-not-isolated-test'
| 'mode-not-authorized'
| 'isolated-test-not-approved'
| 'live-approval-not-disabled'
| 'production-approval-not-granted'
| 'invalid-environment-role'
| 'indexing-enabled'
| 'route-not-authorized'
@@ -38,6 +39,8 @@ export interface FormAIframeConfig {
reason: FormAIframeReason;
route: FormAIframeRoute | string;
locale: 'en' | 'es' | string;
mode?: 'isolated-test' | 'live';
environmentRole?: 'isolated-test' | 'production';
context?: FormAIframeContext;
url?: string;
title?: string;
@@ -49,6 +52,7 @@ export interface ResolveFormAIframeOptions {
rawMode: string | undefined;
liveApproved: string | undefined;
isolatedTestApproved: string | undefined;
productionApproved: string | undefined;
environmentRole: string | undefined;
allowIndexing: string | undefined;
route: string;
@@ -57,12 +61,13 @@ export interface ResolveFormAIframeOptions {
/**
* The owner-approved Form A identifier is deliberately only made into an
* iframe URL after every isolated-test gate has passed. It is not a
* production setting and it is not enabled by an API URL or a live mode.
* iframe URL after every explicit isolated-test or production gate has
* passed. It is never enabled by an API URL, hostname, or publication flag.
*/
export const formAIframeOrigin = 'https://form.jotform.com' as const;
export const formAIframeId = '262946078314059' as const;
const isolatedTestEnvironmentRole = 'isolated-test';
const productionEnvironmentRole = 'production';
export type FormAIframeContext = 'contact' | 'landing';
export type FormAIframeRoute =
@@ -81,7 +86,8 @@ interface FormAIframePlacement {
}
/**
* This is the complete fixed allowlist for the isolated Form A adapter.
* This is the complete fixed allowlist for the Form A adapter in both
* explicitly approved modes.
* Campaign placements are an owner-approved override of their earlier
* logical Form B mapping. The shared compact landing presentation uses the
* same fixed `landing` context; no route may supply its own context or URL.
@@ -121,8 +127,9 @@ export function buildFormAIframeUrl(locale: 'en' | 'es', context: FormAIframeCon
}
/**
* Enables the real Form A iframe only in an explicitly approved isolated
* test build. `live` is intentionally not a valid route to this adapter.
* Enables the real Form A iframe only through one of two explicit gates:
* a non-indexing isolated test, or a separately approved production build.
* No API URL, hostname, indexing setting, or form ID can activate it alone.
*/
export function resolveFormAIframe(options: ResolveFormAIframeOptions): FormAIframeConfig {
const disabled = (reason: Exclude<FormAIframeReason, 'enabled'>): FormAIframeConfig => ({
@@ -132,11 +139,25 @@ export function resolveFormAIframe(options: ResolveFormAIframeOptions): FormAIfr
locale: options.locale,
});
const config = resolveFormMode(options.rawMode, options.liveApproved);
if (config.mode !== 'isolated-test') return disabled('mode-not-isolated-test');
if (options.liveApproved?.trim().toLowerCase() !== 'false') return disabled('live-approval-not-disabled');
if (!isTrue(options.isolatedTestApproved)) return disabled('isolated-test-not-approved');
if (options.environmentRole?.trim().toLowerCase() !== isolatedTestEnvironmentRole) return disabled('invalid-environment-role');
if (isTrue(options.allowIndexing)) return disabled('indexing-enabled');
const environmentRole = options.environmentRole?.trim().toLowerCase();
let mode: 'isolated-test' | 'live';
let approvedEnvironment: 'isolated-test' | 'production';
if (config.mode === 'isolated-test') {
if (options.liveApproved?.trim().toLowerCase() !== 'false') return disabled('live-approval-not-disabled');
if (!isTrue(options.isolatedTestApproved)) return disabled('isolated-test-not-approved');
if (environmentRole !== isolatedTestEnvironmentRole) return disabled('invalid-environment-role');
if (isTrue(options.allowIndexing)) return disabled('indexing-enabled');
mode = 'isolated-test';
approvedEnvironment = 'isolated-test';
} else if (config.mode === 'live') {
if (!isTrue(options.productionApproved)) return disabled('production-approval-not-granted');
if (environmentRole !== productionEnvironmentRole) return disabled('invalid-environment-role');
mode = 'live';
approvedEnvironment = 'production';
} else {
return disabled('mode-not-authorized');
}
const placement = formAIframePlacements.find((candidate) => candidate.route === options.route);
if (!placement) return disabled('route-not-authorized');
@@ -147,6 +168,8 @@ export function resolveFormAIframe(options: ResolveFormAIframeOptions): FormAIfr
reason: 'enabled',
route: options.route,
locale: placement.locale,
mode,
environmentRole: approvedEnvironment,
context: placement.context,
url: buildFormAIframeUrl(placement.locale, placement.context),
...formAIframeCopy(placement.locale),