@tinya-code/gas-admin-ui 0.2.0-alpha.2 → 0.2.0-alpha.4

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 (39) hide show
  1. package/README.md +234 -2
  2. package/fesm2022/{tinya-code-gas-admin-ui-calendar-view-CquWGzw7.mjs → tinya-code-gas-admin-ui-calendar-view-ZTYs-r49.mjs} +12 -7
  3. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-ZTYs-r49.mjs.map +1 -0
  4. package/fesm2022/{tinya-code-gas-admin-ui-condition-evaluator-DmvlAP9z.mjs → tinya-code-gas-admin-ui-condition-evaluator-CHzJuOx2.mjs} +2 -2
  5. package/fesm2022/{tinya-code-gas-admin-ui-condition-evaluator-DmvlAP9z.mjs.map → tinya-code-gas-admin-ui-condition-evaluator-CHzJuOx2.mjs.map} +1 -1
  6. package/fesm2022/{tinya-code-gas-admin-ui-data-source.service-vAi2DYL9.mjs → tinya-code-gas-admin-ui-data-source.service-Cw1rdrWZ.mjs} +2 -2
  7. package/fesm2022/{tinya-code-gas-admin-ui-data-source.service-vAi2DYL9.mjs.map → tinya-code-gas-admin-ui-data-source.service-Cw1rdrWZ.mjs.map} +1 -1
  8. package/fesm2022/{tinya-code-gas-admin-ui-error-mapper.service-dKQNLNRJ.mjs → tinya-code-gas-admin-ui-error-mapper.service-BQ--gSnT.mjs} +2 -2
  9. package/fesm2022/{tinya-code-gas-admin-ui-error-mapper.service-dKQNLNRJ.mjs.map → tinya-code-gas-admin-ui-error-mapper.service-BQ--gSnT.mjs.map} +1 -1
  10. package/fesm2022/{tinya-code-gas-admin-ui-file-CKh878UH.mjs → tinya-code-gas-admin-ui-file-JstsF8C5.mjs} +3 -3
  11. package/fesm2022/{tinya-code-gas-admin-ui-file-CKh878UH.mjs.map → tinya-code-gas-admin-ui-file-JstsF8C5.mjs.map} +1 -1
  12. package/fesm2022/{tinya-code-gas-admin-ui-form-view-_LpdZb15.mjs → tinya-code-gas-admin-ui-form-view-BcjgVVKC.mjs} +9 -9
  13. package/fesm2022/{tinya-code-gas-admin-ui-form-view-_LpdZb15.mjs.map → tinya-code-gas-admin-ui-form-view-BcjgVVKC.mjs.map} +1 -1
  14. package/fesm2022/{tinya-code-gas-admin-ui-image-BPfPNwru.mjs → tinya-code-gas-admin-ui-image-CnGes7gs.mjs} +3 -3
  15. package/fesm2022/{tinya-code-gas-admin-ui-image-BPfPNwru.mjs.map → tinya-code-gas-admin-ui-image-CnGes7gs.mjs.map} +1 -1
  16. package/fesm2022/{tinya-code-gas-admin-ui-kanban-view-C-w9mhiB.mjs → tinya-code-gas-admin-ui-kanban-view-QK7OSFoV.mjs} +4 -4
  17. package/fesm2022/{tinya-code-gas-admin-ui-kanban-view-C-w9mhiB.mjs.map → tinya-code-gas-admin-ui-kanban-view-QK7OSFoV.mjs.map} +1 -1
  18. package/fesm2022/{tinya-code-gas-admin-ui-list-BKr33pde.mjs → tinya-code-gas-admin-ui-list-CiNQ3DMg.mjs} +2 -2
  19. package/fesm2022/{tinya-code-gas-admin-ui-list-BKr33pde.mjs.map → tinya-code-gas-admin-ui-list-CiNQ3DMg.mjs.map} +1 -1
  20. package/fesm2022/{tinya-code-gas-admin-ui-multiselect-SfZJHfbh.mjs → tinya-code-gas-admin-ui-multiselect-BiKb7192.mjs} +3 -3
  21. package/fesm2022/{tinya-code-gas-admin-ui-multiselect-SfZJHfbh.mjs.map → tinya-code-gas-admin-ui-multiselect-BiKb7192.mjs.map} +1 -1
  22. package/fesm2022/{tinya-code-gas-admin-ui-relation-WCflawIU.mjs → tinya-code-gas-admin-ui-relation-CvxkEGHs.mjs} +3 -3
  23. package/fesm2022/{tinya-code-gas-admin-ui-relation-WCflawIU.mjs.map → tinya-code-gas-admin-ui-relation-CvxkEGHs.mjs.map} +1 -1
  24. package/fesm2022/{tinya-code-gas-admin-ui-render-registry-ghv7Mb1x.mjs → tinya-code-gas-admin-ui-render-registry-B7mmgFSW.mjs} +10 -10
  25. package/fesm2022/{tinya-code-gas-admin-ui-render-registry-ghv7Mb1x.mjs.map → tinya-code-gas-admin-ui-render-registry-B7mmgFSW.mjs.map} +1 -1
  26. package/fesm2022/{tinya-code-gas-admin-ui-schema-catalog-CL4IZDce.mjs → tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs} +193 -58
  27. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs.map +1 -0
  28. package/fesm2022/{tinya-code-gas-admin-ui-seed-BnwHE1Tw.mjs → tinya-code-gas-admin-ui-seed-CJEt__kZ.mjs} +2 -2
  29. package/fesm2022/{tinya-code-gas-admin-ui-seed-BnwHE1Tw.mjs.map → tinya-code-gas-admin-ui-seed-CJEt__kZ.mjs.map} +1 -1
  30. package/fesm2022/{tinya-code-gas-admin-ui-select-BaF4kSXl.mjs → tinya-code-gas-admin-ui-select-DPKRS6Gn.mjs} +3 -3
  31. package/fesm2022/{tinya-code-gas-admin-ui-select-BaF4kSXl.mjs.map → tinya-code-gas-admin-ui-select-DPKRS6Gn.mjs.map} +1 -1
  32. package/fesm2022/{tinya-code-gas-admin-ui-upload.service-C7GzSmuL.mjs → tinya-code-gas-admin-ui-upload.service-BNvH04S3.mjs} +2 -2
  33. package/fesm2022/{tinya-code-gas-admin-ui-upload.service-C7GzSmuL.mjs.map → tinya-code-gas-admin-ui-upload.service-BNvH04S3.mjs.map} +1 -1
  34. package/fesm2022/tinya-code-gas-admin-ui.mjs +87 -42
  35. package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -1
  36. package/package.json +1 -1
  37. package/types/tinya-code-gas-admin-ui.d.ts +224 -25
  38. package/fesm2022/tinya-code-gas-admin-ui-calendar-view-CquWGzw7.mjs.map +0 -1
  39. package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CL4IZDce.mjs.map +0 -1
