@parag.more.withsurface.com/forms-sdk 0.1.4

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.
Files changed (177) hide show
  1. package/README.md +63 -0
  2. package/dist/index.cjs +2737 -0
  3. package/dist/index.cjs.map +7 -0
  4. package/dist/index.mjs +2714 -0
  5. package/dist/index.mjs.map +7 -0
  6. package/dist/react/index.cjs +44 -0
  7. package/dist/react/index.cjs.map +7 -0
  8. package/dist/react/index.mjs +21 -0
  9. package/dist/react/index.mjs.map +7 -0
  10. package/dist/surface-forms-sdk.min.js +2 -0
  11. package/dist/surface-forms-sdk.min.js.map +7 -0
  12. package/dist/types/bind/bindForm.d.ts +43 -0
  13. package/dist/types/bind/bindForm.d.ts.map +1 -0
  14. package/dist/types/bind/bindForm.test.d.ts +2 -0
  15. package/dist/types/bind/bindForm.test.d.ts.map +1 -0
  16. package/dist/types/bind/bookingWidget.d.ts +35 -0
  17. package/dist/types/bind/bookingWidget.d.ts.map +1 -0
  18. package/dist/types/bind/bookingWidget.test.d.ts +2 -0
  19. package/dist/types/bind/bookingWidget.test.d.ts.map +1 -0
  20. package/dist/types/core/client/emailValidation.d.ts +23 -0
  21. package/dist/types/core/client/emailValidation.d.ts.map +1 -0
  22. package/dist/types/core/client/emailValidation.test.d.ts +2 -0
  23. package/dist/types/core/client/emailValidation.test.d.ts.map +1 -0
  24. package/dist/types/core/client/responses.d.ts +35 -0
  25. package/dist/types/core/client/responses.d.ts.map +1 -0
  26. package/dist/types/core/client/responses.test.d.ts +2 -0
  27. package/dist/types/core/client/responses.test.d.ts.map +1 -0
  28. package/dist/types/core/client/runtimeConfig.contract.test.d.ts +2 -0
  29. package/dist/types/core/client/runtimeConfig.contract.test.d.ts.map +1 -0
  30. package/dist/types/core/client/runtimeConfig.d.ts +72 -0
  31. package/dist/types/core/client/runtimeConfig.d.ts.map +1 -0
  32. package/dist/types/core/client/runtimeConfig.test.d.ts +2 -0
  33. package/dist/types/core/client/runtimeConfig.test.d.ts.map +1 -0
  34. package/dist/types/core/client/scheduler.contract.test.d.ts +2 -0
  35. package/dist/types/core/client/scheduler.contract.test.d.ts.map +1 -0
  36. package/dist/types/core/client/scheduler.d.ts +121 -0
  37. package/dist/types/core/client/scheduler.d.ts.map +1 -0
  38. package/dist/types/core/client/scheduler.test.d.ts +2 -0
  39. package/dist/types/core/client/scheduler.test.d.ts.map +1 -0
  40. package/dist/types/core/client/transport.d.ts +56 -0
  41. package/dist/types/core/client/transport.d.ts.map +1 -0
  42. package/dist/types/core/client/transport.test.d.ts +2 -0
  43. package/dist/types/core/client/transport.test.d.ts.map +1 -0
  44. package/dist/types/core/engine/answerAudit.d.ts +21 -0
  45. package/dist/types/core/engine/answerAudit.d.ts.map +1 -0
  46. package/dist/types/core/engine/answerAudit.test.d.ts +2 -0
  47. package/dist/types/core/engine/answerAudit.test.d.ts.map +1 -0
  48. package/dist/types/core/engine/answerStates.contract.test.d.ts +2 -0
  49. package/dist/types/core/engine/answerStates.contract.test.d.ts.map +1 -0
  50. package/dist/types/core/engine/answerStates.d.ts +92 -0
  51. package/dist/types/core/engine/answerStates.d.ts.map +1 -0
  52. package/dist/types/core/engine/formEngine.d.ts +145 -0
  53. package/dist/types/core/engine/formEngine.d.ts.map +1 -0
  54. package/dist/types/core/engine/formEngine.test.d.ts +2 -0
  55. package/dist/types/core/engine/formEngine.test.d.ts.map +1 -0
  56. package/dist/types/core/engine/redirect.d.ts +36 -0
  57. package/dist/types/core/engine/redirect.d.ts.map +1 -0
  58. package/dist/types/core/engine/redirect.test.d.ts +2 -0
  59. package/dist/types/core/engine/redirect.test.d.ts.map +1 -0
  60. package/dist/types/core/engine/responsePayload.contract.test.d.ts +2 -0
  61. package/dist/types/core/engine/responsePayload.contract.test.d.ts.map +1 -0
  62. package/dist/types/core/engine/responsePayload.d.ts +74 -0
  63. package/dist/types/core/engine/responsePayload.d.ts.map +1 -0
  64. package/dist/types/core/engine/responsePayload.test.d.ts +2 -0
  65. package/dist/types/core/engine/responsePayload.test.d.ts.map +1 -0
  66. package/dist/types/core/engine/urlData.contract.test.d.ts +2 -0
  67. package/dist/types/core/engine/urlData.contract.test.d.ts.map +1 -0
  68. package/dist/types/core/engine/urlData.d.ts +30 -0
  69. package/dist/types/core/engine/urlData.d.ts.map +1 -0
  70. package/dist/types/core/engine/urlData.test.d.ts +2 -0
  71. package/dist/types/core/engine/urlData.test.d.ts.map +1 -0
  72. package/dist/types/core/engine/urlPrefill.d.ts +21 -0
  73. package/dist/types/core/engine/urlPrefill.d.ts.map +1 -0
  74. package/dist/types/core/engine/urlPrefill.test.d.ts +2 -0
  75. package/dist/types/core/engine/urlPrefill.test.d.ts.map +1 -0
  76. package/dist/types/core/events/dropoffDetection.d.ts +21 -0
  77. package/dist/types/core/events/dropoffDetection.d.ts.map +1 -0
  78. package/dist/types/core/events/dropoffDetection.test.d.ts +2 -0
  79. package/dist/types/core/events/dropoffDetection.test.d.ts.map +1 -0
  80. package/dist/types/core/events/emitter.d.ts +23 -0
  81. package/dist/types/core/events/emitter.d.ts.map +1 -0
  82. package/dist/types/core/events/emitter.test.d.ts +2 -0
  83. package/dist/types/core/events/emitter.test.d.ts.map +1 -0
  84. package/dist/types/core/events/formJourneyTracker.contract.test.d.ts +2 -0
  85. package/dist/types/core/events/formJourneyTracker.contract.test.d.ts.map +1 -0
  86. package/dist/types/core/events/formJourneyTracker.d.ts +69 -0
  87. package/dist/types/core/events/formJourneyTracker.d.ts.map +1 -0
  88. package/dist/types/core/events/formJourneyTracker.test.d.ts +2 -0
  89. package/dist/types/core/events/formJourneyTracker.test.d.ts.map +1 -0
  90. package/dist/types/core/events/pushEvents.contract.test.d.ts +2 -0
  91. package/dist/types/core/events/pushEvents.contract.test.d.ts.map +1 -0
  92. package/dist/types/core/events/pushEvents.d.ts +62 -0
  93. package/dist/types/core/events/pushEvents.d.ts.map +1 -0
  94. package/dist/types/core/events/pushEvents.test.d.ts +2 -0
  95. package/dist/types/core/events/pushEvents.test.d.ts.map +1 -0
  96. package/dist/types/core/events/startedDetection.d.ts +11 -0
  97. package/dist/types/core/events/startedDetection.d.ts.map +1 -0
  98. package/dist/types/core/events/startedDetection.test.d.ts +2 -0
  99. package/dist/types/core/events/startedDetection.test.d.ts.map +1 -0
  100. package/dist/types/core/events/viewDetection.d.ts +15 -0
  101. package/dist/types/core/events/viewDetection.d.ts.map +1 -0
  102. package/dist/types/core/events/viewDetection.test.d.ts +2 -0
  103. package/dist/types/core/events/viewDetection.test.d.ts.map +1 -0
  104. package/dist/types/core/identity/browserFingerprint.d.ts +40 -0
  105. package/dist/types/core/identity/browserFingerprint.d.ts.map +1 -0
  106. package/dist/types/core/identity/browserFingerprint.test.d.ts +2 -0
  107. package/dist/types/core/identity/browserFingerprint.test.d.ts.map +1 -0
  108. package/dist/types/core/identity/ensureIdentified.d.ts +27 -0
  109. package/dist/types/core/identity/ensureIdentified.d.ts.map +1 -0
  110. package/dist/types/core/identity/ensureIdentified.test.d.ts +2 -0
  111. package/dist/types/core/identity/ensureIdentified.test.d.ts.map +1 -0
  112. package/dist/types/core/identity/identify.contract.test.d.ts +2 -0
  113. package/dist/types/core/identity/identify.contract.test.d.ts.map +1 -0
  114. package/dist/types/core/identity/identify.d.ts +48 -0
  115. package/dist/types/core/identity/identify.d.ts.map +1 -0
  116. package/dist/types/core/identity/identify.test.d.ts +2 -0
  117. package/dist/types/core/identity/identify.test.d.ts.map +1 -0
  118. package/dist/types/core/identity/journey.contract.test.d.ts +2 -0
  119. package/dist/types/core/identity/journey.contract.test.d.ts.map +1 -0
  120. package/dist/types/core/identity/journey.d.ts +28 -0
  121. package/dist/types/core/identity/journey.d.ts.map +1 -0
  122. package/dist/types/core/identity/journey.test.d.ts +2 -0
  123. package/dist/types/core/identity/journey.test.d.ts.map +1 -0
  124. package/dist/types/core/identity/journey.testStubs.d.ts +5 -0
  125. package/dist/types/core/identity/journey.testStubs.d.ts.map +1 -0
  126. package/dist/types/core/identity/leadDataCache.d.ts +27 -0
  127. package/dist/types/core/identity/leadDataCache.d.ts.map +1 -0
  128. package/dist/types/core/identity/leadDataCache.test.d.ts +2 -0
  129. package/dist/types/core/identity/leadDataCache.test.d.ts.map +1 -0
  130. package/dist/types/enrichment/attachEnrichment.d.ts +35 -0
  131. package/dist/types/enrichment/attachEnrichment.d.ts.map +1 -0
  132. package/dist/types/enrichment/attachEnrichment.test.d.ts +2 -0
  133. package/dist/types/enrichment/attachEnrichment.test.d.ts.map +1 -0
  134. package/dist/types/index.d.ts +28 -0
  135. package/dist/types/index.d.ts.map +1 -0
  136. package/dist/types/react/index.d.ts +2 -0
  137. package/dist/types/react/index.d.ts.map +1 -0
  138. package/dist/types/react/ssr.test.d.ts +2 -0
  139. package/dist/types/react/ssr.test.d.ts.map +1 -0
  140. package/dist/types/react/useSurfaceForm.d.ts +25 -0
  141. package/dist/types/react/useSurfaceForm.d.ts.map +1 -0
  142. package/dist/types/react/useSurfaceForm.test.d.ts +2 -0
  143. package/dist/types/react/useSurfaceForm.test.d.ts.map +1 -0
  144. package/dist/types/surfaceForms.d.ts +120 -0
  145. package/dist/types/surfaceForms.d.ts.map +1 -0
  146. package/dist/types/surfaceForms.test.d.ts +2 -0
  147. package/dist/types/surfaceForms.test.d.ts.map +1 -0
  148. package/dist/types/tracking/attachTracking.d.ts +35 -0
  149. package/dist/types/tracking/attachTracking.d.ts.map +1 -0
  150. package/dist/types/tracking/attachTracking.test.d.ts +2 -0
  151. package/dist/types/tracking/attachTracking.test.d.ts.map +1 -0
  152. package/dist/types/tracking/conversionRules.contract.test.d.ts +2 -0
  153. package/dist/types/tracking/conversionRules.contract.test.d.ts.map +1 -0
  154. package/dist/types/tracking/conversionRules.d.ts +87 -0
  155. package/dist/types/tracking/conversionRules.d.ts.map +1 -0
  156. package/dist/types/tracking/conversionRules.test.d.ts +2 -0
  157. package/dist/types/tracking/conversionRules.test.d.ts.map +1 -0
  158. package/dist/types/tracking/vendors.d.ts +46 -0
  159. package/dist/types/tracking/vendors.d.ts.map +1 -0
  160. package/dist/types/tracking/vendors.test.d.ts +2 -0
  161. package/dist/types/tracking/vendors.test.d.ts.map +1 -0
  162. package/dist/types/validation/attachEmailValidation.d.ts +8 -0
  163. package/dist/types/validation/attachEmailValidation.d.ts.map +1 -0
  164. package/dist/types/validation/attachEmailValidation.test.d.ts +2 -0
  165. package/dist/types/validation/attachEmailValidation.test.d.ts.map +1 -0
  166. package/docs/api.md +310 -0
  167. package/docs/reference/binding.md +116 -0
  168. package/docs/reference/clients.md +212 -0
  169. package/docs/reference/engine.md +193 -0
  170. package/docs/reference/events.md +93 -0
  171. package/docs/reference/identity.md +116 -0
  172. package/llms.txt +317 -0
  173. package/package.json +25 -0
  174. package/skills/surface-forms-sdk/SKILL.md +153 -0
  175. package/skills/surface-forms-sdk/debugging.md +64 -0
  176. package/skills/surface-forms-sdk/editing.md +67 -0
  177. package/skills/surface-forms-sdk/patterns.md +222 -0
