@aglyn/aglyn 1.0.0-beta.194 → 1.0.0-beta.196

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.
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/dataset-models.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { validateCustomFieldValue } from '../plugin-manager/custom-fields'\nimport { type DatasetFieldEntry, humanizeDatasetFieldId } from './datasets'\n\n/**\n * Dataset models (AGL-177): the runtime promotion of the type-level\n * blueprint in `libs/shared/data/types/src/lib/dod.ts` (kept as the\n * referenced design doc — this module is the single runtime source of\n * truth). A model lives on the dataset doc\n * (`orgs/{orgId}/datasets/{id}.model`) and drives the typed editor, import\n * and site-restore validation, and the console and `/v1` record writes\n * through the shared `validateDocument`/`coerceDocumentValues` pair so they\n * can't disagree. Form submissions and automation steps write through\n * `buildDatasetRecordValues` instead, which stores each value as text and\n * validates nothing.\n *\n * Storage conventions (Firestore-safe): timestamps as epoch millis\n * numbers, coordinates as `{ latitude, longitude }`, `sorted` as arrays,\n * `map` as plain objects, references as target-document id strings.\n */\n\n/** dod.ts `FT.Tag` vocabulary plus `reference` (AGL-180 builds on it). */\nexport type DatasetFieldType =\n | 'bool'\n | 'bytes'\n | 'timestamp'\n | 'float'\n | 'int32'\n | 'int64'\n | 'nil'\n | 'text'\n | 'coordinates'\n | 'map'\n | 'sorted'\n | 'reference'\n\nexport const DATASET_FIELD_TYPES: DatasetFieldType[] = [\n 'text',\n 'bool',\n 'int32',\n 'int64',\n 'float',\n 'timestamp',\n 'coordinates',\n 'map',\n 'sorted',\n 'bytes',\n 'nil',\n 'reference',\n]\n\n/** Display names, mirroring dod.ts `lbl`. */\nexport const DATASET_FIELD_TYPE_LABELS: Record<DatasetFieldType, string> = {\n text: 'Text',\n bool: 'Boolean',\n int32: 'Integer',\n int64: 'Big integer',\n float: 'Number',\n timestamp: 'Date & time',\n coordinates: 'Coordinates',\n map: 'Map',\n sorted: 'List',\n bytes: 'Bytes',\n nil: 'Null',\n reference: 'Reference',\n}\n\n/**\n * Plain-JSON validation vocabulary (the dod.ts `Eval` shape, extended\n * with min/max and options, serialized flat instead of enum-keyed).\n */\nexport interface DatasetFieldValidation {\n required?: boolean\n /** Source of a RegExp applied to text values. */\n regex?: string\n /** Numbers/timestamps: value bound. Text: length bound. */\n min?: number\n max?: number\n /** Enum: value must be one of these (text fields). */\n options?: string[]\n}\n\nexport interface DatasetFieldDefinition {\n /**\n * Human-facing display label only. The stable reference id is the KEY in\n * `DatasetModel.fields` (and `order`), NOT this name — bindings resolve\n * `{{item.<fieldId>}}` against that key. The default id is derived from\n * this name once at creation but is user-overridable (AGL-578); renaming\n * the label afterwards never changes the id.\n */\n name: string\n type: DatasetFieldType\n /**\n * Plugin-declared custom type riding this base type (AGL-434) — see\n * plugin-manager/custom-fields. Unknown names degrade to the base type.\n */\n customType?: string\n description?: string\n required?: boolean\n /** Default applied by editors when creating documents; never coerced. */\n default?: unknown\n validation?: DatasetFieldValidation\n /**\n * Reference fields (AGL-180): target collection + display field id.\n * `multiple` stores a `sorted` array of FKeys (small-cardinality\n * many-to-many per the dod.ts guidance); `onDelete` is the referenced-\n * document delete policy (default `setNull` — never cascade in v2).\n */\n reference?: {\n datasetId: string\n displayFieldId?: string\n multiple?: boolean\n onDelete?: 'restrict' | 'setNull'\n }\n}\n\nexport interface DatasetModel {\n fields: Record<string, DatasetFieldDefinition>\n /** Field ids in display order. */\n order: string[]\n}\n\n/**\n * Migration shim (v1 → v2): datasets created before models carry flat\n * `fields: string[]` — derive a model where every column is an optional\n * text field whose id is the column name, so the editor and AGL-103\n * bindings keep working on unmigrated docs during rollout.\n */\nexport function deriveModelFromFields(fields: string[]): DatasetModel {\n const model: DatasetModel = { fields: {}, order: [] }\n for (const name of fields) {\n // Raw snake_case ids read as titles in table headers and pickers;\n // the id stays the stable key (AGL-558).\n model.fields[name] = { name: humanizeDatasetFieldId(name), type: 'text' }\n model.order.push(name)\n }\n return model\n}\n\n/**\n * Model from quick-creator entries (AGL-558): stable slug ids with the\n * human display names preserved — \"Roast preference\" → id\n * `roast_preference`, name \"Roast preference\".\n */\nexport function modelFromFieldEntries(\n entries: readonly DatasetFieldEntry[],\n): DatasetModel {\n const model: DatasetModel = { fields: {}, order: [] }\n for (const entry of entries) {\n model.fields[entry.id] = { name: entry.name, type: 'text' }\n model.order.push(entry.id)\n }\n return model\n}\n\n/** The dataset's model, deriving one from v1 `fields` when absent. */\nexport function effectiveDatasetModel(dataset: {\n model?: DatasetModel\n fields?: string[]\n}): DatasetModel {\n if (dataset.model?.fields && dataset.model.order?.length) {\n return dataset.model\n }\n return deriveModelFromFields(dataset.fields ?? [])\n}\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value)\n\n/**\n * Validates a document's values against a model, returning fieldId →\n * human-readable error (empty object = valid). Values are expected in\n * storage form (see the module doc); use `coerceDocumentValues` first\n * when starting from user input strings.\n */\nexport function validateDocument(\n model: DatasetModel,\n values: Record<string, unknown>,\n): Record<string, string> {\n const errors: Record<string, string> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field) continue\n const value = values[fieldId]\n const required = field.required || field.validation?.required\n if (value == null || value === '') {\n if (required) errors[fieldId] = `${field.name} is required`\n continue\n }\n const rules = field.validation ?? {}\n switch (field.type) {\n case 'text': {\n if (typeof value !== 'string') {\n errors[fieldId] = `${field.name} must be text`\n break\n }\n if (rules.min != null && value.length < rules.min) {\n errors[fieldId] = `${field.name} must be at least ${rules.min} characters`\n } else if (rules.max != null && value.length > rules.max) {\n errors[fieldId] = `${field.name} must be at most ${rules.max} characters`\n } else if (rules.regex) {\n try {\n if (!new RegExp(rules.regex).test(value)) {\n errors[fieldId] = `${field.name} has an invalid format`\n }\n } catch {\n // Broken pattern in the model never blocks writes.\n }\n }\n if (\n !errors[fieldId] &&\n rules.options?.length &&\n !rules.options.includes(value)\n ) {\n errors[fieldId] = `${field.name} must be one of: ${rules.options.join(', ')}`\n }\n break\n }\n case 'bool':\n if (typeof value !== 'boolean') {\n errors[fieldId] = `${field.name} must be true or false`\n }\n break\n case 'int32':\n case 'int64':\n if (!isFiniteNumber(value) || !Number.isInteger(value)) {\n errors[fieldId] = `${field.name} must be a whole number`\n break\n }\n if (rules.min != null && value < rules.min) {\n errors[fieldId] = `${field.name} must be ≥ ${rules.min}`\n } else if (rules.max != null && value > rules.max) {\n errors[fieldId] = `${field.name} must be ≤ ${rules.max}`\n }\n break\n case 'float':\n case 'timestamp':\n if (!isFiniteNumber(value)) {\n errors[fieldId] =\n field.type === 'timestamp'\n ? `${field.name} must be a date`\n : `${field.name} must be a number`\n break\n }\n if (rules.min != null && value < rules.min) {\n errors[fieldId] = `${field.name} must be ≥ ${rules.min}`\n } else if (rules.max != null && value > rules.max) {\n errors[fieldId] = `${field.name} must be ≤ ${rules.max}`\n }\n break\n case 'coordinates': {\n const coordinates = value as { latitude?: unknown; longitude?: unknown }\n if (\n !isFiniteNumber(coordinates?.latitude) ||\n !isFiniteNumber(coordinates?.longitude) ||\n Math.abs(coordinates.latitude) > 90 ||\n Math.abs(coordinates.longitude) > 180\n ) {\n errors[fieldId] = `${field.name} must be valid coordinates`\n }\n break\n }\n case 'sorted':\n if (!Array.isArray(value)) {\n errors[fieldId] = `${field.name} must be a list`\n }\n break\n case 'map':\n if (typeof value !== 'object' || Array.isArray(value)) {\n errors[fieldId] = `${field.name} must be a map`\n }\n break\n case 'reference':\n if (field.reference?.multiple) {\n if (\n !Array.isArray(value) ||\n value.some((entry) => typeof entry !== 'string' || !entry)\n ) {\n errors[fieldId] = `${field.name} must reference documents`\n }\n } else if (typeof value !== 'string' || !value) {\n errors[fieldId] = `${field.name} must reference a document`\n }\n break\n case 'bytes':\n case 'nil':\n break\n }\n }\n // Custom field types (AGL-434): plugin validators run after the base\n // checks, only on fields that passed them.\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field?.customType || errors[fieldId]) continue\n const customError = validateCustomFieldValue(\n field.customType,\n values[fieldId],\n )\n if (customError) errors[fieldId] = `${field.name}: ${customError}`\n }\n return errors\n}\n\n/** Storage value → grid display string (AGL-179). */\nexport function formatDatasetValue(\n field: DatasetFieldDefinition,\n value: unknown,\n): string {\n if (value == null || value === '') return ''\n switch (field.type) {\n case 'bool':\n return value === true ? '✓' : value === false ? '—' : String(value)\n case 'timestamp':\n return isFiniteNumber(value)\n ? new Date(value).toISOString().slice(0, 16).replace('T', ' ')\n : String(value)\n case 'coordinates': {\n const coordinates = value as { latitude?: number; longitude?: number }\n return isFiniteNumber(coordinates?.latitude) &&\n isFiniteNumber(coordinates?.longitude)\n ? `${coordinates.latitude}, ${coordinates.longitude}`\n : String(value)\n }\n case 'sorted':\n return Array.isArray(value) ? value.join(', ') : String(value)\n case 'map':\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n default:\n return String(value)\n }\n}\n\n/**\n * Storage value → form-input string (AGL-179): the inverse of\n * `coerceDocumentValues` for populating type-appropriate inputs\n * (timestamps as `datetime-local` values, coordinates as \"lat, lon\").\n */\nexport function datasetValueToInput(\n field: DatasetFieldDefinition,\n value: unknown,\n): string {\n if (value == null) return ''\n if (field.type === 'timestamp' && isFiniteNumber(value)) {\n return new Date(value).toISOString().slice(0, 16)\n }\n if (field.type === 'bool') {\n return value === true ? 'true' : value === false ? 'false' : String(value)\n }\n if (field.type === 'coordinates' || field.type === 'sorted') {\n return formatDatasetValue(field, value)\n }\n if (field.type === 'map') return formatDatasetValue(field, value)\n return String(value)\n}\n\n/**\n * Coerces user-input strings (form fields, CSV cells) into storage form\n * per the field type. Unparseable input is passed through untouched so\n * `validateDocument` reports it instead of silently mangling it.\n */\nexport function coerceDocumentValues(\n model: DatasetModel,\n input: Record<string, unknown>,\n): Record<string, unknown> {\n const values: Record<string, unknown> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n const raw = input[fieldId]\n if (!field || raw == null || raw === '') continue\n if (typeof raw !== 'string') {\n values[fieldId] = raw\n continue\n }\n switch (field.type) {\n case 'bool':\n values[fieldId] =\n raw === 'true' ? true : raw === 'false' ? false : raw\n break\n case 'int32':\n case 'int64': {\n const parsed = Number(raw)\n values[fieldId] = Number.isInteger(parsed) ? parsed : raw\n break\n }\n case 'float': {\n const parsed = Number(raw)\n values[fieldId] = Number.isFinite(parsed) ? parsed : raw\n break\n }\n case 'timestamp': {\n const millis = Date.parse(raw)\n values[fieldId] = Number.isFinite(millis) ? millis : raw\n break\n }\n case 'coordinates': {\n const [latitude, longitude] = raw.split(',').map((part) => Number(part.trim()))\n values[fieldId] =\n Number.isFinite(latitude) && Number.isFinite(longitude)\n ? { latitude, longitude }\n : raw\n break\n }\n case 'sorted':\n values[fieldId] = raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n break\n case 'map':\n try {\n values[fieldId] = JSON.parse(raw)\n } catch {\n values[fieldId] = raw\n }\n break\n case 'reference':\n values[fieldId] = field.reference?.multiple\n ? raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n : raw\n break\n default:\n values[fieldId] = raw\n }\n }\n return values\n}\n\n/**\n * Every reference id a record holds, flattened out of its `reference` fields\n * into one de-duplicated list.\n *\n * A reference field stores either a single target id or — when\n * `reference.multiple` is set — an array of them, and a model may declare\n * several. Both shapes flatten into the same list because the question asked\n * of it is never \"which field\", it is \"does this record still point at that\n * document\".\n *\n * Fields are read from `order` UNIONED with the keys of `fields`. Every other\n * pass over a model walks `order` alone, which is right for anything the user\n * sees — but a reference declared without a display slot still holds a real\n * FKey, and an integrity index that skipped it would under-report.\n */\nexport function datasetReferencedIds(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n): string[] {\n const ids = new Set<string>()\n const fieldIds = new Set([\n ...(model.order ?? []),\n ...Object.keys(model.fields ?? {}),\n ])\n for (const fieldId of fieldIds) {\n if (model.fields?.[fieldId]?.type !== 'reference') continue\n const stored = values?.[fieldId]\n for (const entry of Array.isArray(stored) ? stored : [stored]) {\n const id = typeof entry === 'string' ? entry.trim() : ''\n if (id) ids.add(id)\n }\n }\n return [...ids]\n}\n\n/**\n * The integrity index a record write carries, so referential integrity can be\n * decided by a QUERY rather than by the rows a listener happened to fetch.\n *\n * Deleting a record has to answer \"is anything still pointing at this?\", and\n * `restrict` refuses the delete on a yes while `setNull` strips the FKey. That\n * question cannot be asked where the answer is stored: dataset fields are\n * user-defined, so `records.values` carries a deliberate index exemption in\n * `cloud/firebase-firestore.indexes.json` — auto-indexing an unbounded map\n * blows Firestore's per-document index-entry limit — and\n * `where('values.<fieldId>', '==', id)` is therefore FAILED_PRECONDITION.\n * Reading a page of records and filtering them in the browser answers only for\n * the rows in that page, which is a browse window standing in for a\n * correctness check: a reference held outside it reads as no reference at all,\n * the delete proceeds, and `restrict` silently fails to restrict.\n *\n * `referencedIds` is that same reference, denormalized to a top-level array\n * Firestore will index, so one `array-contains` reaches every record.\n *\n * ⚠️ OMITTED when a record references nothing, rather than written as `[]`.\n * `isNotEmpty` is served as `!= null` and an empty array is not null, so a\n * record stamped `[]` answers \"holds a reference\" for a dataset that holds\n * none.\n *\n * ⚠️ Spread this at EVERY write that sets a record's `values`. A write that\n * sets values without it leaves the index describing the PREVIOUS values, and\n * a stale integrity index is the exact failure it exists to prevent — with the\n * UI reporting the record as safe to delete. On a merging write use\n * `datasetIntegrityUpdate` instead: omission leaves a stale array in place\n * where clearing the last reference has to remove the field.\n */\nexport function datasetIntegrityFields(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n): { referencedIds?: string[] } {\n const referencedIds = datasetReferencedIds(model, values)\n return referencedIds.length ? { referencedIds } : {}\n}\n\n/**\n * `datasetIntegrityFields` for a MERGING write (`update`, `set` with `merge`\n * or `mergeFields`), where leaving the field out preserves what is stored\n * rather than clearing it.\n *\n * A record whose last reference is cleared has to have the field REMOVED, or\n * it goes on answering the `array-contains` for a document it no longer points\n * at — a `restrict` that refuses a delete nothing is holding. `clear` is the\n * caller's delete sentinel: `deleteField()` in the web SDK,\n * `FieldValue.delete()` in the Admin SDK. It is passed in rather than imported\n * because this module is shared by both and must stay SDK-free.\n */\nexport function datasetIntegrityUpdate<TClear>(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n clear: TClear,\n): { referencedIds: string[] | TClear } {\n const referencedIds = datasetReferencedIds(model, values)\n return { referencedIds: referencedIds.length ? referencedIds : clear }\n}\n"],"names":["validateCustomFieldValue","humanizeDatasetFieldId","DATASET_FIELD_TYPES","DATASET_FIELD_TYPE_LABELS","text","bool","int32","int64","float","timestamp","coordinates","map","sorted","bytes","nil","reference","deriveModelFromFields","fields","model","order","name","type","push","modelFromFieldEntries","entries","entry","id","effectiveDatasetModel","dataset","length","isFiniteNumber","value","Number","isFinite","validateDocument","values","errors","fieldId","field","required","validation","rules","min","max","regex","RegExp","test","options","includes","join","isInteger","latitude","longitude","Math","abs","Array","isArray","multiple","some","customType","customError","formatDatasetValue","String","Date","toISOString","slice","replace","JSON","stringify","datasetValueToInput","coerceDocumentValues","input","raw","parsed","millis","parse","split","part","trim","filter","Boolean","datasetReferencedIds","ids","Set","fieldIds","Object","keys","stored","add","datasetIntegrityFields","referencedIds","datasetIntegrityUpdate","clear"],"mappings":"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"}
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/dataset-models.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n\nimport { validateCustomFieldValue } from '../plugin-manager/custom-fields'\nimport { type DatasetFieldEntry, humanizeDatasetFieldId } from './datasets'\n\n/**\n * Dataset models (AGL-177): the runtime promotion of the type-level\n * blueprint in `libs/shared/data/types/src/lib/dod.ts` (kept as the\n * referenced design doc — this module is the single runtime source of\n * truth). A model lives on the dataset doc\n * (`orgs/{orgId}/datasets/{id}.model`) and drives the typed editor, import\n * and site-restore validation, and the console and `/v1` record writes\n * through the shared `validateDocument`/`coerceDocumentValues` pair so they\n * can't disagree. Form submissions and automation steps write through\n * `buildDatasetRecordValues` instead, which stores each value as text and\n * validates nothing.\n *\n * Storage conventions (Firestore-safe): timestamps as epoch millis\n * numbers, coordinates as `{ latitude, longitude }`, `sorted` as arrays,\n * `map` as plain objects, references as target-document id strings.\n */\n\n/** dod.ts `FT.Tag` vocabulary plus `reference` (AGL-180 builds on it). */\nexport type DatasetFieldType =\n | 'bool'\n | 'bytes'\n | 'timestamp'\n | 'float'\n | 'int32'\n | 'int64'\n | 'nil'\n | 'text'\n | 'coordinates'\n | 'map'\n | 'sorted'\n | 'reference'\n\nexport const DATASET_FIELD_TYPES: DatasetFieldType[] = [\n 'text',\n 'bool',\n 'int32',\n 'int64',\n 'float',\n 'timestamp',\n 'coordinates',\n 'map',\n 'sorted',\n 'bytes',\n 'nil',\n 'reference',\n]\n\n/** Display names, mirroring dod.ts `lbl`. */\nexport const DATASET_FIELD_TYPE_LABELS: Record<DatasetFieldType, string> = {\n text: 'Text',\n bool: 'Boolean',\n int32: 'Integer',\n int64: 'Big integer',\n float: 'Number',\n timestamp: 'Date & time',\n coordinates: 'Coordinates',\n map: 'Map',\n sorted: 'List',\n bytes: 'Bytes',\n nil: 'Null',\n reference: 'Reference',\n}\n\n/**\n * Plain-JSON validation vocabulary (the dod.ts `Eval` shape, extended\n * with min/max and options, serialized flat instead of enum-keyed).\n */\nexport interface DatasetFieldValidation {\n required?: boolean\n /** Source of a RegExp applied to text values. */\n regex?: string\n /** Numbers/timestamps: value bound. Text: length bound. */\n min?: number\n max?: number\n /** Enum: value must be one of these (text fields). */\n options?: string[]\n}\n\nexport interface DatasetFieldDefinition {\n /**\n * Human-facing display label only. The stable reference id is the KEY in\n * `DatasetModel.fields` (and `order`), NOT this name — bindings resolve\n * `{{item.<fieldId>}}` against that key. The default id is derived from\n * this name once at creation but is user-overridable (AGL-578); renaming\n * the label afterwards never changes the id.\n */\n name: string\n type: DatasetFieldType\n /**\n * Plugin-declared custom type riding this base type (AGL-434) — see\n * plugin-manager/custom-fields. Unknown names degrade to the base type.\n */\n customType?: string\n description?: string\n required?: boolean\n /** Default applied by editors when creating documents; never coerced. */\n default?: unknown\n validation?: DatasetFieldValidation\n /**\n * Reference fields (AGL-180): target collection + display field id.\n * `multiple` stores a `sorted` array of FKeys (small-cardinality\n * many-to-many per the dod.ts guidance); `onDelete` is the referenced-\n * document delete policy (default `setNull` — never cascade in v2).\n */\n reference?: {\n datasetId: string\n displayFieldId?: string\n multiple?: boolean\n onDelete?: 'restrict' | 'setNull'\n }\n}\n\nexport interface DatasetModel {\n fields: Record<string, DatasetFieldDefinition>\n /** Field ids in display order. */\n order: string[]\n}\n\n/**\n * Migration shim (v1 → v2): datasets created before models carry flat\n * `fields: string[]` — derive a model where every column is an optional\n * text field whose id is the column name, so the editor and AGL-103\n * bindings keep working on unmigrated docs during rollout.\n */\nexport function deriveModelFromFields(fields: string[]): DatasetModel {\n const model: DatasetModel = { fields: {}, order: [] }\n for (const name of fields) {\n // Raw snake_case ids read as titles in table headers and pickers;\n // the id stays the stable key (AGL-558).\n model.fields[name] = { name: humanizeDatasetFieldId(name), type: 'text' }\n model.order.push(name)\n }\n return model\n}\n\n/**\n * Model from quick-creator entries (AGL-558): stable slug ids with the\n * human display names preserved — \"Roast preference\" → id\n * `roast_preference`, name \"Roast preference\".\n */\nexport function modelFromFieldEntries(\n entries: readonly DatasetFieldEntry[],\n): DatasetModel {\n const model: DatasetModel = { fields: {}, order: [] }\n for (const entry of entries) {\n model.fields[entry.id] = { name: entry.name, type: 'text' }\n model.order.push(entry.id)\n }\n return model\n}\n\n/** The dataset's model, deriving one from v1 `fields` when absent. */\nexport function effectiveDatasetModel(dataset: {\n model?: DatasetModel\n fields?: string[]\n}): DatasetModel {\n if (dataset.model?.fields && dataset.model.order?.length) {\n return dataset.model\n }\n return deriveModelFromFields(dataset.fields ?? [])\n}\n\nconst isFiniteNumber = (value: unknown): value is number =>\n typeof value === 'number' && Number.isFinite(value)\n\n/**\n * Validates a document's values against a model, returning fieldId →\n * human-readable error (empty object = valid). Values are expected in\n * storage form (see the module doc); use `coerceDocumentValues` first\n * when starting from user input strings.\n */\nexport function validateDocument(\n model: DatasetModel,\n values: Record<string, unknown>,\n): Record<string, string> {\n const errors: Record<string, string> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field) continue\n const value = values[fieldId]\n const required = field.required || field.validation?.required\n if (value == null || value === '') {\n if (required) errors[fieldId] = `${field.name} is required`\n continue\n }\n const rules = field.validation ?? {}\n switch (field.type) {\n case 'text': {\n if (typeof value !== 'string') {\n errors[fieldId] = `${field.name} must be text`\n break\n }\n if (rules.min != null && value.length < rules.min) {\n errors[fieldId] = `${field.name} must be at least ${rules.min} characters`\n } else if (rules.max != null && value.length > rules.max) {\n errors[fieldId] = `${field.name} must be at most ${rules.max} characters`\n } else if (rules.regex) {\n try {\n if (!new RegExp(rules.regex).test(value)) {\n errors[fieldId] = `${field.name} has an invalid format`\n }\n } catch {\n // Broken pattern in the model never blocks writes.\n }\n }\n if (\n !errors[fieldId] &&\n rules.options?.length &&\n !rules.options.includes(value)\n ) {\n errors[fieldId] = `${field.name} must be one of: ${rules.options.join(', ')}`\n }\n break\n }\n case 'bool':\n if (typeof value !== 'boolean') {\n errors[fieldId] = `${field.name} must be true or false`\n }\n break\n case 'int32':\n case 'int64':\n if (!isFiniteNumber(value) || !Number.isInteger(value)) {\n errors[fieldId] = `${field.name} must be a whole number`\n break\n }\n if (rules.min != null && value < rules.min) {\n errors[fieldId] = `${field.name} must be ≥ ${rules.min}`\n } else if (rules.max != null && value > rules.max) {\n errors[fieldId] = `${field.name} must be ≤ ${rules.max}`\n }\n break\n case 'float':\n case 'timestamp':\n if (!isFiniteNumber(value)) {\n errors[fieldId] =\n field.type === 'timestamp'\n ? `${field.name} must be a date`\n : `${field.name} must be a number`\n break\n }\n if (rules.min != null && value < rules.min) {\n errors[fieldId] = `${field.name} must be ≥ ${rules.min}`\n } else if (rules.max != null && value > rules.max) {\n errors[fieldId] = `${field.name} must be ≤ ${rules.max}`\n }\n break\n case 'coordinates': {\n const coordinates = value as { latitude?: unknown; longitude?: unknown }\n if (\n !isFiniteNumber(coordinates?.latitude) ||\n !isFiniteNumber(coordinates?.longitude) ||\n Math.abs(coordinates.latitude) > 90 ||\n Math.abs(coordinates.longitude) > 180\n ) {\n errors[fieldId] = `${field.name} must be valid coordinates`\n }\n break\n }\n case 'sorted':\n if (!Array.isArray(value)) {\n errors[fieldId] = `${field.name} must be a list`\n }\n break\n case 'map':\n if (typeof value !== 'object' || Array.isArray(value)) {\n errors[fieldId] = `${field.name} must be a map`\n }\n break\n case 'reference':\n if (field.reference?.multiple) {\n if (\n !Array.isArray(value) ||\n value.some((entry) => typeof entry !== 'string' || !entry)\n ) {\n errors[fieldId] = `${field.name} must reference documents`\n }\n } else if (typeof value !== 'string' || !value) {\n errors[fieldId] = `${field.name} must reference a document`\n }\n break\n case 'bytes':\n case 'nil':\n break\n }\n }\n // Custom field types (AGL-434): plugin validators run after the base\n // checks, only on fields that passed them.\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n if (!field?.customType || errors[fieldId]) continue\n const customError = validateCustomFieldValue(\n field.customType,\n values[fieldId],\n )\n if (customError) errors[fieldId] = `${field.name}: ${customError}`\n }\n return errors\n}\n\n/** Storage value → grid display string (AGL-179). */\nexport function formatDatasetValue(\n field: DatasetFieldDefinition,\n value: unknown,\n): string {\n if (value == null || value === '') return ''\n switch (field.type) {\n case 'bool':\n return value === true ? '✓' : value === false ? '—' : String(value)\n case 'timestamp':\n return isFiniteNumber(value)\n ? new Date(value).toISOString().slice(0, 16).replace('T', ' ')\n : String(value)\n case 'coordinates': {\n const coordinates = value as { latitude?: number; longitude?: number }\n return isFiniteNumber(coordinates?.latitude) &&\n isFiniteNumber(coordinates?.longitude)\n ? `${coordinates.latitude}, ${coordinates.longitude}`\n : String(value)\n }\n case 'sorted':\n return Array.isArray(value) ? value.join(', ') : String(value)\n case 'map':\n try {\n return JSON.stringify(value)\n } catch {\n return String(value)\n }\n default:\n return String(value)\n }\n}\n\n/**\n * Storage value → form-input string (AGL-179): the inverse of\n * `coerceDocumentValues` for populating type-appropriate inputs\n * (timestamps as `datetime-local` values, coordinates as \"lat, lon\").\n */\nexport function datasetValueToInput(\n field: DatasetFieldDefinition,\n value: unknown,\n): string {\n if (value == null) return ''\n if (field.type === 'timestamp' && isFiniteNumber(value)) {\n return new Date(value).toISOString().slice(0, 16)\n }\n if (field.type === 'bool') {\n return value === true ? 'true' : value === false ? 'false' : String(value)\n }\n if (field.type === 'coordinates' || field.type === 'sorted') {\n return formatDatasetValue(field, value)\n }\n if (field.type === 'map') return formatDatasetValue(field, value)\n return String(value)\n}\n\n/**\n * Coerces user-input strings (form fields, CSV cells) into storage form\n * per the field type. Unparseable input is passed through untouched so\n * `validateDocument` reports it instead of silently mangling it.\n */\nexport function coerceDocumentValues(\n model: DatasetModel,\n input: Record<string, unknown>,\n): Record<string, unknown> {\n const values: Record<string, unknown> = {}\n for (const fieldId of model.order) {\n const field = model.fields[fieldId]\n const raw = input[fieldId]\n if (!field || raw == null || raw === '') continue\n if (typeof raw !== 'string') {\n values[fieldId] = raw\n continue\n }\n switch (field.type) {\n case 'bool':\n values[fieldId] =\n raw === 'true' ? true : raw === 'false' ? false : raw\n break\n case 'int32':\n case 'int64': {\n const parsed = Number(raw)\n values[fieldId] = Number.isInteger(parsed) ? parsed : raw\n break\n }\n case 'float': {\n const parsed = Number(raw)\n values[fieldId] = Number.isFinite(parsed) ? parsed : raw\n break\n }\n case 'timestamp': {\n const millis = Date.parse(raw)\n values[fieldId] = Number.isFinite(millis) ? millis : raw\n break\n }\n case 'coordinates': {\n const [latitude, longitude] = raw.split(',').map((part) => Number(part.trim()))\n values[fieldId] =\n Number.isFinite(latitude) && Number.isFinite(longitude)\n ? { latitude, longitude }\n : raw\n break\n }\n case 'sorted':\n values[fieldId] = raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n break\n case 'map':\n try {\n values[fieldId] = JSON.parse(raw)\n } catch {\n values[fieldId] = raw\n }\n break\n case 'reference':\n values[fieldId] = field.reference?.multiple\n ? raw\n .split(',')\n .map((part) => part.trim())\n .filter(Boolean)\n : raw\n break\n default:\n values[fieldId] = raw\n }\n }\n return values\n}\n\n/**\n * Every reference id a record holds, flattened out of its `reference` fields\n * into one de-duplicated list.\n *\n * A reference field stores either a single target id or — when\n * `reference.multiple` is set — an array of them, and a model may declare\n * several. Both shapes flatten into the same list because the question asked\n * of it is never \"which field\", it is \"does this record still point at that\n * document\".\n *\n * Fields are read from `order` UNIONED with the keys of `fields`. Every other\n * pass over a model walks `order` alone, which is right for anything the user\n * sees — but a reference declared without a display slot still holds a real\n * FKey, and an integrity index that skipped it would under-report.\n */\nexport function datasetReferencedIds(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n): string[] {\n const ids = new Set<string>()\n const fieldIds = new Set([\n ...(model.order ?? []),\n ...Object.keys(model.fields ?? {}),\n ])\n for (const fieldId of fieldIds) {\n if (model.fields?.[fieldId]?.type !== 'reference') continue\n const stored = values?.[fieldId]\n for (const entry of Array.isArray(stored) ? stored : [stored]) {\n const id = typeof entry === 'string' ? entry.trim() : ''\n if (id) ids.add(id)\n }\n }\n return [...ids]\n}\n\n/**\n * The integrity index a record write carries, so referential integrity can be\n * decided by a QUERY rather than by the rows a listener happened to fetch.\n *\n * Deleting a record has to answer \"is anything still pointing at this?\", and\n * `restrict` refuses the delete on a yes while `setNull` strips the FKey. That\n * question cannot be asked where the answer is stored: dataset fields are\n * user-defined, so `records.values` carries a deliberate index exemption in\n * `cloud/firebase-firestore.indexes.json` — auto-indexing an unbounded map\n * blows Firestore's per-document index-entry limit — and\n * `where('values.<fieldId>', '==', id)` is therefore FAILED_PRECONDITION.\n * Reading a page of records and filtering them in the browser answers only for\n * the rows in that page, which is a browse window standing in for a\n * correctness check: a reference held outside it reads as no reference at all,\n * the delete proceeds, and `restrict` silently fails to restrict.\n *\n * `referencedIds` is that same reference, denormalized to a top-level array\n * Firestore will index, so one `array-contains` reaches every record.\n *\n * ⚠️ OMITTED when a record references nothing, rather than written as `[]`.\n * `isNotEmpty` is served as `!= null` and an empty array is not null, so a\n * record stamped `[]` answers \"holds a reference\" for a dataset that holds\n * none.\n *\n * ⚠️ Spread this at EVERY write that sets a record's `values`. A write that\n * sets values without it leaves the index describing the PREVIOUS values, and\n * a stale integrity index is the exact failure it exists to prevent — with the\n * UI reporting the record as safe to delete. On a merging write use\n * `datasetIntegrityUpdate` instead: omission leaves a stale array in place\n * where clearing the last reference has to remove the field.\n */\nexport function datasetIntegrityFields(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n): { referencedIds?: string[]; filterKeys?: string[] } {\n const referencedIds = datasetReferencedIds(model, values)\n // The records table's filter tokens (`datasetFilterKeys`) travel on the\n // same writes for the same reason: a record written without them is\n // invisible to every filter the query serves. Omitted when empty, like\n // `referencedIds`.\n const filterKeys = datasetFilterKeys(model, values)\n return {\n ...(referencedIds.length ? { referencedIds } : {}),\n ...(filterKeys.length ? { filterKeys } : {}),\n }\n}\n\n/**\n * `datasetIntegrityFields` for a MERGING write (`update`, `set` with `merge`\n * or `mergeFields`), where leaving the field out preserves what is stored\n * rather than clearing it.\n *\n * A record whose last reference is cleared has to have the field REMOVED, or\n * it goes on answering the `array-contains` for a document it no longer points\n * at — a `restrict` that refuses a delete nothing is holding. `clear` is the\n * caller's delete sentinel: `deleteField()` in the web SDK,\n * `FieldValue.delete()` in the Admin SDK. It is passed in rather than imported\n * because this module is shared by both and must stay SDK-free. The filter\n * tokens are cleared the same way, so a record emptied of every filterable\n * value stops answering the filters its old values did.\n */\nexport function datasetIntegrityUpdate<TClear>(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n clear: TClear,\n): { referencedIds: string[] | TClear; filterKeys: string[] | TClear } {\n const referencedIds = datasetReferencedIds(model, values)\n const filterKeys = datasetFilterKeys(model, values)\n return {\n referencedIds: referencedIds.length ? referencedIds : clear,\n filterKeys: filterKeys.length ? filterKeys : clear,\n }\n}\n\n/**\n * A dataset record's FILTER TOKENS: every question the records table can ask\n * of a record, flattened into one array of strings Firestore indexes on its\n * own.\n *\n * ## Why a token array, and not the values\n *\n * A record's fields live under `values`, a user-defined, unbounded map that\n * the index configuration exempts from indexing — auto-indexing it can exceed\n * Firestore's per-document index-entry limit — so `where('values.<field>', …)`\n * is refused. A composite index per dataset would need an admin call per\n * dataset, runs into the project's composite-index cap, and is deleted by the\n * next `firestore:indexes` deploy of a file that does not list it.\n *\n * `filterKeys` needs none of that. Firestore's AUTOMATIC single-field index\n * serves `where('filterKeys', 'array-contains', token)` with\n * `orderBy(documentId())`, so one clause, or one search word, reaches every\n * record of any dataset on any project, with no index deploy.\n *\n * ## The token grammar\n *\n * `f:<fieldId>=<value>` a field equals a value. Enum (a text field with\n * `validation.options`) values are kept exactly;\n * plain text is lower-cased, trimmed and clipped to\n * {@link DATASET_FILTER_VALUE_MAX} characters;\n * booleans are `true`/`false`; numbers are\n * `String(number)`; a `sorted` list contributes one\n * token per member.\n * `f:<fieldId>^<prefix>` a word of a plain text field starts with this.\n * `s:<prefix>` a word of ANY text value (enums and list members\n * included) starts with this — the quick search.\n *\n * Timestamps, references, maps, bytes, coordinates and nil fields carry no\n * field tokens: a timestamp is asked in ranges, which one token cannot serve,\n * and the rest are not asked about by value.\n *\n * The array is sorted, de-duplicated and capped at\n * {@link DATASET_FILTER_KEYS_MAX}. Past the cap, the `=` tokens are kept\n * first, then the per-field word prefixes, then the search prefixes, so a\n * very long record loses search reach before it loses exact matches.\n */\nexport const DATASET_FILTER_KEYS_MAX = 500\n\n/** Plain text values are clipped to this many characters in an `=` token. */\nexport const DATASET_FILTER_VALUE_MAX = 64\n/** Word prefixes run from 1 to this many characters. */\nexport const DATASET_FILTER_PREFIX_MAX = 12\n/** Only the first this-many words of a value contribute prefixes. */\nexport const DATASET_FILTER_WORDS_MAX = 40\n\n/** One clause of the records table's filter: `{ field, op, value }`. */\nexport interface DatasetFilterClause {\n field: string\n op: string\n value: string\n}\n\n/**\n * The words of a text value: split on anything that is not a letter or a\n * digit, lower-cased, at most {@link DATASET_FILTER_WORDS_MAX} of them.\n */\nexport function datasetFilterWords(text: string): string[] {\n return String(text)\n .toLowerCase()\n .split(/[^\\p{L}\\p{N}]+/u)\n .filter(Boolean)\n .slice(0, DATASET_FILTER_WORDS_MAX)\n}\n\n/** A word's prefixes, 1 to {@link DATASET_FILTER_PREFIX_MAX} characters. */\nfunction prefixes(word: string): string[] {\n const chars = Array.from(word).slice(0, DATASET_FILTER_PREFIX_MAX)\n return chars.map((_char, at) => chars.slice(0, at + 1).join(''))\n}\n\n/** A word clipped the way its stored prefixes are. */\nfunction clipWord(word: string): string {\n return Array.from(word).slice(0, DATASET_FILTER_PREFIX_MAX).join('')\n}\n\nconst isEnum = (field: DatasetFieldDefinition): boolean =>\n field.type === 'text' && (field.validation?.options?.length ?? 0) > 0\n\nconst isNumeric = (field: DatasetFieldDefinition): boolean =>\n field.type === 'int32' || field.type === 'int64' || field.type === 'float'\n\n/**\n * A stored value as text, or null. Numbers are accepted because a form or an\n * automation stores every value as text and an import may do the reverse.\n */\nfunction asText(value: unknown): string | null {\n if (typeof value === 'string') return value\n if (typeof value === 'number' && Number.isFinite(value)) return String(value)\n return null\n}\n\n/** Plain text as its `=` token's value: lower-cased, trimmed, clipped. */\nfunction textKey(value: string): string {\n return Array.from(value.trim().toLowerCase())\n .slice(0, DATASET_FILTER_VALUE_MAX)\n .join('')\n}\n\n/** A stored number (or its text form) as its `=` token's value. */\nfunction numberKey(value: unknown): string | null {\n const number =\n typeof value === 'number'\n ? value\n : typeof value === 'string' && value.trim() !== ''\n ? Number(value)\n : Number.NaN\n return Number.isFinite(number) ? String(number) : null\n}\n\n/** A stored boolean (or its text form) as its `=` token's value. */\nfunction boolKey(value: unknown): string | null {\n if (typeof value === 'boolean') return String(value)\n if (value === 'true' || value === 'false') return value\n return null\n}\n\n/** Every field a model declares, in display order and then the rest. */\nfunction modelFieldIds(model: DatasetModel): string[] {\n return [...new Set([...(model.order ?? []), ...Object.keys(model.fields ?? {})])]\n}\n\n/** The tokens described in {@link DATASET_FILTER_KEYS_MAX}'s comment. */\nexport function datasetFilterKeys(\n model: DatasetModel,\n values: Record<string, unknown> | undefined,\n): string[] {\n const exact: string[] = []\n const fieldWords: string[] = []\n const search: string[] = []\n const searchable = (text: string) => {\n for (const word of datasetFilterWords(text)) {\n for (const prefix of prefixes(word)) search.push(`s:${prefix}`)\n }\n }\n for (const fieldId of modelFieldIds(model)) {\n const field = model.fields?.[fieldId]\n const stored = values?.[fieldId]\n if (!field || stored == null) continue\n if (field.type === 'text') {\n const text = asText(stored)\n if (text == null || !text.trim()) continue\n if (isEnum(field)) {\n exact.push(`f:${fieldId}=${text}`)\n } else {\n exact.push(`f:${fieldId}=${textKey(text)}`)\n for (const word of datasetFilterWords(text)) {\n for (const prefix of prefixes(word)) {\n fieldWords.push(`f:${fieldId}^${prefix}`)\n }\n }\n }\n searchable(text)\n } else if (field.type === 'bool') {\n const key = boolKey(stored)\n if (key) exact.push(`f:${fieldId}=${key}`)\n } else if (isNumeric(field)) {\n const key = numberKey(stored)\n if (key) exact.push(`f:${fieldId}=${key}`)\n } else if (field.type === 'sorted') {\n for (const member of Array.isArray(stored) ? stored : [stored]) {\n const text = asText(member)?.trim()\n if (!text) continue\n exact.push(`f:${fieldId}=${text}`)\n searchable(text)\n }\n }\n }\n const kept = [...new Set([...exact, ...fieldWords, ...search])].slice(\n 0,\n DATASET_FILTER_KEYS_MAX,\n )\n return kept.sort()\n}\n\n/**\n * The one token that serves a filter clause over every record, or null when\n * no token can: the clause is then matched over a window of records instead.\n *\n * - enum, boolean, number and list `equals` → the `=` token of the value;\n * - plain text `equals` → the lower-cased `=` token;\n * - plain text `contains` → the `^` token of the value's FIRST word, so a\n * served `contains` is a word-prefix match, not a mid-string one;\n * - everything else — ranges, dates, `isEmpty`, `isAnyOf`, negations — null.\n *\n * `clause.field` is the field id. The operator names are the grid's: a\n * select's `equals`, a number's `=`, a boolean's `is`, a list's `contains`.\n */\nexport function datasetFilterToken(\n model: DatasetModel,\n clause: DatasetFilterClause,\n): string | null {\n const field = model.fields?.[clause.field]\n if (!field) return null\n const { op } = clause\n const value = String(clause.value ?? '')\n if (!value.trim()) return null\n const equals = op === 'equals' || op === '=' || op === 'is'\n if (field.type === 'text') {\n if (isEnum(field)) return equals ? `f:${clause.field}=${value}` : null\n if (equals) return `f:${clause.field}=${textKey(value)}`\n if (op === 'contains') {\n const [first] = datasetFilterWords(value)\n return first ? `f:${clause.field}^${clipWord(first)}` : null\n }\n return null\n }\n if (field.type === 'bool') {\n const key = boolKey(value.trim())\n return equals && key ? `f:${clause.field}=${key}` : null\n }\n if (isNumeric(field)) {\n const key = numberKey(value)\n return equals && key ? `f:${clause.field}=${key}` : null\n }\n if (field.type === 'sorted') {\n return equals || op === 'contains' ? `f:${clause.field}=${value.trim()}` : null\n }\n return null\n}\n\n/**\n * Every token a record must hold to answer a clause, or null when the clause\n * is not token-served. The same as {@link datasetFilterToken} except for a\n * plain text `contains` of several words, which needs each word's prefix —\n * the query can serve only one of them, and the rest are matched over the\n * rows it returns, by these same tokens, so both answers agree.\n */\nexport function datasetFilterTokens(\n model: DatasetModel,\n clause: DatasetFilterClause,\n): string[] | null {\n const first = datasetFilterToken(model, clause)\n if (!first) return null\n const field = model.fields?.[clause.field]\n if (field?.type === 'text' && !isEnum(field) && clause.op === 'contains') {\n return datasetFilterWords(clause.value).map(\n (word) => `f:${clause.field}^${clipWord(word)}`,\n )\n }\n return [first]\n}\n\n/**\n * The quick-search token for one typed word, or null for a word with no\n * letters or digits. A word with punctuation inside it is asked by its first\n * run — split the search text with {@link datasetFilterWords} to ask for\n * every run.\n */\nexport function datasetSearchToken(word: string): string | null {\n const [first] = datasetFilterWords(word)\n return first ? `s:${clipWord(first)}` : null\n}\n"],"names":["validateCustomFieldValue","humanizeDatasetFieldId","DATASET_FIELD_TYPES","DATASET_FIELD_TYPE_LABELS","text","bool","int32","int64","float","timestamp","coordinates","map","sorted","bytes","nil","reference","deriveModelFromFields","fields","model","order","name","type","push","modelFromFieldEntries","entries","entry","id","effectiveDatasetModel","dataset","length","isFiniteNumber","value","Number","isFinite","validateDocument","values","errors","fieldId","field","required","validation","rules","min","max","regex","RegExp","test","options","includes","join","isInteger","latitude","longitude","Math","abs","Array","isArray","multiple","some","customType","customError","formatDatasetValue","String","Date","toISOString","slice","replace","JSON","stringify","datasetValueToInput","coerceDocumentValues","input","raw","parsed","millis","parse","split","part","trim","filter","Boolean","datasetReferencedIds","ids","Set","fieldIds","Object","keys","stored","add","datasetIntegrityFields","referencedIds","filterKeys","datasetFilterKeys","datasetIntegrityUpdate","clear","DATASET_FILTER_KEYS_MAX","DATASET_FILTER_VALUE_MAX","DATASET_FILTER_PREFIX_MAX","DATASET_FILTER_WORDS_MAX","datasetFilterWords","toLowerCase","prefixes","word","chars","from","_char","at","clipWord","isEnum","isNumeric","asText","textKey","numberKey","number","NaN","boolKey","modelFieldIds","exact","fieldWords","search","searchable","prefix","key","member","kept","sort","datasetFilterToken","clause","op","equals","first","datasetFilterTokens","datasetSearchToken"],"mappings":"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"}
@@ -306,7 +306,7 @@ export declare const PLUGIN_DOCS_ANCHORS: {
306
306
  readonly crmSettings: readonly ["#companies", "#create-companies-from-work-email-domains", "#default-owner", "#assignment-rules", "#round-robin", "#email-templates", "#email-capture", "#your-sending-addresses", "#recipes", "#related"];
307
307
  readonly crmTasks: readonly ["#the-tasks-page", "#the-calendar-view", "#snoozing-a-task", "#selecting-exporting-and-acting-on-many", "#import-from-csv", "#creating-a-task", "#assigning-a-task-to-someone-else", "#completing-and-reopening", "#organization-tasks", "#tasks-on-a-contact-company-or-deal", "#reminders", "#turning-reminders-off", "#next-activity", "#the-daily-digest", "#turning-it-off", "#the-dashboard-card", "#who-can-do-what", "#related"];
308
308
  readonly crmViews: readonly ["#the-views-control", "#a-view-is-a-link", "#filters", "#filters-on-the-contacts-list", "#filters-on-the-other-lists", "#columns-and-sort", "#segments-and-views", "#who-sees-what", "#related"];
309
- readonly datasets: readonly ["#model-builder", "#typed-documents", "#relations", "#query-layer", "#repeatable-components", "#who-a-dataset-is-shared-with", "#import--export", "#related"];
309
+ readonly datasets: readonly ["#model-builder", "#typed-documents", "#filter-records", "#relations", "#query-layer", "#repeatable-components", "#who-a-dataset-is-shared-with", "#import--export", "#related"];
310
310
  readonly deals: readonly ["#pipelines", "#stages", "#the-board-and-the-table", "#import-from-csv", "#creating-a-deal", "#line-items", "#moving-winning-and-losing", "#a-won-deal-makes-its-contact-a-customer", "#a-deals-page", "#files", "#related"];
311
311
  readonly designedEmails: readonly ["#create-a-template", "#find-a-template", "#duplicate-a-template", "#styling-email-blocks", "#merge-tokens", "#send-it", "#the-plain-text-version", "#start-from-a-brief-instead"];
312
312
  readonly emailCampaigns: readonly ["#send-a-campaign", "#campaigns-belong-to-the-organization", "#organization-emails-page", "#campaigns-group-emails", "#filter-the-lists", "#what-belongs-to-a-campaign", "#who-the-email-comes-from", "#sending-domains", "#account-email-always-sends", "#marketing-needs-a-domain", "#two-ways-to-get-a-domain", "#a-domain-we-set-up-is-a-request", "#domain-states", "#senders", "#send-a-test", "#preview-the-email", "#monthly-send-cap", "#personalize-with-merge-tags", "#recipient-count", "#who-a-campaign-is-allowed-to-reach", "#schedule-a-send", "#duplicate-an-email", "#email-lists", "#manual-lists", "#list-members", "#add-to-a-list", "#import-a-list", "#remove-from-a-list", "#lists-built-from-a-rule", "#experiments", "#experiments-across-sites", "#opens--clicks", "#the-campaign-report", "#per-contact-engagement", "#which-links-were-clicked", "#revenue-from-a-campaign", "#conversions", "#compliance", "#list-unsubscribe", "#topics", "#preference-page", "#frequency-opt-down", "#double-opt-in", "#consent-group-confirmation", "#marketing-mail", "#frequency-cap", "#suppressions", "#add-a-suppression", "#platform-suppressions", "#related"];
@@ -324,7 +324,7 @@ export declare const PLUGIN_DOCS_ANCHORS: {
324
324
  readonly publisherHandbook: readonly ["#before-your-first-publish", "#the-publisher-agreement", "#where-to-publish-from", "#what-installing-each-type-does", "#rules-an-email-starter-has-to-meet", "#publishing-a-version", "#before-you-publish", "#review-what-happens-after-you-publish", "#the-two-badges-and-what-each-one-promises", "#asking-to-be-verified", "#testing-a-version-before-it-is-approved", "#watching-your-own-submission", "#disabled-versions", "#private-plugins", "#authoring-your-listing", "#what-your-listing-can-say-about-aglyn", "#versioning--updates", "#shipping-a-new-version", "#how-installs-work-the-buyer-side", "#getting-paid", "#low-prices-and-processing"];
325
325
  readonly redirects: readonly ["#manage-redirects", "#sending-visitors-to-another-site", "#metrics", "#match-modes-v2", "#related"];
326
326
  readonly sandboxSecurity: readonly ["#a-separate-origin", "#per-manifest-network-policy", "#when-you-cant-declare-the-origin", "#pinned-immutable-artifacts", "#what-this-means-when-you-build", "#related"];
327
- readonly sequences: readonly ["#what-it-is-for", "#sent-from-your-own-mailbox", "#where-it-lives", "#connect-a-mailbox", "#send-as", "#daily-cap", "#mailbox-status", "#auto-pause", "#mailbox-actions", "#link-domains", "#compliance-settings", "#allowed-countries", "#do-not-contact-domains", "#sequences", "#build-a-sequence", "#sequence-status", "#enroll", "#cold-contacts", "#enrollments", "#sending", "#what-stops-a-sequence", "#unsubscribe", "#related"];
327
+ readonly sequences: readonly ["#what-it-is-for", "#sent-from-your-own-mailbox", "#where-it-lives", "#connect-a-mailbox", "#send-as", "#daily-cap", "#mailbox-status", "#auto-pause", "#mailbox-actions", "#link-domains", "#compliance-settings", "#allowed-countries", "#do-not-contact-domains", "#sequences", "#build-a-sequence", "#sequence-status", "#enroll", "#cold-contacts", "#enrollments", "#curate", "#sending", "#what-stops-a-sequence", "#unsubscribe", "#related"];
328
328
  readonly webhooks: readonly ["#outbound-webhooks", "#inbound-webhooks", "#tips", "#related"];
329
329
  };
330
330
  type PluginAnchorMap = typeof PLUGIN_DOCS_ANCHORS;
@@ -682,6 +682,7 @@ export const PLUGIN_DOCS_ANCHORS = {
682
682
  datasets: [
683
683
  '#model-builder',
684
684
  '#typed-documents',
685
+ '#filter-records',
685
686
  '#relations',
686
687
  '#query-layer',
687
688
  '#repeatable-components',
@@ -950,6 +951,7 @@ export const PLUGIN_DOCS_ANCHORS = {
950
951
  '#enroll',
951
952
  '#cold-contacts',
952
953
  '#enrollments',
954
+ '#curate',
953
955
  '#sending',
954
956
  '#what-stops-a-sequence',
955
957
  '#unsubscribe',
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/docs-help.generated.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// GENERATED FILE — do not edit. Regenerate with:\n// node tools/scripts/generate-docs-help.mjs\n// Source of truth: apps/docs/docs frontmatter + headings (AGL-602).\n\n// The first-party plugin consoles live in `libs/plugins/*` and cannot import\n// the console's constants, so they carry their own generated subset of the\n// docs help registry — the topics their cards actually link to, and no others.\n\nexport interface PluginDocsTopic {\n /** Docs-site path, e.g. `/commerce-and-bookings/commerce/overview`. */\n path: string\n /** Docs page title. */\n title: string\n /** Verbatim docs frontmatter description — the tooltip excerpt. */\n excerpt: string\n}\n\nexport const PLUGIN_DOCS = {\n abuseReports: {\n path: '/staff-console/abuse-reports',\n title: 'Abuse reports',\n excerpt: 'The public abuse-report queue — where outside reports land, how to triage by severity, which lever answers which report, and the CSAM and DMCA paths that are not takedown buttons.',\n },\n actionsBuilder: {\n path: '/marketing-and-automation/workflows-and-actions/actions-builder',\n title: 'Actions builder',\n excerpt: 'Map a single event to a single action without building a full workflow.',\n },\n aglynAssist: {\n path: '/getting-started/aglyn-assist',\n title: 'Aglyn Assist',\n excerpt: 'Ask the built-in AI helper how to do anything in Aglyn — it answers from these docs and links you straight to the right page.',\n },\n aiAutomations: {\n path: '/ai/automations-with-ai',\n title: 'Explain automations with AI',\n excerpt: 'Aglyn AI can explain an automation you already have and tell you why one of its runs failed. Drafting an automation from a description is not available yet.',\n },\n aiCrm: {\n path: '/ai/crm-by-ai',\n title: 'The AI CRM built into Aglyn',\n excerpt: 'An AI CRM for small business: a short summary and a suggested next step on a contact, company, deal or lead, a one-to-one email drafted into the composer, and an import\\'s columns matched to fields.',\n },\n aiExperiments: {\n path: '/ai/ab-tests-with-ai',\n title: 'A/B tests by AI: write variants, read the result',\n excerpt: 'Have Aglyn AI write two to four variants for a screen, section or email experiment, and put a finished test into plain language — with the verdict decided from the counts before the model is asked anything.',\n },\n aiMonitoring: {\n path: '/staff-console/ai-monitoring',\n title: 'AI monitoring',\n excerpt: 'How staff watch one organization\\'s AI usage — the add-on, credit pool, overage, refusals, jobs, tokens and cache hit rate, top spenders and margin — and where those figures appear across the staff console.',\n },\n aiProducts: {\n path: '/ai/products-with-ai',\n title: 'Product copy and catalogs with AI',\n excerpt: 'An AI product description generator for your catalog: write copy for one product or a whole import, propose a first catalog, and propose categories and discounts — all as proposals you review.',\n },\n aiSeo: {\n path: '/building-sites/seo/seo-by-ai',\n title: 'AI SEO for your website',\n excerpt: 'AI SEO for websites, on the pages you already have: have AI write a page or product\\'s search listing, audit every published page with a proposed fix for each finding, and draft your structured data and /llms.txt.',\n },\n aiThemes: {\n path: '/ai/theme-assist',\n title: 'Change your site\\'s theme with AI',\n excerpt: 'Describe a change to your site\\'s theme and get a proposal for the theme editor\\'s own controls, previewed before and after, that you save in the editor. Rolling out.',\n },\n assistSignals: {\n path: '/staff-console/assist-signals',\n title: 'Assist Signal',\n excerpt: 'The docs-gap and cost board behind Assist — how the ranking is ordered, why ungrounded questions are counted separately, and what the cache-read rate says about margin.',\n },\n billing: {\n path: '/workspace-and-billing/billing-and-plans/overview',\n title: 'Billing & Plans',\n excerpt: 'How Aglyn\\'s tiers, entitlements, quotas, usage meters, and seat add-ons work.',\n },\n bindings: {\n path: '/building-sites/bindings/overview',\n title: 'Bindings, Variables & Functions',\n excerpt: 'Live values in your content — typed variables, no-code functions, and rename-safe id tokens.',\n },\n bookings: {\n path: '/commerce-and-bookings/bookings/overview',\n title: 'Bookings & Scheduling',\n excerpt: 'Offer services with availability, let visitors book, take payment, and send reminders.',\n },\n buildAWorkflow: {\n path: '/marketing-and-automation/workflows-and-actions/build-a-workflow',\n title: 'Build a workflow',\n excerpt: 'Create a multi-step workflow that runs when a site event fires.',\n },\n catalog: {\n path: '/commerce-and-bookings/commerce/catalog',\n title: 'Product catalog',\n excerpt: 'Products with options and variants, categories, tags, and manual or smart collections.',\n },\n commerce: {\n path: '/commerce-and-bookings/commerce/overview',\n title: 'Commerce',\n excerpt: 'Sell physical, digital, and service products with a full catalog, orders pipeline, shipping, taxes, and your own Stripe account.',\n },\n commerceEndToEnd: {\n path: '/guides/commerce-end-to-end',\n title: 'Commerce end to end',\n excerpt: 'Create products with billing modes, design the storefront with Commerce blocks, take Stripe checkout for one-time and subscription sales, and run orders from the console.',\n },\n companies: {\n path: '/content-and-data/crm/companies',\n title: 'Companies',\n excerpt: 'Group your contacts under the businesses they belong to — one record per company, with its domain, owner, address and the people who work there.',\n },\n consoleTour: {\n path: '/getting-started/console-tour',\n title: 'The console tour',\n excerpt: 'Where things live in the Aglyn console app bar and navigation.',\n },\n contactActivities: {\n path: '/content-and-data/crm/activities',\n title: 'Activities & the timeline',\n excerpt: 'Log calls, emails, meetings and notes against a contact, a company, a deal or a lead, email one person from their record, and read it all in one timeline beside everything captured and every campaign sent.',\n },\n contactFields: {\n path: '/content-and-data/crm/custom-fields',\n title: 'Custom fields',\n excerpt: 'Define your own properties on contacts, companies, deals and leads — text, number, date, choice, checkbox or link — show them on every record and its list, and save form answers straight into a contact\\'s.',\n },\n contactRecord: {\n path: '/content-and-data/crm/contact-record',\n title: 'The contact record',\n excerpt: 'Add a contact by hand, keep a profile on them — phone, company, title, address, owner and lifecycle stage — open their own page in the CRM, and merge two records that turn out to be one person.',\n },\n contacts: {\n path: '/content-and-data/crm/overview',\n title: 'CRM',\n excerpt: 'One place for the people who interact with your sites — contacts captured from forms, members, orders and bookings, with leads, companies, a deals pipeline, tasks, a timeline, reports and custom fields.',\n },\n crmEmailTemplates: {\n path: '/content-and-data/crm/email-templates',\n title: 'Email templates',\n excerpt: 'Keep the letters your team sends from a record — templates that fill in the subject and the message, snippets that drop in a paragraph, and merge fields that fill in the person\\'s name, their company, the deal and you.',\n },\n crmLeads: {\n path: '/content-and-data/crm/leads',\n title: 'Leads',\n excerpt: 'Work the people your site has captured — a status, an owner and notes on every lead — and convert one into a contact, a company and a deal.',\n },\n crmReports: {\n path: '/content-and-data/crm/reports',\n title: 'Reports',\n excerpt: 'New contacts, where they came from and which sources convert, the lead funnel, the open pipeline and its forecast, won and lost, who logged what, and the task load — counted on the server, every table exportable as CSV.',\n },\n crmSettings: {\n path: '/content-and-data/crm/settings',\n title: 'CRM settings',\n excerpt: 'What the CRM does on its own for every site — whether a company is created from a contact\\'s work email domain, who a new contact is assigned to, the address that files replies on a record, and each site\\'s recipes.',\n },\n crmTasks: {\n path: '/content-and-data/crm/tasks',\n title: 'Tasks & follow-ups',\n excerpt: 'Calls, emails, meetings and to-dos with a due date, an assignee and a link to the record they are for — overdue and today read off the clock, a snooze, a reminder at its own time, and a morning digest.',\n },\n crmViews: {\n path: '/content-and-data/crm/views',\n title: 'Saved views',\n excerpt: 'Keep a CRM list\\'s filters, columns and sort under a name, open it from the views menu or a link, share it with the team, and use a contacts view as an email audience.',\n },\n datasets: {\n path: '/content-and-data/datasets/overview',\n title: 'Datasets & Dynamic Content',\n excerpt: 'Model structured content with typed fields and relations, then bind it into repeatable components.',\n },\n deals: {\n path: '/content-and-data/crm/deals',\n title: 'Deals pipeline',\n excerpt: 'Every open deal by stage — with an amount, an owner and an expected close — as a board you drag across or a table you page through, and the won and lost history behind it.',\n },\n designedEmails: {\n path: '/marketing-and-automation/email-campaigns/designed-emails',\n title: 'Designed emails',\n excerpt: 'Build campaign emails in the besigner with email-safe blocks and merge tokens — no separate editor.',\n },\n emailCampaigns: {\n path: '/marketing-and-automation/email-campaigns/overview',\n title: 'Email Campaigns',\n excerpt: 'Campaigns to audiences built from your contacts. Campaign email starts at Pro and needs a sending domain of the site\\'s own; receipts and account email send on every plan.',\n },\n events: {\n path: '/content-and-data/events/overview',\n title: 'Events Calendar',\n excerpt: 'Keep a schedule of events in the console and publish the ones you choose to any screen, with search-engine event markup.',\n },\n forms: {\n path: '/content-and-data/forms/overview',\n title: 'Forms & Lead Capture',\n excerpt: 'Add forms to your site, collect submissions in an inbox, and write them into datasets.',\n },\n installYourFirstPlugin: {\n path: '/guides/install-your-first-plugin',\n title: 'Install your first marketplace item',\n excerpt: 'A click-by-click walkthrough of the Marketplace — find something, choose which sites get it, install it, and turn it off again.',\n },\n inviteTeammates: {\n path: '/workspace-and-billing/teams-and-roles/invite-teammates',\n title: 'Invite teammates',\n excerpt: 'Add people to your site and understand how team members act within your organization.',\n },\n manifestAndEnvs: {\n path: '/developers/plugins/reference/manifest-and-envs',\n title: 'Manifests, trust lifecycle & environment',\n excerpt: 'The plugin manifest schema, the marketplace listing/version documents, the trust state machine, and every PLUGIN_* environment variable.',\n },\n marketingOverlays: {\n path: '/marketing-and-automation/marketing-overlays/overview',\n title: 'Marketing Overlays',\n excerpt: 'Site-wide announcement bars and promotional popups with triggers, scheduling, and email capture.',\n },\n membersOnly: {\n path: '/workspace-and-billing/teams-and-roles/members-only',\n title: 'Members-only areas',\n excerpt: 'Let visitors sign up as members and gate screens so only members can view them.',\n },\n orgAutomations: {\n path: '/marketing-and-automation/workflows-and-actions/org-automations',\n title: 'Org automations',\n excerpt: 'Write an automation once for the whole organization and run it on the sites you choose, with a pause on each site.',\n },\n plugins: {\n path: '/developers/plugins/overview',\n title: 'Plugins & Marketplace',\n excerpt: 'Extend Aglyn with sandboxed plugins — install from the marketplace, configure them, and publish your own.',\n },\n pos: {\n path: '/commerce-and-bookings/commerce/pos-and-reservations',\n title: 'POS & reservations',\n excerpt: 'Sell in person from the console register and take date-range reservations with deposits.',\n },\n publishAPlugin: {\n path: '/developers/plugins/publish-a-plugin',\n title: 'Publish a plugin',\n excerpt: 'Ship your own plugin to the marketplace with version pinning.',\n },\n publisherHandbook: {\n path: '/developers/plugins/publishing/publisher-handbook',\n title: 'Publisher handbook',\n excerpt: 'Publishing to the Aglyn marketplace — from profile setup through listing authoring, review, updates, and getting paid.',\n },\n redirects: {\n path: '/building-sites/redirects/overview',\n title: 'Redirects',\n excerpt: 'Manage URL redirects with validation, loop detection, and hit metrics.',\n },\n sandboxSecurity: {\n path: '/developers/plugins/reference/sandbox-security',\n title: 'Sandbox security model',\n excerpt: 'How sandboxed marketplace plugins are isolated — separate origin, per-manifest CSP, pinned artifacts — and what that means when you write one.',\n },\n sequences: {\n path: '/content-and-data/crm/sequences',\n title: 'Sequences',\n excerpt: 'One-to-one email sequences a rep sends to a person from their own connected mailbox, kept with the CRM. Rolling out.',\n },\n webhooks: {\n path: '/marketing-and-automation/workflows-and-actions/webhooks',\n title: 'Webhooks',\n excerpt: 'Connect Aglyn to other systems with outbound and inbound webhooks.',\n },\n} as const satisfies Record<string, PluginDocsTopic>\n\nexport type PluginDocsKey = keyof typeof PLUGIN_DOCS\n\nexport const PLUGIN_DOCS_ANCHORS = {\n abuseReports: ['#where-reports-come-from', '#triage-by-severity', '#csam', '#which-lever', '#statuses', '#disclosure', '#dmca', '#counter-notices', '#counter-notice-clock', '#counter-notice-steps', '#repeat-infringers', '#repeat-infringer-threshold', '#known-gaps', '#related'],\n actionsBuilder: ['#create-an-action', '#recipes', '#describe-it', '#triggers', '#crm-events', '#only-run-when-a-field-matches', '#chain-multiple-conditions-andor', '#steps', '#crm-steps', '#step-conditions', '#sequences', '#run-history', '#what-is-and-isnt-recorded', '#interactions-from-the-besigner', '#when-to-use-which', '#related'],\n aglynAssist: ['#what-it-can-do', '#aglyn-ai', '#answers-for-beginners-and-developers', '#offers-to-open-a-page', '#edits-in-the-besigner', '#where-an-answer-came-from', '#answers-straight-from-the-documentation', '#message-limits', '#feedback', '#privacy'],\n aiAutomations: ['#draft', '#explain', '#why-a-run-failed', '#what-is-sent', '#who-can-use-it', '#related'],\n aiCrm: ['#summarize-a-record', '#summaries-are-reused-until-the-record-changes', '#draft-an-email', '#match-columns', '#what-is-sent', '#who-can-use-it', '#related'],\n aiExperiments: ['#it-proposes-you-write', '#write-variants', '#putting-them-in', '#what-it-will-not-write', '#read-a-result', '#the-verdict', '#the-words', '#undecided', '#what-is-sent', '#who-can-use-it', '#related'],\n aiMonitoring: ['#the-ai-card', '#where-else', '#one-account', '#the-spend-leaderboard', '#alerts', '#related'],\n aiProducts: ['#write-a-products-copy', '#write-copy-for-many-products', '#when-you-import-products', '#propose-a-first-catalog', '#propose-categories-and-discounts', '#what-the-copy-never-says', '#what-is-sent-to-the-ai-provider', '#who-can-use-it', '#related'],\n aiSeo: ['#write-a-pages-listing', '#write-a-products-listing', '#audit-the-whole-site', '#target-keywords', '#apply-all-as-drafts', '#structured-data-and-llmstxt', '#related'],\n aiThemes: ['#change-what-you-describe-or-design-a-new-theme', '#match-your-brand', '#review-the-proposal', '#save-it-or-dont', '#who-can-use-it', '#related'],\n assistSignals: ['#the-workflow-this-board-exists-for', '#fleet', '#the-cache-read-rate-and-what-a-bad-number-looks-like', '#where-the-money-goes', '#tokens-by-kind', '#docs-gaps', '#questions-the-docs-could-not-answer', '#what-people-actually-asked', '#what-assist-costs-by-workspace', '#reading-the-sample-honestly', '#related'],\n billing: ['#tiers--entitlements', '#enterprise', '#single-sign-on-and-enforcement', '#usage-meters', '#who-is-generating-what', '#ai-allotments', '#storage-overage', '#if-you-would-rather-uploads-stopped', '#assist-overage', '#stop-ai-assist-at-the-included-band', '#ai-overage-ceiling', '#free-ai-credits', '#ai-credit-alerts', '#usage-budget', '#seats', '#crm-records', '#the-crm-suite', '#one-to-one-email', '#organization-data', '#api-access', '#payments', '#outstanding', '#plan-total', '#billing-email', '#payment-methods', '#billing-address', '#tax-ids', '#sales-tax', '#platform-fees', '#related'],\n bindings: ['#binding-tokens', '#rename-safe-id-tokens', '#insert-a-variable', '#token-pills', '#in-the-canvas-text-editor', '#site-details', '#typed-variables', '#no-code-functions', '#parameters-a-visitor-can-answer', '#a-calculator-you-lay-out', '#where-used--safety', '#workflows', '#related'],\n bookings: ['#set-up-bookings', '#taking-bookings', '#reminders', '#payments-and-fees', '#service-tax', '#manage', '#booking-from-the-crm', '#canceling-and-refunding', '#related'],\n buildAWorkflow: ['#1-open-the-workflows-page', '#2-choose-a-trigger', '#3-add-steps', '#waiting', '#4-save-and-test', '#duplicate-a-workflow', '#tips', '#related'],\n catalog: ['#products-options-and-variants', '#billing-modes-and-subscriptions', '#ai', '#categories-and-tags', '#collections', '#slugs', '#merchant-center-feed', '#related'],\n commerce: ['#products-hub', '#inventory', '#reserved-stock', '#stock-movements', '#gift-cards', '#recovery-and-alerts', '#orders', '#orders-screen', '#order-statuses', '#order-money-tiles', '#a-lost-dispute', '#shipping--taxes', '#lodging-tax-on-reservations', '#storefront-sales-tax', '#destination-coverage', '#dropshipping', '#related'],\n commerceEndToEnd: ['#1-connect-payments', '#2-create-products', '#3-design-the-storefront', '#catalog-search-filters-and-sort', '#category-pages', '#the-product-page-template', '#4-what-checkout-does', '#paying-without-leaving-your-site', '#5-run-orders-from-the-console', '#6-subscriptions--the-stripe-portal', '#related'],\n companies: ['#the-companies-list', '#create-a-company', '#a-companys-page', '#contacts-at-a-company', '#linked-on-capture', '#import-from-csv', '#export-csv', '#deleting-a-company', '#who-can-see-a-company', '#files', '#related'],\n consoleTour: ['#the-app-bar', '#in-context-help', '#primary-navigation', '#editing-vs-managing', '#the-sites-list', '#the-status-pill', '#how-the-pill-is-decided', '#your-site-allowance', '#a-sites-dashboard', '#next', '#workspace-settings--notifications', '#the-notifications-feed', '#notification-settings', '#one-kind-at-a-time', '#workspace-and-site-overrides', '#daily-digests', '#alerts-on-this-device'],\n contactActivities: ['#four-kinds-of-history', '#campaign-email', '#logging-an-activity', '#meeting-from-a-booking', '#click-to-call', '#sending-an-email', '#delivery-states', '#captured-email', '#where-an-activity-is-visible', '#the-recent-activity-feed', '#related'],\n contactFields: ['#define-a-field', '#fields-per-record', '#where-values-show', '#save-a-form-field', '#lead-source-values', '#over-the-api', '#retire-restore-delete', '#recompute-next-activity', '#related'],\n contactRecord: ['#adding-a-contact-by-hand', '#the-record-page', '#deleting-and-erasing', '#what-each-site-keeps-to-itself', '#merging-two-records', '#likely-duplicates', '#owner', '#last-engaged', '#lifecycle-stages', '#where-the-persons-lead-is', '#finding-a-contact', '#files', '#related'],\n contacts: ['#whats-in-the-crm-area', '#unified-ingestion', '#what-each-plan-includes', '#the-contacts-page', '#import-from-csv', '#segments', '#everywhere-the-crm-shows-up', '#capture-replies', '#at-the-organization-level', '#who-can-open-the-crm', '#related'],\n crmEmailTemplates: ['#templates-and-snippets', '#merge-fields', '#saving', '#managing-templates', '#duplicate-a-template', '#shared-or-personal', '#over-the-rest-api', '#related'],\n crmLeads: ['#what-makes-a-lead', '#what-a-lead-holds', '#adding-a-lead-by-hand', '#the-leads-list', '#working-a-lead-from-the-row', '#several-leads-at-once', '#export-csv', '#import-from-csv', '#who-owns-a-lead', '#a-leads-page', '#email-state', '#converting-a-lead', '#unqualifying-a-lead', '#erasing-the-person', '#who-can-do-this', '#related'],\n crmReports: ['#choosing-a-period', '#contacts', '#sources-and-lifecycle', '#conversion-by-source', '#lead-funnel', '#pipeline', '#forecast-by-close-month', '#won-and-lost', '#won-and-lost-by-owner', '#activity-by-teammate', '#tasks', '#exporting-a-table', '#crm-at-a-glance', '#how-the-numbers-are-counted', '#related'],\n crmSettings: ['#companies', '#create-companies-from-work-email-domains', '#default-owner', '#assignment-rules', '#round-robin', '#email-templates', '#email-capture', '#your-sending-addresses', '#recipes', '#related'],\n crmTasks: ['#the-tasks-page', '#the-calendar-view', '#snoozing-a-task', '#selecting-exporting-and-acting-on-many', '#import-from-csv', '#creating-a-task', '#assigning-a-task-to-someone-else', '#completing-and-reopening', '#organization-tasks', '#tasks-on-a-contact-company-or-deal', '#reminders', '#turning-reminders-off', '#next-activity', '#the-daily-digest', '#turning-it-off', '#the-dashboard-card', '#who-can-do-what', '#related'],\n crmViews: ['#the-views-control', '#a-view-is-a-link', '#filters', '#filters-on-the-contacts-list', '#filters-on-the-other-lists', '#columns-and-sort', '#segments-and-views', '#who-sees-what', '#related'],\n datasets: ['#model-builder', '#typed-documents', '#relations', '#query-layer', '#repeatable-components', '#who-a-dataset-is-shared-with', '#import--export', '#related'],\n deals: ['#pipelines', '#stages', '#the-board-and-the-table', '#import-from-csv', '#creating-a-deal', '#line-items', '#moving-winning-and-losing', '#a-won-deal-makes-its-contact-a-customer', '#a-deals-page', '#files', '#related'],\n designedEmails: ['#create-a-template', '#find-a-template', '#duplicate-a-template', '#styling-email-blocks', '#merge-tokens', '#send-it', '#the-plain-text-version', '#start-from-a-brief-instead'],\n emailCampaigns: ['#send-a-campaign', '#campaigns-belong-to-the-organization', '#organization-emails-page', '#campaigns-group-emails', '#filter-the-lists', '#what-belongs-to-a-campaign', '#who-the-email-comes-from', '#sending-domains', '#account-email-always-sends', '#marketing-needs-a-domain', '#two-ways-to-get-a-domain', '#a-domain-we-set-up-is-a-request', '#domain-states', '#senders', '#send-a-test', '#preview-the-email', '#monthly-send-cap', '#personalize-with-merge-tags', '#recipient-count', '#who-a-campaign-is-allowed-to-reach', '#schedule-a-send', '#duplicate-an-email', '#email-lists', '#manual-lists', '#list-members', '#add-to-a-list', '#import-a-list', '#remove-from-a-list', '#lists-built-from-a-rule', '#experiments', '#experiments-across-sites', '#opens--clicks', '#the-campaign-report', '#per-contact-engagement', '#which-links-were-clicked', '#revenue-from-a-campaign', '#conversions', '#compliance', '#list-unsubscribe', '#topics', '#preference-page', '#frequency-opt-down', '#double-opt-in', '#consent-group-confirmation', '#marketing-mail', '#frequency-cap', '#suppressions', '#add-a-suppression', '#platform-suppressions', '#related'],\n events: ['#manage-events', '#show-events-on-a-screen', '#search-engines', '#related'],\n forms: ['#reading-submissions-from-code', '#build-a-form', '#monthly-allowance-per-plan', '#spam-and-abuse-protection', '#the-per-site-monthly-ceiling', '#field-types', '#labels-and-placeholders', '#example-a-quick-survey', '#after-submit', '#example-grow-an-email-list-from-a-signup-form', '#where-submissions-go', '#the-inbox', '#who-a-submission-is-from', '#where-this-one-went', '#replying-to-a-submission', '#every-sites-inbox-at-once', '#one-forms-own-page', '#find-a-form', '#duplicate-a-form', '#switch-forms-off-for-one-site', '#related'],\n installYourFirstPlugin: ['#before-you-start', '#step-1-open', '#step-2-browse', '#step-3-reviews', '#step-4-targeting', '#step-5-install', '#step-6-use', '#step-7-off', '#what-to-do-next', '#related'],\n inviteTeammates: ['#invite-someone', '#pending-invites', '#who-gets-told', '#accepting-an-invite', '#an-invitation-never-changes-who-owns-the-workspace', '#how-team-members-act', '#you-are-a-site-collaborators-support-channel', '#help-a-teammate-who-is-locked-out', '#why-you-cant-always-set-a-password', '#activity-log', '#ai-actions', '#ai-usage', '#ai-allotment', '#tips', '#related'],\n manifestAndEnvs: ['#plugin-manifest-published-with-every-version', '#contributes--where-the-plugin-loads', '#config--settings-without-writing-a-settings-screen', '#listing--version-documents', '#review--trust-lifecycle', '#environment-variables', '#pluginsconfigjson-first-party-contributors'],\n marketingOverlays: ['#announcement-bar', '#promotional-popups', '#frequency', '#popup-v2', '#multiple-overlays-scheduling--page-targeting', '#variables-in-copy', '#engagement-stats', '#across-your-sites', '#related'],\n membersOnly: ['#let-visitors-sign-up', '#sign-in-sign-up-and-recovery-pages', '#forgotten-passwords', '#gate-a-screen', '#manage-your-members', '#suspend-or-reactivate-a-member', '#tips', '#related'],\n orgAutomations: ['#what-an-org-automation-is', '#create-one', '#triggers', '#steps', '#pause-it-on-one-site', '#waiting-switching-off-and-deleting', '#every-sites-own-automations', '#related'],\n plugins: ['#install--upgrade', '#browse-card', '#whats-included', '#what-the-badges-on-a-listing-mean', '#how-plugins-run', '#when-one-plugin-depends-on-another', '#a-dependency-that-is-off-for-one-site', '#configure', '#configure-site', '#publish-your-own', '#related'],\n pos: ['#registers', '#the-register', '#platform-fees-at-the-register', '#selling-past-the-count', '#when-something-disconnects', '#reservations', '#related'],\n publishAPlugin: ['#the-publish-pipeline', '#private-plugins', '#paid-listings', '#your-publisher-profile', '#tips', '#related'],\n publisherHandbook: ['#before-your-first-publish', '#the-publisher-agreement', '#where-to-publish-from', '#what-installing-each-type-does', '#rules-an-email-starter-has-to-meet', '#publishing-a-version', '#before-you-publish', '#review-what-happens-after-you-publish', '#the-two-badges-and-what-each-one-promises', '#asking-to-be-verified', '#testing-a-version-before-it-is-approved', '#watching-your-own-submission', '#disabled-versions', '#private-plugins', '#authoring-your-listing', '#what-your-listing-can-say-about-aglyn', '#versioning--updates', '#shipping-a-new-version', '#how-installs-work-the-buyer-side', '#getting-paid', '#low-prices-and-processing'],\n redirects: ['#manage-redirects', '#sending-visitors-to-another-site', '#metrics', '#match-modes-v2', '#related'],\n sandboxSecurity: ['#a-separate-origin', '#per-manifest-network-policy', '#when-you-cant-declare-the-origin', '#pinned-immutable-artifacts', '#what-this-means-when-you-build', '#related'],\n sequences: ['#what-it-is-for', '#sent-from-your-own-mailbox', '#where-it-lives', '#connect-a-mailbox', '#send-as', '#daily-cap', '#mailbox-status', '#auto-pause', '#mailbox-actions', '#link-domains', '#compliance-settings', '#allowed-countries', '#do-not-contact-domains', '#sequences', '#build-a-sequence', '#sequence-status', '#enroll', '#cold-contacts', '#enrollments', '#sending', '#what-stops-a-sequence', '#unsubscribe', '#related'],\n webhooks: ['#outbound-webhooks', '#inbound-webhooks', '#tips', '#related'],\n} as const satisfies Partial<Record<PluginDocsKey, readonly `#${string}`[]>>\n\ntype PluginAnchorMap = typeof PLUGIN_DOCS_ANCHORS\n\n/** Valid heading anchors for a plugin docs page (`never` when none). */\nexport type PluginDocsAnchor<K extends PluginDocsKey> =\n K extends keyof PluginAnchorMap ? PluginAnchorMap[K][number] : never\n"],"names":["PLUGIN_DOCS","abuseReports","path","title","excerpt","actionsBuilder","aglynAssist","aiAutomations","aiCrm","aiExperiments","aiMonitoring","aiProducts","aiSeo","aiThemes","assistSignals","billing","bindings","bookings","buildAWorkflow","catalog","commerce","commerceEndToEnd","companies","consoleTour","contactActivities","contactFields","contactRecord","contacts","crmEmailTemplates","crmLeads","crmReports","crmSettings","crmTasks","crmViews","datasets","deals","designedEmails","emailCampaigns","events","forms","installYourFirstPlugin","inviteTeammates","manifestAndEnvs","marketingOverlays","membersOnly","orgAutomations","plugins","pos","publishAPlugin","publisherHandbook","redirects","sandboxSecurity","sequences","webhooks","PLUGIN_DOCS_ANCHORS"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,iDAAiD;AACjD,8CAA8C;AAC9C,oEAAoE;AAEpE,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAW/E,OAAO,MAAMA,cAAc;IACzBC,cAAc;QACZC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAC,gBAAgB;QACdH,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAE,aAAa;QACXJ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAG,eAAe;QACbL,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAI,OAAO;QACLN,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAK,eAAe;QACbP,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAM,cAAc;QACZR,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAO,YAAY;QACVT,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAQ,OAAO;QACLV,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAS,UAAU;QACRX,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAU,eAAe;QACbZ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAW,SAAS;QACPb,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAY,UAAU;QACRd,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAa,UAAU;QACRf,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAc,gBAAgB;QACdhB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAe,SAAS;QACPjB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgB,UAAU;QACRlB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiB,kBAAkB;QAChBnB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkB,WAAW;QACTpB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmB,aAAa;QACXrB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoB,mBAAmB;QACjBtB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqB,eAAe;QACbvB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsB,eAAe;QACbxB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuB,UAAU;QACRzB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwB,mBAAmB;QACjB1B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyB,UAAU;QACR3B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0B,YAAY;QACV5B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2B,aAAa;QACX7B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4B,UAAU;QACR9B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA6B,UAAU;QACR/B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA8B,UAAU;QACRhC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA+B,OAAO;QACLjC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgC,gBAAgB;QACdlC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiC,gBAAgB;QACdnC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkC,QAAQ;QACNpC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmC,OAAO;QACLrC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoC,wBAAwB;QACtBtC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqC,iBAAiB;QACfvC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsC,iBAAiB;QACfxC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuC,mBAAmB;QACjBzC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwC,aAAa;QACX1C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyC,gBAAgB;QACd3C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0C,SAAS;QACP5C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2C,KAAK;QACH7C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4C,gBAAgB;QACd9C,MAAM;QACNC,O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"}
1
+ {"version":3,"sources":["../../../../../../libs/aglyn/src/lib/app-utils/docs-help.generated.ts"],"sourcesContent":["/**\n * @license\n * Copyright 2026 Aglyn LLC\n *\n * Licensed under the Apache License, Version 2.0 (the \"License\");\n * you may not use this file except in compliance with the License.\n * You may obtain a copy of the License at\n *\n * http://www.apache.org/licenses/LICENSE-2.0\n *\n * Unless required by applicable law or agreed to in writing, software\n * distributed under the License is distributed on an \"AS IS\" BASIS,\n * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.\n * See the License for the specific language governing permissions and\n * limitations under the License.\n */\n// GENERATED FILE — do not edit. Regenerate with:\n// node tools/scripts/generate-docs-help.mjs\n// Source of truth: apps/docs/docs frontmatter + headings (AGL-602).\n\n// The first-party plugin consoles live in `libs/plugins/*` and cannot import\n// the console's constants, so they carry their own generated subset of the\n// docs help registry — the topics their cards actually link to, and no others.\n\nexport interface PluginDocsTopic {\n /** Docs-site path, e.g. `/commerce-and-bookings/commerce/overview`. */\n path: string\n /** Docs page title. */\n title: string\n /** Verbatim docs frontmatter description — the tooltip excerpt. */\n excerpt: string\n}\n\nexport const PLUGIN_DOCS = {\n abuseReports: {\n path: '/staff-console/abuse-reports',\n title: 'Abuse reports',\n excerpt: 'The public abuse-report queue — where outside reports land, how to triage by severity, which lever answers which report, and the CSAM and DMCA paths that are not takedown buttons.',\n },\n actionsBuilder: {\n path: '/marketing-and-automation/workflows-and-actions/actions-builder',\n title: 'Actions builder',\n excerpt: 'Map a single event to a single action without building a full workflow.',\n },\n aglynAssist: {\n path: '/getting-started/aglyn-assist',\n title: 'Aglyn Assist',\n excerpt: 'Ask the built-in AI helper how to do anything in Aglyn — it answers from these docs and links you straight to the right page.',\n },\n aiAutomations: {\n path: '/ai/automations-with-ai',\n title: 'Explain automations with AI',\n excerpt: 'Aglyn AI can explain an automation you already have and tell you why one of its runs failed. Drafting an automation from a description is not available yet.',\n },\n aiCrm: {\n path: '/ai/crm-by-ai',\n title: 'The AI CRM built into Aglyn',\n excerpt: 'An AI CRM for small business: a short summary and a suggested next step on a contact, company, deal or lead, a one-to-one email drafted into the composer, and an import\\'s columns matched to fields.',\n },\n aiExperiments: {\n path: '/ai/ab-tests-with-ai',\n title: 'A/B tests by AI: write variants, read the result',\n excerpt: 'Have Aglyn AI write two to four variants for a screen, section or email experiment, and put a finished test into plain language — with the verdict decided from the counts before the model is asked anything.',\n },\n aiMonitoring: {\n path: '/staff-console/ai-monitoring',\n title: 'AI monitoring',\n excerpt: 'How staff watch one organization\\'s AI usage — the add-on, credit pool, overage, refusals, jobs, tokens and cache hit rate, top spenders and margin — and where those figures appear across the staff console.',\n },\n aiProducts: {\n path: '/ai/products-with-ai',\n title: 'Product copy and catalogs with AI',\n excerpt: 'An AI product description generator for your catalog: write copy for one product or a whole import, propose a first catalog, and propose categories and discounts — all as proposals you review.',\n },\n aiSeo: {\n path: '/building-sites/seo/seo-by-ai',\n title: 'AI SEO for your website',\n excerpt: 'AI SEO for websites, on the pages you already have: have AI write a page or product\\'s search listing, audit every published page with a proposed fix for each finding, and draft your structured data and /llms.txt.',\n },\n aiThemes: {\n path: '/ai/theme-assist',\n title: 'Change your site\\'s theme with AI',\n excerpt: 'Describe a change to your site\\'s theme and get a proposal for the theme editor\\'s own controls, previewed before and after, that you save in the editor. Rolling out.',\n },\n assistSignals: {\n path: '/staff-console/assist-signals',\n title: 'Assist Signal',\n excerpt: 'The docs-gap and cost board behind Assist — how the ranking is ordered, why ungrounded questions are counted separately, and what the cache-read rate says about margin.',\n },\n billing: {\n path: '/workspace-and-billing/billing-and-plans/overview',\n title: 'Billing & Plans',\n excerpt: 'How Aglyn\\'s tiers, entitlements, quotas, usage meters, and seat add-ons work.',\n },\n bindings: {\n path: '/building-sites/bindings/overview',\n title: 'Bindings, Variables & Functions',\n excerpt: 'Live values in your content — typed variables, no-code functions, and rename-safe id tokens.',\n },\n bookings: {\n path: '/commerce-and-bookings/bookings/overview',\n title: 'Bookings & Scheduling',\n excerpt: 'Offer services with availability, let visitors book, take payment, and send reminders.',\n },\n buildAWorkflow: {\n path: '/marketing-and-automation/workflows-and-actions/build-a-workflow',\n title: 'Build a workflow',\n excerpt: 'Create a multi-step workflow that runs when a site event fires.',\n },\n catalog: {\n path: '/commerce-and-bookings/commerce/catalog',\n title: 'Product catalog',\n excerpt: 'Products with options and variants, categories, tags, and manual or smart collections.',\n },\n commerce: {\n path: '/commerce-and-bookings/commerce/overview',\n title: 'Commerce',\n excerpt: 'Sell physical, digital, and service products with a full catalog, orders pipeline, shipping, taxes, and your own Stripe account.',\n },\n commerceEndToEnd: {\n path: '/guides/commerce-end-to-end',\n title: 'Commerce end to end',\n excerpt: 'Create products with billing modes, design the storefront with Commerce blocks, take Stripe checkout for one-time and subscription sales, and run orders from the console.',\n },\n companies: {\n path: '/content-and-data/crm/companies',\n title: 'Companies',\n excerpt: 'Group your contacts under the businesses they belong to — one record per company, with its domain, owner, address and the people who work there.',\n },\n consoleTour: {\n path: '/getting-started/console-tour',\n title: 'The console tour',\n excerpt: 'Where things live in the Aglyn console app bar and navigation.',\n },\n contactActivities: {\n path: '/content-and-data/crm/activities',\n title: 'Activities & the timeline',\n excerpt: 'Log calls, emails, meetings and notes against a contact, a company, a deal or a lead, email one person from their record, and read it all in one timeline beside everything captured and every campaign sent.',\n },\n contactFields: {\n path: '/content-and-data/crm/custom-fields',\n title: 'Custom fields',\n excerpt: 'Define your own properties on contacts, companies, deals and leads — text, number, date, choice, checkbox or link — show them on every record and its list, and save form answers straight into a contact\\'s.',\n },\n contactRecord: {\n path: '/content-and-data/crm/contact-record',\n title: 'The contact record',\n excerpt: 'Add a contact by hand, keep a profile on them — phone, company, title, address, owner and lifecycle stage — open their own page in the CRM, and merge two records that turn out to be one person.',\n },\n contacts: {\n path: '/content-and-data/crm/overview',\n title: 'CRM',\n excerpt: 'One place for the people who interact with your sites — contacts captured from forms, members, orders and bookings, with leads, companies, a deals pipeline, tasks, a timeline, reports and custom fields.',\n },\n crmEmailTemplates: {\n path: '/content-and-data/crm/email-templates',\n title: 'Email templates',\n excerpt: 'Keep the letters your team sends from a record — templates that fill in the subject and the message, snippets that drop in a paragraph, and merge fields that fill in the person\\'s name, their company, the deal and you.',\n },\n crmLeads: {\n path: '/content-and-data/crm/leads',\n title: 'Leads',\n excerpt: 'Work the people your site has captured — a status, an owner and notes on every lead — and convert one into a contact, a company and a deal.',\n },\n crmReports: {\n path: '/content-and-data/crm/reports',\n title: 'Reports',\n excerpt: 'New contacts, where they came from and which sources convert, the lead funnel, the open pipeline and its forecast, won and lost, who logged what, and the task load — counted on the server, every table exportable as CSV.',\n },\n crmSettings: {\n path: '/content-and-data/crm/settings',\n title: 'CRM settings',\n excerpt: 'What the CRM does on its own for every site — whether a company is created from a contact\\'s work email domain, who a new contact is assigned to, the address that files replies on a record, and each site\\'s recipes.',\n },\n crmTasks: {\n path: '/content-and-data/crm/tasks',\n title: 'Tasks & follow-ups',\n excerpt: 'Calls, emails, meetings and to-dos with a due date, an assignee and a link to the record they are for — overdue and today read off the clock, a snooze, a reminder at its own time, and a morning digest.',\n },\n crmViews: {\n path: '/content-and-data/crm/views',\n title: 'Saved views',\n excerpt: 'Keep a CRM list\\'s filters, columns and sort under a name, open it from the views menu or a link, share it with the team, and use a contacts view as an email audience.',\n },\n datasets: {\n path: '/content-and-data/datasets/overview',\n title: 'Datasets & Dynamic Content',\n excerpt: 'Model structured content with typed fields and relations, then bind it into repeatable components.',\n },\n deals: {\n path: '/content-and-data/crm/deals',\n title: 'Deals pipeline',\n excerpt: 'Every open deal by stage — with an amount, an owner and an expected close — as a board you drag across or a table you page through, and the won and lost history behind it.',\n },\n designedEmails: {\n path: '/marketing-and-automation/email-campaigns/designed-emails',\n title: 'Designed emails',\n excerpt: 'Build campaign emails in the besigner with email-safe blocks and merge tokens — no separate editor.',\n },\n emailCampaigns: {\n path: '/marketing-and-automation/email-campaigns/overview',\n title: 'Email Campaigns',\n excerpt: 'Campaigns to audiences built from your contacts. Campaign email starts at Pro and needs a sending domain of the site\\'s own; receipts and account email send on every plan.',\n },\n events: {\n path: '/content-and-data/events/overview',\n title: 'Events Calendar',\n excerpt: 'Keep a schedule of events in the console and publish the ones you choose to any screen, with search-engine event markup.',\n },\n forms: {\n path: '/content-and-data/forms/overview',\n title: 'Forms & Lead Capture',\n excerpt: 'Add forms to your site, collect submissions in an inbox, and write them into datasets.',\n },\n installYourFirstPlugin: {\n path: '/guides/install-your-first-plugin',\n title: 'Install your first marketplace item',\n excerpt: 'A click-by-click walkthrough of the Marketplace — find something, choose which sites get it, install it, and turn it off again.',\n },\n inviteTeammates: {\n path: '/workspace-and-billing/teams-and-roles/invite-teammates',\n title: 'Invite teammates',\n excerpt: 'Add people to your site and understand how team members act within your organization.',\n },\n manifestAndEnvs: {\n path: '/developers/plugins/reference/manifest-and-envs',\n title: 'Manifests, trust lifecycle & environment',\n excerpt: 'The plugin manifest schema, the marketplace listing/version documents, the trust state machine, and every PLUGIN_* environment variable.',\n },\n marketingOverlays: {\n path: '/marketing-and-automation/marketing-overlays/overview',\n title: 'Marketing Overlays',\n excerpt: 'Site-wide announcement bars and promotional popups with triggers, scheduling, and email capture.',\n },\n membersOnly: {\n path: '/workspace-and-billing/teams-and-roles/members-only',\n title: 'Members-only areas',\n excerpt: 'Let visitors sign up as members and gate screens so only members can view them.',\n },\n orgAutomations: {\n path: '/marketing-and-automation/workflows-and-actions/org-automations',\n title: 'Org automations',\n excerpt: 'Write an automation once for the whole organization and run it on the sites you choose, with a pause on each site.',\n },\n plugins: {\n path: '/developers/plugins/overview',\n title: 'Plugins & Marketplace',\n excerpt: 'Extend Aglyn with sandboxed plugins — install from the marketplace, configure them, and publish your own.',\n },\n pos: {\n path: '/commerce-and-bookings/commerce/pos-and-reservations',\n title: 'POS & reservations',\n excerpt: 'Sell in person from the console register and take date-range reservations with deposits.',\n },\n publishAPlugin: {\n path: '/developers/plugins/publish-a-plugin',\n title: 'Publish a plugin',\n excerpt: 'Ship your own plugin to the marketplace with version pinning.',\n },\n publisherHandbook: {\n path: '/developers/plugins/publishing/publisher-handbook',\n title: 'Publisher handbook',\n excerpt: 'Publishing to the Aglyn marketplace — from profile setup through listing authoring, review, updates, and getting paid.',\n },\n redirects: {\n path: '/building-sites/redirects/overview',\n title: 'Redirects',\n excerpt: 'Manage URL redirects with validation, loop detection, and hit metrics.',\n },\n sandboxSecurity: {\n path: '/developers/plugins/reference/sandbox-security',\n title: 'Sandbox security model',\n excerpt: 'How sandboxed marketplace plugins are isolated — separate origin, per-manifest CSP, pinned artifacts — and what that means when you write one.',\n },\n sequences: {\n path: '/content-and-data/crm/sequences',\n title: 'Sequences',\n excerpt: 'One-to-one email sequences a rep sends to a person from their own connected mailbox, kept with the CRM. Rolling out.',\n },\n webhooks: {\n path: '/marketing-and-automation/workflows-and-actions/webhooks',\n title: 'Webhooks',\n excerpt: 'Connect Aglyn to other systems with outbound and inbound webhooks.',\n },\n} as const satisfies Record<string, PluginDocsTopic>\n\nexport type PluginDocsKey = keyof typeof PLUGIN_DOCS\n\nexport const PLUGIN_DOCS_ANCHORS = {\n abuseReports: ['#where-reports-come-from', '#triage-by-severity', '#csam', '#which-lever', '#statuses', '#disclosure', '#dmca', '#counter-notices', '#counter-notice-clock', '#counter-notice-steps', '#repeat-infringers', '#repeat-infringer-threshold', '#known-gaps', '#related'],\n actionsBuilder: ['#create-an-action', '#recipes', '#describe-it', '#triggers', '#crm-events', '#only-run-when-a-field-matches', '#chain-multiple-conditions-andor', '#steps', '#crm-steps', '#step-conditions', '#sequences', '#run-history', '#what-is-and-isnt-recorded', '#interactions-from-the-besigner', '#when-to-use-which', '#related'],\n aglynAssist: ['#what-it-can-do', '#aglyn-ai', '#answers-for-beginners-and-developers', '#offers-to-open-a-page', '#edits-in-the-besigner', '#where-an-answer-came-from', '#answers-straight-from-the-documentation', '#message-limits', '#feedback', '#privacy'],\n aiAutomations: ['#draft', '#explain', '#why-a-run-failed', '#what-is-sent', '#who-can-use-it', '#related'],\n aiCrm: ['#summarize-a-record', '#summaries-are-reused-until-the-record-changes', '#draft-an-email', '#match-columns', '#what-is-sent', '#who-can-use-it', '#related'],\n aiExperiments: ['#it-proposes-you-write', '#write-variants', '#putting-them-in', '#what-it-will-not-write', '#read-a-result', '#the-verdict', '#the-words', '#undecided', '#what-is-sent', '#who-can-use-it', '#related'],\n aiMonitoring: ['#the-ai-card', '#where-else', '#one-account', '#the-spend-leaderboard', '#alerts', '#related'],\n aiProducts: ['#write-a-products-copy', '#write-copy-for-many-products', '#when-you-import-products', '#propose-a-first-catalog', '#propose-categories-and-discounts', '#what-the-copy-never-says', '#what-is-sent-to-the-ai-provider', '#who-can-use-it', '#related'],\n aiSeo: ['#write-a-pages-listing', '#write-a-products-listing', '#audit-the-whole-site', '#target-keywords', '#apply-all-as-drafts', '#structured-data-and-llmstxt', '#related'],\n aiThemes: ['#change-what-you-describe-or-design-a-new-theme', '#match-your-brand', '#review-the-proposal', '#save-it-or-dont', '#who-can-use-it', '#related'],\n assistSignals: ['#the-workflow-this-board-exists-for', '#fleet', '#the-cache-read-rate-and-what-a-bad-number-looks-like', '#where-the-money-goes', '#tokens-by-kind', '#docs-gaps', '#questions-the-docs-could-not-answer', '#what-people-actually-asked', '#what-assist-costs-by-workspace', '#reading-the-sample-honestly', '#related'],\n billing: ['#tiers--entitlements', '#enterprise', '#single-sign-on-and-enforcement', '#usage-meters', '#who-is-generating-what', '#ai-allotments', '#storage-overage', '#if-you-would-rather-uploads-stopped', '#assist-overage', '#stop-ai-assist-at-the-included-band', '#ai-overage-ceiling', '#free-ai-credits', '#ai-credit-alerts', '#usage-budget', '#seats', '#crm-records', '#the-crm-suite', '#one-to-one-email', '#organization-data', '#api-access', '#payments', '#outstanding', '#plan-total', '#billing-email', '#payment-methods', '#billing-address', '#tax-ids', '#sales-tax', '#platform-fees', '#related'],\n bindings: ['#binding-tokens', '#rename-safe-id-tokens', '#insert-a-variable', '#token-pills', '#in-the-canvas-text-editor', '#site-details', '#typed-variables', '#no-code-functions', '#parameters-a-visitor-can-answer', '#a-calculator-you-lay-out', '#where-used--safety', '#workflows', '#related'],\n bookings: ['#set-up-bookings', '#taking-bookings', '#reminders', '#payments-and-fees', '#service-tax', '#manage', '#booking-from-the-crm', '#canceling-and-refunding', '#related'],\n buildAWorkflow: ['#1-open-the-workflows-page', '#2-choose-a-trigger', '#3-add-steps', '#waiting', '#4-save-and-test', '#duplicate-a-workflow', '#tips', '#related'],\n catalog: ['#products-options-and-variants', '#billing-modes-and-subscriptions', '#ai', '#categories-and-tags', '#collections', '#slugs', '#merchant-center-feed', '#related'],\n commerce: ['#products-hub', '#inventory', '#reserved-stock', '#stock-movements', '#gift-cards', '#recovery-and-alerts', '#orders', '#orders-screen', '#order-statuses', '#order-money-tiles', '#a-lost-dispute', '#shipping--taxes', '#lodging-tax-on-reservations', '#storefront-sales-tax', '#destination-coverage', '#dropshipping', '#related'],\n commerceEndToEnd: ['#1-connect-payments', '#2-create-products', '#3-design-the-storefront', '#catalog-search-filters-and-sort', '#category-pages', '#the-product-page-template', '#4-what-checkout-does', '#paying-without-leaving-your-site', '#5-run-orders-from-the-console', '#6-subscriptions--the-stripe-portal', '#related'],\n companies: ['#the-companies-list', '#create-a-company', '#a-companys-page', '#contacts-at-a-company', '#linked-on-capture', '#import-from-csv', '#export-csv', '#deleting-a-company', '#who-can-see-a-company', '#files', '#related'],\n consoleTour: ['#the-app-bar', '#in-context-help', '#primary-navigation', '#editing-vs-managing', '#the-sites-list', '#the-status-pill', '#how-the-pill-is-decided', '#your-site-allowance', '#a-sites-dashboard', '#next', '#workspace-settings--notifications', '#the-notifications-feed', '#notification-settings', '#one-kind-at-a-time', '#workspace-and-site-overrides', '#daily-digests', '#alerts-on-this-device'],\n contactActivities: ['#four-kinds-of-history', '#campaign-email', '#logging-an-activity', '#meeting-from-a-booking', '#click-to-call', '#sending-an-email', '#delivery-states', '#captured-email', '#where-an-activity-is-visible', '#the-recent-activity-feed', '#related'],\n contactFields: ['#define-a-field', '#fields-per-record', '#where-values-show', '#save-a-form-field', '#lead-source-values', '#over-the-api', '#retire-restore-delete', '#recompute-next-activity', '#related'],\n contactRecord: ['#adding-a-contact-by-hand', '#the-record-page', '#deleting-and-erasing', '#what-each-site-keeps-to-itself', '#merging-two-records', '#likely-duplicates', '#owner', '#last-engaged', '#lifecycle-stages', '#where-the-persons-lead-is', '#finding-a-contact', '#files', '#related'],\n contacts: ['#whats-in-the-crm-area', '#unified-ingestion', '#what-each-plan-includes', '#the-contacts-page', '#import-from-csv', '#segments', '#everywhere-the-crm-shows-up', '#capture-replies', '#at-the-organization-level', '#who-can-open-the-crm', '#related'],\n crmEmailTemplates: ['#templates-and-snippets', '#merge-fields', '#saving', '#managing-templates', '#duplicate-a-template', '#shared-or-personal', '#over-the-rest-api', '#related'],\n crmLeads: ['#what-makes-a-lead', '#what-a-lead-holds', '#adding-a-lead-by-hand', '#the-leads-list', '#working-a-lead-from-the-row', '#several-leads-at-once', '#export-csv', '#import-from-csv', '#who-owns-a-lead', '#a-leads-page', '#email-state', '#converting-a-lead', '#unqualifying-a-lead', '#erasing-the-person', '#who-can-do-this', '#related'],\n crmReports: ['#choosing-a-period', '#contacts', '#sources-and-lifecycle', '#conversion-by-source', '#lead-funnel', '#pipeline', '#forecast-by-close-month', '#won-and-lost', '#won-and-lost-by-owner', '#activity-by-teammate', '#tasks', '#exporting-a-table', '#crm-at-a-glance', '#how-the-numbers-are-counted', '#related'],\n crmSettings: ['#companies', '#create-companies-from-work-email-domains', '#default-owner', '#assignment-rules', '#round-robin', '#email-templates', '#email-capture', '#your-sending-addresses', '#recipes', '#related'],\n crmTasks: ['#the-tasks-page', '#the-calendar-view', '#snoozing-a-task', '#selecting-exporting-and-acting-on-many', '#import-from-csv', '#creating-a-task', '#assigning-a-task-to-someone-else', '#completing-and-reopening', '#organization-tasks', '#tasks-on-a-contact-company-or-deal', '#reminders', '#turning-reminders-off', '#next-activity', '#the-daily-digest', '#turning-it-off', '#the-dashboard-card', '#who-can-do-what', '#related'],\n crmViews: ['#the-views-control', '#a-view-is-a-link', '#filters', '#filters-on-the-contacts-list', '#filters-on-the-other-lists', '#columns-and-sort', '#segments-and-views', '#who-sees-what', '#related'],\n datasets: ['#model-builder', '#typed-documents', '#filter-records', '#relations', '#query-layer', '#repeatable-components', '#who-a-dataset-is-shared-with', '#import--export', '#related'],\n deals: ['#pipelines', '#stages', '#the-board-and-the-table', '#import-from-csv', '#creating-a-deal', '#line-items', '#moving-winning-and-losing', '#a-won-deal-makes-its-contact-a-customer', '#a-deals-page', '#files', '#related'],\n designedEmails: ['#create-a-template', '#find-a-template', '#duplicate-a-template', '#styling-email-blocks', '#merge-tokens', '#send-it', '#the-plain-text-version', '#start-from-a-brief-instead'],\n emailCampaigns: ['#send-a-campaign', '#campaigns-belong-to-the-organization', '#organization-emails-page', '#campaigns-group-emails', '#filter-the-lists', '#what-belongs-to-a-campaign', '#who-the-email-comes-from', '#sending-domains', '#account-email-always-sends', '#marketing-needs-a-domain', '#two-ways-to-get-a-domain', '#a-domain-we-set-up-is-a-request', '#domain-states', '#senders', '#send-a-test', '#preview-the-email', '#monthly-send-cap', '#personalize-with-merge-tags', '#recipient-count', '#who-a-campaign-is-allowed-to-reach', '#schedule-a-send', '#duplicate-an-email', '#email-lists', '#manual-lists', '#list-members', '#add-to-a-list', '#import-a-list', '#remove-from-a-list', '#lists-built-from-a-rule', '#experiments', '#experiments-across-sites', '#opens--clicks', '#the-campaign-report', '#per-contact-engagement', '#which-links-were-clicked', '#revenue-from-a-campaign', '#conversions', '#compliance', '#list-unsubscribe', '#topics', '#preference-page', '#frequency-opt-down', '#double-opt-in', '#consent-group-confirmation', '#marketing-mail', '#frequency-cap', '#suppressions', '#add-a-suppression', '#platform-suppressions', '#related'],\n events: ['#manage-events', '#show-events-on-a-screen', '#search-engines', '#related'],\n forms: ['#reading-submissions-from-code', '#build-a-form', '#monthly-allowance-per-plan', '#spam-and-abuse-protection', '#the-per-site-monthly-ceiling', '#field-types', '#labels-and-placeholders', '#example-a-quick-survey', '#after-submit', '#example-grow-an-email-list-from-a-signup-form', '#where-submissions-go', '#the-inbox', '#who-a-submission-is-from', '#where-this-one-went', '#replying-to-a-submission', '#every-sites-inbox-at-once', '#one-forms-own-page', '#find-a-form', '#duplicate-a-form', '#switch-forms-off-for-one-site', '#related'],\n installYourFirstPlugin: ['#before-you-start', '#step-1-open', '#step-2-browse', '#step-3-reviews', '#step-4-targeting', '#step-5-install', '#step-6-use', '#step-7-off', '#what-to-do-next', '#related'],\n inviteTeammates: ['#invite-someone', '#pending-invites', '#who-gets-told', '#accepting-an-invite', '#an-invitation-never-changes-who-owns-the-workspace', '#how-team-members-act', '#you-are-a-site-collaborators-support-channel', '#help-a-teammate-who-is-locked-out', '#why-you-cant-always-set-a-password', '#activity-log', '#ai-actions', '#ai-usage', '#ai-allotment', '#tips', '#related'],\n manifestAndEnvs: ['#plugin-manifest-published-with-every-version', '#contributes--where-the-plugin-loads', '#config--settings-without-writing-a-settings-screen', '#listing--version-documents', '#review--trust-lifecycle', '#environment-variables', '#pluginsconfigjson-first-party-contributors'],\n marketingOverlays: ['#announcement-bar', '#promotional-popups', '#frequency', '#popup-v2', '#multiple-overlays-scheduling--page-targeting', '#variables-in-copy', '#engagement-stats', '#across-your-sites', '#related'],\n membersOnly: ['#let-visitors-sign-up', '#sign-in-sign-up-and-recovery-pages', '#forgotten-passwords', '#gate-a-screen', '#manage-your-members', '#suspend-or-reactivate-a-member', '#tips', '#related'],\n orgAutomations: ['#what-an-org-automation-is', '#create-one', '#triggers', '#steps', '#pause-it-on-one-site', '#waiting-switching-off-and-deleting', '#every-sites-own-automations', '#related'],\n plugins: ['#install--upgrade', '#browse-card', '#whats-included', '#what-the-badges-on-a-listing-mean', '#how-plugins-run', '#when-one-plugin-depends-on-another', '#a-dependency-that-is-off-for-one-site', '#configure', '#configure-site', '#publish-your-own', '#related'],\n pos: ['#registers', '#the-register', '#platform-fees-at-the-register', '#selling-past-the-count', '#when-something-disconnects', '#reservations', '#related'],\n publishAPlugin: ['#the-publish-pipeline', '#private-plugins', '#paid-listings', '#your-publisher-profile', '#tips', '#related'],\n publisherHandbook: ['#before-your-first-publish', '#the-publisher-agreement', '#where-to-publish-from', '#what-installing-each-type-does', '#rules-an-email-starter-has-to-meet', '#publishing-a-version', '#before-you-publish', '#review-what-happens-after-you-publish', '#the-two-badges-and-what-each-one-promises', '#asking-to-be-verified', '#testing-a-version-before-it-is-approved', '#watching-your-own-submission', '#disabled-versions', '#private-plugins', '#authoring-your-listing', '#what-your-listing-can-say-about-aglyn', '#versioning--updates', '#shipping-a-new-version', '#how-installs-work-the-buyer-side', '#getting-paid', '#low-prices-and-processing'],\n redirects: ['#manage-redirects', '#sending-visitors-to-another-site', '#metrics', '#match-modes-v2', '#related'],\n sandboxSecurity: ['#a-separate-origin', '#per-manifest-network-policy', '#when-you-cant-declare-the-origin', '#pinned-immutable-artifacts', '#what-this-means-when-you-build', '#related'],\n sequences: ['#what-it-is-for', '#sent-from-your-own-mailbox', '#where-it-lives', '#connect-a-mailbox', '#send-as', '#daily-cap', '#mailbox-status', '#auto-pause', '#mailbox-actions', '#link-domains', '#compliance-settings', '#allowed-countries', '#do-not-contact-domains', '#sequences', '#build-a-sequence', '#sequence-status', '#enroll', '#cold-contacts', '#enrollments', '#curate', '#sending', '#what-stops-a-sequence', '#unsubscribe', '#related'],\n webhooks: ['#outbound-webhooks', '#inbound-webhooks', '#tips', '#related'],\n} as const satisfies Partial<Record<PluginDocsKey, readonly `#${string}`[]>>\n\ntype PluginAnchorMap = typeof PLUGIN_DOCS_ANCHORS\n\n/** Valid heading anchors for a plugin docs page (`never` when none). */\nexport type PluginDocsAnchor<K extends PluginDocsKey> =\n K extends keyof PluginAnchorMap ? PluginAnchorMap[K][number] : never\n"],"names":["PLUGIN_DOCS","abuseReports","path","title","excerpt","actionsBuilder","aglynAssist","aiAutomations","aiCrm","aiExperiments","aiMonitoring","aiProducts","aiSeo","aiThemes","assistSignals","billing","bindings","bookings","buildAWorkflow","catalog","commerce","commerceEndToEnd","companies","consoleTour","contactActivities","contactFields","contactRecord","contacts","crmEmailTemplates","crmLeads","crmReports","crmSettings","crmTasks","crmViews","datasets","deals","designedEmails","emailCampaigns","events","forms","installYourFirstPlugin","inviteTeammates","manifestAndEnvs","marketingOverlays","membersOnly","orgAutomations","plugins","pos","publishAPlugin","publisherHandbook","redirects","sandboxSecurity","sequences","webhooks","PLUGIN_DOCS_ANCHORS"],"mappings":"AAAA;;;;;;;;;;;;;;;CAeC,GACD,iDAAiD;AACjD,8CAA8C;AAC9C,oEAAoE;AAEpE,6EAA6E;AAC7E,2EAA2E;AAC3E,+EAA+E;AAW/E,OAAO,MAAMA,cAAc;IACzBC,cAAc;QACZC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAC,gBAAgB;QACdH,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAE,aAAa;QACXJ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAG,eAAe;QACbL,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAI,OAAO;QACLN,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAK,eAAe;QACbP,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAM,cAAc;QACZR,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAO,YAAY;QACVT,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAQ,OAAO;QACLV,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAS,UAAU;QACRX,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAU,eAAe;QACbZ,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAW,SAAS;QACPb,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAY,UAAU;QACRd,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAa,UAAU;QACRf,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAc,gBAAgB;QACdhB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAe,SAAS;QACPjB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgB,UAAU;QACRlB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiB,kBAAkB;QAChBnB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkB,WAAW;QACTpB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmB,aAAa;QACXrB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoB,mBAAmB;QACjBtB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqB,eAAe;QACbvB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsB,eAAe;QACbxB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuB,UAAU;QACRzB,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwB,mBAAmB;QACjB1B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyB,UAAU;QACR3B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0B,YAAY;QACV5B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2B,aAAa;QACX7B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4B,UAAU;QACR9B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA6B,UAAU;QACR/B,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA8B,UAAU;QACRhC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA+B,OAAO;QACLjC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgC,gBAAgB;QACdlC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiC,gBAAgB;QACdnC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAkC,QAAQ;QACNpC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAmC,OAAO;QACLrC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAoC,wBAAwB;QACtBtC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAqC,iBAAiB;QACfvC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAsC,iBAAiB;QACfxC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAuC,mBAAmB;QACjBzC,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAwC,aAAa;QACX1C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAyC,gBAAgB;QACd3C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA0C,SAAS;QACP5C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA2C,KAAK;QACH7C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA4C,gBAAgB;QACd9C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA6C,mBAAmB;QACjB/C,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA8C,WAAW;QACThD,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACA+C,iBAAiB;QACfjD,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAgD,WAAW;QACTlD,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;IACAiD,UAAU;QACRnD,MAAM;QACNC,OAAO;QACPC,SAAS;IACX;AACF,EAAoD;AAIpD,OAAO,MAAMkD,sBAAsB;IACjCrD,cAAc;QAAC;QAA4B;QAAuB;QAAS;QAAgB;QAAa;QAAe;QAAS;QAAoB;QAAyB;QAAyB;QAAsB;QAA+B;QAAe;KAAW;IACrRI,gBAAgB;QAAC;QAAqB;QAAY;QAAgB;QAAa;QAAe;QAAkC;QAAoC;QAAU;QAAc;QAAoB;QAAc;QAAgB;QAA8B;QAAmC;QAAsB;KAAW;IAChVC,aAAa;QAAC;QAAmB;QAAa;QAAyC;QAA0B;QAA0B;QAA8B;QAA4C;QAAmB;QAAa;KAAW;IAChQC,eAAe;QAAC;QAAU;QAAY;QAAqB;QAAiB;QAAmB;KAAW;IAC1GC,OAAO;QAAC;QAAuB;QAAkD;QAAmB;QAAkB;QAAiB;QAAmB;KAAW;IACrKC,eAAe;QAAC;QAA0B;QAAmB;QAAoB;QAA2B;QAAkB;QAAgB;QAAc;QAAc;QAAiB;QAAmB;KAAW;IACzNC,cAAc;QAAC;QAAgB;QAAe;QAAgB;QAA0B;QAAW;KAAW;IAC9GC,YAAY;QAAC;QAA0B;QAAiC;QAA6B;QAA4B;QAAqC;QAA6B;QAAoC;QAAmB;KAAW;IACrQC,OAAO;QAAC;QAA0B;QAA6B;QAAyB;QAAoB;QAAwB;QAAgC;KAAW;IAC/KC,UAAU;QAAC;QAAmD;QAAqB;QAAwB;QAAoB;QAAmB;KAAW;IAC7JC,eAAe;QAAC;QAAuC;QAAU;QAAyD;QAAyB;QAAmB;QAAc;QAAwC;QAA+B;QAAmC;QAAgC;KAAW;IACzUC,SAAS;QAAC;QAAwB;QAAe;QAAmC;QAAiB;QAA2B;QAAkB;QAAoB;QAAwC;QAAmB;QAAwC;QAAuB;QAAoB;QAAqB;QAAiB;QAAU;QAAgB;QAAkB;QAAqB;QAAsB;QAAe;QAAa;QAAgB;QAAe;QAAkB;QAAoB;QAAoB;QAAY;QAAc;QAAkB;KAAW;IAC7lBC,UAAU;QAAC;QAAmB;QAA0B;QAAsB;QAAgB;QAA8B;QAAiB;QAAoB;QAAsB;QAAoC;QAA6B;QAAuB;QAAc;KAAW;IACxSC,UAAU;QAAC;QAAoB;QAAoB;QAAc;QAAsB;QAAgB;QAAW;QAAyB;QAA4B;KAAW;IAClLC,gBAAgB;QAAC;QAA8B;QAAuB;QAAgB;QAAY;QAAoB;QAAyB;QAAS;KAAW;IACnKC,SAAS;QAAC;QAAkC;QAAoC;QAAO;QAAwB;QAAgB;QAAU;QAAyB;KAAW;IAC7KC,UAAU;QAAC;QAAiB;QAAc;QAAmB;QAAoB;QAAe;QAAwB;QAAW;QAAkB;QAAmB;QAAsB;QAAmB;QAAoB;QAAgC;QAAyB;QAAyB;QAAiB;KAAW;IACnVC,kBAAkB;QAAC;QAAuB;QAAsB;QAA4B;QAAoC;QAAmB;QAA8B;QAAyB;QAAqC;QAAkC;QAAuC;KAAW;IACnUC,WAAW;QAAC;QAAuB;QAAqB;QAAoB;QAA0B;QAAsB;QAAoB;QAAe;QAAuB;QAA0B;QAAU;KAAW;IACrOC,aAAa;QAAC;QAAgB;QAAoB;QAAuB;QAAwB;QAAmB;QAAoB;QAA4B;QAAwB;QAAsB;QAAS;QAAsC;QAA2B;QAA0B;QAAuB;QAAiC;QAAkB;KAAyB;IACzZC,mBAAmB;QAAC;QAA0B;QAAmB;QAAwB;QAA2B;QAAkB;QAAqB;QAAoB;QAAmB;QAAiC;QAA6B;KAAW;IAC3QC,eAAe;QAAC;QAAmB;QAAsB;QAAsB;QAAsB;QAAuB;QAAiB;QAA0B;QAA4B;KAAW;IAC9MC,eAAe;QAAC;QAA6B;QAAoB;QAAyB;QAAmC;QAAwB;QAAsB;QAAU;QAAiB;QAAqB;QAA8B;QAAsB;QAAU;KAAW;IACpSC,UAAU;QAAC;QAA0B;QAAsB;QAA4B;QAAsB;QAAoB;QAAa;QAAgC;QAAoB;QAA8B;QAAyB;KAAW;IACpQC,mBAAmB;QAAC;QAA2B;QAAiB;QAAW;QAAuB;QAAyB;QAAuB;QAAsB;KAAW;IACnLC,UAAU;QAAC;QAAsB;QAAsB;QAA0B;QAAmB;QAAgC;QAA0B;QAAe;QAAoB;QAAoB;QAAiB;QAAgB;QAAsB;QAAwB;QAAuB;QAAoB;KAAW;IAC1VC,YAAY;QAAC;QAAsB;QAAa;QAA0B;QAAyB;QAAgB;QAAa;QAA4B;QAAiB;QAA0B;QAAyB;QAAU;QAAsB;QAAoB;QAAgC;KAAW;IAC/TC,aAAa;QAAC;QAAc;QAA6C;QAAkB;QAAqB;QAAgB;QAAoB;QAAkB;QAA2B;QAAY;KAAW;IACxNC,UAAU;QAAC;QAAmB;QAAsB;QAAoB;QAA2C;QAAoB;QAAoB;QAAqC;QAA6B;QAAuB;QAAuC;QAAc;QAA0B;QAAkB;QAAqB;QAAmB;QAAuB;QAAoB;KAAW;IACnbC,UAAU;QAAC;QAAsB;QAAqB;QAAY;QAAiC;QAA+B;QAAqB;QAAuB;QAAkB;KAAW;IAC3MC,UAAU;QAAC;QAAkB;QAAoB;QAAmB;QAAc;QAAgB;QAA0B;QAAiC;QAAmB;KAAW;IAC3LC,OAAO;QAAC;QAAc;QAAW;QAA4B;QAAoB;QAAoB;QAAe;QAA8B;QAA4C;QAAiB;QAAU;KAAW;IACpOC,gBAAgB;QAAC;QAAsB;QAAoB;QAAyB;QAAyB;QAAiB;QAAY;QAA2B;KAA8B;IACnMC,gBAAgB;QAAC;QAAoB;QAAyC;QAA6B;QAA2B;QAAqB;QAA+B;QAA6B;QAAoB;QAA+B;QAA6B;QAA6B;QAAoC;QAAkB;QAAY;QAAgB;QAAsB;QAAqB;QAAgC;QAAoB;QAAuC;QAAoB;QAAuB;QAAgB;QAAiB;QAAiB;QAAkB;QAAkB;QAAuB;QAA4B;QAAgB;QAA6B;QAAkB;QAAwB;QAA2B;QAA6B;QAA4B;QAAgB;QAAe;QAAqB;QAAW;QAAoB;QAAuB;QAAkB;QAA+B;QAAmB;QAAkB;QAAiB;QAAsB;QAA0B;KAAW;IACvoCC,QAAQ;QAAC;QAAkB;QAA4B;QAAmB;KAAW;IACrFC,OAAO;QAAC;QAAkC;QAAiB;QAA+B;QAA8B;QAAiC;QAAgB;QAA4B;QAA2B;QAAiB;QAAkD;QAAyB;QAAc;QAA6B;QAAwB;QAA6B;QAA8B;QAAuB;QAAgB;QAAqB;QAAkC;KAAW;IACniBC,wBAAwB;QAAC;QAAqB;QAAgB;QAAkB;QAAmB;QAAqB;QAAmB;QAAe;QAAe;QAAoB;KAAW;IACxMC,iBAAiB;QAAC;QAAmB;QAAoB;QAAkB;QAAwB;QAAuD;QAAyB;QAAiD;QAAsC;QAAuC;QAAiB;QAAe;QAAa;QAAiB;QAAS;KAAW;IACnYC,iBAAiB;QAAC;QAAiD;QAAwC;QAAuD;QAA+B;QAA4B;QAA0B;KAA8C;IACrSC,mBAAmB;QAAC;QAAqB;QAAuB;QAAc;QAAa;QAAiD;QAAsB;QAAqB;QAAsB;KAAW;IACxNC,aAAa;QAAC;QAAyB;QAAuC;QAAwB;QAAkB;QAAwB;QAAmC;QAAS;KAAW;IACvMC,gBAAgB;QAAC;QAA8B;QAAe;QAAa;QAAU;QAAyB;QAAuC;QAAgC;KAAW;IAChMC,SAAS;QAAC;QAAqB;QAAgB;QAAmB;QAAsC;QAAoB;QAAuC;QAA0C;QAAc;QAAmB;QAAqB;KAAW;IAC9QC,KAAK;QAAC;QAAc;QAAiB;QAAkC;QAA2B;QAA+B;QAAiB;KAAW;IAC7JC,gBAAgB;QAAC;QAAyB;QAAoB;QAAkB;QAA2B;QAAS;KAAW;IAC/HC,mBAAmB;QAAC;QAA8B;QAA4B;QAA0B;QAAmC;QAAuC;QAAyB;QAAuB;QAA0C;QAA8C;QAA0B;QAA4C;QAAiC;QAAsB;QAAoB;QAA2B;QAA0C;QAAwB;QAA2B;QAAqC;QAAiB;KAA6B;IACtpBC,WAAW;QAAC;QAAqB;QAAqC;QAAY;QAAmB;KAAW;IAChHC,iBAAiB;QAAC;QAAsB;QAAgC;QAAqC;QAA+B;QAAmC;KAAW;IAC1LC,WAAW;QAAC;QAAmB;QAA+B;QAAmB;QAAsB;QAAY;QAAc;QAAmB;QAAe;QAAoB;QAAiB;QAAwB;QAAsB;QAA2B;QAAc;QAAqB;QAAoB;QAAW;QAAkB;QAAgB;QAAW;QAAY;QAA0B;QAAgB;KAAW;IACjcC,UAAU;QAAC;QAAsB;QAAqB;QAAS;KAAW;AAC5E,EAA4E"}