@embeddables/forms 0.0.1

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.
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.cjs","names":["isValidPublishableKey","hc","isObjectLike","items"],"sources":["../src/errors.ts","../src/analytics.ts","../src/persistence-config.ts","../src/persistence.ts","../src/persistence-client.ts","../src/resolve.ts","../src/storage.ts","../src/validation.ts","../src/form.ts"],"sourcesContent":["/**\n * Typed error hierarchy. Every failure this SDK raises on its own behalf is an\n * instance of one of these, so consumers branch on the type\n * (`if (e instanceof SchemaError) …`) instead of string-matching messages.\n * Catch `FormsError` to handle them all.\n *\n * An error thrown by a consumer's own custom validator is never wrapped in one\n * of these — it propagates with its original type and stack.\n */\n\n/** Base class for every error the SDK throws. */\nexport class FormsError extends Error {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'FormsError'\n }\n}\n\n/** The schema is malformed. */\nexport class SchemaError extends FormsError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'SchemaError'\n }\n}\n\n/** A custom validator returned a thenable, or a shape that is not a message. */\nexport class ValidatorError extends FormsError {\n constructor(message: string, options?: ErrorOptions) {\n super(message, options)\n this.name = 'ValidatorError'\n }\n}\n","import type {\n DataUpdatedEvent,\n FieldUpdatedEvent,\n FieldUpdatedType,\n FormSubmittedEvent,\n} from '@embeddables/shared-types/analytics-ingest'\nimport type { JsonValue } from '@embeddables/shared-types/json'\n\nimport type { FieldConfig, FieldType } from './config.js'\n\nexport type {\n AnalyticsInstance,\n AnalyticsTrackEvent,\n AnalyticsTrackResult,\n} from '@embeddables/shared-types/analytics-instance'\nexport type {\n DataUpdatedEvent,\n FieldUpdatedEvent,\n FieldUpdatedType,\n FormSubmittedEvent,\n} from '@embeddables/shared-types/analytics-ingest'\n\n/** The ingest bound on a `data:updated` entry's `value`. */\nconst MAX_VALUE_LENGTH = 1024\n\n/** The ingest bound on a `data:updated` entry's `label`. */\nconst MAX_LABEL_LENGTH = 256\n\nexport type FormsAnalyticsEvent = DataUpdatedEvent | FieldUpdatedEvent | FormSubmittedEvent\n\n/** Maps a form field's declared type to the analytics `field:updated` class. */\nexport function mapFieldUpdatedType(type: FieldType): FieldUpdatedType {\n return type\n}\n\n/**\n * Stringifies values for `data:updated` entries. `field:updated` carries the\n * raw `field_value`; only the batch event caps and stringifies for ingest.\n */\nexport function formatFieldValue({ value }: { value: JsonValue; field?: FieldConfig }): string {\n return (typeof value === 'string' ? value : JSON.stringify(value)).slice(0, MAX_VALUE_LENGTH)\n}\n\n/** One event carrying every key in one `.set()` call. */\nexport function buildDataUpdatedEvent({\n fields,\n patch,\n}: {\n fields: readonly FieldConfig[]\n patch: Record<string, JsonValue>\n}): DataUpdatedEvent {\n const byKey = new Map(fields.map((field) => [field.key, field]))\n\n // * The key count is intentionally unbounded: `.set()` only ever applies keys\n // * the config declares, so it can never exceed the form's field count — a\n // * developer-authored, code-reviewed number rather than user input.\n const data = Object.fromEntries(\n Object.entries(patch).map(([key, value]) => {\n const field = byKey.get(key)\n return [\n key,\n {\n value: formatFieldValue({ value, field }),\n label: (field?.label ?? key).slice(0, MAX_LABEL_LENGTH),\n },\n ]\n }),\n )\n\n return { event_name: 'data:updated', data }\n}\n\n/** One `field:updated` per changed key, emitted alongside `data:updated`. */\nexport function buildFieldUpdatedEvents({\n fields,\n patch,\n}: {\n fields: readonly FieldConfig[]\n patch: Record<string, JsonValue>\n}): FieldUpdatedEvent[] {\n const byKey = new Map(fields.map((field) => [field.key, field]))\n\n return Object.entries(patch).map(([key, value]) => {\n const field = byKey.get(key)\n const event: FieldUpdatedEvent = {\n event_name: 'field:updated',\n field_key: key,\n field_type: mapFieldUpdatedType(field?.type ?? 'text'),\n field_value: value,\n }\n if (field?.registryFieldId !== undefined) {\n event.registry_field_id = field.registryFieldId\n }\n if (field?.protocolFieldId !== undefined) {\n event.protocol_field_id = field.protocolFieldId\n }\n return event\n })\n}\n","import { isValidPublishableKey } from '@embeddables/core'\nimport type { EmbeddablesInstance } from '@embeddables/core'\n\nexport const DEFAULT_BASE_URL = 'https://backend-worker.heysavvy.workers.dev'\nexport const DEFAULT_TIMEOUT_MS = 10_000\n\nexport interface PersistenceClientConfig {\n core: EmbeddablesInstance\n /** Takes precedence over the key exposed by the core instance. */\n publishableKey?: string\n baseUrl?: string\n fetch?: typeof fetch\n timeoutMs?: number\n}\n\nexport interface ResolvedPersistenceConfig {\n core: EmbeddablesInstance\n projectId: string\n appUserId: string\n publishableKey: string\n baseUrl: string\n fetch: typeof fetch\n timeoutMs: number\n}\n\n/**\n * Returns null when persistence cannot be configured (missing publishable key\n * or fetch). The SDK keeps the no-op default in that case.\n */\nexport function resolvePersistenceConfig(\n config: PersistenceClientConfig,\n): ResolvedPersistenceConfig | null {\n const core = config.core\n const publishableKey = config.publishableKey ?? core.getPublishableKey()\n if (!publishableKey || !isValidPublishableKey(publishableKey)) {\n return null\n }\n\n const projectId = core.getProjectId()\n const appUserId = core.getAppUserId()\n if (!projectId || !appUserId) {\n return null\n }\n\n const fetchImpl =\n config.fetch ??\n (typeof globalThis.fetch === 'function' ? globalThis.fetch.bind(globalThis) : undefined)\n if (!fetchImpl) {\n return null\n }\n\n return {\n core,\n projectId,\n appUserId,\n publishableKey,\n baseUrl: config.baseUrl ?? DEFAULT_BASE_URL,\n fetch: fetchImpl,\n timeoutMs: config.timeoutMs ?? DEFAULT_TIMEOUT_MS,\n }\n}\n","import type { JsonValue } from '@embeddables/shared-types/json'\n\n// * Provisional payload shapes. The real R2 key scheme and the Supabase table\n// * (and therefore these argument shapes) are blocked on the Jeremy meeting.\n// * Everything here is a drop-in behind this port: when the table lands, the\n// * only edits are a real implementation plus, if the table forces it, these\n// * shapes and their call sites in form.ts together.\n\n/** A changed field plus the registry/protocol ids the persistence layer keys on. */\nexport interface PersistedField {\n readonly key: string\n readonly value: JsonValue\n readonly registryFieldId?: string\n readonly protocolFieldId?: string\n}\n\n/** A field whose stored value the persistence layer may be asked to recover. */\nexport interface RecoverableField {\n readonly key: string\n readonly registryFieldId?: string\n readonly protocolFieldId?: string\n}\n\n/**\n * The seam between the SDK and durable storage (R2 for raw form data, Supabase\n * for the queryable fields table). Every method is best-effort: a form must\n * work with the no-op mock, and a real implementation that throws or rejects\n * must never break `set` / `submit` / `initForm`.\n */\nexport interface FormsPersistence {\n /** Partial save to R2 on every successful `set`. */\n savePartial(args: { formKey: string; values: Record<string, JsonValue> }): void | Promise<void>\n /** Per-field save to the Supabase table on every successful `set`. */\n saveFields(args: { formKey: string; fields: readonly PersistedField[] }): void | Promise<void>\n /** Full submission save to R2 on `submit`. */\n saveSubmission(args: { formKey: string; values: Record<string, JsonValue> }): void | Promise<void>\n /**\n * Cross-form recovery from Supabase, consulted at `initForm` only for\n * registry/protocol fields absent from `localStorage`. localStorage always\n * wins; the returned map is merged only for still-absent keys.\n */\n recoverRegistryFields(args: {\n formKey: string\n fields: readonly RecoverableField[]\n }): Record<string, JsonValue> | Promise<Record<string, JsonValue>>\n}\n\n/**\n * The default: does nothing, never throws, and recovers nothing. With this in\n * place a form is pure local state, exactly as before the port existed.\n */\nexport function createNoopPersistence(): FormsPersistence {\n return {\n savePartial: () => undefined,\n saveFields: () => undefined,\n saveSubmission: () => undefined,\n recoverRegistryFields: () => ({}),\n }\n}\n","import { hc } from 'hono/client'\n\nimport type { FormsApiErrorCode } from '@embeddables/shared-types'\nimport type { ProblemBody } from '@embeddables/shared-types/errors'\n\nimport { resolvePersistenceConfig } from './persistence-config.js'\nimport { createNoopPersistence } from './persistence.js'\n\nimport type { PersistenceClientConfig, ResolvedPersistenceConfig } from './persistence-config.js'\nimport type { FormsPersistence } from './persistence.js'\nimport type { FormsAppType } from 'backend-worker'\nimport type { ClientResponse } from 'hono/client'\n\nconst PUBLISHABLE_KEY_HEADER = 'x-publishable-key'\n\ntype FormsRpc = ReturnType<typeof hc<FormsAppType>>\nconst hcWithType = (...args: Parameters<typeof hc>): FormsRpc => hc<FormsAppType>(...args)\n\ntype SuccessBody<R extends ClientResponse<unknown, number, string>> =\n R extends ClientResponse<infer T, infer _S, infer _F> ? T : never\n\nfunction withTimeout(fetchImpl: typeof fetch, timeoutMs: number): typeof fetch {\n return async (input, init) => {\n const controller = new AbortController()\n const timer = setTimeout(() => controller.abort(), timeoutMs)\n const path = typeof input === 'string' ? input : input instanceof URL ? input.href : input.url\n\n try {\n return await fetchImpl(input, { ...init, signal: controller.signal })\n } catch (error) {\n if (error instanceof Error && error.name === 'AbortError') {\n throw new Error(`Request to ${path} timed out after ${timeoutMs}ms`, { cause: error })\n }\n throw new Error(`Request to ${path} failed to reach the API`, { cause: error })\n } finally {\n clearTimeout(timer)\n }\n }\n}\n\nasync function rpcCall<R extends ClientResponse<unknown, number, string>>(\n fn: () => Promise<R>,\n): Promise<SuccessBody<R>> {\n const res = await fn()\n if (!res.ok) {\n const body: unknown = await res.json().catch(() => null)\n const problem = body as ProblemBody<FormsApiErrorCode> | null\n const message = problem?.detail ?? problem?.title ?? `forms persistence failed: ${res.status}`\n throw new Error(message)\n }\n return res.json() as Promise<SuccessBody<R>>\n}\n\nexport function createApiPersistence(config: ResolvedPersistenceConfig): FormsPersistence {\n const root = config.baseUrl.replace(/\\/+$/, '')\n const rpc = hcWithType(`${root}/forms`, {\n fetch: withTimeout(config.fetch, config.timeoutMs),\n headers: { [PUBLISHABLE_KEY_HEADER]: config.publishableKey },\n })\n\n return {\n savePartial({ formKey, values }) {\n return rpcCall(() =>\n rpc.v1.public.sessions.$post({\n json: {\n project_id: config.projectId,\n app_user_id: config.appUserId,\n form_id: formKey,\n data: values,\n },\n }),\n ).then(() => undefined)\n },\n saveFields: () => undefined,\n saveSubmission({ formKey, values }) {\n return rpcCall(() =>\n rpc.v1.public.submissions.$post({\n json: {\n project_id: config.projectId,\n app_user_id: config.appUserId,\n form_id: formKey,\n values,\n },\n }),\n ).then(() => undefined)\n },\n recoverRegistryFields: () => ({}),\n }\n}\n\nexport function resolveDefaultPersistence(config: PersistenceClientConfig): FormsPersistence {\n const resolved = resolvePersistenceConfig(config)\n if (!resolved) return createNoopPersistence()\n return createApiPersistence(resolved)\n}\n","import { SchemaError } from './errors.js'\n\nimport type { FieldConfig, FieldType, FormSchema } from './config.js'\n\nconst FIELD_TYPES: readonly FieldType[] = [\n 'text',\n 'email',\n 'number',\n 'boolean',\n 'select',\n 'multiselect',\n 'json',\n]\n\nconst VALIDATION_RULES: readonly string[] = [\n 'required',\n 'minLength',\n 'maxLength',\n 'min',\n 'max',\n 'pattern',\n 'patternFlags',\n 'oneOf',\n 'custom',\n]\n\nconst NUMERIC_RULES: readonly string[] = ['minLength', 'maxLength', 'min', 'max']\n\n/** The ingest `z.string().max(128)` bound on a `data:updated` key. */\nconst MAX_FIELD_KEY_LENGTH = 128\n\n/** The ingest `z.string().max(128)` bound on a `form:submitted` key. */\nconst MAX_FORM_KEY_LENGTH = 128\n\nconst VALID_PATTERN_FLAGS = /^[dgimsuvy]*$/\n\n/** Internal. The snapshot `initForm` holds for the life of an instance. */\nexport interface ResolvedForm {\n readonly formKey: string\n readonly fields: readonly FieldConfig[]\n /** Compiled once per config object, keyed by field key. */\n readonly patterns: ReadonlyMap<string, RegExp>\n}\n\n// ! The only module-level binding in this package. Keyed by schema object\n// ! identity, it holds nothing but data derived from an argument the caller\n// ! already had, and nothing reads it except the call that supplied the key.\n// ! It must never hold user or per-request state. This is not a registry: there\n// ! is no name a caller can guess, and entries are collectable with the schema.\nconst RESOLVED_SCHEMAS = new WeakMap<FormSchema, ResolvedForm>()\n\nexport function resolveForm({ schema }: { schema: FormSchema }): ResolvedForm {\n const memoized = RESOLVED_SCHEMAS.get(schema)\n if (memoized) return memoized\n\n const resolved = validateAndCompile({ schema })\n RESOLVED_SCHEMAS.set(schema, resolved)\n return resolved\n}\n\n// ---------------------------------------------------------------------------\n// Validation\n// ---------------------------------------------------------------------------\n\nfunction validateAndCompile({ schema }: { schema: FormSchema }): ResolvedForm {\n // * Every check below reads the schema as `unknown`, because the whole point\n // * is the input the compiler never saw: a JavaScript consumer, a schema that\n // * arrived from the platform, or one whose `as const` was dropped.\n const root: unknown = schema\n\n assertJsonRepresentable({ root })\n\n if (!isObjectLike(root)) throw new SchemaError('schema: must be an object')\n\n const formKey = root['id']\n if (typeof formKey !== 'string' || formKey.trim() === '')\n throw new SchemaError('schema.id: must be a non-empty string')\n // ! The id is the storage key verbatim, so `' signup '` would persist under a\n // ! different key than `'signup'`. Rejected rather than trimmed: silently\n // ! normalizing would orphan whatever a schema had already stored.\n if (formKey !== formKey.trim())\n throw new SchemaError('schema.id: must not have leading or trailing whitespace')\n if (formKey.length > MAX_FORM_KEY_LENGTH)\n throw new SchemaError(\n `schema.id: must be at most ${MAX_FORM_KEY_LENGTH} characters (received ${formKey.length})`,\n )\n\n const name = root['name']\n if (name !== undefined) {\n if (typeof name !== 'string') throw new SchemaError('schema.name: must be a string')\n if (name.trim() === '') throw new SchemaError('schema.name: must be a non-empty string')\n }\n\n if (!Array.isArray(root['fields'])) throw new SchemaError('schema.fields: must be an array')\n\n const fields: unknown[] = root['fields']\n if (fields.length === 0) throw new SchemaError('schema.fields: must declare at least one field')\n\n const patterns = new Map<string, RegExp>()\n const seenKeys = new Set<string>()\n fields.forEach((field, index) => {\n validateField({ field, path: `schema.fields[${index}]`, seenKeys, patterns })\n })\n\n // * The field list is copied, not aliased: an instance holds this snapshot for\n // * its whole life, so a schema array mutated afterwards must not change what\n // * a live form validates and writes against.\n return { formKey, fields: [...fields] as readonly FieldConfig[], patterns }\n}\n\nfunction validateField({\n field,\n path,\n seenKeys,\n patterns,\n}: {\n field: unknown\n path: string\n seenKeys: Set<string>\n patterns: Map<string, RegExp>\n}): void {\n if (!isObjectLike(field)) throw new SchemaError(`${path}: must be an object`)\n\n const key = field['key']\n if (typeof key !== 'string' || key.trim() === '')\n throw new SchemaError(`${path}.key: must be a non-empty string`)\n if (key.length > MAX_FIELD_KEY_LENGTH)\n throw new SchemaError(\n `${path}.key: must be at most ${MAX_FIELD_KEY_LENGTH} characters (received ${key.length})`,\n )\n if (seenKeys.has(key))\n throw new SchemaError(`${path}.key: duplicate field key \"${key}\" in this form`)\n seenKeys.add(key)\n\n const label = field['label']\n if (typeof label !== 'string' || label.trim() === '')\n throw new SchemaError(`${path}.label: must be a non-empty string`)\n\n const type = field['type']\n if (typeof type !== 'string' || !FIELD_TYPES.includes(type as FieldType))\n throw new SchemaError(`${path}.type: must be one of ${FIELD_TYPES.join(', ')}`)\n\n const registryFieldId = field['registryFieldId']\n if (registryFieldId !== undefined && typeof registryFieldId !== 'string')\n throw new SchemaError(`${path}.registryFieldId: must be a string`)\n\n const protocolFieldId = field['protocolFieldId']\n if (protocolFieldId !== undefined && typeof protocolFieldId !== 'string')\n throw new SchemaError(`${path}.protocolFieldId: must be a string`)\n\n // * Unknown keys on the field object itself are tolerated, deliberately\n // * asymmetric with `validations` below: the platform may add presentation\n // * metadata, and an older SDK should not reject a newer config outright.\n // * An unknown key inside `validations` can only be a typo for a rule, and\n // * silently skipping a rule is the worst failure available. The JSON\n // * round-trip check still rejects a *function* on an unknown field key, so\n // * this tolerance opens no second door for functions.\n const validations = field['validations']\n if (validations === undefined) return\n\n validateValidations({ validations, path: `${path}.validations` })\n if (!isObjectLike(validations)) return\n\n const pattern = validations['pattern']\n if (typeof pattern !== 'string') return\n\n const flags = validations['patternFlags']\n patterns.set(\n key,\n compilePattern({\n pattern,\n flags: typeof flags === 'string' ? flags : '',\n path: `${path}.validations.pattern`,\n }),\n )\n}\n\nfunction validateValidations({ validations, path }: { validations: unknown; path: string }): void {\n if (!isObjectLike(validations)) throw new SchemaError(`${path}: must be an object`)\n\n for (const rule of Object.keys(validations)) {\n if (!VALIDATION_RULES.includes(rule))\n throw new SchemaError(\n `${path}.${rule}: unknown validation rule; expected one of ${VALIDATION_RULES.join(', ')}`,\n )\n }\n\n const required = validations['required']\n if (required !== undefined && typeof required !== 'boolean')\n throw new SchemaError(`${path}.required: must be a boolean`)\n\n for (const rule of NUMERIC_RULES) {\n const value = validations[rule]\n // * `Number.isFinite` is also what rejects the `NaN`/`Infinity` pair that\n // * survives TypeScript's `number` but serializes to `null`.\n if (value !== undefined && !(typeof value === 'number' && Number.isFinite(value)))\n throw new SchemaError(`${path}.${rule}: must be a finite number`)\n }\n\n const minLength = validations['minLength']\n const maxLength = validations['maxLength']\n if (typeof minLength === 'number' && typeof maxLength === 'number' && maxLength < minLength)\n throw new SchemaError(`${path}.maxLength: must be greater than or equal to minLength`)\n\n const min = validations['min']\n const max = validations['max']\n if (typeof min === 'number' && typeof max === 'number' && max < min)\n throw new SchemaError(`${path}.max: must be greater than or equal to min`)\n\n const oneOf = validations['oneOf']\n if (oneOf !== undefined && !(Array.isArray(oneOf) && oneOf.length > 0))\n throw new SchemaError(`${path}.oneOf: must be a non-empty array`)\n\n const pattern = validations['pattern']\n if (pattern !== undefined && typeof pattern !== 'string')\n throw new SchemaError(`${path}.pattern: must be a string`)\n\n const patternFlags = validations['patternFlags']\n if (\n patternFlags !== undefined &&\n !(typeof patternFlags === 'string' && VALID_PATTERN_FLAGS.test(patternFlags))\n )\n throw new SchemaError(`${path}.patternFlags: must contain only the characters dgimsuvy`)\n\n // * The runtime half of the one JSON exception: a widened config or a\n // * JavaScript consumer can put anything here, and a non-function would be\n // * called and throw a TypeError from inside validation on the first\n // * keystroke. Arity and async-ness are deliberately not inspected — the\n // * return-shape and thenable checks at call time own that.\n const custom = validations['custom']\n if (custom !== undefined && typeof custom !== 'function')\n throw new SchemaError(`${path}.custom: must be a function (received ${typeof custom})`)\n}\n\nfunction compilePattern({\n pattern,\n flags,\n path,\n}: {\n pattern: string\n flags: string\n path: string\n}): RegExp {\n // * `g` and `y` carry `lastIndex` across `.test()` calls, so a pattern reused\n // * for every keystroke would silently alternate pass and fail.\n try {\n return new RegExp(pattern, flags.replace(/[gy]/g, ''))\n } catch (error) {\n throw new SchemaError(`${path}: invalid pattern — ${errorMessage(error)}`, { cause: error })\n }\n}\n\n// ---------------------------------------------------------------------------\n// JSON representability\n// ---------------------------------------------------------------------------\n\n/**\n * Rejects every value in the config that would not survive\n * `JSON.parse(JSON.stringify(x))` — a function included, except at the one\n * permitted location, `validations.custom` on a field.\n */\nfunction assertJsonRepresentable({ root }: { root: unknown }): void {\n const stripped = withoutFieldValidators(root)\n const serialized = stringifyOrUndefined(stripped)\n\n if (serialized === undefined) {\n const path = findNonJsonPath({ value: stripped, path: 'schema', seen: new Set() })\n throw new SchemaError(`${path ?? 'schema'}: value cannot be serialized to JSON`)\n }\n\n const mismatch = firstMismatch({\n actual: stripped,\n expected: JSON.parse(serialized),\n path: 'schema',\n })\n if (mismatch)\n throw new SchemaError(\n `${mismatch}: value does not survive a JSON round trip; only a field's validations.custom may hold a function, and every other value must be JSON-representable`,\n )\n}\n\n// ! Copies along `schema.fields[*].validations` only, so the caller's schema is\n// ! never mutated and no other key named `custom` at any depth is stripped.\n// ! A blanket strip would let a function through anywhere and gut the check.\nfunction withoutFieldValidators(root: unknown): unknown {\n if (!isObjectLike(root)) return root\n if (!Array.isArray(root['fields'])) return root\n\n const fields: unknown[] = root['fields']\n return { ...root, fields: fields.map(stripField) }\n}\n\nfunction stripField(field: unknown): unknown {\n if (!isObjectLike(field)) return field\n const validations = field['validations']\n if (!isObjectLike(validations) || !('custom' in validations)) return field\n\n const { custom: _custom, ...rest } = validations\n return { ...field, validations: rest }\n}\n\nfunction stringifyOrUndefined(value: unknown): string | undefined {\n try {\n return JSON.stringify(value)\n } catch {\n return undefined\n }\n}\n\n/** The path of the first value `JSON.stringify` cannot handle at all. */\nfunction findNonJsonPath({\n value,\n path,\n seen,\n}: {\n value: unknown\n path: string\n seen: Set<object>\n}): string | undefined {\n if (typeof value === 'bigint' || typeof value === 'symbol') return path\n if (value === null || typeof value !== 'object') return undefined\n if (seen.has(value)) return path\n\n seen.add(value)\n for (const [childPath, child] of childEntries({ value, path })) {\n const found = findNonJsonPath({ value: child, path: childPath, seen })\n if (found) return found\n }\n seen.delete(value)\n return undefined\n}\n\nfunction childEntries({ value, path }: { value: object; path: string }): [string, unknown][] {\n if (Array.isArray(value)) {\n const items: unknown[] = value\n return items.map((item, index) => [`${path}[${index}]`, item])\n }\n return Object.entries(value as Record<string, unknown>).map(([key, item]) => [\n `${path}.${key}`,\n item,\n ])\n}\n\n/** The path of the first value that changed across the round trip. */\nfunction firstMismatch({\n actual,\n expected,\n path,\n}: {\n actual: unknown\n expected: unknown\n path: string\n}): string | undefined {\n if (Array.isArray(actual) || Array.isArray(expected)) {\n if (!Array.isArray(actual) || !Array.isArray(expected)) return path\n\n const actualItems: unknown[] = actual\n const expectedItems: unknown[] = expected\n if (actualItems.length !== expectedItems.length) return path\n\n for (const [index, item] of actualItems.entries()) {\n const found = firstMismatch({\n actual: item,\n expected: expectedItems[index],\n path: `${path}[${index}]`,\n })\n if (found) return found\n }\n return undefined\n }\n\n if (isJsonObject(actual) && isJsonObject(expected)) {\n const actualKeys = Object.keys(actual)\n const expectedKeys = Object.keys(expected)\n // * A key present before and absent after is exactly how `undefined`, a\n // * function, and a `Symbol` value disappear.\n if (actualKeys.length !== expectedKeys.length) {\n const dropped = actualKeys.find((key) => !expectedKeys.includes(key))\n return dropped === undefined ? path : `${path}.${dropped}`\n }\n for (const key of actualKeys) {\n const found = firstMismatch({\n actual: actual[key],\n expected: expected[key],\n path: `${path}.${key}`,\n })\n if (found) return found\n }\n return undefined\n }\n\n // * Catches `NaN`/`Infinity` (both become `null`), a `Date` (becomes a\n // * string), and a `RegExp`, `Map`, `Set`, or class instance (all become\n // * `{}`, which is not the original object).\n return actual === expected ? undefined : path\n}\n\n// ---------------------------------------------------------------------------\n// Shared predicates\n// ---------------------------------------------------------------------------\n\nfunction isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n\n/** Narrower than `isObjectLike`: a `Date`, `RegExp`, or class instance is not one. */\nfunction isJsonObject(value: unknown): value is Record<string, unknown> {\n if (!isObjectLike(value)) return false\n const prototype = Object.getPrototypeOf(value)\n return prototype === Object.prototype || prototype === null\n}\n\nfunction errorMessage(error: unknown): string {\n return error instanceof Error ? error.message : String(error)\n}\n","import type { JsonValue } from '@embeddables/shared-types/json'\n\n/** Every form on the origin shares this one entry, indexed by form key. */\nexport const FORM_DATA_KEY = 'EMBEDDABLES-FORM-DATA'\n\nexport interface FormsStorage {\n getItem(key: string): string | null\n setItem(key: string, value: string): void\n removeItem(key: string): void\n}\n\n/** Internal. The whole document: form key → that form's field bag. */\ntype FormsDocument = Record<string, Record<string, JsonValue>>\n\n// * Keyed by storage object identity so two form instances that share one\n// * store share one parsed document. Entries die with the storage object —\n// * this is not a name-guessable registry.\nconst LIVE_DOCUMENTS = new WeakMap<FormsStorage, FormsDocument>()\n\nfunction readDocumentFromStorage({ storage }: { storage: FormsStorage }): FormsDocument {\n try {\n const raw = storage.getItem(FORM_DATA_KEY)\n if (raw === null) return {}\n\n const parsed: unknown = JSON.parse(raw)\n if (!isObjectLike(parsed)) return {}\n\n // * Returned as-is, with no per-form validation: this function's job is to\n // * hand back exactly what is stored so a write can preserve it. A sibling\n // * whose value is a string or `null` is carried through untouched.\n return parsed as FormsDocument\n } catch {\n return {}\n }\n}\n\n/**\n * Load once per storage object; later calls reuse the in-memory document.\n *\n * There is no invalidation: a write from another tab or a user clearing site\n * data is never picked up, and the next write here overwrites it. Recovering\n * from an external mutation means constructing a new storage object.\n */\nfunction loadDocument({ storage }: { storage: FormsStorage }): FormsDocument {\n const cached = LIVE_DOCUMENTS.get(storage)\n if (cached) return cached\n\n const document = readDocumentFromStorage({ storage })\n LIVE_DOCUMENTS.set(storage, document)\n return document\n}\n\nexport function resolveStorage({ storage }: { storage?: FormsStorage }): FormsStorage {\n if (storage) return storage\n\n try {\n const candidate = globalThis.localStorage\n // * Safari private mode throws on access rather than being absent, so\n // * presence alone is not a usable probe — a throwaway read is.\n candidate.getItem(FORM_DATA_KEY)\n return candidate\n } catch {\n return createMemoryStorage()\n }\n}\n\n/**\n * A fresh in-memory shim seeded with the document as last read, for an instance\n * whose real storage started throwing mid-session.\n */\nexport function degradeToMemory({ storage }: { storage: FormsStorage }): FormsStorage {\n const shim = createMemoryStorage()\n // * Prefer the live snapshot: a throwing `getItem` after a quota failure\n // * would otherwise seed an empty shim and drop every sibling this instance\n // * already had in memory.\n const document = LIVE_DOCUMENTS.get(storage) ?? readDocumentFromStorage({ storage })\n const snapshot: FormsDocument = { ...document }\n shim.setItem(FORM_DATA_KEY, JSON.stringify(snapshot))\n LIVE_DOCUMENTS.set(shim, snapshot)\n return shim\n}\n\nexport function readFields({\n storage,\n formKey,\n}: {\n storage: FormsStorage\n formKey: string\n}): Record<string, JsonValue> {\n const bag: unknown = loadDocument({ storage })[formKey]\n if (!isObjectLike(bag)) return {}\n\n // * Unfiltered: field keys the config does not declare are returned here and\n // * filtered at the instance boundary, not in this layer.\n return bag as Record<string, JsonValue>\n}\n\nexport function writeFields({\n storage,\n formKey,\n fields,\n}: {\n storage: FormsStorage\n formKey: string\n fields: Record<string, JsonValue>\n}): void {\n // * Replaces exactly one subtree and carries every other form key through\n // * verbatim, including keys this page has no config for. Merging *within* the\n // * bag is the caller's job. A throwing `setItem` propagates so the form\n // * instance can degrade and report. The live snapshot is updated only after\n // * `setItem` succeeds, so a quota failure leaves memory matching storage.\n // ! `fields` is copied rather than stored by reference: the caller keeps its\n // ! own handle on that object, and aliasing it into the cached document would\n // ! make a later mutation there visible to every instance on this storage\n // ! without a write.\n const next = { ...loadDocument({ storage }), [formKey]: { ...fields } }\n storage.setItem(FORM_DATA_KEY, JSON.stringify(next))\n LIVE_DOCUMENTS.set(storage, next)\n}\n\nexport function removeFields({\n storage,\n formKey,\n}: {\n storage: FormsStorage\n formKey: string\n}): void {\n const { [formKey]: _dropped, ...rest } = loadDocument({ storage })\n\n if (Object.keys(rest).length === 0) {\n // * A missing entry and a stored `{}` are indistinguishable to every\n // * reader, so releasing the entry is strictly better: a leftover key\n // * visible in devtools reads as data that was not deleted.\n storage.removeItem(FORM_DATA_KEY)\n LIVE_DOCUMENTS.set(storage, rest)\n return\n }\n storage.setItem(FORM_DATA_KEY, JSON.stringify(rest))\n LIVE_DOCUMENTS.set(storage, rest)\n}\n\n/**\n * Whether a value survives `JSON.stringify`. `undefined`, a function, and a\n * `Symbol` make it return `undefined`; a circular reference and a `BigInt` make\n * it throw. All five must be rejected before a write, because a value that\n * cannot stringify aborts a write carrying every form's data.\n */\nexport function isSerializable({ value }: { value: unknown }): boolean {\n try {\n return typeof JSON.stringify(value) === 'string'\n } catch {\n return false\n }\n}\n\nfunction createMemoryStorage(): FormsStorage {\n // * Created per call and never module-level, because it holds user data.\n const entries = new Map<string, string>()\n\n return {\n getItem: (key) => entries.get(key) ?? null,\n setItem: (key, value) => {\n entries.set(key, value)\n },\n removeItem: (key) => {\n entries.delete(key)\n },\n }\n}\n\nfunction isObjectLike(value: unknown): value is Record<string, unknown> {\n return typeof value === 'object' && value !== null && !Array.isArray(value)\n}\n","import type { JsonValue } from '@embeddables/shared-types/json'\n\nimport { ValidatorError } from './errors.js'\n\nimport type { FieldConfig, FieldType, FieldValidator } from './config.js'\n\n/** Runtime counterpart to `FieldType`. Exhaustive by construction. */\n// ! Must stay in lockstep with `ValueOfFieldType` in `src/config.ts`: the two\n// ! are the compile-time and runtime halves of one claim. Typing this as\n// ! `Record<FieldType, …>` is what makes a new field type a compile error\n// ! here; only the type tests catch a mismatch between the two.\nconst FIELD_TYPE_PREDICATES: Record<FieldType, (value: JsonValue) => boolean> = {\n text: (value) => typeof value === 'string',\n email: (value) => typeof value === 'string',\n number: (value) => typeof value === 'number',\n boolean: (value) => typeof value === 'boolean',\n select: (value) => typeof value === 'string',\n multiselect: (value) => Array.isArray(value),\n json: () => true,\n}\n\n// * The WHATWG `input[type=email]` production, so a value the browser accepts in\n// * an email input is a value this accepts. It is deliberately narrower than\n// * RFC 5322 (no quoted local parts, no comments) and deliberately wider than\n// * \"must have a dot\": `user@localhost` and intranet hosts are valid. A form that\n// * needs a public TLD adds `pattern` on top.\nconst EMAIL_PATTERN =\n /^[\\w.!#$%&'*+/=?^`{|}~-]+@[a-zA-Z\\d](?:[a-zA-Z\\d-]{0,61}[a-zA-Z\\d])?(?:\\.[a-zA-Z\\d](?:[a-zA-Z\\d-]{0,61}[a-zA-Z\\d])?)*$/\n\n/**\n * Every message a single field's value earns. Empty means valid. Not generic:\n * the per-field types live at the instance boundary, and the cast down to\n * `JsonValue` happens once, in `initForm`.\n */\nexport function validateValue({\n field,\n value,\n values,\n pattern,\n validator,\n}: {\n field: FieldConfig\n value: JsonValue | undefined\n values: Readonly<Record<string, JsonValue>>\n pattern?: RegExp\n validator?: FieldValidator\n}): readonly string[] {\n const rules = field.validations\n const messages: string[] = []\n\n const isAbsent = value === undefined || value === null\n const isBlank = isAbsent || value === '' || (Array.isArray(value) && value.length === 0)\n if (rules?.required === true && isBlank) messages.push(`${field.label} is required`)\n\n // * An absent value earns no further message and never reaches the custom\n // * validator, whether or not it was required.\n if (isAbsent) return messages\n\n if (!FIELD_TYPE_PREDICATES[field.type](value))\n messages.push(\n `${field.label} expects ${/^[aeiou]/.test(field.type) ? 'an' : 'a'} ${field.type} value`,\n )\n\n if (typeof value === 'string') {\n // * Intrinsic to the declared type, so it runs before the author's own rules\n // * and cannot be switched off. That is why the blank case belongs to\n // * `required` alone: an author who wants an optional email cleared has no\n // * way to opt out of this check, so it must not claim `''` is malformed.\n if (field.type === 'email' && value !== '' && !EMAIL_PATTERN.test(value))\n messages.push(`${field.label} must be a valid email address`)\n if (rules?.minLength !== undefined && value.length < rules.minLength)\n messages.push(`${field.label} must be at least ${rules.minLength} characters`)\n if (rules?.maxLength !== undefined && value.length > rules.maxLength)\n messages.push(`${field.label} must be at most ${rules.maxLength} characters`)\n if (pattern && !pattern.test(value))\n messages.push(`${field.label} is not in the expected format`)\n }\n\n if (Array.isArray(value)) {\n if (rules?.minLength !== undefined && value.length < rules.minLength)\n messages.push(`${field.label} must have at least ${rules.minLength} items`)\n if (rules?.maxLength !== undefined && value.length > rules.maxLength)\n messages.push(`${field.label} must have at most ${rules.maxLength} items`)\n }\n\n if (typeof value === 'number') {\n if (rules?.min !== undefined && value < rules.min)\n messages.push(`${field.label} must be at least ${rules.min}`)\n if (rules?.max !== undefined && value > rules.max)\n messages.push(`${field.label} must be at most ${rules.max}`)\n }\n\n if (rules?.oneOf) {\n // * Canonical JSON equality, so an object option matches whatever key order\n // * the stored value happens to carry, while arrays still compare\n // * positionally.\n const encoded = canonicalize(value)\n if (!rules.oneOf.some((option) => canonicalize(option) === encoded))\n messages.push(`${field.label} must be one of the allowed options`)\n }\n\n // ! The validator runs only on a present, type-correct value whose every\n // ! declarative rule passed. Those three conditions are what make the\n // ! declared `value` type honest: a validator body dereferences `value` with\n // ! no guard because the type says it can. Deleting or reordering this check\n // ! hands consumer code a value whose runtime type contradicts its declared\n // ! type, with no error anywhere.\n if (!validator || messages.length > 0) return messages\n\n return normalizeValidatorResult({\n // * Read as `unknown` because a JavaScript consumer, or a widened config,\n // * can return anything at all from here.\n result: validator({ value, values }),\n field,\n })\n}\n\nfunction normalizeValidatorResult({\n result,\n field,\n}: {\n result: unknown\n field: FieldConfig\n}): readonly string[] {\n if (isThenable(result))\n throw new ValidatorError(\n `Validator for \"${field.key}\" returned a promise; custom validators must be synchronous`,\n )\n if (result === null || result === undefined) return []\n if (typeof result === 'string') return [result]\n if (Array.isArray(result))\n return (result as unknown[]).filter((entry): entry is string => typeof entry === 'string')\n\n throw new ValidatorError(\n `Validator for \"${field.key}\" returned ${typeof result}; expected a string, an array of strings, or null`,\n )\n}\n\nfunction isThenable(value: unknown): boolean {\n return typeof (value as { then?: unknown } | null | undefined)?.then === 'function'\n}\n\n/**\n * JSON encoding with object keys sorted at every depth, so two values compare\n * by content rather than by insertion order.\n */\n// * A stored value reaches this through `JSON.parse` of the shared document, so\n// * its key order is whatever was written first, not the order the config\n// * author wrote the option in. Plain `JSON.stringify` equality would reject a\n// * `json` value that differs from its option only by key order.\nfunction canonicalize(value: JsonValue): string {\n const walk = (input: JsonValue): JsonValue => {\n if (Array.isArray(input)) return input.map(walk)\n if (input !== null && typeof input === 'object')\n return Object.fromEntries(\n Object.entries(input)\n .sort(([left], [right]) => (left < right ? -1 : left > right ? 1 : 0))\n .map(([key, item]) => [key, walk(item)]),\n )\n return input\n }\n return JSON.stringify(walk(value))\n}\n","import type { EmbeddablesInstance } from '@embeddables/core'\nimport type { JsonValue } from '@embeddables/shared-types/json'\n\nimport { buildDataUpdatedEvent, buildFieldUpdatedEvents } from './analytics.js'\nimport { FormsError, SchemaError } from './errors.js'\nimport { resolveDefaultPersistence } from './persistence-client.js'\nimport { resolveForm } from './resolve.js'\nimport {\n degradeToMemory,\n isSerializable,\n readFields,\n removeFields,\n resolveStorage,\n writeFields,\n} from './storage.js'\nimport { validateValue } from './validation.js'\n\nimport type { AnalyticsInstance } from './analytics.js'\nimport type { FieldConfig, FieldValidator, FormFieldKey, FormSchema, FormValues } from './config.js'\nimport type { FormsPersistence, PersistedField, RecoverableField } from './persistence.js'\nimport type { FormsStorage } from './storage.js'\n\n/** Per-key validation errors. An empty object means the operation succeeded. */\nexport type FieldErrors<TSchema extends FormSchema> = Readonly<\n Partial<Record<FormFieldKey<TSchema>, readonly string[]>>\n>\n\nexport interface SetResult<TSchema extends FormSchema> {\n ok: boolean\n errors: FieldErrors<TSchema>\n /** Set when an `analyticsInstance` was configured and `trackEvent` rejected. Never thrown. */\n trackError?: unknown\n}\n\nexport interface SubmitResult<TSchema extends FormSchema> {\n ok: boolean\n errors: FieldErrors<TSchema>\n values: Partial<FormValues<TSchema>>\n trackError?: unknown\n}\n\nexport interface ValidateResult<TSchema extends FormSchema> {\n ok: boolean\n errors: FieldErrors<TSchema>\n values: Partial<FormValues<TSchema>>\n}\n\nexport interface FormInstance<TSchema extends FormSchema> {\n readonly key: TSchema['id']\n /**\n * Applies every key atomically: all or nothing, one write, one event.\n * Validates and persists synchronously; the returned promise never rejects.\n * Throws synchronously only if a custom validator throws or returns an\n * illegal shape.\n */\n set(patch: Partial<FormValues<TSchema>>): Promise<SetResult<TSchema>>\n /** Typed by the field's declared `type`. Nothing verifies the stored value against it. */\n get<K extends FormFieldKey<TSchema>>(key: K): FormValues<TSchema>[K] | undefined\n getAll(): Partial<FormValues<TSchema>>\n /**\n * Validates every declared field, then emits one `form:submitted` event.\n *\n * Not idempotent: every call emits another event. The caller owns dedupe —\n * disable the button, or guard on a route transition.\n *\n * Same synchronous-throw and never-reject contract as `set`.\n */\n submit(): Promise<SubmitResult<TSchema>>\n /**\n * Runs validation without writing to storage or emitting analytics.\n *\n * With no argument, validates every declared field against stored values and\n * replaces `errors()` wholesale. With a patch, validates only those keys\n * against a merged snapshot and updates errors for those keys only.\n *\n * Same synchronous-throw and never-reject contract as `set` / `submit`.\n */\n validate(patch?: Partial<FormValues<TSchema>>): Promise<ValidateResult<TSchema>>\n errors(): FieldErrors<TSchema>\n clear(): void\n}\n\nconst REQUIRED_CORE_METHODS = ['getAppUserId', 'getProjectId', 'getPublishableKey'] as const\n\nfunction hasRequiredCoreMethods(value: unknown): value is EmbeddablesInstance {\n if (typeof value !== 'object' || value === null) return false\n return REQUIRED_CORE_METHODS.every(\n (method) => typeof (value as Record<string, unknown>)[method] === 'function',\n )\n}\n\nfunction mergeCustomValidations<TSchema extends FormSchema>({\n schema,\n customValidations,\n}: {\n schema: TSchema\n customValidations?: { readonly [K in FormFieldKey<TSchema>]?: FieldValidator }\n}): TSchema {\n if (!customValidations) return schema\n\n const declared = new Set(schema.fields.map((field) => field.key))\n for (const key of Object.keys(customValidations)) {\n if (!declared.has(key)) {\n throw new SchemaError(`customValidations: unknown field key \"${key}\"`)\n }\n const validator = customValidations[key as FormFieldKey<TSchema>]\n if (typeof validator !== 'function') {\n throw new SchemaError(`customValidations.${key}: must be a function`)\n }\n }\n\n const fields = schema.fields.map((field) => {\n const custom = customValidations[field.key as FormFieldKey<TSchema>]\n if (!custom) return field\n return {\n ...field,\n validations: { ...field.validations, custom },\n }\n })\n\n return { ...schema, fields }\n}\n\n// ! The public surface, matching the approved Miro flow: `core`, optional\n// ! analytics client, and optional API base URL for durable persistence.\n// ! Storage and persistence ports are not consumer options — internal seams\n// ! (see `FormsClientOptions`).\nexport interface InitFormsOptions {\n core: EmbeddablesInstance\n analyticsInstance?: AnalyticsInstance\n /** Overrides the default production backend URL for R2 persistence writes. */\n baseUrl?: string\n}\n\nexport interface FormsClient {\n initForm<const TSchema extends FormSchema>(options: {\n schema: TSchema\n customValidations?: { readonly [K in FormFieldKey<TSchema>]?: FieldValidator }\n }): FormInstance<TSchema>\n}\n\n/**\n * Validates the core instance once, then returns a per-form `initForm`. Public\n * API — the Miro signature. Consumers pass only `core` and, optionally, an\n * analytics client.\n */\nexport function initForms(options: InitFormsOptions): FormsClient {\n return createFormsClient(options)\n}\n\n// ! Internal, not exported from the package barrel. The storage and persistence\n// ! seams live here so tests can inject a memory store / spy port and the real\n// ! R2/Supabase client can be wired later, without widening the public\n// ! `initForms` signature beyond what the Miro shows.\nexport interface FormsClientOptions extends InitFormsOptions {\n storage?: FormsStorage\n persistence?: FormsPersistence\n}\n\nexport function createFormsClient({\n core,\n analyticsInstance,\n baseUrl,\n storage,\n persistence,\n}: FormsClientOptions): FormsClient {\n if (!hasRequiredCoreMethods(core)) {\n throw new FormsError('initForms requires an initialized Embeddables core instance.')\n }\n\n const resolvedPersistence = persistence ?? resolveDefaultPersistence({ core, baseUrl })\n\n // * Retained as the composition root; Forms does not persist identity.\n void core\n\n return {\n initForm: <const TSchema extends FormSchema>(options: {\n schema: TSchema\n customValidations?: { readonly [K in FormFieldKey<TSchema>]?: FieldValidator }\n }): FormInstance<TSchema> =>\n createFormInstance({\n analyticsInstance,\n storage,\n persistence: resolvedPersistence,\n schema: options.schema,\n customValidations: options.customValidations,\n }),\n }\n}\n\nfunction createFormInstance<const TSchema extends FormSchema>({\n analyticsInstance,\n storage,\n persistence,\n schema,\n customValidations,\n}: {\n analyticsInstance?: AnalyticsInstance\n storage?: FormsStorage\n persistence: FormsPersistence\n schema: TSchema\n customValidations?: { readonly [K in FormFieldKey<TSchema>]?: FieldValidator }\n}): FormInstance<TSchema> {\n const schemaForResolve = mergeCustomValidations({ schema, customValidations })\n // * Snapshotted for the instance's life, so a schema mutated afterwards\n // * cannot change a live form. Memoized on schema object identity, so a second\n // * instance over the same literal is free — but `customValidations` builds a\n // * new object above and therefore always resolves afresh.\n const resolved = resolveForm({ schema: schemaForResolve })\n const declared = new Map<string, FieldConfig>(resolved.fields.map((field) => [field.key, field]))\n\n // * Held in one object rather than as bindings, because `storage` is swapped\n // * on degradation and the bag/error map are mutated in place.\n const resolvedStorage = resolveStorage({ storage })\n const state = {\n storage: resolvedStorage,\n // ! Copied once at init and never refreshed: get/submit read this bag, and\n // ! set/clear persist it without another storage read. One live instance per\n // ! `schema.id` is therefore assumed. A second instance, another tab, or a\n // ! user clearing site data is invisible here, and the next `set` overwrites\n // ! it.\n bag: { ...readFields({ storage: resolvedStorage, formKey: resolved.formKey }) },\n errors: new Map<string, readonly string[]>(),\n }\n\n // * Runs a persistence call without ever letting it break the caller: a\n // * synchronous throw is caught and a returned promise's rejection is\n // * swallowed. Fire-and-forget by contract — the SDK never awaits a durable\n // * write, so `set` / `submit` keep their never-rejects guarantee.\n const firePersistence = (run: () => void | Promise<void>): void => {\n try {\n const result = run()\n if (result instanceof Promise) {\n void result.then(undefined, () => undefined)\n }\n } catch {\n // best-effort: a failing persistence port never surfaces to set/submit\n }\n }\n\n // * localStorage was seeded above and always wins. Recovery is eligible only\n // * for a field that declares a registry/protocol id and is still absent\n // * locally, and a recovered value is merged only while the local value stays\n // * missing. With the no-op default this whole block is inert.\n const mergeRecovered = (recovered: Record<string, JsonValue>): void => {\n for (const [key, value] of Object.entries(recovered)) {\n if (value !== undefined && state.bag[key] === undefined) state.bag[key] = value\n }\n }\n\n const recoverable: RecoverableField[] = resolved.fields\n .filter(\n (field) =>\n (field.registryFieldId !== undefined || field.protocolFieldId !== undefined) &&\n state.bag[field.key] === undefined,\n )\n .map((field) => ({\n key: field.key,\n registryFieldId: field.registryFieldId,\n protocolFieldId: field.protocolFieldId,\n }))\n\n if (recoverable.length > 0) {\n try {\n const result = persistence.recoverRegistryFields({\n formKey: resolved.formKey,\n fields: recoverable,\n })\n if (result instanceof Promise) {\n void result.then(\n (recovered) => mergeRecovered(recovered ?? {}),\n () => undefined,\n )\n } else {\n mergeRecovered(result)\n }\n } catch {\n // best-effort: recovery must never throw out of initForm\n }\n }\n\n const freeze = (entries: Map<string, readonly string[]>): FieldErrors<TSchema> =>\n Object.freeze(Object.fromEntries(entries)) as FieldErrors<TSchema>\n\n const noErrors = (): FieldErrors<TSchema> => freeze(new Map())\n\n /** The stored bag narrowed to the keys the config declares. */\n const narrow = (bag: Record<string, JsonValue>): Record<string, JsonValue> => {\n const narrowed: Record<string, JsonValue> = {}\n for (const field of resolved.fields) {\n const value = bag[field.key]\n if (value !== undefined) narrowed[field.key] = value\n }\n return narrowed\n }\n\n const readBag = (): Record<string, JsonValue> => state.bag\n\n // * The whole type boundary, in one place: a field declares its validator\n // * against its own value type, while `validateValue` is a runtime predicate\n // * over `JsonValue`. Sound because `validateValue` calls the validator only\n // * after the field's type predicate passed.\n const validatorFor = (field: FieldConfig): FieldValidator | undefined =>\n field.validations?.custom as FieldValidator | undefined\n\n // * Validates the given keys against one snapshot. Callers that pass every\n // * declared field — `submit()` and parameterless `validate()` — do so to\n // * catch a field invalidated by an earlier `.set()` on some other key, not\n // * only the keys touched in the latest patch.\n const validateDeclaredFields = ({\n snapshot,\n keys,\n }: {\n snapshot: Record<string, JsonValue>\n keys: readonly string[]\n }): Map<string, readonly string[]> => {\n const errors = new Map<string, readonly string[]>()\n\n for (const key of keys) {\n const field = declared.get(key)\n if (!field) continue\n\n const messages = validateValue({\n field,\n value: snapshot[field.key],\n values: snapshot,\n pattern: resolved.patterns.get(key),\n validator: validatorFor(field),\n })\n if (messages.length > 0) errors.set(key, messages)\n }\n\n return errors\n }\n\n const replaceErrors = (errors: Map<string, readonly string[]>): void => {\n state.errors.clear()\n for (const [key, messages] of errors) state.errors.set(key, messages)\n }\n\n const applyPatchValidationErrors = ({\n errors,\n patchKeys,\n }: {\n errors: Map<string, readonly string[]>\n patchKeys: readonly string[]\n }): void => {\n for (const key of patchKeys) {\n const messages = errors.get(key)\n if (messages) state.errors.set(key, messages)\n else state.errors.delete(key)\n }\n }\n\n // ! Deliberately not `async`. An `async` function turns the synchronous throw\n // ! from a misbehaving custom validator into a rejected promise, which would\n // ! break the never-rejects contract and hide a loud developer error inside\n // ! an unhandled rejection that `void form.set(…)` swallows. Every write and\n // ! every validation below completes before this function returns.\n const set = (patch: Partial<FormValues<TSchema>>): Promise<SetResult<TSchema>> => {\n const changes = patch as Record<string, JsonValue>\n const entries = Object.entries(changes)\n\n // * Mirrors the analytics SDK's `track([])`: no validation, no write, no\n // * event. The in-memory bag is already the source of truth.\n if (entries.length === 0) return Promise.resolve({ ok: true, errors: noErrors() })\n\n const errors = new Map<string, readonly string[]>()\n\n for (const [key, value] of entries) {\n const field = declared.get(key)\n if (!field) {\n // * The compiler rejects this for a typed config, so this is the path a\n // * JavaScript caller or a widened config takes. It is reachable.\n errors.set(key, [`Unknown field: ${key}`])\n continue\n }\n if (!isSerializable({ value }))\n errors.set(key, [`${field.label} value is not JSON-serializable`])\n }\n\n // * The candidate bag is assembled whole and validated whole before a\n // * single byte is written, so a cross-field validator sees every key\n // * arriving in the same call rather than the stale stored one.\n const candidate: Record<string, JsonValue> = { ...readBag(), ...changes }\n const snapshot = narrow(candidate)\n\n for (const [key, value] of entries) {\n const field = declared.get(key)\n if (!field || errors.has(key)) continue\n\n // * A throwing validator propagates out of `set` synchronously. No write\n // * has happened yet, so the batch is trivially atomic — which is why\n // * this is not wrapped in a try/catch.\n const messages = validateValue({\n field,\n value,\n values: snapshot,\n pattern: resolved.patterns.get(key),\n validator: validatorFor(field),\n })\n if (messages.length > 0) errors.set(key, messages)\n }\n\n if (errors.size > 0) {\n for (const [key, messages] of errors) state.errors.set(key, messages)\n // * Not one key of the patch is applied: storage is byte-identical and\n // * nothing is emitted.\n return Promise.resolve({ ok: false, errors: freeze(errors) })\n }\n\n for (const [key] of entries) state.errors.delete(key)\n\n try {\n writeFields({ storage: state.storage, formKey: resolved.formKey, fields: candidate })\n state.bag = candidate\n } catch {\n return Promise.resolve(degradeAndReport({ entries }))\n }\n\n // * Best-effort durable persistence, fired after the local write succeeds\n // * and swallowed whole. Every key here is declared (an unknown key would\n // * have failed validation above), so its config carries the ids.\n const persistedFields: PersistedField[] = entries.map(([key, value]) => {\n const field = declared.get(key)\n return {\n key,\n value,\n registryFieldId: field?.registryFieldId,\n protocolFieldId: field?.protocolFieldId,\n }\n })\n firePersistence(() => persistence.savePartial({ formKey: resolved.formKey, values: snapshot }))\n firePersistence(() =>\n persistence.saveFields({ formKey: resolved.formKey, fields: persistedFields }),\n )\n\n if (!analyticsInstance) return Promise.resolve({ ok: true, errors: noErrors() })\n\n return analyticsInstance\n .trackEvent([\n buildDataUpdatedEvent({ fields: resolved.fields, patch: changes }),\n ...buildFieldUpdatedEvents({ fields: resolved.fields, patch: changes }),\n ])\n .then(() => ({ ok: true, errors: noErrors() }))\n .catch((error: unknown) => ({\n // * `ok` stays true only for values that were persisted; here the write\n // * succeeded and only the emission failed.\n ok: true,\n errors: noErrors(),\n trackError: error,\n }))\n }\n\n const degradeAndReport = ({\n entries,\n }: {\n entries: [string, JsonValue][]\n }): SetResult<TSchema> => {\n state.storage = degradeToMemory({ storage: state.storage })\n\n const errors = new Map<string, readonly string[]>()\n for (const [key] of entries) {\n const label = declared.get(key)?.label ?? key\n const message = `${label} could not be persisted; this form is now in-memory only`\n errors.set(key, [message])\n state.errors.set(key, [message])\n }\n return { ok: false, errors: freeze(errors) }\n }\n\n const get = <K extends FormFieldKey<TSchema>>(key: K): FormValues<TSchema>[K] | undefined => {\n const fieldKey = key as unknown as string\n // * An undeclared key is never handed back, even when the stored bag holds\n // * one: the config is the source of truth for what a form has.\n if (!declared.has(fieldKey)) return undefined\n\n // ! The one place this package asserts something it has not verified.\n // ! `localStorage` is untrusted, so a hand-edited or stale value comes back\n // ! typed as whatever the config declares. Do not \"fix\" it by returning\n // ! `JsonValue` — that drops the typing this surface exists to provide —\n // ! and do not add a runtime coercion, which would rewrite user data.\n return state.bag[fieldKey] as FormValues<TSchema>[K] | undefined\n }\n\n const getAll = (): Partial<FormValues<TSchema>> =>\n narrow(state.bag) as Partial<FormValues<TSchema>>\n\n // ! Not `async`, for the same reason as `set`.\n const submit = (): Promise<SubmitResult<TSchema>> => {\n const snapshot = narrow(readBag())\n const values = snapshot as Partial<FormValues<TSchema>>\n const errors = validateDeclaredFields({\n snapshot,\n keys: resolved.fields.map((field) => field.key),\n })\n\n if (errors.size > 0) {\n replaceErrors(errors)\n // * A `form:submitted` row must mean a real submission, so nothing is sent.\n return Promise.resolve({ ok: false, errors: freeze(errors), values })\n }\n\n state.errors.clear()\n\n // * Best-effort full-submission save, swallowed like the `set` persistence.\n firePersistence(() =>\n persistence.saveSubmission({ formKey: resolved.formKey, values: snapshot }),\n )\n\n if (!analyticsInstance) return Promise.resolve({ ok: true, errors: noErrors(), values })\n\n return analyticsInstance\n .trackEvent([{ event_name: 'form:submitted', form_key: resolved.formKey }])\n .then(() => ({ ok: true, errors: noErrors(), values }))\n .catch((error: unknown) => ({\n ok: true,\n errors: noErrors(),\n values,\n trackError: error,\n }))\n }\n\n // ! Not `async`, for the same reason as `set`.\n const validate = (patch?: Partial<FormValues<TSchema>>): Promise<ValidateResult<TSchema>> => {\n if (patch === undefined) {\n const snapshot = narrow(readBag())\n const values = snapshot as Partial<FormValues<TSchema>>\n const errors = validateDeclaredFields({\n snapshot,\n keys: resolved.fields.map((field) => field.key),\n })\n\n if (errors.size > 0) {\n replaceErrors(errors)\n return Promise.resolve({ ok: false, errors: freeze(errors), values })\n }\n\n state.errors.clear()\n return Promise.resolve({ ok: true, errors: noErrors(), values })\n }\n\n const changes = patch as Record<string, JsonValue>\n const entries = Object.entries(changes)\n const values = narrow({ ...readBag(), ...changes }) as Partial<FormValues<TSchema>>\n\n // * Mirrors `set({})`: nothing to validate, no error-state change.\n if (entries.length === 0) return Promise.resolve({ ok: true, errors: noErrors(), values })\n\n const errors = new Map<string, readonly string[]>()\n const patchKeys = entries.map(([key]) => key)\n\n for (const [key, value] of entries) {\n const field = declared.get(key)\n if (!field) {\n errors.set(key, [`Unknown field: ${key}`])\n continue\n }\n if (!isSerializable({ value }))\n errors.set(key, [`${field.label} value is not JSON-serializable`])\n }\n\n const snapshot = narrow({ ...readBag(), ...changes })\n\n for (const [key] of entries) {\n if (errors.has(key)) continue\n\n const field = declared.get(key)\n if (!field) continue\n\n const messages = validateValue({\n field,\n value: snapshot[key],\n values: snapshot,\n pattern: resolved.patterns.get(key),\n validator: validatorFor(field),\n })\n if (messages.length > 0) errors.set(key, messages)\n }\n\n applyPatchValidationErrors({ errors, patchKeys })\n\n if (errors.size > 0) return Promise.resolve({ ok: false, errors: freeze(errors), values })\n\n return Promise.resolve({ ok: true, errors: noErrors(), values })\n }\n\n // ! All-or-nothing within the form: undeclared field keys in this form's bag\n // ! go too, making this the one operation that does not preserve them. Every\n // ! other form key survives — removing the whole entry would wipe every form\n // ! on the origin.\n const clear = (): void => {\n removeFields({ storage: state.storage, formKey: resolved.formKey })\n state.bag = {}\n state.errors.clear()\n }\n\n return {\n key: schema.id,\n set,\n get,\n getAll,\n submit,\n validate,\n errors: () => freeze(state.errors),\n clear,\n }\n}\n"],"mappings":"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"}
@@ -0,0 +1,241 @@
1
+ import { EmbeddablesInstance } from "@embeddables/core";
2
+ //#region src/errors.d.ts
3
+ /**
4
+ * Typed error hierarchy. Every failure this SDK raises on its own behalf is an
5
+ * instance of one of these, so consumers branch on the type
6
+ * (`if (e instanceof SchemaError) …`) instead of string-matching messages.
7
+ * Catch `FormsError` to handle them all.
8
+ *
9
+ * An error thrown by a consumer's own custom validator is never wrapped in one
10
+ * of these — it propagates with its original type and stack.
11
+ */
12
+ /** Base class for every error the SDK throws. */
13
+ declare class FormsError extends Error {
14
+ constructor(message: string, options?: ErrorOptions);
15
+ }
16
+ /** The schema is malformed. */
17
+ declare class SchemaError extends FormsError {
18
+ constructor(message: string, options?: ErrorOptions);
19
+ }
20
+ /** A custom validator returned a thenable, or a shape that is not a message. */
21
+ declare class ValidatorError extends FormsError {
22
+ constructor(message: string, options?: ErrorOptions);
23
+ }
24
+ //#endregion
25
+ //#region ../shared-types/dist/analytics-instance.types.d.ts
26
+ /**
27
+ * Hono-free analytics client surface other SDKs accept without depending on
28
+ * `hono` or `@embeddables/analytics`. Precise ingest event types stay inferred
29
+ * from the Worker in analytics-sdk; this module is the structural instance, not
30
+ * the HTTP contract.
31
+ *
32
+ * `trackEvent` is a method (not a function property) so parameter checking
33
+ * stays bivariant: a precise analytics-sdk client remains assignable here, and
34
+ * callers without those types can still pass their payloads.
35
+ */
36
+ /** Loose event payload other SDKs pass to `trackEvent`. */
37
+ interface AnalyticsTrackEvent {
38
+ event_name: string;
39
+ [key: string]: unknown;
40
+ }
41
+ /** Body `trackEvent` resolves with — identity plus ingest outcome. */
42
+ interface AnalyticsTrackResult {
43
+ app_user_id: string;
44
+ accepted: number;
45
+ forwarded: boolean;
46
+ }
47
+ /**
48
+ * Structural stand-in for `ReturnType<typeof initAnalytics>`. Other SDKs type
49
+ * injected clients against this; analytics-sdk's `AnalyticsClient` must remain
50
+ * assignable to it.
51
+ */
52
+ interface AnalyticsInstance<TEvent = AnalyticsTrackEvent> {
53
+ trackEvent(input: TEvent | readonly TEvent[]): Promise<AnalyticsTrackResult>;
54
+ /** Live identity: the composed core instance's current user. */
55
+ getAppUserId(): string | null;
56
+ getProjectId(): string;
57
+ }
58
+ //#endregion
59
+ //#region ../shared-types/dist/json.types.d.ts
60
+ /**
61
+ * Recursive JSON value, compatible with JSONB column values and public
62
+ * portal entity payloads.
63
+ */
64
+ type JsonValue = string | number | boolean | null | JsonValue[] | {
65
+ [key: string]: JsonValue;
66
+ };
67
+ //#endregion
68
+ //#region ../shared-types/dist/analytics-ingest.types.d.ts
69
+ type FieldUpdatedType = 'text' | 'email' | 'number' | 'boolean' | 'select' | 'multiselect' | 'json';
70
+ /**
71
+ * Raw `field_value` accepted by ingest. Every forms-sdk `ValueOfFieldType` is a
72
+ * JSON value — scalar (`text`/`email`/`select` → string, `number` → number,
73
+ * `boolean` → boolean), `multiselect` → `string[]`, `json` → arbitrary JSON —
74
+ * so the contract collapses to `JsonValue`; the runtime ingest schema is what
75
+ * bounds each shape.
76
+ */
77
+ type FieldUpdatedValue = JsonValue;
78
+ type FunnelStepFields = {
79
+ is_funnel_step?: boolean;
80
+ funnel_step_label?: string;
81
+ };
82
+ type FieldUpdatedEvent = FunnelStepFields & {
83
+ event_name: 'field:updated';
84
+ /** Schema key of the updated field. */
85
+ field_key: string;
86
+ field_type: FieldUpdatedType;
87
+ field_value?: FieldUpdatedValue;
88
+ /** Field Registry identifier when the field is registry-backed. */
89
+ registry_field_id?: string;
90
+ /** Protocol question identifier when the field is protocol-backed. */
91
+ protocol_field_id?: string;
92
+ };
93
+ type DataUpdatedEntry = {
94
+ value: string;
95
+ label: string;
96
+ };
97
+ type DataUpdatedEvent = FunnelStepFields & {
98
+ event_name: 'data:updated';
99
+ data: Record<string, DataUpdatedEntry>;
100
+ };
101
+ type FormSubmittedEvent = FunnelStepFields & {
102
+ event_name: 'form:submitted';
103
+ form_key: string;
104
+ };
105
+ //#endregion
106
+ //#region src/config.d.ts
107
+ type FieldType = 'text' | 'email' | 'number' | 'boolean' | 'select' | 'multiselect' | 'json';
108
+ /** Runtime `type` literal → the TypeScript type of that field's value. */
109
+ interface ValueOfFieldType {
110
+ text: string;
111
+ email: string;
112
+ number: number;
113
+ boolean: boolean;
114
+ select: string;
115
+ multiselect: string[];
116
+ json: JsonValue;
117
+ }
118
+ type FieldValidator<TValue extends JsonValue = JsonValue> = (args: {
119
+ value: TValue;
120
+ values: Readonly<Record<string, JsonValue>>;
121
+ }) => string | readonly string[] | null;
122
+ interface FieldValidationsFor<TType extends FieldType> {
123
+ readonly required?: boolean;
124
+ readonly minLength?: number;
125
+ readonly maxLength?: number;
126
+ readonly min?: number;
127
+ readonly max?: number;
128
+ /** ECMAScript source without delimiters. */
129
+ readonly pattern?: string;
130
+ /** Flags for `pattern`. `g` and `y` are stripped before compilation. */
131
+ readonly patternFlags?: string;
132
+ readonly oneOf?: readonly JsonValue[];
133
+ /** `value` is bound to this field's declared `type`. */
134
+ readonly custom?: FieldValidator<ValueOfFieldType[TType]>;
135
+ }
136
+ interface FieldConfigFor<TType extends FieldType> {
137
+ readonly key: string;
138
+ readonly label: string;
139
+ readonly type: TType;
140
+ readonly validations?: FieldValidationsFor<TType>;
141
+ readonly registryFieldId?: string;
142
+ readonly protocolFieldId?: string;
143
+ }
144
+ type FieldConfig = { [T in FieldType]: FieldConfigFor<T>; }[FieldType];
145
+ type FieldValidations = { [T in FieldType]: FieldValidationsFor<T>; }[FieldType];
146
+ interface FormSchema {
147
+ readonly id: string;
148
+ readonly name?: string;
149
+ readonly fields: readonly FieldConfig[];
150
+ }
151
+ type FieldsOf<TSchema extends FormSchema> = TSchema['fields'][number];
152
+ type FormFieldKey<TSchema extends FormSchema> = FieldsOf<TSchema>['key'];
153
+ type FormValues<TSchema extends FormSchema> = { [F in FieldsOf<TSchema> as F['key']]: ValueOfFieldType[F['type']]; };
154
+ //#endregion
155
+ //#region src/analytics.d.ts
156
+ type FormsAnalyticsEvent = DataUpdatedEvent | FieldUpdatedEvent | FormSubmittedEvent;
157
+ //#endregion
158
+ //#region src/storage.d.ts
159
+ /** Every form on the origin shares this one entry, indexed by form key. */
160
+ declare const FORM_DATA_KEY = "EMBEDDABLES-FORM-DATA";
161
+ interface FormsStorage {
162
+ getItem(key: string): string | null;
163
+ setItem(key: string, value: string): void;
164
+ removeItem(key: string): void;
165
+ }
166
+ //#endregion
167
+ //#region src/form.d.ts
168
+ /** Per-key validation errors. An empty object means the operation succeeded. */
169
+ type FieldErrors<TSchema extends FormSchema> = Readonly<Partial<Record<FormFieldKey<TSchema>, readonly string[]>>>;
170
+ interface SetResult<TSchema extends FormSchema> {
171
+ ok: boolean;
172
+ errors: FieldErrors<TSchema>;
173
+ /** Set when an `analyticsInstance` was configured and `trackEvent` rejected. Never thrown. */
174
+ trackError?: unknown;
175
+ }
176
+ interface SubmitResult<TSchema extends FormSchema> {
177
+ ok: boolean;
178
+ errors: FieldErrors<TSchema>;
179
+ values: Partial<FormValues<TSchema>>;
180
+ trackError?: unknown;
181
+ }
182
+ interface ValidateResult<TSchema extends FormSchema> {
183
+ ok: boolean;
184
+ errors: FieldErrors<TSchema>;
185
+ values: Partial<FormValues<TSchema>>;
186
+ }
187
+ interface FormInstance<TSchema extends FormSchema> {
188
+ readonly key: TSchema['id'];
189
+ /**
190
+ * Applies every key atomically: all or nothing, one write, one event.
191
+ * Validates and persists synchronously; the returned promise never rejects.
192
+ * Throws synchronously only if a custom validator throws or returns an
193
+ * illegal shape.
194
+ */
195
+ set(patch: Partial<FormValues<TSchema>>): Promise<SetResult<TSchema>>;
196
+ /** Typed by the field's declared `type`. Nothing verifies the stored value against it. */
197
+ get<K extends FormFieldKey<TSchema>>(key: K): FormValues<TSchema>[K] | undefined;
198
+ getAll(): Partial<FormValues<TSchema>>;
199
+ /**
200
+ * Validates every declared field, then emits one `form:submitted` event.
201
+ *
202
+ * Not idempotent: every call emits another event. The caller owns dedupe —
203
+ * disable the button, or guard on a route transition.
204
+ *
205
+ * Same synchronous-throw and never-reject contract as `set`.
206
+ */
207
+ submit(): Promise<SubmitResult<TSchema>>;
208
+ /**
209
+ * Runs validation without writing to storage or emitting analytics.
210
+ *
211
+ * With no argument, validates every declared field against stored values and
212
+ * replaces `errors()` wholesale. With a patch, validates only those keys
213
+ * against a merged snapshot and updates errors for those keys only.
214
+ *
215
+ * Same synchronous-throw and never-reject contract as `set` / `submit`.
216
+ */
217
+ validate(patch?: Partial<FormValues<TSchema>>): Promise<ValidateResult<TSchema>>;
218
+ errors(): FieldErrors<TSchema>;
219
+ clear(): void;
220
+ }
221
+ interface InitFormsOptions {
222
+ core: EmbeddablesInstance;
223
+ analyticsInstance?: AnalyticsInstance;
224
+ /** Overrides the default production backend URL for R2 persistence writes. */
225
+ baseUrl?: string;
226
+ }
227
+ interface FormsClient {
228
+ initForm<const TSchema extends FormSchema>(options: {
229
+ schema: TSchema;
230
+ customValidations?: { readonly [K in FormFieldKey<TSchema>]?: FieldValidator; };
231
+ }): FormInstance<TSchema>;
232
+ }
233
+ /**
234
+ * Validates the core instance once, then returns a per-form `initForm`. Public
235
+ * API — the Miro signature. Consumers pass only `core` and, optionally, an
236
+ * analytics client.
237
+ */
238
+ declare function initForms(options: InitFormsOptions): FormsClient;
239
+ //#endregion
240
+ export { type AnalyticsInstance, type AnalyticsTrackEvent, type AnalyticsTrackResult, type DataUpdatedEvent, FORM_DATA_KEY, type FieldConfig, type FieldErrors, type FieldType, type FieldUpdatedEvent, type FieldUpdatedType, type FieldValidations, type FieldValidator, type FormFieldKey, type FormInstance, type FormSchema, type FormSubmittedEvent, type FormValues, type FormsAnalyticsEvent, type FormsClient, FormsError, type FormsStorage, type InitFormsOptions, type JsonValue, SchemaError, type SetResult, type SubmitResult, type ValidateResult, ValidatorError, initForms };
241
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","names":[],"sources":["../src/errors.ts","../../shared-types/dist/analytics-instance.types.d.ts","../../shared-types/dist/json.types.d.ts","../../shared-types/dist/analytics-ingest.types.d.ts","../src/config.ts","../src/analytics.ts","../src/storage.ts","../src/form.ts"],"mappings":";;;;;;;;;;;;cAWa,mBAAmB;EAClB,YAAA,iBAAiB,UAAU;;;cAO5B,oBAAoB;EACnB,YAAA,iBAAiB,UAAU;;;cAO5B,uBAAuB;EACtB,YAAA,iBAAiB,UAAU;;;;;;;;;;;;;;;UCjBxB;EACb;GACC;;;UAGY;EACb;EACA;EACA;;;;;;;UAOa,kBAAkB,SAAS;EACxC,WAAW,OAAO,kBAAkB,WAAW,QAAQ;;EAEvD;EACA;;;;;;;;KC1BQ,+CAA+C;GACtD,cAAc;;;;KCCP;;;;;;;;KAQA,oBAAoB;KACpB;EACR;EACA;;KAsBQ,oBAAoB;EAC5B;;EAEA;EACA,YAAY;EACZ,cAAc;;EAEd;;EAEA;;KAEQ;EACR;EACA;;KAEQ,mBAAmB;EAC3B;EACA,MAAM,eAAe;;KAMb,qBAAqB;EAC7B;EACA;;;;KC9DQ;;UAMF;EACR;EACA;EACA;EACA;EACA;EACA;EACA,MAAM;;KAGI,eAAe,eAAe,YAAY,cAAc;EAClE,OAAO;EACP,QAAQ,SAAS,eAAe;;UAUxB,oBAAoB,cAAc;WACjC;WACA;WACA;WACA;WACA;;WAEA;;WAEA;WACA,iBAAiB;;WAEjB,SAAS,eAAe,iBAAiB;;UAG1C,eAAe,cAAc;WAC5B;WACA;WACA,MAAM;WACN,cAAc,oBAAoB;WAGlC;WACA;;KAUC,iBAAiB,KAAK,YAAY,eAAe,MAAK;KAEtD,sBAAsB,KAAK,YAAY,oBAAoB,MAAK;UAE3D;WACN;WACA;WACA,iBAAiB;;KAGvB,SAAS,gBAAgB,cAAc;KAEhC,aAAa,gBAAgB,cAAc,SAAS;KAEpD,WAAW,gBAAgB,iBACpC,KAAK,SAAS,YAAY,WAAW,iBAAiB;;;KClD7C,sBAAsB,mBAAmB,oBAAoB;;;;cCzB5D;UAEI;EACf,QAAQ;EACR,QAAQ,aAAa;EACrB,WAAW;;;;;KCeD,YAAY,gBAAgB,cAAc,SACpD,QAAQ,OAAO,aAAa;UAGb,UAAU,gBAAgB;EACzC;EACA,QAAQ,YAAY;;EAEpB;;UAGe,aAAa,gBAAgB;EAC5C;EACA,QAAQ,YAAY;EACpB,QAAQ,QAAQ,WAAW;EAC3B;;UAGe,eAAe,gBAAgB;EAC9C;EACA,QAAQ,YAAY;EACpB,QAAQ,QAAQ,WAAW;;UAGZ,aAAa,gBAAgB;WACnC,KAAK;;;;;;;EAOd,IAAI,OAAO,QAAQ,WAAW,YAAY,QAAQ,UAAU;;EAE5D,IAAI,UAAU,aAAa,UAAU,KAAK,IAAI,WAAW,SAAS;EAClE,UAAU,QAAQ,WAAW;;;;;;;;;EAS7B,UAAU,QAAQ,aAAa;;;;;;;;;;EAU/B,SAAS,QAAQ,QAAQ,WAAW,YAAY,QAAQ,eAAe;EACvE,UAAU,YAAY;EACtB;;UAgDe;EACf,MAAM;EACN,oBAAoB;;EAEpB;;UAGe;EACf,eAAe,gBAAgB,YAAY;IACzC,QAAQ;IACR,gCAAgC,KAAK,aAAa,YAAY;MAC5D,aAAa;;;;;;;iBAQH,UAAU,SAAS,mBAAmB"}