@@ -0,0 +1,7 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/index.ts", "../src/core/events/viewDetection.ts", "../src/bind/bindForm.ts", "../src/bind/bookingWidget.ts", "../src/core/client/emailValidation.ts", "../src/core/client/responses.ts", "../src/core/client/runtimeConfig.ts", "../src/core/client/scheduler.ts", "../src/core/client/transport.ts", "../src/core/engine/answerStates.ts", "../src/core/events/emitter.ts", "../src/core/events/pushEvents.ts", "../src/core/events/startedDetection.ts", "../src/core/engine/responsePayload.ts", "../src/core/engine/formEngine.ts", "../src/core/engine/redirect.ts", "../src/core/engine/urlData.ts", "../src/core/engine/urlPrefill.ts", "../src/core/events/dropoffDetection.ts", "../src/core/events/formJourneyTracker.ts", "../src/core/identity/browserFingerprint.ts", "../src/core/identity/identify.ts", "../src/core/identity/leadDataCache.ts", "../src/core/identity/ensureIdentified.ts", "../src/core/identity/journey.ts", "../src/enrichment/attachEnrichment.ts", "../src/core/engine/answerAudit.ts", "../src/tracking/conversionRules.ts", "../src/tracking/vendors.ts", "../src/tracking/attachTracking.ts", "../src/validation/attachEmailValidation.ts", "../src/surfaceForms.ts"],
4
+ "sourcesContent": ["export { bindForm, type BindFormOptions } from \"./bind/bindForm\";\nexport { mountBookingWidget, type BookingWidgetOptions } from \"./bind/bookingWidget\";\nexport {\n createEmailValidator,\n type CreateEmailValidatorOptions,\n type EmailValidationResult,\n type EmailValidator,\n} from \"./core/client/emailValidation\";\nexport { submitResponse, updateResponse, type CreateResponseResult } from \"./core/client/responses\";\nexport {\n enrichmentSourcesOf,\n fetchRuntimeConfig,\n hasEnabledEnrichmentProvider,\n statefulQuestionIdsOf,\n statefulQuestionsOf,\n stepsOf,\n type RuntimeConfig,\n} from \"./core/client/runtimeConfig\";\nexport {\n createSchedulerClient,\n toSchedulerAnswerState,\n type AvailabilitySummary,\n type Booking,\n type BookingAttendee,\n type SchedulerClient,\n type TimeSlot,\n} from \"./core/client/scheduler\";\nexport {\n DEFAULT_API_BASE_URL,\n createTransport,\n type Transport,\n type TransportError,\n type TransportResult,\n} from \"./core/client/transport\";\nexport {\n IDENTITY_INFO_ANSWER_KEYS,\n type DisclaimerAnswer,\n type DropdownAnswer,\n type EmailFormAnswer,\n type FileUploaderAnswer,\n type GraphicOptionsAnswer,\n type IdentityInfoAnswer,\n type IdentityInfoAnswerKey,\n type KnownAnswerState,\n type LongInputAnswer,\n type MMChoiceAnswer,\n type MultipleChoiceAnswer,\n type MultipleChoiceSingleAnswerAnswer,\n type MultipleOptionsAnswer,\n type SchedulerAnswer,\n type ShortInputAnswer,\n} from \"./core/engine/answerStates\";\nexport {\n createFormEngine,\n type FormEngine,\n type FormEngineEvents,\n type FormEngineState,\n type ResolveNextStep,\n type ResolvedNextStep,\n} from \"./core/engine/formEngine\";\nexport {\n DEFAULT_REDIRECT_TIMEOUT_MS,\n buildRedirectUrl,\n performRedirect,\n type RedirectType,\n} from \"./core/engine/redirect\";\nexport {\n buildResponsesArray,\n createSubmitResponsePayload,\n createUpdateResponsePayload,\n type AnswerStates,\n type ExternalStates,\n type FormResponsePayload,\n type FormUpdateResponsePayload,\n type SingleFormResponse,\n} from \"./core/engine/responsePayload\";\nexport {\n buildUrlData,\n constructUrlParamsObject,\n parseCookiesObject,\n type UrlData,\n} from \"./core/engine/urlData\";\nexport { parsePrefillParams, parseQuestionId, type ParsedUrlQuestionId } from \"./core/engine/urlPrefill\";\nexport { observeDropoff } from \"./core/events/dropoffDetection\";\nexport { createEmitter, type Emitter, type Unsubscribe } from \"./core/events/emitter\";\nexport {\n createFormJourneyTracker,\n type FormJourneyOutcome,\n type FormJourneyTrackPayload,\n type FormJourneyTracker,\n type FormJourneyTransitionReason,\n type FormJourneyVisit,\n} from \"./core/events/formJourneyTracker\";\nexport {\n buildStepTransitionEventBatch,\n createPushEventClient,\n type PushEventBatch,\n type PushEventClient,\n type PushEventPayload,\n type PushEventProperty,\n type PushEventRequest,\n type SurfaceEventEntityType,\n type SurfaceEventType,\n} from \"./core/events/pushEvents\";\nexport { createStartedDetector } from \"./core/events/startedDetection\";\nexport { observeFormView } from \"./core/events/viewDetection\";\nexport { getBrowserFingerprint, getHash, type Fingerprint } from \"./core/identity/browserFingerprint\";\nexport { ensureIdentified } from \"./core/identity/ensureIdentified\";\nexport {\n buildIdentifyPayload,\n identifyLead,\n type IdentifyPayload,\n type IdentifyResult,\n type LeadSource,\n} from \"./core/identity/identify\";\nexport {\n JOURNEY_COOKIE_NAME,\n RECENT_VISIT_COOKIE_NAME,\n createJourneyTracker,\n type JourneyTracker,\n} from \"./core/identity/journey\";\nexport {\n LEAD_DATA_STORAGE_KEY,\n LEAD_DATA_TTL_MS,\n readLeadData,\n writeLeadData,\n type CachedLeadData,\n} from \"./core/identity/leadDataCache\";\nexport {\n ENRICHMENT_STATE_ID,\n attachEnrichment,\n type AttachEnrichmentOptions,\n type EnrichmentSource,\n} from \"./enrichment/attachEnrichment\";\nexport { SurfaceForms, type SurfaceForm, type SurfaceFormsInitOptions } from \"./surfaceForms\";\nexport { attachEmailValidation, type AttachEmailValidationOptions } from \"./validation/attachEmailValidation\";\n", "/**\n * `form_viewed` detection (forms-sdk-plan.md row 21): an IntersectionObserver\n * on the bound form root, firing the callback exactly once per observer \u2014\n * form-render's `useDetectFormView` semantics with its React scaffolding\n * removed. The once-guard replaces native's belt-and-braces 1 s throttle:\n * with a single fire per instance there is nothing left to throttle. The\n * caller (bind layer / engine) emits `form_viewed` + first-step\n * `form_step_viewed`, exactly what native's throttled callback did.\n *\n * If `IntersectionObserver` is unavailable the callback fires immediately \u2014\n * losing view analytics entirely is worse than counting a below-fold mount,\n * and native never handled this case (it would throw).\n */\nexport const observeFormView = (element: Element, onViewed: () => void): (() => void) => {\n if (typeof IntersectionObserver === \"undefined\") {\n onViewed();\n return () => undefined;\n }\n\n let viewed = false;\n const observer = new IntersectionObserver((entries) => {\n const [entry] = entries;\n if (!entry?.isIntersecting || viewed) return;\n viewed = true;\n observer.disconnect();\n onViewed();\n });\n observer.observe(element);\n return () => observer.disconnect();\n};\n", "import type { FormEngine } from \"../core/engine/formEngine\";\nimport { observeFormView } from \"../core/events/viewDetection\";\n\n/**\n * The `data-*` binding layer (forms-sdk-plan.md \u00A72.1/\u00A75.2): makes plain\n * agent-authored HTML drive the headless engine with zero authored JS. The\n * attribute contract is a superset of the conventions the public tag's\n * external-form path already uses (`data-question-id` / `data-field-name`\n * discovery, `input[type=email]` \u2192 `emailAddress` inference,\n * `surface-next-button` / `surface-submit-button` classes), plus\n * customer-owned routing affordances (`data-surface-goto-step` branch buttons,\n * `surface-disqualify-button` \u2014 Decisions #6) and the\n * stepped-only rule: `data-step-id` containers matching the record's steps,\n * which the SDK shows/hides itself \u2014 a multi-step record presents one step at\n * a time (\u00A72.9). A single-step record may omit containers entirely.\n *\n * Fields merge into one component state per question (`{ [fieldName]: value }`\n * accumulates firstName/lastName style groups); `data-field-name` defaults to\n * `\"input\"` \u2014 ShortInput's state key \u2014 and email inputs without it default to\n * `\"email\"`, EmailForm's; a `<select>` on a Dropdown defaults to `\"selected\"`,\n * its state key. Every state carries its `type` discriminator\n * (`data-question-type`, inferred for the two text states) because the wire\n * schema validates states as a discriminated union.\n *\n * Choice questions are captured per GROUP, not per control: their wire states\n * are structural (`MultipleOptionsQuestion` wants the ENTIRE option list as\n * `{key, index, value}` entries, `GraphicOptions` wants `{value, index}`),\n * which no single radio's string value can express \u2014 the 2026-08 field run\n * shipped exactly that and ingest rejected it. Every change rebuilds the full\n * answer from all radios/checkboxes under the binding (key = the control's\n * `value` attribute, index = DOM order, so author options in record order).\n *\n * Runtime drift guard (\u00A74.3): Surface never sees the customer's HTML, so on\n * bind the record's stateful questionIds are compared against what the DOM\n * actually bound \u2014 unbound ids get a console warning, the publish-gate-less\n * counterpart of `validate_form_html`.\n */\n\nexport type BindFormOptions = {\n engine: FormEngine;\n root: Element;\n /** Stateful questionIds from the form record; unbound ones are warned about. */\n expectedQuestionIds?: string[];\n};\n\nconst fieldSelector = \"input, select, textarea\";\n\ntype BoundField = HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement;\n\n/**\n * Every control in the wrapper \u2014 a radio/checkbox group binds all its inputs,\n * not just the first. Nearest-wrapper rule: a control inside a NESTED\n * data-question-id wrapper belongs to that inner question only; without the\n * filter one input would write its value under two questionIds.\n */\nconst resolveFields = (element: Element): BoundField[] => {\n if (element.matches(fieldSelector)) {\n return [element as BoundField];\n }\n return Array.from(element.querySelectorAll<BoundField>(fieldSelector)).filter(\n (field) => field.closest(\"[data-question-id]\") === element\n );\n};\n\nconst fieldNameFor = (element: Element, field: Element, questionType: string): string => {\n const explicit = element.getAttribute(\"data-field-name\") ?? field.getAttribute(\"data-field-name\");\n if (explicit) return explicit;\n if (questionType === \"Dropdown\" && field instanceof HTMLSelectElement) return \"selected\";\n if (field instanceof HTMLInputElement && field.type === \"email\") return \"email\";\n return \"input\";\n};\n\n/**\n * Component states are a discriminated union on the wire (ZSingleFormResponse:\n * StateObject requires `type`), so every answer must carry it. Authors set\n * `data-question-type` from the binding map; without it, email inputs infer\n * EmailForm and everything else ShortInput \u2014 the two single-field text states.\n */\nconst questionTypeFor = (element: Element, field: Element): string => {\n const explicit = element.getAttribute(\"data-question-type\") ?? field.getAttribute(\"data-question-type\");\n if (explicit) return explicit;\n if (field instanceof HTMLInputElement && field.type === \"email\") return \"EmailForm\";\n return \"ShortInput\";\n};\n\nconst fieldValue = (field: HTMLInputElement | HTMLSelectElement | HTMLTextAreaElement): string | boolean => {\n if (field instanceof HTMLInputElement && (field.type === \"checkbox\" || field.type === \"radio\")) {\n return field.type === \"checkbox\" ? field.checked : field.value;\n }\n return field.value;\n};\n\nconst isChoiceControl = (field: Element): field is HTMLInputElement =>\n field instanceof HTMLInputElement && (field.type === \"radio\" || field.type === \"checkbox\");\n\nconst selectedValueAndIndex = (options: HTMLInputElement[]) => {\n const index = options.findIndex((option) => option.checked);\n return { value: index === -1 ? \"\" : options[index].value, index };\n};\n\n// Wire shapes per choice type, from each component's state schema: MOQ carries\n// the full list with per-option index, MCQ/MMChoice the full list without,\n// GraphicOptions/MCSA just the selection. A stray text control in the group\n// (an \"Other\" input) is left to the author's own setAnswer call.\nconst CHOICE_ANSWER_BUILDERS: Record<string, (options: HTMLInputElement[]) => Record<string, unknown>> = {\n MultipleOptionsQuestion: (options) => ({\n choices: options.map((option, index) => ({ key: option.value, value: option.checked, index })),\n }),\n MultipleChoiceQuestion: (options) => ({\n choices: options.map((option) => ({ key: option.value, value: option.checked })),\n }),\n MMChoiceQuestion: (options) => ({\n choices: options.map((option) => ({ key: option.value, value: option.checked })),\n }),\n GraphicOptions: selectedValueAndIndex,\n MultipleChoiceSingleAnswer: selectedValueAndIndex,\n};\n\nexport const bindForm = ({ engine, root, expectedQuestionIds }: BindFormOptions): (() => void) => {\n const teardowns: Array<() => void> = [];\n const boundQuestionIds = new Set<string>();\n\n const listen = (target: Element, type: string, handler: (event: Event) => void) => {\n target.addEventListener(type, handler);\n teardowns.push(() => target.removeEventListener(type, handler));\n };\n\n for (const element of Array.from(root.querySelectorAll(\"[data-question-id]\"))) {\n const questionId = element.getAttribute(\"data-question-id\")!;\n const fields = resolveFields(element);\n if (fields.length === 0) continue;\n boundQuestionIds.add(questionId);\n\n const groupType = questionTypeFor(element, fields[0]);\n const buildChoiceAnswer = CHOICE_ANSWER_BUILDERS[groupType];\n const choiceControls = fields.filter(isChoiceControl);\n if (buildChoiceAnswer && choiceControls.length > 0) {\n const apply = () =>\n engine.setAnswer(questionId, { type: groupType, ...buildChoiceAnswer(choiceControls) });\n for (const control of choiceControls) {\n listen(control, \"change\", apply);\n }\n // Values present before bind (browser autofill, SSR-rendered state, a fast\n // visitor beating the async boot) never fire events \u2014 seed them or the\n // first write ships without them.\n if (choiceControls.some((control) => control.checked)) apply();\n continue;\n }\n\n for (const field of fields) {\n const type = questionTypeFor(element, field);\n const fieldName = fieldNameFor(element, field, type);\n const apply = () => engine.setAnswer(questionId, { type, [fieldName]: fieldValue(field) });\n listen(field, \"input\", apply);\n listen(field, \"change\", apply);\n const initial = fieldValue(field);\n if (initial !== \"\" && initial !== false) apply();\n }\n }\n\n const unbound = (expectedQuestionIds ?? []).filter((id) => !boundQuestionIds.has(id));\n if (unbound.length > 0) {\n console.warn(\n `Surface SDK: form record declares questionIds with no bound element: ${unbound.join(\", \")}. ` +\n \"Answers for these will never be captured \u2014 check data-question-id attributes (validate_form_html catches this at authoring time).\"\n );\n }\n\n // Navigation markers, including the customer-owned routing affordances\n // (Decisions #6): each element gets exactly ONE action \u2014 an element carrying\n // several markers must not advance AND jump AND finish on a single click, so\n // the most specific marker wins (explicit target > terminal verbs > generic\n // advance) and the conflict is warned about.\n const navigationMarkerSelector =\n \"[data-surface-goto-step], .surface-disqualify-button, .surface-submit-button, .surface-next-button\";\n for (const button of Array.from(root.querySelectorAll(navigationMarkerSelector))) {\n const gotoStepId = button.getAttribute(\"data-surface-goto-step\");\n const markers = [\n gotoStepId != null ? (\"goto\" as const) : null,\n button.classList.contains(\"surface-disqualify-button\") ? (\"disqualify\" as const) : null,\n button.classList.contains(\"surface-submit-button\") ? (\"submit\" as const) : null,\n button.classList.contains(\"surface-next-button\") ? (\"next\" as const) : null,\n ].filter((marker): marker is NonNullable<typeof marker> => marker != null);\n const action = markers[0];\n if (markers.length > 1) {\n console.warn(\n `Surface SDK: element carries multiple navigation markers (${markers.join(\n \", \"\n )}); only \"${action}\" is bound.`\n );\n }\n listen(button, \"click\", (event) => {\n event.preventDefault();\n if (action === \"goto\") {\n void engine.goToStep(gotoStepId!).catch((error) => console.warn(`Surface SDK: ${String(error)}`));\n } else if (action === \"disqualify\") {\n void engine.disqualify();\n } else if (action === \"submit\") {\n void engine.submit();\n } else {\n void engine.next();\n }\n });\n }\n if (root instanceof HTMLFormElement) {\n listen(root, \"submit\", (event) => {\n event.preventDefault();\n void engine.submit();\n });\n }\n\n const stepContainers = Array.from(root.querySelectorAll<HTMLElement>(\"[data-step-id]\"));\n const showCurrentStep = () => {\n const { currentStepId } = engine.state();\n for (const container of stepContainers) {\n container.hidden = container.getAttribute(\"data-step-id\") !== currentStepId;\n }\n };\n if (stepContainers.length > 0) {\n showCurrentStep();\n teardowns.push(engine.on(\"stepChanged\", showCurrentStep));\n }\n\n teardowns.push(observeFormView(root, () => engine.markViewed()));\n\n return () => teardowns.forEach((teardown) => teardown());\n};\n", "import type { Booking, SchedulerClient, TimeSlot } from \"../core/client/scheduler\";\n\n/**\n * The SDK's own thin booking widget (forms-sdk-plan.md \u00A72.9 scheduler note):\n * in bind/ and React modes the Phase-1 booking step renders through this \u2014\n * the `@surface/scheduler-ui` package is AGPL-tree and cannot ship in the MIT\n * SDK. It walks the native sub-step sequence (date \u2192 time \u2192 form \u2192 booked)\n * over the public scheduler endpoints and hands the completed booking to the\n * caller, who persists it with `toSchedulerAnswerState`.\n *\n * Deliberately unstyled: presentation belongs to the customer's page (\u00A75.2),\n * so the widget emits semantic markup under stable `surface-booking-*` class\n * names and nothing else. Every interactive element is a real <button> or\n * <input>; no shadow DOM, no injected CSS.\n */\n\ntype AvailableDate = { date: string; slots?: TimeSlot[] };\n\nexport type BookingWidgetOptions = {\n container: Element;\n scheduler: SchedulerClient;\n eventTypeId: string;\n timezone?: string;\n duration?: number;\n prefill?: { name?: string; email?: string };\n /** Threads booking\u2194response linkage into the booking meta block. */\n identity?: { responseId?: string; leadSessionId?: string; fingerprint?: string };\n /**\n * Overrides for the widget's human-readable copy. Defaults use\n * `Intl.DateTimeFormat` in the visitor's locale; every button also carries\n * the raw value in `data-value` (`YYYY-MM` months, `YYYY-MM-DD` dates, ISO\n * instants for slots), so relabeling never needs to parse the text back.\n */\n formatters?: {\n /** `month` is `YYYY-MM`. */\n month?: (month: string) => string;\n /** `date` is `YYYY-MM-DD`. */\n date?: (date: string) => string;\n /** `slot.start`/`slot.end` are ISO instants; format in the widget's timezone. */\n time?: (slot: TimeSlot) => string;\n };\n onComplete: (booking: Booking) => void;\n};\n\nconst currentMonth = (): string => {\n const now = new Date();\n return `${now.getFullYear()}-${String(now.getMonth() + 1).padStart(2, \"0\")}`;\n};\n\n// Local-time constructors on purpose: `YYYY-MM`/`YYYY-MM-DD` name calendar\n// days in the scheduler's availability, and `new Date(\"YYYY-MM-DD\")` would\n// reinterpret them as UTC midnight (off by one west of Greenwich).\nconst monthLabel = (month: string): string => {\n const [year, monthNum] = month.split(\"-\").map(Number);\n return new Date(year, monthNum - 1, 1).toLocaleDateString(undefined, { month: \"long\", year: \"numeric\" });\n};\n\nconst dateLabel = (date: string): string => {\n const [year, monthNum, day] = date.split(\"-\").map(Number);\n return new Date(year, monthNum - 1, day).toLocaleDateString(undefined, {\n weekday: \"short\",\n month: \"short\",\n day: \"numeric\",\n });\n};\n\nconst shiftMonth = (month: string, delta: number): string => {\n const [year, monthNum] = month.split(\"-\").map(Number);\n const shifted = new Date(year, monthNum - 1 + delta, 1);\n return `${shifted.getFullYear()}-${String(shifted.getMonth() + 1).padStart(2, \"0\")}`;\n};\n\nexport const mountBookingWidget = ({\n container,\n scheduler,\n eventTypeId,\n timezone = Intl.DateTimeFormat().resolvedOptions().timeZone,\n duration,\n prefill,\n identity,\n formatters,\n onComplete,\n}: BookingWidgetOptions): (() => void) => {\n const formatMonth = formatters?.month ?? monthLabel;\n const formatDate = formatters?.date ?? dateLabel;\n const formatTime =\n formatters?.time ??\n ((slot: TimeSlot) =>\n new Date(slot.start).toLocaleTimeString(undefined, {\n hour: \"numeric\",\n minute: \"2-digit\",\n timeZone: timezone,\n }));\n const root = document.createElement(\"div\");\n root.className = \"surface-booking\";\n container.appendChild(root);\n\n let month = currentMonth();\n let dates: AvailableDate[] = [];\n let selectedDate: AvailableDate | null = null;\n let selectedSlot: TimeSlot | null = null;\n let destroyed = false;\n // Navigation can outrun the network (e.g. a pending slot fetch while the\n // user moves to another month): each async render captures the generation\n // at entry and only the latest may touch the DOM when its response lands.\n let generation = 0;\n\n const el = <K extends keyof HTMLElementTagNameMap>(\n tag: K,\n className: string,\n text?: string\n ): HTMLElementTagNameMap[K] => {\n const node = document.createElement(tag);\n node.className = className;\n if (text != null) node.textContent = text;\n return node;\n };\n\n const render = (children: Element[]) => {\n if (destroyed) return;\n root.replaceChildren(...children);\n };\n\n const renderError = (message: string, retry: () => void) => {\n const error = el(\"p\", \"surface-booking-error\", message);\n const retryButton = el(\"button\", \"surface-booking-retry\", \"Try again\");\n retryButton.type = \"button\";\n retryButton.addEventListener(\"click\", retry);\n render([error, retryButton]);\n };\n\n const renderDates = async () => {\n const requestedMonth = month;\n const gen = ++generation;\n render([el(\"p\", \"surface-booking-loading\", \"Loading availability\u2026\")]);\n const result = await scheduler.getMonthAvailability({\n eventTypeId,\n month: requestedMonth,\n timezone,\n duration,\n });\n if (destroyed || gen !== generation) return;\n if (!result.ok) {\n renderError(\"Unable to load availability.\", () => void renderDates());\n return;\n }\n dates = (result.data.data?.dates as AvailableDate[] | undefined) ?? [];\n\n const heading = el(\"p\", \"surface-booking-month\", formatMonth(requestedMonth));\n heading.dataset.value = requestedMonth;\n const nav = el(\"div\", \"surface-booking-month-nav\");\n for (const [label, delta] of [\n [\"Previous month\", -1],\n [\"Next month\", 1],\n ] as const) {\n const button = el(\"button\", \"surface-booking-month-button\", label);\n button.type = \"button\";\n button.addEventListener(\"click\", () => {\n month = shiftMonth(month, delta);\n void renderDates();\n });\n nav.appendChild(button);\n }\n\n const list = el(\"ul\", \"surface-booking-dates\");\n for (const date of dates.filter((d) => d.slots && d.slots.length > 0)) {\n const item = el(\"li\", \"surface-booking-date\");\n const button = el(\"button\", \"surface-booking-date-button\", formatDate(date.date));\n button.dataset.value = date.date;\n button.type = \"button\";\n button.addEventListener(\"click\", () => {\n selectedDate = date;\n void renderSlots();\n });\n item.appendChild(button);\n list.appendChild(item);\n }\n if (list.childElementCount === 0) {\n list.appendChild(el(\"li\", \"surface-booking-no-dates\", \"No availability this month.\"));\n }\n render([heading, nav, list]);\n };\n\n const renderSlots = async () => {\n if (!selectedDate) return;\n const gen = ++generation;\n let slots = selectedDate.slots ?? [];\n if (slots.length === 0) {\n const result = await scheduler.getSlots({ eventTypeId, date: selectedDate.date, timezone, duration });\n if (destroyed || gen !== generation) return;\n if (!result.ok) {\n renderError(\"Unable to load times.\", () => void renderSlots());\n return;\n }\n slots = result.data.data?.slots ?? [];\n }\n\n const heading = el(\"p\", \"surface-booking-day\", formatDate(selectedDate.date));\n heading.dataset.value = selectedDate.date;\n const back = el(\"button\", \"surface-booking-back\", \"Back\");\n back.type = \"button\";\n back.addEventListener(\"click\", () => void renderDates());\n\n const list = el(\"ul\", \"surface-booking-slots\");\n for (const slot of slots) {\n const item = el(\"li\", \"surface-booking-slot\");\n const button = el(\"button\", \"surface-booking-slot-button\", formatTime(slot));\n button.dataset.value = slot.start;\n button.type = \"button\";\n button.addEventListener(\"click\", () => {\n selectedSlot = slot;\n renderForm();\n });\n item.appendChild(button);\n list.appendChild(item);\n }\n render([heading, back, list]);\n };\n\n const renderForm = (errorMessage?: string) => {\n if (!selectedSlot) return;\n const form = el(\"form\", \"surface-booking-form\");\n const name = el(\"input\", \"surface-booking-name\");\n name.name = \"name\";\n name.placeholder = \"Name\";\n name.value = prefill?.name ?? \"\";\n const email = el(\"input\", \"surface-booking-email\");\n email.type = \"email\";\n email.name = \"email\";\n email.placeholder = \"Email\";\n email.value = prefill?.email ?? \"\";\n const submit = el(\"button\", \"surface-booking-submit\", \"Book\");\n submit.type = \"submit\";\n form.append(name, email, submit);\n if (errorMessage) form.appendChild(el(\"p\", \"surface-booking-error\", errorMessage));\n\n form.addEventListener(\"submit\", (event) => {\n event.preventDefault();\n void (async () => {\n submit.disabled = true;\n const result = await scheduler.book({\n eventTypeId,\n startTime: selectedSlot!.start,\n endTime: selectedSlot!.end,\n timezone,\n inviteeName: name.value,\n inviteeEmail: email.value,\n duration,\n ...identity,\n });\n if (destroyed) return;\n if (!result.ok) {\n renderForm(\"Booking failed. Please try again.\");\n return;\n }\n render([el(\"p\", \"surface-booking-booked\", \"Booked!\")]);\n onComplete(result.data);\n })();\n });\n render([form]);\n };\n\n void renderDates();\n\n return () => {\n destroyed = true;\n root.remove();\n };\n};\n", "import type { Transport } from \"./transport\";\n\n/**\n * Client for the waterfall email-deliverability endpoint (forms-sdk-plan.md\n * row 37): `POST /api/v1/edge/emailValidation` runs the server-side provider\n * waterfall (ZeroBounce \u2192 MillionVerifier) plus the environment's spam\n * blacklist \u2014 credentials never reach the page. Results are cached per email\n * for the validator's lifetime, including failures (native semantics: one\n * verdict per address, never re-billed), and in-flight requests are shared so\n * concurrent callers of the same address produce one HTTP call.\n *\n * Fail-open like native: when the validator cannot run (network error, server\n * fallback), the result reports `isValid: true` with `failed: true` \u2014 an\n * unreachable validator must never lock a real visitor out of a form.\n */\n\nconst VALIDATION_PATH = \"/api/v1/edge/emailValidation\";\n\nexport type EmailValidationResult = {\n email: string;\n /** Deliverable per the waterfall + blacklist; fail-open true when validation could not run. */\n isValid: boolean;\n status?: string;\n reason?: string;\n blacklistEntryIds?: string[];\n /** Validation did not actually run (network/server failure) \u2014 `isValid` is the fail-open default. */\n failed?: boolean;\n};\n\ntype WireRow = {\n email?: string;\n isValid?: boolean;\n validationSuccessfullyRan?: boolean;\n status?: string;\n reason?: string;\n blacklistEntryIds?: string[];\n};\n\nexport type EmailValidator = {\n validate: (email: string) => Promise<EmailValidationResult>;\n validateBatch: (emails: string[]) => Promise<EmailValidationResult[]>;\n};\n\nexport type CreateEmailValidatorOptions = {\n transport: Transport;\n environmentId: string;\n /** Preview never spends validator quota: every email reports a synthetic valid result. */\n preview?: boolean;\n};\n\nconst failOpenResult = (email: string): EmailValidationResult => ({\n email,\n isValid: true,\n status: \"unknown\",\n reason: \"validation_failed\",\n failed: true,\n});\n\nconst resultOf = (email: string, row: WireRow | undefined): EmailValidationResult => {\n if (!row || typeof row.isValid !== \"boolean\") return failOpenResult(email);\n return {\n email,\n isValid: row.isValid,\n status: row.status,\n reason: row.reason,\n ...(row.blacklistEntryIds?.length ? { blacklistEntryIds: row.blacklistEntryIds } : {}),\n ...(row.validationSuccessfullyRan === false ? { failed: true } : {}),\n };\n};\n\nexport const createEmailValidator = ({\n transport,\n environmentId,\n preview = false,\n}: CreateEmailValidatorOptions): EmailValidator => {\n const cache = new Map<string, Promise<EmailValidationResult>>();\n\n const validateBatch = (emails: string[]): Promise<EmailValidationResult[]> => {\n const normalized = [...new Set(emails.map((email) => email.trim()).filter((email) => email !== \"\"))];\n if (preview) {\n for (const email of normalized) {\n if (!cache.has(email)) {\n cache.set(email, Promise.resolve({ email, isValid: true, status: \"preview\" }));\n }\n }\n }\n const pending = normalized.filter((email) => !cache.has(email));\n if (pending.length > 0) {\n const request = transport\n .post<{ data?: Record<string, WireRow> }>(VALIDATION_PATH, { emails: pending, environmentId })\n .then((result) => (result.ok ? result.data.data ?? {} : {}))\n .catch(() => ({} as Record<string, WireRow>));\n for (const email of pending) {\n cache.set(\n email,\n request.then((rows) => resultOf(email, rows[email]))\n );\n }\n }\n return Promise.all(normalized.map((email) => cache.get(email)!));\n };\n\n return {\n validateBatch,\n validate: async (email) => {\n const [result] = await validateBatch([email]);\n return result ?? failOpenResult(email.trim());\n },\n };\n};\n", "import type { FormResponsePayload, FormUpdateResponsePayload } from \"../engine/responsePayload\";\nimport type { Transport, TransportResult } from \"./transport\";\n\n/**\n * Delivery for the two response writes (forms-sdk-plan.md rows 24-25),\n * matching native transport choices: creates use plain fetch because the\n * engine needs the body back (`responseId` seeds later updates, `meta.leadId`\n * resolves the visitor); updates are beacon-first fire-and-forget \u2014 the\n * drop-off sweep reconciles missed ones, so failures stay silent like\n * form-render's `updateResponse`.\n */\n\nconst CREATE_PATH = \"/api/v1/responses/\";\nconst UPDATE_PATH = \"/api/v1/responses/update\";\nconst GET_PATH = \"/api/v1/responses/getResponse\";\n\nexport type CreateResponseResult = {\n responseId: string;\n leadId: string | null;\n /** Authorizes the token-gated read-back (resume); persist alongside the responseId. */\n resumeToken: string | null;\n};\n\ntype CreateResponseBody = {\n data?: { id?: string; meta?: { leadId?: string }; resumeToken?: string };\n};\n\nexport const submitResponse = async (\n transport: Transport,\n payload: FormResponsePayload\n): Promise<TransportResult<CreateResponseResult>> => {\n // Credentialed: the create both reads and refreshes the `${formId}_pa`\n // repeat-visitor cookie on the API origin (Decisions #12).\n const result = await transport.post<CreateResponseBody>(CREATE_PATH, payload, { credentials: true });\n if (!result.ok) return result;\n const id = result.data.data?.id;\n if (!id) {\n return { ok: false, error: { kind: \"http\", status: 200, body: result.data } };\n }\n return {\n ok: true,\n data: {\n responseId: id,\n leadId: result.data.data?.meta?.leadId ?? null,\n resumeToken: result.data.data?.resumeToken ?? null,\n },\n };\n};\n\nexport const updateResponse = (transport: Transport, payload: FormUpdateResponsePayload): void => {\n transport.beacon(UPDATE_PATH, payload);\n};\n\n/**\n * Awaited delivery for the FINISHING update (the 2026-08 field run measured\n * the beacon path silently dropping the terminal write on fast page close:\n * `submit()` resolved, `saved` fired, and the server kept a step-1 partial).\n * `keepalive` lets the request survive an immediate navigation; credentials\n * match the beacon path's `${formId}_pa` cookie round-trip.\n */\nexport const updateResponseConfirmed = (\n transport: Transport,\n payload: FormUpdateResponsePayload\n): Promise<TransportResult<unknown>> =>\n transport.post(UPDATE_PATH, payload, { keepalive: true, credentials: true });\n\nexport type StoredAnswerRow = { questionId: string; response: Record<string, unknown> };\n\ntype StoredResponseBody = {\n // successResponse wraps the Response row; the row's `data` column is the\n // answers array ([{ questionId, response: <state> }]).\n data?: { data?: unknown };\n};\n\nconst isAnswerRow = (row: unknown): row is StoredAnswerRow =>\n typeof (row as StoredAnswerRow | null)?.questionId === \"string\" &&\n typeof (row as StoredAnswerRow | null)?.response === \"object\" &&\n (row as StoredAnswerRow).response !== null;\n\n/**\n * Read-back of a stored response for resume (Decisions #11: the route is\n * token-gated; the create reply issued the token). External-state\n * pseudo-answers (URL_DATA) are stripped \u2014 they are attribution snapshots the\n * engine re-derives from its own page context, not visitor answers.\n */\nexport const fetchStoredResponse = async (\n transport: Transport,\n { responseId, resumeToken }: { responseId: string; resumeToken: string }\n): Promise<TransportResult<{ answers: StoredAnswerRow[] }>> => {\n const result = await transport.get<StoredResponseBody>(\n `${GET_PATH}?rid=${encodeURIComponent(responseId)}&rt=${encodeURIComponent(resumeToken)}`\n );\n if (!result.ok) return result;\n const rows = Array.isArray(result.data.data?.data) ? result.data.data.data : [];\n return {\n ok: true,\n data: { answers: rows.filter(isAnswerRow).filter((row) => row.response.type !== \"URL_DATA\") },\n };\n};\n", "import type { Transport, TransportResult } from \"./transport\";\n\n/**\n * Boot-time fetch of the published form record (forms-sdk-plan.md \u00A72.3,\n * Decisions #7): `GET /api/v1/public/forms/[formId]/runtime-config` serves the\n * same `TCachedForm` payload the hosted `/s/[formId]` page reads \u2014 config\n * (steps + components, the data contract) and settings (behavioral gates like\n * `trackPartialResponses`; tracking ids for the Phase-2 tracking module).\n * `settings.password` never arrives \u2014 the server strips it and the SDK\n * validates gated forms through `/api/v1/check-password`.\n *\n * The step/question extraction mirrors `extractFlatComponentsFromStep`\n * (form-render gridLayoutUtils): a step's `components` is either a flat\n * component array or a ComponentGridLayout whose rows hold components or\n * `GridLayoutRowItem` wrappers; stateful components carry `state.questionId` \u2014\n * the same discriminator the MCP validator's `collectQuestionIds` uses.\n */\n\ntype RuntimeStep = { id: string; endStepKind?: \"thank_you\" | \"disqualified\"; components?: unknown };\n\nexport type RuntimeConfig = {\n id: string;\n name?: string;\n environmentId?: string;\n config: { steps?: RuntimeStep[] } & Record<string, unknown>;\n settings?: ({ trackPartialResponses?: boolean; trackCookie?: boolean } & Record<string, unknown>) | null;\n};\n\n/** `preview` asks the server for the draft config of a never-published form (authoring loop); published forms serve live either way. */\nexport const fetchRuntimeConfig = (\n transport: Transport,\n formId: string,\n { preview = false, previewToken }: { preview?: boolean; previewToken?: string } = {}\n): Promise<TransportResult<{ data?: RuntimeConfig }>> =>\n transport.get(\n `/api/v1/public/forms/${formId}/runtime-config${\n // The signed token (from the create_form / get_sdk_binding_map replies)\n // unlocks the DRAFT config of a never-published form; without it the\n // server serves the published config.\n preview ? `?preview=1${previewToken ? `&pt=${encodeURIComponent(previewToken)}` : \"\"}` : \"\"\n }`\n );\n\nconst flatComponentsOf = (step: RuntimeStep): unknown[] => {\n const components = step.components;\n if (Array.isArray(components)) return components;\n const layout = (components as { type?: string; layout?: unknown } | undefined)?.layout;\n if (!Array.isArray(layout)) return [];\n return layout.flatMap((layoutRow) => {\n const row = (layoutRow as { row?: unknown[] }).row;\n if (!Array.isArray(row)) return [];\n return row.map((item) =>\n (item as { type?: string }).type === \"GridLayoutRowItem\"\n ? (item as { component?: unknown }).component\n : item\n );\n });\n};\n\n/** Step order + ending kinds \u2014 the engine's traversal contract, including where submit/disqualify land. */\nexport const stepsOf = (\n config: RuntimeConfig[\"config\"]\n): Array<{ id: string; endStepKind?: \"thank_you\" | \"disqualified\" }> =>\n (config.steps ?? []).map((step) => ({\n id: step.id,\n ...(step.endStepKind !== undefined && { endStepKind: step.endStepKind }),\n }));\n\nexport const statefulQuestionsOf = (\n config: RuntimeConfig[\"config\"]\n): Array<{ questionId: string; componentType?: string }> =>\n (config.steps ?? []).flatMap(flatComponentsOf).flatMap((component) => {\n const typed = component as { type?: unknown; state?: { questionId?: unknown } | null } | undefined;\n if (typeof typed?.state?.questionId !== \"string\") return [];\n return [\n {\n questionId: typed.state.questionId,\n ...(typeof typed.type === \"string\" && { componentType: typed.type }),\n },\n ];\n });\n\nexport const statefulQuestionIdsOf = (config: RuntimeConfig[\"config\"]): string[] =>\n statefulQuestionsOf(config).map((question) => question.questionId);\n\n/**\n * Questions whose answers can trigger real-time enrichment, with the state\n * keys to watch \u2014 the native renderer's blur triggers translated to data\n * (identityInfo.tsx handleOnBlur): IdentityInfo fires on its configured\n * `enrichmentSourceField` (default emailAddress) and always on `websiteUrl`;\n * EmailForm fires on its email.\n */\nexport const enrichmentSourcesOf = (\n config: RuntimeConfig[\"config\"]\n): Array<{ questionId: string; fieldNames: string[] }> =>\n (config.steps ?? []).flatMap(flatComponentsOf).flatMap((component) => {\n const typed = component as\n | {\n type?: unknown;\n state?: { questionId?: unknown } | null;\n content?: { enrichmentSourceField?: unknown } | null;\n }\n | undefined;\n if (typeof typed?.state?.questionId !== \"string\") return [];\n if (typed.type === \"IdentityInfo\") {\n const source =\n typeof typed.content?.enrichmentSourceField === \"string\"\n ? typed.content.enrichmentSourceField\n : \"emailAddress\";\n return [{ questionId: typed.state.questionId, fieldNames: [...new Set([source, \"websiteUrl\"])] }];\n }\n if (typed.type === \"EmailForm\") {\n return [{ questionId: typed.state.questionId, fieldNames: [\"email\"] }];\n }\n return [];\n });\n\n/**\n * True when a component EXPLICITLY declares `enrichmentSourceField` \u2014 the\n * authoring-time signal that the owner expects enrichment to run. Implicit\n * sources (every EmailForm / IdentityInfo default) don't count: they make any\n * form with an email question look enrichment-configured.\n */\nexport const hasDeclaredEnrichmentSource = (config: RuntimeConfig[\"config\"]): boolean =>\n (config.steps ?? [])\n .flatMap(flatComponentsOf)\n .some(\n (component) =>\n typeof (component as { content?: { enrichmentSourceField?: unknown } | null } | undefined)?.content\n ?.enrichmentSourceField === \"string\"\n );\n\n/** Mirrors form-render's provider gate (buildExternalStateStore): v2 config with at least one enabled provider exposing fields. */\nexport const hasEnabledEnrichmentProvider = (settings: RuntimeConfig[\"settings\"]): boolean => {\n const enrichment = (settings as { enrichment?: { version?: unknown; providers?: unknown } } | null)\n ?.enrichment;\n if (enrichment?.version !== 2 || !Array.isArray(enrichment.providers)) return false;\n return enrichment.providers.some(\n (provider) =>\n (provider as { enabled?: boolean; enabledFields?: unknown[] } | null)?.enabled === true &&\n Array.isArray((provider as { enabledFields?: unknown[] }).enabledFields) &&\n (provider as { enabledFields: unknown[] }).enabledFields.length > 0\n );\n};\n", "import type { Transport, TransportResult } from \"./transport\";\n\n/**\n * Thin wrap of the public Surface-native scheduler endpoints (forms-sdk-plan.md\n * row 46 \u2014 Phase-1 MVP scope by product decision). Query and payload shapes\n * mirror `@surface/scheduler-ui`'s hooks byte-for-byte (that package is\n * AGPL-tree and cannot ship in the MIT SDK \u2014 plan \u00A72.9), including the split\n * of `YYYY-MM` into numeric month/year params and the booking `meta` block\n * that drives server-side booking\u2194response linkage.\n *\n * `preview: true` mirrors the native BookingForm exactly: queries carry\n * `preview=true`, and `book()` resolves a fabricated preview booking without\n * any network call \u2014 draft interactions never create real bookings.\n *\n * `toSchedulerAnswerState` reproduces `SurfaceScheduler.handleBookingComplete`:\n * the persisted DynamicScheduler component state whose `eventScheduled`/`uri`\n * pair the payload builder's bookingId detection and the server's booking\n * meta injection key on. `googleMeetLink` is the frozen persisted key even\n * though the API field is `meetingJoinLink`.\n */\n\nexport type BookingAttendee = { name: string; email: string; isHost: boolean };\n\nexport type Booking = {\n id: string;\n startTime: string;\n endTime: string;\n timezone: string;\n inviteeName: string;\n inviteeEmail: string;\n meetingJoinLink: string | null;\n cancelToken: string;\n rescheduleToken: string;\n attendees: BookingAttendee[];\n};\n\nexport type TimeSlot = { start: string; end: string };\n\nexport type AvailabilitySummary = {\n has_availability: boolean;\n available_slots_7d: number;\n available_slots_14d: number;\n available_slots_30d: number;\n available_days_7d: number;\n next_available_date: string | null;\n total_available_slots: number;\n rep_meeting_count_today: number;\n};\n\ntype HostScope = { hostId?: string; ownerEmail?: string };\n\nexport type SchedulerClient = {\n getPublicEventType: <TEventType = unknown>(eventTypeId: string) => Promise<TransportResult<TEventType>>;\n getAvailabilitySummary: (args: {\n eventTypeId: string;\n timezone?: string;\n }) => Promise<TransportResult<{ data?: AvailabilitySummary }>>;\n getMonthAvailability: (\n args: {\n eventTypeId: string;\n /** Calendar month as `YYYY-MM`; split into numeric month/year params like native. */\n month: string;\n timezone: string;\n duration?: number;\n } & HostScope\n ) => Promise<TransportResult<{ data?: { dates?: unknown[]; resolvedHost?: unknown } }>>;\n getSlots: (\n args: { eventTypeId: string; date: string; timezone: string; duration?: number } & HostScope\n ) => Promise<TransportResult<{ data?: { slots?: TimeSlot[] } }>>;\n book: (args: {\n eventTypeId: string;\n startTime: string;\n /**\n * The selected slot's end. Required \u2014 every booking comes from a picked\n * slot, and a fallback would fabricate zero-length preview meetings. Only\n * preview fabrication reads it (the server derives real end times); it is\n * never sent on the wire.\n */\n endTime: string;\n timezone: string;\n inviteeName: string;\n inviteeEmail: string;\n duration?: number;\n intakeResponses?: Record<string, string>;\n guestEmails?: string[];\n captchaToken?: string;\n responseId?: string;\n leadSessionId?: string;\n fingerprint?: string;\n hostRouting?: unknown;\n }) => Promise<TransportResult<Booking>>;\n reschedule: (args: {\n bookingId: string;\n rescheduleToken: string;\n newStartTime: string;\n timezone: string;\n }) => Promise<TransportResult<Booking>>;\n};\n\nconst toParams = (entries: Record<string, string | undefined>): URLSearchParams =>\n new URLSearchParams(\n Object.fromEntries(Object.entries(entries).filter(([, value]) => value != null)) as Record<string, string>\n );\n\nexport const createSchedulerClient = ({\n transport,\n preview = false,\n}: {\n transport: Transport;\n preview?: boolean;\n}): SchedulerClient => {\n const previewParam = preview ? \"true\" : undefined;\n\n const unwrapBooking = (result: TransportResult<{ data?: Booking }>): TransportResult<Booking> => {\n if (!result.ok) return result;\n const booking = result.data.data;\n if (!booking?.id) return { ok: false, error: { kind: \"http\", status: 200, body: result.data } };\n return { ok: true, data: booking };\n };\n\n return {\n getPublicEventType: (eventTypeId) => transport.get(`/api/v1/scheduler/event-types/${eventTypeId}/public`),\n\n getAvailabilitySummary: ({ eventTypeId, timezone }) => {\n const params = new URLSearchParams({\n eventTypeId,\n timezone: timezone ?? Intl.DateTimeFormat().resolvedOptions().timeZone,\n });\n return transport.get(`/api/v1/scheduler/availability-summary?${params}`);\n },\n\n getMonthAvailability: ({ eventTypeId, month, timezone, duration, hostId, ownerEmail }) => {\n const [year, monthNum] = month.split(\"-\").map(Number);\n const params = toParams({\n eventTypeId,\n month: String(monthNum),\n year: String(year),\n timezone,\n duration: duration ? String(duration) : undefined,\n preview: previewParam,\n hostId,\n ownerEmail,\n });\n return transport.get(`/api/v1/scheduler/availability?${params}`);\n },\n\n getSlots: ({ eventTypeId, date, timezone, duration, hostId, ownerEmail }) => {\n const params = toParams({\n eventTypeId,\n date,\n timezone,\n duration: duration ? String(duration) : undefined,\n preview: previewParam,\n hostId,\n ownerEmail,\n });\n return transport.get(`/api/v1/scheduler/slots?${params}`);\n },\n\n book: async ({\n eventTypeId,\n startTime,\n endTime,\n timezone,\n inviteeName,\n inviteeEmail,\n duration,\n intakeResponses,\n guestEmails,\n captchaToken,\n responseId,\n leadSessionId,\n fingerprint,\n hostRouting,\n }) => {\n if (preview) {\n return {\n ok: true,\n data: {\n id: \"preview-booking-\" + Date.now(),\n startTime,\n // Native fabricates from the selected slot (BookingForm: slot.end).\n endTime,\n timezone,\n inviteeName: inviteeName || \"Test User\",\n inviteeEmail: inviteeEmail || \"test@example.com\",\n meetingJoinLink: null,\n cancelToken: \"preview-cancel-\" + Date.now(),\n rescheduleToken: \"preview-reschedule-\" + Date.now(),\n attendees: [{ name: \"Host\", email: \"host@example.com\", isHost: true }],\n },\n };\n }\n const result = await transport.post<{ data?: Booking }>(\"/api/v1/scheduler/book\", {\n eventTypeId,\n startTime,\n timezone,\n inviteeName,\n inviteeEmail: inviteeEmail.trim(),\n ...(duration ? { duration } : {}),\n ...(intakeResponses && Object.keys(intakeResponses).length > 0 ? { intakeResponses } : {}),\n ...(guestEmails && guestEmails.length > 0 ? { guestEmails } : {}),\n ...(captchaToken ? { captchaToken } : {}),\n meta: {\n source: \"form\",\n ...(responseId ? { responseId } : {}),\n ...(leadSessionId ? { leadSessionId } : {}),\n ...(fingerprint ? { fingerprint } : {}),\n ...(hostRouting ? { hostRouting } : {}),\n },\n });\n return unwrapBooking(result);\n },\n\n reschedule: async ({ bookingId, rescheduleToken, newStartTime, timezone }) => {\n const result = await transport.post<{ data?: Booking }>(\n `/api/v1/scheduler/bookings/${bookingId}/reschedule`,\n { rescheduleToken, newStartTime, timezone }\n );\n return unwrapBooking(result);\n },\n };\n};\n\n/** The persisted DynamicScheduler component state for a completed booking. */\nexport const toSchedulerAnswerState = (booking: Booking): Record<string, unknown> => {\n const hostAttendee = booking.attendees?.find((attendee) => attendee.isHost);\n return {\n type: \"DynamicScheduler\",\n eventScheduled: true,\n uri: booking.id,\n meetingTime: booking.startTime,\n meetingEndTime: booking.endTime,\n ownerEmails: hostAttendee?.email ?? \"\",\n guestEmails: booking.inviteeEmail,\n inviteeName: booking.inviteeName,\n googleMeetLink: booking.meetingJoinLink ?? \"\",\n };\n};\n", "/**\n * Delivery layer for the SDK's first-party requests, mirroring the native\n * runtime's two transports (forms-sdk-plan.md \u00A72.4):\n *\n * - `post` \u2014 plain `fetch` for calls whose response body the engine needs\n * (response create returns `responseId`/`meta`, identify returns\n * `leadId`/`sessionId`). Never throws: resolves to a typed result so\n * callers keep the never-break-the-host-page guarantee (\u00A72.6).\n * - `beacon` \u2014 `sendBeacon`-first with `fetch(keepalive)` fallback for\n * fire-and-forget writes (response updates, events, journey), the same\n * semantics as form-render's `updateResponse.ts` / `sendPushEventRequest.ts`.\n * Failures are swallowed by design: the server's drop-off sweep reconciles\n * missed updates, and events are best-effort.\n *\n * Unlike form-render (relative paths, same-origin only), every request is\n * absolute against a configurable base URL \u2014 SDK pages are customer-hosted\n * and always cross-origin (\u00A74.1).\n */\n\n/** The host the public tag already targets (scripts:src/constants.ts). */\nexport const DEFAULT_API_BASE_URL = \"https://forms.withsurface.com\";\n\n/**\n * Sent as `X-Surface-Sdk-Version` on every fetch-path request (Decisions #14:\n * SDK 429s must be measurable before rate limits are revisited). `sendBeacon`\n * cannot carry headers, so beacon deliveries carry the version as the `sdv`\n * query param instead \u2014 the server reads both. Bumped manually until\n * extraction wires it to package.json at build time.\n */\nexport const SDK_VERSION = \"0.1.0\";\n\nconst versionedHeaders = (headers: Record<string, string> = {}) => ({\n ...headers,\n \"X-Surface-Sdk-Version\": SDK_VERSION,\n});\n\nconst versionedUrl = (url: string) => `${url}${url.includes(\"?\") ? \"&\" : \"?\"}sdv=${SDK_VERSION}`;\n\nexport type TransportResult<TData> = { ok: true; data: TData } | { ok: false; error: TransportError };\n\nexport type TransportError =\n | { kind: \"network\"; cause: unknown }\n | { kind: \"http\"; status: number; body?: unknown };\n\nexport type Transport = {\n get: <TData>(path: string) => Promise<TransportResult<TData>>;\n post: <TData>(\n path: string,\n payload: unknown,\n opts?: { keepalive?: boolean; credentials?: boolean }\n ) => Promise<TransportResult<TData>>;\n /** Returns true only when `sendBeacon` queued the payload; the fire-and-forget fetch fallback reports false. */\n beacon: (path: string, payload: unknown) => boolean;\n};\n\nexport const createTransport = ({\n apiBaseUrl = DEFAULT_API_BASE_URL,\n}: { apiBaseUrl?: string } = {}): Transport => {\n const baseUrl = apiBaseUrl.replace(/\\/$/, \"\");\n const toUrl = (path: string) => `${baseUrl}${path}`;\n\n const get = async <TData>(path: string): Promise<TransportResult<TData>> => {\n try {\n const response = await fetch(toUrl(path), { headers: versionedHeaders() });\n if (!response.ok) {\n const body = await response.json().catch(() => undefined);\n return { ok: false, error: { kind: \"http\", status: response.status, body } };\n }\n return { ok: true, data: (await response.json()) as TData };\n } catch (cause) {\n return { ok: false, error: { kind: \"network\", cause } };\n }\n };\n\n const post = async <TData>(\n path: string,\n payload: unknown,\n opts?: { keepalive?: boolean; credentials?: boolean }\n ): Promise<TransportResult<TData>> => {\n try {\n const response = await fetch(toUrl(path), {\n method: \"POST\",\n headers: versionedHeaders({ \"Content-Type\": \"application/json\" }),\n body: JSON.stringify(payload),\n ...(opts?.keepalive ? { keepalive: true } : {}),\n // The `${formId}_pa` person-attributes cookie (repeat-visitor signals)\n // lives on the API origin; only credentialed requests carry it from a\n // customer-hosted page (Decisions #12 \u2014 the endpoints echo the origin).\n ...(opts?.credentials ? { credentials: \"include\" as const } : {}),\n });\n if (!response.ok) {\n const body = await response.json().catch(() => undefined);\n return { ok: false, error: { kind: \"http\", status: response.status, body } };\n }\n return { ok: true, data: (await response.json()) as TData };\n } catch (cause) {\n return { ok: false, error: { kind: \"network\", cause } };\n }\n };\n\n const beacon = (path: string, payload: unknown): boolean => {\n let serialized: string;\n try {\n serialized = JSON.stringify(payload);\n } catch {\n return false; // unserializable payloads are swallowed like every other beacon failure\n }\n const url = versionedUrl(toUrl(path));\n try {\n if (typeof navigator !== \"undefined\" && typeof navigator.sendBeacon === \"function\") {\n const queued = navigator.sendBeacon(url, new Blob([serialized], { type: \"application/json\" }));\n if (queued) return true;\n }\n } catch {\n // fall through to fetch\n }\n try {\n void fetch(url, {\n method: \"POST\",\n keepalive: true,\n // sendBeacon always sends credentials; the fallback must match, or the\n // update path's `${formId}_pa` cookie round-trip depends on which\n // delivery won.\n credentials: \"include\",\n headers: versionedHeaders({ \"Content-Type\": \"application/json\" }),\n body: serialized,\n }).catch(() => undefined);\n } catch {\n // swallow \u2014 beacon delivery is best-effort\n }\n return false;\n };\n\n return { get, post, beacon };\n};\n", "/**\n * Typed answer states for headless callers (plan \u00A72.9): the bind layer builds\n * these automatically, but React/headless code hands them to `setAnswer` by\n * hand \u2014 and shipping a bare label string where a structured state belongs is\n * the classic production 400 (2026-08 field run). These local types mirror\n * each component's wire schema and are contract-tested against\n * `@surface/types` (dev dependency only \u2014 the SDK ships zero runtime deps).\n *\n * `setAnswer` itself stays structurally typed (`Record<string, unknown>`):\n * legacy component types not listed here remain settable, and answers merge\n * per question, so partial patches are legal. Annotate call sites with these\n * types to get the compiler's help.\n */\n\nexport type ShortInputAnswer = { type: \"ShortInput\"; input: string };\nexport type LongInputAnswer = { type: \"LongInput\"; input: string };\nexport type EmailFormAnswer = { type: \"EmailForm\"; email: string; subscriptionCheck?: boolean };\nexport type DropdownAnswer = { type: \"Dropdown\"; selected: string | string[] };\nexport type DisclaimerAnswer = { type: \"Disclaimer\"; check?: boolean };\nexport type FileUploaderAnswer = { type: \"FileUploader\"; fileUrl?: string };\n\n/** The ENTIRE option list, one entry per record option \u2014 never only the picked one. */\nexport type MultipleOptionsAnswer = {\n type: \"MultipleOptionsQuestion\";\n choices: Array<{ key: string; value: boolean; index: number }>;\n selectedOther?: boolean;\n};\nexport type MMChoiceAnswer = {\n type: \"MMChoiceQuestion\";\n choices: Array<{ key: string; value: boolean }>;\n};\nexport type MultipleChoiceAnswer = {\n type: \"MultipleChoiceQuestion\";\n choices: Array<{ key: string; value: boolean }>;\n};\nexport type GraphicOptionsAnswer = { type: \"GraphicOptions\"; value: string; index: number };\nexport type MultipleChoiceSingleAnswerAnswer = {\n type: \"MultipleChoiceSingleAnswer\";\n value: string;\n index: number;\n};\n\n/** Canonical IdentityInfo answer keys (mirrors IdentityInfoKeysArray; contract-tested). */\nexport const IDENTITY_INFO_ANSWER_KEYS = [\n \"firstName\",\n \"lastName\",\n \"fullName\",\n \"emailAddress\",\n \"workEmailAddress\",\n \"phoneNumber\",\n \"companyName\",\n \"numberOfEmployees\",\n \"websiteUrl\",\n \"title\",\n \"streetAddress\",\n \"aptSuiteEtc\",\n \"city\",\n \"state\",\n \"country\",\n \"zipCode\",\n \"companyRevenue\",\n \"profilePictureUrl\",\n] as const;\n\nexport type IdentityInfoAnswerKey = (typeof IDENTITY_INFO_ANSWER_KEYS)[number];\n\nexport type IdentityInfoAnswer = { type: \"IdentityInfo\" } & Partial<Record<IdentityInfoAnswerKey, string>>;\n\n/** Booking answers; `toSchedulerAnswerState` produces this \u2014 override `type` to the record's component type. */\nexport type SchedulerAnswer = {\n type: \"CalendlyScreen\" | \"DynamicScheduler\";\n eventScheduled: boolean;\n uri: string;\n meetingTime?: string;\n meetingEndTime?: string;\n ownerEmails?: string;\n guestEmails?: string;\n inviteeName?: string;\n googleMeetLink?: string;\n};\n\nexport type KnownAnswerState =\n | ShortInputAnswer\n | LongInputAnswer\n | EmailFormAnswer\n | DropdownAnswer\n | DisclaimerAnswer\n | FileUploaderAnswer\n | MultipleOptionsAnswer\n | MMChoiceAnswer\n | MultipleChoiceAnswer\n | GraphicOptionsAnswer\n | MultipleChoiceSingleAnswerAnswer\n | IdentityInfoAnswer\n | SchedulerAnswer;\n", "/**\n * Instance-scoped typed event emitter \u2014 the primitive behind the SDK's\n * public `form.on(...)` lifecycle surface (forms-sdk-plan.md \u00A72.2) and the\n * store-subscription contract adapters build on (\u00A72.9).\n *\n * Exists because the SDK cannot use Node's EventEmitter (zero runtime deps,\n * browser bundle) and must not reproduce form-render's module-level\n * singleton listeners, which break multi-form pages (\u00A72.7). Handler\n * exceptions are isolated per handler: a throwing host callback never breaks\n * the engine or sibling handlers \u2014 the never-break-the-host-page guarantee\n * applied to the callback boundary.\n *\n * The concrete SDK event map (viewed/started/stepChanged/\u2026) is owned by the\n * step engine, which defines the payload shapes it emits; this module is\n * deliberately payload-agnostic.\n */\n\nexport type Unsubscribe = () => void;\n\nexport type Emitter<TEventMap extends Record<string, unknown>> = {\n on: <K extends keyof TEventMap>(event: K, handler: (payload: TEventMap[K]) => void) => Unsubscribe;\n emit: <K extends keyof TEventMap>(event: K, payload: TEventMap[K]) => void;\n};\n\nexport const createEmitter = <TEventMap extends Record<string, unknown>>(): Emitter<TEventMap> => {\n const handlers = new Map<keyof TEventMap, Set<(payload: never) => void>>();\n\n return {\n on: (event, handler) => {\n const existing = handlers.get(event) ?? new Set();\n existing.add(handler as (payload: never) => void);\n handlers.set(event, existing);\n return () => {\n existing.delete(handler as (payload: never) => void);\n };\n },\n emit: (event, payload) => {\n handlers.get(event)?.forEach((handler) => {\n try {\n (handler as (value: typeof payload) => void)(payload);\n } catch (error) {\n console.error(`Surface SDK: \"${String(event)}\" handler threw`, error);\n }\n });\n },\n };\n};\n", "import type { Transport } from \"../client/transport\";\n\n/**\n * Client for the internal event pipeline `POST /api/v1/pushEvent`\n * (forms-sdk-plan.md row 33), mirroring form-render's `callPushEventApi`:\n * same wire shapes, same client-side bot filter, same required-field guard\n * (any invalid event drops the whole request), same beacon-first delivery.\n * Two deliberate departures, both decided in the plan: no PostHog mirror\n * (Surface-internal telemetry \u2014 \u00A71D row 33) and a `preview` flag that blocks\n * every send so agent preview loops never pollute data (\u00A72.2).\n *\n * The wire types below are structural mirrors of the Zod schemas in\n * `@surface/types/v1/surfaceEvent/model/types.ts` \u2014 local because the SDK\n * ships with zero runtime dependencies; the contract test in this directory\n * validates them against the real schemas.\n */\n\nexport type SurfaceEventType =\n | \"form_viewed\"\n | \"form_started\"\n | \"form_completed\"\n | \"form_step_viewed\"\n | \"form_step_submitted\"\n | \"form_step_dropoff\"\n | \"form_question_submitted\"\n | \"response_submission_created\"\n | \"response_submission_error\"\n | \"script_initiated\";\n\nexport type SurfaceEventEntityType = \"form\" | \"form_step\" | \"response\";\n\nexport type PushEventProperty = { key: string; value: unknown };\n\nexport type PushEventPayload = {\n type: SurfaceEventType;\n entityType: SurfaceEventEntityType;\n entityId: string;\n stepId?: string | null;\n leadSessionId?: string | null;\n properties?: PushEventProperty[];\n leadId?: string;\n environmentId?: string;\n};\n\n/** The server accepts exactly one batch shape: a step transition pair. */\nexport type PushEventBatch = {\n events: [\n PushEventPayload & { type: \"form_step_submitted\"; entityType: \"form_step\"; stepId: string },\n PushEventPayload & { type: \"form_step_viewed\"; entityType: \"form_step\"; stepId: string }\n ];\n};\n\nexport type PushEventRequest = PushEventPayload | PushEventBatch;\n\nconst PUSH_EVENT_PATH = \"/api/v1/pushEvent\";\n\nconst KNOWN_BOT_UA =\n /bot|crawl|spider|slurp|baidu|bingpreview|googlebot|yandex|duckduck|ahrefs|semrush|facebookexternalhit|embedly|quora link preview|pinterest|twitterbot|linkedinbot|whatsapp|telegram|discord|headless|lighthouse|pagespeed/i;\n\nconst isLikelyBot = (): boolean => {\n const ua = navigator.userAgent;\n if (!ua) return false;\n return KNOWN_BOT_UA.test(ua);\n};\n\nconst hasRequiredFields = (event: PushEventPayload): boolean =>\n Boolean(event?.type && event?.entityType && event?.entityId);\n\nexport const buildStepTransitionEventBatch = ({\n sessionId,\n formId,\n currentStepId,\n nextStepId,\n stepCompletionTime,\n}: {\n sessionId: string | undefined;\n formId: string;\n currentStepId: string;\n nextStepId: string;\n stepCompletionTime: number;\n}): PushEventBatch => ({\n events: [\n {\n type: \"form_step_submitted\",\n entityType: \"form_step\",\n entityId: formId,\n stepId: currentStepId,\n leadSessionId: sessionId,\n properties: [{ key: \"stepCompletionTime\", value: stepCompletionTime }],\n },\n {\n type: \"form_step_viewed\",\n entityType: \"form_step\",\n entityId: formId,\n stepId: nextStepId,\n leadSessionId: sessionId,\n properties: [],\n },\n ],\n});\n\nexport type PushEventClient = {\n push: (request: PushEventRequest) => void;\n};\n\nexport const createPushEventClient = ({\n transport,\n preview = false,\n}: {\n transport: Transport;\n preview?: boolean;\n}): PushEventClient => ({\n push: (request) => {\n if (preview) return;\n if (typeof navigator === \"undefined\") return;\n\n const events = \"events\" in request ? request.events : [request];\n if (isLikelyBot()) return;\n if (events.some((event) => !hasRequiredFields(event))) return;\n\n transport.beacon(PUSH_EVENT_PATH, request);\n },\n});\n", "/**\n * `form_started` detection (forms-sdk-plan.md row 22): native fires it on the\n * first deep-inequality between the current answer state and the snapshot\n * taken at mount, once per form instance (`DualPaneAdjustableForm`'s\n * `startedForm` ref + lodash `isEqual`). The detector captures the snapshot at\n * creation; `check(current)` returns true exactly once, on the first\n * divergence. The local deep-equal covers the answer-state shape (plain\n * objects, arrays, primitives) \u2014 key order insensitive, like lodash.\n */\nexport const createStartedDetector = <T>(initial: T): ((current: T) => boolean) => {\n const snapshot = deepClone(initial);\n let started = false;\n return (current) => {\n if (started) return false;\n if (deepEqual(snapshot, current)) return false;\n started = true;\n return true;\n };\n};\n\nconst deepClone = <T>(value: T): T => {\n if (Array.isArray(value)) return value.map(deepClone) as T;\n if (value !== null && typeof value === \"object\") {\n const clone: Record<string, unknown> = {};\n for (const [key, entry] of Object.entries(value)) clone[key] = deepClone(entry);\n return clone as T;\n }\n return value;\n};\n\nconst deepEqual = (a: unknown, b: unknown): boolean => {\n if (Object.is(a, b)) return true;\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length) return false;\n return a.every((entry, index) => deepEqual(entry, b[index]));\n }\n if (a !== null && b !== null && typeof a === \"object\" && typeof b === \"object\") {\n const aKeys = Object.keys(a);\n const bKeys = Object.keys(b);\n if (aKeys.length !== bKeys.length) return false;\n return aKeys.every((key) =>\n deepEqual((a as Record<string, unknown>)[key], (b as Record<string, unknown>)[key])\n );\n }\n return false;\n};\n", "/**\n * Response payload builders (forms-sdk-plan.md rows 24-26), mirroring\n * form-render's `createResponseApiPayload` exactly \u2014 the semantics here are\n * load-bearing server contracts:\n *\n * - **Full answer-set resend on every write** (row 26): all steps' answers\n * plus every external-state entry as a pseudo-answer keyed by its stateId.\n * Server-side UTM preservation depends on the URL_DATA entry riding every\n * update.\n * - `SCHEDULER_AVAILABILITY_DATA` entries are transient client-only data and\n * are never persisted.\n * - Surface-native booking detection: the first answer with\n * `eventScheduled: true` and a non-Calendly/Cal.com `uri` stamps\n * `meta.bookingId`.\n * - `enrichedFields` precedence: person-attribute enrichment wins over the\n * processed APOLLO_EMAIL_ENRICHMENT external state, `{}` as the floor.\n * - `meta.cookies` is stripped when `trackCookies` is off.\n * - Creates pin `responseShapeVersion: \"2.0\"`; updates carry `responseId`.\n *\n * Types are local structural mirrors of `ZFormResponseData` /\n * `ZFormUpdateResponseData` (zero-runtime-deps); the contract test validates\n * built payloads against the real schemas. Answer/external-state entry shapes\n * are pass-through records \u2014 component state shapes belong to the engine.\n */\n\nexport type SingleFormResponse = {\n questionId: string;\n response: Record<string, unknown>;\n};\n\n/** Answers grouped per step, keyed stepId \u2192 questionId \u2192 component state. */\nexport type AnswerStates = Record<string, Record<string, Record<string, unknown>>>;\n\n/** External state entries keyed by stateId; `type` discriminates (URL_DATA, enrichment, \u2026). */\nexport type ExternalStates = Record<string, { type: string } & Record<string, unknown>>;\n\nexport type FormResponsePayload = {\n formId: string;\n responses: SingleFormResponse[];\n enrichedFields: Record<string, unknown>;\n finished: boolean;\n invalidResponse: boolean;\n stepId: string;\n fingerprint?: string;\n leadSessionId?: string;\n meta: Record<string, unknown>;\n responseShapeVersion: \"2.0\";\n};\n\nexport type FormUpdateResponsePayload = Omit<FormResponsePayload, \"responseShapeVersion\"> & {\n responseId: string;\n};\n\nexport const buildResponsesArray = (\n answers: AnswerStates,\n externalStates: ExternalStates\n): { responses: SingleFormResponse[]; enrichedFields: Record<string, unknown>; bookingId?: string } => {\n const responses: SingleFormResponse[] = [];\n let enrichedFields: Record<string, unknown> = {};\n let bookingId: string | undefined;\n\n for (const step in answers) {\n const stepState = answers[step];\n for (const questionId in stepState) {\n const entry = stepState[questionId] as { eventScheduled?: boolean; uri?: string };\n if (\n !bookingId &&\n entry?.eventScheduled === true &&\n typeof entry.uri === \"string\" &&\n entry.uri.length > 0 &&\n !entry.uri.includes(\"calendly.com\") &&\n !entry.uri.includes(\"cal.com\")\n ) {\n bookingId = entry.uri;\n }\n responses.push({ questionId, response: { ...stepState[questionId] } });\n }\n }\n\n for (const stateId in externalStates) {\n const externalState = externalStates[stateId];\n if (externalState.type === \"SCHEDULER_AVAILABILITY_DATA\") continue;\n responses.push({ questionId: stateId, response: { ...externalState } });\n if (externalState.type === \"APOLLO_EMAIL_ENRICHMENT\" && externalState.processed) {\n enrichedFields = (externalState.data as Record<string, unknown>) ?? {};\n }\n }\n\n return { responses, enrichedFields, bookingId };\n};\n\ntype BuildPayloadOptions = {\n formId: string;\n answers: AnswerStates;\n externalStates: ExternalStates;\n submittingOnStepId: string;\n finished: boolean;\n invalidResponse: boolean;\n trackCookies: boolean;\n meta?: Record<string, unknown>;\n /** Person-attribute enrichment; wins over external-state enrichment like native. */\n personAttributeEnrichedFields?: Record<string, unknown>;\n fingerprint?: string;\n leadSessionId?: string;\n};\n\nconst buildBasePayload = ({\n formId,\n answers,\n externalStates,\n submittingOnStepId,\n finished,\n invalidResponse,\n trackCookies,\n meta = {},\n personAttributeEnrichedFields,\n fingerprint,\n leadSessionId,\n}: BuildPayloadOptions) => {\n const { responses, enrichedFields, bookingId } = buildResponsesArray(answers, externalStates);\n\n const filteredMeta = trackCookies\n ? meta\n : Object.fromEntries(Object.entries(meta).filter(([key]) => key !== \"cookies\"));\n\n return {\n responses,\n enrichedFields: personAttributeEnrichedFields ?? enrichedFields ?? {},\n formId,\n finished,\n invalidResponse,\n stepId: submittingOnStepId,\n fingerprint,\n leadSessionId,\n meta: bookingId ? { ...filteredMeta, bookingId } : filteredMeta,\n };\n};\n\nexport const createSubmitResponsePayload = (options: BuildPayloadOptions): FormResponsePayload => ({\n ...buildBasePayload(options),\n responseShapeVersion: \"2.0\",\n});\n\nexport const createUpdateResponsePayload = (\n options: BuildPayloadOptions & { responseId: string }\n): FormUpdateResponsePayload => ({\n ...buildBasePayload(options),\n responseId: options.responseId,\n});\n", "import { submitResponse, updateResponse, updateResponseConfirmed } from \"../client/responses\";\nimport type { Transport } from \"../client/transport\";\nimport { createEmitter, type Unsubscribe } from \"../events/emitter\";\nimport type { FormJourneyTracker, FormJourneyTransitionReason } from \"../events/formJourneyTracker\";\nimport { buildStepTransitionEventBatch, type PushEventClient } from \"../events/pushEvents\";\nimport { createStartedDetector } from \"../events/startedDetection\";\nimport {\n createSubmitResponsePayload,\n createUpdateResponsePayload,\n type AnswerStates,\n type ExternalStates,\n} from \"./responsePayload\";\n\n/**\n * The headless step engine (forms-sdk-plan.md \u00A72.2): answers, traversal,\n * response writes, and lifecycle events over the modules this stack built.\n * Native semantics preserved:\n *\n * - **Partial saves on forward step change only** (row 23): first forward\n * move creates the response, later moves update it, and every write sends\n * the id of the step being *left* \u2014 all gated by\n * `settings.trackPartialResponses` except the finishing write, which always\n * happens.\n * - **Finished/invalid derivation** (row 27): a resolved next step of\n * `\"END\"`/`\"INVALID\"`/`undefined` finishes the form; `\"INVALID\"`\n * disqualifies.\n * - **Step transition events** (row 31): the `form_step_submitted` +\n * `form_step_viewed` batch with `stepCompletionTime` in seconds since the\n * engine was created (native's `initialRenderTime`), skipped when the form\n * finishes (native returns before emitting on `\"END\"`).\n * - `markViewed` mirrors native's view actions: `form_viewed` + first-step\n * `form_step_viewed`, once.\n * - Backward navigation never writes (native only re-arms `stepIdToSubmit`).\n *\n * **The engine does not evaluate routing** (Decisions #6): the customer's own\n * code owns navigation. `next()`/`back()` are linear conveniences,\n * `goToStep()` is the explicit move \u2014 forward jumps carry full forward\n * semantics (step events, journey transition, partial write), jumps to an\n * already-visited step rewind like `back()` (no write). Disqualification is\n * the explicit `disqualify()` verb \u2014 in native it was a routing outcome (the\n * `INVALID` sentinel), so without routing it needs its own API. The pluggable\n * `resolveNextStep` remains as the headless hook for callers who express\n * their routing as a resolver instead of imperative `goToStep` calls.\n */\n\nexport type ResolvedNextStep = { stepId: string; reason?: FormJourneyTransitionReason };\n\nexport type ResolveNextStep = (\n currentStepId: string,\n answers: AnswerStates\n) => ResolvedNextStep | \"END\" | \"INVALID\";\n\nexport type FormEngineEvents = {\n viewed: { formId: string };\n started: { formId: string };\n stepChanged: { fromStepId: string; toStepId: string };\n stepCompleted: { stepId: string };\n completed: { formId: string };\n disqualified: { stepId: string };\n saved: { responseId: string; finished: boolean; resumeToken: string | null };\n error: { scope: \"submit\"; error: unknown };\n};\n\nexport type FormEngineState = {\n currentStepId: string;\n answers: AnswerStates;\n /** Pseudo-answer states riding every write (URL_DATA attribution, enrichment results, \u2026). */\n externalStates: ExternalStates;\n responseId: string | null;\n /** From the create reply; with the responseId it authorizes a later resume (persist both). */\n resumeToken: string | null;\n finished: boolean;\n};\n\nexport type FormEngine = {\n setAnswer: (questionId: string, state: Record<string, unknown>) => void;\n /** Writes a pseudo-answer external state (enrichment results, custom attribution) that rides every subsequent save. */\n setExternalState: (id: string, state: { type: string } & Record<string, unknown>) => void;\n /** Merges keys into the response `meta` object carried by every subsequent save (post-finish it amends the stored response). */\n mergeMeta: (partial: Record<string, unknown>) => void;\n next: () => Promise<void>;\n back: () => void;\n /** Customer-owned navigation (Decisions #6): forward jumps save like next(), visited-step jumps rewind like back(). */\n goToStep: (stepId: string) => Promise<void>;\n submit: () => Promise<void>;\n /** Finishes the form as disqualified (`invalidResponse: true`) \u2014 the explicit replacement for native's INVALID routing outcome. */\n disqualify: () => Promise<void>;\n savePartial: () => Promise<void>;\n /** Resolves when every write queued so far has settled \u2014 await it before tearing the page down (test harnesses, SPA unmounts). */\n flush: () => Promise<void>;\n markViewed: () => void;\n on: <K extends keyof FormEngineEvents>(\n event: K,\n handler: (payload: FormEngineEvents[K]) => void\n ) => Unsubscribe;\n state: () => FormEngineState;\n subscribe: (listener: () => void) => Unsubscribe;\n};\n\nexport const createFormEngine = ({\n formId,\n environmentId,\n steps,\n transport,\n resolveNextStep,\n trackPartialResponses = true,\n trackCookies = false,\n externalStates = {},\n meta = {},\n identity,\n pushEvents,\n formJourney,\n preview = false,\n resume,\n}: {\n formId: string;\n environmentId?: string;\n /** Ordered logical steps of the form record (the data contract). */\n steps: Array<{ id: string; endStepKind?: \"thank_you\" | \"disqualified\" }>;\n transport: Transport;\n resolveNextStep?: ResolveNextStep;\n trackPartialResponses?: boolean;\n trackCookies?: boolean;\n externalStates?: ExternalStates;\n meta?: Record<string, unknown>;\n /**\n * Read at every write/event, not captured at construction \u2014 a re-identify\n * (SurfaceForm.identify after cache expiry) must attribute subsequent\n * responses and events to the current visitor, not the boot-time one.\n */\n identity?: () => { fingerprint?: string; leadSessionId?: string; leadId?: string };\n pushEvents?: PushEventClient;\n formJourney?: FormJourneyTracker;\n /** Preview mode never writes (\u00A72.2): traversal and events run, responses are never created. */\n preview?: boolean;\n /**\n * Resume a stored response (row 28): the seeded responseId turns every write\n * into an update (no duplicate row), and the seeded answers ride along in\n * the full-answer-set resend. Answers are keyed by questionId and seeded\n * under the first step \u2014 the wire flattens steps, and presentation (which\n * step to show) is the caller's own navigation.\n */\n resume?: { responseId: string; answers?: Record<string, Record<string, unknown>> };\n}): FormEngine => {\n if (steps.length === 0) throw new Error(\"createFormEngine requires at least one step\");\n\n const resolve: ResolveNextStep =\n resolveNextStep ??\n ((currentStepId) => {\n const index = steps.findIndex((step) => step.id === currentStepId);\n const following = steps[index + 1];\n return following ? { stepId: following.id, reason: \"linear\" } : \"END\";\n });\n\n const emitter = createEmitter<FormEngineEvents>();\n const storeListeners = new Set<() => void>();\n // The snapshot is cached until the next mutation so state() is referentially\n // stable between changes \u2014 the store contract useSyncExternalStore requires\n // (\u00A72.9); an uncached snapshot re-renders React hosts forever.\n let snapshotDirty = true;\n let snapshot: FormEngineState;\n const notify = () => {\n snapshotDirty = true;\n storeListeners.forEach((listener) => listener());\n };\n\n const currentIdentity = () => identity?.() ?? {};\n const answers: AnswerStates = {};\n let currentStepId = steps[0].id;\n let responseId: string | null = resume?.responseId ?? null;\n let resumeToken: string | null = null;\n if (resume?.answers) {\n const seeded: Record<string, Record<string, unknown>> = {};\n for (const [questionId, state] of Object.entries(resume.answers)) {\n seeded[questionId] = { ...state };\n }\n answers[currentStepId] = seeded;\n }\n let finished = false;\n // The finishing write's parameters, kept so a post-completion external-state\n // mutation can re-issue it (see setExternalState).\n let terminalWrite: { stepId: string; invalid: boolean } | null = null;\n let viewed = false;\n const createdAt = Date.now();\n const history: string[] = [];\n const hasStarted = createStartedDetector(answers);\n\n formJourney?.setFormId(formId);\n if (responseId != null) formJourney?.setResponseId(responseId);\n formJourney?.recordEntry(currentStepId);\n\n const write = async (submittingOnStepId: string, isFinished: boolean, invalid: boolean) => {\n if (preview) return;\n const payloadOptions = {\n formId,\n answers,\n externalStates,\n submittingOnStepId,\n finished: isFinished,\n invalidResponse: invalid,\n trackCookies,\n meta,\n fingerprint: currentIdentity().fingerprint,\n leadSessionId: currentIdentity().leadSessionId,\n };\n if (responseId == null) {\n const result = await submitResponse(transport, createSubmitResponsePayload(payloadOptions));\n if (!result.ok) {\n // Native declares this emitter but never calls it client-side \u2014 the\n // server's captureResponseError writes the event row for any request\n // that arrives (including HTTP failures), so the client emits ONLY for\n // network-level failures the server never sees; emitting on HTTP\n // errors too would double-count them (row 34: Reimplement).\n if (result.error.kind === \"network\") {\n pushEvents?.push({\n type: \"response_submission_error\",\n entityType: \"response\",\n entityId: formId,\n stepId: submittingOnStepId,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [{ key: \"error\", value: \"network\" }],\n });\n }\n emitter.emit(\"error\", { scope: \"submit\", error: result.error });\n return;\n }\n responseId = result.data.responseId;\n resumeToken = result.data.resumeToken;\n formJourney?.setResponseId(responseId);\n pushEvents?.push({\n type: \"response_submission_created\",\n entityType: \"response\",\n entityId: formId,\n stepId: submittingOnStepId,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [{ key: \"responseId\", value: responseId }],\n });\n } else if (isFinished) {\n // The terminal update is awaited (keepalive) so `submit()` resolving \u2014\n // and the `saved` event \u2014 mean the server actually has the finished\n // response; the beacon path let a fast page close silently keep a\n // partial. Partial-step updates below stay fire-and-forget: the\n // drop-off sweep reconciles those.\n const result = await updateResponseConfirmed(\n transport,\n createUpdateResponsePayload({ ...payloadOptions, responseId })\n );\n if (!result.ok) {\n updateResponse(transport, createUpdateResponsePayload({ ...payloadOptions, responseId }));\n emitter.emit(\"error\", { scope: \"submit\", error: result.error });\n return;\n }\n } else {\n updateResponse(transport, createUpdateResponsePayload({ ...payloadOptions, responseId }));\n }\n notify();\n emitter.emit(\"saved\", { responseId: responseId!, finished: isFinished, resumeToken });\n };\n\n // Serialization: every write-initiating operation (next/submit/savePartial)\n // runs through one queue \u2014 two concurrent operations would both observe a\n // null responseId and create separate response records. Native's UI\n // serializes this at the button; a headless engine must do it itself.\n // On top of the queue: a re-entrant next() joins the pending advance (a\n // double-click advances once, never skips a step), a re-entrant submit()\n // queues behind it and then finishes \u2014 submit intent is never silently\n // dropped \u2014 and queued operations re-check finished when they actually run,\n // so nothing writes after the finishing submit.\n let writeQueue: Promise<void> = Promise.resolve();\n const enqueueWrite = (task: () => Promise<void>): Promise<void> => {\n const run = writeQueue.then(() => (finished ? undefined : task()));\n writeQueue = run.catch(() => undefined);\n return run;\n };\n\n // States/meta ride every save \u2014 but the queue drops writes once finished,\n // so a mutation landing after the finishing write (enrichment or email\n // validation resolving post-submit; those requests never block submission)\n // would be silently unpersistable. Amend the stored response by re-issuing\n // the terminal update: full-answer-set resends are idempotent. Chained on\n // (and EXTENDING) the queue rather than checking responseId now \u2014 a result\n // landing while the terminal create is still in flight must amend after it\n // settles, and successive amends stay serialized so the last dispatch\n // carries every state. The responseId check happens inside the chain: a\n // failed terminal create must not be resurrected as a fresh response.\n const amendAfterFinish = () => {\n if (!finished || terminalWrite == null) return;\n const amend = terminalWrite;\n writeQueue = writeQueue\n .then(() => {\n if (responseId != null) return write(amend.stepId, true, amend.invalid);\n })\n .catch(() => undefined);\n };\n\n let pendingAdvance: Promise<void> | null = null;\n\n const advance = (submitting: boolean): Promise<void> => {\n if (finished) return Promise.resolve();\n if (pendingAdvance) {\n return submitting ? pendingAdvance.then(() => advance(true)) : pendingAdvance;\n }\n const tracked: Promise<void> = enqueueWrite(() => advanceNow(submitting)).finally(() => {\n if (pendingAdvance === tracked) pendingAdvance = null;\n });\n pendingAdvance = tracked;\n return tracked;\n };\n\n const rewindTo = (targetStepId: string) => {\n const from = currentStepId;\n while (history.length > 0 && currentStepId !== targetStepId) {\n currentStepId = history.pop()!;\n }\n notify();\n formJourney?.recordTransition({ fromStepId: from, toStepId: currentStepId, reason: \"back_nav\" });\n emitter.emit(\"stepChanged\", { fromStepId: from, toStepId: currentStepId });\n };\n\n const goToStep = (targetStepId: string): Promise<void> => {\n if (!steps.some((step) => step.id === targetStepId)) {\n return Promise.reject(new Error(`goToStep: no step with id \"${targetStepId}\"`));\n }\n if (finished) return Promise.resolve();\n if (pendingAdvance) {\n return pendingAdvance.then(() => goToStep(targetStepId));\n }\n if (targetStepId === currentStepId) return Promise.resolve();\n // Jumping to a step we already left is backward navigation \u2014 native's\n // back() semantics: rewind the history, never write.\n if (history.includes(targetStepId)) {\n rewindTo(targetStepId);\n return Promise.resolve();\n }\n const tracked: Promise<void> = enqueueWrite(async () => {\n if (targetStepId === currentStepId) return;\n emitter.emit(\"stepCompleted\", { stepId: currentStepId });\n // The customer's own condition chose this target \u2014 conditional_match is\n // the journey reason that describes routing decided outside the engine.\n await moveForwardNow({ stepId: targetStepId, reason: \"conditional_match\" });\n }).finally(() => {\n if (pendingAdvance === tracked) pendingAdvance = null;\n });\n pendingAdvance = tracked;\n return tracked;\n };\n\n const disqualify = (): Promise<void> => {\n if (finished) return Promise.resolve();\n if (pendingAdvance) {\n return pendingAdvance.then(() => disqualify());\n }\n const tracked: Promise<void> = enqueueWrite(() => finishNow(true)).finally(() => {\n if (pendingAdvance === tracked) pendingAdvance = null;\n });\n pendingAdvance = tracked;\n return tracked;\n };\n\n const moveForwardNow = async (target: ResolvedNextStep) => {\n const leavingStepId = currentStepId;\n pushEvents?.push(\n buildStepTransitionEventBatch({\n sessionId: currentIdentity().leadSessionId,\n formId,\n currentStepId: leavingStepId,\n nextStepId: target.stepId,\n stepCompletionTime: (Date.now() - createdAt) / 1000,\n })\n );\n formJourney?.recordTransition({\n fromStepId: leavingStepId,\n toStepId: target.stepId,\n reason: target.reason ?? \"linear\",\n });\n if (trackPartialResponses) await write(leavingStepId, false, false);\n history.push(leavingStepId);\n currentStepId = target.stepId;\n notify();\n emitter.emit(\"stepChanged\", { fromStepId: leavingStepId, toStepId: currentStepId });\n };\n\n // Finishing does not stay on the question step: like the native renderer,\n // which routes into its thank-you/disqualified screen after the terminal\n // write, the engine moves onto the record's matching ending step (if one\n // exists) so `data-step-id` containers reveal it \u2014 the 2026-08 field run\n // showed that a submit that silently stays put strands visitors on the last\n // question. Display-only: no write, just the step change.\n const revealEndingStep = (kind: \"thank_you\" | \"disqualified\") => {\n const ending = steps.find((step) => step.endStepKind === kind);\n if (!ending || ending.id === currentStepId) return;\n const from = currentStepId;\n history.push(from);\n currentStepId = ending.id;\n notify();\n emitter.emit(\"stepChanged\", { fromStepId: from, toStepId: currentStepId });\n };\n\n const finishNow = async (invalid: boolean) => {\n const leavingStepId = currentStepId;\n finished = true;\n terminalWrite = { stepId: leavingStepId, invalid };\n await write(leavingStepId, true, invalid);\n revealEndingStep(invalid ? \"disqualified\" : \"thank_you\");\n if (invalid) {\n formJourney?.recordTerminal({\n outcome: \"disqualified\",\n disqualification: { reason: \"conditional_match\", atStepId: leavingStepId },\n });\n emitter.emit(\"disqualified\", { stepId: leavingStepId });\n } else {\n formJourney?.recordTerminal({ outcome: \"completed\" });\n pushEvents?.push({\n type: \"form_completed\",\n entityType: \"form\",\n entityId: formId,\n stepId: null,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [],\n environmentId,\n leadId: currentIdentity().leadId,\n });\n emitter.emit(\"completed\", { formId });\n }\n notify();\n };\n\n const advanceNow = async (submitting: boolean) => {\n const resolved = resolve(currentStepId, answers);\n const isFinished = submitting || resolved === \"END\" || resolved === \"INVALID\" || resolved == null;\n\n emitter.emit(\"stepCompleted\", { stepId: currentStepId });\n\n if (!isFinished) {\n await moveForwardNow(resolved as ResolvedNextStep);\n return;\n }\n await finishNow(resolved === \"INVALID\");\n };\n\n return {\n setAnswer: (questionId, state) => {\n const stepState = (answers[currentStepId] ??= {});\n stepState[questionId] = { ...stepState[questionId], ...state };\n if (hasStarted(answers)) {\n pushEvents?.push({\n type: \"form_started\",\n entityType: \"form\",\n entityId: formId,\n stepId: null,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [],\n });\n emitter.emit(\"started\", { formId });\n }\n notify();\n },\n setExternalState: (id, state) => {\n externalStates[id] = state;\n notify();\n amendAfterFinish();\n },\n mergeMeta: (partial) => {\n // meta rides every write by reference, so a merge lands in the next\n // save automatically; after the finishing write it amends like a late\n // external state (email validation resolving as the visitor submits).\n Object.assign(meta, partial);\n amendAfterFinish();\n },\n next: () => advance(false),\n goToStep,\n submit: () => advance(true),\n disqualify,\n back: () => {\n const previous = history.pop();\n if (previous == null || finished) return;\n const from = currentStepId;\n currentStepId = previous;\n notify();\n formJourney?.recordTransition({ fromStepId: from, toStepId: previous, reason: \"back_nav\" });\n emitter.emit(\"stepChanged\", { fromStepId: from, toStepId: previous });\n },\n savePartial: () => {\n // Captured at call time: a save queued behind an in-flight advance must\n // stay attributed to the step the caller was on, not the destination.\n const submittingOnStepId = currentStepId;\n return enqueueWrite(() => write(submittingOnStepId, false, false));\n },\n // Reads the queue at call time (it grows via amendAfterFinish), so this\n // settles after everything already queued \u2014 including post-finish amends.\n flush: () => writeQueue.then(() => undefined),\n markViewed: () => {\n if (viewed) return;\n viewed = true;\n pushEvents?.push({\n type: \"form_viewed\",\n entityType: \"form\",\n entityId: formId,\n stepId: null,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [],\n environmentId,\n leadId: currentIdentity().leadId,\n });\n pushEvents?.push({\n type: \"form_step_viewed\",\n entityType: \"form_step\",\n entityId: formId,\n stepId: steps[0].id,\n leadSessionId: currentIdentity().leadSessionId,\n properties: [],\n });\n emitter.emit(\"viewed\", { formId });\n },\n on: emitter.on,\n state: () => {\n if (snapshotDirty) {\n snapshot = { currentStepId, answers, externalStates, responseId, resumeToken, finished };\n snapshotDirty = false;\n }\n return snapshot;\n },\n subscribe: (listener) => {\n storeListeners.add(listener);\n return () => storeListeners.delete(listener);\n },\n };\n};\n", "/**\n * Redirect handling (forms-sdk-plan.md rows 17/48), mirroring form-render's\n * `handleRedirect.ts`:\n *\n * - Identity handoff: `leadId` and `sessionId` are appended as query params so\n * the destination page's tag/SDK resolves the same visitor (row 17).\n * - Protocol default matches `addProtocolToUrl` verbatim, including its quirk:\n * the check is `startsWith(\"https\")`, so an explicit `http://` URL gets\n * double-prefixed. Replicated, not fixed \u2014 it's on the plan's\n * replicate-then-review list territory (Phase 0 item 5); the parity harness\n * compares against native.\n * - Unparseable URLs pass through unchanged, blank URLs redirect nowhere.\n * - `CurrentWindow` navigates `window.location` \u2014 the SDK runs first-party,\n * which is exactly what native's `window.parent.location` resolves to on a\n * top-level page. `NewTab` opens `_blank`.\n * - Preview never navigates (native gates on preview/editing screens).\n *\n * The step engine owns *when* to redirect (per-step + thank-you triggers and\n * the `redirectTimeout ?? 400 ms` delay \u2014 the default is exported here);\n * parent-param forwarding via `redirectUrlParams` templating lands with the\n * external-state store work (row 56).\n */\n\nexport type RedirectType = \"NewTab\" | \"CurrentWindow\";\n\nexport const DEFAULT_REDIRECT_TIMEOUT_MS = 400;\n\nconst addProtocolToUrl = (url: string, protocol = \"https\") => {\n if (!url) return url;\n if (url.startsWith(protocol)) return url;\n return `${protocol}://${url}`;\n};\n\nexport const buildRedirectUrl = (\n url: string,\n { leadId, sessionId }: { leadId?: string; sessionId?: string } = {}\n): string => {\n if (!url || !url.trim()) return \"\";\n try {\n const redirectUrl = new URL(addProtocolToUrl(url));\n if (leadId) redirectUrl.searchParams.set(\"leadId\", leadId);\n if (sessionId) redirectUrl.searchParams.set(\"sessionId\", sessionId);\n return redirectUrl.toString();\n } catch {\n return url;\n }\n};\n\nexport const performRedirect = ({\n url,\n redirectType = \"CurrentWindow\",\n leadId,\n sessionId,\n preview = false,\n}: {\n url: string;\n redirectType?: RedirectType;\n leadId?: string;\n sessionId?: string;\n preview?: boolean;\n}): void => {\n if (!url || preview) return;\n if (typeof window === \"undefined\") return;\n\n const redirectUrl = buildRedirectUrl(url, { leadId, sessionId });\n // Whitespace-only URLs build to \"\" \u2014 navigating there reloads the page\n // (CurrentWindow) or opens a blank tab (NewTab) instead of the documented no-op.\n if (!redirectUrl) return;\n if (redirectType === \"CurrentWindow\") {\n window.location.href = redirectUrl;\n } else if (redirectType === \"NewTab\") {\n window.open(redirectUrl, \"_blank\");\n }\n};\n", "/**\n * Attribution capture (forms-sdk-plan.md row 56): the `URL_DATA`\n * external-state entry that rides every response write and feeds UTM/source\n * attribution. Mirrors the URL-config branch of form-render's\n * `buildExternalStateStore` \u2014 same shape (`fullUrl`/`params`/`referrer`/\n * `cookies`, wire-validated against `ZURLData` in the contract test), same\n * `defaultUrl` precedence, same swallow-on-malformed behavior.\n *\n * One structural simplification the self-hosted model earns (plan \u00A74.1): the\n * SDK runs in the page it measures, so `fullUrl`/`referrer`/`cookies` are\n * read directly from `location`/`document` \u2014 native needs them relayed\n * through `?url=`/`?referrer=`/`?cookies=` query params by the tag, including\n * cookies as a JSON blob. Cookie capture stays gated by the same\n * `trackCookies` setting.\n */\n\nexport type UrlData = {\n type: \"URL_DATA\";\n fullUrl?: string;\n params?: Record<string, string>;\n referrer?: string;\n cookies?: Record<string, string>;\n};\n\nexport const constructUrlParamsObject = (url: string): Record<string, string> => {\n const urlObj = new URL(url);\n if (!urlObj.search) return {};\n const paramsObject: Record<string, string> = {};\n new URLSearchParams(urlObj.search).forEach((value, key) => {\n paramsObject[key] = value;\n });\n return paramsObject;\n};\n\nexport const parseCookiesObject = (cookieString: string): Record<string, string> => {\n const cookies: Record<string, string> = {};\n for (const cookie of cookieString.split(\";\")) {\n const trimmed = cookie.trim();\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex <= 0) continue;\n const value = trimmed.substring(eqIndex + 1);\n try {\n cookies[trimmed.substring(0, eqIndex)] = decodeURIComponent(value);\n } catch {\n cookies[trimmed.substring(0, eqIndex)] = value;\n }\n }\n return cookies;\n};\n\nexport const buildUrlData = ({\n defaultUrl,\n trackCookies = false,\n}: {\n /** Config-pinned URL that wins over the live page URL, like native. */\n defaultUrl?: string;\n trackCookies?: boolean;\n} = {}): UrlData => {\n const inBrowser = typeof window !== \"undefined\";\n\n const urlData: UrlData = {\n type: \"URL_DATA\",\n fullUrl: defaultUrl ?? (inBrowser ? window.location.href : undefined),\n referrer: inBrowser && typeof document !== \"undefined\" ? document.referrer || \"\" : undefined,\n };\n\n if (urlData.fullUrl) {\n try {\n urlData.params = constructUrlParamsObject(urlData.fullUrl);\n } catch {\n // malformed url \u2014 attribution params are best-effort, like native\n }\n }\n\n if (trackCookies) {\n urlData.cookies = inBrowser && typeof document !== \"undefined\" ? parseCookiesObject(document.cookie) : {};\n } else {\n urlData.cookies = {};\n }\n\n return urlData;\n};\n", "/**\n * URL prefill parsing (forms-sdk-plan.md row 19), same syntax as the native\n * runtime's `useFormUrlParameters`/`parseQuestionId`: any\n * `?<questionId>_<fieldName>=value` query param prefills a field. The param\n * name splits on the FIRST underscore (field names may contain more), both\n * sides are trimmed, `url`/`referrer`/`cookies` are reserved for attribution,\n * and params without an underscore are ignored (no field to target).\n */\n\nexport type ParsedUrlQuestionId = {\n originalId: string;\n questionId: string;\n fieldName: string;\n value: string;\n};\n\nexport const parseQuestionId = (input: string) => {\n const firstUnderscore = input.indexOf(\"_\");\n return {\n originalId: input,\n questionId: firstUnderscore >= 0 ? input.slice(0, firstUnderscore).trim() : input,\n fieldName: firstUnderscore >= 0 ? input.slice(firstUnderscore + 1).trim() : null,\n };\n};\n\nconst RESERVED_PARAMS = new Set([\"url\", \"referrer\", \"cookies\"]);\n\nexport const parsePrefillParams = (\n search: string | URLSearchParams\n): Record<string, ParsedUrlQuestionId[]> | null => {\n const params = typeof search === \"string\" ? new URLSearchParams(search) : search;\n\n let questionIds: Record<string, ParsedUrlQuestionId[]> | null = null;\n // Iterating keys() + get() is native behavior: a repeated param name yields\n // one entry per occurrence, each carrying the FIRST value.\n for (const id of params.keys()) {\n if (RESERVED_PARAMS.has(id)) continue;\n\n const { originalId, questionId, fieldName } = parseQuestionId(id);\n if (fieldName == null) continue;\n\n const prefill = { originalId, questionId, fieldName, value: params.get(id)! };\n // Null prototype: a question id like \"constructor\" must read as absent,\n // not as an inherited function (native shares this crash \u2014 not replicated,\n // a throw here would break the host page, which the SDK never may).\n questionIds ??= Object.create(null) as Record<string, ParsedUrlQuestionId[]>;\n questionIds[questionId] = [...(questionIds[questionId] ?? []), prefill];\n }\n\n return questionIds;\n};\n", "import type { PushEventClient } from \"./pushEvents\";\n\n/**\n * `form_step_dropoff` beacon (forms-sdk-plan.md row 32), form-render's\n * `useBeforeUnload` semantics without React: on `pagehide` \u2014 the only\n * teardown event that still delivers beacons reliably \u2014 emit the drop-off\n * event for the step the visitor abandoned, but only after the form was\n * started and never for bfcache suspensions (`event.persisted`), which are\n * not abandonment.\n *\n * State is read through a getter at fire time because the current step and\n * session change after the listener attaches (native reads refs for the same\n * reason). Delivery rides the pushEvent client, whose transport is\n * sendBeacon-first \u2014 the property that makes a pagehide send survivable.\n */\nexport const observeDropoff = (\n pushEventClient: PushEventClient,\n getState: () => {\n started: boolean;\n formId: string;\n stepId: string;\n sessionId?: string;\n }\n): (() => void) => {\n if (typeof window === \"undefined\") return () => undefined;\n\n const handlePageHide = (event: PageTransitionEvent) => {\n const { started, formId, stepId, sessionId } = getState();\n if (!started || event.persisted) return;\n pushEventClient.push({\n type: \"form_step_dropoff\",\n entityType: \"form_step\",\n entityId: formId,\n stepId,\n leadSessionId: sessionId,\n properties: [],\n });\n };\n\n window.addEventListener(\"pagehide\", handlePageHide);\n return () => window.removeEventListener(\"pagehide\", handlePageHide);\n};\n", "import type { Transport } from \"../client/transport\";\n\n/**\n * Form-journey step telemetry (forms-sdk-plan.md row 30): visits, transitions,\n * and outcomes beaconed to `POST /api/v1/form-journey/track`. A direct port of\n * form-render's `createFormJourneyTracker` \u2014 same ordinal bookkeeping, same\n * close-previous-visit timing, same 50-visit cap with `truncated`, same\n * freeze-on-terminal-outcome, same microtask coalescing (a transition\n * immediately followed by a terminal sends one beacon, so an in-progress\n * write can't race the disqualified one), and the same synchronous flush for\n * the `in_progress` terminal, which only fires from pagehide and cannot\n * depend on a microtask racing page teardown.\n *\n * Wire types are local structural mirrors of the Zod schemas in\n * `@surface/types/v1/formJourney` (zero-runtime-deps); the contract test\n * validates them against the real `ZFormJourneyTrackPayload`. The\n * `transitionMeta`/`matched` payloads are typed opaque here \u2014 they are\n * constructed by routing evaluation, which lands with the routing extraction,\n * and the tracker only passes them through.\n */\n\nexport type FormJourneyOutcome = \"in_progress\" | \"completed\" | \"partial\" | \"disqualified\" | \"dropped_off\";\n\nexport type FormJourneyTransitionReason =\n | \"initial\"\n | \"linear\"\n | \"conditional_match\"\n | \"default_fallback\"\n | \"prefill_jump\"\n | \"back_nav\"\n | \"auto_skip\";\n\nexport type FormJourneyVisit = {\n ordinal: number;\n stepId: string;\n enteredAt: string;\n exitedAt?: string | null;\n durationMs?: number | null;\n fromStepId?: string | null;\n transitionReason: FormJourneyTransitionReason;\n transitionMeta?: unknown;\n};\n\nexport type FormJourneyTrackPayload = {\n responseId: string;\n formId: string;\n outcome?: FormJourneyOutcome;\n disqualification?: { reason: \"conditional_match\" | \"default_fallback\"; matched?: unknown } | null;\n disqualifiedAtStepId?: string | null;\n disqualifiedTriggerStepId?: string | null;\n events: FormJourneyVisit[];\n};\n\nexport interface FormJourneyTracker {\n recordEntry: (stepId: string) => void;\n recordTransition: (args: {\n fromStepId: string;\n toStepId: string;\n reason: FormJourneyTransitionReason;\n transitionMeta?: unknown;\n }) => void;\n recordTerminal: (args: {\n outcome: FormJourneyOutcome;\n disqualification?: {\n reason: \"conditional_match\" | \"default_fallback\";\n atStepId: string;\n triggerStepId?: string;\n matched?: unknown;\n };\n }) => void;\n setResponseId: (responseId: string) => void;\n setFormId: (formId: string) => void;\n hasRecordedTransition: () => boolean;\n}\n\nconst TRACK_PATH = \"/api/v1/form-journey/track\";\n\n// Mirrors FORM_JOURNEY_MAX_VISITS server-side; duplicated like form-render does\n// to keep server imports out of the client bundle.\nconst MAX_VISITS = 50;\n\nconst TERMINAL_OUTCOMES: ReadonlySet<FormJourneyOutcome> = new Set([\n \"completed\",\n \"disqualified\",\n \"dropped_off\",\n \"partial\",\n]);\n\ntype TrackerInternal = {\n responseId: string | null;\n formId: string | null;\n nextOrdinal: number;\n // Keyed by ordinal so back-nav revisits don't overwrite the prior enter time.\n enteredAt: Map<number, string>;\n pendingClose: { ordinal: number; stepId: string } | null;\n // Kept across flushes so closePrevious can update exitedAt/durationMs in place.\n // Server merge is idempotent on ordinal.\n visits: FormJourneyVisit[];\n truncated: boolean;\n terminal: Pick<\n FormJourneyTrackPayload,\n \"outcome\" | \"disqualification\" | \"disqualifiedAtStepId\" | \"disqualifiedTriggerStepId\"\n >;\n frozen: boolean;\n flushScheduled: boolean;\n};\n\nexport const createFormJourneyTracker = ({\n transport,\n preview = false,\n}: {\n transport: Transport;\n preview?: boolean;\n}): FormJourneyTracker => {\n const state: TrackerInternal = {\n responseId: null,\n formId: null,\n nextOrdinal: 1,\n enteredAt: new Map(),\n pendingClose: null,\n visits: [],\n truncated: false,\n terminal: {},\n frozen: false,\n flushScheduled: false,\n };\n\n const flushNow = () => {\n state.flushScheduled = false;\n if (preview) return;\n if (!state.responseId || !state.formId) return;\n if (state.visits.length === 0 && !state.terminal.outcome) return;\n transport.beacon(TRACK_PATH, {\n responseId: state.responseId,\n formId: state.formId,\n events: state.visits,\n ...state.terminal,\n } satisfies FormJourneyTrackPayload);\n state.terminal = {};\n };\n\n const flush = () => {\n if (state.flushScheduled) return;\n state.flushScheduled = true;\n queueMicrotask(() => {\n if (state.flushScheduled) flushNow();\n });\n };\n\n const closePrevious = (nowIso: string) => {\n if (!state.pendingClose) return;\n const { ordinal, stepId } = state.pendingClose;\n const entered = state.enteredAt.get(ordinal);\n const existing = state.visits.find((visit) => visit.ordinal === ordinal);\n const durationMs = entered ? Date.parse(nowIso) - Date.parse(entered) : null;\n if (existing) {\n existing.exitedAt = nowIso;\n existing.durationMs = durationMs;\n } else {\n state.visits.push({\n ordinal,\n stepId,\n enteredAt: entered ?? nowIso,\n exitedAt: nowIso,\n durationMs,\n fromStepId: null,\n transitionReason: \"initial\",\n });\n }\n state.pendingClose = null;\n };\n\n const pushVisit = (visit: FormJourneyVisit) => {\n if (state.visits.length >= MAX_VISITS) {\n state.truncated = true;\n return false;\n }\n state.visits.push(visit);\n return true;\n };\n\n return {\n hasRecordedTransition: () => state.nextOrdinal > 1,\n setResponseId: (id) => {\n state.responseId = id;\n flush();\n },\n setFormId: (id) => {\n state.formId = id;\n flush();\n },\n recordEntry: (stepId) => {\n if (state.frozen || state.truncated) return;\n const now = new Date().toISOString();\n if (state.nextOrdinal === 1) {\n state.enteredAt.set(1, now);\n state.pendingClose = { ordinal: 1, stepId };\n state.nextOrdinal = 2;\n }\n },\n recordTransition: ({ fromStepId, toStepId, reason, transitionMeta }) => {\n if (state.frozen || state.truncated) return;\n const now = new Date().toISOString();\n closePrevious(now);\n const ordinal = state.nextOrdinal++;\n state.enteredAt.set(ordinal, now);\n const pushed = pushVisit({\n ordinal,\n stepId: toStepId,\n enteredAt: now,\n exitedAt: null,\n durationMs: null,\n fromStepId,\n transitionReason: reason,\n transitionMeta: transitionMeta ?? null,\n });\n state.pendingClose = pushed ? { ordinal, stepId: toStepId } : null;\n flush();\n },\n recordTerminal: ({ outcome, disqualification }) => {\n if (state.frozen) return;\n const now = new Date().toISOString();\n closePrevious(now);\n state.terminal = {\n outcome,\n disqualification: disqualification\n ? { reason: disqualification.reason, matched: disqualification.matched }\n : undefined,\n disqualifiedAtStepId: disqualification?.atStepId,\n disqualifiedTriggerStepId: disqualification?.triggerStepId,\n };\n if (TERMINAL_OUTCOMES.has(outcome)) state.frozen = true;\n if (outcome === \"in_progress\") flushNow();\n else flush();\n },\n };\n};\n", "/**\n * Canonical browser-fingerprint implementation for Surface lead identity.\n *\n * The lead-identity pipeline keys on the SHA-256 of `JSON.stringify` over the\n * collected fields, so the object's insertion order, value shapes, and falsy\n * fallbacks (`||`, not `??`) ARE the wire contract: any deviation produces a\n * different hash and splits one visitor into two leads. Do not reorder fields,\n * rename keys, or change fallback behavior here without a coordinated\n * migration.\n *\n * This module supersedes the two byte-identical copies it was lifted from \u2014\n * `packages/form-render/src/lib/client/leads/browserFingerprint.ts` and the\n * public tag's `src/lead/fingerprint.ts` (trysurface/scripts) \u2014 which consume\n * it over time (forms-sdk-plan.md, parity row 9). The identity test in this\n * directory pins hash equality against the form-render copy.\n */\n\ntype NavigatorUaData = {\n brands?: Array<{ brand: string; version: string }>;\n uaList?: Array<{ brand: string; version: string }>;\n platform?: string;\n};\n\nexport type Fingerprint = {\n deviceType: \"Mobile\" | \"Desktop\";\n screen: {\n width: number;\n height: number;\n colorDepth: number;\n };\n userAgent: string;\n browser: Array<{ brand: string; version: string }>;\n os: string;\n language: string;\n /** Absent (never null/empty) when `navigator.plugins` is null. */\n plugins?: string[];\n timezone: string;\n environmentId: string;\n /** SHA-256 hex of the serialized fields above. */\n id: string;\n};\n\nexport async function getHash(input: string): Promise<string> {\n const data = new TextEncoder().encode(input);\n const hashBuffer = await crypto.subtle.digest(\"SHA-256\", data);\n return Array.from(new Uint8Array(hashBuffer))\n .map((b) => b.toString(16).padStart(2, \"0\"))\n .join(\"\");\n}\n\nexport const getBrowserFingerprint = async (environmentId: string): Promise<Fingerprint> => {\n // userAgentData is Chromium-only; `uaList` is the legacy pre-spec field name.\n const userAgentData: NavigatorUaData =\n (navigator as { userAgentData?: NavigatorUaData }).userAgentData || {};\n\n const fields: Omit<Fingerprint, \"id\"> = {\n deviceType: /Mobi|Android/i.test(navigator.userAgent) ? \"Mobile\" : \"Desktop\",\n screen: {\n width: screen.width,\n height: screen.height,\n colorDepth: screen.colorDepth,\n },\n userAgent: navigator.userAgent,\n browser: userAgentData.brands || userAgentData.uaList || [{ brand: \"unknown\", version: \"unknown\" }],\n os: userAgentData.platform || \"unknown\",\n language: navigator.language,\n ...(navigator.plugins != null\n ? { plugins: Array.from(navigator.plugins).map((plugin) => plugin.name) }\n : {}),\n timezone: Intl.DateTimeFormat().resolvedOptions().timeZone,\n environmentId,\n };\n\n return { ...fields, id: await getHash(JSON.stringify(fields)) };\n};\n", "import type { Transport } from \"../client/transport\";\n\n/**\n * Wrapper for `POST /api/v1/lead/identify` (forms-sdk-plan.md row 10),\n * mirroring form-render's `identifyLeadForFormRequest`: same payload fields,\n * same URL normalization (trailing slashes stripped from href and pathname),\n * same keepalive delivery, same `data.data` response unwrap, null on any\n * failure. The wire types are structural mirrors of `ZLeadIdentifyPayload`\n * (`@surface/types/v1/lead/app/types.ts`) \u2014 local because the SDK ships with\n * zero runtime dependencies; the contract test validates them against the\n * real schema.\n *\n * `source` defaults to `\"sdkForm\"` \u2014 the dedicated SDK value (Decisions #8),\n * so SDK-originated leads stay distinguishable from the native runtime's\n * `\"surfaceForm\"` in the leads hub and analytics.\n */\n\nexport type LeadSource =\n | \"surfaceForm\"\n | \"htmlForm\"\n | \"websiteDeAnon\"\n | \"webhook\"\n | \"website\"\n | \"imported\"\n | \"scheduler\"\n | \"linkedin\"\n | \"sdkForm\";\n\nexport type IdentifyPayload = {\n environmentId: string;\n source: LeadSource;\n sourceURL: string;\n sourceURLDomain: string;\n sourceURLPath: string;\n sourceUrlSearchParams: string;\n leadId?: string | null;\n formId?: string;\n fingerprint?: string;\n sessionIdFromParams?: string | null;\n referrer?: string | null;\n};\n\nexport type IdentifyResult = {\n leadId: string;\n sessionId: string;\n existing: boolean;\n leadHasExistingBookingAttr: boolean;\n leadHasExistingEmailAttr: boolean;\n};\n\nconst IDENTIFY_PATH = \"/api/v1/lead/identify\";\n\nexport const buildIdentifyPayload = ({\n environmentId,\n fingerprintId,\n pageUrl,\n source = \"sdkForm\",\n formId,\n leadId = null,\n sessionIdFromParams = null,\n referrer,\n}: {\n environmentId: string;\n fingerprintId: string;\n pageUrl: string;\n source?: LeadSource;\n formId?: string;\n leadId?: string | null;\n sessionIdFromParams?: string | null;\n referrer?: string | null;\n}): IdentifyPayload => {\n const url = new URL(pageUrl);\n return {\n environmentId,\n source,\n sourceURL: url.href.replace(/\\/$/, \"\"),\n sourceURLDomain: url.hostname,\n sourceURLPath: url.pathname.replace(/\\/$/, \"\"),\n sourceUrlSearchParams: url.search,\n fingerprint: fingerprintId,\n formId,\n leadId,\n sessionIdFromParams,\n ...(referrer != null ? { referrer } : {}),\n };\n};\n\ntype IdentifyApiResponse = { data?: { data?: IdentifyResult } };\n\nexport const identifyLead = async (\n transport: Transport,\n payload: IdentifyPayload\n): Promise<IdentifyResult | null> => {\n const result = await transport.post<IdentifyApiResponse>(IDENTIFY_PATH, payload, {\n keepalive: true,\n credentials: true,\n });\n if (!result.ok) return null;\n const data = result.data.data?.data;\n if (!data?.leadId || !data?.sessionId) return null;\n return {\n leadId: data.leadId,\n sessionId: data.sessionId,\n existing: data.existing,\n leadHasExistingBookingAttr: data.leadHasExistingBookingAttr,\n leadHasExistingEmailAttr: data.leadHasExistingEmailAttr,\n };\n};\n", "/**\n * TTL-stamped lead-identity cache (forms-sdk-plan.md row 11), byte-compatible\n * with the public tag's `surfaceLeadData` localStorage entry \u2014 same key, same\n * shape, same 10-minute TTL, same remove-on-expiry read semantics\n * (trysurface/scripts `src/lead/identify.ts`).\n *\n * Sharing the tag's key IS the interop rule (plan \u00A74.1): on a page where the\n * tag is also installed, the SDK reads the identity the tag already resolved\n * and skips its own identify \u2014 and vice versa \u2014 so both agree on the visitor\n * without any cross-component protocol.\n *\n * Every access is guarded: no localStorage (SSR) reads as a cache miss, and\n * storage exceptions (Safari private mode, quota) are swallowed \u2014 cache loss\n * only costs an extra identify round-trip.\n */\n\nexport const LEAD_DATA_STORAGE_KEY = \"surfaceLeadData\";\nexport const LEAD_DATA_TTL_MS = 10 * 60 * 1000;\n\nexport type CachedLeadData = {\n leadId: string | null;\n leadSessionId: string | null;\n fingerprint: string;\n landingPageUrl?: string;\n expiry?: number;\n};\n\nexport const readLeadData = (): CachedLeadData | null => {\n if (typeof localStorage === \"undefined\") return null;\n try {\n const raw = localStorage.getItem(LEAD_DATA_STORAGE_KEY);\n if (!raw) return null;\n const item = JSON.parse(raw) as CachedLeadData;\n if (Date.now() > (item.expiry ?? 0)) {\n localStorage.removeItem(LEAD_DATA_STORAGE_KEY);\n return null;\n }\n return {\n leadId: item.leadId,\n leadSessionId: item.leadSessionId,\n fingerprint: item.fingerprint,\n landingPageUrl: item.landingPageUrl,\n expiry: item.expiry,\n };\n } catch {\n return null;\n }\n};\n\nexport const writeLeadData = (data: Omit<CachedLeadData, \"expiry\">): void => {\n if (typeof localStorage === \"undefined\") return;\n try {\n localStorage.setItem(\n LEAD_DATA_STORAGE_KEY,\n JSON.stringify({ ...data, expiry: Date.now() + LEAD_DATA_TTL_MS })\n );\n } catch {\n // swallow \u2014 cache loss only costs an extra identify\n }\n};\n", "import type { Transport } from \"../client/transport\";\nimport { getBrowserFingerprint } from \"./browserFingerprint\";\nimport { buildIdentifyPayload, identifyLead, type LeadSource } from \"./identify\";\nimport { readLeadData, writeLeadData, type CachedLeadData } from \"./leadDataCache\";\n\n/**\n * The boot-sequence identity step (forms-sdk-plan.md \u00A72.2): resolve the\n * visitor before any response write, since attribute sync silently no-ops for\n * responses whose lead was never identified (row 60). Mirrors the tag's\n * `identifyLead` flow: a fresh cache entry with a session and fingerprint\n * skips the network entirely; otherwise compute the fingerprint, carry any\n * cached leadId/session forward so the server can preserve identity, and\n * cache the result under the shared tag key.\n *\n * `preview: true` blocks the identify call outright \u2014 the preview contract\n * (\u00A72.2) is that drafts never create leads. Concurrent calls (multi-form\n * pages) may race one identify each; that is safe \u2014 the server find-or-creates\n * by fingerprint, so both resolve to the same lead \u2014 and avoids the tag's\n * module-level in-flight flag, which the SDK's instance-scoped rule forbids.\n */\nexport const ensureIdentified = async ({\n transport,\n environmentId,\n formId,\n pageUrl,\n source,\n preview = false,\n}: {\n transport: Transport;\n environmentId: string;\n formId?: string;\n pageUrl?: string;\n source?: LeadSource;\n preview?: boolean;\n}): Promise<CachedLeadData | null> => {\n if (preview) return null;\n if (typeof window === \"undefined\") return null;\n\n const cached = readLeadData();\n if (cached?.leadSessionId && cached?.fingerprint) {\n return cached;\n }\n\n const landingPageUrl = pageUrl ?? window.location.href;\n const fingerprint = await getBrowserFingerprint(environmentId);\n const result = await identifyLead(\n transport,\n buildIdentifyPayload({\n environmentId,\n fingerprintId: fingerprint.id,\n pageUrl: landingPageUrl,\n formId,\n source,\n leadId: cached?.leadId ?? null,\n sessionIdFromParams: cached?.leadSessionId ?? null,\n })\n );\n if (result == null) return null;\n\n const leadData: Omit<CachedLeadData, \"expiry\"> = {\n leadId: result.leadId,\n leadSessionId: result.sessionId,\n fingerprint: fingerprint.id,\n landingPageUrl,\n };\n writeLeadData(leadData);\n return leadData;\n};\n", "import type { Transport } from \"../client/transport\";\nimport { readLeadData } from \"./leadDataCache\";\n\n/**\n * Opt-in user-journey page-view tracking (forms-sdk-plan.md row 16), the\n * SDK's `journey: true` module. Mirrors the public tag's implementation\n * (trysurface/scripts `src/store/{user-journey,journey-cookies}.ts`, verified\n * at HEAD): same cookies (`surface_journey_id`, 60 d, eTLD+1 domain;\n * `surface_recent_visit`, 1 d), same duplicate-URL skip, same delivery split \u2014\n * beacon when the journey id is already known (nothing to read back), fetch\n * when it isn't so the server-issued id can be captured \u2014 and the same\n * history-patching SPA route detection.\n *\n * Journey\u2192response stitching stays server-side (UTM backfill on response\n * create); the client's only job is delivering page views under a stable id.\n */\n\nexport const JOURNEY_COOKIE_NAME = \"surface_journey_id\";\nexport const RECENT_VISIT_COOKIE_NAME = \"surface_recent_visit\";\nconst JOURNEY_COOKIE_MAX_AGE = 5184000; // 60 days\nconst RECENT_VISIT_COOKIE_MAX_AGE = 86400; // 1 day\nconst TRACK_PATH = \"/api/v1/lead/track\";\n\nconst getCookie = (name: string): string | null => {\n if (typeof document === \"undefined\") return null;\n for (const cookie of document.cookie.split(\";\")) {\n const trimmed = cookie.trim();\n const eqIndex = trimmed.indexOf(\"=\");\n if (eqIndex === -1) continue;\n if (trimmed.substring(0, eqIndex) !== name) continue;\n const value = trimmed.substring(eqIndex + 1);\n try {\n return decodeURIComponent(value);\n } catch {\n return value;\n }\n }\n return null;\n};\n\nconst setCookie = (name: string, value: string, maxAge: number, domain: string | undefined): void => {\n if (typeof document === \"undefined\") return;\n const domainAttr = domain ? `; domain=${domain}` : \"\";\n document.cookie = `${name}=${encodeURIComponent(\n value\n )}; path=/; max-age=${maxAge}; samesite=lax${domainAttr}`;\n};\n\n/** Naive eTLD+1 like the tag: everything after the first label, or the bare two-label host. */\nconst getJourneyCookieDomain = (): string | undefined => {\n const hostname = typeof window === \"undefined\" ? \"\" : window.location?.hostname ?? \"\";\n if (!hostname || !hostname.includes(\".\")) return undefined;\n const parts = hostname.split(\".\");\n return \".\" + (parts.length === 2 ? hostname : parts.slice(1).join(\".\"));\n};\n\ntype JourneyTrackPayload = {\n id?: string;\n data: {\n type: \"page_view\";\n payload: { url: string; timestamp: string; referrer?: string };\n };\n metadata?: {\n environmentId?: string;\n leadId?: string;\n leadSessionId?: string;\n fingerprint?: string;\n landingPageUrl?: string;\n };\n};\n\nexport type JourneyTracker = {\n trackPageView: (url?: string) => Promise<void>;\n /** Patches history + popstate; returns a teardown restoring the originals. */\n observeRouteChanges: () => () => void;\n /** Deletes both journey cookies \u2014 the native clear-on-first-step-completion hook. */\n clear: () => void;\n};\n\nexport const createJourneyTracker = ({\n transport,\n environmentId,\n}: {\n transport: Transport;\n environmentId: string;\n}): JourneyTracker => {\n let journeyId = getCookie(JOURNEY_COOKIE_NAME);\n\n const refreshJourneyCookie = () => {\n if (!journeyId) return;\n setCookie(JOURNEY_COOKIE_NAME, journeyId, JOURNEY_COOKIE_MAX_AGE, getJourneyCookieDomain());\n };\n\n const buildPayload = (url: string): JourneyTrackPayload => {\n const leadData = readLeadData();\n return {\n ...(journeyId ? { id: journeyId } : {}),\n data: {\n type: \"page_view\",\n payload: {\n url,\n timestamp: new Date().toISOString(),\n referrer: typeof document === \"undefined\" ? \"\" : document.referrer || \"\",\n },\n },\n metadata: {\n environmentId,\n ...(leadData\n ? {\n ...(leadData.leadId ? { leadId: leadData.leadId } : {}),\n ...(leadData.leadSessionId ? { leadSessionId: leadData.leadSessionId } : {}),\n fingerprint: leadData.fingerprint,\n ...(leadData.landingPageUrl ? { landingPageUrl: leadData.landingPageUrl } : {}),\n }\n : {}),\n },\n };\n };\n\n const trackPageView = async (url?: string) => {\n if (typeof window === \"undefined\") return;\n const pageUrl = url ?? window.location.href;\n if (getCookie(RECENT_VISIT_COOKIE_NAME) === pageUrl) return;\n\n const payload = buildPayload(pageUrl);\n if (journeyId && transport.beacon(TRACK_PATH, payload)) {\n refreshJourneyCookie();\n } else {\n const result = await transport.post<{ data?: { id?: string } }>(TRACK_PATH, payload);\n if (result.ok && result.data.data?.id) {\n journeyId = result.data.data.id;\n }\n refreshJourneyCookie();\n }\n\n setCookie(RECENT_VISIT_COOKIE_NAME, pageUrl, RECENT_VISIT_COOKIE_MAX_AGE, getJourneyCookieDomain());\n };\n\n const observeRouteChanges = () => {\n if (typeof window === \"undefined\") return () => undefined;\n\n let currentUrl = window.location.href;\n const notify = () => {\n const newUrl = window.location.href;\n if (newUrl === currentUrl) return;\n currentUrl = newUrl;\n void trackPageView(newUrl);\n };\n\n window.addEventListener(\"popstate\", notify);\n const originalPushState = history.pushState;\n const originalReplaceState = history.replaceState;\n history.pushState = function (...args) {\n originalPushState.apply(history, args);\n setTimeout(notify, 0);\n };\n history.replaceState = function (...args) {\n originalReplaceState.apply(history, args);\n setTimeout(notify, 0);\n };\n\n return () => {\n window.removeEventListener(\"popstate\", notify);\n history.pushState = originalPushState;\n history.replaceState = originalReplaceState;\n };\n };\n\n const clear = () => {\n const domain = getJourneyCookieDomain();\n const domainAttr = domain ? `; domain=${domain}` : \"\";\n if (typeof document === \"undefined\") return;\n document.cookie = `${JOURNEY_COOKIE_NAME}=; path=/; max-age=0; samesite=lax${domainAttr}`;\n document.cookie = `${RECENT_VISIT_COOKIE_NAME}=; path=/; max-age=0; samesite=lax${domainAttr}`;\n journeyId = null;\n };\n\n return { trackPageView, observeRouteChanges, clear };\n};\n", "import type { Transport } from \"../core/client/transport\";\nimport type { FormEngine } from \"../core/engine/formEngine\";\n\n/**\n * Real-time identity enrichment for SDK forms (field-run finding 4.10): the\n * native renderer fires `/api/v1/services/enrichment/realtime` on blur of the\n * IdentityInfo `enrichmentSourceField` (or `websiteUrl`, or EmailForm's email)\n * and stores the result as the `selfServeEnrichment` APOLLO_EMAIL_ENRICHMENT\n * external state \u2014 which the response payload forwards as `enrichedFields`\n * and which drives field autofill. The SDK has no blur moment (headless\n * callers have no DOM at all), so the trigger is a debounced answer-watch: a\n * candidate value that is a valid email/domain and has been stable for\n * `DEBOUNCE_MS` fires once (deduped per value, native semantics); completing\n * a step flushes the pending debounce so a type-then-advance never loses the\n * window. The request is never awaited \u2014 submission must not block on the\n * vendor API \u2014 so a result can resolve after the finishing write; the engine\n * persists it anyway by amending the stored response on setExternalState.\n * Results merge existing-keys-win, exactly like native's G2 rule \u2014 a later\n * trigger only fills gaps.\n *\n * The provider key never reaches the page: the endpoint resolves it\n * server-side and is rate-limited per-IP and per-form.\n */\n\nexport type EnrichmentSource = { questionId: string; fieldNames: string[] };\n\nconst ENRICHMENT_PATH = \"/api/v1/services/enrichment/realtime\";\nexport const ENRICHMENT_STATE_ID = \"selfServeEnrichment\";\nconst DEBOUNCE_MS = 1000;\n\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/;\nconst DOMAIN_PATTERN = /^(?:https?:\\/\\/)?(?:www\\.)?([a-z0-9-]+(?:\\.[a-z0-9-]+)+)/i;\n\nconst enrichmentInputOf = (value: string): { email?: string; domain?: string } | null => {\n const trimmed = value.trim();\n if (EMAIL_PATTERN.test(trimmed)) return { email: trimmed };\n const domain = trimmed.match(DOMAIN_PATTERN)?.[1];\n return domain ? { domain } : null;\n};\n\nexport type AttachEnrichmentOptions = {\n engine: FormEngine;\n transport: Transport;\n formId: string;\n sources: EnrichmentSource[];\n};\n\nexport const attachEnrichment = ({\n engine,\n transport,\n formId,\n sources,\n}: AttachEnrichmentOptions): (() => void) => {\n const processed = new Set<string>();\n const inFlight = new Set<string>();\n let pendingTimer: ReturnType<typeof setTimeout> | undefined;\n let pendingValue: string | undefined;\n let detached = false;\n\n const fire = async (value: string) => {\n const input = enrichmentInputOf(value);\n if (!input) return;\n const key = input.email ?? input.domain!;\n if (processed.has(key) || inFlight.has(key)) return;\n inFlight.add(key);\n try {\n const result = await transport.post<{ data?: Record<string, unknown> }>(ENRICHMENT_PATH, {\n formId,\n ...input,\n });\n if (detached || !result.ok) return;\n const data = result.data.data ?? {};\n if (Object.keys(data).length === 0) return;\n processed.add(key);\n const existing = engine.state().externalStates[ENRICHMENT_STATE_ID];\n const existingData =\n existing?.type === \"APOLLO_EMAIL_ENRICHMENT\"\n ? (existing.data as Record<string, unknown> | undefined) ?? {}\n : {};\n engine.setExternalState(ENRICHMENT_STATE_ID, {\n type: \"APOLLO_EMAIL_ENRICHMENT\",\n processed: true,\n // existing keys win: a later trigger (e.g. a website after the email)\n // only fills gaps, never overwrites resolved fields.\n data: { ...data, ...existingData },\n });\n } finally {\n inFlight.delete(key);\n }\n };\n\n const candidateValues = (): string[] => {\n const values: string[] = [];\n const flat: Record<string, Record<string, unknown>> = {};\n for (const stepAnswers of Object.values(engine.state().answers)) Object.assign(flat, stepAnswers);\n for (const { questionId, fieldNames } of sources) {\n const state = flat[questionId];\n if (!state) continue;\n for (const fieldName of fieldNames) {\n const value = state[fieldName];\n if (typeof value === \"string\" && value.trim().length > 0) values.push(value);\n }\n }\n return values;\n };\n\n const scheduleLatest = () => {\n const latest = candidateValues().find((value) => {\n const input = enrichmentInputOf(value);\n return input != null && !processed.has(input.email ?? input.domain!);\n });\n if (latest === undefined || latest === pendingValue) return;\n pendingValue = latest;\n clearTimeout(pendingTimer);\n pendingTimer = setTimeout(() => {\n pendingValue = undefined;\n void fire(latest);\n }, DEBOUNCE_MS);\n };\n\n const flushPending = () => {\n if (pendingValue === undefined) return;\n clearTimeout(pendingTimer);\n const value = pendingValue;\n pendingValue = undefined;\n void fire(value);\n };\n\n const teardowns = [\n engine.subscribe(scheduleLatest),\n engine.on(\"stepCompleted\", flushPending),\n engine.on(\"completed\", flushPending),\n ];\n return () => {\n detached = true;\n clearTimeout(pendingTimer);\n teardowns.forEach((teardown) => teardown());\n };\n};\n", "/**\n * `init({ debug: true })` answer auditing: the bind layer always produces\n * valid shapes, but headless `setAnswer` callers are one label-string away\n * from the ingest 400 that static gates cannot see (2026-08 field run). The\n * auditor checks only facts that cannot false-positive \u2014 unknown questionId,\n * wrong `type` discriminator, a merged state with no `type` at all, and a\n * choice-list answer whose `choices` is not an array \u2014 and logs every\n * captured answer so a session is replayable from the console.\n */\n\nconst CHOICE_LIST_TYPES = new Set([\"MultipleOptionsQuestion\", \"MultipleChoiceQuestion\", \"MMChoiceQuestion\"]);\n\n// The wire entry shape: {key: string, value: boolean}, plus index for MOQ.\n// Deterministic, so a malformed entry (a bare label string, a missing index)\n// is warnable without false positives.\nconst isValidChoiceEntry = (entry: unknown, needsIndex: boolean): boolean =>\n typeof entry === \"object\" &&\n entry !== null &&\n typeof (entry as { key?: unknown }).key === \"string\" &&\n typeof (entry as { value?: unknown }).value === \"boolean\" &&\n (!needsIndex || typeof (entry as { index?: unknown }).index === \"number\");\n\nexport type AuditedQuestion = { questionId: string; componentType?: string };\n\nexport const auditAnswer = ({\n questions,\n questionId,\n merged,\n}: {\n /** Stateful questions of the record; empty when the record wasn't fetched (caller-provided steps). */\n questions: Map<string, AuditedQuestion>;\n questionId: string;\n /** The post-merge state (setAnswer patches accumulate per question). */\n merged: Record<string, unknown>;\n}): void => {\n const prefix = `Surface SDK [debug]: setAnswer(\"${questionId}\")`;\n const expected = questions.size > 0 ? questions.get(questionId) : undefined;\n if (questions.size > 0 && !expected) {\n console.warn(`${prefix} \u2014 the record has no stateful question with this id; the answer will be dropped.`);\n // Shape checks are meaningless for a question that doesn't exist, but the\n // audit trail still records what was sent.\n console.debug(`Surface SDK [debug]: answer ${questionId}`, merged);\n return;\n }\n if (merged.type === undefined) {\n console.warn(\n `${prefix} \u2014 state has no \"type\" discriminator; the wire schema rejects untyped states. Include type: \"${\n expected?.componentType ?? \"<ComponentType>\"\n }\".`\n );\n } else if (expected?.componentType !== undefined && merged.type !== expected.componentType) {\n console.warn(\n `${prefix} \u2014 state type \"${String(merged.type)}\" but the record's component is ${\n expected.componentType\n }.`\n );\n }\n const effectiveType = expected?.componentType ?? merged.type;\n if (typeof effectiveType === \"string\" && CHOICE_LIST_TYPES.has(effectiveType)) {\n const needsIndex = effectiveType === \"MultipleOptionsQuestion\";\n const malformed =\n !Array.isArray(merged.choices) ||\n merged.choices.some((entry) => !isValidChoiceEntry(entry, needsIndex));\n if (malformed) {\n console.warn(\n `${prefix} \u2014 ${effectiveType} answers need the ENTIRE option list under \"choices\" as {key, value${\n needsIndex ? \", index\" : \"\"\n }} objects, not ${JSON.stringify(merged.choices ?? merged)}. See get_sdk_binding_map's answerShape.`\n );\n }\n }\n console.debug(`Surface SDK [debug]: answer ${questionId}`, merged);\n};\n", "/**\n * Ad-conversion rule engine (forms-sdk-plan.md row 55): a dependency-free port\n * of form-render's `adConversions/{evaluateRules,fireConversion}.ts` and the\n * `ZAdConversionRule` settings schema. The SDK always runs first-party, so the\n * native parent-page/postMessage/ack hop disappears \u2014 matching rules fire\n * directly on this window. Rule semantics, provider payloads, and the\n * `responseId` dedupe key are identical by construction; the contract test\n * validates these local types against the real Zod schema.\n */\n\nexport type AdConversionProvider = \"x\" | \"meta\" | \"openai\" | \"ga4\" | \"linkedin\";\n\nexport type AdConversionTrigger =\n | \"reached_qualified\"\n | \"form_submitted\"\n | \"reached_step\"\n | \"form_started\"\n | \"step_submitted\"\n | \"email_provided\"\n | \"meeting_booked\";\n\nexport type AdConversionCondition = {\n param: string;\n operator: \"equals_any\" | \"contains\" | \"is_present\";\n values?: string[];\n};\n\nexport type AdConversionRule = {\n id: string;\n provider: AdConversionProvider;\n trigger?: AdConversionTrigger;\n triggerStepId?: string;\n enabled?: boolean;\n conditionsOperator?: \"and\" | \"or\";\n conditions?: AdConversionCondition[];\n eventId?: string;\n pixelId?: string;\n measurementId?: string;\n eventName?: string;\n partnerId?: string;\n conversionId?: string;\n};\n\nexport type TrackingParams = Record<string, string>;\n\nexport type ConversionClickIds = {\n twclid?: string;\n fbclid?: string;\n gclid?: string;\n li_fat_id?: string;\n};\n\nexport type FireContext = { responseId: string; email?: string } & ConversionClickIds;\n\nexport type ConversionEvent =\n | { provider: \"x\"; event: { event_id: string; pixel_id: string } }\n | { provider: \"meta\"; event: { pixel_id: string; event_name: string } }\n | { provider: \"openai\"; event: { pixel_id: string; event_name: string } }\n | { provider: \"ga4\"; event: { measurement_id: string; event_name: string } }\n | { provider: \"linkedin\"; event: { partner_id: string; conversion_id: string } };\n\nexport const DEFAULT_META_EVENT_NAME = \"Lead\";\nexport const DEFAULT_GA4_EVENT_NAME = \"generate_lead\";\nexport const DEFAULT_OPENAI_EVENT_NAME = \"lead_created\";\n\nconst X_EVENT_ID_REGEX = /^tw-([a-z0-9]+)-([a-z0-9]+)$/i;\n\nconst parseXPixelId = (eventId: string | undefined): string | null => {\n const match = eventId?.trim().match(X_EVENT_ID_REGEX);\n return match ? match[1] : null;\n};\n\nconst isNumericId = (value: string | undefined): boolean => /^\\d+$/.test(value?.trim() ?? \"\");\n\nconst isRuleFireable = (rule: AdConversionRule): boolean => {\n if (rule.enabled === false) return false;\n if ((rule.trigger ?? \"reached_qualified\") === \"reached_step\" && !rule.triggerStepId?.trim()) return false;\n switch (rule.provider) {\n case \"x\":\n return X_EVENT_ID_REGEX.test(rule.eventId?.trim() ?? \"\");\n case \"meta\":\n case \"openai\":\n return !!rule.pixelId?.trim();\n case \"ga4\":\n return !!rule.measurementId?.trim();\n case \"linkedin\":\n return isNumericId(rule.partnerId) && isNumericId(rule.conversionId);\n default:\n return false;\n }\n};\n\n// Case-insensitive on both name and value \u2014 parent pages capitalize UTMs\n// inconsistently (`utm_source=Twitter`), same as the native matcher.\nconst getParamValue = (params: TrackingParams, name: string): string | undefined => {\n const lowerName = name.toLowerCase();\n for (const [key, value] of Object.entries(params)) {\n if (key.toLowerCase() === lowerName) return value;\n }\n return undefined;\n};\n\nexport const matchesCondition = (condition: AdConversionCondition, params: TrackingParams): boolean => {\n const value = getParamValue(params, condition.param)?.trim() ?? \"\";\n const values = condition.values ?? [];\n switch (condition.operator) {\n case \"is_present\":\n return value.length > 0;\n case \"equals_any\":\n return values.some((v) => v.trim().toLowerCase() === value.toLowerCase());\n case \"contains\":\n return value.length > 0 && values.some((v) => value.toLowerCase().includes(v.trim().toLowerCase()));\n default:\n return false;\n }\n};\n\nexport const matchesConditions = (\n conditions: AdConversionCondition[],\n params: TrackingParams,\n operator: \"and\" | \"or\" = \"and\"\n): boolean => {\n if (conditions.length === 0) return true;\n return operator === \"or\"\n ? conditions.some((c) => matchesCondition(c, params))\n : conditions.every((c) => matchesCondition(c, params));\n};\n\nexport const ruleToConversionEvent = (rule: AdConversionRule): ConversionEvent | null => {\n if (!isRuleFireable(rule)) return null;\n switch (rule.provider) {\n case \"x\": {\n const pixelId = parseXPixelId(rule.eventId);\n if (!pixelId) return null;\n return { provider: \"x\", event: { event_id: rule.eventId!.trim(), pixel_id: pixelId } };\n }\n case \"meta\":\n return {\n provider: \"meta\",\n event: {\n pixel_id: rule.pixelId!.trim(),\n event_name: rule.eventName?.trim() || DEFAULT_META_EVENT_NAME,\n },\n };\n case \"openai\":\n return {\n provider: \"openai\",\n event: {\n pixel_id: rule.pixelId!.trim(),\n event_name: rule.eventName?.trim() || DEFAULT_OPENAI_EVENT_NAME,\n },\n };\n case \"ga4\":\n return {\n provider: \"ga4\",\n event: {\n measurement_id: rule.measurementId!.trim(),\n event_name: rule.eventName?.trim() || DEFAULT_GA4_EVENT_NAME,\n },\n };\n case \"linkedin\":\n return {\n provider: \"linkedin\",\n event: { partner_id: rule.partnerId!.trim(), conversion_id: rule.conversionId!.trim() },\n };\n default:\n return null;\n }\n};\n\n/** Rules firing for this trigger given the page's tracking params; `reached_step` also needs the step id to match. */\nexport const selectFiringEvents = (\n rules: AdConversionRule[],\n trigger: AdConversionTrigger,\n params: TrackingParams,\n stepId?: string\n): { rule: AdConversionRule; conversion: ConversionEvent }[] => {\n const results: { rule: AdConversionRule; conversion: ConversionEvent }[] = [];\n for (const rule of rules) {\n if ((rule.trigger ?? \"reached_qualified\") !== trigger) continue;\n if (trigger === \"reached_step\" && (!stepId || rule.triggerStepId !== stepId)) continue;\n if (!matchesConditions(rule.conditions ?? [], params, rule.conditionsOperator ?? \"and\")) continue;\n const conversion = ruleToConversionEvent(rule);\n if (conversion) results.push({ rule, conversion });\n }\n return results;\n};\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyWindow = Window & Record<string, any>;\n\n// Vendor bootstrap snippets, run only when the global isn't already present \u2014\n// customers often already run their own pixel; never double-inject. Verbatim\n// ports of fireConversion.ts:17-101 (which itself mirrors the parent tag).\nconst ensureTwq = (win: AnyWindow, pixelId: string) => {\n if (!win.twq) {\n const s: any = (win.twq = function (...args: any[]) {\n s.exe ? s.exe.apply(s, args) : s.queue.push(args);\n });\n s.version = \"1.1\";\n s.queue = [];\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = \"https://static.ads-twitter.com/uwt.js\";\n win.document.head.appendChild(el);\n }\n win.twq(\"config\", pixelId);\n};\n\nconst ensureFbq = (win: AnyWindow, pixelId: string) => {\n if (!win.fbq) {\n const n: any = (win.fbq = function (...args: any[]) {\n n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args);\n });\n if (!win._fbq) win._fbq = n;\n n.push = n;\n n.loaded = true;\n n.version = \"2.0\";\n n.queue = [];\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = \"https://connect.facebook.net/en_US/fbevents.js\";\n win.document.head.appendChild(el);\n }\n win.fbq(\"init\", pixelId);\n};\n\nconst ensureOaiq = (win: AnyWindow, pixelId: string) => {\n if (!win.oaiq) {\n const q: any = (win.oaiq = function (...args: any[]) {\n (q.q as any[]).push(args);\n });\n q.q = [];\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = \"https://bzrcdn.openai.com/sdk/oaiq.min.js\";\n win.document.head.appendChild(el);\n }\n win.oaiq(\"init\", { pixelId });\n};\n\nconst ensureGtag = (win: AnyWindow, measurementId: string) => {\n if (!win.gtag) {\n win.dataLayer = win.dataLayer || [];\n win.gtag = function (...args: any[]) {\n (win.dataLayer as any[]).push(args);\n };\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(measurementId)}`;\n win.document.head.appendChild(el);\n win.gtag(\"js\", new Date());\n }\n // Register our measurement ID even when the page already runs gtag; idempotent,\n // send_page_view off so registering never counts a phantom page view.\n win.gtag(\"config\", measurementId, { send_page_view: false });\n};\n\nconst ensureLintrk = (win: AnyWindow, partnerId: string) => {\n if (!win.lintrk) {\n win._linkedin_partner_id = partnerId;\n const l: any = (win.lintrk = function (a: any, b: any) {\n l.q.push([a, b]);\n });\n l.q = [];\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = \"https://snap.licdn.com/li.lms-analytics/insight.min.js\";\n win.document.head.appendChild(el);\n }\n win._linkedin_data_partner_ids = win._linkedin_data_partner_ids || [];\n if (!win._linkedin_data_partner_ids.includes(partnerId)) {\n win._linkedin_data_partner_ids.push(partnerId);\n }\n};\n\n/** Fire one conversion on this window. Best-effort: silent under ad blockers, never throws into the form. */\nexport const fireConversion = (win: Window, conversion: ConversionEvent, ctx: FireContext): boolean => {\n const w = win as AnyWindow;\n try {\n switch (conversion.provider) {\n case \"x\": {\n ensureTwq(w, conversion.event.pixel_id);\n w.twq(\"event\", conversion.event.event_id, {\n conversion_id: ctx.responseId,\n ...(ctx.twclid ? { twclid: ctx.twclid } : {}),\n ...(ctx.email ? { email_address: ctx.email } : {}),\n });\n return true;\n }\n case \"meta\": {\n ensureFbq(w, conversion.event.pixel_id);\n w.fbq(\"track\", conversion.event.event_name, {}, { eventID: ctx.responseId });\n return true;\n }\n case \"openai\": {\n ensureOaiq(w, conversion.event.pixel_id);\n w.oaiq(\n \"measure\",\n conversion.event.event_name,\n { type: \"customer_action\" },\n { event_id: ctx.responseId }\n );\n return true;\n }\n case \"ga4\": {\n ensureGtag(w, conversion.event.measurement_id);\n w.gtag(\"event\", conversion.event.event_name, {\n transaction_id: ctx.responseId,\n send_to: conversion.event.measurement_id,\n });\n return true;\n }\n case \"linkedin\": {\n ensureLintrk(w, conversion.event.partner_id);\n w.lintrk(\"track\", { conversion_id: conversion.event.conversion_id });\n return true;\n }\n default:\n return false;\n }\n } catch {\n return false;\n }\n};\n", "/**\n * Customer-tag bootstrap + lifecycle emission (forms-sdk-plan.md rows 51\u201354,\n * 58): GTM container, GA4, Meta Pixel, and HubSpot from the form's settings,\n * with the same don't-double-inject guards as the native runtime and the\n * parent tag. No React, no react-gtm-module / react-facebook-pixel \u2014 direct\n * global bootstraps like the parent tag's providers.\n *\n * Three native quirks are FIXED here by decision (2026-08-10, memory +\n * plan rows 51\u201352) \u2014 the parity harness whitelists them as intentional diffs:\n * - GTM `SurfaceFormSubmitEvent` carries `formId` (native omits it).\n * - `stepId` in `SurfaceFormStepSubmitted` is the real step id (native sends\n * the step *name*) \u2014 migration note for name-keyed GTM triggers.\n * - GA4 config does NOT hardcode `debug_mode: true`.\n */\n\n/* eslint-disable @typescript-eslint/no-explicit-any */\ntype AnyWindow = Window & Record<string, any>;\n\nexport type LifecycleUrlData = { url: string; urlParams: Record<string, string> };\n\nexport type VendorSettings = {\n gtmId?: string;\n gaMeasurementId?: string;\n metaPixelId?: string;\n hubspotTracking?: { trackingId?: string };\n};\n\nconst scriptPresent = (win: AnyWindow, src: string) =>\n win.document.querySelector(`script[src=\"${src}\"]`) != null;\n\nconst injectScriptOnce = (win: AnyWindow, src: string, parent: \"head\" | \"body\", id?: string) => {\n if (scriptPresent(win, src)) return;\n const el = win.document.createElement(\"script\");\n el.async = true;\n el.src = src;\n if (id) el.id = id;\n win.document[parent].appendChild(el);\n};\n\n// The standard GTM loader (what react-gtm-module emits), minus the noscript\n// iframe \u2014 an SDK page without JS never booted the SDK either. The whole\n// bootstrap (loader push AND script) is keyed on the container script's\n// presence: a second form instance \u2014 or a page already running the same\n// container \u2014 must not push another `gtm.js` event, which would re-fire any\n// trigger keyed on it.\nconst initGtm = (win: AnyWindow, gtmId: string) => {\n const src = `https://www.googletagmanager.com/gtm.js?id=${encodeURIComponent(gtmId)}`;\n if (scriptPresent(win, src)) return;\n win.dataLayer = win.dataLayer || [];\n win.dataLayer.push({ \"gtm.start\": new Date().getTime(), event: \"gtm.js\" });\n injectScriptOnce(win, src, \"head\");\n};\n\nconst initGa4 = (win: AnyWindow, measurementId: string) => {\n const src = `https://www.googletagmanager.com/gtag/js?id=${encodeURIComponent(measurementId)}`;\n // `config` without send_page_view sends an automatic page_view, so it must\n // run once per measurement id per page: a repeat from a second form\n // instance \u2014 or on top of the page's own tag \u2014 double-counts page views.\n // (fireConversion's ensureGtag re-configs freely; it sets send_page_view: false.)\n if (scriptPresent(win, src)) return;\n win.dataLayer = win.dataLayer || [];\n if (!win.gtag) {\n // Must push `arguments` objects (not rest arrays) \u2014 gtag.js expects them.\n win.gtag = function () {\n // eslint-disable-next-line prefer-rest-params\n win.dataLayer.push(arguments);\n };\n win.gtag(\"js\", new Date());\n }\n injectScriptOnce(win, src, \"head\");\n const isEmbeddedInIframe = win.self !== win.top;\n // Quirk fix: no `debug_mode: true` (native hardcodes it). Partitioned-cookie\n // flags kept for iframe embeds, same as native.\n win.gtag(\"config\", measurementId, {\n ...(isEmbeddedInIframe && { cookie_flags: \"SameSite=None;Secure;Partitioned\" }),\n });\n};\n\nconst initMetaPixel = (win: AnyWindow, pixelId: string) => {\n if (!win.fbq) {\n const n: any = (win.fbq = function (...args: any[]) {\n n.callMethod ? n.callMethod.apply(n, args) : n.queue.push(args);\n });\n if (!win._fbq) win._fbq = n;\n n.push = n;\n n.loaded = true;\n n.version = \"2.0\";\n n.queue = [];\n injectScriptOnce(win, \"https://connect.facebook.net/en_US/fbevents.js\", \"head\");\n }\n win.fbq(\"init\", pixelId);\n};\n\nconst initHubspot = (win: AnyWindow, trackingId: string) => {\n injectScriptOnce(win, `https://js.hs-scripts.com/${trackingId}.js`, \"body\", \"hs-script-loader\");\n};\n\nexport type StepSubmittedPayload = LifecycleUrlData & {\n /** Quirk fix: the real step id \u2014 native sends the step name here. */\n stepId: string;\n formId: string;\n // Pushed on every step including when false: GTM's data model is cumulative,\n // so omitting a false flag leaves the previous step's `true` standing.\n emailProvided: boolean;\n meetingBooked: boolean;\n};\n\n/**\n * One instance per SurfaceForms.init (no module-level singletons \u2014 \u00A72.7):\n * injects the configured vendors immediately, exposes the three lifecycle\n * emitters with native event names/payload keys (they are customers' GTM\n * trigger contracts).\n */\nexport const createVendorTracker = (win: Window, settings: VendorSettings) => {\n const w = win as AnyWindow;\n if (settings.gtmId) initGtm(w, settings.gtmId);\n if (settings.gaMeasurementId) initGa4(w, settings.gaMeasurementId);\n if (settings.metaPixelId) initMetaPixel(w, settings.metaPixelId);\n if (settings.hubspotTracking?.trackingId) initHubspot(w, settings.hubspotTracking.trackingId);\n\n const dataLayerPush = (event: Record<string, unknown>) => {\n if (!settings.gtmId) return;\n w.dataLayer = w.dataLayer || [];\n w.dataLayer.push(event);\n };\n const gtagEvent = (name: string, params: Record<string, unknown>) => {\n if (!settings.gaMeasurementId) return;\n w.gtag?.(\"event\", name, params);\n };\n const fbqTrackCustom = (name: string, data: Record<string, unknown>) => {\n if (!settings.metaPixelId) return;\n w.fbq?.(\"trackCustom\", name, data);\n };\n\n return {\n formStarted: (formId: string, urlData: LifecycleUrlData) => {\n dataLayerPush({ event: \"SurfaceFormStarted\", formId, ...urlData });\n fbqTrackCustom(\"SurfaceFormStarted\", { formId, ...urlData });\n gtagEvent(\"SurfaceFormStarted\", { formId, ...urlData });\n },\n stepSubmitted: (payload: StepSubmittedPayload) => {\n dataLayerPush({ event: \"SurfaceFormStepSubmitted\", ...payload });\n fbqTrackCustom(\"SurfaceFormStepSubmitted\", payload);\n gtagEvent(\"SurfaceFormStepSubmitted\", payload);\n },\n formCompleted: (formId: string, urlData: LifecycleUrlData) => {\n // Quirk fix: native's SurfaceFormSubmitEvent omits formId; the SDK sends it.\n dataLayerPush({ event: \"SurfaceFormSubmitEvent\", formId, ...urlData });\n fbqTrackCustom(\"SurfaceFormCompleted\", { formId, ...urlData });\n gtagEvent(\"SurfaceFormCompleted\", { formId, ...urlData });\n },\n };\n};\n\nexport type VendorTracker = ReturnType<typeof createVendorTracker>;\n", "import type { FormEngine } from \"../core/engine/formEngine\";\nimport {\n fireConversion,\n selectFiringEvents,\n type AdConversionRule,\n type AdConversionTrigger,\n type ConversionClickIds,\n type TrackingParams,\n} from \"./conversionRules\";\nimport { createVendorTracker, type LifecycleUrlData, type VendorSettings } from \"./vendors\";\n\n/**\n * Phase-2 tracking runtime (forms-sdk-plan.md rows 51\u201355): binds one engine\n * instance to the customer-tag lifecycle events and the ad-conversion rule\n * engine. Trigger moments mirror `useConversionRules`' semantics translated\n * from React effects to engine events:\n *\n * - `form_started`: the response row landing (first `saved`) in a session that\n * began without a responseId \u2014 a resume never refires.\n * - `step_submitted`: the first `stepCompleted` of the session.\n * - `reached_step`: every step that becomes current (including the initial\n * one), once per step \u2014 back-nav never refires.\n * - terminal (`reached_qualified` + `form_submitted` union, deduped by rule):\n * the `completed` event; a disqualified finish never fires.\n * - `email_provided` / `meeting_booked`: first non-empty email answer / first\n * scheduler state with `eventScheduled` \u2014 detected via `subscribe`.\n *\n * Every rule fires once per instance; `responseId` stays the platform-side\n * dedupe key, so moments reached before the first write queue and flush when\n * `saved` delivers the id (native's pending-refs, minus the React plumbing).\n * All state is instance-scoped (\u00A72.7) \u2014 two forms on one page track separately.\n */\n\nexport type TrackingSettings = VendorSettings & { adsConversions?: AdConversionRule[] };\n\nexport type AttachTrackingOptions = {\n engine: FormEngine;\n formId: string;\n settings: TrackingSettings;\n win?: Window;\n};\n\nconst parseLocationParams = (win: Window): TrackingParams => {\n try {\n return Object.fromEntries(new URLSearchParams(win.location.search).entries());\n } catch {\n return {};\n }\n};\n\nconst getParam = (params: TrackingParams, name: string): string | undefined => {\n const lower = name.toLowerCase();\n for (const [key, value] of Object.entries(params)) {\n if (key.toLowerCase() === lower) return value?.trim() || undefined;\n }\n return undefined;\n};\n\nconst pickClickIds = (params: TrackingParams): ConversionClickIds => ({\n twclid: getParam(params, \"twclid\"),\n fbclid: getParam(params, \"fbclid\"),\n gclid: getParam(params, \"gclid\"),\n li_fat_id: getParam(params, \"li_fat_id\"),\n});\n\nconst EMAIL_ANSWER_KEYS = [\"email\", \"emailAddress\", \"workEmailAddress\"] as const;\n\n// The SDK's answer states are the wire states themselves, so email/meeting\n// detection reads them directly (native goes through the lead-attribute\n// extractor over its richer client state).\nconst findEmail = (answers: Record<string, Record<string, unknown>>): string | undefined => {\n for (const state of Object.values(answers)) {\n for (const key of EMAIL_ANSWER_KEYS) {\n const value = state[key];\n if (typeof value === \"string\" && value.trim().length > 0) return value.trim();\n }\n }\n return undefined;\n};\n\nconst hasBookedMeeting = (answers: Record<string, Record<string, unknown>>): boolean =>\n Object.values(answers).some((state) => state.eventScheduled === true);\n\nconst flatAnswers = (engine: FormEngine): Record<string, Record<string, unknown>> => {\n const flat: Record<string, Record<string, unknown>> = {};\n for (const stepAnswers of Object.values(engine.state().answers)) {\n Object.assign(flat, stepAnswers);\n }\n return flat;\n};\n\nexport const attachTracking = ({ engine, formId, settings, win }: AttachTrackingOptions): (() => void) => {\n const w = win ?? window;\n const tracker = createVendorTracker(w, settings);\n const rules = settings.adsConversions ?? [];\n const params = parseLocationParams(w);\n const urlData: LifecycleUrlData = { url: w.location.href, urlParams: params };\n\n const firedRuleIds = new Set<string>();\n const processedStepIds = new Set<string>();\n const pendingStepIds = new Set<string>();\n const pendingEventTriggers = new Set<AdConversionTrigger>();\n let pendingTerminal = false;\n let firedTerminal = false;\n let firedStepSubmitted = false;\n let firedEmail = false;\n let firedMeeting = false;\n // A session that attaches with a responseId already set is a resume \u2014 its\n // form_started / step_submitted / email / meeting moments already happened.\n const freshSession = engine.state().responseId == null;\n let firedStarted = !freshSession;\n\n const fire = (selected: ReturnType<typeof selectFiringEvents>, responseId: string) => {\n const fresh = selected.filter(({ rule }) => !firedRuleIds.has(rule.id));\n if (fresh.length === 0) return;\n fresh.forEach(({ rule }) => firedRuleIds.add(rule.id));\n const ctx = { responseId, email: findEmail(flatAnswers(engine)), ...pickClickIds(params) };\n fresh.forEach(({ conversion }) => fireConversion(w, conversion, ctx));\n };\n\n const fireTrigger = (trigger: AdConversionTrigger, responseId: string | null) => {\n if (!responseId) {\n pendingEventTriggers.add(trigger);\n return;\n }\n fire(selectFiringEvents(rules, trigger, params), responseId);\n };\n\n const fireStep = (stepId: string, responseId: string | null) => {\n if (!responseId) {\n pendingStepIds.add(stepId);\n return;\n }\n fire(selectFiringEvents(rules, \"reached_step\", params, stepId), responseId);\n };\n\n // Reaching the non-disqualified terminal step is the submission in Surface,\n // so both triggers resolve at the same moment \u2014 union, deduped by rule.\n const fireTerminal = (responseId: string | null) => {\n if (!responseId) {\n pendingTerminal = true;\n return;\n }\n firedTerminal = true;\n pendingTerminal = false;\n const byRule = new Map<string, ReturnType<typeof selectFiringEvents>[number]>();\n for (const trigger of [\"reached_qualified\", \"form_submitted\"] as const) {\n for (const hit of selectFiringEvents(rules, trigger, params)) {\n byRule.set(hit.rule.id, hit);\n }\n }\n fire(Array.from(byRule.values()), responseId);\n };\n\n const detectAnswerMoments = () => {\n const answers = flatAnswers(engine);\n if (!firedEmail && freshSession && findEmail(answers) !== undefined) {\n firedEmail = true;\n fireTrigger(\"email_provided\", engine.state().responseId);\n }\n if (!firedMeeting && freshSession && hasBookedMeeting(answers)) {\n firedMeeting = true;\n fireTrigger(\"meeting_booked\", engine.state().responseId);\n }\n };\n\n const teardowns: Array<() => void> = [];\n\n teardowns.push(\n engine.on(\"started\", () => {\n tracker.formStarted(formId, urlData);\n })\n );\n\n // Native fires the vendor SurfaceFormStepSubmitted only when the completion\n // ADVANCES to another step \u2014 the finishing step emits SurfaceFormSubmitEvent\n // alone (verified against /s in the layer-2 harness). Buffer the payload and\n // flush on the following stepChanged; `completed` discards it (the ending\n // reveal's stepChanged arrives after `completed`, so it cannot flush).\n let pendingStepSubmitted: Parameters<typeof tracker.stepSubmitted>[0] | undefined;\n\n teardowns.push(\n engine.on(\"stepCompleted\", ({ stepId }) => {\n const answers = flatAnswers(engine);\n pendingStepSubmitted = {\n stepId,\n formId,\n emailProvided: findEmail(answers) !== undefined,\n meetingBooked: hasBookedMeeting(answers),\n ...urlData,\n };\n if (!firedStepSubmitted && freshSession) {\n firedStepSubmitted = true;\n fireTrigger(\"step_submitted\", engine.state().responseId);\n }\n })\n );\n\n teardowns.push(\n engine.on(\"stepChanged\", ({ toStepId }) => {\n if (pendingStepSubmitted) {\n // The reveal of a thank-you/disqualified ending step is a stepChanged\n // AFTER the finishing write \u2014 native's finishing step emits\n // SubmitEvent only, never StepSubmitted, so the buffer is discarded\n // there instead of flushed.\n if (!engine.state().finished) tracker.stepSubmitted(pendingStepSubmitted);\n pendingStepSubmitted = undefined;\n }\n if (processedStepIds.has(toStepId)) return;\n processedStepIds.add(toStepId);\n fireStep(toStepId, engine.state().responseId);\n })\n );\n\n teardowns.push(\n engine.on(\"completed\", () => {\n pendingStepSubmitted = undefined;\n tracker.formCompleted(formId, urlData);\n if (!firedTerminal) fireTerminal(engine.state().responseId);\n })\n );\n\n // form_started (conversion trigger): the response row lands with the first\n // saved \u2014 also the flush point for every moment reached before the id existed.\n teardowns.push(\n engine.on(\"saved\", ({ responseId }) => {\n if (!firedStarted) {\n firedStarted = true;\n fireTrigger(\"form_started\", responseId);\n }\n if (pendingTerminal) fireTerminal(responseId);\n if (pendingStepIds.size > 0) {\n const stepIds = Array.from(pendingStepIds);\n pendingStepIds.clear();\n stepIds.forEach((stepId) => fireStep(stepId, responseId));\n }\n if (pendingEventTriggers.size > 0) {\n const triggers = Array.from(pendingEventTriggers);\n pendingEventTriggers.clear();\n triggers.forEach((trigger) => fireTrigger(trigger, responseId));\n }\n })\n );\n\n teardowns.push(engine.subscribe(detectAnswerMoments));\n\n // The initial step counts as reached (native processes the mounted step).\n const initialStepId = engine.state().currentStepId;\n processedStepIds.add(initialStepId);\n fireStep(initialStepId, engine.state().responseId);\n detectAnswerMoments();\n\n return () => teardowns.forEach((teardown) => teardown());\n};\n", "import type { EmailValidationResult, EmailValidator } from \"../core/client/emailValidation\";\nimport type { FormEngine } from \"../core/engine/formEngine\";\n\n/**\n * Automatic waterfall email validation for SDK forms (forms-sdk-plan.md row\n * 37): the native renderer validates emails referenced by \"is valid email\"\n * routing conditions and annotates the response `meta` with the verdict. SDK\n * records carry no routing conditions \u2014 navigation is customer-owned \u2014 so\n * this module watches the email-bearing answer keys directly (same set the\n * tracking module reads) and writes the SAME meta keys native writes\n * (`isEmailValid`, `emailValidation`, `emailValidationFailed`), keeping SDK\n * responses indistinguishable to dashboards and workflows.\n *\n * Trigger mirrors native's debounce (300ms) instead of blur \u2014 headless\n * callers have no DOM; completing a step (or the form) flushes the pending\n * window. Verdicts are per-email sticky via the shared validator cache, so a\n * customer's own `validateEmail` calls and this watcher never double-bill an\n * address. Aggregation is native's: `isEmailValid` is true when ANY watched\n * email is valid (fail-open verdicts count as valid), `emailValidation`\n * carries the first detailed verdict, `emailValidationFailed` marks that a\n * validator could not run.\n */\n\nconst DEBOUNCE_MS = 300;\nconst EMAIL_ANSWER_KEYS = [\"email\", \"emailAddress\", \"workEmailAddress\"] as const;\nconst EMAIL_PATTERN = /^[^\\s@]+@[^\\s@]+\\.[^\\s@]{2,}$/;\n\nexport type AttachEmailValidationOptions = {\n engine: FormEngine;\n validator: EmailValidator;\n};\n\nexport const attachEmailValidation = ({ engine, validator }: AttachEmailValidationOptions): (() => void) => {\n const requested = new Set<string>();\n const results = new Map<string, EmailValidationResult>();\n let pendingTimer: ReturnType<typeof setTimeout> | undefined;\n let pendingScheduled = false;\n let lastMetaKey: string | undefined;\n let detached = false;\n\n const candidateEmails = (): string[] => {\n const emails: string[] = [];\n for (const stepAnswers of Object.values(engine.state().answers)) {\n for (const state of Object.values(stepAnswers)) {\n for (const key of EMAIL_ANSWER_KEYS) {\n const value = (state as Record<string, unknown>)[key];\n if (typeof value === \"string\" && EMAIL_PATTERN.test(value.trim())) emails.push(value.trim());\n }\n }\n }\n return emails;\n };\n\n const writeMeta = () => {\n // Aggregate ONLY currently-present emails \u2014 native rebuilds its verdict\n // set from the live answers each cycle, so a replaced address's verdict\n // must stop describing the response. The verdict cache stays (sticky\n // per-address billing); only the aggregation window follows the answers.\n const current = new Set(candidateEmails());\n const verdicts = [...results.values()].filter((verdict) => current.has(verdict.email));\n if (verdicts.length === 0) return;\n const metaKey = JSON.stringify(verdicts.map((v) => [v.email, v.isValid, v.failed === true]));\n if (metaKey === lastMetaKey) return;\n lastMetaKey = metaKey;\n // Native aggregation: fail-open verdicts (isValid: true, failed) count as\n // valid; the first detailed verdict rides `emailValidation`.\n const detailed = verdicts.find((verdict) => verdict.status && verdict.reason);\n engine.mergeMeta({\n isEmailValid: verdicts.some((verdict) => verdict.isValid),\n emailValidation: detailed\n ? {\n status: detailed.status,\n reason: detailed.reason,\n ...(detailed.blacklistEntryIds?.length && { blacklistEntryIds: detailed.blacklistEntryIds }),\n }\n : undefined,\n emailValidationFailed: verdicts.some((verdict) => verdict.failed === true),\n });\n };\n\n const fire = async () => {\n const fresh = candidateEmails().filter((email) => !requested.has(email));\n if (fresh.length === 0) return;\n fresh.forEach((email) => requested.add(email));\n const verdicts = await validator.validateBatch(fresh);\n if (detached) return;\n verdicts.forEach((verdict) => results.set(verdict.email, verdict));\n writeMeta();\n };\n\n const scheduleLatest = () => {\n if (!candidateEmails().some((email) => !requested.has(email))) {\n // No unvalidated address \u2014 but the visitor may have switched back to an\n // already-verdicted one, so the aggregation window must still follow.\n writeMeta();\n return;\n }\n pendingScheduled = true;\n clearTimeout(pendingTimer);\n pendingTimer = setTimeout(() => {\n pendingScheduled = false;\n void fire();\n }, DEBOUNCE_MS);\n };\n\n const flushPending = () => {\n if (!pendingScheduled) return;\n pendingScheduled = false;\n clearTimeout(pendingTimer);\n void fire();\n };\n\n const teardowns = [\n engine.subscribe(scheduleLatest),\n engine.on(\"stepCompleted\", flushPending),\n engine.on(\"completed\", flushPending),\n ];\n return () => {\n detached = true;\n clearTimeout(pendingTimer);\n teardowns.forEach((teardown) => teardown());\n };\n};\n", "import { bindForm } from \"./bind/bindForm\";\nimport { createEmailValidator, type EmailValidationResult } from \"./core/client/emailValidation\";\nimport { fetchStoredResponse } from \"./core/client/responses\";\nimport {\n enrichmentSourcesOf,\n fetchRuntimeConfig,\n hasDeclaredEnrichmentSource,\n hasEnabledEnrichmentProvider,\n statefulQuestionsOf,\n stepsOf,\n type RuntimeConfig,\n} from \"./core/client/runtimeConfig\";\nimport { createTransport, DEFAULT_API_BASE_URL } from \"./core/client/transport\";\nimport { auditAnswer, type AuditedQuestion } from \"./core/engine/answerAudit\";\nimport { createFormEngine, type FormEngine, type ResolveNextStep } from \"./core/engine/formEngine\";\nimport { buildUrlData } from \"./core/engine/urlData\";\nimport { observeDropoff } from \"./core/events/dropoffDetection\";\nimport { createFormJourneyTracker } from \"./core/events/formJourneyTracker\";\nimport { createPushEventClient } from \"./core/events/pushEvents\";\nimport { ensureIdentified } from \"./core/identity/ensureIdentified\";\nimport type { LeadSource } from \"./core/identity/identify\";\nimport { createJourneyTracker, type JourneyTracker } from \"./core/identity/journey\";\nimport { attachEnrichment } from \"./enrichment/attachEnrichment\";\nimport { attachTracking, type TrackingSettings } from \"./tracking/attachTracking\";\nimport { attachEmailValidation } from \"./validation/attachEmailValidation\";\n\n/**\n * The public entry point (forms-sdk-plan.md \u00A72.2): composes the boot sequence\n * in the native, load-bearing order \u2014 identify before the first write (row\n * 60: attribute sync silently no-ops otherwise) \u2014 then wires events, journey,\n * drop-off, and the optional DOM binding around one engine instance.\n *\n * **The form definition boots from the runtime-config endpoint** (\u00A72.3,\n * Decisions #7): when `steps` is omitted, init fetches the published record\n * and derives the step order, the behavioral settings gates, and the expected\n * questionIds for the \u00A74.3 drift warning. Caller-provided `steps`/`settings`/\n * `expectedQuestionIds` still win \u2014 offline tests and agents that already\n * hold the record skip the fetch entirely.\n *\n * `preview: true` replicates the native guarantee that previews never pollute\n * data (\u00A72.2): identify, response writes, pushEvents, form-journey, and the\n * journey module are all blocked client-side.\n */\n\nexport type SurfaceFormsInitOptions = {\n environmentId: string;\n formId: string;\n /** Ordered logical steps of the form record; omitted = fetched from runtime-config. */\n steps?: Array<{ id: string; endStepKind?: \"thank_you\" | \"disqualified\" }>;\n /**\n * Behavioral gates + customer-tag config (rows 51\u201355). Omitted values fill\n * from runtime-config ONLY when `steps` is also omitted (the record fetch) \u2014\n * caller-provided `steps` skip the fetch entirely, so pass tracking settings\n * explicitly in that offline mode.\n */\n settings?: {\n trackPartialResponses?: boolean;\n trackCookies?: boolean;\n } & TrackingSettings;\n apiBaseUrl?: string;\n /** Enables the bind/ layer + view detection on this root. */\n container?: Element;\n /** Stateful questionIds from the record; unbound ones get the \u00A74.3 runtime warning. */\n expectedQuestionIds?: string[];\n /** Routing evaluation; defaults to linear order until the extracted routing module lands. */\n resolveNextStep?: ResolveNextStep;\n /** Seeds a URL_DATA external-state entry under this id (attribution, row 56). */\n urlDataStateId?: string;\n source?: LeadSource;\n /** Page-view tracking module (tag parity), default off. */\n journey?: boolean;\n /**\n * Automatic waterfall email validation (row 37), default off: watches\n * email answers (debounced, per-address verdicts, fail-open) and annotates\n * the response `meta` with native's `isEmailValid`/`emailValidation`/\n * `emailValidationFailed` keys. Opt-in because verdicts spend the form\n * owner's validator quota. The on-demand `validateEmail` on the handle is\n * always available and shares the same per-address cache.\n */\n emailValidation?: boolean;\n preview?: boolean;\n /**\n * Signed token from the create_form / get_sdk_binding_map replies; with\n * `preview: true` it unlocks the DRAFT config of a never-published form.\n * Without it, preview serves the published config.\n */\n previewToken?: string;\n /**\n * Resume a stored response: pass the `responseId` + `resumeToken` pair a\n * previous session's create returned (`state().resumeToken`, or the `saved`\n * event). Boot fetches the stored answers through the token-gated read-back\n * and seeds the engine \u2014 writes become updates and earlier answers are\n * preserved; a failed fetch warns and starts fresh. Ignored in preview.\n */\n resume?: { responseId: string; resumeToken: string };\n /** Logs every captured answer and warns on states the server would reject (unknown questionId, wrong/missing type, malformed choices). Development aid; never enable in production. */\n debug?: boolean;\n meta?: Record<string, unknown>;\n};\n\n/**\n * Response-meta keys the SDK itself owns; caller merges must not overwrite\n * them. `surfaceTagStatus` keys the responses-table SDK badge (Decisions #8);\n * the email-validation keys are server-billed verdicts dashboards trust.\n */\nconst RESERVED_META_KEYS = new Set([\n \"surfaceTagStatus\",\n \"isEmailValid\",\n \"emailValidation\",\n \"emailValidationFailed\",\n]);\n\nexport type SurfaceForm = Pick<\n FormEngine,\n | \"setAnswer\"\n | \"setExternalState\"\n | \"next\"\n | \"back\"\n | \"goToStep\"\n | \"submit\"\n | \"disqualify\"\n | \"savePartial\"\n | \"flush\"\n | \"markViewed\"\n | \"on\"\n | \"state\"\n | \"subscribe\"\n> & {\n /** Re-runs identify (e.g. after an SPA route change); cache makes it cheap. */\n identify: () => Promise<unknown>;\n /**\n * On-demand waterfall email validation (row 37): resolves a per-address\n * deliverability verdict, cached for the form's lifetime and fail-open on\n * validator outage. Use it to gate your own navigation:\n * `if ((await form.validateEmail(value)).isValid) form.next()`.\n * In preview it resolves a synthetic valid verdict without network.\n */\n validateEmail: (email: string) => Promise<EmailValidationResult>;\n /**\n * Records caller-computed values (a qualification score, an A/B bucket, \u2026)\n * onto the response `meta` \u2014 they ride the next save, or amend the stored\n * response when the form already finished. SDK-owned keys\n * (`surfaceTagStatus` and the email-validation verdicts) are dropped with a\n * console warning: dashboards trust those.\n */\n mergeMeta: (partial: Record<string, unknown>) => void;\n /**\n * What actually runs in THIS environment \u2014 the record can declare features\n * (an enrichment source field) that the environment does not back with a\n * provider, and nothing else surfaces that.\n */\n capabilities: { enrichment: boolean; emailValidation: boolean; tracking: boolean };\n /** The fetched published record (labels, component types); undefined when `steps` was caller-provided. */\n runtimeConfig?: RuntimeConfig;\n destroy: () => void;\n};\n\nexport const SurfaceForms = {\n init: async ({\n environmentId,\n formId,\n steps,\n settings = {},\n apiBaseUrl,\n container,\n expectedQuestionIds,\n resolveNextStep,\n urlDataStateId,\n source,\n journey = false,\n emailValidation = false,\n preview = false,\n previewToken,\n debug = false,\n resume,\n meta,\n }: SurfaceFormsInitOptions): Promise<SurfaceForm> => {\n const transport = createTransport({ apiBaseUrl });\n\n // Native boot order (\u00A72.2): config before identify. Caller-provided values\n // always win so offline callers never pay (or depend on) the fetch.\n let runtimeConfig: RuntimeConfig | undefined;\n if (!steps) {\n const fetched = await fetchRuntimeConfig(transport, formId, { preview, previewToken });\n if (!fetched.ok || !fetched.data.data) {\n // The 2026-08 field run burned hours here because the failure did not\n // name the host it tried: an agent pasted the init snippet against an\n // environment on a different deployment and had nothing to diagnose\n // with. Name the URL, the status, and the fix.\n const baseUrl = (apiBaseUrl ?? DEFAULT_API_BASE_URL).replace(/\\/$/, \"\");\n const detail = !fetched.ok\n ? fetched.error.kind === \"http\"\n ? `HTTP ${fetched.error.status}`\n : \"network error\"\n : \"empty response\";\n throw new Error(\n `SurfaceForms.init: could not fetch runtime config for form \"${formId}\" ` +\n `(${detail} from ${baseUrl}/api/v1/public/forms/${formId}/runtime-config). ` +\n `If this environment is not served from ${DEFAULT_API_BASE_URL}, pass apiBaseUrl \u2014 ` +\n `the get_sdk_binding_map MCP tool returns the correct value.`\n );\n }\n runtimeConfig = fetched.data.data;\n steps = stepsOf(runtimeConfig.config);\n expectedQuestionIds =\n expectedQuestionIds ?? statefulQuestionsOf(runtimeConfig.config).map((q) => q.questionId);\n const fetchedSettings = (runtimeConfig.settings ?? {}) as TrackingSettings & {\n trackPartialResponses?: boolean;\n trackCookie?: boolean;\n };\n settings = {\n trackPartialResponses: fetchedSettings.trackPartialResponses,\n trackCookies: fetchedSettings.trackCookie,\n gtmId: fetchedSettings.gtmId,\n gaMeasurementId: fetchedSettings.gaMeasurementId,\n metaPixelId: fetchedSettings.metaPixelId,\n hubspotTracking: fetchedSettings.hubspotTracking,\n adsConversions: fetchedSettings.adsConversions,\n ...settings,\n };\n }\n const trackCookies = settings.trackCookies ?? false;\n\n // Resume (row 28, gated read-back per Decisions #11): a verified fetch\n // seeds the engine \u2014 writes become updates, stored answers ride the\n // full-answer-set resend. Any failure (revoked/wrong token, deleted\n // response) falls back to a fresh session instead of blind-updating an id\n // we could not read. Preview sessions never resume: they must not write to\n // (or leak) a real visitor's response.\n let engineResume: { responseId: string; answers: Record<string, Record<string, unknown>> } | undefined;\n if (resume && !preview) {\n const stored = await fetchStoredResponse(transport, resume);\n if (stored.ok) {\n engineResume = {\n responseId: resume.responseId,\n answers: Object.fromEntries(stored.data.answers.map((row) => [row.questionId, row.response])),\n };\n } else {\n console.warn(\n `Surface SDK: resume fetch for response \"${resume.responseId}\" failed \u2014 starting a fresh session.`\n );\n }\n }\n\n // Mutable so identify() swaps in the freshly resolved visitor \u2014 the engine\n // and drop-off observer read through it at event time, never a boot-time copy.\n let identity = await ensureIdentified({ transport, environmentId, formId, source, preview });\n\n const pushEvents = createPushEventClient({ transport, preview });\n const formJourney = createFormJourneyTracker({ transport, preview });\n\n const engine = createFormEngine({\n formId,\n environmentId,\n steps,\n transport,\n resolveNextStep,\n trackPartialResponses: settings.trackPartialResponses ?? true,\n trackCookies,\n externalStates: urlDataStateId ? { [urlDataStateId]: buildUrlData({ trackCookies }) } : {},\n // Native forms report tag detection here; for the SDK the answer is static \u2014\n // the SDK IS the runtime \u2014 and it keys the responses-table \"SDK\" badge, so\n // callers cannot override it (Decisions #8).\n meta: { ...meta, surfaceTagStatus: \"sdk\" },\n identity: () => ({\n fingerprint: identity?.fingerprint,\n leadSessionId: identity?.leadSessionId ?? undefined,\n leadId: identity?.leadId ?? undefined,\n }),\n pushEvents,\n formJourney,\n preview,\n resume: engineResume,\n });\n\n const teardowns: Array<() => void> = [];\n\n // Debug mode: audits every answer (headless setAnswer is one label-string\n // away from the ingest 400 no static gate can see) and logs the lifecycle.\n // The audited engine is what both the bind layer and the returned handle\n // use, so bound and headless answers are checked identically.\n let auditedEngine = engine;\n if (debug) {\n const questions = new Map<string, AuditedQuestion>(\n (runtimeConfig ? statefulQuestionsOf(runtimeConfig.config) : []).map((q) => [q.questionId, q])\n );\n auditedEngine = {\n ...engine,\n setAnswer: (questionId, state) => {\n const stepId = engine.state().currentStepId;\n engine.setAnswer(questionId, state);\n const merged = (engine.state().answers[stepId]?.[questionId] ?? state) as Record<string, unknown>;\n auditAnswer({ questions, questionId, merged });\n },\n };\n for (const event of [\n \"viewed\",\n \"started\",\n \"stepChanged\",\n \"stepCompleted\",\n \"completed\",\n \"disqualified\",\n \"saved\",\n \"error\",\n ] as const) {\n teardowns.push(\n engine.on(event, (payload) => console.debug(`Surface SDK [debug]: ${event}`, payload))\n );\n }\n }\n\n let started = false;\n teardowns.push(\n engine.on(\"started\", () => {\n started = true;\n })\n );\n teardowns.push(\n observeDropoff(pushEvents, () => ({\n started,\n formId,\n stepId: engine.state().currentStepId,\n sessionId: identity?.leadSessionId ?? undefined,\n }))\n );\n\n if (container) {\n teardowns.push(bindForm({ engine: auditedEngine, root: container, expectedQuestionIds }));\n }\n\n // Phase-2 tracking (rows 51\u201355): customer-tag lifecycle + ad conversions,\n // entirely settings-driven. Preview blocks it like every other emission \u2014\n // loading GTM/pixels on a draft page would report the customer's tags from\n // a page that isn't theirs (native previews skip these for the same reason).\n const hasTrackingConfig =\n !!settings.gtmId ||\n !!settings.gaMeasurementId ||\n !!settings.metaPixelId ||\n !!settings.hubspotTracking?.trackingId ||\n (settings.adsConversions?.length ?? 0) > 0;\n if (hasTrackingConfig && !preview && typeof window !== \"undefined\") {\n teardowns.push(attachTracking({ engine, formId, settings }));\n }\n\n // Real-time enrichment (4.10): runs only when the record's environment has\n // an enabled provider AND the record itself was fetched \u2014 offline callers\n // (caller-provided steps) can wire attachEnrichment themselves with their\n // own source list. Preview never spends the owner's provider credits.\n const enrichmentSources = runtimeConfig ? enrichmentSourcesOf(runtimeConfig.config) : [];\n const enrichmentActive =\n runtimeConfig != null &&\n enrichmentSources.length > 0 &&\n hasEnabledEnrichmentProvider(runtimeConfig.settings);\n if (enrichmentActive && !preview) {\n teardowns.push(attachEnrichment({ engine, transport, formId, sources: enrichmentSources }));\n } else if (debug && runtimeConfig && !enrichmentActive && hasDeclaredEnrichmentSource(runtimeConfig.config)) {\n // Silent-inert trap (2026-08 field run): the record explicitly declares\n // an enrichmentSourceField, so a doc reader assumes enrichment runs \u2014\n // but the environment has no enabled provider, and enrichedFields stays\n // empty with no other signal.\n console.warn(\n \"Surface SDK: the record declares an enrichmentSourceField, but this environment has no \" +\n \"enabled enrichment provider \u2014 no enrichment will run (capabilities.enrichment is false).\"\n );\n }\n\n // Waterfall email validation (row 37). The validator is always created \u2014\n // the handle's on-demand validateEmail costs nothing until called \u2014 and\n // the automatic answer-watch is opt-in (`emailValidation: true`): SDK\n // records carry no routing conditions, so unlike native there is no\n // record-driven signal that the owner wants verdicts billed.\n const emailValidator = createEmailValidator({ transport, environmentId, preview });\n if (emailValidation && !preview) {\n teardowns.push(attachEmailValidation({ engine, validator: emailValidator }));\n }\n\n let journeyTracker: JourneyTracker | undefined;\n if (journey && !preview) {\n journeyTracker = createJourneyTracker({ transport, environmentId });\n void journeyTracker.trackPageView();\n teardowns.push(journeyTracker.observeRouteChanges());\n }\n\n return {\n setAnswer: auditedEngine.setAnswer,\n setExternalState: engine.setExternalState,\n next: engine.next,\n back: engine.back,\n goToStep: engine.goToStep,\n submit: engine.submit,\n disqualify: engine.disqualify,\n savePartial: engine.savePartial,\n flush: engine.flush,\n markViewed: engine.markViewed,\n mergeMeta: (partial) => {\n const entries = Object.entries(partial);\n const reserved = entries.filter(([key]) => RESERVED_META_KEYS.has(key));\n if (reserved.length > 0) {\n console.warn(\n `Surface SDK: mergeMeta dropped reserved key(s) ${reserved.map(([key]) => key).join(\", \")} \u2014 ` +\n \"these are SDK-owned response markers.\"\n );\n }\n engine.mergeMeta(Object.fromEntries(entries.filter(([key]) => !RESERVED_META_KEYS.has(key))));\n },\n capabilities: {\n enrichment: enrichmentActive,\n emailValidation,\n tracking: hasTrackingConfig,\n },\n on: engine.on,\n state: engine.state,\n subscribe: engine.subscribe,\n identify: async () => {\n const fresh = await ensureIdentified({ transport, environmentId, formId, source, preview });\n if (fresh) identity = fresh;\n return fresh;\n },\n validateEmail: emailValidator.validate,\n runtimeConfig,\n destroy: () => teardowns.forEach((teardown) => teardown()),\n };\n },\n};\n"],
5
+ "mappings": "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",
6
+ "names": ["index_exports", "__export", "DEFAULT_API_BASE_URL", "DEFAULT_REDIRECT_TIMEOUT_MS", "ENRICHMENT_STATE_ID", "IDENTITY_INFO_ANSWER_KEYS", "JOURNEY_COOKIE_NAME", "LEAD_DATA_STORAGE_KEY", "LEAD_DATA_TTL_MS", "RECENT_VISIT_COOKIE_NAME", "SurfaceForms", "attachEmailValidation", "attachEnrichment", "bindForm", "buildIdentifyPayload", "buildRedirectUrl", "buildResponsesArray", "buildStepTransitionEventBatch", "buildUrlData", "constructUrlParamsObject", "createEmailValidator", "createEmitter", "createFormEngine", "createFormJourneyTracker", "createJourneyTracker", "createPushEventClient", "createSchedulerClient", "createStartedDetector", "createSubmitResponsePayload", "createTransport", "createUpdateResponsePayload", "enrichmentSourcesOf", "ensureIdentified", "fetchRuntimeConfig", "getBrowserFingerprint", "getHash", "hasEnabledEnrichmentProvider", "identifyLead", "mountBookingWidget", "observeDropoff", "observeFormView", "parseCookiesObject", "parsePrefillParams", "parseQuestionId", "performRedirect", "readLeadData", "statefulQuestionIdsOf", "statefulQuestionsOf", "stepsOf", "submitResponse", "toSchedulerAnswerState", "updateResponse", "writeLeadData", "observeFormView", "element", "onViewed", "viewed", "observer", "entries", "entry", "fieldSelector", "resolveFields", "element", "field", "fieldNameFor", "questionType", "explicit", "questionTypeFor", "fieldValue", "isChoiceControl", "selectedValueAndIndex", "options", "index", "option", "CHOICE_ANSWER_BUILDERS", "bindForm", "engine", "root", "expectedQuestionIds", "teardowns", "boundQuestionIds", "listen", "target", "type", "handler", "questionId", "fields", "groupType", "buildChoiceAnswer", "choiceControls", "apply", "control", "fieldName", "initial", "unbound", "id", "navigationMarkerSelector", "button", "gotoStepId", "markers", "marker", "action", "event", "error", "stepContainers", "showCurrentStep", "currentStepId", "container", "observeFormView", "teardown", "currentMonth", "now", "monthLabel", "month", "year", "monthNum", "dateLabel", "date", "day", "shiftMonth", "delta", "shifted", "mountBookingWidget", "container", "scheduler", "eventTypeId", "timezone", "duration", "prefill", "identity", "formatters", "onComplete", "formatMonth", "formatDate", "formatTime", "slot", "root", "dates", "selectedDate", "selectedSlot", "destroyed", "generation", "el", "tag", "className", "text", "node", "render", "children", "renderError", "message", "retry", "error", "retryButton", "renderDates", "requestedMonth", "gen", "result", "heading", "nav", "label", "button", "list", "d", "item", "renderSlots", "slots", "back", "renderForm", "errorMessage", "form", "name", "email", "submit", "event", "VALIDATION_PATH", "failOpenResult", "email", "resultOf", "row", "createEmailValidator", "transport", "environmentId", "preview", "cache", "validateBatch", "emails", "normalized", "pending", "request", "result", "rows", "CREATE_PATH", "UPDATE_PATH", "GET_PATH", "submitResponse", "transport", "payload", "result", "id", "updateResponse", "updateResponseConfirmed", "isAnswerRow", "row", "fetchStoredResponse", "responseId", "resumeToken", "fetchRuntimeConfig", "transport", "formId", "preview", "previewToken", "flatComponentsOf", "step", "components", "layout", "layoutRow", "row", "item", "stepsOf", "config", "statefulQuestionsOf", "component", "typed", "statefulQuestionIdsOf", "question", "enrichmentSourcesOf", "source", "hasDeclaredEnrichmentSource", "hasEnabledEnrichmentProvider", "settings", "enrichment", "provider", "toParams", "entries", "value", "createSchedulerClient", "transport", "preview", "previewParam", "unwrapBooking", "result", "booking", "eventTypeId", "timezone", "params", "month", "duration", "hostId", "ownerEmail", "year", "monthNum", "date", "startTime", "endTime", "inviteeName", "inviteeEmail", "intakeResponses", "guestEmails", "captchaToken", "responseId", "leadSessionId", "fingerprint", "hostRouting", "bookingId", "rescheduleToken", "newStartTime", "toSchedulerAnswerState", "hostAttendee", "attendee", "DEFAULT_API_BASE_URL", "SDK_VERSION", "versionedHeaders", "headers", "versionedUrl", "url", "createTransport", "apiBaseUrl", "baseUrl", "toUrl", "path", "response", "body", "cause", "payload", "opts", "serialized", "IDENTITY_INFO_ANSWER_KEYS", "createEmitter", "handlers", "event", "handler", "existing", "payload", "error", "PUSH_EVENT_PATH", "KNOWN_BOT_UA", "isLikelyBot", "ua", "hasRequiredFields", "event", "buildStepTransitionEventBatch", "sessionId", "formId", "currentStepId", "nextStepId", "stepCompletionTime", "createPushEventClient", "transport", "preview", "request", "events", "createStartedDetector", "initial", "snapshot", "deepClone", "started", "current", "deepEqual", "value", "clone", "key", "entry", "a", "b", "index", "aKeys", "bKeys", "buildResponsesArray", "answers", "externalStates", "responses", "enrichedFields", "bookingId", "step", "stepState", "questionId", "entry", "stateId", "externalState", "buildBasePayload", "formId", "submittingOnStepId", "finished", "invalidResponse", "trackCookies", "meta", "personAttributeEnrichedFields", "fingerprint", "leadSessionId", "filteredMeta", "key", "createSubmitResponsePayload", "options", "createUpdateResponsePayload", "createFormEngine", "formId", "environmentId", "steps", "transport", "resolveNextStep", "trackPartialResponses", "trackCookies", "externalStates", "meta", "identity", "pushEvents", "formJourney", "preview", "resume", "resolve", "currentStepId", "index", "step", "following", "emitter", "createEmitter", "storeListeners", "snapshotDirty", "snapshot", "notify", "listener", "currentIdentity", "answers", "responseId", "resumeToken", "seeded", "questionId", "state", "finished", "terminalWrite", "viewed", "createdAt", "history", "hasStarted", "createStartedDetector", "write", "submittingOnStepId", "isFinished", "invalid", "payloadOptions", "result", "submitResponse", "createSubmitResponsePayload", "updateResponseConfirmed", "createUpdateResponsePayload", "updateResponse", "writeQueue", "enqueueWrite", "task", "run", "amendAfterFinish", "amend", "pendingAdvance", "advance", "submitting", "tracked", "advanceNow", "rewindTo", "targetStepId", "from", "goToStep", "moveForwardNow", "disqualify", "finishNow", "target", "leavingStepId", "buildStepTransitionEventBatch", "revealEndingStep", "kind", "ending", "resolved", "stepState", "id", "partial", "previous", "DEFAULT_REDIRECT_TIMEOUT_MS", "addProtocolToUrl", "url", "protocol", "buildRedirectUrl", "leadId", "sessionId", "redirectUrl", "performRedirect", "redirectType", "preview", "constructUrlParamsObject", "url", "urlObj", "paramsObject", "value", "key", "parseCookiesObject", "cookieString", "cookies", "cookie", "trimmed", "eqIndex", "buildUrlData", "defaultUrl", "trackCookies", "inBrowser", "urlData", "parseQuestionId", "input", "firstUnderscore", "RESERVED_PARAMS", "parsePrefillParams", "search", "params", "questionIds", "id", "originalId", "questionId", "fieldName", "prefill", "observeDropoff", "pushEventClient", "getState", "handlePageHide", "event", "started", "formId", "stepId", "sessionId", "TRACK_PATH", "TERMINAL_OUTCOMES", "createFormJourneyTracker", "transport", "preview", "state", "flushNow", "TRACK_PATH", "flush", "closePrevious", "nowIso", "ordinal", "stepId", "entered", "existing", "visit", "durationMs", "pushVisit", "id", "now", "fromStepId", "toStepId", "reason", "transitionMeta", "pushed", "outcome", "disqualification", "getHash", "input", "data", "hashBuffer", "b", "getBrowserFingerprint", "environmentId", "userAgentData", "fields", "plugin", "IDENTIFY_PATH", "buildIdentifyPayload", "environmentId", "fingerprintId", "pageUrl", "source", "formId", "leadId", "sessionIdFromParams", "referrer", "url", "identifyLead", "transport", "payload", "result", "data", "LEAD_DATA_STORAGE_KEY", "LEAD_DATA_TTL_MS", "readLeadData", "raw", "item", "writeLeadData", "data", "ensureIdentified", "transport", "environmentId", "formId", "pageUrl", "source", "preview", "cached", "readLeadData", "landingPageUrl", "fingerprint", "getBrowserFingerprint", "result", "identifyLead", "buildIdentifyPayload", "leadData", "writeLeadData", "JOURNEY_COOKIE_NAME", "RECENT_VISIT_COOKIE_NAME", "JOURNEY_COOKIE_MAX_AGE", "RECENT_VISIT_COOKIE_MAX_AGE", "TRACK_PATH", "getCookie", "name", "cookie", "trimmed", "eqIndex", "value", "setCookie", "maxAge", "domain", "domainAttr", "getJourneyCookieDomain", "hostname", "parts", "createJourneyTracker", "transport", "environmentId", "journeyId", "refreshJourneyCookie", "buildPayload", "url", "leadData", "readLeadData", "trackPageView", "pageUrl", "payload", "result", "currentUrl", "notify", "newUrl", "originalPushState", "originalReplaceState", "args", "ENRICHMENT_PATH", "ENRICHMENT_STATE_ID", "EMAIL_PATTERN", "DOMAIN_PATTERN", "enrichmentInputOf", "value", "trimmed", "domain", "attachEnrichment", "engine", "transport", "formId", "sources", "processed", "inFlight", "pendingTimer", "pendingValue", "detached", "fire", "input", "key", "result", "ENRICHMENT_PATH", "data", "existing", "ENRICHMENT_STATE_ID", "existingData", "candidateValues", "values", "flat", "stepAnswers", "questionId", "fieldNames", "state", "fieldName", "scheduleLatest", "latest", "flushPending", "teardowns", "teardown", "CHOICE_LIST_TYPES", "isValidChoiceEntry", "entry", "needsIndex", "auditAnswer", "questions", "questionId", "merged", "prefix", "expected", "effectiveType", "DEFAULT_META_EVENT_NAME", "DEFAULT_GA4_EVENT_NAME", "DEFAULT_OPENAI_EVENT_NAME", "X_EVENT_ID_REGEX", "parseXPixelId", "eventId", "match", "isNumericId", "value", "isRuleFireable", "rule", "getParamValue", "params", "name", "lowerName", "key", "matchesCondition", "condition", "values", "v", "matchesConditions", "conditions", "operator", "c", "ruleToConversionEvent", "pixelId", "selectFiringEvents", "rules", "trigger", "stepId", "results", "conversion", "ensureTwq", "win", "s", "args", "el", "ensureFbq", "n", "ensureOaiq", "q", "ensureGtag", "measurementId", "ensureLintrk", "partnerId", "l", "a", "b", "fireConversion", "ctx", "w", "scriptPresent", "win", "src", "injectScriptOnce", "parent", "id", "el", "initGtm", "gtmId", "initGa4", "measurementId", "isEmbeddedInIframe", "initMetaPixel", "pixelId", "n", "args", "initHubspot", "trackingId", "createVendorTracker", "settings", "w", "dataLayerPush", "event", "gtagEvent", "name", "params", "fbqTrackCustom", "data", "formId", "urlData", "payload", "parseLocationParams", "win", "getParam", "params", "name", "lower", "key", "value", "pickClickIds", "EMAIL_ANSWER_KEYS", "findEmail", "answers", "state", "hasBookedMeeting", "flatAnswers", "engine", "flat", "stepAnswers", "attachTracking", "formId", "settings", "w", "tracker", "createVendorTracker", "rules", "urlData", "firedRuleIds", "processedStepIds", "pendingStepIds", "pendingEventTriggers", "pendingTerminal", "firedTerminal", "firedStepSubmitted", "firedEmail", "firedMeeting", "freshSession", "firedStarted", "fire", "selected", "responseId", "fresh", "rule", "ctx", "conversion", "fireConversion", "fireTrigger", "trigger", "selectFiringEvents", "fireStep", "stepId", "fireTerminal", "byRule", "hit", "detectAnswerMoments", "teardowns", "pendingStepSubmitted", "toStepId", "stepIds", "triggers", "initialStepId", "teardown", "EMAIL_ANSWER_KEYS", "EMAIL_PATTERN", "attachEmailValidation", "engine", "validator", "requested", "results", "pendingTimer", "pendingScheduled", "lastMetaKey", "detached", "candidateEmails", "emails", "stepAnswers", "state", "key", "value", "writeMeta", "current", "verdicts", "verdict", "metaKey", "v", "detailed", "fire", "fresh", "email", "scheduleLatest", "flushPending", "teardowns", "teardown", "RESERVED_META_KEYS", "SurfaceForms", "environmentId", "formId", "steps", "settings", "apiBaseUrl", "container", "expectedQuestionIds", "resolveNextStep", "urlDataStateId", "source", "journey", "emailValidation", "preview", "previewToken", "debug", "resume", "meta", "transport", "createTransport", "runtimeConfig", "fetched", "fetchRuntimeConfig", "baseUrl", "DEFAULT_API_BASE_URL", "detail", "stepsOf", "statefulQuestionsOf", "q", "fetchedSettings", "trackCookies", "engineResume", "stored", "fetchStoredResponse", "row", "identity", "ensureIdentified", "pushEvents", "createPushEventClient", "formJourney", "createFormJourneyTracker", "engine", "createFormEngine", "buildUrlData", "teardowns", "auditedEngine", "questions", "questionId", "state", "stepId", "merged", "auditAnswer", "event", "payload", "started", "observeDropoff", "bindForm", "hasTrackingConfig", "attachTracking", "enrichmentSources", "enrichmentSourcesOf", "enrichmentActive", "hasEnabledEnrichmentProvider", "attachEnrichment", "hasDeclaredEnrichmentSource", "emailValidator", "createEmailValidator", "attachEmailValidation", "journeyTracker", "createJourneyTracker", "partial", "entries", "reserved", "key", "fresh", "teardown"]
7
+ }