@@ -1 +1 @@
1
- {"version":3,"file":"tinya-code-gas-admin-ui-render-registry-ghv7Mb1x.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/columns/descriptors.ts","../../../projects/gas-admin-ui/src/lib/fields/boolean/boolean.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/currency/currency.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/date/date.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/email/email.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/file/file.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/group/group.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/image/image.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/key-value/key-value.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/list/list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/multiselect/multiselect.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/number/number.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/phone/phone.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/readonly-text/readonly-text.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/relation/relation.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/select/select.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/slug/slug.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/string-list/string-list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/text/text.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/textarea/textarea.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/time/time.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/url/url.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/descriptors.ts","../../../projects/gas-admin-ui/src/lib/layouts/descriptors.ts","../../../projects/gas-admin-ui/src/lib/widgets/series.ts","../../../projects/gas-admin-ui/src/lib/widgets/bar-chart/bar-chart.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/chart-line/chart-line.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/metric-card/metric-card.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/quick-actions/quick-actions.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/record-list/record-list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/status-progress/status-progress.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/descriptors.ts","../../../projects/gas-admin-ui/src/lib/views/descriptors.ts","../../../projects/gas-admin-ui/src/lib/core/registry/render-registry.ts"],"sourcesContent":["import type { RenderDescriptor, RenderExtras } from '../core/registry/render-registry';\n\n/**\n * Manifiesto de descriptores de formato de columna (R4.3 · `kind:\n * 'column-format'`).\n *\n * Es el equivalente a `fields/descriptors.ts` y `widgets/descriptors.ts`:\n * una línea por formato y ningún import de componente — cada `load()` guarda\n * el cierre de un `import()` **con literal**, que es lo que permite al\n * bundler partir el chunk; el registro los recoge al importar este módulo\n * (`core/registry/render-registry.ts`).\n *\n * **Añadir un formato** ⇒ crear `format-<nombre>.ts` + una entrada acá.\n * `list-view` no se toca: ése es el criterio de éxito de R4.3.\n *\n * Todos comparten el cableado: el descriptor sólo expone la celda, que la\n * vista cuelga de `extras.data`.\n */\nconst inputs = (_config: unknown, extras: RenderExtras): Record<string, unknown> => ({\n cell: extras.data,\n});\n\nconst text: RenderDescriptor = {\n kind: 'column-format',\n type: 'text',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-text').then((module) => module.ColumnFormatText),\n inputs,\n};\n\nconst badge: RenderDescriptor = {\n kind: 'column-format',\n type: 'badge',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-badge').then((module) => module.ColumnFormatBadge),\n inputs,\n};\n\nconst thumbnail: RenderDescriptor = {\n kind: 'column-format',\n type: 'thumbnail',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-thumbnail').then((module) => module.ColumnFormatThumbnail),\n inputs,\n};\n\nconst boolean: RenderDescriptor = {\n kind: 'column-format',\n type: 'boolean',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-boolean').then((module) => module.ColumnFormatBoolean),\n inputs,\n};\n\nconst number: RenderDescriptor = {\n kind: 'column-format',\n type: 'number',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-number').then((module) => module.ColumnFormatNumber),\n inputs,\n};\n\nconst currency: RenderDescriptor = {\n kind: 'column-format',\n type: 'currency',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-currency').then((module) => module.ColumnFormatCurrency),\n inputs,\n};\n\nconst date: RenderDescriptor = {\n kind: 'column-format',\n type: 'date',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-date').then((module) => module.ColumnFormatDate),\n inputs,\n};\n\n/** Los 7 formatos del `@switch` que este registro reemplaza (R4.3). */\nexport const columnFormatDescriptors: readonly RenderDescriptor[] = [\n text,\n badge,\n thumbnail,\n boolean,\n number,\n currency,\n date,\n];\n\n/**\n * Los 7 nombres, como dato.\n *\n * Va en paralelo a `ListColumnFormat` (unión de `schema.model`) y lo vigila\n * `core/registry/contract.spec.ts`: la unión vive en tipos y el registro en\n * runtime, y sólo un test reconcilia los dos — el mismo tripwire que ya\n * existe para los 20 campos y los 6 widgets.\n */\nexport const COLUMN_FORMAT_TYPES = [\n 'text',\n 'badge',\n 'thumbnail',\n 'boolean',\n 'number',\n 'currency',\n 'date',\n] as const;\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `boolean` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'boolean',\n since: '1.0',\n load: () => import('./boolean').then((module) => module.FieldBoolean),\n seed: 'boolean',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `currency` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'currency',\n since: '1.0',\n load: () => import('./currency').then((module) => module.FieldCurrency),\n // Nace como `null`: no puede ser `0`, que sería un valor ya cargado.\n seed: 'number',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `date` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'date',\n since: '1.0',\n load: () => import('./date').then((module) => module.FieldDate),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `email` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'email',\n since: '1.0',\n load: () => import('./email').then((module) => module.FieldEmail),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `file` (R3.3 · R9.5.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'file',\n since: '9.5',\n load: () => import('./file').then((module) => module.FieldFile),\n // Nace como cadena: la URL pública es el valor, igual que en `image`.\n seed: 'string',\n surfaces: ['form', 'display'],\n // Como `image` (D27): control propio cuya sincronización con Signal Forms\n // vive en ɵɵcontrol, así que el host lo declara a mano con `[formField]`.\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `group` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'group',\n since: '1.0',\n load: () => import('./group').then((module) => module.FieldGroup),\n // Contenedor: siembra un nodo por cada hijo declarado.\n seed: 'recursive',\n surfaces: ['form', 'display'],\n // Compuesto: además de su árbol dibuja el template de sus hijos, que sólo\n // existe en la plantilla del host. Él es quien decide recibirlo (R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n serverErrors: extras.ctx.serverErrors,\n pathPrefix: extras.ctx.pathPrefix,\n content: extras.groupContent,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `image` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'image',\n since: '1.0',\n load: () => import('./image').then((module) => module.FieldImage),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `key-value` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'key-value',\n since: '1.0',\n load: () => import('./key-value').then((module) => module.FieldKeyValue),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `list` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'list',\n since: '1.0',\n load: () => import('./list').then((module) => module.FieldList),\n seed: 'array',\n surfaces: ['form', 'display'],\n // Compuesto: además de su árbol dibuja el template de cada hijo y hereda\n // el `exists` del nivel para no reactivar el borrado de filas (R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n childTemplate: extras.childTemplate,\n serverErrors: extras.ctx.serverErrors,\n pathPrefix: extras.ctx.pathPrefix,\n exists: extras.ctx.exists,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `multiselect` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'multiselect',\n since: '1.0',\n load: () => import('./multiselect').then((module) => module.FieldMultiselect),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `number` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'number',\n since: '1.0',\n load: () => import('./number').then((module) => module.FieldNumber),\n // Nace como `null`: no puede ser `0`, que sería un valor ya cargado.\n seed: 'number',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `phone` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'phone',\n since: '1.0',\n load: () => import('./phone').then((module) => module.FieldPhone),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `readonly-text` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'readonly-text',\n since: '1.0',\n load: () => import('./readonly-text').then((module) => module.FieldReadonlyText),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `relation` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'relation',\n since: '1.0',\n load: () => import('./relation').then((module) => module.FieldRelation),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `select` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'select',\n since: '1.0',\n load: () => import('./select').then((module) => module.FieldSelect),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `slug` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'slug',\n since: '1.0',\n load: () => import('./slug').then((module) => module.FieldSlug),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n // Se aparta de la forma estándar sólo por `exists`: con el registro ya\n // creado el campo queda bloqueado (`lockAfterCreate`, R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n exists: extras.ctx.exists,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `string-list` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'string-list',\n since: '1.0',\n load: () => import('./string-list').then((module) => module.FieldStringList),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `text` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'text',\n since: '1.0',\n load: () => import('./text').then((module) => module.FieldText),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `textarea` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'textarea',\n since: '1.0',\n load: () => import('./textarea').then((module) => module.FieldTextarea),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `time` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'time',\n since: '1.0',\n load: () => import('./time').then((module) => module.FieldTime),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `url` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'url',\n since: '1.0',\n load: () => import('./url').then((module) => module.FieldUrl),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../core/registry/render-registry';\nimport type { FieldType } from '../core/models/schema.model';\n\nimport { descriptor as booleanDescriptor } from './boolean/boolean.descriptor';\nimport { descriptor as currencyDescriptor } from './currency/currency.descriptor';\nimport { descriptor as dateDescriptor } from './date/date.descriptor';\nimport { descriptor as emailDescriptor } from './email/email.descriptor';\nimport { descriptor as fileDescriptor } from './file/file.descriptor';\nimport { descriptor as groupDescriptor } from './group/group.descriptor';\nimport { descriptor as imageDescriptor } from './image/image.descriptor';\nimport { descriptor as keyValueDescriptor } from './key-value/key-value.descriptor';\nimport { descriptor as listDescriptor } from './list/list.descriptor';\nimport { descriptor as multiselectDescriptor } from './multiselect/multiselect.descriptor';\nimport { descriptor as numberDescriptor } from './number/number.descriptor';\nimport { descriptor as phoneDescriptor } from './phone/phone.descriptor';\nimport { descriptor as readonlyTextDescriptor } from './readonly-text/readonly-text.descriptor';\nimport { descriptor as relationDescriptor } from './relation/relation.descriptor';\nimport { descriptor as selectDescriptor } from './select/select.descriptor';\nimport { descriptor as slugDescriptor } from './slug/slug.descriptor';\nimport { descriptor as stringListDescriptor } from './string-list/string-list.descriptor';\nimport { descriptor as textDescriptor } from './text/text.descriptor';\nimport { descriptor as textareaDescriptor } from './textarea/textarea.descriptor';\nimport { descriptor as timeDescriptor } from './time/time.descriptor';\nimport { descriptor as urlDescriptor } from './url/url.descriptor';\n\n/**\n * Tripwire de compilación (R1.7 · D17): que la unión `FieldType` y los\n * tipos que la UI sabe dibujar sigan diciendo lo mismo.\n *\n * · un valor que no esté en la unión `FieldSchema` ⇒ `satisfies` falla;\n * · un tipo de la unión que falte acá ⇒ `FaltaEnLaUi` no es `never`.\n *\n * **No es una fuente de verdad en runtime.** El catálogo vive en\n * `core/registry/render-registry.ts`, alimentado por los descriptores de\n * abajo. Esta lista sólo existe para que `npm run build` y `npm test` vean\n * la aserción por igual, sin depender de que un test la ejecute.\n *\n * **Exportada en R3.7** para que `core/registry/contract.spec.ts` pueda\n * verificar además el sentido que este archivo no cubre — que cada nombre de\n * la lista tenga **descriptor**: aquí sólo se comprueba que está en la unión,\n * y un tipo declarado en la lista pero ausente del manifiesto se vería en el\n * primer schema que lo use.\n *\n * **Mudado acá en R3.8.** Vivía en `field-host/field-host.ts`, y §0 es\n * explícito: «si añadir un tipo obliga a editar `FieldHost`, el motor no\n * está terminado». Estaba sin uso en runtime — sólo servía a este tripwire —\n * así que trasladarlo acá no cambia comportamiento y deja el registro y su\n * aserción en el **mismo archivo**: añadir un tipo toca una carpeta y una\n * línea de este manifiesto, y el host no se entera.\n */\nexport const SUPPORTED_FIELD_TYPE_LIST = [\n 'text',\n 'textarea',\n 'slug',\n 'number',\n 'currency',\n 'boolean',\n 'select',\n 'multiselect',\n 'url',\n 'email',\n 'phone',\n 'date',\n 'time',\n 'readonly-text',\n 'group',\n 'list',\n 'string-list',\n 'key-value',\n 'relation',\n 'image',\n 'file',\n] as const satisfies readonly FieldType[];\n\ntype FaltaEnLaUi = Exclude<FieldType, (typeof SUPPORTED_FIELD_TYPE_LIST)[number]>;\nconst _exhaustivo: FaltaEnLaUi extends never\n ? true\n : ['Falta en SUPPORTED_FIELD_TYPE_LIST', FaltaEnLaUi] = true;\n\n/**\n * Manifiesto de descriptores de campo (R3.3 · registro único de render).\n *\n * Una línea por tipo: el registro los recoge al importar este módulo. Es la\n * **única** lista manual del catálogo de campos — `import.meta.glob` no\n * sobrevive a `ng build`, así que D9-1 se resuelve con «registro manual de\n * una línea». Ver `core/registry/render-registry.ts`.\n *\n * Añadir un tipo de campo ⇒ crear la carpeta + su `.descriptor.ts` + una\n * línea acá. **Ningún host se toca** (R3.8).\n */\nexport const fieldDescriptors: readonly RenderDescriptor[] = [\n booleanDescriptor,\n currencyDescriptor,\n dateDescriptor,\n emailDescriptor,\n fileDescriptor,\n groupDescriptor,\n imageDescriptor,\n keyValueDescriptor,\n listDescriptor,\n multiselectDescriptor,\n numberDescriptor,\n phoneDescriptor,\n readonlyTextDescriptor,\n relationDescriptor,\n selectDescriptor,\n slugDescriptor,\n stringListDescriptor,\n textDescriptor,\n textareaDescriptor,\n timeDescriptor,\n urlDescriptor,\n];\n","import type { LayoutDescriptor } from '../core/registry/render-registry';\n\nexport const layoutDescriptors: readonly LayoutDescriptor[] = [\n { kind: 'layout', type: 'grid', since: '9.2' },\n { kind: 'layout', type: 'tabs', since: '9.2' },\n { kind: 'layout', type: 'sections', since: '9.2' },\n { kind: 'layout', type: 'steps', since: '9.2' },\n { kind: 'layout', type: 'columns', since: '9.2' },\n];\n","import type { BarDatum } from './bar-chart/bar-chart';\n\n/**\n * Normaliza el payload de un gráfico a `{ label: string, value: number }`.\n *\n * El dashboard recibe filas de una tabla y no todas llegan limpias, así que\n * el filtro se hace en el **borde** — en el descriptor, antes de que el dato\n * llegue al componente — y no dentro de cada gráfico. `bar-chart` y\n * `chart-line` comparten la misma regla, de ahí la función suelta.\n *\n * Devuelve `[]` ante cualquier cosa que no sea un array: un `metric-card`\n * pasado por error a un gráfico no puede romper la tarjeta.\n */\nexport function toSeries(data: unknown): BarDatum[] {\n if (!Array.isArray(data)) {\n return [];\n }\n return data\n .map((row): BarDatum | null => {\n if (typeof row !== 'object' || row === null) return null;\n const r = row as { label?: unknown; group?: unknown; value?: unknown };\n // El agregado agrupado del backend (R6.2) llega como { group, value };\n // la forma histórica de tabla es { label, value }. El gráfico sólo\n // entiende label ⇒ traducimos acá, en el borde.\n const label = typeof r.label === 'string' ? r.label : r.group;\n if (typeof label !== 'string' || typeof r.value !== 'number') return null;\n return { label, value: r.value };\n })\n .filter((row): row is BarDatum => row !== null);\n}\n\n/**\n * Normaliza el payload de un contador repartido por segmentos a\n * `{ clave: número }`.\n *\n * Dos formas, igual que `toSeries`:\n * - **payload** del panel: ya es un objeto plano de contadores por clave;\n * - **fuente declarada** (F8 · R6.5): una vista con `groupBy` devuelve filas\n * `[{ group, value }]` y cada grupo es el nombre de un segmento.\n *\n * `null` ante cualquier otra cosa: `StatusProgress` lo pinta como vacío en\n * vez de sumar un `[object Object]`.\n */\nexport function toCounters(data: unknown): Record<string, unknown> | null {\n if (Array.isArray(data)) {\n const out: Record<string, unknown> = {};\n for (const row of data) {\n if (typeof row !== 'object' || row === null) continue;\n const r = row as { group?: unknown; value?: unknown };\n if (typeof r.group === 'string' && 'value' in r) out[r.group] = r.value;\n }\n return out;\n }\n if (typeof data === 'object' && data !== null) return data as Record<string, unknown>;\n return null;\n}\n","import type { BarChartWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toSeries } from '../series';\n\n/** Descriptor del widget `bar-chart` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'bar-chart',\n since: '1.0',\n load: () => import('./bar-chart').then((module) => module.BarChart),\n surfaces: ['display'],\n inputs: (config, extras) => {\n const cfg = config as BarChartWidget;\n return { label: cfg.label, data: toSeries(extras.data), unit: cfg.unit ?? '' };\n },\n};\n","import type { ChartLineWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toSeries } from '../series';\n\n/** Descriptor del widget `chart-line` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'chart-line',\n since: '1.0',\n load: () => import('./chart-line').then((module) => module.ChartLine),\n surfaces: ['display'],\n inputs: (config, extras) => {\n const cfg = config as ChartLineWidget;\n return { label: cfg.label, data: toSeries(extras.data), unit: cfg.unit ?? '' };\n },\n};\n","import type { MetricCardWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/**\n * El dato de un KPI es un ESCALAR y puede llegar de dos formas:\n *\n * - **payload**: `data[widget.key]` ya es la cifra (la resuelve el handler\n * del panel);\n * - **fuente declarada** (F8 · R6.5): una vista con `aggregate` devuelve\n * `[{ value: … }]` y la cifra es ese `value`.\n *\n * Cualquier otra forma ⇒ `null`, que `MetricCard` pinta como vacío. Se\n * traduce acá, en el borde — el componente no debería saber de dónde salió\n * el número.\n */\nfunction valorDeKpi(data: unknown): number | string | null {\n if (Array.isArray(data)) {\n const first = data[0];\n if (typeof first !== 'object' || first === null) return null;\n const value = (first as { value?: unknown }).value;\n return value === undefined || value === null ? null : (value as number | string);\n }\n if (data === undefined) return null;\n return data as number | string | null;\n}\n\n/** Descriptor del widget `metric-card` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'metric-card',\n since: '1.0',\n load: () => import('./metric-card').then((module) => module.MetricCard),\n surfaces: ['display'],\n // El KPI no recibe el widget entero: sólo vive de su rótulo, del dato y de\n // la nota al pie. Pasa el dato ya traducido — `MetricCard` distingue el\n // `0` de un vacío, y el `0` de un agregado llega como `[{ value: 0 }]`.\n inputs: (config, extras) => {\n const cfg = config as MetricCardWidget;\n return { label: cfg.label, value: valorDeKpi(extras.data), hint: cfg.hint ?? '' };\n },\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del widget `quick-actions` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'quick-actions',\n since: '1.0',\n load: () => import('./quick-actions').then((module) => module.QuickActions),\n surfaces: ['display'],\n // El único widget sin dato: sus botones salen todos del schema. Por eso no\n // recibe `data` — `ngComponentOutletInputs` no admite inputs inexistentes.\n inputs: (config) => ({ widget: config }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del widget `record-list` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'record-list',\n since: '1.0',\n load: () => import('./record-list').then((module) => module.RecordList),\n surfaces: ['display'],\n // `RecordList` dibuja filas: fuera de un array no hay nada que listar, y un\n // objeto suelto no debe colarse como si fuera una única fila.\n inputs: (config, extras) => ({\n widget: config,\n data: Array.isArray(extras.data) ? (extras.data as Record<string, unknown>[]) : null,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toCounters } from '../series';\n\n/** Descriptor del widget `status-progress` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'status-progress',\n since: '1.0',\n load: () => import('./status-progress').then((module) => module.StatusProgress),\n surfaces: ['display'],\n // Contadores por clave: un objeto plano del payload O las filas de una\n // fuente con `groupBy` (F8 · R6.5) — `toCounters` traduce en el borde y\n // devuelve `null` si no hay nada que contar.\n inputs: (config, extras) => ({\n widget: config,\n data: toCounters(extras.data),\n }),\n};\n","import type { RenderDescriptor } from '../core/registry/render-registry';\n\nimport { descriptor as barChartDescriptor } from './bar-chart/bar-chart.descriptor';\nimport { descriptor as chartLineDescriptor } from './chart-line/chart-line.descriptor';\nimport { descriptor as metricCardDescriptor } from './metric-card/metric-card.descriptor';\nimport { descriptor as quickActionsDescriptor } from './quick-actions/quick-actions.descriptor';\nimport { descriptor as recordListDescriptor } from './record-list/record-list.descriptor';\nimport { descriptor as statusProgressDescriptor } from './status-progress/status-progress.descriptor';\n\n/**\n * Manifiesto de descriptores de widget (R3.6 · registro único de render).\n *\n * Mismo criterio que `fields/descriptors.ts`: una línea por tipo y el\n * registro los recoge al importar este módulo. Es la **única** lista manual\n * del catálogo de widgets — `import.meta.glob` no sobrevive a `ng build`\n * (D9-1), así que se mantiene el «registro manual de una línea».\n *\n * Añadir un widget ⇒ crear la carpeta + su `.descriptor.ts` + una línea\n * acá. **Ningún host se toca** (R3.8): si el componente sigue la forma\n * estándar `{widget, data}` ni siquiera hay que escribir `inputs`.\n */\nexport const widgetDescriptors: readonly RenderDescriptor[] = [\n barChartDescriptor,\n chartLineDescriptor,\n metricCardDescriptor,\n quickActionsDescriptor,\n recordListDescriptor,\n statusProgressDescriptor,\n];\n","import type { RenderDescriptor } from '../core/registry/render-registry';\n\nexport const viewDescriptors: readonly RenderDescriptor[] = [\n {\n kind: 'view',\n type: 'list',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'detail',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'form',\n since: '9.1',\n load: async () => (await import('../pages/form-view/form-view')).FormView,\n },\n {\n kind: 'view',\n type: 'dashboard',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'calendar',\n since: '9.8',\n load: async () => (await import('./calendar-view/calendar-view')).CalendarView,\n },\n {\n kind: 'view',\n type: 'kanban',\n since: '9.8',\n load: async () => (await import('./kanban-view/kanban-view')).KanbanView,\n },\n {\n kind: 'view',\n type: 'tabs',\n since: '9.9',\n load: async () => (await import('./composer/composer-host')).ComposerHost,\n },\n];\n","import {\n isDevMode,\n makeEnvironmentProviders,\n provideAppInitializer,\n type EnvironmentProviders,\n type TemplateRef,\n type Type,\n} from '@angular/core';\n\nimport type { RootTree } from '../../fields/field-node';\nimport type { SeedKind } from '../../shared/utils/seed';\nimport { columnFormatDescriptors } from '../../columns/descriptors';\nimport { fieldDescriptors } from '../../fields/descriptors';\nimport { layoutDescriptors } from '../../layouts/descriptors';\nimport { widgetDescriptors } from '../../widgets/descriptors';\nimport { viewDescriptors } from '../../views/descriptors';\nimport type { FieldSchema, LayoutMode, ListColumn, WidgetSchema } from '../models/schema.model';\n\n/**\n * Registro único de render (R3.1 · `doc/plan-refactor-motor.md` §3.1).\n *\n * Un solo sitio declara qué componentes sabe dibujar la UI: cada tipo de\n * campo, widget, acción o vista aporta un `RenderDescriptor` y el registro\n * lo resuelve por `(kind, type)`. Los hosts dejan de mantener `Set`s de tipos\n * e imports a mano — **en runtime el registro es la única fuente de verdad**.\n *\n * Se carga a scope de módulo y no desde DI: `buildFormSchema()` es una\n * función pura que consulta el registro sin inyectar nada, así que un\n * registro llenado únicamente por un provider dejaría esa consulta correr\n * contra un catálogo vacío. `provideRenderDescriptors()` existe igualmente\n * como punto de entrada explícito para `app.config.ts` (R3.2).\n *\n * Autodescubrimiento (D9-1): se opta por **registro manual** — un manifiesto\n * con una línea por descriptor — porque `import.meta.glob` no está\n * implementada por el bundler de producción (`@angular/build:application`\n * usa esbuild) y la llamada cruda sobreviviría en `dist/`, rompiendo el\n * arranque. Con Vite sólo en el dev-server y en el runner de tests, además,\n * el comportamiento habría diferido entre `npm test` y `npm run build`.\n */\n\n/** Qué clase de cosa se está resolviendo. Identificador único dentro de su `kind`. */\nexport type RenderKind = 'field' | 'column-format' | 'widget' | 'action' | 'view' | 'layout';\nexport type ComponentRenderKind = Exclude<RenderKind, 'layout'>;\n\n/** Superficies en las que un descriptor puede aparecer. */\nexport type RenderSurface = 'form' | 'display' | 'list' | 'filter';\n\n/**\n * Qué puede describir un `RenderDescriptor`: un campo del formulario, un\n * widget del dashboard o una columna de listado (R4.3).\n *\n * Es el tipo del input `config` del host. Los descriptores sólo comparten\n * `key` y `label`; lo demás lo decide cada `kind`, y quien necesita el resto\n * lo castea con su propia mirada (`cfgCampo()`, que es lo que el host ya\n * hacía antes de que existieran las columnas).\n */\nexport type RenderConfig = FieldSchema | WidgetSchema | ListColumn;\n\n/**\n * Contexto de render que el host expone por DI (R3.4 · `doc/plan-refactor-motor.md` §3.4).\n *\n * Los controles viven en un componente distinto por cada tipo, así que en vez\n * de repetir cinco inputs en los 20 el host lo provee una sola vez y cada\n * control lo inyecta si lo necesita — el mismo criterio que ya usaba\n * `FIELD_ARIA`.\n *\n * `tree` viaja en el contexto y no como input suelto porque es **por\n * instancia**: los hijos de un `group` o de un `list` navegan su subárbol, no\n * el del padre.\n *\n * Vive acá y no en `render-host.ts` porque el contrato de los descriptores\n * (`RenderExtras`) necesita nombrarlo: el descriptor de un campo compuesto\n * decide qué se le pasa al componente y eso sólo es escribible conociendo el\n * tipo. `render-host.ts` lo re-exporta para no mover a sus consumidores.\n */\nexport interface RenderContext {\n /** Árbol del formulario del nivel de este campo. */\n tree: RootTree;\n /** Errores del backend por ruta (`address.street`, `faq[2].answer`). */\n serverErrors: Record<string, string>;\n /** Prefijo de ruta de este campo en el registro raíz (`address.`). */\n pathPrefix: string;\n /** Si el registro ya existe (lo consume `slug` con `lockAfterCreate`). */\n exists: boolean;\n /** Recurso dueño del formulario (lo consume `image` para la firma, §11.2). */\n resource: string;\n}\n\n/**\n * Contexto vacío con el que arranca `RenderHost.ctx`.\n *\n * Sólo lo alcanza quien renderiza sin contexto — los widgets, que no forman\n * parte de un formulario. Un campo montado sin `ctx` es un error de\n * programación y `childTree` lo dice con su propio mensaje, igual que lo\n * decía el `input.required` anterior.\n */\nexport const RENDER_CONTEXT_VACIO: RenderContext = {\n tree: undefined as unknown as RootTree,\n serverErrors: {},\n pathPrefix: '',\n exists: false,\n resource: '',\n};\n\n/**\n * Segundo argumento de `RenderDescriptor.inputs`.\n *\n * Aporta lo que el host conoce y el descriptor no: el contexto de formulario\n * (sólo para campos), el payload del dato (sólo para widgets) y los dos\n * templates con los que se componen `group` y `list`.\n */\nexport interface RenderExtras {\n /** Contexto del nivel; `RENDER_CONTEXT_VACIO` cuando no hay formulario. */\n ctx: RenderContext;\n /** Payload del widget (`<app-widget-host [data]>`); `null` en campos. */\n data: unknown;\n /** Template del contenido de un `group`. */\n groupContent?: TemplateRef<unknown>;\n /** Template de los hijos de un `list`. */\n childTemplate?: TemplateRef<unknown>;\n}\n\n/**\n * Declaración de un componente renderizable.\n *\n * No lleva `configSchema`: esa cláusula de `refactormotor.md` no existe en\n * el código y el plan la descartó (D17).\n */\nexport interface RenderDescriptor<C = unknown> {\n /** Clase de cosa. */\n kind: ComponentRenderKind;\n /** Identificador `kebab-case`, único dentro de `kind`. */\n type: string;\n /** Versión del contrato en que apareció (`doc/refactormotor.md`). */\n since: string;\n /**\n * Carga perezosa del componente. El registro se resuelve sin arrastrar el\n * bundle: los descriptores sólo guardan el cierre, no la clase.\n */\n load: () => Promise<Type<any>>;\n /** Superficies en las que se usa. Sólo lo que se pueda evidenciar en el código. */\n surfaces?: RenderSurface[];\n /** Valores por defecto de la configuración del descriptor. */\n defaults?: Partial<C>;\n /**\n * Forma del valor inicial que siembra este campo en el modelo del\n * formulario (D32 · R3.8).\n *\n * **Dato, no función**: un nombre resuelto por `shared/utils/seed.ts`, no\n * una clausura. Así el descriptor sigue siendo puro —`kind`, `type`,\n * `load`, `surfaces`, `seed`— y `seed.ts` es el único dueño de recorrer\n * un árbol de campos. La alternativa (`seed: (cfg) => …`) obligaría a que\n * `group` importara `seedFields`, lo que cerraría un ciclo\n * registro → manifiesto → descriptor → `seed` → registro.\n *\n * Sólo los campos lo declaran. **Obligatorio para `kind: 'field'`** — lo\n * vigila `core/registry/contract.spec.ts`, porque la exhaustividad de una\n * unión de strings no puede imponerse en tiempo de compilación.\n */\n seed?: SeedKind;\n /**\n * Cableado del componente: qué inputs recibe y con qué valor.\n *\n * Es **la** pieza que mantiene el host genérico: sin esto el motor tendría\n * que saber que `metric-card` recibe `label/value/hint` y que `group`\n * necesita además el template de sus hijos, y «añadir un tipo» volvería a\n * tocar `render-host.ts` (R3.8). Cada descriptor declara el suyo y el host\n * sólo hace `ngComponentOutletInputs = descriptor.inputs(config, extras)`.\n *\n * No es obligatorio: el 80 % de los tipos comparten la forma estándar de su\n * `kind` — `{field, tree}` en campos, `{widget, data}` en widgets — y para\n * ellos el host aplica esa forma por defecto. Se declara sólo cuando el\n * componente se desvía de ella.\n */\n inputs?: (config: C, extras: RenderExtras) => Record<string, unknown>;\n}\n\n/** Declaración de un layout manejado por el host de formularios. */\nexport interface LayoutDescriptor {\n kind: 'layout';\n type: LayoutMode;\n since: string;\n}\n\n/** Catálogo en memoria: `kind:type` → descriptor. */\nconst RENDERERS = new Map<string, RenderDescriptor>();\nconst LAYOUTS = new Map<string, LayoutDescriptor>();\n\nfunction keyOf(kind: RenderKind, type: string): string {\n return `${kind}:${type}`;\n}\n\n/**\n * Registra un descriptor. Idempotente por clave: volver a registrar el mismo\n * `(kind, type)` lo sobrescribe, lo que permite que un módulo se recargue en\n * desarrollo sin duplicar entradas.\n */\nexport function register(kind: 'layout', descriptor: LayoutDescriptor): void;\nexport function register(kind: ComponentRenderKind, descriptor: RenderDescriptor): void;\nexport function register(kind: RenderKind, descriptor: RenderDescriptor | LayoutDescriptor): void {\n if (kind === 'layout') {\n if (!('kind' in descriptor) || descriptor.kind !== 'layout') {\n throw new Error(`El descriptor de layout \"${descriptor.type}\" no declara kind: \"layout\".`);\n }\n LAYOUTS.set(descriptor.type, descriptor);\n return;\n }\n if (descriptor.kind === 'layout') {\n throw new Error(\n `El descriptor de layout \"${descriptor.type}\" no puede registrarse como ${kind}.`,\n );\n }\n RENDERERS.set(keyOf(kind, descriptor.type), descriptor);\n}\n\n/**\n * Quita un descriptor (R7.6). Simétrico a `register`: los specs que\n * registran entradas de prueba deben retirarlas, o el catálogo global queda\n * contaminado para cualquier otro spec que lea `renderKinds()` (flaky por\n * orden de ejecución).\n */\nexport function unregister(kind: RenderKind, type: string): void {\n if (kind === 'layout') {\n LAYOUTS.delete(type);\n } else {\n RENDERERS.delete(keyOf(kind, type));\n }\n}\n\n/** Descriptor declarado para `(kind, type)`, o `undefined` si nadie lo registró. */\nexport function get(kind: ComponentRenderKind, type: string): RenderDescriptor | undefined {\n return RENDERERS.get(keyOf(kind, type));\n}\n\n/** ¿La UI sabe dibujar este `(kind, type)`? Reemplaza a los `Set`s de los hosts. */\nexport function isSupported(kind: RenderKind, type: string): boolean {\n return kind === 'layout' ? LAYOUTS.has(type) : RENDERERS.has(keyOf(kind, type));\n}\n\n/**\n * Componente para `(kind, type)`, o `fallback` si el tipo no está en el\n * catálogo.\n *\n * Es **asíncrona** porque `load()` importa el componente bajo demanda; el\n * `fallback` es síncrono y sólo se usa cuando no hay descriptor. Un fallo de\n * `load()` NO se traga: propagarlo es lo que hace visible un descriptor mal\n * escrito, y la política «nunca pantalla rota» la resuelve el llamante con el\n * `fallback` que ya recibe.\n */\nexport async function resolve<C = unknown>(\n kind: ComponentRenderKind,\n type: string,\n fallback: Type<C>,\n): Promise<Type<C>> {\n const descriptor = get(kind, type);\n if (!descriptor) return fallback;\n return (await descriptor.load()) as Type<C>;\n}\n\n// Catálogo a scope de módulo: se registra al importar, sin esperar a DI.\nfor (const descriptor of [\n ...fieldDescriptors,\n ...widgetDescriptors,\n ...columnFormatDescriptors,\n ...viewDescriptors,\n ...layoutDescriptors,\n]) {\n if (descriptor.kind === 'layout') {\n register('layout', descriptor);\n } else {\n register(descriptor.kind, descriptor);\n }\n}\n\n/**\n * Punto de entrada para `app.config.ts` (R3.2).\n *\n * El catálogo ya quedó cargado al importar este módulo; el provider sirve\n * para que el arranque sea explícito y para avisar en desarrollo si el\n * manifiesto vino vacío — que es exactamente lo que pasaría si alguien\n * borra una línea del manifiesto sin reemplazarla.\n */\nexport function provideRenderDescriptors(): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideAppInitializer(() => {\n if (isDevMode() && RENDERERS.size === 0 && LAYOUTS.size === 0) {\n console.warn('[render-registry] el catálogo de descriptores vino vacío');\n }\n }),\n ]);\n}\n\n/** Cuántos descriptores hay registrados. Sólo para comprobaciones y tests. */\nexport function renderDescriptorCount(): number {\n return RENDERERS.size + LAYOUTS.size;\n}\n\n/**\n * `kind`s que hoy tienen al menos un descriptor.\n *\n * Existe para el test de exhaustividad (R3.7): él recorre los schemas de los\n * `kind`s que tienen registro y **falla** si aparece un `kind` con descriptor\n * que nadie recorre — de lo contrario «tener registro» y «estar cubierto»\n * serían dos afirmaciones distintas que nadie reconcilia.\n */\nexport function renderKinds(): RenderKind[] {\n const kinds = new Set<RenderKind>([...RENDERERS.values()].map((descriptor) => descriptor.kind));\n if (LAYOUTS.size > 0) {\n kinds.add('layout');\n }\n return [...kinds];\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"tinya-code-gas-admin-ui-render-registry-B7mmgFSW.mjs","names":[],"sources":["../../../projects/gas-admin-ui/src/lib/columns/descriptors.ts","../../../projects/gas-admin-ui/src/lib/fields/boolean/boolean.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/currency/currency.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/date/date.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/email/email.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/file/file.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/group/group.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/image/image.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/key-value/key-value.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/list/list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/multiselect/multiselect.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/number/number.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/phone/phone.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/readonly-text/readonly-text.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/relation/relation.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/select/select.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/slug/slug.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/string-list/string-list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/text/text.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/textarea/textarea.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/time/time.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/url/url.descriptor.ts","../../../projects/gas-admin-ui/src/lib/fields/descriptors.ts","../../../projects/gas-admin-ui/src/lib/layouts/descriptors.ts","../../../projects/gas-admin-ui/src/lib/widgets/series.ts","../../../projects/gas-admin-ui/src/lib/widgets/bar-chart/bar-chart.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/chart-line/chart-line.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/metric-card/metric-card.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/quick-actions/quick-actions.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/record-list/record-list.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/status-progress/status-progress.descriptor.ts","../../../projects/gas-admin-ui/src/lib/widgets/descriptors.ts","../../../projects/gas-admin-ui/src/lib/views/descriptors.ts","../../../projects/gas-admin-ui/src/lib/core/registry/render-registry.ts"],"sourcesContent":["import type { RenderDescriptor, RenderExtras } from '../core/registry/render-registry';\n\n/**\n * Manifiesto de descriptores de formato de columna (R4.3 · `kind:\n * 'column-format'`).\n *\n * Es el equivalente a `fields/descriptors.ts` y `widgets/descriptors.ts`:\n * una línea por formato y ningún import de componente — cada `load()` guarda\n * el cierre de un `import()` **con literal**, que es lo que permite al\n * bundler partir el chunk; el registro los recoge al importar este módulo\n * (`core/registry/render-registry.ts`).\n *\n * **Añadir un formato** ⇒ crear `format-<nombre>.ts` + una entrada acá.\n * `list-view` no se toca: ése es el criterio de éxito de R4.3.\n *\n * Todos comparten el cableado: el descriptor sólo expone la celda, que la\n * vista cuelga de `extras.data`.\n */\nconst inputs = (_config: unknown, extras: RenderExtras): Record<string, unknown> => ({\n cell: extras.data,\n});\n\nconst text: RenderDescriptor = {\n kind: 'column-format',\n type: 'text',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-text').then((module) => module.ColumnFormatText),\n inputs,\n};\n\nconst badge: RenderDescriptor = {\n kind: 'column-format',\n type: 'badge',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-badge').then((module) => module.ColumnFormatBadge),\n inputs,\n};\n\nconst thumbnail: RenderDescriptor = {\n kind: 'column-format',\n type: 'thumbnail',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-thumbnail').then((module) => module.ColumnFormatThumbnail),\n inputs,\n};\n\nconst boolean: RenderDescriptor = {\n kind: 'column-format',\n type: 'boolean',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-boolean').then((module) => module.ColumnFormatBoolean),\n inputs,\n};\n\nconst number: RenderDescriptor = {\n kind: 'column-format',\n type: 'number',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-number').then((module) => module.ColumnFormatNumber),\n inputs,\n};\n\nconst currency: RenderDescriptor = {\n kind: 'column-format',\n type: 'currency',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-currency').then((module) => module.ColumnFormatCurrency),\n inputs,\n};\n\nconst date: RenderDescriptor = {\n kind: 'column-format',\n type: 'date',\n since: '1.0',\n surfaces: ['list'],\n load: () => import('./format-date').then((module) => module.ColumnFormatDate),\n inputs,\n};\n\n/** Los 7 formatos del `@switch` que este registro reemplaza (R4.3). */\nexport const columnFormatDescriptors: readonly RenderDescriptor[] = [\n text,\n badge,\n thumbnail,\n boolean,\n number,\n currency,\n date,\n];\n\n/**\n * Los 7 nombres, como dato.\n *\n * Va en paralelo a `ListColumnFormat` (unión de `schema.model`) y lo vigila\n * `core/registry/contract.spec.ts`: la unión vive en tipos y el registro en\n * runtime, y sólo un test reconcilia los dos — el mismo tripwire que ya\n * existe para los 20 campos y los 6 widgets.\n */\nexport const COLUMN_FORMAT_TYPES = [\n 'text',\n 'badge',\n 'thumbnail',\n 'boolean',\n 'number',\n 'currency',\n 'date',\n] as const;\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `boolean` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'boolean',\n since: '1.0',\n load: () => import('./boolean').then((module) => module.FieldBoolean),\n seed: 'boolean',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `currency` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'currency',\n since: '1.0',\n load: () => import('./currency').then((module) => module.FieldCurrency),\n // Nace como `null`: no puede ser `0`, que sería un valor ya cargado.\n seed: 'number',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `date` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'date',\n since: '1.0',\n load: () => import('./date').then((module) => module.FieldDate),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `email` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'email',\n since: '1.0',\n load: () => import('./email').then((module) => module.FieldEmail),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `file` (R3.3 · R9.5.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'file',\n since: '9.5',\n load: () => import('./file').then((module) => module.FieldFile),\n // Nace como cadena: la URL pública es el valor, igual que en `image`.\n seed: 'string',\n surfaces: ['form', 'display'],\n // Como `image` (D27): control propio cuya sincronización con Signal Forms\n // vive en ɵɵcontrol, así que el host lo declara a mano con `[formField]`.\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `group` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'group',\n since: '1.0',\n load: () => import('./group').then((module) => module.FieldGroup),\n // Contenedor: siembra un nodo por cada hijo declarado.\n seed: 'recursive',\n surfaces: ['form', 'display'],\n // Compuesto: además de su árbol dibuja el template de sus hijos, que sólo\n // existe en la plantilla del host. Él es quien decide recibirlo (R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n serverErrors: extras.ctx.serverErrors,\n pathPrefix: extras.ctx.pathPrefix,\n content: extras.groupContent,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `image` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'image',\n since: '1.0',\n load: () => import('./image').then((module) => module.FieldImage),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `key-value` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'key-value',\n since: '1.0',\n load: () => import('./key-value').then((module) => module.FieldKeyValue),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `list` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'list',\n since: '1.0',\n load: () => import('./list').then((module) => module.FieldList),\n seed: 'array',\n surfaces: ['form', 'display'],\n // Compuesto: además de su árbol dibuja el template de cada hijo y hereda\n // el `exists` del nivel para no reactivar el borrado de filas (R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n childTemplate: extras.childTemplate,\n serverErrors: extras.ctx.serverErrors,\n pathPrefix: extras.ctx.pathPrefix,\n exists: extras.ctx.exists,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `multiselect` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'multiselect',\n since: '1.0',\n load: () => import('./multiselect').then((module) => module.FieldMultiselect),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `number` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'number',\n since: '1.0',\n load: () => import('./number').then((module) => module.FieldNumber),\n // Nace como `null`: no puede ser `0`, que sería un valor ya cargado.\n seed: 'number',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `phone` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'phone',\n since: '1.0',\n load: () => import('./phone').then((module) => module.FieldPhone),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `readonly-text` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'readonly-text',\n since: '1.0',\n load: () => import('./readonly-text').then((module) => module.FieldReadonlyText),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `relation` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'relation',\n since: '1.0',\n load: () => import('./relation').then((module) => module.FieldRelation),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `select` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'select',\n since: '1.0',\n load: () => import('./select').then((module) => module.FieldSelect),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `slug` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'slug',\n since: '1.0',\n load: () => import('./slug').then((module) => module.FieldSlug),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n // Se aparta de la forma estándar sólo por `exists`: con el registro ya\n // creado el campo queda bloqueado (`lockAfterCreate`, R3.6).\n inputs: (config, extras) => ({\n field: config,\n tree: extras.ctx.tree,\n exists: extras.ctx.exists,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `string-list` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'string-list',\n since: '1.0',\n load: () => import('./string-list').then((module) => module.FieldStringList),\n seed: 'array',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `text` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'text',\n since: '1.0',\n load: () => import('./text').then((module) => module.FieldText),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `textarea` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'textarea',\n since: '1.0',\n load: () => import('./textarea').then((module) => module.FieldTextarea),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `time` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'time',\n since: '1.0',\n load: () => import('./time').then((module) => module.FieldTime),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del campo `url` (R3.3). */\nexport const descriptor: RenderDescriptor = {\n kind: 'field',\n type: 'url',\n since: '1.0',\n load: () => import('./url').then((module) => module.FieldUrl),\n // Nace como cadena: los textos, fechas, urls, selects y relacionales.\n seed: 'string',\n surfaces: ['form', 'display'],\n};\n","import type { RenderDescriptor } from '../core/registry/render-registry';\nimport type { FieldType } from '../core/models/schema.model';\n\nimport { descriptor as booleanDescriptor } from './boolean/boolean.descriptor';\nimport { descriptor as currencyDescriptor } from './currency/currency.descriptor';\nimport { descriptor as dateDescriptor } from './date/date.descriptor';\nimport { descriptor as emailDescriptor } from './email/email.descriptor';\nimport { descriptor as fileDescriptor } from './file/file.descriptor';\nimport { descriptor as groupDescriptor } from './group/group.descriptor';\nimport { descriptor as imageDescriptor } from './image/image.descriptor';\nimport { descriptor as keyValueDescriptor } from './key-value/key-value.descriptor';\nimport { descriptor as listDescriptor } from './list/list.descriptor';\nimport { descriptor as multiselectDescriptor } from './multiselect/multiselect.descriptor';\nimport { descriptor as numberDescriptor } from './number/number.descriptor';\nimport { descriptor as phoneDescriptor } from './phone/phone.descriptor';\nimport { descriptor as readonlyTextDescriptor } from './readonly-text/readonly-text.descriptor';\nimport { descriptor as relationDescriptor } from './relation/relation.descriptor';\nimport { descriptor as selectDescriptor } from './select/select.descriptor';\nimport { descriptor as slugDescriptor } from './slug/slug.descriptor';\nimport { descriptor as stringListDescriptor } from './string-list/string-list.descriptor';\nimport { descriptor as textDescriptor } from './text/text.descriptor';\nimport { descriptor as textareaDescriptor } from './textarea/textarea.descriptor';\nimport { descriptor as timeDescriptor } from './time/time.descriptor';\nimport { descriptor as urlDescriptor } from './url/url.descriptor';\n\n/**\n * Tripwire de compilación (R1.7 · D17): que la unión `FieldType` y los\n * tipos que la UI sabe dibujar sigan diciendo lo mismo.\n *\n * · un valor que no esté en la unión `FieldSchema` ⇒ `satisfies` falla;\n * · un tipo de la unión que falte acá ⇒ `FaltaEnLaUi` no es `never`.\n *\n * **No es una fuente de verdad en runtime.** El catálogo vive en\n * `core/registry/render-registry.ts`, alimentado por los descriptores de\n * abajo. Esta lista sólo existe para que `npm run build` y `npm test` vean\n * la aserción por igual, sin depender de que un test la ejecute.\n *\n * **Exportada en R3.7** para que `core/registry/contract.spec.ts` pueda\n * verificar además el sentido que este archivo no cubre — que cada nombre de\n * la lista tenga **descriptor**: aquí sólo se comprueba que está en la unión,\n * y un tipo declarado en la lista pero ausente del manifiesto se vería en el\n * primer schema que lo use.\n *\n * **Mudado acá en R3.8.** Vivía en `field-host/field-host.ts`, y §0 es\n * explícito: «si añadir un tipo obliga a editar `FieldHost`, el motor no\n * está terminado». Estaba sin uso en runtime — sólo servía a este tripwire —\n * así que trasladarlo acá no cambia comportamiento y deja el registro y su\n * aserción en el **mismo archivo**: añadir un tipo toca una carpeta y una\n * línea de este manifiesto, y el host no se entera.\n */\nexport const SUPPORTED_FIELD_TYPE_LIST = [\n 'text',\n 'textarea',\n 'slug',\n 'number',\n 'currency',\n 'boolean',\n 'select',\n 'multiselect',\n 'url',\n 'email',\n 'phone',\n 'date',\n 'time',\n 'readonly-text',\n 'group',\n 'list',\n 'string-list',\n 'key-value',\n 'relation',\n 'image',\n 'file',\n] as const satisfies readonly FieldType[];\n\ntype FaltaEnLaUi = Exclude<FieldType, (typeof SUPPORTED_FIELD_TYPE_LIST)[number]>;\nconst _exhaustivo: FaltaEnLaUi extends never\n ? true\n : ['Falta en SUPPORTED_FIELD_TYPE_LIST', FaltaEnLaUi] = true;\n\n/**\n * Manifiesto de descriptores de campo (R3.3 · registro único de render).\n *\n * Una línea por tipo: el registro los recoge al importar este módulo. Es la\n * **única** lista manual del catálogo de campos — `import.meta.glob` no\n * sobrevive a `ng build`, así que D9-1 se resuelve con «registro manual de\n * una línea». Ver `core/registry/render-registry.ts`.\n *\n * Añadir un tipo de campo ⇒ crear la carpeta + su `.descriptor.ts` + una\n * línea acá. **Ningún host se toca** (R3.8).\n */\nexport const fieldDescriptors: readonly RenderDescriptor[] = [\n booleanDescriptor,\n currencyDescriptor,\n dateDescriptor,\n emailDescriptor,\n fileDescriptor,\n groupDescriptor,\n imageDescriptor,\n keyValueDescriptor,\n listDescriptor,\n multiselectDescriptor,\n numberDescriptor,\n phoneDescriptor,\n readonlyTextDescriptor,\n relationDescriptor,\n selectDescriptor,\n slugDescriptor,\n stringListDescriptor,\n textDescriptor,\n textareaDescriptor,\n timeDescriptor,\n urlDescriptor,\n];\n","import type { LayoutDescriptor } from '../core/registry/render-registry';\n\nexport const layoutDescriptors: readonly LayoutDescriptor[] = [\n { kind: 'layout', type: 'grid', since: '9.2' },\n { kind: 'layout', type: 'tabs', since: '9.2' },\n { kind: 'layout', type: 'sections', since: '9.2' },\n { kind: 'layout', type: 'steps', since: '9.2' },\n { kind: 'layout', type: 'columns', since: '9.2' },\n];\n","import type { BarDatum } from './bar-chart/bar-chart';\n\n/**\n * Normaliza el payload de un gráfico a `{ label: string, value: number }`.\n *\n * El dashboard recibe filas de una tabla y no todas llegan limpias, así que\n * el filtro se hace en el **borde** — en el descriptor, antes de que el dato\n * llegue al componente — y no dentro de cada gráfico. `bar-chart` y\n * `chart-line` comparten la misma regla, de ahí la función suelta.\n *\n * Devuelve `[]` ante cualquier cosa que no sea un array: un `metric-card`\n * pasado por error a un gráfico no puede romper la tarjeta.\n */\nexport function toSeries(data: unknown): BarDatum[] {\n if (!Array.isArray(data)) {\n return [];\n }\n return data\n .map((row): BarDatum | null => {\n if (typeof row !== 'object' || row === null) return null;\n const r = row as { label?: unknown; group?: unknown; value?: unknown };\n // El agregado agrupado del backend (R6.2) llega como { group, value };\n // la forma histórica de tabla es { label, value }. El gráfico sólo\n // entiende label ⇒ traducimos acá, en el borde.\n const label = typeof r.label === 'string' ? r.label : r.group;\n if (typeof label !== 'string' || typeof r.value !== 'number') return null;\n return { label, value: r.value };\n })\n .filter((row): row is BarDatum => row !== null);\n}\n\n/**\n * Normaliza el payload de un contador repartido por segmentos a\n * `{ clave: número }`.\n *\n * Dos formas, igual que `toSeries`:\n * - **payload** del panel: ya es un objeto plano de contadores por clave;\n * - **fuente declarada** (F8 · R6.5): una vista con `groupBy` devuelve filas\n * `[{ group, value }]` y cada grupo es el nombre de un segmento.\n *\n * `null` ante cualquier otra cosa: `StatusProgress` lo pinta como vacío en\n * vez de sumar un `[object Object]`.\n */\nexport function toCounters(data: unknown): Record<string, unknown> | null {\n if (Array.isArray(data)) {\n const out: Record<string, unknown> = {};\n for (const row of data) {\n if (typeof row !== 'object' || row === null) continue;\n const r = row as { group?: unknown; value?: unknown };\n if (typeof r.group === 'string' && 'value' in r) out[r.group] = r.value;\n }\n return out;\n }\n if (typeof data === 'object' && data !== null) return data as Record<string, unknown>;\n return null;\n}\n","import type { BarChartWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toSeries } from '../series';\n\n/** Descriptor del widget `bar-chart` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'bar-chart',\n since: '1.0',\n load: () => import('./bar-chart').then((module) => module.BarChart),\n surfaces: ['display'],\n inputs: (config, extras) => {\n const cfg = config as BarChartWidget;\n return { label: cfg.label, data: toSeries(extras.data), unit: cfg.unit ?? '' };\n },\n};\n","import type { ChartLineWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toSeries } from '../series';\n\n/** Descriptor del widget `chart-line` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'chart-line',\n since: '1.0',\n load: () => import('./chart-line').then((module) => module.ChartLine),\n surfaces: ['display'],\n inputs: (config, extras) => {\n const cfg = config as ChartLineWidget;\n return { label: cfg.label, data: toSeries(extras.data), unit: cfg.unit ?? '' };\n },\n};\n","import type { MetricCardWidget } from '../../core/models/schema.model';\nimport type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/**\n * El dato de un KPI es un ESCALAR y puede llegar de dos formas:\n *\n * - **payload**: `data[widget.key]` ya es la cifra (la resuelve el handler\n * del panel);\n * - **fuente declarada** (F8 · R6.5): una vista con `aggregate` devuelve\n * `[{ value: … }]` y la cifra es ese `value`.\n *\n * Cualquier otra forma ⇒ `null`, que `MetricCard` pinta como vacío. Se\n * traduce acá, en el borde — el componente no debería saber de dónde salió\n * el número.\n */\nfunction valorDeKpi(data: unknown): number | string | null {\n if (Array.isArray(data)) {\n const first = data[0];\n if (typeof first !== 'object' || first === null) return null;\n const value = (first as { value?: unknown }).value;\n return value === undefined || value === null ? null : (value as number | string);\n }\n if (data === undefined) return null;\n return data as number | string | null;\n}\n\n/** Descriptor del widget `metric-card` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'metric-card',\n since: '1.0',\n load: () => import('./metric-card').then((module) => module.MetricCard),\n surfaces: ['display'],\n // El KPI no recibe el widget entero: sólo vive de su rótulo, del dato y de\n // la nota al pie. Pasa el dato ya traducido — `MetricCard` distingue el\n // `0` de un vacío, y el `0` de un agregado llega como `[{ value: 0 }]`.\n inputs: (config, extras) => {\n const cfg = config as MetricCardWidget;\n return { label: cfg.label, value: valorDeKpi(extras.data), hint: cfg.hint ?? '' };\n },\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del widget `quick-actions` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'quick-actions',\n since: '1.0',\n load: () => import('./quick-actions').then((module) => module.QuickActions),\n surfaces: ['display'],\n // El único widget sin dato: sus botones salen todos del schema. Por eso no\n // recibe `data` — `ngComponentOutletInputs` no admite inputs inexistentes.\n inputs: (config) => ({ widget: config }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\n/** Descriptor del widget `record-list` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'record-list',\n since: '1.0',\n load: () => import('./record-list').then((module) => module.RecordList),\n surfaces: ['display'],\n // `RecordList` dibuja filas: fuera de un array no hay nada que listar, y un\n // objeto suelto no debe colarse como si fuera una única fila.\n inputs: (config, extras) => ({\n widget: config,\n data: Array.isArray(extras.data) ? (extras.data as Record<string, unknown>[]) : null,\n }),\n};\n","import type { RenderDescriptor } from '../../core/registry/render-registry';\n\nimport { toCounters } from '../series';\n\n/** Descriptor del widget `status-progress` (R3.6). */\nexport const descriptor: RenderDescriptor = {\n kind: 'widget',\n type: 'status-progress',\n since: '1.0',\n load: () => import('./status-progress').then((module) => module.StatusProgress),\n surfaces: ['display'],\n // Contadores por clave: un objeto plano del payload O las filas de una\n // fuente con `groupBy` (F8 · R6.5) — `toCounters` traduce en el borde y\n // devuelve `null` si no hay nada que contar.\n inputs: (config, extras) => ({\n widget: config,\n data: toCounters(extras.data),\n }),\n};\n","import type { RenderDescriptor } from '../core/registry/render-registry';\n\nimport { descriptor as barChartDescriptor } from './bar-chart/bar-chart.descriptor';\nimport { descriptor as chartLineDescriptor } from './chart-line/chart-line.descriptor';\nimport { descriptor as metricCardDescriptor } from './metric-card/metric-card.descriptor';\nimport { descriptor as quickActionsDescriptor } from './quick-actions/quick-actions.descriptor';\nimport { descriptor as recordListDescriptor } from './record-list/record-list.descriptor';\nimport { descriptor as statusProgressDescriptor } from './status-progress/status-progress.descriptor';\n\n/**\n * Manifiesto de descriptores de widget (R3.6 · registro único de render).\n *\n * Mismo criterio que `fields/descriptors.ts`: una línea por tipo y el\n * registro los recoge al importar este módulo. Es la **única** lista manual\n * del catálogo de widgets — `import.meta.glob` no sobrevive a `ng build`\n * (D9-1), así que se mantiene el «registro manual de una línea».\n *\n * Añadir un widget ⇒ crear la carpeta + su `.descriptor.ts` + una línea\n * acá. **Ningún host se toca** (R3.8): si el componente sigue la forma\n * estándar `{widget, data}` ni siquiera hay que escribir `inputs`.\n */\nexport const widgetDescriptors: readonly RenderDescriptor[] = [\n barChartDescriptor,\n chartLineDescriptor,\n metricCardDescriptor,\n quickActionsDescriptor,\n recordListDescriptor,\n statusProgressDescriptor,\n];\n","import type { RenderDescriptor } from '../core/registry/render-registry';\n\nexport const viewDescriptors: readonly RenderDescriptor[] = [\n {\n kind: 'view',\n type: 'list',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'detail',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'form',\n since: '9.1',\n load: async () => (await import('../pages/form-view/form-view')).FormView,\n },\n {\n kind: 'view',\n type: 'dashboard',\n since: '9.1',\n load: async () => (await import('../pages/resource-page/resource-page')).ResourcePage,\n },\n {\n kind: 'view',\n type: 'calendar',\n since: '9.8',\n load: async () => (await import('./calendar-view/calendar-view')).CalendarView,\n },\n {\n kind: 'view',\n type: 'kanban',\n since: '9.8',\n load: async () => (await import('./kanban-view/kanban-view')).KanbanView,\n },\n {\n kind: 'view',\n type: 'tabs',\n since: '9.9',\n load: async () => (await import('./composer/composer-host')).ComposerHost,\n },\n];\n","import {\n isDevMode,\n makeEnvironmentProviders,\n provideAppInitializer,\n type EnvironmentProviders,\n type TemplateRef,\n type Type,\n} from '@angular/core';\n\nimport type { RootTree } from '../../fields/field-node';\nimport type { SeedKind } from '../../shared/utils/seed';\nimport { columnFormatDescriptors } from '../../columns/descriptors';\nimport { fieldDescriptors } from '../../fields/descriptors';\nimport { layoutDescriptors } from '../../layouts/descriptors';\nimport { widgetDescriptors } from '../../widgets/descriptors';\nimport { viewDescriptors } from '../../views/descriptors';\nimport type { FieldSchema, LayoutMode, ListColumn, WidgetSchema } from '../models/schema.model';\n\n/**\n * Registro único de render (R3.1 · `doc/plan-refactor-motor.md` §3.1).\n *\n * Un solo sitio declara qué componentes sabe dibujar la UI: cada tipo de\n * campo, widget, acción o vista aporta un `RenderDescriptor` y el registro\n * lo resuelve por `(kind, type)`. Los hosts dejan de mantener `Set`s de tipos\n * e imports a mano — **en runtime el registro es la única fuente de verdad**.\n *\n * Se carga a scope de módulo y no desde DI: `buildFormSchema()` es una\n * función pura que consulta el registro sin inyectar nada, así que un\n * registro llenado únicamente por un provider dejaría esa consulta correr\n * contra un catálogo vacío. `provideRenderDescriptors()` existe igualmente\n * como punto de entrada explícito para `app.config.ts` (R3.2).\n *\n * Autodescubrimiento (D9-1): se opta por **registro manual** — un manifiesto\n * con una línea por descriptor — porque `import.meta.glob` no está\n * implementada por el bundler de producción (`@angular/build:application`\n * usa esbuild) y la llamada cruda sobreviviría en `dist/`, rompiendo el\n * arranque. Con Vite sólo en el dev-server y en el runner de tests, además,\n * el comportamiento habría diferido entre `npm test` y `npm run build`.\n */\n\n/** Qué clase de cosa se está resolviendo. Identificador único dentro de su `kind`. */\nexport type RenderKind = 'field' | 'column-format' | 'widget' | 'action' | 'view' | 'layout';\nexport type ComponentRenderKind = Exclude<RenderKind, 'layout'>;\n\n/** Superficies en las que un descriptor puede aparecer. */\nexport type RenderSurface = 'form' | 'display' | 'list' | 'filter';\n\n/**\n * Qué puede describir un `RenderDescriptor`: un campo del formulario, un\n * widget del dashboard o una columna de listado (R4.3).\n *\n * Es el tipo del input `config` del host. Los descriptores sólo comparten\n * `key` y `label`; lo demás lo decide cada `kind`, y quien necesita el resto\n * lo castea con su propia mirada (`cfgCampo()`, que es lo que el host ya\n * hacía antes de que existieran las columnas).\n */\nexport type RenderConfig = FieldSchema | WidgetSchema | ListColumn;\n\n/**\n * Contexto de render que el host expone por DI (R3.4 · `doc/plan-refactor-motor.md` §3.4).\n *\n * Los controles viven en un componente distinto por cada tipo, así que en vez\n * de repetir cinco inputs en los 20 el host lo provee una sola vez y cada\n * control lo inyecta si lo necesita — el mismo criterio que ya usaba\n * `FIELD_ARIA`.\n *\n * `tree` viaja en el contexto y no como input suelto porque es **por\n * instancia**: los hijos de un `group` o de un `list` navegan su subárbol, no\n * el del padre.\n *\n * Vive acá y no en `render-host.ts` porque el contrato de los descriptores\n * (`RenderExtras`) necesita nombrarlo: el descriptor de un campo compuesto\n * decide qué se le pasa al componente y eso sólo es escribible conociendo el\n * tipo. `render-host.ts` lo re-exporta para no mover a sus consumidores.\n */\nexport interface RenderContext {\n /** Árbol del formulario del nivel de este campo. */\n tree: RootTree;\n /** Errores del backend por ruta (`address.street`, `faq[2].answer`). */\n serverErrors: Record<string, string>;\n /** Prefijo de ruta de este campo en el registro raíz (`address.`). */\n pathPrefix: string;\n /** Si el registro ya existe (lo consume `slug` con `lockAfterCreate`). */\n exists: boolean;\n /** Recurso dueño del formulario (lo consume `image` para la firma, §11.2). */\n resource: string;\n}\n\n/**\n * Contexto vacío con el que arranca `RenderHost.ctx`.\n *\n * Sólo lo alcanza quien renderiza sin contexto — los widgets, que no forman\n * parte de un formulario. Un campo montado sin `ctx` es un error de\n * programación y `childTree` lo dice con su propio mensaje, igual que lo\n * decía el `input.required` anterior.\n */\nexport const RENDER_CONTEXT_VACIO: RenderContext = {\n tree: undefined as unknown as RootTree,\n serverErrors: {},\n pathPrefix: '',\n exists: false,\n resource: '',\n};\n\n/**\n * Segundo argumento de `RenderDescriptor.inputs`.\n *\n * Aporta lo que el host conoce y el descriptor no: el contexto de formulario\n * (sólo para campos), el payload del dato (sólo para widgets) y los dos\n * templates con los que se componen `group` y `list`.\n */\nexport interface RenderExtras {\n /** Contexto del nivel; `RENDER_CONTEXT_VACIO` cuando no hay formulario. */\n ctx: RenderContext;\n /** Payload del widget (`<app-widget-host [data]>`); `null` en campos. */\n data: unknown;\n /** Template del contenido de un `group`. */\n groupContent?: TemplateRef<unknown>;\n /** Template de los hijos de un `list`. */\n childTemplate?: TemplateRef<unknown>;\n}\n\n/**\n * Declaración de un componente renderizable.\n *\n * No lleva `configSchema`: esa cláusula de `refactormotor.md` no existe en\n * el código y el plan la descartó (D17).\n */\nexport interface RenderDescriptor<C = unknown> {\n /** Clase de cosa. */\n kind: ComponentRenderKind;\n /** Identificador `kebab-case`, único dentro de `kind`. */\n type: string;\n /** Versión del contrato en que apareció (`doc/refactormotor.md`). */\n since: string;\n /**\n * Carga perezosa del componente. El registro se resuelve sin arrastrar el\n * bundle: los descriptores sólo guardan el cierre, no la clase.\n */\n load: () => Promise<Type<any>>;\n /** Superficies en las que se usa. Sólo lo que se pueda evidenciar en el código. */\n surfaces?: RenderSurface[];\n /** Valores por defecto de la configuración del descriptor. */\n defaults?: Partial<C>;\n /**\n * Forma del valor inicial que siembra este campo en el modelo del\n * formulario (D32 · R3.8).\n *\n * **Dato, no función**: un nombre resuelto por `shared/utils/seed.ts`, no\n * una clausura. Así el descriptor sigue siendo puro —`kind`, `type`,\n * `load`, `surfaces`, `seed`— y `seed.ts` es el único dueño de recorrer\n * un árbol de campos. La alternativa (`seed: (cfg) => …`) obligaría a que\n * `group` importara `seedFields`, lo que cerraría un ciclo\n * registro → manifiesto → descriptor → `seed` → registro.\n *\n * Sólo los campos lo declaran. **Obligatorio para `kind: 'field'`** — lo\n * vigila `core/registry/contract.spec.ts`, porque la exhaustividad de una\n * unión de strings no puede imponerse en tiempo de compilación.\n */\n seed?: SeedKind;\n /**\n * Cableado del componente: qué inputs recibe y con qué valor.\n *\n * Es **la** pieza que mantiene el host genérico: sin esto el motor tendría\n * que saber que `metric-card` recibe `label/value/hint` y que `group`\n * necesita además el template de sus hijos, y «añadir un tipo» volvería a\n * tocar `render-host.ts` (R3.8). Cada descriptor declara el suyo y el host\n * sólo hace `ngComponentOutletInputs = descriptor.inputs(config, extras)`.\n *\n * No es obligatorio: el 80 % de los tipos comparten la forma estándar de su\n * `kind` — `{field, tree}` en campos, `{widget, data}` en widgets — y para\n * ellos el host aplica esa forma por defecto. Se declara sólo cuando el\n * componente se desvía de ella.\n */\n inputs?: (config: C, extras: RenderExtras) => Record<string, unknown>;\n}\n\n/** Declaración de un layout manejado por el host de formularios. */\nexport interface LayoutDescriptor {\n kind: 'layout';\n type: LayoutMode;\n since: string;\n}\n\n/** Catálogo en memoria: `kind:type` → descriptor. */\nconst RENDERERS = new Map<string, RenderDescriptor>();\nconst LAYOUTS = new Map<string, LayoutDescriptor>();\n\nfunction keyOf(kind: RenderKind, type: string): string {\n return `${kind}:${type}`;\n}\n\n/**\n * Registra un descriptor. Idempotente por clave: volver a registrar el mismo\n * `(kind, type)` lo sobrescribe, lo que permite que un módulo se recargue en\n * desarrollo sin duplicar entradas.\n */\nexport function register(kind: 'layout', descriptor: LayoutDescriptor): void;\nexport function register(kind: ComponentRenderKind, descriptor: RenderDescriptor): void;\nexport function register(kind: RenderKind, descriptor: RenderDescriptor | LayoutDescriptor): void {\n if (kind === 'layout') {\n if (!('kind' in descriptor) || descriptor.kind !== 'layout') {\n throw new Error(`El descriptor de layout \"${descriptor.type}\" no declara kind: \"layout\".`);\n }\n LAYOUTS.set(descriptor.type, descriptor);\n return;\n }\n if (descriptor.kind === 'layout') {\n throw new Error(\n `El descriptor de layout \"${descriptor.type}\" no puede registrarse como ${kind}.`,\n );\n }\n RENDERERS.set(keyOf(kind, descriptor.type), descriptor);\n}\n\n/**\n * Quita un descriptor (R7.6). Simétrico a `register`: los specs que\n * registran entradas de prueba deben retirarlas, o el catálogo global queda\n * contaminado para cualquier otro spec que lea `renderKinds()` (flaky por\n * orden de ejecución).\n */\nexport function unregister(kind: RenderKind, type: string): void {\n if (kind === 'layout') {\n LAYOUTS.delete(type);\n } else {\n RENDERERS.delete(keyOf(kind, type));\n }\n}\n\n/** Descriptor declarado para `(kind, type)`, o `undefined` si nadie lo registró. */\nexport function get(kind: ComponentRenderKind, type: string): RenderDescriptor | undefined {\n return RENDERERS.get(keyOf(kind, type));\n}\n\n/** ¿La UI sabe dibujar este `(kind, type)`? Reemplaza a los `Set`s de los hosts. */\nexport function isSupported(kind: RenderKind, type: string): boolean {\n return kind === 'layout' ? LAYOUTS.has(type) : RENDERERS.has(keyOf(kind, type));\n}\n\n/**\n * Componente para `(kind, type)`, o `fallback` si el tipo no está en el\n * catálogo.\n *\n * Es **asíncrona** porque `load()` importa el componente bajo demanda; el\n * `fallback` es síncrono y sólo se usa cuando no hay descriptor. Un fallo de\n * `load()` NO se traga: propagarlo es lo que hace visible un descriptor mal\n * escrito, y la política «nunca pantalla rota» la resuelve el llamante con el\n * `fallback` que ya recibe.\n */\nexport async function resolve<C = unknown>(\n kind: ComponentRenderKind,\n type: string,\n fallback: Type<C>,\n): Promise<Type<C>> {\n const descriptor = get(kind, type);\n if (!descriptor) return fallback;\n return (await descriptor.load()) as Type<C>;\n}\n\n// Catálogo a scope de módulo: se registra al importar, sin esperar a DI.\nfor (const descriptor of [\n ...fieldDescriptors,\n ...widgetDescriptors,\n ...columnFormatDescriptors,\n ...viewDescriptors,\n ...layoutDescriptors,\n]) {\n if (descriptor.kind === 'layout') {\n register('layout', descriptor);\n } else {\n register(descriptor.kind, descriptor);\n }\n}\n\n/**\n * Punto de entrada para `app.config.ts` (R3.2).\n *\n * El catálogo ya quedó cargado al importar este módulo; el provider sirve\n * para que el arranque sea explícito y para avisar en desarrollo si el\n * manifiesto vino vacío — que es exactamente lo que pasaría si alguien\n * borra una línea del manifiesto sin reemplazarla.\n */\nexport function provideRenderDescriptors(): EnvironmentProviders {\n return makeEnvironmentProviders([\n provideAppInitializer(() => {\n if (isDevMode() && RENDERERS.size === 0 && LAYOUTS.size === 0) {\n console.warn('[render-registry] el catálogo de descriptores vino vacío');\n }\n }),\n ]);\n}\n\n/** Cuántos descriptores hay registrados. Sólo para comprobaciones y tests. */\nexport function renderDescriptorCount(): number {\n return RENDERERS.size + LAYOUTS.size;\n}\n\n/**\n * `kind`s que hoy tienen al menos un descriptor.\n *\n * Existe para el test de exhaustividad (R3.7): él recorre los schemas de los\n * `kind`s que tienen registro y **falla** si aparece un `kind` con descriptor\n * que nadie recorre — de lo contrario «tener registro» y «estar cubierto»\n * serían dos afirmaciones distintas que nadie reconcilia.\n */\nexport function renderKinds(): RenderKind[] {\n const kinds = new Set<RenderKind>([...RENDERERS.values()].map((descriptor) => descriptor.kind));\n if (LAYOUTS.size > 0) {\n kinds.add('layout');\n }\n return [...kinds];\n}\n"],"mappings":"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"}
@@ -28,6 +28,7 @@ const API_URL = new InjectionToken("API_URL");
28
28
  const FIREBASE_AUTH_ADAPTER = new InjectionToken("gas.admin.firebaseAuthAdapter");
