@tinya-code/gas-admin-ui 0.2.0-alpha.3 → 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.
- package/README.md +186 -2
- package/fesm2022/{tinya-code-gas-admin-ui-calendar-view-DkYfP4n9.mjs → tinya-code-gas-admin-ui-calendar-view-ZTYs-r49.mjs} +12 -7
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-ZTYs-r49.mjs.map +1 -0
- package/fesm2022/{tinya-code-gas-admin-ui-condition-evaluator-C1tjeb6D.mjs → tinya-code-gas-admin-ui-condition-evaluator-CHzJuOx2.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-condition-evaluator-C1tjeb6D.mjs.map → tinya-code-gas-admin-ui-condition-evaluator-CHzJuOx2.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-data-source.service-BUoA9kBh.mjs → tinya-code-gas-admin-ui-data-source.service-Cw1rdrWZ.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-data-source.service-BUoA9kBh.mjs.map → tinya-code-gas-admin-ui-data-source.service-Cw1rdrWZ.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-error-mapper.service-BDA1dL5V.mjs → tinya-code-gas-admin-ui-error-mapper.service-BQ--gSnT.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-error-mapper.service-BDA1dL5V.mjs.map → tinya-code-gas-admin-ui-error-mapper.service-BQ--gSnT.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-file-DhLi3eO0.mjs → tinya-code-gas-admin-ui-file-JstsF8C5.mjs} +3 -3
- package/fesm2022/{tinya-code-gas-admin-ui-file-DhLi3eO0.mjs.map → tinya-code-gas-admin-ui-file-JstsF8C5.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-form-view-CjC-GOQl.mjs → tinya-code-gas-admin-ui-form-view-BcjgVVKC.mjs} +9 -9
- package/fesm2022/{tinya-code-gas-admin-ui-form-view-CjC-GOQl.mjs.map → tinya-code-gas-admin-ui-form-view-BcjgVVKC.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-image-D9-mpBhA.mjs → tinya-code-gas-admin-ui-image-CnGes7gs.mjs} +3 -3
- package/fesm2022/{tinya-code-gas-admin-ui-image-D9-mpBhA.mjs.map → tinya-code-gas-admin-ui-image-CnGes7gs.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-kanban-view-B4u2ibPb.mjs → tinya-code-gas-admin-ui-kanban-view-QK7OSFoV.mjs} +4 -4
- package/fesm2022/{tinya-code-gas-admin-ui-kanban-view-B4u2ibPb.mjs.map → tinya-code-gas-admin-ui-kanban-view-QK7OSFoV.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-list-CQpL6vyE.mjs → tinya-code-gas-admin-ui-list-CiNQ3DMg.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-list-CQpL6vyE.mjs.map → tinya-code-gas-admin-ui-list-CiNQ3DMg.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-multiselect-CTQPGBOK.mjs → tinya-code-gas-admin-ui-multiselect-BiKb7192.mjs} +3 -3
- package/fesm2022/{tinya-code-gas-admin-ui-multiselect-CTQPGBOK.mjs.map → tinya-code-gas-admin-ui-multiselect-BiKb7192.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-relation-lr_XG6jt.mjs → tinya-code-gas-admin-ui-relation-CvxkEGHs.mjs} +3 -3
- package/fesm2022/{tinya-code-gas-admin-ui-relation-lr_XG6jt.mjs.map → tinya-code-gas-admin-ui-relation-CvxkEGHs.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-render-registry-CcIgBsSl.mjs → tinya-code-gas-admin-ui-render-registry-B7mmgFSW.mjs} +10 -10
- package/fesm2022/{tinya-code-gas-admin-ui-render-registry-CcIgBsSl.mjs.map → tinya-code-gas-admin-ui-render-registry-B7mmgFSW.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-schema-catalog-DU_6_CtP.mjs → tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs} +190 -61
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs.map +1 -0
- package/fesm2022/{tinya-code-gas-admin-ui-seed-Bn6tl-yM.mjs → tinya-code-gas-admin-ui-seed-CJEt__kZ.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-seed-Bn6tl-yM.mjs.map → tinya-code-gas-admin-ui-seed-CJEt__kZ.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-select-BwefyMVx.mjs → tinya-code-gas-admin-ui-select-DPKRS6Gn.mjs} +3 -3
- package/fesm2022/{tinya-code-gas-admin-ui-select-BwefyMVx.mjs.map → tinya-code-gas-admin-ui-select-DPKRS6Gn.mjs.map} +1 -1
- package/fesm2022/{tinya-code-gas-admin-ui-upload.service-DRmKFrSH.mjs → tinya-code-gas-admin-ui-upload.service-BNvH04S3.mjs} +2 -2
- package/fesm2022/{tinya-code-gas-admin-ui-upload.service-DRmKFrSH.mjs.map → tinya-code-gas-admin-ui-upload.service-BNvH04S3.mjs.map} +1 -1
- package/fesm2022/tinya-code-gas-admin-ui.mjs +51 -53
- package/fesm2022/tinya-code-gas-admin-ui.mjs.map +1 -1
- package/package.json +1 -1
- package/types/tinya-code-gas-admin-ui.d.ts +190 -12
- package/fesm2022/tinya-code-gas-admin-ui-calendar-view-DkYfP4n9.mjs.map +0 -1
- package/fesm2022/tinya-code-gas-admin-ui-schema-catalog-DU_6_CtP.mjs.map +0 -1
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tinya-code-gas-admin-ui-render-registry-CcIgBsSl.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";
|
|
@@ -100,12 +101,6 @@ var AuthService = class AuthService {
|
|
|
100
101
|
}
|
|
101
102
|
}), map(() => void 0));
|
|
102
103
|
}
|
|
103
|
-
logoutAll() {
|
|
104
|
-
return this.post("/auth/logout-all").pipe(tap(() => {
|
|
105
|
-
this.clear();
|
|
106
|
-
this.goLogin();
|
|
107
|
-
}), map((res) => ({ effectiveWithinSeconds: res.effectiveWithinSeconds })));
|
|
108
|
-
}
|
|
109
104
|
restore() {
|
|
110
105
|
if (this._token() === null) return of(void 0);
|
|
111
106
|
return this.post("/auth/me").pipe(tap((res) => {
|
|
@@ -146,6 +141,10 @@ var AuthService = class AuthService {
|
|
|
146
141
|
return required.some((one) => this.hasRole(one));
|
|
147
142
|
}
|
|
148
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
|
+
}
|
|
149
148
|
const ops = schema.policies?.access?.operations;
|
|
150
149
|
if (ops && ops[operation]) return this.meetsLevel(ops[operation]);
|
|
151
150
|
if (schema.policies?.access) {
|
|
@@ -286,6 +285,46 @@ const apiErrorInterceptor = (req, next) => {
|
|
|
286
285
|
return throwError(() => err);
|
|
287
286
|
}));
|
|
288
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
|
+
}
|
|
289
328
|
const MARKER = /\{([a-zA-Z0-9_.]+)\}/g;
|
|
290
329
|
function resolveEndpointPath(path, sources) {
|
|
291
330
|
if (!path.includes("{")) return path;
|
|
@@ -312,6 +351,56 @@ function leerRuta(valor, ruta) {
|
|
|
312
351
|
}
|
|
313
352
|
return actual;
|
|
314
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
|
+
}
|
|
315
404
|
var ApiService = class ApiService {
|
|
316
405
|
http = inject(HttpClient);
|
|
317
406
|
apiUrl = inject(API_URL);
|
|
@@ -320,25 +409,93 @@ var ApiService = class ApiService {
|
|
|
320
409
|
valueSources = inject(VALUE_SOURCES, { optional: true }) ?? {};
|
|
321
410
|
firebaseAuthAdapter = inject(FIREBASE_AUTH_ADAPTER, { optional: true });
|
|
322
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
|
+
}
|
|
323
423
|
list(endpoint, payload) {
|
|
324
|
-
|
|
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
|
+
}));
|
|
325
439
|
}
|
|
326
440
|
get(endpoint, key) {
|
|
327
|
-
|
|
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
|
+
}));
|
|
328
446
|
}
|
|
329
447
|
create(endpoint, payload) {
|
|
330
|
-
|
|
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
|
+
}));
|
|
331
453
|
}
|
|
332
454
|
update(endpoint, key, payload) {
|
|
333
|
-
|
|
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
|
+
}));
|
|
334
460
|
}
|
|
335
461
|
remove(endpoint, key) {
|
|
336
|
-
|
|
462
|
+
endpoint.responseUnwrap;
|
|
463
|
+
return this.send(this.withKey(endpoint.remove, key), "DELETE").pipe(map(() => void 0));
|
|
337
464
|
}
|
|
338
465
|
request(method, path, payload) {
|
|
339
466
|
return this.send(path, method, payload);
|
|
340
467
|
}
|
|
341
|
-
|
|
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) {
|
|
342
499
|
if (!path) return throwError(() => /* @__PURE__ */ new Error("Operación no disponible para este recurso"));
|
|
343
500
|
let resolvedPath;
|
|
344
501
|
try {
|
|
@@ -346,11 +503,21 @@ var ApiService = class ApiService {
|
|
|
346
503
|
} catch (error) {
|
|
347
504
|
return throwError(() => error);
|
|
348
505
|
}
|
|
349
|
-
|
|
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) => {
|
|
350
508
|
const renewed = renewedTokenOf(res);
|
|
351
509
|
if (renewed !== null) this.auth.applyRenewedToken(renewed);
|
|
352
510
|
}));
|
|
353
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
|
+
}
|
|
354
521
|
buildSources() {
|
|
355
522
|
return {
|
|
356
523
|
...this.valueSources,
|
|
@@ -361,39 +528,6 @@ var ApiService = class ApiService {
|
|
|
361
528
|
config: () => this.injector.get(ConfigService, null)?.globalConfig() ?? null
|
|
362
529
|
};
|
|
363
530
|
}
|
|
364
|
-
sendGas(path, method, payload) {
|
|
365
|
-
const body = {
|
|
366
|
-
token: this.auth.token(),
|
|
367
|
-
method,
|
|
368
|
-
path,
|
|
369
|
-
payload: payload ?? {}
|
|
370
|
-
};
|
|
371
|
-
return this.http.post(this.apiUrl, body, { headers: { "Content-Type": "text/plain" } });
|
|
372
|
-
}
|
|
373
|
-
sendRest(path, method, payload) {
|
|
374
|
-
const url = this.buildUrl(path);
|
|
375
|
-
const headers = new HttpHeaders();
|
|
376
|
-
if (this.firebaseAuthAdapter?.getIdToken) return from(this.firebaseAuthAdapter.getIdToken()).pipe(switchMap((freshToken) => this.doRestRequest(url, method, payload, headers.set("Authorization", `Bearer ${freshToken}`))));
|
|
377
|
-
const token = this.auth.token();
|
|
378
|
-
const finalHeaders = token ? headers.set("Authorization", `Bearer ${token}`) : headers;
|
|
379
|
-
return this.doRestRequest(url, method, payload, finalHeaders);
|
|
380
|
-
}
|
|
381
|
-
doRestRequest(url, method, payload, headers) {
|
|
382
|
-
if (method === "GET" || method === "DELETE") {
|
|
383
|
-
const params = toHttpParams(payload);
|
|
384
|
-
return this.http.request(method, url, {
|
|
385
|
-
headers,
|
|
386
|
-
params
|
|
387
|
-
});
|
|
388
|
-
}
|
|
389
|
-
return this.http.request(method, url, {
|
|
390
|
-
headers: headers.set("Content-Type", "application/json"),
|
|
391
|
-
body: payload ?? {}
|
|
392
|
-
});
|
|
393
|
-
}
|
|
394
|
-
buildUrl(path) {
|
|
395
|
-
return `${this.apiUrl ? this.apiUrl.replace(/\/+$/, "") : ""}${path.startsWith("/") ? path : `/${path}`}`;
|
|
396
|
-
}
|
|
397
531
|
withKey(path, key) {
|
|
398
532
|
if (!path) return;
|
|
399
533
|
return path.includes("{key}") ? path.replace("{key}", encodeURIComponent(key ?? "")) : path;
|
|
@@ -420,26 +554,17 @@ i0.ɵɵngDeclareClassMetadata({
|
|
|
420
554
|
type: ApiService,
|
|
421
555
|
decorators: [{ type: Service }]
|
|
422
556
|
});
|
|
423
|
-
function
|
|
424
|
-
|
|
425
|
-
if (!payload) return params;
|
|
426
|
-
for (const [key, value] of Object.entries(payload)) {
|
|
427
|
-
if (value === void 0 || value === null) continue;
|
|
428
|
-
if (typeof value === "object" && !Array.isArray(value)) {
|
|
429
|
-
for (const [nestedKey, nestedValue] of Object.entries(value)) if (nestedValue !== void 0 && nestedValue !== null) params = params.set(nestedKey, String(nestedValue));
|
|
430
|
-
} else if (Array.isArray(value)) {
|
|
431
|
-
for (const item of value) if (item !== void 0 && item !== null) params = params.append(key, String(item));
|
|
432
|
-
} else params = params.set(key, String(value));
|
|
433
|
-
}
|
|
434
|
-
return params;
|
|
557
|
+
function isResourceSchema(value) {
|
|
558
|
+
return typeof value === "object" && value !== null && "endpoint" in value && "fields" in value;
|
|
435
559
|
}
|
|
436
560
|
function unwrapList(raw) {
|
|
437
561
|
if (Array.isArray(raw)) return raw;
|
|
438
562
|
if (raw !== null && typeof raw === "object") {
|
|
439
563
|
const items = raw.items;
|
|
440
564
|
if (Array.isArray(items)) return items;
|
|
565
|
+
return [];
|
|
441
566
|
}
|
|
442
|
-
|
|
567
|
+
throw new Error(`List response must be an array or an object with an 'items' array; received ${raw === null ? "null" : typeof raw}`);
|
|
443
568
|
}
|
|
444
569
|
var ConfigService = class ConfigService {
|
|
445
570
|
api = inject(ApiService, { optional: true });
|
|
@@ -533,6 +658,10 @@ function provideGasAdmin(config) {
|
|
|
533
658
|
provide: VALUE_SOURCES,
|
|
534
659
|
useValue: config.valueSources ?? {}
|
|
535
660
|
},
|
|
661
|
+
{
|
|
662
|
+
provide: DEFAULT_RESPONSE_UNWRAP,
|
|
663
|
+
useValue: config.defaultResponseUnwrap
|
|
664
|
+
},
|
|
536
665
|
provideHttpClient(withInterceptors([apiErrorInterceptor])),
|
|
537
666
|
provideAppInitializer(() => inject(ConfigService).load(configEndpoints())),
|
|
538
667
|
provideAppInitializer(() => inject(AuthService).restore())
|
|
@@ -544,6 +673,6 @@ function provideFirebaseAdapter(adapter) {
|
|
|
544
673
|
useValue: adapter
|
|
545
674
|
};
|
|
546
675
|
}
|
|
547
|
-
export {
|
|
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 };
|
|
548
677
|
|
|
549
|
-
//# sourceMappingURL=tinya-code-gas-admin-ui-schema-catalog-
|
|
678
|
+
//# sourceMappingURL=tinya-code-gas-admin-ui-schema-catalog-CsB26qUM.mjs.map
|