@bettercms-ai/kit 2.0.0-next.0 → 2.0.0-next.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (90) hide show
  1. package/dist/adapters/lossy.d.ts +9 -1
  2. package/dist/adapters/lossy.js +16 -5
  3. package/dist/adapters/lossy.js.map +1 -1
  4. package/dist/adapters/prod-types.d.ts +9 -22
  5. package/dist/adapters/prod-types.js +36 -35
  6. package/dist/adapters/prod-types.js.map +1 -1
  7. package/dist/adapters/schema.js +84 -39
  8. package/dist/adapters/schema.js.map +1 -1
  9. package/dist/context.d.ts +39 -0
  10. package/dist/context.js +40 -1
  11. package/dist/context.js.map +1 -1
  12. package/dist/controls/link.js +112 -196
  13. package/dist/controls/link.js.map +1 -1
  14. package/dist/controls/location.js +3 -8
  15. package/dist/controls/location.js.map +1 -1
  16. package/dist/controls/media.d.ts +0 -14
  17. package/dist/controls/media.js +52 -95
  18. package/dist/controls/media.js.map +1 -1
  19. package/dist/controls/rich-text/article-shell.d.ts +145 -0
  20. package/dist/controls/rich-text/article-shell.js +510 -0
  21. package/dist/controls/rich-text/article-shell.js.map +1 -0
  22. package/dist/controls/rich-text/author.d.ts +25 -0
  23. package/dist/controls/rich-text/author.js +104 -0
  24. package/dist/controls/rich-text/author.js.map +1 -0
  25. package/dist/controls/rich-text/blocks.d.ts +19 -2
  26. package/dist/controls/rich-text/blocks.js +273 -638
  27. package/dist/controls/rich-text/blocks.js.map +1 -1
  28. package/dist/controls/rich-text/button.d.ts +23 -0
  29. package/dist/controls/rich-text/button.js +85 -0
  30. package/dist/controls/rich-text/button.js.map +1 -0
  31. package/dist/controls/rich-text/catalog.d.ts +2 -5
  32. package/dist/controls/rich-text/catalog.js +120 -6
  33. package/dist/controls/rich-text/catalog.js.map +1 -1
  34. package/dist/controls/rich-text/checklist.d.ts +24 -0
  35. package/dist/controls/rich-text/checklist.js +115 -0
  36. package/dist/controls/rich-text/checklist.js.map +1 -0
  37. package/dist/controls/rich-text/codec.d.ts +10 -1
  38. package/dist/controls/rich-text/codec.js +11 -1
  39. package/dist/controls/rich-text/codec.js.map +1 -1
  40. package/dist/controls/rich-text/columns.d.ts +41 -0
  41. package/dist/controls/rich-text/columns.js +181 -0
  42. package/dist/controls/rich-text/columns.js.map +1 -0
  43. package/dist/controls/rich-text/control.js +1 -0
  44. package/dist/controls/rich-text/control.js.map +1 -1
  45. package/dist/controls/rich-text/dom.d.ts +84 -4
  46. package/dist/controls/rich-text/dom.js +171 -10
  47. package/dist/controls/rich-text/dom.js.map +1 -1
  48. package/dist/controls/rich-text/editor.d.ts +4 -2
  49. package/dist/controls/rich-text/editor.js +184 -12
  50. package/dist/controls/rich-text/editor.js.map +1 -1
  51. package/dist/controls/rich-text/embed.d.ts +28 -0
  52. package/dist/controls/rich-text/embed.js +210 -0
  53. package/dist/controls/rich-text/embed.js.map +1 -0
  54. package/dist/controls/rich-text/footnote.d.ts +41 -0
  55. package/dist/controls/rich-text/footnote.js +185 -0
  56. package/dist/controls/rich-text/footnote.js.map +1 -0
  57. package/dist/controls/rich-text/gallery.d.ts +28 -0
  58. package/dist/controls/rich-text/gallery.js +167 -0
  59. package/dist/controls/rich-text/gallery.js.map +1 -0
  60. package/dist/controls/rich-text/link-form.d.ts +3 -1
  61. package/dist/controls/rich-text/link-form.js +2 -2
  62. package/dist/controls/rich-text/link-form.js.map +1 -1
  63. package/dist/controls/rich-text/ops.js +6 -0
  64. package/dist/controls/rich-text/ops.js.map +1 -1
  65. package/dist/controls/rich-text/related.d.ts +36 -0
  66. package/dist/controls/rich-text/related.js +213 -0
  67. package/dist/controls/rich-text/related.js.map +1 -0
  68. package/dist/controls/rich-text/toc.d.ts +47 -0
  69. package/dist/controls/rich-text/toc.js +160 -0
  70. package/dist/controls/rich-text/toc.js.map +1 -0
  71. package/dist/core/core.d.ts +11 -3
  72. package/dist/core/core.js +24 -6
  73. package/dist/core/core.js.map +1 -1
  74. package/dist/core/facets.d.ts +16 -0
  75. package/dist/core/facets.js +17 -1
  76. package/dist/core/facets.js.map +1 -1
  77. package/dist/core/index.js +2 -2
  78. package/dist/index.js +4 -4
  79. package/dist/library/kit-catalog.json +47 -44
  80. package/dist/schema/types.d.ts +15 -0
  81. package/dist/schema/types.js.map +1 -1
  82. package/dist/styles.css +1 -1
  83. package/dist/ui/autocomplete.d.ts +29 -1
  84. package/dist/ui/autocomplete.js +102 -47
  85. package/dist/ui/autocomplete.js.map +1 -1
  86. package/dist/ui/button.js +3 -5
  87. package/dist/ui/button.js.map +1 -1
  88. package/dist/ui/index.js +2 -2
  89. package/dist/ui/toast.js +1 -1
  90. package/package.json +3 -1
@@ -115,7 +115,7 @@ export declare const FEATURES: {
115
115
  };
116
116
  readonly "reserved name": {
117
117
  readonly backlog: "corpus-fix";
118
- readonly reason: "A model field's key is not one a resolver would misread (KEY_RESERVED: derived, layout, page, or a leading _) and starts with a letter (KEY_FORMAT): this one is stored renamed.";
118
+ readonly reason: "A model field's key is not one the API reserves (types' KEY_RESERVED: derived, layout, page, a forbidden key or a leading _) and is a letter, then letters, digits, - and _ (KEY_FORMAT): this one is stored renamed. id is allowed.";
119
119
  };