29
29
  const API_DRIVER = new InjectionToken("gas.admin.driver");
30
30
  const VALUE_SOURCES = new InjectionToken("gas.admin.valueSources");
31
+ const DEFAULT_RESPONSE_UNWRAP = new InjectionToken("gas.admin.defaultResponseUnwrap");
31
32
  const LOGIN_PATH = "/login";
32
33
  const SESSION_TOKEN_KEY = "admin.session.token";
33
34
  const SESSION_USER_KEY = "admin.session.user";
@@ -91,19 +92,15 @@ var AuthService = class AuthService {
91
92
  next: () => {
92
93
  this.clear();
93
94
  this.firebaseAdapter?.signOut();
95
+ this.goLogin();
94
96
  },
95
97
  error: () => {
96
98
  this.clear();
97
99
  this.firebaseAdapter?.signOut();
100
+ this.goLogin();
98
101
  }
99
102
  }), map(() => void 0));
100
103
  }
101
- logoutAll() {
102
- return this.post("/auth/logout-all").pipe(tap(() => {
103
- this.clear();
104
- this.goLogin();
105
- }), map((res) => ({ effectiveWithinSeconds: res.effectiveWithinSeconds })));
106
- }
107
104
  restore() {
108
105
  if (this._token() === null) return of(void 0);
109
106
  return this.post("/auth/me").pipe(tap((res) => {
@@ -144,6 +141,10 @@ var AuthService = class AuthService {
144
141
  return required.some((one) => this.hasRole(one));
145
142
  }
146
143
  canDoOperation(schema, operation) {
144
+ if (operation === "create" || operation === "update" || operation === "remove") {
145
+ const ep = schema.endpoint;
146
+ if (!!ep && Object.keys(ep).length > 0 && !ep[operation]) return false;
147
+ }
147
148
  const ops = schema.policies?.access?.operations;
148
149
  if (ops && ops[operation]) return this.meetsLevel(ops[operation]);
149
150
  if (schema.policies?.access) {
@@ -284,6 +285,46 @@ const apiErrorInterceptor = (req, next) => {
284
285
  return throwError(() => err);
285
286
  }));
286
287
  };
288
+ function appliesTo(unwrap, operation) {
289
+ const apply = unwrap.apply ?? "all";
290
+ return apply === "all" || apply === operation;
291
+ }
292
+ function unwrapResponse(raw, unwrap, operation) {
293
+ if (!unwrap || !appliesTo(unwrap, operation)) return raw;
294
+ if (raw !== null && typeof raw === "object" && !Array.isArray(raw)) {
295
+ const record = raw;
296
+ if (Object.prototype.hasOwnProperty.call(record, unwrap.dataKey)) return record[unwrap.dataKey];
297
+ }
298
+ throw new Error(`Response unwrap declared dataKey '${unwrap.dataKey}' but it is missing in the response for operation '${operation}'`);
299
+ }
300
+ const NO_PAGINATION = {
301
+ nextCursor: null,
302
+ total: 0,
303
+ hasMore: false
304
+ };
305
+ function extractPagination(raw, unwrap) {
306
+ if (raw === null || typeof raw !== "object" || Array.isArray(raw)) return { ...NO_PAGINATION };
307
+ const body = raw;
308
+ let source = body;
309
+ const metaKey = unwrap?.metaKey;
310
+ if (metaKey) {
311
+ const meta = body[metaKey];
312
+ if (meta !== null && typeof meta === "object" && !Array.isArray(meta)) source = meta;
313
+ }
314
+ const cursorKey = unwrap?.pagination?.cursorKey ?? "nextCursor";
315
+ const totalKey = unwrap?.pagination?.totalKey ?? "total";
316
+ const hasMoreKey = unwrap?.pagination?.hasMoreKey ?? "hasMore";
317
+ const cursorValue = source[cursorKey] ?? body[cursorKey];
318
+ const nextCursor = typeof cursorValue === "string" && cursorValue !== "" ? cursorValue : null;
319
+ const totalValue = source[totalKey] ?? body[totalKey];
320
+ const total = typeof totalValue === "number" ? totalValue : 0;
321
+ const hasMoreValue = source[hasMoreKey] ?? body[hasMoreKey];
322
+ return {
323
+ nextCursor,
324
+ total,
325
+ hasMore: typeof hasMoreValue === "boolean" ? hasMoreValue : nextCursor !== null
326
+ };
327
+ }
287
328
  const MARKER = /\{([a-zA-Z0-9_.]+)\}/g;
288
329
  function resolveEndpointPath(path, sources) {
289
330
  if (!path.includes("{")) return path;
@@ -310,32 +351,151 @@ function leerRuta(valor, ruta) {
310
351
  }
311
352
  return actual;
312
353
  }
354
+ function sendGas(deps, path, method, payload, multipart = false) {
355
+ if (multipart) throw new Error("Multipart payload mode is only supported with the REST driver");
356
+ const body = {
357
+ token: deps.sessionToken(),
358
+ method,
359
+ path,
360
+ payload: payload ?? {}
361
+ };
362
+ return deps.http.post(deps.apiUrl, body, { headers: { "Content-Type": "text/plain" } });
363
+ }
364
+ function sendRest(deps, path, method, payload, multipart = false) {
365
+ const url = buildUrl(deps.apiUrl, path);
366
+ const headers = new HttpHeaders();
367
+ if (deps.getIdToken) return from(deps.getIdToken()).pipe(switchMap((freshToken) => doRestRequest(deps, url, method, payload, headers.set("Authorization", `Bearer ${freshToken}`), multipart)));
368
+ const token = deps.sessionToken();
369
+ return doRestRequest(deps, url, method, payload, token ? headers.set("Authorization", `Bearer ${token}`) : headers, multipart);
370
+ }
371
+ function doRestRequest(deps, url, method, payload, headers = new HttpHeaders(), multipart = false) {
372
+ if (method === "GET" || method === "DELETE") {
373
+ const params = toHttpParams(payload instanceof FormData ? void 0 : payload);
374
+ return deps.http.request(method, url, {
375
+ headers,
376
+ params
377
+ });
378
+ }
379
+ if (multipart || payload instanceof FormData) return deps.http.request(method, url, {
380
+ headers,
381
+ body: payload ?? {}
382
+ });
383
+ return deps.http.request(method, url, {
384
+ headers: headers.set("Content-Type", "application/json"),
385
+ body: payload ?? {}
386
+ });
387
+ }
388
+ function buildUrl(apiUrl, path) {
389
+ return `${apiUrl ? apiUrl.replace(/\/+$/, "") : ""}${path.startsWith("/") ? path : `/${path}`}`;
390
+ }
391
+ function toHttpParams(payload) {
392
+ let params = new HttpParams();
393
+ if (!payload) return params;
394
+ for (const [key, value] of Object.entries(payload)) {
395
+ if (value === void 0 || value === null) continue;
396
+ if (typeof value === "object" && !Array.isArray(value)) {
397
+ for (const [nestedKey, nestedValue] of Object.entries(value)) if (nestedValue !== void 0 && nestedValue !== null) params = params.set(nestedKey, String(nestedValue));
398
+ } else if (Array.isArray(value)) {
399
+ for (const item of value) if (item !== void 0 && item !== null) params = params.append(key, String(item));
400
+ } else params = params.set(key, String(value));
401
+ }
402
+ return params;
403
+ }
313
404
  var ApiService = class ApiService {
314
405
  http = inject(HttpClient);
315
406
  apiUrl = inject(API_URL);
316
407
  auth = inject(AuthService);
317
408
  driver = inject(API_DRIVER, { optional: true }) ?? "gas";
318
409
  valueSources = inject(VALUE_SOURCES, { optional: true }) ?? {};
410
+ firebaseAuthAdapter = inject(FIREBASE_AUTH_ADAPTER, { optional: true });
319
411
  injector = inject(Injector);
412
+ defaultUnwrap = inject(DEFAULT_RESPONSE_UNWRAP, { optional: true }) ?? void 0;
413
+ effectiveUnwrap(endpoint) {
414
+ const global = this.defaultUnwrap;
415
+ const local = endpoint.responseUnwrap;
416
+ if (!global) return local;
417
+ if (!local) return global;
418
+ return {
419
+ ...global,
420
+ ...local
421
+ };
422
+ }
320
423
  list(endpoint, payload) {
321
- return this.send(endpoint.list, "GET", payload).pipe(map((raw) => unwrapList(raw)));
424
+ const unwrap = this.effectiveUnwrap(endpoint);
425
+ return this.send(endpoint.list, "GET", payload).pipe(map((raw) => {
426
+ if (unwrap && (unwrap.apply === "list" || unwrap.apply === "all" || !unwrap.apply)) return unwrapResponse(raw, unwrap, "list");
427
+ return unwrapList(raw);
428
+ }));
429
+ }
430
+ listPage(endpoint, payload) {
431
+ const unwrap = this.effectiveUnwrap(endpoint);
432
+ const applies = !unwrap || unwrap.apply === "list" || unwrap.apply === "all" || !unwrap.apply;
433
+ return this.send(endpoint.list, "GET", payload).pipe(map((raw) => {
434
+ return {
435
+ items: unwrap && applies ? unwrapResponse(raw, unwrap, "list") : unwrapList(raw),
436
+ ...extractPagination(raw, unwrap)
437
+ };
438
+ }));
322
439
  }
323
440
  get(endpoint, key) {
324
- return this.send(this.withKey(endpoint.get, key), "GET");
441
+ const unwrap = this.effectiveUnwrap(endpoint);
442
+ return this.send(this.withKey(endpoint.get, key), "GET").pipe(map((raw) => {
443
+ if (unwrap && (unwrap.apply === "get" || unwrap.apply === "all" || !unwrap.apply)) return unwrapResponse(raw, unwrap, "get");
444
+ return raw;
445
+ }));
325
446
  }
326
447
  create(endpoint, payload) {
327
- return this.send(endpoint.create, "POST", payload);
448
+ const unwrap = this.effectiveUnwrap(endpoint);
449
+ return this.send(endpoint.create, "POST", payload).pipe(map((raw) => {
450
+ if (unwrap && (unwrap.apply === "create" || unwrap.apply === "all" || !unwrap.apply)) return unwrapResponse(raw, unwrap, "create");
451
+ return raw;
452
+ }));
328
453
  }
329
454
  update(endpoint, key, payload) {
330
- return this.send(this.withKey(endpoint.update, key), "PUT", payload);
455
+ const unwrap = this.effectiveUnwrap(endpoint);
456
+ return this.send(this.withKey(endpoint.update, key), "PUT", payload).pipe(map((raw) => {
457
+ if (unwrap && (unwrap.apply === "update" || unwrap.apply === "all" || !unwrap.apply)) return unwrapResponse(raw, unwrap, "update");
458
+ return raw;
459
+ }));
331
460
  }
332
461
  remove(endpoint, key) {
333
- return this.send(this.withKey(endpoint.remove, key), "DELETE");
462
+ endpoint.responseUnwrap;
463
+ return this.send(this.withKey(endpoint.remove, key), "DELETE").pipe(map(() => void 0));
334
464
  }
335
465
  request(method, path, payload) {
336
466
  return this.send(path, method, payload);
337
467
  }
338
- send(path, method, payload) {
468
+ invokeCustomEndpoint(definitionOrSchema, nameOrPayload, payload, key) {
469
+ let definition;
470
+ let actualPayload;
471
+ let actualKey = key;
472
+ if (isResourceSchema(definitionOrSchema)) {
473
+ const name = typeof nameOrPayload === "string" ? nameOrPayload : void 0;
474
+ if (!name) throw new Error("invokeCustomEndpoint requires an endpoint name when given a schema");
475
+ definition = definitionOrSchema.customEndpoints?.[name];
476
+ if (!definition) throw new Error(`Custom endpoint '${name}' is not declared for resource '${definitionOrSchema.id}'`);
477
+ actualPayload = (typeof nameOrPayload === "string" ? payload : nameOrPayload) ?? payload;
478
+ } else {
479
+ definition = definitionOrSchema;
480
+ actualPayload = nameOrPayload ?? payload;
481
+ }
482
+ if (!definition) return throwError(() => /* @__PURE__ */ new Error("Custom endpoint definition is required"));
483
+ const multipart = definition.payloadMode === "multipart" || actualPayload instanceof FormData;
484
+ const path = this.withKey(definition.path, actualKey);
485
+ const method = definition.method;
486
+ const unwrap = definition.responseUnwrap;
487
+ return this.send(path, method, actualPayload, multipart).pipe(map((raw) => {
488
+ if (unwrap) return unwrapResponse(raw, unwrap, "get");
489
+ return raw;
490
+ }));
491
+ }
492
+ invokeCustom(schemaOrDefinition, nameOrPayload, payload, key) {
493
+ return this.invokeCustomEndpoint(schemaOrDefinition, nameOrPayload, payload, key);
494
+ }
495
+ custom(schemaOrDefinition, nameOrPayload, payload, key) {
496
+ return this.invokeCustomEndpoint(schemaOrDefinition, nameOrPayload, payload, key);
497
+ }
498
+ send(path, method, payload, multipart = false) {
339
499
  if (!path) return throwError(() => /* @__PURE__ */ new Error("Operación no disponible para este recurso"));
340
500
  let resolvedPath;
341
501
  try {
@@ -343,11 +503,21 @@ var ApiService = class ApiService {
343
503
  } catch (error) {
344
504
  return throwError(() => error);
345
505
  }
346
- return (this.driver === "rest" ? this.sendRest(resolvedPath, method, payload) : this.sendGas(resolvedPath, method, payload)).pipe(tap((res) => {
506
+ const deps = this.transportDeps();
507
+ return (this.driver === "rest" ? sendRest(deps, resolvedPath, method, payload, multipart) : sendGas(deps, resolvedPath, method, payload, multipart)).pipe(tap((res) => {
347
508
  const renewed = renewedTokenOf(res);
348
509
  if (renewed !== null) this.auth.applyRenewedToken(renewed);
349
510
  }));
350
511
  }
512
+ transportDeps() {
513
+ const adapter = this.firebaseAuthAdapter;
514
+ return {
515
+ http: this.http,
516
+ apiUrl: this.apiUrl,
517
+ sessionToken: () => this.auth.token(),
518
+ getIdToken: adapter?.getIdToken ? () => adapter.getIdToken() : void 0
519
+ };
520
+ }
351
521
  buildSources() {
352
522
  return {
353
523
  ...this.valueSources,
@@ -358,36 +528,6 @@ var ApiService = class ApiService {
358
528
  config: () => this.injector.get(ConfigService, null)?.globalConfig() ?? null
359
529
  };
360
530
  }
361
- sendGas(path, method, payload) {
362
- const body = {
363
- token: this.auth.token(),
364
- method,
365
- path,
366
- payload: payload ?? {}
367
- };
368
- return this.http.post(this.apiUrl, body, { headers: { "Content-Type": "text/plain" } });
369
- }
370
- sendRest(path, method, payload) {
371
- const url = this.buildUrl(path);
372
- let headers = new HttpHeaders();
373
- const token = this.auth.token();
374
- if (token) headers = headers.set("Authorization", `Bearer ${token}`);
375
- if (method === "GET" || method === "DELETE") {
376
- const params = toHttpParams(payload);
377
- return this.http.request(method, url, {
378
- headers,
379
- params
380
- });
381
- }
382
- headers = headers.set("Content-Type", "application/json");
383
- return this.http.request(method, url, {
384
- headers,
385
- body: payload ?? {}
386
- });
387
- }
388
- buildUrl(path) {
389
- return `${this.apiUrl ? this.apiUrl.replace(/\/+$/, "") : ""}${path.startsWith("/") ? path : `/${path}`}`;
390
- }
391
531
  withKey(path, key) {
392
532
  if (!path) return;
393
533
  return path.includes("{key}") ? path.replace("{key}", encodeURIComponent(key ?? "")) : path;
@@ -414,26 +554,17 @@ i0.ɵɵngDeclareClassMetadata({
414
554
  type: ApiService,
415
555
  decorators: [{ type: Service }]
416
556
  });
417
- function toHttpParams(payload) {
418
- let params = new HttpParams();
419
- if (!payload) return params;
420
- for (const [key, value] of Object.entries(payload)) {
421
- if (value === void 0 || value === null) continue;
422
- if (typeof value === "object" && !Array.isArray(value)) {
423
- for (const [nestedKey, nestedValue] of Object.entries(value)) if (nestedValue !== void 0 && nestedValue !== null) params = params.set(nestedKey, String(nestedValue));
424
- } else if (Array.isArray(value)) {
425
- for (const item of value) if (item !== void 0 && item !== null) params = params.append(key, String(item));
426
- } else params = params.set(key, String(value));
427
- }
428
- return params;
557
+ function isResourceSchema(value) {
558
+ return typeof value === "object" && value !== null && "endpoint" in value && "fields" in value;
429
559
  }
430
560
  function unwrapList(raw) {
431
561
  if (Array.isArray(raw)) return raw;
432
562
  if (raw !== null && typeof raw === "object") {
433
563
  const items = raw.items;
434
564
  if (Array.isArray(items)) return items;
565
+ return [];
435
566
  }
436
- return [];
567
+ throw new Error(`List response must be an array or an object with an 'items' array; received ${raw === null ? "null" : typeof raw}`);
437
568
  }
438
569
  var ConfigService = class ConfigService {
439
570
  api = inject(ApiService, { optional: true });
@@ -527,6 +658,10 @@ function provideGasAdmin(config) {
527
658
  provide: VALUE_SOURCES,
528
659
  useValue: config.valueSources ?? {}
529
660
  },
661
+ {
662
+ provide: DEFAULT_RESPONSE_UNWRAP,
663
+ useValue: config.defaultResponseUnwrap
664
+ },
530
665
  provideHttpClient(withInterceptors([apiErrorInterceptor])),
531
666
  provideAppInitializer(() => inject(ConfigService).load(configEndpoints())),
532
667
  provideAppInitializer(() => inject(AuthService).restore())
@@ -538,6 +673,6 @@ function provideFirebaseAdapter(adapter) {
538
673
  useValue: adapter
539
674
  };
540
675
  }
541
- export { FIREBASE_AUTH_ADAPTER as _, provideFirebaseAdapter as a, renewedTokenOf as b, ConfigService as c, AuthService as d, LOGIN_PATH as f, API_URL as g, API_DRIVER as h, getSchema as i, ApiService as l, SESSION_USER_KEY as m, allSchemas as n, provideGasAdmin as o, SESSION_TOKEN_KEY as p, getAuth as r, setSchemaCatalog as s, GAS_SCHEMAS as t, apiErrorInterceptor as u, VALUE_SOURCES as v, ApiError as y };
676
+ export { DEFAULT_RESPONSE_UNWRAP as _, provideFirebaseAdapter as a, ApiError as b, ConfigService as c, AuthService as d, LOGIN_PATH as f, API_URL as g, API_DRIVER as h, getSchema as i, ApiService as l, SESSION_USER_KEY as m, allSchemas as n, provideGasAdmin as o, SESSION_TOKEN_KEY as p, getAuth as r, setSchemaCatalog as s, GAS_SCHEMAS as t, apiErrorInterceptor as u, FIREBASE_AUTH_ADAPTER as v, renewedTokenOf as x, VALUE_SOURCES as y };
542
677
 
543
- //# sourceMappingURL=tinya-code-gas-admin-ui-schema-catalog-CL4IZDce.mjs.map
678
+ //# sourceMappingURL=tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs.map