@ghentcdh/crouton-api 0.0.1-alpha.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.cjs +3787 -0
- package/dist/index.cjs.map +1 -0
- package/dist/index.d.cts +344 -0
- package/dist/index.d.ts +344 -0
- package/dist/index.js +3751 -0
- package/dist/index.js.map +1 -0
- package/package.json +38 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/lib/crouton-api.module.ts","../src/lib/crud/app-layout.controller.ts","../../crouton-core/src/lib/request.model.ts","../../crouton-core/src/lib/zod.types.ts","../../crouton-core/src/lib/filter.ts","../../crouton-core/src/lib/response.model.ts","../../crouton-core/src/lib/create-schema.ts","../../crouton-core/src/lib/layout/base.builder.ts","../../crouton-core/src/lib/layout/control.builder.ts","../../crouton-core/src/lib/layout/layout.builder.ts","../../crouton-core/src/lib/json-config.types.ts","../../crouton-core/src/lib/value-label.ts","../../crouton-core/src/lib/table/table.builder.ts","../src/lib/crud/dev-mode.ts","../src/lib/crud/resource-config.registry.ts","../src/lib/crud/crouton-validation.filter.ts","../src/lib/crud/crouton-validation.error.ts","../src/lib/crud/crud-controller.factory.ts","../src/lib/crud/crud.config.ts","../src/lib/crud/read.repository.ts","../src/lib/crud/sql.helpers.ts","../src/lib/crud/schema.utils.ts","../src/lib/crud/write.repository.ts","../src/lib/crud/constants.ts","../src/lib/crud/crud-repository.factory.ts","../src/lib/crud/data-source/data-source.registry.ts","../src/lib/crud/data-source/data-source.loader.ts","../src/lib/crud/operations/register-actions.ts","../src/lib/crud/operations/decorator.utils.ts","../src/lib/crud/operations/register-crud.ts","../src/lib/crud/request.dto.ts","../src/lib/crud/zod-validation.pipe.ts","../src/lib/crud/operations/register-schema-endpoints.ts","../src/lib/crud/operations/payload-builders.ts","../src/lib/crud/operations/register-sub-resources.ts","../src/lib/crud/loader/module.loader.ts","../src/lib/crud/loader/action.loader.ts","../src/lib/crud/loader/enum-registry.ts","../src/lib/crud/loader/json-adapter.ts","../src/lib/crud/loader/schema.helpers.ts","../src/lib/crud/loader/view.builders.ts","../src/lib/crud/loader/form-schema.builder.ts","../src/lib/crud/loader/schema-transforms.ts","../src/lib/crud/loader/table-schema.builder.ts","../src/lib/crud/loader/index.ts","../src/lib/crud/loader/resource-config.loader.ts","../src/lib/crud/loader/fs-resource-config.loader.ts"],"sourcesContent":["export * from './lib/crouton-api.module';\nexport * from './lib/crud/loader/index';\nexport * from './lib/crud/loader/resource-config.loader';\nexport * from './lib/crud/loader/fs-resource-config.loader';\nexport * from './lib/crud/resource-config.registry';\nexport * from './lib/crud/data-source';\nexport * from './lib/crud/crud.config';\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { APP_FILTER } from '@nestjs/core';\n\nimport type { SidebarGroupConfig } from '@ghentcdh/crouton-core';\n\nimport { createAppLayoutController } from './crud/app-layout.controller';\nimport { CroutonValidationExceptionFilter } from './crud/crouton-validation.filter';\nimport { createCrudController } from './crud/crud-controller.factory';\nimport { type ResourceConfig } from './crud/crud.config';\nimport type { DataSourceEntry } from './crud/data-source';\nimport { DataSourceRegistry, loadDataSourcesFromDir } from './crud/data-source';\nimport { FileSystemResourceConfigLoader } from './crud/loader/fs-resource-config.loader';\nimport { loadResourceConfigsFromDir } from './crud/loader/index';\nimport { type ResourceConfigLoader } from './crud/loader/resource-config.loader';\nimport { ResourceConfigRegistry } from './crud/resource-config.registry';\n\ntype CroutonConfig = {\n baseUrl: string;\n /**\n * Explicit path to the project enum registry (`crouton.enums.json`).\n * When omitted, the loader walks up from the resources dir to find it.\n */\n enumsFile?: string;\n /**\n * Sidebar group definitions, keyed by group slug.\n * Matches `sidebarGroups` in `crouton.json`.\n * Resources reference a group via `sidebar.group` in their `resource.json`.\n */\n sidebarGroups?: Record<string, SidebarGroupConfig>;\n /**\n * Application title served to the frontend via `GET /_app/layout`.\n * Displayed in the admin sidebar header.\n */\n title?: string;\n /**\n * Whether form fields are saved automatically as the user edits them.\n * Served to the frontend via `GET /_app/layout`. Defaults to `true`.\n * Set to `false` to restore explicit Save/Cancel buttons across the app.\n * Matches `autoSave` in `crouton.json`.\n */\n autoSave?: boolean;\n};\n@Module({\n controllers: [],\n providers: [],\n exports: [],\n})\nexport class CroutonApiModule {\n static forResources(\n configs: ResourceConfig[],\n dataSources: DataSourceEntry[],\n loader: ResourceConfigLoader,\n config: CroutonConfig,\n ): DynamicModule {\n const dataSourceRegistry = new DataSourceRegistry(dataSources);\n const configRegistry = new ResourceConfigRegistry(loader, configs);\n const controllers = [\n ...configs.map((c) => createCrudController(c, config.baseUrl)),\n createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true),\n ];\n\n return {\n module: CroutonApiModule,\n controllers,\n providers: [\n { provide: APP_FILTER, useClass: CroutonValidationExceptionFilter },\n { provide: DataSourceRegistry, useValue: dataSourceRegistry },\n { provide: ResourceConfigRegistry, useValue: configRegistry },\n ],\n };\n }\n\n static async forResourceDir(\n dirPath: string,\n dataSourcesPath: string,\n config: CroutonConfig,\n ): Promise<DynamicModule> {\n const loader = new FileSystemResourceConfigLoader(\n dirPath,\n config.baseUrl,\n config.enumsFile,\n );\n const configs = await loadResourceConfigsFromDir(\n dirPath,\n config.baseUrl,\n config.enumsFile,\n );\n const dataSources = await loadDataSourcesFromDir(dataSourcesPath);\n return CroutonApiModule.forResources(configs, dataSources, loader, config);\n }\n\n static forLoader(\n loader: ResourceConfigLoader,\n configs: ResourceConfig[],\n dataSources: DataSourceEntry[],\n config: CroutonConfig,\n ): DynamicModule {\n return CroutonApiModule.forResources(configs, dataSources, loader, config);\n }\n}\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport { type SidebarGroupConfig, labelFromId } from '@ghentcdh/crouton-core';\n\nimport { type ResourceConfig } from './crud.config';\nimport { IS_DEV } from './dev-mode';\nimport { ResourceConfigRegistry } from './resource-config.registry';\n\n// ─── Sidebar node types ───────────────────────────────────────────────────────\n\nexport type SidebarLeaf = {\n kind: 'item';\n id: string;\n label: string;\n position?: number;\n};\n\nexport type SidebarGroup = {\n kind: 'group';\n id: string;\n label: string;\n position?: number;\n children: SidebarLeaf[];\n};\n\nexport type SidebarNode = SidebarLeaf | SidebarGroup;\n\n// ─── Sort helper ─────────────────────────────────────────────────────────────\n\nconst byPosition = (\n a: { position?: number; label: string },\n b: { position?: number; label: string },\n) => {\n if (a.position != null && b.position != null) return a.position - b.position;\n if (a.position != null) return -1;\n if (b.position != null) return 1;\n return a.label.localeCompare(b.label);\n};\n\n// ─── Builder ──────────────────────────────────────────────────────────────────\n\nconst buildLayoutPayload = (\n configs: ResourceConfig[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n) => {\n const visible = configs.filter(\n (c) => c.sidebar?.hide !== true && c.views?.['table'],\n );\n\n const topLevel: SidebarLeaf[] = [];\n // Pre-seed group map from the central config so label/position are authoritative.\n const groupMap = new Map<\n string,\n { label: string; position?: number; children: SidebarLeaf[] }\n >(\n Object.entries(sidebarGroups).map(([slug, cfg]) => [\n slug,\n {\n label: cfg.label ?? labelFromId(slug),\n position: cfg.position,\n children: [],\n },\n ]),\n );\n\n for (const c of visible) {\n const leaf: SidebarLeaf = {\n kind: 'item',\n id: c.name,\n label: c.sidebar?.label ?? c.title ?? c.tag,\n position: c.sidebar?.position,\n };\n\n const groupSlug = c.sidebar?.group;\n if (groupSlug) {\n // Group must exist in the central config; fall back gracefully if not.\n if (!groupMap.has(groupSlug)) {\n groupMap.set(groupSlug, {\n label: labelFromId(groupSlug),\n children: [],\n });\n }\n groupMap.get(groupSlug)!.children.push(leaf);\n } else {\n topLevel.push(leaf);\n }\n }\n\n // Sort children within each group, then build group nodes.\n const groups: SidebarGroup[] = [...groupMap.entries()]\n // Only include groups that have at least one visible resource.\n .filter(([, g]) => g.children.length > 0)\n .map(([id, g]) => ({\n kind: 'group',\n id,\n label: g.label,\n position: g.position,\n children: g.children.sort(byPosition),\n }));\n\n // Merge top-level items and groups, sort together.\n const sidebar: SidebarNode[] = [...topLevel, ...groups].sort(byPosition);\n\n return { sidebar, title, autoSave };\n};\n\nexport const createAppLayoutController = (\n configs: ResourceConfig[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n) => {\n const layoutPayload = buildLayoutPayload(configs, sidebarGroups, title, autoSave);\n\n @Controller('_app')\n @ApiTags('App')\n class AppLayoutController {\n constructor(public readonly configRegistry: ResourceConfigRegistry) {}\n\n @Get('layout')\n @ApiOperation({ summary: 'Get the application layout (sidebar, …)' })\n @ApiResponse({ status: 200, description: 'Application layout metadata' })\n async getLayout() {\n if (IS_DEV) {\n const fresh = await this.configRegistry.getAll();\n return buildLayoutPayload(fresh, sidebarGroups, title, autoSave);\n }\n return layoutPayload;\n }\n }\n\n Reflect.defineMetadata(\n 'design:paramtypes',\n [ResourceConfigRegistry],\n AppLayoutController,\n );\n\n return AppLayoutController;\n};\n","import { z } from 'zod';\n\nimport { PositiveRequestNumber, StringOrArray } from './zod.types';\n\nexport const SortDirEnum = z.enum(['asc', 'desc']);\nexport type SortDir = z.infer<typeof SortDirEnum>;\n\nexport const RequestSchema = z.object({\n page: PositiveRequestNumber().optional().default(1),\n pageSize: PositiveRequestNumber().optional().default(20),\n sort: z.string().optional().default('id'),\n sortDir: SortDirEnum.optional().default('asc'),\n // Filter is of the format key:value:operator (e.g. name:john:eq) operator is optional\n filter: StringOrArray().optional().default([]),\n});\n\nexport type ListRequest = z.infer<typeof RequestSchema>;\n\n/** @deprecated Use `ListRequest` instead — `Request` shadows the global DOM `Request` type. */\nexport type Request = ListRequest;\n\nexport const RequestSchemaWithOffset = RequestSchema.transform((schema) => {\n const { page, pageSize, sort } = schema;\n return {\n ...schema,\n sort: sort || 'id',\n offset: (page - 1) * pageSize,\n };\n});\n","import { z } from 'zod';\n\nexport const PositiveRequestNumber = () =>\n z.coerce.number().int().positive().nonnegative();\nexport const StringOrArray = () =>\n z\n .string()\n .or(z.array(z.string()))\n .transform((val) => {\n if (Array.isArray(val)) return val;\n return [val];\n });\n","import { SortDirEnum } from './request.model';\n\nexport const Operator = [\n 'contains',\n 'not_contains',\n 'equals',\n 'not_equals',\n 'gt',\n 'lt',\n 'isnull',\n 'isnotnull',\n] as const;\n\nexport type OperatorType = (typeof Operator)[number];\n\n/** Human-readable label shown in the filter operator dropdown. */\nexport const OperatorLabel: Record<OperatorType, string> = {\n contains: 'contains',\n not_contains: 'not contains',\n equals: 'equals',\n not_equals: 'not equals',\n gt: '>',\n lt: '<',\n isnull: 'is empty',\n isnotnull: 'is not empty',\n};\n\nexport const OperatorOptions = Operator.map((k) => ({\n value: k,\n label: OperatorLabel[k],\n}));\n\n/** Operators that don't require a user-supplied value. */\nexport const OperatorNoValue = new Set<OperatorType>(['isnull', 'isnotnull']);\n\n/** Field types used to restrict which operators are shown in the filter UI. */\nexport type FieldType = 'string' | 'number' | 'date' | 'boolean' | 'enum';\n\n/** Operators available for each field type. */\nexport const OperatorsByType: Record<FieldType, OperatorType[]> = {\n string: ['contains', 'not_contains', 'equals', 'not_equals', 'isnull', 'isnotnull'],\n number: ['equals', 'not_equals', 'gt', 'lt', 'isnull', 'isnotnull'],\n date: ['equals', 'not_equals', 'gt', 'lt', 'isnull', 'isnotnull'],\n boolean: ['equals', 'not_equals', 'isnull', 'isnotnull'],\n enum: ['equals', 'not_equals', 'isnull', 'isnotnull'],\n};\n\nexport type Filter = {\n key: string;\n value: any;\n operator: OperatorType;\n label?: string;\n};\n\nconst getFilterValues = (filter: string): Filter => {\n const parts = filter.split(':');\n const key = parts[0] ?? '';\n const lastPart = parts[parts.length - 1] as OperatorType;\n const hasOp = parts.length >= 3 && Operator.includes(lastPart);\n const operator: OperatorType = hasOp ? lastPart : 'contains';\n const value = hasOp ? parts.slice(1, -1).join(':') : parts.slice(1).join(':');\n return { key, value, operator };\n};\n\nconst buildFilterKey = (keys: string[], filterObj: any): any => {\n if (keys.length === 1) return { key: keys[0], filterObj };\n const buildKey = keys.pop() as string;\n return buildFilterKey(keys, { [buildKey]: filterObj });\n};\n\nexport const buildSort = (key: string, sortDir?: string) =>\n buildSortKey(key.split('.'), SortDirEnum.safeParse(sortDir).data ?? 'asc');\n\nexport const buildSortKey = (keys: string[], sortDir: any): any => {\n if (keys.length === 1) return { [keys[0]]: sortDir };\n const buildKey = keys.pop() as string;\n return buildSortKey(keys, { [buildKey]: sortDir });\n};\n\nexport const buildFilter = (filters: string[]) => {\n const filter: Record<string, any> = {};\n filters?.forEach((f) => {\n const { key, value, operator } = getFilterValues(f);\n if (!key) return;\n const op = operator || 'contains';\n const filterObj: Record<string, string> = { [operator || 'contains']: value.toLowerCase() };\n if (op === 'contains') filterObj['mode'] = 'insensitive';\n const build = buildFilterKey(key.split('.'), filterObj);\n filter[build.key] = build.filterObj;\n });\n return filter;\n};\n\nexport const extractFilters = (filters: string[]) => {\n const result: Filter[] = [];\n filters.forEach((f) => {\n const { key, value, operator } = getFilterValues(f);\n if (!key) return;\n result.push({ label: key, key, value, operator });\n });\n return result;\n};\n\nexport const filterToString = (filter: Filter): string =>\n `${filter.key}:${filter.value}:${filter.operator}`;\n\nexport const stringToFilter = (s: string): Filter => getFilterValues(s);\n","import { z } from 'zod';\n\nimport { RequestSchema } from './request.model';\nimport { PositiveRequestNumber } from './zod.types';\n\nexport const ResponseRequestSchema = RequestSchema.extend({\n count: PositiveRequestNumber(),\n totalPages: PositiveRequestNumber(),\n});\n\nexport const ResponseSchema = z.object({\n data: z.array(z.unknown()),\n request: ResponseRequestSchema,\n});\n\nexport type ResponseData<TYPE> = z.infer<typeof ResponseSchema> & {\n data: TYPE[];\n};\n","import type { JsonSchema, Layout } from '@jsonforms/core';\nimport type { ZodObject } from 'zod';\nimport { toJSONSchema } from 'zod';\n\nexport enum ModalSize {\n xs = 'xs',\n sm = 'sm',\n lg = 'lg',\n xl = 'xl',\n}\n\nexport type ModalSizeType = keyof typeof ModalSize;\n\n/** @deprecated Use `ModalSize` instead. */\nexport { ModalSize as Size };\n/** @deprecated Use `ModalSizeType` instead. */\nexport type SizeType = ModalSizeType;\n\nexport type JsonFormsLayout = {\n uiSchema: Layout;\n schema: JsonSchema;\n modalSize?: ModalSizeType;\n};\n\nexport type FormSchemaModel = {\n form: JsonFormsLayout;\n table?: JsonFormsLayout;\n filter?: JsonFormsLayout;\n uri: string;\n searchUri: string;\n};\n\n/** Collapses a nullable `anyOf` to its non-null branch. Returns true if the property was nullable. */\nconst simplifyNullableAnyOf = (property: Record<string, unknown>): boolean => {\n const anyOf = property['anyOf'];\n if (!Array.isArray(anyOf) || anyOf.length !== 2) return false;\n const nonNull = anyOf.find((s: Record<string, unknown>) => s['type'] !== 'null');\n const hasNull = anyOf.some((s: Record<string, unknown>) => s['type'] === 'null');\n if (nonNull && hasNull) {\n delete property['anyOf'];\n Object.assign(property, nonNull);\n return true;\n }\n return false;\n};\n\nconst transformToJsonSchema = (schema: ZodObject<any>): JsonSchema => {\n const jsonSchema = toJSONSchema(schema, { unrepresentable: 'any', target: 'draft-07' });\n jsonSchema.additionalProperties = true;\n const properties = (jsonSchema as any).properties;\n if (properties) {\n const nullableKeys = new Set<string>();\n for (const key of Object.keys(properties)) {\n if (simplifyNullableAnyOf(properties[key])) nullableKeys.add(key);\n }\n // Nullable fields are treated as optional, so drop them from `required`.\n const required = (jsonSchema as any).required;\n if (Array.isArray(required)) {\n (jsonSchema as any).required = required.filter((key: string) => !nullableKeys.has(key));\n }\n }\n return jsonSchema as any;\n};\n\nexport const createSchema = (props: {\n uiSchema: any;\n tableSchema?: JsonSchema;\n filterSchema?: JsonSchema;\n schema: ZodObject<any>;\n dtoSchema: ZodObject<any>;\n responseSchema?: ZodObject<any>;\n uri: string;\n searchUri?: string;\n modalSize?: ModalSizeType;\n}) => {\n if (!props.schema) throw new Error('no schema provided');\n const schema = props.schema;\n const dtoSchema = props.dtoSchema;\n const formSchema = transformToJsonSchema(dtoSchema);\n const optionalSchema = transformToJsonSchema(schema.partial());\n return {\n dtoSchema,\n responseSchema: props.responseSchema ?? dtoSchema,\n schema: {\n form: { uiSchema: props.uiSchema, schema: formSchema, modalSize: props.modalSize ?? 'sm' },\n table: props.tableSchema ? { uiSchema: props.tableSchema, schema: optionalSchema } : undefined,\n filter: props.filterSchema ? { uiSchema: props.filterSchema, schema: optionalSchema } : undefined,\n uri: props.uri,\n searchUri: props.searchUri ?? `${props.uri}?filter=`,\n } as FormSchemaModel,\n };\n};\n","import type { ElementBuilder } from './layout.builder';\n\nexport abstract class Builder<TYPE> {\n constructor(protected readonly type: string) {}\n abstract build(): TYPE;\n}\n\nexport abstract class BuilderWithElements<TYPE, CONTROL_TYPE> extends Builder<TYPE> {\n protected elements: Array<ElementBuilder<CONTROL_TYPE>> = [];\n\n addControl(control: ElementBuilder<CONTROL_TYPE>) {\n this.elements.push(control);\n return this;\n }\n\n addControls(...controls: Array<ElementBuilder<CONTROL_TYPE>>) {\n this.elements.push(...controls);\n return this;\n }\n\n protected buildElements() {\n return this.elements.map((e) => e.build());\n }\n}\n","import { Builder } from './base.builder';\nimport type { LayoutBuilder } from './layout.builder';\n\nexport const ControlType = {\n number: 'number',\n string: 'string',\n integer: 'Integer',\n autocomplete: 'autocomplete',\n textArea: 'textarea',\n markdown: 'markdown',\n array: 'array',\n custom: 'custom',\n select: 'select',\n mutliSelect: 'mutliSelect',\n boolean: 'boolean',\n link: 'link',\n relation: 'relation',\n date: 'date',\n dateTime: 'dateTime',\n dateRange: 'date-range',\n} as const;\n\nexport interface DateRangeOptions extends ControlOption {\n format: 'date-range';\n /** Label shown above the start date input. Defaults to \"From\". */\n fromLabel?: string;\n /** Label shown above the end date input. Defaults to \"To\". */\n toLabel?: string;\n /** JSON object key for the start date. Defaults to \"from\". */\n fromField?: string;\n /** JSON object key for the end date. Defaults to \"to\". */\n toField?: string;\n}\n\nexport interface TextAreaOptions extends ControlOption {\n format: 'textarea';\n}\nexport interface MarkdownOptions extends ControlOption {\n format: 'markdown';\n minHeight: string;\n}\n\nexport interface DetailOptions extends ControlOption {\n format: 'array';\n layout: 'row' | 'column';\n}\nexport interface SelectOptions extends ControlOption {\n format: 'select' | 'multiselect';\n options: Array<any>;\n values?: Array<any>;\n resource?: string;\n labelKey?: string;\n valueKey?: string;\n}\n\nexport interface AutocompleteOptions extends Omit<SelectOptions, 'format'> {\n format: 'autocomplete';\n freeText?: boolean;\n enableCreate?: boolean;\n}\nexport interface AutocompleteRemoteOptions extends Omit<\n AutocompleteOptions,\n 'format' | 'options'\n> {\n format: 'autocomplete';\n uri: string;\n dataField?: string;\n skipAuth?: boolean;\n}\nexport interface AutocompleteResourceOptions extends Omit<\n AutocompleteOptions,\n 'format' | 'options'\n> {\n format: 'autocomplete';\n resource: string;\n skipAuth?: boolean;\n}\n\nexport type AutocompleteAllOptions =\n | AutocompleteOptions\n | AutocompleteRemoteOptions\n | AutocompleteResourceOptions;\n\nexport type ArrayActionType = 'edit';\nexport type ArrayAction = {\n type: ArrayActionType;\n idField: string;\n};\n\nexport interface ControlOption {\n format?: string;\n readonly?: boolean;\n label?: string;\n styles?: Partial<any>;\n elements?: any;\n elementLabelProp?: string;\n customLabel?: string;\n actions?: ArrayAction[];\n placeholder?: string;\n hideLabel?: boolean;\n hideActions?: boolean;\n layout?: 'row' | 'column';\n labelKey?: string;\n valueKey?: string;\n options?: Array<any>;\n dataField?: string;\n uri?: string;\n skipAuth?: boolean;\n freeText?: boolean;\n enableCreate?: boolean;\n /** date-range: label above the start date input. */\n fromLabel?: string;\n /** date-range: label above the end date input. */\n toLabel?: string;\n /** date-range: JSON object key for the start date. Defaults to \"from\". */\n fromField?: string;\n /** date-range: JSON object key for the end date. Defaults to \"to\". */\n toField?: string;\n customRender?: any;\n}\n\nexport type ControlTypes = {\n type: 'Control' | 'Object' | 'TextCell';\n scope: string;\n options?: TextAreaOptions | AutocompleteOptions | DetailOptions;\n};\n\nexport class ControlBuilder<\n TYPE,\n KEY = keyof TYPE,\n> extends Builder<ControlTypes> {\n private options: ControlOption = {\n format: 'Control',\n styles: {},\n };\n\n private _detail?: LayoutBuilder<any>;\n\n private constructor(\n private readonly scope: string,\n type = 'Control',\n ) {\n super(type);\n }\n\n static asObject<TYPE>(property: keyof TYPE): ControlBuilder<TYPE> {\n return new ControlBuilder<TYPE>(\n `#/properties/${property as string}`,\n 'Object',\n );\n }\n\n static properties<TYPE>(property: keyof TYPE): ControlBuilder<TYPE> {\n return new ControlBuilder<TYPE>(`#/properties/${property as string}`);\n }\n\n static asCustom<TYPE>(\n property: keyof TYPE,\n type: string,\n ): ControlBuilder<TYPE> {\n const builder = new ControlBuilder<TYPE>(\n `#/properties/${property as string}`,\n );\n\n builder.addOptions({\n format: ControlType.custom,\n type,\n } as unknown as Partial<ControlOption>);\n\n return builder;\n }\n\n setCustomRender(customRender: string) {\n this.addOptions({ customRender });\n\n return this;\n }\n\n detail<TYPE>(layoutBuilder: LayoutBuilder<TYPE>, label?: string) {\n this._detail = layoutBuilder;\n this.addOptions({\n format: ControlType.array,\n elementLabelProp: label,\n });\n return this;\n }\n\n addAction(action: ArrayAction) {\n const actions = this.options?.actions ?? [];\n actions.push(action);\n return this.addOptions({ actions });\n }\n\n detailFixed<TYPE>(\n layoutBuilder: LayoutBuilder<TYPE>,\n options: {\n label?: string;\n layout?: 'row' | 'column';\n } = {},\n ) {\n this._detail = layoutBuilder;\n return this.addOptions({\n hideActions: true,\n format: ControlType.array,\n layout: options.layout ?? 'column',\n elementLabelProp: options.label,\n });\n }\n\n labelKey(labelKey: string) {\n return this.addOptions({ labelKey });\n }\n\n readonly(): ControlBuilder<TYPE> {\n return this.addOptions({\n format: ControlType.string,\n readonly: true,\n });\n }\n\n link(): ControlBuilder<TYPE> {\n return this.addOptions({\n format: ControlType.link,\n });\n }\n\n markdown(options?: Omit<MarkdownOptions, 'format'>): ControlBuilder<TYPE> {\n return this.addOptions({\n format: ControlType.markdown,\n ...(options ?? {}),\n });\n }\n\n textArea(options?: Omit<TextAreaOptions, 'format'>) {\n return this.addOptions({\n format: ControlType.textArea,\n ...(options ?? {}),\n });\n }\n\n autocomplete(\n options:\n | Omit<AutocompleteOptions, 'format'>\n | Omit<AutocompleteRemoteOptions, 'format'>,\n ) {\n return this.addOptions({\n format: ControlType.autocomplete,\n dataField: 'data',\n ...(options ?? {}),\n });\n }\n\n control(format: string, options?: Partial<ControlOption>) {\n return this.addOptions({\n format,\n ...options,\n });\n }\n\n select(options: Omit<SelectOptions, 'format'>) {\n return this.addOptions({\n format: ControlType.select,\n ...options,\n });\n }\n\n mutliSelect(options: Omit<SelectOptions, 'format'>) {\n return this.addOptions({\n format: ControlType.mutliSelect,\n ...options,\n });\n }\n\n width(width: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full') {\n return this.addOptions({\n styles: {\n ...this.options?.styles,\n width,\n control: {\n wrapper: `input-${width}`,\n },\n },\n });\n }\n\n customLabel(label: string) {\n return this.addOptions({ label });\n }\n\n placeHolder(placeholder: string) {\n return this.addOptions({ placeholder });\n }\n\n hideLabel() {\n return this.addOptions({ hideLabel: true });\n }\n\n private addOptions(options: Partial<ControlOption>) {\n this.options = {\n ...this.options,\n ...options,\n };\n return this;\n }\n\n override build(): ControlTypes {\n return {\n type: this.type,\n scope: this.scope,\n options: {\n ...this.options,\n detail: this._detail ? this._detail?.build() : undefined,\n },\n } as ControlTypes;\n }\n}\n","import { BuilderWithElements } from './base.builder';\nimport type { CategoryBuilder } from './category.builder';\nimport type { ControlBuilder, ControlTypes } from './control.builder';\nimport type { GroupBuilder } from './group.builder';\nimport type { TextCellBuilder } from '../table/table.builder';\n\nexport type ElementBuilder<TYPE> =\n | ControlBuilder<TYPE>\n | LayoutBuilder<TYPE>\n | CategoryBuilder<TYPE>\n | GroupBuilder<TYPE>\n | TextCellBuilder<TYPE>;\n\nexport const LayoutTypes = {\n HorizontalLayout: 'HorizontalLayout',\n VerticalLayout: 'VerticalLayout',\n CollapseLayout: 'CollapseLayout',\n GridLayout: 'GridLayout',\n} as const;\n\ntype _LayoutTypes = (typeof LayoutTypes)[keyof typeof LayoutTypes];\n\nexport type LayoutType = {\n type: 'LayoutTypes';\n elements: Array<ControlTypes | LayoutType>;\n};\n\nexport class LayoutBuilder<TYPE> extends BuilderWithElements<LayoutType, TYPE> {\n private options: any;\n\n protected constructor(type: _LayoutTypes, options = {}) {\n super(type);\n this.options = options;\n }\n\n static horizontal<TYPE>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutTypes.HorizontalLayout);\n }\n static collapse<TYPE>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutTypes.CollapseLayout);\n }\n\n static vertical<TYPE>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutTypes.VerticalLayout);\n }\n\n static grid<TYPE>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutTypes.GridLayout);\n }\n\n titleKey(titleKey: string) {\n return this.addOptions({ titleKey });\n }\n\n title(title: string) {\n return this.addOptions({ title });\n }\n\n private addOptions(options: Partial<any>) {\n this.options = {\n ...this.options,\n ...options,\n };\n return this;\n }\n\n override build(): LayoutType {\n return {\n type: this.type,\n elements: this.buildElements(),\n options: this.options,\n } as LayoutType;\n }\n}\n","/**\n * Types that mirror the shape of a `resource.json` config file.\n *\n * These are pure, framework-agnostic types so they can be shared by:\n * - `@ghentcdh/crouton-api` (loads + serves resource configs)\n * - `@ghentcdh/crouton-codegen` (generates/updates resource configs)\n * - any tooling that reads or writes `resource.json`\n */\n\nimport type { RelationType } from './relation.types';\n\ntype BoolOrUpsert = boolean | { upsertOn: string | string[] };\n\nexport type JsonDisplay = {\n mode?: 'page' | 'modal';\n customComponent?: string | null;\n};\n\nexport type JsonOperations = {\n findAll?: boolean;\n findOne?: boolean;\n create?: boolean;\n update?: boolean;\n upsert?: BoolOrUpsert;\n delete?: boolean;\n};\n\n/** Describes a nested control inside a `detail`/`detailFixed` array layout. */\nexport type DetailControl = {\n /** Property name on the array item. */\n property: string;\n /** Control type (e.g. `\"text\"`, `\"markdown\"`). Defaults to `\"text\"`. */\n type?: string;\n options?: Record<string, unknown>;\n hideLabel?: boolean;\n width?: string;\n};\n\n/** Configuration for array columns rendered via `detailFixed`. */\nexport type DetailConfig = {\n /** Layout style: `\"collapse\"` wraps each item in a collapsible panel. */\n layout: 'collapse' | 'row';\n /** Key on the array item used as the collapse panel title. */\n titleKey?: string;\n /** Nested controls rendered for each array item. */\n controls: DetailControl[];\n};\n\n/**\n * Options for relation field inputs (`fieldInput.format === \"relation\"`).\n * These are injected into the frontend control and — for `sort`/`sortDir` —\n * also used by the backend to apply `orderBy` on included relation records.\n */\nexport type RelationFieldInputOptions = {\n /** Field to sort related records by, e.g. `\"title\"` or `\"author.name\"`. */\n sort?: string;\n /** Sort direction. Defaults to `\"asc\"` when omitted. */\n sortDir?: 'asc' | 'desc';\n /** CSS flex direction for the relation control button layout. */\n direction?: string;\n /** Key used as the display label in the relation control. */\n displayKey?: string;\n /** Path to the related resource (resolved to a URI at load time). */\n resource?: string;\n [k: string]: unknown;\n};\n\nexport type FieldInput = {\n type: string;\n customRender?: string;\n /**\n * Render format hint for the frontend (e.g. `\"relation\"` for sub-resource\n * relations). When `format` is `\"relation\"`, `resource` must also be set.\n */\n format?: string;\n /**\n * Relative path to the child resource definition, e.g. `\"./author.resource\"`.\n * Only used when `format` is `\"relation\"`. Resolved at load time to inject\n * sub-resource URIs into `options`.\n */\n resource?: string;\n /**\n * Cardinality of the relation. Used by the frontend to determine the correct\n * renderer and behaviour (e.g. single-select vs multi-select).\n * - `manyToOne` / `oneToOne` — single FK reference (autocomplete / relation control)\n * - `oneToMany` / `manyToMany` — collection (sub-resource table / multi-select)\n */\n relationType?: RelationType;\n /** Override the display order in form views. Lower values come first. */\n position?: number;\n options?: RelationFieldInputOptions | unknown;\n /** Nested array detail layout (renders via `detailFixed`). */\n detail?: DetailConfig;\n};\n\nexport type JsonColumn = {\n id: string;\n column?: string;\n label?: string;\n hiddenInTable?: boolean;\n hiddenInForm?: boolean;\n hiddenInView?: boolean;\n sortable?: boolean;\n defaultSort?: boolean;\n searchable?: boolean;\n filterable?: boolean;\n createable?: boolean;\n updateable?: boolean;\n /** Hide the label for this control in form views. */\n hideLabel?: boolean;\n /**\n * Show this field only when another field matches a value.\n * e.g. `{ \"field\": \"source\", \"eq\": \"existing\" }`\n * Translates to a JSON Forms `SHOW` rule.\n */\n showWhen?: {\n field: string;\n eq?: unknown;\n neq?: unknown;\n exists?: boolean;\n notExists?: boolean;\n };\n /**\n * Hide this field when another field matches a value.\n * e.g. `{ \"field\": \"source\", \"eq\": \"new\" }`\n * Translates to a JSON Forms `HIDE` rule.\n */\n hideWhen?: {\n field: string;\n eq?: unknown;\n neq?: unknown;\n exists?: boolean;\n notExists?: boolean;\n };\n /**\n * Disable this field when another field has no value (or matches a condition).\n * e.g. `{ \"field\": \"author_origin\", \"notExists\": true }` — disabled when author_origin is empty.\n * Translates to a JSON Forms `DISABLE` rule.\n */\n disabledWhen?: {\n field: string;\n eq?: unknown;\n neq?: unknown;\n exists?: boolean;\n notExists?: boolean;\n };\n /** Display a nested key (e.g. `\"name\"` for `speech.name`). Maps to `TextCellBuilder.key()`. */\n displayKey?: string;\n /** Override the sort column (e.g. `\"speech.name\"`). Maps to `TextCellBuilder.setSortId()`. */\n sortId?: string;\n /**\n * Name of a shared enum in the project enum registry (`crouton.enums.json`).\n * At load time the loader injects that enum's `{ value, label }[]` into\n * `fieldInput.options.values`, so columns don't duplicate the option list.\n */\n enum?: string;\n /** Mark as the primary key column for lookup resolution. */\n idField?: boolean;\n /** Include this column as a display label in the resource lookup descriptor. */\n showInLookup?: boolean;\n /**\n * JSON schema type for this column when no Zod schema is available.\n * Defaults to `\"string\"`. Used by `buildViewsFromColumns`.\n */\n columnType?: string;\n fieldInput?: FieldInput;\n /**\n * Path to another `resource.json` whose columns are expanded as nested sub-columns\n * under this column's object key.\n *\n * Example: `\"extend\": \"../internalAuthor/resource.json\"` on a column `author`\n * auto-generates virtual sub-columns like `author_name` (column: \"author\", displayKey: \"name\").\n *\n * Visibility (`hiddenInTable/Form/View`) on this column is inherited by all sub-columns as a\n * default; the referenced resource's own column visibility further restricts it.\n */\n extend?: string;\n /**\n * Per-sub-column overrides when using `extend`.\n * Key: the virtual column id (`\"{extendId}_{refColId}\"`) or just the referenced column id.\n * Value: any `JsonColumn` fields to merge over the generated virtual column.\n */\n columns?: Record<string, Partial<Omit<JsonColumn, 'id'>>>;\n [k: string]: unknown;\n};\n\nexport type JsonColumnsMap = Record<string, Omit<JsonColumn, 'id'>>;\n\n/**\n * A column whose value is computed by a raw SQL subquery at query time.\n * The `sqlExpression` may reference the parent table via the alias `main`.\n *\n * Example:\n * ```json\n * {\n * \"id\": \"inception\",\n * \"alias\": \"inception\",\n * \"label\": \"Available in inception\",\n * \"sqlExpression\": \"SELECT COUNT(id) FROM text_content WHERE text_content.text_id = main.id\",\n * \"position\": 8\n * }\n * ```\n */\nexport type CalculatedColumn = {\n /** Column identifier used in the response payload and UI schema. */\n id: string;\n /** SQL alias — must match `id`. */\n alias: string;\n /** Human-readable label shown in the table header. */\n label?: string;\n /**\n * Raw SQL subquery. Use `main` as the alias for the parent table row,\n * e.g. `SELECT COUNT(*) FROM child WHERE child.parent_id = main.id`.\n */\n sqlExpression: string;\n /** JSON schema / cast type for the computed value. Defaults to `\"number\"`. `\"string\"` skips CAST. */\n type?: 'number' | 'boolean' | 'string';\n /**\n * Insertion position relative to the other visible columns.\n * Uses the same semantics as `fieldInput.position` on regular columns:\n * `position: N` places this column before the element currently at index N.\n * Can also be set via `fieldInput.position` (takes precedence).\n */\n position?: number;\n hiddenInTable?: boolean;\n hiddenInView?: boolean;\n /**\n * Field input options for rendering in form / view schemas.\n * Supports `colspan`, `format`, and any other options passed to the Control renderer.\n * `position` here takes precedence over the top-level `position`.\n */\n fieldInput?: {\n position?: number;\n options?: Record<string, unknown>;\n };\n};\n\nexport type JsonActionCondition = {\n /** Row field to evaluate. */\n field: string;\n /**\n * Comparison operator. Defaults to `\"eq\"`.\n * - `eq` / `neq` — strict equality\n * - `gt` / `gte` / `lt` / `lte` — numeric or date comparison\n * - `exists` — field is not null / undefined / empty string\n * - `notExists` — field is null / undefined / empty string\n */\n op?: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'exists' | 'notExists';\n /** Comparison value. Not required for `exists` / `notExists`. */\n value?: unknown;\n};\n\n/** Action that calls a backend procedure endpoint. */\nexport type JsonProcedureAction = {\n type?: 'procedure';\n /** Unique identifier used as the URL segment, e.g. `\"sendToInception\"`. */\n id: string;\n /** Human-readable button label shown in the table. */\n label: string;\n /**\n * Filename (without extension) inside the resource's `actions/` directory\n * that exports the `procedure` function, e.g. `\"sendToInception\"`.\n */\n procedure: string;\n /** HTTP method for the frontend to call this action. Defaults to `\"post\"`. */\n method?: string;\n /**\n * Static data payload merged into the request body by the frontend.\n * Values may contain `{id}` which the frontend replaces with the record id.\n * e.g. `{ \"textId\": \"{id}\" }`.\n */\n data?: Record<string, unknown>;\n /** Optional condition evaluated per row. Button is hidden when the condition is false. */\n condition?: JsonActionCondition;\n};\n\n/** Action that opens a URL in a new browser tab — no backend call. */\nexport type JsonLinkAction = {\n type: 'link';\n /** Unique identifier for the action. */\n id: string;\n /** Human-readable button label shown in the table. */\n label: string;\n /**\n * URL to open. May contain `{id}` which the frontend replaces with the record id.\n * e.g. `\"/preview/{id}\"`.\n */\n href: string;\n /** Optional condition evaluated per row. Button is hidden when the condition is false. */\n condition?: JsonActionCondition;\n};\n\nexport type JsonAction = JsonProcedureAction | JsonLinkAction;\n\n// ─── Table-level (global) actions ────────────────────────────────────────────\n\n/** Table-level action that calls a backend procedure endpoint (no record id). */\nexport type JsonTableProcedureAction = {\n type?: 'procedure';\n /** Unique identifier used as the URL segment, e.g. `\"syncZotero\"`. */\n id: string;\n /** Human-readable button label (shown as tooltip when `icon` is set). */\n label?: string;\n /** MDI icon name, e.g. `\"mdi:sync\"`. When set, the button shows an icon instead of a label. */\n icon?: string;\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip?: string;\n /**\n * Filename (without extension) inside the resource's `actions/` directory\n * that exports the table-action procedure, e.g. `\"syncZotero\"`.\n */\n procedure: string;\n /** HTTP method for the frontend. Defaults to `\"post\"`. */\n method?: string;\n /** Static query / body params passed to the endpoint. */\n data?: Record<string, unknown>;\n};\n\n/** Table-level action that opens a URL in a new browser tab. */\nexport type JsonTableLinkAction = {\n type: 'link';\n /** Unique identifier for the action. */\n id: string;\n /** Human-readable button label. */\n label?: string;\n /** MDI icon name, e.g. `\"mdi:open-in-new\"`. */\n icon?: string;\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip?: string;\n /** URL to open. May contain `{env.VAR}` placeholders. */\n href: string;\n};\n\nexport type JsonTableAction = JsonTableProcedureAction | JsonTableLinkAction;\n\n/**\n * Configuration for a single sidebar group, defined centrally in `crouton.json`.\n * Keyed by the group slug (e.g. `\"metadata\"`).\n */\nexport type SidebarGroupConfig = {\n /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */\n label?: string;\n /** Controls the order of this group among top-level sidebar items. */\n position?: number;\n};\n\nexport type JsonResourceConfig = {\n name: string;\n route: string;\n model: string;\n tag: string;\n title?: string;\n table?: string;\n idType?: 'number' | 'string';\n database?: string;\n sidebar?: {\n /** Hide this resource from the sidebar entirely. */\n hide?: boolean;\n /** Order within its group (or at the top level). Lower values come first. */\n position?: number;\n /** Override the sidebar label. Defaults to the resource `title`. */\n label?: string;\n /**\n * Slug of the group this resource belongs to.\n * Must match a key in `sidebarGroups` in `crouton.json`.\n * Resources with the same `group` are nested under a shared collapsible section.\n */\n group?: string;\n };\n display?: JsonDisplay;\n operations: JsonOperations;\n columns?: JsonColumn[] | JsonColumnsMap;\n calculatedColumns?: CalculatedColumn[];\n actions?: JsonAction[];\n /** Global table-level actions (no record id). Shown as toolbar buttons. */\n tableActions?: JsonTableAction[];\n /** Modal width when opening the form for this resource. One of `xs`, `sm`, `lg`, `xl`. */\n modalSize?: 'xs' | 'sm' | 'lg' | 'xl';\n /**\n * Relations to include when querying this resource.\n * Each entry is either a plain relation name (`\"author\"` → `include: { author: true }`)\n * or an object for nested includes:\n * `{ \"relation\": \"text_author\", \"include\": [\"author\"] }` →\n * `include: { text_author: { include: { author: true } } }`\n */\n include?: JsonIncludeEntry[];\n};\n\n/**\n * A single entry in an `include` list.\n * - Plain string: `\"author\"` → `{ author: true }`\n * - Object with nested includes: `{ relation: \"text_author\", include: [\"author\"] }`\n * → `{ text_author: { include: { author: true } } }`\n * - Object with orderBy: `{ relation: \"sections\", orderBy: { title: \"asc\" } }`\n * → `{ sections: { orderBy: { title: \"asc\" } } }`\n */\nexport type JsonIncludeEntry =\n | string\n | {\n relation: string;\n include?: JsonIncludeEntry[];\n /** Prisma-format orderBy clause applied to the included records. */\n orderBy?: Record<string, unknown>;\n };\n\n/**\n * Derive a human-readable label from a column id.\n * `\"field_label\"` → `\"Field label\"`, `\"fieldLabel\"` → `\"Field label\"`\n */\nexport const labelFromId = (id: string): string => {\n const words = id\n .replace(/([a-z])([A-Z])/g, '$1 $2') // camelCase → camel Case\n .replace(/[_-]+/g, ' ') // snake_case / kebab-case → spaces\n .trim();\n return words.charAt(0).toUpperCase() + words.slice(1).toLowerCase();\n};\n\n/** Normalise `columns` from either array or object-map form. */\nexport const normalizeColumns = (\n columns: JsonColumn[] | JsonColumnsMap | undefined,\n): JsonColumn[] | undefined => {\n if (!columns) return undefined;\n const raw: JsonColumn[] = Array.isArray(columns)\n ? columns\n : Object.entries(columns).map(([id, col]) => ({ id, ...col }));\n return raw.map((col) => ({\n ...col,\n label: col.label ?? labelFromId(col.id),\n }));\n};\n","/**\n * Helpers for the `{ value, label }` envelope used by enum/select columns.\n *\n * The DB stores a bare scalar; the API can wrap it into `{ value, label }` on\n * read (so the UI shows a human-readable label) and unwrap it back to the\n * scalar on write. These helpers are pure and shared by the read/write paths.\n */\n\nexport interface ValueLabelOption {\n value: unknown;\n label: string;\n}\n\nexport interface ValueLabel {\n value: unknown;\n label: string;\n}\n\nconst wrapOne = (value: unknown, values: ValueLabelOption[]): ValueLabel => {\n const match = values.find((o) => o.value === value);\n return { value, label: match ? match.label : String(value) };\n};\n\n/**\n * Wrap a stored scalar into `{ value, label }` using the option list.\n * - `null` / `undefined` pass through unchanged (never wrapped).\n * - An array (multi-value enum) is mapped element-wise.\n * - A value missing from `values` falls back to `label = String(value)`.\n */\nexport const toValueLabel = (\n value: unknown,\n values: ValueLabelOption[],\n): unknown => {\n if (value === null || value === undefined) return value;\n if (Array.isArray(value)) return value.map((v) => wrapOne(v, values));\n return wrapOne(value, values);\n};\n\n/**\n * Unwrap a `{ value, label }` (or array of them) back to the bare scalar for\n * persistence / filtering. Plain scalars pass through unchanged (idempotent).\n */\nexport const fromValueLabel = (input: unknown): unknown => {\n if (Array.isArray(input)) return input.map(fromValueLabel);\n if (input && typeof input === 'object' && 'value' in (input as object)) {\n return (input as { value: unknown }).value;\n }\n return input;\n};\n","import { Builder } from '../layout/base.builder';\nimport { LayoutBuilder } from '../layout/layout.builder';\n\nexport interface TextCellOption {\n format: 'TextCell';\n sortId?: string;\n sortable?: boolean;\n}\n\nexport interface KeyValueOption extends Omit<TextCellOption, 'format'> {\n format: 'keyValue';\n key: string;\n}\n\nexport type TextCellType = {\n type: 'TextCell';\n scope: string;\n options?: KeyValueOption;\n};\nexport class TextCellBuilder<TYPE> extends Builder<TextCellType> {\n private options: KeyValueOption | TextCellOption | undefined;\n\n protected constructor(\n private readonly scope: string,\n type = 'TextCell',\n ) {\n super(type);\n }\n\n static properties<TYPE>(property: keyof TYPE): TextCellBuilder<TYPE> {\n return new TextCellBuilder<TYPE>(`#/properties/${property as string}`);\n }\n\n key(key: string): TextCellBuilder<TYPE> {\n this.options = {\n format: 'keyValue',\n key: key,\n };\n return this;\n }\n\n setSortId(sortId: string): TextCellBuilder<TYPE> {\n this.options = {\n ...(this.options ?? { format: this.type as TextCellOption['format'] }),\n sortId: sortId,\n };\n return this;\n }\n\n override build(): TextCellType {\n return {\n type: this.type,\n scope: this.scope,\n options: this.options,\n } as TextCellType;\n }\n}\n\nexport class BooleanCellBuilder extends TextCellBuilder<boolean> {\n protected constructor(scope: string) {\n super(scope, 'BooleanCell');\n }\n static override properties<TYPE>(property: keyof TYPE): BooleanCellBuilder {\n return new BooleanCellBuilder(`#/properties/${property as string}`);\n }\n}\nexport class TableBuilder<TYPE> {\n private builder: LayoutBuilder<TYPE>;\n\n private constructor() {\n this.builder = LayoutBuilder.horizontal();\n }\n\n static init<TYPE>() {\n return new TableBuilder<TYPE>();\n }\n\n addControl(control: TextCellBuilder<TYPE>) {\n this.builder.addControls(control);\n return this;\n }\n\n addControls(...controls: Array<TextCellBuilder<TYPE>>) {\n this.builder.addControls(...controls);\n return this;\n }\n\n build() {\n return this.builder.build();\n }\n}\n","/**\n * `true` when running in development mode.\n * Works in both Node and Vite (Vite replaces process.env.NODE_ENV at build time).\n */\nexport const IS_DEV = process.env['NODE_ENV'] !== 'production';\n","import { Injectable } from '@nestjs/common';\n\nimport type { ResourceConfig } from './crud.config';\nimport { IS_DEV } from './dev-mode';\nimport type { ResourceConfigLoader } from './loader/resource-config.loader';\n\n@Injectable()\nexport class ResourceConfigRegistry {\n private configs: ResourceConfig[];\n\n constructor(\n private readonly loader: ResourceConfigLoader,\n initialConfigs: ResourceConfig[],\n ) {\n this.configs = initialConfigs;\n }\n\n async getAll(): Promise<ResourceConfig[]> {\n if (IS_DEV) {\n this.configs = await this.loader.loadAll();\n }\n return this.configs;\n }\n\n async getByRoute(route: string): Promise<ResourceConfig | undefined> {\n if (IS_DEV) {\n return this.loader.loadByRoute(route);\n }\n return this.configs.find((c) => c.route === route);\n }\n}\n","import {\n type ArgumentsHost,\n Catch,\n type ExceptionFilter,\n} from '@nestjs/common';\n\nimport { CroutonValidationError } from './crouton-validation.error';\n\n/**\n * Handles `CroutonValidationError` thrown by `ZodValidationPipe`.\n *\n * Writes the 400 response directly on the HTTP response object so that no\n * `HttpException` class is involved — avoiding the `instanceof` mismatch\n * that occurs when crouton-api's `@nestjs/common` is a different runtime\n * instance from the consumer's one.\n */\n@Catch(CroutonValidationError)\nexport class CroutonValidationExceptionFilter implements ExceptionFilter {\n catch(exception: CroutonValidationError, host: ArgumentsHost): void {\n const res = host.switchToHttp().getResponse<{\n status: (code: number) => { json: (body: unknown) => void };\n }>();\n res.status(400).json({\n statusCode: 400,\n message: exception.errors,\n error: 'Bad Request',\n });\n }\n}\n","/**\n * Thrown by `ZodValidationPipe` when the request body fails Zod validation.\n *\n * Using a plain `Error` subclass (instead of NestJS's `BadRequestException`)\n * avoids the `instanceof HttpException` check in `BaseExceptionFilter`, which\n * fails when crouton-api's `@nestjs/common` module is a different runtime\n * instance from the consumer's one (common in Docker + tsconfig-paths setups).\n *\n * `CroutonValidationExceptionFilter` catches this class and writes a 400\n * response directly on the HTTP response object, bypassing the HttpException\n * hierarchy entirely.\n */\nexport class CroutonValidationError extends Error {\n constructor(\n public readonly errors: Array<{ field: string; message: string }>,\n ) {\n super('Validation failed');\n this.name = 'CroutonValidationError';\n }\n}\n","import { Controller, type Type } from '@nestjs/common';\nimport { Body } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\n\nimport { type CrudRepository, createCrudRepository } from './crud-repository.factory';\nimport {\n type ResourceConfig,\n isOperationEnabled,\n resolveDefinition,\n schemaFor,\n upsertOnFor,\n} from './crud.config';\nimport { DataSourceRegistry } from './data-source';\nimport type { OperationContext } from './operations/operation-context';\nimport { registerActionRoutes, registerTableActionRoutes } from './operations/register-actions';\nimport { registerCreate, registerDelete, registerFindAll, registerFindOne, registerUpdate, registerUpsert } from './operations/register-crud';\nimport { registerDefinitionEndpoint, registerResourceJsonEndpoint, registerSchemasEndpoint } from './operations/register-schema-endpoints';\nimport { registerSubResourceRoutes } from './operations/register-sub-resources';\nimport { ResourceConfigRegistry } from './resource-config.registry';\nimport { isZodSchema } from './schema.utils';\nimport { ZodValidationPipe, type ZodValidationPipeOptions } from './zod-validation.pipe';\n\n/**\n * Dynamically build a NestJS controller class for the given resource config.\n *\n * The factory registers standard CRUD routes, schema/definition endpoints,\n * procedure-action routes, and sub-resource routes — skipping any operation\n * not enabled in `config`. The returned class can be passed directly to\n * a NestJS module's `controllers` array.\n *\n * @param config - Resource definition including model, route, operations, views, etc.\n * @param baseUrl - Absolute base URL prepended to operation URIs in schema payloads (e.g. `https://api.example.com`).\n * @throws {Error} When `upsert` is enabled but no `upsertOn` key is configured.\n */\nexport function createCrudController(\n config: ResourceConfig,\n baseUrl?: string,\n): Type<any> {\n const { route, name, tag, idType = 'string' } = config;\n const definition = resolveDefinition(config);\n const listSchema = schemaFor(definition, 'findAll');\n const oneSchema = schemaFor(definition, 'findOne') ?? listSchema;\n const createSchema = schemaFor(definition, 'create');\n const updateSchema = schemaFor(definition, 'update');\n const upsertSchema = schemaFor(definition, 'upsert') ?? createSchema;\n\n if (isOperationEnabled(definition, 'upsert') && !upsertOnFor(definition)) {\n throw new Error(`Resource \"${name}\" declares 'upsert' but no upsertOn`);\n }\n\n const bodyDecorator = (\n schema?: ReturnType<typeof schemaFor>,\n options?: ZodValidationPipeOptions,\n ): ParameterDecorator => {\n if (!schema) return Body();\n if (isZodSchema(schema)) return Body(new ZodValidationPipe(schema, options));\n return Body();\n };\n\n class CrudControllerBase {\n protected readonly repo: CrudRepository;\n protected readonly configRegistry: ResourceConfigRegistry;\n constructor(registry: DataSourceRegistry, configRegistry: ResourceConfigRegistry) {\n const prisma = registry.resolve(config.database);\n this.repo = createCrudRepository(prisma, config);\n this.configRegistry = configRegistry;\n }\n }\n\n const ctx: OperationContext = {\n cls: CrudControllerBase,\n config,\n definition,\n listSchema,\n oneSchema,\n createSchema,\n updateSchema,\n upsertSchema,\n idParamMeta: { name: 'id', type: idType === 'number' ? 'number' : 'string' },\n bodyDecorator,\n baseUrl,\n };\n\n // ── Register operations (order matters: static routes before :id routes) ──\n registerFindAll(ctx);\n registerDefinitionEndpoint(ctx);\n registerSchemasEndpoint(ctx);\n registerResourceJsonEndpoint(ctx);\n registerActionRoutes(ctx);\n registerTableActionRoutes(ctx);\n registerSubResourceRoutes(ctx);\n registerFindOne(ctx);\n registerCreate(ctx);\n registerUpdate(ctx);\n registerUpsert(ctx);\n registerDelete(ctx);\n\n // ── Class-level decorators ─────────────────────────────────────────────\n Controller(route)(CrudControllerBase);\n ApiTags(tag)(CrudControllerBase);\n Object.defineProperty(CrudControllerBase, 'name', {\n value: `${name.charAt(0).toUpperCase() + name.slice(1)}Controller`,\n });\n Reflect.defineMetadata(\n 'design:paramtypes',\n [DataSourceRegistry, ResourceConfigRegistry],\n CrudControllerBase,\n );\n\n return CrudControllerBase;\n}\n","import { type ZodObject, type ZodRawShape } from 'zod';\n\nimport type {\n CalculatedColumn,\n FieldInput,\n JsonAction,\n JsonActionCondition,\n JsonIncludeEntry,\n} from './loader/json-config.types';\n\nexport type ResourceProcedureAction = {\n type?: 'procedure';\n /** URL segment used in the endpoint: `POST /{route}/procedure/{id}/:recordId` */\n id: string;\n /** Human-readable label shown as a button in the table. */\n label: string;\n /** HTTP method for the endpoint. Defaults to `\"post\"`. */\n method?: string;\n /** Static data payload merged into the request body by the frontend. */\n data?: Record<string, unknown>;\n /** The procedure function to call with (prisma, recordId). */\n procedure: (prisma: any, recordId: string | number) => Promise<any>;\n /** Optional condition evaluated per row. Button is hidden when false. */\n condition?: JsonActionCondition;\n};\n\nexport type ResourceLinkAction = {\n type: 'link';\n /** Unique identifier for the action. */\n id: string;\n /** Human-readable label shown as a button in the table. */\n label: string;\n /**\n * URL pattern to open in a new tab. May contain `{id}` which the frontend\n * replaces with the record id, e.g. `\"/preview/{id}\"`.\n */\n href: string;\n /** Optional condition evaluated per row. Button is hidden when false. */\n condition?: JsonActionCondition;\n};\n\nexport type ResourceAction = ResourceProcedureAction | ResourceLinkAction;\n\n// ─── Table-level (global) actions ────────────────────────────────────────────\n\n/** Table-level procedure action — no record id is passed to the procedure. */\nexport type ResourceTableProcedureAction = {\n type?: 'procedure';\n id: string;\n label?: string;\n icon?: string;\n tooltip?: string;\n method?: string;\n data?: Record<string, unknown>;\n /** The procedure function called with only prisma (no record id). */\n procedure: (prisma: any) => Promise<any>;\n};\n\nexport type ResourceTableLinkAction = {\n type: 'link';\n id: string;\n label?: string;\n icon?: string;\n tooltip?: string;\n href: string;\n};\n\nexport type ResourceTableAction =\n | ResourceTableProcedureAction\n | ResourceTableLinkAction;\n\nexport type CrudOperation =\n | 'findAll'\n | 'findOne'\n | 'create'\n | 'update'\n | 'upsert'\n | 'delete';\n\nexport type SchemaInput = ZodObject<ZodRawShape> | JsonSchemaInput;\n\nexport interface JsonSchemaInput {\n type: 'object';\n properties: Record<string, unknown>;\n required?: string[];\n additionalProperties?: boolean;\n}\n\n/** @deprecated Use `JsonSchemaInput` instead — `JsonSchema` clashes with the `@jsonforms/core` type of the same name. */\nexport type JsonSchema = JsonSchemaInput;\n\nexport type WriteOp = 'create' | 'update' | 'upsert' | 'delete';\nexport type ReadOp = 'findAll' | 'findOne';\n\nexport interface WriteHookContext<PRISMACLIENT> {\n prisma: PRISMACLIENT;\n op: WriteOp;\n /** The record id for `update`; `undefined` for `create`/`upsert`. */\n id?: string | number;\n}\n\nexport interface ReadHookContext<PRISMACLIENT> {\n prisma: PRISMACLIENT;\n op: ReadOp;\n}\n\nexport interface ResourceHooks<PRISMACLIENT = any> {\n /**\n * Runs before the data is passed to Prisma for create/update/upsert.\n * Use this to connect-or-create related entities.\n */\n beforeWrite?: (\n data: any,\n ctx: WriteHookContext<PRISMACLIENT>,\n ) => Promise<any> | any;\n /**\n * Runs after Prisma has persisted the record for create/update/delete.\n * For upsert the op is resolved to `'create'` or `'update'` depending on\n * whether a matching record existed before the operation.\n * Receives the persisted record; the return value replaces the response.\n */\n afterWrite?: (\n result: any,\n ctx: WriteHookContext<PRISMACLIENT>,\n ) => Promise<any> | any;\n /**\n * Runs on every row returned by findAll / findOne. Use this to\n * decorate rows with derived fields (e.g. URIs).\n */\n afterRead?: (\n row: any,\n ctx: ReadHookContext<PRISMACLIENT>,\n ) => Promise<any> | any;\n}\n\n/**\n * Per-operation descriptor. Use `true` to enable with no schema, or\n * an object to also attach a schema (request body for write ops, row\n * projection for read ops). For read operations the schema also drives\n * the Prisma `select` — nested zod objects/arrays become nested\n * `select` clauses, which transparently load relations.\n */\nexport type OperationDef =\n | true\n | {\n schema?: SchemaInput;\n };\n\nexport type UpsertOperationDef = {\n schema?: SchemaInput;\n upsertOn: string | string[];\n};\n\nexport interface ResourceDefinition {\n findAll?: OperationDef;\n findOne?: OperationDef;\n create?: OperationDef;\n update?: OperationDef;\n upsert?: UpsertOperationDef;\n delete?: OperationDef;\n}\n\nexport type DefinitionCallback = () => ResourceDefinition;\n\n// ─── view / resource config ──────────────────────────────────────────────────\n\nexport type ViewColumnConfig = {\n id: string;\n label?: string;\n sortable?: boolean;\n searchable?: boolean;\n fieldInput?: FieldInput;\n};\n\nexport type ViewConfig = {\n json_schema: Record<string, unknown>;\n ui_schema: Record<string, unknown>;\n columns: ViewColumnConfig[];\n defaultSort?: string;\n};\n\nexport type ResourceDisplay = {\n mode: 'page' | 'modal';\n customComponent: string | null;\n};\n\n/**\n * A column whose stored scalar is serialized as `{ value, label }` on read and\n * normalized back to the scalar on write. Computed at load time from columns\n * flagged `fieldInput.options.emitObject` that carry an `options.values` list.\n */\nexport type ValueLabelColumn = {\n /** Row field/key to transform. */\n field: string;\n values: { value: unknown; label: string }[];\n};\n\nexport type LookupConfig = {\n /** The primary key field name (used for id-based lookups). */\n key: string;\n /**\n * The field used for text search (`?q=`). When absent, `?q=` is silently ignored.\n * Derived from the first `showInLookup` column, then first `searchable` column.\n */\n label?: string;\n};\n\n/**\n * Describes a sub-resource relation exposed as `GET /:id/{childRoute}`.\n * The parent `findAll` response includes a count for the relation column.\n */\nexport type SubResourceConfig = {\n /** Column id in the parent resource that holds the count, e.g. `\"text_author\"`. */\n column: string;\n /** Prisma relation field name on the parent model, e.g. `\"text_author\"`. */\n relation: string;\n /** Route segment for the sub-resource endpoint, e.g. `\"author\"`. */\n childRoute: string;\n /** Prisma model name of the child, e.g. `\"text_author\"`. */\n childModel: string;\n /** FK field on the child model pointing back to the parent, e.g. `\"text_id\"`. */\n foreignKey: string;\n /** Human-readable name for the child resource. */\n name?: string;\n /** Display title for the child resource. */\n title?: string;\n /** Primary key field name on the child model. */\n idField?: string;\n /** Primary key type on the child model. */\n idType?: 'string' | 'number';\n /** View schemas (table/form/view) for the child resource. */\n views?: Record<string, ViewConfig>;\n /** Enabled operations on the child resource. */\n operations?: Partial<\n Record<'findAll' | 'findOne' | 'create' | 'update' | 'delete', boolean>\n >;\n /** Actions declared in the child resource.json (serializable form, no procedure functions). */\n actions?: JsonAction[];\n /** Modal width when opening a form for this sub-resource. */\n modalSize?: 'xs' | 'sm' | 'lg' | 'xl';\n /** Relations to include when querying this sub-resource. Supports nested includes — see `JsonIncludeEntry`. */\n include?: JsonIncludeEntry[];\n /** Calculated columns to compute and merge for each row of this sub-resource. */\n calculatedColumns?: CalculatedColumn[];\n /** When true, the relation is included in findOne responses (column is visible in form or view). */\n includeInFindOne?: boolean;\n /** Lifecycle hooks for this sub-resource (beforeWrite, afterRead). */\n hooks?: ResourceHooks;\n /** Columns serialized as `{ value, label }` on read / unwrapped on write. */\n valueLabelColumns?: ValueLabelColumn[];\n};\n\nexport type ResourceConfig = {\n name: string;\n route: string;\n model: string;\n tag: string;\n title?: string;\n /** Primary key field name on the model. Defaults to `\"id\"`. */\n idField?: string;\n idType?: 'number' | 'string';\n database?: string;\n sidebar?: { hide?: boolean; position?: number };\n hooks?: ResourceHooks;\n definition: ResourceDefinition | DefinitionCallback;\n views?: Record<string, ViewConfig>;\n lookup?: LookupConfig;\n subResources?: SubResourceConfig[];\n calculatedColumns?: CalculatedColumn[];\n actions?: ResourceAction[];\n /** Global table-level actions (no record id). Shown as toolbar buttons. */\n tableActions?: ResourceTableAction[];\n /** Relations to eagerly include when querying this resource. Supports nested includes — see `JsonIncludeEntry`. */\n include?: JsonIncludeEntry[];\n /** Modal width when opening a form for this resource. */\n modalSize?: 'xs' | 'sm' | 'lg' | 'xl';\n /** Columns serialized as `{ value, label }` on read / unwrapped on write. */\n valueLabelColumns?: ValueLabelColumn[];\n display: ResourceDisplay;\n};\n\n// ─── helpers ────────────────────────────────────────────────────────────────\n\nexport const resolveDefinition = (\n config: ResourceConfig,\n): ResourceDefinition => {\n const def = config.definition;\n return typeof def === 'function' ? def() : def;\n};\n\nexport const isOperationEnabled = (\n def: ResourceDefinition,\n op: CrudOperation,\n): boolean => def[op] != null;\n\nexport const schemaFor = (\n def: ResourceDefinition,\n op: CrudOperation,\n): SchemaInput | undefined => {\n const entry = def[op];\n if (!entry || entry === true) return undefined;\n return (entry as { schema?: SchemaInput }).schema;\n};\n\nexport const upsertOnFor = (\n def: ResourceDefinition,\n): string | string[] | undefined => def.upsert?.upsertOn;\n","import { NotFoundException } from '@nestjs/common';\n\nimport { Operator, type OperatorType, buildSort, toValueLabel } from '@ghentcdh/crouton-core';\n\nimport type { ReadOp, ResourceConfig, SubResourceConfig, ValueLabelColumn } from './crud.config';\nimport type { RequestDto } from './request.dto';\nimport { buildChildSortClause, buildIncludeClause, mergeCalculatedColumnsForRows } from './sql.helpers';\n\n// FilterOperator (OperatorType) and Operator list are imported from @ghentcdh/crouton-core\n\n/**\n * Parse a filter string of the form `field:value:operator`.\n * The last segment is treated as the operator only when it matches a known value.\n * Values that contain colons are handled correctly (everything between the first and last colon is the value).\n * Defaults to `contains` when no recognised operator is present.\n */\nexport const parseFilterString = (\n raw: string,\n): { field: string; value: string; operator: OperatorType } | null => {\n const parts = raw.split(':');\n if (parts.length < 2 || !parts[0]) return null;\n\n const field = parts[0];\n const lastPart = parts[parts.length - 1];\n const hasOperator = (Operator as readonly string[]).includes(lastPart);\n\n const value = hasOperator ? parts.slice(1, -1).join(':') : parts.slice(1).join(':');\n const operator: OperatorType = hasOperator ? (lastPart as OperatorType) : 'contains';\n\n return { field, value, operator };\n};\n\n/**\n * Build a nested Prisma condition object from a dot-separated field path.\n * `\"author.name\"` → `{ author: { name: condition } }`\n */\nconst buildNestedPath = (path: string[], condition: unknown): Record<string, unknown> => {\n if (path.length === 1) return { [path[0]]: condition };\n const [head, ...rest] = path;\n return { [head]: buildNestedPath(rest, condition) };\n};\n\n/**\n * Separator marking a JSON (jsonb) column path in a filter key.\n * `\"date_range->from\"` targets the `from` key inside the `date_range` json column.\n */\nconst JSON_PATH_SEP = '->';\n\nconst isJsonPath = (field: string): boolean => field.includes(JSON_PATH_SEP);\n\n/**\n * Build a Prisma JSON-filter `where` fragment for a jsonb sub-path, e.g.\n * `date_range->from` + `gt` → `{ date_range: { path: ['from'], gt: value } }`.\n *\n * Values are kept as strings: ISO-8601 dates compare lexicographically, which\n * is the same as chronological order, so no casting is needed for `gt`/`lt`.\n * Returns `null` for operators that have no meaningful JSON-path mapping.\n */\nconst buildJsonPathCondition = (\n field: string,\n value: string,\n operator: OperatorType,\n): Record<string, unknown> | null => {\n const [column, ...path] = field.split(JSON_PATH_SEP);\n if (!column || path.length === 0) return null;\n const frag = (extra: Record<string, unknown>) => ({ [column]: { path, ...extra } });\n\n switch (operator) {\n case 'equals':\n return frag({ equals: value });\n case 'not_equals':\n return frag({ not: value });\n case 'gt':\n return frag({ gt: value });\n case 'lt':\n return frag({ lt: value });\n case 'contains':\n return frag({ string_contains: value });\n case 'not_contains':\n return { NOT: frag({ string_contains: value }) };\n // isnull/isnotnull on a json sub-path are not supported — filter on the\n // whole column instead if you need an emptiness check.\n default:\n return null;\n }\n};\n\n/**\n * Map a parsed operator + value to a Prisma field condition.\n * Numeric coercion is applied for `gt` and `lt`.\n */\nconst operatorToCondition = (value: string, operator: OperatorType): unknown => {\n const num = Number(value);\n const numVal = Number.isNaN(num) ? value : num;\n\n switch (operator) {\n case 'contains':\n return { contains: value };\n case 'not_contains':\n return { not: { contains: value } };\n case 'equals':\n return { equals: value };\n case 'not_equals':\n return { not: value };\n case 'gt':\n return { gt: numVal };\n case 'lt':\n return { lt: numVal };\n case 'isnull':\n return null;\n case 'isnotnull':\n return { not: null };\n default:\n return undefined;\n }\n};\n\n/**\n * Build a Prisma `where` clause from an array of filter strings.\n * Returns `undefined` (no filter) when the array is empty or all entries are unparseable.\n */\nexport const buildFilterWhere = (\n filter: string[] | undefined,\n): Record<string, unknown> | undefined => {\n if (!filter?.length) return undefined;\n\n const conditions = filter\n .map(parseFilterString)\n .filter((f): f is NonNullable<typeof f> => f !== null)\n .map(({ field, value, operator }) =>\n isJsonPath(field)\n ? buildJsonPathCondition(field, value, operator)\n : buildNestedPath(field.split('.'), operatorToCondition(value, operator)),\n )\n .filter((c): c is Record<string, unknown> => c !== null);\n\n return conditions.length ? { AND: conditions } : undefined;\n};\n\n/**\n * Drop a trailing `.label` from a sort path when it targets a value-label\n * column — the label is a serialization envelope, not a DB field, so sorting\n * must fall back to the underlying scalar (e.g. `text_type.label` → `text_type`,\n * `author.origin.label` → `author.origin`). Real columns named `label` are not\n * affected: only paths whose value-label field sits right before `.label`.\n */\nexport const sanitizeValueLabelSort = (\n sort: string | undefined,\n cols: ValueLabelColumn[] | undefined,\n): string | undefined => {\n if (!sort || !cols?.length || !sort.endsWith('.label')) return sort;\n const base = sort.slice(0, -'.label'.length);\n const leaf = base.split('.').pop();\n return cols.some((c) => c.field === base || c.field === leaf) ? base : sort;\n};\n\n/**\n * Sanitize a sub-resource `orderBy` field so Prisma never rejects it:\n *\n * - A nested path (`author.origin_name`) is kept as-is — Prisma builds a nested\n * `orderBy` and validates the leaf against the related model.\n * - A single segment must be a real **scalar/enum** field of the child model\n * (the Prisma field-reference API, `model.fields`, lists exactly those — not\n * object relations). A bare relation name (`author`) or a computed/aliased\n * column id is NOT orderable on its own and would throw\n * (`Expected …OrderByWithRelationInput, provided String`), so it is dropped.\n * - This also covers join tables (composite PK, no `id`): the frontend's default\n * `id` isn't a scalar field, so it's dropped instead of crashing.\n *\n * When the model exposes no field metadata we can't validate, so we trust the\n * caller (e.g. mocked models in tests).\n */\nexport const orderableChildSort = (\n sort: string | undefined,\n childModel: any,\n _sub: SubResourceConfig,\n): string | undefined => {\n if (!sort) return undefined;\n const scalarFields = new Set(\n Object.keys((childModel?.fields ?? {}) as Record<string, unknown>),\n );\n if (scalarFields.size === 0) return sort; // no metadata → trust the caller\n // Nested relation path: Prisma builds a valid nested orderBy.\n if (sort.includes('.')) return sort;\n // Single segment must be an orderable scalar/enum field of the child.\n return scalarFields.has(sort) ? sort : undefined;\n};\n\n/** Wrap configured columns of a row as `{ value, label }`. Returns a shallow copy. */\nexport const applyValueLabelColumns = (\n row: any,\n cols: ValueLabelColumn[] | undefined,\n): any => {\n if (!row || !cols?.length) return row;\n const out = { ...row };\n for (const { field, values } of cols) {\n if (field in out) out[field] = toValueLabel(out[field], values);\n }\n return out;\n};\n\n/**\n * Handles all read operations for a resource — list, count, detail, and sub-resource queries.\n *\n * Constructed by `createCrudRepository`; instantiate directly only in tests.\n *\n * @param prismaModel - The Prisma delegate for the resource's model (e.g. `prisma.text`).\n * @param prisma - Full PrismaClient, used for sub-resource queries and calculated columns.\n * @param config - Resource config including model name, idType, hooks, and sub-resources.\n * @param listSelect - Prisma `select` clause for list queries, derived from the `findAll` schema. `undefined` = select all.\n * @param oneSelect - Prisma `select` clause for detail queries. Falls back to `listSelect` when absent.\n */\nexport class ReadRepository<T = any> {\n constructor(\n private readonly prismaModel: any,\n private readonly prisma: any,\n private readonly config: ResourceConfig,\n private readonly listSelect: Record<string, any> | undefined,\n private readonly oneSelect: Record<string, any> | undefined,\n ) {}\n\n private toId(id: string | number): string | number {\n return (this.config.idType ?? 'string') === 'number' ? +id : String(id);\n }\n\n private buildWhere(filter: string[] | undefined) {\n return buildFilterWhere(filter);\n }\n\n private projection(op: 'findAll' | 'findOne') {\n const select = op === 'findAll' ? this.listSelect : this.oneSelect;\n return select ? { select } : {};\n }\n\n private safeSort(sort: string | undefined, sortDir: string | undefined) {\n if (!sort) return undefined;\n if (this.listSelect && !(sort in this.listSelect)) return undefined;\n return buildSort(sort, sortDir);\n }\n\n private async decorate(rows: any[], op: ReadOp): Promise<any[]> {\n const hook = this.config.hooks?.afterRead;\n const hooked = hook\n ? await Promise.all(rows.map((row) => hook(row, { prisma: this.prisma, op })))\n : rows;\n const cols = this.config.valueLabelColumns;\n return cols?.length ? hooked.map((r) => applyValueLabelColumns(r, cols)) : hooked;\n }\n\n private async decorateOne(row: any, op: ReadOp): Promise<any> {\n // Note: the `{ value, label }` envelope is applied on list reads only.\n // findOne feeds the form/detail view, where the select control maps the\n // stored scalar to its label itself and submits the scalar back.\n const hook = this.config.hooks?.afterRead;\n return hook ? hook(row, { prisma: this.prisma, op }) : row;\n }\n\n /**\n * Fetch a paginated, sorted, and filtered list of records.\n * Sub-resource counts are merged onto each row; calculated columns are resolved via raw SQL.\n */\n async findAll(params: RequestDto): Promise<T[]> {\n const subResources = this.config.subResources ?? [];\n const projection = this.projection('findAll');\n\n let query: Record<string, any> = {\n where: this.buildWhere(params.filter),\n take: params.pageSize,\n skip: (params as any).offset ?? (params.page - 1) * params.pageSize,\n orderBy: this.safeSort(\n sanitizeValueLabelSort(params.sort, this.config.valueLabelColumns),\n params.sortDir,\n ),\n };\n\n if (subResources.length) {\n const countClause = {\n select: Object.fromEntries(subResources.map((s) => [s.relation, true])),\n };\n if (projection.select) {\n query.select = { ...projection.select, _count: countClause };\n } else {\n query = { ...query, _count: countClause };\n }\n } else {\n Object.assign(query, projection);\n }\n\n const rows = await this.prismaModel.findMany(query);\n\n const mapped = subResources.length\n ? rows.map((row: any) => {\n const { _count, ...rest } = row;\n if (!_count) return rest;\n const counts = Object.fromEntries(\n subResources.map((s) => [s.column, _count[s.relation] ?? 0]),\n );\n return { ...rest, ...counts };\n })\n : rows;\n\n const withCalc = await mergeCalculatedColumnsForRows(\n mapped,\n this.config.calculatedColumns ?? [],\n this.config.model,\n this.prisma,\n );\n return this.decorate(withCalc, 'findAll');\n }\n\n /** Count records matching the given filter strings. */\n count(filter: string[]): Promise<number> {\n return this.prismaModel.count({ where: this.buildWhere(filter) });\n }\n\n /**\n * Fetch a single record by id.\n * Sub-resources with `includeInFindOne: true` are eagerly loaded (flat).\n * `config.include` entries are loaded with full nesting via `buildIncludeClause`.\n * @throws {NotFoundException} When no record exists for the given id.\n */\n async findOne(id: number | string): Promise<T> {\n const formIncludes = (this.config.subResources ?? [])\n .filter((s) => s.includeInFindOne)\n .map((s) => s.relation);\n\n const projection = this.projection('findOne');\n const idField = this.config.idField ?? 'id';\n const query: Record<string, any> = {\n where: { [idField]: this.toId(id) },\n ...projection,\n };\n\n // Merge flat sub-resource includes (includeInFindOne) with nested config.include\n const flatIncludes = formIncludes.length\n ? Object.fromEntries(formIncludes.map((r) => [r, true]))\n : undefined;\n const configInclude = buildIncludeClause(this.config.include);\n const mergedInclude =\n flatIncludes || configInclude\n ? { ...flatIncludes, ...configInclude }\n : undefined;\n\n if (mergedInclude) {\n if (projection.select) {\n query.select = { ...projection.select, ...mergedInclude };\n } else {\n query.include = mergedInclude;\n }\n }\n\n const record = await this.prismaModel.findUnique(query);\n if (!record)\n throw new NotFoundException(\n `${this.config.name} with id ${id} not found`,\n );\n const [withCalc] = await mergeCalculatedColumnsForRows(\n [record],\n this.config.calculatedColumns ?? [],\n this.config.model,\n this.prisma,\n );\n\n // Enrich nested sub-resource arrays with their own calculated columns.\n // e.g. text.text_metadata items need metadata's calculatedColumns applied.\n let enriched: any = withCalc ?? record;\n for (const sub of this.config.subResources ?? []) {\n if (!sub.calculatedColumns?.length) continue;\n const nested = enriched[sub.relation];\n if (!Array.isArray(nested) || !nested.length) continue;\n const enrichedNested = await mergeCalculatedColumnsForRows(\n nested,\n sub.calculatedColumns,\n sub.childModel,\n this.prisma,\n );\n enriched = { ...enriched, [sub.relation]: enrichedNested };\n }\n\n return this.decorateOne(enriched, 'findOne');\n }\n\n /**\n * Fetch a paginated list of child records belonging to the given parent.\n * @param childRoute - Matches the `childRoute` key on a `SubResourceConfig`.\n * @throws {Error} When no matching sub-resource config or Prisma model is found.\n */\n async findAllByParent(\n parentId: string | number,\n childRoute: string,\n params: RequestDto,\n ): Promise<{ data: T[]; count: number }> {\n const sub = (this.config.subResources ?? []).find(\n (s) => s.childRoute === childRoute,\n );\n if (!sub)\n throw new Error(\n `No sub-resource \"${childRoute}\" on \"${this.config.name}\"`,\n );\n\n const childModel = this.prisma[sub.childModel];\n if (!childModel)\n throw new Error(`Prisma model \"${sub.childModel}\" not found`);\n\n const where = {\n ...this.buildWhere(params.filter),\n [sub.foreignKey]: this.toId(parentId),\n };\n const includeClause = buildIncludeClause(sub.include);\n const childSort = orderableChildSort(\n sanitizeValueLabelSort(params.sort, sub.valueLabelColumns),\n childModel,\n sub,\n );\n\n const [data, count] = await Promise.all([\n childModel.findMany({\n where,\n take: params.pageSize,\n skip: (params as any).offset ?? (params.page - 1) * params.pageSize,\n orderBy: childSort ? buildChildSortClause(childSort, params.sortDir) : undefined,\n ...(includeClause && { include: includeClause }),\n }),\n childModel.count({ where }),\n ]);\n\n const withCalc = sub.calculatedColumns?.length\n ? await mergeCalculatedColumnsForRows(\n data,\n sub.calculatedColumns,\n sub.childModel,\n this.prisma,\n )\n : data;\n\n const decorated = sub.hooks?.afterRead\n ? await Promise.all(\n withCalc.map((row: any) =>\n sub.hooks!.afterRead!(row, { prisma: this.prisma, op: 'findAll' }),\n ),\n )\n : withCalc;\n\n const labeled = sub.valueLabelColumns?.length\n ? decorated.map((r: any) => applyValueLabelColumns(r, sub.valueLabelColumns))\n : decorated;\n return { data: labeled, count };\n }\n\n /**\n * Fetch a single child record. When `parentId` is supplied the query also filters by the foreign key.\n * @throws {NotFoundException} When no matching record is found.\n */\n async findOneChild(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n ): Promise<any> {\n const childModel = this.prisma[sub.childModel];\n if (!childModel)\n throw new Error(`Prisma model \"${sub.childModel}\" not found`);\n\n const id =\n (sub.idType ?? 'string') === 'number' ? +childId : String(childId);\n const idField = sub.idField ?? 'id';\n const where: Record<string, unknown> = { [idField]: id };\n if (parentId !== undefined) where[sub.foreignKey] = this.toId(parentId);\n\n const includeClause = buildIncludeClause(sub.include);\n const record = await childModel.findFirst({\n where,\n ...(includeClause && { include: includeClause }),\n });\n if (!record)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n\n const [withCalc] = sub.calculatedColumns?.length\n ? await mergeCalculatedColumnsForRows(\n [record],\n sub.calculatedColumns,\n sub.childModel,\n this.prisma,\n )\n : [record];\n\n // findOne (single child) keeps the scalar — see decorateOne.\n if (sub.hooks?.afterRead)\n return sub.hooks.afterRead(withCalc, { prisma: this.prisma, op: 'findOne' });\n return withCalc;\n }\n}\n","import { buildSort } from '@ghentcdh/crouton-core';\n\nimport type { CalculatedColumn, JsonIncludeEntry } from './loader/json-config.types';\n\n// ── SQL expression helpers ────────────────────────────────────────────────\n\n/** Wrap a column's SQL expression with the appropriate CAST for its type. */\nconst castExpression = (col: CalculatedColumn): string => {\n if (col.type === 'string') return `(${col.sqlExpression})`;\n if (col.type === 'boolean') return `CAST((${col.sqlExpression}) AS BOOLEAN)`;\n return `CAST((${col.sqlExpression}) AS INTEGER)`;\n};\n\n/** Default value for a column type when a SQL query fails or returns null. */\nconst defaultValueForType = (col: CalculatedColumn): unknown => {\n if (col.type === 'boolean') return false;\n if (col.type === 'string') return null;\n return 0;\n};\n\n/** Coercion function for the column's type. */\nconst coerceColumnValue = (col: CalculatedColumn) => {\n if (col.type === 'boolean') return (v: any) => Boolean(v);\n if (col.type === 'string') return (v: any) => (v === undefined || v === null ? null : String(v));\n return (v: any) => Number(v ?? 0);\n};\n\n/** Build the parameterised SQL for one calculated column query. */\nconst buildCalculatedColumnSql = (col: CalculatedColumn, tableName: string, ids: unknown[]): string => {\n const alias = col.alias ?? col.id;\n const placeholders = ids.map((_, i) => `$${i + 1}`).join(', ');\n return `SELECT main.id, ${castExpression(col)} AS \"${alias}\" FROM \"${tableName}\" main WHERE main.id IN (${placeholders})`;\n};\n\n// ── Public helpers ────────────────────────────────────────────────────────\n\n/**\n * Run raw SQL for each calculated column and merge results onto rows by id.\n * Each `sqlExpression` may reference the row via the alias `main`.\n */\nexport const mergeCalculatedColumnsForRows = async (\n rows: any[],\n calcCols: CalculatedColumn[],\n tableName: string,\n prisma: any,\n): Promise<any[]> => {\n if (!calcCols.length || !rows.length) return rows;\n\n const ids = rows.map((r) => r.id);\n const results = await Promise.all(\n calcCols.map(async (col) => {\n const alias = col.alias ?? col.id;\n const sql = buildCalculatedColumnSql(col, tableName, ids);\n const defaultValue = defaultValueForType(col);\n const coerce = coerceColumnValue(col);\n try {\n const calcRows: any[] = await prisma.$queryRawUnsafe(sql, ...ids);\n return {\n id: col.id,\n defaultValue,\n map: Object.fromEntries(calcRows.map((r) => [String(r.id), coerce(r[alias])])),\n };\n } catch (e) {\n console.error(`[calculatedColumns] Failed for \"${tableName}.${col.id}\":`, e);\n return { id: col.id, defaultValue, map: {} };\n }\n }),\n );\n\n return rows.map((row) => {\n const extra: Record<string, unknown> = {};\n for (const { id, defaultValue, map } of results) {\n extra[id] = map[String(row.id)] ?? defaultValue;\n }\n return { ...row, ...extra };\n });\n};\n\n/**\n * Build a Prisma `include` clause from an array of `JsonIncludeEntry` values.\n *\n * Supports three forms:\n * - Plain string: `\"author\"` → `{ author: true }`\n * - Dotted string: `\"author.internal_author\"` → `{ author: { include: { internal_author: true } } }`\n * - Object: `{ relation: \"author\", include: [\"internal_author\"] }` → same as above\n *\n * Multiple entries for the same relation are merged:\n * `[\"author\", \"author.internal_author\"]`\n * → `{ author: { include: { internal_author: true } } }`\n */\nexport const buildIncludeClause = (include: JsonIncludeEntry[] | undefined): Record<string, unknown> | undefined => {\n if (!include?.length) return undefined;\n\n // Normalise every entry to { relation, nestedIncludes[], orderBy? }\n const map = new Map<string, JsonIncludeEntry[]>();\n const orderByMap = new Map<string, Record<string, unknown>>();\n\n for (const entry of include) {\n if (typeof entry === 'string') {\n const dotIdx = entry.indexOf('.');\n if (dotIdx === -1) {\n // Plain relation — only add if nothing more specific already exists\n if (!map.has(entry)) map.set(entry, []);\n } else {\n // Dotted path: \"author.internal_author\" → relation \"author\", nested \"internal_author\"\n const relation = entry.slice(0, dotIdx);\n const rest = entry.slice(dotIdx + 1) as JsonIncludeEntry;\n map.set(relation, [...(map.get(relation) ?? []), rest]);\n }\n } else {\n // Object form: { relation, include[], orderBy? }\n map.set(entry.relation, [...(map.get(entry.relation) ?? []), ...(entry.include ?? [])]);\n if (entry.orderBy) orderByMap.set(entry.relation, entry.orderBy);\n }\n }\n\n return Object.fromEntries(\n Array.from(map.entries()).map(([relation, nestedIncludes]) => {\n const orderBy = orderByMap.get(relation);\n if (!nestedIncludes.length && !orderBy) return [relation, true];\n const nested = buildIncludeClause(nestedIncludes);\n const clause: Record<string, unknown> = {};\n if (nested) clause.include = nested;\n if (orderBy) clause.orderBy = orderBy;\n return [relation, clause];\n }),\n );\n};\n\n/**\n * Build Prisma `orderBy` supporting dotted paths like `\"author.origin\"`.\n * Plain names delegate to the standard `buildSort` helper.\n */\nexport const buildChildSortClause = (\n sort: string,\n sortDir: string | undefined,\n): Record<string, unknown> => {\n const parts = sort.split('.');\n if (parts.length === 1) return buildSort(sort, sortDir) as Record<string, unknown>;\n const dir = (sortDir ?? 'asc') as 'asc' | 'desc';\n return parts.reduceRight<Record<string, unknown>>(\n (acc, part, i) => (i === parts.length - 1 ? { [part]: dir } : { [part]: acc }),\n {},\n );\n};\n","import { ZodObject, type ZodRawShape, type ZodType, toJSONSchema, z } from 'zod';\n\nimport { type JsonSchemaInput, type SchemaInput } from './crud.config';\n\ntype ToJSONSchemaParams = NonNullable<Parameters<typeof toJSONSchema>[1]>;\ntype OverrideContext = Parameters<NonNullable<ToJSONSchemaParams['override']>>[0];\n\n/** Post-process override: patch date schemas to `{ type: \"string\", format: \"date-time\" }`. */\nconst dateOverride = ({ zodSchema, jsonSchema }: OverrideContext) => {\n if (zodSchema instanceof z.ZodDate) {\n jsonSchema.type = 'string';\n jsonSchema.format = 'date-time';\n }\n};\n\nexport const jsonSchemaOpts = {\n unrepresentable: 'any' as const,\n override: dateOverride,\n};\n\nexport function isZodSchema(\n schema: SchemaInput,\n): schema is ZodObject<ZodRawShape> {\n return schema instanceof ZodObject;\n}\n\n/** A property is nullable when its `anyOf` contains a `{ type: \"null\" }` branch. */\nconst isNullableProperty = (property: unknown): boolean => {\n const anyOf = (property as Record<string, unknown>)?.['anyOf'];\n return (\n Array.isArray(anyOf) &&\n anyOf.some((s: Record<string, unknown>) => s?.['type'] === 'null')\n );\n};\n\n/** Nullable fields are treated as optional: drop them from `required` (keeping the null branch). */\nconst dropNullableFromRequired = (jsonSchema: Record<string, any>): void => {\n const { properties, required } = jsonSchema;\n if (!properties || !Array.isArray(required)) return;\n jsonSchema.required = required.filter(\n (key: string) => !isNullableProperty(properties[key]),\n );\n};\n\n/** Returns a plain JSON Schema object for Swagger / AJV */\nexport function toJsonSchema(schema: SchemaInput): JsonSchemaInput {\n if (isZodSchema(schema)) {\n const jsonSchema = toJSONSchema(schema, {\n target: 'openApi3',\n ...jsonSchemaOpts,\n }) as Record<string, any>;\n dropNullableFromRequired(jsonSchema);\n return jsonSchema as JsonSchemaInput;\n }\n return schema;\n}\n\n/**\n * Strip wrapping types (`optional`, `nullable`, `default`, `readonly`)\n * to get at the actual underlying zod type.\n */\nconst unwrap = (schema: ZodType): ZodType => {\n let s: any = schema;\n let t: string | undefined = s?._zod?.def?.type;\n while (\n t === 'optional' ||\n t === 'nullable' ||\n t === 'default' ||\n t === 'readonly'\n ) {\n s = s._zod.def.innerType;\n t = s?._zod?.def?.type;\n }\n return s as ZodType;\n};\n\nconst typeOf = (schema: ZodType): string | undefined =>\n (schema as any)?._zod?.def?.type;\n\n/**\n * Build a Prisma-compatible `select` tree from a zod schema. Scalar\n * fields become `true`; nested objects (and arrays of objects) become\n * `{ select: { ... } }` so relations are loaded in one query.\n *\n * For non-zod (raw) JSON schemas we fall back to a flat top-level select.\n */\nexport function toSelectFields(schema: SchemaInput): Record<string, any> {\n if (!isZodSchema(schema)) {\n return Object.keys(schema.properties).reduce<Record<string, any>>(\n (acc, key) => {\n acc[key] = true;\n return acc;\n },\n {},\n );\n }\n\n const result: Record<string, any> = {};\n for (const [key, value] of Object.entries(schema.shape)) {\n const inner = unwrap(value as ZodType);\n const t = typeOf(inner);\n\n if (t === 'object') {\n result[key] = { select: toSelectFields(inner as ZodObject<ZodRawShape>) };\n continue;\n }\n\n if (t === 'array') {\n const element = unwrap((inner as any)._zod.def.element);\n if (typeOf(element) === 'object') {\n result[key] = {\n select: toSelectFields(element as ZodObject<ZodRawShape>),\n };\n continue;\n }\n }\n\n result[key] = true;\n }\n return result;\n}\n","import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport { fromValueLabel } from '@ghentcdh/crouton-core';\n\nimport { DEFAULT_ID_FIELD, PRISMA_NOT_FOUND_CODE } from './constants';\nimport type { ResourceConfig, SubResourceConfig, ValueLabelColumn, WriteOp } from './crud.config';\nimport { resolveDefinition, upsertOnFor } from './crud.config';\nimport type { JsonIncludeEntry } from './loader/json-config.types';\n\n/** Unwrap `{ value, label }` fields back to their scalar before persistence. */\nconst normalizeValueLabels = (data: unknown, cols: ValueLabelColumn[] | undefined): unknown => {\n if (!data || typeof data !== 'object' || Array.isArray(data) || !cols?.length) return data;\n const out = { ...(data as Record<string, unknown>) };\n for (const { field } of cols) {\n if (field in out) out[field] = fromValueLabel(out[field]);\n }\n return out;\n};\n\n/** Extract the top-level relation names from a `JsonIncludeEntry[]` (for payload stripping). */\nconst includeRelationNames = (include: JsonIncludeEntry[] | undefined): Set<string> =>\n new Set((include ?? []).map((e) => (typeof e === 'string' ? e : e.relation)));\n\n/**\n * Handles all write operations for a resource — create, update, upsert, delete, and child mutations.\n *\n * Sub-resource count columns are stripped from payloads before writing.\n * `beforeWrite` hooks are invoked (when configured) prior to every Prisma call.\n * Prisma `P2025` (record not found) errors are mapped to `NotFoundException`.\n */\nexport class WriteRepository<T = any> {\n constructor(\n private readonly prismaModel: any,\n private readonly prisma: any,\n private readonly config: ResourceConfig,\n ) {}\n\n private toId(id: string | number): string | number {\n return (this.config.idType ?? 'string') === 'number' ? +id : String(id);\n }\n\n private notFound(id: string | number): NotFoundException {\n return new NotFoundException(`${this.config.name} with id ${id} not found`);\n }\n\n private stripSubResourceKeys(data: unknown): unknown {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const subKeys = new Set((this.config.subResources ?? []).map((s) => s.column));\n if (!subKeys.size) return data;\n return Object.fromEntries(\n Object.entries(data as Record<string, unknown>).filter(([k]) => !subKeys.has(k)),\n );\n }\n\n private stripNonCreateableChildFields(data: unknown, sub: SubResourceConfig): unknown {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const nonCreateable = new Set<string>(\n (sub.views?.form?.columns ?? [])\n .filter((c) => (c as any).createable === false)\n .map((c) => c.id),\n );\n if (!nonCreateable.size) return data;\n return Object.fromEntries(\n Object.entries(data as Record<string, unknown>).filter(([k]) => !nonCreateable.has(k)),\n );\n }\n\n private async prepare(data: any, op: WriteOp, id?: string | number): Promise<any> {\n const normalized = normalizeValueLabels(data, this.config.valueLabelColumns);\n const hook = this.config.hooks?.beforeWrite;\n return hook ? hook(normalized, { prisma: this.prisma, op, id }) : normalized;\n }\n\n private async postWrite(result: any, op: WriteOp, id?: string | number): Promise<any> {\n const hook = this.config.hooks?.afterWrite;\n return hook ? hook(result, { prisma: this.prisma, op, id }) : result;\n }\n\n private upsertWhere(data: any): Record<string, unknown> {\n const keys = upsertOnFor(resolveDefinition(this.config));\n if (!keys) throw new BadRequestException(`${this.config.name} has no upsertOn configured`);\n if (typeof keys === 'string') return { [keys]: data[keys] };\n const composite = keys.join('_');\n return { [composite]: Object.fromEntries(keys.map((k) => [k, data[k]])) };\n }\n\n async create(data: unknown): Promise<T> {\n const result = await this.prismaModel.create({\n data: await this.prepare(this.stripSubResourceKeys(data), 'create'),\n });\n return this.postWrite(result, 'create');\n }\n\n async update(id: number | string, data: unknown): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n const result = await this.prismaModel.update({\n where: { [idField]: this.toId(id) },\n data: await this.prepare(this.stripSubResourceKeys(data), 'update', this.toId(id)),\n });\n return this.postWrite(result, 'update', this.toId(id));\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n async upsert(data: unknown): Promise<T> {\n const where = this.upsertWhere(data);\n const existing = await this.prismaModel.findFirst({ where });\n const op: WriteOp = existing ? 'update' : 'create';\n const prepared = await this.prepare(this.stripSubResourceKeys(data), op, existing ? existing[this.config.idField ?? DEFAULT_ID_FIELD] : undefined);\n const result = await this.prismaModel.upsert({ where, create: prepared, update: prepared });\n return this.postWrite(result, op, existing ? existing[this.config.idField ?? DEFAULT_ID_FIELD] : undefined);\n }\n\n /** Upsert multiple rows in parallel. */\n upsertMany(rows: unknown[]): Promise<T[]> {\n return Promise.all(rows.map((r) => this.upsert(r)));\n }\n\n async delete(id: number | string): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n const result = await this.prismaModel.delete({ where: { [idField]: this.toId(id) } });\n return this.postWrite(result, 'delete', this.toId(id));\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n /**\n * Create a child record and attach it to the parent via the configured foreign key.\n * Fields marked `createable: false` in the form view are stripped before writing.\n */\n async createChild(parentId: string | number, sub: SubResourceConfig, data: unknown): Promise<any> {\n const childModel = this.prisma[sub.childModel];\n if (!childModel) throw new Error(`Prisma model \"${sub.childModel}\" not found`);\n\n const stripped = this.stripNonCreateableChildFields(data, sub);\n const normalized = normalizeValueLabels(stripped, sub.valueLabelColumns) as object;\n const payload = { ...normalized, [sub.foreignKey]: this.toId(parentId) };\n const prepared = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(payload, { prisma: this.prisma, op: 'create' })\n : payload;\n\n const includeKeys = includeRelationNames(sub.include);\n const prismaData = {\n ...Object.fromEntries(\n Object.entries(prepared as Record<string, unknown>).filter(([k]) => !includeKeys.has(k)),\n ),\n [sub.foreignKey]: this.toId(parentId),\n };\n const result = await childModel.create({ data: prismaData });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, { prisma: this.prisma, op: 'create' })\n : result;\n }\n\n /**\n * Update a child record. Relation include-keys are stripped from the payload so Prisma doesn't\n * receive non-scalar fields.\n * @throws {NotFoundException} When the child record does not exist (Prisma P2025).\n */\n async updateChild(sub: SubResourceConfig, childId: string | number, data: unknown): Promise<any> {\n const childModel = this.prisma[sub.childModel];\n if (!childModel) throw new Error(`Prisma model \"${sub.childModel}\" not found`);\n\n const id = (sub.idType ?? 'string') === 'number' ? +childId : String(childId);\n const normalized = normalizeValueLabels(data, sub.valueLabelColumns);\n const afterHook = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(normalized, { prisma: this.prisma, op: 'update', id })\n : normalized;\n\n const includeKeys = includeRelationNames(sub.include);\n const prepared = Object.fromEntries(\n Object.entries(afterHook as Record<string, unknown>).filter(([k]) => !includeKeys.has(k)),\n );\n try {\n const result = await childModel.update({ where: { [sub.idField ?? DEFAULT_ID_FIELD]: id }, data: prepared });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, { prisma: this.prisma, op: 'update', id })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw new NotFoundException(`${sub.childRoute} with id ${childId} not found`);\n throw e;\n }\n }\n\n /**\n * Delete a child record. When `parentId` is supplied the foreign key is included in the `where`\n * clause to prevent cross-parent deletions.\n * @throws {NotFoundException} When no matching record is found.\n */\n async deleteChild(sub: SubResourceConfig, childId: string | number, parentId?: string | number): Promise<any> {\n const childModel = this.prisma[sub.childModel];\n if (!childModel) throw new Error(`Prisma model \"${sub.childModel}\" not found`);\n\n const id = (sub.idType ?? 'string') === 'number' ? +childId : String(childId);\n const idField = sub.idField ?? 'id';\n const where: Record<string, unknown> = { [idField]: id };\n if (parentId !== undefined) where[sub.foreignKey] = this.toId(parentId);\n\n try {\n const result = await childModel.deleteMany({ where });\n if (result.count === 0) throw new NotFoundException(`${sub.childRoute} with id ${childId} not found`);\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, { prisma: this.prisma, op: 'delete', id })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw new NotFoundException(`${sub.childRoute} with id ${childId} not found`);\n throw e;\n }\n }\n}\n","// ── Route segments ────────────────────────────────────────────────────────\n\n/** Static route segments registered before any :id route. */\nexport const ROUTE_DEFINITION = 'definition';\nexport const ROUTE_SCHEMAS = 'schemas';\nexport const ROUTE_RESOURCE_JSON = 'resource.json';\nexport const ROUTE_PROCEDURE = 'procedure';\n\n// ── HTTP methods ──────────────────────────────────────────────────────────\n\nexport const HTTP_GET = 'get';\nexport const HTTP_POST = 'post';\nexport const HTTP_PATCH = 'patch';\nexport const HTTP_DELETE = 'delete';\n\n// ── Field formats ─────────────────────────────────────────────────────────\n\nexport const FORMAT_RELATION = 'relation';\n\n// ── Prisma ────────────────────────────────────────────────────────────────\n\n/** Prisma error code for \"record not found\". */\nexport const PRISMA_NOT_FOUND_CODE = 'P2025';\n\n// ── UI defaults ───────────────────────────────────────────────────────────\n\nexport const DEFAULT_COLSPAN = 12;\nexport const DEFAULT_ID_TYPE = 'string';\nexport const DEFAULT_ID_FIELD = 'id';\n","\nimport type { ResourceConfig, SubResourceConfig } from './crud.config';\nimport { resolveDefinition, schemaFor } from './crud.config';\nimport { ReadRepository } from './read.repository';\nimport type { RequestDto } from './request.dto';\nimport { toSelectFields } from './schema.utils';\nimport { WriteRepository } from './write.repository';\n\n/** Unified read/write interface for a CRUD resource, combining `ReadRepository` and `WriteRepository`. */\nexport interface CrudRepository<T = any> {\n /** Raw Prisma client — used by action procedures. */\n readonly prisma: any;\n findAll(params: RequestDto): Promise<T[]>;\n count(filter: string[]): Promise<number>;\n findOne(id: number | string): Promise<T>;\n findAllByParent(parentId: string | number, childRoute: string, params: RequestDto): Promise<{ data: T[]; count: number }>;\n findOneChild(sub: SubResourceConfig, childId: string | number, parentId?: string | number): Promise<T>;\n createChild(parentId: string | number, sub: SubResourceConfig, data: unknown): Promise<T>;\n updateChild(sub: SubResourceConfig, childId: string | number, data: unknown): Promise<T>;\n deleteChild(sub: SubResourceConfig, childId: string | number, parentId?: string | number): Promise<T>;\n create(data: unknown): Promise<T>;\n update(id: number | string, data: unknown): Promise<T>;\n upsert(data: unknown): Promise<T>;\n upsertMany(rows: unknown[]): Promise<T[]>;\n delete(id: number | string): Promise<T>;\n}\n\n/**\n * Construct a `CrudRepository` by wiring a `ReadRepository` and `WriteRepository` together.\n *\n * The `findAll`/`findOne` schemas are used to derive Prisma `select` clauses so only the\n * columns the view needs are fetched.\n *\n * @param prisma - Full PrismaClient instance.\n * @param config - Resource config. `config.model` must match a key on the PrismaClient.\n * @throws {Error} When `config.model` is not found on the provided PrismaClient.\n */\nexport function createCrudRepository<T = any>(\n prisma: any,\n config: ResourceConfig,\n): CrudRepository<T> {\n const model = prisma[config.model];\n if (!model) {\n throw new Error(\n `Model \"${config.model}\" not found on the provided PrismaClient. ` +\n `Check the resource config for \"${config.name}\".`,\n );\n }\n\n const definition = resolveDefinition(config);\n const listSchema = schemaFor(definition, 'findAll');\n const oneSchema = schemaFor(definition, 'findOne');\n const listSelect = listSchema ? toSelectFields(listSchema) : undefined;\n const oneSelect = oneSchema ? toSelectFields(oneSchema) : listSelect;\n\n const reader = new ReadRepository<T>(model, prisma, config, listSelect, oneSelect);\n const writer = new WriteRepository<T>(model, prisma, config);\n\n return {\n prisma,\n findAll: reader.findAll.bind(reader),\n count: reader.count.bind(reader),\n findOne: reader.findOne.bind(reader),\n findAllByParent: reader.findAllByParent.bind(reader),\n findOneChild: reader.findOneChild.bind(reader),\n create: writer.create.bind(writer),\n update: writer.update.bind(writer),\n upsert: writer.upsert.bind(writer),\n upsertMany: writer.upsertMany.bind(writer),\n delete: writer.delete.bind(writer),\n createChild: writer.createChild.bind(writer),\n updateChild: writer.updateChild.bind(writer),\n deleteChild: writer.deleteChild.bind(writer),\n };\n}\n","import { Injectable, type OnModuleDestroy } from '@nestjs/common';\n\nimport type { DataSourceEntry } from './data-source.types';\n\n@Injectable()\nexport class DataSourceRegistry implements OnModuleDestroy {\n private readonly clients = new Map<string, any>();\n private defaultName: string | undefined;\n\n constructor(entries: DataSourceEntry[]) {\n for (const entry of entries) {\n this.clients.set(entry.config.name, entry.client);\n if (entry.config.default) {\n this.defaultName = entry.config.name;\n }\n }\n // If no explicit default, use the first entry.\n if (!this.defaultName && entries.length > 0) {\n this.defaultName = entries[0].config.name;\n }\n }\n\n get(name: string): any {\n const client = this.clients.get(name);\n if (!client) {\n throw new Error(`Data source \"${name}\" not found in registry`);\n }\n return client;\n }\n\n getDefault(): any {\n if (!this.defaultName) {\n throw new Error('No default data source configured');\n }\n return this.get(this.defaultName);\n }\n\n resolve(database?: string): any {\n return database ? this.get(database) : this.getDefault();\n }\n\n async onModuleDestroy() {\n for (const client of this.clients.values()) {\n if (typeof client.$disconnect === 'function') {\n await client.$disconnect();\n }\n }\n }\n}\n","import type { DataSourceEntry, DataSourceJsonConfig } from './data-source.types';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\n\n/**\n * Scan a directory for data-source subdirectories and load their configs + clients.\n *\n * Each subdirectory must contain:\n * - `data-source.json` — config with `name`, `type`, and optional `default`\n * - `index.ts` (or `.js`) — default export of a PrismaClient instance\n */\nexport const loadDataSourcesFromDir = async (\n dirPath: string,\n): Promise<DataSourceEntry[]> => {\n if (!existsSync(dirPath)) return [];\n\n const entries = readdirSync(dirPath, { withFileTypes: true });\n const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);\n const results: DataSourceEntry[] = [];\n\n for (const dir of dirs) {\n const basePath = join(dirPath, dir);\n const jsonFile = join(basePath, 'data-source.json');\n\n if (!existsSync(jsonFile)) continue;\n\n const config: DataSourceJsonConfig = JSON.parse(\n readFileSync(jsonFile, 'utf-8'),\n );\n\n const indexFile = findModule(basePath, 'index');\n if (!indexFile) continue;\n\n const mod = await import(indexFile);\n const client = mod.default;\n if (!client) continue;\n\n results.push({ config, client });\n }\n\n return results;\n};\n\nconst findModule = (dir: string, name: string): string | undefined => {\n for (const ext of ['.ts', '.js']) {\n const p = join(dir, `${name}${ext}`);\n if (existsSync(p)) return p;\n }\n return undefined;\n};\n","import { Param, Post } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { ResourceProcedureAction, ResourceTableProcedureAction } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\n\n/**\n * Register a `POST /procedure/{action.id}/:recordId` route for each non-link action\n * declared in the resource config.\n */\nexport const registerActionRoutes = (ctx: OperationContext): void => {\n const { cls, config } = ctx;\n const { name } = config;\n const procedureActions = (config.actions ?? []).filter(\n (a): a is ResourceProcedureAction => a.type !== 'link',\n );\n\n for (const action of procedureActions) {\n const methodName = `procedure_${action.id}`;\n def(cls, methodName, async function (this: { repo: CrudRepository }, recordId: string) {\n return action.procedure(this.repo.prisma, recordId);\n });\n const d = desc(cls, methodName);\n Post(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);\n Param('recordId')(cls.prototype, methodName, 0);\n ApiOperation({ summary: `Execute action \"${action.label}\" on a ${name}` })(cls.prototype, methodName, d);\n ApiParam({ name: 'recordId', type: 'string' })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `Action \"${action.id}\" result` })(cls.prototype, methodName, d);\n }\n};\n\n/**\n * Register a `POST /table-action/{action.id}` route for each non-link table-level action.\n * Unlike row-level procedure routes, these take no `:recordId` parameter.\n */\nexport const registerTableActionRoutes = (ctx: OperationContext): void => {\n const { cls, config } = ctx;\n const { name } = config;\n const procedureActions = (config.tableActions ?? []).filter(\n (a): a is ResourceTableProcedureAction => a.type !== 'link',\n );\n\n for (const action of procedureActions) {\n const methodName = `tableAction_${action.id}`;\n def(cls, methodName, async function (this: { repo: CrudRepository }) {\n return action.procedure(this.repo.prisma);\n });\n const d = desc(cls, methodName);\n Post(`table-action/${action.id}`)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Execute table action \"${action.label ?? action.id}\" on ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `Table action \"${action.id}\" result` })(cls.prototype, methodName, d);\n }\n};\n","/** Dynamically define a method on a class prototype. */\nexport const def = (cls: any, method: string, fn: (...args: any[]) => any): void => {\n Object.defineProperty(cls.prototype, method, {\n value: fn,\n writable: true,\n configurable: true,\n });\n};\n\n/** Get the property descriptor for a method just defined via `def()`. */\nexport const desc = (cls: any, method: string): PropertyDescriptor =>\n Object.getOwnPropertyDescriptor(cls.prototype, method)!;\n","import { Delete, Get, Param, Patch, Post, Put, Query } from '@nestjs/common';\nimport {\n ApiBody,\n type ApiBodyOptions,\n ApiNotFoundResponse,\n ApiOperation,\n ApiParam,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled } from '../crud.config';\nimport { RequestDtoNoOffset } from '../request.dto';\nimport { toJsonSchema } from '../schema.utils';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\n\n/** Swagger's SchemaObject is not exported from the package root — derive it from ApiBodyOptions. */\ntype SchemaObject = NonNullable<Extract<ApiBodyOptions, { schema?: unknown }>['schema']>;\n\n/**\n * Register `GET /` with pagination, sorting, filtering, and optional `?q=` lookup search.\n * No-ops when `findAll` is disabled in the resource config.\n */\nexport const registerFindAll = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'findAll')) return;\n const { cls, config, listSchema } = ctx;\n const { name } = config;\n const lookupLabel = config.lookup?.label;\n\n def(cls, 'findAll', async function (this: { repo: CrudRepository }, params: any, q?: string) {\n const effectiveParams = { ...params };\n if (q && lookupLabel) {\n effectiveParams.filter = [...(params.filter ?? []), `${lookupLabel}:${q}`];\n }\n const [data, count] = await Promise.all([\n this.repo.findAll(effectiveParams),\n this.repo.count(effectiveParams.filter),\n ]);\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: { count, page: params.page, pageSize: params.pageSize, totalPages, sort: params.sort, sortDir: params.sortDir, filter: params.filter },\n };\n });\n const d = desc(cls, 'findAll');\n Get()(cls.prototype, 'findAll', d);\n Query(new ZodValidationPipe(RequestDtoNoOffset.zodSchema as any))(cls.prototype, 'findAll', 0);\n Query('q')(cls.prototype, 'findAll', 1);\n ApiOperation({ summary: `List all ${name}s` })(cls.prototype, 'findAll', d);\n ApiResponse({\n status: 200,\n description: `Array of ${name}`,\n ...(listSchema && { schema: { type: 'array', items: toJsonSchema(listSchema) } }),\n })(cls.prototype, 'findAll', d);\n};\n\n/** Register `GET /:id`. No-ops when `findOne` is disabled. */\nexport const registerFindOne = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'findOne')) return;\n const { cls, config, oneSchema, idParamMeta } = ctx;\n const { name } = config;\n\n def(cls, 'findOne', function (this: { repo: CrudRepository }, id: string) {\n return this.repo.findOne(id);\n });\n const d = desc(cls, 'findOne');\n Get(':id')(cls.prototype, 'findOne', d);\n Param('id')(cls.prototype, 'findOne', 0);\n ApiOperation({ summary: `Get one ${name} by id` })(cls.prototype, 'findOne', d);\n ApiParam(idParamMeta)(cls.prototype, 'findOne', d);\n ApiResponse({\n status: 200,\n description: `The ${name}`,\n ...(oneSchema && { schema: toJsonSchema(oneSchema) }),\n })(cls.prototype, 'findOne', d);\n ApiNotFoundResponse({ description: 'Not found' })(cls.prototype, 'findOne', d);\n};\n\n/** Register `POST /`. Applies Zod body validation when the create schema is a Zod schema. No-ops when `create` is disabled. */\nexport const registerCreate = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'create')) return;\n const { cls, config, createSchema, bodyDecorator } = ctx;\n const { name } = config;\n\n def(cls, 'create', function (this: { repo: CrudRepository }, body: any) {\n return this.repo.create(body);\n });\n const d = desc(cls, 'create');\n Post()(cls.prototype, 'create', d);\n bodyDecorator(createSchema, { coerceNullableUndefinedToNull: true })(cls.prototype, 'create', 0);\n ApiOperation({ summary: `Create a ${name}` })(cls.prototype, 'create', d);\n if (createSchema) ApiBody({ schema: toJsonSchema(createSchema) as SchemaObject })(cls.prototype, 'create', d);\n ApiResponse({ status: 201, description: `${name} created` })(cls.prototype, 'create', d);\n};\n\n/** Register `PATCH /:id`. Applies Zod body validation when the update schema is a Zod schema. No-ops when `update` is disabled. */\nexport const registerUpdate = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'update')) return;\n const { cls, config, updateSchema, idParamMeta, bodyDecorator } = ctx;\n const { name } = config;\n\n def(cls, 'update', function (this: { repo: CrudRepository }, id: string, body: any) {\n return this.repo.update(id, body);\n });\n const d = desc(cls, 'update');\n Patch(':id')(cls.prototype, 'update', d);\n Param('id')(cls.prototype, 'update', 0);\n bodyDecorator(updateSchema)(cls.prototype, 'update', 1);\n ApiOperation({ summary: `Update a ${name}` })(cls.prototype, 'update', d);\n ApiParam(idParamMeta)(cls.prototype, 'update', d);\n if (updateSchema) ApiBody({ schema: toJsonSchema(updateSchema) as SchemaObject })(cls.prototype, 'update', d);\n ApiResponse({ status: 200, description: `${name} updated` })(cls.prototype, 'update', d);\n ApiNotFoundResponse({ description: 'Not found' })(cls.prototype, 'update', d);\n};\n\n/** Register `PUT /` for create-or-update. The `upsertOn` key(s) from the config determine the uniqueness constraint. No-ops when `upsert` is disabled. */\nexport const registerUpsert = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'upsert')) return;\n const { cls, config, upsertSchema, bodyDecorator } = ctx;\n const { name } = config;\n\n def(cls, 'upsert', function (this: { repo: CrudRepository }, body: any) {\n return this.repo.upsert(body);\n });\n const d = desc(cls, 'upsert');\n Put()(cls.prototype, 'upsert', d);\n bodyDecorator(upsertSchema, { coerceNullableUndefinedToNull: true })(cls.prototype, 'upsert', 0);\n ApiOperation({ summary: `Upsert a ${name}` })(cls.prototype, 'upsert', d);\n if (upsertSchema) ApiBody({ schema: toJsonSchema(upsertSchema) as SchemaObject })(cls.prototype, 'upsert', d);\n ApiResponse({ status: 200, description: `${name} upserted` })(cls.prototype, 'upsert', d);\n};\n\n/** Register `DELETE /:id`. No-ops when `delete` is disabled. */\nexport const registerDelete = (ctx: OperationContext): void => {\n if (!isOperationEnabled(ctx.definition, 'delete')) return;\n const { cls, config, idParamMeta } = ctx;\n const { name } = config;\n\n def(cls, 'delete', function (this: { repo: CrudRepository }, id: string) {\n return this.repo.delete(id);\n });\n const d = desc(cls, 'delete');\n Delete(':id')(cls.prototype, 'delete', d);\n Param('id')(cls.prototype, 'delete', 0);\n ApiOperation({ summary: `Delete a ${name}` })(cls.prototype, 'delete', d);\n ApiParam(idParamMeta)(cls.prototype, 'delete', d);\n ApiResponse({ status: 200, description: `${name} deleted` })(cls.prototype, 'delete', d);\n ApiNotFoundResponse({ description: 'Not found' })(cls.prototype, 'delete', d);\n};\n","import { createZodDto } from '@anatine/zod-nestjs';\n\nimport { RequestSchema, RequestSchemaWithOffset } from '@ghentcdh/crouton-core';\n\nexport class RequestDtoNoOffset extends createZodDto(RequestSchema) {}\nexport class RequestDto extends createZodDto(RequestSchemaWithOffset) {}\n","import { type PipeTransform } from '@nestjs/common';\nimport { type ZodError, type ZodObject, type ZodRawShape, type ZodType } from 'zod';\n\nimport { CroutonValidationError } from './crouton-validation.error';\n\nexport interface ZodValidationPipeOptions {\n /**\n * Coerce `undefined` → `null` on top-level fields that accept `null`.\n * Use for create/upsert: once nullable fields are optional in the JSON\n * Schema the client may omit them, and an omitted nullable field should be\n * stored as `null` rather than rejected. Do NOT use for PATCH/update, where\n * an omitted field means \"leave unchanged\".\n */\n coerceNullableUndefinedToNull?: boolean;\n}\n\nexport class ZodValidationPipe implements PipeTransform {\n /** Top-level field names that accept `null` (i.e. are nullable). */\n private readonly nullableKeys: readonly string[];\n /** Whether to coerce `undefined` → `null` on nullable fields (create/upsert only). */\n private readonly coerceUndefinedToNull: boolean;\n\n constructor(\n private readonly schema: ZodObject<ZodRawShape>,\n options: ZodValidationPipeOptions = {},\n ) {\n // Always compute nullable keys — needed for \"\" → null coercion in stripEmptyStrings\n this.nullableKeys = Object.entries(schema.shape)\n .filter(([, field]) => (field as ZodType).safeParse(null).success)\n .map(([key]) => key);\n this.coerceUndefinedToNull = options.coerceNullableUndefinedToNull ?? false;\n }\n\n transform(value: unknown) {\n const stripped = this.stripEmptyStrings(value);\n const input = this.coerceNullable(stripped);\n const result = this.schema.safeParse(input);\n if (!result.success) {\n throw new CroutonValidationError(this.formatErrors(result.error));\n }\n return result.data;\n }\n\n /**\n * Convert empty strings (`''`) on all top-level fields:\n * - Nullable fields (`z.string().nullable()`): `\"\"` → `null`\n * (clearing a nullable field should store null, not fail validation)\n * - Required/optional fields (`z.string()` / `z.string().optional()`): `\"\"` → `undefined`\n * (required → fails with invalid_type; optional → passes as absent)\n */\n private stripEmptyStrings(value: unknown): unknown {\n if (value == null || typeof value !== 'object' || Array.isArray(value)) {\n return value;\n }\n const out = { ...(value as Record<string, unknown>) };\n for (const key of Object.keys(out)) {\n if (out[key] === '') {\n out[key] = this.nullableKeys.includes(key) ? null : undefined;\n }\n }\n return out;\n }\n\n /** Replace `undefined` with `null` on nullable fields (create/upsert only). */\n private coerceNullable(value: unknown): unknown {\n if (\n !this.coerceUndefinedToNull ||\n value == null ||\n typeof value !== 'object' ||\n Array.isArray(value)\n ) {\n return value;\n }\n const out = { ...(value as Record<string, unknown>) };\n for (const key of this.nullableKeys) {\n if (out[key] === undefined) out[key] = null;\n }\n return out;\n }\n\n private formatErrors(error: ZodError) {\n return error.issues.map((e) => ({\n field: e.path.join('.'),\n message: e.message,\n }));\n }\n}\n","import { Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { IS_DEV } from '../dev-mode';\nimport { type ResourceConfigRegistry } from '../resource-config.registry';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport {\n buildDefinitionPayload,\n buildResourceJsonPayload,\n buildViewsPayload,\n} from './payload-builders';\n\n/**\n * Register `GET /definition` — returns the resource's enabled operations and JSON Schemas.\n * In dev mode the response is rebuilt from the live config registry on every request.\n */\nexport const registerDefinitionEndpoint = (ctx: OperationContext): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n const definitionPayload = buildDefinitionPayload(config);\n\n def(cls, 'getDefinition', async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (IS_DEV) {\n const fresh = await this.configRegistry.getByRoute(route);\n if (fresh) return buildDefinitionPayload(fresh);\n }\n return definitionPayload;\n });\n const d = desc(cls, 'getDefinition');\n Get('definition')(cls.prototype, 'getDefinition', d);\n ApiOperation({ summary: `Get the resource definition for ${name}` })(cls.prototype, 'getDefinition', d);\n ApiResponse({ status: 200, description: `Definition (operations + schemas) for ${name}` })(cls.prototype, 'getDefinition', d);\n};\n\n/**\n * Register `GET /schemas` — returns view schemas (table/form) for the resource.\n * In dev mode the response is rebuilt from the live config registry on every request.\n */\nexport const registerSchemasEndpoint = (ctx: OperationContext): void => {\n const { cls, config, baseUrl } = ctx;\n const { route, name } = config;\n const viewsPayload = buildViewsPayload(config, baseUrl);\n\n def(cls, 'getSchemas', async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (IS_DEV) {\n const fresh = await this.configRegistry.getByRoute(route);\n if (fresh) return buildViewsPayload(fresh, baseUrl) ?? viewsPayload;\n }\n return viewsPayload;\n });\n const d = desc(cls, 'getSchemas');\n Get('schemas')(cls.prototype, 'getSchemas', d);\n ApiOperation({ summary: `Get view schemas (table/form) for ${name}` })(cls.prototype, 'getSchemas', d);\n ApiResponse({ status: 200, description: `View schemas for ${name}` })(cls.prototype, 'getSchemas', d);\n};\n\n/**\n * Register `GET /resource.json` — returns the compact resource descriptor used by the frontend.\n * In dev mode the response is rebuilt from the live config registry on every request.\n */\nexport const registerResourceJsonEndpoint = (ctx: OperationContext): void => {\n const { cls, config, baseUrl } = ctx;\n const { route, name } = config;\n const resourceJsonPayload = buildResourceJsonPayload(config, baseUrl);\n\n def(cls, 'getResourceJson', async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (IS_DEV) {\n const fresh = await this.configRegistry.getByRoute(route);\n if (fresh) return buildResourceJsonPayload(fresh, baseUrl);\n }\n return resourceJsonPayload;\n });\n const d = desc(cls, 'getResourceJson');\n Get('resource.json')(cls.prototype, 'getResourceJson', d);\n ApiOperation({ summary: `Get resource descriptor for ${name}` })(cls.prototype, 'getResourceJson', d);\n ApiResponse({ status: 200, description: `Resource descriptor (operations + JSON Schema) for ${name}` })(cls.prototype, 'getResourceJson', d);\n};\n","import {\n type ResourceConfig,\n isOperationEnabled,\n resolveDefinition,\n schemaFor,\n upsertOnFor,\n} from '../crud.config';\nimport { toJsonSchema } from '../schema.utils';\n\n// ── Internal helpers ──────────────────────────────────────────────────────\n\n/**\n * Replace `{env.VAR_NAME}` placeholders with `process.env.VAR_NAME`.\n * Unknown variables are left as-is.\n */\nexport const resolveEnvPlaceholders = (value: string): string =>\n value.replace(\n /\\{env\\.([^}]+)\\}/g,\n (match, varName) => process.env[varName] ?? match,\n );\n\n/**\n * Build an operations map for a sub-resource with full URIs.\n * `baseUri` is the collection endpoint, e.g. `http://host/text/{id}/content`.\n */\nexport const buildSubResourceOperations = (\n ops:\n | Partial<\n Record<'findAll' | 'findOne' | 'create' | 'update' | 'delete', boolean>\n >\n | undefined,\n baseUri: string,\n idField = 'id',\n): Record<string, unknown> => {\n if (!ops) return {};\n const idPlaceholder = `{${idField}}`;\n return {\n ...(ops.findAll && { findAll: { uri: baseUri, method: 'get' } }),\n ...(ops.findOne && {\n findOne: { uri: `${baseUri}/${idPlaceholder}`, method: 'get' },\n }),\n ...(ops.create && { create: { uri: baseUri, method: 'post' } }),\n ...(ops.update && {\n update: { uri: `${baseUri}/${idPlaceholder}`, method: 'patch' },\n }),\n ...(ops.delete && {\n delete: { uri: `${baseUri}/${idPlaceholder}`, method: 'delete' },\n }),\n };\n};\n\nconst RESOURCE_OPS = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'delete',\n] as const;\ntype ResourceOp = (typeof RESOURCE_OPS)[number];\n\nconst OP_METHOD: Record<ResourceOp, string> = {\n findAll: 'get',\n findOne: 'get',\n create: 'post',\n update: 'patch',\n delete: 'delete',\n};\nconst OP_SUFFIX: Record<ResourceOp, string> = {\n findAll: '',\n findOne: '/{id}',\n create: '',\n update: '/{id}',\n delete: '/{id}',\n};\n\n/** Build an operations map for a top-level resource with full URIs. */\nexport const buildResourceOperations = (\n definition: ReturnType<typeof resolveDefinition>,\n baseUri: string,\n): Record<string, unknown> =>\n Object.fromEntries(\n RESOURCE_OPS.filter((op) => isOperationEnabled(definition, op)).map(\n (op) => [\n op,\n { uri: `${baseUri}${OP_SUFFIX[op]}`, method: OP_METHOD[op] },\n ],\n ),\n );\n\n// ── Public payload builders ───────────────────────────────────────────────\n\n/** Build the payload for `GET /definition` — enabled operations and their JSON Schemas. */\nexport const buildDefinitionPayload = (\n config: ResourceConfig,\n): Record<string, unknown> => {\n const { route, name, tag, idType = 'string' } = config;\n const definition = resolveDefinition(config);\n const listSchema = schemaFor(definition, 'findAll');\n const oneSchema = schemaFor(definition, 'findOne') ?? listSchema;\n const createSchema = schemaFor(definition, 'create');\n const updateSchema = schemaFor(definition, 'update');\n const upsertSchema = schemaFor(definition, 'upsert') ?? createSchema;\n\n const operations = (\n ['findAll', 'findOne', 'create', 'update', 'upsert', 'delete'] as const\n ).filter((op) => isOperationEnabled(definition, op));\n\n return {\n name,\n route,\n idType,\n tag,\n operations,\n upsertOn: upsertOnFor(definition),\n schemas: {\n ...(listSchema && { findAll: toJsonSchema(listSchema) }),\n ...(oneSchema && { findOne: toJsonSchema(oneSchema) }),\n ...(createSchema && { create: toJsonSchema(createSchema) }),\n ...(updateSchema && { update: toJsonSchema(updateSchema) }),\n ...(isOperationEnabled(definition, 'upsert') && upsertSchema\n ? { upsert: toJsonSchema(upsertSchema) }\n : {}),\n },\n };\n};\n\n/** Build the payload for `GET /resource.json` — URI, enabled operations, and optional form schema. */\nexport const buildResourceJsonPayload = (\n config: ResourceConfig,\n baseUrl?: string,\n): Record<string, unknown> => {\n const { name, route } = config;\n const definition = resolveDefinition(config);\n const uri = `${baseUrl}/${route}`;\n const operations: any = Object.fromEntries(\n RESOURCE_OPS.map((op) => [op, isOperationEnabled(definition, op)]),\n );\n operations.lookup = `${uri}?q={text}`;\n\n const form = config.views?.['form'];\n const schema = form?.json_schema\n ? { data: form.json_schema, ui: form.ui_schema }\n : null;\n\n return { id: name, uri, operations, schema };\n};\n\n/**\n * Build the payload for `GET /schemas` — view schemas (table/form), operations, and actions.\n * Returns `undefined` when the resource has no views configured.\n */\nexport const buildViewsPayload = (\n config: ResourceConfig,\n baseUrl?: string,\n): Record<string, unknown> | undefined => {\n if (!config.views || !Object.keys(config.views).length) return undefined;\n const definition = resolveDefinition(config);\n const baseUri = `${baseUrl}/${config.route}`;\n const operations: Record<string, unknown> = buildResourceOperations(\n definition,\n baseUri,\n );\n if (isOperationEnabled(definition, 'findAll')) {\n operations['lookup'] = `${baseUri}?q={text}`;\n }\n const schemas = Object.fromEntries(\n Object.entries(config.views).map(([key, v]) => [\n key,\n {\n data: v.json_schema,\n ui: v.ui_schema,\n ...(v.defaultSort !== undefined && { defaultSort: v.defaultSort }),\n },\n ]),\n );\n return {\n id: config.name,\n name: config.name,\n route: config.route,\n uri: `${baseUrl}/${config.route}`,\n title: config.title ?? config.tag,\n idField: config.lookup?.key ?? 'id',\n idType: config.idType ?? 'string',\n ...(config.modalSize && { modalSize: config.modalSize }),\n operations,\n display: config.display,\n schemas,\n ...(config.actions?.length && {\n actions: config.actions.map((a) =>\n a.type === 'link'\n ? {\n type: 'link',\n id: a.id,\n label: a.label,\n href: resolveEnvPlaceholders(a.href),\n ...(a.condition && { condition: a.condition }),\n }\n : {\n id: a.id,\n label: a.label,\n uri: `${baseUrl}/${config.route}/procedure/${a.id}/{id}`,\n method: a.method ?? 'post',\n ...(a.data && { data: a.data }),\n ...(a.condition && { condition: a.condition }),\n },\n ),\n }),\n ...(config.tableActions?.length && {\n tableActions: config.tableActions.map((a) =>\n a.type === 'link'\n ? {\n type: 'link',\n id: a.id,\n label: a.label,\n icon: a.icon,\n tooltip: a.tooltip,\n href: resolveEnvPlaceholders(a.href),\n }\n : {\n id: a.id,\n label: a.label,\n icon: a.icon,\n tooltip: a.tooltip,\n uri: `${baseUrl}/${config.route}/table-action/${a.id}`,\n method: a.method ?? 'post',\n ...(a.data && { data: a.data }),\n },\n ),\n }),\n };\n};\n","import { Body, Delete, Get, Param, Patch, Post, Query } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { SubResourceConfig } from '../crud.config';\nimport { RequestDtoNoOffset } from '../request.dto';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport { buildSubResourceOperations, resolveEnvPlaceholders } from './payload-builders';\n\n// ── Sub-resource schemas endpoint ─────────────────────────────────────────\n\nconst registerSubResourceSchemas = (\n ctx: OperationContext,\n sub: SubResourceConfig,\n): void => {\n if (!sub.views) return;\n const { cls, config, baseUrl } = ctx;\n const { route } = config;\n const methodName = `getSchemas_${sub.childRoute}`;\n const childUri = `${baseUrl}/${route}/{parent.id}/${sub.childRoute}`;\n\n const schemasPayload = {\n id: sub.name ?? sub.childRoute,\n name: sub.name ?? sub.childRoute,\n route: sub.childRoute,\n uri: childUri,\n title: sub.title ?? sub.childRoute,\n idField: sub.idField ?? 'id',\n idType: sub.idType ?? 'string',\n ...(sub.modalSize && { modalSize: sub.modalSize }),\n operations: buildSubResourceOperations(sub.operations, childUri, sub.idField ?? 'id'),\n schemas: Object.fromEntries(\n Object.entries(sub.views).map(([key, v]) => [\n key,\n {\n data: v.json_schema,\n ui: v.ui_schema,\n ...(v.defaultSort !== undefined && { defaultSort: v.defaultSort }),\n },\n ]),\n ),\n ...(sub.actions?.length && {\n actions: sub.actions.map((a) =>\n a.type === 'link'\n ? { type: 'link', id: a.id, label: a.label, href: resolveEnvPlaceholders(a.href), ...(a.condition && { condition: a.condition }) }\n : {\n id: a.id,\n label: a.label,\n uri: `${baseUrl}/${sub.childRoute}/procedure/${a.id}/{id}`,\n method: a.method ?? 'post',\n ...(a.data && { data: a.data }),\n ...(a.condition && { condition: a.condition }),\n },\n ),\n }),\n };\n\n def(cls, methodName, async function () { return schemasPayload; });\n const ds = desc(cls, methodName);\n Get(`${sub.childRoute}/schemas`)(cls.prototype, methodName, ds);\n ApiOperation({ summary: `Get schemas for ${sub.childRoute}` })(cls.prototype, methodName, ds);\n ApiResponse({ status: 200, description: `View schemas for ${sub.childRoute}` })(cls.prototype, methodName, ds);\n};\n\n// ── Sub-resource CRUD routes ──────────────────────────────────────────────\n\nconst registerSubResourceFindAll = (ctx: OperationContext, sub: SubResourceConfig): void => {\n if (sub.operations?.findAll === false) return;\n const { cls, config } = ctx;\n const { name } = config;\n const idParamMeta = ctx.idParamMeta;\n const methodName = `findAllBy_${sub.childRoute}`;\n\n def(cls, methodName, async function (this: { repo: CrudRepository }, id: string, params: any) {\n const { data, count } = await this.repo.findAllByParent(id, sub.childRoute, params);\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: { count, page: params.page, pageSize: params.pageSize, totalPages, sort: params.sort, sortDir: params.sortDir, filter: params.filter },\n };\n });\n const d = desc(cls, methodName);\n Get(`:id/${sub.childRoute}`)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n Query(new ZodValidationPipe(RequestDtoNoOffset.zodSchema as any))(cls.prototype, methodName, 1);\n ApiOperation({ summary: `List ${sub.childRoute} for a ${name}` })(cls.prototype, methodName, d);\n ApiParam(idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${sub.childRoute} list` })(cls.prototype, methodName, d);\n};\n\nconst registerSubResourceCreate = (ctx: OperationContext, sub: SubResourceConfig): void => {\n if (!sub.operations?.create) return;\n const { cls, config } = ctx;\n const { name } = config;\n const methodName = `createChild_${sub.childRoute}`;\n\n def(cls, methodName, async function (this: { repo: CrudRepository }, id: string, body: any) {\n return this.repo.createChild(id, sub, body);\n });\n const d = desc(cls, methodName);\n Post(`:id/${sub.childRoute}`)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n Body()(cls.prototype, methodName, 1);\n ApiOperation({ summary: `Create ${sub.childRoute} for a ${name}` })(cls.prototype, methodName, d);\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 201, description: `${sub.childRoute} created` })(cls.prototype, methodName, d);\n};\n\nconst registerSubResourceFindOne = (ctx: OperationContext, sub: SubResourceConfig): void => {\n if (!sub.operations?.findOne) return;\n const { cls } = ctx;\n const methodName = `findOneChild_${sub.childRoute}`;\n\n def(cls, methodName, async function (this: { repo: CrudRepository }, parentId: string, childId: string) {\n return this.repo.findOneChild(sub, childId, parentId);\n });\n const d = desc(cls, methodName);\n Get(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n ApiOperation({ summary: `Get a ${sub.childRoute} record` })(cls.prototype, methodName, d);\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${sub.childRoute} record` })(cls.prototype, methodName, d);\n};\n\nconst registerSubResourceUpdate = (ctx: OperationContext, sub: SubResourceConfig): void => {\n if (!sub.operations?.update) return;\n const { cls } = ctx;\n const methodName = `updateChild_${sub.childRoute}`;\n\n def(cls, methodName, async function (this: { repo: CrudRepository }, _id: string, childId: string, body: any) {\n return this.repo.updateChild(sub, childId, body);\n });\n const d = desc(cls, methodName);\n Patch(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Body()(cls.prototype, methodName, 2);\n ApiOperation({ summary: `Update a ${sub.childRoute} record` })(cls.prototype, methodName, d);\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${sub.childRoute} updated` })(cls.prototype, methodName, d);\n};\n\nconst registerSubResourceDelete = (ctx: OperationContext, sub: SubResourceConfig): void => {\n if (!sub.operations?.delete) return;\n const { cls } = ctx;\n const methodName = `deleteChild_${sub.childRoute}`;\n\n def(cls, methodName, async function (this: { repo: CrudRepository }, parentId: string, childId: string) {\n return this.repo.deleteChild(sub, childId, parentId);\n });\n const d = desc(cls, methodName);\n Delete(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n ApiOperation({ summary: `Delete ${sub.childRoute} record` })(cls.prototype, methodName, d);\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${sub.childRoute} deleted` })(cls.prototype, methodName, d);\n};\n\n/** Register all routes for all sub-resources (schemas endpoint + CRUD). */\nexport const registerSubResourceRoutes = (ctx: OperationContext): void => {\n for (const sub of ctx.config.subResources ?? []) {\n registerSubResourceSchemas(ctx, sub);\n registerSubResourceFindAll(ctx, sub);\n registerSubResourceCreate(ctx, sub);\n registerSubResourceFindOne(ctx, sub);\n registerSubResourceUpdate(ctx, sub);\n registerSubResourceDelete(ctx, sub);\n }\n};\n","import { IS_DEV } from '../dev-mode';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\n\n// createRequire works in both CJS and ESM contexts, unlike bare `require`.\nconst _require = createRequire(import.meta.url);\n\n/** Find a module file by trying `.ts` then `.js` extensions. */\nexport const findModule = (dir: string, name: string): string | undefined => {\n for (const ext of ['.ts', '.js']) {\n const p = join(dir, `${name}${ext}`);\n if (existsSync(p)) return p;\n }\n return undefined;\n};\n\n/**\n * `true` when running inside Vite's module graph (dev server or SSR build).\n * The `?t=` cache-busting trick only works in Vite; in plain Node.js it\n * causes `import()` to throw because query strings aren't valid on file paths.\n */\nconst IS_VITE = typeof (globalThis as any).__vite_ssr_import__ === 'function';\n\n/** Dynamically import a default export, returning `undefined` on failure. */\nexport const importDefault = async <T>(filePath: string): Promise<T | undefined> => {\n try {\n if (IS_VITE) {\n // In Vite dev mode, bust the module cache so edits are picked up without\n // a full server restart. The ?t= trick only works inside Vite's resolver.\n const importPath = IS_DEV ? `${filePath}?t=${Date.now()}` : filePath;\n const mod = await import(importPath);\n return (mod.default ?? mod) as T;\n } else {\n // In CJS mode (nodemon + @swc-node/register), native import() goes\n // through Node's ESM loader which rejects .ts files. require() is\n // intercepted by @swc-node/register and handles .ts source correctly.\n // nodemon restarts the whole process on file changes, so no cache-busting\n // is needed here.\n \n const mod = _require(filePath) as { default?: T };\n return mod.default;\n }\n } catch {\n return undefined;\n }\n};\n","import type { JsonAction, JsonTableAction } from './json-config.types';\nimport type { ResourceAction, ResourceTableAction } from '../crud.config';\nimport { findModule, importDefault } from './module.loader';\nimport { join } from 'node:path';\n\n/**\n * Resolve each declared action into a `ResourceAction`:\n * - `type: \"link\"` actions pass through as-is (no file to load).\n * - Procedure actions import their function from `{basePath}/actions/{procedure}.ts`.\n */\nexport const loadActions = async (\n jsonActions: JsonAction[],\n basePath: string,\n): Promise<ResourceAction[]> => {\n const results: ResourceAction[] = [];\n for (const action of jsonActions) {\n if (action.type === 'link') {\n results.push({ type: 'link', id: action.id, label: action.label, href: action.href, ...(action.condition && { condition: action.condition }) });\n continue;\n }\n\n const file = findModule(join(basePath, 'actions'), action.procedure);\n if (!file) {\n console.warn(`[actions] Procedure file not found for \"${action.id}\" in ${basePath}/actions/`);\n continue;\n }\n const mod = await importDefault<(prisma: any, id: string | number) => Promise<any>>(file);\n if (!mod) {\n console.warn(`[actions] No default export in ${file}`);\n continue;\n }\n results.push({ id: action.id, label: action.label, method: action.method, data: action.data, ...(action.condition && { condition: action.condition }), procedure: mod });\n }\n return results;\n};\n\n/**\n * Resolve each declared table-level action into a `ResourceTableAction`:\n * - `type: \"link\"` actions pass through as-is.\n * - Procedure actions import their function from `{basePath}/actions/{procedure}.ts`.\n * The loaded function receives only `(prisma)` — no record id.\n */\nexport const loadTableActions = async (\n jsonActions: JsonTableAction[],\n basePath: string,\n): Promise<ResourceTableAction[]> => {\n const results: ResourceTableAction[] = [];\n for (const action of jsonActions) {\n if (action.type === 'link') {\n results.push({ type: 'link', id: action.id, label: action.label, icon: action.icon, tooltip: action.tooltip, href: action.href });\n continue;\n }\n\n const file = findModule(join(basePath, 'actions'), action.procedure);\n if (!file) {\n console.warn(`[tableActions] Procedure file not found for \"${action.id}\" in ${basePath}/actions/`);\n continue;\n }\n const mod = await importDefault<(prisma: any) => Promise<any>>(file);\n if (!mod) {\n console.warn(`[tableActions] No default export in ${file}`);\n continue;\n }\n results.push({ id: action.id, label: action.label, icon: action.icon, tooltip: action.tooltip, method: action.method, data: action.data, procedure: mod });\n }\n return results;\n};\n","/**\n * Project-level enum registry (`crouton.enums.json`): the single source of\n * `{ value, label }` option lists for enum columns. Columns reference an enum\n * by name (`JsonColumn.enum`); at load time the referenced list is injected\n * into `fieldInput.options.values`, so no column duplicates the labels.\n */\n\nimport type { JsonColumn } from './json-config.types';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n\nexport type EnumRegistry = Record<string, { value: unknown; label: string }[]>;\n\nconst ENUMS_FILE = 'crouton.enums.json';\n\n/**\n * Load the enum registry: an explicit `enumsFile` path if given, otherwise the\n * first `crouton.enums.json` found by walking up from `startDir` (the resources\n * dir). Returns `{}` when none exists.\n */\nexport const loadEnumRegistry = (startDir: string, enumsFile?: string): EnumRegistry => {\n let file = enumsFile;\n if (!file) {\n let dir = startDir;\n \n while (true) {\n const candidate = join(dir, ENUMS_FILE);\n if (existsSync(candidate)) {\n file = candidate;\n break;\n }\n const parent = dirname(dir);\n if (parent === dir) break;\n dir = parent;\n }\n }\n if (!file || !existsSync(file)) return {};\n try {\n return JSON.parse(readFileSync(file, 'utf-8')) as EnumRegistry;\n } catch {\n return {};\n }\n};\n\n/**\n * Inject registry option lists into columns that reference an enum by name.\n * Mutates each matching column's `fieldInput.options.values` (only when not\n * already present, so an inline override still wins).\n */\nexport const injectEnumValues = (\n columns: JsonColumn[] | undefined,\n enums: EnumRegistry,\n): void => {\n if (!columns) return;\n for (const col of columns) {\n if (!col.enum) continue;\n const values = enums[col.enum];\n if (!values) continue;\n col.fieldInput = col.fieldInput ?? { type: 'select' };\n const options = (col.fieldInput.options as Record<string, unknown> | undefined) ?? {};\n if (!('values' in options)) options.values = values;\n col.fieldInput.options = options;\n }\n};\n","import {\n ZodArray,\n ZodNullable,\n type ZodObject,\n ZodOptional,\n type ZodRawShape,\n} from 'zod';\n\nimport { type EnumRegistry, injectEnumValues } from './enum-registry';\nimport type {\n CalculatedColumn,\n JsonColumn,\n JsonIncludeEntry,\n JsonResourceConfig,\n RelationFieldInputOptions,\n RelationType,\n} from './json-config.types';\nimport { normalizeColumns } from './json-config.types';\nimport { buildChildSortClause } from '../sql.helpers';\nimport { opWithSchema, pickByColumns, upsertOp } from './schema.helpers';\nimport {\n buildViews,\n buildViewsFromColumns,\n injectCalculatedColumns,\n injectCalculatedColumnsToView,\n} from './view.builders';\nimport {\n type LookupConfig,\n type ResourceAction,\n type ResourceConfig,\n type ResourceDefinition,\n type ResourceDisplay,\n type ResourceHooks,\n type ResourceTableAction,\n type SubResourceConfig,\n type ValueLabelColumn,\n} from '../crud.config';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\ntype ResolvedChildResource = { json: JsonResourceConfig; dir: string };\n\n/**\n * Resolve `fieldInput.resource` (e.g. `\"./author.resource\"`) relative to the\n * parent resource's directory and return the child `resource.json` contents\n * AND the child's directory (needed so the child can resolve its own `extend` paths).\n *\n * Convention: `\"./author.resource\"` → sibling directory `author/resource.json`.\n */\nconst resolveChildResource = (\n resourcePath: string,\n parentDir: string,\n): ResolvedChildResource | undefined => {\n // Direct .json file reference (e.g. \"./resource.content.json\") — resolve relative to parentDir itself\n const directPath = resolve(parentDir, resourcePath);\n if (resourcePath.endsWith('.json') && existsSync(directPath)) {\n try {\n return {\n json: JSON.parse(\n readFileSync(directPath, 'utf-8'),\n ) as JsonResourceConfig,\n dir: dirname(directPath),\n };\n } catch {\n return undefined;\n }\n }\n\n // Directory convention: \"./author.resource\" → sibling dir \"author/resource.json\"\n const childName = resourcePath\n .replace(/^\\.\\//, '')\n .replace(/\\.resource$/, '');\n const childJsonPath = resolve(dirname(parentDir), childName, 'resource.json');\n if (!existsSync(childJsonPath)) return undefined;\n try {\n return {\n json: JSON.parse(\n readFileSync(childJsonPath, 'utf-8'),\n ) as JsonResourceConfig,\n dir: dirname(childJsonPath),\n };\n } catch {\n return undefined;\n }\n};\n\n/**\n * Expand columns that declare `extend` into virtual sub-columns derived from the\n * referenced resource.json.\n *\n * Each non-id column in the referenced resource becomes a virtual column:\n * id → `{extendColId}_{refColId}`\n * column → the extending column's `column` value (or its `id`)\n * displayKey → the referenced column's `displayKey` or its `id`\n * label → the referenced column's label\n *\n * Visibility is the union of the extending column's visibility and the referenced\n * column's own visibility — the more restrictive setting wins.\n * Optional `columns` map on the extending column lets you override individual sub-columns.\n */\nconst expandExtendColumns = (\n columns: JsonColumn[],\n dirPath: string | undefined,\n): JsonColumn[] => {\n if (!dirPath) return columns;\n\n const result: JsonColumn[] = [];\n for (const col of columns) {\n if (!col.extend) {\n result.push(col);\n continue;\n }\n\n const resolved = resolveChildResource(col.extend, dirPath);\n if (!resolved) {\n console.warn(\n `[extend] Could not resolve \"${col.extend}\" for column \"${col.id}\" — keeping as-is`,\n );\n result.push(col);\n continue;\n }\n\n const refColumns = normalizeColumns(resolved.json.columns) ?? [];\n const parentColumnKey = col.column ?? col.id;\n\n for (const refCol of refColumns) {\n // Skip primary key fields\n if (refCol.idField) continue;\n\n const virtualId = `${col.id}_${refCol.id}`;\n // When refCol has a displayKey (e.g. internal_author.displayKey = \"name\"), the value\n // lives at refCol.id.displayKey within the parent column object. Build the full dotted\n // path so scopes and table keys navigate correctly: \"internal_author.name\".\n // For plain scalar columns with no displayKey the path is just refCol.id.\n const displayKey = refCol.displayKey\n ? `${refCol.id}.${refCol.displayKey}`\n : refCol.id;\n\n // The more restrictive visibility wins (true = hidden beats false = visible)\n const hiddenInTable =\n col.hiddenInTable === true || refCol.hiddenInTable === true\n ? true\n : (col.hiddenInTable ?? refCol.hiddenInTable);\n const hiddenInForm =\n col.hiddenInForm === true || refCol.hiddenInForm === true\n ? true\n : (col.hiddenInForm ?? refCol.hiddenInForm);\n const hiddenInView =\n col.hiddenInView === true || refCol.hiddenInView === true\n ? true\n : (col.hiddenInView ?? refCol.hiddenInView);\n\n // Per-sub-column overrides keyed by virtual id or ref column id\n const override =\n col.columns?.[virtualId] ?? col.columns?.[refCol.id] ?? {};\n\n const virtualCol: JsonColumn = {\n id: virtualId,\n column: parentColumnKey,\n displayKey,\n label: refCol.label ?? refCol.id,\n columnType: 'object',\n ...(hiddenInTable !== undefined && { hiddenInTable }),\n ...(hiddenInForm !== undefined && { hiddenInForm }),\n ...(hiddenInView !== undefined && { hiddenInView }),\n ...(refCol.sortable != null && { sortable: refCol.sortable }),\n ...(refCol.fieldInput && { fieldInput: refCol.fieldInput }),\n ...override,\n };\n\n result.push(virtualCol);\n }\n }\n\n return result;\n};\n\n/**\n * Collect columns that should be serialized as `{ value, label }`: those whose\n * `fieldInput.options.emitObject` is true and that carry an `options.values`\n * list (typically enum/select columns).\n */\nconst buildValueLabelColumns = (\n columns: JsonColumn[] | undefined,\n): ValueLabelColumn[] =>\n (columns ?? []).flatMap((c) => {\n const opts = c.fieldInput?.options as\n | { emitObject?: boolean; values?: { value: unknown; label: string }[] }\n | undefined;\n if (!opts?.emitObject || !Array.isArray(opts.values)) return [];\n return [{ field: c.column ?? c.id, values: opts.values }];\n });\n\n/**\n * Default `fieldInput.format` to `\"relation\"` for columns that reference a\n * resource (`fieldInput.resource`) but declare no explicit `format` or control\n * `type`. Such a column is a relation by convention, e.g.:\n * `\"fieldInput\": { \"resource\": \"../bibliography/resource.json\", \"options\": { \"displayKey\": \"bib\" } }`\n * (A typed control that references a resource — `type: \"select\"`/`\"autocomplete\"` —\n * is left untouched.)\n */\nconst applyRelationFormatDefault = (\n cols: JsonColumn[] | undefined,\n): JsonColumn[] | undefined =>\n cols?.map((col) => {\n const fi = col.fieldInput;\n if (fi && fi.resource && !fi.format && !fi.type) {\n return { ...col, fieldInput: { ...fi, format: 'relation' } };\n }\n return col;\n });\n\n/**\n * Heuristic `relationType` for when no Zod schema is available (sub-resources):\n * a relation column with a sibling scalar foreign-key column (`<name>_id`) is a\n * single reference (`manyToOne`); otherwise it's a collection (`oneToMany`).\n */\nconst deriveRelationTypeFromColumns = (\n col: JsonColumn,\n cols: JsonColumn[],\n): RelationType => {\n const base = col.column ?? col.id;\n const fkNames = new Set([`${base}_id`, `${col.id}_id`]);\n return cols.some((c) => fkNames.has(c.id)) ? 'manyToOne' : 'oneToMany';\n};\n\n/**\n * Inject resource references (`uri`, `resourceUri`, `resource` = schemas URL)\n * into a sub-resource's own relation columns. `enrichActionColumns` only runs\n * for top-level resource columns, so a relation nested inside a sub-resource\n * (e.g. `text → text_author → author`) would otherwise have no way to fetch the\n * related form/list. These point at the related resource's standalone routes.\n */\nconst enrichNestedRelationColumns = (\n cols: JsonColumn[] | undefined,\n dir: string | undefined,\n baseUrl?: string,\n): JsonColumn[] | undefined => {\n if (!cols || !dir) return cols;\n const base = baseUrl ?? '';\n return cols.map((col) => {\n if (col.fieldInput?.format !== 'relation' || !col.fieldInput.resource)\n return col;\n const resolved = resolveChildResource(col.fieldInput.resource, dir);\n const targetRoute =\n resolved?.json?.route ??\n col.fieldInput.resource\n .replace(/^\\.\\//, '')\n .replace(/\\/resource\\.json$/, '')\n .replace(/\\.resource$/, '');\n const relationType =\n col.fieldInput.relationType ?? deriveRelationTypeFromColumns(col, cols);\n return {\n ...col,\n fieldInput: {\n ...col.fieldInput,\n relationType,\n options: {\n ...(col.fieldInput.options as object | undefined),\n uri: `${base}/${targetRoute}`,\n resourceUri: `${base}/${targetRoute}`,\n resource: `${base}/${targetRoute}/schemas`,\n },\n },\n };\n });\n};\n\n/**\n * Build `SubResourceConfig` entries for columns with `fieldInput.format === \"action\"`.\n */\nconst buildSubResources = (\n columns: JsonColumn[] | undefined,\n parentRoute: string,\n parentModel: string,\n parentDir?: string,\n enums: EnumRegistry = {},\n baseUrl?: string,\n): SubResourceConfig[] => {\n if (!columns || !parentDir) return [];\n\n return columns\n .filter(\n (c) => c.fieldInput?.format === 'relation' && c.fieldInput?.resource,\n )\n .map((c) => {\n const childResolved = resolveChildResource(\n c.fieldInput!.resource!,\n parentDir,\n );\n const childJson = childResolved?.json;\n const childDir = childResolved?.dir;\n const childRoute =\n childJson?.route ??\n c.fieldInput!.resource!.replace(/^\\.\\//, '').replace(/\\.resource$/, '');\n\n const rawChildColumns = childJson\n ? normalizeColumns(childJson.columns)\n : undefined;\n const expandedChildColumns = rawChildColumns\n ? expandExtendColumns(rawChildColumns, childDir)\n : undefined;\n const childColumns =\n applyRelationFormatDefault(expandedChildColumns) ??\n expandedChildColumns;\n injectEnumValues(childColumns, enums);\n const enrichedChildColumns = enrichNestedRelationColumns(\n childColumns,\n childDir,\n baseUrl,\n );\n const childLookupKey =\n childColumns?.find((col) => col.idField)?.id ?? 'id';\n const childCalculatedColumns = childJson?.calculatedColumns ?? [];\n let childViews = childJson\n ? buildViewsFromColumns(enrichedChildColumns)\n : undefined;\n if (childViews && childCalculatedColumns.length) {\n childViews = {\n ...childViews,\n table: injectCalculatedColumns(\n childViews.table,\n childCalculatedColumns,\n ),\n };\n if (childViews.view) {\n childViews = {\n ...childViews,\n view: injectCalculatedColumnsToView(\n childViews.view,\n childCalculatedColumns,\n ),\n };\n }\n }\n const childOps = childJson?.operations ?? {};\n\n return {\n column: c.id,\n relation: c.id,\n childRoute,\n childModel: c.id,\n foreignKey: `${parentModel}_id`,\n name: childJson?.name ?? childRoute,\n title: childJson?.title ?? childJson?.tag ?? childRoute,\n idField: childLookupKey,\n idType: childJson?.idType ?? 'string',\n ...(childViews && { views: childViews }),\n operations: {\n findAll: childOps.findAll !== false,\n findOne: childOps.findOne !== false,\n create: childOps.create !== false,\n update: childOps.update !== false,\n delete: childOps.delete !== false,\n },\n ...(childJson?.actions?.length && { actions: childJson.actions }),\n ...(childJson?.modalSize && { modalSize: childJson.modalSize }),\n ...(childJson?.include?.length && { include: childJson.include }),\n ...(childJson?.calculatedColumns?.length && {\n calculatedColumns: childJson.calculatedColumns,\n }),\n ...((c.hiddenInForm === false || c.hiddenInView === false) && {\n includeInFindOne: true,\n }),\n ...(buildValueLabelColumns(childColumns).length && {\n valueLabelColumns: buildValueLabelColumns(childColumns),\n }),\n } satisfies SubResourceConfig;\n });\n};\n\n/**\n * Return a new columns array with `uri`, `resourceUri`, and `resource` (schemas URL)\n * injected into `fieldInput.options` for relation columns.\n */\nconst enrichActionColumns = (\n columns: JsonColumn[] | undefined,\n parentRoute: string,\n subResources: SubResourceConfig[],\n baseUrl?: string,\n): JsonColumn[] | undefined => {\n if (!columns) return columns;\n const base = baseUrl ?? '';\n return columns.map((col) => {\n if (col.fieldInput?.format !== 'relation') return col;\n const sub = subResources.find((s) => s.column === col.id);\n if (!sub) return col;\n return {\n ...col,\n fieldInput: {\n ...col.fieldInput,\n options: {\n ...(col.fieldInput.options as object | undefined),\n uri: `${base}/${parentRoute}/{id}/${sub.childRoute}`,\n resourceUri: `${base}/${sub.childRoute}`,\n ...(sub.views && {\n resource: `${base}/${parentRoute}/${sub.childRoute}/schemas`,\n }),\n },\n },\n };\n });\n};\n\n/**\n * Return a new columns array with `resourceUri`/`schemasUri` injected into\n * `fieldInput.options` for NON-relation columns that reference a resource file\n * (e.g. a select whose values come from another resource). Relation columns\n * are handled by `enrichActionColumns`.\n */\nconst enrichResourceRefColumns = (\n columns: JsonColumn[] | undefined,\n parentDir?: string,\n baseUrl?: string,\n): JsonColumn[] | undefined => {\n if (!columns || !parentDir) return columns;\n const base = baseUrl ?? '';\n return columns.map((col) => {\n if (!col.fieldInput?.resource || col.fieldInput.format === 'relation')\n return col;\n const childResolved = resolveChildResource(\n col.fieldInput.resource,\n parentDir,\n );\n const childRoute =\n childResolved?.json?.route ??\n col.fieldInput.resource.replace(/^\\.\\//, '').replace(/\\.resource$/, '');\n return {\n ...col,\n fieldInput: {\n ...col.fieldInput,\n options: {\n ...(col.fieldInput.options as object | undefined),\n resourceUri: `${base}/${childRoute}`,\n schemasUri: `${base}/${childRoute}/schemas`,\n },\n },\n };\n });\n};\n\n/**\n * Scan relation columns for a `sort` option and inject a Prisma-format `orderBy`\n * into the corresponding `include` entry so included records are returned sorted.\n *\n * Example: a column `{ id: \"sections\", fieldInput: { options: { sort: \"title\" } } }`\n * turns `include: [\"sections\"]` into `include: [{ relation: \"sections\", orderBy: { title: \"asc\" } }]`.\n */\nconst enrichIncludeWithSort = (\n include: JsonIncludeEntry[] | undefined,\n columns: JsonColumn[],\n): JsonIncludeEntry[] | undefined => {\n if (!include?.length) return include;\n return include.map((entry) => {\n const relationName = typeof entry === 'string' ? entry : entry.relation;\n const col = columns.find((c) => {\n const opts = c.fieldInput?.options as RelationFieldInputOptions | undefined;\n return (c.column ?? c.id) === relationName && opts?.sort;\n });\n if (!col) return entry;\n const opts = col.fieldInput!.options as RelationFieldInputOptions;\n const orderBy = buildChildSortClause(opts.sort!, opts.sortDir ?? 'asc');\n return typeof entry === 'string'\n ? { relation: entry, orderBy }\n : { ...entry, orderBy };\n });\n};\n\nexport const fromJson = (\n json: JsonResourceConfig,\n schema: ZodObject<ZodRawShape> | undefined,\n hooks: ResourceHooks | undefined,\n /** Absolute path to the resource directory (needed to resolve sibling resources). */\n dirPath?: string,\n /** Base URL for generating full URIs in column options (e.g. `http://localhost:3000`). */\n baseUrl?: string,\n /** Resolved action procedures loaded from the `actions/` directory. */\n actions?: ResourceAction[],\n /** Resolved table-level action procedures loaded from the `actions/` directory. */\n tableActions?: ResourceTableAction[],\n /** Project enum registry — injected into columns that reference an enum by name. */\n enums: EnumRegistry = {},\n): ResourceConfig => {\n const rawColumns = expandExtendColumns(\n normalizeColumns(json.columns) ?? [],\n dirPath,\n );\n const columns = enrichRelationTypes(\n applyRelationFormatDefault(rawColumns) ?? rawColumns,\n schema,\n );\n injectEnumValues(columns, enums);\n\n const subResources = buildSubResources(\n columns,\n json.route,\n json.model,\n dirPath,\n enums,\n baseUrl,\n );\n const enrichedColumns =\n enrichResourceRefColumns(\n enrichActionColumns(columns, json.route, subResources, baseUrl),\n dirPath,\n baseUrl,\n ) ?? columns;\n\n const calculatedColumns: CalculatedColumn[] = json.calculatedColumns ?? [];\n\n const picked = pickByColumns(schema, enrichedColumns);\n const createSchema = pickByColumns(\n schema,\n enrichedColumns,\n (c) => !c.idField && c.createable !== false,\n );\n const updateSchema = pickByColumns(\n schema,\n enrichedColumns,\n (c) => !c.idField && c.updateable !== false,\n );\n let views = buildViews(schema, enrichedColumns);\n if (views && calculatedColumns.length) {\n views = {\n ...views,\n table: injectCalculatedColumns(views.table, calculatedColumns),\n };\n if (views.view) {\n views = {\n ...views,\n view: injectCalculatedColumnsToView(views.view, calculatedColumns),\n };\n }\n }\n\n const lookup = buildLookup(enrichedColumns);\n const enrichedInclude = enrichIncludeWithSort(json.include, enrichedColumns);\n\n const definition: ResourceDefinition = {\n ...(opWithSchema(json.operations.findAll, picked) && {\n findAll: opWithSchema(json.operations.findAll, picked)!,\n }),\n ...(opWithSchema(json.operations.findOne, picked) && {\n findOne: opWithSchema(json.operations.findOne, picked)!,\n }),\n ...(opWithSchema(json.operations.create, createSchema) && {\n create: opWithSchema(json.operations.create, createSchema)!,\n }),\n ...(opWithSchema(json.operations.update, updateSchema) && {\n update: opWithSchema(json.operations.update, updateSchema)!,\n }),\n ...(upsertOp(json.operations.upsert, createSchema) && {\n upsert: upsertOp(json.operations.upsert, createSchema)!,\n }),\n ...(json.operations.delete !== false && { delete: true }),\n };\n\n const display: ResourceDisplay = {\n mode: json.display?.mode === 'page' ? 'page' : 'modal',\n customComponent: json.display?.customComponent ?? null,\n };\n\n return {\n name: json.name,\n route: json.route,\n model: json.model,\n tag: json.tag,\n display,\n ...(json.title && { title: json.title }),\n ...(json.sidebar && { sidebar: json.sidebar }),\n ...(json.idType && { idType: json.idType }),\n ...(lookup?.key && lookup.key !== 'id' && { idField: lookup.key }),\n ...(json.database && { database: json.database }),\n ...(hooks && { hooks }),\n definition,\n ...(views && { views }),\n ...(lookup && { lookup }),\n ...(subResources.length && { subResources }),\n ...(calculatedColumns.length && { calculatedColumns }),\n ...(actions?.length && { actions }),\n ...(tableActions?.length && { tableActions }),\n ...(enrichedInclude?.length && { include: enrichedInclude }),\n ...(json.modalSize && { modalSize: json.modalSize }),\n ...(buildValueLabelColumns(enrichedColumns).length && {\n valueLabelColumns: buildValueLabelColumns(enrichedColumns),\n }),\n };\n};\n\n// ─── Relation type derivation ─────────────────────────────────────────────────\n\n/** Recursively unwrap Optional / Nullable wrappers to reach the inner Zod type. */\nconst unwrapZodType = (type: any): any => {\n if (type instanceof ZodOptional || type instanceof ZodNullable) {\n return unwrapZodType(type.unwrap());\n }\n return type;\n};\n\n/**\n * Derive the `RelationType` for a column from the Zod schema field:\n * - `ZodArray` → `'oneToMany'`\n * - `ZodObject` → `'manyToOne'` (embedded single record)\n * - scalar (number / string FK) → `'manyToOne'`\n * - absent from schema → `undefined` (can't determine)\n */\nconst deriveRelationType = (\n schema: ZodObject<ZodRawShape> | undefined,\n columnId: string,\n): RelationType | undefined => {\n if (!schema) return undefined;\n const field = schema.shape[columnId];\n if (!field) return undefined;\n const inner = unwrapZodType(field);\n return inner instanceof ZodArray ? 'oneToMany' : 'manyToOne';\n};\n\n/**\n * Enrich columns that declare a relation `fieldInput` (type `\"autocomplete\"` or\n * format `\"relation\"`) with a `relationType` derived from the Zod schema,\n * **unless** the column already has an explicit `relationType` set.\n */\nconst enrichRelationTypes = (\n columns: JsonColumn[],\n schema: ZodObject<ZodRawShape> | undefined,\n): JsonColumn[] => {\n if (!schema) return columns;\n return columns.map((col) => {\n const fi = col.fieldInput;\n if (!fi) return col;\n const isRelationField =\n fi.type === 'autocomplete' || fi.format === 'relation';\n if (!isRelationField) return col;\n if (fi.relationType) return col; // explicit wins\n const derived =\n deriveRelationType(schema, col.id) ??\n deriveRelationTypeFromColumns(col, columns);\n if (!derived) return col;\n return { ...col, fieldInput: { ...fi, relationType: derived } };\n });\n};\n\nconst buildLookup = (\n columns: JsonColumn[] | undefined,\n): LookupConfig | undefined => {\n if (!columns) return undefined;\n\n const keyCol = columns.find((c) => c.idField);\n // Prefer explicit showInLookup, then fall back to first searchable column.\n // Never fall back to the id field — it's typically an integer and doesn't support `contains`.\n const labelCol =\n columns.find((c) => c.showInLookup) ?? columns.find((c) => c.searchable);\n\n if (!keyCol && !labelCol) return undefined;\n\n return {\n key: keyCol?.id ?? 'id',\n ...(labelCol && { label: labelCol.id }),\n };\n};\n","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport type { JsonColumn } from './json-config.types';\nimport type {\n OperationDef,\n SchemaInput,\n UpsertOperationDef,\n} from '../crud.config';\n\n/** Narrow a Zod object schema to the set of column ids listed in JSON. */\nexport const pickByColumns = (\n schema: ZodObject<ZodRawShape> | undefined,\n columns: JsonColumn[] | undefined,\n filter?: (col: JsonColumn) => boolean,\n): SchemaInput | undefined => {\n if (!schema) return undefined;\n if (!columns?.length) return schema;\n // Relation columns are managed via sub-resource endpoints — always exclude from write schemas.\n const isRelation = (c: JsonColumn) => c.fieldInput?.format === 'relation';\n const baseFilter = (c: JsonColumn) => !isRelation(c) && (filter ? filter(c) : true);\n const filtered = columns.filter(baseFilter);\n if (!filtered.length) return undefined;\n const mask = Object.fromEntries(filtered.map((c) => [c.id, true as const]));\n return schema.pick(mask as any) as SchemaInput;\n};\n\nexport const opWithSchema = (\n enabled: boolean | undefined,\n schema: SchemaInput | undefined,\n): OperationDef | undefined => {\n // `undefined` means the key was omitted → default to enabled.\n if (enabled === false) return undefined;\n return schema ? { schema } : true;\n};\n\ntype BoolOrUpsert = boolean | { upsertOn: string | string[] };\n\nexport const upsertOp = (\n entry: BoolOrUpsert | undefined,\n schema: SchemaInput | undefined,\n): UpsertOperationDef | undefined => {\n if (!entry) return undefined;\n if (entry === true) {\n throw new Error(\n '`operations.upsert` must be an object with `upsertOn`, not `true`.',\n );\n }\n if (typeof entry === 'object') {\n return { upsertOn: entry.upsertOn, ...(schema && { schema }) };\n }\n return undefined;\n};\n","import { type ZodObject, type ZodRawShape, toJSONSchema } from 'zod';\n\nimport type { CalculatedColumn, JsonColumn } from './json-config.types';\nimport type { ViewColumnConfig, ViewConfig } from '../crud.config';\nimport { jsonSchemaOpts } from '../schema.utils';\nimport { buildFormUiSchema } from './form-schema.builder';\nimport { allowAdditionalProperties, dropNullableFromRequired, enforceRequiredMinLength } from './schema-transforms';\nimport { buildTableUiSchema, resolveDefaultSort } from './table-schema.builder';\n\n// ── Filter schema enrichment ──────────────────────────────────────────────\n\n/**\n * Patch a filter view's JSON schema properties with human-readable titles and\n * enum/type hints so the frontend can show correct labels, restricted operator\n * lists, and a select box for enum fields.\n *\n * Called after `buildView` for the filter view, where `columns` are the\n * filterable columns (already enum-injected by `injectEnumValues`).\n */\nconst patchFilterProperties = (\n jsonSchema: Record<string, any>,\n columns: JsonColumn[] | undefined,\n): void => {\n if (!columns?.length) return;\n const properties = jsonSchema.properties as Record<string, any> | undefined;\n if (!properties) return;\n\n for (const col of columns) {\n // A date-range json column isn't filterable as a whole object. Expand it\n // into two date filter fields keyed with the `->` json-path marker that\n // the API filter builder (buildFilterWhere) understands, e.g.\n // `date_range->from` / `date_range->to`. The frontend filter dropdown\n // reads these straight from `properties` and emits `key:value:operator`.\n if (col.fieldInput?.format === 'date-range') {\n delete properties[col.id];\n const opts = (col.fieldInput?.options as Record<string, unknown> | undefined) ?? {};\n const base = col.label ?? col.id;\n const fromField = (opts['fromField'] as string) ?? 'from';\n const toField = (opts['toField'] as string) ?? 'to';\n const dateProp = (title: string) => ({\n type: 'string',\n format: 'date',\n title,\n 'x-field-type': 'date',\n });\n properties[`${col.id}->${fromField}`] = dateProp((opts['fromLabel'] as string) ?? `${base} (from)`);\n properties[`${col.id}->${toField}`] = dateProp((opts['toLabel'] as string) ?? `${base} (to)`);\n continue;\n }\n\n const prop = properties[col.id];\n if (!prop) continue;\n\n // Always inject title from the column label.\n prop.title = col.label ?? col.id;\n\n // Inject enum values so the UI can render a select box.\n const values = (col.fieldInput?.options as Record<string, unknown> | undefined)?.['values'];\n if (values) {\n prop['x-values'] = values;\n }\n\n // Inject a field-type hint for operator restriction on the frontend.\n const ft = col.fieldInput?.type;\n if (ft === 'select' || col.enum) {\n prop['x-field-type'] = 'enum';\n } else if (ft === 'number' || prop.type === 'number' || prop.type === 'integer') {\n prop['x-field-type'] = 'number';\n } else if (prop.format === 'date-time' || prop.format === 'date') {\n prop['x-field-type'] = 'date';\n } else if (prop.type === 'boolean') {\n prop['x-field-type'] = 'boolean';\n }\n // string / default: no hint needed — frontend defaults to 'string'\n }\n};\n\n// ── Column sorting ────────────────────────────────────────────────────────\n\n/** Resolve the sort position for a column: `fieldInput.position`, then natural index. */\nconst colPosition = (col: JsonColumn, i: number): number =>\n col.fieldInput?.position ?? i;\n\n/** Sort columns by position; columns without an explicit position keep array order. */\nconst sortByPosition = (cols: JsonColumn[]): JsonColumn[] =>\n cols\n .map((col, i) => ({ col, i }))\n .sort((a, b) => colPosition(a.col, a.i) - colPosition(b.col, b.i))\n .map(({ col }) => col);\n\nconst toViewColumn = (col: JsonColumn): ViewColumnConfig => ({\n id: col.id,\n ...(col.label && { label: col.label }),\n ...(col.sortable != null && { sortable: col.sortable }),\n ...(col.searchable != null && { searchable: col.searchable }),\n ...(col.fieldInput && { fieldInput: col.fieldInput }),\n});\n\n// ── View building ─────────────────────────────────────────────────────────\n\nconst buildView = (\n schema: ZodObject<ZodRawShape> | undefined,\n columns: JsonColumn[] | undefined,\n visible: (column: JsonColumn) => boolean,\n buildUiSchema: (cols: JsonColumn[]) => Record<string, unknown>,\n sort = false,\n schemaVisible?: (column: JsonColumn) => boolean,\n): ViewConfig | undefined => {\n if (!schema || !columns?.length) return undefined;\n const visibleCols = sort\n ? sortByPosition(columns.filter(visible))\n : columns.filter(visible);\n if (!visibleCols.length) return undefined;\n\n const schemaCols = schemaVisible\n ? columns.filter((c) => visible(c) || schemaVisible(c))\n : visibleCols;\n\n const schemaIds = schemaCols.map((c) => c.id);\n const mask = Object.fromEntries(schemaIds.map((id) => [id, true as const]));\n const picked = schema.pick(mask as any);\n const jsonSchema = toJSONSchema(picked, {\n target: 'draft-07',\n ...jsonSchemaOpts,\n }) as Record<string, unknown>;\n allowAdditionalProperties(jsonSchema);\n dropNullableFromRequired(jsonSchema);\n enforceRequiredMinLength(jsonSchema);\n\n return {\n json_schema: jsonSchema,\n ui_schema: buildUiSchema(visibleCols),\n columns: visibleCols.map(toViewColumn),\n };\n};\n\n// ── Calculated column injection ───────────────────────────────────────────\n\ntype InjectionMode = 'table' | 'view';\n\nconst isVisibleInMode = (c: CalculatedColumn, mode: InjectionMode): boolean =>\n mode === 'table' ? !c.hiddenInTable : !c.hiddenInView;\n\nconst buildCalculatedElement = (c: CalculatedColumn, mode: InjectionMode) =>\n mode === 'table'\n ? {\n type: c.type === 'boolean' ? 'BooleanCell' : 'TextCell',\n scope: `#/properties/${c.id}`,\n options: {\n label: c.label ?? c.id,\n },\n }\n : {\n type: 'Control',\n scope: `#/properties/${c.id}`,\n options: {\n // Spread fieldInput.options first (e.g. colspan), then layer type-derived options on top.\n ...(c.fieldInput?.options ?? {}),\n label: c.label ?? c.id,\n ...(c.type === 'boolean' && { format: 'boolean' }),\n },\n };\n\n/**\n * Effective insertion position for a calculated column.\n * `fieldInput.position` takes precedence over top-level `position`.\n * `undefined` means append to the end.\n */\nconst calcPosition = (c: CalculatedColumn): number | undefined =>\n c.fieldInput?.position ?? c.position;\n\nconst injectCalculatedColumnsIntoView = (\n viewConfig: ViewConfig,\n calculated: CalculatedColumn[],\n mode: InjectionMode,\n): ViewConfig => {\n if (!calculated.length) return viewConfig;\n\n const visible = calculated.filter((c) => isVisibleInMode(c, mode));\n if (!visible.length) return viewConfig;\n\n const jsonSchema = { ...(viewConfig.json_schema as any) };\n jsonSchema.properties = { ...jsonSchema.properties };\n for (const c of visible) {\n jsonSchema.properties[c.id] = {\n type: c.type === 'boolean' ? 'boolean' : 'string',\n title: c.label ?? c.id,\n };\n }\n\n const uiSchema = { ...(viewConfig.ui_schema as any) };\n const existing: any[] = [...(uiSchema.elements ?? [])];\n\n // Merge-sort existing elements (implicit position = index + 0.5) with calculated\n // elements (explicit position). Using i + 0.5 means `position: N` slots a calculated\n // column before the regular column currently at index N.\n const tagged: Array<{ el: any; pos: number }> = [\n ...existing.map((el, i) => ({ el, pos: i + 0.5 })),\n ...visible.map((c) => ({\n el: buildCalculatedElement(c, mode),\n pos: calcPosition(c) ?? Infinity,\n })),\n ];\n tagged.sort((a, b) => a.pos - b.pos);\n uiSchema.elements = tagged.map((t) => t.el);\n\n // Insert new ViewColumnConfig entries at the same relative position.\n const columns = [...viewConfig.columns];\n for (const c of visible) {\n const pos = calcPosition(c);\n const entry: ViewColumnConfig = { id: c.id, label: c.label };\n if (pos !== undefined) {\n columns.splice(pos, 0, entry);\n } else {\n columns.push(entry);\n }\n }\n\n return {\n ...viewConfig,\n json_schema: jsonSchema,\n ui_schema: uiSchema,\n columns,\n };\n};\n\n/** Inject calculated columns into a table ViewConfig (TextCell/BooleanCell elements). */\nexport const injectCalculatedColumns = (\n tableView: ViewConfig,\n calculated: CalculatedColumn[],\n): ViewConfig =>\n injectCalculatedColumnsIntoView(tableView, calculated, 'table');\n\n/** Inject calculated columns into a form/view ViewConfig (Control elements). */\nexport const injectCalculatedColumnsToView = (\n viewConfig: ViewConfig,\n calculated: CalculatedColumn[],\n): ViewConfig =>\n injectCalculatedColumnsIntoView(viewConfig, calculated, 'view');\n\n// ── Public view builders ──────────────────────────────────────────────────\n\n/**\n * A minimal, column-less `table` view. The frontend always expects\n * `schemas.table` to be an object, so resources whose columns are all hidden in\n * the table (e.g. join tables like `text_author`) still get a valid — if empty —\n * table view instead of `undefined`.\n */\nconst emptyTableView = (): ViewConfig => ({\n json_schema: { type: 'object', additionalProperties: true, properties: {} },\n ui_schema: buildTableUiSchema([]),\n columns: [],\n});\n\n/** Build table / form / filter / view schemas from a Zod schema + column definitions. */\nexport const buildViews = (\n schema: ZodObject<ZodRawShape> | undefined,\n columns: JsonColumn[] | undefined,\n): Record<string, ViewConfig> | undefined => {\n const views: Record<string, ViewConfig> = {};\n\n const table = buildView(\n schema,\n columns,\n (c) => !c.hiddenInTable,\n buildTableUiSchema,\n );\n if (table) {\n table.defaultSort = resolveDefaultSort(\n table.columns as JsonColumn[],\n columns,\n );\n views.table = table;\n } else if (columns?.length) {\n views.table = emptyTableView();\n }\n\n const form = buildView(\n schema,\n columns,\n (c) => !c.hiddenInForm,\n buildFormUiSchema,\n true,\n (c) => c.createable === true || c.updateable === true,\n );\n if (form) views.form = form;\n\n const filter = buildView(\n schema,\n columns,\n (c) => !!c.filterable,\n buildFormUiSchema,\n true,\n );\n if (filter) {\n patchFilterProperties(filter.json_schema as Record<string, any>, columns?.filter((c) => !!c.filterable));\n views.filter = filter;\n }\n\n const view = buildView(\n schema,\n columns,\n (c) => !c.hiddenInView,\n buildFormUiSchema,\n true,\n );\n if (view) views.view = view;\n\n return Object.keys(views).length ? views : undefined;\n};\n\n/**\n * Build views from column definitions without a Zod schema.\n * Used for sub-resources. Columns with `col.column` are grouped as nested objects\n * to match the actual API response shape.\n */\nexport const buildViewsFromColumns = (\n columns: JsonColumn[] | undefined,\n): Record<string, ViewConfig> | undefined => {\n if (!columns?.length) return undefined;\n\n const buildJsonSchema = (cols: JsonColumn[]): Record<string, unknown> => {\n const properties: Record<string, any> = {};\n for (const c of cols) {\n if (c.column) {\n if (!properties[c.column]) {\n properties[c.column] = {\n type: 'object',\n additionalProperties: true,\n properties: {},\n };\n }\n // Support dotted displayKey paths (e.g. \"internal_author.name\") by building\n // nested object nodes so the JSON schema mirrors the actual data structure.\n const keyPath = (c.displayKey ?? c.id).split('.');\n let target = properties[c.column].properties;\n for (let i = 0; i < keyPath.length - 1; i++) {\n const segment = keyPath[i];\n if (!target[segment]) {\n target[segment] = { type: 'object', additionalProperties: true, properties: {} };\n }\n target = target[segment].properties;\n }\n target[keyPath[keyPath.length - 1]] = {\n type: 'string',\n title: c.label ?? c.id,\n };\n } else {\n properties[c.id] = {\n type: c.columnType ?? 'string',\n title: c.label ?? c.id,\n };\n }\n }\n return { type: 'object', additionalProperties: true, properties };\n };\n\n /** Rewrite scopes for nested columns to match the grouped JSON schema. */\n const fixNestedScopes = (\n uiSchema: Record<string, unknown>,\n cols: JsonColumn[],\n ): Record<string, unknown> => {\n const colMap = Object.fromEntries(cols.map((c) => [c.id, c]));\n const elements = (uiSchema as any).elements as any[] | undefined;\n if (!elements) return uiSchema;\n return {\n ...uiSchema,\n elements: elements.map((el) => {\n const id = (el.scope as string | undefined)?.replace(\n '#/properties/',\n '',\n );\n const col = id ? colMap[id] : undefined;\n if (!col?.column) return el;\n // Support dotted displayKey paths (e.g. \"internal_author.name\") — each segment\n // becomes a nested /properties/ step in the JSON pointer.\n const keyPath = (col.displayKey ?? col.id).split('.');\n const propPath = keyPath.map((k) => `properties/${k}`).join('/');\n return {\n ...el,\n scope: `#/properties/${col.column}/${propPath}`,\n };\n }),\n };\n };\n\n const makeView = (\n visible: JsonColumn[],\n buildUiSchema: (cols: JsonColumn[]) => Record<string, unknown>,\n ): ViewConfig | undefined => {\n if (!visible.length) return undefined;\n return {\n json_schema: buildJsonSchema(visible),\n ui_schema: fixNestedScopes(buildUiSchema(visible), visible),\n columns: visible.map(toViewColumn),\n };\n };\n\n const views: Record<string, ViewConfig> = {};\n\n const tableCols = sortByPosition(columns.filter((c) => !c.hiddenInTable));\n const table = makeView(tableCols, buildTableUiSchema);\n if (table) {\n table.defaultSort = resolveDefaultSort(tableCols, columns);\n views.table = table;\n } else {\n views.table = emptyTableView();\n }\n\n const formCols = sortByPosition(columns.filter((c) => !c.hiddenInForm));\n const form = makeView(formCols, buildFormUiSchema);\n if (form) views.form = form;\n\n const viewCols = sortByPosition(columns.filter((c) => !c.hiddenInView));\n const viewView = makeView(viewCols, buildFormUiSchema);\n if (viewView) views.view = viewView;\n\n return Object.keys(views).length ? views : undefined;\n};\n","import { ControlBuilder, LayoutBuilder } from '@ghentcdh/crouton-core';\n\nimport type { DetailConfig, JsonColumn } from './json-config.types';\n\n// ── Condition / rule builders ─────────────────────────────────────────────\n\n/** Condition descriptor used to build JSON Forms rules (`showWhen`, `hideWhen`, `disabledWhen`). */\nexport type WhenCondition = {\n field: string;\n eq?: unknown;\n neq?: unknown;\n exists?: boolean;\n notExists?: boolean;\n};\n\n/** Convert a `WhenCondition` to the JSON Schema fragment used inside a JSON Forms rule. */\nexport const buildConditionSchema = (\n when: WhenCondition,\n): Record<string, unknown> => {\n if (when.notExists) return { not: { minLength: 1 } };\n if (when.exists) return { minLength: 1 };\n if (when.neq !== undefined) return { not: { const: when.neq } };\n return { const: when.eq };\n};\n\n/**\n * Build a JSON Forms rule object for a column's visibility/disabled condition.\n * Returns `undefined` when the column has no conditional rules.\n */\nexport const buildRule = (\n col: JsonColumn,\n): Record<string, unknown> | undefined => {\n if (col.disabledWhen) {\n return {\n effect: 'DISABLE',\n condition: {\n scope: `#/properties/${col.disabledWhen.field}`,\n schema: buildConditionSchema(col.disabledWhen),\n },\n };\n }\n const when = col.showWhen ?? col.hideWhen;\n if (!when) return undefined;\n const effect = col.showWhen ? 'SHOW' : 'HIDE';\n return {\n effect,\n condition: {\n scope: `#/properties/${when.field}`,\n schema: buildConditionSchema(when),\n },\n };\n};\n\n// ── Form control builders ─────────────────────────────────────────────────\n\nconst buildDetailLayout = (detail: DetailConfig) => {\n const inner =\n detail.layout === 'collapse'\n ? LayoutBuilder.collapse<any>()\n : LayoutBuilder.horizontal<any>();\n\n inner.addControls(\n ...detail.controls.map((dc) => {\n const ctrl = ControlBuilder.properties<any>(dc.property as keyof any);\n if (dc.type === 'markdown') {\n ctrl.markdown(dc.options as any);\n } else if (dc.type) {\n ctrl.control(dc.type, dc.options ?? {});\n }\n if (dc.hideLabel) ctrl.hideLabel();\n if (dc.width) ctrl.width(dc.width as any);\n return ctrl;\n }),\n );\n\n if (detail.titleKey) inner.titleKey(detail.titleKey);\n return inner;\n};\n\nconst buildFormControl = (col: JsonColumn) => {\n const control = ControlBuilder.properties<any>(col.id as keyof any);\n const fieldInput = col.fieldInput;\n\n if (fieldInput?.format === 'relation') {\n const options: any = { ...(fieldInput.options as object | undefined) };\n if (!options.colspan) options.colspan = 12;\n if (fieldInput.relationType) options.relationType = fieldInput.relationType;\n control.control('relation', options).width('full');\n } else if (fieldInput?.type === 'autocomplete') {\n const options: any = { ...(fieldInput.options as object | undefined) };\n if (!options.colspan) options.colspan = 12;\n if (fieldInput.relationType) options.relationType = fieldInput.relationType;\n // Use explicit format when set; otherwise the type itself is the format.\n const format = fieldInput.format ?? fieldInput.type;\n control.control(format, options).width('full');\n } else if (fieldInput?.detail) {\n const detailLayout = buildDetailLayout(fieldInput.detail);\n control.detailFixed(detailLayout, {\n layout: fieldInput.detail.layout === 'collapse' ? 'row' : undefined,\n });\n } else if (fieldInput?.format === 'date-range') {\n // Drive the renderer off the explicit `format` so its option-based tester\n // matches, not `type` (which for this json column is 'object' and has no\n // renderer). Mirrors the relation branch.\n const options: any = { ...(fieldInput.options as object | undefined) };\n if (!options.colspan) options.colspan = 12;\n control.control('date-range', options).width('full');\n } else {\n const options: any = fieldInput?.options ?? {};\n if (!options.colspan) options.colspan = 12;\n const type = fieldInput?.type ?? 'text';\n control.control(type, options).width('full');\n }\n\n if (fieldInput?.customRender)\n control.setCustomRender(fieldInput?.customRender);\n if (col.hideLabel) control.hideLabel();\n return control;\n};\n\n/** Build the GridLayout UI schema for a form view. */\nexport const buildFormUiSchema = (\n cols: JsonColumn[],\n): Record<string, unknown> => {\n const layout = LayoutBuilder.grid<any>()\n .addControls(...cols.map(buildFormControl))\n .build() as any;\n\n const colMap = Object.fromEntries(cols.map((c) => [c.id, c]));\n layout.elements = (layout.elements as any[]).map((el: any) => {\n const id = el.scope?.replace('#/properties/', '');\n const col = id ? colMap[id] : undefined;\n if (!col) return el;\n const rule = buildRule(col);\n return {\n ...el,\n options: { ...(el.options ?? {}), label: col.label },\n ...(rule && { rule }),\n };\n });\n\n return layout as Record<string, unknown>;\n};\n","/**\n * Recursively set `additionalProperties: true` on every object in a JSON Schema.\n * Required so Prisma-returned rows (which may contain extra fields) pass validation.\n */\nexport const allowAdditionalProperties = (schema: Record<string, unknown>): void => {\n if (schema['type'] === 'object') {\n schema['additionalProperties'] = true;\n const props = schema['properties'] as Record<string, Record<string, unknown>> | undefined;\n if (props) {\n for (const value of Object.values(props)) {\n allowAdditionalProperties(value);\n }\n }\n }\n if (schema['type'] === 'array' && schema['items']) {\n allowAdditionalProperties(schema['items'] as Record<string, unknown>);\n }\n};\n\n/** A property is nullable when its `anyOf` contains a `{ type: \"null\" }` branch. */\nconst isNullableProperty = (prop: Record<string, unknown> | undefined): boolean => {\n const anyOf = prop?.['anyOf'];\n return (\n Array.isArray(anyOf) &&\n anyOf.some((s: Record<string, unknown>) => s?.['type'] === 'null')\n );\n};\n\n/**\n * Recursively drop nullable fields from `required`. A nullable field accepts\n * `null`, so it should be treated as optional rather than required.\n */\nexport const dropNullableFromRequired = (schema: Record<string, unknown>): void => {\n if (schema['type'] !== 'object') return;\n\n const props = schema['properties'] as Record<string, Record<string, unknown>> | undefined;\n if (!props) return;\n\n const required = schema['required'] as string[] | undefined;\n if (Array.isArray(required)) {\n schema['required'] = required.filter((key) => !isNullableProperty(props[key]));\n }\n\n for (const value of Object.values(props)) {\n dropNullableFromRequired(value);\n }\n};\n\n/** Add `minLength: 1` to all string properties so empty strings are rejected. */\nexport const enforceRequiredMinLength = (schema: Record<string, unknown>): void => {\n if (schema['type'] !== 'object') return;\n\n const props = schema['properties'] as Record<string, Record<string, unknown>> | undefined;\n if (!props) return;\n\n for (const prop of Object.values(props)) {\n if (prop?.['type'] === 'string' && !('minLength' in prop)) {\n prop['minLength'] = 1;\n } else if (prop?.['type'] === 'object') {\n enforceRequiredMinLength(prop);\n }\n }\n};\n","import { BooleanCellBuilder, TableBuilder, TextCellBuilder } from '@ghentcdh/crouton-core';\n\nimport type { JsonColumn } from './json-config.types';\n\n// ── Column type helpers ───────────────────────────────────────────────────\n\n/** Returns `true` when the column should render as a boolean (checkbox) cell. */\nexport const isBoolean = (col: JsonColumn): boolean =>\n col.fieldInput?.type === 'boolean' || col.columnType === 'boolean';\n\n/** Returns `true` when the column is a sub-resource relation (renders an inline sub-table). */\nexport const isRelation = (col: JsonColumn): boolean =>\n col.fieldInput?.format === 'relation';\n\n/** Returns `true` when the column is an autocomplete FK reference (renders as a `RecordCell`). */\nexport const isAutocomplete = (col: JsonColumn): boolean =>\n col.fieldInput?.type === 'autocomplete';\n\n/** Returns `true` when the column should render as a `RecordCell` in the table. */\nexport const isRecordCell = (col: JsonColumn): boolean =>\n isRelation(col) || isAutocomplete(col);\n\n/** Returns `true` when the column is a date-range control rendered in the table. */\nexport const isDateRange = (col: JsonColumn): boolean =>\n col.fieldInput?.format === 'date-range';\n\n// ── Sort helpers ──────────────────────────────────────────────────────────\n\n/**\n * Derive the sort key for a column:\n * - Explicit `sortId` wins.\n * - Value/label enum column (`enum` ref or `options.emitObject`): sort by the\n * scalar column, NOT `${column}.label` — the label is a serialization\n * envelope, not a DB field, so a nested orderBy would be invalid.\n * - Nested relation column: `${column ?? id}.${displayKey}` (e.g. `author.origin_name`).\n * - Plain column: `col.id`.\n * Returns `null` when `sortable: false`.\n */\nexport const deriveSortId = (col: JsonColumn): string | null => {\n if (col.sortable === false) return null;\n if (col.sortId) return col.sortId;\n const base = col.column ?? col.id;\n const fi = col.fieldInput;\n const opts = (fi?.options ?? {}) as Record<string, unknown>;\n\n // Relation columns (autocomplete / `format: relation`) can't be ordered by the\n // bare relation name — Prisma expects a nested `…OrderByWithRelationInput`, not\n // a scalar. Sort by a nested scalar of the related model instead, preferring an\n // explicit `displayKey`, then the autocomplete label/display key. With no usable\n // key the column is not sortable (`null`) rather than crashing at query time.\n const isRelation =\n fi?.format === 'relation' ||\n !!fi?.relationType ||\n fi?.type === 'autocomplete' ||\n typeof opts.resource === 'string';\n if (isRelation) {\n const key =\n (typeof col.displayKey === 'string' ? col.displayKey : undefined) ??\n (typeof opts.displayKey === 'string' ? opts.displayKey : undefined) ??\n (typeof opts.labelKey === 'string' ? opts.labelKey : undefined);\n if (!key) return null;\n const path = key.includes('.') ? key : `${base}.${key}`;\n return path.endsWith('.label') ? path.slice(0, -'.label'.length) : path;\n }\n\n if (!col.displayKey) return base;\n const path = `${base}.${col.displayKey}`;\n const isValueLabel =\n !!col.enum ||\n (opts as { emitObject?: boolean }).emitObject === true;\n // For value-label columns the displayKey targets the `{value,label}` envelope,\n // which is not a DB field. Sort by the underlying scalar: drop a trailing\n // `.label` while keeping any relation path (e.g. `author.origin.label` →\n // `author.origin`, `text_type.label` → `text_type`).\n if (isValueLabel && path.endsWith('.label')) return path.slice(0, -'.label'.length);\n return path;\n};\n\n/**\n * Pick the best default sort column:\n * 1. Explicit `defaultSort: true` column that is also sortable.\n * 2. First sortable visible column.\n * 3. The idField column as a last resort.\n */\nexport const resolveDefaultSort = (\n tableCols: JsonColumn[],\n allColumns: JsonColumn[] | undefined,\n): string | undefined => {\n const isSortable = (c: JsonColumn) => c.sortable !== false;\n const sortCol =\n tableCols.find((c) => c.defaultSort && isSortable(c)) ??\n tableCols.find(isSortable) ??\n allColumns?.find((c) => c.idField);\n return sortCol ? (deriveSortId(sortCol) ?? sortCol.id) : undefined;\n};\n\n// ── Table UI schema builder ───────────────────────────────────────────────\n\n/**\n * Field-input options that are also meaningful in table cells, so the table\n * can reuse the same logic as the form (e.g. mapping a select's stored value\n * to its label, or resolving a referenced resource):\n * - `values` / `storeValue` — select options\n * - `uri` / `resourceUri` / `schemasUri` — injected resource references\n */\nconst SHARED_CELL_OPTION_KEYS = ['values', 'storeValue', 'uri', 'resourceUri', 'schemasUri'] as const;\n\n/** Pick the shared (form ↔ table) option keys from a column's `fieldInput.options`. */\nexport const pickSharedCellOptions = (col: JsonColumn): Record<string, unknown> => {\n const options = (col.fieldInput?.options ?? {}) as Record<string, unknown>;\n return Object.fromEntries(\n SHARED_CELL_OPTION_KEYS.filter((key) => options[key] !== undefined).map((key) => [key, options[key]]),\n );\n};\n\n/** Build the TableBuilder UI schema — one TextCell / BooleanCell per visible column. */\nexport const buildTableUiSchema = (cols: JsonColumn[]): Record<string, unknown> => {\n const layout = TableBuilder.init<any>()\n .addControls(\n ...cols.map((col) => {\n const cellBuilder = isBoolean(col) ? BooleanCellBuilder : TextCellBuilder;\n let builder = cellBuilder.properties<any>(col.id as keyof any);\n if (col.displayKey) builder = builder.key(col.displayKey);\n if (col.sortId) builder = builder.setSortId(col.sortId);\n return builder;\n }),\n )\n .build() as any;\n\n const colMap = Object.fromEntries(cols.map((c) => [c.id, c]));\n layout.elements = (layout.elements as any[]).map((el: any) => {\n const id = el.scope?.replace('#/properties/', '');\n const col = id ? colMap[id] : undefined;\n if (!col) return el;\n // Record cells get all fieldInput options; plain cells still receive the\n // shared ones (select values, resource URIs) so they can reuse form logic.\n // Date-range reuses the form control renderer, so it needs its full options\n // (format, fromField/toField, labels).\n const fieldInputOptions =\n isRecordCell(col) || isDateRange(col)\n ? (col.fieldInput?.options as object ?? {})\n : pickSharedCellOptions(col);\n const dataPathOption = col.column ? { dataPath: col.column } : {};\n const derivedSortId = isRecordCell(col) || isDateRange(col) ? null : deriveSortId(col);\n const sortOptions = derivedSortId ? { sortId: derivedSortId } : { sortable: false };\n const relationTypeOption = col.fieldInput?.relationType ? { relationType: col.fieldInput.relationType } : {};\n return {\n ...el,\n options: {\n ...(el.options ?? {}),\n ...fieldInputOptions,\n ...dataPathOption,\n ...sortOptions,\n ...relationTypeOption,\n ...(isDateRange(col) && { format: 'date-range' }),\n label: col.label,\n },\n ...(isRecordCell(col) && { type: 'RecordCell' }),\n ...(isDateRange(col) && { type: 'Control' }),\n };\n });\n\n return layout as Record<string, unknown>;\n};\n","/**\n * Filesystem-driven resource loader.\n *\n * Two sources feed the resource registry:\n *\n * 1. `<dir>/<name>/resource.json` — declarative configuration\n * (route / operations / columns / …).\n *\n * 2. `<dir>/<name>/resource.ts` — imperative configuration as a\n * plain `ResourceConfig` default export.\n *\n * When both exist for the same name, the JSON wins.\n *\n * The JSON only carries operation toggles; actual Zod schemas come from\n * a sibling `schema.ts` (default export). If the JSON lists `columns`,\n * the loader narrows the Zod schema down to those column ids via\n * `.pick()` before attaching it to every enabled operation.\n *\n * `resource.ts` / `hooks.ts` / `schema.ts` do **not** import from each\n * other — this loader is the only place that stitches them together.\n */\n\nimport type { ZodObject, ZodRawShape } from 'zod';\n\n\nimport { loadActions, loadTableActions } from './action.loader';\nimport { loadEnumRegistry } from './enum-registry';\nimport { fromJson } from './json-adapter';\nimport type { JsonResourceConfig } from './json-config.types';\nimport { findModule, importDefault } from './module.loader';\nimport type { ResourceConfig, ResourceHooks, SubResourceConfig } from '../crud.config';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nconst loadSubResourceHooks = async (\n subResources: SubResourceConfig[],\n basePath: string,\n): Promise<void> => {\n for (const sub of subResources) {\n const file = sub.name ? findModule(join(basePath, 'hooks'), sub.name) : undefined;\n if (!file) continue;\n const hooks = await importDefault<ResourceHooks>(file);\n if (hooks) (sub as any).hooks = hooks;\n }\n};\n\nexport const loadResourceConfigsFromDir = async (\n dirPath: string,\n baseUrl?: string,\n enumsFile?: string,\n): Promise<ResourceConfig[]> => {\n const enums = loadEnumRegistry(dirPath, enumsFile);\n const entries = readdirSync(dirPath, { withFileTypes: true });\n const dirs = entries.filter((e: { isDirectory(): boolean }) => e.isDirectory()).map((e: { name: string }) => e.name);\n const configs: ResourceConfig[] = [];\n\n for (const dir of dirs) {\n const basePath = join(dirPath, dir);\n\n const schemaFile = findModule(basePath, 'schema');\n const schema = schemaFile ? await importDefault<ZodObject<ZodRawShape>>(schemaFile) : undefined;\n\n const hooksFile = findModule(basePath, 'hooks');\n const hooks = hooksFile ? await importDefault<ResourceHooks>(hooksFile) : undefined;\n\n const jsonFile = join(basePath, 'resource.json');\n if (existsSync(jsonFile)) {\n const json: JsonResourceConfig = JSON.parse(readFileSync(jsonFile, 'utf-8'));\n const actions = await loadActions(json.actions ?? [], basePath);\n const tableActions = await loadTableActions(json.tableActions ?? [], basePath);\n const config = fromJson(json, schema, hooks, basePath, baseUrl, actions, tableActions, enums);\n await loadSubResourceHooks(config.subResources ?? [], basePath);\n configs.push(config);\n continue;\n }\n\n const tsFile = findModule(basePath, 'resource');\n if (tsFile) {\n const config = await importDefault<ResourceConfig>(tsFile);\n if (config) configs.push(hooks ? { ...config, hooks } : config);\n }\n }\n\n return configs;\n};\n","import type { ResourceConfig } from '../crud.config';\n\nexport abstract class ResourceConfigLoader {\n abstract loadAll(): Promise<ResourceConfig[]>;\n abstract loadByRoute(route: string): Promise<ResourceConfig | undefined>;\n}\n","import { loadResourceConfigsFromDir } from './index';\n\nimport { ResourceConfigLoader } from './resource-config.loader';\nimport type { ResourceConfig } from '../crud.config';\n\nexport class FileSystemResourceConfigLoader extends ResourceConfigLoader {\n constructor(\n private readonly dirPath: string,\n private readonly baseUrl?: string,\n private readonly enumsFile?: string,\n ) {\n super();\n }\n\n async loadAll(): Promise<ResourceConfig[]> {\n return loadResourceConfigsFromDir(this.dirPath, this.baseUrl, this.enumsFile);\n }\n\n async loadByRoute(route: string): Promise<ResourceConfig | undefined> {\n const configs = await this.loadAll();\n return configs.find((c) => c.route === route);\n }\n}\n"],"mappings":"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","names":["ResourceConfigLoader","import_common","import_common","import_zod","PositiveRequestNumber","z","coerce","number","int","positive","nonnegative","StringOrArray","string","or","array","transform","val","Array","isArray","SortDirEnum","z","enum","RequestSchema","object","page","PositiveRequestNumber","optional","default","pageSize","sort","string","sortDir","filter","StringOrArray","RequestSchemaWithOffset","transform","schema","offset","Operator","OperatorLabel","contains","not_contains","equals","not_equals","gt","lt","isnull","isnotnull","OperatorOptions","map","k","value","label","buildSort","key","sortDir","buildSortKey","split","SortDirEnum","safeParse","data","keys","length","buildKey","pop","import_zod","ResponseRequestSchema","RequestSchema","extend","count","PositiveRequestNumber","totalPages","ResponseSchema","z","object","data","array","unknown","request","import_zod","Builder","type","BuilderWithElements","elements","addControl","control","push","addControls","controls","buildElements","map","e","build","ControlType","number","string","integer","autocomplete","textArea","markdown","array","custom","select","mutliSelect","boolean","link","relation","date","dateTime","dateRange","ControlBuilder","Builder","options","format","styles","_detail","scope","type","asObject","property","properties","asCustom","builder","addOptions","setCustomRender","customRender","detail","layoutBuilder","label","elementLabelProp","addAction","action","actions","push","detailFixed","hideActions","layout","labelKey","readonly","dataField","control","width","wrapper","customLabel","placeHolder","placeholder","hideLabel","build","undefined","LayoutTypes","HorizontalLayout","VerticalLayout","CollapseLayout","GridLayout","LayoutBuilder","BuilderWithElements","options","type","horizontal","collapse","vertical","grid","titleKey","addOptions","title","build","elements","buildElements","labelFromId","id","words","replace","trim","charAt","toUpperCase","slice","toLowerCase","normalizeColumns","columns","undefined","raw","Array","isArray","Object","entries","map","col","label","wrapOne","value","values","match","find","o","label","String","toValueLabel","undefined","Array","isArray","map","v","fromValueLabel","input","TextCellBuilder","Builder","options","scope","type","properties","property","key","format","setSortId","sortId","build","BooleanCellBuilder","TableBuilder","builder","LayoutBuilder","horizontal","init","addControl","control","addControls","controls","IS_DEV","process","env","ResourceConfigRegistry","configs","loader","initialConfigs","getAll","IS_DEV","loadAll","getByRoute","route","loadByRoute","find","c","byPosition","a","b","position","label","localeCompare","buildLayoutPayload","configs","sidebarGroups","title","autoSave","visible","filter","c","sidebar","hide","views","topLevel","groupMap","Map","Object","entries","map","slug","cfg","labelFromId","children","leaf","kind","id","name","tag","groupSlug","group","has","set","get","push","groups","g","length","sort","createAppLayoutController","layoutPayload","AppLayoutController","configRegistry","getLayout","IS_DEV","fresh","getAll","summary","status","description","Reflect","defineMetadata","ResourceConfigRegistry","import_common","CroutonValidationError","Error","errors","name","CroutonValidationExceptionFilter","catch","exception","host","res","switchToHttp","getResponse","status","json","statusCode","message","errors","error","import_common","import_swagger","resolveDefinition","config","def","definition","isOperationEnabled","op","schemaFor","entry","undefined","schema","upsertOnFor","upsert","upsertOn","import_common","castExpression","col","type","sqlExpression","defaultValueForType","coerceColumnValue","v","Boolean","undefined","String","Number","buildCalculatedColumnSql","tableName","ids","alias","id","placeholders","map","_","i","join","mergeCalculatedColumnsForRows","rows","calcCols","prisma","length","r","results","Promise","all","sql","defaultValue","coerce","calcRows","$queryRawUnsafe","Object","fromEntries","e","console","error","row","extra","buildIncludeClause","include","Map","orderByMap","entry","dotIdx","indexOf","has","set","relation","slice","rest","get","orderBy","Array","from","entries","nestedIncludes","nested","clause","buildChildSortClause","sort","sortDir","parts","split","buildSort","dir","reduceRight","acc","part","parseFilterString","raw","parts","split","length","field","lastPart","hasOperator","Operator","includes","value","slice","join","operator","buildNestedPath","path","condition","head","rest","JSON_PATH_SEP","isJsonPath","buildJsonPathCondition","column","frag","extra","equals","not","gt","lt","string_contains","NOT","operatorToCondition","num","Number","numVal","isNaN","contains","undefined","buildFilterWhere","filter","conditions","map","f","c","AND","sanitizeValueLabelSort","sort","cols","endsWith","base","leaf","pop","some","orderableChildSort","childModel","_sub","scalarFields","Set","Object","keys","fields","size","has","applyValueLabelColumns","row","out","values","toValueLabel","ReadRepository","prismaModel","prisma","config","listSelect","oneSelect","toId","id","idType","String","buildWhere","projection","op","select","safeSort","sortDir","buildSort","decorate","rows","hook","hooks","afterRead","hooked","Promise","all","valueLabelColumns","r","decorateOne","findAll","params","subResources","query","where","take","pageSize","skip","offset","page","orderBy","countClause","fromEntries","s","relation","_count","assign","findMany","mapped","counts","withCalc","mergeCalculatedColumnsForRows","calculatedColumns","model","count","findOne","formIncludes","includeInFindOne","idField","flatIncludes","configInclude","buildIncludeClause","include","mergedInclude","record","findUnique","NotFoundException","name","enriched","sub","nested","Array","isArray","enrichedNested","findAllByParent","parentId","childRoute","find","Error","foreignKey","includeClause","childSort","data","buildChildSortClause","decorated","labeled","findOneChild","childId","findFirst","import_zod","dateOverride","zodSchema","jsonSchema","z","ZodDate","type","format","jsonSchemaOpts","unrepresentable","override","isZodSchema","schema","ZodObject","isNullableProperty","property","anyOf","Array","isArray","some","s","dropNullableFromRequired","properties","required","filter","key","toJsonSchema","toJSONSchema","target","unwrap","t","_zod","def","innerType","typeOf","toSelectFields","Object","keys","reduce","acc","result","value","entries","shape","inner","select","element","import_common","PRISMA_NOT_FOUND_CODE","DEFAULT_ID_FIELD","normalizeValueLabels","data","cols","Array","isArray","length","out","field","fromValueLabel","includeRelationNames","include","Set","map","e","relation","WriteRepository","prismaModel","prisma","config","toId","id","idType","String","notFound","NotFoundException","name","stripSubResourceKeys","subKeys","subResources","s","column","size","Object","fromEntries","entries","filter","k","has","stripNonCreateableChildFields","sub","nonCreateable","views","form","columns","c","createable","prepare","op","normalized","valueLabelColumns","hook","hooks","beforeWrite","postWrite","result","afterWrite","upsertWhere","keys","upsertOnFor","resolveDefinition","BadRequestException","composite","join","create","update","idField","where","code","PRISMA_NOT_FOUND_CODE","upsert","existing","findFirst","prepared","DEFAULT_ID_FIELD","undefined","upsertMany","rows","Promise","all","r","delete","createChild","parentId","childModel","Error","stripped","payload","foreignKey","includeKeys","prismaData","updateChild","childId","afterHook","childRoute","deleteChild","deleteMany","count","createCrudRepository","prisma","config","model","Error","name","definition","resolveDefinition","listSchema","schemaFor","oneSchema","listSelect","toSelectFields","undefined","oneSelect","reader","ReadRepository","writer","WriteRepository","findAll","bind","count","findOne","findAllByParent","findOneChild","create","update","upsert","upsertMany","delete","createChild","updateChild","deleteChild","import_common","DataSourceRegistry","clients","Map","defaultName","entries","entry","set","config","name","client","default","length","get","Error","getDefault","resolve","database","onModuleDestroy","values","$disconnect","loadDataSourcesFromDir","dirPath","existsSync","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","name","results","dir","basePath","join","jsonFile","config","JSON","parse","readFileSync","indexFile","findModule","mod","client","default","push","ext","p","undefined","import_common","import_swagger","def","cls","method","fn","Object","defineProperty","prototype","value","writable","configurable","desc","getOwnPropertyDescriptor","registerActionRoutes","ctx","cls","config","name","procedureActions","actions","filter","a","type","action","methodName","id","def","recordId","procedure","repo","prisma","d","desc","Post","prototype","Param","ApiOperation","summary","label","ApiParam","ApiResponse","status","description","registerTableActionRoutes","tableActions","import_common","import_swagger","RequestDtoNoOffset","createZodDto","RequestSchema","RequestDto","RequestSchemaWithOffset","ZodValidationPipe","nullableKeys","coerceUndefinedToNull","schema","options","Object","entries","shape","filter","field","safeParse","success","map","key","coerceNullableUndefinedToNull","transform","value","stripped","stripEmptyStrings","input","coerceNullable","result","CroutonValidationError","formatErrors","error","data","Array","isArray","out","keys","includes","undefined","issues","e","path","join","message","registerFindAll","ctx","isOperationEnabled","definition","cls","config","listSchema","name","lookupLabel","lookup","label","def","params","q","effectiveParams","filter","data","count","Promise","all","repo","findAll","totalPages","Math","max","ceil","pageSize","request","page","sort","sortDir","d","desc","Get","prototype","Query","ZodValidationPipe","RequestDtoNoOffset","zodSchema","ApiOperation","summary","ApiResponse","status","description","schema","type","items","toJsonSchema","registerFindOne","oneSchema","idParamMeta","id","findOne","Param","ApiParam","ApiNotFoundResponse","registerCreate","createSchema","bodyDecorator","body","create","Post","coerceNullableUndefinedToNull","ApiBody","registerUpdate","updateSchema","update","Patch","registerUpsert","upsertSchema","upsert","Put","registerDelete","delete","Delete","import_common","import_swagger","resolveEnvPlaceholders","value","replace","match","varName","process","env","buildSubResourceOperations","ops","baseUri","idField","idPlaceholder","findAll","uri","method","findOne","create","update","delete","RESOURCE_OPS","OP_METHOD","OP_SUFFIX","buildResourceOperations","definition","Object","fromEntries","filter","op","isOperationEnabled","map","buildDefinitionPayload","config","route","name","tag","idType","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","upsertSchema","operations","upsertOn","upsertOnFor","schemas","toJsonSchema","upsert","buildResourceJsonPayload","baseUrl","lookup","form","views","schema","json_schema","data","ui","ui_schema","id","buildViewsPayload","keys","length","undefined","entries","key","v","defaultSort","title","modalSize","display","actions","a","type","label","href","condition","tableActions","icon","tooltip","registerDefinitionEndpoint","ctx","cls","config","route","name","definitionPayload","buildDefinitionPayload","def","IS_DEV","fresh","configRegistry","getByRoute","d","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","registerSchemasEndpoint","baseUrl","viewsPayload","buildViewsPayload","registerResourceJsonEndpoint","resourceJsonPayload","buildResourceJsonPayload","import_common","import_swagger","registerSubResourceSchemas","ctx","sub","views","cls","config","baseUrl","route","methodName","childRoute","childUri","schemasPayload","id","name","uri","title","idField","idType","modalSize","operations","buildSubResourceOperations","schemas","Object","fromEntries","entries","map","key","v","data","json_schema","ui","ui_schema","defaultSort","undefined","actions","length","a","type","label","href","resolveEnvPlaceholders","condition","method","def","ds","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","registerSubResourceFindAll","findAll","idParamMeta","params","count","repo","findAllByParent","totalPages","Math","max","ceil","pageSize","request","page","sort","sortDir","filter","d","Param","Query","ZodValidationPipe","RequestDtoNoOffset","zodSchema","ApiParam","registerSubResourceCreate","create","body","createChild","Post","Body","registerSubResourceFindOne","findOne","parentId","childId","findOneChild","registerSubResourceUpdate","update","_id","updateChild","Patch","registerSubResourceDelete","delete","deleteChild","Delete","registerSubResourceRoutes","subResources","createCrudController","config","baseUrl","route","name","tag","idType","definition","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","upsertSchema","isOperationEnabled","upsertOnFor","Error","bodyDecorator","schema","options","Body","isZodSchema","ZodValidationPipe","CrudControllerBase","repo","configRegistry","registry","prisma","resolve","database","createCrudRepository","ctx","cls","idParamMeta","type","registerFindAll","registerDefinitionEndpoint","registerSchemasEndpoint","registerResourceJsonEndpoint","registerActionRoutes","registerTableActionRoutes","registerSubResourceRoutes","registerFindOne","registerCreate","registerUpdate","registerUpsert","registerDelete","Controller","ApiTags","Object","defineProperty","value","charAt","toUpperCase","slice","Reflect","defineMetadata","DataSourceRegistry","ResourceConfigRegistry","import_node_fs","import_node_path","_require","createRequire","url","findModule","dir","name","ext","p","join","existsSync","undefined","IS_VITE","globalThis","__vite_ssr_import__","importDefault","filePath","importPath","IS_DEV","Date","now","mod","default","import_node_path","loadActions","jsonActions","basePath","results","action","type","push","id","label","href","condition","file","findModule","join","procedure","console","warn","mod","importDefault","method","data","loadTableActions","icon","tooltip","import_node_fs","import_node_path","ENUMS_FILE","loadEnumRegistry","startDir","enumsFile","file","dir","candidate","join","existsSync","parent","dirname","JSON","parse","readFileSync","injectEnumValues","columns","enums","col","enum","values","fieldInput","type","options","import_zod","pickByColumns","schema","columns","filter","undefined","length","isRelation","c","fieldInput","format","baseFilter","filtered","mask","Object","fromEntries","map","id","pick","opWithSchema","enabled","upsertOp","entry","Error","upsertOn","import_zod","buildConditionSchema","when","notExists","not","minLength","exists","neq","undefined","const","eq","buildRule","col","disabledWhen","effect","condition","scope","field","schema","showWhen","hideWhen","buildDetailLayout","detail","inner","layout","LayoutBuilder","collapse","horizontal","addControls","controls","map","dc","ctrl","ControlBuilder","properties","property","type","markdown","options","control","hideLabel","width","titleKey","buildFormControl","id","fieldInput","format","colspan","relationType","detailLayout","detailFixed","customRender","setCustomRender","buildFormUiSchema","cols","grid","build","colMap","Object","fromEntries","c","elements","el","replace","rule","label","allowAdditionalProperties","schema","props","value","Object","values","isNullableProperty","prop","anyOf","Array","isArray","some","s","dropNullableFromRequired","required","filter","key","enforceRequiredMinLength","isBoolean","col","fieldInput","type","columnType","isRelation","format","isAutocomplete","isRecordCell","isDateRange","deriveSortId","sortable","sortId","base","column","id","fi","opts","options","relationType","resource","key","displayKey","undefined","labelKey","path","includes","endsWith","slice","length","isValueLabel","enum","emitObject","resolveDefaultSort","tableCols","allColumns","isSortable","c","sortCol","find","defaultSort","idField","SHARED_CELL_OPTION_KEYS","pickSharedCellOptions","Object","fromEntries","filter","map","buildTableUiSchema","cols","layout","TableBuilder","init","addControls","cellBuilder","BooleanCellBuilder","TextCellBuilder","builder","properties","setSortId","build","colMap","elements","el","scope","replace","fieldInputOptions","dataPathOption","dataPath","derivedSortId","sortOptions","relationTypeOption","label","patchFilterProperties","jsonSchema","columns","length","properties","col","fieldInput","format","id","opts","options","base","label","fromField","toField","dateProp","title","type","prop","values","ft","enum","colPosition","i","position","sortByPosition","cols","map","sort","a","b","toViewColumn","sortable","searchable","buildView","schema","visible","buildUiSchema","schemaVisible","undefined","visibleCols","filter","schemaCols","c","schemaIds","mask","Object","fromEntries","picked","pick","toJSONSchema","target","jsonSchemaOpts","allowAdditionalProperties","dropNullableFromRequired","enforceRequiredMinLength","json_schema","ui_schema","isVisibleInMode","mode","hiddenInTable","hiddenInView","buildCalculatedElement","scope","calcPosition","injectCalculatedColumnsIntoView","viewConfig","calculated","uiSchema","existing","elements","tagged","el","pos","Infinity","t","entry","splice","push","injectCalculatedColumns","tableView","injectCalculatedColumnsToView","emptyTableView","additionalProperties","buildTableUiSchema","buildViews","views","table","defaultSort","resolveDefaultSort","form","hiddenInForm","buildFormUiSchema","createable","updateable","filterable","view","keys","buildViewsFromColumns","buildJsonSchema","column","keyPath","displayKey","split","segment","columnType","fixNestedScopes","colMap","replace","propPath","k","join","makeView","tableCols","formCols","viewCols","viewView","import_node_fs","import_node_path","resolveChildResource","resourcePath","parentDir","directPath","resolve","endsWith","existsSync","json","JSON","parse","readFileSync","dir","dirname","undefined","childName","replace","childJsonPath","expandExtendColumns","columns","dirPath","result","col","extend","push","resolved","console","warn","id","refColumns","normalizeColumns","parentColumnKey","column","refCol","idField","virtualId","displayKey","hiddenInTable","hiddenInForm","hiddenInView","override","virtualCol","label","columnType","sortable","fieldInput","buildValueLabelColumns","flatMap","c","opts","options","emitObject","Array","isArray","values","field","applyRelationFormatDefault","cols","map","fi","resource","format","type","deriveRelationTypeFromColumns","base","fkNames","Set","some","has","enrichNestedRelationColumns","baseUrl","targetRoute","route","relationType","uri","resourceUri","buildSubResources","parentRoute","parentModel","enums","filter","childResolved","childJson","childDir","childRoute","rawChildColumns","expandedChildColumns","childColumns","injectEnumValues","enrichedChildColumns","childLookupKey","find","childCalculatedColumns","calculatedColumns","childViews","buildViewsFromColumns","length","table","injectCalculatedColumns","view","injectCalculatedColumnsToView","childOps","operations","relation","childModel","foreignKey","name","title","tag","idType","views","findAll","findOne","create","update","delete","actions","modalSize","include","includeInFindOne","valueLabelColumns","enrichActionColumns","subResources","sub","s","enrichResourceRefColumns","schemasUri","enrichIncludeWithSort","entry","relationName","sort","orderBy","buildChildSortClause","sortDir","fromJson","schema","hooks","tableActions","rawColumns","enrichRelationTypes","model","enrichedColumns","picked","pickByColumns","createSchema","createable","updateSchema","updateable","buildViews","lookup","buildLookup","enrichedInclude","definition","opWithSchema","upsertOp","upsert","display","mode","customComponent","sidebar","key","database","unwrapZodType","ZodOptional","ZodNullable","unwrap","deriveRelationType","columnId","shape","inner","ZodArray","isRelationField","derived","keyCol","labelCol","showInLookup","searchable","import_node_fs","import_node_path","loadSubResourceHooks","subResources","basePath","sub","file","name","findModule","join","undefined","hooks","importDefault","loadResourceConfigsFromDir","dirPath","baseUrl","enumsFile","enums","loadEnumRegistry","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","configs","dir","schemaFile","schema","hooksFile","jsonFile","existsSync","json","JSON","parse","readFileSync","actions","loadActions","tableActions","loadTableActions","config","fromJson","push","tsFile","ResourceConfigLoader","FileSystemResourceConfigLoader","ResourceConfigLoader","dirPath","baseUrl","enumsFile","loadAll","loadResourceConfigsFromDir","loadByRoute","route","configs","find","c","CroutonApiModule","forResources","configs","dataSources","loader","config","dataSourceRegistry","DataSourceRegistry","configRegistry","ResourceConfigRegistry","controllers","map","c","createCrudController","baseUrl","createAppLayoutController","sidebarGroups","title","autoSave","module","providers","provide","APP_FILTER","useClass","CroutonValidationExceptionFilter","useValue","forResourceDir","dirPath","dataSourcesPath","FileSystemResourceConfigLoader","enumsFile","loadResourceConfigsFromDir","loadDataSourcesFromDir","forLoader","exports"]}
|