@duffcloudservices/site-forms 0.4.2 → 0.7.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +42 -3
- package/dist/composables/readExpectedJson.d.ts +158 -0
- package/dist/composables/useFormSubmission.d.ts +5 -1
- package/dist/composables/useSitePhiPosture.d.ts +71 -0
- package/dist/fields/DcsFormDate.vue.d.ts +2 -2
- package/dist/fields/DcsFormSelect.vue.d.ts +2 -2
- package/dist/fields/DcsFormText.vue.d.ts +2 -2
- package/dist/fields/DcsFormTextarea.vue.d.ts +2 -2
- package/dist/index.d.ts +4 -0
- package/dist/index.js +1014 -486
- package/dist/index.js.map +1 -1
- package/dist/site-forms.css +1 -1
- package/dist/types.d.ts +16 -0
- package/package.json +1 -1
- package/src/DcsForm.vue +98 -14
- package/src/__tests__/missing-form-error-surfacing.test.ts +124 -0
- package/src/__tests__/non-json-response.test.ts +282 -0
- package/src/__tests__/phi-guidance.test.ts +239 -0
- package/src/__tests__/receipt-validation.test.ts +425 -0
- package/src/__tests__/submission.test.ts +46 -5
- package/src/__tests__/visible-if.test.ts +17 -4
- package/src/composables/readExpectedJson.ts +360 -0
- package/src/composables/useFormSubmission.ts +66 -13
- package/src/composables/useSitePhiPosture.ts +123 -0
- package/src/index.ts +29 -0
- package/src/style.css +25 -0
- package/src/types.ts +16 -0
package/dist/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sources":["../src/composables/useFormValidation.ts","../src/composables/useDcsForm.ts","../src/composables/useFormSubmission.ts","../src/schema/validate.ts","../src/loaders/yaml.ts","../src/fields/DcsFormFieldWrapper.vue","../src/fields/DcsFormText.vue","../src/fields/DcsFormTextarea.vue","../src/fields/DcsFormSelect.vue","../src/fields/DcsFormRadio.vue","../src/fields/DcsFormCheckboxGroup.vue","../src/fields/DcsFormCheckbox.vue","../src/fields/DcsFormDate.vue","../src/fields/DcsFormFile.vue","../src/fields/DcsFormHidden.vue","../src/fields/DcsFormSection.vue","../src/fields/DcsFormHtmlBlock.vue","../src/DcsForm.vue","../src/presets.ts"],"sourcesContent":["import type {\n PortalFormAttachmentPolicy,\n PortalFormDefinition,\n PortalFormField,\n FormErrors,\n FormValues,\n} from '../types'\n\n/**\n * Returns true iff `field` is currently visible given the form's\n * other values. Hidden fields are never validated and never sent.\n */\nexport function isFieldVisible(\n field: PortalFormField,\n values: FormValues,\n): boolean {\n if (!field.visibleIf) return true\n const sibling = values[field.visibleIf.fieldId]\n return sibling === field.visibleIf.equals\n}\n\n/**\n * Validates a single field's value. Returns an error string or\n * `undefined` if valid. Layout-only field types (section-heading,\n * html-block) and hidden fields never produce errors.\n */\nexport function validateField(\n field: PortalFormField,\n value: unknown,\n attachmentPolicy?: PortalFormAttachmentPolicy,\n): string | undefined {\n if (\n field.type === 'section-heading' ||\n field.type === 'html-block' ||\n field.type === 'hidden'\n ) {\n return undefined\n }\n\n const normalizedValue = typeof value === 'string' ? value.trim() : value\n const isEmpty =\n value === undefined ||\n value === null ||\n normalizedValue === '' ||\n (Array.isArray(value) && value.length === 0)\n\n if (field.required && isEmpty) {\n return `${field.label} is required`\n }\n if (isEmpty) return undefined\n\n // Type-specific built-ins\n if (field.type === 'email' && typeof normalizedValue === 'string') {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(normalizedValue)) {\n return `${field.label} must be a valid email address`\n }\n }\n\n const v: NonNullable<PortalFormField['validation']> = field.validation ?? {}\n\n if (typeof normalizedValue === 'string') {\n if (v.minLength != null && normalizedValue.length < v.minLength) {\n return `${field.label} must be at least ${v.minLength} characters`\n }\n if (v.maxLength != null && normalizedValue.length > v.maxLength) {\n return `${field.label} must be at most ${v.maxLength} characters`\n }\n if (v.regex) {\n try {\n if (!new RegExp(v.regex).test(normalizedValue)) {\n return `${field.label} is invalid`\n }\n } catch {\n // bad regex in the definition — treat as no rule\n }\n }\n }\n\n if (typeof value === 'number') {\n if (v.min != null && value < v.min) {\n return `${field.label} must be at least ${v.min}`\n }\n if (v.max != null && value > v.max) {\n return `${field.label} must be at most ${v.max}`\n }\n }\n\n if (field.type === 'file') {\n const files = filesFromValue(value)\n const maxFiles = attachmentPolicy?.maxFiles\n const maxFileSizeBytes = attachmentPolicy?.maxFileSizeBytes\n const accept = v.accept && v.accept.length > 0 ? v.accept : attachmentPolicy?.accept\n\n if (maxFiles != null && files.length > maxFiles) {\n return `${field.label} accepts up to ${maxFiles} file${maxFiles === 1 ? '' : 's'}`\n }\n if (maxFileSizeBytes != null) {\n const oversized = files.find((file) => file.size > maxFileSizeBytes)\n if (oversized) {\n return `${oversized.name} exceeds the ${formatBytes(maxFileSizeBytes)} limit`\n }\n }\n if (accept && accept.length > 0) {\n const rejected = files.find((file) => !isAcceptedFile(file, accept))\n if (rejected) {\n return `${rejected.name} must be one of: ${accept.join(', ')}`\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Validates an entire form. Skips fields that are not visible.\n * If `fieldIds` is supplied, only those fields are validated\n * (used for per-step validation in multi-step forms).\n */\nexport function validateForm(\n def: PortalFormDefinition,\n values: FormValues,\n fieldIds?: string[],\n): FormErrors {\n const errors: FormErrors = {}\n const ids = fieldIds ? new Set(fieldIds) : null\n for (const field of def.fields) {\n if (ids && !ids.has(field.id)) continue\n if (!isFieldVisible(field, values)) continue\n const err = validateField(field, values[field.id], def.attachmentPolicy)\n if (err) errors[field.id] = err\n }\n return errors\n}\n\nexport function hasErrors(errors: FormErrors): boolean {\n return Object.values(errors).some((e) => !!e)\n}\n\nfunction filesFromValue(value: unknown): File[] {\n if (typeof File === 'undefined') {\n return []\n }\n if (value instanceof File) {\n return [value]\n }\n if (Array.isArray(value)) {\n return value.filter((item): item is File => item instanceof File)\n }\n return []\n}\n\nfunction isAcceptedFile(file: File, accept: string[]): boolean {\n const name = file.name.toLowerCase()\n const contentType = file.type.toLowerCase()\n\n return accept.some((rule) => {\n const normalized = rule.trim().toLowerCase()\n if (normalized === '') {\n return false\n }\n if (normalized.startsWith('.')) {\n return name.endsWith(normalized)\n }\n if (normalized.endsWith('/*')) {\n return contentType.startsWith(normalized.slice(0, -1))\n }\n return contentType === normalized\n })\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${Math.round(bytes / 1024)} KB`\n }\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n","import { computed, reactive, ref, type ComputedRef, type Ref } from 'vue'\nimport type {\n PortalFormDefinition,\n PortalFormField,\n PortalFormStep,\n FormErrors,\n FormValues,\n} from '../types'\nimport {\n hasErrors,\n isFieldVisible,\n validateForm,\n} from './useFormValidation'\n\nexport interface UseDcsFormOptions {\n definition: PortalFormDefinition\n}\n\nexport interface UseDcsFormReturn {\n values: FormValues\n errors: Ref<FormErrors>\n touched: Ref<Record<string, boolean>>\n submitting: Ref<boolean>\n submitted: Ref<boolean>\n submitError: Ref<string | null>\n /** All fields, with layout-only types preserved. */\n fields: ComputedRef<PortalFormField[]>\n /** Steps if multi-step, else null. */\n steps: ComputedRef<PortalFormStep[] | null>\n currentStepIndex: Ref<number>\n currentStep: ComputedRef<PortalFormStep | null>\n currentStepFields: ComputedRef<PortalFormField[]>\n isFirstStep: ComputedRef<boolean>\n isLastStep: ComputedRef<boolean>\n visibleFields: ComputedRef<PortalFormField[]>\n /** Sets a field value and clears that field's error. */\n setValue: (id: string, value: unknown) => void\n /** Marks a field as touched + revalidates only that field's row. */\n touch: (id: string) => void\n /** Validates the current step (multi-step) or the entire form. */\n validateCurrentScope: () => boolean\n validateAll: () => boolean\n next: () => boolean\n prev: () => void\n reset: () => void\n /** Returns the values that should actually be submitted (visible only). */\n collectSubmissionValues: () => FormValues\n}\n\nfunction defaultsFor(def: PortalFormDefinition): FormValues {\n const out: FormValues = {}\n for (const f of def.fields) {\n if (f.defaultValue !== undefined) {\n out[f.id] = f.defaultValue as unknown\n } else if (f.type === 'checkbox') {\n out[f.id] = false\n } else if (f.type === 'multiselect' || f.type === 'checkbox-group') {\n out[f.id] = [] as string[]\n } else {\n out[f.id] = ''\n }\n }\n return out\n}\n\nexport function useDcsForm(opts: UseDcsFormOptions): UseDcsFormReturn {\n const { definition } = opts\n const values = reactive<FormValues>(defaultsFor(definition))\n const errors = ref<FormErrors>({})\n const touched = ref<Record<string, boolean>>({})\n const submitting = ref(false)\n const submitted = ref(false)\n const submitError = ref<string | null>(null)\n const currentStepIndex = ref(0)\n\n const fields = computed(() => definition.fields)\n const steps = computed<PortalFormStep[] | null>(() =>\n definition.steps && definition.steps.length > 0 ? definition.steps : null,\n )\n const currentStep = computed<PortalFormStep | null>(() => {\n const s = steps.value\n return s ? (s[currentStepIndex.value] ?? null) : null\n })\n const currentStepFields = computed<PortalFormField[]>(() => {\n const step = currentStep.value\n if (!step) return definition.fields\n const ids = new Set(step.fieldIds)\n return definition.fields.filter((f) => ids.has(f.id))\n })\n const isFirstStep = computed(() => currentStepIndex.value === 0)\n const isLastStep = computed(() => {\n const s = steps.value\n return !s || currentStepIndex.value >= s.length - 1\n })\n const visibleFields = computed(() =>\n currentStepFields.value.filter((f) => isFieldVisible(f, values as FormValues)),\n )\n\n function setValue(id: string, value: unknown): void {\n ;(values as FormValues)[id] = value\n if (errors.value[id]) {\n errors.value = { ...errors.value, [id]: undefined }\n }\n }\n\n function touch(id: string): void {\n touched.value = { ...touched.value, [id]: true }\n }\n\n function validateScope(scopeFieldIds?: string[]): boolean {\n const next = validateForm(definition, values as FormValues, scopeFieldIds)\n // Merge with existing errors but only for the validated scope so we\n // don't wipe out errors from other steps.\n if (scopeFieldIds) {\n const merged = { ...errors.value }\n for (const id of scopeFieldIds) {\n merged[id] = next[id]\n }\n errors.value = merged\n } else {\n errors.value = next\n }\n return !hasErrors(errors.value)\n }\n\n function validateCurrentScope(): boolean {\n const scope = currentStep.value?.fieldIds\n return validateScope(scope)\n }\n\n function validateAll(): boolean {\n return validateScope()\n }\n\n function next(): boolean {\n if (!steps.value) return false\n if (!validateCurrentScope()) return false\n if (currentStepIndex.value < steps.value.length - 1) {\n currentStepIndex.value++\n return true\n }\n return false\n }\n\n function prev(): void {\n if (currentStepIndex.value > 0) currentStepIndex.value--\n }\n\n function reset(): void {\n const fresh = defaultsFor(definition)\n for (const k of Object.keys(values as object)) {\n delete (values as FormValues)[k]\n }\n Object.assign(values as FormValues, fresh)\n errors.value = {}\n touched.value = {}\n submitting.value = false\n submitted.value = false\n submitError.value = null\n currentStepIndex.value = 0\n }\n\n function collectSubmissionValues(): FormValues {\n const out: FormValues = {}\n for (const f of definition.fields) {\n if (\n f.type === 'section-heading' ||\n f.type === 'html-block'\n )\n continue\n if (!isFieldVisible(f, values as FormValues)) continue\n out[f.id] = (values as FormValues)[f.id]\n }\n return out\n }\n\n return {\n values: values as FormValues,\n errors,\n touched,\n submitting,\n submitted,\n submitError,\n fields,\n steps,\n currentStepIndex,\n currentStep,\n currentStepFields,\n isFirstStep,\n isLastStep,\n visibleFields,\n setValue,\n touch,\n validateCurrentScope,\n validateAll,\n next,\n prev,\n reset,\n collectSubmissionValues,\n }\n}\n","import type {\n DcsFormSubmitPayload,\n DcsFormSubmitSuccess,\n DcsFormSubmitError,\n} from '../types'\n\nexport interface SubmitOptions {\n apiBase: string\n siteSlug: string\n payload: DcsFormSubmitPayload\n /** Number of retries on 5xx / network errors. Default 1. */\n retries?: number\n /** Optional fetch implementation override (tests). */\n fetchImpl?: typeof fetch\n}\n\n/**\n * POSTs a form submission to\n * `${apiBase}/sites/{siteSlug}/forms/{formId}/submissions`.\n *\n * Uses JSON for plain values and `multipart/form-data` when any\n * value is a `File` (file-upload fields).\n */\nexport async function submitFormValues(\n opts: SubmitOptions,\n): Promise<DcsFormSubmitSuccess> {\n const { apiBase, siteSlug, payload } = opts\n const retries = opts.retries ?? 1\n const fetchImpl = opts.fetchImpl ?? fetch\n const url = `${apiBase.replace(/\\/$/, '')}/sites/${encodeURIComponent(\n siteSlug,\n )}/forms/${encodeURIComponent(payload.formId)}/submissions`\n\n const hasFile = Object.values(payload.values).some(valueHasFile)\n\n let lastError: Error | undefined\n let lastStatus: number | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const init: RequestInit = hasFile\n ? { method: 'POST', body: buildFormData(payload) }\n : {\n method: 'POST',\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }\n const res = await fetchImpl(url, init)\n lastStatus = res.status\n if (res.ok) {\n const body = await safeJson(res)\n return { payload, response: body }\n }\n // Retry only on 5xx\n if (res.status < 500) {\n const body = await safeText(res)\n const err: DcsFormSubmitError = {\n payload,\n status: res.status,\n error: new Error(`Submission failed (${res.status}): ${body}`),\n }\n throw err\n }\n lastError = new Error(`Server error ${res.status}`)\n } catch (e) {\n // If `e` is already a DcsFormSubmitError-shaped object, rethrow.\n if (e && typeof e === 'object' && 'payload' in e && 'error' in e) {\n throw e\n }\n lastError = e as Error\n }\n }\n\n throw {\n payload,\n status: lastStatus,\n error: lastError ?? new Error('Submission failed'),\n } satisfies DcsFormSubmitError\n}\n\nfunction buildFormData(payload: DcsFormSubmitPayload): FormData {\n const fd = new FormData()\n fd.append('formId', payload.formId)\n if (payload.captchaToken) fd.append('captchaToken', payload.captchaToken)\n for (const [key, value] of Object.entries(payload.values)) {\n if (value === undefined || value === null) continue\n if (typeof File !== 'undefined' && value instanceof File) {\n fd.append(`values[${key}]`, value)\n } else if (Array.isArray(value) && value.some((item) => typeof File !== 'undefined' && item instanceof File)) {\n for (const item of value) {\n if (typeof File !== 'undefined' && item instanceof File) {\n fd.append(`values[${key}][]`, item)\n }\n }\n } else if (Array.isArray(value)) {\n for (const item of value) fd.append(`values[${key}][]`, String(item))\n } else {\n fd.append(`values[${key}]`, String(value))\n }\n }\n return fd\n}\n\nfunction valueHasFile(value: unknown): boolean {\n if (typeof File === 'undefined') {\n return false\n }\n if (value instanceof File) {\n return true\n }\n return Array.isArray(value) && value.some((item) => item instanceof File)\n}\n\nasync function safeJson(res: Response): Promise<unknown> {\n try {\n return await res.json()\n } catch {\n return null\n }\n}\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return ''\n }\n}\n","/**\n * Validates a loaded form definition against the form-definition JSON\n * Schema emitted by `@dcs/contracts`. Dev-only — failures are logged\n * via `console.warn` rather than thrown so a malformed YAML never\n * takes down a customer site in production.\n *\n * Schema is bundled as a snapshot of\n * `contracts/dist/form-definition.schema.json` to avoid a runtime\n * dependency on the contracts build output.\n */\nimport Ajv, { type ErrorObject, type ValidateFunction } from 'ajv'\nimport addFormats from 'ajv-formats'\nimport schema from './form-definition.schema.json'\nimport type { PortalFormDefinition } from '../types'\n\nlet validator: ValidateFunction | null = null\n\nfunction getValidator(): ValidateFunction {\n if (validator) return validator\n const ajv = new Ajv({\n allErrors: true,\n strict: false,\n discriminator: false,\n })\n addFormats(ajv)\n validator = ajv.compile(schema as object)\n return validator\n}\n\nexport interface SchemaValidationResult {\n valid: boolean\n errors: ErrorObject[]\n}\n\nexport function validateFormDefinition(\n def: PortalFormDefinition | unknown,\n): SchemaValidationResult {\n const v = getValidator()\n const valid = v(def) as boolean\n return { valid, errors: valid ? [] : (v.errors ?? []) }\n}\n\n/** Logs a `console.warn` when invalid, but only when `import.meta.env.DEV`. */\nexport function warnIfInvalid(\n formId: string,\n def: PortalFormDefinition | unknown,\n isDev: boolean,\n): SchemaValidationResult {\n const result = validateFormDefinition(def)\n if (!result.valid && isDev) {\n // eslint-disable-next-line no-console\n console.warn(\n `[@duffcloudservices/site-forms] Form \"${formId}\" failed schema validation:`,\n result.errors,\n )\n }\n return result\n}\n","import yaml from 'js-yaml'\nimport type { PortalFormDefinition } from '../types'\n\n/**\n * Eagerly load every form YAML under `/.dcs/forms/*.yaml` from the\n * consuming Vite app and parse them into PortalFormDefinition objects.\n *\n * Vite returns the modules as raw strings (when using `?raw` or the\n * default text loader for unknown extensions) or as parsed objects\n * (when `vite-plugin-yaml` is installed). This helper handles both.\n */\nexport function loadFormDefinitions(\n modules: Record<string, unknown>,\n): Record<string, PortalFormDefinition> {\n const out: Record<string, PortalFormDefinition> = {}\n for (const [path, mod] of Object.entries(modules)) {\n const formId = extractFormId(path)\n const def = parseModule(mod)\n if (def) {\n out[def.formId ?? formId] = def\n }\n }\n return out\n}\n\nfunction extractFormId(path: string): string {\n const file = path.split('/').pop() ?? path\n return file.replace(/\\.ya?ml$/i, '')\n}\n\nfunction parseModule(mod: unknown): PortalFormDefinition | null {\n if (!mod) return null\n if (typeof mod === 'string') {\n return yaml.load(mod) as PortalFormDefinition\n }\n if (typeof mod === 'object') {\n // vite-plugin-yaml returns parsed objects, possibly wrapped in\n // `{ default: ... }` when imported via `import: 'default'`.\n const maybeDefault = (mod as { default?: unknown }).default\n if (maybeDefault && typeof maybeDefault === 'object') {\n return maybeDefault as PortalFormDefinition\n }\n return mod as PortalFormDefinition\n }\n return null\n}\n\n/** Parse a single raw YAML string into a PortalFormDefinition. */\nexport function parseFormYaml(raw: string): PortalFormDefinition {\n return yaml.load(raw) as PortalFormDefinition\n}\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n error?: string\n /** Optional id to use for the input — wrappers use it for label `for=`. */\n inputId?: string\n}>()\n</script>\n\n<template>\n <div\n class=\"dcs-form-field\"\n :class=\"[`dcs-form-field--${field.type}`, `dcs-form-field--width-${field.width ?? 'full'}`]\"\n :data-form-field-key=\"field.id\"\n >\n <slot name=\"label\">\n <label\n v-if=\"field.type !== 'checkbox' && field.type !== 'hidden' && field.type !== 'section-heading' && field.type !== 'html-block'\"\n :for=\"inputId ?? `field-${field.id}`\"\n class=\"dcs-form-field__label\"\n >\n {{ field.label }}\n <span v-if=\"field.required\" aria-hidden=\"true\" class=\"dcs-form-field__required\">*</span>\n </label>\n </slot>\n\n <slot />\n\n <slot name=\"help\">\n <p v-if=\"field.helpText\" class=\"dcs-form-field__help\">{{ field.helpText }}</p>\n </slot>\n\n <slot name=\"error\">\n <p v-if=\"error\" class=\"dcs-form-field__error\" role=\"alert\">{{ error }}</p>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | number | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst inputType = computed(() => {\n switch (props.field.type) {\n case 'email':\n return 'email'\n case 'tel':\n return 'tel'\n default:\n return 'text'\n }\n})\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :on-input=\"(e: Event) => emit('update:modelValue', (e.target as HTMLInputElement).value)\"\n :on-blur=\"() => emit('blur')\"\n >\n <input\n :id=\"inputId\"\n class=\"dcs-form-input\"\n :type=\"inputType\"\n :name=\"field.id\"\n :value=\"modelValue ?? ''\"\n :placeholder=\"field.placeholder\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :aria-describedby=\"error ? `${inputId}-error` : undefined\"\n @input=\"emit('update:modelValue', ($event.target as HTMLInputElement).value)\"\n @blur=\"emit('blur')\"\n />\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :on-input=\"(e: Event) => emit('update:modelValue', (e.target as HTMLTextAreaElement).value)\"\n :on-blur=\"() => emit('blur')\"\n >\n <textarea\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-textarea\"\n :name=\"field.id\"\n :placeholder=\"field.placeholder\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n rows=\"5\"\n :value=\"modelValue ?? ''\"\n @input=\"emit('update:modelValue', ($event.target as HTMLTextAreaElement).value)\"\n @blur=\"emit('blur')\"\n />\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | string[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[]]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst isMulti = computed(() => props.field.type === 'multiselect')\nconst options = computed(() => props.field.options ?? [])\n\nfunction onChange(e: Event): void {\n const sel = e.target as HTMLSelectElement\n if (isMulti.value) {\n const values: string[] = []\n for (const opt of Array.from(sel.selectedOptions)) values.push(opt.value)\n emit('update:modelValue', values)\n } else {\n emit('update:modelValue', sel.value)\n }\n}\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :options=\"options\"\n :on-change=\"onChange\"\n >\n <select\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-select\"\n :name=\"field.id\"\n :required=\"field.required\"\n :multiple=\"isMulti\"\n :aria-invalid=\"!!error\"\n :value=\"modelValue ?? (isMulti ? [] : '')\"\n @change=\"onChange\"\n @blur=\"emit('blur')\"\n >\n <option v-if=\"!isMulti\" value=\"\" disabled>\n {{ field.placeholder ?? 'Select…' }}\n </option>\n <option v-for=\"opt in options\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </select>\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst options = computed(() => props.field.options ?? [])\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <fieldset\n class=\"dcs-form-radio-group\"\n role=\"radiogroup\"\n :aria-required=\"field.required\"\n :aria-invalid=\"!!error\"\n >\n <legend class=\"sr-only\">{{ field.label }}</legend>\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n class=\"dcs-form-radio\"\n >\n <input\n type=\"radio\"\n :name=\"field.id\"\n :value=\"opt.value\"\n :checked=\"modelValue === opt.value\"\n @change=\"emit('update:modelValue', opt.value)\"\n />\n <span>{{ opt.label }}</span>\n </label>\n </fieldset>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst options = computed(() => props.field.options ?? [])\nconst current = computed(() => props.modelValue ?? [])\n\nfunction toggle(value: string, checked: boolean): void {\n const set = new Set(current.value)\n if (checked) set.add(value)\n else set.delete(value)\n emit('update:modelValue', Array.from(set))\n}\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <fieldset\n class=\"dcs-form-checkbox-group\"\n :aria-required=\"field.required\"\n :aria-invalid=\"!!error\"\n >\n <legend class=\"sr-only\">{{ field.label }}</legend>\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n class=\"dcs-form-checkbox\"\n >\n <input\n type=\"checkbox\"\n :name=\"`${field.id}[]`\"\n :value=\"opt.value\"\n :checked=\"current.includes(opt.value)\"\n @change=\"toggle(opt.value, ($event.target as HTMLInputElement).checked)\"\n />\n <span>{{ opt.label }}</span>\n </label>\n </fieldset>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: boolean | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <template #label><span class=\"sr-only\">{{ field.label }}</span></template>\n <label class=\"dcs-form-checkbox-single\" :for=\"inputId\">\n <input\n :id=\"inputId\"\n type=\"checkbox\"\n :name=\"field.id\"\n :checked=\"!!modelValue\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n @change=\"emit('update:modelValue', ($event.target as HTMLInputElement).checked)\"\n />\n <span>{{ field.label }}<span v-if=\"field.required\" aria-hidden=\"true\"> *</span></span>\n </label>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <input\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-date\"\n type=\"date\"\n :name=\"field.id\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :value=\"modelValue ?? ''\"\n @input=\"emit('update:modelValue', ($event.target as HTMLInputElement).value)\"\n @blur=\"emit('blur')\"\n />\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport type { PortalFormAttachmentPolicy, PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n attachmentPolicy?: PortalFormAttachmentPolicy\n modelValue: File | File[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: File | File[] | undefined]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst accept = computed(() => (props.field.validation?.accept ?? props.attachmentPolicy?.accept ?? []).join(','))\nconst maxFiles = computed(() => Math.max(1, Math.floor(props.attachmentPolicy?.maxFiles ?? 1)))\nconst allowsMultiple = computed(() => maxFiles.value > 1)\nconst selectedFiles = computed(() => normalizeFiles(props.modelValue))\nconst previews = ref<Array<{ file: File; url: string; canPreview: boolean }>>([])\n\nfunction normalizeFiles(value: File | File[] | undefined): File[] {\n if (Array.isArray(value)) {\n return value.filter(Boolean)\n }\n return value ? [value] : []\n}\n\nfunction emitFiles(files: File[]): void {\n const capped = files.slice(0, maxFiles.value)\n emit('update:modelValue', allowsMultiple.value ? capped : capped[0])\n}\n\nfunction fileKey(file: File): string {\n return [file.name, file.type, file.size, file.lastModified].join(':')\n}\n\nfunction uniqueFiles(files: File[]): File[] {\n const seen = new Set<string>()\n const out: File[] = []\n for (const file of files) {\n const key = fileKey(file)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n out.push(file)\n }\n return out\n}\n\nfunction onChange(e: Event): void {\n const target = e.target as HTMLInputElement\n const picked = Array.from(target.files ?? []).filter((file) => file.size > 0)\n if (picked.length === 0) {\n return\n }\n emitFiles(allowsMultiple.value ? uniqueFiles([...selectedFiles.value, ...picked]) : picked)\n target.value = ''\n}\n\nfunction removeFile(index: number): void {\n const next = selectedFiles.value.filter((_, i) => i !== index)\n emitFiles(next)\n if (next.length === 0 && inputEl.value) {\n inputEl.value.value = ''\n }\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction revokePreviews(): void {\n for (const preview of previews.value) {\n URL.revokeObjectURL(preview.url)\n }\n previews.value = []\n}\n\nwatch(\n selectedFiles,\n (files) => {\n revokePreviews()\n previews.value = files.map((file) => ({\n file,\n url: URL.createObjectURL(file),\n canPreview: file.type.toLowerCase().startsWith('image/'),\n }))\n },\n { immediate: true },\n)\n\nonBeforeUnmount(revokePreviews)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <input\n ref=\"inputEl\"\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-file\"\n type=\"file\"\n :name=\"field.id\"\n :multiple=\"allowsMultiple\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :accept=\"accept || undefined\"\n @change=\"onChange\"\n />\n\n <p v-if=\"allowsMultiple\" class=\"dcs-form-file__status\">\n {{ selectedFiles.length }} of {{ maxFiles }} files selected\n </p>\n\n <div\n v-if=\"previews.length > 0\"\n class=\"dcs-form-file-preview-grid\"\n aria-live=\"polite\"\n >\n <div\n v-for=\"(preview, index) in previews\"\n :key=\"fileKey(preview.file)\"\n class=\"dcs-form-file-preview\"\n >\n <img\n v-if=\"preview.canPreview\"\n class=\"dcs-form-file-preview__image\"\n :src=\"preview.url\"\n :alt=\"`${preview.file.name} preview`\"\n />\n <div v-else class=\"dcs-form-file-preview__placeholder\" aria-hidden=\"true\">\n File\n </div>\n <div class=\"dcs-form-file-preview__meta\">\n <span class=\"dcs-form-file-preview__name\">{{ preview.file.name }}</span>\n <span class=\"dcs-form-file-preview__size\">{{ formatFileSize(preview.file.size) }}</span>\n </div>\n <button\n type=\"button\"\n class=\"dcs-form-file-preview__remove\"\n :aria-label=\"`Remove ${preview.file.name}`\"\n @click=\"removeFile(index)\"\n >\n Remove\n </button>\n </div>\n </div>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n modelValue: string | number | undefined\n}>()\n</script>\n\n<template>\n <input\n type=\"hidden\"\n :name=\"field.id\"\n :value=\"modelValue ?? (field.defaultValue as string | number | undefined) ?? ''\"\n :data-form-field-key=\"field.id\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n}>()\n</script>\n\n<template>\n <div\n class=\"dcs-form-section\"\n :data-form-field-key=\"field.id\"\n >\n <slot>\n <h3 class=\"dcs-form-section__heading\">{{ field.label }}</h3>\n <p v-if=\"field.helpText\" class=\"dcs-form-section__help\">{{ field.helpText }}</p>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n}>()\n</script>\n\n<template>\n <!--\n `html` is sanitized server-side per the schema; rendering with v-html\n is intentional. Site authors must keep portal-side sanitization on.\n -->\n <div\n class=\"dcs-form-html-block\"\n :data-form-field-key=\"field.id\"\n v-html=\"field.html ?? ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, watch } from 'vue'\nimport type {\n DcsFormSubmitError,\n DcsFormSubmitSuccess,\n PortalFormDefinition,\n PortalFormField,\n} from './types'\nimport { useDcsForm } from './composables/useDcsForm'\nimport { submitFormValues } from './composables/useFormSubmission'\nimport { warnIfInvalid } from './schema/validate'\nimport { loadFormDefinitions } from './loaders/yaml'\n\nimport DcsFormText from './fields/DcsFormText.vue'\nimport DcsFormTextarea from './fields/DcsFormTextarea.vue'\nimport DcsFormSelect from './fields/DcsFormSelect.vue'\nimport DcsFormRadio from './fields/DcsFormRadio.vue'\nimport DcsFormCheckboxGroup from './fields/DcsFormCheckboxGroup.vue'\nimport DcsFormCheckbox from './fields/DcsFormCheckbox.vue'\nimport DcsFormDate from './fields/DcsFormDate.vue'\nimport DcsFormFile from './fields/DcsFormFile.vue'\nimport DcsFormHidden from './fields/DcsFormHidden.vue'\nimport DcsFormSection from './fields/DcsFormSection.vue'\nimport DcsFormHtmlBlock from './fields/DcsFormHtmlBlock.vue'\n\ninterface Props {\n /** Kebab-case form id; matches `.dcs/forms/<formId>.yaml`. */\n formId: string\n /** Site slug used for the submission endpoint path. */\n siteSlug?: string\n /** Override the loaded definition (used by the portal preview iframe). */\n definitionOverride?: PortalFormDefinition\n /** Override the API base URL; defaults to `VITE_DCS_PUBLIC_API`. */\n apiBase?: string\n /** Optional captcha token, attached to the submission payload. */\n captchaToken?: string\n /**\n * Optional override for the YAML modules map. Mostly for tests; in\n * real apps the build-time `import.meta.glob` call below is used.\n */\n formsModules?: Record<string, unknown>\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'submit-success': [event: DcsFormSubmitSuccess]\n 'submit-error': [event: DcsFormSubmitError]\n 'validation-error': [errors: Record<string, string | undefined>]\n}>()\n\n// Eager glob — Vite inlines every site form at build time. Customer\n// sites should configure `vite-plugin-yaml` so YAML is parsed to an\n// object; without it the loader falls back to parsing raw strings.\nconst eagerFormsModules = (import.meta as unknown as {\n glob: (\n pattern: string,\n opts: { eager: true; import: string; query?: string },\n ) => Record<string, unknown>\n}).glob('/.dcs/forms/*.yaml', { eager: true, import: 'default' })\n\nconst definitions = computed(() =>\n loadFormDefinitions(props.formsModules ?? eagerFormsModules),\n)\n\nconst definition = computed<PortalFormDefinition | null>(() => {\n if (props.definitionOverride) return props.definitionOverride\n return definitions.value[props.formId] ?? null\n})\n\nconst isDev = !!(import.meta as unknown as { env?: { DEV?: boolean } }).env?.DEV\n\nwatch(\n definition,\n (def) => {\n if (def) warnIfInvalid(props.formId, def, isDev)\n },\n { immediate: true },\n)\n\n// We always call useDcsForm with *some* definition so hooks render\n// stably; if the form is missing we'll show an error state instead.\nconst safeDefinition = computed<PortalFormDefinition>(\n () =>\n definition.value ?? {\n formId: props.formId,\n submission: { kind: 'lead' },\n fields: [],\n },\n)\n\nconst form = useDcsForm({ definition: safeDefinition.value })\n\n// If the resolved definition changes (e.g. preview iframe updates),\n// re-create derived state by resetting.\nwatch(\n () => safeDefinition.value,\n () => form.reset(),\n)\n\nconst apiBase = computed(\n () =>\n props.apiBase ??\n (import.meta as unknown as { env?: { VITE_DCS_PUBLIC_API?: string } }).env\n ?.VITE_DCS_PUBLIC_API ??\n '',\n)\n\nconst resolvedSiteSlug = computed(\n () =>\n props.siteSlug ??\n (import.meta as unknown as { env?: { VITE_DCS_SITE_SLUG?: string } }).env\n ?.VITE_DCS_SITE_SLUG ??\n '',\n)\n\nconst submitLabel = computed(\n () => safeDefinition.value.submitLabel ?? 'Send',\n)\n\nfunction fieldComponent(field: PortalFormField) {\n switch (field.type) {\n case 'text':\n case 'email':\n case 'tel':\n return DcsFormText\n case 'textarea':\n return DcsFormTextarea\n case 'select':\n case 'multiselect':\n return DcsFormSelect\n case 'radio':\n return DcsFormRadio\n case 'checkbox-group':\n return DcsFormCheckboxGroup\n case 'checkbox':\n return DcsFormCheckbox\n case 'date':\n return DcsFormDate\n case 'file':\n return DcsFormFile\n case 'hidden':\n return DcsFormHidden\n case 'section-heading':\n return DcsFormSection\n case 'html-block':\n return DcsFormHtmlBlock\n default:\n return DcsFormText\n }\n}\n\nconst formEl = ref<HTMLFormElement | null>(null)\n\ndefineExpose({\n values: form.values,\n errors: form.errors,\n validateAll: form.validateAll,\n collectSubmissionValues: form.collectSubmissionValues,\n reset: form.reset,\n})\n\nasync function onSubmit(e: Event): Promise<void> {\n e.preventDefault()\n if (!definition.value) return\n const ok = form.validateAll()\n if (!ok) {\n emit('validation-error', form.errors.value)\n return\n }\n form.submitting.value = true\n form.submitError.value = null\n const payload = {\n formId: props.formId,\n values: form.collectSubmissionValues(),\n captchaToken: props.captchaToken,\n }\n try {\n const result = await submitFormValues({\n apiBase: apiBase.value,\n siteSlug: resolvedSiteSlug.value,\n payload,\n })\n form.submitted.value = true\n emit('submit-success', result)\n } catch (err) {\n const e2 = err as DcsFormSubmitError\n form.submitError.value = e2.error?.message ?? 'Submission failed'\n emit('submit-error', e2)\n } finally {\n form.submitting.value = false\n }\n}\n\nonMounted(() => {\n if (!definition.value) {\n // eslint-disable-next-line no-console\n console.warn(\n `[@duffcloudservices/site-forms] No form definition found for \"${props.formId}\". ` +\n `Expected a YAML at .dcs/forms/${props.formId}.yaml. ` +\n `In customer-site repos the YAML lives above the Vite root, so the ` +\n `internal auto-glob will not find it — pass formsModules explicitly: ` +\n `<DcsForm form-id=\"${props.formId}\" :forms-modules=\"dcsFormsModules\" />. ` +\n `See @duffcloudservices/site-forms README \"Vite setup\" section.`,\n )\n }\n})\n</script>\n\n<template>\n <div v-if=\"!definition\" class=\"dcs-form dcs-form--missing\" :data-form-key=\"formId\">\n <slot name=\"missing\" :form-id=\"formId\">\n <p>Form “{{ formId }}” is not configured.</p>\n </slot>\n </div>\n\n <div v-else-if=\"form.submitted.value\" class=\"dcs-form dcs-form--success\" :data-form-key=\"formId\">\n <slot name=\"success\" :definition=\"definition\">\n <p>{{ definition.successMessage ?? 'Thanks — we received your message.' }}</p>\n </slot>\n </div>\n\n <form\n v-else\n ref=\"formEl\"\n class=\"dcs-form\"\n :data-form-key=\"formId\"\n novalidate\n @submit=\"onSubmit\"\n >\n <slot name=\"header\" :definition=\"definition\" />\n\n <div v-if=\"form.steps.value\" class=\"dcs-form__progress\" aria-live=\"polite\">\n <slot\n name=\"progress\"\n :current=\"form.currentStepIndex.value\"\n :total=\"form.steps.value.length\"\n :step=\"form.currentStep.value\"\n >\n <p>\n Step {{ form.currentStepIndex.value + 1 }} of\n {{ form.steps.value.length }}\n <template v-if=\"form.currentStep.value\">\n — {{ form.currentStep.value.title }}\n </template>\n </p>\n </slot>\n </div>\n\n <div class=\"dcs-form__fields\">\n <component\n :is=\"fieldComponent(field)\"\n v-for=\"field in form.visibleFields.value\"\n :key=\"field.id\"\n :field=\"field\"\n :attachment-policy=\"safeDefinition.attachmentPolicy\"\n :model-value=\"form.values[field.id]\"\n :error=\"form.errors.value[field.id]\"\n @update:model-value=\"(v: unknown) => form.setValue(field.id, v)\"\n @blur=\"form.touch(field.id)\"\n />\n </div>\n\n <div v-if=\"form.submitError.value\" class=\"dcs-form__submit-error\" role=\"alert\">\n {{ form.submitError.value }}\n </div>\n\n <div class=\"dcs-form__actions\">\n <slot\n name=\"actions\"\n :is-first-step=\"form.isFirstStep.value\"\n :is-last-step=\"form.isLastStep.value\"\n :submitting=\"form.submitting.value\"\n :prev=\"form.prev\"\n :next=\"form.next\"\n >\n <button\n v-if=\"form.steps.value && !form.isFirstStep.value\"\n type=\"button\"\n class=\"dcs-form__btn dcs-form__btn--prev\"\n @click=\"form.prev()\"\n >\n Previous\n </button>\n <button\n v-if=\"form.steps.value && !form.isLastStep.value\"\n type=\"button\"\n class=\"dcs-form__btn dcs-form__btn--next\"\n @click=\"form.next()\"\n >\n Next\n </button>\n <button\n v-if=\"!form.steps.value || form.isLastStep.value\"\n type=\"submit\"\n class=\"dcs-form__btn dcs-form__btn--submit\"\n :disabled=\"form.submitting.value\"\n >\n {{ form.submitting.value ? 'Sending…' : submitLabel }}\n </button>\n </slot>\n </div>\n </form>\n</template>\n","import type { PortalFormDefinition, PortalFormField } from './types'\n\nexport type StandardFormPreset = 'contact' | 'revenue-contractor' | 'resume-submission' | 'custom'\n\nexport interface BuildStandardFormOptions {\n formId?: string\n submitLabel?: string\n successMessage?: string\n leadCategory?: string\n}\n\nexport const STANDARD_FORM_PRESET_META: Record<StandardFormPreset, { label: string; description: string }> = {\n contact: {\n label: 'Contact',\n description: 'Canonical contact form with standard contact fields.',\n },\n 'revenue-contractor': {\n label: 'Revenue contractor',\n description: 'Contact fields plus a required project summary and optional image upload.',\n },\n 'resume-submission': {\n label: 'Resume submission',\n description: 'Candidate contact fields plus a required resume upload.',\n },\n custom: {\n label: 'Custom / free-form',\n description: 'Flexible starter that stays fully editable for questionnaires and bespoke intake.',\n },\n}\n\nconst buildContactFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', width: 'half' },\n { id: 'company', type: 'text', role: 'contact-company', label: 'Company', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'message',\n label: 'How can we help?',\n required: true,\n width: 'full',\n validation: { minLength: 10, maxLength: 2000 },\n },\n]\n\nconst buildRevenueContractorFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', required: true, width: 'half' },\n { id: 'company', type: 'text', role: 'contact-company', label: 'Company', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'summary',\n label: 'Project summary',\n helpText: 'Tell us what you want built, repaired, or updated.',\n required: true,\n width: 'full',\n validation: { minLength: 20, maxLength: 4000 },\n },\n {\n id: 'project-image',\n type: 'file',\n role: 'image-attachments',\n label: 'Reference image',\n helpText: 'Optional. Upload one photo or inspiration image to help us understand the request.',\n width: 'full',\n validation: { accept: ['image/*'] },\n },\n]\n\nconst buildResumeSubmissionFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', width: 'half' },\n { id: 'position', type: 'text', label: 'Role you are applying for', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'message',\n label: 'Anything else we should know?',\n width: 'full',\n validation: { maxLength: 2000 },\n },\n {\n id: 'resume',\n type: 'file',\n role: 'resume',\n label: 'Resume',\n required: true,\n width: 'full',\n validation: {\n accept: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n ],\n },\n },\n]\n\nconst buildCustomFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', label: 'Phone', width: 'half' },\n {\n id: 'message',\n type: 'textarea',\n label: 'Message',\n required: true,\n width: 'full',\n validation: { minLength: 10, maxLength: 2000 },\n },\n]\n\nexport function buildStandardFormDefinition(\n preset: StandardFormPreset,\n options: BuildStandardFormOptions = {},\n): PortalFormDefinition {\n const resolvedPreset = preset ?? 'custom'\n\n switch (resolvedPreset) {\n case 'contact':\n return {\n formId: options.formId ?? 'contact',\n formKind: 'contact',\n submitLabel: options.submitLabel ?? 'Send',\n successMessage: options.successMessage ?? 'Thanks — we’ll be in touch shortly.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n fields: buildContactFields(),\n }\n\n case 'revenue-contractor':\n return {\n formId: options.formId ?? 'contact',\n formKind: 'revenue-contractor',\n submitLabel: options.submitLabel ?? 'Request estimate',\n successMessage: options.successMessage ?? 'Thanks — we’ll review your project and follow up soon.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n attachmentPolicy: {\n expected: true,\n required: false,\n maxFiles: 5,\n accept: ['image/*'],\n },\n fields: buildRevenueContractorFields(),\n }\n\n case 'resume-submission':\n return {\n formId: options.formId ?? 'resume',\n formKind: 'resume-submission',\n submitLabel: options.submitLabel ?? 'Submit resume',\n successMessage: options.successMessage ?? 'Thanks — your application was received.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n attachmentPolicy: {\n expected: true,\n required: true,\n maxFiles: 1,\n accept: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n ],\n },\n fields: buildResumeSubmissionFields(),\n }\n\n default:\n return {\n formId: options.formId ?? 'custom-form',\n formKind: 'freeform',\n submitLabel: options.submitLabel ?? 'Send',\n successMessage: options.successMessage ?? 'Thanks — we received your submission.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n fields: buildCustomFields(),\n }\n }\n}\n"],"names":["isFieldVisible","field","values","validateField","value","attachmentPolicy","normalizedValue","isEmpty","v","files","filesFromValue","maxFiles","maxFileSizeBytes","accept","oversized","file","formatBytes","rejected","isAcceptedFile","validateForm","def","fieldIds","errors","ids","err","hasErrors","e","item","name","contentType","rule","normalized","bytes","defaultsFor","out","f","useDcsForm","opts","definition","reactive","ref","touched","submitting","submitted","submitError","currentStepIndex","fields","computed","steps","currentStep","s","currentStepFields","step","isFirstStep","isLastStep","visibleFields","setValue","id","touch","validateScope","scopeFieldIds","next","merged","validateCurrentScope","scope","validateAll","prev","reset","fresh","k","collectSubmissionValues","submitFormValues","apiBase","siteSlug","payload","retries","fetchImpl","url","hasFile","valueHasFile","lastError","lastStatus","attempt","init","buildFormData","res","body","safeJson","safeText","fd","key","validator","getValidator","ajv","Ajv","addFormats","schema","validateFormDefinition","valid","warnIfInvalid","formId","isDev","result","loadFormDefinitions","modules","path","mod","extractFormId","parseModule","yaml","maybeDefault","parseFormYaml","raw","_createElementBlock","_normalizeClass","__props","_renderSlot","_ctx","_hoisted_3","_openBlock","_hoisted_4","_toDisplayString","_hoisted_5","props","emit","__emit","inputId","inputType","_createBlock","DcsFormFieldWrapper","_createElementVNode","$event","isMulti","options","onChange","sel","opt","_hoisted_2","_Fragment","_renderList","current","toggle","checked","set","_hoisted_1","_createTextVNode","inputEl","allowsMultiple","selectedFiles","normalizeFiles","previews","emitFiles","capped","fileKey","uniqueFiles","seen","target","picked","removeFile","index","_","i","formatFileSize","revokePreviews","preview","watch","onBeforeUnmount","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","eagerFormsModules","definitions","safeDefinition","form","__vite_import_meta_env__","resolvedSiteSlug","submitLabel","fieldComponent","DcsFormText","DcsFormTextarea","DcsFormSelect","DcsFormRadio","DcsFormCheckboxGroup","DcsFormCheckbox","DcsFormDate","DcsFormFile","DcsFormHidden","DcsFormSection","DcsFormHtmlBlock","formEl","__expose","onSubmit","e2","onMounted","_unref","_resolveDynamicComponent","_cache","STANDARD_FORM_PRESET_META","buildContactFields","buildRevenueContractorFields","buildResumeSubmissionFields","buildCustomFields","buildStandardFormDefinition","preset"],"mappings":"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"}
|
|
1
|
+
{"version":3,"file":"index.js","sources":["../../dcs-ui/src/sound/config.ts","../../dcs-ui/src/sound/synth.ts","../../dcs-ui/src/sound/roles.ts","../../dcs-ui/src/sound/engine.ts","../../dcs-ui/src/sound/useUiSound.ts","../src/composables/useFormValidation.ts","../src/composables/useDcsForm.ts","../src/composables/readExpectedJson.ts","../src/composables/useFormSubmission.ts","../src/composables/useSitePhiPosture.ts","../src/schema/validate.ts","../src/loaders/yaml.ts","../src/fields/DcsFormFieldWrapper.vue","../src/fields/DcsFormText.vue","../src/fields/DcsFormTextarea.vue","../src/fields/DcsFormSelect.vue","../src/fields/DcsFormRadio.vue","../src/fields/DcsFormCheckboxGroup.vue","../src/fields/DcsFormCheckbox.vue","../src/fields/DcsFormDate.vue","../src/fields/DcsFormFile.vue","../src/fields/DcsFormHidden.vue","../src/fields/DcsFormSection.vue","../src/fields/DcsFormHtmlBlock.vue","../src/DcsForm.vue","../src/presets.ts"],"sourcesContent":["// Reactive, localStorage-backed sound preferences (key `dcs.sound`).\n//\n// The library default is SILENT (enabled:false) — that is the operational-\n// surface contract. Surfaces that opt into default-on (the portal, per the\n// Q-72=B carve-out) call configureSoundDefaults() once at startup; it seeds\n// the defaults ONLY when the user has no stored preference yet, so a user's\n// explicit opt-out is never overwritten on the next visit.\n\nimport { ref, watch } from 'vue'\nimport type { SoundCategory, SoundConfig } from './types'\n\nexport const STORAGE_KEY = 'dcs.sound'\n\nconst LIBRARY_DEFAULT: SoundConfig = {\n enabled: false,\n userSet: false,\n prmOverride: false,\n volume: 0.3,\n categories: {\n interaction: true,\n overlay: true,\n navigation: true,\n notification: true,\n hero: false,\n },\n hintShown: false,\n}\n\nfunction clampVolume(v: unknown): number {\n const n = typeof v === 'number' && Number.isFinite(v) ? v : LIBRARY_DEFAULT.volume\n return Math.min(0.8, Math.max(0, n))\n}\n\n/** Merge a stored/partial object over the library default, defensively. */\nfunction normalize(raw: Partial<SoundConfig> | null | undefined): SoundConfig {\n const base = LIBRARY_DEFAULT\n const cats = (raw?.categories ?? {}) as Partial<Record<SoundCategory, boolean>>\n return {\n enabled: typeof raw?.enabled === 'boolean' ? raw.enabled : base.enabled,\n userSet: typeof raw?.userSet === 'boolean' ? raw.userSet : base.userSet,\n prmOverride: typeof raw?.prmOverride === 'boolean' ? raw.prmOverride : base.prmOverride,\n volume: clampVolume(raw?.volume),\n categories: {\n interaction: cats.interaction ?? base.categories.interaction,\n overlay: cats.overlay ?? base.categories.overlay,\n navigation: cats.navigation ?? base.categories.navigation,\n notification: cats.notification ?? base.categories.notification,\n hero: cats.hero ?? base.categories.hero,\n },\n hintShown: typeof raw?.hintShown === 'boolean' ? raw.hintShown : base.hintShown,\n }\n}\n\nfunction readStored(): SoundConfig | null {\n if (typeof window === 'undefined' || !window.localStorage) {\n return null\n }\n try {\n const raw = window.localStorage.getItem(STORAGE_KEY)\n if (!raw) {\n return null\n }\n return normalize(JSON.parse(raw) as Partial<SoundConfig>)\n } catch {\n return null\n }\n}\n\nconst stored = readStored()\n\n/** The single reactive config instance shared across every useUiSound() call. */\nexport const config = ref<SoundConfig>(stored ?? normalize(null))\n\n/** True when the user already has a persisted preference (do not re-seed). */\nlet hasPersisted = stored !== null\n\nfunction persist(next: SoundConfig): void {\n if (typeof window === 'undefined' || !window.localStorage) {\n return\n }\n try {\n window.localStorage.setItem(STORAGE_KEY, JSON.stringify(next))\n hasPersisted = true\n } catch {\n /* storage full / disabled — keep running in-memory */\n }\n}\n\n// Persist every change (deep — categories is nested).\nwatch(config, (next) => persist(next), { deep: true })\n\n/**\n * Seed surface-level defaults (e.g. portal default-ON at subtle gain) WITHOUT\n * clobbering an existing user preference. Idempotent and safe to call once at\n * app startup before the first useUiSound().\n */\nexport function configureSoundDefaults(defaults: Partial<SoundConfig>): void {\n if (hasPersisted) {\n return\n }\n config.value = normalize({ ...config.value, ...defaults })\n // First seed is written eagerly so the mute UI reflects a real stored value.\n persist(config.value)\n}\n\n/** Cross-tab sync: mirror external `dcs.sound` writes into the reactive config. */\nif (typeof window !== 'undefined' && window.addEventListener) {\n window.addEventListener('storage', (e) => {\n if (e.key === STORAGE_KEY && e.newValue) {\n try {\n config.value = normalize(JSON.parse(e.newValue) as Partial<SoundConfig>)\n hasPersisted = true\n } catch {\n /* ignore malformed external write */\n }\n }\n })\n}\n","// Low-level Web Audio synthesis primitives. Every UI sound is generated here\n// at runtime — no audio files, no network, no bundle weight beyond this code.\n//\n// These helpers encode the dcs-product-sound implementation rules:\n// - gain-set-before-ramp every ramp preceded by setValueAtTime()\n// - gain-no-zero-target exponential ramps target 0.001, never 0\n// - capture-now-once callers pass a single `now`; we derive from it\n// - stop-after-envelope osc.stop(now + dur + tail) to avoid end clicks\n// - exponential-over-linear exponential ramps for gain/frequency\n// - node-cleanup BufferSources disconnect their chain onended\n// - oscillator-for-tonal / noise-for-percussion\n// - volume-ceiling callers clamp; filter Q ≤ 10 (no ringing)\n\n/** Tail (seconds) added after the envelope end before stopping the node. */\nconst STOP_TAIL = 0.02\nconst MIN_GAIN = 0.0001\n\ninterface ToneOpts {\n freq: number\n type?: OscillatorType\n dur?: number\n gain?: number\n /** Attack time in seconds (soft by default — \"felt mallet\", not a click). */\n attack?: number\n /** Optional exponential pitch glide target by envelope end. */\n glideTo?: number\n}\n\n/** A single enveloped oscillator note (tonal roles: toggles, confirms, tones). */\nexport function playTone(\n ctx: AudioContext,\n dest: AudioNode,\n opts: ToneOpts,\n now: number,\n): void {\n const { freq, type = 'sine', dur = 0.15, gain = 0.2, attack = 0.01, glideTo } = opts\n const osc = ctx.createOscillator()\n const amp = ctx.createGain()\n\n osc.type = type\n osc.frequency.setValueAtTime(freq, now)\n if (glideTo) {\n osc.frequency.exponentialRampToValueAtTime(glideTo, now + dur)\n }\n\n amp.gain.setValueAtTime(MIN_GAIN, now)\n amp.gain.exponentialRampToValueAtTime(gain, now + attack)\n amp.gain.exponentialRampToValueAtTime(0.001, now + dur)\n\n osc.connect(amp).connect(dest)\n osc.start(now)\n osc.stop(now + dur + STOP_TAIL)\n osc.onended = () => {\n try {\n osc.disconnect()\n amp.disconnect()\n } catch {\n /* already torn down */\n }\n }\n}\n\ninterface BellOpts {\n freq: number\n /** Modulator:carrier frequency ratio. */\n ratio?: number\n /** FM index (modulation depth in Hz); decays to give a bell-like attack. */\n index?: number\n dur?: number\n gain?: number\n}\n\n/** FM bell — the notification/info character (bell-like, warm, non-alarming). */\nexport function playFmBell(\n ctx: AudioContext,\n dest: AudioNode,\n opts: BellOpts,\n now: number,\n): void {\n const { freq, ratio = 2, index = 120, dur = 0.4, gain = 0.2 } = opts\n const carrier = ctx.createOscillator()\n const mod = ctx.createOscillator()\n const modGain = ctx.createGain()\n const amp = ctx.createGain()\n\n carrier.type = 'sine'\n mod.type = 'sine'\n carrier.frequency.setValueAtTime(freq, now)\n mod.frequency.setValueAtTime(freq * ratio, now)\n\n modGain.gain.setValueAtTime(index, now)\n modGain.gain.exponentialRampToValueAtTime(1, now + dur)\n\n amp.gain.setValueAtTime(MIN_GAIN, now)\n amp.gain.exponentialRampToValueAtTime(gain, now + 0.012)\n amp.gain.exponentialRampToValueAtTime(0.001, now + dur)\n\n mod.connect(modGain).connect(carrier.frequency)\n carrier.connect(amp).connect(dest)\n\n mod.start(now)\n carrier.start(now)\n mod.stop(now + dur + STOP_TAIL)\n carrier.stop(now + dur + STOP_TAIL)\n carrier.onended = () => {\n try {\n carrier.disconnect()\n mod.disconnect()\n modGain.disconnect()\n amp.disconnect()\n } catch {\n /* already torn down */\n }\n }\n}\n\ninterface NoiseOpts {\n dur?: number\n gain?: number\n /** Bandpass centre frequency. */\n cutoff?: number\n /** Filter Q — kept ≤ 10 so the burst never rings. */\n q?: number\n /** Optional exponential filter sweep target (whoosh). */\n sweepTo?: number\n}\n\n/** Filtered noise burst — percussive character (taps, whooshes, transitions). */\nexport function playNoiseBurst(\n ctx: AudioContext,\n dest: AudioNode,\n opts: NoiseOpts,\n now: number,\n): void {\n const { dur = 0.08, gain = 0.2, cutoff = 2000, q = 1, sweepTo } = opts\n const frames = Math.max(1, Math.floor(ctx.sampleRate * dur))\n const buffer = ctx.createBuffer(1, frames, ctx.sampleRate)\n const data = buffer.getChannelData(0)\n for (let i = 0; i < frames; i++) {\n data[i] = Math.random() * 2 - 1\n }\n\n const src = ctx.createBufferSource()\n src.buffer = buffer\n\n const filter = ctx.createBiquadFilter()\n filter.type = 'bandpass'\n filter.frequency.setValueAtTime(cutoff, now)\n filter.Q.value = Math.min(q, 10)\n if (sweepTo) {\n filter.frequency.exponentialRampToValueAtTime(sweepTo, now + dur)\n }\n\n const amp = ctx.createGain()\n amp.gain.setValueAtTime(gain, now)\n amp.gain.exponentialRampToValueAtTime(0.001, now + dur)\n\n src.connect(filter).connect(amp).connect(dest)\n src.start(now)\n src.stop(now + dur + STOP_TAIL)\n // BufferSources do not auto-disconnect — clean the whole chain on end.\n src.onended = () => {\n try {\n src.disconnect()\n filter.disconnect()\n amp.disconnect()\n } catch {\n /* already torn down */\n }\n }\n}\n","// The semantic role map: role name → category, base gain, and render recipe.\n//\n// Character rules (dcs-product-sound): success = ascending major third,\n// error = descending/darker, warning = double pulse, notification = bell-like\n// FM, tap = filtered noise burst, whoosh = filtered noise sweep. All tonal\n// content stays in one key (C major family) so the pack coheres, and inside the\n// 200Hz–2kHz fundamental band for accessibility (age-related HF loss).\n//\n// Base gains are pre-master; the engine multiplies by config.volume and clamps\n// at 0.8. With the portal's subtle-tier master (0.3), notification roles land\n// at ~0.045–0.084 effective — the subtle band the carve-out requires, while the\n// loudness hierarchy (error > warning > success > info > interaction) holds.\n\nimport type { RoleSpec, SoundRole } from './types'\nimport { playFmBell, playNoiseBurst, playTone } from './synth'\n\n// C-major family fundamentals (Hz).\nconst C5 = 523.25\nconst D5 = 587.33\nconst E5 = 659.25\nconst G5 = 783.99\nconst C6 = 1046.5\nconst G4 = 392.0\nconst A4 = 440.0\nconst D4 = 293.66\n\nexport const ROLES: Record<SoundRole, RoleSpec> = {\n // ── interaction ────────────────────────────────────────────────────────\n 'interaction.tap': {\n category: 'interaction',\n gain: 0.25,\n duration: 0.06,\n render: (ctx, dest, now, gain) =>\n playNoiseBurst(ctx, dest, { dur: 0.05, gain, cutoff: 1800, q: 1 }, now),\n },\n 'interaction.subtle': {\n category: 'interaction',\n gain: 0.12,\n duration: 0.04,\n render: (ctx, dest, now, gain) =>\n playNoiseBurst(ctx, dest, { dur: 0.035, gain, cutoff: 2400, q: 0.7 }, now),\n },\n 'interaction.toggle': {\n category: 'interaction',\n gain: 0.2,\n duration: 0.07,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: E5, type: 'triangle', dur: 0.07, gain, attack: 0.005 }, now),\n },\n 'interaction.confirm': {\n category: 'interaction',\n gain: 0.3,\n duration: 0.09,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: C5, type: 'sine', dur: 0.09, gain, attack: 0.008 }, now),\n },\n\n // ── overlay ────────────────────────────────────────────────────────────\n 'overlay.open': {\n category: 'overlay',\n gain: 0.18,\n duration: 0.18,\n render: (ctx, dest, now, gain) =>\n playNoiseBurst(ctx, dest, { dur: 0.18, gain, cutoff: 700, q: 0.8, sweepTo: 2200 }, now),\n },\n 'overlay.close': {\n category: 'overlay',\n gain: 0.18,\n duration: 0.18,\n render: (ctx, dest, now, gain) =>\n playNoiseBurst(ctx, dest, { dur: 0.18, gain, cutoff: 2200, q: 0.8, sweepTo: 600 }, now),\n },\n 'overlay.expand': {\n category: 'overlay',\n gain: 0.16,\n duration: 0.16,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: C5, type: 'sine', dur: 0.16, gain, glideTo: E5 }, now),\n },\n 'overlay.collapse': {\n category: 'overlay',\n gain: 0.16,\n duration: 0.16,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: E5, type: 'sine', dur: 0.16, gain, glideTo: C5 }, now),\n },\n\n // ── navigation ─────────────────────────────────────────────────────────\n 'navigation.forward': {\n category: 'navigation',\n gain: 0.2,\n duration: 0.14,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: D5, type: 'sine', dur: 0.13, gain, glideTo: G5 }, now),\n },\n 'navigation.backward': {\n category: 'navigation',\n gain: 0.2,\n duration: 0.14,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: G5, type: 'sine', dur: 0.13, gain, glideTo: D5 }, now),\n },\n 'navigation.tab': {\n category: 'navigation',\n gain: 0.18,\n duration: 0.1,\n render: (ctx, dest, now, gain) =>\n playTone(ctx, dest, { freq: A4, type: 'triangle', dur: 0.09, gain, attack: 0.005 }, now),\n },\n\n // ── notification ─────────────────────────────────────────────────────────\n 'notification.info': {\n category: 'notification',\n gain: 0.15,\n duration: 0.4,\n render: (ctx, dest, now, gain) =>\n playFmBell(ctx, dest, { freq: E5, ratio: 2, index: 90, dur: 0.42, gain }, now),\n },\n 'notification.success': {\n // Ascending major third (C5 → E5) — unmistakably \"up\" vs the error contour.\n category: 'notification',\n gain: 0.2,\n duration: 0.34,\n render: (ctx, dest, now, gain) => {\n playTone(ctx, dest, { freq: C5, type: 'sine', dur: 0.14, gain, attack: 0.008 }, now)\n playTone(ctx, dest, { freq: E5, type: 'sine', dur: 0.2, gain, attack: 0.008 }, now + 0.11)\n },\n },\n 'notification.warning': {\n // Double pulse on one note — attention without alarm.\n category: 'notification',\n gain: 0.24,\n duration: 0.3,\n render: (ctx, dest, now, gain) => {\n playTone(ctx, dest, { freq: A4, type: 'triangle', dur: 0.1, gain, attack: 0.006 }, now)\n playTone(ctx, dest, { freq: A4, type: 'triangle', dur: 0.1, gain, attack: 0.006 }, now + 0.16)\n },\n },\n 'notification.error': {\n // Descending, darker (G4 → D4, triangle) — never a harsh klaxon.\n category: 'notification',\n gain: 0.28,\n duration: 0.42,\n render: (ctx, dest, now, gain) => {\n playTone(ctx, dest, { freq: G4, type: 'triangle', dur: 0.16, gain, attack: 0.008 }, now)\n playTone(ctx, dest, { freq: D4, type: 'triangle', dur: 0.26, gain, attack: 0.008 }, now + 0.13)\n },\n },\n\n // ── hero (disabled by default even when sound is on) ──────────────────────\n 'hero.complete': {\n category: 'hero',\n gain: 0.4,\n duration: 0.9,\n render: (ctx, dest, now, gain) => {\n playTone(ctx, dest, { freq: C5, type: 'sine', dur: 0.2, gain, attack: 0.01 }, now)\n playTone(ctx, dest, { freq: E5, type: 'sine', dur: 0.2, gain, attack: 0.01 }, now + 0.16)\n playTone(ctx, dest, { freq: G5, type: 'sine', dur: 0.4, gain, attack: 0.01 }, now + 0.32)\n },\n },\n 'hero.milestone': {\n category: 'hero',\n gain: 0.5,\n duration: 1.3,\n render: (ctx, dest, now, gain) => {\n playTone(ctx, dest, { freq: C5, type: 'sine', dur: 0.22, gain, attack: 0.01 }, now)\n playTone(ctx, dest, { freq: E5, type: 'sine', dur: 0.22, gain, attack: 0.01 }, now + 0.18)\n playTone(ctx, dest, { freq: G5, type: 'sine', dur: 0.22, gain, attack: 0.01 }, now + 0.36)\n playTone(ctx, dest, { freq: C6, type: 'sine', dur: 0.55, gain, attack: 0.01 }, now + 0.54)\n },\n },\n}\n","// The singleton sound engine: one AudioContext per app, lazily created inside a\n// user gesture, gesture-gate tolerant, throttled, and gated by config +\n// accessibility + embedding. Components never touch AudioContext directly —\n// they call play(role) and the engine owns everything else.\n\nimport { config } from './config'\nimport { ROLES } from './roles'\nimport type { PlayOptions, SoundCategory, SoundRole } from './types'\n\n/** Max one sound per role per this window (dcs-product-sound rule: ~120ms). */\nconst THROTTLE_MS = 120\n\nlet ctx: AudioContext | null = null\nlet master: GainNode | null = null\nlet unlockBound = false\n/** True once a real user gesture has fired (pointerdown/keydown/touchstart). */\nlet gestureSeen = false\n\nconst lastPlayed = new Map<SoundRole, number>()\nconst didPlayListeners = new Set<() => void>()\n\n/**\n * True when running inside an iframe/embedded context. Hard-silent there\n * (customer sites render inside the portal editor iframe). Never assume\n * `window.top` is reachable — a cross-origin access throws, which we treat as\n * \"embedded\" (fail closed to silence).\n */\nfunction isEmbedded(): boolean {\n if (typeof window === 'undefined') {\n return true\n }\n try {\n if (window.frameElement !== null) {\n return true\n }\n } catch {\n return true\n }\n try {\n return window.self !== window.top\n } catch {\n return true\n }\n}\n\n/** Live check of the OS/browser `prefers-reduced-motion: reduce` signal. */\nexport function prefersReducedMotion(): boolean {\n if (typeof window === 'undefined' || !window.matchMedia) {\n return false\n }\n return window.matchMedia('(prefers-reduced-motion: reduce)').matches\n}\n\nfunction ensureContext(): AudioContext | null {\n if (typeof window === 'undefined') {\n return null\n }\n if (ctx) {\n return ctx\n }\n const Ctor =\n window.AudioContext ??\n (window as unknown as { webkitAudioContext?: typeof AudioContext }).webkitAudioContext\n if (!Ctor) {\n return null\n }\n try {\n ctx = new Ctor()\n master = ctx.createGain()\n master.gain.value = 1\n master.connect(ctx.destination)\n } catch {\n ctx = null\n master = null\n }\n return ctx\n}\n\n/**\n * Bind one-time gesture listeners that unlock (resume) the AudioContext on the\n * user's first interaction. Browsers block audio until a gesture; this defers\n * context creation to a valid moment and tolerates rejection silently — no\n * console spam, no retry loop (gesture-gate rule).\n */\nexport function bindUnlock(): void {\n if (unlockBound || typeof window === 'undefined') {\n return\n }\n unlockBound = true\n const events: Array<keyof WindowEventMap> = ['pointerdown', 'keydown', 'touchstart']\n const handler = () => {\n gestureSeen = true\n const c = ensureContext()\n if (c && c.state === 'suspended') {\n void c.resume().catch(() => {\n /* still gated — a later gesture will retry via the next event */\n })\n }\n // Self-remove once the context exists and is (or is becoming) running.\n if (c && c.state !== 'suspended') {\n events.forEach((ev) => window.removeEventListener(ev, handler))\n }\n }\n events.forEach((ev) => window.addEventListener(ev, handler, { passive: true }))\n}\n\n/** Subscribe to \"a sound actually played\" (used for the one-time portal hint). */\nexport function onDidPlay(listener: () => void): () => void {\n didPlayListeners.add(listener)\n return () => didPlayListeners.delete(listener)\n}\n\nfunction categoryOf(role: SoundRole): SoundCategory {\n return ROLES[role].category\n}\n\n/**\n * Full gating decision — the single source of truth for \"may this sound?\".\n * Exported for white-box unit testing of the gate (see engine.spec.ts); it is\n * NOT part of the package's public surface (`index.ts` does not re-export it).\n */\nexport function shouldPlay(role: SoundRole, opts?: PlayOptions): boolean {\n if (typeof document === 'undefined') {\n return false\n }\n const spec = ROLES[role]\n if (!spec) {\n return false\n }\n // Hard-silent in iframe/embedded contexts (rule beats every preference).\n if (isEmbedded()) {\n return false\n }\n const c = config.value\n if (!c.enabled) {\n return false\n }\n // prefers-reduced-motion auto-mutes UNLESS the user explicitly ENABLED sound\n // while the signal was active (prmOverride). Merely muting, unmuting while\n // PRM was off, or tweaking a category never defeats the auto-mute.\n if (prefersReducedMotion() && !c.prmOverride) {\n return false\n }\n const category = spec.category\n if (!c.categories[category]) {\n return false\n }\n // Suppress non-notification roles while the tab is hidden; notification roles\n // are exactly the \"you were in another tab\" case, so they are allowed.\n if (document.hidden && category !== 'notification') {\n return false\n }\n if (!opts?.force) {\n const last = lastPlayed.get(role) ?? 0\n if (performance.now() - last < THROTTLE_MS) {\n return false\n }\n }\n return true\n}\n\n/**\n * Request a sound by semantic role. Returns true only when a sound was actually\n * emitted (all gates passed AND the context was running). Never throws.\n */\nexport function play(role: SoundRole, opts?: PlayOptions): boolean {\n if (!shouldPlay(role, opts)) {\n return false\n }\n // Never construct an AudioContext outside a user gesture (e.g. a WS-driven\n // toast before any interaction) — Chrome logs an autoplay warning for that.\n // Bail silently; the unlock handler creates the context on the first gesture.\n if (!ctx && !gestureSeen) {\n return false\n }\n const c = ensureContext()\n if (!c || !master) {\n return false\n }\n // If still suspended (no gesture yet), attempt an async resume and bail for\n // now — we cannot emit synchronously before the gate lifts. A later, post-\n // gesture call will succeed. This keeps the very first pre-interaction event\n // silent instead of throwing or queuing a surprise chime.\n if (c.state === 'suspended') {\n void c.resume().catch(() => {})\n return false\n }\n\n const spec = ROLES[role]\n lastPlayed.set(role, performance.now())\n const now = c.currentTime\n const finalGain = Math.min(0.8, spec.gain * config.value.volume)\n try {\n spec.render(c, master, now, finalGain)\n } catch {\n return false\n }\n\n didPlayListeners.forEach((fn) => {\n try {\n fn()\n } catch {\n /* listener errors must not break playback */\n }\n })\n return true\n}\n\n/** Test/diagnostic hook: is the context live and running? */\nexport function isRunning(): boolean {\n return ctx?.state === 'running'\n}\n","// The public composable. Components call `useUiSound()` and get a play()\n// function plus reactive, writable preference state for a mute/volume UI. The\n// engine (singleton) owns synthesis, gating, throttle, and persistence — this\n// is a thin, reactive facade over it.\n\nimport { computed, ref } from 'vue'\nimport { config } from './config'\nimport { bindUnlock, onDidPlay, play, prefersReducedMotion } from './engine'\nimport type { PlayOptions, SoundCategory, SoundRole } from './types'\n\n// Reactive mirror of `prefers-reduced-motion: reduce` so UI (mute icons,\n// tooltips) can reflect the auto-mute live. The engine itself always queries\n// the media state directly; this ref exists purely for reactivity.\nconst reducedMotionActive = ref(false)\nif (typeof window !== 'undefined' && typeof window.matchMedia === 'function') {\n try {\n const mq = window.matchMedia('(prefers-reduced-motion: reduce)')\n reducedMotionActive.value = mq.matches\n mq.addEventListener?.('change', (e) => {\n reducedMotionActive.value = e.matches\n })\n } catch {\n /* matchMedia unavailable — treat as no-preference */\n }\n}\n\n/**\n * The single mutation path for the master enable. An explicit ENABLE performed\n * while `prefers-reduced-motion` is active is a knowing override and records\n * `prmOverride`; an explicit mute withdraws it. Enabling while PRM is off never\n * sets the override — if the user later turns on reduced motion, sounds\n * auto-mute again (that is the documented contract).\n */\nfunction applyEnabled(value: boolean): void {\n config.value.enabled = value\n config.value.userSet = true\n if (value) {\n if (prefersReducedMotion()) {\n config.value.prmOverride = true\n }\n } else {\n config.value.prmOverride = false\n }\n}\n\nexport interface UseUiSound {\n /** Play a sound by semantic role. Returns true if a sound was emitted. */\n play: (role: SoundRole, opts?: PlayOptions) => boolean\n /** Master on/off (writable). Setting it marks the preference user-explicit. */\n enabled: import('vue').WritableComputedRef<boolean>\n /** Master volume 0..0.8 (writable). */\n volume: import('vue').WritableComputedRef<number>\n /** True once any sound has actually played and the one-time hint is due. */\n hintShown: import('vue').ComputedRef<boolean>\n /**\n * True while `prefers-reduced-motion` is actively auto-muting (signal on and\n * the user has not knowingly overridden it). Mute UIs must reflect this —\n * `enabled` alone can read true while the engine is silent.\n */\n mutedByReducedMotion: import('vue').ComputedRef<boolean>\n /** Toggle master on/off in one call (marks user-explicit). */\n toggleMute: () => void\n /** Explicitly set master enable (marks user-explicit). */\n setEnabled: (value: boolean) => void\n /** Set master volume (clamped 0..0.8). */\n setVolume: (value: number) => void\n /** Read a per-category enable. */\n isCategoryEnabled: (category: SoundCategory) => boolean\n /** Set a per-category enable (marks user-explicit). */\n setCategory: (category: SoundCategory, value: boolean) => void\n /** Mark the one-time hint as shown (persisted). */\n markHintShown: () => void\n /** Subscribe to \"a sound actually played\"; returns an unsubscribe fn. */\n onDidPlay: (listener: () => void) => () => void\n}\n\nexport function useUiSound(): UseUiSound {\n // Ensure gesture-unlock listeners exist the moment any surface uses sound.\n bindUnlock()\n\n const enabled = computed<boolean>({\n get: () => config.value.enabled,\n set: (value) => applyEnabled(value),\n })\n\n const volume = computed<number>({\n get: () => config.value.volume,\n set: (value) => {\n config.value.volume = Math.min(0.8, Math.max(0, value))\n },\n })\n\n const hintShown = computed<boolean>(() => config.value.hintShown)\n\n const mutedByReducedMotion = computed<boolean>(\n () => reducedMotionActive.value && !config.value.prmOverride,\n )\n\n return {\n play,\n enabled,\n volume,\n hintShown,\n mutedByReducedMotion,\n toggleMute: () => applyEnabled(!config.value.enabled),\n setEnabled: (value) => applyEnabled(value),\n setVolume: (value) => {\n config.value.volume = Math.min(0.8, Math.max(0, value))\n },\n isCategoryEnabled: (category) => config.value.categories[category],\n setCategory: (category, value) => {\n // Category tweaks are user-explicit metadata but NEVER a PRM override —\n // only an explicit master enable while PRM is active records that intent.\n config.value.categories[category] = value\n config.value.userSet = true\n },\n markHintShown: () => {\n config.value.hintShown = true\n },\n onDidPlay,\n }\n}\n","import type {\n PortalFormAttachmentPolicy,\n PortalFormDefinition,\n PortalFormField,\n FormErrors,\n FormValues,\n} from '../types'\n\n/**\n * Returns true iff `field` is currently visible given the form's\n * other values. Hidden fields are never validated and never sent.\n */\nexport function isFieldVisible(\n field: PortalFormField,\n values: FormValues,\n): boolean {\n if (!field.visibleIf) return true\n const sibling = values[field.visibleIf.fieldId]\n return sibling === field.visibleIf.equals\n}\n\n/**\n * Validates a single field's value. Returns an error string or\n * `undefined` if valid. Layout-only field types (section-heading,\n * html-block) and hidden fields never produce errors.\n */\nexport function validateField(\n field: PortalFormField,\n value: unknown,\n attachmentPolicy?: PortalFormAttachmentPolicy,\n): string | undefined {\n if (\n field.type === 'section-heading' ||\n field.type === 'html-block' ||\n field.type === 'hidden'\n ) {\n return undefined\n }\n\n const normalizedValue = typeof value === 'string' ? value.trim() : value\n const isEmpty =\n value === undefined ||\n value === null ||\n normalizedValue === '' ||\n (Array.isArray(value) && value.length === 0)\n\n if (field.required && isEmpty) {\n return `${field.label} is required`\n }\n if (isEmpty) return undefined\n\n // Type-specific built-ins\n if (field.type === 'email' && typeof normalizedValue === 'string') {\n if (!/^[^\\s@]+@[^\\s@]+\\.[^\\s@]+$/.test(normalizedValue)) {\n return `${field.label} must be a valid email address`\n }\n }\n\n const v: NonNullable<PortalFormField['validation']> = field.validation ?? {}\n\n if (typeof normalizedValue === 'string') {\n if (v.minLength != null && normalizedValue.length < v.minLength) {\n return `${field.label} must be at least ${v.minLength} characters`\n }\n if (v.maxLength != null && normalizedValue.length > v.maxLength) {\n return `${field.label} must be at most ${v.maxLength} characters`\n }\n if (v.regex) {\n try {\n if (!new RegExp(v.regex).test(normalizedValue)) {\n return `${field.label} is invalid`\n }\n } catch {\n // bad regex in the definition — treat as no rule\n }\n }\n }\n\n if (typeof value === 'number') {\n if (v.min != null && value < v.min) {\n return `${field.label} must be at least ${v.min}`\n }\n if (v.max != null && value > v.max) {\n return `${field.label} must be at most ${v.max}`\n }\n }\n\n if (field.type === 'file') {\n const files = filesFromValue(value)\n const maxFiles = attachmentPolicy?.maxFiles\n const maxFileSizeBytes = attachmentPolicy?.maxFileSizeBytes\n const accept = v.accept && v.accept.length > 0 ? v.accept : attachmentPolicy?.accept\n\n if (maxFiles != null && files.length > maxFiles) {\n return `${field.label} accepts up to ${maxFiles} file${maxFiles === 1 ? '' : 's'}`\n }\n if (maxFileSizeBytes != null) {\n const oversized = files.find((file) => file.size > maxFileSizeBytes)\n if (oversized) {\n return `${oversized.name} exceeds the ${formatBytes(maxFileSizeBytes)} limit`\n }\n }\n if (accept && accept.length > 0) {\n const rejected = files.find((file) => !isAcceptedFile(file, accept))\n if (rejected) {\n return `${rejected.name} must be one of: ${accept.join(', ')}`\n }\n }\n }\n\n return undefined\n}\n\n/**\n * Validates an entire form. Skips fields that are not visible.\n * If `fieldIds` is supplied, only those fields are validated\n * (used for per-step validation in multi-step forms).\n */\nexport function validateForm(\n def: PortalFormDefinition,\n values: FormValues,\n fieldIds?: string[],\n): FormErrors {\n const errors: FormErrors = {}\n const ids = fieldIds ? new Set(fieldIds) : null\n for (const field of def.fields) {\n if (ids && !ids.has(field.id)) continue\n if (!isFieldVisible(field, values)) continue\n const err = validateField(field, values[field.id], def.attachmentPolicy)\n if (err) errors[field.id] = err\n }\n return errors\n}\n\nexport function hasErrors(errors: FormErrors): boolean {\n return Object.values(errors).some((e) => !!e)\n}\n\nfunction filesFromValue(value: unknown): File[] {\n if (typeof File === 'undefined') {\n return []\n }\n if (value instanceof File) {\n return [value]\n }\n if (Array.isArray(value)) {\n return value.filter((item): item is File => item instanceof File)\n }\n return []\n}\n\nfunction isAcceptedFile(file: File, accept: string[]): boolean {\n const name = file.name.toLowerCase()\n const contentType = file.type.toLowerCase()\n\n return accept.some((rule) => {\n const normalized = rule.trim().toLowerCase()\n if (normalized === '') {\n return false\n }\n if (normalized.startsWith('.')) {\n return name.endsWith(normalized)\n }\n if (normalized.endsWith('/*')) {\n return contentType.startsWith(normalized.slice(0, -1))\n }\n return contentType === normalized\n })\n}\n\nfunction formatBytes(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${Math.round(bytes / 1024)} KB`\n }\n return `${Math.round(bytes / (1024 * 1024))} MB`\n}\n","import { computed, reactive, ref, type ComputedRef, type Ref } from 'vue'\nimport type {\n PortalFormDefinition,\n PortalFormField,\n PortalFormStep,\n FormErrors,\n FormValues,\n} from '../types'\nimport {\n hasErrors,\n isFieldVisible,\n validateForm,\n} from './useFormValidation'\n\nexport interface UseDcsFormOptions {\n definition: PortalFormDefinition\n}\n\nexport interface UseDcsFormReturn {\n values: FormValues\n errors: Ref<FormErrors>\n touched: Ref<Record<string, boolean>>\n submitting: Ref<boolean>\n submitted: Ref<boolean>\n submitError: Ref<string | null>\n /** All fields, with layout-only types preserved. */\n fields: ComputedRef<PortalFormField[]>\n /** Steps if multi-step, else null. */\n steps: ComputedRef<PortalFormStep[] | null>\n currentStepIndex: Ref<number>\n currentStep: ComputedRef<PortalFormStep | null>\n currentStepFields: ComputedRef<PortalFormField[]>\n isFirstStep: ComputedRef<boolean>\n isLastStep: ComputedRef<boolean>\n visibleFields: ComputedRef<PortalFormField[]>\n /** Sets a field value and clears that field's error. */\n setValue: (id: string, value: unknown) => void\n /** Marks a field as touched + revalidates only that field's row. */\n touch: (id: string) => void\n /** Validates the current step (multi-step) or the entire form. */\n validateCurrentScope: () => boolean\n validateAll: () => boolean\n next: () => boolean\n prev: () => void\n reset: () => void\n /** Returns the values that should actually be submitted (visible only). */\n collectSubmissionValues: () => FormValues\n}\n\nfunction defaultsFor(def: PortalFormDefinition): FormValues {\n const out: FormValues = {}\n for (const f of def.fields) {\n if (f.defaultValue !== undefined) {\n out[f.id] = f.defaultValue as unknown\n } else if (f.type === 'checkbox') {\n out[f.id] = false\n } else if (f.type === 'multiselect' || f.type === 'checkbox-group') {\n out[f.id] = [] as string[]\n } else {\n out[f.id] = ''\n }\n }\n return out\n}\n\nexport function useDcsForm(opts: UseDcsFormOptions): UseDcsFormReturn {\n const { definition } = opts\n const values = reactive<FormValues>(defaultsFor(definition))\n const errors = ref<FormErrors>({})\n const touched = ref<Record<string, boolean>>({})\n const submitting = ref(false)\n const submitted = ref(false)\n const submitError = ref<string | null>(null)\n const currentStepIndex = ref(0)\n\n const fields = computed(() => definition.fields)\n const steps = computed<PortalFormStep[] | null>(() =>\n definition.steps && definition.steps.length > 0 ? definition.steps : null,\n )\n const currentStep = computed<PortalFormStep | null>(() => {\n const s = steps.value\n return s ? (s[currentStepIndex.value] ?? null) : null\n })\n const currentStepFields = computed<PortalFormField[]>(() => {\n const step = currentStep.value\n if (!step) return definition.fields\n const ids = new Set(step.fieldIds)\n return definition.fields.filter((f) => ids.has(f.id))\n })\n const isFirstStep = computed(() => currentStepIndex.value === 0)\n const isLastStep = computed(() => {\n const s = steps.value\n return !s || currentStepIndex.value >= s.length - 1\n })\n const visibleFields = computed(() =>\n currentStepFields.value.filter((f) => isFieldVisible(f, values as FormValues)),\n )\n\n function setValue(id: string, value: unknown): void {\n ;(values as FormValues)[id] = value\n if (errors.value[id]) {\n errors.value = { ...errors.value, [id]: undefined }\n }\n }\n\n function touch(id: string): void {\n touched.value = { ...touched.value, [id]: true }\n }\n\n function validateScope(scopeFieldIds?: string[]): boolean {\n const next = validateForm(definition, values as FormValues, scopeFieldIds)\n // Merge with existing errors but only for the validated scope so we\n // don't wipe out errors from other steps.\n if (scopeFieldIds) {\n const merged = { ...errors.value }\n for (const id of scopeFieldIds) {\n merged[id] = next[id]\n }\n errors.value = merged\n } else {\n errors.value = next\n }\n return !hasErrors(errors.value)\n }\n\n function validateCurrentScope(): boolean {\n const scope = currentStep.value?.fieldIds\n return validateScope(scope)\n }\n\n function validateAll(): boolean {\n return validateScope()\n }\n\n function next(): boolean {\n if (!steps.value) return false\n if (!validateCurrentScope()) return false\n if (currentStepIndex.value < steps.value.length - 1) {\n currentStepIndex.value++\n return true\n }\n return false\n }\n\n function prev(): void {\n if (currentStepIndex.value > 0) currentStepIndex.value--\n }\n\n function reset(): void {\n const fresh = defaultsFor(definition)\n for (const k of Object.keys(values as object)) {\n delete (values as FormValues)[k]\n }\n Object.assign(values as FormValues, fresh)\n errors.value = {}\n touched.value = {}\n submitting.value = false\n submitted.value = false\n submitError.value = null\n currentStepIndex.value = 0\n }\n\n function collectSubmissionValues(): FormValues {\n const out: FormValues = {}\n for (const f of definition.fields) {\n if (\n f.type === 'section-heading' ||\n f.type === 'html-block'\n )\n continue\n if (!isFieldVisible(f, values as FormValues)) continue\n out[f.id] = (values as FormValues)[f.id]\n }\n return out\n }\n\n return {\n values: values as FormValues,\n errors,\n touched,\n submitting,\n submitted,\n submitError,\n fields,\n steps,\n currentStepIndex,\n currentStep,\n currentStepFields,\n isFirstStep,\n isLastStep,\n visibleFields,\n setValue,\n touch,\n validateCurrentScope,\n validateAll,\n next,\n prev,\n reset,\n collectSubmissionValues,\n }\n}\n","/**\n * CANONICAL receipt primitive for DCS form-submission clients (C-310).\n *\n * This module is the single definition of \"did the submission actually get\n * stored?\" for the whole fleet. Site-local copies (lamphere's\n * `theme/lib/readOkBody.ts`, iron-oak's `src/lib/submissionResponse.ts`, and the\n * first-party `web/`+`portal/` helpers) are BACKPORTS of this file and say so in\n * their headers. Change the contract here first.\n *\n * ── Two layers, deliberately separate ──────────────────────────────────────\n *\n * `readOkBody(response)` is TRANSPORT validation: did a DCS API answer at all?\n * `readExpectedJson(response, validator)` adds RECEIPT validation: does the\n * body it answered with actually prove a row exists?\n *\n * Transport validation alone is not enough (Codex cross-model review §c,\n * 2026-07-26). Before C-310 any syntactically valid JSON passed — `{}`, `[]`,\n * `\"ok\"`, `{\"hello\":\"world\"}` — so a 2xx from anything that speaks JSON was\n * reported to the visitor as a stored lead. The endpoints all return a real\n * receipt; requiring one is cheap and materially stronger.\n *\n * ── Why 204 is NOT exempt any more (C-310, was the last hole) ──────────────\n *\n * C-301/C-302 trusted an empty body when the STATUS asserted the emptiness\n * (`204 No Content`). That was defensible in the abstract and wrong in fact:\n * `204` proves only that *the responder* deliberately sent no content. It does\n * not prove the DCS API ran, and every guarded endpoint returns a JSON receipt:\n *\n * - managed forms `202` + `PublicSiteFormSubmissionResponse`\n * (server/internal/handlers/public_site_forms.go)\n * - site contact `201` + `ContactFormResponse`\n * (server/internal/handlers/contact_form.go)\n * - estimate creation `201` + estimate JSON\n * (server/internal/handlers/revenue_estimate_visitor.go)\n * - passwordless verify `200` + `{success, redirectTo}`\n * (server/internal/handlers/site_auth_multi.go:401)\n * - booking cancellation `200` + `CancelBookingResponse`\n * (server/internal/handlers/revenue_public.go:2134)\n *\n * No guarded operation needs `204`. Keeping the exemption meant a bodyless 204\n * from a proxy, a CDN, or a CORS-mangled hop still read as \"sent\". Removed. If a\n * future endpoint genuinely contracts `204`, add it back for that endpoint only,\n * with its own predicate — not as a blanket transport exemption.\n *\n * ── Failures are TERMINAL ──────────────────────────────────────────────────\n *\n * Every throw here means \"we cannot confirm this was stored\", which is NOT the\n * same as \"this was not stored\". Callers must surface it as a visible failure\n * and must never retry: if the request *did* reach the API, a retry double-stores\n * the lead; if it did not, a retry cannot help. Wording shown to the visitor says\n * \"could not confirm\", never \"not received\".\n */\n\n/** A caller-supplied type predicate describing one endpoint's receipt. */\nexport type ReceiptValidator<T> = (value: unknown) => value is T\n\n/**\n * Error thrown when a submission cannot be confirmed. `receiptRejected`\n * distinguishes the two causes, because they have different remedies:\n *\n * - `false` — transport failure. The body was not JSON at all (HTML shell,\n * proxy interstitial, empty body, unreadable stream). Check routing.\n * - `true` — the body WAS valid JSON but did not carry a receipt. Check that\n * the endpoint contract and the predicate still agree.\n */\nexport interface UnconfirmedSubmissionError extends Error {\n receiptRejected?: boolean\n}\n\n/**\n * Reads the body of an **ok** (2xx) submission response and refuses to treat a\n * non-JSON body as a successful submission.\n *\n * Contract:\n * - JSON body -> parsed value\n * - anything else -> throws (empty, non-JSON content-type, unparseable,\n * unreadable stream — including on `204`)\n *\n * @param label prefix for the console diagnostic, so a site copy can name itself.\n */\nexport async function readOkBody(res: Response, label = LOG_PREFIX): Promise<unknown> {\n // Non-`Response` fetch implementations (older test doubles) may expose only\n // `json()`. Preserve the historical behaviour for them rather than throwing on\n // a shape this package never controlled. NOTE: this path used to be a silent\n // success hole — a rejected `json()` became `null`. It no longer is, because\n // `readExpectedJson` runs a receipt predicate over whatever comes back and\n // `null` satisfies no receipt.\n if (typeof res.text !== 'function') {\n try {\n return await res.json()\n } catch {\n return null\n }\n }\n\n const contentType = readContentType(res)\n // Read as text FIRST: a body can only be consumed once, so calling `json()`\n // first would leave nothing to inspect when it fails.\n let raw: string\n try {\n raw = (await res.text()).trim()\n } catch (readError) {\n // We never saw the body — never claim success from that.\n throw unreadableBodyError(label, res.status, readError)\n }\n\n if (raw === '') {\n // C-310: `204` used to be exempt here. It is not any more — see the header.\n throw emptyBodyError(label, res.status)\n }\n\n if (contentType && !contentType.includes('json')) {\n throw nonJsonBodyError(label, res.status, contentType, raw)\n }\n try {\n return JSON.parse(raw)\n } catch {\n throw nonJsonBodyError(label, res.status, contentType, raw)\n }\n}\n\n/**\n * Reads an **ok** (2xx) response and requires it to carry the receipt the\n * endpoint contracts. Throws an {@link UnconfirmedSubmissionError} otherwise.\n *\n * Zero dependencies and no schema library on purpose: `site-forms` is a leaf\n * package that sites pin independently, so anything that adds a dependency is\n * unshippable to exactly the sites that need the fix most.\n */\nexport async function readExpectedJson<T>(\n res: Response,\n validator: ReceiptValidator<T>,\n options: { label?: string; receiptName?: string } = {},\n): Promise<T> {\n const label = options.label ?? LOG_PREFIX\n const body = await readOkBody(res, label)\n if (validator(body)) return body\n throw invalidReceiptError(label, res.status, options.receiptName ?? 'submission', body)\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Per-endpoint receipt predicates.\n//\n// One shared success contract across contact, estimate, authentication and\n// cancellation would be a fiction, so transport parsing is shared and the\n// receipt shape stays per-endpoint (Codex §a). Shapes are pinned to the REAL\n// generated contract types in contracts/generated/typescript/types.gen.ts —\n// deliberately re-declared here rather than imported, because customer sites\n// install this package from npm and do not have @dcs/contracts.\n// ───────────────────────────────────────────────────────────────────────────\n\n/**\n * NO LEGACY SPAM-QUARANTINE EXEMPTION — removed by C-319, deliberately.\n *\n * C-310 widened both predicates below to accept a bare `{\"status\":\"ok\"}`,\n * because two of the five spam-quarantine paths answered that instead of their\n * endpoint's real receipt (C-307 held every quarantine response byte-identical\n * to its pre-change self, and two of those shapes were already wrong). Without\n * the widening, every quarantined submitter — including an AI false-positive\n * victim whose message really was stored — would have seen a visible failure.\n *\n * C-319 removed the cause: all five quarantine paths now answer their route's\n * GENUINE success receipt, built by the same writer the success path uses and\n * populated from the row C-307 stores. So the widening is gone with it. A\n * `{\"status\":\"ok\"}` body from any of these endpoints is now what it always\n * looked like — a misroute — and must fail.\n *\n * ORDERING NOTE, because this package ships independently of the server: this\n * removal is only safe while no DEPLOYED client carries these predicates.\n * Verified at removal time — the predicates were introduced in 0.6.0 (C-310)\n * and 0.6.0 has never been published (npm latest: 0.5.0), so every deployed\n * site is on a version with no receipt validation at all. site-forms must not\n * be published AHEAD of the server roll that carries C-319; both ride the same\n * attended C-239 train.\n */\n\n/** `PublicSiteFormSubmissionResponse` — types.gen.ts:14845. */\nexport interface ManagedFormReceipt {\n id?: string\n status: string\n submittedAt?: string\n message?: string\n contactMessageId?: string | null\n notificationQueued?: boolean\n}\n\nconst MANAGED_FORM_STATUSES = ['submitted', 'accepted', 'queued']\n\nexport function isManagedFormReceipt(value: unknown): value is ManagedFormReceipt {\n return (\n isRecord(value) &&\n isNonEmptyString(value['id']) &&\n isOneOf(value['status'], MANAGED_FORM_STATUSES) &&\n isTimestamp(value['submittedAt'])\n )\n}\n\n/** `ContactFormResponse` — types.gen.ts:19831. */\nexport interface SiteContactReceipt {\n id?: string\n status: string\n submittedAt?: string\n message?: string\n}\n\nconst CONTACT_STATUSES = ['submitted', 'processing', 'responded']\n\nexport function isSiteContactReceipt(value: unknown): value is SiteContactReceipt {\n return (\n isRecord(value) &&\n isNonEmptyString(value['id']) &&\n isOneOf(value['status'], CONTACT_STATUSES)\n )\n}\n\n/**\n * Visitor estimate creation — `201` + the mapped estimate row\n * (revenue_estimate_visitor.go:1419 `mapSiteVisitorEstimateResponse`). The\n * estimate honeypot's decoy is built by the same row constructor and answered\n * by the same writer a genuine estimate uses (C-319), so it carries a real ULID\n * `id` and passes — which is the point: the honeypot must stay\n * indistinguishable from a genuine submission.\n */\nexport interface EstimateReceipt {\n id: string\n status?: string\n}\n\nexport function isEstimateReceipt(value: unknown): value is EstimateReceipt {\n return isRecord(value) && isNonEmptyString(value['id'])\n}\n\n/** `PasswordlessVerifyCodeResponse` — types.gen.ts:20780. */\nexport interface PasswordlessVerifyReceipt {\n success: true\n redirectTo?: string\n}\n\nexport function isPasswordlessVerifyReceipt(value: unknown): value is PasswordlessVerifyReceipt {\n return isRecord(value) && value['success'] === true\n}\n\n/** `CancelBookingResponse` — types.gen.ts:21486. */\nexport interface BookingCancellationReceipt {\n success: true\n refundAmountCents?: number | null\n message?: string\n}\n\nexport function isBookingCancellationReceipt(value: unknown): value is BookingCancellationReceipt {\n return isRecord(value) && value['success'] === true\n}\n\n// ───────────────────────────────────────────────────────────────────────────\n// Internals\n// ───────────────────────────────────────────────────────────────────────────\n\nconst LOG_PREFIX = '[@duffcloudservices/site-forms]'\n\n/**\n * The one honest sentence a visitor is shown for any unconfirmable 2xx. The\n * technical diagnosis belongs in the console for whoever maintains the site —\n * never on the page. \"Could not confirm\" is deliberate: a post-storage body\n * failure means UNKNOWN, not \"not stored\".\n */\nconst VISITOR_UNCONFIRMED_MESSAGE =\n 'We could not confirm your message was received. Please try again, or contact us directly.'\n\nfunction readContentType(res: Response): string {\n const get = res.headers?.get\n if (typeof get !== 'function') return ''\n return (res.headers.get('content-type') ?? '').toLowerCase()\n}\n\nfunction isRecord(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\nfunction isNonEmptyString(value: unknown): value is string {\n return typeof value === 'string' && value.trim().length > 0\n}\n\nfunction isOneOf(value: unknown, allowed: string[]): boolean {\n return typeof value === 'string' && allowed.includes(value)\n}\n\nfunction isTimestamp(value: unknown): boolean {\n return isNonEmptyString(value) && Number.isFinite(Date.parse(value))\n}\n\nfunction unconfirmed(message: string, receiptRejected: boolean): UnconfirmedSubmissionError {\n const err = new Error(message) as UnconfirmedSubmissionError\n err.receiptRejected = receiptRejected\n return err\n}\n\nfunction unreadableBodyError(label: string, status: number, cause: unknown): UnconfirmedSubmissionError {\n const detail = cause instanceof Error ? cause.message : String(cause)\n // eslint-disable-next-line no-console\n console.error(\n `${label} Submission could not be confirmed: the server answered ${status} but the response ` +\n `body could not be read (${detail}). The submission may or may not have been stored, so it ` +\n `is reported as a failure rather than risk telling the visitor it was sent.`,\n )\n return unconfirmed(VISITOR_UNCONFIRMED_MESSAGE, false)\n}\n\nfunction emptyBodyError(label: string, status: number): UnconfirmedSubmissionError {\n // eslint-disable-next-line no-console\n console.error(\n `${label} Submission NOT confirmed: the server answered ${status} with an empty body. ` +\n `EVERY DCS submission endpoint returns a JSON receipt — including on 204, which is why the ` +\n `old 204 exemption was removed (C-310) — so an empty body means the request was answered by ` +\n `something other than the DCS API (a misrouted POST).`,\n )\n return unconfirmed(VISITOR_UNCONFIRMED_MESSAGE, false)\n}\n\nfunction nonJsonBodyError(\n label: string,\n status: number,\n contentType: string,\n raw: string,\n): UnconfirmedSubmissionError {\n const looksLikeHtml = contentType.includes('html') || /^\\s*<(?:!doctype|html)/i.test(raw)\n // eslint-disable-next-line no-console\n console.error(\n `${label} Submission NOT stored: the server answered ${status} ` +\n `with a ${contentType || 'bodyless/unknown'} body instead of JSON` +\n (looksLikeHtml\n ? ' — this is an HTML page, so the POST did not reach the DCS API (check the resolved api-base and the host routing for /api/v1/*).'\n : '.') +\n ` First 200 bytes: ${raw.slice(0, 200)}`,\n )\n return unconfirmed(VISITOR_UNCONFIRMED_MESSAGE, false)\n}\n\nfunction invalidReceiptError(\n label: string,\n status: number,\n receiptName: string,\n body: unknown,\n): UnconfirmedSubmissionError {\n // eslint-disable-next-line no-console\n console.error(\n `${label} Submission NOT confirmed: the server answered ${status} with JSON that is not a ` +\n `valid ${receiptName} receipt. A 2xx and parseable JSON prove only that SOMETHING answered; ` +\n `only the endpoint's receipt proves a row was stored. Received: ` +\n `${safeStringify(body).slice(0, 200)}`,\n )\n return unconfirmed(VISITOR_UNCONFIRMED_MESSAGE, true)\n}\n\nfunction safeStringify(value: unknown): string {\n try {\n return JSON.stringify(value) ?? String(value)\n } catch {\n return String(value)\n }\n}\n","import type {\n DcsFormSubmitPayload,\n DcsFormSubmitSuccess,\n DcsFormSubmitError,\n} from '../types'\nimport {\n isManagedFormReceipt,\n readExpectedJson,\n type UnconfirmedSubmissionError,\n} from './readExpectedJson'\n\nexport interface SubmitOptions {\n apiBase: string\n siteSlug: string\n payload: DcsFormSubmitPayload\n /** Number of retries on 5xx / network errors. Default 1. */\n retries?: number\n /** Optional fetch implementation override (tests). */\n fetchImpl?: typeof fetch\n}\n\n/**\n * POSTs a form submission to\n * `${apiBase}/sites/{siteSlug}/forms/{formId}/submissions`, or — when no site\n * slug is configured — to the slug-free\n * `${apiBase}/forms/{formId}/submissions`, where the server infers the site\n * from the request origin/host. A missing slug used to produce the broken\n * `/sites//forms/...` shape (kimduffhomes.com 405, 2026-07-20).\n *\n * Uses JSON for plain values and `multipart/form-data` when any\n * value is a `File` (file-upload fields).\n */\nexport async function submitFormValues(\n opts: SubmitOptions,\n): Promise<DcsFormSubmitSuccess> {\n const { apiBase, siteSlug, payload } = opts\n const retries = opts.retries ?? 1\n const fetchImpl = opts.fetchImpl ?? fetch\n const base = apiBase.replace(/\\/$/, '')\n const formPath = `forms/${encodeURIComponent(payload.formId)}/submissions`\n const trimmedSlug = siteSlug.trim()\n const url = trimmedSlug\n ? `${base}/sites/${encodeURIComponent(trimmedSlug)}/${formPath}`\n : `${base}/${formPath}`\n\n const hasFile = Object.values(payload.values).some(valueHasFile)\n\n let lastError: Error | undefined\n let lastStatus: number | undefined\n for (let attempt = 0; attempt <= retries; attempt++) {\n try {\n const init: RequestInit = hasFile\n ? { method: 'POST', redirect: REDIRECT_MODE, body: buildFormData(payload) }\n : {\n method: 'POST',\n redirect: REDIRECT_MODE,\n headers: { 'Content-Type': 'application/json' },\n body: JSON.stringify(payload),\n }\n const res = await fetchImpl(url, init)\n lastStatus = res.status\n if (res.ok) {\n let body: unknown\n try {\n body = await readExpectedJson(res, isManagedFormReceipt, {\n receiptName: 'managed-form submission',\n })\n } catch (bodyError) {\n // TERMINAL — never retried. A 2xx that does not carry the endpoint's\n // receipt means either the POST was answered by something that is not\n // the DCS API (SPA shell, proxy interstitial, gateway error page) or\n // the API answered with something that does not prove a row exists.\n // Retrying could double-store the lead if the request *did* reach the\n // API, and cannot help if it did not. Surface it as a failure so the\n // visitor is never told \"sent\" without a receipt (C-301 / C-310).\n const receiptRejected = Boolean(\n (bodyError as UnconfirmedSubmissionError)?.receiptRejected,\n )\n throw {\n payload,\n status: res.status,\n error: bodyError as Error,\n // `nonJsonResponse` keeps its original literal meaning (the body was\n // not JSON at all); a JSON body that failed the receipt predicate is\n // reported through the additive `unconfirmedReceipt` flag instead.\n nonJsonResponse: !receiptRejected,\n unconfirmedReceipt: receiptRejected,\n } satisfies DcsFormSubmitError\n }\n return { payload, response: body }\n }\n // Retry only on 5xx\n if (res.status < 500) {\n const body = await safeText(res)\n const err: DcsFormSubmitError = {\n payload,\n status: res.status,\n error: new Error(`Submission failed (${res.status}): ${body}`),\n }\n throw err\n }\n lastError = new Error(`Server error ${res.status}`)\n } catch (e) {\n // If `e` is already a DcsFormSubmitError-shaped object, rethrow.\n if (e && typeof e === 'object' && 'payload' in e && 'error' in e) {\n throw e\n }\n lastError = e as Error\n }\n }\n\n throw {\n payload,\n status: lastStatus,\n error: lastError ?? new Error('Submission failed'),\n } satisfies DcsFormSubmitError\n}\n\nfunction buildFormData(payload: DcsFormSubmitPayload): FormData {\n const fd = new FormData()\n fd.append('formId', payload.formId)\n if (payload.captchaToken) fd.append('captchaToken', payload.captchaToken)\n for (const [key, value] of Object.entries(payload.values)) {\n if (value === undefined || value === null) continue\n if (typeof File !== 'undefined' && value instanceof File) {\n fd.append(`values[${key}]`, value)\n } else if (Array.isArray(value) && value.some((item) => typeof File !== 'undefined' && item instanceof File)) {\n for (const item of value) {\n if (typeof File !== 'undefined' && item instanceof File) {\n fd.append(`values[${key}][]`, item)\n }\n }\n } else if (Array.isArray(value)) {\n for (const item of value) fd.append(`values[${key}][]`, String(item))\n } else {\n fd.append(`values[${key}]`, String(value))\n }\n }\n return fd\n}\n\nfunction valueHasFile(value: unknown): boolean {\n if (typeof File === 'undefined') {\n return false\n }\n if (value instanceof File) {\n return true\n }\n return Array.isArray(value) && value.some((item) => item instanceof File)\n}\n\n/**\n * A submission POST must never FOLLOW a redirect (C-310, Codex review §b).\n *\n * Browser `fetch` follows redirects by default, so the guard only ever sees the\n * FINAL response. An HTML landing page is caught by the receipt check, but a\n * redirect that terminates at some other host's valid JSON would not be — and a\n * `301`/`302` also silently rewrites a POST into a GET, so the submission body\n * is dropped on the way.\n *\n * Verified against production routing before enabling: the Front Door `api`\n * route (`infrastructure/partner/front-door-routes.bicep:1626`) and the portal\n * `/api/*` route (`:2318`) carry NO rule sets — their only redirect is\n * `httpsRedirect`, which cannot fire because every fleet site resolves an\n * absolute `https://` api-base (C-301 live-bundle sweep). The one `/*`-scoped\n * 301 in the profile (`kduff-homes-www-redirect`, `:2125`) applies to\n * `www.kimduffhomes.com` and is a MISROUTE by definition for a submission POST.\n *\n * So on the intended path this changes nothing, and on every unintended path it\n * converts a silent, body-losing hop into a visible failure.\n */\nconst REDIRECT_MODE: RequestRedirect = 'error'\n\nasync function safeText(res: Response): Promise<string> {\n try {\n return await res.text()\n } catch {\n return ''\n }\n}\n","/**\n * Site PHI posture — the ONE platform signal that decides whether a managed\n * form shows PHI guidance to the visitor.\n *\n * WHY THIS EXISTS (C-415 / KEPT re-review F1). On a HIPAA-mode tenant the AI\n * chat widget already opens with \"please don't include personal health\n * details\", because `/agent/config` projects `hipaaMode` to it. The managed\n * form on the same tenant — the higher-volume intake path, with a required\n * free-text message box — projected nothing, so the platform was doing the\n * hard half of the problem (redacting PHI it had already received) and\n * skipping the cheap half (asking the visitor not to send it).\n *\n * THE SIGNAL, AND ONLY THIS SIGNAL. `GET {apiBase}/sites/{slug}/forms/compliance`\n * returns `{ siteHandlesPhi }`, the server's projection of\n * `portal.Service.SiteHandlesPHI` — whose authoritative input is\n * `SiteAgentConfigs/{slug}/default.HipaaMode`, the same admin-pinned row the\n * C-352 redaction gate reads. There is no second signal, no YAML flag, and no\n * per-site opt-in: a site-local switch could drift from the tenant's real HIPAA\n * posture, which is the exact class of bug C-352 fixed.\n *\n * NOT `/agent/config`, which already carries `hipaaMode`: that endpoint 404s\n * unless the `aiAgent` feature, the per-site toggle, and the global kill switch\n * are all on. Reading the flag from there would silently give no guidance to a\n * HIPAA-mode tenant that does not run the chat widget — a fail-OPEN gate hidden\n * behind an unrelated feature flag.\n *\n * FAIL DIRECTION. The server side fails CLOSED (an unresolvable HipaaMode\n * reports `true`, so the guidance shows). The client cannot: a transport\n * failure or an offline build has no verdict at all, and defaulting to \"show\"\n * would put a health-privacy line on every non-medical customer's contact form.\n * So the client defaults to `false` on any failure, and the server-side\n * redactions (C-352) remain the actual control — this module is guidance, not\n * enforcement.\n */\n\nexport interface SitePhiPostureOptions {\n /** API base URL, e.g. `https://api.duffcloudservices.com/api/v1`. */\n apiBase: string\n /**\n * Site slug. When empty the slug-free `/forms/compliance` route is used and\n * the server infers the site from the request origin/host — the same\n * fallback `submitFormValues` uses, so a build with no baked slug still gets\n * a verdict instead of requesting the broken `/sites//forms/...` shape.\n */\n siteSlug: string\n /** Optional fetch implementation override (tests). */\n fetchImpl?: typeof fetch\n}\n\n/** Shape of `GET /sites/{siteSlug}/forms/compliance`. */\ninterface SiteFormComplianceResponse {\n siteHandlesPhi?: unknown\n}\n\n/**\n * In-flight/settled verdicts keyed by `${base}|${slug}`. A page can host several\n * `<DcsForm>`s (a contact form plus an intake questionnaire); they must not each\n * pay for a round trip, and they must not be able to disagree with each other.\n */\nconst postureCache = new Map<string, Promise<boolean>>()\n\n/** Clears the memoized verdicts. Exported for tests and the portal preview iframe. */\nexport function resetSitePhiPostureCache(): void {\n postureCache.clear()\n}\n\n/**\n * Resolves whether this site's managed-form submissions are PHI-bearing.\n *\n * Returns `false` on any failure (network, non-2xx, non-JSON, or a body whose\n * `siteHandlesPhi` is not a boolean). A missing/garbled body is treated as \"no\n * verdict\", never as an implicit yes — see the fail-direction note above.\n */\nexport async function fetchSiteHandlesPhi(\n opts: SitePhiPostureOptions,\n): Promise<boolean> {\n const base = (opts.apiBase ?? '').replace(/\\/$/, '')\n const slug = (opts.siteSlug ?? '').trim()\n const url = slug\n ? `${base}/sites/${encodeURIComponent(slug)}/forms/compliance`\n : `${base}/forms/compliance`\n\n const cacheKey = `${base}|${slug}`\n const cached = postureCache.get(cacheKey)\n if (cached) return cached\n\n const fetchImpl = opts.fetchImpl ?? (typeof fetch === 'function' ? fetch : undefined)\n if (!fetchImpl) return false\n\n const pending = (async (): Promise<boolean> => {\n try {\n const res = await fetchImpl(url, { method: 'GET' })\n if (!res.ok) return false\n const body = (await res.json()) as SiteFormComplianceResponse\n return body?.siteHandlesPhi === true\n } catch {\n // Deliberately silent: the only console output this package emits is the\n // missing-definition warning (see the PHI-log grep gate in the site-forms\n // skill). A failed posture read must never become a visitor-visible error\n // on an otherwise working form.\n return false\n }\n })()\n\n postureCache.set(cacheKey, pending)\n return pending\n}\n\n/**\n * The standard PHI guidance copy. It lives in the package, not in the API\n * response and not in any site's YAML, so one platform decision renders the\n * same sentence on every HIPAA-mode tenant.\n *\n * It is guidance, not a legal notice: it tells the visitor what to do instead\n * of what the law requires, and it deliberately mirrors the sentence the AI\n * chat already ships on these tenants (\"please don't include personal health\n * details\") so the two surfaces read as one product.\n */\nexport const PHI_GUIDANCE_COPY = {\n lead: \"Please don't include personal health details.\",\n detail:\n \"A general description of what you need is enough — we'll go over anything specific with you directly.\",\n} as const\n","/**\n * Validates a loaded form definition against the form-definition JSON\n * Schema emitted by `@dcs/contracts`. Dev-only — failures are logged\n * via `console.warn` rather than thrown so a malformed YAML never\n * takes down a customer site in production.\n *\n * Schema is bundled as a snapshot of\n * `contracts/dist/form-definition.schema.json` to avoid a runtime\n * dependency on the contracts build output.\n */\nimport Ajv, { type ErrorObject, type ValidateFunction } from 'ajv'\nimport addFormats from 'ajv-formats'\nimport schema from './form-definition.schema.json'\nimport type { PortalFormDefinition } from '../types'\n\nlet validator: ValidateFunction | null = null\n\nfunction getValidator(): ValidateFunction {\n if (validator) return validator\n const ajv = new Ajv({\n allErrors: true,\n strict: false,\n discriminator: false,\n })\n addFormats(ajv)\n validator = ajv.compile(schema as object)\n return validator\n}\n\nexport interface SchemaValidationResult {\n valid: boolean\n errors: ErrorObject[]\n}\n\nexport function validateFormDefinition(\n def: PortalFormDefinition | unknown,\n): SchemaValidationResult {\n const v = getValidator()\n const valid = v(def) as boolean\n return { valid, errors: valid ? [] : (v.errors ?? []) }\n}\n\n/** Logs a `console.warn` when invalid, but only when `import.meta.env.DEV`. */\nexport function warnIfInvalid(\n formId: string,\n def: PortalFormDefinition | unknown,\n isDev: boolean,\n): SchemaValidationResult {\n const result = validateFormDefinition(def)\n if (!result.valid && isDev) {\n // eslint-disable-next-line no-console\n console.warn(\n `[@duffcloudservices/site-forms] Form \"${formId}\" failed schema validation:`,\n result.errors,\n )\n }\n return result\n}\n","import yaml from 'js-yaml'\nimport type { PortalFormDefinition } from '../types'\n\n/**\n * Eagerly load every form YAML under `/.dcs/forms/*.yaml` from the\n * consuming Vite app and parse them into PortalFormDefinition objects.\n *\n * Vite returns the modules as raw strings (when using `?raw` or the\n * default text loader for unknown extensions) or as parsed objects\n * (when `vite-plugin-yaml` is installed). This helper handles both.\n */\nexport function loadFormDefinitions(\n modules: Record<string, unknown>,\n): Record<string, PortalFormDefinition> {\n const out: Record<string, PortalFormDefinition> = {}\n for (const [path, mod] of Object.entries(modules)) {\n const formId = extractFormId(path)\n const def = parseModule(mod)\n if (def) {\n out[def.formId ?? formId] = def\n }\n }\n return out\n}\n\nfunction extractFormId(path: string): string {\n const file = path.split('/').pop() ?? path\n return file.replace(/\\.ya?ml$/i, '')\n}\n\nfunction parseModule(mod: unknown): PortalFormDefinition | null {\n if (!mod) return null\n if (typeof mod === 'string') {\n return yaml.load(mod) as PortalFormDefinition\n }\n if (typeof mod === 'object') {\n // vite-plugin-yaml returns parsed objects, possibly wrapped in\n // `{ default: ... }` when imported via `import: 'default'`.\n const maybeDefault = (mod as { default?: unknown }).default\n if (maybeDefault && typeof maybeDefault === 'object') {\n return maybeDefault as PortalFormDefinition\n }\n return mod as PortalFormDefinition\n }\n return null\n}\n\n/** Parse a single raw YAML string into a PortalFormDefinition. */\nexport function parseFormYaml(raw: string): PortalFormDefinition {\n return yaml.load(raw) as PortalFormDefinition\n}\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n error?: string\n /** Optional id to use for the input — wrappers use it for label `for=`. */\n inputId?: string\n}>()\n</script>\n\n<template>\n <div\n class=\"dcs-form-field\"\n :class=\"[`dcs-form-field--${field.type}`, `dcs-form-field--width-${field.width ?? 'full'}`]\"\n :data-form-field-key=\"field.id\"\n >\n <slot name=\"label\">\n <label\n v-if=\"field.type !== 'checkbox' && field.type !== 'hidden' && field.type !== 'section-heading' && field.type !== 'html-block'\"\n :for=\"inputId ?? `field-${field.id}`\"\n class=\"dcs-form-field__label\"\n >\n {{ field.label }}\n <span v-if=\"field.required\" aria-hidden=\"true\" class=\"dcs-form-field__required\">*</span>\n </label>\n </slot>\n\n <slot />\n\n <slot name=\"help\">\n <p v-if=\"field.helpText\" class=\"dcs-form-field__help\">{{ field.helpText }}</p>\n </slot>\n\n <slot name=\"error\">\n <p v-if=\"error\" class=\"dcs-form-field__error\" role=\"alert\">{{ error }}</p>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | number | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst inputType = computed(() => {\n switch (props.field.type) {\n case 'email':\n return 'email'\n case 'tel':\n return 'tel'\n default:\n return 'text'\n }\n})\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :on-input=\"(e: Event) => emit('update:modelValue', (e.target as HTMLInputElement).value)\"\n :on-blur=\"() => emit('blur')\"\n >\n <input\n :id=\"inputId\"\n class=\"dcs-form-input\"\n :type=\"inputType\"\n :name=\"field.id\"\n :value=\"modelValue ?? ''\"\n :placeholder=\"field.placeholder\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :aria-describedby=\"error ? `${inputId}-error` : undefined\"\n @input=\"emit('update:modelValue', ($event.target as HTMLInputElement).value)\"\n @blur=\"emit('blur')\"\n />\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :on-input=\"(e: Event) => emit('update:modelValue', (e.target as HTMLTextAreaElement).value)\"\n :on-blur=\"() => emit('blur')\"\n >\n <textarea\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-textarea\"\n :name=\"field.id\"\n :placeholder=\"field.placeholder\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n rows=\"5\"\n :value=\"modelValue ?? ''\"\n @input=\"emit('update:modelValue', ($event.target as HTMLTextAreaElement).value)\"\n @blur=\"emit('blur')\"\n />\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | string[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string | string[]]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst isMulti = computed(() => props.field.type === 'multiselect')\nconst options = computed(() => props.field.options ?? [])\n\nfunction onChange(e: Event): void {\n const sel = e.target as HTMLSelectElement\n if (isMulti.value) {\n const values: string[] = []\n for (const opt of Array.from(sel.selectedOptions)) values.push(opt.value)\n emit('update:modelValue', values)\n } else {\n emit('update:modelValue', sel.value)\n }\n}\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <slot\n name=\"input\"\n :id=\"inputId\"\n :value=\"modelValue\"\n :options=\"options\"\n :on-change=\"onChange\"\n >\n <select\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-select\"\n :name=\"field.id\"\n :required=\"field.required\"\n :multiple=\"isMulti\"\n :aria-invalid=\"!!error\"\n :value=\"modelValue ?? (isMulti ? [] : '')\"\n @change=\"onChange\"\n @blur=\"emit('blur')\"\n >\n <option v-if=\"!isMulti\" value=\"\" disabled>\n {{ field.placeholder ?? 'Select…' }}\n </option>\n <option v-for=\"opt in options\" :key=\"opt.value\" :value=\"opt.value\">\n {{ opt.label }}\n </option>\n </select>\n </slot>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst options = computed(() => props.field.options ?? [])\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <fieldset\n class=\"dcs-form-radio-group\"\n role=\"radiogroup\"\n :aria-required=\"field.required\"\n :aria-invalid=\"!!error\"\n >\n <legend class=\"sr-only\">{{ field.label }}</legend>\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n class=\"dcs-form-radio\"\n >\n <input\n type=\"radio\"\n :name=\"field.id\"\n :value=\"opt.value\"\n :checked=\"modelValue === opt.value\"\n @change=\"emit('update:modelValue', opt.value)\"\n />\n <span>{{ opt.label }}</span>\n </label>\n </fieldset>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string[]]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst options = computed(() => props.field.options ?? [])\nconst current = computed(() => props.modelValue ?? [])\n\nfunction toggle(value: string, checked: boolean): void {\n const set = new Set(current.value)\n if (checked) set.add(value)\n else set.delete(value)\n emit('update:modelValue', Array.from(set))\n}\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <fieldset\n class=\"dcs-form-checkbox-group\"\n :aria-required=\"field.required\"\n :aria-invalid=\"!!error\"\n >\n <legend class=\"sr-only\">{{ field.label }}</legend>\n <label\n v-for=\"opt in options\"\n :key=\"opt.value\"\n class=\"dcs-form-checkbox\"\n >\n <input\n type=\"checkbox\"\n :name=\"`${field.id}[]`\"\n :value=\"opt.value\"\n :checked=\"current.includes(opt.value)\"\n @change=\"toggle(opt.value, ($event.target as HTMLInputElement).checked)\"\n />\n <span>{{ opt.label }}</span>\n </label>\n </fieldset>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: boolean | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: boolean]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <template #label><span class=\"sr-only\">{{ field.label }}</span></template>\n <label class=\"dcs-form-checkbox-single\" :for=\"inputId\">\n <input\n :id=\"inputId\"\n type=\"checkbox\"\n :name=\"field.id\"\n :checked=\"!!modelValue\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n @change=\"emit('update:modelValue', ($event.target as HTMLInputElement).checked)\"\n />\n <span>{{ field.label }}<span v-if=\"field.required\" aria-hidden=\"true\"> *</span></span>\n </label>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed } from 'vue'\nimport type { PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n modelValue: string | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: string]\n blur: []\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <input\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-date\"\n type=\"date\"\n :name=\"field.id\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :value=\"modelValue ?? ''\"\n @input=\"emit('update:modelValue', ($event.target as HTMLInputElement).value)\"\n @blur=\"emit('blur')\"\n />\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onBeforeUnmount, ref, watch } from 'vue'\nimport type { PortalFormAttachmentPolicy, PortalFormField } from '../types'\nimport DcsFormFieldWrapper from './DcsFormFieldWrapper.vue'\n\nconst props = defineProps<{\n field: PortalFormField\n attachmentPolicy?: PortalFormAttachmentPolicy\n modelValue: File | File[] | undefined\n error?: string\n}>()\n\nconst emit = defineEmits<{\n 'update:modelValue': [value: File | File[] | undefined]\n}>()\n\nconst inputId = computed(() => `field-${props.field.id}`)\nconst inputEl = ref<HTMLInputElement | null>(null)\nconst accept = computed(() => (props.field.validation?.accept ?? props.attachmentPolicy?.accept ?? []).join(','))\nconst maxFiles = computed(() => Math.max(1, Math.floor(props.attachmentPolicy?.maxFiles ?? 1)))\nconst allowsMultiple = computed(() => maxFiles.value > 1)\nconst selectedFiles = computed(() => normalizeFiles(props.modelValue))\nconst previews = ref<Array<{ file: File; url: string; canPreview: boolean }>>([])\n\nfunction normalizeFiles(value: File | File[] | undefined): File[] {\n if (Array.isArray(value)) {\n return value.filter(Boolean)\n }\n return value ? [value] : []\n}\n\nfunction emitFiles(files: File[]): void {\n const capped = files.slice(0, maxFiles.value)\n emit('update:modelValue', allowsMultiple.value ? capped : capped[0])\n}\n\nfunction fileKey(file: File): string {\n return [file.name, file.type, file.size, file.lastModified].join(':')\n}\n\nfunction uniqueFiles(files: File[]): File[] {\n const seen = new Set<string>()\n const out: File[] = []\n for (const file of files) {\n const key = fileKey(file)\n if (seen.has(key)) {\n continue\n }\n seen.add(key)\n out.push(file)\n }\n return out\n}\n\nfunction onChange(e: Event): void {\n const target = e.target as HTMLInputElement\n const picked = Array.from(target.files ?? []).filter((file) => file.size > 0)\n if (picked.length === 0) {\n return\n }\n emitFiles(allowsMultiple.value ? uniqueFiles([...selectedFiles.value, ...picked]) : picked)\n target.value = ''\n}\n\nfunction removeFile(index: number): void {\n const next = selectedFiles.value.filter((_, i) => i !== index)\n emitFiles(next)\n if (next.length === 0 && inputEl.value) {\n inputEl.value.value = ''\n }\n}\n\nfunction formatFileSize(bytes: number): string {\n if (bytes < 1024) {\n return `${bytes} B`\n }\n if (bytes < 1024 * 1024) {\n return `${(bytes / 1024).toFixed(1)} KB`\n }\n return `${(bytes / (1024 * 1024)).toFixed(1)} MB`\n}\n\nfunction revokePreviews(): void {\n for (const preview of previews.value) {\n URL.revokeObjectURL(preview.url)\n }\n previews.value = []\n}\n\nwatch(\n selectedFiles,\n (files) => {\n revokePreviews()\n previews.value = files.map((file) => ({\n file,\n url: URL.createObjectURL(file),\n canPreview: file.type.toLowerCase().startsWith('image/'),\n }))\n },\n { immediate: true },\n)\n\nonBeforeUnmount(revokePreviews)\n</script>\n\n<template>\n <DcsFormFieldWrapper :field=\"field\" :error=\"error\" :input-id=\"inputId\">\n <input\n ref=\"inputEl\"\n :id=\"inputId\"\n class=\"dcs-form-input dcs-form-file\"\n type=\"file\"\n :name=\"field.id\"\n :multiple=\"allowsMultiple\"\n :required=\"field.required\"\n :aria-invalid=\"!!error\"\n :accept=\"accept || undefined\"\n @change=\"onChange\"\n />\n\n <p v-if=\"allowsMultiple\" class=\"dcs-form-file__status\">\n {{ selectedFiles.length }} of {{ maxFiles }} files selected\n </p>\n\n <div\n v-if=\"previews.length > 0\"\n class=\"dcs-form-file-preview-grid\"\n aria-live=\"polite\"\n >\n <div\n v-for=\"(preview, index) in previews\"\n :key=\"fileKey(preview.file)\"\n class=\"dcs-form-file-preview\"\n >\n <img\n v-if=\"preview.canPreview\"\n class=\"dcs-form-file-preview__image\"\n :src=\"preview.url\"\n :alt=\"`${preview.file.name} preview`\"\n />\n <div v-else class=\"dcs-form-file-preview__placeholder\" aria-hidden=\"true\">\n File\n </div>\n <div class=\"dcs-form-file-preview__meta\">\n <span class=\"dcs-form-file-preview__name\">{{ preview.file.name }}</span>\n <span class=\"dcs-form-file-preview__size\">{{ formatFileSize(preview.file.size) }}</span>\n </div>\n <button\n type=\"button\"\n class=\"dcs-form-file-preview__remove\"\n :aria-label=\"`Remove ${preview.file.name}`\"\n @click=\"removeFile(index)\"\n >\n Remove\n </button>\n </div>\n </div>\n </DcsFormFieldWrapper>\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n modelValue: string | number | undefined\n}>()\n</script>\n\n<template>\n <input\n type=\"hidden\"\n :name=\"field.id\"\n :value=\"modelValue ?? (field.defaultValue as string | number | undefined) ?? ''\"\n :data-form-field-key=\"field.id\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n}>()\n</script>\n\n<template>\n <div\n class=\"dcs-form-section\"\n :data-form-field-key=\"field.id\"\n >\n <slot>\n <h3 class=\"dcs-form-section__heading\">{{ field.label }}</h3>\n <p v-if=\"field.helpText\" class=\"dcs-form-section__help\">{{ field.helpText }}</p>\n </slot>\n </div>\n</template>\n","<script setup lang=\"ts\">\nimport type { PortalFormField } from '../types'\n\ndefineProps<{\n field: PortalFormField\n}>()\n</script>\n\n<template>\n <!--\n `html` is sanitized server-side per the schema; rendering with v-html\n is intentional. Site authors must keep portal-side sanitization on.\n -->\n <div\n class=\"dcs-form-html-block\"\n :data-form-field-key=\"field.id\"\n v-html=\"field.html ?? ''\"\n />\n</template>\n","<script setup lang=\"ts\">\nimport { computed, onMounted, ref, watch } from 'vue'\nimport type {\n DcsFormSubmitError,\n DcsFormSubmitSuccess,\n PortalFormDefinition,\n PortalFormField,\n} from './types'\nimport { useUiSound } from '@dcs/ui/sound'\nimport { useDcsForm } from './composables/useDcsForm'\nimport { submitFormValues } from './composables/useFormSubmission'\nimport {\n PHI_GUIDANCE_COPY,\n fetchSiteHandlesPhi,\n} from './composables/useSitePhiPosture'\nimport { warnIfInvalid } from './schema/validate'\nimport { loadFormDefinitions } from './loaders/yaml'\n\nimport DcsFormText from './fields/DcsFormText.vue'\nimport DcsFormTextarea from './fields/DcsFormTextarea.vue'\nimport DcsFormSelect from './fields/DcsFormSelect.vue'\nimport DcsFormRadio from './fields/DcsFormRadio.vue'\nimport DcsFormCheckboxGroup from './fields/DcsFormCheckboxGroup.vue'\nimport DcsFormCheckbox from './fields/DcsFormCheckbox.vue'\nimport DcsFormDate from './fields/DcsFormDate.vue'\nimport DcsFormFile from './fields/DcsFormFile.vue'\nimport DcsFormHidden from './fields/DcsFormHidden.vue'\nimport DcsFormSection from './fields/DcsFormSection.vue'\nimport DcsFormHtmlBlock from './fields/DcsFormHtmlBlock.vue'\n\ninterface Props {\n /** Kebab-case form id; matches `.dcs/forms/<formId>.yaml`. */\n formId: string\n /** Site slug used for the submission endpoint path. */\n siteSlug?: string\n /** Override the loaded definition (used by the portal preview iframe). */\n definitionOverride?: PortalFormDefinition\n /** Override the API base URL; defaults to `VITE_DCS_PUBLIC_API`. */\n apiBase?: string\n /** Optional captcha token, attached to the submission payload. */\n captchaToken?: string\n /**\n * Optional override for the YAML modules map. Mostly for tests; in\n * real apps the build-time `import.meta.glob` call below is used.\n */\n formsModules?: Record<string, unknown>\n}\n\nconst props = defineProps<Props>()\n\nconst emit = defineEmits<{\n 'submit-success': [event: DcsFormSubmitSuccess]\n 'submit-error': [event: DcsFormSubmitError]\n 'validation-error': [errors: Record<string, string | undefined>]\n}>()\n\n// Eager glob — Vite inlines every site form at build time. Customer\n// sites should configure `vite-plugin-yaml` so YAML is parsed to an\n// object; without it the loader falls back to parsing raw strings.\nconst eagerFormsModules = (import.meta as unknown as {\n glob: (\n pattern: string,\n opts: { eager: true; import: string; query?: string },\n ) => Record<string, unknown>\n}).glob('/.dcs/forms/*.yaml', { eager: true, import: 'default' })\n\nconst definitions = computed(() =>\n loadFormDefinitions(props.formsModules ?? eagerFormsModules),\n)\n\nconst definition = computed<PortalFormDefinition | null>(() => {\n if (props.definitionOverride) return props.definitionOverride\n return definitions.value[props.formId] ?? null\n})\n\nconst isDev = !!(import.meta as unknown as { env?: { DEV?: boolean } }).env?.DEV\n\nwatch(\n definition,\n (def) => {\n if (def) warnIfInvalid(props.formId, def, isDev)\n },\n { immediate: true },\n)\n\n// We always call useDcsForm with *some* definition so hooks render\n// stably; if the form is missing we'll show an error state instead.\nconst safeDefinition = computed<PortalFormDefinition>(\n () =>\n definition.value ?? {\n formId: props.formId,\n submission: { kind: 'lead' },\n fields: [],\n },\n)\n\nconst form = useDcsForm({ definition: safeDefinition.value })\n\n// First-party form-success chime (dcs-product-sound). Synthesis lives entirely in\n// the shared engine — this component owns no AudioContext. Calling useUiSound() here\n// also binds the engine's gesture-unlock listeners, so the user's submit click\n// (pointerdown/keydown) resumes the AudioContext synchronously in the gesture;\n// the chime that fires after the async submit resolves then plays on a running\n// context (autoplay-safe by construction). It stays SILENT by default: customer\n// sites are silent-by-default (they never seed sound via configureSoundDefaults),\n// and the engine additionally hard-silences inside the portal editor iframe. The\n// chime activates only once a site opts into sound.\nconst { play: playUiSound } = useUiSound()\n\n// If the resolved definition changes (e.g. preview iframe updates),\n// re-create derived state by resetting.\nwatch(\n () => safeDefinition.value,\n () => form.reset(),\n)\n\nconst apiBase = computed(() => {\n const configured =\n props.apiBase ??\n (import.meta as unknown as { env?: { VITE_DCS_PUBLIC_API?: string } }).env\n ?.VITE_DCS_PUBLIC_API ??\n ''\n if (configured) return configured\n return defaultPublicApiBase()\n})\n\n/**\n * Fallback API base when neither the `api-base` prop nor VITE_DCS_PUBLIC_API\n * is set. A customer apex does not route `/api/v1/sites/*` (an empty base\n * produced a same-origin POST the static host rejects with a 405), so default\n * to the shared public API host; localhost keeps the relative base for the\n * dev proxy.\n */\nfunction defaultPublicApiBase(): string {\n if (typeof window === 'undefined') return ''\n const host = window.location.hostname.toLowerCase()\n if (host === 'localhost' || host === '127.0.0.1' || host === '::1') {\n return '/api/v1'\n }\n return 'https://api.duffcloudservices.com/api/v1'\n}\n\nconst resolvedSiteSlug = computed(\n () =>\n props.siteSlug ??\n (import.meta as unknown as { env?: { VITE_DCS_SITE_SLUG?: string } }).env\n ?.VITE_DCS_SITE_SLUG ??\n '',\n)\n\nconst submitLabel = computed(\n () => safeDefinition.value.submitLabel ?? 'Send',\n)\n\nfunction fieldComponent(field: PortalFormField) {\n switch (field.type) {\n case 'text':\n case 'email':\n case 'tel':\n return DcsFormText\n case 'textarea':\n return DcsFormTextarea\n case 'select':\n case 'multiselect':\n return DcsFormSelect\n case 'radio':\n return DcsFormRadio\n case 'checkbox-group':\n return DcsFormCheckboxGroup\n case 'checkbox':\n return DcsFormCheckbox\n case 'date':\n return DcsFormDate\n case 'file':\n return DcsFormFile\n case 'hidden':\n return DcsFormHidden\n case 'section-heading':\n return DcsFormSection\n case 'html-block':\n return DcsFormHtmlBlock\n default:\n return DcsFormText\n }\n}\n\n// ── PHI guidance (C-415) ────────────────────────────────────────────────────\n// Default-ON for HIPAA-mode tenants (Q-393(b)); there is no per-site opt-in\n// prop, because a site-local switch could disagree with the tenant's real HIPAA\n// posture and the whole point of the C-352 predicate is that exactly one thing\n// decides. Starts false and flips only when the platform says so, so nothing\n// renders on the 11 non-PHI sites in the fleet.\nconst siteHandlesPhi = ref(false)\n\nconst showPhiGuidance = computed(\n () => siteHandlesPhi.value && !!definition.value,\n)\n\n/**\n * Where the guidance sits: immediately above the first FREE-TEXT field the\n * visitor will actually type prose into. Guidance parked at the top of a long\n * form is guidance nobody reads; this puts it in the line of sight of the box\n * that can carry PHI (on KEPT's contact form, the required `message` textarea).\n * Falls back to the top of the visible fields when a form/step has no free-text\n * field — a HIPAA-mode tenant's structured intake is still health information.\n */\nconst phiGuidanceIndex = computed(() => {\n const idx = form.visibleFields.value.findIndex(\n (f) =>\n f.type === 'textarea' || f.role === 'message' || f.role === 'summary',\n )\n return idx >= 0 ? idx : 0\n})\n\nonMounted(async () => {\n siteHandlesPhi.value = await fetchSiteHandlesPhi({\n apiBase: apiBase.value,\n siteSlug: resolvedSiteSlug.value,\n })\n})\n\nconst formEl = ref<HTMLFormElement | null>(null)\n\ndefineExpose({\n values: form.values,\n errors: form.errors,\n validateAll: form.validateAll,\n collectSubmissionValues: form.collectSubmissionValues,\n reset: form.reset,\n})\n\nasync function onSubmit(e: Event): Promise<void> {\n e.preventDefault()\n if (!definition.value) return\n const ok = form.validateAll()\n if (!ok) {\n emit('validation-error', form.errors.value)\n return\n }\n form.submitting.value = true\n form.submitError.value = null\n const payload = {\n formId: props.formId,\n values: form.collectSubmissionValues(),\n captchaToken: props.captchaToken,\n }\n try {\n const result = await submitFormValues({\n apiBase: apiBase.value,\n siteSlug: resolvedSiteSlug.value,\n payload,\n })\n form.submitted.value = true\n // Success confirmed by the server (never on optimistic fire): play only after\n // the submission resolves. Inert unless the site has enabled sound.\n playUiSound('notification.success')\n emit('submit-success', result)\n } catch (err) {\n const e2 = err as DcsFormSubmitError\n form.submitError.value = e2.error?.message ?? 'Submission failed'\n emit('submit-error', e2)\n } finally {\n form.submitting.value = false\n }\n}\n\nonMounted(() => {\n if (!definition.value) {\n // eslint-disable-next-line no-console\n console.warn(\n `[@duffcloudservices/site-forms] No form definition found for \"${props.formId}\". ` +\n `Expected a YAML at .dcs/forms/${props.formId}.yaml. ` +\n `In customer-site repos the YAML lives above the Vite root, so the ` +\n `internal auto-glob will not find it — pass formsModules explicitly: ` +\n `<DcsForm form-id=\"${props.formId}\" :forms-modules=\"dcsFormsModules\" />. ` +\n `See @duffcloudservices/site-forms README \"Vite setup\" section.`,\n )\n }\n})\n</script>\n\n<template>\n <div v-if=\"!definition\" class=\"dcs-form dcs-form--missing\" :data-form-key=\"formId\">\n <slot name=\"missing\" :form-id=\"formId\">\n <p>Form “{{ formId }}” is not configured.</p>\n </slot>\n </div>\n\n <div v-else-if=\"form.submitted.value\" class=\"dcs-form dcs-form--success\" :data-form-key=\"formId\">\n <slot name=\"success\" :definition=\"definition\">\n <p>{{ definition.successMessage ?? 'Thanks — we received your message.' }}</p>\n </slot>\n </div>\n\n <form\n v-else\n ref=\"formEl\"\n class=\"dcs-form\"\n :data-form-key=\"formId\"\n novalidate\n @submit=\"onSubmit\"\n >\n <slot name=\"header\" :definition=\"definition\" />\n\n <div v-if=\"form.steps.value\" class=\"dcs-form__progress\" aria-live=\"polite\">\n <slot\n name=\"progress\"\n :current=\"form.currentStepIndex.value\"\n :total=\"form.steps.value.length\"\n :step=\"form.currentStep.value\"\n >\n <p>\n Step {{ form.currentStepIndex.value + 1 }} of\n {{ form.steps.value.length }}\n <template v-if=\"form.currentStep.value\">\n — {{ form.currentStep.value.title }}\n </template>\n </p>\n </slot>\n </div>\n\n <div class=\"dcs-form__fields\">\n <template\n v-for=\"(field, index) in form.visibleFields.value\"\n :key=\"field.id\"\n >\n <p\n v-if=\"showPhiGuidance && index === phiGuidanceIndex\"\n class=\"dcs-form__phi-guidance\"\n data-form-phi-guidance\n role=\"note\"\n >\n <strong>{{ PHI_GUIDANCE_COPY.lead }}</strong>\n {{ PHI_GUIDANCE_COPY.detail }}\n </p>\n <component\n :is=\"fieldComponent(field)\"\n :field=\"field\"\n :attachment-policy=\"safeDefinition.attachmentPolicy\"\n :model-value=\"form.values[field.id]\"\n :error=\"form.errors.value[field.id]\"\n @update:model-value=\"(v: unknown) => form.setValue(field.id, v)\"\n @blur=\"form.touch(field.id)\"\n />\n </template>\n </div>\n\n <div v-if=\"form.submitError.value\" class=\"dcs-form__submit-error\" role=\"alert\">\n {{ form.submitError.value }}\n </div>\n\n <div class=\"dcs-form__actions\">\n <slot\n name=\"actions\"\n :is-first-step=\"form.isFirstStep.value\"\n :is-last-step=\"form.isLastStep.value\"\n :submitting=\"form.submitting.value\"\n :prev=\"form.prev\"\n :next=\"form.next\"\n >\n <button\n v-if=\"form.steps.value && !form.isFirstStep.value\"\n type=\"button\"\n class=\"dcs-form__btn dcs-form__btn--prev\"\n @click=\"form.prev()\"\n >\n Previous\n </button>\n <button\n v-if=\"form.steps.value && !form.isLastStep.value\"\n type=\"button\"\n class=\"dcs-form__btn dcs-form__btn--next\"\n @click=\"form.next()\"\n >\n Next\n </button>\n <button\n v-if=\"!form.steps.value || form.isLastStep.value\"\n type=\"submit\"\n class=\"dcs-form__btn dcs-form__btn--submit\"\n :disabled=\"form.submitting.value\"\n >\n {{ form.submitting.value ? 'Sending…' : submitLabel }}\n </button>\n </slot>\n </div>\n </form>\n</template>\n","import type { PortalFormDefinition, PortalFormField } from './types'\n\nexport type StandardFormPreset = 'contact' | 'revenue-contractor' | 'resume-submission' | 'custom'\n\nexport interface BuildStandardFormOptions {\n formId?: string\n submitLabel?: string\n successMessage?: string\n leadCategory?: string\n}\n\nexport const STANDARD_FORM_PRESET_META: Record<StandardFormPreset, { label: string; description: string }> = {\n contact: {\n label: 'Contact',\n description: 'Canonical contact form with standard contact fields.',\n },\n 'revenue-contractor': {\n label: 'Revenue contractor',\n description: 'Contact fields plus a required project summary and optional image upload.',\n },\n 'resume-submission': {\n label: 'Resume submission',\n description: 'Candidate contact fields plus a required resume upload.',\n },\n custom: {\n label: 'Custom / free-form',\n description: 'Flexible starter that stays fully editable for questionnaires and bespoke intake.',\n },\n}\n\nconst buildContactFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', width: 'half' },\n { id: 'company', type: 'text', role: 'contact-company', label: 'Company', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'message',\n label: 'How can we help?',\n required: true,\n width: 'full',\n validation: { minLength: 10, maxLength: 2000 },\n },\n]\n\nconst buildRevenueContractorFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', required: true, width: 'half' },\n { id: 'company', type: 'text', role: 'contact-company', label: 'Company', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'summary',\n label: 'Project summary',\n helpText: 'Tell us what you want built, repaired, or updated.',\n required: true,\n width: 'full',\n validation: { minLength: 20, maxLength: 4000 },\n },\n {\n id: 'project-image',\n type: 'file',\n role: 'image-attachments',\n label: 'Reference image',\n helpText: 'Optional. Upload one photo or inspiration image to help us understand the request.',\n width: 'full',\n validation: { accept: ['image/*'] },\n },\n]\n\nconst buildResumeSubmissionFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', role: 'contact-name', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', role: 'contact-email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', role: 'contact-phone', label: 'Phone', width: 'half' },\n { id: 'position', type: 'text', label: 'Role you are applying for', width: 'full' },\n {\n id: 'message',\n type: 'textarea',\n role: 'message',\n label: 'Anything else we should know?',\n width: 'full',\n validation: { maxLength: 2000 },\n },\n {\n id: 'resume',\n type: 'file',\n role: 'resume',\n label: 'Resume',\n required: true,\n width: 'full',\n validation: {\n accept: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n ],\n },\n },\n]\n\nconst buildCustomFields = (): PortalFormField[] => [\n { id: 'name', type: 'text', label: 'Full name', required: true, width: 'full' },\n { id: 'email', type: 'email', label: 'Email', required: true, width: 'half' },\n { id: 'phone', type: 'tel', label: 'Phone', width: 'half' },\n {\n id: 'message',\n type: 'textarea',\n label: 'Message',\n required: true,\n width: 'full',\n validation: { minLength: 10, maxLength: 2000 },\n },\n]\n\nexport function buildStandardFormDefinition(\n preset: StandardFormPreset,\n options: BuildStandardFormOptions = {},\n): PortalFormDefinition {\n const resolvedPreset = preset ?? 'custom'\n\n switch (resolvedPreset) {\n case 'contact':\n return {\n formId: options.formId ?? 'contact',\n formKind: 'contact',\n submitLabel: options.submitLabel ?? 'Send',\n successMessage: options.successMessage ?? 'Thanks — we’ll be in touch shortly.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n fields: buildContactFields(),\n }\n\n case 'revenue-contractor':\n return {\n formId: options.formId ?? 'contact',\n formKind: 'revenue-contractor',\n submitLabel: options.submitLabel ?? 'Request estimate',\n successMessage: options.successMessage ?? 'Thanks — we’ll review your project and follow up soon.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n attachmentPolicy: {\n expected: true,\n required: false,\n maxFiles: 5,\n accept: ['image/*'],\n },\n fields: buildRevenueContractorFields(),\n }\n\n case 'resume-submission':\n return {\n formId: options.formId ?? 'resume',\n formKind: 'resume-submission',\n submitLabel: options.submitLabel ?? 'Submit resume',\n successMessage: options.successMessage ?? 'Thanks — your application was received.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n attachmentPolicy: {\n expected: true,\n required: true,\n maxFiles: 1,\n accept: [\n 'application/pdf',\n 'application/msword',\n 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',\n ],\n },\n fields: buildResumeSubmissionFields(),\n }\n\n default:\n return {\n formId: options.formId ?? 'custom-form',\n formKind: 'freeform',\n submitLabel: options.submitLabel ?? 'Send',\n successMessage: options.successMessage ?? 'Thanks — we received your submission.',\n submission: {\n kind: 'lead',\n ...(options.leadCategory ? { category: options.leadCategory } : {}),\n },\n fields: buildCustomFields(),\n }\n }\n}\n"],"names":["STORAGE_KEY","LIBRARY_DEFAULT","clampVolume","v","n","normalize","raw","base","cats","readStored","stored","config","ref","hasPersisted","persist","next","watch","STOP_TAIL","MIN_GAIN","playTone","ctx","dest","opts","now","freq","type","dur","gain","attack","glideTo","osc","amp","playFmBell","ratio","index","carrier","mod","modGain","playNoiseBurst","cutoff","q","sweepTo","frames","buffer","data","i","src","filter","C5","D5","E5","G5","C6","G4","A4","D4","ROLES","THROTTLE_MS","master","unlockBound","gestureSeen","lastPlayed","didPlayListeners","isEmbedded","prefersReducedMotion","ensureContext","Ctor","bindUnlock","events","handler","c","ev","onDidPlay","listener","shouldPlay","role","spec","category","last","play","finalGain","fn","reducedMotionActive","mq","e","applyEnabled","value","useUiSound","enabled","computed","volume","hintShown","mutedByReducedMotion","isFieldVisible","field","values","validateField","attachmentPolicy","normalizedValue","isEmpty","files","filesFromValue","maxFiles","maxFileSizeBytes","accept","oversized","file","formatBytes","rejected","isAcceptedFile","validateForm","def","fieldIds","errors","ids","err","hasErrors","item","name","contentType","rule","normalized","bytes","defaultsFor","out","f","useDcsForm","definition","reactive","touched","submitting","submitted","submitError","currentStepIndex","fields","steps","currentStep","s","currentStepFields","step","isFirstStep","isLastStep","visibleFields","setValue","id","touch","validateScope","scopeFieldIds","merged","validateCurrentScope","scope","validateAll","prev","reset","fresh","k","collectSubmissionValues","readOkBody","res","label","LOG_PREFIX","readContentType","readError","unreadableBodyError","emptyBodyError","nonJsonBodyError","readExpectedJson","validator","options","body","invalidReceiptError","MANAGED_FORM_STATUSES","isManagedFormReceipt","isRecord","isNonEmptyString","isOneOf","isTimestamp","CONTACT_STATUSES","isSiteContactReceipt","isEstimateReceipt","isPasswordlessVerifyReceipt","isBookingCancellationReceipt","VISITOR_UNCONFIRMED_MESSAGE","allowed","unconfirmed","message","receiptRejected","status","cause","detail","looksLikeHtml","receiptName","safeStringify","submitFormValues","apiBase","siteSlug","payload","retries","fetchImpl","formPath","trimmedSlug","url","hasFile","valueHasFile","lastError","lastStatus","attempt","init","REDIRECT_MODE","buildFormData","bodyError","safeText","fd","key","postureCache","resetSitePhiPostureCache","fetchSiteHandlesPhi","slug","cacheKey","cached","pending","PHI_GUIDANCE_COPY","getValidator","ajv","Ajv","addFormats","schema","validateFormDefinition","valid","warnIfInvalid","formId","isDev","result","loadFormDefinitions","modules","path","extractFormId","parseModule","yaml","maybeDefault","parseFormYaml","_createElementBlock","_normalizeClass","__props","_renderSlot","_ctx","_hoisted_3","_openBlock","_hoisted_4","_toDisplayString","_hoisted_5","props","emit","__emit","inputId","inputType","_createBlock","DcsFormFieldWrapper","_createElementVNode","$event","isMulti","onChange","sel","opt","_hoisted_2","_Fragment","_renderList","current","toggle","checked","set","_hoisted_1","_createTextVNode","inputEl","allowsMultiple","selectedFiles","normalizeFiles","previews","emitFiles","capped","fileKey","uniqueFiles","seen","target","picked","removeFile","_","formatFileSize","revokePreviews","preview","onBeforeUnmount","_hoisted_6","_hoisted_7","_hoisted_8","_hoisted_9","eagerFormsModules","definitions","safeDefinition","form","playUiSound","configured","__vite_import_meta_env__","defaultPublicApiBase","host","resolvedSiteSlug","submitLabel","fieldComponent","DcsFormText","DcsFormTextarea","DcsFormSelect","DcsFormRadio","DcsFormCheckboxGroup","DcsFormCheckbox","DcsFormDate","DcsFormFile","DcsFormHidden","DcsFormSection","DcsFormHtmlBlock","siteHandlesPhi","showPhiGuidance","phiGuidanceIndex","idx","onMounted","formEl","__expose","onSubmit","e2","_unref","_resolveDynamicComponent","_cache","STANDARD_FORM_PRESET_META","buildContactFields","buildRevenueContractorFields","buildResumeSubmissionFields","buildCustomFields","buildStandardFormDefinition","preset"],"mappings":"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"}
|