@nodii/onboarding 0.0.1 → 0.1.0-dev.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/dist/chunk-34BQX2KR.js +164 -0
- package/dist/chunk-34BQX2KR.js.map +1 -0
- package/dist/chunk-4SWOVHZ2.js +434 -0
- package/dist/chunk-4SWOVHZ2.js.map +1 -0
- package/dist/chunk-7NS7ENJV.js +232 -0
- package/dist/chunk-7NS7ENJV.js.map +1 -0
- package/dist/chunk-AFCJLUPK.js +92 -0
- package/dist/chunk-AFCJLUPK.js.map +1 -0
- package/dist/chunk-AW7W3HAC.js +154 -0
- package/dist/chunk-AW7W3HAC.js.map +1 -0
- package/dist/chunk-BIFANV7M.js +22 -0
- package/dist/chunk-BIFANV7M.js.map +1 -0
- package/dist/chunk-BQCTDU5V.js +327 -0
- package/dist/chunk-BQCTDU5V.js.map +1 -0
- package/dist/chunk-JFIONONR.js +3 -0
- package/dist/chunk-JFIONONR.js.map +1 -0
- package/dist/chunk-SWMIIUXR.js +1162 -0
- package/dist/chunk-SWMIIUXR.js.map +1 -0
- package/dist/chunk-VH6FWDWI.js +3 -0
- package/dist/chunk-VH6FWDWI.js.map +1 -0
- package/dist/chunk-Z4PA6C2Z.js +3 -0
- package/dist/chunk-Z4PA6C2Z.js.map +1 -0
- package/dist/chunk-ZDY2I6KY.js +3 -0
- package/dist/chunk-ZDY2I6KY.js.map +1 -0
- package/dist/dynamic/index.d.ts +184 -0
- package/dist/dynamic/index.js +4 -0
- package/dist/dynamic/index.js.map +1 -0
- package/dist/form/index.d.ts +64 -0
- package/dist/form/index.js +5 -0
- package/dist/form/index.js.map +1 -0
- package/dist/index.d.ts +10 -2
- package/dist/index.js +14 -2
- package/dist/index.js.map +1 -0
- package/dist/model-IEyDI54w.d.ts +487 -0
- package/dist/recaptcha/index.d.ts +102 -0
- package/dist/recaptcha/index.js +4 -0
- package/dist/recaptcha/index.js.map +1 -0
- package/dist/schema-TfyBU6JW.d.ts +107 -0
- package/dist/signup-client-Bl6eUrxR.d.ts +259 -0
- package/dist/spec/index.d.ts +88 -0
- package/dist/spec/index.js +4 -0
- package/dist/spec/index.js.map +1 -0
- package/dist/submit/index.d.ts +106 -0
- package/dist/submit/index.js +6 -0
- package/dist/submit/index.js.map +1 -0
- package/dist/widget/index.d.ts +219 -0
- package/dist/widget/index.js +10 -0
- package/dist/widget/index.js.map +1 -0
- package/package.json +77 -6
- package/README.md +0 -5
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/dynamic/derive.ts","../src/dynamic/stepper.ts"],"names":["z"],"mappings":"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","file":"chunk-4SWOVHZ2.js","sourcesContent":["/**\n * Spec → Zod validator derivation (D540 §3).\n *\n * Turns arbitrary SpecField descriptors from the served spec into Zod\n * schemas for CLIENT-side UX validation. The server re-validates\n * authoritatively (D540 §2) — client validation is a convenience layer,\n * so the derivation is deliberately conservative:\n *\n * - Known `type`s map to typed schemas (see FIELD TYPE MAP below).\n * - An UNKNOWN type falls back to z.string() (never blocks a field the\n * server knows how to validate).\n * - Known `validation` keys are applied (minLength, maxLength, min, max,\n * pattern, format:\"email\"). Unknown validation keys are IGNORED\n * client-side — the server enforces them.\n * - `required:false` fields accept undefined AND \"\" (an empty input is\n * \"not provided\").\n * - select/radio values must be one of `options`; multiselect values\n * must be a subset.\n *\n * FIELD TYPE MAP:\n * text | textarea | tel | (unknown) → string\n * email → string().email()\n * number → coerce.number (DOM inputs are strings)\n * checkbox | boolean → boolean\n * select | radio → string ∈ options\n * multiselect → string[] ⊆ options\n * date → string, parseable as a date\n */\n\nimport { z } from \"zod/v3\";\nimport type { SpecField, SpecStep } from \"../spec/model.js\";\n\n/** Extract the comparable value of an option entry ({value}, {key}, or scalar). */\nexport function optionValue(option: unknown): string {\n if (option !== null && typeof option === \"object\") {\n const o = option as Record<string, unknown>;\n if (\"value\" in o) return String(o[\"value\"]);\n if (\"key\" in o) return String(o[\"key\"]);\n }\n return String(option);\n}\n\ninterface KnownValidation {\n minLength?: number;\n maxLength?: number;\n min?: number;\n max?: number;\n pattern?: string;\n format?: string;\n}\n\nfunction knownValidation(field: SpecField): KnownValidation {\n const v = field.validation ?? {};\n const out: KnownValidation = {};\n if (typeof v[\"minLength\"] === \"number\") out.minLength = v[\"minLength\"];\n if (typeof v[\"maxLength\"] === \"number\") out.maxLength = v[\"maxLength\"];\n if (typeof v[\"min\"] === \"number\") out.min = v[\"min\"];\n if (typeof v[\"max\"] === \"number\") out.max = v[\"max\"];\n if (typeof v[\"pattern\"] === \"string\") out.pattern = v[\"pattern\"];\n if (typeof v[\"format\"] === \"string\") out.format = v[\"format\"];\n return out;\n}\n\nfunction stringSchema(field: SpecField): z.ZodTypeAny {\n const v = knownValidation(field);\n let s = z.string();\n if (field.type === \"email\" || v.format === \"email\") {\n s = s.email(`${field.label} must be a valid email`);\n }\n if (v.minLength !== undefined) {\n s = s.min(\n v.minLength,\n `${field.label} must be at least ${v.minLength} characters`,\n );\n }\n if (v.maxLength !== undefined) {\n s = s.max(\n v.maxLength,\n `${field.label} must be at most ${v.maxLength} characters`,\n );\n }\n if (v.pattern !== undefined) {\n try {\n s = s.regex(\n new RegExp(v.pattern),\n `${field.label} has an invalid format`,\n );\n } catch {\n // Invalid regex in the spec — skip client-side; server enforces.\n }\n }\n return s;\n}\n\nfunction numberSchema(field: SpecField): z.ZodTypeAny {\n const v = knownValidation(field);\n let s = z.coerce.number({\n invalid_type_error: `${field.label} must be a number`,\n });\n if (v.min !== undefined) {\n s = s.min(v.min, `${field.label} must be at least ${v.min}`);\n }\n if (v.max !== undefined) {\n s = s.max(v.max, `${field.label} must be at most ${v.max}`);\n }\n return s;\n}\n\nfunction enumSchema(field: SpecField): z.ZodTypeAny {\n const allowed = (field.options ?? []).map(optionValue);\n if (allowed.length === 0) return z.string();\n return z.string().refine((val) => allowed.includes(val), {\n message: `${field.label} must be one of the offered options`,\n });\n}\n\nfunction multiEnumSchema(field: SpecField): z.ZodTypeAny {\n const allowed = (field.options ?? []).map(optionValue);\n const item =\n allowed.length === 0\n ? z.string()\n : z.string().refine((val) => allowed.includes(val), {\n message: `${field.label} contains a value outside the offered options`,\n });\n return z.array(item);\n}\n\nfunction dateSchema(field: SpecField): z.ZodTypeAny {\n return z.string().refine((val) => !Number.isNaN(Date.parse(val)), {\n message: `${field.label} must be a valid date`,\n });\n}\n\n/** Derive the value schema for one field, BEFORE the required/optional wrap. */\nfunction baseSchema(field: SpecField): z.ZodTypeAny {\n switch (field.type) {\n case \"email\":\n return stringSchema(field);\n case \"number\":\n return numberSchema(field);\n case \"checkbox\":\n case \"boolean\":\n return z.boolean();\n case \"select\":\n case \"radio\":\n return enumSchema(field);\n case \"multiselect\":\n return multiEnumSchema(field);\n case \"date\":\n return dateSchema(field);\n default:\n // text | textarea | tel | any unknown type → string with validation\n return stringSchema(field);\n }\n}\n\n/**\n * Derive the full Zod schema for one SpecField.\n * Optional fields accept undefined and \"\" (\"not provided\" in a form UI).\n * Required fields additionally reject \"\" for string-typed inputs.\n */\nexport function deriveFieldSchema(field: SpecField): z.ZodTypeAny {\n const base = baseSchema(field);\n if (field.required) {\n // Required string inputs must be non-empty.\n if (\n field.type !== \"checkbox\" &&\n field.type !== \"boolean\" &&\n field.type !== \"number\" &&\n field.type !== \"multiselect\"\n ) {\n return z\n .string({ required_error: `${field.label} is required` })\n .min(1, `${field.label} is required`)\n .pipe(base);\n }\n if (field.type === \"number\") {\n // A required number must be PRESENT. Without this guard,\n // z.coerce.number(\"\") coerces the empty DOM value to 0 and passes —\n // then buildSubmitPayload drops the \"\" answer, so the client declares\n // the form valid while the server 422s on a missing required field.\n // Reject empty/missing BEFORE coercion; a provided value flows to\n // the coercing number schema (min/max still apply).\n return z\n .any()\n .refine(\n (val) => val !== \"\" && val !== undefined && val !== null,\n `${field.label} is required`,\n )\n .pipe(base);\n }\n if (field.type === \"multiselect\") {\n return base.refine(\n (val) => Array.isArray(val) && val.length > 0,\n `${field.label} requires at least one selection`,\n );\n }\n return base;\n }\n // Optional: \"\" normalizes to undefined before validation.\n return z.preprocess(\n (val) =>\n val === \"\" || val === undefined || val === null ? undefined : val,\n base.optional(),\n );\n}\n\n/**\n * Derive a STRICT Zod object schema for one step's fields — unknown answer\n * keys within the step are rejected (mirrors the server's authoritative\n * re-validation posture; a stale client must not silently carry fields the\n * spec no longer defines).\n */\nexport function deriveStepSchema(step: SpecStep) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const field of step.fields) {\n shape[field.key] = deriveFieldSchema(field);\n }\n return z.object(shape).strict();\n}\n\n/**\n * Derive the STRICT schema for the complete answers object across all\n * steps (used at submit time and by the 409-stale re-validation).\n */\nexport function deriveAnswersSchema(steps: SpecStep[]) {\n const shape: Record<string, z.ZodTypeAny> = {};\n for (const step of steps) {\n for (const field of step.fields) {\n shape[field.key] = deriveFieldSchema(field);\n }\n }\n return z.object(shape).strict();\n}\n","/**\n * Headless dynamic signup stepper (D540 §1/§3).\n *\n * The steps are GENERATED from the served spec: fields bucket by `stage`\n * server-side → the spec's forms.signup.steps array. More configured\n * fields ⇒ more steps. The final `activation` stage carries the\n * service-selection inputs feeding the existing terminal-stage guards.\n *\n * Framework-agnostic: same subscribe/mutate contract as the Phase-1\n * contact-form state. The default component layer renders it; framework\n * integrations can wrap it.\n *\n * 409 spec_stale flow (D540 reject-stale): the CALLER (widget/submit\n * orchestration) refetches the spec on OnboardingSpecStaleError and calls\n * `applyNewSpec(newSpec)`. The stepper re-validates every answer against\n * the NEW derived schema, DROPS answers whose fields no longer exist,\n * marks `specStale: true`, and repositions to the first step with errors —\n * the user re-confirms; the SDK NEVER silently auto-resubmits.\n */\n\nimport { z, type ZodIssue } from \"zod/v3\";\nimport type { OnboardingSpec, SpecStep, TerminalStage } from \"../spec/model.js\";\nimport { deriveAnswersSchema, deriveStepSchema } from \"./derive.js\";\nimport type { FieldError } from \"../form/state.js\";\n\nexport type StepperStatus = \"editing\" | \"submitting\" | \"success\" | \"error\";\n\nexport interface SignupConsent {\n tosAccepted: boolean;\n privacyAccepted: boolean;\n}\n\nexport interface SignupCredentials {\n email: string;\n password: string;\n}\n\nexport interface SignupStepperState {\n /** Zero-based index of the current step. */\n stepIndex: number;\n stepCount: number;\n currentStep: SpecStep | null;\n /** Answers keyed by field key (only keys defined by the active spec). */\n answers: Record<string, unknown>;\n /** Derived from serviceSelection-flagged answers (see buildSubmitPayload). */\n selectedServices: string[];\n /** Validation errors for the CURRENT step (or full-form at submit). */\n errors: FieldError[];\n /** Credential/consent errors (submit-time). */\n accountErrors: FieldError[];\n consent: SignupConsent;\n credentials: SignupCredentials;\n status: StepperStatus;\n serverError: string | null;\n /** True after a 409-stale spec swap until the user re-validates. */\n specStale: boolean;\n /** The specVersion currently driving the form (echoed on submit). */\n specVersion: string;\n /** Set on success from the submit response. */\n terminalStage: TerminalStage | null;\n}\n\nexport type SignupStepperListener = (state: SignupStepperState) => void;\n\n/** The locked credential constraints (PublicOnboardingSubmitRequest). */\nconst credentialsSchema = z.object({\n email: z.string().email(\"A valid account email is required\"),\n password: z\n .string()\n .min(12, \"Password must be at least 12 characters\")\n .max(256, \"Password must be at most 256 characters\"),\n});\n\nfunction zodIssuesToFieldErrors(issues: ZodIssue[]): FieldError[] {\n return issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n}\n\n/** Flatten a serviceSelection field's answer into service ids. */\nfunction serviceIdsOf(key: string, value: unknown): string[] {\n if (typeof value === \"string\" && value !== \"\") return [value];\n if (Array.isArray(value)) return value.map((v) => String(v));\n if (value === true) return [key];\n return [];\n}\n\nexport interface SignupStepperControl {\n getState(): SignupStepperState;\n setAnswer(key: string, value: unknown): void;\n setConsent(consent: Partial<SignupConsent>): void;\n setCredentials(credentials: Partial<SignupCredentials>): void;\n /** Validate ONLY the current step. Returns true when clean. */\n validateStep(): boolean;\n /** Validate current step; advance when clean. Returns true if advanced. */\n next(): boolean;\n back(): void;\n isFirstStep(): boolean;\n isLastStep(): boolean;\n /**\n * Full-form validation: every step's answers + credentials + consent.\n * Populates errors/accountErrors. Returns true when submittable.\n */\n validateAll(): boolean;\n /**\n * The submit payload body (minus botToken, which the transport attaches).\n * Call ONLY after validateAll() returns true.\n */\n buildSubmitPayload(): {\n specVersion: string;\n answers: Record<string, unknown>;\n selectedServices?: string[];\n consent: { tosAccepted: true; privacyAccepted: true };\n credentials: SignupCredentials;\n };\n /**\n * Swap in a refetched spec after 409 spec_stale. Drops answers for\n * removed fields, re-validates the rest, marks specStale, repositions\n * to the first step with errors. NEVER auto-resubmits.\n */\n applyNewSpec(spec: OnboardingSpec): void;\n /** Clear the specStale flag once the user has re-confirmed. */\n acknowledgeSpecStale(): void;\n setSubmitting(): void;\n setSuccess(terminalStage: TerminalStage): void;\n setError(message: string): void;\n /**\n * Reset to the pristine initial state against the CURRENT spec: step 0,\n * status \"editing\", answers/credentials/consent/errors cleared. This is\n * the only transition back OUT of \"success\"/\"error\"; the widget's reset()\n * relies on it (otherwise a post-success keystroke would re-emit\n * status \"success\" and re-hide the form).\n */\n reset(): void;\n subscribe(listener: SignupStepperListener): () => void;\n}\n\n/**\n * Create a headless stepper for the spec's signup form.\n *\n * @example\n * ```ts\n * const spec = await fetchOnboardingSpec({ baseUrl, onboarder });\n * const stepper = createSignupStepper(spec);\n * stepper.subscribe(render);\n * stepper.setAnswer(\"company_name\", \"ACME\");\n * if (stepper.next()) { ... }\n * ```\n */\nexport function createSignupStepper(\n spec: OnboardingSpec,\n): SignupStepperControl {\n let steps: SpecStep[] = spec.forms.signup.steps;\n let specVersion = spec.specVersion;\n\n let state: SignupStepperState = {\n stepIndex: 0,\n stepCount: steps.length,\n currentStep: steps[0] ?? null,\n answers: {},\n selectedServices: [],\n errors: [],\n accountErrors: [],\n consent: { tosAccepted: false, privacyAccepted: false },\n credentials: { email: \"\", password: \"\" },\n status: \"editing\",\n serverError: null,\n specStale: false,\n specVersion,\n terminalStage: null,\n };\n\n // Which step indices have been validated at least once. Once a step has\n // been validated, EVERY subsequent setAnswer revalidates it — so a\n // fix-then-rebreak on that step re-shows the error immediately (matching\n // the Phase-1 contact-form `hasValidated` fix). Before a step is validated,\n // typing does not spray errors. Cleared on reset()/applyNewSpec.\n let validatedSteps = new Set<number>();\n\n const listeners = new Set<SignupStepperListener>();\n\n function emit(): void {\n for (const listener of listeners) {\n listener(structuredClone(state));\n }\n }\n\n function knownFieldKeys(): Set<string> {\n const keys = new Set<string>();\n for (const step of steps) {\n for (const field of step.fields) keys.add(field.key);\n }\n return keys;\n }\n\n /** Answers restricted to the current step's fields. */\n function stepAnswers(step: SpecStep): Record<string, unknown> {\n const out: Record<string, unknown> = {};\n for (const field of step.fields) {\n if (field.key in state.answers) out[field.key] = state.answers[field.key];\n }\n return out;\n }\n\n function deriveSelectedServices(): string[] {\n const services: string[] = [];\n for (const step of steps) {\n for (const field of step.fields) {\n if (field.serviceSelection === true) {\n services.push(...serviceIdsOf(field.key, state.answers[field.key]));\n }\n }\n }\n return [...new Set(services)];\n }\n\n function runStepValidation(step: SpecStep): FieldError[] {\n const result = deriveStepSchema(step).safeParse(stepAnswers(step));\n return result.success ? [] : zodIssuesToFieldErrors(result.error.issues);\n }\n\n function firstStepWithErrors(): number {\n for (let i = 0; i < steps.length; i++) {\n const step = steps[i];\n if (step && runStepValidation(step).length > 0) return i;\n }\n return 0;\n }\n\n return {\n getState() {\n return structuredClone(state);\n },\n\n setAnswer(key, value) {\n state = {\n ...state,\n answers: { ...state.answers, [key]: value },\n };\n state.selectedServices = deriveSelectedServices();\n // Live-revalidate once THIS step has been validated at least once —\n // regardless of whether errors are currently showing. This is the\n // fix-then-rebreak fix: after fixing a field (errors → 0), breaking it\n // again must re-show the error without a fresh next()/validateStep().\n if (validatedSteps.has(state.stepIndex) && state.currentStep) {\n state = { ...state, errors: runStepValidation(state.currentStep) };\n }\n emit();\n },\n\n setConsent(consent) {\n state = { ...state, consent: { ...state.consent, ...consent } };\n emit();\n },\n\n setCredentials(credentials) {\n state = {\n ...state,\n credentials: { ...state.credentials, ...credentials },\n };\n emit();\n },\n\n validateStep() {\n if (!state.currentStep) return true;\n validatedSteps.add(state.stepIndex);\n const errors = runStepValidation(state.currentStep);\n state = { ...state, errors };\n emit();\n return errors.length === 0;\n },\n\n next() {\n if (!state.currentStep) return false;\n validatedSteps.add(state.stepIndex);\n const errors = runStepValidation(state.currentStep);\n if (errors.length > 0) {\n state = { ...state, errors };\n emit();\n return false;\n }\n if (state.stepIndex >= steps.length - 1) return false;\n const stepIndex = state.stepIndex + 1;\n state = {\n ...state,\n stepIndex,\n currentStep: steps[stepIndex] ?? null,\n errors: [],\n };\n emit();\n return true;\n },\n\n back() {\n if (state.stepIndex === 0) return;\n const stepIndex = state.stepIndex - 1;\n state = {\n ...state,\n stepIndex,\n currentStep: steps[stepIndex] ?? null,\n errors: [],\n };\n emit();\n },\n\n isFirstStep() {\n return state.stepIndex === 0;\n },\n\n isLastStep() {\n return state.stepIndex >= steps.length - 1;\n },\n\n validateAll() {\n // A full validation counts as validating every step.\n for (let i = 0; i < steps.length; i++) validatedSteps.add(i);\n // Answers across ALL steps (strict — unknown keys rejected).\n const answersResult = deriveAnswersSchema(steps).safeParse(state.answers);\n const errors = answersResult.success\n ? []\n : zodIssuesToFieldErrors(answersResult.error.issues);\n\n // Credentials + consent (locked submit contract).\n const accountErrors: FieldError[] = [];\n const credResult = credentialsSchema.safeParse(state.credentials);\n if (!credResult.success) {\n accountErrors.push(...zodIssuesToFieldErrors(credResult.error.issues));\n }\n if (state.consent.tosAccepted !== true) {\n accountErrors.push({\n path: \"tosAccepted\",\n message: \"You must accept the Terms of Service\",\n });\n }\n if (state.consent.privacyAccepted !== true) {\n accountErrors.push({\n path: \"privacyAccepted\",\n message: \"You must accept the Privacy Policy\",\n });\n }\n\n state = { ...state, errors, accountErrors };\n emit();\n return errors.length === 0 && accountErrors.length === 0;\n },\n\n buildSubmitPayload() {\n // COMPLIANCE-CRITICAL: never fabricate legal consent. Read the ACTUAL\n // consent state and refuse to build a payload unless the user genuinely\n // accepted both. A headless caller that skips validateAll() must not be\n // able to transmit consent:true for a user who never consented.\n if (\n state.consent.tosAccepted !== true ||\n state.consent.privacyAccepted !== true\n ) {\n throw new Error(\n \"buildSubmitPayload: cannot build a submit payload without genuine \" +\n \"user consent (tosAccepted && privacyAccepted must both be true). \" +\n \"Call validateAll() and surface the consent errors to the user first.\",\n );\n }\n\n // Run answers through the derived schema so the wire carries COERCED\n // typed values (e.g. number fields as numbers, not raw DOM strings) —\n // this is the exact validation validateAll() applies, so a payload can\n // only be built from a state that would pass. A required field that is\n // empty/missing FAILS here (see deriveFieldSchema's required wrap),\n // so buildSubmitPayload throws rather than silently dropping it.\n const parsed = deriveAnswersSchema(steps).safeParse(state.answers);\n if (!parsed.success) {\n const detail = parsed.error.issues\n .map((i) => `${i.path.join(\".\") || \"(answers)\"}: ${i.message}`)\n .join(\"; \");\n throw new Error(\n `buildSubmitPayload: answers failed validation — call validateAll() first (${detail}).`,\n );\n }\n\n // Only keys the active spec defines, with empty optionals omitted.\n const known = knownFieldKeys();\n const answers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(parsed.data)) {\n if (known.has(key) && value !== undefined && value !== \"\") {\n answers[key] = value;\n }\n }\n const selectedServices = deriveSelectedServices();\n return {\n specVersion,\n answers,\n ...(selectedServices.length > 0 ? { selectedServices } : {}),\n consent: {\n tosAccepted: state.consent.tosAccepted,\n privacyAccepted: state.consent.privacyAccepted,\n } as { tosAccepted: true; privacyAccepted: true },\n credentials: { ...state.credentials },\n };\n },\n\n applyNewSpec(newSpec) {\n steps = newSpec.forms.signup.steps;\n specVersion = newSpec.specVersion;\n\n // Drop answers for fields the new spec no longer defines.\n const known = new Set<string>();\n for (const step of steps) {\n for (const field of step.fields) known.add(field.key);\n }\n const answers: Record<string, unknown> = {};\n for (const [key, value] of Object.entries(state.answers)) {\n if (known.has(key)) answers[key] = value;\n }\n\n state = {\n ...state,\n answers,\n stepCount: steps.length,\n specVersion,\n specStale: true,\n status: \"editing\",\n serverError: null,\n };\n state.selectedServices = deriveSelectedServices();\n\n // Reposition to the first step with errors under the NEW schema so\n // the user reviews exactly what changed; errors render immediately.\n const stepIndex = Math.min(firstStepWithErrors(), steps.length - 1);\n const currentStep = steps[Math.max(stepIndex, 0)] ?? null;\n // The repositioned step is being shown with errors → treat it as\n // validated so live-revalidation is active there immediately.\n validatedSteps = new Set<number>([Math.max(stepIndex, 0)]);\n state = {\n ...state,\n stepIndex: Math.max(stepIndex, 0),\n currentStep,\n errors: currentStep ? runStepValidation(currentStep) : [],\n };\n emit();\n },\n\n acknowledgeSpecStale() {\n state = { ...state, specStale: false };\n emit();\n },\n\n setSubmitting() {\n state = {\n ...state,\n status: \"submitting\",\n serverError: null,\n };\n emit();\n },\n\n setSuccess(terminalStage) {\n state = { ...state, status: \"success\", terminalStage, serverError: null };\n emit();\n },\n\n setError(message) {\n state = { ...state, status: \"error\", serverError: message };\n emit();\n },\n\n reset() {\n validatedSteps = new Set<number>();\n state = {\n stepIndex: 0,\n stepCount: steps.length,\n currentStep: steps[0] ?? null,\n answers: {},\n selectedServices: [],\n errors: [],\n accountErrors: [],\n consent: { tosAccepted: false, privacyAccepted: false },\n credentials: { email: \"\", password: \"\" },\n status: \"editing\",\n serverError: null,\n specStale: false,\n specVersion,\n terminalStage: null,\n };\n emit();\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,232 @@
|
|
|
1
|
+
// src/recaptcha/loader.ts
|
|
2
|
+
var RECAPTCHA_SCRIPT_ID = "__nodii_recaptcha_script__";
|
|
3
|
+
var DEFAULT_TIMEOUT_MS = 1e4;
|
|
4
|
+
var POLL_INTERVAL_MS = 50;
|
|
5
|
+
var RecaptchaError = class extends Error {
|
|
6
|
+
kind;
|
|
7
|
+
constructor(kind, message) {
|
|
8
|
+
super(message);
|
|
9
|
+
this.name = "RecaptchaError";
|
|
10
|
+
this.kind = kind;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
var cachedLoad = null;
|
|
14
|
+
var activeSiteKey = null;
|
|
15
|
+
var ownsGlobal = false;
|
|
16
|
+
function removeOwnScriptTag() {
|
|
17
|
+
if (typeof document === "undefined") return;
|
|
18
|
+
const tag = document.getElementById(RECAPTCHA_SCRIPT_ID);
|
|
19
|
+
tag?.parentNode?.removeChild(tag);
|
|
20
|
+
}
|
|
21
|
+
function readyWithTimeout(grecaptcha, timeoutMs, onReady, onTimeout) {
|
|
22
|
+
let done = false;
|
|
23
|
+
const timer = setTimeout(() => {
|
|
24
|
+
if (done) return;
|
|
25
|
+
done = true;
|
|
26
|
+
onTimeout();
|
|
27
|
+
}, timeoutMs);
|
|
28
|
+
grecaptcha.ready(() => {
|
|
29
|
+
if (done) return;
|
|
30
|
+
done = true;
|
|
31
|
+
clearTimeout(timer);
|
|
32
|
+
onReady();
|
|
33
|
+
});
|
|
34
|
+
}
|
|
35
|
+
function loadRecaptcha(siteKey, opts) {
|
|
36
|
+
if (activeSiteKey !== null && activeSiteKey !== siteKey) {
|
|
37
|
+
return Promise.reject(
|
|
38
|
+
new RecaptchaError(
|
|
39
|
+
"sitekey_mismatch",
|
|
40
|
+
"reCAPTCHA is already initialized for a different siteKey. The v3 script supports one siteKey per page; remount with the original key or reload the page."
|
|
41
|
+
)
|
|
42
|
+
);
|
|
43
|
+
}
|
|
44
|
+
if (cachedLoad !== null && cachedLoad.siteKey !== siteKey) {
|
|
45
|
+
return Promise.reject(
|
|
46
|
+
new RecaptchaError(
|
|
47
|
+
"sitekey_mismatch",
|
|
48
|
+
"A reCAPTCHA load for a different siteKey is already in flight."
|
|
49
|
+
)
|
|
50
|
+
);
|
|
51
|
+
}
|
|
52
|
+
if (cachedLoad !== null) return cachedLoad.promise;
|
|
53
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
54
|
+
const promise = new Promise((resolve, reject) => {
|
|
55
|
+
let settled = false;
|
|
56
|
+
const settleOk = () => {
|
|
57
|
+
if (settled) return;
|
|
58
|
+
settled = true;
|
|
59
|
+
activeSiteKey = siteKey;
|
|
60
|
+
ownsGlobal = true;
|
|
61
|
+
resolve();
|
|
62
|
+
};
|
|
63
|
+
const settleFail = (err) => {
|
|
64
|
+
if (settled) return;
|
|
65
|
+
settled = true;
|
|
66
|
+
cachedLoad = null;
|
|
67
|
+
removeOwnScriptTag();
|
|
68
|
+
reject(err);
|
|
69
|
+
};
|
|
70
|
+
if (typeof document === "undefined" || typeof window === "undefined") {
|
|
71
|
+
settleFail(
|
|
72
|
+
new RecaptchaError(
|
|
73
|
+
"unavailable",
|
|
74
|
+
"loadRecaptcha: no DOM available (browser-only API)."
|
|
75
|
+
)
|
|
76
|
+
);
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
const ourTagPresent = document.getElementById(RECAPTCHA_SCRIPT_ID) !== null;
|
|
80
|
+
if (window.grecaptcha) {
|
|
81
|
+
if (!ownsGlobal && !ourTagPresent) {
|
|
82
|
+
settleFail(
|
|
83
|
+
new RecaptchaError(
|
|
84
|
+
"sitekey_mismatch",
|
|
85
|
+
"A reCAPTCHA global was pre-loaded by the host page with an unknown site key. The v3 script supports one render key per page and its key cannot be introspected, so executing a different key against it is unsafe. Load reCAPTCHA only via this SDK, or ensure the host uses the same site key."
|
|
86
|
+
)
|
|
87
|
+
);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
readyWithTimeout(
|
|
91
|
+
window.grecaptcha,
|
|
92
|
+
timeoutMs,
|
|
93
|
+
settleOk,
|
|
94
|
+
() => settleFail(
|
|
95
|
+
new RecaptchaError(
|
|
96
|
+
"timeout",
|
|
97
|
+
`grecaptcha.ready() did not fire within ${timeoutMs}ms (reCAPTCHA runtime blocked).`
|
|
98
|
+
)
|
|
99
|
+
)
|
|
100
|
+
);
|
|
101
|
+
return;
|
|
102
|
+
}
|
|
103
|
+
if (ourTagPresent) {
|
|
104
|
+
const startedAt2 = Date.now();
|
|
105
|
+
const poll = setInterval(() => {
|
|
106
|
+
if (window.grecaptcha) {
|
|
107
|
+
clearInterval(poll);
|
|
108
|
+
const remaining = Math.max(timeoutMs - (Date.now() - startedAt2), 0);
|
|
109
|
+
readyWithTimeout(
|
|
110
|
+
window.grecaptcha,
|
|
111
|
+
remaining,
|
|
112
|
+
settleOk,
|
|
113
|
+
() => settleFail(
|
|
114
|
+
new RecaptchaError(
|
|
115
|
+
"timeout",
|
|
116
|
+
`grecaptcha.ready() did not fire within the ${timeoutMs}ms budget.`
|
|
117
|
+
)
|
|
118
|
+
)
|
|
119
|
+
);
|
|
120
|
+
return;
|
|
121
|
+
}
|
|
122
|
+
if (Date.now() - startedAt2 >= timeoutMs) {
|
|
123
|
+
clearInterval(poll);
|
|
124
|
+
settleFail(
|
|
125
|
+
new RecaptchaError(
|
|
126
|
+
"timeout",
|
|
127
|
+
`reCAPTCHA script tag present but grecaptcha did not appear within ${timeoutMs}ms.`
|
|
128
|
+
)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
}, POLL_INTERVAL_MS);
|
|
132
|
+
return;
|
|
133
|
+
}
|
|
134
|
+
const script = document.createElement("script");
|
|
135
|
+
script.id = RECAPTCHA_SCRIPT_ID;
|
|
136
|
+
script.src = `https://www.google.com/recaptcha/api.js?render=${encodeURIComponent(siteKey)}`;
|
|
137
|
+
script.async = true;
|
|
138
|
+
script.defer = true;
|
|
139
|
+
const loadTimeout = setTimeout(() => {
|
|
140
|
+
settleFail(
|
|
141
|
+
new RecaptchaError(
|
|
142
|
+
"timeout",
|
|
143
|
+
`reCAPTCHA script did not load within ${timeoutMs}ms.`
|
|
144
|
+
)
|
|
145
|
+
);
|
|
146
|
+
}, timeoutMs);
|
|
147
|
+
const startedAt = Date.now();
|
|
148
|
+
script.onload = () => {
|
|
149
|
+
clearTimeout(loadTimeout);
|
|
150
|
+
if (!window.grecaptcha) {
|
|
151
|
+
settleFail(
|
|
152
|
+
new RecaptchaError(
|
|
153
|
+
"load_failed",
|
|
154
|
+
"reCAPTCHA script loaded but the grecaptcha global was not defined."
|
|
155
|
+
)
|
|
156
|
+
);
|
|
157
|
+
return;
|
|
158
|
+
}
|
|
159
|
+
const remaining = Math.max(timeoutMs - (Date.now() - startedAt), 0);
|
|
160
|
+
readyWithTimeout(
|
|
161
|
+
window.grecaptcha,
|
|
162
|
+
remaining,
|
|
163
|
+
settleOk,
|
|
164
|
+
() => settleFail(
|
|
165
|
+
new RecaptchaError(
|
|
166
|
+
"timeout",
|
|
167
|
+
`reCAPTCHA loaded but grecaptcha.ready() did not fire within ${timeoutMs}ms.`
|
|
168
|
+
)
|
|
169
|
+
)
|
|
170
|
+
);
|
|
171
|
+
};
|
|
172
|
+
script.onerror = () => {
|
|
173
|
+
clearTimeout(loadTimeout);
|
|
174
|
+
settleFail(
|
|
175
|
+
new RecaptchaError(
|
|
176
|
+
"load_failed",
|
|
177
|
+
"Failed to load the reCAPTCHA script (blocked by an ad blocker / CSP, or offline)."
|
|
178
|
+
)
|
|
179
|
+
);
|
|
180
|
+
};
|
|
181
|
+
document.head.appendChild(script);
|
|
182
|
+
});
|
|
183
|
+
cachedLoad = { siteKey, promise };
|
|
184
|
+
return promise;
|
|
185
|
+
}
|
|
186
|
+
async function executeRecaptcha(siteKey, action, opts) {
|
|
187
|
+
await loadRecaptcha(siteKey, opts);
|
|
188
|
+
if (typeof window === "undefined" || !window.grecaptcha) {
|
|
189
|
+
throw new RecaptchaError(
|
|
190
|
+
"unavailable",
|
|
191
|
+
"executeRecaptcha: grecaptcha is not available. Are you running in a browser?"
|
|
192
|
+
);
|
|
193
|
+
}
|
|
194
|
+
const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;
|
|
195
|
+
const grecaptcha = window.grecaptcha;
|
|
196
|
+
let timer;
|
|
197
|
+
const timeout = new Promise((_resolve, reject) => {
|
|
198
|
+
timer = setTimeout(() => {
|
|
199
|
+
reject(
|
|
200
|
+
new RecaptchaError(
|
|
201
|
+
"timeout",
|
|
202
|
+
`reCAPTCHA execute() did not settle within ${timeoutMs}ms (runtime blocked).`
|
|
203
|
+
)
|
|
204
|
+
);
|
|
205
|
+
}, timeoutMs);
|
|
206
|
+
});
|
|
207
|
+
try {
|
|
208
|
+
return await Promise.race([
|
|
209
|
+
grecaptcha.execute(siteKey, { action }),
|
|
210
|
+
timeout
|
|
211
|
+
]);
|
|
212
|
+
} catch (err) {
|
|
213
|
+
if (err instanceof RecaptchaError) throw err;
|
|
214
|
+
const detail = err instanceof Error ? err.message : String(err ?? "unknown error");
|
|
215
|
+
throw new RecaptchaError(
|
|
216
|
+
"execute_failed",
|
|
217
|
+
`reCAPTCHA execute() failed: ${detail}`
|
|
218
|
+
);
|
|
219
|
+
} finally {
|
|
220
|
+
if (timer !== void 0) clearTimeout(timer);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
function _resetRecaptchaState() {
|
|
224
|
+
cachedLoad = null;
|
|
225
|
+
activeSiteKey = null;
|
|
226
|
+
ownsGlobal = false;
|
|
227
|
+
removeOwnScriptTag();
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
export { RecaptchaError, _resetRecaptchaState, executeRecaptcha, loadRecaptcha };
|
|
231
|
+
//# sourceMappingURL=chunk-7NS7ENJV.js.map
|
|
232
|
+
//# sourceMappingURL=chunk-7NS7ENJV.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/recaptcha/loader.ts"],"names":["startedAt"],"mappings":";AAwDO,IAAM,mBAAA,GAAsB,4BAAA;AACnC,IAAM,kBAAA,GAAqB,GAAA;AAC3B,IAAM,gBAAA,GAAmB,EAAA;AAUlB,IAAM,cAAA,GAAN,cAA6B,KAAA,CAAM;AAAA,EACxB,IAAA;AAAA,EAEhB,WAAA,CAAY,MAA0B,OAAA,EAAiB;AACrD,IAAA,KAAA,CAAM,OAAO,CAAA;AACb,IAAA,IAAA,CAAK,IAAA,GAAO,gBAAA;AACZ,IAAA,IAAA,CAAK,IAAA,GAAO,IAAA;AAAA,EACd;AACF;AAWA,IAAI,UAAA,GAAiE,IAAA;AAOrE,IAAI,aAAA,GAA+B,IAAA;AASnC,IAAI,UAAA,GAAa,KAAA;AAEjB,SAAS,kBAAA,GAA2B;AAClC,EAAA,IAAI,OAAO,aAAa,WAAA,EAAa;AACrC,EAAA,MAAM,GAAA,GAAM,QAAA,CAAS,cAAA,CAAe,mBAAmB,CAAA;AACvD,EAAA,GAAA,EAAK,UAAA,EAAY,YAAY,GAAG,CAAA;AAClC;AAQA,SAAS,gBAAA,CACP,UAAA,EACA,SAAA,EACA,OAAA,EACA,SAAA,EACM;AACN,EAAA,IAAI,IAAA,GAAO,KAAA;AACX,EAAA,MAAM,KAAA,GAAQ,WAAW,MAAM;AAC7B,IAAA,IAAI,IAAA,EAAM;AACV,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,SAAA,EAAU;AAAA,EACZ,GAAG,SAAS,CAAA;AACZ,EAAA,UAAA,CAAW,MAAM,MAAM;AACrB,IAAA,IAAI,IAAA,EAAM;AACV,IAAA,IAAA,GAAO,IAAA;AACP,IAAA,YAAA,CAAa,KAAK,CAAA;AAClB,IAAA,OAAA,EAAQ;AAAA,EACV,CAAC,CAAA;AACH;AAaO,SAAS,aAAA,CACd,SACA,IAAA,EACe;AAEf,EAAA,IAAI,aAAA,KAAkB,IAAA,IAAQ,aAAA,KAAkB,OAAA,EAAS;AACvD,IAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,MACb,IAAI,cAAA;AAAA,QACF,kBAAA;AAAA,QACA;AAAA;AAGF,KACF;AAAA,EACF;AACA,EAAA,IAAI,UAAA,KAAe,IAAA,IAAQ,UAAA,CAAW,OAAA,KAAY,OAAA,EAAS;AACzD,IAAA,OAAO,OAAA,CAAQ,MAAA;AAAA,MACb,IAAI,cAAA;AAAA,QACF,kBAAA;AAAA,QACA;AAAA;AACF,KACF;AAAA,EACF;AAEA,EAAA,IAAI,UAAA,KAAe,IAAA,EAAM,OAAO,UAAA,CAAW,OAAA;AAE3C,EAAA,MAAM,SAAA,GAAY,MAAM,SAAA,IAAa,kBAAA;AAErC,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAc,CAAC,SAAS,MAAA,KAAW;AACrD,IAAA,IAAI,OAAA,GAAU,KAAA;AAEd,IAAA,MAAM,WAAW,MAAY;AAC3B,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AACV,MAAA,aAAA,GAAgB,OAAA;AAChB,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,OAAA,EAAQ;AAAA,IACV,CAAA;AAEA,IAAA,MAAM,UAAA,GAAa,CAAC,GAAA,KAA8B;AAChD,MAAA,IAAI,OAAA,EAAS;AACb,MAAA,OAAA,GAAU,IAAA;AAGV,MAAA,UAAA,GAAa,IAAA;AACb,MAAA,kBAAA,EAAmB;AACnB,MAAA,MAAA,CAAO,GAAG,CAAA;AAAA,IACZ,CAAA;AAEA,IAAA,IAAI,OAAO,QAAA,KAAa,WAAA,IAAe,OAAO,WAAW,WAAA,EAAa;AACpE,MAAA,UAAA;AAAA,QACE,IAAI,cAAA;AAAA,UACF,aAAA;AAAA,UACA;AAAA;AACF,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,aAAA,GAAgB,QAAA,CAAS,cAAA,CAAe,mBAAmB,CAAA,KAAM,IAAA;AAEvE,IAAA,IAAI,OAAO,UAAA,EAAY;AAMrB,MAAA,IAAI,CAAC,UAAA,IAAc,CAAC,aAAA,EAAe;AACjC,QAAA,UAAA;AAAA,UACE,IAAI,cAAA;AAAA,YACF,kBAAA;AAAA,YACA;AAAA;AAKF,SACF;AACA,QAAA;AAAA,MACF;AAEA,MAAA,gBAAA;AAAA,QAAiB,MAAA,CAAO,UAAA;AAAA,QAAY,SAAA;AAAA,QAAW,QAAA;AAAA,QAAU,MACvD,UAAA;AAAA,UACE,IAAI,cAAA;AAAA,YACF,SAAA;AAAA,YACA,0CAA0C,SAAS,CAAA,+BAAA;AAAA;AACrD;AACF,OACF;AACA,MAAA;AAAA,IACF;AAEA,IAAA,IAAI,aAAA,EAAe;AAIjB,MAAA,MAAMA,UAAAA,GAAY,KAAK,GAAA,EAAI;AAC3B,MAAA,MAAM,IAAA,GAAO,YAAY,MAAM;AAC7B,QAAA,IAAI,OAAO,UAAA,EAAY;AACrB,UAAA,aAAA,CAAc,IAAI,CAAA;AAClB,UAAA,MAAM,SAAA,GAAY,KAAK,GAAA,CAAI,SAAA,IAAa,KAAK,GAAA,EAAI,GAAIA,aAAY,CAAC,CAAA;AAClE,UAAA,gBAAA;AAAA,YAAiB,MAAA,CAAO,UAAA;AAAA,YAAY,SAAA;AAAA,YAAW,QAAA;AAAA,YAAU,MACvD,UAAA;AAAA,cACE,IAAI,cAAA;AAAA,gBACF,SAAA;AAAA,gBACA,8CAA8C,SAAS,CAAA,UAAA;AAAA;AACzD;AACF,WACF;AACA,UAAA;AAAA,QACF;AACA,QAAA,IAAI,IAAA,CAAK,GAAA,EAAI,GAAIA,UAAAA,IAAa,SAAA,EAAW;AACvC,UAAA,aAAA,CAAc,IAAI,CAAA;AAClB,UAAA,UAAA;AAAA,YACE,IAAI,cAAA;AAAA,cACF,SAAA;AAAA,cACA,qEAAqE,SAAS,CAAA,GAAA;AAAA;AAChF,WACF;AAAA,QACF;AAAA,MACF,GAAG,gBAAgB,CAAA;AACnB,MAAA;AAAA,IACF;AAEA,IAAA,MAAM,MAAA,GAAS,QAAA,CAAS,aAAA,CAAc,QAAQ,CAAA;AAC9C,IAAA,MAAA,CAAO,EAAA,GAAK,mBAAA;AACZ,IAAA,MAAA,CAAO,GAAA,GAAM,CAAA,+CAAA,EAAkD,kBAAA,CAAmB,OAAO,CAAC,CAAA,CAAA;AAC1F,IAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AACf,IAAA,MAAA,CAAO,KAAA,GAAQ,IAAA;AAEf,IAAA,MAAM,WAAA,GAAc,WAAW,MAAM;AACnC,MAAA,UAAA;AAAA,QACE,IAAI,cAAA;AAAA,UACF,SAAA;AAAA,UACA,wCAAwC,SAAS,CAAA,GAAA;AAAA;AACnD,OACF;AAAA,IACF,GAAG,SAAS,CAAA;AACZ,IAAA,MAAM,SAAA,GAAY,KAAK,GAAA,EAAI;AAE3B,IAAA,MAAA,CAAO,SAAS,MAAM;AACpB,MAAA,YAAA,CAAa,WAAW,CAAA;AACxB,MAAA,IAAI,CAAC,OAAO,UAAA,EAAY;AACtB,QAAA,UAAA;AAAA,UACE,IAAI,cAAA;AAAA,YACF,aAAA;AAAA,YACA;AAAA;AACF,SACF;AACA,QAAA;AAAA,MACF;AAGA,MAAA,MAAM,SAAA,GAAY,KAAK,GAAA,CAAI,SAAA,IAAa,KAAK,GAAA,EAAI,GAAI,YAAY,CAAC,CAAA;AAClE,MAAA,gBAAA;AAAA,QAAiB,MAAA,CAAO,UAAA;AAAA,QAAY,SAAA;AAAA,QAAW,QAAA;AAAA,QAAU,MACvD,UAAA;AAAA,UACE,IAAI,cAAA;AAAA,YACF,SAAA;AAAA,YACA,+DAA+D,SAAS,CAAA,GAAA;AAAA;AAC1E;AACF,OACF;AAAA,IACF,CAAA;AAEA,IAAA,MAAA,CAAO,UAAU,MAAM;AACrB,MAAA,YAAA,CAAa,WAAW,CAAA;AACxB,MAAA,UAAA;AAAA,QACE,IAAI,cAAA;AAAA,UACF,aAAA;AAAA,UACA;AAAA;AACF,OACF;AAAA,IACF,CAAA;AAEA,IAAA,QAAA,CAAS,IAAA,CAAK,YAAY,MAAM,CAAA;AAAA,EAClC,CAAC,CAAA;AAED,EAAA,UAAA,GAAa,EAAE,SAAS,OAAA,EAAQ;AAChC,EAAA,OAAO,OAAA;AACT;AAiBA,eAAsB,gBAAA,CACpB,OAAA,EACA,MAAA,EACA,IAAA,EACiB;AACjB,EAAA,MAAM,aAAA,CAAc,SAAS,IAAI,CAAA;AAEjC,EAAA,IAAI,OAAO,MAAA,KAAW,WAAA,IAAe,CAAC,OAAO,UAAA,EAAY;AACvD,IAAA,MAAM,IAAI,cAAA;AAAA,MACR,aAAA;AAAA,MACA;AAAA,KACF;AAAA,EACF;AAEA,EAAA,MAAM,SAAA,GAAY,MAAM,SAAA,IAAa,kBAAA;AAMrC,EAAA,MAAM,aAAa,MAAA,CAAO,UAAA;AAC1B,EAAA,IAAI,KAAA;AACJ,EAAA,MAAM,OAAA,GAAU,IAAI,OAAA,CAAe,CAAC,UAAU,MAAA,KAAW;AACvD,IAAA,KAAA,GAAQ,WAAW,MAAM;AACvB,MAAA,MAAA;AAAA,QACE,IAAI,cAAA;AAAA,UACF,SAAA;AAAA,UACA,6CAA6C,SAAS,CAAA,qBAAA;AAAA;AACxD,OACF;AAAA,IACF,GAAG,SAAS,CAAA;AAAA,EACd,CAAC,CAAA;AAED,EAAA,IAAI;AACF,IAAA,OAAO,MAAM,QAAQ,IAAA,CAAK;AAAA,MACxB,UAAA,CAAW,OAAA,CAAQ,OAAA,EAAS,EAAE,QAAQ,CAAA;AAAA,MACtC;AAAA,KACD,CAAA;AAAA,EACH,SAAS,GAAA,EAAK;AACZ,IAAA,IAAI,GAAA,YAAe,gBAAgB,MAAM,GAAA;AACzC,IAAA,MAAM,SACJ,GAAA,YAAe,KAAA,GAAQ,IAAI,OAAA,GAAU,MAAA,CAAO,OAAO,eAAe,CAAA;AACpE,IAAA,MAAM,IAAI,cAAA;AAAA,MACR,gBAAA;AAAA,MACA,+BAA+B,MAAM,CAAA;AAAA,KACvC;AAAA,EACF,CAAA,SAAE;AACA,IAAA,IAAI,KAAA,KAAU,MAAA,EAAW,YAAA,CAAa,KAAK,CAAA;AAAA,EAC7C;AACF;AAQO,SAAS,oBAAA,GAA6B;AAC3C,EAAA,UAAA,GAAa,IAAA;AACb,EAAA,aAAA,GAAgB,IAAA;AAChB,EAAA,UAAA,GAAa,KAAA;AACb,EAAA,kBAAA,EAAmB;AACrB","file":"chunk-7NS7ENJV.js","sourcesContent":["/// <reference lib=\"dom\" />\n/// <reference lib=\"dom.iterable\" />\n/**\n * reCAPTCHA v3 loader and token executor.\n *\n * Per D537:\n * - Site key is public (supplied at mount time from the spec response).\n * - Secret key is NEVER in the browser — only the site key is here.\n * - v3 score-based by default; the operator may configure a v2 fallback\n * on the server side for low-score requests.\n * - The loader injects the reCAPTCHA script once and exposes execute()\n * to obtain a fresh token before each submit.\n *\n * Failure semantics (all recoverable, all bounded by opts.timeoutMs / 10s):\n * - A script load failure (adblock / CSP / offline) REJECTS with\n * RecaptchaError(kind:\"load_failed\"), EVICTS the cached promise, and\n * REMOVES the injected script tag — the next loadRecaptcha call starts\n * fresh. A transient failure never poisons the siteKey.\n * - EVERY wait is bounded, including grecaptcha.ready() AFTER onload and on\n * the adoption/poll paths: if api.js serves but the inner runtime never\n * boots (ready() never fires), the loader rejects RecaptchaError(\n * kind:\"timeout\") and evicts, rather than hanging the widget on\n * \"Sending…\" forever.\n * - The \"existing script tag but no grecaptcha global\" poll is BOUNDED,\n * then the subsequent ready() is bounded by the remaining budget.\n *\n * Multi-siteKey + foreign-global handling (honest):\n * - The v3 script loads with `?render=<siteKey>` and initializes for ONE\n * site key per page. A SECOND different siteKey after our first load is\n * rejected RecaptchaError(kind:\"sitekey_mismatch\").\n * - If the HOST page pre-loaded grecaptcha with an unknown render key (a\n * FOREIGN global this SDK did not create), we CANNOT introspect its key,\n * so executing our key against it would be the exact silent misfire we\n * promise to prevent. We reject RecaptchaError(kind:\"sitekey_mismatch\")\n * instead. (Detection: we only adopt a global we brought up ourselves or\n * that our own script tag is loading.)\n *\n * execute() rejections (invalid key at execute time, Google-internal errors,\n * often plain strings) are wrapped in RecaptchaError(kind:\"execute_failed\").\n *\n * This module is browser-only. It accesses the `window` and `document`\n * globals explicitly.\n */\n\ndeclare global {\n interface Window {\n grecaptcha?: Grecaptcha;\n }\n}\n\ninterface Grecaptcha {\n ready(callback: () => void): void;\n execute(siteKey: string, options: { action: string }): Promise<string>;\n}\n\n/** Exported for tests — the id of the script tag this loader owns. */\nexport const RECAPTCHA_SCRIPT_ID = \"__nodii_recaptcha_script__\";\nconst DEFAULT_TIMEOUT_MS = 10_000;\nconst POLL_INTERVAL_MS = 50;\n\nexport type RecaptchaErrorKind =\n | \"load_failed\"\n | \"timeout\"\n | \"sitekey_mismatch\"\n | \"execute_failed\"\n | \"unavailable\";\n\n/** Typed error for every reCAPTCHA loader failure path. */\nexport class RecaptchaError extends Error {\n public readonly kind: RecaptchaErrorKind;\n\n constructor(kind: RecaptchaErrorKind, message: string) {\n super(message);\n this.name = \"RecaptchaError\";\n this.kind = kind;\n }\n}\n\nexport interface RecaptchaLoadOptions {\n /**\n * Max time to wait for the script / grecaptcha global to become ready\n * before rejecting with RecaptchaError(kind:\"timeout\"). Default 10s.\n */\n timeoutMs?: number;\n}\n\n/** In-flight or settled load promise for the ACTIVE siteKey. */\nlet cachedLoad: { siteKey: string; promise: Promise<void> } | null = null;\n\n/**\n * The siteKey the page's grecaptcha script was initialized with. Set on\n * successful load; cleared only by _resetRecaptchaState. A different siteKey\n * after this is set → RecaptchaError(kind:\"sitekey_mismatch\").\n */\nlet activeSiteKey: string | null = null;\n\n/**\n * True once THIS loader's own <script?render=key> has successfully brought up\n * window.grecaptcha. Distinguishes a global WE initialized (safe to execute\n * against `activeSiteKey`) from a FOREIGN global the host page loaded with an\n * unknown render key (unsafe — we cannot know its key, so we must reject\n * rather than silently execute against it; see P8 in the module doc).\n */\nlet ownsGlobal = false;\n\nfunction removeOwnScriptTag(): void {\n if (typeof document === \"undefined\") return;\n const tag = document.getElementById(RECAPTCHA_SCRIPT_ID);\n tag?.parentNode?.removeChild(tag);\n}\n\n/**\n * Run grecaptcha.ready() with a hard timeout. reCAPTCHA's inner init can be\n * blocked (api.js served but the runtime never boots — corp proxy, partial\n * CSP); ready() would then never fire and the loader would hang forever with\n * the cache un-evicted. This bounds ALL ready() waits and evicts on hang.\n */\nfunction readyWithTimeout(\n grecaptcha: Grecaptcha,\n timeoutMs: number,\n onReady: () => void,\n onTimeout: () => void,\n): void {\n let done = false;\n const timer = setTimeout(() => {\n if (done) return;\n done = true;\n onTimeout();\n }, timeoutMs);\n grecaptcha.ready(() => {\n if (done) return;\n done = true;\n clearTimeout(timer);\n onReady();\n });\n}\n\n/**\n * Inject the reCAPTCHA v3 script for the given siteKey.\n * Idempotent per siteKey: concurrent/repeated calls share one load.\n * A FAILED load is evicted — the next call retries from scratch.\n *\n * @throws {RecaptchaError} kind:\"sitekey_mismatch\" — a different siteKey\n * is already active (single-render-script limitation, see module doc).\n * @throws {RecaptchaError} kind:\"load_failed\" — script failed to load.\n * @throws {RecaptchaError} kind:\"timeout\" — script/global never became ready.\n * @throws {RecaptchaError} kind:\"unavailable\" — no DOM (not a browser).\n */\nexport function loadRecaptcha(\n siteKey: string,\n opts?: RecaptchaLoadOptions,\n): Promise<void> {\n // A different siteKey is already active or loading → hard, typed error.\n if (activeSiteKey !== null && activeSiteKey !== siteKey) {\n return Promise.reject(\n new RecaptchaError(\n \"sitekey_mismatch\",\n \"reCAPTCHA is already initialized for a different siteKey. \" +\n \"The v3 script supports one siteKey per page; remount with the \" +\n \"original key or reload the page.\",\n ),\n );\n }\n if (cachedLoad !== null && cachedLoad.siteKey !== siteKey) {\n return Promise.reject(\n new RecaptchaError(\n \"sitekey_mismatch\",\n \"A reCAPTCHA load for a different siteKey is already in flight.\",\n ),\n );\n }\n\n if (cachedLoad !== null) return cachedLoad.promise;\n\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n const promise = new Promise<void>((resolve, reject) => {\n let settled = false;\n\n const settleOk = (): void => {\n if (settled) return;\n settled = true;\n activeSiteKey = siteKey;\n ownsGlobal = true;\n resolve();\n };\n\n const settleFail = (err: RecaptchaError): void => {\n if (settled) return;\n settled = true;\n // Evict so the NEXT loadRecaptcha starts fresh — a transient failure\n // must not poison this siteKey for the page's lifetime.\n cachedLoad = null;\n removeOwnScriptTag();\n reject(err);\n };\n\n if (typeof document === \"undefined\" || typeof window === \"undefined\") {\n settleFail(\n new RecaptchaError(\n \"unavailable\",\n \"loadRecaptcha: no DOM available (browser-only API).\",\n ),\n );\n return;\n }\n\n const ourTagPresent = document.getElementById(RECAPTCHA_SCRIPT_ID) !== null;\n\n if (window.grecaptcha) {\n // A grecaptcha global exists. If WE didn't put it there (no prior\n // successful self-load AND no tag of ours in the DOM), it's a FOREIGN\n // global the host page loaded with an unknown ?render= key. We cannot\n // read that key, so executing our siteKey against it would be the exact\n // opaque Google-side misfire we promise to prevent — reject instead.\n if (!ownsGlobal && !ourTagPresent) {\n settleFail(\n new RecaptchaError(\n \"sitekey_mismatch\",\n \"A reCAPTCHA global was pre-loaded by the host page with an \" +\n \"unknown site key. The v3 script supports one render key per \" +\n \"page and its key cannot be introspected, so executing a \" +\n \"different key against it is unsafe. Load reCAPTCHA only via \" +\n \"this SDK, or ensure the host uses the same site key.\",\n ),\n );\n return;\n }\n // It's ours (or our tag is present) — adopt it, bounding ready().\n readyWithTimeout(window.grecaptcha, timeoutMs, settleOk, () =>\n settleFail(\n new RecaptchaError(\n \"timeout\",\n `grecaptcha.ready() did not fire within ${timeoutMs}ms (reCAPTCHA runtime blocked).`,\n ),\n ),\n );\n return;\n }\n\n if (ourTagPresent) {\n // Our tag exists but grecaptcha isn't up yet (still loading, or a stale\n // tag from an earlier failure mode). Poll — BOUNDED — then ALSO bound\n // the subsequent ready() with the remaining budget.\n const startedAt = Date.now();\n const poll = setInterval(() => {\n if (window.grecaptcha) {\n clearInterval(poll);\n const remaining = Math.max(timeoutMs - (Date.now() - startedAt), 0);\n readyWithTimeout(window.grecaptcha, remaining, settleOk, () =>\n settleFail(\n new RecaptchaError(\n \"timeout\",\n `grecaptcha.ready() did not fire within the ${timeoutMs}ms budget.`,\n ),\n ),\n );\n return;\n }\n if (Date.now() - startedAt >= timeoutMs) {\n clearInterval(poll);\n settleFail(\n new RecaptchaError(\n \"timeout\",\n `reCAPTCHA script tag present but grecaptcha did not appear within ${timeoutMs}ms.`,\n ),\n );\n }\n }, POLL_INTERVAL_MS);\n return;\n }\n\n const script = document.createElement(\"script\");\n script.id = RECAPTCHA_SCRIPT_ID;\n script.src = `https://www.google.com/recaptcha/api.js?render=${encodeURIComponent(siteKey)}`;\n script.async = true;\n script.defer = true;\n\n const loadTimeout = setTimeout(() => {\n settleFail(\n new RecaptchaError(\n \"timeout\",\n `reCAPTCHA script did not load within ${timeoutMs}ms.`,\n ),\n );\n }, timeoutMs);\n const startedAt = Date.now();\n\n script.onload = () => {\n clearTimeout(loadTimeout);\n if (!window.grecaptcha) {\n settleFail(\n new RecaptchaError(\n \"load_failed\",\n \"reCAPTCHA script loaded but the grecaptcha global was not defined.\",\n ),\n );\n return;\n }\n // Bound ready() with the remaining budget — onload succeeding does NOT\n // guarantee the inner runtime boots.\n const remaining = Math.max(timeoutMs - (Date.now() - startedAt), 0);\n readyWithTimeout(window.grecaptcha, remaining, settleOk, () =>\n settleFail(\n new RecaptchaError(\n \"timeout\",\n `reCAPTCHA loaded but grecaptcha.ready() did not fire within ${timeoutMs}ms.`,\n ),\n ),\n );\n };\n\n script.onerror = () => {\n clearTimeout(loadTimeout);\n settleFail(\n new RecaptchaError(\n \"load_failed\",\n \"Failed to load the reCAPTCHA script (blocked by an ad blocker / CSP, or offline).\",\n ),\n );\n };\n\n document.head.appendChild(script);\n });\n\n cachedLoad = { siteKey, promise };\n return promise;\n}\n\n/**\n * Obtain a fresh reCAPTCHA v3 token for the given action.\n * Loads the script if not already loaded. A previous load FAILURE does not\n * block this call — the loader retries from scratch (see loadRecaptcha).\n *\n * @param siteKey - The public reCAPTCHA site key (from the spec endpoint).\n * @param action - The action name (e.g. \"contact_submit\"). Used for score analytics.\n * @param opts - Optional load options (timeoutMs — also bounds execute()).\n * @returns A fresh reCAPTCHA token. Valid for ~2 minutes.\n *\n * @throws {RecaptchaError} kind:\"timeout\" if execute() does not settle within\n * the timeout (Google runtime hung) — bounded so the widget re-enables.\n * @throws {RecaptchaError} on any load failure (see loadRecaptcha kinds) or\n * an execute() rejection (kind:\"execute_failed\").\n */\nexport async function executeRecaptcha(\n siteKey: string,\n action: string,\n opts?: RecaptchaLoadOptions,\n): Promise<string> {\n await loadRecaptcha(siteKey, opts);\n\n if (typeof window === \"undefined\" || !window.grecaptcha) {\n throw new RecaptchaError(\n \"unavailable\",\n \"executeRecaptcha: grecaptcha is not available. Are you running in a browser?\",\n );\n }\n\n const timeoutMs = opts?.timeoutMs ?? DEFAULT_TIMEOUT_MS;\n\n // grecaptcha.execute() can (a) HANG (Google runtime blocked) with no abort\n // API, or (b) reject with a plain string. Bound it with a timeout so the\n // widget never stays on \"Sending…\" forever, and wrap every rejection in a\n // typed RecaptchaError so callers get a consistent taxonomy.\n const grecaptcha = window.grecaptcha;\n let timer: ReturnType<typeof setTimeout> | undefined;\n const timeout = new Promise<never>((_resolve, reject) => {\n timer = setTimeout(() => {\n reject(\n new RecaptchaError(\n \"timeout\",\n `reCAPTCHA execute() did not settle within ${timeoutMs}ms (runtime blocked).`,\n ),\n );\n }, timeoutMs);\n });\n\n try {\n return await Promise.race([\n grecaptcha.execute(siteKey, { action }),\n timeout,\n ]);\n } catch (err) {\n if (err instanceof RecaptchaError) throw err; // the timeout race\n const detail =\n err instanceof Error ? err.message : String(err ?? \"unknown error\");\n throw new RecaptchaError(\n \"execute_failed\",\n `reCAPTCHA execute() failed: ${detail}`,\n );\n } finally {\n if (timer !== undefined) clearTimeout(timer);\n }\n}\n\n/**\n * Reset ALL loader state: cached load promise, active siteKey, and the\n * injected script tag (removed from the DOM if present). Primarily for\n * tests and for host pages that intentionally tear down reCAPTCHA.\n * Does NOT unset window.grecaptcha (the script may still own it).\n */\nexport function _resetRecaptchaState(): void {\n cachedLoad = null;\n activeSiteKey = null;\n ownsGlobal = false;\n removeOwnScriptTag();\n}\n"]}
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { contactFormSchema } from './chunk-BIFANV7M.js';
|
|
2
|
+
|
|
3
|
+
// src/form/state.ts
|
|
4
|
+
function zodIssuesToFieldErrors(issues) {
|
|
5
|
+
return issues.map((issue) => ({
|
|
6
|
+
path: issue.path.join("."),
|
|
7
|
+
message: issue.message
|
|
8
|
+
}));
|
|
9
|
+
}
|
|
10
|
+
var INITIAL_VALUES = {
|
|
11
|
+
name: "",
|
|
12
|
+
email: "",
|
|
13
|
+
phone: void 0,
|
|
14
|
+
message: void 0
|
|
15
|
+
};
|
|
16
|
+
function createContactFormState() {
|
|
17
|
+
let state = {
|
|
18
|
+
values: { ...INITIAL_VALUES },
|
|
19
|
+
errors: [],
|
|
20
|
+
serverError: null,
|
|
21
|
+
status: "idle",
|
|
22
|
+
dirty: false
|
|
23
|
+
};
|
|
24
|
+
const listeners = /* @__PURE__ */ new Set();
|
|
25
|
+
function emit() {
|
|
26
|
+
for (const listener of listeners) {
|
|
27
|
+
listener({ ...state, values: { ...state.values } });
|
|
28
|
+
}
|
|
29
|
+
}
|
|
30
|
+
function runValidation() {
|
|
31
|
+
const result = contactFormSchema.safeParse(state.values);
|
|
32
|
+
if (result.success) return [];
|
|
33
|
+
return zodIssuesToFieldErrors(result.error.issues);
|
|
34
|
+
}
|
|
35
|
+
let hasValidated = false;
|
|
36
|
+
return {
|
|
37
|
+
getState() {
|
|
38
|
+
return { ...state, values: { ...state.values } };
|
|
39
|
+
},
|
|
40
|
+
setValue(field, value) {
|
|
41
|
+
state = {
|
|
42
|
+
...state,
|
|
43
|
+
values: { ...state.values, [field]: value },
|
|
44
|
+
dirty: true
|
|
45
|
+
};
|
|
46
|
+
if (hasValidated) {
|
|
47
|
+
state = { ...state, errors: runValidation() };
|
|
48
|
+
}
|
|
49
|
+
emit();
|
|
50
|
+
},
|
|
51
|
+
validate() {
|
|
52
|
+
hasValidated = true;
|
|
53
|
+
const errors = runValidation();
|
|
54
|
+
state = { ...state, errors, dirty: true };
|
|
55
|
+
emit();
|
|
56
|
+
return errors.length === 0;
|
|
57
|
+
},
|
|
58
|
+
setSubmitting() {
|
|
59
|
+
state = { ...state, status: "submitting", serverError: null, errors: [] };
|
|
60
|
+
emit();
|
|
61
|
+
},
|
|
62
|
+
setSuccess() {
|
|
63
|
+
state = { ...state, status: "success", serverError: null };
|
|
64
|
+
emit();
|
|
65
|
+
},
|
|
66
|
+
setError(message) {
|
|
67
|
+
state = { ...state, status: "error", serverError: message };
|
|
68
|
+
emit();
|
|
69
|
+
},
|
|
70
|
+
reset() {
|
|
71
|
+
hasValidated = false;
|
|
72
|
+
state = {
|
|
73
|
+
values: { ...INITIAL_VALUES },
|
|
74
|
+
errors: [],
|
|
75
|
+
serverError: null,
|
|
76
|
+
status: "idle",
|
|
77
|
+
dirty: false
|
|
78
|
+
};
|
|
79
|
+
emit();
|
|
80
|
+
},
|
|
81
|
+
subscribe(listener) {
|
|
82
|
+
listeners.add(listener);
|
|
83
|
+
return () => {
|
|
84
|
+
listeners.delete(listener);
|
|
85
|
+
};
|
|
86
|
+
}
|
|
87
|
+
};
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
export { createContactFormState };
|
|
91
|
+
//# sourceMappingURL=chunk-AFCJLUPK.js.map
|
|
92
|
+
//# sourceMappingURL=chunk-AFCJLUPK.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/form/state.ts"],"names":[],"mappings":"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","file":"chunk-AFCJLUPK.js","sourcesContent":["/**\n * Headless form state manager for the contact form.\n *\n * Designed to be framework-agnostic — callers supply a change callback\n * and call the returned mutators. The widget layer uses this internally;\n * framework integrations (React, Vue, etc.) can wrap it in their own hooks.\n */\n\nimport type { ZodIssue } from \"zod/v3\";\nimport { contactFormSchema, type ContactFormValues } from \"./schema.js\";\n\nexport interface FieldError {\n path: string;\n message: string;\n}\n\nexport type FormStatus = \"idle\" | \"submitting\" | \"success\" | \"error\";\n\nexport interface ContactFormState {\n values: ContactFormValues;\n /** Per-field validation errors from the last validate() call. */\n errors: FieldError[];\n /** Cross-field / server error message. */\n serverError: string | null;\n status: FormStatus;\n /** True if values have been touched at least once. */\n dirty: boolean;\n}\n\nexport type ContactFormStateListener = (state: ContactFormState) => void;\n\nexport interface ContactFormControl {\n /** Current snapshot of form state. */\n getState(): ContactFormState;\n /** Update a single field value and re-validate if dirty. */\n setValue<K extends keyof ContactFormValues>(\n field: K,\n value: ContactFormValues[K],\n ): void;\n /**\n * Run full client-side validation. Returns true if valid.\n * Also marks the form dirty so future setValue calls auto-validate.\n */\n validate(): boolean;\n /** Mark the form as submitting. Called by the submit client. */\n setSubmitting(): void;\n /** Mark the form as successfully submitted. */\n setSuccess(): void;\n /** Set a server-side error (e.g. 429 rate limited). */\n setError(message: string): void;\n /** Reset to initial idle state. */\n reset(): void;\n /** Subscribe to state changes. Returns unsubscribe function. */\n subscribe(listener: ContactFormStateListener): () => void;\n}\n\nfunction zodIssuesToFieldErrors(issues: ZodIssue[]): FieldError[] {\n return issues.map((issue) => ({\n path: issue.path.join(\".\"),\n message: issue.message,\n }));\n}\n\nconst INITIAL_VALUES: ContactFormValues = {\n name: \"\",\n email: \"\",\n phone: undefined,\n message: undefined,\n};\n\n/**\n * Create a new headless contact form state controller.\n *\n * @example\n * ```ts\n * const form = createContactFormState();\n * form.subscribe((state) => renderUI(state));\n * form.setValue(\"name\", \"Alice\");\n * const valid = form.validate();\n * if (valid) await submitContact(form.getState().values, botToken);\n * ```\n */\nexport function createContactFormState(): ContactFormControl {\n let state: ContactFormState = {\n values: { ...INITIAL_VALUES },\n errors: [],\n serverError: null,\n status: \"idle\",\n dirty: false,\n };\n\n const listeners = new Set<ContactFormStateListener>();\n\n function emit(): void {\n for (const listener of listeners) {\n listener({ ...state, values: { ...state.values } });\n }\n }\n\n function runValidation(): FieldError[] {\n const result = contactFormSchema.safeParse(state.values);\n if (result.success) return [];\n return zodIssuesToFieldErrors(result.error.issues);\n }\n\n // Once validate() has run at least once, EVERY subsequent setValue\n // revalidates — errors both clear when a field is fixed AND reappear\n // when a fixed field is broken again. (Previously the revalidation was\n // gated on errors.length > 0, so fix-then-rebreak silently showed no\n // error until the next explicit validate().)\n let hasValidated = false;\n\n return {\n getState() {\n return { ...state, values: { ...state.values } };\n },\n\n setValue(field, value) {\n state = {\n ...state,\n values: { ...state.values, [field]: value },\n dirty: true,\n };\n if (hasValidated) {\n state = { ...state, errors: runValidation() };\n }\n emit();\n },\n\n validate() {\n hasValidated = true;\n const errors = runValidation();\n state = { ...state, errors, dirty: true };\n emit();\n return errors.length === 0;\n },\n\n setSubmitting() {\n state = { ...state, status: \"submitting\", serverError: null, errors: [] };\n emit();\n },\n\n setSuccess() {\n state = { ...state, status: \"success\", serverError: null };\n emit();\n },\n\n setError(message) {\n state = { ...state, status: \"error\", serverError: message };\n emit();\n },\n\n reset() {\n hasValidated = false;\n state = {\n values: { ...INITIAL_VALUES },\n errors: [],\n serverError: null,\n status: \"idle\",\n dirty: false,\n };\n emit();\n },\n\n subscribe(listener) {\n listeners.add(listener);\n return () => {\n listeners.delete(listener);\n };\n },\n };\n}\n"]}
|
|
@@ -0,0 +1,154 @@
|
|
|
1
|
+
// src/submit/errors.ts
|
|
2
|
+
var OnboardingError = class extends Error {
|
|
3
|
+
kind;
|
|
4
|
+
statusCode;
|
|
5
|
+
constructor(kind, message, statusCode = null) {
|
|
6
|
+
super(message);
|
|
7
|
+
this.name = "OnboardingError";
|
|
8
|
+
this.kind = kind;
|
|
9
|
+
this.statusCode = statusCode;
|
|
10
|
+
}
|
|
11
|
+
};
|
|
12
|
+
var OnboardingBotChallengeError = class extends OnboardingError {
|
|
13
|
+
constructor(message) {
|
|
14
|
+
super(
|
|
15
|
+
"bot_challenge_failed",
|
|
16
|
+
message ?? "Bot challenge verification failed (403 bot_challenge_failed). Refresh the CAPTCHA and try again.",
|
|
17
|
+
403
|
|
18
|
+
);
|
|
19
|
+
this.name = "OnboardingBotChallengeError";
|
|
20
|
+
}
|
|
21
|
+
};
|
|
22
|
+
var OnboardingConflictError = class extends OnboardingError {
|
|
23
|
+
constructor(statusCode = 409, message) {
|
|
24
|
+
super(
|
|
25
|
+
"conflict",
|
|
26
|
+
message ?? `Request conflicted with the current server state (${statusCode}).`,
|
|
27
|
+
statusCode
|
|
28
|
+
);
|
|
29
|
+
this.name = "OnboardingConflictError";
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
var OnboardingRateLimitError = class extends OnboardingError {
|
|
33
|
+
retryAfterSeconds;
|
|
34
|
+
constructor(retryAfterSeconds = null) {
|
|
35
|
+
super(
|
|
36
|
+
"rate_limited",
|
|
37
|
+
retryAfterSeconds !== null ? `Rate limited. Retry after ${retryAfterSeconds}s.` : "Rate limited. Please wait before retrying.",
|
|
38
|
+
429
|
|
39
|
+
);
|
|
40
|
+
this.name = "OnboardingRateLimitError";
|
|
41
|
+
this.retryAfterSeconds = retryAfterSeconds;
|
|
42
|
+
}
|
|
43
|
+
};
|
|
44
|
+
var OnboardingSpecStaleError = class extends OnboardingError {
|
|
45
|
+
currentSpecVersion;
|
|
46
|
+
constructor(currentSpecVersion) {
|
|
47
|
+
super(
|
|
48
|
+
"spec_stale",
|
|
49
|
+
`The onboarding form has been updated (new version: ${currentSpecVersion}). Please refresh and try again.`,
|
|
50
|
+
409
|
|
51
|
+
);
|
|
52
|
+
this.name = "OnboardingSpecStaleError";
|
|
53
|
+
this.currentSpecVersion = currentSpecVersion;
|
|
54
|
+
}
|
|
55
|
+
};
|
|
56
|
+
var OnboardingServerError = class extends OnboardingError {
|
|
57
|
+
constructor(statusCode, message) {
|
|
58
|
+
super(
|
|
59
|
+
"server_error",
|
|
60
|
+
message ?? `Server error (${statusCode}). The request will be retried.`,
|
|
61
|
+
statusCode
|
|
62
|
+
);
|
|
63
|
+
this.name = "OnboardingServerError";
|
|
64
|
+
}
|
|
65
|
+
};
|
|
66
|
+
var OnboardingNetworkError = class extends OnboardingError {
|
|
67
|
+
constructor(cause) {
|
|
68
|
+
super(
|
|
69
|
+
"network_error",
|
|
70
|
+
"Network error \u2014 check your connection and try again.",
|
|
71
|
+
null
|
|
72
|
+
);
|
|
73
|
+
this.name = "OnboardingNetworkError";
|
|
74
|
+
if (cause instanceof Error) {
|
|
75
|
+
this.cause = cause;
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
};
|
|
79
|
+
var OnboardingValidationError = class extends OnboardingError {
|
|
80
|
+
constructor(message) {
|
|
81
|
+
super("validation_error", message, 422);
|
|
82
|
+
this.name = "OnboardingValidationError";
|
|
83
|
+
}
|
|
84
|
+
};
|
|
85
|
+
var OnboardingSpecInvalidError = class extends OnboardingError {
|
|
86
|
+
constructor(detail) {
|
|
87
|
+
super(
|
|
88
|
+
"spec_invalid",
|
|
89
|
+
`The onboarding spec response does not match the D540 contract: ${detail}`,
|
|
90
|
+
null
|
|
91
|
+
);
|
|
92
|
+
this.name = "OnboardingSpecInvalidError";
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
// src/submit/http.ts
|
|
97
|
+
var DEFAULT_REQUEST_TIMEOUT_MS = 15e3;
|
|
98
|
+
async function fetchWithTimeout(url, options = {}) {
|
|
99
|
+
const {
|
|
100
|
+
timeoutMs = DEFAULT_REQUEST_TIMEOUT_MS,
|
|
101
|
+
fetchImpl = globalThis.fetch,
|
|
102
|
+
signal: callerSignal,
|
|
103
|
+
...init
|
|
104
|
+
} = options;
|
|
105
|
+
const controller = new AbortController();
|
|
106
|
+
const timer = setTimeout(() => {
|
|
107
|
+
controller.abort(new Error(`request timed out after ${timeoutMs}ms`));
|
|
108
|
+
}, timeoutMs);
|
|
109
|
+
if (callerSignal) {
|
|
110
|
+
if (callerSignal.aborted) {
|
|
111
|
+
clearTimeout(timer);
|
|
112
|
+
controller.abort(callerSignal.reason);
|
|
113
|
+
} else {
|
|
114
|
+
callerSignal.addEventListener(
|
|
115
|
+
"abort",
|
|
116
|
+
() => controller.abort(callerSignal.reason),
|
|
117
|
+
{ once: true }
|
|
118
|
+
);
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
try {
|
|
122
|
+
return await fetchImpl(url, { ...init, signal: controller.signal });
|
|
123
|
+
} finally {
|
|
124
|
+
clearTimeout(timer);
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
function withTimeout(op, timeoutMs, onTimeout) {
|
|
128
|
+
return new Promise((resolve, reject) => {
|
|
129
|
+
let settled = false;
|
|
130
|
+
const timer = setTimeout(() => {
|
|
131
|
+
if (settled) return;
|
|
132
|
+
settled = true;
|
|
133
|
+
reject(onTimeout());
|
|
134
|
+
}, timeoutMs);
|
|
135
|
+
op.then(
|
|
136
|
+
(v) => {
|
|
137
|
+
if (settled) return;
|
|
138
|
+
settled = true;
|
|
139
|
+
clearTimeout(timer);
|
|
140
|
+
resolve(v);
|
|
141
|
+
},
|
|
142
|
+
(err) => {
|
|
143
|
+
if (settled) return;
|
|
144
|
+
settled = true;
|
|
145
|
+
clearTimeout(timer);
|
|
146
|
+
reject(err);
|
|
147
|
+
}
|
|
148
|
+
);
|
|
149
|
+
});
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export { DEFAULT_REQUEST_TIMEOUT_MS, OnboardingBotChallengeError, OnboardingConflictError, OnboardingError, OnboardingNetworkError, OnboardingRateLimitError, OnboardingServerError, OnboardingSpecInvalidError, OnboardingSpecStaleError, OnboardingValidationError, fetchWithTimeout, withTimeout };
|
|
153
|
+
//# sourceMappingURL=chunk-AW7W3HAC.js.map
|
|
154
|
+
//# sourceMappingURL=chunk-AW7W3HAC.js.map
|