120
120
  readonly rows: {
121
121
  readonly backlog: "corpus-fix";
@@ -169,6 +169,14 @@ export declare const FEATURES: {
169
169
  readonly backlog: "corpus-fix";
170
170
  readonly reason: "A field's time zone is true, false, \"site\" or an IANA zone name, on a date or datetime.";
171
171
  };
172
+ readonly "richtext references": {
173
+ readonly backlog: "corpus-fix";
174
+ readonly reason: "A rich text's references (config.references) are { posts?, authors? }, each a content-model id (letters, digits, - and _, 1-64), on a rich text or document field only: anything else is not stored.";
175
+ };
176
+ readonly "richtext features": {
177
+ readonly backlog: "corpus-fix";
178
+ readonly reason: "A rich text's features (config.features) are distinct names from types RICHTEXT_FEATURES, on a rich text or document field only: a name outside it is not stored, and the rest are.";
179
+ };
172
180
  readonly "shopify reference": {
173
181
  readonly backlog: "deferred:shopify";
174
182
  readonly reason: "A prop reference to Shopify: no Shopify integration backs one (reference_target_unsupported), so a Shopify-only reference is locked text holding the product id (SHOPIFY_REF_LOCK) and a mixed one keeps its other targets. Owner 2026-10-11: deferred until the Shopify integration pipeline is built (allowed-deviations.json status deferred).";
@@ -82,7 +82,7 @@ var FEATURES = {
82
82
  },
83
83
  "reserved name": {
84
84
  backlog: "corpus-fix",
85
- reason: "A model field's key is not one a resolver would misread (KEY_RESERVED: derived, layout, page, or a leading _) and starts with a letter (KEY_FORMAT): this one is stored renamed."
85
+ reason: "A model field's key is not one the API reserves (types' KEY_RESERVED: derived, layout, page, a forbidden key or a leading _) and is a letter, then letters, digits, - and _ (KEY_FORMAT): this one is stored renamed. id is allowed."
86
86
  },
87
87
  rows: {
88
88
  backlog: "corpus-fix",
@@ -136,6 +136,14 @@ var FEATURES = {
136
136
  backlog: "corpus-fix",
137
137
  reason: "A field's time zone is true, false, \"site\" or an IANA zone name, on a date or datetime."
138
138
  },
139
+ "richtext references": {
140
+ backlog: "corpus-fix",
141
+ reason: "A rich text's references (config.references) are { posts?, authors? }, each a content-model id (letters, digits, - and _, 1-64), on a rich text or document field only: anything else is not stored."
142
+ },
143
+ "richtext features": {
144
+ backlog: "corpus-fix",
145
+ reason: "A rich text's features (config.features) are distinct names from types RICHTEXT_FEATURES, on a rich text or document field only: a name outside it is not stored, and the rest are."
146
+ },
139
147
  "shopify reference": {
140
148
  backlog: "deferred:shopify",
141
149
  reason: "A prop reference to Shopify: no Shopify integration backs one (reference_target_unsupported), so a Shopify-only reference is locked text holding the product id (SHOPIFY_REF_LOCK) and a mixed one keeps its other targets. Owner 2026-10-11: deferred until the Shopify integration pipeline is built (allowed-deviations.json status deferred)."
@@ -285,8 +293,7 @@ var HOST_CONFIG_KEYS = {
285
293
  "inline",
286
294
  "allowTargetBlank",
287
295
  "components",
288
- "hostTag",
289
- "features"
296
+ "hostTag"
290
297
  ])
291
298
  };
292
299
  var isHostConfigKey = (type, key) => HOST_CONFIG_KEYS.any.has(key) || (type === "richtext" || type === "document") && HOST_CONFIG_KEYS.richtext.has(key);
@@ -331,14 +338,18 @@ var KIT_READ_CONFIG_KEYS = {
331
338
  "maxLength",
332
339
  "pattern",
333
340
  "patternMessage",
334
- "inputType"
341
+ "inputType",
342
+ "features",
343
+ "references"
335
344
  ],
336
345
  document: [
337
346
  "minLength",
338
347
  "maxLength",
339
348
  "pattern",
340
349
  "patternMessage",
341
- "inputType"
350
+ "inputType",
351
+ "features",
352
+ "references"
342
353
  ],
343
354
  number: [
344
355
  "min",
@@ -1 +1 @@
1
- {"version":3,"file":"lossy.js","names":[],"sources":["../../src/adapters/lossy.ts"],"sourcesContent":["/**\n * LOSSY ITEMS — every V2 schema feature the production language cannot hold is named, never dropped silently.\n * CATALOG ITEMS (below) are the V2 metadata a host sets at seeding time, which the dock never stores.\n *\n * `path` is a JSON pointer into the V2 TypeSchema (\"/fields/3/of/0/fields/1/localized\"). `feature` is a stable name\n * from FEATURES (what the lossy ledger counts), `reason` says why prod cannot keep it, and FEATURES[feature].backlog\n * names what removes the loss.\n */\nexport interface LossyItem {\n path: string;\n feature: LossyFeature;\n reason: string;\n}\n\n/**\n * What removes a lossy feature: a named backend backlog item (its receipt is this feature's lossy count reaching 0), or\n * an explicit disposition that is not backend work: `corpus-fix` (the V2 schema breaks a prod rule the author can\n * satisfy: rename, shorten, reorder, drop a key the type cannot use), `dashboard:F12` (prod stores it; only the dock's\n * DockFieldTabs drops it, and the kit's GroupTabs replaces that at the dock cutover), `wontfix:depth` (a prod rule kept\n * on purpose: the backend refuses an 11th level with field_depth_exceeded), `wontfix:item-config` (the backend refuses\n * per-item config on a list of scalars on purpose, array_config_key_unknown), `wontfix:nesting` (the backend keeps a\n * slot's settings leaf fields, on purpose: slot_settings_invalid), `deferred:shopify` (owner 2026-10-11: a Shopify\n * reference stays locked text until the Shopify integration pipeline is built; allowed-deviations.json \"deferred\"). Owner 2026-10-11 (C11): the backend keeps a scalar list's\n * item settings (config.item), a list's bounds to 500, openMode on code, a slot's allow names (config.allow), a dotted\n * document preview path, the tabs no top-level prop sits in (components.tabs) and a nested field's tab (ui.tab { id }).\n * corpus-fix items are V2 corpus defects, an\n * owner note for the demo repo: the sandbox renders them from the V2 schema, seeding skips them.\n *\n * Landed on origin/dev and mapped here, so they name no feature any more: prop-reference (73a120c50), prop reference targets + filter (a4ce1ae95; shopify stays named), validation-parity\n * (dd021ceba), option-meta (ab15fe893), chrome-keys (98e48b9e3, 324580b2e), adapter:icons (the V2 icon vocabulary,\n * e126bf33d), localized-flag (279a10490), table / polymorphic list nesting (B1/B2: a data table or a polymorphic list at\n * any depth, in an object, a list's rows or an item type), slot nesting (C1/C2: a slot prop at any depth). What those\n * keys still cannot hold is a value the backend refuses, named below as corpus-fix.\n */\nexport type Backlog =\n | \"reference-targets\"\n | \"table\"\n | \"slot\"\n | \"block-model-fields\"\n | \"corpus-fix\"\n | \"dashboard:F12\"\n | \"wontfix:depth\"\n | \"wontfix:nesting\"\n | \"wontfix:item-config\"\n | \"deferred:shopify\";\n\nexport const FEATURES = {\n /* field types prod has no home for (the value is kept in a json field, or a near type) */\n \"type:table\": { backlog: \"table\", reason: \"Prod has no table field type (BE: a new type): the TableValue is stored verbatim in a json field.\" },\n \"type:slot\": { backlog: \"slot\", reason: \"Blocks inside a block on a content model: the backend's slot field (kind:'block' models by blockSlugs) is not mapped by this adapter yet, so it is stored as json. A component's top-level slot is a slot prop.\" },\n \"type:polymorphic-array\": { backlog: \"slot\", reason: \"An array of several item types: a model stores it as modular and a prop as a polymorphic list (table, config.mode \\\"types\\\"), both of object item types only. A list mixing scalar item types is stored as json.\" },\n \"item chrome (types)\": { backlog: \"slot\", reason: \"A polymorphic list's item type is { name, label?, fields, icon?, preview? } (item_types_invalid): it keeps its dock icon and row preview, and no other chrome.\" },\n \"type:primitive-array\": { backlog: \"wontfix:item-config\", reason: \"A list of this item type has no prod array form: config.itemType is text, number, date, image, link or richtext. Stored as json.\" },\n \"depth>10\": { backlog: \"wontfix:depth\", reason: \"Prod allows 10 field levels: the object at level 10 that would nest an 11th is stored as json.\" },\n /* document level */\n \"type name\": { backlog: \"corpus-fix\", reason: \"The schema name is stored as a kebab-case slug, which does not read back as this name.\" },\n /* tabs and sections */\n \"group name>40\": { backlog: \"corpus-fix\", reason: \"A tab name is at most 40 characters; truncated.\" },\n \"group title\": { backlog: \"corpus-fix\", reason: \"A prop tab's label is the group title trimmed (1–20 characters): a blank title defines no tab, so the group is not stored and its props sit in the default tab; spaces around a title are not kept.\" },\n \"group default\": { backlog: \"corpus-fix\", reason: \"The default tab is always the first one in prod.\" },\n \"group icon\": { backlog: \"corpus-fix\", reason: \"A tab icon is a dock icon name (DOCK_ICON_NAMES); this name is not one.\" },\n \"group (nested)\": { backlog: \"corpus-fix\", reason: \"A nested field names its tab as ui.tab { id } only when the tab is stored: this group is not (named on the group itself).\" },\n \"groups>3\": { backlog: \"dashboard:F12\", reason: \"The dock shows at most 3 tabs (DockFieldTabs), so the adapter keeps 3 until the kit GroupTabs replaces DockFieldTabs at the dock cutover: later groups' fields land in the default tab meanwhile.\" },\n \"group name collision\": { backlog: \"corpus-fix\", reason: \"Two tabs share an id, or a stored name (the first 20 characters, trimmed, any case): the backend refuses that (tab_name, fieldset ids), so the later tab is not stored.\" },\n \"prop tab limit\": { backlog: \"corpus-fix\", reason: \"A component holds at most 8 tabs, each with an id of 1–40 characters (the backend's ui.tab rule): this group is not stored and its props sit in the default tab.\" },\n \"fieldset spans groups\": { backlog: \"corpus-fix\", reason: \"A prod fieldset sits in one tab; this field's tab differs from its fieldset's.\" },\n \"fieldset (props)\": { backlog: \"corpus-fix\", reason: \"A prop group is defined on the first prop that uses it: a fieldset no prop uses is not stored (and the ones after it move up a place).\" },\n \"fieldset name>limit\": { backlog: \"corpus-fix\", reason: \"A fieldset name is at most 60 characters (a prop group label 32); truncated.\" },\n \"fieldset collision\": { backlog: \"corpus-fix\", reason: \"A fieldset shares its id with a group, or this field names a fieldset the schema does not define.\" },\n /* field chrome and rules */\n \"duplicate name\": { backlog: \"corpus-fix\", reason: \"Two sibling fields share a name; prod keys are unique per level, so the later one is renamed.\" },\n \"reserved name\": {\n backlog: \"corpus-fix\",\n reason: \"A model field's key is not one a resolver would misread (KEY_RESERVED: derived, layout, page, or a leading _) and starts with a letter (KEY_FORMAT): this one is stored renamed.\",\n },\n rows: { backlog: \"corpus-fix\", reason: \"ui.rows is a whole number from 1 to 40, on a text or long text field only.\" },\n synced: { backlog: \"corpus-fix\", reason: \"ui.synced names its global in 1–64 characters (trimmed).\" },\n valueShape: { backlog: \"corpus-fix\", reason: \"ui.valueShape is for a link, image or button field only.\" },\n \"default value\": { backlog: \"corpus-fix\", reason: \"This initial value holds what the prod value cannot keep (named under it): a crop preset with no image size, a datetime without seconds, a button icon outside the dock vocabulary…\" },\n slotSettings: { backlog: \"wontfix:nesting\", reason: \"A slot's per-child settings are at most 20 leaf fields (slot_settings_invalid): this setting is an object, a list, a table, a slot or a form, or past the 20th, or the field holding them is not a slot.\" },\n icon: { backlog: \"corpus-fix\", reason: \"A field icon is ui.icon, a dock icon name, on a nesting field only (an object, a list of objects, a modular list); this field is a leaf, or the name is not a dock icon.\" },\n layout: { backlog: \"corpus-fix\", reason: \"This layout does not fit the field in prod: ui.control is dropdown / radio / grid on a select, cards on a select or multiselect, checkbox on a boolean or multiselect, switch on a boolean, segmented on a select of 2–4 options, slider on a number with min < max (≤ 1000 stops); a list of scalars or entries lays out as rows or a gallery.\" },\n \"help>limit\": { backlog: \"corpus-fix\", reason: \"Help text is at most 500 characters on a field and 200 on a prop (a placeholder 120, a prop group description 200); truncated.\" },\n \"option icon\": { backlog: \"corpus-fix\", reason: \"Option icons are dock icon names, all or none per list: an icon in this list is not a dock name, so the list stores none (option_icon_unknown).\" },\n \"option description\": { backlog: \"corpus-fix\", reason: \"An option description is one line of 1–140 characters (option_description_invalid).\" },\n condition: { backlog: \"corpus-fix\", reason: \"This condition has no prod showIf form: it names something that is not a sibling (the block's _variant is one only for a top-level prop: show_if_variant_field), names it by `scope` (prod resolves a rule at the nearest level that declares its field), or tests a value showIf cannot.\" },\n access: { backlog: \"corpus-fix\", reason: \"ui.access takes view \\\"schema.view\\\" and edit \\\"schema.manage\\\" only (access_cap_unknown), and a developer lock (readOnly \\\"developer\\\") is not also a plain read-only flag.\" },\n timezone: { backlog: \"corpus-fix\", reason: \"A field's time zone is true, false, \\\"site\\\" or an IANA zone name, on a date or datetime.\" },\n \"shopify reference\": {\n backlog: \"deferred:shopify\",\n reason:\n \"A prop reference to Shopify: no Shopify integration backs one (reference_target_unsupported), so a Shopify-only reference is locked text holding the product id (SHOPIFY_REF_LOCK) and a mixed one keeps its other targets. Owner 2026-10-11: deferred until the Shopify integration pipeline is built (allowed-deviations.json status deferred).\",\n },\n \"reference target\": { backlog: \"reference-targets\", reason: \"A prop reference keeps entry models (contentModelId / allowedModelSlugs) and page, form and collection (config.targets, backend a4ce1ae95); Shopify has no integration behind it (reference_target_unsupported), so a shopify target is dropped and a reference with only shopify is stored as json. A content-model field keeps entry models only.\" },\n \"reference order\": { backlog: \"corpus-fix\", reason: \"Prod keeps a reference's entry models apart from its page / form / collection targets: the list reads back entry models first, then the targets.\" },\n \"reference filter\": { backlog: \"reference-targets\", reason: \"A prop reference keeps its filter as config.filter (1–500 characters, no $parameters or ^ parent: reference_filter_invalid); a content-model field keeps none.\" },\n \"numeric unit\": { backlog: \"corpus-fix\", reason: \"config.unit is a number's (1–24 characters); a rating has no unit.\" },\n \"rating bounds\": { backlog: \"corpus-fix\", reason: \"A prod rating runs from config.min (≥ 0) to config.max (a whole 1–10) in steps of config.step, min < max and at most 100 whole steps apart.\" },\n \"scale rules\": { backlog: \"corpus-fix\", reason: \"This scale breaks prod's scale rules: token values 1–32 characters and distinct, labels 1–24, at most 50 steps and 20 presets, a token preset naming a step, a { value, unit } preset needing allowCustom.\" },\n \"validation.patternMessage\": { backlog: \"corpus-fix\", reason: \"A pattern message needs a stored pattern and is 1–200 characters.\" },\n \"validation.pattern\": { backlog: \"corpus-fix\", reason: \"A pattern is kept on text, long text and url values, a regex of at most 200 characters that compiles.\" },\n \"validation.length\": { backlog: \"corpus-fix\", reason: \"Length limits are whole numbers ≥ 0, on text, long text, url and rich text values.\" },\n \"validation.items\": { backlog: \"corpus-fix\", reason: \"Item limits are whole numbers ≥ 0 on a list, min ≤ max: a tags max 1–500 and min 0–500, a prop's own list (table, array) at most 500 (LIST_ITEMS_CAP), a slot's at most 50 (SLOT_ITEMS_CAP).\" },\n \"validation.unique\": { backlog: \"corpus-fix\", reason: \"unique is for text, long text, slug, email, phone, link, number, select, date and single-model reference fields, and lists; a polymorphic reference has no one id to compare.\" },\n \"validation.recommendedMax\": { backlog: \"corpus-fix\", reason: \"A soft limit is a positive whole number in prod.\" },\n \"item identity\": { backlog: \"corpus-fix\", reason: \"A list item's name is an identifier (a letter, then letters, digits or _; ≤ 64) and its title 1–60 characters (ui.itemName / ui.itemTitle); an object item keeps no other key.\" },\n \"item settings\": { backlog: \"corpus-fix\", reason: \"A list of scalars keeps its item's description (1–200 characters), localized flag, required, a text or rich text item's length and a text item's pattern (config.item, array_item_settings_invalid): this setting is none of those, or out of their bounds (a multi-line text item reads back single-line).\" },\n itemNoun: { backlog: \"corpus-fix\", reason: \"The item noun is ui.itemLabel, capitalised, at most 24 characters.\" },\n \"block model field\": { backlog: \"block-model-fields\", reason: \"A modular item type is a kind:'block' model, which holds only fields a block primitive renders (text, long text, rich text, image, link, slug, email, phone, color, select, number, rating, date, datetime, boolean): this field is not stored.\" },\n \"item icon\": { backlog: \"corpus-fix\", reason: \"Prod keeps one icon per list (ui.icon, a dock name) and one per polymorphic item type: the list has its own icon, or this name is not a dock icon.\" },\n \"preview icon\": { backlog: \"corpus-fix\", reason: \"A row preview's icon is a dock icon name.\" },\n \"preview path\": { backlog: \"corpus-fix\", reason: \"A row preview names a child key, or a dotted path whose later segments are children or keys of an image, video, link, button, file, location, json, code or reference value, or a data table's caption or notes (preview_path_unknown).\" },\n openMode: { backlog: \"corpus-fix\", reason: \"openMode is for object, array, table and code fields only (openMode_leaf).\" },\n \"unsupported key\": { backlog: \"corpus-fix\", reason: \"This V2 key has no prod mapping.\" },\n} as const satisfies Record<string, { reason: string; backlog: Backlog }>;\n\nexport type LossyFeature = keyof typeof FEATURES;\n\n/**\n * CATALOG ITEMS — V2 metadata the dock never stores, set when a schema is seeded or placed by its host: not a loss of\n * stored content. Reported apart from LossyItem so the lossy ledger counts only what prod drops.\n */\nexport interface CatalogItem {\n path: string;\n feature: CatalogFeature;\n reason: string;\n}\n\nexport const CATALOG = {\n \"block icon\": \"The block picker's icon belongs to the catalog entry; a model carries none (a component stores it as component.icon, a dock icon, so only one with no dock name for it lands here).\",\n category: \"The block picker's category is catalog metadata. A component takes the nearest prod category (CATEGORY_TO_PROD) when there is one; a model has none.\",\n \"document preview\": \"The document-level preview (how a row of this type reads in a parent's list) has no place on a model; a component stores it as component.preview.\",\n \"document preview path\": \"component.preview names a top-level prop key or a dotted path into one (`slides.0.heading`, componentPreviewRefusals); a key no prop has, or a path through a renamed value key (`image.alt`), is not stored (preview_key_unknown), so the slot row reads the child's first text instead.\",\n \"kind:block (fields)\": \"A section's fields are stored as a model (kind model): which host places it is set at seeding.\",\n \"kind:global\": \"A global (synced) block is a host-level placement; its fields are stored as a model or a component.\",\n \"kind:page\": \"A page schema is stored as a model; the host makes it a page.\",\n \"kind:object\": \"An object type is stored as a model.\",\n \"kind:entry (props)\": \"Only blocks become components; the host decides what an entry schema is placed as.\",\n variants: \"Variants are separate components sharing a sectionType in prod: the host seeds one per variant.\",\n ai: \"The AI-assist sparkle is a host setting, not stored on the field.\",\n \"item openMode\": \"Prod keeps one openMode per list, the array's own; the V2 engine reads only that one too (lib/schema.ts itemOpenMode ignores the item's), so the item's changes nothing the dock shows.\",\n \"itemNoun (derived)\": \"A list with no itemNoun whose item title is not the field title's singular: ui.itemLabel keeps the item title, and the read side names the noun from it, which is the noun the V2 engine already falls back to (lib/schema.ts itemNoun).\",\n \"fieldset (derived)\": \"A field names a fieldset the schema does not declare: the V2 engine draws it as a section titled by its name (engine/field-list.tsx arrange), so it is stored as that prop group and the read side declares it. Not a loss.\",\n \"prop target\": \"A V2 prop has no binding path, so fromTypeSchema('props') returns none: seeding binds each prop to its target. Not a loss.\",\n \"block placement\": \"Where a block fits (inline / section / page) is the host's: the block picker and a body's Insert menu place it; a model or component carries none.\",\n \"slot allow\": \"A slot keeps its V2 allow list as config.allow (1–50 block names of 1–64 characters, no repeats: slot_allow_invalid), which the dock resolves to the project's components; this list breaks those bounds, so the slot takes any component.\",\n \"segmented fallback\": \"A segmented select of 5+ options: V2 draws the dropdown (D46, choice.tsx fitsSegmented) and prod stores the select with no control (control_segmented holds 2–4), which the dock draws as the same dropdown. Nothing drawn differs.\",\n \"seeded instance\": \"A starting value the host writes into a new instance when it seeds or places one: a schema-level initialValue, a reference prop's default (a definition holds none: reference_in_definition), or a slot's children (they name V2 block types, which become component instances at seeding).\",\n \"not applicable (props)\": \"unique on a scalar prop, or on a sub-field outside a table: each placement holds its own value, so there is nothing to be unique across (unique_prop_scope). The instance is the whole document.\",\n \"host config\": \"A prod-only prop config key the host reads, not the V2 schema: a rich text's Accept list, its one-paragraph flags (allowMultipleParagraphs, the older inline), allowTargetBlank and component allowlist (the dock's rich-text codec and insert menu read them from the stored prop: dock-v2 richTextCodec configAt, kitServices insertableComponents), a section label, and the import's write-back metadata no editor reads (SERVER_CONFIG_KEYS). Read back, it names no loss: the kit never writes a definition, so the config rides untouched.\",\n} as const;\n\nexport type CatalogFeature = keyof typeof CATALOG;\n\n/**\n * Keys the import (BE derive-schema.ts, register-editable-pages.ts, template-copy.ts) writes onto a field for the\n * SERVER: how publish writes a value back into the site's own HTML (`attr`, `numeric`, `iconFont`, `htmlClasses`,\n * `units`, `lead`), which band a field belongs to (`band`, `family`, `shape`), and import markers (`seeded`, `shared`,\n * `sharedValue`). No form reads them, so no form loses anything by leaving them alone, and no agent may write them: the\n * backend MCP drops them from what an agent sends, and its contract test fails on any key the import writes that is\n * neither here, a host key, nor read by the kit (kit-catalog.json `fieldConfig`).\n */\nexport const SERVER_CONFIG_KEYS: ReadonlySet<string> = new Set([\n \"seeded\", \"shared\", \"sharedValue\", \"attr\", \"numeric\", \"iconFont\", \"htmlClasses\", \"units\", \"lead\", \"band\", \"family\", \"shape\",\n]);\n\n/** The prop config keys CATALOG \"host config\" covers: any type's, then a rich text's (richtext, document) own. */\nexport const HOST_CONFIG_KEYS: { any: ReadonlySet<string>; richtext: ReadonlySet<string> } = {\n // A band's name, its kind and its own heading, which the derive lane writes on the band's first field.\n // `format`: how a number is shown ($1,200+), which the canvas, the classic preview and publish read; the value stays a number\n any: new Set([\"sectionLabel\", \"sectionShape\", \"sectionTitle\", \"format\", ...SERVER_CONFIG_KEYS]),\n // `hostTag` and `features` (the dock's load hint) are read from the stored field by the rich-text host, like the rest\n richtext: new Set([\"accept\", \"allowMultipleParagraphs\", \"inline\", \"allowTargetBlank\", \"components\", \"hostTag\", \"features\"]),\n};\n\nexport const isHostConfigKey = (type: string, key: string): boolean =>\n HOST_CONFIG_KEYS.any.has(key) || ((type === \"richtext\" || type === \"document\") && HOST_CONFIG_KEYS.richtext.has(key));\n\n/**\n * The prod config keys the kit adapter READS, per prod field type (`*` = every type): what an agent may write on a\n * field and still edit it in the kit. Exported to the backend with the host and server keys (kit-catalog.json\n * `fieldConfig`), where the MCP warns on any other key and its contract test checks what the import writes.\n * field-config-contract.test.ts proves each entry against `toTypeSchema`, so this list cannot claim a key the\n * adapter drops; a key missing here only costs a warning.\n */\nexport const KIT_READ_CONFIG_KEYS: Readonly<Record<string, readonly string[]>> = {\n \"*\": [\"placeholder\", \"zones\", \"options\", \"fields\", \"linkHref\"],\n text: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n longtext: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n url: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n richtext: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n document: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n number: [\"min\", \"max\", \"step\", \"scale\", \"unit\", \"validation\"],\n rating: [\"min\", \"max\", \"step\", \"scale\", \"unit\", \"validation\"],\n select: [\"multiSelect\"],\n multiselect: [\"min\", \"max\", \"allowCustom\"],\n tags: [\"min\", \"max\", \"allowCustom\"],\n code: [\"language\", \"languages\"],\n date: [\"timezone\", \"includeTime\"],\n datetime: [\"timezone\", \"includeTime\"],\n reference: [\"contentModelId\", \"polymorphic\", \"allowedModelSlugs\", \"targets\", \"filter\"],\n \"multi-reference\": [\"contentModelId\", \"polymorphic\", \"allowedModelSlugs\", \"targets\", \"filter\", \"min\", \"max\"],\n array: [\"itemType\", \"minItems\", \"maxItems\", \"item\"],\n image: [\"media\"],\n modular: [\"blockSlugs\", \"minItems\", \"maxItems\"],\n};\n\n/** The field-config contract the backend reads (kit-catalog.json `fieldConfig`). */\nexport const fieldConfigContract = () => ({\n read: KIT_READ_CONFIG_KEYS,\n host: { any: [...HOST_CONFIG_KEYS.any].filter((k) => !SERVER_CONFIG_KEYS.has(k)), richtext: [...HOST_CONFIG_KEYS.richtext] },\n server: [...SERVER_CONFIG_KEYS],\n});\n"],"mappings":"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"}
1
+ {"version":3,"file":"lossy.js","names":[],"sources":["../../src/adapters/lossy.ts"],"sourcesContent":["/**\n * LOSSY ITEMS — every V2 schema feature the production language cannot hold is named, never dropped silently.\n * CATALOG ITEMS (below) are the V2 metadata a host sets at seeding time, which the dock never stores.\n *\n * `path` is a JSON pointer into the V2 TypeSchema (\"/fields/3/of/0/fields/1/localized\"). `feature` is a stable name\n * from FEATURES (what the lossy ledger counts), `reason` says why prod cannot keep it, and FEATURES[feature].backlog\n * names what removes the loss.\n */\nexport interface LossyItem {\n path: string;\n feature: LossyFeature;\n reason: string;\n}\n\n/**\n * What removes a lossy feature: a named backend backlog item (its receipt is this feature's lossy count reaching 0), or\n * an explicit disposition that is not backend work: `corpus-fix` (the V2 schema breaks a prod rule the author can\n * satisfy: rename, shorten, reorder, drop a key the type cannot use), `dashboard:F12` (prod stores it; only the dock's\n * DockFieldTabs drops it, and the kit's GroupTabs replaces that at the dock cutover), `wontfix:depth` (a prod rule kept\n * on purpose: the backend refuses an 11th level with field_depth_exceeded), `wontfix:item-config` (the backend refuses\n * per-item config on a list of scalars on purpose, array_config_key_unknown), `wontfix:nesting` (the backend keeps a\n * slot's settings leaf fields, on purpose: slot_settings_invalid), `deferred:shopify` (owner 2026-10-11: a Shopify\n * reference stays locked text until the Shopify integration pipeline is built; allowed-deviations.json \"deferred\"). Owner 2026-10-11 (C11): the backend keeps a scalar list's\n * item settings (config.item), a list's bounds to 500, openMode on code, a slot's allow names (config.allow), a dotted\n * document preview path, the tabs no top-level prop sits in (components.tabs) and a nested field's tab (ui.tab { id }).\n * corpus-fix items are V2 corpus defects, an\n * owner note for the demo repo: the sandbox renders them from the V2 schema, seeding skips them.\n *\n * Landed on origin/dev and mapped here, so they name no feature any more: prop-reference (73a120c50), prop reference targets + filter (a4ce1ae95; shopify stays named), validation-parity\n * (dd021ceba), option-meta (ab15fe893), chrome-keys (98e48b9e3, 324580b2e), adapter:icons (the V2 icon vocabulary,\n * e126bf33d), localized-flag (279a10490), table / polymorphic list nesting (B1/B2: a data table or a polymorphic list at\n * any depth, in an object, a list's rows or an item type), slot nesting (C1/C2: a slot prop at any depth). What those\n * keys still cannot hold is a value the backend refuses, named below as corpus-fix.\n */\nexport type Backlog =\n | \"reference-targets\"\n | \"table\"\n | \"slot\"\n | \"block-model-fields\"\n | \"corpus-fix\"\n | \"dashboard:F12\"\n | \"wontfix:depth\"\n | \"wontfix:nesting\"\n | \"wontfix:item-config\"\n | \"deferred:shopify\";\n\nexport const FEATURES = {\n /* field types prod has no home for (the value is kept in a json field, or a near type) */\n \"type:table\": { backlog: \"table\", reason: \"Prod has no table field type (BE: a new type): the TableValue is stored verbatim in a json field.\" },\n \"type:slot\": { backlog: \"slot\", reason: \"Blocks inside a block on a content model: the backend's slot field (kind:'block' models by blockSlugs) is not mapped by this adapter yet, so it is stored as json. A component's top-level slot is a slot prop.\" },\n \"type:polymorphic-array\": { backlog: \"slot\", reason: \"An array of several item types: a model stores it as modular and a prop as a polymorphic list (table, config.mode \\\"types\\\"), both of object item types only. A list mixing scalar item types is stored as json.\" },\n \"item chrome (types)\": { backlog: \"slot\", reason: \"A polymorphic list's item type is { name, label?, fields, icon?, preview? } (item_types_invalid): it keeps its dock icon and row preview, and no other chrome.\" },\n \"type:primitive-array\": { backlog: \"wontfix:item-config\", reason: \"A list of this item type has no prod array form: config.itemType is text, number, date, image, link or richtext. Stored as json.\" },\n \"depth>10\": { backlog: \"wontfix:depth\", reason: \"Prod allows 10 field levels: the object at level 10 that would nest an 11th is stored as json.\" },\n /* document level */\n \"type name\": { backlog: \"corpus-fix\", reason: \"The schema name is stored as a kebab-case slug, which does not read back as this name.\" },\n /* tabs and sections */\n \"group name>40\": { backlog: \"corpus-fix\", reason: \"A tab name is at most 40 characters; truncated.\" },\n \"group title\": { backlog: \"corpus-fix\", reason: \"A prop tab's label is the group title trimmed (1–20 characters): a blank title defines no tab, so the group is not stored and its props sit in the default tab; spaces around a title are not kept.\" },\n \"group default\": { backlog: \"corpus-fix\", reason: \"The default tab is always the first one in prod.\" },\n \"group icon\": { backlog: \"corpus-fix\", reason: \"A tab icon is a dock icon name (DOCK_ICON_NAMES); this name is not one.\" },\n \"group (nested)\": { backlog: \"corpus-fix\", reason: \"A nested field names its tab as ui.tab { id } only when the tab is stored: this group is not (named on the group itself).\" },\n \"groups>3\": { backlog: \"dashboard:F12\", reason: \"The dock shows at most 3 tabs (DockFieldTabs), so the adapter keeps 3 until the kit GroupTabs replaces DockFieldTabs at the dock cutover: later groups' fields land in the default tab meanwhile.\" },\n \"group name collision\": { backlog: \"corpus-fix\", reason: \"Two tabs share an id, or a stored name (the first 20 characters, trimmed, any case): the backend refuses that (tab_name, fieldset ids), so the later tab is not stored.\" },\n \"prop tab limit\": { backlog: \"corpus-fix\", reason: \"A component holds at most 8 tabs, each with an id of 1–40 characters (the backend's ui.tab rule): this group is not stored and its props sit in the default tab.\" },\n \"fieldset spans groups\": { backlog: \"corpus-fix\", reason: \"A prod fieldset sits in one tab; this field's tab differs from its fieldset's.\" },\n \"fieldset (props)\": { backlog: \"corpus-fix\", reason: \"A prop group is defined on the first prop that uses it: a fieldset no prop uses is not stored (and the ones after it move up a place).\" },\n \"fieldset name>limit\": { backlog: \"corpus-fix\", reason: \"A fieldset name is at most 60 characters (a prop group label 32); truncated.\" },\n \"fieldset collision\": { backlog: \"corpus-fix\", reason: \"A fieldset shares its id with a group, or this field names a fieldset the schema does not define.\" },\n /* field chrome and rules */\n \"duplicate name\": { backlog: \"corpus-fix\", reason: \"Two sibling fields share a name; prod keys are unique per level, so the later one is renamed.\" },\n \"reserved name\": {\n backlog: \"corpus-fix\",\n reason: \"A model field's key is not one the API reserves (types' KEY_RESERVED: derived, layout, page, a forbidden key or a leading _) and is a letter, then letters, digits, - and _ (KEY_FORMAT): this one is stored renamed. id is allowed.\",\n },\n rows: { backlog: \"corpus-fix\", reason: \"ui.rows is a whole number from 1 to 40, on a text or long text field only.\" },\n synced: { backlog: \"corpus-fix\", reason: \"ui.synced names its global in 1–64 characters (trimmed).\" },\n valueShape: { backlog: \"corpus-fix\", reason: \"ui.valueShape is for a link, image or button field only.\" },\n \"default value\": { backlog: \"corpus-fix\", reason: \"This initial value holds what the prod value cannot keep (named under it): a crop preset with no image size, a datetime without seconds, a button icon outside the dock vocabulary…\" },\n slotSettings: { backlog: \"wontfix:nesting\", reason: \"A slot's per-child settings are at most 20 leaf fields (slot_settings_invalid): this setting is an object, a list, a table, a slot or a form, or past the 20th, or the field holding them is not a slot.\" },\n icon: { backlog: \"corpus-fix\", reason: \"A field icon is ui.icon, a dock icon name, on a nesting field only (an object, a list of objects, a modular list); this field is a leaf, or the name is not a dock icon.\" },\n layout: { backlog: \"corpus-fix\", reason: \"This layout does not fit the field in prod: ui.control is dropdown / radio / grid on a select, cards on a select or multiselect, checkbox on a boolean or multiselect, switch on a boolean, segmented on a select of 2–4 options, slider on a number with min < max (≤ 1000 stops); a list of scalars or entries lays out as rows or a gallery.\" },\n \"help>limit\": { backlog: \"corpus-fix\", reason: \"Help text is at most 500 characters on a field and 200 on a prop (a placeholder 120, a prop group description 200); truncated.\" },\n \"option icon\": { backlog: \"corpus-fix\", reason: \"Option icons are dock icon names, all or none per list: an icon in this list is not a dock name, so the list stores none (option_icon_unknown).\" },\n \"option description\": { backlog: \"corpus-fix\", reason: \"An option description is one line of 1–140 characters (option_description_invalid).\" },\n condition: { backlog: \"corpus-fix\", reason: \"This condition has no prod showIf form: it names something that is not a sibling (the block's _variant is one only for a top-level prop: show_if_variant_field), names it by `scope` (prod resolves a rule at the nearest level that declares its field), or tests a value showIf cannot.\" },\n access: { backlog: \"corpus-fix\", reason: \"ui.access takes view \\\"schema.view\\\" and edit \\\"schema.manage\\\" only (access_cap_unknown), and a developer lock (readOnly \\\"developer\\\") is not also a plain read-only flag.\" },\n timezone: { backlog: \"corpus-fix\", reason: \"A field's time zone is true, false, \\\"site\\\" or an IANA zone name, on a date or datetime.\" },\n \"richtext references\": {\n backlog: \"corpus-fix\",\n reason: \"A rich text's references (config.references) are { posts?, authors? }, each a content-model id (letters, digits, - and _, 1-64), on a rich text or document field only: anything else is not stored.\",\n },\n \"richtext features\": {\n backlog: \"corpus-fix\",\n reason: \"A rich text's features (config.features) are distinct names from types RICHTEXT_FEATURES, on a rich text or document field only: a name outside it is not stored, and the rest are.\",\n },\n \"shopify reference\": {\n backlog: \"deferred:shopify\",\n reason:\n \"A prop reference to Shopify: no Shopify integration backs one (reference_target_unsupported), so a Shopify-only reference is locked text holding the product id (SHOPIFY_REF_LOCK) and a mixed one keeps its other targets. Owner 2026-10-11: deferred until the Shopify integration pipeline is built (allowed-deviations.json status deferred).\",\n },\n \"reference target\": { backlog: \"reference-targets\", reason: \"A prop reference keeps entry models (contentModelId / allowedModelSlugs) and page, form and collection (config.targets, backend a4ce1ae95); Shopify has no integration behind it (reference_target_unsupported), so a shopify target is dropped and a reference with only shopify is stored as json. A content-model field keeps entry models only.\" },\n \"reference order\": { backlog: \"corpus-fix\", reason: \"Prod keeps a reference's entry models apart from its page / form / collection targets: the list reads back entry models first, then the targets.\" },\n \"reference filter\": { backlog: \"reference-targets\", reason: \"A prop reference keeps its filter as config.filter (1–500 characters, no $parameters or ^ parent: reference_filter_invalid); a content-model field keeps none.\" },\n \"numeric unit\": { backlog: \"corpus-fix\", reason: \"config.unit is a number's (1–24 characters); a rating has no unit.\" },\n \"rating bounds\": { backlog: \"corpus-fix\", reason: \"A prod rating runs from config.min (≥ 0) to config.max (a whole 1–10) in steps of config.step, min < max and at most 100 whole steps apart.\" },\n \"scale rules\": { backlog: \"corpus-fix\", reason: \"This scale breaks prod's scale rules: token values 1–32 characters and distinct, labels 1–24, at most 50 steps and 20 presets, a token preset naming a step, a { value, unit } preset needing allowCustom.\" },\n \"validation.patternMessage\": { backlog: \"corpus-fix\", reason: \"A pattern message needs a stored pattern and is 1–200 characters.\" },\n \"validation.pattern\": { backlog: \"corpus-fix\", reason: \"A pattern is kept on text, long text and url values, a regex of at most 200 characters that compiles.\" },\n \"validation.length\": { backlog: \"corpus-fix\", reason: \"Length limits are whole numbers ≥ 0, on text, long text, url and rich text values.\" },\n \"validation.items\": { backlog: \"corpus-fix\", reason: \"Item limits are whole numbers ≥ 0 on a list, min ≤ max: a tags max 1–500 and min 0–500, a prop's own list (table, array) at most 500 (LIST_ITEMS_CAP), a slot's at most 50 (SLOT_ITEMS_CAP).\" },\n \"validation.unique\": { backlog: \"corpus-fix\", reason: \"unique is for text, long text, slug, email, phone, link, number, select, date and single-model reference fields, and lists; a polymorphic reference has no one id to compare.\" },\n \"validation.recommendedMax\": { backlog: \"corpus-fix\", reason: \"A soft limit is a positive whole number in prod.\" },\n \"item identity\": { backlog: \"corpus-fix\", reason: \"A list item's name is an identifier (a letter, then letters, digits or _; ≤ 64) and its title 1–60 characters (ui.itemName / ui.itemTitle); an object item keeps no other key.\" },\n \"item settings\": { backlog: \"corpus-fix\", reason: \"A list of scalars keeps its item's description (1–200 characters), localized flag, required, a text or rich text item's length and a text item's pattern (config.item, array_item_settings_invalid): this setting is none of those, or out of their bounds (a multi-line text item reads back single-line).\" },\n itemNoun: { backlog: \"corpus-fix\", reason: \"The item noun is ui.itemLabel, capitalised, at most 24 characters.\" },\n \"block model field\": { backlog: \"block-model-fields\", reason: \"A modular item type is a kind:'block' model, which holds only fields a block primitive renders (text, long text, rich text, image, link, slug, email, phone, color, select, number, rating, date, datetime, boolean): this field is not stored.\" },\n \"item icon\": { backlog: \"corpus-fix\", reason: \"Prod keeps one icon per list (ui.icon, a dock name) and one per polymorphic item type: the list has its own icon, or this name is not a dock icon.\" },\n \"preview icon\": { backlog: \"corpus-fix\", reason: \"A row preview's icon is a dock icon name.\" },\n \"preview path\": { backlog: \"corpus-fix\", reason: \"A row preview names a child key, or a dotted path whose later segments are children or keys of an image, video, link, button, file, location, json, code or reference value, or a data table's caption or notes (preview_path_unknown).\" },\n openMode: { backlog: \"corpus-fix\", reason: \"openMode is for object, array, table and code fields only (openMode_leaf).\" },\n \"unsupported key\": { backlog: \"corpus-fix\", reason: \"This V2 key has no prod mapping.\" },\n} as const satisfies Record<string, { reason: string; backlog: Backlog }>;\n\nexport type LossyFeature = keyof typeof FEATURES;\n\n/**\n * CATALOG ITEMS — V2 metadata the dock never stores, set when a schema is seeded or placed by its host: not a loss of\n * stored content. Reported apart from LossyItem so the lossy ledger counts only what prod drops.\n */\nexport interface CatalogItem {\n path: string;\n feature: CatalogFeature;\n reason: string;\n}\n\nexport const CATALOG = {\n \"block icon\": \"The block picker's icon belongs to the catalog entry; a model carries none (a component stores it as component.icon, a dock icon, so only one with no dock name for it lands here).\",\n category: \"The block picker's category is catalog metadata. A component takes the nearest prod category (CATEGORY_TO_PROD) when there is one; a model has none.\",\n \"document preview\": \"The document-level preview (how a row of this type reads in a parent's list) has no place on a model; a component stores it as component.preview.\",\n \"document preview path\": \"component.preview names a top-level prop key or a dotted path into one (`slides.0.heading`, componentPreviewRefusals); a key no prop has, or a path through a renamed value key (`image.alt`), is not stored (preview_key_unknown), so the slot row reads the child's first text instead.\",\n \"kind:block (fields)\": \"A section's fields are stored as a model (kind model): which host places it is set at seeding.\",\n \"kind:global\": \"A global (synced) block is a host-level placement; its fields are stored as a model or a component.\",\n \"kind:page\": \"A page schema is stored as a model; the host makes it a page.\",\n \"kind:object\": \"An object type is stored as a model.\",\n \"kind:entry (props)\": \"Only blocks become components; the host decides what an entry schema is placed as.\",\n variants: \"Variants are separate components sharing a sectionType in prod: the host seeds one per variant.\",\n ai: \"The AI-assist sparkle is a host setting, not stored on the field.\",\n \"item openMode\": \"Prod keeps one openMode per list, the array's own; the V2 engine reads only that one too (lib/schema.ts itemOpenMode ignores the item's), so the item's changes nothing the dock shows.\",\n \"itemNoun (derived)\": \"A list with no itemNoun whose item title is not the field title's singular: ui.itemLabel keeps the item title, and the read side names the noun from it, which is the noun the V2 engine already falls back to (lib/schema.ts itemNoun).\",\n \"fieldset (derived)\": \"A field names a fieldset the schema does not declare: the V2 engine draws it as a section titled by its name (engine/field-list.tsx arrange), so it is stored as that prop group and the read side declares it. Not a loss.\",\n \"prop target\": \"A V2 prop has no binding path, so fromTypeSchema('props') returns none: seeding binds each prop to its target. Not a loss.\",\n \"block placement\": \"Where a block fits (inline / section / page) is the host's: the block picker and a body's Insert menu place it; a model or component carries none.\",\n \"slot allow\": \"A slot keeps its V2 allow list as config.allow (1–50 block names of 1–64 characters, no repeats: slot_allow_invalid), which the dock resolves to the project's components; this list breaks those bounds, so the slot takes any component.\",\n \"segmented fallback\": \"A segmented select of 5+ options: V2 draws the dropdown (D46, choice.tsx fitsSegmented) and prod stores the select with no control (control_segmented holds 2–4), which the dock draws as the same dropdown. Nothing drawn differs.\",\n \"seeded instance\": \"A starting value the host writes into a new instance when it seeds or places one: a schema-level initialValue, a reference prop's default (a definition holds none: reference_in_definition), or a slot's children (they name V2 block types, which become component instances at seeding).\",\n \"not applicable (props)\": \"unique on a scalar prop, or on a sub-field outside a table: each placement holds its own value, so there is nothing to be unique across (unique_prop_scope). The instance is the whole document.\",\n \"host config\": \"A prod-only prop config key the host reads, not the V2 schema: a rich text's Accept list, its one-paragraph flags (allowMultipleParagraphs, the older inline), allowTargetBlank and component allowlist (the dock's rich-text codec and insert menu read them from the stored prop: dock-v2 richTextCodec configAt, kitServices insertableComponents), a section label, and the import's write-back metadata no editor reads (SERVER_CONFIG_KEYS). Read back, it names no loss: the kit never writes a definition, so the config rides untouched.\",\n} as const;\n\nexport type CatalogFeature = keyof typeof CATALOG;\n\n/**\n * Keys the import (BE derive-schema.ts, register-editable-pages.ts, template-copy.ts) writes onto a field for the\n * SERVER: how publish writes a value back into the site's own HTML (`attr`, `numeric`, `iconFont`, `htmlClasses`,\n * `units`, `lead`), which band a field belongs to (`band`, `family`, `shape`), and import markers (`seeded`, `shared`,\n * `sharedValue`). No form reads them, so no form loses anything by leaving them alone, and no agent may write them: the\n * backend MCP drops them from what an agent sends, and its contract test fails on any key the import writes that is\n * neither here, a host key, nor read by the kit (kit-catalog.json `fieldConfig`).\n */\nexport const SERVER_CONFIG_KEYS: ReadonlySet<string> = new Set([\n \"seeded\", \"shared\", \"sharedValue\", \"attr\", \"numeric\", \"iconFont\", \"htmlClasses\", \"units\", \"lead\", \"band\", \"family\", \"shape\",\n]);\n\n/** The prop config keys CATALOG \"host config\" covers: any type's, then a rich text's (richtext, document) own. */\nexport const HOST_CONFIG_KEYS: { any: ReadonlySet<string>; richtext: ReadonlySet<string> } = {\n // A band's name, its kind and its own heading, which the derive lane writes on the band's first field.\n // `format`: how a number is shown ($1,200+), which the canvas, the classic preview and publish read; the value stays a number\n any: new Set([\"sectionLabel\", \"sectionShape\", \"sectionTitle\", \"format\", ...SERVER_CONFIG_KEYS]),\n // `hostTag` is read from the stored field by the rich-text host, like the rest. `features` is a V2 facet now (RT0, facets.ts)\n richtext: new Set([\"accept\", \"allowMultipleParagraphs\", \"inline\", \"allowTargetBlank\", \"components\", \"hostTag\"]),\n};\n\nexport const isHostConfigKey = (type: string, key: string): boolean =>\n HOST_CONFIG_KEYS.any.has(key) || ((type === \"richtext\" || type === \"document\") && HOST_CONFIG_KEYS.richtext.has(key));\n\n/**\n * The prod config keys the kit adapter READS, per prod field type (`*` = every type): what an agent may write on a\n * field and still edit it in the kit. Exported to the backend with the host and server keys (kit-catalog.json\n * `fieldConfig`), where the MCP warns on any other key and its contract test checks what the import writes.\n * field-config-contract.test.ts proves each entry against `toTypeSchema`, so this list cannot claim a key the\n * adapter drops; a key missing here only costs a warning.\n */\nexport const KIT_READ_CONFIG_KEYS: Readonly<Record<string, readonly string[]>> = {\n \"*\": [\"placeholder\", \"zones\", \"options\", \"fields\", \"linkHref\"],\n text: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n longtext: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n url: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\"],\n richtext: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\", \"features\", \"references\"],\n document: [\"minLength\", \"maxLength\", \"pattern\", \"patternMessage\", \"inputType\", \"features\", \"references\"],\n number: [\"min\", \"max\", \"step\", \"scale\", \"unit\", \"validation\"],\n rating: [\"min\", \"max\", \"step\", \"scale\", \"unit\", \"validation\"],\n select: [\"multiSelect\"],\n multiselect: [\"min\", \"max\", \"allowCustom\"],\n tags: [\"min\", \"max\", \"allowCustom\"],\n code: [\"language\", \"languages\"],\n date: [\"timezone\", \"includeTime\"],\n datetime: [\"timezone\", \"includeTime\"],\n reference: [\"contentModelId\", \"polymorphic\", \"allowedModelSlugs\", \"targets\", \"filter\"],\n \"multi-reference\": [\"contentModelId\", \"polymorphic\", \"allowedModelSlugs\", \"targets\", \"filter\", \"min\", \"max\"],\n array: [\"itemType\", \"minItems\", \"maxItems\", \"item\"],\n image: [\"media\"],\n modular: [\"blockSlugs\", \"minItems\", \"maxItems\"],\n};\n\n/** The field-config contract the backend reads (kit-catalog.json `fieldConfig`). */\nexport const fieldConfigContract = () => ({\n read: KIT_READ_CONFIG_KEYS,\n host: { any: [...HOST_CONFIG_KEYS.any].filter((k) => !SERVER_CONFIG_KEYS.has(k)), richtext: [...HOST_CONFIG_KEYS.richtext] },\n server: [...SERVER_CONFIG_KEYS],\n});\n"],"mappings":";AA8CA,IAAa,WAAW;CAEtB,cAAc;EAAE,SAAS;EAAS,QAAQ;CAAoG;CAC9I,aAAa;EAAE,SAAS;EAAQ,QAAQ;CAAkN;CAC1P,0BAA0B;EAAE,SAAS;EAAQ,QAAQ;CAAmN;CACxQ,uBAAuB;EAAE,SAAS;EAAQ,QAAQ;CAAiK;CACnN,wBAAwB;EAAE,SAAS;EAAuB,QAAQ;CAAmI;CACrM,YAAY;EAAE,SAAS;EAAiB,QAAQ;CAAiG;CAEjJ,aAAa;EAAE,SAAS;EAAc,QAAQ;CAAyF;CAEvI,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAAkD;CACpG,eAAe;EAAE,SAAS;EAAc,QAAQ;CAAsM;CACtP,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAAmD;CACrG,cAAc;EAAE,SAAS;EAAc,QAAQ;CAA0E;CACzH,kBAAkB;EAAE,SAAS;EAAc,QAAQ;CAA4H;CAC/K,YAAY;EAAE,SAAS;EAAiB,QAAQ;CAAoM;CACpP,wBAAwB;EAAE,SAAS;EAAc,QAAQ;CAA0K;CACnO,kBAAkB;EAAE,SAAS;EAAc,QAAQ;CAAmK;CACtN,yBAAyB;EAAE,SAAS;EAAc,QAAQ;CAAiF;CAC3I,oBAAoB;EAAE,SAAS;EAAc,QAAQ;CAAyI;CAC9L,uBAAuB;EAAE,SAAS;EAAc,QAAQ;CAA+E;CACvI,sBAAsB;EAAE,SAAS;EAAc,QAAQ;CAAoG;CAE3J,kBAAkB;EAAE,SAAS;EAAc,QAAQ;CAAgG;CACnJ,iBAAiB;EACf,SAAS;EACT,QAAQ;CACV;CACA,MAAM;EAAE,SAAS;EAAc,QAAQ;CAA6E;CACpH,QAAQ;EAAE,SAAS;EAAc,QAAQ;CAA2D;CACpG,YAAY;EAAE,SAAS;EAAc,QAAQ;CAA2D;CACxG,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAAsL;CACxO,cAAc;EAAE,SAAS;EAAmB,QAAQ;CAA2M;CAC/P,MAAM;EAAE,SAAS;EAAc,QAAQ;CAA2K;CAClN,QAAQ;EAAE,SAAS;EAAc,QAAQ;CAAkV;CAC3X,cAAc;EAAE,SAAS;EAAc,QAAQ;CAAiI;CAChL,eAAe;EAAE,SAAS;EAAc,QAAQ;CAAkJ;CAClM,sBAAsB;EAAE,SAAS;EAAc,QAAQ;CAAsF;CAC7I,WAAW;EAAE,SAAS;EAAc,QAAQ;CAA4R;CACxU,QAAQ;EAAE,SAAS;EAAc,QAAQ;CAA+K;CACxN,UAAU;EAAE,SAAS;EAAc,QAAQ;CAA4F;CACvI,uBAAuB;EACrB,SAAS;EACT,QAAQ;CACV;CACA,qBAAqB;EACnB,SAAS;EACT,QAAQ;CACV;CACA,qBAAqB;EACnB,SAAS;EACT,QACE;CACJ;CACA,oBAAoB;EAAE,SAAS;EAAqB,QAAQ;CAAsV;CAClZ,mBAAmB;EAAE,SAAS;EAAc,QAAQ;CAAmJ;CACvM,oBAAoB;EAAE,SAAS;EAAqB,QAAQ;CAAiK;CAC7N,gBAAgB;EAAE,SAAS;EAAc,QAAQ;CAAqE;CACtH,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAA8I;CAChM,eAAe;EAAE,SAAS;EAAc,QAAQ;CAA6M;CAC7P,6BAA6B;EAAE,SAAS;EAAc,QAAQ;CAAoE;CAClI,sBAAsB;EAAE,SAAS;EAAc,QAAQ;CAAwG;CAC/J,qBAAqB;EAAE,SAAS;EAAc,QAAQ;CAAqF;CAC3I,oBAAoB;EAAE,SAAS;EAAc,QAAQ;CAA+L;CACpP,qBAAqB;EAAE,SAAS;EAAc,QAAQ;CAAgL;CACtO,6BAA6B;EAAE,SAAS;EAAc,QAAQ;CAAmD;CACjH,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAAiL;CACnO,iBAAiB;EAAE,SAAS;EAAc,QAAQ;CAA8S;CAChW,UAAU;EAAE,SAAS;EAAc,QAAQ;CAAqE;CAChH,qBAAqB;EAAE,SAAS;EAAsB,QAAQ;CAAkP;CAChT,aAAa;EAAE,SAAS;EAAc,QAAQ;CAAqJ;CACnM,gBAAgB;EAAE,SAAS;EAAc,QAAQ;CAA4C;CAC7F,gBAAgB;EAAE,SAAS;EAAc,QAAQ;CAA0O;CAC3R,UAAU;EAAE,SAAS;EAAc,QAAQ;CAA6E;CACxH,mBAAmB;EAAE,SAAS;EAAc,QAAQ;CAAmC;AACzF;AAcA,IAAa,UAAU;CACrB,cAAc;CACd,UAAU;CACV,oBAAoB;CACpB,yBAAyB;CACzB,uBAAuB;CACvB,eAAe;CACf,aAAa;CACb,eAAe;CACf,sBAAsB;CACtB,UAAU;CACV,IAAI;CACJ,iBAAiB;CACjB,sBAAsB;CACtB,sBAAsB;CACtB,eAAe;CACf,mBAAmB;CACnB,cAAc;CACd,sBAAsB;CACtB,mBAAmB;CACnB,0BAA0B;CAC1B,eAAe;AACjB;;;;;;;;;AAYA,IAAa,qCAA0C,IAAI,IAAI;CAC7D;CAAU;CAAU;CAAe;CAAQ;CAAW;CAAY;CAAe;CAAS;CAAQ;CAAQ;CAAU;AACtH,CAAC;;AAGD,IAAa,mBAAgF;CAG3F,qBAAK,IAAI,IAAI;EAAC;EAAgB;EAAgB;EAAgB;EAAU,GAAG;CAAkB,CAAC;CAE9F,0BAAU,IAAI,IAAI;EAAC;EAAU;EAA2B;EAAU;EAAoB;EAAc;CAAS,CAAC;AAChH;AAEA,IAAa,mBAAmB,MAAc,QAC5C,iBAAiB,IAAI,IAAI,GAAG,MAAO,SAAS,cAAc,SAAS,eAAe,iBAAiB,SAAS,IAAI,GAAG;;;;;;;;AASrH,IAAa,uBAAoE;CAC/E,KAAK;EAAC;EAAe;EAAS;EAAW;EAAU;CAAU;CAC7D,MAAM;EAAC;EAAa;EAAa;EAAW;EAAkB;CAAW;CACzE,UAAU;EAAC;EAAa;EAAa;EAAW;EAAkB;CAAW;CAC7E,KAAK;EAAC;EAAa;EAAa;EAAW;EAAkB;CAAW;CACxE,UAAU;EAAC;EAAa;EAAa;EAAW;EAAkB;EAAa;EAAY;CAAY;CACvG,UAAU;EAAC;EAAa;EAAa;EAAW;EAAkB;EAAa;EAAY;CAAY;CACvG,QAAQ;EAAC;EAAO;EAAO;EAAQ;EAAS;EAAQ;CAAY;CAC5D,QAAQ;EAAC;EAAO;EAAO;EAAQ;EAAS;EAAQ;CAAY;CAC5D,QAAQ,CAAC,aAAa;CACtB,aAAa;EAAC;EAAO;EAAO;CAAa;CACzC,MAAM;EAAC;EAAO;EAAO;CAAa;CAClC,MAAM,CAAC,YAAY,WAAW;CAC9B,MAAM,CAAC,YAAY,aAAa;CAChC,UAAU,CAAC,YAAY,aAAa;CACpC,WAAW;EAAC;EAAkB;EAAe;EAAqB;EAAW;CAAQ;CACrF,mBAAmB;EAAC;EAAkB;EAAe;EAAqB;EAAW;EAAU;EAAO;CAAK;CAC3G,OAAO;EAAC;EAAY;EAAY;EAAY;CAAM;CAClD,OAAO,CAAC,OAAO;CACf,SAAS;EAAC;EAAc;EAAY;CAAU;AAChD;;AAGA,IAAa,6BAA6B;CACxC,MAAM;CACN,MAAM;EAAE,KAAK,CAAC,GAAG,iBAAiB,GAAG,CAAC,CAAC,QAAQ,MAAM,CAAC,mBAAmB,IAAI,CAAC,CAAC;EAAG,UAAU,CAAC,GAAG,iBAAiB,QAAQ;CAAE;CAC3H,QAAQ,CAAC,GAAG,kBAAkB;AAChC"}
@@ -1,28 +1,15 @@
1
- /**
2
- * PROD SHAPES — the production schema language and stored values, typed locally so the kit stays a package that could
3
- * leave the repo (it may not import @bettercms-ai/types, and the dashboard's pin predates F1 / F1.x-props anyway).
4
- *
5
- * Mirrors the backend at F1 + F1.x-props + link objects + tags / rating / code (72ea2b68d), then reference props
6
- * (73a120c50), validation parity (dd021ceba), option meta (ab15fe893), V2 chrome keys and types (98e48b9e3, 324580b2e),
7
- * the V2 icon vocabulary (e126bf33d) and the localized flag (279a10490) — origin/dev 81f385ff3:
8
- * packages/types/src/content-model.ts, component.ts, link-value.ts, button-look.ts, dock-icon-names.ts, video-value.ts
9
- * src/lib/validation/schemas/content.ts (baseField, fieldUiSchema, chromeUiProblems, fieldsets, MAX_FIELD_DEPTH)
10
- * src/lib/validation/schemas/components.ts (componentPropDefSchema, subFieldSchema, propUiSchema, propValidationHardening)
11
- * src/lib/content/validation-parity.ts, src/lib/content/dock-vocabulary.ts (TAB_MAX, TAB_NAME_MAX)
12
- * When the backend widens, widen these and the adapters together; the round-trip test then shrinks the lossy ledger.
13
- */
14
1
  /** Field levels one schema may nest (a top-level field, or a prop, is level 1). */
15
2
  export declare const MAX_FIELD_DEPTH = 10;
16
- /** Tabs (`kind: "tab"` fieldsets) one screen may hold, and a tab name's length. */
3
+ /** Tabs (`kind: "tab"` fieldsets) a model screen holds TODAY (it rises to types' TAB_MAX at F12), and a tab name's length. */
17
4
  export declare const TAB_MAX = 3;
18
5
  export declare const TAB_NAME_MAX = 40;
19
6
  export declare const FIELDSETS_MAX = 30;
20
7
  export declare const FIELDSET_NAME_MAX = 60;
21
- export declare const FIELDSET_DESCRIPTION_MAX = 500;
22
- export declare const FIELD_HELP_MAX = 500;
23
- export declare const PROP_HELP_MAX = 200;
24
- export declare const PROP_PLACEHOLDER_MAX = 120;
25
- export declare const HELP_MORE_MAX = 2000;
8
+ export declare const FIELDSET_DESCRIPTION_MAX: 500;
9
+ export declare const FIELD_HELP_MAX: 500;
10
+ export declare const PROP_HELP_MAX: 200;
11
+ export declare const PROP_PLACEHOLDER_MAX: 120;
12
+ export declare const HELP_MORE_MAX: 2000;
26
13
  export declare const LOCK_REASON_MAX = 200;
27
14
  export declare const ITEM_LABEL_MAX = 24;
28
15
  export declare const PREVIEW_FALLBACK_MAX = 60;
@@ -38,19 +25,19 @@ export declare const RATING_MAX_STOPS = 100;
38
25
  /** tagsConfigSchema: config.min 0–500, config.max 1–500. */
39
26
  export declare const TAGS_ITEMS_MAX = 500;
40
27
  /** A choice option's description (OPTION_DESCRIPTION_MAX): one line. */
41
- export declare const OPTION_DESCRIPTION_MAX = 140;
28
+ export declare const OPTION_DESCRIPTION_MAX: 140;
42
29
  /** config.patternMessage (PATTERN_MESSAGE_MAX), config.unit on a number (NUMBER_UNIT_MAX). */
43
30
  export declare const PATTERN_MESSAGE_MAX = 200;
44
31
  export declare const NUMBER_UNIT_MAX = 24;
45
32
  /** fieldUiSchema: ui.rows 1–40, ui.placeholder 1–120, ui.itemTitle 1–60, ui.synced.from 1–64. */
46
33
  export declare const UI_ROWS_MAX = 40;
47
- export declare const UI_PLACEHOLDER_MAX = 120;
34
+ export declare const UI_PLACEHOLDER_MAX: 120;
48
35
  export declare const ITEM_TITLE_MAX = 60;
49
36
  export declare const SYNCED_FROM_MAX = 64;
50
37
  /** ui.itemName is an identifier: a letter, then letters, digits or _ (≤ 64). */
51
38
  export declare const ITEM_NAME_RE: RegExp;
52
39
  /** propUiSchema group: description 1–200, order 0–99. */
53
- export declare const PROP_GROUP_DESCRIPTION_MAX = 200;
40
+ export declare const PROP_GROUP_DESCRIPTION_MAX: 200;
54
41
  export declare const PROP_GROUP_ORDER_MAX = 99;
55
42
  /** propUiSchema tab: at most 8 distinct tabs per component, an id 1–40, a label ≤ TAB_NAME_MAX trimmed, order 0–99. */
56
43
  export declare const PROP_TAB_MAX = 8;
@@ -1,5 +1,19 @@
1
1
  import { __exportAll } from "../_virtual/_rolldown/runtime.js";
2
+ import { DEPTH_MAX, HELP_CAPS, TAB_MAX as TAB_MAX$1, TAB_MAX_RENDERABLE_NOW } from "@bettercms-ai/types";
2
3
  //#region src/adapters/prod-types.ts
4
+ /**
5
+ * PROD SHAPES — the production schema language and stored values, typed locally. The caps and key rules the backend
6
+ * and the kit must agree on come from @bettercms-ai/types (W1a, a peer of the kit since W1c): one home per constant.
7
+ *
8
+ * Mirrors the backend at F1 + F1.x-props + link objects + tags / rating / code (72ea2b68d), then reference props
9
+ * (73a120c50), validation parity (dd021ceba), option meta (ab15fe893), V2 chrome keys and types (98e48b9e3, 324580b2e),
10
+ * the V2 icon vocabulary (e126bf33d) and the localized flag (279a10490) — origin/dev 81f385ff3:
11
+ * packages/types/src/content-model.ts, component.ts, link-value.ts, button-look.ts, dock-icon-names.ts, video-value.ts
12
+ * src/lib/validation/schemas/content.ts (baseField, fieldUiSchema, chromeUiProblems, fieldsets, MAX_FIELD_DEPTH)
13
+ * src/lib/validation/schemas/components.ts (componentPropDefSchema, subFieldSchema, propUiSchema, propValidationHardening)
14
+ * src/lib/content/validation-parity.ts, src/lib/content/dock-vocabulary.ts (TAB_MAX, TAB_NAME_MAX)
15
+ * When the backend widens, widen these and the adapters together; the round-trip test then shrinks the lossy ledger.
16
+ */
3
17
  var prod_types_exports = /* @__PURE__ */ __exportAll({
4
18
  BUTTON_SIZES: () => BUTTON_SIZES,
5
19
  BUTTON_VARIANTS: () => BUTTON_VARIANTS,
@@ -12,9 +26,9 @@ var prod_types_exports = /* @__PURE__ */ __exportAll({
12
26
  DOCK_ICON_NAMES: () => DOCK_ICON_NAMES,
13
27
  DOCK_ICON_NAME_SET: () => DOCK_ICON_NAME_SET,
14
28
  FIELDSETS_MAX: () => 30,
15
- FIELDSET_DESCRIPTION_MAX: () => 500,
29
+ FIELDSET_DESCRIPTION_MAX: () => FIELDSET_DESCRIPTION_MAX,
16
30
  FIELDSET_NAME_MAX: () => 60,
17
- FIELD_HELP_MAX: () => 500,
31
+ FIELD_HELP_MAX: () => FIELD_HELP_MAX,
18
32
  HELP_MORE_MAX: () => HELP_MORE_MAX,
19
33
  ITEM_LABEL_MAX: () => 24,
20
34
  ITEM_NAME_RE: () => ITEM_NAME_RE,
@@ -22,19 +36,19 @@ var prod_types_exports = /* @__PURE__ */ __exportAll({
22
36
  LINK_RELS: () => LINK_RELS,
23
37
  LINK_VALUE_TYPES: () => LINK_VALUE_TYPES,
24
38
  LOCK_REASON_MAX: () => 200,
25
- MAX_FIELD_DEPTH: () => 10,
39
+ MAX_FIELD_DEPTH: () => MAX_FIELD_DEPTH,
26
40
  NUMBER_UNIT_MAX: () => 24,
27
- OPTION_DESCRIPTION_MAX: () => 140,
41
+ OPTION_DESCRIPTION_MAX: () => OPTION_DESCRIPTION_MAX,
28
42
  PATTERN_MAX: () => 200,
29
43
  PATTERN_MESSAGE_MAX: () => 200,
30
44
  PREVIEW_FALLBACK_MAX: () => 60,
31
- PROP_GROUP_DESCRIPTION_MAX: () => 200,
45
+ PROP_GROUP_DESCRIPTION_MAX: () => PROP_GROUP_DESCRIPTION_MAX,
32
46
  PROP_GROUP_LABEL_MAX: () => 32,
33
47
  PROP_GROUP_ORDER_MAX: () => 99,
34
- PROP_HELP_MAX: () => 200,
35
- PROP_PLACEHOLDER_MAX: () => 120,
48
+ PROP_HELP_MAX: () => PROP_HELP_MAX,
49
+ PROP_PLACEHOLDER_MAX: () => PROP_PLACEHOLDER_MAX,
36
50
  PROP_TAB_ID_MAX: () => 40,
37
- PROP_TAB_MAX: () => 8,
51
+ PROP_TAB_MAX: () => PROP_TAB_MAX,
38
52
  RATING_DEFAULT_MAX: () => 5,
39
53
  RATING_MAX: () => 10,
40
54
  RATING_MAX_STOPS: () => 100,
@@ -45,41 +59,28 @@ var prod_types_exports = /* @__PURE__ */ __exportAll({
45
59
  SCALE_TITLE_MAX: () => 60,
46
60
  SCALE_TOKEN_VALUE_MAX: () => 32,
47
61
  SYNCED_FROM_MAX: () => 64,
48
- TAB_MAX: () => 3,
62
+ TAB_MAX: () => TAB_MAX,
49
63
  TAB_NAME_MAX: () => 40,
50
64
  TAGS_ITEMS_MAX: () => 500,
51
65
  TAG_VALUE_MAX_LENGTH: () => 64,
52
66
  UI_CONTROLS: () => UI_CONTROLS,
53
- UI_PLACEHOLDER_MAX: () => 120,
67
+ UI_PLACEHOLDER_MAX: () => UI_PLACEHOLDER_MAX,
54
68
  UI_ROWS_MAX: () => 40,
55
69
  VIDEO_TRANSCRIPT_MAX: () => VIDEO_TRANSCRIPT_MAX,
56
70
  VIDEO_VALUE_KEYS: () => VIDEO_VALUE_KEYS
57
71
  });
58
- /**
59
- * PROD SHAPES — the production schema language and stored values, typed locally so the kit stays a package that could
60
- * leave the repo (it may not import @bettercms-ai/types, and the dashboard's pin predates F1 / F1.x-props anyway).
61
- *
62
- * Mirrors the backend at F1 + F1.x-props + link objects + tags / rating / code (72ea2b68d), then reference props
63
- * (73a120c50), validation parity (dd021ceba), option meta (ab15fe893), V2 chrome keys and types (98e48b9e3, 324580b2e),
64
- * the V2 icon vocabulary (e126bf33d) and the localized flag (279a10490) — origin/dev 81f385ff3:
65
- * packages/types/src/content-model.ts, component.ts, link-value.ts, button-look.ts, dock-icon-names.ts, video-value.ts
66
- * src/lib/validation/schemas/content.ts (baseField, fieldUiSchema, chromeUiProblems, fieldsets, MAX_FIELD_DEPTH)
67
- * src/lib/validation/schemas/components.ts (componentPropDefSchema, subFieldSchema, propUiSchema, propValidationHardening)
68
- * src/lib/content/validation-parity.ts, src/lib/content/dock-vocabulary.ts (TAB_MAX, TAB_NAME_MAX)
69
- * When the backend widens, widen these and the adapters together; the round-trip test then shrinks the lossy ledger.
70
- */
71
72
  /** Field levels one schema may nest (a top-level field, or a prop, is level 1). */
72
- var MAX_FIELD_DEPTH = 10;
73
- /** Tabs (`kind: "tab"` fieldsets) one screen may hold, and a tab name's length. */
74
- var TAB_MAX = 3;
73
+ var MAX_FIELD_DEPTH = DEPTH_MAX;
74
+ /** Tabs (`kind: "tab"` fieldsets) a model screen holds TODAY (it rises to types' TAB_MAX at F12), and a tab name's length. */
75
+ var TAB_MAX = TAB_MAX_RENDERABLE_NOW;
75
76
  var TAB_NAME_MAX = 40;
76
77
  var FIELDSETS_MAX = 30;
77
78
  var FIELDSET_NAME_MAX = 60;
78
- var FIELDSET_DESCRIPTION_MAX = 500;
79
- var FIELD_HELP_MAX = 500;
80
- var PROP_HELP_MAX = 200;
81
- var PROP_PLACEHOLDER_MAX = 120;
82
- var HELP_MORE_MAX = 2e3;
79
+ var FIELDSET_DESCRIPTION_MAX = HELP_CAPS.fieldset;
80
+ var FIELD_HELP_MAX = HELP_CAPS.field;
81
+ var PROP_HELP_MAX = HELP_CAPS.prop;
82
+ var PROP_PLACEHOLDER_MAX = HELP_CAPS.placeholder;
83
+ var HELP_MORE_MAX = HELP_CAPS.helpMore;
83
84
  var LOCK_REASON_MAX = 200;
84
85
  var ITEM_LABEL_MAX = 24;
85
86
  var PREVIEW_FALLBACK_MAX = 60;
@@ -95,22 +96,22 @@ var RATING_MAX_STOPS = 100;
95
96
  /** tagsConfigSchema: config.min 0–500, config.max 1–500. */
96
97
  var TAGS_ITEMS_MAX = 500;
97
98
  /** A choice option's description (OPTION_DESCRIPTION_MAX): one line. */
98
- var OPTION_DESCRIPTION_MAX = 140;
99
+ var OPTION_DESCRIPTION_MAX = HELP_CAPS.option;
99
100
  /** config.patternMessage (PATTERN_MESSAGE_MAX), config.unit on a number (NUMBER_UNIT_MAX). */
100
101
  var PATTERN_MESSAGE_MAX = 200;
101
102
  var NUMBER_UNIT_MAX = 24;
102
103
  /** fieldUiSchema: ui.rows 1–40, ui.placeholder 1–120, ui.itemTitle 1–60, ui.synced.from 1–64. */
103
104
  var UI_ROWS_MAX = 40;
104
- var UI_PLACEHOLDER_MAX = 120;
105
+ var UI_PLACEHOLDER_MAX = HELP_CAPS.placeholder;
105
106
  var ITEM_TITLE_MAX = 60;
106
107
  var SYNCED_FROM_MAX = 64;
107
108
  /** ui.itemName is an identifier: a letter, then letters, digits or _ (≤ 64). */
108
109
  var ITEM_NAME_RE = /^[A-Za-z][A-Za-z0-9_]{0,63}$/;
109
110
  /** propUiSchema group: description 1–200, order 0–99. */
110
- var PROP_GROUP_DESCRIPTION_MAX = 200;
111
+ var PROP_GROUP_DESCRIPTION_MAX = HELP_CAPS.propGroup;
111
112
  var PROP_GROUP_ORDER_MAX = 99;
112
113
  /** propUiSchema tab: at most 8 distinct tabs per component, an id 1–40, a label ≤ TAB_NAME_MAX trimmed, order 0–99. */
113
- var PROP_TAB_MAX = 8;
114
+ var PROP_TAB_MAX = TAB_MAX$1;
114
115
  var PROP_TAB_ID_MAX = 40;
115
116
  /** numberScaleSchema: token value 1–32, label 1–24, title 1–60, css 1–60; 1–50 steps; at most 20 presets. */
116
117
  var SCALE_TOKEN_VALUE_MAX = 32;