@ghentcdh/crouton-api 0.0.1-alpha.74 → 0.0.1-alpha.75
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.map +1 -1
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
package/dist/index.cjs.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.4.0__@swc+core@1.16.1_@swc+he_9a17c50ee76d0369ad0c28a18d209a0d/node_modules/tsup/assets/cjs_shims.js","../../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/schema.utils.ts","../../crouton-core/src/lib/layout/base.builder.ts","../../crouton-core/src/lib/layout/control.builder.ts","../../crouton-core/src/lib/layout/layout.options.ts","../../crouton-core/src/lib/layout/layout.builder.ts","../../crouton-core/src/lib/value-label.ts","../../crouton-core/src/lib/table/table.builder.ts","../../crouton-core/src/lib/compile/action.types.ts","../../crouton-core/src/lib/resource/Layout.schema.ts","../../crouton-core/src/lib/resource/ResourceJson.schema.ts","../../crouton-core/src/lib/resource/CalculatedColumn.schema.ts","../../crouton-core/src/lib/resource/FieldInput.schema.ts","../../crouton-core/src/lib/schema/label.helper.ts","../../crouton-core/src/lib/resource/Column.ts","../../crouton-core/src/lib/resource/ColumnType.schema.ts","../../crouton-core/src/lib/resource/ParentRef.schema.ts","../../crouton-core/src/lib/resource/ResourceKind.ts","../../crouton-core/src/lib/resource/Sidebar.schema.ts","../../crouton-core/src/lib/resource/TableAction.schema.ts","../../crouton-core/src/lib/resource/extensions.ts","../../crouton-core/src/lib/resource/include.schema.ts","../../crouton-core/src/lib/resource/version.ts","../../crouton-core/src/lib/data-source/Operations.schema.ts","../../crouton-core/src/lib/data-source/Security.schema.ts","../../crouton-core/src/lib/resource/migrations/types.ts","../../crouton-core/src/lib/resource/migrations/index.ts","../../crouton-core/src/lib/resource/fieldVariants.ts","../../crouton-core/src/lib/view/column-predicates.ts","../../crouton-core/src/lib/view/column.utils.ts","../../crouton-core/src/lib/view/sort.helpers.ts","../../crouton-core/src/lib/view/schema-transforms.ts","../../crouton-core/src/lib/view/table-schema.builder.ts","../../crouton-core/src/lib/view/form-schema.builder.ts","../../crouton-core/src/lib/view/calculated-columns.builder.ts","../../crouton-core/src/lib/view/view.builder.ts","../../crouton-core/src/lib/view/column-type-schema.source.ts","../../crouton-core/src/lib/view/json-schema.opts.ts","../../crouton-core/src/lib/view/layout-ui-schema.builder.ts","../../crouton-core/src/lib/view/layout-table-order.ts","../../crouton-core/src/lib/view/view.schema.ts","../../crouton-core/src/lib/compile/enum-registry.ts","../../crouton-core/src/lib/compile/relation-type.ts","../../crouton-core/src/lib/compile/compiled-resource.schema.ts","../../crouton-core/src/lib/compile/compiled-sub-resource.schema.ts","../../crouton-core/src/lib/data-source/DataSourceSchema.ts","../../crouton-core/src/lib/compile/value-label-column.ts","../../crouton-core/src/lib/compile/definition.schema.ts","../../crouton-core/src/lib/compile/schema-input.ts","../../crouton-core/src/lib/compile/lookup.schema.ts","../../crouton-core/src/lib/compile/to-json-schema.ts","../../crouton-core/src/lib/config/CroutonConfig.schema.ts","../../crouton-core/src/lib/config/readConfig.ts","../../crouton-core/src/lib/i18n/Translations.schema.ts","../../crouton-core/src/lib/i18n/translation-keys.ts","../../crouton-core/src/lib/i18n/translator.ts","../../crouton-core/src/lib/i18n/negotiate.ts","../src/lib/crouton-api.module.ts","../src/lib/crud/app-layout/app-layout.types.ts","../src/lib/crud/app-layout/app-layout.builder.ts","../src/lib/crud/app-layout/app-layout.controller.ts","../src/lib/crud/dev-mode.ts","../src/lib/crud/resource-config.registry.ts","../src/lib/crud/resource/ReadResourceJson.ts","../src/lib/crud/adapter/resource-resolver.ts","../src/lib/crud/adapter/column-transforms.ts","../src/lib/crud/translation/localize-resource.ts","../src/lib/crud/translation/language.context.ts","../src/lib/crud/config/read.ts","../src/lib/crud/crouton-validation.filter.ts","../src/lib/crud/crouton-validation.error.ts","../src/lib/crud/translation/translation.loader.ts","../src/lib/crud/translation/translation.registry.ts","../src/lib/crud/crud-controller.factory.ts","../src/lib/crud/crud-repository.factory.ts","../src/lib/crud/action/action.types.ts","../src/lib/crud/loader/module.loader.ts","../src/lib/crud/action/action.loader.ts","../src/lib/crud/crud.config.ts","../src/lib/crud/custom-repository/custom-repository.types.ts","../src/lib/crud/resource/resource-load-errors.registry.ts","../src/lib/crud/custom-repository/custom-repository.loader.ts","../src/lib/crud/custom-repository/custom-repository.adapter.ts","../src/lib/crud/constants.ts","../src/lib/crud/data-source/prisma.adapter.ts","../src/lib/crud/read.repository.ts","../src/lib/crud/custom-repository/child-delegate.ts","../src/lib/crud/resource/valueLabel.apply.ts","../src/lib/crud/sql.helpers.ts","../src/lib/crud/translation/language.interceptor.ts","../src/lib/crud/translation/resolve-value-labels.ts","../src/lib/crud/write.repository.ts","../src/lib/crud/hooks/hooks.types.ts","../src/lib/crud/hooks/hooks.loader.ts","../src/lib/crud/hooks/hooks.apply.ts","../src/lib/crud/custom-repository/custom-repository.validate.ts","../src/lib/crud/schema.utils.ts","../src/lib/crud/data-source/data-source.registry.ts","../src/lib/crud/data-source/data-source.loader.ts","../src/lib/crud/data-source/in-memory.adapter.ts","../src/lib/crud/operations/register-actions.ts","../src/lib/crud/security/crouton-security.guard.ts","../src/lib/crud/security/security-guard.registry.ts","../src/lib/crud/operations/decorator.utils.ts","../src/lib/crud/operations/register-create.ts","../src/lib/crud/operations/register-delete.ts","../src/lib/crud/operations/register-findall.ts","../src/lib/crud/request.dto.ts","../src/lib/crud/zod-validation.pipe.ts","../src/lib/crud/operations/register-findone.ts","../src/lib/crud/operations/register-patch.ts","../src/lib/crud/operations/register-schema-endpoints.ts","../src/lib/crud/resource/PatchResourceJson.schema.ts","../src/lib/crud/resource/WriteResourceJson.ts","../src/lib/crud/operations/payload-builders.ts","../src/lib/crud/operations/register-schemas.ts","../src/lib/crud/operations/register-update.ts","../src/lib/crud/operations/register-endpoints.ts","../src/lib/crud/dev-tools/dev-resources.controller.ts","../../crouton-codegen/src/naming.ts","../../crouton-codegen/src/introspect.ts","../../crouton-codegen/src/classify.ts","../../crouton-codegen/src/util.ts","../../crouton-codegen/src/diff.ts","../../crouton-codegen/src/resolve.ts","../../crouton-codegen/src/serialize.ts","../../crouton-codegen/src/apply.ts","../../crouton-codegen/src/commit.ts","../../crouton-codegen/src/config.ts","../../crouton-codegen/src/scaffold.ts","../../crouton-codegen/src/datasource-scaffold.ts","../../crouton-codegen/src/project.ts","../../crouton-codegen/src/plan.ts","../../crouton-codegen/src/prisma-shell.ts","../src/lib/crud/resource/ResourceFlags.ts","../src/lib/crud/resource/resource-load-report.registry.ts","../src/lib/crud/enum-registry/enum-registry.types.ts","../src/lib/crud/enum-registry/enum-registry.loader.ts","../src/lib/crud/enum-registry/enum-registry.injector.ts","../src/lib/crud/interceptors/no-cache.interceptor.ts","../src/lib/crud/builder/schema.helpers.ts","../src/lib/crud/adapter/relation-type.ts","../src/lib/crud/adapter/column-enrichment.ts","../src/lib/crud/adapter/sub-resource.builder.ts","../src/lib/crud/adapter/json-adapter.ts","../src/lib/crud/resource/MigrateResourceJson.ts","../src/lib/crud/resource/resource-config.validator.ts","../src/lib/crud/loader/index.ts","../src/lib/crud/loader/resource-config.loader.ts","../src/lib/crud/loader/fs-resource-config.loader.ts","../src/lib/crud/status/status.service.ts","../src/lib/crud/status/status.controller.ts","../src/lib/crud/parse-schema.ts"],"sourcesContent":["export { buildViews } from '@ghentcdh/crouton-core';\n\nexport * from './lib/crouton-api.module';\nexport type { CroutonAppConfig } from './lib/crud/app-config';\nexport {\n type ParseAppConfig,\n type ParseSchemaInput,\n type ParseSchemaView,\n parseSchema,\n} from './lib/crud/parse-schema';\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';\nexport * from './lib/crud/hooks';\nexport * from './lib/crud/security';\n\n// Types a consumer needs to type their own `repository.ts` on a\n// `kind: \"custom\"` resource.\nexport {\n type CustomListResult,\n type CustomOp,\n type CustomRepository,\n type CustomRepositoryContext,\n} from './lib/crud/custom-repository';\n\n// Filter-grammar helpers, so a custom repository can reuse the\n// `field:value:operator` parsing instead of reimplementing it.\nexport {\n buildFilterWhere,\n parseFilterString,\n} from './lib/crud/read.repository';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\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 q: z.string().optional(),\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\nexport type ListRequestWithOffset = z.infer<typeof RequestSchemaWithOffset>;\n\n/**\n * Zero-based row offset for a list request.\n *\n * Controllers validate query params with `RequestSchema` (no `offset`), while\n * `RequestSchemaWithOffset` adds one — so consumers cannot rely on the field\n * being present. Derive it here instead of duplicating the arithmetic at every\n * call site.\n */\nexport const offsetOf = (params: ListRequest): number =>\n (params as Partial<ListRequestWithOffset>).offset ??\n (params.page - 1) * params.pageSize;\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","/**\n * Browser-safe JSON Schema utilities shared across crouton-core and crouton-api.\n *\n * Keep this file free of Node-only imports. Zod-specific conversion lives in\n * compile/to-json-schema.ts; mutable view-build transforms live in\n * view/schema-transforms.ts.\n */\n\nimport type { JsonSchema } from '@jsonforms/core';\n\ntype Field = { scope: string };\n\n/**\n * Returns true when a JSON Schema property represents a nullable field.\n * Handles both Zod v4 (`\"type\": [\"string\",\"null\"]`) and the older\n * anyOf `[{type:\"string\"},{type:\"null\"}]` format.\n */\nexport const isNullableProperty = (property: unknown): boolean => {\n const prop = property as Record<string, unknown> | undefined;\n if (!prop) return false;\n if (Array.isArray(prop['type']) && (prop['type'] as string[]).includes('null')) return true;\n const anyOf = prop['anyOf'];\n return Array.isArray(anyOf) && anyOf.some((s: Record<string, unknown>) => s?.['type'] === 'null');\n};\n\n/**\n * Recursively drop nullable fields from `required`. A nullable field\n * (anyOf with a `{ type: \"null\" }` branch) should be treated as optional.\n */\nexport const dropNullableFromRequired = (schema: JsonSchema): JsonSchema => {\n if (!schema?.properties) return schema;\n\n const required = schema.required as string[] | undefined;\n if (!Array.isArray(required) || required.length === 0) return schema;\n\n const filteredRequired = required.filter(\n (key) => !isNullableProperty(schema.properties![key]),\n );\n\n if (filteredRequired.length === required.length) return schema;\n\n return { ...schema, required: filteredRequired } as JsonSchema;\n};\n\nexport const enforceRequiredStringMinLength = (schema: JsonSchema): JsonSchema => {\n if (!schema?.properties) return schema;\n const patchedProperties = { ...schema.properties };\n let changed = false;\n for (const key of Object.keys(patchedProperties)) {\n const prop = patchedProperties[key];\n if (!prop || typeof prop !== 'object') continue;\n if (prop.type === 'string' && prop.minLength === undefined) {\n patchedProperties[key] = { ...prop, minLength: 1 };\n changed = true;\n } else if (prop.type === 'object') {\n const patched = enforceRequiredStringMinLength(prop as JsonSchema);\n if (patched !== prop) { patchedProperties[key] = patched; changed = true; }\n }\n }\n return changed ? ({ ...schema, properties: patchedProperties } as JsonSchema) : schema;\n};\n\n/**\n * Resolve a column's scope to its schema property.\n *\n * Scopes may be nested (`#/properties/author/properties/name`, produced for\n * `extend` columns and inline object types). Previously only the\n * `#/properties/` prefix was stripped, so a nested scope yielded the id\n * `\"author/properties/name\"` and an empty property — leaving such columns with\n * no schema type at all. Each `properties/<key>` segment is now walked.\n */\nexport const findProperty = <F extends Field>(column: F, schema: JsonSchema) => {\n if (!column.scope) return { id: null, property: null };\n const id = column.scope.substring('#/properties/'.length);\n const segments = id.split('/properties/');\n\n let property: any = schema?.properties?.[segments[0]] ?? {};\n for (const segment of segments.slice(1)) {\n property = property?.properties?.[segment] ?? {};\n }\n\n return { id, property } as { id: string; property: any };\n};\n","import type {\n Layout,\n Rule,\n RuleEffect,\n SchemaBasedCondition,\n UISchemaElement,\n} from '@jsonforms/core';\n\nimport type { CroutonElementOptions, CroutonLayoutOptions } from './layout.options';\n\n/** Anything that can be built into a JSON Forms UI-schema element. */\nexport type Buildable = { build(): UISchemaElement };\n\n/**\n * Options for the string form of `addControl`. `type` selects the control format\n * (e.g. `textarea`, `boolean`, `relation`); omit it for a plain control. Every other\n * key is a normal element option (`label`, `colspan`, `styles`).\n */\nexport type ControlShortcut = CroutonElementOptions & { type?: string };\n\n/** Effect names for a rule; kept as string literals so no runtime enum import is needed. */\nexport type RuleEffectName = 'SHOW' | 'HIDE' | 'ENABLE' | 'DISABLE';\n\n/** Minimal base: a typed discriminator plus a `build()` contract. */\nexport abstract class Builder<OUT> {\n protected constructor(protected readonly type: string) {}\n abstract build(): OUT;\n}\n\n/**\n * Base for elements that carry a typed `options` bag and an optional JSON Forms `rule`.\n *\n * `label` / `colspan` and the `showWhen` / `hideWhen` / `disableWhen` helpers are shared by\n * every layout and control, so labels and conditional rules are expressed in the builder\n * chain instead of being mutated onto the built object afterwards.\n */\nexport abstract class ElementBuilder<\n OUT extends UISchemaElement,\n OPT extends CroutonElementOptions = CroutonElementOptions,\n> extends Builder<OUT> {\n protected options: Partial<OPT> = {};\n protected _rule?: Rule;\n\n label(label: string): this {\n return this.opt({ label } as Partial<OPT>);\n }\n\n colspan(colspan: number): this {\n return this.opt({ colspan } as Partial<OPT>);\n }\n\n rowspan(rowspan: number): this {\n return this.opt({ rowspan } as Partial<OPT>);\n }\n\n showWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('SHOW', scope, schema);\n }\n\n hideWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('HIDE', scope, schema);\n }\n\n disableWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('DISABLE', scope, schema);\n }\n\n rule(effect: RuleEffectName, scope: string, schema: Record<string, unknown>): this {\n this._rule = {\n effect: effect as RuleEffect,\n condition: { scope, schema } as SchemaBasedCondition,\n };\n return this;\n }\n\n /** Merge a patch into the typed options bag. */\n opt(patch: Partial<OPT>): this {\n this.options = { ...this.options, ...patch };\n return this;\n }\n\n /** `options` / `rule` fields, emitted only when non-empty. */\n protected baseFields(): { options?: Partial<OPT>; rule?: Rule } {\n return {\n ...(Object.keys(this.options).length ? { options: this.options } : {}),\n ...(this._rule ? { rule: this._rule } : {}),\n };\n }\n}\n\n/**\n * Base for layouts that hold child elements. Exposes the overloaded `addControl` /\n * `addControls` surface: pass a fully-configured builder, or a bare property name (with\n * optional shortcut options). Each concrete container turns a shortcut into its own leaf\n * builder via `resolveShortcut`, so this base never imports a control/cell builder and\n * there is no dependency cycle.\n */\nexport abstract class ContainerBuilder<\n OUT extends Layout,\n OPT extends CroutonLayoutOptions = CroutonLayoutOptions,\n> extends ElementBuilder<OUT, OPT> {\n protected children: Buildable[] = [];\n\n /** Turn a shortcut (property name + options) into a concrete leaf builder. */\n protected abstract resolveShortcut(name: string, options?: ControlShortcut): Buildable;\n\n addControl(builder: Buildable): this;\n addControl(name: string, options?: ControlShortcut): this;\n addControl(arg: string | Buildable, options?: ControlShortcut): this {\n this.children.push(\n typeof arg === 'string' ? this.resolveShortcut(arg, options) : arg,\n );\n return this;\n }\n\n addControls(...builders: Buildable[]): this;\n addControls(map: Record<string, ControlShortcut | undefined>): this;\n addControls(\n first: Buildable | Record<string, ControlShortcut | undefined>,\n ...rest: Buildable[]\n ): this {\n if (first && typeof first === 'object' && !('build' in first)) {\n for (const [name, options] of Object.entries(first)) {\n this.addControl(name, options);\n }\n } else if (first) {\n for (const builder of [first as Buildable, ...rest]) {\n this.addControl(builder);\n }\n }\n return this;\n }\n\n protected buildElements(): UISchemaElement[] {\n return this.children.map((child) => child.build());\n }\n}\n","import type { UISchemaElement } from '@jsonforms/core';\n\nimport { ElementBuilder } 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 object: 'object',\n custom: 'custom',\n select: 'select',\n mutliSelect: 'mutliSelect',\n toggle: 'toggle',\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 DateOptions extends ControlOption {\n /** `date` renders a day only, `dateTime` adds a time. @default 'date' */\n format: 'date' | 'dateTime';\n /**\n * Force the time on or off, overriding `format`. Useful for a Prisma\n * `DateTime` column that should be edited as a plain day.\n */\n withTime?: boolean;\n /** Earliest selectable date, ISO or `yyyy-MM-dd`. */\n min?: string;\n /** Latest selectable date, ISO or `yyyy-MM-dd`. */\n max?: string;\n /** BCP-47 locale for the month heading and weekday labels. @default 'en-GB' */\n locale?: string;\n /** 0 = Sunday, 1 = Monday. @default 1 */\n firstDayOfWeek?: number;\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\n/**\n * A single-select control rendered as a row of buttons where exactly one\n * option is shown as active. Same data shape and option sources as\n * {@link SelectOptions}; only the presentation differs.\n */\nexport interface ToggleOptions extends ControlOption {\n format: 'toggle';\n options?: Array<any>;\n values?: Array<any>;\n labelKey?: string;\n valueKey?: string;\n /** Store `option[valueKey]` instead of the whole option object. */\n storeValue?: boolean;\n /** Clicking the active button clears the value. @default true */\n clearable?: boolean;\n /** `Btn` color for the active button. @default 'primary' */\n color?: string;\n /** `Btn` size. @default 'sm' */\n size?: 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 | AutocompleteRemoteOptions | 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 /** date: force the time input on or off, overriding `format`. */\n withTime?: boolean;\n /** date: earliest selectable date, ISO or `yyyy-MM-dd`. */\n min?: string;\n /** date: latest selectable date, ISO or `yyyy-MM-dd`. */\n max?: string;\n /** date: BCP-47 locale for the month heading and weekday labels. */\n locale?: string;\n /** date: first day of the week, 0 = Sunday, 1 = Monday. */\n firstDayOfWeek?: number;\n customRender?: any;\n colspan?: number;\n rowspan?: number;\n}\n\nexport type ControlTypes = {\n type: 'Control' | 'Object' | 'TextCell';\n scope: string;\n options?: TextAreaOptions | AutocompleteOptions | DetailOptions;\n};\n\nexport class ControlBuilder<TYPE, KEY = keyof TYPE> extends ElementBuilder<\n UISchemaElement,\n ControlOption\n> {\n private _detail?: LayoutBuilder<any>;\n\n private constructor(\n private readonly scope: string,\n type = 'Control',\n ) {\n super(type);\n this.opt({ format: 'Control', styles: {} });\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.opt({\n format: ControlType.custom,\n type,\n } as unknown as Partial<ControlOption>);\n\n return builder;\n }\n\n setCustomRender(customRender: string) {\n this.opt({ customRender });\n\n return this;\n }\n\n detail<TYPE>(layoutBuilder: LayoutBuilder<TYPE>, label?: string) {\n this._detail = layoutBuilder;\n this.opt({\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.opt({ 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.opt({\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.opt({ labelKey });\n }\n\n readonly(): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.string,\n readonly: true,\n });\n }\n\n link(): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.link,\n });\n }\n\n markdown(options?: Omit<MarkdownOptions, 'format'>): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.markdown,\n ...(options ?? {}),\n });\n }\n\n /**\n * Render a datepicker. Defaults to a day-only picker; pass\n * `{ format: 'dateTime' }` (or `{ withTime: true }`) to include a time.\n */\n date(options?: Partial<DateOptions>) {\n return this.opt({\n format: ControlType.date,\n ...(options ?? {}),\n });\n }\n\n textArea(options?: Omit<TextAreaOptions, 'format'>) {\n return this.opt({\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.opt({\n format: ControlType.autocomplete,\n dataField: 'data',\n ...(options ?? {}),\n });\n }\n\n control(format: string, options?: Partial<ControlOption>) {\n return this.opt({\n format,\n ...options,\n });\n }\n\n select(options: Omit<SelectOptions, 'format'>) {\n return this.opt({\n format: ControlType.select,\n ...options,\n });\n }\n\n mutliSelect(options: Omit<SelectOptions, 'format'>) {\n return this.opt({\n format: ControlType.mutliSelect,\n ...options,\n });\n }\n\n toggle(options: Omit<ToggleOptions, 'format'>) {\n return this.opt({\n format: ControlType.toggle,\n ...options,\n });\n }\n\n width(width: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full' | (string & {})) {\n const named = ['xs', 'sm', 'md', 'lg', 'xl', 'full'];\n const isNamed = named.includes(width);\n return this.opt({\n styles: {\n ...this.options?.styles,\n width,\n control: {\n wrapper: isNamed ? `input-${width}` : width,\n },\n },\n });\n }\n\n customLabel(label: string) {\n return this.opt({ label });\n }\n\n placeHolder(placeholder: string) {\n return this.opt({ placeholder });\n }\n\n hideLabel() {\n return this.opt({ hideLabel: true });\n }\n\n override build(): ControlTypes {\n const detail = this._detail ? this._detail.build() : undefined;\n const options = {\n ...this.options,\n ...(detail ? { detail } : {}),\n };\n return {\n type: this.type,\n scope: this.scope,\n options,\n ...(this._rule ? { rule: this._rule } : {}),\n } as unknown as ControlTypes;\n }\n}\n","/**\n * Typed options for crouton UI-schema elements.\n *\n * These type the `options` bag of a standard `@jsonforms/core` element — the builders\n * still emit plain `Layout` / `UISchemaElement` objects (exactly the shape\n * `JsonFormsLayout.uiSchema` consumes), so nothing about the output contract changes.\n */\n\n/** Crouton layout types layered on top of the JSON Forms defaults. */\nexport const LayoutType = {\n Horizontal: 'HorizontalLayout',\n Vertical: 'VerticalLayout',\n Grid: 'GridLayout',\n Collapse: 'CollapseLayout',\n Group: 'GroupLayout',\n} as const;\n\nexport type LayoutType = (typeof LayoutType)[keyof typeof LayoutType];\n\n/** Options shared by every UI element. `colspan`/`rowspan` are crouton-custom (read by the renderers). */\nexport interface CroutonElementOptions {\n label?: string;\n /** 1..12 column span, mapped to a Tailwind class by the layout renderers. */\n colspan?: number;\n /** Row span for CSS grid; mapped to a Tailwind `row-span-*` class. */\n rowspan?: number;\n styles?: Record<string, unknown>;\n}\n\n/** Layout-only options. Collapse uses `title` / `titleKey`; Grid carries the column count. */\nexport interface CroutonLayoutOptions extends CroutonElementOptions {\n title?: string;\n titleKey?: string;\n columns?: number;\n}\n","import type { Layout } from '@jsonforms/core';\n\nimport type { Buildable, ControlShortcut } from './base.builder';\nimport { ContainerBuilder } from './base.builder';\nimport { ControlBuilder } from './control.builder';\nimport type { ControlOption } from './control.builder';\nimport { LayoutType } from './layout.options';\nimport type { CroutonLayoutOptions } from './layout.options';\n\n/**\n * Property name for the `addControl` shortcut. Known keys of `TYPE` get autocomplete and\n * typo-checking; any string is still accepted so the shortcut works without a generic.\n */\ntype Name<TYPE> = (keyof TYPE & string) | (string & {});\n\nexport class LayoutBuilder<TYPE = Record<string, unknown>> extends ContainerBuilder<\n Layout,\n CroutonLayoutOptions\n> {\n private constructor(type: string) {\n super(type);\n }\n\n static horizontal<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Horizontal);\n }\n\n static vertical<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Vertical);\n }\n\n static grid<TYPE = Record<string, unknown>>(columns?: number): LayoutBuilder<TYPE> {\n const layout = new LayoutBuilder<TYPE>(LayoutType.Grid);\n return columns === undefined ? layout : layout.opt({ columns });\n }\n\n static collapse<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Collapse);\n }\n\n static group<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Group);\n }\n\n /** Collapse layout title. */\n title(title: string): this {\n return this.opt({ title });\n }\n\n /** Collapse layout: resolve the title from a field value at render time. */\n titleKey(titleKey: string): this {\n return this.opt({ titleKey });\n }\n\n // Narrow the shortcut name to TYPE's keys (still accepts any string).\n override addControl(builder: Buildable): this;\n override addControl(name: Name<TYPE>, options?: ControlShortcut): this;\n override addControl(arg: string | Buildable, options?: ControlShortcut): this {\n return super.addControl(arg as string, options);\n }\n\n protected resolveShortcut(name: string, options?: ControlShortcut): Buildable {\n const control = ControlBuilder.properties<TYPE>(name as keyof TYPE);\n if (options) {\n const { type, ...rest } = options;\n if (type) control.control(type, rest);\n else if (Object.keys(rest).length) control.opt(rest as Partial<ControlOption>);\n }\n return control;\n }\n\n override build(): Layout {\n return {\n type: this.type,\n elements: this.buildElements(),\n ...this.baseFields(),\n };\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 type { Layout } from '@jsonforms/core';\n\nimport { Builder, ContainerBuilder } from '../layout/base.builder';\nimport type { Buildable } from '../layout/base.builder';\nimport { LayoutType } from '../layout/layout.options';\nimport type { CroutonLayoutOptions } from '../layout/layout.options';\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}\n\n/**\n * Builds a `HorizontalLayout` of table cells. Shares the overloaded\n * `addControl` / `addControls` surface with `LayoutBuilder`; its shortcut form\n * resolves to a `TextCellBuilder` instead of a form control.\n */\nexport class TableBuilder<TYPE = Record<string, unknown>> extends ContainerBuilder<\n Layout,\n CroutonLayoutOptions\n> {\n private constructor() {\n super(LayoutType.Horizontal);\n }\n\n static init<TYPE = Record<string, unknown>>(): TableBuilder<TYPE> {\n return new TableBuilder<TYPE>();\n }\n\n protected resolveShortcut(name: string): Buildable {\n return TextCellBuilder.properties<TYPE>(name as keyof TYPE);\n }\n\n override build(): Layout {\n return {\n type: this.type,\n elements: this.buildElements(),\n ...this.baseFields(),\n };\n }\n}\n","import { z } from 'zod';\n\nimport type { JsonActionCondition } from '../resource/TableAction.schema';\n\nconst ActionMetadataSchema = z.object({\n id: z.string(),\n label: z.string().optional(),\n icon: z.string().optional(),\n tooltip: z.string().optional(),\n condition: z.custom<JsonActionCondition>().optional(),\n});\n\nconst ResourceLinkActionSchema = ActionMetadataSchema.extend({\n type: z.literal('link'),\n href: z.string(),\n});\n\nconst ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n method: z.string().optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n procedure: z.custom<(prisma: any, recordId: string | number) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\nconst ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n method: z.string().optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n procedure: z.custom<(prisma: any) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\nexport type ResourceLinkAction = z.infer<typeof ResourceLinkActionSchema>;\nexport type ResourceRowProcedureAction = z.infer<typeof ResourceRowProcedureActionSchema>;\nexport type ResourceTableProcedureAction = z.infer<typeof ResourceTableProcedureActionSchema>;\n\nexport const ResourceRowActionSchema = z.union([\n ResourceRowProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceRowAction = z.infer<typeof ResourceRowActionSchema>;\n\nexport const ResourceTableActionSchema = z.union([\n ResourceTableProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceTableAction = z.infer<typeof ResourceTableActionSchema>;\n\nexport const isRowProcedureAction = (\n action: ResourceRowAction,\n): action is ResourceRowProcedureAction => action.type !== 'link';\n\nexport const isTableProcedureAction = (\n action: ResourceTableAction,\n): action is ResourceTableProcedureAction => action.type !== 'link';\n","import { z } from 'zod';\n\nexport const LayoutControlSchema = z.union([\n z.string(),\n z.object({\n id: z.string(),\n colspan: z.number().int().min(1).max(12).optional(),\n rowspan: z.number().int().min(1).optional(),\n width: z.string().optional(),\n label: z.string().optional(),\n hideLabel: z.boolean().optional(),\n type: z.string().optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n }),\n]);\n\nexport type LayoutControl = z.infer<typeof LayoutControlSchema>;\n\nexport type LayoutNode = {\n type?: 'grid' | 'vertical' | 'horizontal' | 'collapse' | 'group';\n columns?: number;\n title?: string;\n titleKey?: string;\n colspan?: number;\n rowspan?: number;\n label?: string;\n controls?: LayoutControl[];\n items?: LayoutNode[];\n};\n\nexport const LayoutNodeSchema: z.ZodType<LayoutNode> = z.lazy(() =>\n z.object({\n type: z.enum(['grid', 'vertical', 'horizontal', 'collapse', 'group']).optional(),\n columns: z.number().int().min(1).max(12).optional(),\n title: z.string().optional(),\n titleKey: z.string().optional(),\n colspan: z.number().int().min(1).max(12).optional(),\n rowspan: z.number().int().min(1).optional(),\n label: z.string().optional(),\n controls: z.array(LayoutControlSchema).optional(),\n items: z.array(LayoutNodeSchema).optional(),\n }),\n);\n\nexport const LayoutSchema = z.object({\n form: LayoutNodeSchema.optional(),\n view: LayoutNodeSchema.optional(),\n table: LayoutNodeSchema.optional(),\n});\n\nexport type Layout = z.infer<typeof LayoutSchema>;\n","import { z } from 'zod';\n\nimport { CalculatedColumnSchema } from './CalculatedColumn.schema';\nimport { type JsonColumn, JsonColumnSchema } from './Column';\nimport { LayoutSchema } from './Layout.schema';\nimport { ParentRefSchema } from './ParentRef.schema';\nimport { ResourceKindSchema } from './ResourceKind';\nimport { SidebarSchema } from './Sidebar.schema';\nimport { JsonActionSchema } from './TableAction.schema';\nimport { getResourceExtensions } from './extensions';\nimport { JsonIncludeEntrySchema } from './include.schema';\nimport { BASELINE_RESOURCE_VERSION } from './version';\nimport { JsonOperationsSchema } from '../data-source/Operations.schema';\nimport { SecuritySchema } from '../data-source/Security.schema';\nimport { labelFromId } from '../schema/label.helper';\n\n// ── Shared primitives ────────────────────────────────────────────────\n\nconst JsonColumnsMapSchema = z.record(\n z.string(),\n JsonColumnSchema.omit({ id: true }).catchall(z.unknown()),\n); // map form — key becomes `id`\nexport type JsonColumnsMap = z.infer<typeof JsonColumnsMapSchema>;\nconst ColumnsSchema = JsonColumnsMapSchema;\n\n// ── Display / sidebar ────────────────────────────────────────────────\n\nexport const JsonDisplaySchema = z.object({\n mode: z.enum(['page', 'modal']).default('modal'), // default: 'modal'\n customComponent: z.string().nullable().optional().default(null), // default: null\n});\n\nexport type JsonDisplay = z.infer<typeof JsonDisplaySchema>;\n\n/** Normalise `columns` from either array or object-map form. */\nexport const normalizeColumns = (\n columns: 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// ── Top-level resource.json ──────────────────────────────────────────\n\nexport const ResourceJsonShape = z.object({\n /**\n * URL of the generated JSON Schema, for editor autocomplete/validation. Declared so the\n * key is *allowed* (not stripped, and not flagged by the very schema it points at).\n * Ignored at runtime.\n */\n $schema: z.string().optional(),\n /**\n * resource.json shape version. Missing ⇒ baseline (see `./version`). Auto-migrated\n * toward `CURRENT_RESOURCE_VERSION` on load in the dev environment.\n */\n schemaVersion: z.number().int().positive().optional(),\n /** When `true`, the resource lives in the repo but is NOT loaded/served (work in progress). */\n draft: z.boolean().optional().default(false),\n /**\n * Where the data comes from. `prisma` (the default) is backed by a Prisma\n * model plus a `schema.ts`; `custom` is configuration only and the developer\n * supplies a `repository.ts`. See `./ResourceKind`.\n */\n kind: ResourceKindSchema,\n name: z.string(), // required — unique id, used as the frontend form id\n route: z.string().optional(), // URL segment for generated endpoints - default id is used\n id: z.string().optional(), // URL segment for generated endpoints - default id is used\n /**\n * Prisma model name. Required when `kind` is `prisma` (enforced by the\n * refinement on `ResourceJsonSchema`), and must be absent when `kind` is\n * `custom` — there is no Prisma delegate to address.\n */\n model: z.string().optional(),\n tag: z.string().optional().default('Crouton'), // required — OpenAPI tag\n title: z.string().optional(), // no computed default — used as UI display title\n table: z.string().optional(), // default: same as `model`\n /**\n * Type of the resource's primary key, used to coerce `:id` route params.\n * Written by codegen from the Prisma model; defaults to `'string'`.\n */\n idType: z.enum(['string', 'number']).optional(),\n database: z.string().optional(), // default: project's default data source\n /**\n * Mount this resource under a parent route instead of at the top level —\n * see `./ParentRef.schema`. Only valid on a `kind: \"custom\"` resource.\n */\n parent: ParentRefSchema.optional(),\n sidebar: SidebarSchema.default(SidebarSchema.parse({})), // default: shown, alphabetically ordered, ungrouped\n display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})), // default: { mode: 'modal', customComponent: null }\n /** Global security block — applies to every operation unless overridden per-operation. */\n security: SecuritySchema.optional(),\n operations: JsonOperationsSchema.optional(), // default applied in transform: custom → all false, prisma → all true\n columns: ColumnsSchema.optional().default(ColumnsSchema.parse({})), // id-keyed map; omit for a columnless resource\n calculatedColumns: z.array(CalculatedColumnSchema).default([]),\n actions: z.array(JsonActionSchema).default([]),\n /** Global table-level actions (no record id). Shown as toolbar buttons. */\n tableActions: z.array(JsonActionSchema).default([]),\n /** Modal width when opening a form for this resource. */\n modalSize: z.enum(['xs', 'sm', 'lg', 'xl']).default('sm'), // default: 'sm' for create/edit modal\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: z.array(JsonIncludeEntrySchema).default([]),\n /** Explicit layout for generated views (`form`, `view`, `table`). When absent, source-order grid is used. */\n layout: LayoutSchema.optional(),\n});\n\n/**\n * Per-kind rules that a plain `z.object` cannot express.\n *\n * Implemented as a refinement rather than a `z.discriminatedUnion` on purpose:\n * `scripts/gen-resource-schema.mjs` runs `z.toJSONSchema(ResourceJsonShape)`\n * and needs a `z.object`, and a defaulted discriminator does not survive the\n * union. The generated JSON Schema is therefore permissive about these rules\n * while the loader enforces them.\n */\nexport const refineByKind = (\n obj: z.infer<typeof ResourceJsonShape>,\n ctx: z.RefinementCtx,\n): void => {\n if (obj.kind === 'custom') {\n if (obj.model !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['model'],\n message:\n 'A custom resource has no Prisma model. Remove \"model\" — data access comes from repository.ts.',\n });\n }\n if (obj.calculatedColumns?.length) {\n ctx.addIssue({\n code: 'custom',\n path: ['calculatedColumns'],\n message:\n 'calculatedColumns run raw SQL against a database table and are not supported on a custom resource. Compute the value in repository.ts instead.',\n });\n }\n for (const [id, col] of Object.entries(obj.columns ?? {})) {\n // A relation or autocomplete column's shape comes from the referenced\n // resource, not from this column.\n if (\n col.fieldInput?.format === 'relation' ||\n col.fieldInput?.type === 'autocomplete'\n ) {\n continue;\n }\n if (col.type === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['columns', id, 'type'],\n message: `Column \"${id}\" needs a \"type\": a custom resource has no schema.ts, so its json_schema is built from the column types.`,\n });\n }\n }\n if (obj.parent && obj.parent.param === 'id') {\n ctx.addIssue({\n code: 'custom',\n path: ['parent', 'param'],\n message:\n 'parent.param cannot be \"id\" — that is the child\\'s own id in /:id routes. Use something like \"groupId\".',\n });\n }\n } else if (obj.parent !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['parent'],\n message:\n '\"parent\" is only supported on a custom resource. A prisma resource is nested by declaring a relation column on its parent.',\n });\n }\n // \"model required for prisma kind\" moved to the Prisma adapter at load time —\n // a resource on a custom-adapter datasource may have no model and is still valid.\n};\n\nexport const buildResourceJsonSchema = () => {\n const ext = getResourceExtensions();\n const extShape = Object.fromEntries(\n [...ext].map(([name, schema]) => [name, schema.optional()]),\n );\n // Cast back to ResourceJsonShape type so refineByKind and transform stay typed.\n // Extension keys are lifted off the top level into `extensions` in the transform.\n const shape = (\n ext.size ? ResourceJsonShape.extend(extShape) : ResourceJsonShape\n ) as unknown as typeof ResourceJsonShape;\n\n return z.preprocess(\n (raw) => {\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n const obj = raw as Record<string, unknown>;\n // Only auto-derive kind='prisma' when a model is present and kind is unset.\n // A modelless resource no longer auto-derives to kind='custom' — set it\n // explicitly when you want the columns-based json_schema behavior.\n if (obj['kind'] === undefined && obj['model'] !== undefined) {\n return { ...obj, kind: 'prisma' };\n }\n }\n return raw;\n },\n shape.superRefine(refineByKind).transform((obj) => {\n const title = obj.title ?? labelFromId(obj.name);\n const schemaVersion = obj.schemaVersion ?? BASELINE_RESOURCE_VERSION;\n const defaultOps =\n obj.kind === 'custom'\n ? JsonOperationsSchema.parse({ findAll: false, findOne: false, create: false, update: false, patch: false, delete: false })\n : JsonOperationsSchema.parse({});\n return {\n title,\n ...obj,\n id: (obj.id ?? obj.name) as string,\n route: (obj.route ?? obj.id ?? obj.name ?? '') as string,\n schemaVersion,\n columns: normalizeColumns(obj.columns),\n operations: obj.operations ?? defaultOps,\n };\n }),\n );\n};\n\n/** Convenience constant — reads the registry at call time via the builder. */\nexport const ResourceJsonSchema = buildResourceJsonSchema();\n\nexport type ResourceJson = z.infer<ReturnType<typeof buildResourceJsonSchema>> & {\n route: string;\n};\nexport type ResourceJsonInput = z.input<typeof ResourceJsonShape> & {\n route: string;\n};\n\nexport type ResourceConfig = ResourceJson;\n\n/**\n * Generate a JSON Schema for resource.json that includes all currently-registered\n * extension keys. Call this after registering extensions to emit an app-specific\n * `resource.schema.json` that includes `annotation`, `context`, etc. as top-level\n * properties — enabling editor autocomplete for extension blocks.\n *\n * The core committed `resource.schema.json` is extension-agnostic (generated at\n * crouton-core build time when no extensions are registered). This helper lets\n * a consuming app emit its own schema after registering its extensions.\n */\nexport const generateResourceJsonSchema = (): Record<string, unknown> => {\n const ext = getResourceExtensions();\n const extShape = Object.fromEntries(\n [...ext].map(([name, schema]) => [name, schema.optional()]),\n );\n const shape = ext.size ? ResourceJsonShape.extend(extShape) : ResourceJsonShape;\n try {\n return z.toJSONSchema(shape, {\n target: 'draft-7',\n io: 'input',\n unrepresentable: 'any',\n }) as Record<string, unknown>;\n } catch {\n // ponytail: if toJSONSchema fails (recursive/record schema), fall back to the base shape.\n return z.toJSONSchema(ResourceJsonShape, {\n target: 'draft-7',\n io: 'input',\n unrepresentable: 'any',\n }) as Record<string, unknown>;\n }\n};\n","import { z } from 'zod';\n\nimport { FieldInputSchema } from './FieldInput.schema';\nimport { normalizeLabel } from '../schema/label.helper'; // ── Calculated columns ──────────────────────────────────────────────\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 const CalculatedColumnSchema = z\n .object({\n /** Column identifier used in the response payload and UI schema. */\n id: z.string(), // required\n /** SQL alias — must match `id`. */\n alias: z.string(), // required — must match `id`\n /** Human-readable label shown in the table header. */\n label: z.string().optional() /**\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: z.string(), // required\n /** JSON schema / cast type for the computed value. Defaults to `\"number\"`. `\"string\"` skips CAST. */\n type: z.enum(['number', 'boolean', 'string']).optional(), // default: 'number'\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: z.number().optional(),\n hiddenInTable: z.boolean().optional(), // default: false\n hiddenInView: z.boolean().optional(), // default: false\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: FieldInputSchema.optional(),\n })\n .transform(normalizeLabel);\n\nexport type CalculatedColumn = z.infer<typeof CalculatedColumnSchema>;\n","import { z } from 'zod';\n\nexport const RelationType = z.enum([\n 'oneToOne',\n 'manyToOne',\n 'oneToMany',\n 'manyToMany',\n]);\nexport type RelationType = z.infer<typeof RelationType>;\n\nexport const DetailControlSchema = z.object({\n property: z.string(), // required\n type: z.string().optional(), // default: 'text'\n options: z.record(z.string(), z.unknown()).optional(),\n hideLabel: z.boolean().optional(), // default: false\n width: z.string().optional(),\n});\n\nexport type DetailControl = z.infer<typeof DetailControlSchema>;\n\nexport const DetailConfigSchema = z.object({\n layout: z.enum(['collapse', 'row']), // required\n titleKey: z.string().optional(),\n controls: z.array(DetailControlSchema), // required\n});\n\nexport type DetailConfig = z.infer<typeof DetailConfigSchema>;\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 const RelationFieldInputOptionsSchema = z\n .object({\n colspan: z.number().optional().default(12),\n /** Field to sort related records by, e.g. `\"title\"` or `\"author.name\"`. */\n sort: z.string().optional(),\n /** Sort direction. Defaults to `\"asc\"` when omitted. */\n sortDir: z.enum(['asc', 'desc']).optional(), // default: 'asc'\n /** CSS flex direction for the relation control button layout. */\n direction: z.string().optional(),\n /** Key used as the display label in the relation control. */\n displayKey: z.string().optional(),\n /** Path to the related resource (resolved to a URI at load time). */\n resource: z.string().optional(),\n })\n .catchall(z.unknown()); // arbitrary extra keys allowed (e.g. colspan, emitObject, values)\n\nexport type RelationFieldInputOptions = z.infer<\n typeof RelationFieldInputOptionsSchema\n>;\nexport const FieldInputSchema = z.object({\n type: z.string().optional(),\n customRender: z.string().optional(),\n\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: z.string().optional(), // 'relation' triggers relation handling; requires `resource`\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: z.string().optional(), // required when format === 'relation'\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.optional(), // auto-derived from the Zod model/sibling FK column if omitted\n /** FK field on the child model pointing back to the parent, e.g. `\"workId\"`. Defaults to `${parentModel}Id`. */\n foreignKey: z.string().optional(),\n /** Override the Prisma relation field name when it differs from the column id. */\n relation: z.string().optional(),\n /** Override the display order in form views. Lower values come first. */\n position: z.number().optional(), // default: source order\n /**\n * Value to pre-fill this field with on the create form. Injected into the\n * generated form view's JSON Schema as `properties[id].default`, which\n * `parseValue({})` (see `@ghentcdh/crouton-vue`'s `form-def.ts`) applies when\n * opening a blank record. Not applicable to `format: \"relation\"` fields —\n * relation columns are excluded from the picked data schema entirely.\n *\n * Supports dynamic default tokens evaluated at form-open time:\n * - `\"$now\"` — current datetime ISO string\n * - `\"$today\"` — current date ISO string (date only, e.g. `\"2025-03-14\"`)\n * - `\"$user\"` — current user object (requires `defaults: { '$user': ... }` on `CroutonPlugin` config, or `useCrouton().setDefault('$user', ...)`)\n */\n defaultValue: z.unknown().optional(),\n options: z.union([RelationFieldInputOptionsSchema, z.unknown()]).optional(),\n /** Nested array detail layout (renders via `detailFixed`). */\n detail: DetailConfigSchema.optional(),\n});\n\nexport type FieldInput = z.infer<typeof FieldInputSchema>;\n\n/**\n * A per-context override of a column's field config. Structurally identical to\n * {@link FieldInputSchema} — every key is optional — so a variant can override\n * just what it needs (typically a single `options` key) and inherit the rest\n * from the level below it via {@link mergeFieldVariant}.\n */\nexport const FieldVariantSchema = FieldInputSchema;\nexport type FieldVariant = z.infer<typeof FieldVariantSchema>;\n\n/** Drop keys whose value is explicitly `null` (used to \"delete\" an inherited key). */\nconst stripNull = (obj: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) if (v !== null) out[k] = v;\n return out;\n};\n\n/**\n * Layer a variant over a base field config (deep-merge, one level into `options`).\n *\n * - `override` wins key-by-key; `base` supplies everything the override omits.\n * - `options` is merged one level deep so a variant can tweak `options.display`\n * without repeating `format`, `resource`, `relationType`, etc.\n * - a `null` value in the override deletes that inherited key (top-level or in\n * `options`).\n *\n * Returns `base` unchanged when there is no override, and `override` when there\n * is no base — so `mergeFieldVariant(x, undefined) === x`.\n */\nexport const mergeFieldVariant = (\n base: FieldInput | undefined,\n override: FieldVariant | undefined,\n): FieldInput | undefined => {\n if (!base) return override;\n if (!override) return base;\n\n const merged = stripNull({ ...base, ...override }) as FieldInput;\n\n if (base.options || override.options) {\n const mergedOptions = stripNull({\n ...(base.options as Record<string, unknown> | undefined),\n ...(override.options as Record<string, unknown> | undefined),\n });\n merged.options = mergedOptions;\n }\n\n return merged;\n};\n","/**\n * Name derivations. The most error-prone one is `clientAccessor`: the value\n * crouton puts in `resource.json.model` must equal the PrismaClient property,\n * which Prisma derives by lower-casing the first character of the model name\n * (the rest is preserved). Getting this wrong silently breaks every query.\n */\n\n/**\n * Derive a human-readable label from an id.\n * `\"field_label\"` → `\"Field label\"`, `\"fieldLabel\"` → `\"Field label\"`.\n *\n * Kept local (mirrors `labelFromId` in `@ghentcdh/crouton-core`) so the engine\n * has no runtime dependency on core — only type-only imports, which keeps the\n * bundle lean and avoids pulling core's peer deps (zod, jsonforms) into it.\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\ntype LabelObj = {\n id: string;\n label?: string;\n};\nexport const normalizeLabel = <L extends LabelObj>(obj: L): L => {\n return { label: labelFromId(obj.id), ...obj };\n};\n","import { z } from 'zod';\n\nimport { ColumnTypeSchema } from './ColumnType.schema';\nimport { FieldInputSchema, FieldVariantSchema } from './FieldInput.schema';\n\n// Used by showWhen / hideWhen / disabledWhen\nexport const WhenConditionSchema = z.object({\n field: z.string(), // required\n eq: z.unknown().optional(),\n neq: z.unknown().optional(),\n exists: z.boolean().optional(),\n notExists: z.boolean().optional(),\n});\n\n// ── Columns ───────────────────────────────────────────────────────────\n\nexport const JsonColumnSchema = z.object({\n id: z.string(), // required in array form; implied by the map key in map form\n column: z.string().optional(), // default: same as `id`\n label: z.string().optional(), // default: title-cased version of `id`\n hiddenInTable: z.boolean().default(false), // default: false\n hiddenInForm: z.boolean().default(false), // default: false\n hiddenInView: z.boolean().default(false), // default: false\n sortable: z.boolean().default(false), // default: false\n defaultSort: z.boolean().default(false), // default: false\n searchable: z.boolean().default(false), // default: false\n filterable: z.boolean().default(false), // default: false\n createable: z.boolean().default(true), // default: true (only `false` excludes it)\n updateable: z.boolean().default(true), // default: true (only `false` excludes it)\n hideLabel: z.boolean().default(false), // default: false\n showWhen: WhenConditionSchema.optional(),\n hideWhen: WhenConditionSchema.optional(),\n disabledWhen: WhenConditionSchema.optional(),\n displayKey: z.string().optional(), // e.g. \"author.name\" for nested display\n sortId: z.string().optional(), // overrides the sort\n\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: z.string().optional(), // name of a shared enum in crouton.enums.json\n idField: z.boolean().default(false), // default: false — exactly one column should set this\n showInLookup: z.boolean().default(false), // default: false\n /**\n * Data type of the column, as a shorthand name (`\"string\"`, `\"integer\"`, …)\n * or a full JSON Schema fragment:\n *\n * ```json\n * \"type\": {\n * \"type\": \"object\",\n * \"properties\": { \"id\": { \"type\": \"string\" }, \"name\": { \"type\": \"string\" } }\n * }\n * ```\n *\n * Required on every column of a `kind: \"custom\"` resource, where it is the\n * only source of the resource's json_schema. Optional on a `prisma`\n * resource, whose schema is derived from the Zod model.\n */\n type: ColumnTypeSchema.optional(),\n /**\n * Whether the form requires a value.\n *\n * A prisma resource derives `required` from its Zod model, so this is an\n * override in either direction: `true` adds the column to the form schema's\n * `required` array, `false` removes it, and omitting it leaves the model's\n * answer alone. A `kind: \"custom\"` resource has no model, so this is the only\n * way to mark one of its fields required.\n *\n * Applies to the **form** view only — a required filter input would make the\n * filter panel unsubmittable, and the table and view schemas are read-only.\n * Ignored on the id column and on columns that are neither createable nor\n * updateable, since the form cannot supply a value for those.\n */\n required: z.boolean().optional(),\n /**\n * @deprecated Use `type` instead. Retained because it is still consumed by\n * the boolean predicate and the schema-less sub-resource view builder.\n */\n columnType: z.string().default('string'), // default: 'string'\n fieldInput: FieldInputSchema.optional(),\n /**\n * Optional per-context override for the read-only VIEW ui. Same shape as\n * `fieldInput`; every key optional. Falls back to `fieldInput` (deep-merged\n * one level into `options`). Resolved at read time by the transformer.\n */\n fieldView: FieldVariantSchema.optional(),\n /**\n * Optional per-context override for the TABLE ui. Same shape as `fieldInput`;\n * every key optional. Falls back to `fieldView`, then `fieldInput`.\n * Resolved at read time by the transformer.\n */\n fieldTable: FieldVariantSchema.optional(),\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: z.string().optional(), // path to another resource.json expanded as virtual sub-columns\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: z.record(z.string(), z.record(z.string(), z.unknown())).optional(), // per-sub-column overrides, only used with `extend`\n});\n\nexport type JsonColumn = z.infer<typeof JsonColumnSchema>;\nexport type JsonColumnInput = z.input<typeof JsonColumnSchema>;\n","import { z } from 'zod';\n\n/**\n * Column data types.\n *\n * A column's `type` is either a shorthand string or a JSON Schema fragment.\n * For a `kind: \"custom\"` resource these are the *only* source of the resource's\n * json_schema — there is no Prisma model to derive it from.\n */\n\n/** Shorthand names, expanded to a JSON Schema fragment by `columnTypeToJsonSchema`. */\nexport const ColumnTypeShorthandSchema = z.enum([\n 'string',\n 'number',\n 'integer',\n 'boolean',\n 'date',\n 'date-time',\n 'object',\n 'array',\n]);\n\nexport type ColumnTypeShorthand = z.infer<typeof ColumnTypeShorthandSchema>;\n\n/**\n * A JSON Schema fragment describing one column.\n *\n * Deliberately a permissive subset: enough to express the shapes the form and\n * table layers can render (scalars, nested objects, arrays, enums, nullables)\n * without re-implementing all of JSON Schema. Unknown keys pass through so a\n * fragment can carry vendor extensions (`x-*`).\n */\nexport type JsonSchemaFragment = {\n type?: string | string[] | JsonSchemaFragment;\n format?: string;\n enum?: unknown[];\n const?: unknown;\n nullable?: boolean;\n properties?: Record<string, JsonSchemaFragment>;\n required?: string[] | boolean;\n items?: JsonSchemaFragment;\n additionalProperties?: boolean | JsonSchemaFragment;\n title?: string;\n description?: string;\n default?: unknown;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n [key: string]: unknown;\n};\n\nexport const JsonSchemaFragmentSchema: z.ZodType<JsonSchemaFragment> = z.lazy(\n () =>\n z\n .object({\n type: z\n .union([z.string(), z.array(z.string()), z.lazy(() => JsonSchemaFragmentSchema)])\n .optional(),\n format: z.string().optional(),\n enum: z.array(z.unknown()).optional(),\n const: z.unknown().optional(),\n nullable: z.boolean().optional(),\n properties: z.record(z.string(), JsonSchemaFragmentSchema).optional(),\n required: z.union([z.array(z.string()), z.boolean()]).optional(),\n items: JsonSchemaFragmentSchema.optional(),\n additionalProperties: z\n .union([z.boolean(), JsonSchemaFragmentSchema])\n .optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n default: z.unknown().optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n minLength: z.number().optional(),\n maxLength: z.number().optional(),\n pattern: z.string().optional(),\n })\n .catchall(z.unknown()),\n);\n\n/** Either a shorthand name or a full JSON Schema fragment. */\nexport const ColumnTypeSchema = z.union([\n ColumnTypeShorthandSchema,\n JsonSchemaFragmentSchema,\n]);\n\nexport type ColumnType = z.infer<typeof ColumnTypeSchema>;\n\nconst SHORTHAND_FRAGMENTS: Record<ColumnTypeShorthand, JsonSchemaFragment> = {\n string: { type: 'string' },\n number: { type: 'number' },\n integer: { type: 'integer' },\n boolean: { type: 'boolean' },\n date: { type: 'string', format: 'date' },\n 'date-time': { type: 'string', format: 'date-time' },\n object: { type: 'object' },\n array: { type: 'array' },\n};\n\nconst isShorthand = (type: ColumnType): type is ColumnTypeShorthand =>\n typeof type === 'string';\n\n/**\n * Shorthands that are not JSON Schema types, and so need expanding wherever they\n * appear — including inside a fragment, where `\"type\"` is otherwise passed\n * through verbatim.\n *\n * `\"type\": \"date\"` is a crouton spelling of `{ type: \"string\", format: \"date\" }`.\n * Left alone at depth it reaches the frontend as an unknown type: the date\n * renderer tests `format`, the string renderer tests `type === 'string'`, so a\n * nested `\"date\"` matches nothing and the control silently fails to render.\n * Every other shorthand happens to be a real JSON Schema type already.\n */\nconst NESTED_SHORTHANDS: Record<string, JsonSchemaFragment> = {\n date: SHORTHAND_FRAGMENTS.date,\n 'date-time': SHORTHAND_FRAGMENTS['date-time'],\n};\n\n/**\n * Expand crouton shorthands at every depth and return a fresh object graph.\n *\n * Copying matters as much as expanding: the fragment comes straight off the\n * loaded resource config, and callers go on to mutate what they get back\n * (`applySchemaTransforms` adds `minLength`, `injectFieldDefaults` adds\n * `default`). Handing out the config's own nested objects would let a view build\n * rewrite the config it was built from.\n */\nconst normalizeFragment = (\n fragment: JsonSchemaFragment,\n): JsonSchemaFragment => {\n const out: JsonSchemaFragment = { ...fragment };\n\n if (typeof out.type === 'string') {\n const expanded = NESTED_SHORTHANDS[out.type];\n if (expanded) {\n out.type = expanded.type;\n // An explicit `format` wins — the shorthand only fills the blank.\n if (out.format === undefined) out.format = expanded.format;\n }\n }\n\n // Flatten nested-schema-as-type: { type: { type: \"object\", properties: {...} } }\n // → { type: \"object\", properties: {...}, ...other_fields }\n if (out.type && typeof out.type === 'object' && !Array.isArray(out.type)) {\n Object.assign(out, out.type);\n }\n\n if (out.properties) {\n const existingRequired = Array.isArray(out.required) ? out.required : [];\n const hoistedRequired: string[] = [...existingRequired];\n\n out.properties = Object.fromEntries(\n Object.entries(out.properties).map(([key, value]) => {\n let v = { ...value };\n // Hoist required: true from individual property into parent required array\n if (v.required === true) {\n hoistedRequired.push(key);\n const { required: _r, ...rest } = v;\n v = rest as JsonSchemaFragment;\n }\n return [key, normalizeFragment(v)];\n }),\n );\n\n if (hoistedRequired.length > 0) {\n out.required = hoistedRequired;\n } else {\n delete out.required;\n }\n }\n\n if (out.items) out.items = normalizeFragment(out.items as JsonSchemaFragment);\n if (out.additionalProperties && typeof out.additionalProperties === 'object') {\n out.additionalProperties = normalizeFragment(out.additionalProperties as JsonSchemaFragment);\n }\n\n return out;\n};\n\n/** Expand a column `type` into a JSON Schema fragment. */\nexport const columnTypeToJsonSchema = (\n type: ColumnType | undefined,\n): JsonSchemaFragment => {\n if (type === undefined) return { type: 'string' };\n if (isShorthand(type)) return { ...SHORTHAND_FRAGMENTS[type] };\n return normalizeFragment(type);\n};\n\n/**\n * The effective JSON Schema `type` of a column, as a single string.\n *\n * Union types (`[\"string\", \"null\"]`) collapse to their first non-null member,\n * matching how the table layer picks a cell renderer.\n */\nexport const columnTypeName = (type: ColumnType | undefined): string => {\n const fragment = columnTypeToJsonSchema(type);\n const raw = fragment.type;\n if (Array.isArray(raw)) return raw.find((t) => t !== 'null') ?? 'string';\n if (typeof raw === 'string') return raw;\n // No explicit type but nested properties/items present — infer it.\n if (fragment.properties) return 'object';\n if (fragment.items) return 'array';\n return 'string';\n};\n\n/** `true` when the column holds a nested object with declared properties. */\nexport const isObjectColumnType = (type: ColumnType | undefined): boolean =>\n columnTypeName(type) === 'object';\n\n/** `true` when the column holds an array. */\nexport const isArrayColumnType = (type: ColumnType | undefined): boolean =>\n columnTypeName(type) === 'array';\n","import { z } from 'zod';\n\n/**\n * Declares that a resource is only addressable underneath a parent.\n *\n * Set on the **child**, which then mounts its own controller at\n * `<parent.route>/:<parent.param>/<route>` and serves every operation from\n * there. Nothing is configured on the parent, and the parent does not need to\n * exist as a crouton resource at all.\n *\n * ```jsonc\n * { \"kind\": \"custom\", \"name\": \"expense\", \"route\": \"expense\",\n * \"parent\": { \"route\": \"group\", \"param\": \"groupId\" } }\n * // → GET group/:groupId/expense\n * // → GET group/:groupId/expense/:id\n * // → POST group/:groupId/expense …\n * ```\n *\n * Nesting is *exclusive*: no top-level route is registered, so the parent id is\n * always present and a query can never accidentally run unscoped.\n *\n * Only valid on a `kind: \"custom\"` resource. Prisma-backed nesting is derived\n * from relation columns on the parent instead — see `buildSubResources`.\n */\nexport const ParentRefSchema = z.object({\n /** Route segment of the parent, e.g. `\"group\"`. */\n route: z.string(),\n /**\n * Name of the path parameter carrying the parent id, e.g. `\"groupId\"`.\n * Avoid `\"id\"` — that is the child's own id in `/:id` routes.\n */\n param: z.string().default('parentId'),\n /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */\n idType: z.enum(['string', 'number']).optional(),\n});\n\nexport type ParentRef = z.infer<typeof ParentRefSchema>;\n\n/** Controller path for a resource, nested under its parent when it has one. */\nexport const resourceControllerPath = (\n route: string,\n parent: ParentRef | undefined,\n): string => (parent ? `${parent.route}/:${parent.param}/${route}` : route);\n","import { z } from 'zod';\n\n/**\n * Where a resource's data comes from.\n *\n * - `prisma` — the default. Backed by a Prisma model (`model` is required) and\n * a Zod model schema in `schema.ts`. The framework generates the whole data\n * access layer.\n * - `custom` — configuration only. There is no Prisma model and no\n * `schema.ts`; the JSON model is assembled from the column `type`s, and the\n * developer implements the operations in a sibling `repository.ts`.\n */\nexport const ResourceKindSchema = z.enum(['prisma', 'custom']).default('prisma');\n\nexport type ResourceKind = z.infer<typeof ResourceKindSchema>;\n\n/** `true` when the resource's data access is supplied by a user `repository.ts`. */\nexport const isCustomKind = (kind: ResourceKind | undefined): boolean =>\n kind === 'custom';\n","import z from 'zod';\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 const SidebarGroupSchema = z.object({\n /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */\n label: z.string().optional(),\n /** Controls the order of this group among top-level sidebar items. */\n position: z.number().optional(),\n});\n\nexport type SidebarGroupConfig = z.infer<typeof SidebarGroupSchema>;\n\nexport const SidebarSchema = z.object({\n hide: z.boolean().default(false), // default: false\n position: z.number().optional(), // default: sorted alphabetically after positioned entries\n label: z.string().optional(), // default: resource `title`\n\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: z.string().optional(), // must match a key in `sidebarGroups` (crouton.json)\n});\n\nexport type Sidebar = z.infer<typeof SidebarSchema>;\n","import { z } from 'zod';\n// ── Table-level (global) actions ────────────────────────────────────\n\n// Used by row-action / table-action `condition`\nconst ActionConditionSchema = z.object({\n /** Row field to evaluate. */\n field: z.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: z\n .enum(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'exists', 'notExists'])\n .default('eq'), // default: 'eq'\n /** Comparison value. Not required for `exists` / `notExists`. */\n value: z.unknown().optional(), // not required for exists/notExists\n});\n\nconst ActionSchema = z.object({\n type: z.string(),\n /** Unique identifier for the action. */\n id: z.string(), // required\n /** Human-readable button label. */\n label: z.string(),\n /** MDI icon name, e.g. `\"mdi:open-in-new\"`. */\n icon: z.string().optional(),\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip: z.string().optional(), // default: falls back to `label`\n condition: ActionConditionSchema.optional(),\n});\n\ntype Action = z.infer<typeof ActionSchema>;\n\nexport const JsonProcedureActionSchema = ActionSchema.extend({\n type: z.literal('procedure').default('procedure'), // default: 'procedure'\n /**\n * Filename (without extension) inside the resource's `actions/` directory\n * that exports the table-action procedure, e.g. `\"syncZotero\"`.\n */\n procedure: z.string(), // required\n /** HTTP method for the frontend. Defaults to `\"post\"`. */\n method: z.string().optional().default('post'), // default: 'post'\n /** Static query / body params passed to the endpoint. */\n data: z.record(z.string(), z.unknown()).optional(),\n});\n\n/** Action that opens a URL in a new browser tab — no backend call. */\nexport const JsonLinkActionSchema = ActionSchema.extend({\n /** Optional condition evaluated per row. Button is hidden when the condition is false. */\n type: z.literal('link').default('link'), // required\n /** URL to open. May contain `{env.VAR}` placeholders. */\n href: z.string(), // required,\n blank: z.boolean().optional().default(true),\n});\n\nconst transformAction = <A extends Action>(action: A) => {\n const label = action.label;\n\n return {\n tooltip: label,\n ...action,\n };\n};\n\nexport const JsonActionSchema = z\n .union([JsonProcedureActionSchema, JsonLinkActionSchema])\n .transform(transformAction);\n\nexport type JsonActionCondition = z.infer<typeof ActionConditionSchema>;\nexport type JsonAction = z.infer<typeof JsonActionSchema>;\nexport type JsonLinkAction = z.infer<typeof JsonLinkActionSchema>;\nexport type JsonProcedureAction = z.infer<typeof JsonProcedureActionSchema>;\n","import type { ZodType } from 'zod';\n\n// Hardcoded to avoid a circular dep with ResourceJson.schema.ts.\n// Update when a key is added to or removed from ResourceJsonShape.\nconst CORE_RESOURCE_KEYS = new Set([\n '$schema', 'schemaVersion', 'draft', 'kind', 'id', 'name', 'route', 'model', 'tag',\n 'title', 'table', 'idType', 'database', 'parent', 'sidebar', 'display',\n 'security', 'operations', 'columns', 'calculatedColumns', 'actions',\n 'tableActions', 'modalSize', 'include', 'extensions',\n]);\n\nconst registry = new Map<string, ZodType>();\n\nexport const registerResourceExtension = (name: string, schema: ZodType): void => {\n if (CORE_RESOURCE_KEYS.has(name))\n throw new Error(`Extension \"${name}\" shadows a core resource key.`);\n registry.set(name, schema);\n};\n\nexport const registerResourceExtensions = (map: Record<string, ZodType> = {}): void =>\n Object.entries(map).forEach(([k, s]) => registerResourceExtension(k, s));\n\nexport const getResourceExtensions = (): ReadonlyMap<string, ZodType> => registry;\n\nexport const clearResourceExtensions = (): void => registry.clear();\n","import { z } from 'zod';\n\n// ── Include ───────────────────────────────────────────────────────────\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 const JsonIncludeEntrySchema: z.ZodType<any> = z.lazy(() =>\n z.union([\n z.string(), // plain relation name → `{ [name]: true }`\n z.object({\n relation: z.string(), // required\n include: z.array(JsonIncludeEntrySchema).optional(), // nested includes;\n /** Prisma-format orderBy clause applied to the included records. */\n orderBy: z.record(z.string(), z.unknown()).optional(),\n }),\n ]),\n);\n\nexport type JsonIncludeEntry = z.infer<typeof JsonIncludeEntrySchema>;\n","/**\n * resource.json schema versioning.\n *\n * `schemaVersion` is a monotonic integer stamped on every `resource.json`. It is\n * **decoupled from the crouton package semver** on purpose — bump it only when the\n * resource.json *shape* changes in a way that needs a migration, and ship a matching\n * step in `./migrations`. This keeps the migration chain one-step-per-bump with no\n * version-range math.\n *\n * Files written before versioning existed carry no field and are treated as the\n * baseline. Because `CURRENT_RESOURCE_VERSION` starts equal to the baseline, shipping\n * the versioning machinery is a pure no-op for every existing file until the first\n * real shape change lands (`CURRENT_RESOURCE_VERSION = 2` + a `1 → 2` migration).\n */\n\n/** Version assumed for a `resource.json` that has no `schemaVersion` field. */\nexport const BASELINE_RESOURCE_VERSION = 1;\n\n/**\n * The version the running crouton understands. Bump by 1 whenever resource.json's\n * shape changes, and add a migration step (`from: N, to: N + 1`) in `./migrations`.\n */\nexport const CURRENT_RESOURCE_VERSION = 1;\n","import { z } from 'zod';\n\nimport { SecuritySchema } from './Security.schema';\n\n// ── Operations ────────────────────────────────────────────────────────\n\n/** An operation served by an external API instead of crouton. */\nconst ExternalOpEntry = z.object({\n uri: z.string(),\n method: z.string().optional(),\n security: SecuritySchema.optional(),\n});\n\nexport type ExternalOpEntry = z.infer<typeof ExternalOpEntry>;\n\n/** A standard operation entry: plain boolean, external route object, or security config. */\nconst OpEntry = z.union([\n z.boolean(),\n ExternalOpEntry,\n z.object({ security: SecuritySchema.optional() }),\n]);\n\nexport const JsonOperationsSchema = z.object({\n findAll: OpEntry.default(true), // default: true — only explicit `false` disables it\n findOne: OpEntry.default(true), // default: true\n create: OpEntry.default(true), // default: true\n update: OpEntry.default(true), // default: true\n patch: OpEntry.default(true), // default: true\n delete: OpEntry.default(true), // default: true\n});\n\nexport type JsonResourceOperations = z.infer<typeof JsonOperationsSchema>;\nexport type JsonResourceOperationsInput = z.input<typeof JsonOperationsSchema>;\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<\n 'findAll' | 'findOne' | 'create' | 'update' | 'patch' | 'delete',\n boolean\n >\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: 'put' },\n }),\n ...(ops.patch && {\n patch: { uri: `${baseUri}/${idPlaceholder}`, method: 'patch' },\n }),\n ...(ops.delete && {\n delete: { uri: `${baseUri}/${idPlaceholder}`, method: 'delete' },\n }),\n };\n};\n","import { z } from 'zod';\n\n/** Public route, or one/more named guards that must all pass (AND). */\nexport const SecuritySchema = z.union([\n z.object({ public: z.literal(true) }),\n z.object({ guard: z.union([z.string(), z.array(z.string()).min(1)]) }),\n]);\n\nexport type SecurityConfig = z.infer<typeof SecuritySchema>;\n","/**\n * Types for the resource.json migration engine.\n *\n * Migrations operate on the **raw** (pre-`ResourceJsonSchema.transform`) object so the\n * result can be written back byte-stably and validated with Zod afterwards — never on a\n * transformed config (which would normalize columns map→array and inject defaults, and\n * so explode diffs). Each step is a pure function returning a new object.\n */\n\nexport type RawResourceJson = Record<string, unknown>;\n\nexport interface ResourceMigration {\n /** Version this step upgrades FROM. */\n readonly from: number;\n /** Version this step upgrades TO — must equal `from + 1`. */\n readonly to: number;\n /** Human-readable summary, surfaced in logs. */\n readonly description: string;\n /** Pure transform: given a raw object at `from`, return a new raw object at `to`. */\n migrate(raw: RawResourceJson): RawResourceJson;\n}\n\nexport interface MigrationResult {\n /** The migrated object, with `schemaVersion` set to `to`. */\n raw: RawResourceJson;\n /** Version the input was at. */\n from: number;\n /** Version the output is at (the requested target). */\n to: number;\n /** Descriptions of the steps applied, in order (empty when already current). */\n applied: string[];\n}\n\n/** No registered step bridges some gap in the chain (or the file is newer than crouton). */\nexport class MigrationPathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MigrationPathError';\n }\n}\n\n/** A migration step threw while transforming the object. */\nexport class MigrationStepError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MigrationStepError';\n }\n}\n","/**\n * The resource.json migration engine.\n *\n * `MIGRATIONS` is an ordered, contiguous chain of single-version steps. `runResourceMigrations`\n * upgrades a raw object from its current `schemaVersion` up to a target (default\n * `CURRENT_RESOURCE_VERSION`), applying each step in turn. It is pure — no fs, no env — so it\n * can be unit-tested in isolation and reused by both the API loader and the CLI.\n */\n\nimport { BASELINE_RESOURCE_VERSION, CURRENT_RESOURCE_VERSION } from '../version';\nimport {\n MigrationPathError,\n type MigrationResult,\n MigrationStepError,\n type RawResourceJson,\n type ResourceMigration,\n} from './types';\n\n/**\n * Ordered, contiguous migration steps. Append one (`from: N, to: N + 1`) every time\n * `CURRENT_RESOURCE_VERSION` is bumped. A gap is a programming error caught by the spec.\n */\nexport const MIGRATIONS: ResourceMigration[] = [\n // Example (add when the first real shape change lands and CURRENT_RESOURCE_VERSION becomes 2):\n // migration_0001to0002,\n];\n\n/** Read a raw object's version, treating a missing/invalid field as the baseline. */\nexport const resourceVersionOf = (raw: RawResourceJson): number => {\n const v = raw['schemaVersion'];\n return typeof v === 'number' && Number.isInteger(v) ? v : BASELINE_RESOURCE_VERSION;\n};\n\n/**\n * Upgrade `raw` from its current version up to `target`.\n *\n * - Already at `target` → returns it unchanged (no `schemaVersion` rewrite), `applied: []`.\n * - Newer than `target` → `MigrationPathError` (crouton is too old; never down-migrate).\n * - A gap with no registered step → `MigrationPathError`.\n * - A step throws → `MigrationStepError`.\n *\n * On success the returned object leads with `schemaVersion: target` for a readable diff.\n */\nexport const runResourceMigrations = (\n raw: RawResourceJson,\n target: number = CURRENT_RESOURCE_VERSION,\n migrations: ResourceMigration[] = MIGRATIONS,\n): MigrationResult => {\n const from = resourceVersionOf(raw);\n\n if (from === target) return { raw, from, to: target, applied: [] };\n\n if (from > target) {\n throw new MigrationPathError(\n `resource.json is version ${from} but this crouton only understands up to ${target} — upgrade crouton`,\n );\n }\n\n let current = raw;\n const applied: string[] = [];\n\n for (let v = from; v < target; v++) {\n const step = migrations.find((m) => m.from === v && m.to === v + 1);\n if (!step) {\n throw new MigrationPathError(`no migration path from version ${v} to ${v + 1}`);\n }\n try {\n current = step.migrate(current);\n } catch (err) {\n throw new MigrationStepError(\n `migration ${v}→${v + 1} (${step.description}) failed: ${(err as Error).message}`,\n );\n }\n applied.push(step.description);\n }\n\n // Lead with schemaVersion so the written file is diff-friendly.\n const { schemaVersion: _old, ...rest } = current;\n return { raw: { schemaVersion: target, ...rest }, from, to: target, applied };\n};\n\nexport * from './types';\n","import type { JsonColumn } from './Column';\nimport { type FieldInput, mergeFieldVariant } from './FieldInput.schema';\n\n/**\n * Resolve the field config that drives each rendering context, applying the\n * `fieldInput → fieldView → fieldTable` fallback chain. These are the single\n * source of truth for the fallback; every consumer (transformer, view builders)\n * goes through them so the three-way behaviour can't drift.\n *\n * form ← fieldInput (base, unchanged)\n * view ← fieldView, then fieldInput\n * table ← fieldTable, then fieldView, then fieldInput\n *\n * Merging is deep one level into `options` (see {@link mergeFieldVariant}).\n */\nexport const resolveFormField = (c: JsonColumn): FieldInput | undefined =>\n c.fieldInput;\n\nexport const resolveViewField = (c: JsonColumn): FieldInput | undefined =>\n mergeFieldVariant(c.fieldInput, c.fieldView);\n\nexport const resolveTableField = (c: JsonColumn): FieldInput | undefined =>\n mergeFieldVariant(resolveViewField(c), c.fieldTable);\n","import type { JsonColumn } from '../resource/Column';\nimport {\n isArrayColumnType,\n isObjectColumnType,\n} from '../resource/ColumnType.schema';\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/** Returns `true` when the column declares a nested object `type`. */\nexport const isObjectColumn = (col: JsonColumn): boolean =>\n isObjectColumnType(col.type);\n\n/** Returns `true` when the column declares an array `type`. */\nexport const isArrayColumn = (col: JsonColumn): boolean =>\n isArrayColumnType(col.type);\n\n/**\n * Returns `true` when an object column can render as a `RecordCell`.\n *\n * Requires a `displayKey`: `RecordCell` shows one nested key, so without one\n * there is nothing meaningful to display and the column is better served by the\n * generic object cell.\n */\nexport const isObjectCell = (col: JsonColumn): boolean =>\n isObjectColumn(col) && !!col.displayKey;\n","import type { ViewColumnConfig } from './view.schema';\nimport type { JsonColumn } from '../resource/Column';\n\n\n/** Resolve the sort position for a column: `fieldInput.position`, then natural index. */\nexport const 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. */\nexport const 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\nexport type FieldContext = 'form' | 'view' | 'table';\n\n/**\n * Return a copy of the column whose `fieldInput` is the resolved variant for the\n * given rendering context, so downstream builders (which all read `fieldInput`)\n * render the right config without any signature change.\n *\n * After the transformer's `resolveColumnFieldVariants` prefill, `fieldView` and\n * `fieldTable` are already the fully-resolved variants; the `?? col.fieldInput`\n * guard covers TS-authored `resource.ts` resources that bypass the transformer.\n */\nexport const columnForContext = (\n col: JsonColumn,\n ctx: FieldContext,\n): JsonColumn => {\n if (ctx === 'view') return { ...col, fieldInput: col.fieldView ?? col.fieldInput };\n if (ctx === 'table') return { ...col, fieldInput: col.fieldTable ?? col.fieldInput };\n return col; // form / filter → base fieldInput\n};\n\nexport const 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","import type { JsonColumn } from '../resource/Column';\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","import { isNullableProperty } from '../schema.utils';\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/**\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\n/**\n * Apply all standard JSON schema post-processing transforms.\n * Ensures every code path that produces a JSON schema gets the same treatment:\n * additional properties allowed, nullable fields dropped from required, and\n * empty strings rejected.\n */\nexport const applySchemaTransforms = (schema: Record<string, unknown>): void => {\n allowAdditionalProperties(schema);\n dropNullableFromRequired(schema);\n enforceRequiredMinLength(schema);\n};\n","\nimport {\n isBoolean,\n isDateRange,\n isObjectCell,\n isRecordCell,\n} from './column-predicates';\nimport { deriveSortId } from './sort.helpers';\nimport type { JsonColumn } from '../resource/Column';\nimport { BooleanCellBuilder, TableBuilder, TextCellBuilder } from '../table/table.builder';\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', 'customComponent'] 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) || isObjectCell(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 // An object column with a displayKey renders the same way as a relation:\n // one nested key out of an object value.\n ...((isRecordCell(col) || isObjectCell(col)) && { type: 'RecordCell' }),\n ...(isDateRange(col) && { type: 'Control' }),\n };\n });\n\n return layout as Record<string, unknown>;\n};\n","import { isArrayColumn, isObjectColumn } from './column-predicates';\nimport { ControlBuilder } from '../layout/control.builder';\nimport { LayoutBuilder } from '../layout/layout.builder';\nimport type { JsonColumn } from '../resource/Column';\nimport { columnTypeName, columnTypeToJsonSchema } from '../resource/ColumnType.schema';\nimport type { DetailConfig } from '../resource/FieldInput.schema';\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 *\n * Kept for backwards compatibility (re-exported from `crud/builder`). The form builder\n * now applies rules through `ControlBuilder.showWhen/hideWhen/disableWhen` instead —\n * see `applyColumnRule`.\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/** Apply a column's conditional rule to a control builder, in the builder chain. */\nconst applyColumnRule = (\n control: ControlBuilder<any>,\n col: JsonColumn,\n): void => {\n if (col.disabledWhen) {\n control.disableWhen(\n `#/properties/${col.disabledWhen.field}`,\n buildConditionSchema(col.disabledWhen),\n );\n return;\n }\n const when = col.showWhen ?? col.hideWhen;\n if (!when) return;\n const scope = `#/properties/${when.field}`;\n const schema = buildConditionSchema(when);\n if (col.showWhen) control.showWhen(scope, schema);\n else control.hideWhen(scope, schema);\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\n/**\n * Renderer format for a column with no explicit `fieldInput.type`, derived from\n * its declared `type`. Scalars keep the historical `text` default.\n */\nconst defaultControlFormat = (col: JsonColumn): string => {\n if (isObjectColumn(col)) return 'object';\n if (isArrayColumn(col)) return 'array';\n const typeName = columnTypeName(col.type);\n if (typeName === 'number' || typeName === 'integer') return typeName;\n const format = columnTypeToJsonSchema(col.type).format;\n if (format === 'date') return 'date';\n if (format === 'date-time') return 'dateTime';\n return 'text';\n};\n\nexport const buildFormControl = (col: JsonColumn): ControlBuilder<any> => {\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 (\n fieldInput?.format !== 'date-range' &&\n (fieldInput?.type === 'date' || fieldInput?.format === 'dateTime')\n ) {\n // Explicit branch (like date-range below) so the datepicker's date options\n // — withTime / min / max / locale — survive into the uischema. Without it\n // these fall through the generic else and are silently dropped.\n const options: any = { ...(fieldInput.options as object | undefined) };\n if (!options.colspan) options.colspan = 12;\n const format = fieldInput.format === 'dateTime' ? 'dateTime' : 'date';\n control.control(format, options).width('full');\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 // Drive the renderer off the column's declared shape when no widget is\n // named. Without this an object/array column falls through to `text`, whose\n // tester requires a string schema, and no renderer matches at all.\n const type = fieldInput?.type ?? defaultControlFormat(col);\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 // Label and conditional rules are expressed in the builder chain — no post-build mutation.\n if (col.label) control.label(col.label);\n applyColumnRule(control, col);\n\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 for (const col of cols) layout.addControl(buildFormControl(col));\n return layout.build() as unknown as Record<string, unknown>;\n};\n","import type { ViewColumnConfig, ViewConfig } from './view.schema';\nimport type { CalculatedColumn } from '../resource/CalculatedColumn.schema';\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","import { type ZodObject, type ZodRawShape, toJSONSchema } from 'zod';\n\n\nimport { isRelation } from './column-predicates';\nimport {\n columnToJsonSchemaProperty,\n columnTypeSchemaSource,\n} from './column-type-schema.source';\nimport { columnForContext, sortByPosition, toViewColumn } from './column.utils';\nimport { buildFormUiSchema } from './form-schema.builder';\nimport { jsonSchemaOpts } from './json-schema.opts';\nimport { orderTableColumnsFromLayout } from './layout-table-order';\nimport { buildFormUiSchemaFromLayout } from './layout-ui-schema.builder';\nimport { applySchemaTransforms } from './schema-transforms';\nimport { resolveDefaultSort } from './sort.helpers';\nimport { buildTableUiSchema } from './table-schema.builder';\nimport type { ViewConfig } from './view.schema';\nimport type { JsonColumn } from '../resource/Column';\nimport type { Layout } from '../resource/Layout.schema';\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 */\nexport const 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 =\n (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(\n (opts['fromLabel'] as string) ?? `${base} (from)`,\n );\n properties[`${col.id}->${toField}`] = dateProp(\n (opts['toLabel'] as string) ?? `${base} (to)`,\n );\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 = (\n col.fieldInput?.options as Record<string, unknown> | undefined\n )?.['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 (\n ft === 'number' ||\n prop.type === 'number' ||\n prop.type === 'integer'\n ) {\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/**\n * Copy each column's `fieldInput.defaultValue` (when set) onto the matching\n * JSON Schema property as `default`. Consumed by the frontend's\n * `form.parseValue({})` (see `@ghentcdh/crouton-vue`'s `form-def.ts`) to\n * pre-fill a blank create-form record. Relation columns never reach here —\n * `buildView` filters them out of the picked schema before this runs.\n */\nconst injectFieldDefaults = (\n jsonSchema: Record<string, unknown>,\n columns: JsonColumn[],\n): void => {\n const properties = jsonSchema.properties as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (!properties) return;\n for (const col of columns) {\n if (col.fieldInput?.defaultValue === undefined) continue;\n const prop = properties[col.id];\n if (prop) prop.default = col.fieldInput.defaultValue;\n }\n};\n\n// ── View building ─────────────────────────────────────────────────────────\n\n/**\n * Produces the `json_schema` for one view from the columns that belong in it.\n *\n * Two implementations exist: `zodSchemaSource` picks a mask off the resource's\n * Zod model schema (prisma resources), and `columnTypeSchemaSource` assembles\n * properties from each column's declared `type` (custom resources, which have\n * no `schema.ts`). Returning `undefined` skips the view entirely.\n */\nexport type ViewJsonSchemaSource = (\n schemaCols: JsonColumn[],\n) => Record<string, unknown> | undefined;\n\n/** Build a view's json_schema by picking a mask off the resource's Zod schema. */\nexport const zodSchemaSource =\n (schema: ZodObject<ZodRawShape>): ViewJsonSchemaSource =>\n (schemaCols) => {\n const schemaKeys = new Set(Object.keys(schema.shape));\n const schemaIds = schemaCols\n .map((c) => c.id)\n .filter((id) => schemaKeys.has(id));\n if (!schemaIds.length) return undefined;\n const mask = Object.fromEntries(schemaIds.map((id) => [id, true as const]));\n const picked = schema.pick(mask as any);\n try {\n return toJSONSchema(picked, {\n target: 'draft-07',\n ...jsonSchemaOpts,\n }) as Record<string, unknown>;\n } catch {\n // Zod v4 bug: z.record() inside z.union() inside z.lazy() crashes toJSONSchema.\n // Skip this field's JSON schema contribution — the column's type will be used instead.\n return undefined;\n }\n };\n\n/**\n * Apply column-level `required` to a form's `json_schema`.\n *\n * For a prisma resource the Zod model has already produced a `required` array and\n * a column overrides it in either direction; for a `kind: \"custom\"` resource\n * there is no model, so this is the only source of `required`.\n *\n * `undefined` leaves the schema's own answer alone — which is why the column flag\n * is optional rather than defaulting to `false`.\n */\n/**\n * Every JSON Schema type except `null`.\n *\n * A typeless property — what an autocomplete column emits, since the shape of its\n * `{ value, label }` envelope depends on the widget's `storeValue` option — becomes\n * `unknown` once the form converts the schema to Zod, and `unknown` accepts\n * `undefined` and `null`. Listing it in `required` therefore validated nothing:\n * the control showed its required marker and an empty field still submitted.\n *\n * Constraining the type to \"anything but null\" is what makes the requirement bite\n * without claiming to know the envelope's shape. `not: { type: 'null' }` would say\n * it more directly but Zod cannot represent `not`.\n */\nconst NON_NULL_TYPES = ['object', 'array', 'string', 'number', 'boolean'];\n\n/** Keys that already constrain a property's shape enough to reject null. */\nconst SHAPE_KEYS = ['type', 'enum', 'const', 'anyOf', 'oneOf', 'allOf', '$ref'];\n\nconst applyRequiredColumns = (\n jsonSchema: Record<string, unknown>,\n columns: JsonColumn[] | undefined,\n): void => {\n if (!columns?.length) return;\n const properties = jsonSchema['properties'] as\n | Record<string, unknown>\n | undefined;\n if (!properties) return;\n\n const required = new Set(\n Array.isArray(jsonSchema['required'])\n ? (jsonSchema['required'] as string[])\n : [],\n );\n\n for (const col of columns) {\n if (col.required === undefined) continue;\n if (!(col.id in properties)) continue;\n if (!col.required) {\n required.delete(col.id);\n continue;\n }\n // Same exclusion `buildView` applies to the model's own `required`: a field\n // the form cannot edit must not be demanded, or every submit fails on a value\n // the user has no way to provide.\n if (col.idField) continue;\n if (col.createable === false && col.updateable === false) continue;\n required.add(col.id);\n\n // A typeless property cannot be required in any meaningful sense — see\n // NON_NULL_TYPES. Give it just enough of a type to reject an empty value.\n const property = properties[col.id];\n if (\n property &&\n typeof property === 'object' &&\n !SHAPE_KEYS.some((key) => key in (property as Record<string, unknown>))\n ) {\n (property as Record<string, unknown>)['type'] = [...NON_NULL_TYPES];\n }\n }\n\n if (required.size) jsonSchema['required'] = [...required];\n else delete jsonSchema['required'];\n};\n\nconst buildView = (\n source: ViewJsonSchemaSource | 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 (!source || !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 // Relation columns are managed via sub-resource endpoints — exclude from\n // the schema pick so their complex Zod definitions (z.lazy arrays) don't\n // produce validation constraints on the parent. With additionalProperties\n // enabled, relation data in the payload still passes validation.\n const schemaCols = (schemaVisible\n ? columns.filter((c) => visible(c) || schemaVisible(c))\n : visibleCols\n ).filter((c) => !isRelation(c));\n\n const jsonSchema = source(schemaCols);\n if (!jsonSchema) return undefined;\n applySchemaTransforms(jsonSchema);\n injectFieldDefaults(jsonSchema, visibleCols);\n\n // Drop idField and explicitly non-editable fields from `required` so\n // hidden-but-schema-included fields don't cause validation failures.\n if (schemaVisible) {\n const nonEditableIds = new Set(\n schemaCols\n .filter((c) => c.idField || (c.createable === false && c.updateable === false))\n .map((c) => c.id),\n );\n const required = jsonSchema['required'] as string[] | undefined;\n if (Array.isArray(required) && nonEditableIds.size) {\n jsonSchema['required'] = required.filter((k) => !nonEditableIds.has(k));\n }\n }\n\n return {\n json_schema: jsonSchema,\n ui_schema: buildUiSchema(visibleCols),\n columns: visibleCols.map(toViewColumn),\n };\n};\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/**\n * Build table / form / filter / view schemas from column definitions and a\n * json_schema source.\n *\n * Shared by the Zod-backed path (`buildViews`) and the column-type path\n * (`buildViewsFromColumnTypes`) so both produce identical view shapes —\n * default sort, filter hints, and the `required` trimming all behave the same\n * regardless of where the properties came from.\n */\nexport const buildViewsWithSource = (\n source: ViewJsonSchemaSource | undefined,\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined => {\n const views: Record<string, ViewConfig> = {};\n\n const tableCols = columns?.map((c) => columnForContext(c, 'table'));\n let table = buildView(\n source,\n tableCols,\n (c) => !c.hiddenInTable,\n buildTableUiSchema,\n true,\n );\n if (table) {\n table.defaultSort = resolveDefaultSort(\n table.columns as JsonColumn[],\n columns,\n );\n if (layout?.table) table = orderTableColumnsFromLayout(table, layout.table);\n views.table = table;\n } else if (columns !== undefined) {\n views.table = emptyTableView();\n }\n\n const formUiBuilder = layout?.form\n ? (cols: JsonColumn[]) => buildFormUiSchemaFromLayout(layout.form!, cols)\n : buildFormUiSchema;\n const form = buildView(\n source,\n columns,\n (c) => !c.hiddenInForm,\n formUiBuilder,\n true,\n (c) => !c.idField && (c.createable === true || c.updateable === true),\n );\n if (form) {\n applyRequiredColumns(form.json_schema as Record<string, unknown>, columns);\n views.form = form;\n }\n\n const filter = buildView(\n source,\n columns,\n (c) => !!c.filterable,\n buildFormUiSchema,\n true,\n );\n if (filter) {\n patchFilterProperties(\n filter.json_schema as Record<string, any>,\n columns?.filter((c) => !!c.filterable),\n );\n views.filter = filter;\n }\n\n const viewCols = columns?.map((c) => columnForContext(c, 'view'));\n const viewUiBuilder = layout?.view\n ? (cols: JsonColumn[]) => buildFormUiSchemaFromLayout(layout.view!, cols)\n : buildFormUiSchema;\n const view = buildView(\n source,\n viewCols,\n (c) => !c.hiddenInView,\n viewUiBuilder,\n true,\n );\n if (view) views.view = view;\n\n return Object.keys(views).length ? views : undefined;\n};\n\n/**\n * Build table / form / filter / view schemas from a Zod schema + column definitions.\n *\n * When `schema` is absent (no schema.ts), falls back to `columnTypeSchemaSource`\n * so column `type` declarations are the single source of truth — same behaviour\n * as `buildViewsFromColumnTypes`, now available for any kind, not just \"custom\".\n */\nexport const buildViews = (\n schema: ZodObject<ZodRawShape> | undefined,\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined =>\n buildViewsWithSource(schema ? zodSchemaSource(schema) : columnTypeSchemaSource, columns, layout);\n\n/**\n * Build table / form / filter / view schemas for a resource with no Zod model\n * schema, deriving every property from the columns' declared `type`.\n *\n * This is the `kind: \"custom\"` path: there is no `schema.ts` to pick from, so\n * the column configuration is the single source of truth for the json model.\n *\n * Note there is no `required` array — a custom resource declares shapes, not\n * obligations, and validating a payload is the `repository.ts` author's job.\n */\nexport const buildViewsFromColumnTypes = (\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined =>\n buildViewsWithSource(columnTypeSchemaSource, columns, layout);\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 // Only nest when `column` introduces genuine grouping (extend columns).\n // When column === id the data is flat — nesting would be self-referential.\n if (c.column && c.column !== c.id) {\n if (!properties[c.column]) {\n properties[c.column] = {\n type: 'object',\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] = {\n type: 'object',\n properties: {},\n };\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 if (c.type !== undefined) {\n // A declared `type` is the whole point of a column config that has no\n // Zod model behind it — honour it here exactly as `columnTypeSchemaSource`\n // does, rather than falling through to the `string` default below.\n properties[c.id] = columnToJsonSchemaProperty(c);\n } else {\n const opts = c.fieldInput?.options as\n Record<string, unknown> | undefined;\n const isObject =\n opts?.emitObject === true || c.fieldInput?.type === 'autocomplete';\n properties[c.id] = {\n ...(isObject ? {} : { type: c.columnType ?? 'string' }),\n title: c.label ?? c.id,\n ...(c.fieldInput?.defaultValue !== undefined\n ? { default: c.fieldInput.defaultValue }\n : {}),\n };\n }\n }\n const schema: Record<string, unknown> = { type: 'object', properties };\n applySchemaTransforms(schema);\n return schema;\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 || col.column === col.id) 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(\n columns.filter((c) => !c.hiddenInTable).map((c) => columnForContext(c, 'table')),\n );\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) {\n applyRequiredColumns(form.json_schema as Record<string, unknown>, formCols);\n views.form = form;\n }\n\n const viewCols = sortByPosition(\n columns.filter((c) => !c.hiddenInView).map((c) => columnForContext(c, 'view')),\n );\n const viewView = makeView(viewCols, buildFormUiSchema);\n if (viewView) views.view = viewView;\n\n return Object.keys(views).length ? views : undefined;\n};\n","import { isAutocomplete } from './column-predicates';\nimport type { JsonColumn } from '../resource/Column';\nimport {\n type JsonSchemaFragment,\n columnTypeToJsonSchema,\n} from '../resource/ColumnType.schema';\n\n/**\n * Assemble a view's `json_schema` from the columns' declared `type`s.\n *\n * This is the `kind: \"custom\"` counterpart to `zodSchemaSource`: a custom\n * resource has no `schema.ts`, so the column configuration is the only\n * description of the data shape.\n *\n * A column's property is its `type` fragment (shorthand expanded), enriched\n * with:\n * - `title` from the column label, so the form and filter layers show a proper\n * heading without a second lookup;\n * - `default` from `fieldInput.defaultValue`, matching the Zod path where\n * `injectFieldDefaults` does the same;\n * - `enum` from `fieldInput.options.values`, so an enum-backed select validates\n * against its own option list.\n *\n * An autocomplete column with no declared `type` is emitted as a typeless\n * property, matching `buildViewsFromColumns`: the value is a `{value, label}`\n * envelope whose exact shape depends on the widget's `storeValue` option.\n */\nconst optionValues = (col: JsonColumn): unknown[] | undefined => {\n const values = (col.fieldInput?.options as Record<string, unknown> | undefined)\n ?.['values'];\n if (!Array.isArray(values)) return undefined;\n // Options are either primitives or `{ value, label }` envelopes.\n const unwrapped = values.map((v) =>\n v && typeof v === 'object' && 'value' in (v as Record<string, unknown>)\n ? (v as Record<string, unknown>).value\n : v,\n );\n return unwrapped.length ? unwrapped : undefined;\n};\n\n/** JSON Schema property for a single column, derived from its `type`. */\nexport const columnToJsonSchemaProperty = (\n col: JsonColumn,\n): JsonSchemaFragment => {\n const property: JsonSchemaFragment =\n col.type === undefined && isAutocomplete(col)\n ? {}\n : { ...columnTypeToJsonSchema(col.type) };\n\n if (property.title === undefined) property.title = col.label ?? col.id;\n\n if (\n col.fieldInput?.defaultValue !== undefined &&\n property.default === undefined\n ) {\n property.default = col.fieldInput.defaultValue;\n }\n\n if (property.enum === undefined) {\n const values = optionValues(col);\n if (values) property.enum = values;\n }\n\n return property;\n};\n\n/**\n * `ViewJsonSchemaSource` for resources without a Zod model schema.\n *\n * Returns `undefined` when no column contributes a property, so the caller\n * skips the view — same contract as `zodSchemaSource`.\n */\nexport const columnTypeSchemaSource = (\n schemaCols: JsonColumn[],\n): Record<string, unknown> | undefined => {\n if (!schemaCols.length) return undefined;\n\n const properties: Record<string, JsonSchemaFragment> = {};\n for (const col of schemaCols) {\n properties[col.id] = columnToJsonSchemaProperty(col);\n }\n\n return { type: 'object', properties };\n};\n","import type { ZodType } from 'zod';\nimport { z } from 'zod';\n\ntype ToJSONSchemaParams = NonNullable<\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n Parameters<typeof import('zod').toJSONSchema>[1]\n>;\ntype OverrideContext = Parameters<\n NonNullable<ToJSONSchemaParams['override']>\n>[0];\n\n/**\n * Detect if a ZodCustom schema wraps a `z.instanceof(Cls)` where `Cls.name`\n * matches the given name. Uses a single `safeParse(null)` to extract the\n * `expected` field from the validation error — lightweight and works even\n * when the class reference is unreachable (closure-captured as `cls`).\n */\nconst isInstanceOf = (zodSchema: unknown, className: string): boolean => {\n if (!(zodSchema instanceof z.ZodCustom)) return false;\n const result = (zodSchema as z.ZodCustom<unknown>).safeParse(null);\n if (result.success) return false;\n const issue = result.error.issues[0] as { expected?: string; message?: string };\n // When z.instanceof(Cls) has no custom message, Zod emits { expected: 'Cls.name' }.\n // When a custom message is provided (e.g. zod-prisma-types does this), Zod emits\n // { code: 'custom', message: '...' } with no `expected` — so also check the message.\n return issue?.expected === className || (issue?.message?.includes(className) ?? false);\n};\n\nconst jsonSchemaOverride = ({ zodSchema, jsonSchema }: OverrideContext) => {\n if (zodSchema instanceof z.ZodDate) {\n jsonSchema.type = 'string';\n jsonSchema.format = 'date-time';\n }\n // Prisma BigInt fields use z.bigint() which has no JSON schema equivalent.\n // Patch to { type: \"integer\" } so the frontend treats them as whole numbers.\n if (zodSchema instanceof z.ZodBigInt) {\n jsonSchema.type = 'integer';\n }\n // Prisma Decimal fields use z.instanceof(Prisma.Decimal) which produces\n // an empty JSON schema ({}). Patch to { type: \"number\" } so the frontend\n // renders a number input with proper validation.\n // Prisma 7+ bundles the class as 'Decimal2'; check both names.\n if (isInstanceOf(zodSchema, 'Decimal') || isInstanceOf(zodSchema, 'Decimal2')) {\n jsonSchema.type = 'number';\n }\n // Prisma Bytes fields use z.instanceof(Buffer) which produces an empty\n // JSON schema. Patch to { type: \"string\" } since binary data is typically\n // base64-encoded when serialized to JSON.\n if (isInstanceOf(zodSchema, 'Buffer')) {\n jsonSchema.type = 'string';\n }\n};\n\ntype ZodTypeInternal = ZodType & { _zod?: { def?: { type?: string; innerType?: ZodType } } };\n\n/** Strip optional/nullable/default/readonly wrappers to reach the core type. */\nconst unwrap = (schema: ZodType): ZodType => {\n let s: ZodTypeInternal = schema;\n let t: string | undefined = s._zod?.def?.type;\n while (t === 'optional' || t === 'nullable' || t === 'default' || t === 'readonly') {\n s = (s._zod?.def?.innerType ?? s) as ZodTypeInternal;\n t = s._zod?.def?.type;\n }\n return s;\n};\n\n/**\n * Returns true when `zodType` (after unwrapping) is a `z.instanceof(Prisma.Decimal)`.\n * Checks both 'Decimal' (Prisma ≤6) and 'Decimal2' (Prisma 7+ runtime bundle).\n */\nexport const isDecimalField = (zodType: ZodType): boolean => {\n const inner = unwrap(zodType);\n return isInstanceOf(inner, 'Decimal') || isInstanceOf(inner, 'Decimal2');\n};\n\nexport const jsonSchemaOpts = {\n unrepresentable: 'any' as const,\n override: jsonSchemaOverride,\n};\n","import { buildFormControl } from './form-schema.builder';\nimport { LayoutBuilder } from '../layout/layout.builder';\nimport type { JsonColumn } from '../resource/Column';\nimport type { LayoutControl, LayoutNode } from '../resource/Layout.schema';\n\nconst buildContainerForNode = (node: LayoutNode): LayoutBuilder<any> => {\n const type = node.type ?? 'grid';\n let builder: LayoutBuilder<any>;\n switch (type) {\n case 'collapse':\n builder = LayoutBuilder.collapse<any>();\n if (node.title) builder.title(node.title);\n if (node.titleKey) builder.titleKey(node.titleKey);\n break;\n case 'group':\n builder = LayoutBuilder.group<any>();\n if (node.title) builder.title(node.title);\n if (node.titleKey) builder.titleKey(node.titleKey);\n break;\n case 'horizontal':\n builder = LayoutBuilder.horizontal<any>();\n break;\n case 'vertical':\n builder = LayoutBuilder.vertical<any>();\n break;\n default:\n builder = LayoutBuilder.grid<any>(node.columns);\n }\n if (node.colspan !== undefined) builder.colspan(node.colspan);\n if (node.rowspan !== undefined) builder.rowspan(node.rowspan);\n if (node.label) builder.label(node.label);\n return builder;\n};\n\nconst resolveControlId = (ctrl: LayoutControl): string =>\n typeof ctrl === 'string' ? ctrl : ctrl.id;\n\nconst applyControlOverrides = (\n base: ReturnType<typeof buildFormControl>,\n ctrl: LayoutControl,\n): ReturnType<typeof buildFormControl> => {\n if (typeof ctrl === 'string') return base;\n if (ctrl.colspan !== undefined) base.colspan(ctrl.colspan);\n if (ctrl.rowspan !== undefined) base.rowspan(ctrl.rowspan);\n if (ctrl.width !== undefined) base.width(ctrl.width as any);\n if (ctrl.label !== undefined) base.label(ctrl.label);\n if (ctrl.hideLabel) base.hideLabel();\n if (ctrl.type !== undefined || ctrl.options !== undefined) {\n base.control(ctrl.type ?? 'text', ctrl.options as any);\n }\n return base;\n};\n\nconst buildNodeInto = (\n node: LayoutNode,\n colMap: Map<string, JsonColumn>,\n warn: (msg: string) => void,\n seenIds: Set<string>,\n): LayoutBuilder<any> => {\n const container = buildContainerForNode(node);\n\n // Controls first, then nested items\n if (node.controls?.length) {\n for (const ctrl of node.controls) {\n const id = resolveControlId(ctrl);\n const col = colMap.get(id);\n if (!col) {\n warn(`layout: unknown or hidden column id \"${id}\" — skipping`);\n continue;\n }\n if (typeof ctrl !== 'string') {\n if (ctrl.colspan !== undefined && (ctrl as any).rowspan !== undefined) {\n // table context: warn on span overrides\n }\n }\n seenIds.add(id);\n const control = buildFormControl(col);\n container.addControl(applyControlOverrides(control, ctrl));\n }\n }\n\n if (node.items?.length) {\n for (const item of node.items) {\n const child = buildNodeInto(item, colMap, warn, seenIds);\n container.addControl(child);\n }\n }\n\n return container;\n};\n\n/**\n * Build a form/view UI schema from an author-declared layout node tree.\n * Falls back to source-order grid for any visible columns not referenced.\n */\nexport const buildFormUiSchemaFromLayout = (\n node: LayoutNode,\n cols: JsonColumn[],\n warn: (msg: string) => void = console.warn,\n): Record<string, unknown> => {\n const colMap = new Map(cols.map((c) => [c.id, c]));\n const seenIds = new Set<string>();\n\n const root = buildNodeInto(node, colMap, warn, seenIds);\n\n // Append unreferenced columns to preserve backward-compat\n const unreferenced = cols.filter((c) => !seenIds.has(c.id));\n if (unreferenced.length) {\n for (const col of unreferenced) {\n warn(`layout: column \"${col.id}\" not referenced in layout — appending`);\n root.addControl(buildFormControl(col));\n }\n }\n\n return root.build() as unknown as Record<string, unknown>;\n};\n\n/**\n * Flatten the layout node tree depth-first into an ordered list of control ids.\n * Used by the table ordering step.\n */\nexport const flattenLayoutControlIds = (node: LayoutNode): string[] => {\n const ids: string[] = [];\n const visit = (n: LayoutNode): void => {\n for (const ctrl of n.controls ?? []) {\n const id = typeof ctrl === 'string' ? ctrl : ctrl.id;\n if (typeof ctrl !== 'string') {\n const c = ctrl as { colspan?: number; rowspan?: number };\n if ((c.colspan !== undefined || c.rowspan !== undefined)) {\n // ponytail: span on table controls silently ignored — table is flat\n }\n }\n ids.push(id);\n }\n for (const item of n.items ?? []) visit(item);\n };\n visit(node);\n return ids;\n};\n","import { flattenLayoutControlIds } from './layout-ui-schema.builder';\nimport type { ViewConfig } from './view.schema';\nimport type { LayoutNode } from '../resource/Layout.schema';\n\n/**\n * Reorder a table view's elements and columns to match the `layout.table` declaration.\n * Unreferenced visible columns keep their relative order at the end.\n */\nexport const orderTableColumnsFromLayout = (\n view: ViewConfig,\n node: LayoutNode,\n warn: (msg: string) => void = console.warn,\n): ViewConfig => {\n const orderedIds = flattenLayoutControlIds(node);\n if (!orderedIds.length) return view;\n\n const elements: any[] = (view.ui_schema as any)?.elements ?? [];\n const columns: any[] = view.columns ?? [];\n\n const elementById = new Map(\n elements.map((el) => {\n const id = (el.scope as string | undefined)?.replace('#/properties/', '');\n return [id, el];\n }),\n );\n const columnById = new Map(columns.map((c: any) => [c.id, c]));\n\n const knownIds = new Set([...elementById.keys()].filter(Boolean) as string[]);\n\n const reorderedElements: any[] = [];\n const reorderedColumns: any[] = [];\n const seen = new Set<string>();\n\n for (const id of orderedIds) {\n if (!knownIds.has(id)) {\n warn(`layout.table: column \"${id}\" not found in visible table columns — skipping`);\n continue;\n }\n seen.add(id);\n const el = elementById.get(id);\n if (el) reorderedElements.push(el);\n const col = columnById.get(id);\n if (col) reorderedColumns.push(col);\n }\n\n // Append unreferenced visible columns in their original relative order\n for (const el of elements) {\n const id = (el.scope as string | undefined)?.replace('#/properties/', '');\n if (id && !seen.has(id)) {\n reorderedElements.push(el);\n const col = columnById.get(id);\n if (col) reorderedColumns.push(col);\n }\n }\n\n return {\n ...view,\n ui_schema: { ...(view.ui_schema as any), elements: reorderedElements },\n columns: reorderedColumns,\n };\n};\n","import { z } from 'zod';\n\nimport { FieldInputSchema } from '../resource/FieldInput.schema';\n\nexport const ViewColumnConfigSchema = z.object({\n id: z.string(),\n label: z.string().optional(),\n sortable: z.boolean().optional(),\n searchable: z.boolean().optional(),\n fieldInput: FieldInputSchema.optional(),\n});\n\nexport type ViewColumnConfig = z.infer<typeof ViewColumnConfigSchema>;\n\nexport const ViewConfigSchema = z.object({\n // TODO why we have both?\n json_schema: z.record(z.string(), z.unknown()).optional(),\n ui_schema: z.record(z.string(), z.unknown()).optional(),\n // TODO why we have both?\n ui: z.record(z.string(), z.unknown()).optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n columns: z.array(ViewColumnConfigSchema),\n defaultSort: z.string().optional(),\n});\n\nexport type ViewConfig = z.infer<typeof ViewConfigSchema>;\n\nconst viewDefList = ['table', 'view', 'form'] as const;\nexport const ViewDefEnum = z.enum(viewDefList);\nexport type ViewDef = (typeof viewDefList)[number];\n","import { z } from 'zod';\n\nimport type { JsonColumn } from '../resource';\n\nconst EnumEntrySchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport type EnumEntry = z.infer<typeof EnumEntrySchema>;\n\nexport const EnumRegistrySchema = z\n .record(z.string(), z.array(EnumEntrySchema))\n .default({});\n\nexport type EnumRegistry = z.infer<typeof EnumRegistrySchema>;\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 =\n (col.fieldInput.options as Record<string, unknown> | undefined) ?? {};\n if (!('values' in options)) options.values = values;\n if (!('emitObject' in options)) options.emitObject = true;\n if (!('displayKey' in options)) options.displayKey = 'label';\n col.fieldInput.options = options;\n }\n};\n","import { ZodArray, ZodNullable, type ZodObject, ZodOptional, type ZodRawShape } from 'zod';\n\nimport type { JsonColumn, RelationType } from '../resource';\n\nexport const unwrapZodType = (type: any): any => {\n if (type instanceof ZodOptional || type instanceof ZodNullable) {\n return unwrapZodType(type.unwrap());\n }\n return type;\n};\n\nexport const 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\nexport const 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\nexport const 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;\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","import { z } from 'zod';\n\nimport { ResourceJsonShape } from '../resource';\nimport { ViewConfigSchema } from '../view';\nimport { CompiledSubResourceConfigSchema } from './compiled-sub-resource.schema';\nimport { DefinitionSchema } from './definition.schema';\nimport { LookupSchema } from './lookup.schema';\nimport { ValueLabelColumnSchema } from './value-label-column';\n\nexport const CompiledResourceSchema = ResourceJsonShape.extend({\n route: z.string(),\n valueLabelColumns: z.array(ValueLabelColumnSchema).default([]),\n subResources: z.lazy(() => z.array(CompiledSubResourceConfigSchema)).default([]),\n lookup: LookupSchema.optional(),\n views: z.record(z.string(), ViewConfigSchema),\n definition: DefinitionSchema,\n idField: z.string(),\n idType: z.enum(['string', 'number']).default('string'),\n});\n\nexport type CompiledResource = z.infer<typeof CompiledResourceSchema>;\n","import { z } from 'zod';\n\nimport { JsonOperationsSchema } from '../data-source';\nimport {\n CalculatedColumnSchema,\n JsonActionSchema,\n JsonDisplaySchema,\n JsonIncludeEntrySchema,\n} from '../resource';\nimport { ViewConfigSchema } from '../view';\nimport { ValueLabelColumnSchema } from './value-label-column';\n\nexport const CompiledSubResourceConfigSchema = z.object({\n column: z.string(),\n relation: z.string(),\n childRoute: z.string(),\n childKind: z.enum(['prisma', 'custom']).default('prisma'),\n childDir: z.string().optional(),\n childModel: z.string(),\n foreignKey: z.string(),\n name: z.string().optional(),\n title: z.string().optional(),\n idField: z.string().optional(),\n idType: z.enum(['string', 'number']).optional(),\n views: z.record(z.string(), ViewConfigSchema).optional(),\n operations: JsonOperationsSchema,\n actions: z.array(JsonActionSchema).optional(),\n modalSize: z.enum(['xs', 'sm', 'lg', 'xl']).optional(),\n display: JsonDisplaySchema.optional(),\n include: z.array(JsonIncludeEntrySchema).optional(),\n calculatedColumns: z.array(CalculatedColumnSchema).optional(),\n includeInFindOne: z.boolean().optional(),\n hiddenInTable: z.boolean().optional(),\n findOneOrderBy: z.record(z.string(), z.unknown()).optional(),\n valueLabelColumns: z.array(ValueLabelColumnSchema).optional(),\n relationType: z.enum(['oneToMany', 'manyToOne']).optional(),\n});\n\nexport type CompiledSubResourceConfig = z.infer<typeof CompiledSubResourceConfigSchema>;\n","import z from 'zod';\n/**\n * Shape of a `data-source.json`. The `type`/`name`/`default` keys are also read by crouton-api at runtime;\n * the rest are codegen-only.\n */\nexport const DataSourceShape = z.object({\n /** Datasource name (folder + `name` in data-source.json). */\n name: z.string(),\n /**\n * Env var holding the connection URL. Required for Prisma adapters; optional\n * for custom adapters whose connection config may differ (secrets file, SDK\n * key, etc.).\n */\n urlEnv: z.string().optional(),\n /** Import path for this datasource's generated Zod types (for resource `schema.ts`). */\n generatedTypesImport: z.string().optional(),\n /** Datasource type tag. Default `postgres`. */\n type: z.string().default('postgres'),\n /** Mark this as the default datasource. Default `false`. */\n default: z.boolean().default(false),\n /**\n * Adapter kind. `\"prisma\"` (default) expects `index.ts` to default-export a\n * `PrismaClient`; `\"custom\"` expects it to default-export a `DataSourceAdapter`.\n */\n adapter: z.enum(['prisma', 'custom']).default('prisma'),\n /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */\n prismaSchema: z.string().optional(),\n /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */\n prismaConfig: z.string().optional(),\n /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */\n zodOutput: z.string().optional(),\n /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */\n clientOutput: z.string().optional(),\n});\n\nexport const transformDataSource = <D extends z.infer<typeof DataSourceShape>>(\n data: D,\n) => {\n const name = data.name ?? 'name';\n\n return {\n ...data,\n generatedTypesImport:\n data.generatedTypesImport ?? `@your-scope/generated/${name}`,\n prismaSchema: data.prismaSchema ?? `prisma/${name}/schema.prisma`,\n prismaConfig: data.prismaConfig ?? `prisma/${name}/prisma.config.ts`,\n zodOutput: data.zodOutput ?? `generated/${name}/src`,\n clientOutput: data.clientOutput ?? `generated/${name}/client`,\n };\n};\n\nexport const DataSourceSchema = DataSourceShape.transform(transformDataSource);\n\nexport type DataSource = z.infer<typeof DataSourceSchema>;\n","import { z } from 'zod';\n\nconst ValueSchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport const ValueLabelColumnSchema = z.object({\n field: z.string(),\n values: z.array(ValueSchema).default([]),\n enumName: z.string().optional(),\n});\n\nexport type ValueLabelColumn = z.infer<typeof ValueLabelColumnSchema>;\n","import { z } from 'zod';\n\nimport { SchemaInputSchema } from './schema-input';\nimport { SecuritySchema } from '../data-source/Security.schema';\n\n\nexport type { JsonSchemaInput, SchemaInput } from './schema-input';\n\nconst ExternalOperationDefSchema = z.object({\n uri: z.string(),\n method: z.string().optional(),\n});\n\nconst OperationDefSchema = z.union([\n z.literal(true),\n ExternalOperationDefSchema,\n z.object({\n schema: SchemaInputSchema.optional(),\n security: SecuritySchema.optional(),\n }),\n]);\n\nexport type OperationDef = z.infer<typeof OperationDefSchema>;\n\nexport type PatchOperationDef = z.infer<typeof OperationDefSchema>;\n\nexport const ResourceDefinitionSchema = z.object({\n findAll: OperationDefSchema.optional(),\n findOne: OperationDefSchema.optional(),\n create: OperationDefSchema.optional(),\n update: OperationDefSchema.optional(),\n patch: OperationDefSchema.optional(),\n delete: OperationDefSchema.optional(),\n});\n\nexport type ResourceDefinition = z.infer<typeof ResourceDefinitionSchema>;\n\nconst DefinitionCallbackSchema = z.function({\n input: [],\n output: ResourceDefinitionSchema,\n});\n\nexport type DefinitionCallback = () => ResourceDefinition;\n\nexport const DefinitionSchema = z.union([\n ResourceDefinitionSchema,\n DefinitionCallbackSchema,\n]);\n","import { ZodObject, type ZodRawShape, z } from 'zod';\n\nexport const JsonSchemaInputSchema = z.object({\n type: z.literal('object'),\n properties: z.record(z.string(), z.unknown()),\n required: z.array(z.string()).optional(),\n additionalProperties: z.boolean().optional(),\n});\n\nexport type JsonSchemaInput = z.infer<typeof JsonSchemaInputSchema>;\n\nexport const SchemaInputSchema = z.union([\n z.custom<ZodObject<ZodRawShape>>((val) => val instanceof ZodObject),\n JsonSchemaInputSchema,\n]);\n\nexport type SchemaInput = z.infer<typeof SchemaInputSchema>;\n","import { z } from 'zod';\n\nexport const LookupSchema = z.object({\n key: z.string(),\n label: z.string().optional(),\n});\n\nexport type LookupConfig = z.infer<typeof LookupSchema>;\n","import { ZodObject, type ZodRawShape, toJSONSchema } from 'zod';\n\nimport type { JsonSchemaInput, SchemaInput } from './schema-input';\nimport { isNullableProperty } from '../schema.utils';\nimport { jsonSchemaOpts } from '../view/json-schema.opts';\n\n\nexport const isZodSchema = (\n schema: SchemaInput,\n): schema is ZodObject<ZodRawShape> => schema instanceof ZodObject;\n\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\nexport const toJsonSchema = (schema: SchemaInput): JsonSchemaInput => {\n if (isZodSchema(schema)) {\n let jsonSchema: Record<string, any>;\n try {\n jsonSchema = toJSONSchema(schema, {\n target: 'openApi3',\n ...jsonSchemaOpts,\n }) as Record<string, any>;\n } catch {\n return { type: 'object' } as JsonSchemaInput;\n }\n dropNullableFromRequired(jsonSchema);\n return jsonSchema as JsonSchemaInput;\n }\n return schema;\n};\n","import { z } from 'zod';\n\nimport { JsonOperationsSchema } from '../data-source/Operations.schema';\nimport { SidebarGroupSchema } from '../resource';\n\nexport const RulesetSchema = z.object({\n hideIdInTable: z.boolean().default(true),\n hideIdInForm: z.boolean().default(true),\n hideIdInView: z.boolean().default(true),\n hideTimestamps: z.boolean().default(true),\n hideForeignKeys: z.boolean().default(true),\n includeRelations: z.boolean().default(true),\n hideRelationsInTable: z.boolean().default(true),\n showRelationsInForm: z.boolean().default(true),\n enumValueLabel: z.boolean().default(true),\n sharedEnums: z.boolean().default(true),\n defaultOperations: JsonOperationsSchema.default(\n JsonOperationsSchema.parse({}),\n ),\n});\n\nexport type Ruleset = z.infer<typeof RulesetSchema>;\n\nexport const I18nConfigSchema = z.object({\n /** Default / fallback language. */\n defaultLanguage: z.string().default('en'),\n /** All supported language codes. */\n languages: z.array(z.string()).min(1),\n /** Directory containing `<lang>.json` bundles, relative to project root. */\n translationsDir: z.string().default('translations'),\n});\n\nexport type I18nConfig = z.infer<typeof I18nConfigSchema>;\n\nexport const CroutonConfigSchema = z.object({\n /**\n * Application title served to the frontend via `GET /_app/layout`.\n * Displayed in the admin sidebar header.\n */\n title: z.string(),\n /** Where resource directories live, relative to the project root. */\n resourcesDir: z.string(),\n /** Where datasource folders live (each with a `data-source.json`). */\n dataSourcesDir: z.string(),\n /**\n * Template for a model's Zod export name. `{Model}` → Prisma model name.\n * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema\n * emitted by zod-prisma-types when `createRelationValuesTypes` is on).\n */\n schemaExportName: z.string().default('{Model}WithRelationsSchema'),\n /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */\n enumsFile: z.string().default('crouton.enums.json'),\n /** Optional overrides of the default visibility ruleset. */\n rules: RulesetSchema.default(RulesetSchema.parse({})),\n /**\n * Sidebar group definitions, keyed by group slug (e.g. `\"metadata\"`).\n * Resources reference a group via `sidebar.group` in their `resource.json`.\n */\n sidebarGroups: z.record(z.string(), SidebarGroupSchema).default({}),\n /**\n * Whether form fields are saved automatically as the user edits them.\n * @default true\n */\n autoSave: z.boolean().default(true),\n /** Optional i18n / translation configuration. */\n i18n: I18nConfigSchema.optional(),\n});\n\nexport type CroutonConfig = z.infer<typeof CroutonConfigSchema>;\n","export const CONFIG_FILES = ['crouton.json', 'crouton.mjs', 'crouton.js'];\n","import { z } from 'zod';\n\nconst NestedStringRecord: z.ZodType<Record<string, unknown>> = z.lazy(() =>\n z.record(z.string(), z.union([z.string(), NestedStringRecord])),\n);\n\nexport const TranslationBundleSchema = z\n .object({\n app: z\n .object({\n title: z.string().optional(),\n })\n .optional(),\n sidebarGroups: z.record(z.string(), z.string()).optional(),\n resources: z\n .record(\n z.string(),\n z\n .object({\n title: z.string().optional(),\n sidebar: z.string().optional(),\n columns: z.record(z.string(), z.string()).optional(),\n actions: z.record(z.string(), z.string()).optional(),\n subResources: z\n .record(\n z.string(),\n z\n .object({\n title: z.string().optional(),\n columns: z.record(z.string(), z.string()).optional(),\n })\n .optional(),\n )\n .optional(),\n })\n .optional(),\n )\n .optional(),\n enums: z.record(z.string(), z.record(z.string(), z.string())).optional(),\n ui: NestedStringRecord.optional(),\n validation: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type TranslationBundle = z.infer<typeof TranslationBundleSchema>;\n","export const resourceTitleKey = (resource: string): string =>\n `resources.${resource}.title`;\n\nexport const resourceSidebarKey = (resource: string): string =>\n `resources.${resource}.sidebar`;\n\nexport const columnKey = (resource: string, column: string): string =>\n `resources.${resource}.columns.${column}`;\n\nexport const actionKey = (resource: string, action: string): string =>\n `resources.${resource}.actions.${action}`;\n\nexport const subResourceTitleKey = (\n resource: string,\n sub: string,\n): string => `resources.${resource}.subResources.${sub}.title`;\n\nexport const subResourceColumnKey = (\n resource: string,\n sub: string,\n column: string,\n): string => `resources.${resource}.subResources.${sub}.columns.${column}`;\n\nexport const enumKey = (enumName: string, value: string): string =>\n `enums.${enumName}.${value}`;\n\nexport const sidebarGroupKey = (group: string): string =>\n `sidebarGroups.${group}`;\n\nexport const uiKey = (path: string): string => `ui.${path}`;\n\nexport const validationKey = (code: string): string =>\n `validation.${code}`;\n","import type { TranslationBundle } from './Translations.schema';\n\nexport type Translator = (path: string, fallback?: string) => string;\n\nconst getNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n): string | undefined => {\n const keys = path.split('.');\n let current: unknown = obj;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[key];\n }\n if (typeof current === 'string' && current !== '') return current;\n return undefined;\n};\n\nexport const createTranslator = (\n bundles: Record<string, TranslationBundle>,\n language: string,\n defaultLanguage = 'en',\n): Translator => {\n const langBundle = bundles[language];\n const defaultBundle =\n language !== defaultLanguage ? bundles[defaultLanguage] : undefined;\n\n return (path: string, fallback?: string): string => {\n if (langBundle) {\n const value = getNestedValue(\n langBundle as unknown as Record<string, unknown>,\n path,\n );\n if (value !== undefined) return value;\n }\n\n if (defaultBundle) {\n const value = getNestedValue(\n defaultBundle as unknown as Record<string, unknown>,\n path,\n );\n if (value !== undefined) return value;\n }\n\n return fallback ?? path;\n };\n};\n","type LanguageEntry = { tag: string; q: number };\n\nconst parseAcceptLanguage = (header: string): LanguageEntry[] => {\n const entries: LanguageEntry[] = [];\n\n for (const part of header.split(',')) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n\n const [tag, ...params] = trimmed.split(';');\n let q = 1;\n for (const param of params) {\n const match = param.trim().match(/^q\\s*=\\s*([0-9.]+)$/);\n if (match) {\n q = parseFloat(match[1]);\n if (isNaN(q)) q = 0;\n }\n }\n entries.push({ tag: tag.trim().toLowerCase(), q });\n }\n\n return entries.sort((a, b) => b.q - a.q);\n};\n\nexport const resolveLanguage = (\n acceptLanguage: string | undefined | null,\n supported: readonly string[],\n defaultLanguage: string,\n): string => {\n if (!acceptLanguage) return defaultLanguage;\n\n const supportedLower = supported.map((s) => s.toLowerCase());\n const entries = parseAcceptLanguage(acceptLanguage);\n\n for (const { tag, q } of entries) {\n if (q <= 0) continue;\n\n if (tag === '*') return defaultLanguage;\n\n // exact match\n const exactIdx = supportedLower.indexOf(tag);\n if (exactIdx !== -1) return supported[exactIdx];\n\n // base tag match: \"nl-BE\" → \"nl\"\n const base = tag.split('-')[0];\n const baseIdx = supportedLower.indexOf(base);\n if (baseIdx !== -1) return supported[baseIdx];\n }\n\n return defaultLanguage;\n};\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';\n\nimport { registerResourceExtensions } from '@ghentcdh/crouton-core';\n\nimport type { CroutonAppConfig } from './crud/app-config';\nimport { createAppLayoutController } from './crud/app-layout';\nimport { type LoadedConfig, loadConfig } from './crud/config/read';\nimport { CroutonValidationExceptionFilter } from './crud/crouton-validation.filter';\nimport { createCrudController } from './crud/crud-controller.factory';\nimport { validateCustomRepository } from './crud/custom-repository';\nimport type { DataSourceAdapter, DataSourceEntry } from './crud/data-source';\nimport { DataSourceRegistry, loadDataSourcesFromDir } from './crud/data-source';\nimport { IS_DEV } from './crud/dev-mode';\nimport { DevResourcesController } from './crud/dev-tools/dev-resources.controller';\nimport { loadEnumRegistry } from './crud/enum-registry';\nimport { NoCacheInterceptor } from './crud/interceptors/no-cache.interceptor';\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 { type Resource } from './crud/resource/ResourceConfig.schema';\nimport { resourceLoadErrorsRegistry } from './crud/resource/resource-load-errors.registry';\nimport { ResourceConfigRegistry } from './crud/resource-config.registry';\nimport { CroutonSecurityGuard, SecurityGuardRegistry } from './crud/security';\nimport { createStatusController } from './crud/status';\nimport { LanguageInterceptor, TranslationRegistry } from './crud/translation';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n@Module({\n controllers: [],\n providers: [],\n exports: [],\n})\nexport class CroutonApiModule {\n async onModuleInit() {\n // BigInt has no toJSON — JSON.stringify throws \"Do not know how to serialize a BigInt\".\n // Patch once so every response containing BigInt fields (e.g. Prisma Int8 / BigInt columns) works.\n if (!(BigInt.prototype as any).toJSON) {\n (BigInt.prototype as any).toJSON = function () {\n return Number(this);\n };\n }\n // Decimal: Prisma.Decimal.prototype.toJSON returns a string by default (\"80\" instead of 80).\n // Patch to emit numbers — consistent with BigInt fix and jsonSchemaOpts (Decimal → type:\"number\").\n // Import from runtime/client (stable, no generated client needed) with a fallback for older Prisma.\n try {\n const { Decimal } = await import('@prisma/client/runtime/client');\n (Decimal.prototype as any).toJSON = function () {\n return parseFloat(this.toString());\n };\n } catch {\n // @prisma/client runtime not reachable — Decimal fields will serialize as strings\n }\n }\n\n private static forResources(\n configs: Resource[],\n dataSources: DataSourceEntry[],\n loader: ResourceConfigLoader,\n appConfig: CroutonAppConfig,\n config: LoadedConfig,\n ): DynamicModule {\n const { baseUrl, prefix, security } = appConfig;\n const dataSourceRegistry = new DataSourceRegistry(dataSources);\n\n // Security guard registry: maps guard names to their NestJS guard classes.\n const guardRegistry = new SecurityGuardRegistry(security?.guards ?? {});\n const moduleDefaultSecurity = security?.default;\n\n // Load enum registry\n const startDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);\n\n // Validate that each resource can actually serve what it advertises:\n // a prisma resource needs its model on the client, a custom resource needs\n // a repository.ts implementing every enabled operation. Failures are\n // skipped and recorded so they appear on the status page instead of\n // crashing the server.\n const validConfigs: Resource[] = [];\n for (const c of configs) {\n // Resolve the datasource adapter to determine data-access strategy.\n // Dispatch branches on the adapter kind, not on config.kind.\n // config.kind controls schema source only (prisma = schema.ts, custom = columns).\n let adapter: DataSourceAdapter | undefined;\n if (c.database || dataSourceRegistry.entries().length > 0) {\n try {\n adapter = dataSourceRegistry.resolveAdapter(c.database);\n } catch (e: any) {\n // A named datasource that doesn't exist is always an error.\n // No datasource at all is ok for kind=custom or custom-adapter resources.\n if (c.database) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: e.message ?? String(e),\n });\n continue;\n }\n }\n }\n\n const adapterIsCustom = adapter ? adapter.kind !== 'prisma' : false;\n const hasRepository = !!c.repository;\n // Adapter exposes the CRUD surface → factory routes through it; no repository.ts needed.\n const adapterHasCrud = !!(adapter?.findAll && adapter.count);\n\n if (adapterHasCrud && !hasRepository) {\n // Adapter guarantees CRUD; skip validateCustomRepository.\n validConfigs.push(c);\n continue;\n }\n\n // A per-resource repository.ts or a custom-adapter datasource without CRUD surface →\n // validate that the enabled operations can be served.\n if (hasRepository || adapterIsCustom || c.kind === 'custom') {\n let adapterClient: unknown = adapter?.client;\n // kind=custom on a prisma adapter: the adapter client is a PrismaClient, not\n // a repository — don't pass it as a fallback repository to the validator.\n if (!adapterIsCustom && !hasRepository) {\n adapterClient = undefined;\n }\n const problem = validateCustomRepository(\n c,\n c.repository,\n adapterClient,\n );\n if (problem) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: problem,\n });\n continue;\n }\n validConfigs.push(c);\n continue;\n }\n\n // Prisma adapter, no per-resource repository.ts: validate model.\n if (!c.model) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error:\n `\"model\" is required for resource \"${c.name}\" on a Prisma datasource. ` +\n 'Set \"model\" to the Prisma model name, or set adapter: \"custom\" on the datasource.',\n });\n continue;\n }\n if (adapter && adapter.supports && !adapter.supports(c.model)) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: `Model \"${c.model}\" not found on the provided PrismaClient. Check the resource config for \"${c.name}\".`,\n });\n continue;\n }\n validConfigs.push(c);\n }\n\n const configRegistry = new ResourceConfigRegistry(loader, validConfigs);\n\n // Translation registry: wire up when i18n is configured.\n let translationRegistry: TranslationRegistry | undefined;\n if (config.i18n) {\n const translationsDir = join(\n config.configDir,\n config.i18n.translationsDir,\n );\n translationRegistry = new TranslationRegistry(\n translationsDir,\n config.i18n,\n );\n configRegistry.setTranslationRegistry(translationRegistry);\n }\n\n const controllers = [\n ...validConfigs.map((c) =>\n createCrudController(\n c,\n baseUrl,\n moduleDefaultSecurity,\n !!security,\n prefix,\n appConfig.schemaEnricher,\n ),\n ),\n createAppLayoutController(\n configs,\n config.sidebarGroups,\n config.title,\n config.autoSave ?? true,\n translationRegistry,\n config.i18n,\n prefix,\n ),\n // Only registered (and thus only visible in Swagger/routing) when the\n // visual resource builder is enabled — see dev-resources.controller.ts.\n ...(IS_DEV ? [DevResourcesController] : []),\n createStatusController(enumRegistry, translationRegistry, prefix),\n ];\n\n return {\n module: CroutonApiModule,\n controllers,\n exports: [ResourceConfigRegistry],\n providers: [\n { provide: APP_INTERCEPTOR, useClass: NoCacheInterceptor },\n { provide: APP_FILTER, useClass: CroutonValidationExceptionFilter },\n { provide: DataSourceRegistry, useValue: dataSourceRegistry },\n { provide: ResourceConfigRegistry, useValue: configRegistry },\n // Security providers only registered when security is configured;\n // without guards the dispatching guard is never applied (see factory).\n ...(security\n ? [\n { provide: SecurityGuardRegistry, useValue: guardRegistry },\n CroutonSecurityGuard,\n ...guardRegistry.classes(),\n ]\n : []),\n ...(translationRegistry\n ? [\n {\n provide: TranslationRegistry,\n useValue: translationRegistry,\n },\n {\n provide: APP_INTERCEPTOR,\n useFactory: () => new LanguageInterceptor(translationRegistry!),\n },\n ]\n : []),\n ],\n };\n }\n\n static async forResourceDir(\n dirPath: string,\n dataSourcesPath: string,\n appConfig: CroutonAppConfig,\n ): Promise<DynamicModule> {\n // Register extensions before parsing resource.json files — ordering contract.\n if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);\n const config = await loadConfig();\n const loader = new FileSystemResourceConfigLoader(\n dirPath,\n appConfig.baseUrl,\n config.enumsFile,\n );\n const configs = await loadResourceConfigsFromDir(\n dirPath,\n appConfig.baseUrl,\n config.enumsFile,\n );\n const dataSources = await loadDataSourcesFromDir(dataSourcesPath);\n\n return CroutonApiModule.forResources(\n configs,\n dataSources,\n loader,\n appConfig,\n config,\n );\n }\n\n static async forLoader(\n loader: ResourceConfigLoader,\n configs: Resource[],\n dataSources: DataSourceEntry[],\n appConfig: CroutonAppConfig,\n ): Promise<DynamicModule> {\n const config = await loadConfig();\n return CroutonApiModule.forResources(\n configs,\n dataSources,\n loader,\n appConfig,\n config,\n );\n }\n}\n","import { z } from 'zod';\n\n// ─── Sidebar node types ───────────────────────────────────────────────────────\n\nexport const SidebarLeafSchema = z.object({\n kind: z.literal('item').default('item'),\n id: z.string(),\n label: z.string(),\n position: z.number().optional(),\n});\n\nexport type SidebarLeaf = z.infer<typeof SidebarLeafSchema>;\n\nexport const SidebarGroupSchema = z.object({\n kind: z.literal('group').default('group'),\n id: z.string(),\n label: z.string(),\n position: z.number().optional(),\n children: z.array(SidebarLeafSchema).default([]),\n});\n\nexport type SidebarGroup = z.infer<typeof SidebarGroupSchema>;\n\nexport const SidebarNodeSchema = z.discriminatedUnion('kind', [\n SidebarLeafSchema,\n SidebarGroupSchema,\n]);\n\nexport type SidebarNode = z.infer<typeof SidebarNodeSchema>;\n","import { type SidebarGroupConfig, labelFromId } from '@ghentcdh/crouton-core';\n\nimport {\n type SidebarGroup,\n type SidebarLeaf,\n SidebarLeafSchema,\n type SidebarNode,\n} from './app-layout.types';\nimport { type Resource } from '../resource/ResourceConfig.schema'; // ─── Sort helper ─────────────────────────────────────────────────────────────\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\nexport const buildLayoutPayload = (\n configs: Resource[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n isDev = false,\n) => {\n const visible = configs.filter(\n (c) =>\n c.sidebar?.hide !== true &&\n c.views?.['table'] &&\n // A resource nested under a parent has no standalone route, so a sidebar\n // entry for it would resolve to `<name>/schemas` and 404. It is reached\n // from its parent's detail view instead.\n !c.parent,\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 = SidebarLeafSchema.parse({\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, isDev };\n};\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport {\n type I18nConfig,\n type SidebarGroupConfig,\n sidebarGroupKey,\n} from '@ghentcdh/crouton-core';\n\nimport { IS_DEV } from '../dev-mode';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport { ResourceConfigRegistry } from '../resource-config.registry';\nimport { buildLayoutPayload } from './app-layout.builder';\nimport { getRequestLanguage } from '../translation/language.context';\nimport { type TranslationRegistry } from '../translation/translation.registry';\n\nexport const createAppLayoutController = (\n configs: Resource[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n translationRegistry?: TranslationRegistry,\n i18nConfig?: I18nConfig,\n prefix?: string,\n) => {\n const layoutPayload = buildLayoutPayload(\n configs,\n sidebarGroups,\n title,\n autoSave,\n IS_DEV,\n );\n\n @Controller(prefix ? `${prefix}/_app` : '_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 const language = getRequestLanguage();\n\n let payload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getAll(language);\n payload = buildLayoutPayload(\n fresh,\n language\n ? translateSidebarGroups(sidebarGroups, language, translationRegistry)\n : sidebarGroups,\n language ? translateTitle(title, language, translationRegistry) : title,\n autoSave,\n IS_DEV,\n );\n } else {\n payload = layoutPayload;\n }\n\n // Append i18n metadata + ui dictionary when translations are active\n if (translationRegistry?.active && i18nConfig) {\n const lang = language ?? i18nConfig.defaultLanguage;\n const bundle = translationRegistry.bundleFor(lang);\n return {\n ...payload,\n i18n: {\n languages: i18nConfig.languages,\n defaultLanguage: i18nConfig.defaultLanguage,\n current: lang,\n },\n ...(bundle.ui && { ui: bundle.ui }),\n };\n }\n\n return payload;\n }\n\n @Get('translations')\n @ApiOperation({\n summary: 'Get ui + validation translation dictionaries',\n })\n @ApiResponse({\n status: 200,\n description: 'Translation dictionaries for the current language',\n })\n getTranslations() {\n if (!translationRegistry?.active || !i18nConfig) {\n return { ui: {}, validation: {} };\n }\n const language = getRequestLanguage() ?? i18nConfig.defaultLanguage;\n const bundle = translationRegistry.bundleFor(language);\n return {\n ui: bundle.ui ?? {},\n validation: bundle.validation ?? {},\n };\n }\n }\n\n Reflect.defineMetadata(\n 'design:paramtypes',\n [ResourceConfigRegistry],\n AppLayoutController,\n );\n\n return AppLayoutController;\n};\n\n/** Translate sidebar group labels using the translator. */\nconst translateSidebarGroups = (\n groups: Record<string, SidebarGroupConfig>,\n language: string,\n registry?: TranslationRegistry,\n): Record<string, SidebarGroupConfig> => {\n if (!registry?.active) return groups;\n const t = registry.translatorFor(language);\n const translated: Record<string, SidebarGroupConfig> = {};\n for (const [slug, cfg] of Object.entries(groups)) {\n const label = t(sidebarGroupKey(slug), cfg.label);\n translated[slug] = label !== cfg.label ? { ...cfg, label } : cfg;\n }\n return translated;\n};\n\n/** Translate app title using app.title key. */\nconst translateTitle = (\n title: string | undefined,\n language: string,\n registry?: TranslationRegistry,\n): string | undefined => {\n if (!title || !registry?.active) return title;\n const t = registry.translatorFor(language);\n return t('app.title', title);\n};","/**\n * Parses a boolean-ish env var value. Accepts \"true\"/\"1\"/\"yes\" (case-insensitive)\n * as truthy; everything else — including `undefined` (unset) — is falsy.\n */\nconst parseBooleanEnv = (value: string | undefined): boolean =>\n !!value && ['true', '1', 'yes'].includes(value.trim().toLowerCase());\n\n/**\n * `true` when the visual resource builder (and its dev-only hot-reload\n * behavior for schemas/layout/resource.json) should be enabled.\n *\n * Read from the `CROUTON_SCHEMA_EDITOR` env var — set it in the consuming\n * app's `.env` file (loaded via `dotenv/config` in `main.ts`, as the\n * generated app templates already do). Defaults to `false` when unset, so\n * production deployments never expose these endpoints unless explicitly\n * opted in.\n */\nexport const IS_DEV = parseBooleanEnv(process.env['CROUTON_SCHEMA_EDITOR']);\n","import { Injectable } from '@nestjs/common';\n\nimport { IS_DEV } from './dev-mode';\nimport type { ResourceConfigLoader } from './loader/resource-config.loader';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { localizeResource } from './translation/localize-resource';\nimport type { TranslationRegistry } from './translation/translation.registry';\n\n@Injectable()\nexport class ResourceConfigRegistry<R extends Resource = Resource> {\n private configs: R[];\n private translationRegistry?: TranslationRegistry;\n\n /**\n * Per-language memo: `Map<language, Map<route, R>>`.\n * Cleared whenever the underlying configs reload (dev mode).\n */\n private localizedCache = new Map<string, Map<string, R>>();\n\n constructor(\n private readonly loader: ResourceConfigLoader,\n initialConfigs: R[],\n ) {\n this.configs = initialConfigs;\n }\n\n setTranslationRegistry(registry: TranslationRegistry): void {\n this.translationRegistry = registry;\n }\n\n async getAll(language?: string): Promise<R[]> {\n if (IS_DEV) {\n this.configs = (await this.loader.loadAll()) as R[];\n this.localizedCache.clear();\n }\n if (!language || !this.translationRegistry?.active) {\n return this.configs;\n }\n return this.configs.map((c) => this.getLocalized(c, language));\n }\n\n async getByRoute(route: string, language?: string): Promise<R | undefined> {\n if (IS_DEV) {\n const fresh = await this.loader.loadByRoute(route);\n this.localizedCache.clear();\n if (!fresh) return undefined;\n if (language && this.translationRegistry?.active) {\n return this.localize(fresh as R, language);\n }\n return fresh as R;\n }\n const config = this.configs.find((c) => c.route === route);\n if (!config) return undefined;\n if (language && this.translationRegistry?.active) {\n return this.getLocalized(config, language);\n }\n return config;\n }\n\n async findById(id: string, language?: string): Promise<R | undefined> {\n const all = await this.getAll(language);\n return all.find((c) => c.id === id);\n }\n\n /**\n * On-disk directory containing `route`'s `resource.json`, if known.\n * Only meaningful after a load has populated the loader's internal map —\n * callers in dev mode should call `getByRoute`/`getAll` first in the same\n * request to guarantee freshness.\n */\n getResourceDir(route: string): string | undefined {\n return this.loader.getResourceDir(route);\n }\n\n private getLocalized(config: R, language: string): R {\n let langMap = this.localizedCache.get(language);\n if (!langMap) {\n langMap = new Map();\n this.localizedCache.set(language, langMap);\n }\n let localized = langMap.get(config.route);\n if (!localized) {\n localized = this.localize(config, language);\n langMap.set(config.route, localized);\n }\n return localized;\n }\n\n private localize(config: R, language: string): R {\n if (!this.translationRegistry) return config;\n const t = this.translationRegistry.translatorFor(language);\n return localizeResource(config, t) as R;\n }\n}\n","import {\n type ResourceJson,\n buildResourceJsonSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nexport type ResolveResource = { json: ResourceJson; dir: string };\n\nexport type ReadResourceJsonResult =\n | { success: true; data: ResolveResource }\n | { success: false; error: string };\n\nexport const readResourceJson = (jsonPath: string): ReadResourceJsonResult | undefined => {\n if (!existsSync(jsonPath)) return undefined;\n\n let fileContent: unknown;\n try {\n fileContent = JSON.parse(readFileSync(jsonPath, 'utf-8'));\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON in ${jsonPath}: ${(err as Error).message}`,\n };\n }\n\n const resource = buildResourceJsonSchema().safeParse(fileContent);\n if (resource.error) {\n return {\n success: false,\n error: `Resource cannot be parsed ${jsonPath}: ${resource.error.message}`,\n };\n }\n\n return {\n success: true,\n data: {\n json: resource.data,\n dir: dirname(jsonPath),\n },\n };\n};\n\nexport const readResourceJsonFromPath = (resourcePath: string) => {\n if (resourcePath.endsWith('.json')) {\n return readResourceJson(resourcePath);\n }\n\n const jsonPath = resolve(dirname(resourcePath), 'resource.json');\n\n return readResourceJson(jsonPath);\n};","import { type ResolveResource, readResourceJson } from '../resource/ReadResourceJson';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\n/**\n * Outcome of resolving a relation column's `resource` path.\n *\n * The two failure modes are worth distinguishing: a path that points at nothing\n * is a typo or a moved directory, while a file that exists but does not parse is\n * a broken child config. Collapsing both into `undefined` — which is what\n * `resolveChildResource` does — leaves the caller unable to say which, and the\n * sub-resource builder then silently invents a Prisma-backed child. See\n * `buildSubResources`.\n */\nexport type ChildResourceResolution =\n | { ok: true; value: ResolveResource }\n | { ok: false; reason: 'missing'; attempted: string[] }\n | { ok: false; reason: 'invalid'; error: string };\n\n/**\n * Resolve `fieldInput.resource` (e.g. `\"./author.resource\"`) relative to the\n * parent resource's directory, reporting *why* it failed.\n *\n * Convention: `\"./author.resource\"` → sibling directory `author/resource.json`.\n * A path ending in `.json` is resolved against the parent directory directly.\n */\nexport const resolveChildResourceDetailed = (\n resourcePath: string,\n parentDir: string,\n): ChildResourceResolution => {\n const attempted: string[] = [];\n try {\n // Direct .json file reference (e.g. \"./content/resource.json\") — resolved\n // relative to parentDir itself.\n if (resourcePath.endsWith('.json')) {\n const directPath = resolve(parentDir, resourcePath);\n attempted.push(directPath);\n if (existsSync(directPath)) {\n const result = readResourceJson(directPath);\n if (result?.success) return { ok: true, value: result.data };\n return {\n ok: false,\n reason: 'invalid',\n error: result?.error ?? `Could not read ${directPath}`,\n };\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(\n dirname(parentDir),\n childName,\n 'resource.json',\n );\n attempted.push(childJsonPath);\n\n const result = readResourceJson(childJsonPath);\n if (result?.success) return { ok: true, value: result.data };\n if (result) return { ok: false, reason: 'invalid', error: result.error };\n\n return { ok: false, reason: 'missing', attempted };\n } catch (err) {\n return { ok: false, reason: 'invalid', error: (err as Error).message };\n }\n};\n\n/**\n * Resolve `fieldInput.resource` and return the child `resource.json` contents\n * AND the child's directory (needed so the child can resolve its own `extend`\n * paths), or `undefined` if it could not be resolved.\n *\n * Prefer {@link resolveChildResourceDetailed} where the failure reason matters.\n */\nexport const resolveChildResource = (\n resourcePath: string,\n parentDir: string,\n): ResolveResource | undefined => {\n const resolution = resolveChildResourceDetailed(resourcePath, parentDir);\n return resolution.ok ? resolution.value : undefined;\n};\n","import {\n type JsonColumn,\n resolveTableField,\n resolveViewField,\n} from '@ghentcdh/crouton-core';\n\nimport { resolveChildResource } from './resource-resolver';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\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 */\nexport const 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 = resolved.json.columns; // 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 */\nexport const 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 [\n {\n field: c.column ?? c.id,\n values: opts.values,\n ...(c.enum && { enumName: c.enum }),\n },\n ];\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 */\nexport const 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 * Prefill each column's `fieldView`/`fieldTable` with the fully-resolved variant\n * (the `fieldInput → fieldView → fieldTable` cascade). After this runs, every\n * consumer sees resolved variants without re-implementing the fallback.\n *\n * MUST run AFTER URI/relation enrichment (the last column transform in\n * `fromJson`), so the resolved view/table variants inherit the injected\n * `uri`/`resourceUri`/`resource`/`schemasUri` options and derived `relationType`\n * that enrichment only lands on `fieldInput`. Do not move it earlier.\n */\nexport const resolveColumnFieldVariants = (\n cols: JsonColumn[] | undefined,\n): JsonColumn[] | undefined =>\n cols?.map((col) => {\n const fieldView = resolveViewField(col);\n const fieldTable = resolveTableField(col);\n return {\n ...col,\n ...(fieldView && { fieldView }),\n ...(fieldTable && { fieldTable }),\n };\n });","/**\n * Apply translations to a Resource config.\n *\n * Patches column labels, resource title, sidebar label, action labels,\n * and the corresponding JSON Schema `title` properties in views —\n * without rebuilding views from scratch (no Zod schema needed).\n */\n\nimport type { JsonColumn, Translator, ViewConfig } from '@ghentcdh/crouton-core';\nimport {\n actionKey,\n columnKey,\n enumKey,\n resourceSidebarKey,\n resourceTitleKey,\n subResourceColumnKey,\n subResourceTitleKey,\n} from '@ghentcdh/crouton-core';\n\nimport { buildValueLabelColumns } from '../adapter/column-transforms';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\n\n/** Deep-clone a plain object (JSON-safe). */\nconst clone = <T>(obj: T): T => JSON.parse(JSON.stringify(obj));\n\n/**\n * Shallow-clone a Resource, deep-cloning only the JSON-safe parts that\n * will be mutated during translation. Fields like `definition` (Zod schema)\n * may contain circular references and are never translated, so they are\n * copied by reference.\n */\nconst cloneResource = (config: Resource): Resource => {\n const { definition, ...rest } = config as Record<string, unknown>;\n const localized = clone(rest) as Resource;\n if (definition) (localized as Record<string, unknown>).definition = definition;\n return localized;\n};\n\n/**\n * Translate enum option labels for columns that reference a shared enum.\n * Mutates the cloned column's `fieldInput.options.values[].label` in place.\n */\nconst translateEnumOptions = (\n columns: JsonColumn[] | undefined,\n t: Translator,\n): void => {\n if (!columns) return;\n for (const col of columns) {\n if (!col.enum) continue;\n const opts = col.fieldInput?.options as\n | { values?: { value: unknown; label: string }[] }\n | undefined;\n if (!Array.isArray(opts?.values)) continue;\n for (const entry of opts!.values!) {\n entry.label = t(\n enumKey(col.enum!, String(entry.value)),\n entry.label,\n );\n }\n }\n};\n\n/**\n * Translate labels in pre-built `valueLabelColumns` entries that carry an\n * `enumName`. Used for sub-resources where the original `JsonColumn` (with\n * its `col.enum` property) is no longer available.\n */\nconst translateValueLabelEntries = (\n vlCols: ValueLabelColumn[] | undefined,\n t: Translator,\n): void => {\n if (!vlCols) return;\n for (const vlc of vlCols) {\n if (!vlc.enumName) continue;\n for (const entry of vlc.values) {\n entry.label = t(\n enumKey(vlc.enumName, String(entry.value)),\n entry.label,\n );\n }\n }\n};\n\n/**\n * Patch `json_schema.properties[key].title` for each column whose label\n * was translated. This keeps the JSON Schema titles in sync with the\n * translated column labels without rebuilding views.\n */\nconst patchViewTitles = (\n views: Record<string, ViewConfig> | undefined,\n columnLabels: Map<string, string>,\n): Record<string, ViewConfig> | undefined => {\n if (!views) return views;\n\n const patched: Record<string, ViewConfig> = {};\n for (const [viewName, view] of Object.entries(views)) {\n const patchedView = clone(view);\n\n // Patch json_schema.properties[col].title\n const props = (patchedView.json_schema as Record<string, unknown>)?.properties;\n if (props && typeof props === 'object') {\n for (const [key, prop] of Object.entries(\n props as Record<string, Record<string, unknown>>,\n )) {\n const translated = columnLabels.get(key);\n if (translated && prop && typeof prop === 'object') {\n prop.title = translated;\n }\n }\n }\n\n // Patch view.columns[].label\n if (patchedView.columns) {\n patchedView.columns = patchedView.columns.map((vc) => {\n const translated = columnLabels.get(vc.id);\n return translated ? { ...vc, label: translated } : vc;\n });\n }\n\n // Patch ui_schema elements' options.label\n const patchUiElements = (elements: unknown[]): void => {\n for (const el of elements) {\n if (!el || typeof el !== 'object') continue;\n const element = el as Record<string, unknown>;\n const scope = element.scope as string | undefined;\n if (scope) {\n const match = /^#\\/properties\\/([^/]+)/.exec(scope);\n if (match) {\n const translated = columnLabels.get(match[1]);\n if (translated) {\n const opts = element.options as Record<string, unknown> | undefined;\n if (opts && typeof opts === 'object') opts.label = translated;\n }\n }\n }\n const nested = element.elements as unknown[] | undefined;\n if (Array.isArray(nested)) patchUiElements(nested);\n }\n };\n const uiSchema = patchedView.ui_schema as Record<string, unknown> | undefined;\n const uiElements = uiSchema?.elements as unknown[] | undefined;\n if (Array.isArray(uiElements)) patchUiElements(uiElements);\n\n patched[viewName] = patchedView;\n }\n return patched;\n};\n\n/**\n * Produce a localized clone of a Resource. The original is never mutated.\n *\n * What is translated:\n * - `title`, `sidebar.label`\n * - `columns[].label`\n * - `views` JSON Schema `title` properties + `columns[].label`\n * - `actions[].label`, `tableActions[].label`\n * - `subResources[].title`, `subResources[].columns.label`, `subResources[].views`\n *\n * What is NOT translated (identity):\n * - `definition`, `hooks`, `repository`, `include`, `lookup`, URIs\n */\nexport const localizeResource = (\n config: Resource,\n t: Translator,\n): Resource => {\n const name = config.name;\n const localized = cloneResource(config);\n\n // Title\n localized.title = t(\n resourceTitleKey(name),\n config.title ?? config.tag,\n );\n\n // Sidebar label\n if (localized.sidebar) {\n const sidebarTranslation = t(\n resourceSidebarKey(name),\n config.sidebar?.label,\n );\n // Only set if we got a real translation (not the path back)\n if (sidebarTranslation !== resourceSidebarKey(name)) {\n localized.sidebar = { ...localized.sidebar, label: sidebarTranslation };\n }\n }\n\n // Columns\n const columnLabels = new Map<string, string>();\n const columns = localized.columns as unknown as JsonColumn[] | undefined;\n if (columns) {\n for (const col of columns) {\n const translated = t(\n columnKey(name, col.id),\n col.label ?? col.id,\n );\n col.label = translated;\n columnLabels.set(col.id, translated);\n }\n\n // Translate enum option labels and rebuild valueLabelColumns\n translateEnumOptions(columns, t);\n localized.valueLabelColumns = buildValueLabelColumns(columns);\n }\n\n // Views — patch JSON Schema titles + view column labels\n if (localized.views) {\n localized.views = patchViewTitles(localized.views, columnLabels) as Resource['views'];\n }\n\n // Actions\n if (localized.actions) {\n for (const a of localized.actions) {\n a.label = t(actionKey(name, a.id), a.label);\n }\n }\n if (localized.tableActions) {\n for (const a of localized.tableActions) {\n a.label = t(actionKey(name, a.id), a.label);\n }\n }\n\n // Sub-resources\n if (localized.subResources) {\n for (const sub of localized.subResources as SubResourceConfig[]) {\n const subName = sub.name ?? sub.childRoute;\n sub.title = t(\n subResourceTitleKey(name, subName),\n sub.title ?? subName,\n );\n\n // Sub-resource view columns\n const subColumnLabels = new Map<string, string>();\n if (sub.views) {\n for (const view of Object.values(sub.views)) {\n if (view.columns) {\n for (const vc of view.columns) {\n const translated = t(\n subResourceColumnKey(name, subName, vc.id),\n vc.label ?? vc.id,\n );\n vc.label = translated;\n subColumnLabels.set(vc.id, translated);\n }\n }\n }\n sub.views = patchViewTitles(\n sub.views as Record<string, ViewConfig>,\n subColumnLabels,\n ) as typeof sub.views;\n }\n\n // Translate enum option labels in sub-resource valueLabelColumns\n translateValueLabelEntries(sub.valueLabelColumns, t);\n }\n }\n\n return localized;\n};\n","/**\n * Per-request language context using AsyncLocalStorage.\n *\n * The LanguageInterceptor stores the resolved language; downstream code\n * reads it via `getRequestLanguage()` without threading a parameter\n * through every function signature.\n *\n * Outside a request scope (tests, CLI), returns the default language.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nconst languageStore = new AsyncLocalStorage<string>();\n\n/** Run a callback within a language context. */\nexport const runWithLanguage = <T>(language: string, fn: () => T): T =>\n languageStore.run(language, fn);\n\n/** Get the current request's resolved language, or `defaultLanguage` if none. */\nexport const getRequestLanguage = (defaultLanguage = 'en'): string =>\n languageStore.getStore() ?? defaultLanguage;\n","import {\n CONFIG_FILES,\n type CroutonConfig,\n CroutonConfigSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { access, readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, resolve as pathResolve } from 'node:path';\n\nconst fileExists = async (p: string): Promise<boolean> => {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Walk up from `cwd` to find `crouton.json`. */\nexport const findConfigPath = async (\n cwd: string,\n): Promise<string | undefined> => {\n let dir = resolve(cwd);\n\n while (true) {\n for (const name of CONFIG_FILES) {\n const candidate = join(dir, name);\n if (await fileExists(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n};\n\nexport type LoadedConfig = CroutonConfig & {\n /** Absolute directory containing the resolved crouton config file. */\n configDir: string;\n};\n\n/** Load + validate `crouton.json`. Throws if none is found. */\nexport const loadConfig = async (): Promise<LoadedConfig> => {\n const cwd = pathResolve(process.cwd());\n const path = await findConfigPath(cwd);\n if (!path) {\n throw new Error(\n `No crouton config found (looked for ${CONFIG_FILES.join(', ')} up from ${cwd}).`,\n );\n }\n let config: CroutonConfig;\n if (path.endsWith('.json')) {\n config = JSON.parse(await readFile(path, 'utf-8')) as CroutonConfig;\n } else {\n const mod = (await import(path)) as {\n default?: CroutonConfig;\n } & CroutonConfig;\n config = mod.default ?? mod;\n }\n\n const parsed = CroutonConfigSchema.parse(config);\n return { ...parsed, configDir: dirname(path) };\n};\n","import {\n type ArgumentsHost,\n Catch,\n type ExceptionFilter,\n Inject,\n Optional,\n} from '@nestjs/common';\n\nimport { validationKey } from '@ghentcdh/crouton-core';\n\nimport { CroutonValidationError } from './crouton-validation.error';\nimport { getRequestLanguage } from './translation/language.context';\nimport { TranslationRegistry } from './translation/translation.registry';\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 * When a `TranslationRegistry` is available, error messages are translated\n * using `validation.<code>` keys with `{field}` interpolation.\n */\n@Catch(CroutonValidationError)\nexport class CroutonValidationExceptionFilter implements ExceptionFilter {\n constructor(\n @Optional()\n @Inject(TranslationRegistry)\n private readonly translationRegistry?: TranslationRegistry,\n ) {}\n\n catch(exception: CroutonValidationError, host: ArgumentsHost): void {\n const res = host.switchToHttp().getResponse<{\n status: (code: number) => { json: (body: unknown) => void };\n }>();\n\n const errors = this.translateErrors(exception.errors);\n\n res.status(400).json({\n statusCode: 400,\n message: errors,\n error: 'Bad Request',\n });\n }\n\n private translateErrors(\n errors: CroutonValidationError['errors'],\n ): Array<{ field: string; message: string }> {\n if (!this.translationRegistry) return errors;\n const language = getRequestLanguage();\n if (!language) return errors;\n\n const t = this.translationRegistry.translatorFor(language);\n\n return errors.map(({ field, message, code }) => {\n if (!code) return { field, message };\n const key = validationKey(code);\n const translated = t(key, '');\n if (!translated) return { field, message };\n // Interpolate {field} placeholder\n return {\n field,\n message: translated.replace(/\\{field\\}/g, field),\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<{\n field: string;\n message: string;\n /** Zod issue code (e.g. `invalid_type`, `too_small`). */\n code?: string;\n }>,\n ) {\n super('Validation failed');\n this.name = 'CroutonValidationError';\n }\n}\n","/**\n * Read per-language translation bundles from disk.\n * Mirrors `enum-registry.loader.ts`.\n */\n\nimport type { TranslationBundle } from '@ghentcdh/crouton-core';\n\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport const loadTranslationBundles = (\n translationsDir: string,\n): Record<string, TranslationBundle> => {\n if (!existsSync(translationsDir)) return {};\n\n const bundles: Record<string, TranslationBundle> = {};\n const entries = readdirSync(translationsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const lang = entry.name.replace(/\\.json$/, '');\n try {\n bundles[lang] = JSON.parse(\n readFileSync(join(translationsDir, entry.name), 'utf-8'),\n ) as TranslationBundle;\n } catch {\n /* skip malformed files */\n }\n }\n\n return bundles;\n};\n","/**\n * Translation registry: holds per-language bundles and provides a\n * `translatorFor(language)` factory. Loaded once at boot; dev mode\n * reloads from disk on each request.\n */\n\nimport {\n type I18nConfig,\n type TranslationBundle,\n type Translator,\n createTranslator,\n} from '@ghentcdh/crouton-core';\n\nimport { IS_DEV } from '../dev-mode';\nimport { loadTranslationBundles } from './translation.loader';\n\nexport class TranslationRegistry {\n private bundles: Record<string, TranslationBundle>;\n\n constructor(\n private readonly translationsDir: string,\n private readonly i18nConfig: I18nConfig,\n ) {\n this.bundles = loadTranslationBundles(translationsDir);\n }\n\n get languages(): readonly string[] {\n return this.i18nConfig.languages;\n }\n\n get defaultLanguage(): string {\n return this.i18nConfig.defaultLanguage;\n }\n\n /** Whether i18n is active (at least one bundle loaded). */\n get active(): boolean {\n return Object.keys(this.bundles).length > 0;\n }\n\n translatorFor(language: string): Translator {\n if (IS_DEV) {\n this.bundles = loadTranslationBundles(this.translationsDir);\n }\n return createTranslator(\n this.bundles,\n language,\n this.i18nConfig.defaultLanguage,\n );\n }\n\n /** Raw bundle for a language (falls back to default). */\n bundleFor(language: string): TranslationBundle {\n if (IS_DEV) {\n this.bundles = loadTranslationBundles(this.translationsDir);\n }\n return (\n this.bundles[language] ??\n this.bundles[this.i18nConfig.defaultLanguage] ??\n {}\n );\n }\n}\n","import { Body, Controller, SetMetadata, type Type, UseGuards } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\n\nimport { type SecurityConfig, resourceControllerPath } from '@ghentcdh/crouton-core';\n\nimport { type CrudRepository, createCrudRepository } from './crud-repository.factory';\nimport { type CrudOperation, isOperationEnabled, resolveDefinition, schemaFor, securityFor, securityForSub } from './crud.config';\nimport { DataSourceRegistry } from './data-source';\nimport type { OperationContext } from './operations/operation-context';\nimport { registerEndpoints } from './operations/register-endpoints';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { ResourceConfigRegistry } from './resource-config.registry';\nimport { isZodSchema } from './schema.utils';\nimport { CROUTON_SECURITY, CroutonSecurityGuard } from './security';\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 */\nexport function createCrudController(\n config: Resource,\n baseUrl?: string,\n moduleDefaultSecurity?: SecurityConfig,\n securityEnabled = false,\n prefix?: string,\n schemaEnricher?: <T extends Record<string, unknown>>(schema: T) => Record<string, unknown>,\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 explicitPatchSchema = schemaFor(definition, 'patch');\n const patchSchema =\n explicitPatchSchema ??\n (updateSchema && isZodSchema(updateSchema)\n ? (updateSchema as any).partial()\n : undefined) ??\n updateSchema;\n const bodyDecorator = (\n schema?: ReturnType<typeof schemaFor>,\n options?: ZodValidationPipeOptions,\n ): ParameterDecorator => {\n if (!schema) return Body();\n if (isZodSchema(schema))\n return Body(new ZodValidationPipe(schema, options));\n return Body();\n };\n\n const resolveClient = (\n registry: DataSourceRegistry,\n resource: Resource,\n ): any => {\n try {\n return registry.resolve(resource.database);\n } catch (e) {\n // A resource with no datasource at all (kind=custom or custom adapter) is valid —\n // the repository receives undefined as its client.\n if (resource.kind === 'custom') return undefined;\n try {\n const adapter = registry.resolveAdapter(resource.database);\n if (adapter.kind !== 'prisma') return adapter.client;\n } catch {\n // fall through to re-throw original\n }\n throw e;\n }\n };\n\n class CrudControllerBase {\n protected readonly repo: CrudRepository;\n protected readonly configRegistry: ResourceConfigRegistry;\n constructor(\n registry: DataSourceRegistry,\n configRegistry: ResourceConfigRegistry,\n ) {\n // A custom resource may legitimately run in a project with no\n // datasources at all, so a resolve failure is not fatal for it — the\n // repository simply receives `ctx.prisma === undefined`.\n const prisma = resolveClient(registry, config);\n this.repo = createCrudRepository(prisma, config, registry, configRegistry);\n this.configRegistry = configRegistry;\n }\n }\n\n const secure = (methodName: string, op: CrudOperation, sub?: SubResourceConfig): void => {\n const sec = sub\n ? securityForSub(config, sub, op, moduleDefaultSecurity)\n : securityFor(config, definition, op, moduleDefaultSecurity);\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(\n CrudControllerBase.prototype,\n methodName,\n Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName)!,\n );\n }\n };\n\n const ctx: OperationContext = {\n cls: CrudControllerBase,\n config,\n definition,\n listSchema,\n oneSchema,\n createSchema,\n updateSchema,\n patchSchema,\n idParamMeta: {\n name: 'id',\n type: idType === 'number' ? 'number' : 'string',\n },\n bodyDecorator,\n baseUrl,\n moduleDefaultSecurity,\n secure,\n schemaEnricher,\n };\n\n registerEndpoints(ctx);\n\n // ── Class-level decorators ─────────────────────────────────────────────\n // A resource that declares a `parent` is reachable ONLY underneath it, so the\n // whole controller moves to `<parent.route>/:<param>/<route>`; every operation\n // route (``, `:id`, `schemas`, …) inherits the prefix, and the parent id is\n // available to handlers through the request they already receive.\n const controllerPath = resourceControllerPath(route, config.parent);\n Controller(prefix ? `${prefix}/${controllerPath}` : controllerPath)(CrudControllerBase);\n // Only apply the dispatching guard when the module has security configured.\n // Without this, the guard's DI dependencies would fail to resolve in\n // projects that do not configure security at all.\n if (securityEnabled) {\n UseGuards(CroutonSecurityGuard)(CrudControllerBase);\n }\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 { NotFoundException } from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport { resolveDefinition, schemaFor } from './crud.config';\nimport {\n type DataSourceResolver,\n createCustomRepository,\n} from './custom-repository';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { PrismaDataSourceAdapter } from './data-source/prisma.adapter';\nimport { applyAfterFindAll, applyBeforeFindAll, decorateRow, decorateRows, postWrite, prepareWrite } from './hooks';\nimport { ReadRepository } from './read.repository';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { type SubResourceConfig } from './resource/SubResource.schema';\nimport type { ResourceConfigRegistry } from './resource-config.registry';\nimport { toSelectFields } from './schema.utils';\nimport { resolveValueLabelColumns } from './translation';\nimport { WriteRepository, stripSubResourceKeys } 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: ListRequest, request?: any): Promise<T[]>;\n count(filter: string[], q?: string): Promise<number>;\n /**\n * Fetch rows *and* their total count in a single call.\n *\n * Optional: the Prisma-backed repository leaves it undefined and callers fall\n * back to `findAll` + `count`. Repositories whose backend cannot count\n * separately (e.g. a remote HTTP API returning `{items, total}`) implement\n * this instead.\n */\n findAllWithCount?(\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }>;\n findOne(id: number | string, request?: any): Promise<T>;\n findAllByParent(\n parentId: string | number,\n childRoute: string,\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }>;\n findOneChild(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T>;\n createChild(\n parentId: string | number,\n sub: SubResourceConfig,\n data: unknown,\n request?: any,\n ): Promise<T>;\n updateChild(\n sub: SubResourceConfig,\n childId: string | number,\n data: unknown,\n request?: any,\n ): Promise<T>;\n deleteChild(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T>;\n create(data: unknown, request?: any): Promise<T>;\n update(id: number | string, data: unknown, request?: any): Promise<T>;\n patch(id: number | string, data: unknown, request?: any): Promise<T>;\n delete(id: number | string, request?: any): 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 * A `kind: \"custom\"` resource short-circuits to `createCustomRepository`, which\n * delegates to the user's `repository.ts`.\n *\n * Resource-level hooks (`beforeWrite`/`afterWrite`/`afterRead`) and valueLabel\n * decoration are applied here in the factory wrapper — the repositories perform\n * pure data access so both Prisma and custom adapters share the same hook path.\n *\n * @param prisma - Full PrismaClient instance (may be `undefined` for a custom\n * resource in a project with no datasources).\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: Resource,\n dataSources?: DataSourceResolver,\n configRegistry?: ResourceConfigRegistry,\n): CrudRepository<T> {\n const fallbackDataSources: DataSourceResolver = dataSources ?? {\n resolve: () => prisma,\n entries: () => [],\n };\n\n // A per-resource repository.ts always takes precedence over the datasource adapter.\n if (config.repository) {\n return createCustomRepository<T>(\n prisma,\n config,\n fallbackDataSources,\n config.repository,\n configRegistry,\n );\n }\n\n const resolvedAdapter = dataSources?.resolveAdapter?.(config.database);\n\n // For kind:custom resources there is no Prisma model; use the resource name as the\n // model key passed to adapter methods so they can route to the right collection.\n const adapterModelKey = config.model ?? config.name;\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 // If the adapter exposes the CRUD surface, route through it regardless of adapter\n // kind or resource kind. Covers:\n // - kind:prisma + adapter:prisma (PrismaDataSourceAdapter or subclass override)\n // - kind:custom + adapter:custom (no repository.ts needed)\n // - kind:prisma + adapter:custom (custom backend with generated schema)\n if (resolvedAdapter?.findAll && resolvedAdapter.count) {\n const baseCtx = { config, op: 'n/a', offset: 0, listSelect, oneSelect, configRegistry };\n const ctx = (request?: any, op = 'findAll', id?: string | number) => ({\n ...baseCtx, op, request, ...(id !== undefined && { id }),\n });\n\n const mkDecorateFindAll = (adapter: DataSourceAdapter) =>\n async (rows: any[], request?: any): Promise<any[]> => {\n const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);\n const target = vlCols === config.valueLabelColumns ? config : { hooks: config.hooks, valueLabelColumns: vlCols };\n const decorated = await decorateRows(rows, 'findAll', target, adapter, request);\n return applyAfterFindAll(decorated, config, adapter, request);\n };\n const decorateFindAll = mkDecorateFindAll(resolvedAdapter);\n const applyBefore = (params: ListRequest, request?: any) =>\n applyBeforeFindAll(params, config, resolvedAdapter, request);\n const decorateFindOne = (row: any, request?: any) => decorateRow(row, 'findOne', config, resolvedAdapter, request);\n const prepareData = (data: unknown, op: 'create'|'update'|'patch', id?: string|number, request?: any) =>\n prepareWrite(data, op, config, resolvedAdapter, id, request);\n const postData = (result: any, op: 'create'|'update'|'patch'|'delete', id?: string|number, request?: any) =>\n postWrite(result, op, config, resolvedAdapter, id, request);\n const toId = (id: string | number): string | number =>\n (config.idType ?? 'string') === 'number' ? +id : String(id);\n\n const adapterFindAllByParent = async (\n parentId: string | number,\n childRoute: string,\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }> => {\n if (resolvedAdapter.findAllByParent) {\n const sub = config.subResources?.find((s) => s.childRoute === childRoute);\n if (!sub) throw new Error(`No sub-resource \"${childRoute}\" on \"${config.name}\"`);\n return resolvedAdapter.findAllByParent(adapterModelKey, parentId, sub, params, ctx(request, 'findAll'));\n }\n // Fallback: only available when prisma model exists (Prisma adapter).\n if (!config.model) throw new Error(`Adapter for \"${config.name}\" does not implement findAllByParent`);\n const prismaModel = prisma[config.model];\n const reader = new ReadRepository<T>(prismaModel, resolvedAdapter, config, listSelect, oneSelect, configRegistry);\n return reader.findAllByParent(parentId, childRoute, params, request);\n };\n\n const adapterFindOneChild = async (\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T> => {\n if (resolvedAdapter.findOneChild) {\n const row = await resolvedAdapter.findOneChild(adapterModelKey, sub, childId, parentId, ctx(request, 'findOne', childId));\n if (row === null || row === undefined) throw new NotFoundException(`${sub.childRoute} with id ${childId} not found`);\n return row;\n }\n if (!config.model) throw new Error(`Adapter for \"${config.name}\" does not implement findOneChild`);\n const prismaModel = prisma[config.model];\n const reader = new ReadRepository<T>(prismaModel, resolvedAdapter, config, listSelect, oneSelect, configRegistry);\n return reader.findOneChild(sub, childId, parentId, request);\n };\n\n const prismaModel = config.model ? prisma?.[config.model] : undefined;\n const writer = prismaModel ? new WriteRepository<T>(prismaModel, resolvedAdapter, config) : undefined;\n\n return {\n prisma,\n findAllWithCount: async (params, request) => {\n const effectiveParams = await applyBefore(params, request);\n const { data, count } = await resolvedAdapter.findAll!(adapterModelKey, effectiveParams, { ...ctx(request, 'findAll'), offset: offsetOf(effectiveParams) });\n return { data: await decorateFindAll(data, request), count };\n },\n findAll: async (params, request) => {\n const effectiveParams = await applyBefore(params, request);\n const { data } = await resolvedAdapter.findAll!(adapterModelKey, effectiveParams, { ...ctx(request, 'findAll'), offset: offsetOf(effectiveParams) });\n return decorateFindAll(data, request);\n },\n count: (filter, q) => resolvedAdapter.count!(adapterModelKey, filter, { ...baseCtx, q }),\n findOne: async (id, request) => {\n const row = await resolvedAdapter.findOne!(adapterModelKey, id, ctx(request, 'findOne', id));\n if (row === null || row === undefined) throw new NotFoundException(`${config.name} with id ${id} not found`);\n return decorateFindOne(row, request);\n },\n findAllByParent: adapterFindAllByParent,\n findOneChild: adapterFindOneChild,\n create: async (data, request) => {\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'create', undefined, request);\n const result = await resolvedAdapter.create!(adapterModelKey, prepared, ctx(request, 'create'));\n return postData(result, 'create', undefined, request);\n },\n update: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'update', coercedId, request);\n const result = await resolvedAdapter.update!(adapterModelKey, id, prepared, ctx(request, 'update', coercedId));\n return postData(result, 'update', coercedId, request);\n },\n patch: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'patch', coercedId, request);\n const patchOrUpdate = (resolvedAdapter.patch ?? resolvedAdapter.update)!.bind(resolvedAdapter);\n const result = await patchOrUpdate(adapterModelKey, id, prepared, ctx(request, 'patch', coercedId));\n return postData(result, 'patch', coercedId, request);\n },\n delete: async (id, request) => {\n const coercedId = toId(id);\n const result = await resolvedAdapter.delete!(adapterModelKey, id, ctx(request, 'delete', coercedId));\n return postData(result, 'delete', coercedId, request);\n },\n createChild: writer\n ? writer.createChild.bind(writer)\n : () => Promise.reject(new Error(`createChild not supported for \"${config.name}\" (no Prisma model)`)),\n updateChild: writer\n ? writer.updateChild.bind(writer)\n : () => Promise.reject(new Error(`updateChild not supported for \"${config.name}\" (no Prisma model)`)),\n deleteChild: writer\n ? writer.deleteChild.bind(writer)\n : () => Promise.reject(new Error(`deleteChild not supported for \"${config.name}\" (no Prisma model)`)),\n };\n }\n\n // If non-prisma adapter has no CRUD surface, fall back to createCustomRepository\n // (requires adapter.client that implements ops, or a repository.ts was already handled above).\n if (resolvedAdapter && resolvedAdapter.kind !== 'prisma') {\n return createCustomRepository<T>(\n resolvedAdapter.client as any,\n config,\n fallbackDataSources,\n undefined,\n configRegistry,\n );\n }\n\n // ── Legacy Prisma path ────────────────────────────────────────────────────\n // Used when no registry is provided (unit tests, direct factory calls).\n // The resolved adapter path above covers all production scenarios.\n\n if (!config.model) {\n throw new Error(\n `Resource \"${config.name}\" has no \"model\". A prisma-backed resource must ` +\n 'name its Prisma model, or point to a datasource with adapter: \"custom\".',\n );\n }\n const legacyModel = prisma[config.model];\n if (!legacyModel) {\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 // Wrap the raw prisma client in an adapter so hooks receive a `DataSourceAdapter`.\n const adapter: DataSourceAdapter = new PrismaDataSourceAdapter(prisma);\n\n const reader = new ReadRepository<T>(\n legacyModel,\n adapter,\n config,\n listSelect,\n oneSelect,\n configRegistry,\n );\n const writer = new WriteRepository<T>(legacyModel, adapter, config);\n\n // ── Resource-level decoration helpers ────────────────────────────────────\n const decorateFindAll = async (rows: any[], request?: any): Promise<any[]> => {\n const vlCols = await resolveValueLabelColumns(\n config.route,\n config.valueLabelColumns,\n configRegistry,\n );\n const target =\n vlCols === config.valueLabelColumns\n ? config\n : { hooks: config.hooks, valueLabelColumns: vlCols };\n const decorated = await decorateRows(rows, 'findAll', target, adapter, request);\n return applyAfterFindAll(decorated, config, adapter, request);\n };\n\n const decorateFindOne = (row: any, request?: any): Promise<any> =>\n decorateRow(row, 'findOne', config, adapter, request);\n\n const prepareData = (\n data: unknown,\n op: 'create' | 'update' | 'patch',\n id?: string | number,\n request?: any,\n ) => prepareWrite(data, op, config, adapter, id, request);\n\n const postData = (\n result: any,\n op: 'create' | 'update' | 'patch' | 'delete',\n id?: string | number,\n request?: any,\n ) => postWrite(result, op, config, adapter, id, request);\n\n const toId = (id: string | number): string | number =>\n (config.idType ?? 'string') === 'number' ? +id : String(id);\n\n return {\n prisma,\n findAll: async (params, request) => {\n const effectiveParams = await applyBeforeFindAll(params, config, adapter, request);\n return decorateFindAll(await reader.findAll(effectiveParams, request), request);\n },\n count: reader.count.bind(reader),\n findOne: async (id, request) =>\n decorateFindOne(await reader.findOne(id, request), request),\n findAllByParent: reader.findAllByParent.bind(reader),\n findOneChild: reader.findOneChild.bind(reader),\n create: async (data, request) => {\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'create', undefined, request);\n const result = await writer.create(prepared, request);\n return postData(result, 'create', undefined, request);\n },\n update: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'update', coercedId, request);\n const result = await writer.update(id, prepared, request);\n return postData(result, 'update', coercedId, request);\n },\n patch: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'patch', coercedId, request);\n const result = await writer.patch(id, prepared, request);\n return postData(result, 'patch', coercedId, request);\n },\n delete: async (id, request) => {\n const coercedId = toId(id);\n const result = await writer.delete(id, request);\n return postData(result, 'delete', coercedId, request);\n },\n createChild: writer.createChild.bind(writer),\n updateChild: writer.updateChild.bind(writer),\n deleteChild: writer.deleteChild.bind(writer),\n };\n}\n","import { z } from 'zod';\n\nimport type { JsonActionCondition } from '@ghentcdh/crouton-core';\n\n// ── Shared metadata ────────────────────────────────────────────────────────\n\nexport const ActionMetadataSchema = z.object({\n /** URL segment used in the endpoint. */\n id: z.string(),\n /** Human-readable label shown as a button. */\n label: z.string().optional(),\n /** MDI icon name, e.g. `\"mdi:open-in-new\"`. */\n icon: z.string().optional(),\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip: z.string().optional(),\n /** Per-row condition — button is hidden when false. */\n condition: z.custom<JsonActionCondition>().optional(),\n});\n\n// ── Link actions (same for row and table) ──────────────────────────────────\n\nexport const ResourceLinkActionSchema = ActionMetadataSchema.extend({\n type: z.literal('link'),\n /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */\n href: z.string(),\n});\n\n// ── Procedure actions — row-level ──────────────────────────────────────────\n\nexport const ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n /** HTTP method for the endpoint. Defaults to `\"post\"`. */\n method: z.string().optional(),\n /** Static data payload merged into the request body by the frontend. */\n data: z.record(z.string(), z.unknown()).optional(),\n /** Procedure called with `(prisma, recordId)`. */\n procedure: z.custom<(prisma: any, recordId: string | number) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\n// ── Procedure actions — table-level ────────────────────────────────────────\n\nexport const ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n /** HTTP method for the endpoint. Defaults to `\"post\"`. */\n method: z.string().optional(),\n /** Static data payload merged into the request body by the frontend. */\n data: z.record(z.string(), z.unknown()).optional(),\n /** Procedure called with `(prisma)` — no record id. */\n procedure: z.custom<(prisma: any) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\n// ── Union types ────────────────────────────────────────────────────────────\n\nexport type ResourceLinkAction = z.infer<typeof ResourceLinkActionSchema>;\nexport type ResourceRowProcedureAction = z.infer<\n typeof ResourceRowProcedureActionSchema\n>;\nexport type ResourceTableProcedureAction = z.infer<\n typeof ResourceTableProcedureActionSchema\n>;\n\nexport const ResourceRowActionSchema = z.union([\n ResourceRowProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceRowAction = z.infer<typeof ResourceRowActionSchema>;\n\nexport const ResourceTableActionSchema = z.union([\n ResourceTableProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceTableAction = z.infer<typeof ResourceTableActionSchema>;\n// ── Type guards ────────────────────────────────────────────────────────────\n\nexport const isRowProcedureAction = (\n action: ResourceRowAction,\n): action is ResourceRowProcedureAction => action.type !== 'link';\n\nexport const isTableProcedureAction = (\n action: ResourceTableAction,\n): action is ResourceTableProcedureAction => action.type !== 'link';\n","import { IS_DEV } from '../dev-mode';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n// createRequire works in both CJS and ESM contexts, unlike bare `require`.\n// In CJS contexts (nodemon + @swc-node/register), import.meta.url is undefined,\n// so fall back to __filename which is always available in CJS.\nconst _require = createRequire(import.meta.url ?? __filename);\n\n// True when running under an ESM loader that handles .ts files (e.g. tsx/esm via\n// `node --import tsx/esm`). In this context require() does NOT handle .ts files —\n// only import() does. In a plain CJS context (import.meta.url undefined),\n// require() is patched by @swc-node/register and is the correct choice.\nconst IS_ESM = typeof import.meta !== 'undefined' && typeof import.meta.url === 'string';\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/**\n * Dynamically import a default export, returning `undefined` on failure.\n *\n * Failures are reported through `onError` when supplied, and logged otherwise.\n * Without that, a broken user file (syntax error, bad import) is\n * indistinguishable from a missing one — which made `hooks.ts` fail silently.\n */\nexport const importDefault = async <T>(\n filePath: string,\n onError?: (error: unknown, filePath: string) => void,\n): 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 if (IS_ESM) {\n // ESM mode (node --import tsx/esm): require() does not handle .ts files.\n // Use import() with a file:// URL so the tsx ESM loader intercepts it.\n // nodemon restarts the whole process on file changes, no cache-busting needed.\n const mod = await import(pathToFileURL(filePath).href);\n return (mod.default ?? mod) as T;\n } else {\n // CJS mode (nodemon + @swc-node/register): require() is patched to handle .ts.\n const mod = _require(filePath) as { default?: T };\n return mod.default;\n }\n } catch (error) {\n if (onError) onError(error, filePath);\n else console.error(`[crouton] Failed to import ${filePath}:`, error);\n return undefined;\n }\n};\n","import type { JsonAction } from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from './action.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport { join } from 'node:path';\n\n/**\n * Resolve each declared action into a runtime action object.\n *\n * - `type: \"link\"` actions pass through as-is (no file to load).\n * - Procedure actions import their function from `{basePath}/actions/{procedure}.ts`.\n *\n * The `scope` parameter controls the procedure signature:\n * - `\"row\"` → `(prisma, recordId) => Promise`\n * - `\"table\"` → `(prisma) => Promise`\n *\n * All metadata fields (icon, tooltip, condition) are passed through for both scopes.\n */\nexport const loadActions = async <S extends 'row' | 'table'>(\n jsonActions: JsonAction[],\n basePath: string,\n scope: S,\n): Promise<S extends 'row' ? ResourceRowAction[] : ResourceTableAction[]> => {\n const tag = scope === 'row' ? 'actions' : 'tableActions';\n const results: (ResourceRowAction | ResourceTableAction)[] = [];\n\n for (const action of jsonActions) {\n if (action.type === 'link') {\n results.push(action);\n continue;\n }\n\n const file = findModule(join(basePath, 'actions'), action.procedure);\n if (!file) {\n console.warn(\n `[${tag}] Procedure file not found for \"${action.id}\" in ${basePath}/actions/`,\n );\n continue;\n }\n const mod = await importDefault<(...args: any[]) => Promise<any>>(file);\n if (!mod) {\n console.warn(`[${tag}] No default export in ${file}`);\n continue;\n }\n\n results.push({ ...action, procedure: mod } as\n ResourceRowAction | ResourceTableAction);\n }\n\n return results as any;\n};\n","import { type JsonResourceOperations, type SecurityConfig } from '@ghentcdh/crouton-core';\n\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { type ResourceDefinition } from './resource/defintion.schema';\nimport { type SchemaInput } from './resource/json.schema';\n\nexport { isRowProcedureAction, isTableProcedureAction } from './action';\n\nexport type CrudOperation =\n 'findAll' | 'findOne' | 'create' | 'update' | 'patch' | 'delete';\n\n// ─── helpers ────────────────────────────────────────────────────────────────\n\nexport const resolveDefinition = (config: Resource): ResourceDefinition => {\n const def = config.definition;\n return typeof def === 'function' ? def() : def;\n};\n\nexport const isOperationEnabled = (\n def: ResourceDefinition | JsonResourceOperations,\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 isOperationExternal = (\n def: ResourceDefinition | JsonResourceOperations,\n op: CrudOperation,\n): boolean => {\n const entry = def[op];\n return typeof entry === 'object' && entry !== null && 'uri' in entry;\n};\n\nexport const externalRouteFor = (\n def: ResourceDefinition | JsonResourceOperations,\n op: CrudOperation,\n): string | undefined => {\n const entry = def[op];\n if (typeof entry === 'object' && entry !== null && 'uri' in entry) {\n return (entry as { uri: string }).uri;\n }\n return undefined;\n};\n\n// ─── security ────────────────────────────────────────────────────────────────\n\n/** Extract security from an operation entry (works for both JSON and typed defs). */\nconst opSecurity = (entry: unknown): SecurityConfig | undefined => {\n if (!entry || entry === true) return undefined;\n return (entry as { security?: SecurityConfig }).security;\n};\n\n/** Effective security for one operation: op-level → resource global → module default. */\nexport const securityFor = (\n config: Resource,\n def: ResourceDefinition,\n op: CrudOperation,\n moduleDefault?: SecurityConfig,\n): SecurityConfig | undefined =>\n opSecurity(def[op]) ?? config.security ?? moduleDefault;\n\n/** Same precedence for sub-resources: op-level → parent global → module default. */\nexport const securityForSub = (\n config: Resource,\n sub: SubResourceConfig,\n op: CrudOperation,\n moduleDefault?: SecurityConfig,\n): SecurityConfig | undefined => {\n const entry = sub.operations[op];\n return opSecurity(entry) ?? config.security ?? moduleDefault;\n};\n","import { z } from 'zod';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { Resource } from '../resource/ResourceConfig.schema';\n\n/**\n * Contract for a `kind: \"custom\"` resource's `repository.ts`.\n *\n * The file default-exports an object implementing whichever operations the\n * resource enables. Discovery is by convention, like `hooks.ts` — see\n * `custom-repository.loader`.\n *\n * Hand-written interfaces, deliberately not `z.infer` of a Zod object:\n * `ResourceHooks` takes that shortcut and its `PRISMACLIENT` generic is erased\n * by the inference, so `ctx.prisma` is always `any` in a hook file. Here the\n * generics survive, and `CustomRepository<Row, PrismaClient>` gives a typed\n * `ctx.prisma`.\n */\n\n/** Operations a custom repository can implement. */\nexport type CustomOp =\n | 'findAll'\n | 'findOne'\n | 'create'\n | 'update'\n | 'patch'\n | 'delete';\n\nexport interface CustomRepositoryContext<PRISMA = any> {\n /**\n * Resolved datasource client for this resource — the one named by the\n * resource's `database`, or the project default.\n *\n * `undefined` when the project has no datasources at all, which is a valid\n * setup for a backend whose resources are all custom.\n */\n prisma: PRISMA;\n /** Escape hatch for a resource that reads from more than one database. */\n dataSources: {\n resolve(name?: string): any;\n entries(): { name: string; client: any }[];\n };\n /** The fully resolved resource config, including columns and views. */\n config: Resource;\n /** Which operation is executing. */\n op: CustomOp;\n /**\n * Zero-based row offset derived from `page`/`pageSize`, for backends that\n * paginate by offset rather than page number.\n */\n offset: number;\n /** Record id, on the operations that address one. */\n id?: string | number;\n /**\n * The incoming HTTP request, when the controller layer supplies one.\n * Same value hooks receive as `ctx.request` — use it for auth/tenant context.\n */\n request?: any;\n /**\n * Set when the resource declares a `parent`, i.e. it is mounted at\n * `<route>/:<param>/…`. The id is read from the path on every request, so it\n * is always present for a nested resource.\n *\n * The parent-aware operations receive the same id as their first argument;\n * this is here for the cases where you want it inside a shared helper.\n */\n parent?: { route: string; param: string; id: string | number };\n}\n\n/** Rows plus the total matching count, used to build the list envelope. */\nexport interface CustomListResult<T = any> {\n data: T[];\n count: number;\n}\n\n/**\n * Operations for a resource that declares a `parent`.\n *\n * A nested resource is *only* reachable under its parent, so these replace the\n * unnested operations rather than supplementing them — the parent id is always\n * available, and a query can never accidentally run across every parent.\n */\nexport interface CustomParentRepository<T = any, PRISMA = any> {\n /** List the children of one parent. Returns rows *and* the total count. */\n findAllByParent?(\n parentId: string | number,\n params: ListRequest,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<CustomListResult<T>>;\n /** Fetch one child of one parent. Return `null`/`undefined` for a 404. */\n findOneByParent?(\n parentId: string | number,\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T | null | undefined>;\n createByParent?(\n parentId: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n updateByParent?(\n parentId: string | number,\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n /** Falls back to `updateByParent` when not implemented. */\n patchByParent?(\n parentId: string | number,\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n deleteByParent?(\n parentId: string | number,\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n}\n\nexport interface CustomRepository<T = any, PRISMA = any>\n extends CustomParentRepository<T, PRISMA> {\n /**\n * List rows. Must return the total `count` as well — the framework builds the\n * `{ data, request: { count, totalPages, ... } }` envelope from it.\n *\n * `params.filter` holds raw `field:value:operator` strings; `parseFilterString`\n * is exported from crouton-api if you want to reuse the grammar.\n */\n findAll?(\n params: ListRequest,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<CustomListResult<T>>;\n /** Fetch one row. Return `null`/`undefined` to produce a 404. */\n findOne?(\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T | null | undefined>;\n create?(data: any, ctx: CustomRepositoryContext<PRISMA>): Promise<T>;\n update?(\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n /**\n * Partial update. Falls back to `update` when not implemented, matching the\n * Prisma repository where `patch` is `update` with a partial schema.\n */\n patch?(\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n delete?(\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n}\n\n/** Every operation a custom repository may implement, in registration order. */\nexport const CUSTOM_OPS: readonly CustomOp[] = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n] as const;\n\n/** Parent-aware method name for an operation, used by a nested resource. */\nexport const PARENT_METHOD: Record<CustomOp, keyof CustomParentRepository> = {\n findAll: 'findAllByParent',\n findOne: 'findOneByParent',\n create: 'createByParent',\n update: 'updateByParent',\n patch: 'patchByParent',\n delete: 'deleteByParent',\n} as const;\n\n/**\n * Loose schema for embedding the loaded repository on `ResourceSchema`.\n *\n * `z.custom` holds the functions without Zod trying to describe them, the same\n * trick `ResourceHooksSchema` uses. The *public* type above is what consumers\n * annotate their file with.\n */\nexport const CustomRepositorySchema = z.custom<CustomRepository>(\n (value) => typeof value === 'object' && value !== null,\n);\n","export interface ResourceLoadError {\n name: string;\n path: string;\n error: string;\n /** Version found on disk (for schema-version / migration failures). */\n version?: number;\n /** Version crouton expected (`CURRENT_RESOURCE_VERSION`). */\n expectedVersion?: number;\n}\n\nclass ResourceLoadErrorsRegistry {\n private errors: ResourceLoadError[] = [];\n\n record(e: ResourceLoadError) {\n this.errors.push(e);\n }\n\n getAll() {\n return [...this.errors];\n }\n\n clear() {\n this.errors = [];\n }\n}\n\nexport const resourceLoadErrorsRegistry = new ResourceLoadErrorsRegistry();","import type { CustomRepository } from './custom-repository.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\n\nexport const REPOSITORY_MODULE = 'repository';\n\n/**\n * Load a custom resource's `repository.ts`.\n *\n * Discovery mirrors `loadResourceHooks`: fixed filename, `.ts` then `.js`, no\n * declaration in resource.json. Unlike the hooks loader this distinguishes\n * \"absent\" from \"broken\" — an import failure is recorded on the load-error\n * registry (and so shown on the status page) rather than silently yielding\n * `undefined`, which would read as a missing file.\n */\nexport const loadCustomRepository = async (\n basePath: string,\n resourceName: string,\n): Promise<CustomRepository | undefined> => {\n const file = findModule(basePath, REPOSITORY_MODULE);\n if (!file) return undefined;\n\n let failure: unknown;\n const repository = await importDefault<CustomRepository>(file, (error) => {\n failure = error;\n });\n\n if (failure !== undefined) {\n resourceLoadErrorsRegistry.record({\n name: resourceName,\n path: file,\n error: `Failed to import ${REPOSITORY_MODULE}: ${\n failure instanceof Error ? failure.message : String(failure)\n }`,\n });\n return undefined;\n }\n\n if (repository && typeof repository !== 'object') {\n resourceLoadErrorsRegistry.record({\n name: resourceName,\n path: file,\n error: `${REPOSITORY_MODULE} must default-export an object of operation functions.`,\n });\n return undefined;\n }\n\n return repository;\n};\n\n/**\n * Attach each custom sub-resource's `repository.ts` to its `SubResourceConfig`.\n *\n * A sub-resource is declared by a relation column on the parent and served by\n * the parent's controller, but a `kind: \"custom\"` child owns its own data\n * access — so the parent's repository delegates to this. Mirrors\n * `loadSubResourceHooks`, which attaches child hooks the same way.\n *\n * Mutates in place, because `buildSubResources` has already produced the\n * configs by the time the loader can resolve the child directories.\n */\nexport const loadSubResourceRepositories = async (\n subResources: { childKind?: string; childDir?: string; childRoute: string; repository?: unknown }[],\n parentName: string,\n): Promise<void> => {\n for (const sub of subResources) {\n if (sub.childKind !== 'custom') continue;\n if (!sub.childDir) {\n resourceLoadErrorsRegistry.record({\n name: parentName,\n path: sub.childRoute,\n error:\n `Sub-resource \"${sub.childRoute}\" is a custom resource but its directory could not be resolved, ` +\n 'so its repository.ts cannot be loaded. Check the relation column\\'s \"resource\" path.',\n });\n continue;\n }\n const repository = await loadCustomRepository(\n sub.childDir,\n `${parentName}.${sub.childRoute}`,\n );\n if (repository) sub.repository = repository;\n }\n};\n","import {\n BadRequestException,\n NotFoundException,\n NotImplementedException,\n} from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport {\n type CustomListResult,\n type CustomOp,\n type CustomRepository,\n type CustomRepositoryContext,\n PARENT_METHOD,\n} from './custom-repository.types';\nimport { DEFAULT_ID_FIELD, DEFAULT_ID_TYPE } from '../constants';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\nimport { PrismaDataSourceAdapter } from '../data-source/prisma.adapter';\nimport { decorateRow, decorateRows, postWrite, prepareWrite } from '../hooks';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { resolveValueLabelColumns } from '../translation';\n\n/** Minimal view of `DataSourceRegistry`, kept structural to avoid a cycle. */\nexport type DataSourceResolver = {\n resolve(name?: string): any;\n entries(): { name: string; client: unknown }[];\n /** Resolve the full adapter for a datasource (optional — not all callers supply it). */\n resolveAdapter?(name?: string): DataSourceAdapter;\n};\n\nconst unsupported = (config: Resource, op: CustomOp): never => {\n const method = config.parent ? PARENT_METHOD[op] : op;\n throw new NotImplementedException(\n `Resource \"${config.name}\" enables \"${op}\" but its repository.ts does not implement \"${method}\".`,\n );\n};\n\n/**\n * Adapt a user-supplied `CustomRepository` to the full `CrudRepository`\n * interface the controllers depend on.\n *\n * Responsibilities that stay with the framework rather than the user:\n * - id coercion per `idType`, so a numeric key arrives as a number;\n * - lifecycle hooks and the `{value,label}` envelope, via the shared helpers —\n * so `hooks.ts` behaves the same on a custom resource;\n * - 404 on a missing row, so the user returns `null` instead of throwing;\n * - `patch` falling back to `update`, matching the Prisma repository.\n *\n * Sub-resource operations are not part of the contract yet: nested child routes\n * are derived from Prisma relations. They throw rather than silently returning\n * nothing.\n */\nexport const createCustomRepository = <T = any>(\n prisma: any,\n config: Resource,\n dataSources: DataSourceResolver,\n repository: CustomRepository<T> | undefined,\n configRegistry?: ResourceConfigRegistry,\n): CrudRepository<T> => {\n // Wrap the raw prisma client in an adapter so hook contexts receive `dataSource`.\n const adapter = new PrismaDataSourceAdapter(prisma);\n\n // Fall back to the adapter client when it implements CustomRepository directly\n // (no repository.ts required).\n const repo = repository ?? (prisma && typeof prisma === 'object' ? (prisma as CustomRepository) : {});\n const idField = config.idField ?? DEFAULT_ID_FIELD;\n\n const toId = (id: string | number): string | number =>\n (config.idType ?? DEFAULT_ID_TYPE) === 'number' ? +id : String(id);\n\n const parentRef = config.parent;\n\n /**\n * Parent id for a nested resource, read from the request path.\n *\n * A nested resource registers no unnested route, so the param is always\n * present in practice. Missing means the repository was called outside the\n * controller — fail loudly rather than silently querying across all parents.\n */\n const parentIdFrom = (request: any): string | number => {\n const raw = request?.params?.[parentRef!.param];\n if (raw === undefined || raw === null || raw === '') {\n throw new BadRequestException(\n `Resource \"${config.name}\" is nested under \"${parentRef!.route}\" but no \"${parentRef!.param}\" was supplied.`,\n );\n }\n return (parentRef!.idType ?? 'string') === 'number' ? +raw : String(raw);\n };\n\n const parentCtx = (\n request: any,\n parentId: string | number,\n ): { parent: NonNullable<CustomRepositoryContext['parent']> } => ({\n parent: { route: parentRef!.route, param: parentRef!.param, id: parentId },\n });\n\n /**\n * The parent for a hook context — same shape hooks get on a sub-resource, so a\n * `hooks.ts` reads `ctx.parent.id` regardless of which way the resource nests.\n * `undefined` when the resource is not nested, or when the request carries no\n * parent id to read (a hook must not be handed a fabricated one).\n */\n const parentHookCtx = (request: any) => {\n if (!parentRef) return undefined;\n const raw = request?.params?.[parentRef.param];\n if (raw === undefined || raw === null || raw === '') return undefined;\n return {\n route: parentRef.route,\n param: parentRef.param,\n id: (parentRef.idType ?? 'string') === 'number' ? +raw : String(raw),\n };\n };\n\n const ctx = (\n op: CustomOp,\n params?: ListRequest,\n id?: string | number,\n request?: any,\n ): CustomRepositoryContext => ({\n prisma,\n dataSources,\n config,\n op,\n offset: params ? offsetOf(params) : 0,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n });\n\n const findAllWithCount = async (\n params: ListRequest,\n request?: any,\n ): Promise<CustomListResult<T>> => {\n let result: CustomListResult<T> | undefined;\n\n if (parentRef) {\n if (!repo.findAllByParent) unsupported(config, 'findAll');\n const parentId = parentIdFrom(request);\n result = await repo.findAllByParent!(parentId, params, {\n ...ctx('findAll', params, undefined, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.findAll) unsupported(config, 'findAll');\n result = await repo.findAll!(\n params,\n ctx('findAll', params, undefined, request),\n );\n }\n\n const vlCols = await resolveValueLabelColumns(\n config.route,\n config.valueLabelColumns,\n configRegistry,\n );\n const target =\n vlCols === config.valueLabelColumns\n ? config\n : { hooks: config.hooks, valueLabelColumns: vlCols };\n const data = await decorateRows(\n result?.data ?? [],\n 'findAll',\n target,\n adapter,\n request,\n parentHookCtx(request),\n );\n return { data, count: result?.count ?? data.length };\n };\n\n const findOne = async (id: string | number, request?: any): Promise<T> => {\n let row: T | null | undefined;\n\n if (parentRef) {\n if (!repo.findOneByParent) unsupported(config, 'findOne');\n const parentId = parentIdFrom(request);\n row = await repo.findOneByParent!(parentId, toId(id), {\n ...ctx('findOne', undefined, id, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.findOne) unsupported(config, 'findOne');\n row = await repo.findOne!(\n toId(id),\n ctx('findOne', undefined, id, request),\n );\n }\n\n if (row === null || row === undefined) {\n throw new NotFoundException(`${config.name} with id ${id} not found`);\n }\n return decorateRow(\n row,\n 'findOne',\n config,\n adapter,\n request,\n parentHookCtx(request),\n );\n };\n\n const write = async (\n op: 'create' | 'update' | 'patch',\n data: unknown,\n id?: string | number,\n request?: any,\n ): Promise<T> => {\n const coercedId = id !== undefined ? toId(id) : undefined;\n\n // `patch` falls back to `update` in both flavours: the Prisma repository\n // treats patch as an update with a partial schema, so a repository that\n // only implements the update variant behaves consistently.\n const prepared = () =>\n prepareWrite(\n data,\n op,\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n\n let result: T;\n\n if (parentRef) {\n const fn =\n op === 'create'\n ? repo.createByParent\n : op === 'update'\n ? repo.updateByParent\n : (repo.patchByParent ?? repo.updateByParent);\n if (!fn) unsupported(config, op);\n\n const parentId = parentIdFrom(request);\n const nestedCtx = {\n ...ctx(op, undefined, coercedId, request),\n ...parentCtx(request, parentId),\n };\n const body = await prepared();\n\n result =\n op === 'create'\n ? await (fn as NonNullable<CustomRepository<T>['createByParent']>)(\n parentId,\n body,\n nestedCtx,\n )\n : await (fn as NonNullable<CustomRepository<T>['updateByParent']>)(\n parentId,\n coercedId!,\n body,\n nestedCtx,\n );\n } else {\n const fn = (\n op === 'create'\n ? repo.create\n : op === 'update'\n ? repo.update\n : (repo.patch ?? repo.update)\n )?.bind(repo);\n if (!fn) unsupported(config, op);\n\n const body = await prepared();\n\n result =\n op === 'create'\n ? await (fn as NonNullable<CustomRepository<T>['create']>)(\n body,\n ctx('create', undefined, undefined, request),\n )\n : await (fn as NonNullable<CustomRepository<T>['update']>)(\n coercedId!,\n body,\n ctx(op, undefined, coercedId, request),\n );\n }\n\n return postWrite(\n result,\n op,\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n };\n\n // Async so callers get a rejected promise rather than a synchronous throw,\n // matching every other method's `Promise<T>` signature.\n const notAChildRepository = async (): Promise<never> => {\n throw new NotImplementedException(\n `Resource \"${config.name}\" is a custom resource; nested sub-resource routes are not supported. ` +\n 'Expose the child collection as its own resource instead.',\n );\n };\n\n return {\n prisma,\n // Preferred by register-findall: one round trip returns rows and count.\n findAllWithCount,\n findAll: async (params, request) =>\n (await findAllWithCount(params, request)).data,\n count: async (filter) =>\n (\n await findAllWithCount({\n page: 1,\n pageSize: 1,\n sort: idField,\n sortDir: 'asc',\n filter: filter ?? [],\n })\n ).count,\n findOne,\n create: (data, request) => write('create', data, undefined, request),\n update: (id, data, request) => write('update', data, id, request),\n patch: (id, data, request) => write('patch', data, id, request),\n delete: async (id, request) => {\n const coercedId = toId(id);\n let result: T;\n\n if (parentRef) {\n if (!repo.deleteByParent) unsupported(config, 'delete');\n const parentId = parentIdFrom(request);\n result = await repo.deleteByParent!(parentId, coercedId, {\n ...ctx('delete', undefined, coercedId, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.delete) unsupported(config, 'delete');\n result = await repo.delete!(\n coercedId,\n ctx('delete', undefined, coercedId, request),\n );\n }\n return postWrite(\n result,\n 'delete',\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n },\n findAllByParent: notAChildRepository,\n findOneChild: notAChildRepository,\n createChild: notAChildRepository,\n updateChild: notAChildRepository,\n deleteChild: notAChildRepository,\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","import { NotFoundException } from '@nestjs/common';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { AdapterCrudContext, DataSourceAdapter } from './data-source.adapter';\nimport { ReadRepository } from '../read.repository';\nimport { WriteRepository } from '../write.repository';\n\nconst DB_CHECK_TIMEOUT_MS = 3_000;\n\n/**\n * Default adapter: wraps a generated PrismaClient.\n *\n * Phase 1: lifecycle wrapper.\n * Phase 2: full CRUD surface — each method delegates to ReadRepository /\n * WriteRepository so subclasses can override individual operations without\n * re-implementing the rest.\n *\n * Extend this class to build a composable adapter:\n *\n * ```ts\n * export default class AnnotationAdapter extends PrismaDataSourceAdapter {\n * constructor() { super(prisma); }\n *\n * override async findAll(model, params, ctx) {\n * const result = await super.findAll(model, params, ctx);\n * return { ...result, data: decorateWithAnnotations(result.data) };\n * }\n * }\n * ```\n */\nexport class PrismaDataSourceAdapter implements DataSourceAdapter {\n readonly kind = 'prisma' as const;\n readonly client: unknown;\n\n constructor(prismaClient: unknown) {\n this.client = prismaClient;\n }\n\n supports(model: string): boolean {\n return typeof (this.client as any)?.[model] !== 'undefined';\n }\n\n async healthCheck(): Promise<void> {\n const c = this.client as any;\n await Promise.race([\n c.$queryRaw`SELECT 1`,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Database health check timed out')), DB_CHECK_TIMEOUT_MS),\n ),\n ]);\n }\n\n async disconnect(): Promise<void> {\n const c = this.client as any;\n if (typeof c?.$disconnect === 'function') {\n await c.$disconnect();\n }\n }\n\n // ── CRUD surface (Phase 2) ────────────────────────────────────────────────\n // Each method resolves the Prisma delegate, constructs the appropriate\n // repository, and delegates. Subclasses may override any of these.\n\n private prismaModel(model: string): any {\n const delegate = (this.client as any)?.[model];\n if (!delegate)\n throw new Error(`Model \"${model}\" not found on the provided PrismaClient.`);\n return delegate;\n }\n\n async findAll(model: string, params: ListRequest, ctx: AdapterCrudContext): Promise<{ data: any[]; count: number }> {\n const prismaModel = this.prismaModel(model);\n const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n const [data, count] = await Promise.all([\n reader.findAll(params, ctx.request),\n reader.count(params.filter ?? [], (params as any).q),\n ]);\n return { data, count };\n }\n\n async count(model: string, filter: string[], ctx: AdapterCrudContext): Promise<number> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, undefined, undefined, ctx.configRegistry);\n return reader.count(filter, ctx.q);\n }\n\n async findOne(model: string, id: string | number, ctx: AdapterCrudContext): Promise<any | null> {\n const prismaModel = this.prismaModel(model);\n const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n try {\n return await reader.findOne(id, ctx.request);\n } catch (e: any) {\n if (e instanceof NotFoundException) return null;\n throw e;\n }\n }\n\n async create(model: string, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).create(data, ctx.request);\n }\n\n async update(model: string, id: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).update(id, data, ctx.request);\n }\n\n async patch(model: string, id: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).patch(id, data, ctx.request);\n }\n\n async delete(model: string, id: string | number, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).delete(id, ctx.request);\n }\n\n async findAllByParent(model: string, parentId: string | number, sub: any, params: ListRequest, ctx: AdapterCrudContext): Promise<{ data: any[]; count: number }> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n return reader.findAllByParent(parentId, sub.childRoute, params, ctx.request);\n }\n\n async findOneChild(model: string, sub: any, childId: string | number, parentId: string | number | undefined, ctx: AdapterCrudContext): Promise<any | null> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n try {\n return await reader.findOneChild(sub, childId, parentId, ctx.request);\n } catch (e: any) {\n if (e instanceof NotFoundException) return null;\n throw e;\n }\n }\n\n async createChild(model: string, parentId: string | number, sub: any, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).createChild(parentId, sub, data, ctx.request);\n }\n\n async updateChild(model: string, sub: any, childId: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).updateChild(sub, childId, data, ctx.request);\n }\n\n async deleteChild(model: string, sub: any, childId: string | number, parentId: string | number | undefined, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).deleteChild(sub, childId, parentId, ctx.request);\n }\n}\n","import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport {\n type ListRequest,\n Operator,\n type OperatorType,\n buildSort,\n offsetOf,\n} from '@ghentcdh/crouton-core';\n\nimport {\n childCtx,\n childRepositoryFn,\n} from './custom-repository/child-delegate';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { type SubResourceConfig } from './resource/SubResource.schema';\nimport type { ValueLabelColumn } from './resource/valueLabel';\nimport { applyValueLabelColumns } from './resource/valueLabel.apply';\nimport type { ResourceConfigRegistry } from './resource-config.registry';\nimport {\n buildChildSortClause,\n buildFindOneIncludes,\n buildIncludeClause,\n mergeCalculatedColumnsForRows,\n} from './sql.helpers';\nimport { resolveValueLabelColumns } from './translation';\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\n ? parts.slice(1, -1).join(':')\n : parts.slice(1).join(':');\n const operator: OperatorType = hasOperator\n ? (lastPart as OperatorType)\n : '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 = (\n path: string[],\n condition: unknown,\n): 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>) => ({\n [column]: { path, ...extra },\n });\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 = (\n value: string,\n operator: OperatorType,\n): 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(\n field.split('.'),\n operatorToCondition(value, operator),\n ),\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// Re-exported for backwards compatibility; the implementation now lives in\n// resource/valueLabel.apply so non-Prisma repositories can share it.\nexport { applyValueLabelColumns };\n\n/**\n * Handles all read operations for a resource — list, count, detail, and sub-resource queries.\n * Pure data access: hooks and valueLabel decoration are applied by the factory wrapper.\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 adapter - The datasource adapter; `adapter.client` is the raw PrismaClient.\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 private get prisma(): any {\n return this.adapter.client;\n }\n\n constructor(\n private readonly prismaModel: any,\n private readonly adapter: DataSourceAdapter,\n private readonly config: Resource,\n private readonly listSelect: Record<string, any> | undefined,\n private readonly oneSelect: Record<string, any> | undefined,\n private readonly configRegistry?: ResourceConfigRegistry,\n ) {}\n\n /**\n * Physical table name for raw SQL (calculated columns).\n *\n * `table` overrides `model` for a `@@map`-ed Prisma model. Empty for a custom\n * resource, which cannot have calculated columns.\n */\n private get tableName(): string {\n return this.config.table ?? this.config.model ?? '';\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 /**\n * The parent a *child* read is scoped to, for the hook context.\n *\n * A sub-resource is served by the parent's controller, so its parent id arrives\n * as the parent's own `:id` — hence `param: 'id'`. `undefined` when no parent id\n * was supplied, so a hook is never handed a fabricated one.\n */\n private parentHookContext(parentId: string | number | undefined) {\n if (parentId === undefined || parentId === null || parentId === '') {\n return undefined;\n }\n return {\n route: this.config.route,\n param: 'id',\n id: this.toId(parentId),\n };\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 * Resource-level `afterRead` and valueLabel decoration are NOT applied here — the\n * factory wrapper handles them so both Prisma and custom adapters use the same path.\n */\n async findAll(params: ListRequest, request?: any): Promise<T[]> {\n const subResources = this.config.subResources ?? [];\n const projection = this.projection('findAll');\n\n const vlCols = await resolveValueLabelColumns(\n this.config.route,\n this.config.valueLabelColumns,\n this.configRegistry,\n );\n const filterWhere = this.buildWhere(params.filter);\n const searchWhere = this.buildSearchOrWhere((params as any).q);\n const where = filterWhere && searchWhere\n ? { AND: [filterWhere, searchWhere] }\n : filterWhere ?? searchWhere;\n const query: Record<string, any> = {\n where,\n take: params.pageSize,\n skip: offsetOf(params),\n orderBy: this.safeSort(\n sanitizeValueLabelSort(params.sort, vlCols),\n params.sortDir,\n ),\n };\n\n // A `kind: \"custom\"` child is served by its own repository.ts and has no\n // Prisma relation of that name, so it must stay out of every Prisma-shaped\n // clause below — `_count`, `include`, and the configInclude filter alike.\n // Asking for a relation the model does not have fails the whole query.\n const prismaSubResources = subResources.filter(\n (s) => s.childKind !== 'custom',\n );\n\n const oneToManySubResources = prismaSubResources.filter(\n (s) => s.relationType !== 'manyToOne',\n );\n\n // The count fills a table cell, so a column the table never renders does not\n // need one. Skipping it keeps `_count` off the query entirely when every\n // relation is hidden.\n const countableSubResources = oneToManySubResources.filter(\n (s) => !s.hiddenInTable,\n );\n\n // Include manyToOne relations (e.g. author) so they appear in list view.\n const manyToOneIncludes = prismaSubResources\n .filter((s) => s.relationType === 'manyToOne')\n .map((s) => s.relation);\n const flatIncludes = manyToOneIncludes.length\n ? Object.fromEntries(manyToOneIncludes.map((r) => [r, true]))\n : undefined;\n const configInclude = buildIncludeClause(this.config.include);\n // Exclude every oneToMany sub-resource from configInclude in findAll: a\n // counted one would have its records overwritten by the count mapping below,\n // and an uncounted one is hidden from the table, so fetching whole child rows\n // per page would be cost for nothing. Deliberately not narrowed to the\n // counted set — that would silently turn a `_count` into a full child fetch\n // the moment a column is hidden.\n // Custom children join this set too: they cannot be Prisma-included at all,\n // so an entry naming one in `config.include` has to be dropped rather than\n // passed through to fail the query.\n const countableRelations = new Set([\n ...oneToManySubResources.map((s) => s.relation),\n ...subResources\n .filter((s) => s.childKind === 'custom')\n .map((s) => s.relation),\n ]);\n const filteredConfigInclude = configInclude\n ? Object.fromEntries(Object.entries(configInclude).filter(([key]) => !countableRelations.has(key)))\n : undefined;\n const safeConfigInclude = filteredConfigInclude && Object.keys(filteredConfigInclude).length ? filteredConfigInclude : undefined;\n const mergedInclude =\n flatIncludes || safeConfigInclude\n ? { ...flatIncludes, ...safeConfigInclude }\n : undefined;\n\n const countClause = countableSubResources.length\n ? { select: Object.fromEntries(countableSubResources.map((s) => [s.relation, true])) }\n : undefined;\n\n if (projection.select) {\n query.select = {\n ...projection.select,\n ...(countClause && { _count: countClause }),\n ...mergedInclude,\n };\n } else {\n if (countClause) query._count = countClause;\n if (mergedInclude) query.include = mergedInclude;\n }\n\n const rows = await this.prismaModel.findMany(query);\n\n const mapped = countableSubResources.length\n ? rows.map((row: any) => {\n const { _count, ...rest } = row;\n if (!_count) return rest;\n const counts = Object.fromEntries(\n countableSubResources.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.tableName,\n this.prisma,\n this.config.idField ?? 'id',\n );\n // Resource-level afterRead + valueLabel decoration is applied by the factory wrapper.\n return withCalc;\n }\n\n private buildSearchOrWhere(q: string | undefined): Record<string, unknown> | undefined {\n const lookup = this.config.lookup;\n const labels = lookup?.labels?.length ? lookup.labels : (lookup?.label ? [lookup.label] : undefined);\n if (!q || !labels?.length) return undefined;\n return {\n OR: labels.map((path) => buildNestedPath(path.split('.'), { contains: q })),\n };\n }\n\n /** Count records matching the given filter strings and optional free-text search. */\n count(filter: string[], q?: string): Promise<number> {\n const filterWhere = this.buildWhere(filter);\n const searchWhere = this.buildSearchOrWhere(q);\n const where = filterWhere && searchWhere\n ? { AND: [filterWhere, searchWhere] }\n : filterWhere ?? searchWhere;\n return this.prismaModel.count({ where });\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 * Resource-level `afterRead` decoration is applied by the factory wrapper.\n * @throws {NotFoundException} When no record exists for the given id.\n */\n async findOne(id: number | string, request?: any): Promise<T> {\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 const mergedInclude = buildFindOneIncludes(\n this.config.subResources ?? [],\n buildIncludeClause(this.config.include),\n );\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.tableName,\n this.prisma,\n this.config.idField ?? 'id',\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 sub.idField ?? 'id',\n );\n enriched = { ...enriched, [sub.relation]: enrichedNested };\n }\n\n // Resource-level afterRead decoration is applied by the factory wrapper.\n return enriched;\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: ListRequest,\n request?: any,\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 if (sub.childKind === 'custom') {\n const findAll = childRepositoryFn(sub, 'findAll', this.config.name);\n const result = await findAll(\n this.toId(parentId),\n params,\n childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op: 'findAll',\n parentId: this.toId(parentId),\n params,\n request,\n }),\n );\n const rows = result?.data ?? [];\n const decorated = sub.hooks?.afterRead\n ? await Promise.all(\n rows.map((row: any) =>\n sub.hooks!.afterRead!(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findAll',\n request,\n parent: this.parentHookContext(parentId),\n }),\n ),\n )\n : rows;\n const subVlCols = await resolveValueLabelColumns(\n this.config.route,\n sub.valueLabelColumns,\n this.configRegistry,\n sub.childRoute,\n );\n const labeled = subVlCols?.length\n ? decorated.map((r: any) =>\n applyValueLabelColumns(r, subVlCols),\n )\n : decorated;\n return { data: labeled, count: result?.count ?? labeled.length };\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 subVlCols = await resolveValueLabelColumns(\n this.config.route,\n sub.valueLabelColumns,\n this.configRegistry,\n sub.childRoute,\n );\n const childSort = orderableChildSort(\n sanitizeValueLabelSort(params.sort, subVlCols),\n childModel,\n sub,\n );\n\n const [data, count] = await Promise.all([\n childModel.findMany({\n where,\n take: params.pageSize,\n skip: offsetOf(params),\n orderBy: childSort\n ? buildChildSortClause(childSort, params.sortDir)\n : 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 sub.idField ?? 'id',\n )\n : data;\n\n const decorated = sub.hooks?.afterRead\n ? await Promise.all(\n withCalc.map((row: any) =>\n sub.hooks!.afterRead!(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findAll',\n request,\n parent: this.parentHookContext(parentId),\n }),\n ),\n )\n : withCalc;\n\n const labeled = subVlCols?.length\n ? decorated.map((r: any) =>\n applyValueLabelColumns(r, subVlCols),\n )\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 request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n if (parentId === undefined) {\n throw new BadRequestException(\n `Sub-resource \"${sub.childRoute}\" of \"${this.config.name}\" requires a parent id.`,\n );\n }\n const findOne = childRepositoryFn(sub, 'findOne', this.config.name);\n const row = await findOne(\n this.toId(parentId),\n (sub.idType ?? 'string') === 'number' ? +childId : String(childId),\n childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op: 'findOne',\n parentId: this.toId(parentId),\n id: childId,\n request,\n }),\n );\n if (row === null || row === undefined) {\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n }\n return sub.hooks?.afterRead\n ? sub.hooks.afterRead(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findOne',\n request,\n parent: this.parentHookContext(parentId),\n })\n : row;\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 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 sub.idField ?? 'id',\n )\n : [record];\n\n // findOne (single child) keeps the scalar — see decorateOne.\n if (sub.hooks?.afterRead)\n return sub.hooks.afterRead(withCalc, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findOne',\n request,\n parent: this.parentHookContext(parentId),\n });\n return withCalc;\n }\n}\n","import { NotImplementedException } from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport { type CustomOp, PARENT_METHOD } from './custom-repository.types';\nimport type { Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\n/**\n * Delegation to a **custom sub-resource's** own repository.\n *\n * A sub-resource is declared by a relation column on the parent and served\n * through the parent's controller, but a `kind: \"custom\"` child owns its data\n * access and has no Prisma model to query. The parent's repositories therefore\n * call the child's `repository.ts` instead of `prisma[childModel]`.\n *\n * The child implements the same parent-aware operations a top-level nested\n * resource does (`findAllByParent`, `createByParent`, …), so one contract covers\n * both ways of nesting.\n *\n * Shared by ReadRepository and WriteRepository so the two cannot drift.\n */\n\n/** Resolve the child's method for `op`, or throw naming what is missing. */\nexport const childRepositoryFn = (\n sub: SubResourceConfig,\n op: CustomOp,\n parentName: string,\n): ((...args: any[]) => Promise<any>) => {\n const repo = sub.repository as Record<string, any> | undefined;\n const method = PARENT_METHOD[op];\n\n if (!repo) {\n throw new NotImplementedException(\n `Sub-resource \"${sub.childRoute}\" of \"${parentName}\" is a custom resource but no repository.ts was loaded for it.`,\n );\n }\n\n // `patch` falls back to the update variant, matching every other path.\n const fn =\n repo[method] ??\n (op === 'patch' ? repo[PARENT_METHOD.update] : undefined);\n\n if (typeof fn !== 'function') {\n throw new NotImplementedException(\n `Sub-resource \"${sub.childRoute}\" of \"${parentName}\" does not implement \"${method}\" in its repository.ts.`,\n );\n }\n return fn.bind(repo);\n};\n\n/** Context handed to a custom child's repository. */\nexport const childCtx = ({\n parentConfig,\n prisma,\n op,\n parentId,\n params,\n id,\n request,\n}: {\n parentConfig: Resource;\n prisma: any;\n op: CustomOp;\n parentId: string | number;\n params?: ListRequest;\n id?: string | number;\n request?: any;\n}): any => ({\n prisma,\n dataSources: { resolve: () => prisma, entries: () => [] },\n config: parentConfig,\n op,\n offset: params ? offsetOf(params) : 0,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n // Served under the parent's `:id`, so that is the param name here — unlike a\n // top-level nested resource, which names its own param.\n parent: { route: parentConfig.route, param: 'id', id: parentId },\n});\n\n/**\n * Parent id for a child write.\n *\n * `updateChild`/`deleteChild` are called without it — the route binds it as\n * `:id`, so it is read back off the request the handler already receives.\n */\nexport const parentIdFromRequest = (\n request: any,\n fallback?: string | number,\n): string | number | undefined => {\n const raw = request?.params?.id;\n return raw === undefined || raw === null || raw === '' ? fallback : raw;\n};\n","import { fromValueLabel, toValueLabel } from '@ghentcdh/crouton-core';\n\nimport type { ValueLabelColumn } from './valueLabel';\n\n/**\n * Value-label envelope transforms, shared by every repository implementation.\n *\n * Lives here rather than inside `read.repository` / `write.repository` so the\n * custom-repository adapter can apply exactly the same treatment without\n * importing a repository (which would be a cycle).\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/** Unwrap `{ value, label }` fields back to their scalar before persistence. */\nexport const normalizeValueLabels = (\n data: unknown,\n cols: ValueLabelColumn[] | undefined,\n): unknown => {\n if (!data || typeof data !== 'object' || Array.isArray(data) || !cols?.length)\n 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","import { buildSort } from '@ghentcdh/crouton-core';\nimport type { CalculatedColumn, JsonIncludeEntry } from '@ghentcdh/crouton-core';\n\nimport type { SubResourceConfig } from './resource/SubResource.schema';\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 = (\n col: CalculatedColumn,\n tableName: string,\n ids: unknown[],\n idField: string,\n): string => {\n const alias = col.alias ?? col.id;\n const placeholders = ids.map((_, i) => `$${i + 1}`).join(', ');\n // The key column is aliased to `id` so the caller can merge on a stable name\n // regardless of what the resource's primary key is called.\n return `SELECT main.\"${idField}\" AS id, ${castExpression(col)} AS \"${alias}\" FROM \"${tableName}\" main WHERE main.\"${idField}\" 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 *\n * @param idField - Primary key column of `tableName`. Defaults to `'id'`.\n */\nexport const mergeCalculatedColumnsForRows = async (\n rows: any[],\n calcCols: CalculatedColumn[],\n tableName: string,\n prisma: any,\n idField = 'id',\n): Promise<any[]> => {\n if (!calcCols.length || !rows.length) return rows;\n\n const ids = rows.map((r) => r[idField]);\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, idField);\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[idField])] ?? 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\n/**\n * Build the merged Prisma `include` clause for `findOne`.\n *\n * Auto-included sub-resources (`includeInFindOne`) are merged with explicit\n * `configInclude` entries. `configInclude` wins when both specify the same relation.\n *\n * A `kind: \"custom\"` child is skipped: it is reached through its own\n * `repository.ts`, so there is no Prisma relation of that name to include and\n * asking for one fails the entire query.\n */\nexport const buildFindOneIncludes = (\n subResources: SubResourceConfig[],\n configInclude: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined => {\n const autoSubs = subResources.filter(\n (s) => s.includeInFindOne && s.childKind !== 'custom',\n );\n const flatIncludes = autoSubs.length\n ? Object.fromEntries(\n autoSubs.map((s) =>\n s.findOneOrderBy\n ? [s.relation, { orderBy: s.findOneOrderBy }]\n : [s.relation, true],\n ),\n )\n : undefined;\n\n if (!flatIncludes && !configInclude) return undefined;\n return { ...flatIncludes, ...configInclude };\n};\n","/**\n * NestJS interceptor: parse `Accept-Language`, resolve against supported\n * languages, store in AsyncLocalStorage, set `Vary` and `Content-Language`\n * response headers.\n */\n\nimport {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport type { Observable } from 'rxjs';\n\nimport { resolveLanguage } from '@ghentcdh/crouton-core';\n\nimport { runWithLanguage } from './language.context';\nimport { type TranslationRegistry } from './translation.registry';\n\n@Injectable()\nexport class LanguageInterceptor implements NestInterceptor {\n constructor(private readonly registry: TranslationRegistry) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n const http = context.switchToHttp();\n const request = http.getRequest();\n const response = http.getResponse();\n\n const acceptLanguage = request.headers['accept-language'] as\n | string\n | undefined;\n const resolved = resolveLanguage(\n acceptLanguage,\n this.registry.languages,\n this.registry.defaultLanguage,\n );\n\n response.setHeader('Vary', 'Accept-Language');\n response.setHeader('Content-Language', resolved);\n\n return runWithLanguage(resolved, () => next.handle());\n }\n}\n","import type { ValueLabelColumn } from '../resource/valueLabel';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { getRequestLanguage } from './language.context';\n\n/**\n * Resolve value-label columns for the current request language.\n *\n * When a language is active and the config registry holds a localized config,\n * the localized `valueLabelColumns` (with translated enum labels) are returned.\n * Otherwise the boot-time columns are returned unchanged.\n *\n * @param route - Resource route (used to look up the localized config).\n * @param bootTimeCols - The valueLabelColumns from the boot-time config.\n * @param configRegistry - Optional config registry for localized lookup.\n * @param childRoute - When set, resolve the sub-resource's valueLabelColumns instead.\n */\nexport const resolveValueLabelColumns = async (\n route: string,\n bootTimeCols: ValueLabelColumn[] | undefined,\n configRegistry?: ResourceConfigRegistry,\n childRoute?: string,\n): Promise<ValueLabelColumn[] | undefined> => {\n if (!configRegistry) return bootTimeCols;\n const language = getRequestLanguage();\n if (!language) return bootTimeCols;\n const localized = await configRegistry.getByRoute(route, language);\n if (!localized) return bootTimeCols;\n if (!childRoute) return localized.valueLabelColumns ?? bootTimeCols;\n const sub = (localized.subResources ?? []).find(\n (s) => s.childRoute === childRoute,\n );\n return sub?.valueLabelColumns ?? bootTimeCols;\n};\n","import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport type { JsonIncludeEntry } from '@ghentcdh/crouton-core';\n\nimport { DEFAULT_ID_FIELD, PRISMA_NOT_FOUND_CODE } from './constants';\nimport {\n childCtx,\n childRepositoryFn,\n parentIdFromRequest,\n} from './custom-repository/child-delegate';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { normalizeValueLabels } from './resource/valueLabel.apply';\n\n/** Extract the top-level relation names from a `JsonIncludeEntry[]` (for payload stripping). */\nconst includeRelationNames = (\n include: JsonIncludeEntry[] | undefined,\n): Set<string> =>\n new Set((include ?? []).map((e) => (typeof e === 'string' ? e : e.relation)));\n\n/** Prisma nested-write keywords that indicate a relation mutation rather than read-only join data. */\nconst PRISMA_RELATION_WRITE_KEYS = new Set([\n 'connect',\n 'connectOrCreate',\n 'create',\n 'createMany',\n 'set',\n 'disconnect',\n 'update',\n 'updateMany',\n 'upsert',\n 'delete',\n 'deleteMany',\n]);\n\n/** Returns `true` when `value` looks like a Prisma relation write (e.g. `{ connect: { id } }`). */\nconst isPrismaRelationWrite = (value: unknown): boolean => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n return Object.keys(value).some((k) => PRISMA_RELATION_WRITE_KEYS.has(k));\n};\n\n/** Remove sub-resource count columns from a write payload. Module-level so the factory can use it. */\nexport const stripSubResourceKeys = (config: Resource, data: unknown): unknown => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const subKeys = new Set((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\nconst stripNonCreateableChildFields = (\n sub: SubResourceConfig,\n data: unknown,\n): 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(\n ([k]) => !nonCreateable.has(k),\n ),\n );\n};\n\n/**\n * Handles all write operations for a resource — create, update, patch, delete, and child mutations.\n *\n * Resource-level `beforeWrite`/`afterWrite` hooks are NOT applied here for the core operations\n * (create, update, patch, delete) — they are applied by the factory wrapper so Prisma and custom\n * adapters share the same hook path. Sub-resource hooks are still applied inline.\n *\n * Prisma `P2025` (record not found) errors are mapped to `NotFoundException`.\n */\nexport class WriteRepository<T = any> {\n private get prisma(): any {\n return this.adapter.client;\n }\n\n constructor(\n private readonly prismaModel: any,\n private readonly adapter: DataSourceAdapter,\n private readonly config: Resource,\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 /**\n * The parent a *child* write is scoped to, for the hook context.\n *\n * A sub-resource is served by the parent's controller, so its parent id arrives\n * as the parent's own `:id` — hence `param: 'id'`. A resource that declares\n * `parent` names its own param and goes through the custom adapter instead.\n */\n private parentHookContext(parentId: string | number) {\n return {\n route: this.config.route,\n param: 'id',\n id: this.toId(parentId),\n };\n }\n\n /**\n * Create a record. The data has already been stripped of sub-resource keys,\n * normalized, and run through `beforeWrite` by the factory wrapper.\n */\n async create(data: unknown, _request?: any): Promise<T> {\n return this.prismaModel.create({ data });\n }\n\n /**\n * Update a record. The data has already been stripped, normalized, and hooked\n * by the factory wrapper.\n */\n async update(id: number | string, data: unknown, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.update({\n where: { [idField]: this.toId(id) },\n data,\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n /**\n * Partial-update a record. Same contract as `update`.\n */\n async patch(id: number | string, data: unknown, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.update({\n where: { [idField]: this.toId(id) },\n data,\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n async delete(id: number | string, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.delete({\n where: { [idField]: this.toId(id) },\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n /**\n * Write to a **custom** sub-resource by delegating to the child's own\n * repository.\n *\n * The child has no Prisma model, so `prisma[childModel]` is not an option.\n * Value-label normalisation and the child's `beforeWrite`/`afterWrite` hooks\n * still apply, so a custom child behaves like a Prisma one from the caller's\n * point of view.\n */\n private async delegateChildWrite(\n sub: SubResourceConfig,\n op: 'create' | 'update' | 'patch' | 'delete',\n parentId: string | number | undefined,\n childId: string | number | undefined,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (parentId === undefined) {\n throw new BadRequestException(\n `Sub-resource \"${sub.childRoute}\" of \"${this.config.name}\" requires a parent id.`,\n );\n }\n\n const fn = childRepositoryFn(sub, op, this.config.name);\n const id =\n childId === undefined\n ? undefined\n : (sub.idType ?? 'string') === 'number'\n ? +childId\n : String(childId);\n\n const ctx = childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op,\n parentId: this.toId(parentId),\n id,\n request,\n });\n\n let payload: unknown;\n if (op !== 'delete') {\n const stripped =\n op === 'create' ? stripNonCreateableChildFields(sub, data) : data;\n const normalized = normalizeValueLabels(stripped, sub.valueLabelColumns);\n payload = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(normalized, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: op === 'patch' ? 'patch' : op,\n ...(id !== undefined && { id }),\n request,\n parent: ctx.parent,\n })\n : normalized;\n }\n\n const result =\n op === 'create'\n ? await fn(this.toId(parentId), payload, ctx)\n : op === 'delete'\n ? await fn(this.toId(parentId), id, ctx)\n : await fn(this.toId(parentId), id, payload, ctx);\n\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: op === 'patch' ? 'patch' : op,\n ...(id !== undefined && { id }),\n request,\n })\n : result;\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(\n parentId: string | number,\n sub: SubResourceConfig,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(sub, 'create', parentId, undefined, data, request);\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 stripped = stripNonCreateableChildFields(sub, data);\n const normalized = normalizeValueLabels(\n stripped,\n sub.valueLabelColumns,\n ) as object;\n const payload = { ...normalized, [sub.foreignKey]: this.toId(parentId) };\n const prepared = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(payload, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'create',\n request,\n parent: this.parentHookContext(parentId),\n })\n : payload;\n\n const includeKeys = includeRelationNames(sub.include);\n const preparedEntries = prepared as Record<string, unknown>;\n const prismaData = {\n ...Object.fromEntries(\n Object.entries(preparedEntries).filter(\n ([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v),\n ),\n ),\n ...(sub.foreignKey in preparedEntries\n ? { [sub.foreignKey]: this.toId(parentId) }\n : {}),\n };\n const result = await childModel.create({ data: prismaData });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'create',\n request,\n })\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(\n sub: SubResourceConfig,\n childId: string | number,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(\n sub,\n 'update',\n parentIdFromRequest(request),\n childId,\n data,\n request,\n );\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 id =\n (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, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'update',\n id,\n request,\n parent: this.parentHookContext(parentIdFromRequest(request) ?? id),\n })\n : normalized;\n\n const includeKeys = includeRelationNames(sub.include);\n const prepared = Object.fromEntries(\n Object.entries(afterHook as Record<string, unknown>).filter(\n ([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v),\n ),\n );\n try {\n const result = await childModel.update({\n where: { [sub.idField ?? DEFAULT_ID_FIELD]: id },\n data: prepared,\n });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'update',\n id,\n request,\n })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\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(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(\n sub,\n 'delete',\n parentIdFromRequest(request, parentId),\n childId,\n undefined,\n request,\n );\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 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 try {\n const result = await childModel.deleteMany({ where });\n if (result.count === 0)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'delete',\n id,\n request,\n })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n throw e;\n }\n }\n}\n","import { z } from 'zod';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\n\nexport const WriteOpSchema = z.enum(['create', 'update', 'patch', 'delete']);\nexport type WriteOp = z.infer<typeof WriteOpSchema>;\n\nexport const ReadOpSchema = z.enum(['findAll', 'findOne']);\nexport type ReadOp = z.infer<typeof ReadOpSchema>;\n\n/**\n * The parent a nested read or write is scoped to.\n *\n * Present whenever the resource is reached under a parent — as a sub-resource\n * declared by a relation column on the parent (`param` is the parent's own `id`),\n * or as a resource that declares `parent` and mounts its own controller beneath\n * it (`param` is the name it chose, e.g. `groupId`). Absent on a top-level write.\n *\n * Deliberately the same shape as `CustomRepositoryContext.parent`, so a hook and a\n * `repository.ts` read the parent identically.\n */\nexport interface ParentHookContext {\n route: string;\n param: string;\n id: string | number;\n}\n\nexport interface WriteHookContext<PRISMACLIENT = unknown> {\n /** The datasource adapter for this resource. Use `dataSource.client` to reach the raw backend. */\n dataSource: DataSourceAdapter;\n /**\n * Raw Prisma client — backward-compatible alias for `dataSource.client`.\n * `undefined` on a non-Prisma datasource.\n * @deprecated prefer `dataSource.client`\n */\n prisma: PRISMACLIENT;\n op: WriteOp;\n id?: string | number;\n request?: any;\n parent?: ParentHookContext;\n}\n\nexport interface ReadHookContext<PRISMACLIENT = unknown> {\n /** The datasource adapter for this resource. Use `dataSource.client` to reach the raw backend. */\n dataSource: DataSourceAdapter;\n /**\n * Raw Prisma client — backward-compatible alias for `dataSource.client`.\n * `undefined` on a non-Prisma datasource.\n * @deprecated prefer `dataSource.client`\n */\n prisma: PRISMACLIENT;\n op: ReadOp;\n request?: any;\n parent?: ParentHookContext;\n}\n\nexport const ResourceHooksSchema = z.object({\n beforeWrite: z\n .custom<(data: any, ctx: WriteHookContext<any>) => Promise<any> | any>()\n .optional(),\n afterWrite: z\n .custom<(result: any, ctx: WriteHookContext<any>) => Promise<any> | any>()\n .optional(),\n afterRead: z\n .custom<(row: any, ctx: ReadHookContext<any>) => Promise<any> | any>()\n .optional(),\n beforeFindAll: z\n .custom<(params: ListRequest, ctx: ReadHookContext<any>) => Promise<ListRequest> | ListRequest>()\n .optional(),\n afterFindAll: z\n .custom<(rows: any[], ctx: ReadHookContext<any>) => Promise<any[]> | any[]>()\n .optional(),\n});\n\n/**\n * Hand-written interface so the `PRISMACLIENT` generic is preserved.\n * `z.infer<typeof ResourceHooksSchema>` erases it (Zod wraps every custom()\n * in `ZodType<T>`, discarding the generic), making `ctx.prisma` always `any`.\n */\nexport interface ResourceHooks<PRISMACLIENT = any> {\n beforeWrite?: (data: any, ctx: WriteHookContext<PRISMACLIENT>) => Promise<any> | any;\n afterWrite?: (result: any, ctx: WriteHookContext<PRISMACLIENT>) => Promise<any> | any;\n afterRead?: (row: any, ctx: ReadHookContext<PRISMACLIENT>) => Promise<any> | any;\n beforeFindAll?: (params: ListRequest, ctx: ReadHookContext<PRISMACLIENT>) => Promise<ListRequest> | ListRequest;\n afterFindAll?: (rows: any[], ctx: ReadHookContext<PRISMACLIENT>) => Promise<any[]> | any[];\n}\n","import type { ResourceHooks } from './hooks.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { join } from 'node:path';\n\nexport const loadResourceHooks = async (\n basePath: string,\n): Promise<ResourceHooks | undefined> => {\n const file = findModule(basePath, 'hooks');\n return file ? importDefault<ResourceHooks>(file) : undefined;\n};\n\n/**\n * Attach each sub-resource's hooks.\n *\n * Two locations, checked in order:\n *\n * 1. `<parent>/hooks/<childName>.ts` — the original convention, which keeps every\n * child's hooks together under the parent that serves them.\n * 2. `<childDir>/hooks.ts` — the child's own directory, same filename a top-level\n * resource uses.\n *\n * The second exists because a child with its own directory already keeps\n * `resource.json` and (for `kind: \"custom\"`) `repository.ts` there, so putting\n * `hooks.ts` beside them is the obvious guess — and until it was supported that\n * file was silently ignored, with no error and no status-page entry.\n *\n * The parent-scoped location wins when both are present, so nothing that relied on\n * convention 1 changes behaviour.\n */\nexport const loadSubResourceHooks = async (\n subResources: SubResourceConfig[],\n basePath: string,\n): Promise<void> => {\n for (const sub of subResources) {\n const file =\n (sub.name ? findModule(join(basePath, 'hooks'), sub.name) : undefined) ??\n (sub.childDir ? findModule(sub.childDir, 'hooks') : undefined);\n if (!file) continue;\n const hooks = await importDefault<ResourceHooks>(file);\n if (hooks) (sub as any).hooks = hooks;\n }\n};","import type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type {\n ParentHookContext,\n ReadOp,\n ResourceHooks,\n WriteOp,\n} from './hooks.types';\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\nimport {\n applyValueLabelColumns,\n normalizeValueLabels,\n} from '../resource/valueLabel.apply';\n\n/**\n * Lifecycle-hook application, extracted so every repository implementation\n * treats hooks identically.\n *\n * All four helpers now accept a `DataSourceAdapter` instead of a raw Prisma\n * client. The adapter is forwarded into the hook context as `dataSource`; the\n * raw client is available as `ctx.prisma` (= `adapter.client`) for backward\n * compatibility with existing hook files.\n */\n\nexport type HookTarget = {\n hooks?: ResourceHooks;\n valueLabelColumns?: ValueLabelColumn[];\n};\n\nconst hookCtxRead = (adapter: DataSourceAdapter, op: ReadOp, request?: any, parent?: ParentHookContext) => ({\n dataSource: adapter,\n prisma: adapter.client,\n op,\n request,\n ...(parent && { parent }),\n});\n\nconst hookCtxWrite = (\n adapter: DataSourceAdapter,\n op: WriteOp,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n) => ({\n dataSource: adapter,\n prisma: adapter.client,\n op,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n ...(parent && { parent }),\n});\n\n/**\n * `afterRead` for a list, plus the `{ value, label }` envelope.\n *\n * The envelope is applied on list reads only — `findOne` feeds the form/detail\n * view, where the select control maps the stored scalar to its label itself and\n * submits the scalar back.\n */\nexport const decorateRows = async (\n rows: any[],\n op: ReadOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any[]> => {\n const hook = target.hooks?.afterRead;\n const ctx = hookCtxRead(adapter, op, request, parent);\n const hooked = hook\n ? await Promise.all(rows.map((row) => hook(row, ctx)))\n : rows;\n const cols = target.valueLabelColumns;\n return cols?.length\n ? hooked.map((r) => applyValueLabelColumns(r, cols))\n : hooked;\n};\n\n/** `afterRead` for a single row. Deliberately no value-label envelope. */\nexport const decorateRow = async (\n row: any,\n op: ReadOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const hook = target.hooks?.afterRead;\n return hook ? hook(row, hookCtxRead(adapter, op, request, parent)) : row;\n};\n\n/** Unwrap value-label envelopes, then run `beforeWrite`. */\nexport const prepareWrite = async (\n data: any,\n op: WriteOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const normalized = normalizeValueLabels(data, target.valueLabelColumns);\n const hook = target.hooks?.beforeWrite;\n return hook\n ? hook(normalized, hookCtxWrite(adapter, op, id, request, parent))\n : normalized;\n};\n\n/** Run `beforeFindAll` to transform query params before the DB query. */\nexport const applyBeforeFindAll = async (\n params: ListRequest,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<ListRequest> => {\n const hook = target.hooks?.beforeFindAll;\n return hook ? hook(params, hookCtxRead(adapter, 'findAll', request, parent)) : params;\n};\n\n/** Run `afterFindAll` on the full result list, after per-row `afterRead` decoration. */\nexport const applyAfterFindAll = async (\n rows: any[],\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any[]> => {\n const hook = target.hooks?.afterFindAll;\n return hook ? hook(rows, hookCtxRead(adapter, 'findAll', request, parent)) : rows;\n};\n\n/** Run `afterWrite` on the persisted result. */\nexport const postWrite = async (\n result: any,\n op: WriteOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const hook = target.hooks?.afterWrite;\n return hook ? hook(result, hookCtxWrite(adapter, op, id, request, parent)) : result;\n};\n","import {\n CUSTOM_OPS,\n type CustomParentRepository,\n type CustomRepository,\n PARENT_METHOD,\n} from './custom-repository.types';\nimport { type CrudOperation, isOperationEnabled, isOperationExternal, resolveDefinition } from '../crud.config';\nimport { type Resource } from '../resource/ResourceConfig.schema';\n\n/**\n * Check that a custom resource can actually serve what it advertises.\n *\n * Returns a human-readable problem, or `undefined` when the resource is sound.\n * Callers record the message on the load-error registry so it surfaces on the\n * status page — the same treatment a prisma resource gets when its model is\n * missing from the client. Failing at load time beats a 501 on first request.\n */\nexport const validateCustomRepository = (\n config: Resource,\n repository: CustomRepository | undefined,\n adapterClient?: unknown,\n): string | undefined => {\n const definition = resolveDefinition(config);\n const enabled = CUSTOM_OPS.filter((op) =>\n isOperationEnabled(definition, op as CrudOperation) &&\n !isOperationExternal(definition, op as CrudOperation),\n );\n\n // A nested resource is only reachable under its parent, so it implements the\n // parent-aware variants instead of the unnested ones.\n const nested = !!config.parent;\n const methodFor = (op: (typeof CUSTOM_OPS)[number]) =>\n nested ? PARENT_METHOD[op] : op;\n\n if (!repository) {\n if (enabled.length === 0) return undefined;\n // If the datasource adapter client implements all required methods it acts\n // as the repository — no repository.ts needed.\n if (adapterClient && typeof adapterClient === 'object') {\n const missing = enabled.filter(\n (op) => typeof (adapterClient as Record<string, unknown>)[methodFor(op)] !== 'function',\n );\n if (missing.length === 0) return undefined;\n }\n return (\n 'No repository.ts found. A custom resource implements its own data access; ' +\n `create ${config.name}/repository.ts with a default export implementing: ` +\n `${enabled.map(methodFor).join(', ')}.`\n );\n }\n\n const implemented = (name: keyof CustomRepository | keyof CustomParentRepository) =>\n typeof (repository as Record<string, unknown>)[name as string] === 'function';\n\n // `patch` is satisfied by `update` — the adapter falls back, matching the\n // Prisma repository where patch is an update with a partial schema.\n const missing = enabled.filter((op) =>\n op === 'patch'\n ? !implemented(methodFor('patch')) && !implemented(methodFor('update'))\n : !implemented(methodFor(op)),\n );\n\n if (missing.length) {\n const names = missing.map(methodFor);\n return (\n `repository.ts does not implement ${names.join(', ')}` +\n (nested\n ? ` (this resource is nested under \"${config.parent!.route}\", so it implements the parent-aware operations)` +\n '. '\n : '. ') +\n 'Either implement them or disable the operation in resource.json ' +\n `(\"operations\": { \"${missing[0]}\": false }).`\n );\n }\n\n return undefined;\n};\n","import {\n ZodObject,\n type ZodRawShape,\n type ZodType,\n toJSONSchema,\n} from 'zod';\n\nimport { isNullableProperty, jsonSchemaOpts } from '@ghentcdh/crouton-core';\n\nimport { type JsonSchemaInput, type SchemaInput } from './resource/json.schema';\n\nexport function isZodSchema(\n schema: SchemaInput,\n): schema is ZodObject<ZodRawShape> {\n return schema instanceof ZodObject;\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 let jsonSchema: Record<string, any>;\n try {\n jsonSchema = toJSONSchema(schema, {\n target: 'openApi3',\n ...jsonSchemaOpts,\n }) as Record<string, any>;\n } catch {\n // Zod v4 bug: z.record() inside z.union() inside z.lazy() crashes toJSONSchema\n // (e.g. Prisma JsonValue schema). Fall back to a permissive object schema.\n return { type: 'object' } as JsonSchemaInput;\n }\n\n dropNullableFromRequired(jsonSchema);\n\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 { Injectable, type OnModuleDestroy } from '@nestjs/common';\n\nimport type { DataSourceAdapter } from './data-source.adapter';\nimport type { DataSourceEntry } from './data-source.types';\n\n@Injectable()\nexport class DataSourceRegistry implements OnModuleDestroy {\n private readonly adapters = new Map<string, DataSourceAdapter>();\n private defaultName: string | undefined;\n\n constructor(entries: DataSourceEntry[]) {\n for (const entry of entries) {\n this.adapters.set(entry.config.name, entry.adapter);\n if (entry.config.default) {\n this.defaultName = entry.config.name;\n }\n }\n if (!this.defaultName && entries.length > 0) {\n this.defaultName = entries[0].config.name;\n }\n }\n\n resolveAdapter(name?: string): DataSourceAdapter {\n const key = name ?? this.defaultName;\n if (!key) throw new Error('No default data source configured');\n const adapter = this.adapters.get(key);\n if (!adapter) throw new Error(`Data source \"${key}\" not found in registry`);\n return adapter;\n }\n\n /** Returns the raw backend client for escape-hatch usage (`ctx.prisma`, action procedures). */\n resolveClient(name?: string): unknown {\n return this.resolveAdapter(name).client;\n }\n\n /**\n * Backward-compatible alias — returns the raw client, same as `resolveClient`.\n * Prefer `resolveAdapter` for new code.\n */\n resolve(name?: string): unknown {\n return this.resolveClient(name);\n }\n\n entries(): { name: string; adapter: DataSourceAdapter; client: unknown }[] {\n return [...this.adapters.entries()].map(([name, adapter]) => ({\n name,\n adapter,\n client: adapter.client,\n }));\n }\n\n async onModuleDestroy() {\n await this.disconnectAll();\n }\n\n /**\n * Disconnect every datasource. Called by `onModuleDestroy` and also by the\n * dev \"restart backend\" action before `process.exit()`.\n */\n async disconnectAll(): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.disconnect?.();\n }\n }\n}\n","import { DataSourceSchema } from '@ghentcdh/crouton-core';\n\nimport type { DataSourceAdapter } from './data-source.adapter';\nimport type { DataSourceEntry } from './data-source.types';\nimport { PrismaDataSourceAdapter } from './prisma.adapter';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/**\n * Scan a directory for data-source subdirectories and load their configs + adapters.\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 let _config: unknown;\n try {\n _config = JSON.parse(readFileSync(jsonFile, 'utf-8'));\n } catch (err) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: `Invalid JSON in ${jsonFile}: ${(err as Error).message}`,\n });\n continue;\n }\n\n const datasource = DataSourceSchema.safeParse(_config);\n\n if (!datasource.success) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: `Invalid datasource schema: ${jsonFile}: ${datasource.error.message}`,\n });\n continue;\n }\n const config = datasource.data;\n\n const indexFile = findModule(basePath, 'index');\n\n if (!indexFile) continue;\n\n let adapter: DataSourceAdapter;\n try {\n const mod = await import(indexFile);\n const exported = mod.default;\n if (!exported) continue;\n\n if (config.adapter === 'custom') {\n // index.ts may default-export a DataSourceAdapter instance or a class\n // that extends PrismaDataSourceAdapter (or any DataSourceAdapter).\n if (typeof exported === 'function') {\n // Class export: `export default class MyAdapter extends PrismaDataSourceAdapter { ... }`\n const instance = new exported() as DataSourceAdapter;\n if (typeof instance.kind !== 'string') {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Custom datasource \"${dir}\": default-exported class must produce a DataSourceAdapter (object with a \"kind\" string field).`,\n });\n continue;\n }\n adapter = instance;\n } else if (typeof exported === 'object' && typeof exported.kind === 'string') {\n adapter = exported as DataSourceAdapter;\n } else {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Custom datasource \"${dir}\": index.ts must default-export a DataSourceAdapter instance or class (with a \"kind\" string field).`,\n });\n continue;\n }\n } else {\n // Default: prisma — wrap the exported PrismaClient.\n adapter = new PrismaDataSourceAdapter(exported);\n }\n } catch (err) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Failed to load datasource adapter: ${(err as Error).message}`,\n });\n continue;\n }\n\n results.push({ config, adapter });\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 type { DataSourceAdapter } from './data-source.adapter';\n\n/**\n * In-memory reference adapter — useful for tests and as a template for custom\n * adapters. Not intended for production use.\n *\n * Seed model rows with `seed(model, rows)` before the test; `supports(model)`\n * returns `true` for every seeded model.\n */\nexport class InMemoryDataSourceAdapter implements DataSourceAdapter {\n readonly kind = 'in-memory' as const;\n readonly client = undefined;\n\n private readonly store = new Map<string, unknown[]>();\n\n seed(model: string, rows: unknown[]): this {\n this.store.set(model, rows);\n return this;\n }\n\n supports(model: string): boolean {\n return this.store.has(model);\n }\n\n async disconnect(): Promise<void> {\n // no-op\n }\n}\n","import { Param, Post, SetMetadata } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isRowProcedureAction, isTableProcedureAction } from '../crud.config';\nimport { CROUTON_SECURITY } from '../security';\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(isRowProcedureAction);\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 const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\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(isTableProcedureAction);\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 const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\n }\n};\n","import {\n type CanActivate,\n type ExecutionContext,\n Injectable,\n} from '@nestjs/common';\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- runtime DI requires value imports\nimport { ModuleRef, Reflector } from '@nestjs/core';\n\nimport type { SecurityConfig } from '@ghentcdh/crouton-core';\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- runtime DI requires value import\nimport { SecurityGuardRegistry } from './security-guard.registry';\n\nexport const CROUTON_SECURITY = 'crouton:security';\n\n@Injectable()\nexport class CroutonSecurityGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly registry: SecurityGuardRegistry,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const sec = this.reflector.get<SecurityConfig | undefined>(\n CROUTON_SECURITY,\n context.getHandler(),\n );\n\n // No metadata or explicitly public → allow.\n if (!sec || 'public' in sec) return true;\n\n const names = Array.isArray(sec.guard) ? sec.guard : [sec.guard];\n for (const name of names) {\n const cls = this.registry.resolve(name);\n const guard = this.moduleRef.get(cls, { strict: false });\n const ok = await guard.canActivate(context);\n if (!ok) return false;\n }\n return true;\n }\n}\n","import { type CanActivate, Injectable, type Type } from '@nestjs/common';\n\n@Injectable()\nexport class SecurityGuardRegistry {\n constructor(\n private readonly guards: Record<string, Type<CanActivate>> = {},\n ) {}\n\n resolve(name: string): Type<CanActivate> {\n const g = this.guards[name];\n if (!g)\n throw new Error(\n `Unknown security guard \"${name}\". Register it in security.guards.`,\n );\n return g;\n }\n\n classes(): Type<CanActivate>[] {\n return Object.values(this.guards);\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 { Body, Param, Post, Req } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultCreate = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'create')) return null;\n if (isOperationExternal(ctx.definition, 'create')) return null;\n const { cls, config, createSchema, bodyDecorator } = ctx;\n const methodName = 'create';\n\n return {\n route: '',\n methodName,\n name: config.name,\n createFn: function (this: { repo: CrudRepository }, body: any, req: any) {\n return this.repo.create(body, req);\n },\n decorators: () => {\n bodyDecorator(createSchema, { coerceNullableUndefinedToNull: true })(\n cls.prototype,\n methodName,\n 0,\n );\n Req()(cls.prototype, methodName, 1);\n },\n };\n};\n\nconst childCreate = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'create')) return null;\n const { cls } = ctx;\n const methodName = `createChild_${sub.childRoute}`;\n\n const createFn = async function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.createChild(id, sub, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Body()(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n route: `:id/${sub.childRoute}`,\n methodName,\n name: sub.childRoute,\n createFn,\n decorators,\n };\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 = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childCreate(sub) : defaultCreate;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.createFn);\n const d = desc(cls, methodName);\n Post(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Create a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 201, description: `${name} created` })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'create', sub);\n};\n","import { Delete, Param, Req } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { type SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultDelete = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'delete')) return null;\n if (isOperationExternal(ctx.definition, 'delete')) return null;\n const { config } = ctx;\n const methodName = 'delete';\n const { name } = config;\n\n return {\n route: ':id',\n methodName,\n name,\n decorators: () => {\n //\n },\n deleteFn: function (this: { repo: CrudRepository }, id: string, req: any) {\n return this.repo.delete(id, req);\n },\n };\n};\n\nexport const deleteChild =\n (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'delete')) return null;\n const { cls } = ctx;\n const methodName = `deleteChild_${sub.childRoute}`;\n\n const deleteFn = async function (\n this: { repo: CrudRepository },\n childId: string,\n parentId: string,\n req: any,\n ) {\n return this.repo.deleteChild(sub, childId, parentId, req);\n };\n\n const decorators = () => {\n Param('childId')(cls.prototype, methodName, 0);\n // The parent id was declared but never bound, so `parentId` always\n // arrived undefined and the foreign-key guard in `deleteChild` — the one\n // that is supposed to prevent cross-parent deletions — never engaged.\n Param('id')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n deleteFn,\n decorators,\n };\n };\n\n/** Register `DELETE /:id`. No-ops when `delete` is disabled. */\nexport const registerDelete = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? deleteChild(sub) : defaultDelete;\n const { cls } = ctx;\n\n const properties = operationFn(ctx);\n if (!properties) return;\n const { methodName, route, name } = properties;\n\n def(cls, methodName, properties.deleteFn);\n const d = desc(cls, methodName);\n Delete(route)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n ApiOperation({ summary: `Delete ${name} record` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200 })(cls.prototype, methodName, d);\n properties.decorators();\n if (!sub) Req()(cls.prototype, methodName, 1);\n ctx.secure(methodName, 'delete', sub);\n};\n","import { Get, Param, Query, Req } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { RequestDtoNoOffset } from '../request.dto';\nimport { type SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { childSchemas } from './register-schemas';\n\nconst _findAll = async (\n repo: CrudRepository,\n params: any,\n request?: any,\n) => {\n // Repositories that cannot count separately (custom repositories backed by a\n // remote API) implement `findAllWithCount` and return both in one round trip.\n const { data, count } = repo.findAllWithCount\n ? await repo.findAllWithCount(params, request)\n : await Promise.all([\n repo.findAll(params, request),\n repo.count(params.filter ?? [], params.q),\n ]).then(([data, count]) => ({ data, count }));\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: {\n count,\n page: params.page,\n pageSize: params.pageSize,\n totalPages,\n sort: params.sort,\n sortDir: params.sortDir,\n filter: params.filter,\n },\n };\n};\nconst findAllByParent = async (\n repo: CrudRepository,\n id: string,\n childRoute: string,\n params: any,\n request?: any,\n) => {\n const { data, count } = await repo.findAllByParent(\n id,\n childRoute,\n params,\n request,\n );\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: {\n count,\n page: params.page,\n pageSize: params.pageSize,\n totalPages,\n sort: params.sort,\n sortDir: params.sortDir,\n filter: params.filter,\n },\n };\n};\n\nconst defaultFindAll = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'findAll')) return;\n if (isOperationExternal(ctx.definition, 'findAll')) return;\n\n const { config } = ctx;\n const findAll = async function (\n this: { repo: CrudRepository },\n params: any,\n req: any,\n ) {\n return _findAll(this.repo, params, req);\n };\n\n return {\n route: '',\n name: config.name,\n methodName: 'findAll',\n findAll,\n listSchema: ctx.listSchema,\n decorators: () => {\n //\n },\n };\n};\n\nconst childFindAll = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'findAll')) return;\n\n const { cls } = ctx;\n const methodName = `findAllBy_${sub.childRoute}`;\n\n const findAll = async function (\n this: { repo: CrudRepository },\n params: any,\n id: string,\n req: any,\n ) {\n return findAllByParent(this.repo, id, sub.childRoute, params, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n name: sub.childRoute,\n methodName,\n findAll,\n route: `:id/${sub.childRoute}`,\n decorators,\n listSchema: ctx.listSchema,\n };\n};\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 = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childFindAll(sub) : defaultFindAll;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name, listSchema } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.findAll);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n Query(new ZodValidationPipe(RequestDtoNoOffset.schema as any))(\n cls.prototype,\n methodName,\n 0,\n );\n if (!sub) Req()(cls.prototype, methodName, 1);\n ApiOperation({ summary: `List all ${name}s` })(cls.prototype, methodName, d);\n ApiResponse({\n status: 200,\n description: `Array of ${name}`,\n ...(listSchema && {\n schema: { type: 'array', items: toJsonSchema(listSchema) },\n }),\n })(cls.prototype, methodName, d);\n\n properties.decorators();\n ctx.secure(methodName, 'findAll', sub);\n};\n","import { createZodDto } from 'nestjs-zod';\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 { isDecimalField } from '@ghentcdh/crouton-core';\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 /** Top-level field names whose unwrapped type is a Prisma Decimal. */\n private readonly decimalKeys: readonly string[];\n /** Prisma Decimal constructor resolved once per pipe instance; null if unavailable. */\n private readonly decimalCtor: (new (v: number | string) => object) | null;\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\n // Resolve Decimal ctor once; skip coercion entirely if @prisma/client is unavailable.\n \n let decimalCtor: (new (v: number | string) => object) | null = null;\n try {\n decimalCtor = require('@prisma/client/runtime/client').Decimal;\n } catch {\n // @prisma/client not available — Decimal coercion disabled, falls back to today's behaviour\n }\n this.decimalCtor = decimalCtor;\n\n this.decimalKeys = decimalCtor\n ? Object.entries(schema.shape)\n .filter(([, field]) => isDecimalField(field as ZodType))\n .map(([key]) => key)\n : [];\n this.coerceUndefinedToNull = options.coerceNullableUndefinedToNull ?? false;\n }\n\n transform(value: unknown) {\n const stripped = this.stripEmptyStrings(value);\n const coerced = this.coerceNullable(stripped);\n const input = this.coerceDecimals(coerced);\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 /**\n * Coerce `number` / `string` values on Decimal fields to `Prisma.Decimal`.\n * `null` / `undefined` / omitted keys are left untouched (PATCH-safe).\n * An invalid numeric string is left as-is so Zod emits a proper validation error.\n * Known limitation: only top-level fields are coerced (nested Decimals in relations/arrays\n * are out of scope — matches how nullableKeys works today).\n */\n private coerceDecimals(value: unknown): unknown {\n if (\n !this.decimalCtor ||\n this.decimalKeys.length === 0 ||\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.decimalKeys) {\n const v = out[key];\n if (v == null) continue;\n if (typeof v !== 'number' && typeof v !== 'string') continue;\n try {\n out[key] = new this.decimalCtor(v);\n } catch {\n // leave raw value — Zod will emit the correct validation error\n }\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 code: e.code,\n }));\n }\n}\n","import { Get, Param, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiParam,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\n\nconst defaultFindOne = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'findOne')) return null;\n if (isOperationExternal(ctx.definition, 'findOne')) return null;\n const { cls, config } = ctx;\n const methodName = 'findOne';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n findOneFn: function (this: { repo: CrudRepository }, id: string, req: any) {\n return this.repo.findOne(id, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n Req()(cls.prototype, methodName, 1);\n },\n };\n};\n\nconst childFindOne = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'findOne')) return null;\n const { cls } = ctx;\n const methodName = `findOneChild_${sub.childRoute}`;\n\n const findOneFn = async function (\n this: { repo: CrudRepository },\n parentId: string,\n childId: string,\n req: any,\n ) {\n return this.repo.findOneChild(sub, childId, parentId, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n findOneFn,\n decorators,\n };\n};\n\n/** Register `GET /:id`. No-ops when `findOne` is disabled. */\nexport const registerFindOne = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childFindOne(sub) : defaultFindOne;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.findOneFn);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Get one ${name} by id` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({\n status: 200,\n description: `The ${name}`,\n ...(ctx.oneSchema && { schema: toJsonSchema(ctx.oneSchema) }),\n })(cls.prototype, methodName, d);\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'findOne', sub);\n};\n","import { Body, Param, Patch, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultPatch = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'patch')) return null;\n if (isOperationExternal(ctx.definition, 'patch')) return null;\n const { cls, config, patchSchema, bodyDecorator } = ctx;\n const methodName = 'patch';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n patchFn: function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.patch(id, body, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n bodyDecorator(patchSchema)(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n },\n };\n};\n\nconst childPatch = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'patch')) return null;\n const { cls } = ctx;\n const methodName = `patchChild_${sub.childRoute}`;\n\n const patchFn = async function (\n this: { repo: CrudRepository },\n _id: string,\n childId: string,\n body: any,\n req: any,\n ) {\n return this.repo.updateChild(sub, childId, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Body()(cls.prototype, methodName, 2);\n Req()(cls.prototype, methodName, 3);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n patchFn,\n decorators,\n };\n};\n\n/** Register `PATCH /:id`. No-ops when `patch` is disabled. */\nexport const registerPatch = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childPatch(sub) : defaultPatch;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.patchFn);\n const d = desc(cls, methodName);\n Patch(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Update a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${name} updated` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'patch', sub);\n};\n","\nimport {\n BadRequestException,\n Body,\n ForbiddenException,\n Get,\n NotFoundException,\n Patch, Put,\n SetMetadata,\n} from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { IS_DEV } from '../dev-mode';\nimport {\n type PatchResourceJson,\n PatchResourceJsonSchema,\n} from '../resource/PatchResourceJson.schema';\nimport {\n applyColumnPatch,\n readRawResourceJson,\n validateResourceJson,\n writeRawResourceJson,\n} from '../resource/WriteResourceJson';\nimport { type ResourceConfigRegistry } from '../resource-config.registry';\nimport { CROUTON_SECURITY } from '../security';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport {\n buildDefinitionPayload,\n buildEditableColumnsPayload,\n buildResourceJsonPayload,\n} from './payload-builders';\nimport { getRequestLanguage } from '../translation/language.context';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { join } from 'node:path';\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, schemaEnricher } = ctx;\n const { route, name } = config;\n const definitionPayload = buildDefinitionPayload(config);\n\n def(\n cls,\n 'getDefinition',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n const language = getRequestLanguage();\n let payload = definitionPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildDefinitionPayload(fresh);\n }\n if (!schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n );\n const d = desc(cls, 'getDefinition');\n Get('definition')(cls.prototype, 'getDefinition', d);\n ApiOperation({ summary: `Get the resource definition for ${name}` })(\n cls.prototype,\n 'getDefinition',\n d,\n );\n ApiResponse({\n status: 200,\n description: `Definition (operations + schemas) for ${name}`,\n })(cls.prototype, 'getDefinition', d);\n\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, 'getDefinition', d);\n }\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, schemaEnricher } = ctx;\n const { route, name } = config;\n const resourceJsonPayload = buildResourceJsonPayload(config, baseUrl);\n\n def(\n cls,\n 'getResourceJson',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n const language = getRequestLanguage();\n let payload = resourceJsonPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildResourceJsonPayload(fresh, baseUrl);\n }\n if (!schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n );\n const d = desc(cls, 'getResourceJson');\n Get('resource.json')(cls.prototype, 'getResourceJson', d);\n ApiOperation({ summary: `Get resource descriptor for ${name}` })(\n cls.prototype,\n 'getResourceJson',\n d,\n );\n ApiResponse({\n status: 200,\n description: `Resource descriptor (operations + JSON Schema) for ${name}`,\n })(cls.prototype, 'getResourceJson', d);\n\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, 'getResourceJson', d);\n }\n};\n\n/**\n * Register `GET /resource-columns` — dev-only endpoint backing the visual\n * resource builder's editor UI. Returns the raw, editable column list (see\n * `buildEditableColumnsPayload`), rebuilt from the live config registry on\n * every request so it reflects any on-disk edits (including ones made by\n * this same builder, or by hand, or by `crouton update resources`).\n */\nexport const registerResourceColumnsEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'getResourceColumns',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The resource schema editor is only available when the backend is running in local dev mode.',\n );\n }\n const fresh = await this.configRegistry.getByRoute(route);\n return buildEditableColumnsPayload(fresh ?? config);\n },\n );\n const d = desc(cls, 'getResourceColumns');\n Get('resource-columns')(cls.prototype, 'getResourceColumns', d);\n ApiOperation({\n summary: `Dev-only: get the editable column list for ${name}`,\n })(cls.prototype, 'getResourceColumns', d);\n ApiResponse({\n status: 200,\n description: `Editable column list for ${name}`,\n })(cls.prototype, 'getResourceColumns', d);\n};\n\n/**\n * Register `PATCH /resource.json` — dev-only endpoint backing the visual\n * resource builder. Patches column display attributes (label, column,\n * hiddenInTable, hiddenInForm, hiddenInView, position, colspan) on the\n * resource's on-disk `resource.json` and returns the freshly reloaded\n * resource descriptor.\n *\n * Hard-gated to `IS_DEV`: refuses with 403 in any non-dev environment, since\n * writing to source files must never happen against a production deployment.\n */\nexport const registerResourceJsonPatchEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'patchResourceJson',\n async function (\n this: { configRegistry: ResourceConfigRegistry },\n body: PatchResourceJson,\n ) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'Editing resource.json is only available when the backend is running in local dev mode.',\n );\n }\n\n // Refresh the registry first so `getResourceDir` reflects the current on-disk layout.\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const jsonPath = join(dir, 'resource.json');\n const raw = readRawResourceJson(jsonPath);\n if (!raw) {\n throw new NotFoundException(`resource.json not found at ${jsonPath}`);\n }\n\n const merged = applyColumnPatch(raw, body);\n const validated = validateResourceJson(merged);\n if (!validated.success) {\n throw new BadRequestException(validated.error.issues);\n }\n\n writeRawResourceJson(jsonPath, merged);\n\n const fresh = await this.configRegistry.getByRoute(route);\n return buildEditableColumnsPayload(fresh ?? config);\n },\n );\n const d = desc(cls, 'patchResourceJson');\n Patch('resource.json')(cls.prototype, 'patchResourceJson', d);\n Body(new ZodValidationPipe(PatchResourceJsonSchema))(\n cls.prototype,\n 'patchResourceJson',\n 0,\n );\n ApiOperation({\n summary: `Dev-only: patch column layout in resource.json for ${name}`,\n })(cls.prototype, 'patchResourceJson', d);\n ApiResponse({\n status: 200,\n description: `Updated resource descriptor for ${name}`,\n })(cls.prototype, 'patchResourceJson', d);\n};\n\n/**\n * Register `GET /resource-json-raw` — dev-only endpoint returning the raw,\n * untransformed resource.json as-is (no schema defaults applied). Backs the\n * standalone resource.json editor component's initial load.\n */\nexport const registerResourceJsonRawGetEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'getResourceJsonRaw',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The resource JSON editor is only available when the backend is running in local dev mode.',\n );\n }\n\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const jsonPath = join(dir, 'resource.json');\n const raw = readRawResourceJson(jsonPath);\n if (!raw) {\n throw new NotFoundException(`resource.json not found at ${jsonPath}`);\n }\n\n return raw;\n },\n );\n const d = desc(cls, 'getResourceJsonRaw');\n Get('resource-json-raw')(cls.prototype, 'getResourceJsonRaw', d);\n ApiOperation({\n summary: `Dev-only: get the raw resource.json for ${name}`,\n })(cls.prototype, 'getResourceJsonRaw', d);\n ApiResponse({\n status: 200,\n description: `Raw resource.json for ${name}`,\n })(cls.prototype, 'getResourceJsonRaw', d);\n};\n\n/**\n * Register `PUT /resource-json-raw` — dev-only endpoint that replaces the\n * entire resource.json with the provided body. Validates through\n * `ResourceJsonSchema` before writing. Backs the standalone resource.json\n * editor component's save action.\n */\nexport const registerResourceJsonRawPutEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'putResourceJsonRaw',\n async function (\n this: { configRegistry: ResourceConfigRegistry },\n body: Record<string, unknown>,\n ) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'Editing resource.json is only available when the backend is running in local dev mode.',\n );\n }\n\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const validated = validateResourceJson(body);\n if (!validated.success) {\n throw new BadRequestException(validated.error.issues);\n }\n\n const jsonPath = join(dir, 'resource.json');\n writeRawResourceJson(jsonPath, body);\n\n return body;\n },\n );\n const d = desc(cls, 'putResourceJsonRaw');\n Put('resource-json-raw')(cls.prototype, 'putResourceJsonRaw', d);\n Body()(cls.prototype, 'putResourceJsonRaw', 0);\n ApiOperation({\n summary: `Dev-only: replace the full resource.json for ${name}`,\n })(cls.prototype, 'putResourceJsonRaw', d);\n ApiResponse({\n status: 200,\n description: `Updated raw resource.json for ${name}`,\n })(cls.prototype, 'putResourceJsonRaw', d);\n};\n","import { z } from 'zod';\n\n/**\n * A per-context field-variant patch (`fieldInput`/`fieldView`/`fieldTable`).\n * Mirrors crouton-core's `FieldVariantSchema` shape loosely — `options` is a\n * catchall since a column's real option set depends on its `format`/`type`\n * (relation vs. plain vs. custom render) and the visual builder can't know\n * that ahead of time.\n *\n * Every key accepts `null`, matching `mergeFieldVariant`'s (crouton-core)\n * \"a `null` value deletes an inherited key\" convention — this is how the\n * editor's \"reset to inherited\" action works: it sends `null` for a key so\n * the column falls back to whatever the level below it (`fieldView` →\n * `fieldInput`, or `fieldTable` → `fieldView` → `fieldInput`) resolves to,\n * rather than pinning a copy of the resolved value at this level.\n */\nconst FieldVariantPatchSchema = z\n .object({\n type: z.string().nullable().optional(),\n format: z.string().nullable().optional(),\n resource: z.string().nullable().optional(),\n position: z.number().nullable().optional(),\n options: z.record(z.string(), z.unknown().nullable()).optional(),\n })\n .partial();\n\nexport type FieldVariantPatch = z.infer<typeof FieldVariantPatchSchema>;\n\n/**\n * Request body for `PATCH <route>/resource.json` — the visual resource\n * builder's edit endpoint (dev-mode only, see `dev-mode.ts`).\n *\n * Covers the display attributes the visual builder exposes: label/column,\n * visibility (`hiddenInTable/Form/View`), and the three field-variant\n * patches. Adding/removing columns is still out of scope — see\n * `FIELD_VARIANTS_EDITOR_PLAN.md`.\n */\nexport const PatchColumnSchema = z\n .object({\n label: z.string().optional(),\n column: z.string().optional(),\n hiddenInTable: z.boolean().optional(),\n hiddenInForm: z.boolean().optional(),\n hiddenInView: z.boolean().optional(),\n fieldInput: FieldVariantPatchSchema.optional(),\n fieldView: FieldVariantPatchSchema.optional(),\n fieldTable: FieldVariantPatchSchema.optional(),\n })\n .partial();\n\nexport type PatchColumn = z.infer<typeof PatchColumnSchema>;\n\nexport const PatchResourceJsonSchema = z.object({\n columns: z.record(z.string(), PatchColumnSchema),\n});\n\nexport type PatchResourceJson = z.infer<typeof PatchResourceJsonSchema>;\n","\nimport {\n type FieldInput,\n type FieldVariant,\n buildResourceJsonSchema,\n mergeFieldVariant,\n} from '@ghentcdh/crouton-core';\n\nimport type {\n PatchColumn,\n PatchResourceJson,\n} from './PatchResourceJson.schema';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\n\n/**\n * Backs the visual resource builder's `PATCH <route>/resource.json` endpoint.\n *\n * Deliberately does NOT reuse `readResourceJson` (`ReadResourceJson.ts`) for the\n * read side: that helper runs the file through `ResourceJsonSchema`, whose\n * `.transform()` normalizes `columns` from map-form to an array and fills in\n * every default. Round-tripping through it would silently rewrite a hand-written\n * map-form resource.json into array form and inject defaults for every\n * untouched field — the opposite of the \"leave every untouched key byte-stable\"\n * goal (see `VISUAL_RESOURCE_BUILDER_PLAN.md`, Phase 1). Instead this module\n * reads the raw JSON, patches only the touched leaf fields, and writes the\n * result back verbatim. `ResourceJsonSchema` is still used, but only to\n * *validate* the merged result before writing — never to shape what's written.\n */\nexport type RawResourceJson = Record<string, unknown>;\n\nexport const readRawResourceJson = (\n jsonPath: string,\n): RawResourceJson | undefined => {\n if (!existsSync(jsonPath)) return undefined;\n return JSON.parse(readFileSync(jsonPath, 'utf-8'));\n};\n\nconst FIELD_VARIANT_KEYS = ['fieldInput', 'fieldView', 'fieldTable'] as const;\ntype FieldVariantKey = (typeof FIELD_VARIANT_KEYS)[number];\n\n/**\n * Merges each of `fieldInput`/`fieldView`/`fieldTable` present on the patch\n * into the column's existing raw value for that key, via crouton-core's\n * `mergeFieldVariant` — the same function that resolves the\n * `fieldInput → fieldView → fieldTable` fallback chain elsewhere, so a patch\n * follows identical \"deep-merge one level into `options`, `null` deletes an\n * inherited key\" semantics instead of a second bespoke implementation.\n */\nconst mergeColumn = (\n existing: Record<string, unknown>,\n patch: PatchColumn,\n): Record<string, unknown> => {\n const { fieldInput, fieldView, fieldTable, ...rest } = patch;\n const variantPatches: Partial<Record<FieldVariantKey, unknown>> = {\n fieldInput,\n fieldView,\n fieldTable,\n };\n\n const merged: Record<string, unknown> = { ...existing, ...rest };\n for (const key of FIELD_VARIANT_KEYS) {\n const variantPatch = variantPatches[key];\n if (!variantPatch) continue;\n merged[key] = mergeFieldVariant(\n existing[key] as FieldInput | undefined,\n variantPatch as FieldVariant,\n );\n }\n return merged;\n};\n\n/**\n * Applies a column patch to a raw (untransformed) resource.json object,\n * preserving whichever column shape (id-keyed map or array) the file already\n * uses, and leaving every other top-level key and every untouched column\n * field byte-stable. Only patches columns that already exist — the visual\n * builder's MVP does not add or remove columns (see optional phases in\n * `VISUAL_RESOURCE_BUILDER_PLAN.md`).\n */\nexport const applyColumnPatch = (\n raw: RawResourceJson,\n patch: PatchResourceJson,\n): RawResourceJson => {\n const columns = raw['columns'];\n\n if (Array.isArray(columns)) {\n const updated = columns.map((col: Record<string, unknown>) => {\n const columnPatch = patch.columns[col['id'] as string];\n return columnPatch ? mergeColumn(col, columnPatch) : col;\n });\n return { ...raw, columns: updated };\n }\n\n if (columns && typeof columns === 'object') {\n const updated: Record<string, unknown> = { ...columns };\n for (const [id, columnPatch] of Object.entries(patch.columns)) {\n if (!(id in updated)) continue;\n updated[id] = mergeColumn(\n updated[id] as Record<string, unknown>,\n columnPatch,\n );\n }\n return { ...raw, columns: updated };\n }\n\n return raw;\n};\n\n/**\n * Mirrors `@ghentcdh/crouton-codegen`'s `serializeResourceJson` (2-space JSON,\n * trailing newline, relies on object key insertion order for minimal diffs).\n * Kept inline here rather than adding crouton-api's first runtime dependency\n * on crouton-codegen (which brings in `@prisma/internals`) for a one-line\n * formatter — see the \"reuse\" note in `VISUAL_RESOURCE_BUILDER_PLAN.md`.\n */\nexport const serializeResourceJson = (config: unknown): string =>\n `${JSON.stringify(config, null, 2)}\\n`;\n\n/** Validates a merged raw resource.json before it's written to disk. */\nexport const validateResourceJson = (raw: unknown) =>\n buildResourceJsonSchema().safeParse(raw);\n\nexport const writeRawResourceJson = (\n jsonPath: string,\n raw: RawResourceJson,\n): void => {\n writeFileSync(jsonPath, serializeResourceJson(raw), 'utf-8');\n};\n","import {\n type FieldInput,\n type JsonColumn,\n buildSubResourceOperations,\n getResourceExtensions,\n resolveTableField,\n resolveViewField,\n} from '@ghentcdh/crouton-core';\n\nimport { type ResourceRowAction } from '../action';\nimport {\n externalRouteFor,\n isOperationEnabled,\n isOperationExternal,\n resolveDefinition,\n schemaFor,\n} from '../crud.config';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\n\n// ── Internal helpers ──────────────────────────────────────────────────────\n\nconst pickExtensions = (config: Resource) =>\n Object.fromEntries([...getResourceExtensions().keys()].filter(k => (config as Record<string, unknown>)[k] !== undefined).map(k => [k, (config as Record<string, unknown>)[k]]));\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\nconst RESOURCE_OPS = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\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: 'put',\n patch: 'patch',\n delete: 'delete',\n};\nconst OP_SUFFIX: Record<ResourceOp, string> = {\n findAll: '',\n findOne: '/{id}',\n create: '',\n update: '/{id}',\n patch: '/{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((op) => {\n const extUri = externalRouteFor(definition, op);\n const uri = extUri ? resolveEnvPlaceholders(extUri) : `${baseUri}${OP_SUFFIX[op]}`;\n const entry = definition[op];\n const method =\n (extUri && typeof entry === 'object' && entry !== null && 'method' in entry\n ? (entry as { method?: string }).method\n : undefined) ?? OP_METHOD[op];\n return [op, { uri, method }];\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: Resource,\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 patchSchema = schemaFor(definition, 'patch');\n const operations = (\n [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n ] as const\n ).filter((op) => isOperationEnabled(definition, op));\n\n return {\n name,\n route,\n idType,\n tag,\n operations,\n display: config.display,\n schemas: {\n ...(listSchema && { findAll: toJsonSchema(listSchema) }),\n ...(oneSchema && { findOne: toJsonSchema(oneSchema) }),\n ...(createSchema && { create: toJsonSchema(createSchema) }),\n ...(updateSchema && { update: toJsonSchema(updateSchema) }),\n ...(patchSchema && { patch: toJsonSchema(patchSchema) }),\n },\n ...pickExtensions(config),\n };\n};\n\n/** Build the payload for `GET /resource.json` — URI, enabled operations, and optional form schema. */\nexport const buildResourceJsonPayload = (\n config: Resource,\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 if (!isOperationExternal(definition, 'findAll')) {\n operations.lookup = `${uri}?q={text}`;\n }\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 {\n id: config.id ?? route,\n uri,\n operations,\n schema,\n ...pickExtensions(config),\n };\n};\n\nconst _resolveActions = (\n baseUrl: string[],\n actions: ResourceRowAction[] | undefined,\n) => {\n if (!actions?.length) return [];\n const resolved = actions.map((a) =>\n a.type === 'link'\n ? {\n ...a,\n href: resolveEnvPlaceholders(a.href),\n }\n : {\n ...a,\n uri: baseUrl.map((b) => (b === '{actionId}' ? a.id : b)).join('/'),\n method: a.method ?? 'post',\n },\n );\n return resolved;\n};\n\nexport const resolveActions = (\n baseUrl: string,\n actions: ResourceRowAction[] | undefined,\n) => {\n return _resolveActions([baseUrl, 'procedure', '{actionId}', '{id}'], actions);\n};\n\nexport const resolveTableActions = (\n baseUrl: string,\n actions: ResourceRowAction[] | undefined,\n) => {\n return _resolveActions([baseUrl, 'table-action', '{actionId}'], actions);\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: Resource,\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 // A nested resource is served under its parent, so its URIs carry the parent\n // id as a `{param}` placeholder — the same substitution the frontend already\n // performs for sub-resource URIs via replaceUriParams.\n const baseUri = config.parent\n ? `${baseUrl}/${config.parent.route}/{${config.parent.param}}/${config.route}`\n : `${baseUrl}/${config.route}`;\n const operations: Record<string, unknown> = buildResourceOperations(\n definition,\n baseUri,\n );\n if (isOperationEnabled(definition, 'findAll') && !isOperationExternal(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 const baseAction = `${baseUri}${config.route}`;\n return {\n id: config.id ?? config.route,\n name: config.name,\n route: config.route,\n uri: baseUri,\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 actions: resolveActions(baseAction, config.actions),\n tableActions: resolveActions(baseAction, config.tableActions),\n ...pickExtensions(config),\n };\n};\n\n/**\n * Build the payload for a sub-resource's `GET /<child>/schemas` endpoint.\n * Returns `undefined` when the sub-resource has no views configured.\n */\nexport const buildSubResourceViewsPayload = (\n config: Resource,\n sub: SubResourceConfig,\n baseUrl?: string,\n): Record<string, unknown> | undefined => {\n if (!sub.views) return undefined;\n const { route } = config;\n const childUri = `${baseUrl}/${route}/{parent.id}/${sub.childRoute}`;\n\n return {\n id: `${route}/${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 ...(sub.display && { display: sub.display }),\n operations: buildSubResourceOperations(\n sub.operations,\n childUri,\n sub.idField ?? 'id',\n ),\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 actions: resolveActions(`${baseUrl}/${sub.childRoute}`, sub.actions),\n };\n};\n\n/**\n * A rendering-context's field config as exposed to the visual builder: the\n * resolved value (walking the `fieldInput → fieldView → fieldTable` fallback\n * chain, via crouton-core's `resolveViewField`/`resolveTableField` — so the\n * editor shows what will actually render) plus whether this column has its\n * own override at this level. `hasOverride: false` means the value shown is\n * pure inheritance from the level below; saving with no changes here should\n * leave it that way rather than pinning a copy into `fieldView`/`fieldTable`.\n */\nexport type EditableFieldVariant = {\n resolved: FieldInput | undefined;\n hasOverride: boolean;\n};\n\nexport type EditableColumn = {\n id: string;\n label?: string;\n column: string;\n hiddenInTable: boolean;\n hiddenInForm: boolean;\n hiddenInView: boolean;\n /** The base level — always \"owned\" by this column, no fallback/override distinction. */\n form: FieldInput | undefined;\n view: EditableFieldVariant;\n table: EditableFieldVariant;\n};\n\n/**\n * Build the payload for `GET /resource-columns` — the raw, editable column\n * list backing the visual resource builder (dev-mode only). Unlike\n * `buildResourceJsonPayload`/`buildViewsPayload`, which expose columns only\n * as compiled JSON Schema + JSONForms UI Schema, this returns the plain\n * per-column attributes the editor lets a developer change directly, split\n * per rendering context (form/view/table) so the editor can offer a tab per\n * context instead of one flat fieldInput-only row.\n *\n * `config.columns` is typed as the pre-normalization map form on `Resource`\n * (inherited from `ResourceJsonShape`), but at runtime it always holds the\n * post-`ResourceJsonSchema`-transform array form (`JsonColumn[]`) — the same\n * assumption other adapter code in this package already relies on.\n */\nexport const buildEditableColumnsPayload = (\n config: Resource,\n): {\n id: string;\n route: string;\n columns: EditableColumn[];\n} => {\n const columns = (config.columns as unknown as JsonColumn[] | undefined) ?? [];\n\n return {\n id: config.name,\n route: config.route,\n columns: columns.map((c) => ({\n id: c.id,\n label: c.label,\n column: c.column ?? c.id,\n hiddenInTable: c.hiddenInTable,\n hiddenInForm: c.hiddenInForm,\n hiddenInView: c.hiddenInView,\n form: c.fieldInput,\n view: { resolved: resolveViewField(c), hasOverride: c.fieldView != null },\n table: {\n resolved: resolveTableField(c),\n hasOverride: c.fieldTable != null,\n },\n })),\n };\n};\n","import { Get, SetMetadata } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport {\n buildSubResourceViewsPayload,\n buildViewsPayload,\n} from './payload-builders';\nimport { IS_DEV } from '../dev-mode';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { CROUTON_SECURITY } from '../security';\nimport { getRequestLanguage } from '../translation/language.context';\n\nexport const defaultSchemas = (ctx: OperationContext) => {\n const { config, baseUrl, schemaEnricher } = ctx;\n const { route, name } = config;\n const viewsPayload = buildViewsPayload(config, baseUrl);\n\n return {\n route: 'schemas',\n methodName: 'getSchemas',\n name,\n schemasFn: async function (this: {\n configRegistry: ResourceConfigRegistry;\n }) {\n const language = getRequestLanguage();\n let payload = viewsPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildViewsPayload(fresh, baseUrl) ?? viewsPayload;\n }\n if (!payload || !schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n decorators: () => {\n //\n },\n };\n};\n\nconst childSchemas = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!sub.views) return null;\n const { config, baseUrl } = ctx;\n const { route } = config;\n const schemasPayload = buildSubResourceViewsPayload(config, sub, baseUrl);\n\n return {\n route: `${sub.childRoute}/schemas`,\n methodName: `getSchemas_${sub.childRoute}`,\n name: sub.childRoute,\n schemasFn: async function (this: {\n configRegistry: ResourceConfigRegistry;\n }) {\n const language = getRequestLanguage();\n if (IS_DEV || language) {\n const localizedParent = await this.configRegistry.getByRoute(route, language);\n if (localizedParent) {\n const localizedSub = (localizedParent.subResources ?? []).find(\n (s) => s.childRoute === sub.childRoute,\n );\n if (localizedSub) {\n return buildSubResourceViewsPayload(localizedParent, localizedSub, baseUrl) ?? schemasPayload;\n }\n }\n }\n return schemasPayload;\n },\n decorators: () => {\n //\n },\n };\n};\n\n/** Register `GET /schemas`. */\nexport const registerSchemas = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childSchemas(sub) : defaultSchemas;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.schemasFn);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Get view schemas for ${name}` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiResponse({ status: 200, description: `View schemas for ${name}` })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n\n // Schema endpoints follow resource-level global security.\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\n};\n","import { Body, Param, Put, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultUpdate = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'update')) return null;\n if (isOperationExternal(ctx.definition, 'update')) return null;\n const { cls, config, updateSchema, bodyDecorator } = ctx;\n const methodName = 'update';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n updateFn: function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.update(id, body, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n bodyDecorator(updateSchema)(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n },\n };\n};\n\nconst childUpdate = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'update')) return null;\n const { cls } = ctx;\n const methodName = `updateChild_${sub.childRoute}`;\n\n const updateFn = async function (\n this: { repo: CrudRepository },\n _id: string,\n childId: string,\n body: any,\n req: any,\n ) {\n return this.repo.updateChild(sub, childId, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Body()(cls.prototype, methodName, 2);\n Req()(cls.prototype, methodName, 3);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n updateFn,\n decorators,\n };\n};\n\n/** Register `PUT /:id`. No-ops when `update` is disabled. */\nexport const registerUpdate = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childUpdate(sub) : defaultUpdate;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.updateFn);\n const d = desc(cls, methodName);\n Put(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Replace a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${name} replaced` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'update', sub);\n};\n","import { type OperationContext } from './operation-context';\nimport {\n registerActionRoutes,\n registerTableActionRoutes,\n} from './register-actions';\nimport { registerCreate } from './register-create';\nimport { registerDelete } from './register-delete';\nimport { registerFindAll } from './register-findall';\nimport { registerFindOne } from './register-findone';\nimport { registerPatch } from './register-patch';\nimport {\n registerDefinitionEndpoint,\n registerResourceColumnsEndpoint,\n registerResourceJsonEndpoint,\n registerResourceJsonPatchEndpoint,\n registerResourceJsonRawGetEndpoint,\n registerResourceJsonRawPutEndpoint,\n} from './register-schema-endpoints';\nimport { registerSchemas } from './register-schemas';\nimport { registerUpdate } from './register-update';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nexport const registerEndpoints = (ctx: OperationContext): void => {\n // ── Register operations (order matters: static routes before :id routes) ──\n //first register subresource routes\n registerSubResourceRoutes(ctx);\n //register other routes\n registerFindAll(ctx);\n\n registerResourceJsonRawGetEndpoint(ctx);\n registerResourceJsonRawPutEndpoint(ctx);\n registerResourceJsonPatchEndpoint(ctx);\n registerResourceJsonEndpoint(ctx);\n registerResourceColumnsEndpoint(ctx);\n\n registerDefinitionEndpoint(ctx);\n registerEndpoint(ctx);\n\n registerActionRoutes(ctx);\n registerTableActionRoutes(ctx);\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 registerEndpoint(ctx, sub);\n }\n};\n\nexport const registerEndpoint = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n registerSchemas(ctx, sub);\n registerFindAll(ctx, sub);\n registerFindOne(ctx, sub);\n registerCreate(ctx, sub);\n registerUpdate(ctx, sub);\n registerPatch(ctx, sub);\n registerDelete(ctx, sub);\n};\n","import {\n BadRequestException,\n Body,\n Controller,\n ForbiddenException,\n Get,\n NotFoundException,\n Param,\n Patch,\n Post,\n} from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport {\n type ApplyContext,\n type DbModel,\n type LoadedConfig,\n apply as applyDiff,\n buildResourceDiff,\n buildResourceDiffs,\n commit,\n introspect,\n isGitDirty,\n listResourceNames,\n loadConfig,\n loadDatasources,\n makeRelationResolver,\n makeSchemaExportName,\n pullAndGenerate,\n readExistingResource,\n recommendedResolver,\n resolve as resolveDiff,\n resolveDatasource,\n resolveFromRoot,\n resolveRuleset,\n} from '@ghentcdh/crouton-codegen';\nimport { type DataSource } from '@ghentcdh/crouton-core';\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { DataSourceRegistry } from '../data-source';\nimport { IS_DEV } from '../dev-mode';\nimport {\n type ResourceFlagPatch,\n applyResourceFlagPatch,\n resolveResourcePath,\n} from '../resource/ResourceFlags';\nimport {\n readRawResourceJson,\n validateResourceJson,\n writeRawResourceJson,\n} from '../resource/WriteResourceJson';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ResourceConfigRegistry } from '../resource-config.registry';\n\n/**\n * Dev-only endpoints that reuse the `@ghentcdh/crouton-codegen` engine\n * (already built for the `crouton update resources` CLI command) directly\n * from a running backend request, so the visual resource builder can\n * generate a resource.json for a new DB table, or preview/apply a full\n * database sync, without shelling out to the CLI.\n *\n * Hard-gated to `IS_DEV` (`CROUTON_SCHEMA_EDITOR` env var) both at the\n * controller-registration level (see `crouton-api.module.ts`) and again on\n * every handler here, mirroring the pattern used by the schema editor's\n * PATCH/GET endpoints in `register-schema-endpoints.ts`.\n *\n * `pull` and `restart` (below) are the two handlers that go beyond reading\n * files: `pull` touches the live database and the Prisma schema file (needs\n * real DB credentials, mutates `schema.prisma` in place, backed up first,\n * mirroring the CLI); `restart` exits this very process. Every other handler\n * here only reads the Prisma client/Zod types already generated on disk.\n *\n * Note that `pull` regenerating the Prisma client on disk does not affect\n * *this* running process — `DataSourceRegistry` holds a client instance\n * built once at boot, so brand-new models exist in `schema.prisma` (and thus\n * in `GET models`) before they're actually usable here. See\n * `isAvailableOnClient` below; the backend needs an actual restart before a\n * newly pulled model can be generated/synced without throwing.\n */\n@Controller('_app/resources')\n@ApiTags('Dev tools')\nexport class DevResourcesController {\n constructor(\n private readonly dataSourceRegistry: DataSourceRegistry,\n private readonly resourceConfigRegistry: ResourceConfigRegistry,\n ) {}\n\n private assertDev(): void {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.',\n );\n }\n }\n\n /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */\n private async loadProject(\n datasourceName?: string,\n ): Promise<{ loaded: LoadedConfig; ds: DataSource; schemaPath: string }> {\n let loaded: LoadedConfig;\n try {\n loaded = await loadConfig(process.cwd());\n } catch (e) {\n throw new NotFoundException(\n (e as Error).message ?? 'No crouton.json config found.',\n );\n }\n\n const datasources = await loadDatasources(loaded);\n let ds: DataSource;\n try {\n ds = resolveDatasource(datasources, datasourceName);\n } catch (e) {\n throw new BadRequestException((e as Error).message);\n }\n\n const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);\n return { loaded, ds, schemaPath };\n }\n\n private async introspectModels(schemaPath: string): Promise<DbModel[]> {\n try {\n return await introspect({ schemaPath });\n } catch (e) {\n throw new BadRequestException(\n `Failed to read Prisma schema at ${schemaPath}: ${(e as Error).message}`,\n );\n }\n }\n\n private buildApplyContext(\n loaded: LoadedConfig,\n ds: DataSource,\n ): ApplyContext {\n return {\n resourcesDir: resolveFromRoot(loaded.root, loaded.config.resourcesDir),\n generatedTypesImport: ds.generatedTypesImport,\n schemaExportName: makeSchemaExportName(loaded.config),\n };\n }\n\n /**\n * True when `clientAccessor` exists on the *currently running* Prisma\n * client for this datasource. `DataSourceRegistry` holds a client instance\n * built once at process boot (see `data-source.registry.ts`); `prisma\n * generate` rewrites the generated client code on disk, but can't change\n * the shape of an already-instantiated object in a running Node process.\n * A model added by `pull` therefore exists in `schema.prisma` (and shows up\n * here via `introspect`, which reads that file directly) before it exists\n * on this live client — using it before a restart throws \"Model ... not\n * found on the provided PrismaClient\" from `createCrudRepository`.\n */\n private isAvailableOnClient(ds: DataSource, clientAccessor: string): boolean {\n try {\n const client = this.dataSourceRegistry.resolve(ds.name);\n return typeof client?.[clientAccessor] !== 'undefined';\n } catch {\n return false;\n }\n }\n\n @Get('models')\n @ApiOperation({\n summary:\n 'Dev-only: list DB models from the Prisma schema, flagging which already have a resource.json and whether the running backend can actually use them yet',\n })\n @ApiResponse({\n status: 200,\n description: 'DB models and their resource/client status',\n })\n async listModels(): Promise<{\n models: {\n prismaName: string;\n clientAccessor: string;\n hasResource: boolean;\n availableOnClient: boolean;\n }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject();\n const models = await this.introspectModels(schemaPath);\n const existing = new Set(await listResourceNames(loaded));\n\n return {\n models: models.map((m) => ({\n prismaName: m.prismaName,\n clientAccessor: m.clientAccessor,\n hasResource: existing.has(m.clientAccessor),\n availableOnClient: this.isAvailableOnClient(ds, m.clientAccessor),\n })),\n };\n }\n\n @Post('restart')\n @ApiOperation({\n summary:\n 'Dev-only: exit this process so a dev watcher/process manager (nodemon, `nest start --watch`, pm2, a Docker restart policy, ...) restarts it with a fresh Prisma client. Does nothing useful if this process isn\\'t supervised by one of those.',\n })\n @ApiResponse({\n status: 200,\n description: 'Restart scheduled — the connection will drop shortly after',\n })\n restart(): { restarting: true } {\n this.assertDev();\n // Give Nest/Express time to flush this response over the socket before\n // the process disappears — the frontend needs to see `{ restarting:\n // true }` to know the exit was intentional, not a crash mid-request.\n // A non-zero exit code is used deliberately: pm2, Docker restart\n // policies, and most \"restart on crash\" nodemon configs treat that as\n // \"needs a restart\" more reliably than a clean (0) exit, which several\n // tools instead read as \"stopped on purpose, leave it stopped\".\n setTimeout(() => {\n this.dataSourceRegistry\n .disconnectAll()\n .catch(() => undefined)\n .finally(() => process.exit(1));\n }, 250);\n return { restarting: true };\n }\n\n @Post('pull')\n @ApiOperation({\n summary:\n 'Dev-only: run `prisma db pull` + case-format + `prisma generate` for a datasource, refreshing schema.prisma and the generated Prisma client/Zod types from the live database',\n })\n @ApiResponse({\n status: 200,\n description:\n 'Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes',\n })\n async pull(\n @Body() body: { datasource?: string; confirm?: boolean } = {},\n ): Promise<{\n requiresConfirmation?: boolean;\n dirtyFile?: string;\n ok?: boolean;\n /**\n * Always true on success: this process's Prisma client was built at boot\n * and can't pick up model changes from a fresh `prisma generate` without\n * restarting — see `isAvailableOnClient` above.\n */\n restartRequired?: boolean;\n backupPath?: string;\n dbPull?: { ok: boolean; output: string };\n caseFormat?: { ok: boolean; output: string };\n normalizeSchema?: { ok: boolean; renamed: number };\n generate?: { ok: boolean; output: string };\n zodImportsFixed?: number;\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const prismaConfigPath = resolveFromRoot(loaded.root, ds.prismaConfig);\n\n // `db pull` overwrites schema.prisma — same uncommitted-changes guard the\n // CLI shows as an interactive confirm, surfaced here as a flag so the\n // frontend can show its own confirmation before retrying with confirm: true.\n if (!body.confirm && (await isGitDirty(loaded.root, schemaPath))) {\n return { requiresConfirmation: true, dirtyFile: ds.prismaSchema };\n }\n\n const zodDir = ds.zodOutput ? resolveFromRoot(loaded.root, ds.zodOutput) : undefined;\n const result = await pullAndGenerate({\n root: loaded.root,\n prismaConfigPath,\n schemaPath,\n zodOutputDir: zodDir,\n });\n\n if (!result.ok) {\n throw new BadRequestException(`prisma db pull failed:\\n${result.dbPull.output}`);\n }\n\n return {\n ok: true,\n restartRequired: true,\n backupPath: result.backupPath,\n dbPull: result.dbPull,\n caseFormat: result.caseFormat,\n normalizeSchema: result.normalizeSchema,\n generate: result.generate,\n zodImportsFixed: result.zodImportsFixed,\n };\n }\n\n @Post('sync')\n @ApiOperation({\n summary:\n 'Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)',\n })\n @ApiResponse({ status: 200, description: 'Files written for this resource' })\n async sync(@Body() body: { model: string; datasource?: string }): Promise<{\n resource: string;\n isNew: boolean;\n written: string[];\n skipped: string[];\n }> {\n this.assertDev();\n if (!body?.model) {\n throw new BadRequestException('\"model\" is required.');\n }\n\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const models = await this.introspectModels(schemaPath);\n const model = models.find(\n (m) => m.prismaName === body.model || m.clientAccessor === body.model,\n );\n if (!model) {\n throw new NotFoundException(\n `Model \"${body.model}\" not found in ${schemaPath}.`,\n );\n }\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diff = await buildResourceDiff(model, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const resolved = await resolveDiff(diff, recommendedResolver);\n const plan = applyDiff(resolved, this.buildApplyContext(loaded, ds));\n const result = await commit(plan);\n\n return { resource: diff.name, isNew: diff.isNew, ...result };\n }\n\n @Post('plan')\n @ApiOperation({\n summary:\n 'Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults — computes what would change, writes nothing',\n })\n @ApiResponse({ status: 200, description: 'Proposed per-resource changes' })\n async plan(\n @Body() body: { models?: string[]; datasource?: string } = {},\n ): Promise<{\n resources: {\n resource: string;\n model: string;\n isNew: boolean;\n decisions: unknown[];\n files: { path: string; action: string }[];\n notes: string[];\n }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const allModels = await this.introspectModels(schemaPath);\n const models = body.models?.length\n ? allModels.filter(\n (m) =>\n body.models!.includes(m.prismaName) ||\n body.models!.includes(m.clientAccessor),\n )\n : allModels;\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diffs = await buildResourceDiffs(models, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const applyCtx = this.buildApplyContext(loaded, ds);\n\n const resources: {\n resource: string;\n model: string;\n isNew: boolean;\n decisions: unknown[];\n files: { path: string; action: string }[];\n notes: string[];\n }[] = [];\n\n for (const diff of diffs) {\n const resolved = await resolveDiff(diff, recommendedResolver);\n const writePlan = applyDiff(resolved, applyCtx);\n // No-op diffs (nothing to write, nothing to warn about) are omitted —\n // re-running against an unchanged DB schema should show an empty list.\n if (writePlan.files.length === 0 && writePlan.notes.length === 0)\n continue;\n\n resources.push({\n resource: diff.name,\n model: diff.model,\n isNew: diff.isNew,\n decisions: diff.decisions,\n files: writePlan.files.map((f) => ({ path: f.path, action: f.action })),\n notes: writePlan.notes,\n });\n }\n\n return { resources };\n }\n\n @Post('apply')\n @ApiOperation({\n summary:\n 'Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults',\n })\n @ApiResponse({ status: 200, description: 'Per-resource commit results' })\n async apply(\n @Body() body: { resources?: string[]; datasource?: string } = {},\n ): Promise<{\n results: { resource: string; written: string[]; skipped: string[] }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const allModels = await this.introspectModels(schemaPath);\n // `resources` filters by resource/directory name (== clientAccessor for\n // new resources) — matches what /plan returns as `resource`.\n const models = body.resources?.length\n ? allModels.filter((m) => body.resources!.includes(m.clientAccessor))\n : allModels;\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diffs = await buildResourceDiffs(models, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const applyCtx = this.buildApplyContext(loaded, ds);\n\n const results: {\n resource: string;\n written: string[];\n skipped: string[];\n }[] = [];\n for (const diff of diffs) {\n const resolved = await resolveDiff(diff, recommendedResolver);\n const writePlan = applyDiff(resolved, applyCtx);\n if (writePlan.files.length === 0) continue;\n const result = await commit(writePlan);\n results.push({ resource: diff.name, ...result });\n }\n\n return { results };\n }\n\n // ─── Visibility & flag endpoints ────────────────────────────────────\n\n @Get('visibility')\n @ApiOperation({\n summary:\n 'Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)',\n })\n @ApiResponse({ status: 200, description: 'Resource visibility list' })\n async visibility(): Promise<{\n resources: {\n name: string;\n path: string;\n state: 'in-menu' | 'hidden' | 'draft' | 'error';\n group?: string;\n position?: number;\n editable: boolean;\n }[];\n }> {\n this.assertDev();\n\n const loaded = await this.resourceConfigRegistry.getAll();\n const fromLoaded = loaded.map((c) => ({\n name: c.name,\n path: c.route,\n state: (c.sidebar?.hide ? 'hidden' : 'in-menu') as\n | 'in-menu'\n | 'hidden',\n group: c.sidebar?.group,\n position: c.sidebar?.position,\n editable: true,\n }));\n\n const drafts = resourceLoadReportRegistry.getByState('draft').map((d) => ({\n name: d.name,\n path: d.path,\n state: 'draft' as const,\n group: undefined,\n position: undefined,\n editable: !d.path.endsWith('.ts'),\n }));\n\n const errors = resourceLoadErrorsRegistry.getAll().map((e) => ({\n name: e.name,\n path: e.path,\n state: 'error' as const,\n group: undefined,\n position: undefined,\n editable: !e.path.endsWith('.ts'),\n }));\n\n return { resources: [...fromLoaded, ...drafts, ...errors] };\n }\n\n @Post(':name/publish')\n @ApiOperation({\n summary:\n 'Dev-only: publish a draft resource (removes `draft: true` from resource.json)',\n })\n @ApiResponse({ status: 200, description: 'Resource published' })\n async publish(@Param('name') name: string): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, { draft: false });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Post(':name/remove-from-menu')\n @ApiOperation({\n summary:\n 'Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)',\n })\n @ApiResponse({ status: 200, description: 'Resource removed from menu' })\n async removeFromMenu(@Param('name') name: string): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, {\n sidebar: { hide: true },\n });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Post(':name/add-to-menu')\n @ApiOperation({\n summary:\n 'Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label',\n })\n @ApiResponse({ status: 200, description: 'Resource added to menu' })\n async addToMenu(\n @Param('name') name: string,\n @Body() body: { group?: string; position?: number; label?: string } = {},\n ): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const sidebarPatch: ResourceFlagPatch['sidebar'] = { hide: false };\n if (body.group !== undefined) sidebarPatch!.group = body.group;\n if (body.position !== undefined) sidebarPatch!.position = body.position;\n if (body.label !== undefined) sidebarPatch!.label = body.label;\n\n const patched = applyResourceFlagPatch(raw, {\n draft: false,\n sidebar: sidebarPatch,\n });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Patch(':name/flags')\n @ApiOperation({\n summary:\n 'Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)',\n })\n @ApiResponse({ status: 200, description: 'Flags updated' })\n async updateFlags(\n @Param('name') name: string,\n @Body() body: ResourceFlagPatch,\n ): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, body);\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n}\n","import { labelFromId } from '@ghentcdh/crouton-core';\n\nexport { labelFromId };\n\n/**\n * PrismaClient accessor for a model name.\n * `Language` → `language`, `InternalAuthor` → `internalAuthor`,\n * `metadata_config` → `metadata_config` (first char already lower-case).\n */\nexport const clientAccessor = (prismaModelName: string): string => {\n if (!prismaModelName) return prismaModelName;\n return prismaModelName.charAt(0).toLowerCase() + prismaModelName.slice(1);\n};\n\nexport interface ResourceNames {\n /** Directory + route + resource `name`. */\n name: string;\n route: string;\n /** resource.json `model` (PrismaClient accessor). */\n model: string;\n tag: string;\n title: string;\n}\n\n/**\n * Derive the resource identity fields from a Prisma model name.\n * Mirrors the `new_polities` convention: `name`/`route`/`model` are the client\n * accessor; `tag` is the Prisma model name; `title` is a humanized label.\n */\nexport const resourceNames = (prismaModelName: string): ResourceNames => {\n const accessor = clientAccessor(prismaModelName);\n return {\n name: accessor,\n route: accessor,\n model: accessor,\n tag: prismaModelName,\n title: labelFromId(accessor),\n };\n};\n\nconst TIMESTAMP_NAME =\n /^(created|updated|inserted|modified|deleted)_?at$|^(created|updated)$/i;\n\n/** Heuristic: is this field a created/updated style timestamp? */\nexport const isTimestampField = (opts: {\n name: string;\n type: string;\n isUpdatedAt: boolean;\n}): boolean => {\n if (opts.type !== 'DateTime') return false;\n if (opts.isUpdatedAt) return true;\n return TIMESTAMP_NAME.test(opts.name);\n};\n\n/** Map a Prisma scalar/enum type to a `fieldInput.type` control hint. */\nexport const fieldInputType = (prismaType: string, isEnum: boolean): string => {\n if (isEnum) return 'select';\n switch (prismaType) {\n case 'Boolean':\n return 'boolean';\n case 'Int':\n case 'BigInt':\n case 'Float':\n case 'Decimal':\n return 'number';\n case 'DateTime':\n return 'date';\n case 'Json':\n return 'json';\n case 'String':\n default:\n return 'string';\n }\n};\n\n/**\n * Control type for a scalar column, taking the field name into account.\n * `description`-style string fields default to a `textarea`.\n */\nexport const scalarFieldInputType = (\n name: string,\n prismaType: string,\n): string => {\n if (prismaType === 'String' && /description/i.test(name)) return 'textarea';\n return fieldInputType(prismaType, false);\n};\n\n/** Infer the resource `idType` from the primary-key Prisma type. */\nexport const idTypeFor = (\n prismaType: string | undefined,\n): 'string' | 'number' => {\n if (prismaType === 'Int' || prismaType === 'BigInt') return 'number';\n return 'string';\n};\n","/**\n * introspect: Prisma schema → normalized `DbModel[]`.\n *\n * The pure normalizer `dmmfToDbModels` is separated from the Prisma call so it\n * can be unit-tested with a hand-built DMMF and so a Prisma version bump only\n * touches `loadDmmf`.\n */\n\nimport type { RelationType } from '@ghentcdh/crouton-core';\n\nimport type { DbField, DbFieldKind, DbModel } from './db-model';\nimport { idTypeFor, isTimestampField } from './naming';\n\n// ─── Minimal DMMF shapes (only what we consume) ──────────────────────────────\n\nexport interface DmmfField {\n name: string;\n kind: 'scalar' | 'object' | 'enum' | 'unsupported';\n type: string;\n isList: boolean;\n isRequired: boolean;\n isId: boolean;\n isUnique: boolean;\n isUpdatedAt: boolean;\n hasDefaultValue: boolean;\n /**\n * Raw Prisma DMMF default: a literal (string/number/boolean/array) for\n * `@default(\"x\")` / `@default(0)` / `@default(true)` / `@default([...])`,\n * or a `{ name, args }` descriptor for a function call like `autoincrement()`,\n * `now()`, `uuid()`, `cuid()`, or `dbgenerated(...)`. Only present when\n * `hasDefaultValue` is true.\n */\n default?: unknown;\n relationName?: string;\n relationFromFields?: string[];\n relationToFields?: string[];\n}\n\nexport interface DmmfModel {\n name: string;\n dbName?: string | null;\n primaryKey?: { name?: string | null; fields: string[] } | null;\n fields: DmmfField[];\n}\n\nexport interface DmmfEnum {\n name: string;\n values: { name: string }[];\n}\n\nexport interface DmmfDatamodel {\n models: DmmfModel[];\n enums: DmmfEnum[];\n}\n\nexport interface Dmmf {\n datamodel: DmmfDatamodel;\n}\n\n// ─── relation cardinality ────────────────────────────────────────────────────\n\ninterface RelationSide {\n model: string;\n isList: boolean;\n}\n\n/** Index relation fields by `relationName` so each side can see its counterpart. */\nconst indexRelations = (models: DmmfModel[]): Map<string, RelationSide[]> => {\n const index = new Map<string, RelationSide[]>();\n for (const model of models) {\n for (const field of model.fields) {\n if (field.kind !== 'object' || !field.relationName) continue;\n const list = index.get(field.relationName) ?? [];\n list.push({ model: model.name, isList: field.isList });\n index.set(field.relationName, list);\n }\n }\n return index;\n};\n\nconst resolveRelationType = (\n field: DmmfField,\n index: Map<string, RelationSide[]>,\n): RelationType => {\n const sides = field.relationName ? index.get(field.relationName) ?? [] : [];\n // Counterpart = the side declared on the related model (`field.type`).\n // (For self-relations both sides share a model; fall back to any other side.)\n const counterpart =\n sides.find((s) => s.model === field.type) ?? sides.find((s) => s.isList !== field.isList);\n const otherIsList = counterpart?.isList ?? false;\n if (field.isList) return otherIsList ? 'manyToMany' : 'oneToMany';\n return otherIsList ? 'manyToOne' : 'oneToOne';\n};\n\n// ─── default value normalization ─────────────────────────────────────────────\n\n/**\n * A Prisma DMMF default is either a literal (representable as-is) or a\n * `{ name, args }` function-call descriptor (`autoincrement()`, `now()`,\n * `uuid()`, `cuid()`, `dbgenerated(...)`, `sequence(...)`, ...). Only literals\n * make sense to echo back into `fieldInput.defaultValue` — a function call has\n * no fixed value to pre-fill a create form with, and is usually DB/server\n * generated anyway (ids, timestamps).\n */\nconst literalDefault = (\n value: unknown,\n): string | number | boolean | (string | number | boolean)[] | undefined => {\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n if (Array.isArray(value) && value.every((v) => ['string', 'number', 'boolean'].includes(typeof v))) {\n return value as (string | number | boolean)[];\n }\n return undefined; // function-call descriptor ({ name, args }) or unrepresentable\n};\n\n// ─── normalizer ──────────────────────────────────────────────────────────────\n\n/** Pure: DMMF datamodel → normalized `DbModel[]`. */\nexport const dmmfToDbModels = (dmmf: Dmmf): DbModel[] => {\n const { models, enums } = dmmf.datamodel;\n const enumNames = new Set(enums.map((e) => e.name));\n const relationIndex = indexRelations(models);\n\n return models.map((model) => {\n // FK scalar columns = every scalar referenced by a relation's relationFromFields.\n const fkFields = new Set<string>();\n for (const f of model.fields) {\n if (f.kind === 'object' && f.relationFromFields) {\n for (const name of f.relationFromFields) fkFields.add(name);\n }\n }\n\n const idFieldDef = model.fields.find((f) => f.isId);\n const hasCompositeId = !!model.primaryKey && model.primaryKey.fields.length > 1;\n const idField = idFieldDef?.name;\n const idType = idFieldDef ? idTypeFor(idFieldDef.type) : undefined;\n\n const fields: DbField[] = model.fields.map((f) => {\n const isEnum = f.kind === 'enum' || enumNames.has(f.type);\n let kind: DbFieldKind;\n if (f.isId) kind = 'id';\n else if (f.kind === 'object') kind = 'relation';\n else if (fkFields.has(f.name)) kind = 'foreignKey';\n else if (isEnum) kind = 'enum';\n else kind = 'scalar';\n\n const field: DbField = {\n name: f.name,\n kind,\n type: f.type,\n isList: f.isList,\n isRequired: f.isRequired,\n isId: f.isId,\n isUnique: f.isUnique,\n isUpdatedAt: f.isUpdatedAt,\n hasDefault: f.hasDefaultValue,\n ...(f.hasDefaultValue && literalDefault(f.default) !== undefined\n ? { defaultValue: literalDefault(f.default) }\n : {}),\n isTimestamp:\n kind === 'scalar' &&\n isTimestampField({ name: f.name, type: f.type, isUpdatedAt: f.isUpdatedAt }),\n };\n\n if (kind === 'relation') {\n field.relationName = f.relationName;\n field.relationModel = f.type;\n field.relationFromFields = f.relationFromFields;\n field.relationToFields = f.relationToFields;\n field.relationType = resolveRelationType(f, relationIndex);\n }\n if (isEnum) {\n field.enumValues = enums.find((e) => e.name === f.type)?.values.map((v) => v.name);\n }\n return field;\n });\n\n return {\n prismaName: model.name,\n clientAccessor: model.name.charAt(0).toLowerCase() + model.name.slice(1),\n tableName: model.dbName ?? undefined,\n idField,\n idType,\n hasCompositeId,\n fields,\n };\n });\n};\n\n// ─── Prisma loader (impure, lazy) ────────────────────────────────────────────\n\nexport type DmmfLoader = (schemaPath: string) => Promise<Dmmf>;\n\ninterface PrismaInternals {\n getSchemaWithPath: (opts: {\n schemaPath: { cliProvidedPath: string };\n }) => Promise<{ schemas: [string, string][] }>;\n getDMMF: (opts: { datamodel: [string, string][] }) => Promise<Dmmf>;\n}\n\n/**\n * Default loader: lazily imports `@prisma/internals` (resolved from the consumer\n * project's Prisma install) and parses the schema file. The import specifier is\n * indirected through a variable so a TypeScript build does not require\n * `@prisma/internals` to be installed in the crouton workspace. Kept out of the\n * pure path so tests can inject a fake.\n */\nexport const loadDmmf: DmmfLoader = async (schemaPath: string) => {\n const specifier = '@prisma/internals';\n let internals: PrismaInternals;\n try {\n // `@prisma/internals` is CommonJS: under Node ESM its API lands on\n // `.default`, while bundler/TS interop may expose it directly — handle both.\n const mod = (await import(specifier)) as { default?: PrismaInternals } & PrismaInternals;\n internals = (mod.default ?? mod) as PrismaInternals;\n } catch {\n throw new Error(\n 'Could not load \\'@prisma/internals\\'. Ensure Prisma is installed in the project ' +\n '(it ships with the `prisma` CLI / `@prisma/client`).',\n );\n }\n const loaded = await internals.getSchemaWithPath({\n schemaPath: { cliProvidedPath: schemaPath },\n });\n return internals.getDMMF({ datamodel: loaded.schemas });\n};\n\nexport interface IntrospectOptions {\n schemaPath: string;\n loader?: DmmfLoader;\n}\n\n/** Read + normalize a Prisma schema into `DbModel[]`. */\nexport const introspect = async (opts: IntrospectOptions): Promise<DbModel[]> => {\n const loader = opts.loader ?? loadDmmf;\n const dmmf = await loader(opts.schemaPath);\n return dmmfToDbModels(dmmf);\n};\n","/**\n * classify: a `DbModel` + `Ruleset` → a fully generated `ResourceDraft`.\n *\n * Encodes the default visibility rules (decided with the user):\n * - primary key: hidden in table/form/view, marked `idField`\n * - created/updated timestamps: hidden in table+form, non-editable\n * - foreign-key scalars: hidden in table+form, non-editable\n * - relations: hidden in table always; unresolved (no sibling resource) hidden\n * everywhere. Resolved relations render in the form by cardinality via\n * `fieldInput.options.display`: the owning (forward) side — `manyToOne` /\n * `oneToOne`, e.g. `groupMembers.group` — as an `autocomplete` picker, and\n * the collection (reverse) side — `oneToMany` / `manyToMany`, e.g.\n * `groups.groupMembers` — as a sub-resource `table`.\n */\n\nimport { type JsonColumnInput, type ResourceJsonInput, type Ruleset, RulesetSchema } from '@ghentcdh/crouton-core';\n\nimport type { DbModel } from './db-model';\nimport type { ResourceDraft } from './draft';\nimport { resourceNames, scalarFieldInputType } from './naming';\n\nexport const defaultRuleset = (): Ruleset => RulesetSchema.parse({});\n\nexport interface ClassifyContext {\n /** Datasource name stamped on `database`. */\n database?: string;\n ruleset?: Ruleset;\n /**\n * Resolve the relative `resource` path for a relation's target model, or\n * `undefined` if no such resource exists (relation left hidden + unwired).\n */\n resolveRelationResource?: (targetModel: string) => string | undefined;\n}\n\ntype Column = Partial<Omit<JsonColumnInput, 'id'>>;\n\nexport const classify = (\n model: DbModel,\n ctx: ClassifyContext = {},\n): ResourceDraft => {\n const ruleset = ctx.ruleset ?? defaultRuleset();\n const names = resourceNames(model.prismaName);\n const columnOrder: string[] = [];\n const columns: Record<string, Column> = {};\n const unwiredRelations: { field: string; targetModel: string }[] = [];\n let position = 0;\n\n for (const field of model.fields) {\n // Relations are ignored by default — they are not real DB columns and can't\n // be ordered/filtered like scalars (a relation column in `orderBy` is a\n // Prisma validation error). Skip them entirely unless explicitly enabled.\n if (field.kind === 'relation' && !ruleset.includeRelations) continue;\n\n let col: Column;\n\n if (field.kind === 'id') {\n col = {\n idField: true,\n hiddenInTable: ruleset.hideIdInTable,\n hiddenInForm: ruleset.hideIdInForm,\n hiddenInView: ruleset.hideIdInView,\n };\n } else if (field.isTimestamp) {\n col = ruleset.hideTimestamps\n ? {\n hiddenInTable: true,\n hiddenInForm: true,\n createable: false,\n updateable: false,\n }\n : {\n fieldInput: {\n type: 'date',\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else if (field.kind === 'foreignKey') {\n col = ruleset.hideForeignKeys\n ? {\n hiddenInTable: true,\n hiddenInForm: true,\n createable: false,\n updateable: false,\n }\n : {\n fieldInput: {\n type: 'text',\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else if (field.kind === 'relation') {\n const target = ctx.resolveRelationResource?.(field.relationModel ?? '');\n // A relation renders in the form according to its cardinality:\n // - manyToOne / oneToOne (a single FK reference) → an autocomplete\n // picker on the owning (forward) side.\n // - oneToMany / manyToMany (a collection) → a sub-resource table listing\n // the related rows.\n // `options.display` drives the frontend `RelationControlRenderer`; without\n // it the control falls back to an inert \"Configure autocomplete\" state.\n // Relations are always hidden in the table (a relation column can't be\n // ordered/filtered like a scalar), but are shown in form + view.\n const isCollectionSide =\n field.relationType === 'oneToMany' || field.relationType === 'manyToMany';\n const display = isCollectionSide ? 'table' : 'autocomplete';\n if (ruleset.showRelationsInForm && target) {\n col = {\n hiddenInTable: ruleset.hideRelationsInTable,\n fieldInput: {\n format: 'relation',\n resource: target,\n relationType: field.relationType,\n options: { display },\n },\n };\n } else {\n col = { hiddenInTable: true, hiddenInForm: true, hiddenInView: true };\n unwiredRelations.push({\n field: field.name,\n targetModel: field.relationModel ?? '',\n });\n }\n } else if (field.kind === 'enum') {\n const options: Record<string, unknown> = {};\n if (ruleset.enumValueLabel) options.emitObject = true;\n if (!ruleset.sharedEnums) {\n options.values = (field.enumValues ?? []).map((v) => ({\n label: v,\n value: v,\n }));\n }\n col = {\n ...(ruleset.enumValueLabel ? { displayKey: 'label' } : {}),\n ...(ruleset.sharedEnums ? { enum: field.type } : {}),\n fieldInput: {\n type: 'select',\n position: position++,\n options,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else {\n col = {\n fieldInput: {\n type: scalarFieldInputType(field.name, field.type),\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n }\n\n columns[field.name] = col;\n columnOrder.push(field.name);\n }\n\n const config: ResourceJsonInput = {\n name: names.name,\n route: names.route,\n model: names.model,\n tag: names.tag,\n title: names.title,\n ...(model.idType ? { idType: model.idType } : {}),\n ...(ctx.database ? { database: ctx.database } : {}),\n sidebar: { hide: false },\n operations: ruleset.defaultOperations,\n columns,\n };\n\n const hasRelations = model.fields.some((f) => f.kind === 'relation');\n return {\n name: names.name,\n prismaName: model.prismaName,\n config,\n hasRelations,\n columnOrder,\n unwiredRelations,\n };\n};\n","/** Small framework-free helpers shared by the engine stages. */\n\nimport type { JsonColumnInput, ResourceJsonInput } from '@ghentcdh/crouton-core';\n\nimport { access } from 'node:fs/promises';\n\n/** Check whether a file exists (async). */\nexport const fileExists = async (p: string): Promise<boolean> => {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Deep clone that preserves object key insertion order (JSON-safe configs). */\nexport const clone = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\n/** Order-insensitive structural equality (sorts object keys before compare). */\nexport const deepEqual = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)\n return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === 'object') {\n const ao = a as Record<string, unknown>;\n const bo = b as Record<string, unknown>;\n const ak = Object.keys(ao).sort();\n const bk = Object.keys(bo).sort();\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) return false;\n return ak.every((k) => deepEqual(ao[k], bo[k]));\n }\n return false;\n};\n\n/**\n * Normalize a `columns` value (array | map | undefined) into ordered\n * `[id, columnWithoutId][]` entries. Preserves declaration order.\n */\nexport const columnEntries = (\n columns: ResourceJsonInput['columns'],\n): [string, Omit<JsonColumnInput, 'id'>][] => {\n if (!columns) return [];\n if (Array.isArray(columns)) {\n return columns.map(({ id, ...rest }) => [id, rest]);\n }\n return Object.entries(columns);\n};\n\n/** Build a `columns` map object from ordered entries (stable order). */\nexport const columnsMapFromEntries = (\n entries: [string, Omit<JsonColumnInput, 'id'>][],\n): Record<string, Omit<JsonColumnInput, 'id'>> => {\n const out: Record<string, Omit<JsonColumnInput, 'id'>> = {};\n for (const [id, col] of entries) out[id] = col;\n return out;\n};\n","/**\n * diff: reconcile a generated `ResourceDraft` against an existing resource.json.\n *\n * Produces serializable `Decision`s with recommended defaults:\n * - new resource → `addToSidebar` (recommended yes)\n * - DB field not in config → `addColumn` (recommended add)\n * - config field not in DB → `removeColumn` (recommended keep — never auto-delete)\n * - field in both, changed → `reconcileColumn` (recommended keep)\n * - field in both, identical → no decision (keeps the run idempotent)\n */\n\nimport type { ResourceJsonInput } from '@ghentcdh/crouton-core';\n\nimport type { Decision, ResourceDiff } from './decision';\nimport type { ResourceDraft } from './draft';\nimport { columnEntries, deepEqual } from './util';\n\nexport interface DiffInput {\n draft: ResourceDraft;\n existing?: ResourceJsonInput | null;\n hasSchemaFile?: boolean;\n}\n\nexport const diff = ({\n draft,\n existing,\n hasSchemaFile = false,\n}: DiffInput): ResourceDiff => {\n const decisions: Decision[] = [];\n const isNew = !existing;\n\n if (isNew) {\n decisions.push({\n id: 'sidebar',\n kind: 'addToSidebar',\n recommended: 'yes',\n options: ['yes', 'no'],\n context: `New resource \"${draft.name}\"`,\n });\n } else {\n const draftMap = new Map(columnEntries(draft.config.columns));\n const existingMap = new Map(columnEntries(existing.columns));\n\n // DB-driven columns (draft order) vs existing.\n for (const id of draft.columnOrder) {\n const draftCol = draftMap.get(id);\n if (!draftCol) continue;\n if (!existingMap.has(id)) {\n decisions.push({\n id: `add:${id}`,\n kind: 'addColumn',\n field: id,\n recommended: 'add',\n options: ['add', 'skip'],\n });\n } else if (!deepEqual(draftCol, existingMap.get(id))) {\n decisions.push({\n id: `reconcile:${id}`,\n kind: 'reconcileColumn',\n field: id,\n recommended: 'keep',\n options: ['keep', 'overwrite', 'merge'],\n context: 'Differs from generated defaults',\n });\n }\n }\n\n // Existing columns no longer present in the DB schema.\n for (const [id] of existingMap) {\n if (!draftMap.has(id)) {\n decisions.push({\n id: `remove:${id}`,\n kind: 'removeColumn',\n field: id,\n recommended: 'keep',\n options: ['keep', 'remove'],\n context: 'Not found in the database schema',\n });\n }\n }\n }\n\n return {\n name: draft.name,\n // Codegen only ever drafts prisma-backed resources, so `model` is set.\n model: draft.config.model ?? draft.name,\n isNew,\n decisions,\n draft,\n existing: existing ?? undefined,\n hasSchemaFile,\n };\n};\n","/**\n * resolve: turn a `ResourceDiff` into a `ResolvedDiff` by collecting a choice\n * per decision. The engine never prompts — a `DecisionResolver` supplies the\n * choices. The CLI plugs in an interactive resolver; a backend can plug in an\n * auto-policy or request-driven resolver.\n */\n\nimport type { Decision, ResolvedDiff, ResourceDiff } from './decision';\n\nexport interface DecisionResolver {\n /**\n * Resolve the given decisions to `{ decisionId → choice }`. Implementations\n * must return a choice for every decision (fall back to `decision.recommended`).\n */\n resolve(\n decisions: Decision[],\n diff: ResourceDiff,\n ): Promise<Record<string, string>> | Record<string, string>;\n}\n\n/** Non-interactive resolver: always picks each decision's recommended choice. */\nexport const recommendedResolver: DecisionResolver = {\n resolve(decisions) {\n const out: Record<string, string> = {};\n for (const d of decisions) out[d.id] = d.recommended;\n return out;\n },\n};\n\nexport const resolve = async (\n diff: ResourceDiff,\n resolver: DecisionResolver = recommendedResolver,\n): Promise<ResolvedDiff> => {\n const raw = await resolver.resolve(diff.decisions, diff);\n const resolutions = new Map<string, string>();\n for (const d of diff.decisions) {\n resolutions.set(d.id, raw[d.id] ?? d.recommended);\n }\n return { diff, resolutions };\n};\n","/**\n * serialize: deterministic text for the generated files.\n *\n * resource.json is emitted as 2-space JSON relying on object key insertion\n * order (the engine builds objects in a stable order and preserves existing\n * order when updating), so re-runs produce minimal git diffs and are idempotent.\n */\n\nimport { CURRENT_RESOURCE_VERSION, type ResourceJsonInput } from '@ghentcdh/crouton-core';\n\n/** Canonical, versioned JSON Schema URL — matches the path published by the docs site. */\nexport const RESOURCE_SCHEMA_URL = `https://ghentcdh.github.io/crouton/schema/v${CURRENT_RESOURCE_VERSION}/resource.schema.json`;\n\n/**\n * Prepend `$schema` / `schemaVersion` (and, when set, `draft` / `kind`) so every generated\n * `resource.json` validates + autocompletes in editors and is born at the current version.\n *\n * `$schema` and `schemaVersion` are always (re)stamped to current — any existing values are\n * dropped and re-added at the front for a stable, diff-friendly key order. `draft` is set from\n * `opts.draft` when provided (new-resource default), otherwise the config's existing `draft`\n * value is preserved (so an update never flips it). `kind` is preserved as-is and hoisted to a\n * fixed position; it is never inferred or removed, so an update cannot turn a custom resource\n * back into a prisma one.\n */\nexport const withResourceHeader = (\n config: ResourceJsonInput,\n opts: { draft?: boolean } = {},\n): Record<string, unknown> => {\n const {\n $schema: _schema,\n schemaVersion: _version,\n draft: existingDraft,\n kind: existingKind,\n ...rest\n } = config as Record<string, unknown>;\n const draft = opts.draft !== undefined ? opts.draft : (existingDraft as boolean | undefined);\n\n return {\n $schema: RESOURCE_SCHEMA_URL,\n schemaVersion: CURRENT_RESOURCE_VERSION,\n ...(draft !== undefined ? { draft } : {}),\n ...(existingKind !== undefined ? { kind: existingKind } : {}),\n ...rest,\n };\n};\n\nexport const serializeResourceJson = (\n config: ResourceJsonInput | Record<string, unknown>,\n): string => `${JSON.stringify(config, null, 2)}\\n`;\n\n/**\n * Content for a resource's `schema.ts` — a default re-export of the model's\n * generated Zod schema. `exportName` / `importPath` come from project config.\n */\nexport const serializeSchemaTs = (\n exportName: string,\n importPath: string,\n): string =>\n `import { ${exportName} } from '${importPath}';\\n\\nexport default ${exportName};\\n`;\n","/**\n * apply: a `ResolvedDiff` → a `WritePlan` (full file contents, no disk I/O).\n *\n * Merges resolved decisions into the existing config, preserving every key the\n * tool didn't touch (actions, calculatedColumns, include, custom fieldInput,\n * sub-resources, …). `commit` performs the actual writes.\n */\n\nimport type { JsonColumnInput } from '@ghentcdh/crouton-core';\n\nimport type { ResolvedDiff } from './decision';\nimport {\n serializeResourceJson,\n serializeSchemaTs,\n withResourceHeader,\n} from './serialize';\nimport { clone, columnEntries, columnsMapFromEntries, deepEqual } from './util';\nimport type { WritePlan } from './write-plan';\n\nconst joinPath = (...parts: string[]): string =>\n parts.join('/').replace(/\\/+/g, '/');\n\nexport interface ApplyContext {\n /** Where resource directories live (e.g. `apps/backend/src/app/resources`). */\n resourcesDir: string;\n /** Import path for the generated Zod types (e.g. `@new-polities/generated/types`). */\n generatedTypesImport: string;\n /** Export name for a model's Zod schema. Default `<PrismaName>WithRelationsSchema`. */\n schemaExportName?: (prismaName: string) => string;\n /**\n * Whether a newly-scaffolded resource is written with `draft: true` (so it isn't served\n * until reviewed). Falls back to `true` when the caller omits it — used by the dev-tools\n * \"create resource\" endpoint, which has no CLI-style flag/prompt of its own. The `crouton\n * update resources` CLI always resolves and passes an explicit value (default `false`,\n * see `resolveDraftOption` in `crouton-cli/src/update/runner.ts`).\n */\n draft?: boolean;\n}\n\ntype Column = Omit<JsonColumnInput, 'id'>;\n\nexport const apply = (resolved: ResolvedDiff, ctx: ApplyContext): WritePlan => {\n const { diff, resolutions } = resolved;\n const exportNameFor = ctx.schemaExportName ?? ((p: string) => `${p}WithRelationsSchema`);\n const dir = joinPath(ctx.resourcesDir, diff.name);\n const notes = diff.draft.unwiredRelations.map(\n (r) => `Relation \"${r.field}\" → model \"${r.targetModel}\": target resource not found; left hidden.`,\n );\n const files: WritePlan['files'] = [];\n\n if (diff.isNew) {\n const config = clone(diff.draft.config);\n const addToSidebar = (resolutions.get('sidebar') ?? 'yes') !== 'no';\n config.sidebar = { hide: !addToSidebar };\n const draft = ctx.draft ?? true; // new resources are drafts unless --no-draft\n files.push({\n path: joinPath(dir, 'resource.json'),\n contents: serializeResourceJson(withResourceHeader(config, { draft })),\n action: 'create',\n });\n } else {\n const existing = clone(diff.existing!);\n const draftMap = new Map<string, Column>(columnEntries(diff.draft.config.columns));\n const entries = columnEntries(existing.columns);\n const indexOf = (id: string) => entries.findIndex(([eid]) => eid === id);\n\n for (const decision of diff.decisions) {\n const choice = resolutions.get(decision.id) ?? decision.recommended;\n const field = decision.field;\n if (!field) continue;\n\n if (decision.kind === 'addColumn' && choice === 'add') {\n const col = draftMap.get(field);\n if (col && indexOf(field) === -1) entries.push([field, col]);\n } else if (decision.kind === 'reconcileColumn') {\n const i = indexOf(field);\n if (i === -1) continue;\n if (choice === 'overwrite') {\n const col = draftMap.get(field);\n if (col) entries[i] = [field, col];\n } else if (choice === 'merge') {\n const col = draftMap.get(field);\n if (col) entries[i] = [field, { ...col, ...entries[i][1] }];\n }\n // 'keep' → leave as-is\n } else if (decision.kind === 'removeColumn' && choice === 'remove') {\n const i = indexOf(field);\n if (i !== -1) entries.splice(i, 1);\n }\n }\n\n const config = { ...existing, columns: columnsMapFromEntries(entries) };\n // Only write when something actually changed — keep \"adjusted files only\".\n // The header (re-stamped $schema/schemaVersion) is applied at serialize time only, so\n // it doesn't by itself trigger a rewrite; an existing `draft` value is preserved.\n if (!deepEqual(config, diff.existing)) {\n files.push({\n path: joinPath(dir, 'resource.json'),\n contents: serializeResourceJson(withResourceHeader(config)),\n action: 'update',\n });\n }\n }\n\n // schema.ts is created only when absent; never clobber a hand-written one.\n if (!diff.hasSchemaFile) {\n // zod-prisma-types only emits `…WithRelationsSchema` for models that have\n // relations; relation-less models only have the plain `…Schema`. Fall back\n // so the generated import always resolves to a real export.\n const exportName = diff.draft.hasRelations\n ? exportNameFor(diff.draft.prismaName)\n : `${diff.draft.prismaName}Schema`;\n files.push({\n path: joinPath(dir, 'schema.ts'),\n contents: serializeSchemaTs(exportName, ctx.generatedTypesImport),\n action: 'create',\n });\n }\n\n return { resource: diff.name, files, notes };\n};\n","/**\n * commit: the only side-effectful stage — write a `WritePlan` to disk.\n *\n * `create` actions never overwrite an existing file (so a hand-written\n * `schema.ts` is safe); `update` actions write unconditionally. `dryRun`\n * computes the result without touching disk.\n */\n\nimport { fileExists } from './util';\nimport type { WritePlan } from './write-plan';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\n\nexport interface CommitOptions {\n dryRun?: boolean;\n}\n\nexport interface CommitResult {\n written: string[];\n skipped: string[];\n}\n\nexport const commit = async (\n plan: WritePlan,\n opts: CommitOptions = {},\n): Promise<CommitResult> => {\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const file of plan.files) {\n if (file.action === 'create' && (await fileExists(file.path))) {\n skipped.push(file.path);\n continue;\n }\n if (!opts.dryRun) {\n await mkdir(dirname(file.path), { recursive: true });\n await writeFile(file.path, file.contents, 'utf-8');\n }\n written.push(file.path);\n }\n\n return { written, skipped };\n};\n","/**\n * Project configuration.\n *\n * `crouton.json` (project root) holds only project-wide settings — paths, the\n * schema export-name template, the enum registry, sidebar groups, ruleset\n * overrides. Datasources are NOT listed here: each is self-describing in its own\n * `<dataSourcesDir>/<name>/data-source.json` and discovered by scanning that\n * directory. Every datasource carries its own Prisma schema, generated zod\n * import, zod output, and Prisma config (for multi-datasource projects).\n */\n\nimport {\n CONFIG_FILES,\n type CroutonConfig,\n type DataSource,\n DataSourceSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\n\nexport interface LoadedConfig {\n config: CroutonConfig;\n /** Absolute path to `crouton.json`. */\n path: string;\n /** Absolute project root (config file directory). */\n root: string;\n}\n\n/** Walk up from `cwd` to find `crouton.json`. */\nexport const findConfigPath = async (\n cwd: string,\n): Promise<string | undefined> => {\n let dir = resolve(cwd);\n\n while (true) {\n for (const name of CONFIG_FILES) {\n const candidate = join(dir, name);\n if (await fileExists(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n};\n\n/** Load + validate `crouton.json`. Throws if none is found. */\nexport const loadConfig = async (cwd: string): Promise<LoadedConfig> => {\n const path = await findConfigPath(cwd);\n if (!path) {\n throw new Error(\n `No crouton config found (looked for ${CONFIG_FILES.join(', ')} up from ${cwd}).`,\n );\n }\n let config: CroutonConfig;\n if (path.endsWith('.json')) {\n config = JSON.parse(await readFile(path, 'utf-8')) as CroutonConfig;\n } else {\n const mod = (await import(path)) as {\n default?: CroutonConfig;\n } & CroutonConfig;\n config = mod.default ?? mod;\n }\n validateConfig(config, path);\n return { config, path, root: dirname(path) };\n};\n\nexport const validateConfig = (\n config: CroutonConfig,\n path = '<config>',\n): void => {\n if (!config.resourcesDir)\n throw new Error(`${path}: \"resourcesDir\" is required.`);\n if (!config.dataSourcesDir)\n throw new Error(`${path}: \"dataSourcesDir\" is required.`);\n};\n\n/** Default Prisma config path for a datasource: `prisma/<name>/prisma.config.ts`. */\nexport const defaultPrismaConfig = (name: string): string =>\n `prisma/${name}/prisma.config.ts`;\n\n/**\n * Discover datasources by scanning `dataSourcesDir`: each subdirectory with a\n * `data-source.json` becomes a `ResolvedDatasource`. The datasource `name`\n * defaults to the folder name; `prismaConfig` defaults to `prisma/<name>/prisma.config.ts`.\n */\nexport const loadDatasources = async (\n loaded: LoadedConfig,\n): Promise<DataSource[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.dataSourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const datasources: DataSource[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'data-source.json');\n if (!(await fileExists(jsonPath))) continue;\n const ds_json = JSON.parse(await readFile(jsonPath, 'utf-8'));\n const name = ds_json.name ?? e.name;\n if (!ds_json.prismaSchema || !ds_json.generatedTypesImport) {\n const missing = [\n !ds_json.prismaSchema && '\"prismaSchema\"',\n !ds_json.generatedTypesImport && '\"generatedTypesImport\"',\n ]\n .filter(Boolean)\n .join(' and ');\n throw new Error(\n `${jsonPath}: datasource \"${name}\" is missing ${missing}. ` +\n 'A v2 data-source.json must be self-describing — add prismaSchema, urlEnv, ' +\n 'generatedTypesImport, zodOutput and prismaConfig (see `crouton create-datasource`).',\n );\n }\n datasources.push(\n DataSourceSchema.parse({\n ...ds_json,\n name,\n prismaConfig: ds_json.prismaConfig ?? defaultPrismaConfig(name),\n }),\n );\n }\n validateDatasources(datasources);\n return datasources;\n};\n\nexport const validateDatasources = (datasources: DataSource[]): void => {\n if (datasources.length === 0) {\n throw new Error(\n 'No datasources found (no data-source.json under the data-sources dir).',\n );\n }\n const defaults = datasources.filter((d) => d.default);\n if (defaults.length > 1) {\n throw new Error(\n `Only one datasource may be marked \"default\" (found: ${defaults.map((d) => d.name).join(', ')}).`,\n );\n }\n};\n\n/**\n * Resolve which discovered datasource to use:\n * - explicit `name` → must exist\n * - else the one marked `default`\n * - else the only one\n * - else ambiguous → throw (the CLI prompts before calling this)\n */\nexport const resolveDatasource = (\n datasources: DataSource[],\n name?: string,\n): DataSource => {\n if (name) {\n const found = datasources.find((d) => d.name === name);\n if (!found) {\n throw new Error(\n `Unknown datasource \"${name}\". Available: ${datasources.map((d) => d.name).join(', ')}.`,\n );\n }\n return found;\n }\n const def = datasources.find((d) => d.default);\n if (def) return def;\n if (datasources.length === 1) return datasources[0];\n throw new Error(\n `Multiple datasources found (${datasources.map((d) => d.name).join(', ')}); specify which one to use.`,\n );\n};\n\n/** Build the `(prismaName) → exportName` function from the config template. */\nexport const makeSchemaExportName = (\n config: CroutonConfig,\n): ((prismaName: string) => string) => {\n const template = config.schemaExportName ?? '{Model}WithRelationsSchema';\n return (prismaName: string) => template.replace('{Model}', prismaName);\n};\n\n/** Resolve a config path (possibly relative) against the project root. */\nexport const resolveFromRoot = (root: string, p: string): string =>\n isAbsolute(p) ? p : join(root, p);\n","/**\n * Scaffolding: best-effort project proposal for a new-style crouton project.\n *\n * Scans an existing project for Prisma configs, datasource folders, and\n * resource directories and returns a proposed `crouton.json` + per-datasource\n * `data-source.json`. Returned, not written — the CLI shows it and offers to save.\n */\n\nimport { z } from 'zod';\n\nimport {\n type CroutonConfig,\n CroutonConfigSchema,\n type DataSource,\n DataSourceShape,\n transformDataSource,\n} from '@ghentcdh/crouton-core';\n\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n\nexport const ScallfoldDatasourceSchema = DataSourceShape.extend({\n /** Folder name under `dataSourcesDir`. */ folder: z\n .string()\n .default('default'),\n}).transform(transformDataSource);\n\nexport type ScaffoldDatasource = z.infer<typeof ScallfoldDatasourceSchema>;\n\nexport interface ScaffoldResult {\n config: CroutonConfig;\n /** Proposed `data-source.json` per discovered datasource folder. */\n datasources: ScaffoldDatasource[];\n notes: string[];\n}\n\nconst firstExisting = async (\n root: string,\n candidates: string[],\n): Promise<string | undefined> => {\n for (const c of candidates) {\n if (await fileExists(join(root, c))) return c;\n }\n return undefined;\n};\n\n/**\n * Best-effort proposal for a new-style project: a `crouton.json` (paths only)\n * plus a self-describing `data-source.json` per discovered datasource folder.\n * Returned, not written — the CLI shows it and offers to save.\n */\nexport const scaffoldConfigFromProject = async (\n root: string,\n): Promise<ScaffoldResult> => {\n const notes: string[] = [];\n\n let urlEnv: string | undefined;\n const prismaConfigFile = await firstExisting(root, [\n 'prisma.config.ts',\n 'prisma.config.js',\n 'prisma.config.mjs',\n ]);\n if (prismaConfigFile) {\n const text = await readFile(join(root, prismaConfigFile), 'utf-8');\n urlEnv = /env\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/.exec(text)?.[1];\n }\n if (!urlEnv)\n notes.push(\n 'Could not detect a DB URL env var; set \"urlEnv\" per datasource manually.',\n );\n\n const dataSourcesDir =\n (await firstExisting(root, [\n 'apps/backend/src/app/data-sources',\n 'src/app/data-sources',\n 'data-sources',\n ])) ?? 'src/app/data-sources';\n\n const resourcesDir =\n (await firstExisting(root, [\n 'apps/backend/src/app/resources',\n 'src/app/resources',\n 'resources',\n ])) ?? join(dirname(dataSourcesDir), 'resources');\n\n // Detect a generated-types import from an existing resource schema.ts.\n let detectedImport: string | undefined;\n if (await fileExists(join(root, resourcesDir))) {\n const dirs = await readdir(join(root, resourcesDir), {\n withFileTypes: true,\n });\n for (const d of dirs) {\n if (!d.isDirectory()) continue;\n const schemaTs = join(root, resourcesDir, d.name, 'schema.ts');\n if (await fileExists(schemaTs)) {\n const m = /from\\s+[\"']([^\"']+)[\"']/.exec(\n await readFile(schemaTs, 'utf-8'),\n );\n if (m) {\n detectedImport = m[1];\n break;\n }\n }\n }\n }\n\n const datasources: ScaffoldDatasource[] = [];\n if (await fileExists(join(root, dataSourcesDir))) {\n const entries = await readdir(join(root, dataSourcesDir), {\n withFileTypes: true,\n });\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const existing = join(root, dataSourcesDir, e.name, 'data-source.json');\n const prev: Partial<DataSource> = (await fileExists(existing))\n ? JSON.parse(await readFile(existing, 'utf-8'))\n : {};\n const name = prev.name ?? e.name;\n datasources.push(\n ScallfoldDatasourceSchema.parse({\n folder: e.name,\n type: prev.type,\n name,\n default: prev.default,\n prismaSchema: prev.prismaSchema,\n urlEnv: prev.urlEnv ?? urlEnv ?? '',\n generatedTypesImport: prev.generatedTypesImport ?? detectedImport,\n zodOutput: prev.zodOutput,\n prismaConfig: prev.prismaConfig,\n }),\n );\n }\n }\n if (datasources.length === 0) {\n datasources.push(\n ScallfoldDatasourceSchema.parse({\n name: 'default',\n default: true,\n urlEnv,\n generatedTypesImport: detectedImport ?? '@your-scope/generated/default',\n }),\n );\n notes.push(\n 'No data-sources found; proposed a single \"default\" datasource.',\n );\n } else if (!datasources.some((d) => d.default)) {\n datasources[0].default = true;\n }\n\n return {\n config: CroutonConfigSchema.parse({\n title: 'Crouton',\n resourcesDir,\n dataSourcesDir,\n }),\n datasources,\n notes,\n };\n};","/**\n * Pure scaffolder for a new datasource: given the desired settings, produce the\n * full set of files (project-root-relative paths + contents) that make a\n * datasource self-describing and ready for `crouton update resources`.\n *\n * No disk I/O — the CLI (or a backend dev endpoint) collects the inputs, calls\n * this, and writes the returned files. Every generated datasource gets its own\n * Prisma schema, Prisma client output, and zod output so multiple datasources\n * never collide (the Prisma-7 multi-datasource requirement).\n */\n\nimport { defaultPrismaConfig } from './config';\nimport { dirname, posix, relative } from 'node:path';\n\n\nexport interface DatasourceScaffoldOptions {\n /** Datasource name (folder + `name` in data-source.json). */\n name: string;\n /** Where datasource folders live, relative to project root (from crouton.json). */\n dataSourcesDir: string;\n /**\n * Env var holding the connection URL. Required for Prisma; optional for\n * custom adapters whose connection config may not use an env var.\n */\n urlEnv?: string;\n /**\n * Adapter kind. `\"prisma\"` (default) generates the full Prisma scaffold;\n * `\"custom\"` emits only `data-source.json` + an `index.ts` adapter stub.\n */\n adapter?: 'prisma' | 'custom';\n /** Import path for this datasource's generated Zod types (for resource `schema.ts`). Prisma only. */\n generatedTypesImport?: string;\n /** Import path for this datasource's generated Prisma client. When set, used instead of a relative path in data-source index.ts. */\n generatedClientImport?: string;\n /** Datasource type tag. Default `postgres`. */\n type?: string;\n /** Mark this as the default datasource. Default `false`. */\n default?: boolean;\n /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */\n prismaSchema?: string;\n /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */\n prismaConfig?: string;\n /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */\n zodOutput?: string;\n /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */\n clientOutput?: string;\n}\n\nexport interface ScaffoldFile {\n /** Path relative to the project root. */\n path: string;\n contents: string;\n}\n\nexport interface DatasourceScaffold {\n files: ScaffoldFile[];\n /** The fully-resolved settings (after defaults), e.g. for printing a summary. */\n resolved: {\n name: string;\n adapter: 'prisma' | 'custom';\n default: boolean;\n urlEnv?: string;\n type?: string;\n generatedTypesImport?: string;\n prismaSchema?: string;\n prismaConfig?: string;\n zodOutput?: string;\n clientOutput?: string;\n };\n notes: string[];\n}\n\nconst PRISMA_PROVIDERS: Record<string, string> = {\n postgres: 'postgresql',\n postgresql: 'postgresql',\n mysql: 'mysql',\n mariadb: 'mysql',\n sqlite: 'sqlite',\n sqlserver: 'sqlserver',\n mssql: 'sqlserver',\n mongodb: 'mongodb',\n cockroachdb: 'cockroachdb',\n};\n\nconst toPascalCase = (s: string): string =>\n s.replace(/[-_](.)/g, (_, c: string) => c.toUpperCase()).replace(/^(.)/, (_, c: string) => c.toUpperCase());\n\n/** Posix-style relative import from one project-relative dir/file to another dir. */\nconst relImport = (fromDir: string, toDir: string): string => {\n const rel = relative(fromDir, toDir).split(/[\\\\/]/).join(posix.sep);\n return rel.startsWith('.') ? rel : `./${rel}`;\n};\n\nexport const buildDatasourceFiles = (opts: DatasourceScaffoldOptions): DatasourceScaffold => {\n const name = opts.name;\n const isDefault = opts.default === true;\n const adapter = opts.adapter ?? 'prisma';\n const dsDir = posix.join(opts.dataSourcesDir, name);\n\n // ── Custom adapter path ───────────────────────────────────────────────────\n if (adapter === 'custom') {\n const dataSourceJson: Record<string, unknown> = {\n adapter: 'custom',\n name,\n ...(opts.urlEnv ? { urlEnv: opts.urlEnv } : {}),\n ...(isDefault ? { default: true } : {}),\n };\n\n const indexTs = `import { PrismaDataSourceAdapter } from '@ghentcdh/crouton-api';\nimport type { AdapterCrudContext } from '@ghentcdh/crouton-api';\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\n/**\n * ${name} datasource adapter.\n *\n * Extends PrismaDataSourceAdapter so every Prisma-backed method is available\n * by default. Override only the methods you need to customise.\n *\n * Example — enrich findAll results:\n *\n * override async findAll(model: string, params: ListRequest, ctx: AdapterCrudContext) {\n * const result = await super.findAll(model, params, ctx);\n * return { ...result, data: result.data.map(decorate) };\n * }\n *\n * To use a non-Prisma backend, remove the super() call and implement methods directly.\n */\nexport default class ${toPascalCase(name)}Adapter extends PrismaDataSourceAdapter {\n constructor() {\n // Replace with your own client if not using Prisma.\n super(null);\n }\n}\n`;\n\n const notes: string[] = [];\n if (opts.urlEnv) notes.push(`Add ${opts.urlEnv} to your .env (and .env.example).`);\n notes.push(`Implement your adapter in ${posix.join(dsDir, 'index.ts')} — override only the methods you need.`);\n notes.push('Pass your client to super() in the constructor, or replace super() with direct calls for a non-Prisma backend.');\n\n return {\n files: [\n { path: posix.join(dsDir, 'data-source.json'), contents: `${JSON.stringify(dataSourceJson, null, 2)}\\n` },\n { path: posix.join(dsDir, 'index.ts'), contents: indexTs },\n ],\n resolved: { name, urlEnv: opts.urlEnv, adapter: 'custom', default: isDefault },\n notes,\n };\n }\n\n // ── Prisma adapter path (default) ─────────────────────────────────────────\n const type = opts.type ?? 'postgres';\n const provider = PRISMA_PROVIDERS[type.toLowerCase()] ?? 'postgresql';\n\n const prismaSchema = opts.prismaSchema ?? `prisma/${name}/schema.prisma`;\n const prismaConfig = opts.prismaConfig ?? defaultPrismaConfig(name);\n const zodOutput = opts.zodOutput ?? `generated/${name}/src`;\n const clientOutput = opts.clientOutput ?? `generated/${name}/client`;\n\n const schemaDir = dirname(prismaSchema);\n const migrationsDir = posix.join(schemaDir, 'migrations');\n\n // ── data-source.json ──────────────────────────────────────────────────────\n const dataSourceJson: Record<string, unknown> = {\n type,\n name,\n ...(isDefault ? { default: true } : {}),\n prismaSchema,\n urlEnv: opts.urlEnv,\n generatedTypesImport: opts.generatedTypesImport,\n zodOutput,\n clientOutput,\n prismaConfig,\n };\n\n // ── index.ts (runtime PrismaClient) ───────────────────────────────────────\n const clientImport = opts.generatedClientImport ?? relImport(dsDir, clientOutput);\n const indexTs = `import { PrismaClient } from '${clientImport}';\nimport { PrismaPg } from '@prisma/adapter-pg';\n\nconst connectionString = process.env.${opts.urlEnv} ?? '';\n// ?schema=<name> in the URL is a Prisma extension; pg ignores it — set search_path explicitly.\nconst _schema = new URLSearchParams((connectionString.split('?')[1]) ?? '').get('schema');\n\nconst adapter = new PrismaPg({\n connectionString,\n ...(_schema && _schema !== 'public' ? { options: \\`--search_path=\\${_schema}\\` } : {}),\n});\nconst client = new PrismaClient({ adapter });\n\nexport default client;\n`;\n\n // ── prisma/<name>/schema.prisma ───────────────────────────────────────────\n const relClient = relImport(schemaDir, clientOutput);\n const relZod = relImport(schemaDir, zodOutput);\n const schemaPrisma = `generator client {\n provider = \"prisma-client-js\"\n output = \"${relClient}\"\n}\n\ngenerator crouton {\n provider = \"crouton-prisma\"\n zodOutput = \"${relZod}\"\n}\n\ndatasource db {\n provider = \"${provider}\"\n // url is provided by ${prismaConfig} (Prisma 7 forbids \\`url\\` here)\n}\n`;\n\n // ── prisma/<name>/prisma.config.ts ────────────────────────────────────────\n // Paths must be relative to the config file, not the project root.\n const configDir = dirname(prismaConfig);\n const relSchema = relImport(configDir, prismaSchema);\n const relMigrations = relImport(configDir, migrationsDir);\n\n const prismaConfigTs = `// Generated by \\`crouton create-datasource\\`.\nimport { defineConfig, env } from 'prisma/config';\n\nexport default defineConfig({\n schema: '${relSchema}',\n migrations: {\n path: '${relMigrations}',\n },\n datasource: {\n url: env('${opts.urlEnv}'),\n },\n});\n`;\n\n const files: ScaffoldFile[] = [\n { path: posix.join(dsDir, 'data-source.json'), contents: `${JSON.stringify(dataSourceJson, null, 2)}\\n` },\n { path: posix.join(dsDir, 'index.ts'), contents: indexTs },\n { path: prismaSchema, contents: schemaPrisma },\n { path: prismaConfig, contents: prismaConfigTs },\n ];\n\n const notes = [\n `Add ${opts.urlEnv} to your .env (and .env.example).`,\n `Map ${opts.generatedTypesImport} to ${zodOutput} in your tsconfig paths / workspace.`,\n `Run \\`crouton update resources --datasource ${name}\\` to introspect and generate resources.`,\n ];\n\n return {\n files,\n resolved: { name, type, adapter: 'prisma', default: isDefault, urlEnv: opts.urlEnv, generatedTypesImport: opts.generatedTypesImport, prismaSchema, prismaConfig, zodOutput, clientOutput },\n notes,\n };\n};\n","/**\n * Filesystem glue between the engine and a crouton project on disk:\n * reading existing resource configs, listing resources, and resolving relation\n * targets to sibling resource files.\n */\n\nimport {\n type ResourceJson,\n type ResourceJsonInput,\n buildResourceJsonSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { type LoadedConfig, resolveFromRoot } from './config';\nimport { clientAccessor } from './naming';\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/** Absolute path to a resource directory. */\nexport const resourceDir = (loaded: LoadedConfig, name: string): string =>\n join(resolveFromRoot(loaded.root, loaded.config.resourcesDir), name);\n\nexport interface ExistingResource {\n config: ResourceJsonInput | null;\n hasSchemaFile: boolean;\n}\n\n/** Read an existing `resource.json` (if any) and detect a sibling `schema.ts`. */\nexport const readExistingResource = async (\n loaded: LoadedConfig,\n name: string,\n): Promise<ExistingResource> => {\n const dir = resourceDir(loaded, name);\n const jsonPath = join(dir, 'resource.json');\n const config = (await fileExists(jsonPath))\n ? (JSON.parse(await readFile(jsonPath, 'utf-8')) as ResourceJsonInput)\n : null;\n const hasSchemaFile =\n (await fileExists(join(dir, 'schema.ts'))) ||\n (await fileExists(join(dir, 'schema.js')));\n return { config, hasSchemaFile };\n};\n\n/** `true` when a resource.json on disk declares `kind: \"custom\"`. */\nexport const isCustomResourceFile = async (\n jsonPath: string,\n): Promise<boolean> => {\n try {\n const parsed = JSON.parse(await readFile(jsonPath, 'utf-8')) as {\n kind?: string;\n };\n return parsed?.kind === 'custom';\n } catch {\n // Unreadable/malformed: let the normal pipeline report it.\n return false;\n }\n};\n\n/**\n * Names of resource directories that contain a `resource.json`.\n *\n * Custom resources are excluded: they have no Prisma model, so the\n * introspect → diff pipeline would see every column as \"not found in the\n * database schema\" and offer to remove it.\n */\nexport const listResourceNames = async (\n loaded: LoadedConfig,\n): Promise<string[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const names: string[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'resource.json');\n if (!(await fileExists(jsonPath))) continue;\n if (await isCustomResourceFile(jsonPath)) continue;\n names.push(e.name);\n }\n return names;\n};\n\n/**\n * Names of all resource directories (including custom resources).\n * Used for translation generation where every resource is translatable.\n */\nexport const listAllResourceNames = async (\n loaded: LoadedConfig,\n): Promise<string[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const names: string[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'resource.json');\n if (!(await fileExists(jsonPath))) continue;\n names.push(e.name);\n }\n return names;\n};\n\n/**\n * Read and parse all `resource.json` files (including custom resources).\n * Invalid files are silently skipped.\n */\nexport const readAllResourceJsons = async (\n loaded: LoadedConfig,\n): Promise<ResourceJson[]> => {\n const names = await listAllResourceNames(loaded);\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n const results: ResourceJson[] = [];\n for (const name of names) {\n try {\n const raw = JSON.parse(\n await readFile(join(base, name, 'resource.json'), 'utf-8'),\n );\n const parsed = buildResourceJsonSchema().safeParse(raw);\n if (parsed.success) results.push(parsed.data);\n } catch {\n /* skip unreadable */\n }\n }\n return results;\n};\n\n/**\n * Build a relation resolver: a relation's target model is \"wired\" when a\n * sibling resource directory exists for it. Returns the relative path used in\n * `fieldInput.resource` (`../<target>/resource.json`), else `undefined`.\n */\nexport const makeRelationResolver = async (\n loaded: LoadedConfig,\n): Promise<(targetModel: string) => string | undefined> => {\n const known = new Set(await listResourceNames(loaded));\n return (targetModel: string) => {\n const accessor = clientAccessor(targetModel);\n return known.has(accessor) ? `../${accessor}/resource.json` : undefined;\n };\n};\n","/**\n * Orchestrator: tie `introspect` output to per-model `classify` + `diff`.\n *\n * Dependencies (existing-config reader, relation resolver, ruleset, database)\n * are injected so this composes cleanly and stays unit-testable without disk.\n */\n\nimport { type CroutonConfig, type Ruleset, RulesetSchema } from '@ghentcdh/crouton-core';\n\nimport { classify } from './classify';\nimport type { DbModel } from './db-model';\nimport type { ResourceDiff } from './decision';\nimport { diff } from './diff';\nimport { resourceNames } from './naming';\nimport type { ExistingResource } from './project';\n\nexport interface BuildDiffsDeps {\n /** Datasource name stamped on generated resources. */\n database?: string;\n ruleset?: Ruleset;\n resolveRelationResource?: (targetModel: string) => string | undefined;\n /** Read the on-disk resource (by directory/route name). */\n readExisting: (name: string) => Promise<ExistingResource>;\n}\n\n/** Merge a config's rule overrides over the defaults. */\nexport const resolveRuleset = (\n config?: Pick<CroutonConfig, 'rules'>,\n): Ruleset => RulesetSchema.parse(config?.rules ?? {});\n\n/** Build the `ResourceDiff` for a single model. */\nexport const buildResourceDiff = async (\n model: DbModel,\n deps: BuildDiffsDeps,\n): Promise<ResourceDiff> => {\n const draft = classify(model, {\n database: deps.database,\n ruleset: deps.ruleset,\n resolveRelationResource: deps.resolveRelationResource,\n });\n const { name } = resourceNames(model.prismaName);\n const { config, hasSchemaFile } = await deps.readExisting(name);\n return diff({ draft, existing: config, hasSchemaFile });\n};\n\n/** Build diffs for many models (sequentially; introspection is already done). */\nexport const buildResourceDiffs = async (\n models: DbModel[],\n deps: BuildDiffsDeps,\n): Promise<ResourceDiff[]> => {\n const diffs: ResourceDiff[] = [];\n for (const model of models) diffs.push(await buildResourceDiff(model, deps));\n return diffs;\n};\n","/**\n * Thin wrappers around the project's Prisma CLI plus git/backup safety for the\n * destructive `db pull` step.\n *\n * Shared by both `crouton-cli` (interactive terminal) and `crouton-api`\n * (dev-mode endpoint). Only uses `node:child_process` / `node:fs` — no\n * framework-specific dependencies.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { copyFile, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\n\n/**\n * Load a .env file from `dir` (or the nearest parent that has one) into\n * `process.env` so that prisma commands inherit DATABASE_URL etc.\n * Uses `dotenv` if available; skips silently otherwise.\n */\nconst loadDotenv = (dir: string): void => {\n try {\n const _require = createRequire(import.meta.url);\n const dotenv = _require('dotenv') as { config: (opts?: { path?: string }) => void };\n let d = dir;\n for (let i = 0; i < 6; i++) {\n if (readdirSync(d).includes('.env')) {\n dotenv.config({ path: join(d, '.env') });\n return;\n }\n const parent = dirname(d);\n if (parent === d) break;\n d = parent;\n }\n } catch { /* dotenv not available or no .env — prisma will read env vars directly */ }\n};\n\n/**\n * Resolve a CLI binary from the project's node_modules first, then fall back\n * to `npx <name>`. Prevents version mismatches where npx downloads a newer\n * major version that has different command names.\n */\nconst resolveBin = (name: string, cwd: string): [string, string[]] => {\n let d = cwd;\n for (let i = 0; i < 6; i++) {\n const bin = join(d, 'node_modules', '.bin', name);\n if (existsSync(bin)) return [bin, []];\n const parent = dirname(d);\n if (parent === d) break;\n d = parent;\n }\n return ['npx', [name]];\n};\n\nconst run = (\n cmd: string,\n args: string[],\n cwd: string,\n): Promise<{ code: number; stdout: string; stderr: string }> =>\n new Promise((resolve) => {\n const child = spawn(cmd, args, { cwd, shell: process.platform === 'win32' });\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d) => (stdout += d.toString()));\n child.stderr?.on('data', (d) => (stderr += d.toString()));\n child.on('error', (err) => resolve({ code: 1, stdout, stderr: stderr + String(err) }));\n child.on('close', (code) => resolve({ code: code ?? 0, stdout, stderr }));\n });\n\n/** True when the given path has uncommitted changes (or git is unavailable → treated as clean). */\nexport const isGitDirty = async (cwd: string, path: string): Promise<boolean> => {\n const { code, stdout } = await run('git', ['status', '--porcelain', '--', path], cwd);\n if (code !== 0) return false; // not a git repo / git missing — don't block\n return stdout.trim().length > 0;\n};\n\n/** Back up a schema file to `<schema>.bak` before a destructive pull. */\nexport const backupSchema = async (schemaPath: string): Promise<string> => {\n const dest = `${schemaPath}.bak`;\n await copyFile(schemaPath, dest);\n return dest;\n};\n\nexport interface PrismaRunResult {\n ok: boolean;\n output: string;\n}\n\n/** Introspect the live database into the schema file. */\nexport const prismaDbPull = async (cwd: string, prismaConfig: string): Promise<PrismaRunResult> => {\n const [bin, prefix] = resolveBin('prisma', cwd);\n const { code, stdout, stderr } = await run(bin, [...prefix, 'db', 'pull', '--config', prismaConfig], cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/** `prisma-case-format` — PascalCase models + camelCase fields with @@map/@map annotations. */\nexport const prismaCaseFormat = async (cwd: string, schemaPath: string): Promise<PrismaRunResult> => {\n // Resolve bin from crouton's own node_modules to avoid ad-hoc npx download failures\n let binPath: string | undefined;\n try {\n const _require = createRequire(import.meta.url);\n binPath = _require.resolve('prisma-case-format/bin/cli.js');\n } catch { /* fall back to npx */ }\n\n const [cmd, args] = binPath\n ? [process.execPath, [binPath, '--file', schemaPath]]\n : ['npx', ['prisma-case-format', '--file', schemaPath]];\n const { code, stdout, stderr } = await run(cmd, args, cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/** `prisma generate` for a datasource's config (triggers the `crouton-prisma` generator). */\nexport const prismaGenerate = async (cwd: string, prismaConfig: string): Promise<PrismaRunResult> => {\n const [bin, prefix] = resolveBin('prisma', cwd);\n const { code, stdout, stderr } = await run(bin, [...prefix, 'generate', '--config', prismaConfig], cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/**\n * zod-prisma-types sometimes omits `import { z } from 'zod'` in generated\n * schema files. Scan the output directory and inject the import where missing.\n */\nexport const fixZodImports = async (zodOutputDir: string): Promise<number> => {\n let fixed = 0;\n const walk = async (dir: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else if (entry.name.endsWith('.ts')) {\n const src = await readFile(full, 'utf-8');\n if (src.includes('z.') && !src.includes('from \\'zod\\'') && !src.includes('from \"zod\"')) {\n await writeFile(full, `import { z } from 'zod';\\n${src}`, 'utf-8');\n fixed++;\n }\n }\n }\n };\n await walk(zodOutputDir);\n return fixed;\n};\n\nexport interface PullAndGenerateInput {\n root: string;\n prismaConfigPath: string;\n schemaPath: string;\n}\n\nexport interface PullAndGenerateResult {\n ok: boolean;\n backupPath: string;\n dbPull: PrismaRunResult;\n caseFormat?: PrismaRunResult;\n normalizeSchema?: { ok: boolean; renamed: number };\n generate?: PrismaRunResult;\n}\n\n/**\n * Full pull-and-generate pipeline: backup → dbPull → caseFormat →\n * normalizeSchema → generate.\n *\n * Returns a structured result; callers handle UI / error presentation.\n * `dbPull` failure is fatal (returns early with `ok: false`); subsequent\n * step failures are recorded but non-fatal.\n *\n * zod post-processing (fixZodImports) is now owned by the crouton-prisma\n * generator and runs inside `prismaGenerate`.\n */\nexport const pullAndGenerate = async (\n input: PullAndGenerateInput,\n): Promise<PullAndGenerateResult> => {\n const { root, prismaConfigPath, schemaPath } = input;\n loadDotenv(root);\n const backupPath = await backupSchema(schemaPath);\n const dbPull = await prismaDbPull(root, prismaConfigPath);\n if (!dbPull.ok) return { ok: false, backupPath, dbPull };\n const caseFormat = await prismaCaseFormat(root, schemaPath);\n const normalized = await normalizeSchema(schemaPath);\n const generate = await prismaGenerate(root, prismaConfigPath);\n return { ok: true, backupPath, dbPull, caseFormat, normalizeSchema: { ok: true, renamed: normalized.renamed }, generate };\n};\n\ninterface NormalizeConfig {\n renames: Record<string, Record<string, string>>;\n}\n\n/**\n * Rename ugly auto-generated relation field names in a Prisma schema using a\n * `normalize-schema.json` config file placed next to the schema.\n */\nexport const normalizeSchema = async (\n schemaPath: string,\n configDir?: string,\n): Promise<{ renamed: number }> => {\n const dir = configDir ?? dirname(schemaPath);\n const configPath = join(dir, 'normalize-schema.json');\n\n if (!existsSync(configPath)) return { renamed: 0 };\n\n const config: NormalizeConfig = JSON.parse(\n await readFile(configPath, 'utf-8'),\n );\n let schema = await readFile(schemaPath, 'utf-8');\n let renamed = 0;\n\n for (const [modelName, fields] of Object.entries(config.renames)) {\n // Match the model block: `model ModelName { ... }`\n const modelRe = new RegExp(\n `(model\\\\s+${modelName}\\\\s*\\\\{)(.*?)(^})`,\n 'ms',\n );\n schema = schema.replace(modelRe, (_, head: string, body: string, tail: string) => {\n for (const [ugly, clean] of Object.entries(fields)) {\n // Replace field name at start of line (after optional whitespace)\n const fieldRe = new RegExp(`^(\\\\s+)${ugly}\\\\b`, 'gm');\n const replaced = body.replace(fieldRe, `$1${clean}`);\n if (replaced !== body) {\n body = replaced;\n renamed++;\n }\n }\n return `${head}${body}${tail}`;\n });\n }\n\n if (renamed > 0) {\n await writeFile(schemaPath, schema, 'utf-8');\n }\n\n return { renamed };\n};","import type { RawResourceJson } from './WriteResourceJson';\nimport { resolve } from 'node:path';\n\nexport interface ResourceFlagPatch {\n draft?: boolean;\n sidebar?: {\n hide?: boolean;\n group?: string;\n position?: number;\n label?: string;\n };\n}\n\n/**\n * Applies flag changes to a raw resource.json object. Removes keys that are\n * at their schema default (publish = delete `draft`, un-hide = delete\n * `sidebar.hide`, empty sidebar object = delete `sidebar`) so the file stays\n * minimal.\n */\nexport const applyResourceFlagPatch = (\n raw: RawResourceJson,\n patch: ResourceFlagPatch,\n): RawResourceJson => {\n const result = { ...raw };\n\n // --- draft ---\n if (patch.draft !== undefined) {\n if (patch.draft) {\n result['draft'] = true;\n } else {\n delete result['draft'];\n }\n }\n\n // --- sidebar ---\n if (patch.sidebar !== undefined) {\n const existing =\n raw['sidebar'] && typeof raw['sidebar'] === 'object'\n ? { ...(raw['sidebar'] as Record<string, unknown>) }\n : {};\n\n if (patch.sidebar.hide !== undefined) {\n if (patch.sidebar.hide) {\n existing['hide'] = true;\n } else {\n delete existing['hide'];\n }\n }\n if (patch.sidebar.group !== undefined) {\n existing['group'] = patch.sidebar.group;\n }\n if (patch.sidebar.position !== undefined) {\n existing['position'] = patch.sidebar.position;\n }\n if (patch.sidebar.label !== undefined) {\n existing['label'] = patch.sidebar.label;\n }\n\n // Drop sidebar key entirely when it's empty (matches schema default).\n if (Object.keys(existing).length === 0) {\n delete result['sidebar'];\n } else {\n result['sidebar'] = existing;\n }\n }\n\n return result;\n};\n\n/**\n * Resolves `<resourcesDir>/<name>/resource.json` with a path-traversal guard.\n * Throws if the resolved path escapes `resourcesDir`.\n */\nexport const resolveResourcePath = (\n resourcesDir: string,\n name: string,\n): string => {\n const resolved = resolve(resourcesDir, name, 'resource.json');\n if (!resolved.startsWith(resolve(resourcesDir) + '/')) {\n throw new Error(`Invalid resource name: \"${name}\"`);\n }\n return resolved;\n};\n","/**\n * Non-error notices from the resource load pass, complementing `resourceLoadErrorsRegistry`\n * (which holds failures). Records resources that were auto-migrated on disk (`migrated`) or\n * are present but intentionally not served (`draft`), so the status page can show them\n * distinctly from hard errors. Like the errors registry it's a per-load singleton, cleared\n * at the start of every `loadResourceConfigsFromDir`.\n */\n\nexport interface MigratedResourceNotice {\n state: 'migrated';\n name: string;\n path: string;\n from: number;\n to: number;\n}\n\nexport interface DraftResourceNotice {\n state: 'draft';\n name: string;\n path: string;\n version?: number;\n}\n\nexport interface WarningResourceNotice {\n state: 'warning';\n name: string;\n path: string;\n warning: string;\n}\n\nexport type ResourceLoadNotice = MigratedResourceNotice | DraftResourceNotice | WarningResourceNotice;\n\nclass ResourceLoadReportRegistry {\n private notices: ResourceLoadNotice[] = [];\n\n record(n: ResourceLoadNotice) {\n this.notices.push(n);\n }\n\n getAll() {\n return [...this.notices];\n }\n\n getByState<S extends ResourceLoadNotice['state']>(\n state: S,\n ): Extract<ResourceLoadNotice, { state: S }>[] {\n return this.notices.filter(\n (n): n is Extract<ResourceLoadNotice, { state: S }> => n.state === state,\n );\n }\n\n clear() {\n this.notices = [];\n }\n}\n\nexport const resourceLoadReportRegistry = new ResourceLoadReportRegistry();\n","import { z } from 'zod';\n\nexport const EnumEntrySchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport type EnumEntry = z.infer<typeof EnumEntrySchema>;\n\nexport const EnumRegistrySchema = z\n .record(z.string(), z.array(EnumEntrySchema))\n .default({});\n\nexport type EnumRegistry = z.infer<typeof EnumRegistrySchema>;\n","import { type EnumRegistry, EnumRegistrySchema } from './enum-registry.types';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n\nconst ENUMS_FILE = 'crouton.enums.json';\n\nexport const loadEnumRegistry = (\n startDir: string,\n enumsFile?: string,\n): 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 EnumRegistrySchema.parse(undefined);\n try {\n return EnumRegistrySchema.parse(JSON.parse(readFileSync(file, 'utf-8')));\n } catch {\n return EnumRegistrySchema.parse(undefined);\n }\n};","import type { JsonColumn } from '@ghentcdh/crouton-core';\n\nimport { type EnumRegistry } from './enum-registry.types';\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 =\n (col.fieldInput.options as Record<string, unknown> | undefined) ?? {};\n if (!('values' in options)) options.values = values;\n if (!('emitObject' in options)) options.emitObject = true;\n if (!('displayKey' in options)) options.displayKey = 'label';\n col.fieldInput.options = options;\n }\n};","import {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport type { Observable } from 'rxjs';\n\n@Injectable()\nexport class NoCacheInterceptor implements NestInterceptor {\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n const response = context.switchToHttp().getResponse();\n response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n response.setHeader('Pragma', 'no-cache');\n response.setHeader('Expires', '0');\n return next.handle();\n }\n}\n","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport { type JsonColumn, type JsonResourceOperations, isRelation } from '@ghentcdh/crouton-core';\n\nimport { type OperationDef, type ResourceDefinition } from '../resource/defintion.schema';\nimport { type SchemaInput } from '../resource/json.schema';\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 baseFilter = (c: JsonColumn) =>\n !isRelation(c) && (filter ? filter(c) : true);\n const schemaKeys = new Set(Object.keys(schema.shape));\n const filtered = columns.filter((c) => baseFilter(c) && schemaKeys.has(c.id));\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 | Record<string, unknown> | 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 if (typeof enabled === 'object' && enabled !== null && 'uri' in enabled) {\n return { uri: enabled['uri'] as string, ...(enabled['method'] ? { method: enabled['method'] as string } : {}) };\n }\n return schema ? { schema } : true;\n};\n\nexport const buildResourceDefinitions = (\n schema: ZodObject<ZodRawShape> | undefined,\n operations: JsonResourceOperations,\n enrichedColumns: JsonColumn[] | undefined,\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\n const definition: ResourceDefinition = {\n ...(opWithSchema(operations.findAll, picked) && {\n findAll: opWithSchema(operations.findAll, picked)!,\n }),\n ...(opWithSchema(operations.findOne, picked) && {\n findOne: opWithSchema(operations.findOne, picked)!,\n }),\n ...(opWithSchema(operations.create, createSchema) && {\n create: opWithSchema(operations.create, createSchema)!,\n }),\n ...(opWithSchema(operations.update, updateSchema) && {\n update: opWithSchema(operations.update, updateSchema)!,\n }),\n ...(opWithSchema(operations.patch as any, undefined) && {\n patch: opWithSchema(operations.patch as any, undefined)!,\n }),\n ...(opWithSchema(operations.delete as any, undefined) && {\n delete: opWithSchema(operations.delete as any, undefined)!,\n }),\n };\n\n return definition;\n};\n","import { ZodArray, ZodNullable, type ZodObject, ZodOptional, type ZodRawShape } from 'zod';\n\nimport type { JsonColumn, RelationType } from '@ghentcdh/crouton-core';\n\n/** Recursively unwrap Optional / Nullable wrappers to reach the inner Zod type. */\nexport const 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 */\nexport const 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 * 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 */\nexport const 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 * 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 */\nexport const 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};","import type { JsonColumn, JsonIncludeEntry, RelationFieldInputOptions } from '@ghentcdh/crouton-core';\n\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { buildChildSortClause } from '../sql.helpers';\nimport { deriveRelationTypeFromColumns } from './relation-type';\nimport { resolveChildResource } from './resource-resolver';\n\n/**\n * Return a new columns array with `uri`, `resourceUri`, and `resource` (schemas URL)\n * injected into `fieldInput.options` for relation columns.\n */\nexport const 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 resource:\n sub.relationType === 'manyToOne'\n ? `${base}/${sub.childRoute}/schemas`\n : `${base}/${parentRoute}/${sub.childRoute}/schemas`,\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 */\nexport const 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\n .replace(/^\\.\\.?\\//, '')\n .replace(/\\/resource\\.json$/, '')\n .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 * 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 */\nexport const 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 * 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 */\nexport const 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\n 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","import type { JsonColumn, JsonIncludeEntry, RelationFieldInputOptions } from '@ghentcdh/crouton-core';\nimport {\n buildViewsFromColumns,\n injectCalculatedColumns,\n injectCalculatedColumnsToView,\n} from '@ghentcdh/crouton-core';\n\nimport { type EnumRegistry, injectEnumValues } from '../enum-registry';\nimport { enrichNestedRelationColumns } from './column-enrichment';\nimport { applyRelationFormatDefault, buildValueLabelColumns, expandExtendColumns } from './column-transforms';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { buildChildSortClause } from '../sql.helpers';\nimport { deriveRelationTypeFromColumns } from './relation-type';\nimport { resolveChildResourceDetailed } from './resource-resolver';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\n\n/**\n * A relation column may point at another service rather than a local child\n * config. Those still render (autocomplete against the remote resource) but are\n * not managed as sub-resources, so they are skipped without complaint.\n */\nconst REMOTE_RESOURCE = /^https?:\\/\\//i;\n\n/**\n * Build `SubResourceConfig` entries for columns with `fieldInput.format === \"action\"`.\n */\nexport const 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 .flatMap((c) => {\n const resourcePath = c.fieldInput!.resource!;\n if (REMOTE_RESOURCE.test(resourcePath)) return [];\n\n const resolution = resolveChildResourceDetailed(resourcePath, parentDir);\n\n // A child that cannot be resolved used to fall through as a Prisma-backed\n // sub-resource named after the column, which registers `:id/<column>`\n // routes that fail at request time with `Prisma model \"<column>\" not\n // found`. Report it at load time and register nothing instead.\n if (!resolution.ok) {\n resourceLoadErrorsRegistry.record({\n name: parentRoute,\n path: resourcePath,\n error:\n resolution.reason === 'missing'\n ? `Relation column \"${c.id}\" points at \"${resourcePath}\", but no resource.json was found there (looked in: ${resolution.attempted.join(', ')}). Sub-resource routes for it were not registered.`\n : `Relation column \"${c.id}\" points at \"${resourcePath}\", which could not be read: ${resolution.error} Sub-resource routes for it were not registered.`,\n });\n return [];\n }\n\n const childJson = resolution.value.json;\n const childDir = resolution.value.dir;\n\n // `parent` mounts the child's own controller under the parent route. Also\n // declaring it as a sub-resource registers a second, competing handler for\n // the same path off the parent's controller — one of the two silently wins.\n if (childJson.parent) {\n resourceLoadErrorsRegistry.record({\n name: parentRoute,\n path: resourcePath,\n error:\n `Relation column \"${c.id}\" declares \"${childJson.name}\" as a sub-resource, but that resource also declares \"parent\": { \"route\": \"${childJson.parent.route}\" }. ` +\n 'The two ways of nesting are mutually exclusive — remove the \"parent\" block to embed it in this resource, or remove this relation column to keep its own nested controller. Sub-resource routes for it were not registered.',\n });\n return [];\n }\n\n const childRoute =\n childJson.route ??\n resourcePath\n .replace(/^\\.\\.?\\//, '')\n .replace(/\\/resource\\.json$/, '')\n .replace(/\\.resource$/, '');\n\n const rawChildColumns = childJson?.columns;\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 // Auto-derive includes for manyToOne child relations (mirrors main resource logic in read.repository)\n const autoIncludes: string[] = (enrichedChildColumns ?? [])\n .filter(\n (col) =>\n col.fieldInput?.format === 'relation' &&\n (col.fieldInput.relationType ??\n deriveRelationTypeFromColumns(col, enrichedChildColumns!)) ===\n 'manyToOne',\n )\n .map((col) => col.fieldInput?.relation ?? col.id);\n const explicitIncludes: JsonIncludeEntry[] = childJson?.include ?? [];\n const explicitNames = new Set(\n explicitIncludes.map((e) =>\n typeof e === 'string' ? e : e.relation,\n ),\n );\n const mergedIncludes: JsonIncludeEntry[] = [\n ...explicitIncludes,\n ...autoIncludes.filter((name) => !explicitNames.has(name)),\n ];\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 const childKind = childJson?.kind === 'custom' ? 'custom' : 'prisma';\n\n return {\n column: c.id,\n relation: c.fieldInput?.relation ?? c.id,\n childRoute,\n childKind,\n ...(childDir && { childDir }),\n // A custom child has no Prisma model. Leave it empty rather than\n // falling back to the column id, which would produce a bogus\n // `prisma[<column>]` lookup at query time.\n // Use the child resource's declared model name so plural column ids\n // (e.g. \"books\") resolve to the correct Prisma delegate (prisma.book).\n // ponytail: charAt toLowerCase is cheap; Prisma model names are always PascalCase\n childModel:\n childKind === 'custom'\n ? ''\n : childJson?.model\n ? childJson.model.charAt(0).toLowerCase() + childJson.model.slice(1)\n : c.id,\n foreignKey: c.fieldInput?.foreignKey ?? `${parentModel}Id`,\n name: childJson?.name ?? childRoute,\n title: childJson?.title ?? childJson?.tag ?? childRoute,\n idField: childLookupKey,\n idType: childJson?.idType ?? 'string',\n ...(c.hiddenInTable && { hiddenInTable: true }),\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 patch: childOps.patch !== false,\n delete: childOps.delete !== false,\n },\n ...(childJson?.actions?.length && { actions: childJson.actions }),\n ...(childJson?.modalSize && { modalSize: childJson.modalSize }),\n ...(childJson?.display && { display: childJson.display }),\n ...(mergedIncludes.length && { include: mergedIncludes }),\n ...(childJson?.calculatedColumns?.length && {\n calculatedColumns: childJson.calculatedColumns,\n }),\n ...((c.hiddenInForm === false || c.hiddenInView === false) && {\n includeInFindOne: true,\n ...(() => {\n const opts = c.fieldInput?.options as RelationFieldInputOptions | undefined;\n if (opts?.sort) return { findOneOrderBy: buildChildSortClause(opts.sort, opts.sortDir) };\n return {};\n })(),\n }),\n ...(buildValueLabelColumns(childColumns).length && {\n valueLabelColumns: buildValueLabelColumns(childColumns),\n }),\n relationType: c.fieldInput?.relationType ?? deriveRelationTypeFromColumns(c, columns!),\n } satisfies SubResourceConfig;\n });\n};","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport type {\n CalculatedColumn,\n JsonColumn,\n ResourceJson,\n} from '@ghentcdh/crouton-core';\nimport {\n buildViews,\n getResourceExtensions,\n injectCalculatedColumns,\n injectCalculatedColumnsToView,\n} from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from '../action';\nimport { buildResourceDefinitions } from '../builder/schema.helpers';\nimport type { CustomRepository } from '../custom-repository';\nimport { type EnumRegistry, injectEnumValues } from '../enum-registry';\nimport type { ResourceHooks } from '../hooks';\nimport {\n enrichActionColumns,\n enrichIncludeWithSort,\n enrichResourceRefColumns,\n} from './column-enrichment';\nimport {\n applyRelationFormatDefault,\n buildValueLabelColumns,\n expandExtendColumns,\n resolveColumnFieldVariants,\n} from './column-transforms';\nimport { enrichRelationTypes } from './relation-type';\nimport { resolveChildResource } from './resource-resolver';\nimport { buildSubResources } from './sub-resource.builder';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { LookupConfig } from '../resource/lookup.schema';\n\nconst pickExtensions = (obj: Record<string, unknown>) =>\n Object.fromEntries([...getResourceExtensions().keys()].filter(k => obj[k] !== undefined).map(k => [k, obj[k]]));\n\nexport const fromJson = (\n json: ResourceJson,\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?: ResourceRowAction[],\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 /** Data access for a `kind: \"custom\"` resource, loaded from `repository.ts`. */\n repository?: CustomRepository,\n): Resource => {\n const isCustom = json.kind === 'custom';\n const rawColumns = expandExtendColumns(json.columns, dirPath);\n const columns = enrichRelationTypes(\n applyRelationFormatDefault(rawColumns) ?? rawColumns,\n schema,\n );\n injectEnumValues(columns, enums);\n\n // Sub-resources are served by nested Prisma queries against the child model,\n // which a custom resource has no equivalent of. Relation columns still render\n // (autocomplete/link) — they just aren't managed through child routes here.\n const subResources = isCustom\n ? []\n : buildSubResources(\n columns,\n json.route,\n json.model ?? '',\n dirPath,\n enums,\n baseUrl,\n );\n // Resolve fieldView/fieldTable variants LAST, after URI/relation enrichment,\n // so the resolved variants inherit the injected relation/resource options.\n const enrichedColumns = resolveColumnFieldVariants(\n enrichResourceRefColumns(\n enrichActionColumns(columns, json.route, subResources, baseUrl),\n dirPath,\n baseUrl,\n ) ?? columns,\n )!;\n\n const calculatedColumns: CalculatedColumn[] = json.calculatedColumns ?? [];\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, dirPath);\n const enrichedInclude = enrichIncludeWithSort(json.include, enrichedColumns);\n const definition = buildResourceDefinitions(\n schema,\n json.operations,\n enrichedColumns,\n );\n\n return {\n ...json,\n name: json.name,\n route: json.route,\n model: json.model,\n tag: json.tag,\n sidebar: json.sidebar,\n display: json.display,\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 ...(repository && { repository }),\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 ...pickExtensions(json as Record<string, unknown>),\n };\n};\n\nconst buildLookup = (\n columns: JsonColumn[] | undefined,\n dirPath?: string,\n): LookupConfig | undefined => {\n if (!columns) return undefined;\n\n const keyCol = columns.find((c) => c.idField);\n const searchCols = columns.filter((c) => c.showInLookup || c.searchable);\n\n if (!keyCol && !searchCols.length) return undefined;\n\n const labels = searchCols.map((col) => {\n if (col.fieldInput?.relationType === 'manyToOne' && col.fieldInput?.resource && dirPath) {\n const relationName = col.id.replace(/Id$/, '');\n const child = resolveChildResource(col.fieldInput.resource, dirPath);\n const childColumns = child ? expandExtendColumns(child.json.columns, dirPath) : undefined;\n const displayCol = childColumns?.find((c) => !c.idField && !c.hiddenInTable);\n if (displayCol) return `${relationName}.${displayCol.id}`;\n }\n return col.id;\n });\n\n return {\n key: keyCol?.id ?? 'id',\n ...(labels.length && { label: labels[0], labels }),\n };\n};\n","/**\n * Load-time migration for a single `resource.json`.\n *\n * Auto-migration is a DEV-ONLY capability: it rewrites the checked-in file, so it needs a\n * writable, version-controlled checkout (the diff is meant to be reviewed and committed).\n * Outside dev, an out-of-date file is reported as a failure rather than silently rewritten\n * or run against stale config — the normal flow is that dev migrates + commits, so prod only\n * ever sees files already at `CURRENT_RESOURCE_VERSION`.\n *\n * Operates on the RAW object (via `WriteResourceJson`'s raw-preserving helpers) so a rewrite\n * stays a minimal, byte-stable diff; validation with Zod happens only after migrating.\n */\n\nimport {\n BASELINE_RESOURCE_VERSION,\n CURRENT_RESOURCE_VERSION,\n MigrationPathError,\n MigrationStepError,\n resourceVersionOf,\n runResourceMigrations,\n} from '@ghentcdh/crouton-core';\n\nimport {\n readRawResourceJson,\n serializeResourceJson,\n validateResourceJson,\n} from './WriteResourceJson';\nimport { writeFileSync } from 'node:fs';\n\nexport type MigrateOutcome =\n | { status: 'current'; version: number }\n | { status: 'migrated'; from: number; to: number; written: boolean }\n | { status: 'failed'; version: number; expected: number; error: string };\n\nexport const migrateResourceJsonFile = (\n jsonPath: string,\n opts: { isDev: boolean },\n): MigrateOutcome => {\n // If the file is missing or not valid JSON, don't fail here — pass through so the normal\n // reader (`readResourceJson`) reports the parse error verbatim, exactly as before.\n let raw: Record<string, unknown> | undefined;\n try {\n raw = readRawResourceJson(jsonPath);\n } catch {\n return { status: 'current', version: BASELINE_RESOURCE_VERSION };\n }\n if (!raw) return { status: 'current', version: BASELINE_RESOURCE_VERSION };\n\n const from = resourceVersionOf(raw);\n if (from === CURRENT_RESOURCE_VERSION) {\n return { status: 'current', version: from };\n }\n\n // Out of date (or newer). Migration only runs in the dev environment.\n if (!opts.isDev) {\n return {\n status: 'failed',\n version: from,\n expected: CURRENT_RESOURCE_VERSION,\n error:\n `resource.json is version ${from} but crouton expects ${CURRENT_RESOURCE_VERSION}; ` +\n 'auto-migration only runs in the dev environment — run crouton in dev to upgrade and commit it',\n };\n }\n\n try {\n const result = runResourceMigrations(raw);\n const validation = validateResourceJson(result.raw);\n if (!validation.success) {\n return {\n status: 'failed',\n version: from,\n expected: CURRENT_RESOURCE_VERSION,\n error: `migrated resource.json (v${from}→v${result.to}) is invalid: ${validation.error.message}`,\n };\n }\n writeFileSync(jsonPath, serializeResourceJson(result.raw), 'utf-8');\n return { status: 'migrated', from: result.from, to: result.to, written: true };\n } catch (err) {\n // MigrationPathError / MigrationStepError (or anything unexpected) → surfaced on status page.\n const error =\n err instanceof MigrationPathError || err instanceof MigrationStepError\n ? (err as Error).message\n : `migration failed: ${(err as Error).message}`;\n return { status: 'failed', version: from, expected: CURRENT_RESOURCE_VERSION, error };\n }\n};\n","import { type CrudOperation, isOperationEnabled, resolveDefinition } from '../crud.config';\nimport type { Resource } from './ResourceConfig.schema';\nimport { validateCustomRepository } from '../custom-repository/custom-repository.validate';\n\nconst ALL_OPS: readonly CrudOperation[] = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n];\n\n/**\n * Run structural checks on a fully-built Resource config before it is served.\n * Returns errors (→ resourceLoadErrorsRegistry) and warnings (→ resourceLoadReportRegistry).\n *\n * @param repositoryFileExistsOnDisk - pass true when a repository.ts file exists next to\n * a prisma resource, so the validator can warn that it will be ignored.\n */\nexport const validateResourceConfig = (\n config: Resource,\n opts?: { repositoryFileExistsOnDisk?: boolean },\n): { errors: string[]; warnings: string[] } => {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const definition = resolveDefinition(config);\n const enabledOps = ALL_OPS.filter((op) => isOperationEnabled(definition, op));\n\n if (enabledOps.length === 0) {\n warnings.push('All operations are disabled — this resource serves nothing.');\n }\n\n if (config.kind === 'custom') {\n if (config.database) {\n warnings.push(\n '\"database\" is set alongside kind: \"custom\" — it selects the client injected as ' +\n 'ctx.prisma, but data access still comes from repository.ts.',\n );\n }\n\n const repoError = validateCustomRepository(config, config.repository);\n if (repoError) errors.push(repoError);\n } else {\n if (opts?.repositoryFileExistsOnDisk) {\n warnings.push(\n 'repository.ts is present on a prisma resource and will be ignored — ' +\n 'set kind: \"custom\" if you want to use it for data access.',\n );\n }\n }\n\n return { errors, warnings };\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 * A `kind: \"custom\"` resource has no `schema.ts` — its json model is built\n * from the column `type`s — and supplies data access in `repository.ts`.\n *\n * `resource.ts` / `hooks.ts` / `schema.ts` / `repository.ts` do **not** import\n * from each other — this loader is the only place that stitches them together.\n */\n\nimport type { ZodObject, ZodRawShape } from 'zod';\n\nimport { loadActions } from '../action';\nimport { fromJson } from '../adapter';\nimport {\n loadCustomRepository,\n loadSubResourceRepositories,\n} from '../custom-repository';\nimport { IS_DEV } from '../dev-mode';\nimport { loadEnumRegistry } from '../enum-registry';\nimport { findModule, importDefault } from './module.loader';\nimport { loadResourceHooks, loadSubResourceHooks } from '../hooks';\nimport { migrateResourceJsonFile } from '../resource/MigrateResourceJson';\nimport { readResourceJson } from '../resource/ReadResourceJson';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport { validateResourceConfig } from '../resource/resource-config.validator';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport const loadResourceConfigsFromDir = async (\n dirPath: string,\n baseUrl?: string,\n enumsFile?: string,\n onResourceDir?: (route: string, dir: string) => void,\n): Promise<Resource[]> => {\n if (!existsSync(dirPath)) return [];\n\n resourceLoadErrorsRegistry.clear();\n resourceLoadReportRegistry.clear();\n\n const enums = loadEnumRegistry(dirPath, enumsFile);\n const entries = readdirSync(dirPath, { withFileTypes: true });\n const dirs = entries\n .filter((e: { isDirectory(): boolean }) => e.isDirectory())\n .map((e: { name: string }) => e.name);\n const configs: Resource[] = [];\n\n for (const dir of dirs) {\n const basePath = join(dirPath, dir);\n\n const schemaFile = findModule(basePath, 'schema');\n const schema = schemaFile\n ? await importDefault<ZodObject<ZodRawShape>>(schemaFile)\n : undefined;\n\n const hooks = await loadResourceHooks(basePath);\n\n const jsonFile = join(basePath, 'resource.json');\n if (existsSync(jsonFile)) {\n // Bring the file to the current schema version first. In dev this rewrites it on\n // disk; elsewhere an out-of-date file is reported as a failure (not migrated).\n const migration = migrateResourceJsonFile(jsonFile, { isDev: IS_DEV });\n if (migration.status === 'failed') {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: migration.error,\n version: migration.version,\n expectedVersion: migration.expected,\n });\n continue;\n }\n if (migration.status === 'migrated') {\n resourceLoadReportRegistry.record({\n state: 'migrated',\n name: dir,\n path: jsonFile,\n from: migration.from,\n to: migration.to,\n });\n // eslint-disable-next-line no-console\n console.info(\n `[crouton] migrated ${jsonFile}: v${migration.from} → v${migration.to}`,\n );\n }\n\n const result = readResourceJson(jsonFile);\n\n if (!result || !result.success) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: result?.error ?? `Failed to read ${jsonFile}`,\n });\n continue;\n }\n\n const json = result.data.json;\n\n // Draft resources live in the repo but are not loaded/served. They are still\n // migrated above (in dev) so they stay current until the flag is flipped.\n if (json.draft) {\n resourceLoadReportRegistry.record({\n state: 'draft',\n name: dir,\n path: jsonFile,\n version: json.schemaVersion,\n });\n continue;\n }\n // Custom resources own their data access; prisma resources never load a\n // repository, so a stray repository.ts on one is simply ignored.\n const errorsBeforeRepo = resourceLoadErrorsRegistry.getAll().length;\n const repository =\n json.kind === 'custom'\n ? await loadCustomRepository(basePath, json.name)\n : undefined;\n // If the repository.ts file exists but failed to import, an error was already\n // recorded by loadCustomRepository. Skip further validation to avoid a double error.\n const repositoryImportFailed = resourceLoadErrorsRegistry.getAll().length > errorsBeforeRepo;\n\n const actions = await loadActions(json.actions ?? [], basePath, 'row');\n const tableActions = await loadActions(\n json.tableActions ?? [],\n basePath,\n 'table',\n );\n const config = fromJson(\n json,\n schema,\n hooks,\n basePath,\n baseUrl,\n actions,\n tableActions,\n enums,\n repository,\n );\n\n if (repositoryImportFailed) continue;\n\n const repositoryFileExistsOnDisk =\n json.kind !== 'custom' && !!findModule(basePath, 'repository');\n const { errors, warnings } = validateResourceConfig(config, { repositoryFileExistsOnDisk });\n\n if (errors.length > 0) {\n for (const error of errors) {\n resourceLoadErrorsRegistry.record({ name: dir, path: jsonFile, error });\n }\n continue;\n }\n\n for (const warning of warnings) {\n resourceLoadReportRegistry.record({ state: 'warning', name: config.name, path: jsonFile, warning });\n }\n\n await loadSubResourceHooks(config.subResources ?? [], basePath);\n // A custom sub-resource brings its own data access; the parent's\n // repository delegates to it instead of querying a Prisma model.\n await loadSubResourceRepositories(config.subResources ?? [], config.name);\n onResourceDir?.(config.route, basePath);\n configs.push(config);\n continue;\n }\n\n const tsFile = findModule(basePath, 'resource');\n if (tsFile) {\n const config = await importDefault<Resource>(tsFile);\n if (!config) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: tsFile,\n error: 'resource.ts has no default export — add `export default { name, route, ... }`.',\n });\n continue;\n }\n if (config.draft) {\n resourceLoadReportRegistry.record({\n state: 'draft',\n name: dir,\n path: tsFile,\n version: config.schemaVersion,\n });\n continue;\n }\n\n const merged = hooks ? { ...config, hooks } : config;\n const { errors, warnings } = validateResourceConfig(merged);\n\n if (errors.length > 0) {\n for (const error of errors) {\n resourceLoadErrorsRegistry.record({ name: dir, path: tsFile, error });\n }\n continue;\n }\n\n for (const warning of warnings) {\n resourceLoadReportRegistry.record({ state: 'warning', name: merged.name, path: tsFile, warning });\n }\n\n configs.push(merged);\n }\n }\n\n return configs;\n};\n","import { type Resource } from '../resource/ResourceConfig.schema';\n\nexport abstract class ResourceConfigLoader {\n abstract loadAll(): Promise<Resource[]>;\n abstract loadByRoute(route: string): Promise<Resource | undefined>;\n /**\n * On-disk directory containing this resource's `resource.json`, if the\n * loader knows one (populated as a side effect of the last `loadAll()`).\n * Returns `undefined` for loaders with no filesystem concept (e.g. a\n * resource defined purely via `resource.ts`) or before any load has run.\n */\n getResourceDir(_route: string): string | undefined {\n return undefined;\n }\n}\n","import { loadResourceConfigsFromDir } from './index';\n\nimport { ResourceConfigLoader } from './resource-config.loader';\nimport { type Resource } from '../resource/ResourceConfig.schema';\n\nexport class FileSystemResourceConfigLoader extends ResourceConfigLoader {\n private dirsByRoute = new Map<string, string>();\n\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<Resource[]> {\n const dirsByRoute = new Map<string, string>();\n const configs = await loadResourceConfigsFromDir(\n this.dirPath,\n this.baseUrl,\n this.enumsFile,\n (route, dir) => dirsByRoute.set(route, dir),\n );\n this.dirsByRoute = dirsByRoute;\n return configs;\n }\n\n async loadByRoute(route: string): Promise<Resource | undefined> {\n const configs = await this.loadAll();\n return configs.find((c) => c.route === route);\n }\n\n override getResourceDir(route: string): string | undefined {\n return this.dirsByRoute.get(route);\n }\n}\n","import { CURRENT_RESOURCE_VERSION } from '@ghentcdh/crouton-core';\n\nimport { CUSTOM_OPS } from '../custom-repository';\nimport type { DataSourceRegistry } from '../data-source';\nimport type {\n CroutonStatus,\n DatabaseStatus,\n EnumGroup,\n EnumSections,\n I18nStatus,\n ResourceStatus,\n StatusSummary,\n} from './status.types';\nimport type { EnumRegistry } from '../enum-registry/enum-registry.types';\nimport type { Resource } from '../resource/ResourceConfig.schema';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\nimport type { TranslationRegistry } from '../translation/translation.registry';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst CONNECTION_STRING_PATTERN =\n /(?:postgresql|postgres|mysql|mongodb|sqlserver|sqlite):\\/\\/[^\\s\"')]+/gi;\n\nconst stripConnectionStrings = (message: string): string =>\n message.replace(CONNECTION_STRING_PATTERN, '[REDACTED]');\n\nexport const getCroutonVersion = (): string => {\n try {\n const startDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n\n let dir = startDir;\n while (dir !== dirname(dir)) {\n const pkgPath = join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n if (pkg.name === '@ghentcdh/crouton-api') return pkg.version;\n }\n dir = dirname(dir);\n }\n } catch {\n // ignore\n }\n return 'unknown';\n};\n\nexport const getVersion = (): string =>\n process.env['APP_VERSION'] ?? 'unknown';\n\nexport const getEnvironment = (): string =>\n process.env['ENVIRONMENT'] ?? process.env['NODE_ENV'] ?? 'unknown';\n\nexport const checkDatabases = async (\n registry: DataSourceRegistry,\n): Promise<DatabaseStatus[]> => {\n const results: DatabaseStatus[] = [];\n\n for (const { name, adapter } of registry.entries()) {\n try {\n await adapter.healthCheck?.();\n results.push({ name, connected: true });\n } catch (err) {\n results.push({\n name,\n connected: false,\n error: stripConnectionStrings((err as Error).message),\n });\n }\n }\n\n return results;\n};\n\nexport const getResourceStatus = (\n loadedConfigs: Resource[],\n): ResourceStatus[] => {\n const warningsByName = new Map<string, string[]>();\n for (const w of resourceLoadReportRegistry.getByState('warning')) {\n const existing = warningsByName.get(w.name) ?? [];\n existing.push(w.warning);\n warningsByName.set(w.name, existing);\n }\n\n const valid: ResourceStatus[] = loadedConfigs.map((c) => ({\n name: c.name,\n path: c.route,\n valid: true,\n version: c.schemaVersion ?? CURRENT_RESOURCE_VERSION,\n kind: c.kind ?? 'prisma',\n // Which operations the user's repository.ts actually implements.\n ...(c.kind === 'custom' && c.repository\n ? {\n customOperations: CUSTOM_OPS.filter(\n (op) => typeof (c.repository as any)?.[op] === 'function',\n ),\n }\n : {}),\n ...(c.sidebar?.hide ? { hidden: true } : {}),\n ...(warningsByName.has(c.name) ? { warnings: warningsByName.get(c.name) } : {}),\n }));\n\n const failed: ResourceStatus[] = resourceLoadErrorsRegistry\n .getAll()\n .map((e) => ({\n name: e.name,\n path: e.path,\n valid: false,\n error: e.error,\n version: e.version,\n expectedVersion: e.expectedVersion,\n }));\n\n // Drafts are present-but-not-served — informational, not errors (valid: true).\n const draft: ResourceStatus[] = resourceLoadReportRegistry\n .getByState('draft')\n .map((d) => ({\n name: d.name,\n path: d.path,\n valid: true,\n draft: true,\n version: d.version,\n }));\n\n return [...valid, ...failed, ...draft];\n};\n\nexport const buildSummary = (\n databases: DatabaseStatus[],\n resources: ResourceStatus[],\n): StatusSummary => {\n const databaseErrors = databases.filter((d) => !d.connected).length;\n const resourceErrors = resources.filter((r) => !r.valid).length;\n const warningCount = resources.reduce((acc, r) => acc + (r.warnings?.length ?? 0), 0);\n\n return {\n ok: databaseErrors === 0 && resourceErrors === 0,\n databaseErrors,\n resourceErrors,\n warningCount,\n };\n};\n\n/**\n * Extract built-in enums from Zod schema definitions.\n * These are system-level enums used throughout the framework.\n */\nconst getSystemEnums = (): EnumGroup[] => {\n return [\n {\n name: 'RelationType',\n category: 'Relationships',\n values: [\n { value: 'oneToOne', label: 'One to One' },\n { value: 'manyToOne', label: 'Many to One' },\n { value: 'oneToMany', label: 'One to Many' },\n { value: 'manyToMany', label: 'Many to Many' },\n ],\n },\n {\n name: 'DetailLayout',\n category: 'Layout',\n values: [\n { value: 'collapse', label: 'Collapse' },\n { value: 'row', label: 'Row' },\n ],\n },\n {\n name: 'SortDirection',\n category: 'Sorting',\n values: [\n { value: 'asc', label: 'Ascending' },\n { value: 'desc', label: 'Descending' },\n ],\n },\n {\n name: 'DisplayMode',\n category: 'Display',\n values: [\n { value: 'page', label: 'Page' },\n { value: 'modal', label: 'Modal' },\n ],\n },\n {\n name: 'ModalSize',\n category: 'Display',\n values: [\n { value: 'xs', label: 'Extra Small' },\n { value: 'sm', label: 'Small' },\n { value: 'lg', label: 'Large' },\n { value: 'xl', label: 'Extra Large' },\n ],\n },\n ];\n};\n\n/**\n * Convert project enum registry into EnumGroup format.\n * Groups enums from crouton.enums.json by generic category.\n */\nconst getProjectEnums = (enumRegistry: EnumRegistry): EnumGroup[] => {\n if (!enumRegistry) return [];\n return Object.entries(enumRegistry).map(([name, entries]) => ({\n name,\n category: 'Project',\n values: entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n })),\n }));\n};\n\n/**\n * Collect all enums (system and project) for display on status page.\n */\nconst getEnums = (enumRegistry: EnumRegistry): EnumSections => {\n return {\n system: getSystemEnums(),\n project: getProjectEnums(enumRegistry),\n };\n};\n\n/** Count leaf string keys in a nested object, and how many are empty. */\nconst countKeys = (\n obj: Record<string, unknown>,\n prefix = '',\n): { total: number; empty: number } => {\n let total = 0;\n let empty = 0;\n for (const [, v] of Object.entries(obj)) {\n if (typeof v === 'string') {\n total++;\n if (v === '') empty++;\n } else if (v && typeof v === 'object' && !Array.isArray(v)) {\n const sub = countKeys(v as Record<string, unknown>, prefix);\n total += sub.total;\n empty += sub.empty;\n }\n }\n return { total, empty };\n};\n\nconst getI18nStatus = (\n translationRegistry?: TranslationRegistry,\n): I18nStatus | undefined => {\n if (!translationRegistry?.active) return undefined;\n const languages = [...translationRegistry.languages];\n const bundles = languages.map((language) => {\n const bundle = translationRegistry.bundleFor(language);\n const { total, empty } = countKeys(bundle as Record<string, unknown>);\n return { language, keyCount: total, emptyKeys: empty };\n });\n return {\n active: true,\n defaultLanguage: translationRegistry.defaultLanguage,\n languages,\n bundles,\n };\n};\n\nexport const buildStatus = async (\n registry: DataSourceRegistry,\n loadedConfigs: Resource[],\n enumRegistry: EnumRegistry,\n translationRegistry?: TranslationRegistry,\n): Promise<CroutonStatus> => {\n const databases = await checkDatabases(registry);\n const resources = getResourceStatus(loadedConfigs);\n const summary = buildSummary(databases, resources);\n\n return {\n version: getVersion(),\n croutonVersion: getCroutonVersion(),\n environment: getEnvironment(),\n summary,\n databases,\n resources,\n enums: getEnums(enumRegistry),\n ...(translationRegistry?.active && {\n i18n: getI18nStatus(translationRegistry),\n }),\n };\n};\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport { DataSourceRegistry } from '../data-source';\nimport { ResourceConfigRegistry } from '../resource-config.registry';\nimport { buildStatus } from './status.service';\nimport type { EnumRegistry } from '../enum-registry/enum-registry.types';\nimport type { TranslationRegistry } from '../translation/translation.registry';\n\nexport const createStatusController = (\n enumRegistry: EnumRegistry,\n translationRegistry?: TranslationRegistry,\n prefix?: string,\n) => {\n @Controller(prefix ? `${prefix}/crouton` : 'crouton')\n @ApiTags('Status')\n class StatusController {\n constructor(\n public readonly dataSourceRegistry: DataSourceRegistry,\n public readonly configRegistry: ResourceConfigRegistry,\n ) {}\n\n @Get('status.json')\n @ApiOperation({ summary: 'Crouton system status (db, resources, version)' })\n @ApiResponse({ status: 200, description: 'System status' })\n async getStatus() {\n const configs = await this.configRegistry.getAll();\n return buildStatus(\n this.dataSourceRegistry,\n configs,\n enumRegistry,\n translationRegistry,\n );\n }\n }\n\n Reflect.defineMetadata(\n 'design:paramtypes',\n [DataSourceRegistry, ResourceConfigRegistry],\n StatusController,\n );\n\n return StatusController;\n};\n","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport { buildResourceJsonSchema, registerResourceExtensions } from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from './action';\nimport { fromJson } from './adapter';\nimport type { CroutonAppConfig } from './app-config';\nimport type { EnumRegistry } from './enum-registry';\nimport type { ResourceHooks } from './hooks';\nimport {\n buildDefinitionPayload,\n buildResourceJsonPayload,\n buildViewsPayload,\n} from './operations/payload-builders';\n\nexport type ParseSchemaView = 'schemas' | 'definition' | 'resource.json';\n\nexport interface ParseSchemaInput {\n /** Raw resource.json (validated internally) or an already-parsed ResourceJson. */\n json: unknown;\n /** Sibling schema.ts default export. Required for prisma resources; omit for kind:\"custom\". */\n schema?: ZodObject<ZodRawShape>;\n /** Enables sibling-resource features (extend columns, resource-ref options, sub-resources). */\n dirPath?: string;\n enums?: EnumRegistry;\n hooks?: ResourceHooks;\n actions?: ResourceRowAction[];\n tableActions?: ResourceTableAction[];\n}\n\nexport type ParseAppConfig = Pick<\n CroutonAppConfig,\n 'baseUrl' | 'prefix' | 'extensions' | 'schemaEnricher'\n>;\n\n/**\n * Compile a single resource to its schema payload without booting a Nest module.\n *\n * `prefix` is accepted for API parity with `forResourceDir` but ignored here —\n * only `baseUrl` affects URIs in the payload.\n *\n * Returns `undefined` for `view: 'schemas'` when the resource declares no views.\n *\n * Without `dirPath`, features that read sibling files are skipped: extend columns,\n * resource-ref column options, and sub-resource views.\n */\nexport const parseSchema = (\n input: ParseSchemaInput | unknown,\n appConfig: ParseAppConfig,\n view: ParseSchemaView = 'schemas',\n): Record<string, unknown> | undefined => {\n if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);\n\n const normalized: ParseSchemaInput =\n input !== null &&\n typeof input === 'object' &&\n 'json' in (input as object)\n ? (input as ParseSchemaInput)\n : { json: input };\n\n const parseResult = buildResourceJsonSchema().safeParse(normalized.json);\n if (!parseResult.success) {\n throw new Error(\n `Resource cannot be parsed: ${parseResult.error.message}`,\n );\n }\n\n const resource = fromJson(\n parseResult.data,\n normalized.schema,\n normalized.hooks,\n normalized.dirPath,\n appConfig.baseUrl,\n normalized.actions,\n normalized.tableActions,\n normalized.enums ?? {},\n undefined,\n );\n\n let payload: Record<string, unknown> | undefined;\n if (view === 'schemas') {\n payload = buildViewsPayload(resource, appConfig.baseUrl);\n } else if (view === 'definition') {\n payload = buildDefinitionPayload(resource);\n } else {\n payload = buildResourceJsonPayload(resource, appConfig.baseUrl);\n }\n\n if (payload && appConfig.schemaEnricher) {\n payload = { ...payload, ...appConfig.schemaEnricher(payload) };\n }\n\n return payload;\n};\n"],"mappings":"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","names":["ResourceConfigLoader","externalRouteFor","isOperationEnabled","isOperationExternal","resolveDefinition","schemaFor","getImportMetaUrl","document","URL","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","importMetaUrl","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","q","RequestSchemaWithOffset","transform","schema","offset","offsetOf","params","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","isNullableProperty","property","prop","Array","isArray","includes","anyOf","some","s","Builder","type","ElementBuilder","options","_rule","label","opt","colspan","rowspan","showWhen","scope","schema","rule","hideWhen","disableWhen","effect","condition","patch","baseFields","Object","keys","length","ContainerBuilder","children","addControl","arg","push","resolveShortcut","addControls","first","rest","name","entries","builder","buildElements","map","child","build","ControlType","number","string","integer","autocomplete","textArea","markdown","array","object","custom","select","mutliSelect","toggle","boolean","link","relation","date","dateTime","dateRange","ControlBuilder","ElementBuilder","_detail","scope","type","opt","format","styles","asObject","property","properties","asCustom","builder","setCustomRender","customRender","detail","layoutBuilder","label","elementLabelProp","addAction","action","actions","options","push","detailFixed","hideActions","layout","labelKey","readonly","dataField","control","width","named","isNamed","includes","wrapper","customLabel","placeHolder","placeholder","hideLabel","build","undefined","_rule","rule","LayoutType","Horizontal","Vertical","Grid","Collapse","Group","LayoutBuilder","ContainerBuilder","type","horizontal","LayoutType","Horizontal","vertical","Vertical","grid","columns","layout","Grid","undefined","opt","collapse","Collapse","group","Group","title","titleKey","addControl","arg","options","resolveShortcut","name","control","ControlBuilder","properties","rest","Object","keys","length","build","elements","buildElements","baseFields","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","ContainerBuilder","LayoutType","Horizontal","init","resolveShortcut","name","elements","buildElements","baseFields","import_zod","ActionMetadataSchema","z","object","id","string","label","optional","icon","tooltip","condition","custom","ResourceLinkActionSchema","extend","type","literal","href","ResourceRowProcedureActionSchema","method","data","record","unknown","procedure","v","ResourceTableProcedureActionSchema","ResourceRowActionSchema","union","ResourceTableActionSchema","import_zod","LayoutControlSchema","z","union","string","object","id","colspan","number","int","min","max","optional","rowspan","width","label","hideLabel","boolean","type","options","record","unknown","LayoutNodeSchema","lazy","enum","columns","title","titleKey","controls","array","items","LayoutSchema","form","view","table","import_zod","import_zod","import_zod","RelationType","z","enum","DetailControlSchema","object","property","string","type","optional","options","record","unknown","hideLabel","boolean","width","DetailConfigSchema","layout","titleKey","controls","array","RelationFieldInputOptionsSchema","colspan","number","default","sort","sortDir","direction","displayKey","resource","catchall","FieldInputSchema","customRender","format","relationType","foreignKey","relation","position","defaultValue","union","detail","FieldVariantSchema","stripNull","obj","out","k","v","Object","entries","mergeFieldVariant","base","override","merged","mergedOptions","labelFromId","id","words","replace","trim","charAt","toUpperCase","slice","toLowerCase","normalizeLabel","obj","label","CalculatedColumnSchema","z","object","id","string","alias","label","optional","sqlExpression","type","enum","position","number","hiddenInTable","boolean","hiddenInView","fieldInput","FieldInputSchema","transform","normalizeLabel","import_zod","import_zod","ColumnTypeShorthandSchema","z","enum","JsonSchemaFragmentSchema","lazy","object","type","union","string","array","optional","format","unknown","const","nullable","boolean","properties","record","required","items","additionalProperties","title","description","default","minimum","number","maximum","minLength","maxLength","pattern","catchall","ColumnTypeSchema","SHORTHAND_FRAGMENTS","integer","date","isShorthand","NESTED_SHORTHANDS","normalizeFragment","fragment","out","expanded","undefined","Array","isArray","Object","assign","existingRequired","hoistedRequired","fromEntries","entries","map","key","value","v","push","_r","rest","length","columnTypeToJsonSchema","columnTypeName","raw","find","t","isObjectColumnType","isArrayColumnType","WhenConditionSchema","z","object","field","string","eq","unknown","optional","neq","exists","boolean","notExists","JsonColumnSchema","id","column","label","hiddenInTable","default","hiddenInForm","hiddenInView","sortable","defaultSort","searchable","filterable","createable","updateable","hideLabel","showWhen","hideWhen","disabledWhen","displayKey","sortId","enum","idField","showInLookup","type","ColumnTypeSchema","required","columnType","fieldInput","FieldInputSchema","fieldView","FieldVariantSchema","fieldTable","extend","columns","record","import_zod","ParentRefSchema","z","object","route","string","param","default","idType","enum","optional","resourceControllerPath","parent","import_zod","ResourceKindSchema","z","enum","default","import_zod","SidebarGroupSchema","z","object","label","string","optional","position","number","SidebarSchema","hide","boolean","default","group","import_zod","ActionConditionSchema","z","object","field","string","op","enum","default","value","unknown","optional","ActionSchema","type","id","label","icon","tooltip","condition","JsonProcedureActionSchema","extend","literal","procedure","method","data","record","JsonLinkActionSchema","href","blank","boolean","transformAction","action","JsonActionSchema","union","transform","CORE_RESOURCE_KEYS","Set","registry","Map","registerResourceExtension","name","schema","has","Error","set","registerResourceExtensions","map","Object","entries","forEach","k","s","getResourceExtensions","import_zod","JsonIncludeEntrySchema","z","lazy","union","string","object","relation","include","array","optional","orderBy","record","unknown","BASELINE_RESOURCE_VERSION","CURRENT_RESOURCE_VERSION","import_zod","import_zod","SecuritySchema","z","union","object","public","literal","guard","string","array","min","ExternalOpEntry","z","object","uri","string","method","optional","security","SecuritySchema","OpEntry","union","boolean","JsonOperationsSchema","findAll","default","findOne","create","update","patch","delete","buildSubResourceOperations","ops","baseUri","idField","idPlaceholder","JsonColumnsMapSchema","z","record","string","JsonColumnSchema","omit","id","catchall","unknown","ColumnsSchema","JsonDisplaySchema","object","mode","enum","default","customComponent","nullable","optional","normalizeColumns","columns","undefined","raw","Array","isArray","Object","entries","map","col","label","labelFromId","ResourceJsonShape","$schema","schemaVersion","number","int","positive","draft","boolean","kind","ResourceKindSchema","name","route","model","tag","title","table","idType","database","parent","ParentRefSchema","sidebar","SidebarSchema","parse","display","security","SecuritySchema","operations","JsonOperationsSchema","calculatedColumns","array","CalculatedColumnSchema","actions","JsonActionSchema","tableActions","modalSize","include","JsonIncludeEntrySchema","layout","LayoutSchema","refineByKind","obj","ctx","addIssue","code","path","message","length","fieldInput","format","type","param","buildResourceJsonSchema","ext","getResourceExtensions","extShape","fromEntries","schema","shape","size","extend","preprocess","superRefine","transform","BASELINE_RESOURCE_VERSION","defaultOps","findAll","findOne","create","update","patch","delete","ResourceJsonSchema","MigrationPathError","Error","message","name","MigrationStepError","MIGRATIONS","resourceVersionOf","raw","v","Number","isInteger","BASELINE_RESOURCE_VERSION","runResourceMigrations","target","CURRENT_RESOURCE_VERSION","migrations","from","to","applied","MigrationPathError","current","step","find","m","migrate","err","MigrationStepError","description","message","push","schemaVersion","_old","rest","resolveViewField","c","mergeFieldVariant","fieldInput","fieldView","resolveTableField","fieldTable","isBoolean","col","fieldInput","type","columnType","isRelation","format","isAutocomplete","isRecordCell","isDateRange","isObjectColumn","isObjectColumnType","isArrayColumn","isArrayColumnType","isObjectCell","displayKey","colPosition","col","i","fieldInput","position","sortByPosition","cols","map","sort","a","b","columnForContext","ctx","fieldView","fieldTable","toViewColumn","id","label","sortable","searchable","deriveSortId","col","sortable","sortId","base","column","id","fi","fieldInput","opts","options","isRelation","format","relationType","type","resource","key","displayKey","undefined","labelKey","path","includes","endsWith","slice","length","isValueLabel","enum","emitObject","resolveDefaultSort","tableCols","allColumns","isSortable","c","sortCol","find","defaultSort","idField","allowAdditionalProperties","schema","props","value","Object","values","dropNullableFromRequired","required","Array","isArray","filter","key","isNullableProperty","enforceRequiredMinLength","prop","applySchemaTransforms","SHARED_CELL_OPTION_KEYS","pickSharedCellOptions","col","options","fieldInput","Object","fromEntries","filter","key","undefined","map","buildTableUiSchema","cols","layout","TableBuilder","init","addControls","cellBuilder","isBoolean","BooleanCellBuilder","TextCellBuilder","builder","properties","id","displayKey","sortId","setSortId","build","colMap","c","elements","el","scope","replace","fieldInputOptions","isRecordCell","isDateRange","isObjectCell","dataPathOption","column","dataPath","derivedSortId","deriveSortId","sortOptions","sortable","relationTypeOption","relationType","format","label","type","buildConditionSchema","when","notExists","not","minLength","exists","neq","undefined","const","eq","applyColumnRule","control","col","disabledWhen","disableWhen","field","buildConditionSchema","when","showWhen","hideWhen","scope","schema","buildDetailLayout","detail","inner","layout","LayoutBuilder","collapse","horizontal","addControls","controls","map","dc","ctrl","ControlBuilder","properties","property","type","markdown","options","hideLabel","width","titleKey","defaultControlFormat","isObjectColumn","isArrayColumn","typeName","columnTypeName","format","columnTypeToJsonSchema","buildFormControl","id","fieldInput","colspan","relationType","detailLayout","detailFixed","undefined","customRender","setCustomRender","label","buildFormUiSchema","cols","grid","addControl","build","isVisibleInMode","c","mode","hiddenInTable","hiddenInView","buildCalculatedElement","type","scope","id","options","label","fieldInput","format","calcPosition","position","injectCalculatedColumnsIntoView","viewConfig","calculated","length","visible","filter","jsonSchema","json_schema","properties","title","uiSchema","ui_schema","existing","elements","tagged","map","el","i","pos","Infinity","sort","a","b","t","columns","entry","undefined","splice","push","injectCalculatedColumns","tableView","injectCalculatedColumnsToView","import_zod","optionValues","col","values","fieldInput","options","Array","isArray","undefined","unwrapped","map","v","value","length","columnToJsonSchemaProperty","property","type","isAutocomplete","columnTypeToJsonSchema","title","label","id","defaultValue","default","enum","columnTypeSchemaSource","schemaCols","properties","import_zod","isInstanceOf","zodSchema","className","z","ZodCustom","result","safeParse","success","issue","error","issues","expected","message","includes","jsonSchemaOverride","jsonSchema","ZodDate","type","format","ZodBigInt","unwrap","schema","s","t","_zod","def","innerType","isDecimalField","zodType","inner","jsonSchemaOpts","unrepresentable","override","buildContainerForNode","node","type","builder","LayoutBuilder","collapse","title","titleKey","group","horizontal","vertical","grid","columns","colspan","undefined","rowspan","label","resolveControlId","ctrl","id","applyControlOverrides","base","width","hideLabel","options","control","buildNodeInto","colMap","warn","seenIds","container","controls","length","col","get","add","buildFormControl","addControl","items","item","child","buildFormUiSchemaFromLayout","cols","console","Map","map","c","Set","root","unreferenced","filter","has","build","flattenLayoutControlIds","ids","visit","n","push","orderTableColumnsFromLayout","view","node","warn","console","orderedIds","flattenLayoutControlIds","length","elements","ui_schema","columns","elementById","Map","map","el","id","scope","replace","columnById","c","knownIds","Set","keys","filter","Boolean","reorderedElements","reorderedColumns","seen","has","add","get","push","col","patchFilterProperties","jsonSchema","columns","length","properties","col","fieldInput","format","id","opts","options","base","label","fromField","toField","dateProp","title","type","prop","values","ft","enum","injectFieldDefaults","defaultValue","undefined","default","zodSchemaSource","schema","schemaCols","schemaKeys","Set","Object","keys","shape","schemaIds","map","c","filter","has","mask","fromEntries","picked","pick","toJSONSchema","target","jsonSchemaOpts","NON_NULL_TYPES","SHAPE_KEYS","applyRequiredColumns","required","Array","isArray","delete","idField","createable","updateable","add","property","some","key","size","buildView","source","visible","buildUiSchema","sort","schemaVisible","visibleCols","sortByPosition","isRelation","applySchemaTransforms","nonEditableIds","k","json_schema","ui_schema","toViewColumn","emptyTableView","additionalProperties","buildTableUiSchema","buildViewsWithSource","layout","views","tableCols","columnForContext","table","hiddenInTable","defaultSort","resolveDefaultSort","orderTableColumnsFromLayout","formUiBuilder","form","cols","buildFormUiSchemaFromLayout","buildFormUiSchema","hiddenInForm","filterable","viewCols","viewUiBuilder","view","hiddenInView","buildViews","columnTypeSchemaSource","buildViewsFromColumns","columns","length","undefined","buildJsonSchema","cols","properties","c","column","id","type","keyPath","displayKey","split","target","i","segment","title","label","columnToJsonSchemaProperty","opts","fieldInput","options","isObject","emitObject","columnType","defaultValue","default","schema","applySchemaTransforms","fixNestedScopes","uiSchema","colMap","Object","fromEntries","map","elements","el","scope","replace","col","propPath","k","join","makeView","visible","buildUiSchema","json_schema","ui_schema","toViewColumn","views","tableCols","sortByPosition","filter","hiddenInTable","columnForContext","table","buildTableUiSchema","defaultSort","resolveDefaultSort","emptyTableView","formCols","hiddenInForm","form","buildFormUiSchema","applyRequiredColumns","viewCols","hiddenInView","viewView","view","keys","import_zod","ViewColumnConfigSchema","z","object","id","string","label","optional","sortable","boolean","searchable","fieldInput","FieldInputSchema","ViewConfigSchema","json_schema","record","unknown","ui_schema","ui","data","columns","array","defaultSort","viewDefList","ViewDefEnum","enum","import_zod","EnumEntrySchema","z","object","value","unknown","label","string","EnumRegistrySchema","record","array","default","import_zod","import_zod","import_zod","import_zod","DataSourceShape","z","object","name","string","urlEnv","optional","generatedTypesImport","type","default","boolean","adapter","enum","prismaSchema","prismaConfig","zodOutput","clientOutput","transformDataSource","data","DataSourceSchema","transform","import_zod","ValueSchema","z","object","value","unknown","label","string","ValueLabelColumnSchema","field","values","array","default","enumName","optional","CompiledSubResourceConfigSchema","z","object","column","string","relation","childRoute","childKind","enum","default","childDir","optional","childModel","foreignKey","name","title","idField","idType","views","record","ViewConfigSchema","operations","JsonOperationsSchema","actions","array","JsonActionSchema","modalSize","display","JsonDisplaySchema","include","JsonIncludeEntrySchema","calculatedColumns","CalculatedColumnSchema","includeInFindOne","boolean","hiddenInTable","findOneOrderBy","unknown","valueLabelColumns","ValueLabelColumnSchema","relationType","import_zod","import_zod","JsonSchemaInputSchema","z","object","type","literal","properties","record","string","unknown","required","array","optional","additionalProperties","boolean","SchemaInputSchema","union","custom","val","ZodObject","ExternalOperationDefSchema","z","object","uri","string","method","optional","OperationDefSchema","union","literal","schema","SchemaInputSchema","security","SecuritySchema","ResourceDefinitionSchema","findAll","findOne","create","update","patch","delete","DefinitionCallbackSchema","function","input","output","DefinitionSchema","import_zod","LookupSchema","z","object","key","string","label","optional","CompiledResourceSchema","ResourceJsonShape","extend","route","z","string","valueLabelColumns","array","ValueLabelColumnSchema","default","subResources","lazy","CompiledSubResourceConfigSchema","lookup","LookupSchema","optional","views","record","ViewConfigSchema","definition","DefinitionSchema","idField","idType","enum","import_zod","import_zod","RulesetSchema","z","object","hideIdInTable","boolean","default","hideIdInForm","hideIdInView","hideTimestamps","hideForeignKeys","includeRelations","hideRelationsInTable","showRelationsInForm","enumValueLabel","sharedEnums","defaultOperations","JsonOperationsSchema","parse","I18nConfigSchema","defaultLanguage","string","languages","array","min","translationsDir","CroutonConfigSchema","title","resourcesDir","dataSourcesDir","schemaExportName","enumsFile","rules","sidebarGroups","record","SidebarGroupSchema","autoSave","i18n","optional","CONFIG_FILES","import_zod","NestedStringRecord","z","lazy","record","string","union","TranslationBundleSchema","object","app","title","optional","sidebarGroups","resources","sidebar","columns","actions","subResources","enums","ui","validation","passthrough","resourceTitleKey","resource","resourceSidebarKey","columnKey","column","actionKey","action","subResourceTitleKey","sub","subResourceColumnKey","enumKey","enumName","value","sidebarGroupKey","group","validationKey","code","getNestedValue","obj","path","keys","split","current","key","undefined","createTranslator","bundles","language","defaultLanguage","langBundle","defaultBundle","fallback","value","parseAcceptLanguage","header","entries","part","split","trimmed","trim","tag","params","q","param","match","parseFloat","isNaN","push","toLowerCase","sort","a","b","resolveLanguage","acceptLanguage","supported","defaultLanguage","supportedLower","map","s","exactIdx","indexOf","base","baseIdx","import_common","import_core","import_zod","SidebarLeafSchema","z","object","kind","literal","default","id","string","label","position","number","optional","SidebarGroupSchema","children","array","SidebarNodeSchema","discriminatedUnion","byPosition","a","b","position","label","localeCompare","buildLayoutPayload","configs","sidebarGroups","title","autoSave","isDev","visible","filter","c","sidebar","hide","views","parent","topLevel","groupMap","Map","Object","entries","map","slug","cfg","labelFromId","children","leaf","SidebarLeafSchema","parse","id","name","tag","groupSlug","group","has","set","get","push","groups","g","length","kind","sort","import_common","parseBooleanEnv","value","includes","trim","toLowerCase","IS_DEV","process","env","readResourceJson","jsonPath","existsSync","undefined","fileContent","JSON","parse","readFileSync","err","success","error","message","resource","buildResourceJsonSchema","safeParse","data","json","dir","dirname","import_node_fs","import_node_path","resolveChildResourceDetailed","resourcePath","parentDir","attempted","endsWith","directPath","resolve","push","existsSync","result","readResourceJson","success","ok","value","data","reason","error","childName","replace","childJsonPath","dirname","err","message","resolveChildResource","resolution","undefined","expandExtendColumns","columns","dirPath","result","col","extend","push","resolved","resolveChildResource","console","warn","id","refColumns","json","parentColumnKey","column","refCol","idField","virtualId","displayKey","hiddenInTable","hiddenInForm","hiddenInView","override","virtualCol","label","columnType","undefined","sortable","fieldInput","buildValueLabelColumns","flatMap","c","opts","options","emitObject","Array","isArray","values","field","enum","enumName","applyRelationFormatDefault","cols","map","fi","resource","format","type","resolveColumnFieldVariants","fieldView","resolveViewField","fieldTable","resolveTableField","clone","obj","JSON","parse","stringify","cloneResource","config","definition","rest","localized","translateEnumOptions","columns","t","col","enum","opts","fieldInput","options","Array","isArray","values","entry","label","enumKey","String","value","translateValueLabelEntries","vlCols","vlc","enumName","patchViewTitles","views","columnLabels","patched","viewName","view","Object","entries","patchedView","props","json_schema","properties","key","prop","translated","get","title","map","vc","id","patchUiElements","elements","el","element","scope","match","exec","nested","uiSchema","ui_schema","uiElements","localizeResource","name","resourceTitleKey","tag","sidebar","sidebarTranslation","resourceSidebarKey","Map","columnKey","set","valueLabelColumns","buildValueLabelColumns","actions","a","actionKey","tableActions","subResources","sub","subName","childRoute","subResourceTitleKey","subColumnLabels","subResourceColumnKey","ResourceConfigRegistry","configs","translationRegistry","localizedCache","Map","loader","initialConfigs","setTranslationRegistry","registry","getAll","language","IS_DEV","loadAll","clear","active","map","c","getLocalized","getByRoute","route","fresh","loadByRoute","undefined","localize","config","find","findById","id","all","getResourceDir","langMap","get","set","localized","t","translatorFor","localizeResource","languageStore","AsyncLocalStorage","runWithLanguage","language","fn","run","getRequestLanguage","defaultLanguage","getStore","createAppLayoutController","configs","sidebarGroups","title","autoSave","translationRegistry","i18nConfig","prefix","layoutPayload","buildLayoutPayload","IS_DEV","AppLayoutController","configRegistry","getLayout","language","getRequestLanguage","payload","fresh","getAll","translateSidebarGroups","translateTitle","active","lang","defaultLanguage","bundle","bundleFor","i18n","languages","current","ui","getTranslations","validation","summary","status","description","Reflect","defineMetadata","ResourceConfigRegistry","groups","registry","t","translatorFor","translated","slug","cfg","Object","entries","label","sidebarGroupKey","import_node_path","fileExists","p","access","findConfigPath","cwd","dir","resolve","name","CONFIG_FILES","candidate","join","parent","dirname","undefined","loadConfig","pathResolve","process","path","Error","config","endsWith","JSON","parse","readFile","mod","default","parsed","CroutonConfigSchema","configDir","import_common","CroutonValidationError","Error","errors","name","import_node_fs","import_node_path","loadTranslationBundles","translationsDir","existsSync","bundles","entries","readdirSync","withFileTypes","entry","isFile","name","endsWith","lang","replace","JSON","parse","readFileSync","join","TranslationRegistry","bundles","translationsDir","i18nConfig","loadTranslationBundles","languages","defaultLanguage","active","Object","keys","length","translatorFor","language","IS_DEV","createTranslator","bundleFor","CroutonValidationExceptionFilter","translationRegistry","catch","exception","host","res","switchToHttp","getResponse","errors","translateErrors","status","json","statusCode","message","error","language","getRequestLanguage","t","translatorFor","map","field","code","key","validationKey","translated","replace","import_common","import_swagger","import_common","import_zod","ActionMetadataSchema","z","object","id","string","label","optional","icon","tooltip","condition","custom","ResourceLinkActionSchema","extend","type","literal","href","ResourceRowProcedureActionSchema","method","data","record","unknown","procedure","v","ResourceTableProcedureActionSchema","ResourceRowActionSchema","union","ResourceTableActionSchema","isRowProcedureAction","action","isTableProcedureAction","import_node_fs","import_node_path","_require","createRequire","__filename","IS_ESM","findModule","dir","name","ext","p","join","existsSync","undefined","IS_VITE","globalThis","__vite_ssr_import__","importDefault","filePath","onError","importPath","IS_DEV","Date","now","mod","default","pathToFileURL","href","error","console","import_node_path","loadActions","jsonActions","basePath","scope","tag","results","action","type","push","file","findModule","join","procedure","console","warn","id","mod","importDefault","resolveDefinition","config","def","definition","isOperationEnabled","op","schemaFor","entry","undefined","schema","isOperationExternal","externalRouteFor","uri","opSecurity","security","securityFor","moduleDefault","securityForSub","sub","operations","import_zod","CUSTOM_OPS","PARENT_METHOD","findAll","findOne","create","update","patch","delete","CustomRepositorySchema","z","custom","value","ResourceLoadErrorsRegistry","errors","record","e","push","getAll","clear","resourceLoadErrorsRegistry","REPOSITORY_MODULE","loadCustomRepository","basePath","resourceName","file","findModule","undefined","failure","repository","importDefault","error","resourceLoadErrorsRegistry","record","name","path","Error","message","String","loadSubResourceRepositories","subResources","parentName","sub","childKind","childDir","childRoute","import_common","PRISMA_NOT_FOUND_CODE","DEFAULT_ID_TYPE","DEFAULT_ID_FIELD","import_common","import_common","import_common","childRepositoryFn","sub","op","parentName","repo","repository","method","PARENT_METHOD","NotImplementedException","childRoute","fn","update","undefined","bind","childCtx","parentConfig","prisma","parentId","params","id","request","dataSources","resolve","entries","config","offset","offsetOf","parent","route","param","parentIdFromRequest","fallback","raw","applyValueLabelColumns","row","cols","length","out","field","values","toValueLabel","normalizeValueLabels","data","Array","isArray","fromValueLabel","castExpression","col","type","sqlExpression","defaultValueForType","coerceColumnValue","v","Boolean","undefined","String","Number","buildCalculatedColumnSql","tableName","ids","idField","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","buildFindOneIncludes","subResources","configInclude","autoSubs","filter","s","includeInFindOne","childKind","flatIncludes","findOneOrderBy","import_common","LanguageInterceptor","registry","intercept","context","next","http","switchToHttp","request","getRequest","response","getResponse","acceptLanguage","headers","resolved","resolveLanguage","languages","defaultLanguage","setHeader","runWithLanguage","handle","resolveValueLabelColumns","route","bootTimeCols","configRegistry","childRoute","language","getRequestLanguage","localized","getByRoute","valueLabelColumns","sub","subResources","find","s","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","ReadRepository","prisma","adapter","client","prismaModel","config","listSelect","oneSelect","configRegistry","tableName","table","model","toId","id","idType","String","buildWhere","filter","buildFilterWhere","projection","op","select","safeSort","sort","sortDir","undefined","buildSort","parentHookContext","parentId","route","param","findAll","params","request","subResources","vlCols","resolveValueLabelColumns","valueLabelColumns","filterWhere","searchWhere","buildSearchOrWhere","q","where","AND","query","take","pageSize","skip","offsetOf","orderBy","sanitizeValueLabelSort","prismaSubResources","s","childKind","oneToManySubResources","relationType","countableSubResources","hiddenInTable","manyToOneIncludes","map","relation","flatIncludes","length","Object","fromEntries","r","configInclude","buildIncludeClause","include","countableRelations","Set","filteredConfigInclude","entries","key","has","safeConfigInclude","keys","mergedInclude","countClause","_count","rows","findMany","mapped","row","rest","counts","column","withCalc","mergeCalculatedColumnsForRows","calculatedColumns","idField","lookup","labels","label","OR","path","buildNestedPath","split","contains","count","findOne","buildFindOneIncludes","record","findUnique","NotFoundException","name","enriched","sub","nested","Array","isArray","enrichedNested","childModel","findAllByParent","childRoute","find","Error","childRepositoryFn","result","childCtx","parentConfig","data","decorated","hooks","afterRead","Promise","all","dataSource","parent","subVlCols","labeled","applyValueLabelColumns","foreignKey","includeClause","childSort","orderableChildSort","buildChildSortClause","findOneChild","childId","BadRequestException","findFirst","import_common","includeRelationNames","include","Set","map","e","relation","PRISMA_RELATION_WRITE_KEYS","isPrismaRelationWrite","value","Array","isArray","Object","keys","some","k","has","stripSubResourceKeys","config","data","subKeys","subResources","s","column","size","fromEntries","entries","filter","stripNonCreateableChildFields","sub","nonCreateable","views","form","columns","c","createable","id","WriteRepository","prisma","adapter","client","prismaModel","toId","idType","String","notFound","NotFoundException","name","parentHookContext","parentId","route","param","create","_request","update","idField","where","code","PRISMA_NOT_FOUND_CODE","patch","delete","delegateChildWrite","op","childId","request","undefined","BadRequestException","childRoute","fn","childRepositoryFn","ctx","childCtx","parentConfig","payload","stripped","normalized","normalizeValueLabels","valueLabelColumns","hooks","beforeWrite","dataSource","parent","result","afterWrite","createChild","childKind","childModel","Error","foreignKey","prepared","includeKeys","preparedEntries","prismaData","v","updateChild","parentIdFromRequest","afterHook","DEFAULT_ID_FIELD","deleteChild","deleteMany","count","DB_CHECK_TIMEOUT_MS","PrismaDataSourceAdapter","kind","client","prismaClient","supports","model","healthCheck","c","Promise","race","$queryRaw","_","reject","setTimeout","Error","disconnect","$disconnect","prismaModel","delegate","findAll","params","ctx","reader","ReadRepository","config","listSelect","oneSelect","configRegistry","data","count","all","request","filter","q","undefined","findOne","id","e","NotFoundException","create","WriteRepository","update","patch","delete","findAllByParent","parentId","sub","childRoute","findOneChild","childId","createChild","updateChild","deleteChild","import_zod","WriteOpSchema","z","enum","ReadOpSchema","ResourceHooksSchema","object","beforeWrite","custom","optional","afterWrite","afterRead","beforeFindAll","afterFindAll","import_node_path","loadResourceHooks","basePath","file","findModule","importDefault","undefined","loadSubResourceHooks","subResources","sub","name","join","childDir","hooks","hookCtxRead","adapter","op","request","parent","dataSource","prisma","client","hookCtxWrite","id","undefined","decorateRows","rows","target","hook","hooks","afterRead","ctx","hooked","Promise","all","map","row","cols","valueLabelColumns","length","r","applyValueLabelColumns","decorateRow","prepareWrite","data","normalized","normalizeValueLabels","beforeWrite","applyBeforeFindAll","params","beforeFindAll","applyAfterFindAll","afterFindAll","postWrite","result","afterWrite","unsupported","config","op","method","parent","PARENT_METHOD","NotImplementedException","name","createCustomRepository","prisma","dataSources","repository","configRegistry","adapter","PrismaDataSourceAdapter","repo","idField","DEFAULT_ID_FIELD","toId","id","idType","DEFAULT_ID_TYPE","String","parentRef","parentIdFrom","request","raw","params","param","undefined","BadRequestException","route","parentCtx","parentId","parentHookCtx","ctx","offset","offsetOf","findAllWithCount","result","findAllByParent","findAll","vlCols","resolveValueLabelColumns","valueLabelColumns","target","hooks","data","decorateRows","count","length","findOne","row","findOneByParent","NotFoundException","decorateRow","write","coercedId","prepared","prepareWrite","fn","createByParent","updateByParent","patchByParent","nestedCtx","body","create","update","patch","bind","postWrite","notAChildRepository","filter","page","pageSize","sort","sortDir","delete","deleteByParent","findOneChild","createChild","updateChild","deleteChild","validateCustomRepository","config","repository","adapterClient","definition","resolveDefinition","enabled","CUSTOM_OPS","filter","op","isOperationEnabled","isOperationExternal","nested","parent","methodFor","PARENT_METHOD","length","undefined","missing","name","map","join","implemented","names","route","import_zod","isZodSchema","schema","ZodObject","dropNullableFromRequired","jsonSchema","properties","required","Array","isArray","filter","key","isNullableProperty","toJsonSchema","toJSONSchema","target","jsonSchemaOpts","type","unwrap","s","t","_zod","def","innerType","typeOf","toSelectFields","Object","keys","reduce","acc","result","value","entries","shape","inner","select","element","createCrudRepository","prisma","config","dataSources","configRegistry","fallbackDataSources","resolve","entries","repository","createCustomRepository","resolvedAdapter","resolveAdapter","database","adapterModelKey","model","name","definition","resolveDefinition","listSchema","schemaFor","oneSchema","listSelect","toSelectFields","undefined","oneSelect","findAll","count","baseCtx","op","offset","ctx","request","id","mkDecorateFindAll","adapter","rows","vlCols","resolveValueLabelColumns","route","valueLabelColumns","target","hooks","decorated","decorateRows","applyAfterFindAll","decorateFindAll","applyBefore","params","applyBeforeFindAll","decorateFindOne","row","decorateRow","prepareData","data","prepareWrite","postData","result","postWrite","toId","idType","String","adapterFindAllByParent","parentId","childRoute","findAllByParent","sub","subResources","find","s","Error","prismaModel","reader","ReadRepository","adapterFindOneChild","childId","findOneChild","NotFoundException","writer","WriteRepository","findAllWithCount","effectiveParams","offsetOf","filter","q","findOne","create","stripped","stripSubResourceKeys","prepared","update","coercedId","patch","patchOrUpdate","bind","delete","createChild","Promise","reject","updateChild","deleteChild","kind","client","legacyModel","PrismaDataSourceAdapter","import_common","DataSourceRegistry","adapters","Map","defaultName","entries","entry","set","config","name","adapter","default","length","resolveAdapter","key","Error","get","resolveClient","client","resolve","map","onModuleDestroy","disconnectAll","values","disconnect","import_node_fs","import_node_path","loadDataSourcesFromDir","dirPath","existsSync","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","name","results","dir","basePath","join","jsonFile","_config","JSON","parse","readFileSync","err","resourceLoadErrorsRegistry","record","path","error","message","datasource","DataSourceSchema","safeParse","success","config","data","indexFile","findModule","adapter","mod","exported","default","instance","kind","PrismaDataSourceAdapter","push","ext","p","undefined","InMemoryDataSourceAdapter","kind","client","undefined","store","Map","seed","model","rows","set","supports","has","disconnect","import_common","import_swagger","import_common","import_common","SecurityGuardRegistry","guards","resolve","name","g","Error","classes","Object","values","CROUTON_SECURITY","CroutonSecurityGuard","reflector","registry","moduleRef","canActivate","context","sec","get","getHandler","names","Array","isArray","guard","name","cls","resolve","strict","ok","def","cls","method","fn","Object","defineProperty","prototype","value","writable","configurable","desc","getOwnPropertyDescriptor","registerActionRoutes","ctx","cls","config","name","procedureActions","actions","filter","isRowProcedureAction","action","methodName","id","def","recordId","procedure","repo","prisma","d","desc","Post","prototype","Param","ApiOperation","summary","label","ApiParam","type","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","registerTableActionRoutes","tableActions","isTableProcedureAction","import_common","import_swagger","defaultCreate","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","createSchema","bodyDecorator","methodName","route","name","createFn","body","req","repo","create","decorators","coerceNullableUndefinedToNull","prototype","Req","childCreate","sub","operations","childRoute","id","createChild","Param","Body","registerCreate","operationFn","properties","def","d","desc","Post","ApiOperation","summary","ApiResponse","status","description","secure","import_common","import_swagger","defaultDelete","ctx","isOperationEnabled","definition","isOperationExternal","config","methodName","name","route","decorators","deleteFn","id","req","repo","delete","deleteChild","sub","operations","cls","childRoute","childId","parentId","Param","prototype","Req","registerDelete","operationFn","properties","def","d","desc","Delete","ApiOperation","summary","ApiParam","idParamMeta","ApiResponse","status","secure","import_common","import_swagger","RequestDtoNoOffset","createZodDto","RequestSchema","RequestDto","RequestSchemaWithOffset","ZodValidationPipe","nullableKeys","decimalKeys","decimalCtor","coerceUndefinedToNull","schema","options","Object","entries","shape","filter","field","safeParse","success","map","key","require","Decimal","isDecimalField","coerceNullableUndefinedToNull","transform","value","stripped","stripEmptyStrings","coerced","coerceNullable","input","coerceDecimals","result","CroutonValidationError","formatErrors","error","data","Array","isArray","out","keys","includes","undefined","length","v","issues","e","path","join","message","code","_findAll","repo","params","request","data","count","findAllWithCount","Promise","all","findAll","filter","q","then","totalPages","Math","max","ceil","pageSize","page","sort","sortDir","findAllByParent","id","childRoute","defaultFindAll","ctx","isOperationEnabled","definition","isOperationExternal","config","req","route","name","methodName","listSchema","decorators","childFindAll","sub","operations","cls","Param","prototype","Req","registerFindAll","operationFn","properties","def","d","desc","Get","Query","ZodValidationPipe","RequestDtoNoOffset","schema","ApiOperation","summary","ApiResponse","status","description","type","items","toJsonSchema","secure","import_common","import_swagger","defaultFindOne","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","methodName","route","name","findOneFn","id","req","repo","findOne","decorators","Param","prototype","Req","childFindOne","sub","operations","childRoute","parentId","childId","findOneChild","registerFindOne","operationFn","properties","def","d","desc","Get","ApiOperation","summary","ApiParam","idParamMeta","ApiResponse","status","description","oneSchema","schema","toJsonSchema","ApiNotFoundResponse","secure","import_common","import_swagger","defaultPatch","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","patchSchema","bodyDecorator","methodName","route","name","patchFn","id","body","req","repo","patch","decorators","Param","prototype","Req","childPatch","sub","operations","childRoute","_id","childId","updateChild","Body","registerPatch","operationFn","properties","def","d","desc","Patch","ApiOperation","summary","ApiResponse","status","description","ApiNotFoundResponse","secure","import_common","import_swagger","import_zod","FieldVariantPatchSchema","z","object","type","string","nullable","optional","format","resource","position","number","options","record","unknown","partial","PatchColumnSchema","label","column","hiddenInTable","boolean","hiddenInForm","hiddenInView","fieldInput","fieldView","fieldTable","PatchResourceJsonSchema","columns","import_node_fs","readRawResourceJson","jsonPath","existsSync","undefined","JSON","parse","readFileSync","FIELD_VARIANT_KEYS","mergeColumn","existing","patch","fieldInput","fieldView","fieldTable","rest","variantPatches","merged","key","variantPatch","mergeFieldVariant","applyColumnPatch","raw","columns","Array","isArray","updated","map","col","columnPatch","id","Object","entries","serializeResourceJson","config","stringify","validateResourceJson","buildResourceJsonSchema","safeParse","writeRawResourceJson","writeFileSync","pickExtensions","config","Object","fromEntries","getResourceExtensions","keys","filter","k","undefined","map","resolveEnvPlaceholders","value","replace","match","varName","process","env","RESOURCE_OPS","OP_METHOD","findAll","findOne","create","update","patch","delete","OP_SUFFIX","buildResourceOperations","definition","baseUri","op","isOperationEnabled","extUri","externalRouteFor","uri","entry","method","buildDefinitionPayload","route","name","tag","idType","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","patchSchema","operations","display","schemas","toJsonSchema","buildResourceJsonPayload","baseUrl","isOperationExternal","lookup","form","views","schema","json_schema","data","ui","ui_schema","id","_resolveActions","actions","length","resolved","a","type","href","b","join","resolveActions","buildViewsPayload","config","baseUrl","views","Object","keys","length","undefined","definition","resolveDefinition","baseUri","parent","route","param","operations","buildResourceOperations","isOperationEnabled","isOperationExternal","schemas","fromEntries","entries","map","key","v","data","json_schema","ui","ui_schema","defaultSort","baseAction","id","name","uri","title","tag","idField","lookup","idType","modalSize","display","actions","resolveActions","tableActions","pickExtensions","buildSubResourceViewsPayload","sub","childUri","childRoute","buildSubResourceOperations","buildEditableColumnsPayload","columns","c","label","column","hiddenInTable","hiddenInForm","hiddenInView","form","fieldInput","view","resolved","resolveViewField","hasOverride","fieldView","table","resolveTableField","fieldTable","import_node_path","registerDefinitionEndpoint","ctx","cls","config","schemaEnricher","route","name","definitionPayload","buildDefinitionPayload","def","language","getRequestLanguage","payload","IS_DEV","fresh","configRegistry","getByRoute","d","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","registerResourceJsonEndpoint","baseUrl","resourceJsonPayload","buildResourceJsonPayload","registerResourceColumnsEndpoint","ForbiddenException","buildEditableColumnsPayload","registerResourceJsonPatchEndpoint","body","dir","getResourceDir","NotFoundException","jsonPath","join","raw","readRawResourceJson","merged","applyColumnPatch","validated","validateResourceJson","success","BadRequestException","error","issues","writeRawResourceJson","Patch","Body","ZodValidationPipe","PatchResourceJsonSchema","registerResourceJsonRawGetEndpoint","registerResourceJsonRawPutEndpoint","Put","import_common","import_swagger","defaultSchemas","ctx","config","baseUrl","schemaEnricher","route","name","viewsPayload","buildViewsPayload","methodName","schemasFn","language","getRequestLanguage","payload","IS_DEV","fresh","configRegistry","getByRoute","decorators","childSchemas","sub","views","schemasPayload","buildSubResourceViewsPayload","childRoute","localizedParent","localizedSub","subResources","find","s","registerSchemas","operationFn","properties","cls","def","d","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","import_common","import_swagger","defaultUpdate","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","updateSchema","bodyDecorator","methodName","route","name","updateFn","id","body","req","repo","update","decorators","Param","prototype","Req","childUpdate","sub","operations","childRoute","_id","childId","updateChild","Body","registerUpdate","operationFn","properties","def","d","desc","Put","ApiOperation","summary","ApiResponse","status","description","ApiNotFoundResponse","secure","registerEndpoints","ctx","registerSubResourceRoutes","registerFindAll","registerResourceJsonRawGetEndpoint","registerResourceJsonRawPutEndpoint","registerResourceJsonPatchEndpoint","registerResourceJsonEndpoint","registerResourceColumnsEndpoint","registerDefinitionEndpoint","registerEndpoint","registerActionRoutes","registerTableActionRoutes","sub","config","subResources","registerSchemas","registerFindOne","registerCreate","registerUpdate","registerPatch","registerDelete","createCrudController","config","baseUrl","moduleDefaultSecurity","securityEnabled","prefix","schemaEnricher","route","name","tag","idType","definition","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","explicitPatchSchema","patchSchema","isZodSchema","partial","undefined","bodyDecorator","schema","options","Body","ZodValidationPipe","resolveClient","registry","resource","resolve","database","e","kind","adapter","resolveAdapter","client","CrudControllerBase","repo","configRegistry","prisma","createCrudRepository","secure","methodName","op","sub","sec","securityForSub","securityFor","SetMetadata","CROUTON_SECURITY","prototype","Object","getOwnPropertyDescriptor","ctx","cls","idParamMeta","type","registerEndpoints","controllerPath","resourceControllerPath","parent","Controller","UseGuards","CroutonSecurityGuard","ApiTags","defineProperty","value","charAt","toUpperCase","slice","Reflect","defineMetadata","DataSourceRegistry","ResourceConfigRegistry","import_common","import_swagger","clientAccessor","prismaModelName","charAt","toLowerCase","slice","resourceNames","accessor","name","route","model","tag","title","labelFromId","TIMESTAMP_NAME","isTimestampField","opts","type","isUpdatedAt","test","fieldInputType","prismaType","isEnum","scalarFieldInputType","idTypeFor","indexRelations","models","index","Map","model","field","fields","kind","relationName","list","get","push","name","isList","set","resolveRelationType","sides","counterpart","find","s","type","otherIsList","literalDefault","value","undefined","Array","isArray","every","v","includes","dmmfToDbModels","dmmf","enums","datamodel","enumNames","Set","map","e","relationIndex","fkFields","f","relationFromFields","add","idFieldDef","isId","hasCompositeId","primaryKey","length","idField","idType","idTypeFor","isEnum","has","isRequired","isUnique","isUpdatedAt","hasDefault","hasDefaultValue","default","defaultValue","isTimestamp","isTimestampField","relationModel","relationToFields","relationType","enumValues","values","prismaName","clientAccessor","charAt","toLowerCase","slice","tableName","dbName","loadDmmf","schemaPath","specifier","internals","mod","Error","loaded","getSchemaWithPath","cliProvidedPath","getDMMF","schemas","introspect","opts","loader","defaultRuleset","RulesetSchema","parse","classify","model","ctx","ruleset","names","resourceNames","prismaName","columnOrder","columns","unwiredRelations","position","field","fields","kind","includeRelations","col","idField","hiddenInTable","hideIdInTable","hiddenInForm","hideIdInForm","hiddenInView","hideIdInView","isTimestamp","hideTimestamps","createable","updateable","fieldInput","type","defaultValue","undefined","hideForeignKeys","target","resolveRelationResource","relationModel","isCollectionSide","relationType","display","showRelationsInForm","hideRelationsInTable","format","resource","options","push","name","targetModel","enumValueLabel","emitObject","sharedEnums","values","enumValues","map","v","label","value","displayKey","enum","scalarFieldInputType","config","route","tag","title","idType","database","sidebar","hide","operations","defaultOperations","hasRelations","some","f","import_promises","fileExists","p","access","clone","value","JSON","parse","stringify","deepEqual","a","b","Array","isArray","length","every","v","i","ao","bo","ak","Object","keys","sort","bk","some","k","columnEntries","columns","map","id","rest","entries","columnsMapFromEntries","out","col","diff","draft","existing","hasSchemaFile","decisions","isNew","push","id","kind","recommended","options","context","name","draftMap","Map","columnEntries","config","columns","existingMap","columnOrder","draftCol","get","has","field","deepEqual","model","undefined","recommendedResolver","resolve","decisions","out","d","id","recommended","diff","resolver","raw","resolutions","Map","set","RESOURCE_SCHEMA_URL","CURRENT_RESOURCE_VERSION","withResourceHeader","config","opts","$schema","_schema","schemaVersion","_version","draft","existingDraft","kind","existingKind","rest","undefined","serializeResourceJson","JSON","stringify","serializeSchemaTs","exportName","importPath","joinPath","parts","join","replace","apply","resolved","ctx","diff","resolutions","exportNameFor","schemaExportName","p","dir","resourcesDir","name","notes","draft","unwiredRelations","map","r","field","targetModel","files","isNew","config","clone","addToSidebar","get","sidebar","hide","push","path","contents","serializeResourceJson","withResourceHeader","action","existing","draftMap","Map","columnEntries","columns","entries","indexOf","id","findIndex","eid","decision","decisions","choice","recommended","kind","col","i","splice","columnsMapFromEntries","deepEqual","hasSchemaFile","exportName","hasRelations","prismaName","serializeSchemaTs","generatedTypesImport","resource","import_promises","import_node_path","commit","plan","opts","written","skipped","file","files","action","fileExists","path","push","dryRun","mkdir","dirname","recursive","writeFile","contents","import_promises","import_node_path","findConfigPath","cwd","dir","resolve","name","CONFIG_FILES","candidate","join","fileExists","parent","dirname","undefined","loadConfig","path","Error","config","endsWith","JSON","parse","readFile","mod","default","validateConfig","root","resourcesDir","dataSourcesDir","defaultPrismaConfig","loadDatasources","loaded","base","resolveFromRoot","entries","readdir","withFileTypes","datasources","e","isDirectory","jsonPath","ds_json","prismaSchema","generatedTypesImport","missing","filter","Boolean","push","DataSourceSchema","prismaConfig","validateDatasources","length","defaults","d","map","resolveDatasource","found","find","def","makeSchemaExportName","template","schemaExportName","prismaName","replace","p","isAbsolute","import_zod","import_promises","import_node_path","ScallfoldDatasourceSchema","DataSourceShape","extend","folder","z","string","default","transform","transformDataSource","import_node_path","import_promises","import_node_path","resourceDir","loaded","name","join","resolveFromRoot","root","config","resourcesDir","readExistingResource","dir","jsonPath","fileExists","JSON","parse","readFile","hasSchemaFile","isCustomResourceFile","parsed","kind","listResourceNames","base","entries","readdir","withFileTypes","names","e","isDirectory","push","makeRelationResolver","loaded","known","Set","listResourceNames","targetModel","accessor","clientAccessor","has","undefined","resolveRuleset","config","RulesetSchema","parse","rules","buildResourceDiff","model","deps","draft","classify","database","ruleset","resolveRelationResource","name","resourceNames","prismaName","hasSchemaFile","readExisting","diff","existing","buildResourceDiffs","models","diffs","push","import_node_fs","import_promises","import_node_module","import_node_path","loadDotenv","dir","_require","createRequire","dotenv","d","i","readdirSync","includes","config","path","join","parent","dirname","resolveBin","name","cwd","bin","existsSync","run","cmd","args","Promise","resolve","child","spawn","shell","process","platform","stdout","stderr","on","toString","err","code","String","isGitDirty","trim","length","backupSchema","schemaPath","dest","copyFile","prismaDbPull","prismaConfig","prefix","ok","output","prismaCaseFormat","binPath","execPath","prismaGenerate","pullAndGenerate","input","root","prismaConfigPath","schemaPath","loadDotenv","backupPath","backupSchema","dbPull","prismaDbPull","ok","caseFormat","prismaCaseFormat","normalized","normalizeSchema","generate","prismaGenerate","renamed","configDir","dir","dirname","configPath","join","existsSync","config","JSON","parse","readFile","schema","modelName","fields","Object","entries","renames","modelRe","RegExp","replace","_","head","body","tail","ugly","clean","fieldRe","replaced","writeFile","import_node_path","applyResourceFlagPatch","raw","patch","result","draft","undefined","sidebar","existing","hide","group","position","label","Object","keys","length","resolveResourcePath","resourcesDir","name","resolved","resolve","startsWith","Error","ResourceLoadReportRegistry","notices","record","n","push","getAll","getByState","state","filter","clear","resourceLoadReportRegistry","DevResourcesController","dataSourceRegistry","resourceConfigRegistry","assertDev","IS_DEV","ForbiddenException","loadProject","datasourceName","loaded","loadConfig","process","cwd","e","NotFoundException","message","datasources","loadDatasources","ds","resolveDatasource","BadRequestException","schemaPath","resolveFromRoot","root","prismaSchema","introspectModels","introspect","buildApplyContext","resourcesDir","config","generatedTypesImport","schemaExportName","makeSchemaExportName","isAvailableOnClient","clientAccessor","client","resolve","name","listModels","models","existing","Set","listResourceNames","map","m","prismaName","hasResource","has","availableOnClient","restart","setTimeout","disconnectAll","catch","undefined","finally","exit","restarting","pull","body","datasource","prismaConfigPath","prismaConfig","confirm","isGitDirty","requiresConfirmation","dirtyFile","zodDir","zodOutput","result","pullAndGenerate","zodOutputDir","ok","dbPull","output","restartRequired","backupPath","caseFormat","normalizeSchema","generate","zodImportsFixed","sync","model","find","resolveRelationResource","makeRelationResolver","diff","buildResourceDiff","database","ruleset","resolveRuleset","readExisting","readExistingResource","resolved","resolveDiff","recommendedResolver","plan","applyDiff","commit","resource","isNew","allModels","length","filter","includes","diffs","buildResourceDiffs","applyCtx","resources","writePlan","files","notes","push","decisions","f","path","action","apply","results","visibility","getAll","fromLoaded","c","route","state","sidebar","hide","group","position","editable","drafts","resourceLoadReportRegistry","getByState","d","endsWith","errors","resourceLoadErrorsRegistry","publish","jsonPath","resolveResourcePath","raw","readRawResourceJson","patched","applyResourceFlagPatch","draft","validateResourceJson","success","error","writeRawResourceJson","removeFromMenu","addToMenu","sidebarPatch","label","updateFlags","summary","status","description","import_zod","EnumEntrySchema","z","object","value","unknown","label","string","EnumRegistrySchema","record","array","default","import_node_fs","import_node_path","ENUMS_FILE","loadEnumRegistry","startDir","enumsFile","file","dir","candidate","join","existsSync","parent","dirname","EnumRegistrySchema","parse","undefined","JSON","readFileSync","injectEnumValues","columns","enums","col","enum","values","fieldInput","type","options","emitObject","displayKey","import_common","NoCacheInterceptor","intercept","context","next","response","switchToHttp","getResponse","setHeader","handle","pickByColumns","schema","columns","filter","undefined","length","baseFilter","c","isRelation","schemaKeys","Set","Object","keys","shape","filtered","has","id","mask","fromEntries","map","pick","opWithSchema","enabled","uri","method","buildResourceDefinitions","operations","enrichedColumns","picked","createSchema","idField","createable","updateSchema","updateable","definition","findAll","findOne","create","update","patch","delete","import_zod","unwrapZodType","type","ZodOptional","ZodNullable","unwrap","deriveRelationType","schema","columnId","undefined","field","shape","inner","ZodArray","deriveRelationTypeFromColumns","col","cols","base","column","id","fkNames","Set","some","c","has","enrichRelationTypes","columns","map","fi","fieldInput","isRelationField","format","relationType","derived","enrichActionColumns","columns","parentRoute","subResources","baseUrl","base","map","col","fieldInput","format","sub","find","s","column","id","options","uri","childRoute","resourceUri","resource","relationType","enrichResourceRefColumns","parentDir","childResolved","resolveChildResource","json","route","replace","schemasUri","enrichNestedRelationColumns","cols","dir","resolved","targetRoute","deriveRelationTypeFromColumns","enrichIncludeWithSort","include","length","entry","relationName","relation","c","opts","sort","orderBy","buildChildSortClause","sortDir","REMOTE_RESOURCE","buildSubResources","columns","parentRoute","parentModel","parentDir","enums","baseUrl","filter","c","fieldInput","format","resource","flatMap","resourcePath","test","resolution","resolveChildResourceDetailed","ok","resourceLoadErrorsRegistry","record","name","path","error","reason","id","attempted","join","childJson","value","json","childDir","dir","parent","route","childRoute","replace","rawChildColumns","expandedChildColumns","expandExtendColumns","undefined","childColumns","applyRelationFormatDefault","injectEnumValues","enrichedChildColumns","enrichNestedRelationColumns","autoIncludes","col","relationType","deriveRelationTypeFromColumns","map","relation","explicitIncludes","include","explicitNames","Set","e","mergedIncludes","has","childLookupKey","find","idField","childCalculatedColumns","calculatedColumns","childViews","buildViewsFromColumns","length","table","injectCalculatedColumns","view","injectCalculatedColumnsToView","childOps","operations","childKind","kind","column","childModel","model","charAt","toLowerCase","slice","foreignKey","title","tag","idType","hiddenInTable","views","findAll","findOne","create","update","patch","delete","actions","modalSize","display","hiddenInForm","hiddenInView","includeInFindOne","opts","options","sort","findOneOrderBy","buildChildSortClause","sortDir","buildValueLabelColumns","valueLabelColumns","pickExtensions","obj","Object","fromEntries","getResourceExtensions","keys","filter","k","undefined","map","fromJson","json","schema","hooks","dirPath","baseUrl","actions","tableActions","enums","repository","isCustom","kind","rawColumns","expandExtendColumns","columns","enrichRelationTypes","applyRelationFormatDefault","injectEnumValues","subResources","buildSubResources","route","model","enrichedColumns","resolveColumnFieldVariants","enrichResourceRefColumns","enrichActionColumns","calculatedColumns","views","buildViews","length","table","injectCalculatedColumns","view","injectCalculatedColumnsToView","lookup","buildLookup","enrichedInclude","enrichIncludeWithSort","include","definition","buildResourceDefinitions","operations","name","tag","sidebar","display","idType","key","idField","database","modalSize","buildValueLabelColumns","valueLabelColumns","keyCol","find","c","searchCols","showInLookup","searchable","labels","col","fieldInput","relationType","resource","relationName","id","replace","child","resolveChildResource","childColumns","displayCol","hiddenInTable","label","import_node_fs","migrateResourceJsonFile","jsonPath","opts","raw","readRawResourceJson","status","version","BASELINE_RESOURCE_VERSION","from","resourceVersionOf","CURRENT_RESOURCE_VERSION","isDev","expected","error","result","runResourceMigrations","validation","validateResourceJson","success","to","message","writeFileSync","serializeResourceJson","written","err","MigrationPathError","MigrationStepError","ALL_OPS","validateResourceConfig","config","opts","errors","warnings","definition","resolveDefinition","enabledOps","filter","op","isOperationEnabled","length","push","kind","database","repoError","validateCustomRepository","repository","repositoryFileExistsOnDisk","import_node_fs","import_node_path","loadResourceConfigsFromDir","dirPath","baseUrl","enumsFile","onResourceDir","existsSync","resourceLoadErrorsRegistry","clear","resourceLoadReportRegistry","enums","loadEnumRegistry","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","name","configs","dir","basePath","join","schemaFile","findModule","schema","importDefault","undefined","hooks","loadResourceHooks","jsonFile","migration","migrateResourceJsonFile","isDev","IS_DEV","status","record","path","error","version","expectedVersion","expected","state","from","to","console","info","result","readResourceJson","success","json","data","draft","schemaVersion","errorsBeforeRepo","getAll","length","repository","kind","loadCustomRepository","repositoryImportFailed","actions","loadActions","tableActions","config","fromJson","repositoryFileExistsOnDisk","errors","warnings","validateResourceConfig","warning","loadSubResourceHooks","subResources","loadSubResourceRepositories","route","push","tsFile","merged","ResourceConfigLoader","getResourceDir","_route","undefined","FileSystemResourceConfigLoader","ResourceConfigLoader","dirsByRoute","Map","dirPath","baseUrl","enumsFile","loadAll","configs","loadResourceConfigsFromDir","route","dir","set","loadByRoute","find","c","getResourceDir","get","import_node_fs","import_node_path","import_node_url","CONNECTION_STRING_PATTERN","stripConnectionStrings","message","replace","getCroutonVersion","startDir","__dirname","dirname","fileURLToPath","dir","pkgPath","join","existsSync","pkg","JSON","parse","readFileSync","name","version","getVersion","process","env","getEnvironment","checkDatabases","registry","results","adapter","entries","healthCheck","push","connected","err","error","getResourceStatus","loadedConfigs","warningsByName","Map","w","resourceLoadReportRegistry","getByState","existing","get","warning","set","valid","map","c","path","route","schemaVersion","CURRENT_RESOURCE_VERSION","kind","repository","customOperations","CUSTOM_OPS","filter","op","sidebar","hide","hidden","has","warnings","failed","resourceLoadErrorsRegistry","getAll","e","expectedVersion","draft","d","buildSummary","databases","resources","databaseErrors","length","resourceErrors","r","warningCount","reduce","acc","ok","getSystemEnums","category","values","value","label","getProjectEnums","enumRegistry","Object","entry","getEnums","system","project","countKeys","obj","prefix","total","empty","v","Array","isArray","sub","getI18nStatus","translationRegistry","active","undefined","languages","bundles","language","bundle","bundleFor","keyCount","emptyKeys","defaultLanguage","buildStatus","summary","croutonVersion","environment","enums","i18n","import_common","import_swagger","createStatusController","enumRegistry","translationRegistry","prefix","StatusController","dataSourceRegistry","configRegistry","getStatus","configs","getAll","buildStatus","summary","status","description","Reflect","defineMetadata","DataSourceRegistry","ResourceConfigRegistry","import_node_path","import_node_url","CroutonApiModule","onModuleInit","BigInt","prototype","toJSON","Number","Decimal","parseFloat","toString","forResources","configs","dataSources","loader","appConfig","config","baseUrl","prefix","security","dataSourceRegistry","DataSourceRegistry","guardRegistry","SecurityGuardRegistry","guards","moduleDefaultSecurity","default","startDir","__dirname","dirname","fileURLToPath","enumRegistry","loadEnumRegistry","enumsFile","validConfigs","c","adapter","database","entries","length","resolveAdapter","e","resourceLoadErrorsRegistry","record","name","path","route","error","message","String","adapterIsCustom","kind","hasRepository","repository","adapterHasCrud","findAll","count","push","adapterClient","client","undefined","problem","validateCustomRepository","model","supports","configRegistry","ResourceConfigRegistry","translationRegistry","i18n","translationsDir","join","configDir","TranslationRegistry","setTranslationRegistry","controllers","map","createCrudController","schemaEnricher","createAppLayoutController","sidebarGroups","title","autoSave","IS_DEV","DevResourcesController","createStatusController","module","exports","providers","provide","APP_INTERCEPTOR","useClass","NoCacheInterceptor","APP_FILTER","CroutonValidationExceptionFilter","useValue","CroutonSecurityGuard","classes","useFactory","LanguageInterceptor","forResourceDir","dirPath","dataSourcesPath","extensions","registerResourceExtensions","loadConfig","FileSystemResourceConfigLoader","loadResourceConfigsFromDir","loadDataSourcesFromDir","forLoader","parseSchema","input","appConfig","view","extensions","registerResourceExtensions","normalized","json","parseResult","buildResourceJsonSchema","safeParse","success","Error","error","message","resource","fromJson","data","schema","hooks","dirPath","baseUrl","actions","tableActions","enums","undefined","payload","buildViewsPayload","buildDefinitionPayload","buildResourceJsonPayload","schemaEnricher"]}
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.4.0__@swc+core@1.16.1_@swc+he_9a17c50ee76d0369ad0c28a18d209a0d/node_modules/tsup/assets/cjs_shims.js","../../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/schema.utils.ts","../../crouton-core/src/lib/layout/base.builder.ts","../../crouton-core/src/lib/layout/control.builder.ts","../../crouton-core/src/lib/layout/layout.options.ts","../../crouton-core/src/lib/layout/layout.builder.ts","../../crouton-core/src/lib/value-label.ts","../../crouton-core/src/lib/table/table.builder.ts","../../crouton-core/src/lib/compile/action.types.ts","../../crouton-core/src/lib/resource/Layout.schema.ts","../../crouton-core/src/lib/resource/ResourceJson.schema.ts","../../crouton-core/src/lib/resource/CalculatedColumn.schema.ts","../../crouton-core/src/lib/resource/FieldInput.schema.ts","../../crouton-core/src/lib/schema/label.helper.ts","../../crouton-core/src/lib/resource/Column.ts","../../crouton-core/src/lib/resource/ColumnType.schema.ts","../../crouton-core/src/lib/resource/ParentRef.schema.ts","../../crouton-core/src/lib/resource/ResourceKind.ts","../../crouton-core/src/lib/resource/Sidebar.schema.ts","../../crouton-core/src/lib/resource/TableAction.schema.ts","../../crouton-core/src/lib/resource/extensions.ts","../../crouton-core/src/lib/resource/include.schema.ts","../../crouton-core/src/lib/resource/version.ts","../../crouton-core/src/lib/data-source/Operations.schema.ts","../../crouton-core/src/lib/data-source/Security.schema.ts","../../crouton-core/src/lib/resource/migrations/types.ts","../../crouton-core/src/lib/resource/migrations/index.ts","../../crouton-core/src/lib/resource/fieldVariants.ts","../../crouton-core/src/lib/view/column-predicates.ts","../../crouton-core/src/lib/view/column.utils.ts","../../crouton-core/src/lib/view/sort.helpers.ts","../../crouton-core/src/lib/view/schema-transforms.ts","../../crouton-core/src/lib/view/table-schema.builder.ts","../../crouton-core/src/lib/view/form-schema.builder.ts","../../crouton-core/src/lib/view/calculated-columns.builder.ts","../../crouton-core/src/lib/view/view.builder.ts","../../crouton-core/src/lib/view/column-type-schema.source.ts","../../crouton-core/src/lib/view/json-schema.opts.ts","../../crouton-core/src/lib/view/layout-ui-schema.builder.ts","../../crouton-core/src/lib/view/layout-table-order.ts","../../crouton-core/src/lib/view/view.schema.ts","../../crouton-core/src/lib/compile/enum-registry.ts","../../crouton-core/src/lib/compile/relation-type.ts","../../crouton-core/src/lib/compile/compiled-resource.schema.ts","../../crouton-core/src/lib/compile/compiled-sub-resource.schema.ts","../../crouton-core/src/lib/data-source/DataSourceSchema.ts","../../crouton-core/src/lib/compile/value-label-column.ts","../../crouton-core/src/lib/compile/definition.schema.ts","../../crouton-core/src/lib/compile/schema-input.ts","../../crouton-core/src/lib/compile/lookup.schema.ts","../../crouton-core/src/lib/compile/to-json-schema.ts","../../crouton-core/src/lib/config/CroutonConfig.schema.ts","../../crouton-core/src/lib/config/readConfig.ts","../../crouton-core/src/lib/i18n/Translations.schema.ts","../../crouton-core/src/lib/i18n/translation-keys.ts","../../crouton-core/src/lib/i18n/translator.ts","../../crouton-core/src/lib/i18n/negotiate.ts","../src/lib/crouton-api.module.ts","../src/lib/crud/app-layout/app-layout.types.ts","../src/lib/crud/app-layout/app-layout.builder.ts","../src/lib/crud/app-layout/app-layout.controller.ts","../src/lib/crud/dev-mode.ts","../src/lib/crud/resource-config.registry.ts","../src/lib/crud/resource/ReadResourceJson.ts","../src/lib/crud/adapter/resource-resolver.ts","../src/lib/crud/adapter/column-transforms.ts","../src/lib/crud/translation/localize-resource.ts","../src/lib/crud/translation/language.context.ts","../src/lib/crud/config/read.ts","../src/lib/crud/crouton-validation.filter.ts","../src/lib/crud/crouton-validation.error.ts","../src/lib/crud/translation/translation.loader.ts","../src/lib/crud/translation/translation.registry.ts","../src/lib/crud/crud-controller.factory.ts","../src/lib/crud/crud-repository.factory.ts","../src/lib/crud/action/action.types.ts","../src/lib/crud/loader/module.loader.ts","../src/lib/crud/action/action.loader.ts","../src/lib/crud/crud.config.ts","../src/lib/crud/custom-repository/custom-repository.types.ts","../src/lib/crud/resource/resource-load-errors.registry.ts","../src/lib/crud/custom-repository/custom-repository.loader.ts","../src/lib/crud/custom-repository/custom-repository.adapter.ts","../src/lib/crud/constants.ts","../src/lib/crud/data-source/prisma.adapter.ts","../src/lib/crud/read.repository.ts","../src/lib/crud/custom-repository/child-delegate.ts","../src/lib/crud/resource/valueLabel.apply.ts","../src/lib/crud/sql.helpers.ts","../src/lib/crud/translation/language.interceptor.ts","../src/lib/crud/translation/resolve-value-labels.ts","../src/lib/crud/write.repository.ts","../src/lib/crud/hooks/hooks.types.ts","../src/lib/crud/hooks/hooks.loader.ts","../src/lib/crud/hooks/hooks.apply.ts","../src/lib/crud/custom-repository/custom-repository.validate.ts","../src/lib/crud/schema.utils.ts","../src/lib/crud/data-source/data-source.registry.ts","../src/lib/crud/data-source/data-source.loader.ts","../src/lib/crud/data-source/in-memory.adapter.ts","../src/lib/crud/operations/register-actions.ts","../src/lib/crud/security/crouton-security.guard.ts","../src/lib/crud/security/security-guard.registry.ts","../src/lib/crud/operations/decorator.utils.ts","../src/lib/crud/operations/register-create.ts","../src/lib/crud/operations/register-delete.ts","../src/lib/crud/operations/register-findall.ts","../src/lib/crud/request.dto.ts","../src/lib/crud/zod-validation.pipe.ts","../src/lib/crud/operations/register-findone.ts","../src/lib/crud/operations/register-patch.ts","../src/lib/crud/operations/register-schema-endpoints.ts","../src/lib/crud/resource/PatchResourceJson.schema.ts","../src/lib/crud/resource/WriteResourceJson.ts","../src/lib/crud/operations/payload-builders.ts","../src/lib/crud/operations/register-schemas.ts","../src/lib/crud/operations/register-update.ts","../src/lib/crud/operations/register-endpoints.ts","../src/lib/crud/dev-tools/dev-resources.controller.ts","../../crouton-codegen/src/naming.ts","../../crouton-codegen/src/introspect.ts","../../crouton-codegen/src/classify.ts","../../crouton-codegen/src/util.ts","../../crouton-codegen/src/diff.ts","../../crouton-codegen/src/resolve.ts","../../crouton-codegen/src/serialize.ts","../../crouton-codegen/src/apply.ts","../../crouton-codegen/src/commit.ts","../../crouton-codegen/src/config.ts","../../crouton-codegen/src/scaffold.ts","../../crouton-codegen/src/datasource-scaffold.ts","../../crouton-codegen/src/project.ts","../../crouton-codegen/src/plan.ts","../../crouton-codegen/src/prisma-shell.ts","../src/lib/crud/resource/ResourceFlags.ts","../src/lib/crud/resource/resource-load-report.registry.ts","../src/lib/crud/enum-registry/enum-registry.types.ts","../src/lib/crud/enum-registry/enum-registry.loader.ts","../src/lib/crud/enum-registry/enum-registry.injector.ts","../src/lib/crud/interceptors/no-cache.interceptor.ts","../src/lib/crud/builder/schema.helpers.ts","../src/lib/crud/adapter/relation-type.ts","../src/lib/crud/adapter/column-enrichment.ts","../src/lib/crud/adapter/sub-resource.builder.ts","../src/lib/crud/adapter/json-adapter.ts","../src/lib/crud/resource/MigrateResourceJson.ts","../src/lib/crud/resource/resource-config.validator.ts","../src/lib/crud/loader/index.ts","../src/lib/crud/loader/resource-config.loader.ts","../src/lib/crud/loader/fs-resource-config.loader.ts","../src/lib/crud/status/status.service.ts","../src/lib/crud/status/status.controller.ts","../src/lib/crud/parse-schema.ts"],"sourcesContent":["export { buildViews } from '@ghentcdh/crouton-core';\n\nexport * from './lib/crouton-api.module';\nexport type { CroutonAppConfig } from './lib/crud/app-config';\nexport {\n type ParseAppConfig,\n type ParseSchemaInput,\n type ParseSchemaView,\n parseSchema,\n} from './lib/crud/parse-schema';\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';\nexport * from './lib/crud/hooks';\nexport * from './lib/crud/security';\n\n// Types a consumer needs to type their own `repository.ts` on a\n// `kind: \"custom\"` resource.\nexport {\n type CustomListResult,\n type CustomOp,\n type CustomRepository,\n type CustomRepositoryContext,\n} from './lib/crud/custom-repository';\n\n// Filter-grammar helpers, so a custom repository can reuse the\n// `field:value:operator` parsing instead of reimplementing it.\nexport {\n buildFilterWhere,\n parseFilterString,\n} from './lib/crud/read.repository';\n","// Shim globals in cjs bundle\n// There's a weird bug that esbuild will always inject importMetaUrl\n// if we export it as `const importMetaUrl = ... __filename ...`\n// But using a function will not cause this issue\n\nconst getImportMetaUrl = () => \n typeof document === \"undefined\" \n ? new URL(`file:${__filename}`).href \n : (document.currentScript && document.currentScript.tagName.toUpperCase() === 'SCRIPT') \n ? document.currentScript.src \n : new URL(\"main.js\", document.baseURI).href;\n\nexport const importMetaUrl = /* @__PURE__ */ getImportMetaUrl()\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 q: z.string().optional(),\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\nexport type ListRequestWithOffset = z.infer<typeof RequestSchemaWithOffset>;\n\n/**\n * Zero-based row offset for a list request.\n *\n * Controllers validate query params with `RequestSchema` (no `offset`), while\n * `RequestSchemaWithOffset` adds one — so consumers cannot rely on the field\n * being present. Derive it here instead of duplicating the arithmetic at every\n * call site.\n */\nexport const offsetOf = (params: ListRequest): number =>\n (params as Partial<ListRequestWithOffset>).offset ??\n (params.page - 1) * params.pageSize;\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","/**\n * Browser-safe JSON Schema utilities shared across crouton-core and crouton-api.\n *\n * Keep this file free of Node-only imports. Zod-specific conversion lives in\n * compile/to-json-schema.ts; mutable view-build transforms live in\n * view/schema-transforms.ts.\n */\n\nimport type { JsonSchema } from '@jsonforms/core';\n\ntype Field = { scope: string };\n\n/**\n * Returns true when a JSON Schema property represents a nullable field.\n * Handles both Zod v4 (`\"type\": [\"string\",\"null\"]`) and the older\n * anyOf `[{type:\"string\"},{type:\"null\"}]` format.\n */\nexport const isNullableProperty = (property: unknown): boolean => {\n const prop = property as Record<string, unknown> | undefined;\n if (!prop) return false;\n if (Array.isArray(prop['type']) && (prop['type'] as string[]).includes('null')) return true;\n const anyOf = prop['anyOf'];\n return Array.isArray(anyOf) && anyOf.some((s: Record<string, unknown>) => s?.['type'] === 'null');\n};\n\n/**\n * Recursively drop nullable fields from `required`. A nullable field\n * (anyOf with a `{ type: \"null\" }` branch) should be treated as optional.\n */\nexport const dropNullableFromRequired = (schema: JsonSchema): JsonSchema => {\n if (!schema?.properties) return schema;\n\n const required = schema.required as string[] | undefined;\n if (!Array.isArray(required) || required.length === 0) return schema;\n\n const filteredRequired = required.filter(\n (key) => !isNullableProperty(schema.properties![key]),\n );\n\n if (filteredRequired.length === required.length) return schema;\n\n return { ...schema, required: filteredRequired } as JsonSchema;\n};\n\n/**\n * For every property NOT in the schema's `required` array, add `null` to its\n * allowed types. This prevents Zod (via `fromJSONSchema`) from emitting a type\n * error — mapped to \"This field is required\" — when an optional field's current\n * value is `null`.\n */\nexport const makeOptionalPropertiesNullable = (schema: JsonSchema): JsonSchema => {\n if (!schema?.properties) return schema;\n const requiredSet = new Set<string>(\n Array.isArray(schema.required) ? (schema.required as string[]) : [],\n );\n const patched = { ...schema.properties };\n let changed = false;\n for (const key of Object.keys(patched)) {\n if (requiredSet.has(key)) continue;\n const prop = patched[key];\n if (!prop || typeof prop !== 'object') continue;\n if (isNullableProperty(prop)) continue;\n const type = (prop as Record<string, unknown>)['type'];\n if (typeof type === 'string' && type !== 'null') {\n patched[key] = { ...prop, type: [type, 'null'] } as JsonSchema;\n changed = true;\n }\n }\n return changed ? ({ ...schema, properties: patched } as JsonSchema) : schema;\n};\n\nexport const enforceRequiredStringMinLength = (schema: JsonSchema): JsonSchema => {\n if (!schema?.properties) return schema;\n const patchedProperties = { ...schema.properties };\n let changed = false;\n for (const key of Object.keys(patchedProperties)) {\n const prop = patchedProperties[key];\n if (!prop || typeof prop !== 'object') continue;\n if (prop.type === 'string' && prop.minLength === undefined) {\n patchedProperties[key] = { ...prop, minLength: 1 };\n changed = true;\n } else if (prop.type === 'object') {\n const patched = enforceRequiredStringMinLength(prop as JsonSchema);\n if (patched !== prop) { patchedProperties[key] = patched; changed = true; }\n }\n }\n return changed ? ({ ...schema, properties: patchedProperties } as JsonSchema) : schema;\n};\n\n/**\n * Resolve a column's scope to its schema property.\n *\n * Scopes may be nested (`#/properties/author/properties/name`, produced for\n * `extend` columns and inline object types). Previously only the\n * `#/properties/` prefix was stripped, so a nested scope yielded the id\n * `\"author/properties/name\"` and an empty property — leaving such columns with\n * no schema type at all. Each `properties/<key>` segment is now walked.\n */\nexport const findProperty = <F extends Field>(column: F, schema: JsonSchema) => {\n if (!column.scope) return { id: null, property: null };\n const id = column.scope.substring('#/properties/'.length);\n const segments = id.split('/properties/');\n\n let property: any = schema?.properties?.[segments[0]] ?? {};\n for (const segment of segments.slice(1)) {\n property = property?.properties?.[segment] ?? {};\n }\n\n return { id, property } as { id: string; property: any };\n};\n","import type {\n Layout,\n Rule,\n RuleEffect,\n SchemaBasedCondition,\n UISchemaElement,\n} from '@jsonforms/core';\n\nimport type { CroutonElementOptions, CroutonLayoutOptions } from './layout.options';\n\n/** Anything that can be built into a JSON Forms UI-schema element. */\nexport type Buildable = { build(): UISchemaElement };\n\n/**\n * Options for the string form of `addControl`. `type` selects the control format\n * (e.g. `textarea`, `boolean`, `relation`); omit it for a plain control. Every other\n * key is a normal element option (`label`, `colspan`, `styles`).\n */\nexport type ControlShortcut = CroutonElementOptions & { type?: string };\n\n/** Effect names for a rule; kept as string literals so no runtime enum import is needed. */\nexport type RuleEffectName = 'SHOW' | 'HIDE' | 'ENABLE' | 'DISABLE';\n\n/** Minimal base: a typed discriminator plus a `build()` contract. */\nexport abstract class Builder<OUT> {\n protected constructor(protected readonly type: string) {}\n abstract build(): OUT;\n}\n\n/**\n * Base for elements that carry a typed `options` bag and an optional JSON Forms `rule`.\n *\n * `label` / `colspan` and the `showWhen` / `hideWhen` / `disableWhen` helpers are shared by\n * every layout and control, so labels and conditional rules are expressed in the builder\n * chain instead of being mutated onto the built object afterwards.\n */\nexport abstract class ElementBuilder<\n OUT extends UISchemaElement,\n OPT extends CroutonElementOptions = CroutonElementOptions,\n> extends Builder<OUT> {\n protected options: Partial<OPT> = {};\n protected _rule?: Rule;\n\n label(label: string): this {\n return this.opt({ label } as Partial<OPT>);\n }\n\n colspan(colspan: number): this {\n return this.opt({ colspan } as Partial<OPT>);\n }\n\n rowspan(rowspan: number): this {\n return this.opt({ rowspan } as Partial<OPT>);\n }\n\n showWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('SHOW', scope, schema);\n }\n\n hideWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('HIDE', scope, schema);\n }\n\n disableWhen(scope: string, schema: Record<string, unknown>): this {\n return this.rule('DISABLE', scope, schema);\n }\n\n rule(effect: RuleEffectName, scope: string, schema: Record<string, unknown>): this {\n this._rule = {\n effect: effect as RuleEffect,\n condition: { scope, schema } as SchemaBasedCondition,\n };\n return this;\n }\n\n /** Merge a patch into the typed options bag. */\n opt(patch: Partial<OPT>): this {\n this.options = { ...this.options, ...patch };\n return this;\n }\n\n /** `options` / `rule` fields, emitted only when non-empty. */\n protected baseFields(): { options?: Partial<OPT>; rule?: Rule } {\n return {\n ...(Object.keys(this.options).length ? { options: this.options } : {}),\n ...(this._rule ? { rule: this._rule } : {}),\n };\n }\n}\n\n/**\n * Base for layouts that hold child elements. Exposes the overloaded `addControl` /\n * `addControls` surface: pass a fully-configured builder, or a bare property name (with\n * optional shortcut options). Each concrete container turns a shortcut into its own leaf\n * builder via `resolveShortcut`, so this base never imports a control/cell builder and\n * there is no dependency cycle.\n */\nexport abstract class ContainerBuilder<\n OUT extends Layout,\n OPT extends CroutonLayoutOptions = CroutonLayoutOptions,\n> extends ElementBuilder<OUT, OPT> {\n protected children: Buildable[] = [];\n\n /** Turn a shortcut (property name + options) into a concrete leaf builder. */\n protected abstract resolveShortcut(name: string, options?: ControlShortcut): Buildable;\n\n addControl(builder: Buildable): this;\n addControl(name: string, options?: ControlShortcut): this;\n addControl(arg: string | Buildable, options?: ControlShortcut): this {\n this.children.push(\n typeof arg === 'string' ? this.resolveShortcut(arg, options) : arg,\n );\n return this;\n }\n\n addControls(...builders: Buildable[]): this;\n addControls(map: Record<string, ControlShortcut | undefined>): this;\n addControls(\n first: Buildable | Record<string, ControlShortcut | undefined>,\n ...rest: Buildable[]\n ): this {\n if (first && typeof first === 'object' && !('build' in first)) {\n for (const [name, options] of Object.entries(first)) {\n this.addControl(name, options);\n }\n } else if (first) {\n for (const builder of [first as Buildable, ...rest]) {\n this.addControl(builder);\n }\n }\n return this;\n }\n\n protected buildElements(): UISchemaElement[] {\n return this.children.map((child) => child.build());\n }\n}\n","import type { UISchemaElement } from '@jsonforms/core';\n\nimport { ElementBuilder } 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 object: 'object',\n custom: 'custom',\n select: 'select',\n mutliSelect: 'mutliSelect',\n toggle: 'toggle',\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 DateOptions extends ControlOption {\n /** `date` renders a day only, `dateTime` adds a time. @default 'date' */\n format: 'date' | 'dateTime';\n /**\n * Force the time on or off, overriding `format`. Useful for a Prisma\n * `DateTime` column that should be edited as a plain day.\n */\n withTime?: boolean;\n /** Earliest selectable date, ISO or `yyyy-MM-dd`. */\n min?: string;\n /** Latest selectable date, ISO or `yyyy-MM-dd`. */\n max?: string;\n /** BCP-47 locale for the month heading and weekday labels. @default 'en-GB' */\n locale?: string;\n /** 0 = Sunday, 1 = Monday. @default 1 */\n firstDayOfWeek?: number;\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\n/**\n * A single-select control rendered as a row of buttons where exactly one\n * option is shown as active. Same data shape and option sources as\n * {@link SelectOptions}; only the presentation differs.\n */\nexport interface ToggleOptions extends ControlOption {\n format: 'toggle';\n options?: Array<any>;\n values?: Array<any>;\n labelKey?: string;\n valueKey?: string;\n /** Store `option[valueKey]` instead of the whole option object. */\n storeValue?: boolean;\n /** Clicking the active button clears the value. @default true */\n clearable?: boolean;\n /** `Btn` color for the active button. @default 'primary' */\n color?: string;\n /** `Btn` size. @default 'sm' */\n size?: 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 | AutocompleteRemoteOptions | 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 /** date: force the time input on or off, overriding `format`. */\n withTime?: boolean;\n /** date: earliest selectable date, ISO or `yyyy-MM-dd`. */\n min?: string;\n /** date: latest selectable date, ISO or `yyyy-MM-dd`. */\n max?: string;\n /** date: BCP-47 locale for the month heading and weekday labels. */\n locale?: string;\n /** date: first day of the week, 0 = Sunday, 1 = Monday. */\n firstDayOfWeek?: number;\n customRender?: any;\n colspan?: number;\n rowspan?: number;\n}\n\nexport type ControlTypes = {\n type: 'Control' | 'Object' | 'TextCell';\n scope: string;\n options?: TextAreaOptions | AutocompleteOptions | DetailOptions;\n};\n\nexport class ControlBuilder<TYPE, KEY = keyof TYPE> extends ElementBuilder<\n UISchemaElement,\n ControlOption\n> {\n private _detail?: LayoutBuilder<any>;\n\n private constructor(\n private readonly scope: string,\n type = 'Control',\n ) {\n super(type);\n this.opt({ format: 'Control', styles: {} });\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.opt({\n format: ControlType.custom,\n type,\n } as unknown as Partial<ControlOption>);\n\n return builder;\n }\n\n setCustomRender(customRender: string) {\n this.opt({ customRender });\n\n return this;\n }\n\n detail<TYPE>(layoutBuilder: LayoutBuilder<TYPE>, label?: string) {\n this._detail = layoutBuilder;\n this.opt({\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.opt({ 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.opt({\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.opt({ labelKey });\n }\n\n readonly(): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.string,\n readonly: true,\n });\n }\n\n link(): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.link,\n });\n }\n\n markdown(options?: Omit<MarkdownOptions, 'format'>): ControlBuilder<TYPE> {\n return this.opt({\n format: ControlType.markdown,\n ...(options ?? {}),\n });\n }\n\n /**\n * Render a datepicker. Defaults to a day-only picker; pass\n * `{ format: 'dateTime' }` (or `{ withTime: true }`) to include a time.\n */\n date(options?: Partial<DateOptions>) {\n return this.opt({\n format: ControlType.date,\n ...(options ?? {}),\n });\n }\n\n textArea(options?: Omit<TextAreaOptions, 'format'>) {\n return this.opt({\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.opt({\n format: ControlType.autocomplete,\n dataField: 'data',\n ...(options ?? {}),\n });\n }\n\n control(format: string, options?: Partial<ControlOption>) {\n return this.opt({\n format,\n ...options,\n });\n }\n\n select(options: Omit<SelectOptions, 'format'>) {\n return this.opt({\n format: ControlType.select,\n ...options,\n });\n }\n\n mutliSelect(options: Omit<SelectOptions, 'format'>) {\n return this.opt({\n format: ControlType.mutliSelect,\n ...options,\n });\n }\n\n toggle(options: Omit<ToggleOptions, 'format'>) {\n return this.opt({\n format: ControlType.toggle,\n ...options,\n });\n }\n\n width(width: 'xs' | 'sm' | 'md' | 'lg' | 'xl' | 'full' | (string & {})) {\n const named = ['xs', 'sm', 'md', 'lg', 'xl', 'full'];\n const isNamed = named.includes(width);\n return this.opt({\n styles: {\n ...this.options?.styles,\n width,\n control: {\n wrapper: isNamed ? `input-${width}` : width,\n },\n },\n });\n }\n\n customLabel(label: string) {\n return this.opt({ label });\n }\n\n placeHolder(placeholder: string) {\n return this.opt({ placeholder });\n }\n\n hideLabel() {\n return this.opt({ hideLabel: true });\n }\n\n override build(): ControlTypes {\n const detail = this._detail ? this._detail.build() : undefined;\n const options = {\n ...this.options,\n ...(detail ? { detail } : {}),\n };\n return {\n type: this.type,\n scope: this.scope,\n options,\n ...(this._rule ? { rule: this._rule } : {}),\n } as unknown as ControlTypes;\n }\n}\n","/**\n * Typed options for crouton UI-schema elements.\n *\n * These type the `options` bag of a standard `@jsonforms/core` element — the builders\n * still emit plain `Layout` / `UISchemaElement` objects (exactly the shape\n * `JsonFormsLayout.uiSchema` consumes), so nothing about the output contract changes.\n */\n\n/** Crouton layout types layered on top of the JSON Forms defaults. */\nexport const LayoutType = {\n Horizontal: 'HorizontalLayout',\n Vertical: 'VerticalLayout',\n Grid: 'GridLayout',\n Collapse: 'CollapseLayout',\n Group: 'GroupLayout',\n} as const;\n\nexport type LayoutType = (typeof LayoutType)[keyof typeof LayoutType];\n\n/** Options shared by every UI element. `colspan`/`rowspan` are crouton-custom (read by the renderers). */\nexport interface CroutonElementOptions {\n label?: string;\n /** 1..12 column span, mapped to a Tailwind class by the layout renderers. */\n colspan?: number;\n /** Row span for CSS grid; mapped to a Tailwind `row-span-*` class. */\n rowspan?: number;\n styles?: Record<string, unknown>;\n}\n\n/** Layout-only options. Collapse uses `title` / `titleKey`; Grid carries the column count. */\nexport interface CroutonLayoutOptions extends CroutonElementOptions {\n title?: string;\n titleKey?: string;\n columns?: number;\n}\n","import type { Layout } from '@jsonforms/core';\n\nimport type { Buildable, ControlShortcut } from './base.builder';\nimport { ContainerBuilder } from './base.builder';\nimport { ControlBuilder } from './control.builder';\nimport type { ControlOption } from './control.builder';\nimport { LayoutType } from './layout.options';\nimport type { CroutonLayoutOptions } from './layout.options';\n\n/**\n * Property name for the `addControl` shortcut. Known keys of `TYPE` get autocomplete and\n * typo-checking; any string is still accepted so the shortcut works without a generic.\n */\ntype Name<TYPE> = (keyof TYPE & string) | (string & {});\n\nexport class LayoutBuilder<TYPE = Record<string, unknown>> extends ContainerBuilder<\n Layout,\n CroutonLayoutOptions\n> {\n private constructor(type: string) {\n super(type);\n }\n\n static horizontal<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Horizontal);\n }\n\n static vertical<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Vertical);\n }\n\n static grid<TYPE = Record<string, unknown>>(columns?: number): LayoutBuilder<TYPE> {\n const layout = new LayoutBuilder<TYPE>(LayoutType.Grid);\n return columns === undefined ? layout : layout.opt({ columns });\n }\n\n static collapse<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Collapse);\n }\n\n static group<TYPE = Record<string, unknown>>(): LayoutBuilder<TYPE> {\n return new LayoutBuilder<TYPE>(LayoutType.Group);\n }\n\n /** Collapse layout title. */\n title(title: string): this {\n return this.opt({ title });\n }\n\n /** Collapse layout: resolve the title from a field value at render time. */\n titleKey(titleKey: string): this {\n return this.opt({ titleKey });\n }\n\n // Narrow the shortcut name to TYPE's keys (still accepts any string).\n override addControl(builder: Buildable): this;\n override addControl(name: Name<TYPE>, options?: ControlShortcut): this;\n override addControl(arg: string | Buildable, options?: ControlShortcut): this {\n return super.addControl(arg as string, options);\n }\n\n protected resolveShortcut(name: string, options?: ControlShortcut): Buildable {\n const control = ControlBuilder.properties<TYPE>(name as keyof TYPE);\n if (options) {\n const { type, ...rest } = options;\n if (type) control.control(type, rest);\n else if (Object.keys(rest).length) control.opt(rest as Partial<ControlOption>);\n }\n return control;\n }\n\n override build(): Layout {\n return {\n type: this.type,\n elements: this.buildElements(),\n ...this.baseFields(),\n };\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 type { Layout } from '@jsonforms/core';\n\nimport { Builder, ContainerBuilder } from '../layout/base.builder';\nimport type { Buildable } from '../layout/base.builder';\nimport { LayoutType } from '../layout/layout.options';\nimport type { CroutonLayoutOptions } from '../layout/layout.options';\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}\n\n/**\n * Builds a `HorizontalLayout` of table cells. Shares the overloaded\n * `addControl` / `addControls` surface with `LayoutBuilder`; its shortcut form\n * resolves to a `TextCellBuilder` instead of a form control.\n */\nexport class TableBuilder<TYPE = Record<string, unknown>> extends ContainerBuilder<\n Layout,\n CroutonLayoutOptions\n> {\n private constructor() {\n super(LayoutType.Horizontal);\n }\n\n static init<TYPE = Record<string, unknown>>(): TableBuilder<TYPE> {\n return new TableBuilder<TYPE>();\n }\n\n protected resolveShortcut(name: string): Buildable {\n return TextCellBuilder.properties<TYPE>(name as keyof TYPE);\n }\n\n override build(): Layout {\n return {\n type: this.type,\n elements: this.buildElements(),\n ...this.baseFields(),\n };\n }\n}\n","import { z } from 'zod';\n\nimport type { JsonActionCondition } from '../resource/TableAction.schema';\n\nconst ActionMetadataSchema = z.object({\n id: z.string(),\n label: z.string().optional(),\n icon: z.string().optional(),\n tooltip: z.string().optional(),\n condition: z.custom<JsonActionCondition>().optional(),\n});\n\nconst ResourceLinkActionSchema = ActionMetadataSchema.extend({\n type: z.literal('link'),\n href: z.string(),\n});\n\nconst ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n method: z.string().optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n procedure: z.custom<(prisma: any, recordId: string | number) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\nconst ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n method: z.string().optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n procedure: z.custom<(prisma: any) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\nexport type ResourceLinkAction = z.infer<typeof ResourceLinkActionSchema>;\nexport type ResourceRowProcedureAction = z.infer<typeof ResourceRowProcedureActionSchema>;\nexport type ResourceTableProcedureAction = z.infer<typeof ResourceTableProcedureActionSchema>;\n\nexport const ResourceRowActionSchema = z.union([\n ResourceRowProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceRowAction = z.infer<typeof ResourceRowActionSchema>;\n\nexport const ResourceTableActionSchema = z.union([\n ResourceTableProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceTableAction = z.infer<typeof ResourceTableActionSchema>;\n\nexport const isRowProcedureAction = (\n action: ResourceRowAction,\n): action is ResourceRowProcedureAction => action.type !== 'link';\n\nexport const isTableProcedureAction = (\n action: ResourceTableAction,\n): action is ResourceTableProcedureAction => action.type !== 'link';\n","import { z } from 'zod';\n\nexport const LayoutControlSchema = z.union([\n z.string(),\n z.object({\n id: z.string(),\n colspan: z.number().int().min(1).max(12).optional(),\n rowspan: z.number().int().min(1).optional(),\n width: z.string().optional(),\n label: z.string().optional(),\n hideLabel: z.boolean().optional(),\n type: z.string().optional(),\n options: z.record(z.string(), z.unknown()).optional(),\n }),\n]);\n\nexport type LayoutControl = z.infer<typeof LayoutControlSchema>;\n\nexport type LayoutNode = {\n type?: 'grid' | 'vertical' | 'horizontal' | 'collapse' | 'group';\n columns?: number;\n title?: string;\n titleKey?: string;\n colspan?: number;\n rowspan?: number;\n label?: string;\n controls?: LayoutControl[];\n items?: LayoutNode[];\n};\n\nexport const LayoutNodeSchema: z.ZodType<LayoutNode> = z.lazy(() =>\n z.object({\n type: z.enum(['grid', 'vertical', 'horizontal', 'collapse', 'group']).optional(),\n columns: z.number().int().min(1).max(12).optional(),\n title: z.string().optional(),\n titleKey: z.string().optional(),\n colspan: z.number().int().min(1).max(12).optional(),\n rowspan: z.number().int().min(1).optional(),\n label: z.string().optional(),\n controls: z.array(LayoutControlSchema).optional(),\n items: z.array(LayoutNodeSchema).optional(),\n }),\n);\n\nexport const LayoutSchema = z.object({\n form: LayoutNodeSchema.optional(),\n view: LayoutNodeSchema.optional(),\n table: LayoutNodeSchema.optional(),\n});\n\nexport type Layout = z.infer<typeof LayoutSchema>;\n","import { z } from 'zod';\n\nimport { CalculatedColumnSchema } from './CalculatedColumn.schema';\nimport { type JsonColumn, JsonColumnSchema } from './Column';\nimport { LayoutSchema } from './Layout.schema';\nimport { ParentRefSchema } from './ParentRef.schema';\nimport { ResourceKindSchema } from './ResourceKind';\nimport { SidebarSchema } from './Sidebar.schema';\nimport { JsonActionSchema } from './TableAction.schema';\nimport { getResourceExtensions } from './extensions';\nimport { JsonIncludeEntrySchema } from './include.schema';\nimport { BASELINE_RESOURCE_VERSION } from './version';\nimport { JsonOperationsSchema } from '../data-source/Operations.schema';\nimport { SecuritySchema } from '../data-source/Security.schema';\nimport { labelFromId } from '../schema/label.helper';\n\n// ── Shared primitives ────────────────────────────────────────────────\n\nconst JsonColumnsMapSchema = z.record(\n z.string(),\n JsonColumnSchema.omit({ id: true }).catchall(z.unknown()),\n); // map form — key becomes `id`\nexport type JsonColumnsMap = z.infer<typeof JsonColumnsMapSchema>;\nconst ColumnsSchema = JsonColumnsMapSchema;\n\n// ── Display / sidebar ────────────────────────────────────────────────\n\nexport const JsonDisplaySchema = z.object({\n mode: z.enum(['page', 'modal']).default('modal'), // default: 'modal'\n customComponent: z.string().nullable().optional().default(null), // default: null\n});\n\nexport type JsonDisplay = z.infer<typeof JsonDisplaySchema>;\n\n/** Normalise `columns` from either array or object-map form. */\nexport const normalizeColumns = (\n columns: 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// ── Top-level resource.json ──────────────────────────────────────────\n\nexport const ResourceJsonShape = z.object({\n /**\n * URL of the generated JSON Schema, for editor autocomplete/validation. Declared so the\n * key is *allowed* (not stripped, and not flagged by the very schema it points at).\n * Ignored at runtime.\n */\n $schema: z.string().optional(),\n /**\n * resource.json shape version. Missing ⇒ baseline (see `./version`). Auto-migrated\n * toward `CURRENT_RESOURCE_VERSION` on load in the dev environment.\n */\n schemaVersion: z.number().int().positive().optional(),\n /** When `true`, the resource lives in the repo but is NOT loaded/served (work in progress). */\n draft: z.boolean().optional().default(false),\n /**\n * Where the data comes from. `prisma` (the default) is backed by a Prisma\n * model plus a `schema.ts`; `custom` is configuration only and the developer\n * supplies a `repository.ts`. See `./ResourceKind`.\n */\n kind: ResourceKindSchema,\n name: z.string(), // required — unique id, used as the frontend form id\n route: z.string().optional(), // URL segment for generated endpoints - default id is used\n id: z.string().optional(), // URL segment for generated endpoints - default id is used\n /**\n * Prisma model name. Required when `kind` is `prisma` (enforced by the\n * refinement on `ResourceJsonSchema`), and must be absent when `kind` is\n * `custom` — there is no Prisma delegate to address.\n */\n model: z.string().optional(),\n tag: z.string().optional().default('Crouton'), // required — OpenAPI tag\n title: z.string().optional(), // no computed default — used as UI display title\n table: z.string().optional(), // default: same as `model`\n /**\n * Type of the resource's primary key, used to coerce `:id` route params.\n * Written by codegen from the Prisma model; defaults to `'string'`.\n */\n idType: z.enum(['string', 'number']).optional(),\n database: z.string().optional(), // default: project's default data source\n /**\n * Mount this resource under a parent route instead of at the top level —\n * see `./ParentRef.schema`. Only valid on a `kind: \"custom\"` resource.\n */\n parent: ParentRefSchema.optional(),\n sidebar: SidebarSchema.default(SidebarSchema.parse({})), // default: shown, alphabetically ordered, ungrouped\n display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})), // default: { mode: 'modal', customComponent: null }\n /** Global security block — applies to every operation unless overridden per-operation. */\n security: SecuritySchema.optional(),\n operations: JsonOperationsSchema.optional(), // default applied in transform: custom → all false, prisma → all true\n columns: ColumnsSchema.optional().default(ColumnsSchema.parse({})), // id-keyed map; omit for a columnless resource\n calculatedColumns: z.array(CalculatedColumnSchema).default([]),\n actions: z.array(JsonActionSchema).default([]),\n /** Global table-level actions (no record id). Shown as toolbar buttons. */\n tableActions: z.array(JsonActionSchema).default([]),\n /** Modal width when opening a form for this resource. */\n modalSize: z.enum(['xs', 'sm', 'lg', 'xl']).default('sm'), // default: 'sm' for create/edit modal\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: z.array(JsonIncludeEntrySchema).default([]),\n /** Explicit layout for generated views (`form`, `view`, `table`). When absent, source-order grid is used. */\n layout: LayoutSchema.optional(),\n});\n\n/**\n * Per-kind rules that a plain `z.object` cannot express.\n *\n * Implemented as a refinement rather than a `z.discriminatedUnion` on purpose:\n * `scripts/gen-resource-schema.mjs` runs `z.toJSONSchema(ResourceJsonShape)`\n * and needs a `z.object`, and a defaulted discriminator does not survive the\n * union. The generated JSON Schema is therefore permissive about these rules\n * while the loader enforces them.\n */\nexport const refineByKind = (\n obj: z.infer<typeof ResourceJsonShape>,\n ctx: z.RefinementCtx,\n): void => {\n if (obj.kind === 'custom') {\n if (obj.model !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['model'],\n message:\n 'A custom resource has no Prisma model. Remove \"model\" — data access comes from repository.ts.',\n });\n }\n if (obj.calculatedColumns?.length) {\n ctx.addIssue({\n code: 'custom',\n path: ['calculatedColumns'],\n message:\n 'calculatedColumns run raw SQL against a database table and are not supported on a custom resource. Compute the value in repository.ts instead.',\n });\n }\n for (const [id, col] of Object.entries(obj.columns ?? {})) {\n // A relation or autocomplete column's shape comes from the referenced\n // resource, not from this column.\n if (\n col.fieldInput?.format === 'relation' ||\n col.fieldInput?.type === 'autocomplete'\n ) {\n continue;\n }\n if (col.type === undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['columns', id, 'type'],\n message: `Column \"${id}\" needs a \"type\": a custom resource has no schema.ts, so its json_schema is built from the column types.`,\n });\n }\n }\n if (obj.parent && obj.parent.param === 'id') {\n ctx.addIssue({\n code: 'custom',\n path: ['parent', 'param'],\n message:\n 'parent.param cannot be \"id\" — that is the child\\'s own id in /:id routes. Use something like \"groupId\".',\n });\n }\n } else if (obj.parent !== undefined) {\n ctx.addIssue({\n code: 'custom',\n path: ['parent'],\n message:\n '\"parent\" is only supported on a custom resource. A prisma resource is nested by declaring a relation column on its parent.',\n });\n }\n // \"model required for prisma kind\" moved to the Prisma adapter at load time —\n // a resource on a custom-adapter datasource may have no model and is still valid.\n};\n\nexport const buildResourceJsonSchema = () => {\n const ext = getResourceExtensions();\n const extShape = Object.fromEntries(\n [...ext].map(([name, schema]) => [name, schema.optional()]),\n );\n // Cast back to ResourceJsonShape type so refineByKind and transform stay typed.\n // Extension keys are lifted off the top level into `extensions` in the transform.\n const shape = (\n ext.size ? ResourceJsonShape.extend(extShape) : ResourceJsonShape\n ) as unknown as typeof ResourceJsonShape;\n\n return z.preprocess(\n (raw) => {\n if (raw && typeof raw === 'object' && !Array.isArray(raw)) {\n const obj = raw as Record<string, unknown>;\n // Only auto-derive kind='prisma' when a model is present and kind is unset.\n // A modelless resource no longer auto-derives to kind='custom' — set it\n // explicitly when you want the columns-based json_schema behavior.\n if (obj['kind'] === undefined && obj['model'] !== undefined) {\n return { ...obj, kind: 'prisma' };\n }\n }\n return raw;\n },\n shape.superRefine(refineByKind).transform((obj) => {\n const title = obj.title ?? labelFromId(obj.name);\n const schemaVersion = obj.schemaVersion ?? BASELINE_RESOURCE_VERSION;\n const defaultOps =\n obj.kind === 'custom'\n ? JsonOperationsSchema.parse({ findAll: false, findOne: false, create: false, update: false, patch: false, delete: false })\n : JsonOperationsSchema.parse({});\n return {\n title,\n ...obj,\n id: (obj.id ?? obj.name) as string,\n route: (obj.route ?? obj.id ?? obj.name ?? '') as string,\n schemaVersion,\n columns: normalizeColumns(obj.columns),\n operations: obj.operations ?? defaultOps,\n };\n }),\n );\n};\n\n/** Convenience constant — reads the registry at call time via the builder. */\nexport const ResourceJsonSchema = buildResourceJsonSchema();\n\nexport type ResourceJson = z.infer<ReturnType<typeof buildResourceJsonSchema>> & {\n route: string;\n};\nexport type ResourceJsonInput = z.input<typeof ResourceJsonShape> & {\n route: string;\n};\n\nexport type ResourceConfig = ResourceJson;\n\n/**\n * Generate a JSON Schema for resource.json that includes all currently-registered\n * extension keys. Call this after registering extensions to emit an app-specific\n * `resource.schema.json` that includes `annotation`, `context`, etc. as top-level\n * properties — enabling editor autocomplete for extension blocks.\n *\n * The core committed `resource.schema.json` is extension-agnostic (generated at\n * crouton-core build time when no extensions are registered). This helper lets\n * a consuming app emit its own schema after registering its extensions.\n */\nexport const generateResourceJsonSchema = (): Record<string, unknown> => {\n const ext = getResourceExtensions();\n const extShape = Object.fromEntries(\n [...ext].map(([name, schema]) => [name, schema.optional()]),\n );\n const shape = ext.size ? ResourceJsonShape.extend(extShape) : ResourceJsonShape;\n try {\n return z.toJSONSchema(shape, {\n target: 'draft-7',\n io: 'input',\n unrepresentable: 'any',\n }) as Record<string, unknown>;\n } catch {\n // ponytail: if toJSONSchema fails (recursive/record schema), fall back to the base shape.\n return z.toJSONSchema(ResourceJsonShape, {\n target: 'draft-7',\n io: 'input',\n unrepresentable: 'any',\n }) as Record<string, unknown>;\n }\n};\n","import { z } from 'zod';\n\nimport { FieldInputSchema } from './FieldInput.schema';\nimport { normalizeLabel } from '../schema/label.helper'; // ── Calculated columns ──────────────────────────────────────────────\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 const CalculatedColumnSchema = z\n .object({\n /** Column identifier used in the response payload and UI schema. */\n id: z.string(), // required\n /** SQL alias — must match `id`. */\n alias: z.string(), // required — must match `id`\n /** Human-readable label shown in the table header. */\n label: z.string().optional() /**\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: z.string(), // required\n /** JSON schema / cast type for the computed value. Defaults to `\"number\"`. `\"string\"` skips CAST. */\n type: z.enum(['number', 'boolean', 'string']).optional(), // default: 'number'\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: z.number().optional(),\n hiddenInTable: z.boolean().optional(), // default: false\n hiddenInView: z.boolean().optional(), // default: false\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: FieldInputSchema.optional(),\n })\n .transform(normalizeLabel);\n\nexport type CalculatedColumn = z.infer<typeof CalculatedColumnSchema>;\n","import { z } from 'zod';\n\nexport const RelationType = z.enum([\n 'oneToOne',\n 'manyToOne',\n 'oneToMany',\n 'manyToMany',\n]);\nexport type RelationType = z.infer<typeof RelationType>;\n\nexport const DetailControlSchema = z.object({\n property: z.string(), // required\n type: z.string().optional(), // default: 'text'\n options: z.record(z.string(), z.unknown()).optional(),\n hideLabel: z.boolean().optional(), // default: false\n width: z.string().optional(),\n});\n\nexport type DetailControl = z.infer<typeof DetailControlSchema>;\n\nexport const DetailConfigSchema = z.object({\n layout: z.enum(['collapse', 'row']), // required\n titleKey: z.string().optional(),\n controls: z.array(DetailControlSchema), // required\n});\n\nexport type DetailConfig = z.infer<typeof DetailConfigSchema>;\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 const RelationFieldInputOptionsSchema = z\n .object({\n colspan: z.number().optional().default(12),\n /** Field to sort related records by, e.g. `\"title\"` or `\"author.name\"`. */\n sort: z.string().optional(),\n /** Sort direction. Defaults to `\"asc\"` when omitted. */\n sortDir: z.enum(['asc', 'desc']).optional(), // default: 'asc'\n /** CSS flex direction for the relation control button layout. */\n direction: z.string().optional(),\n /** Key used as the display label in the relation control. */\n displayKey: z.string().optional(),\n /** Path to the related resource (resolved to a URI at load time). */\n resource: z.string().optional(),\n })\n .catchall(z.unknown()); // arbitrary extra keys allowed (e.g. colspan, emitObject, values)\n\nexport type RelationFieldInputOptions = z.infer<\n typeof RelationFieldInputOptionsSchema\n>;\nexport const FieldInputSchema = z.object({\n type: z.string().optional(),\n customRender: z.string().optional(),\n\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: z.string().optional(), // 'relation' triggers relation handling; requires `resource`\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: z.string().optional(), // required when format === 'relation'\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.optional(), // auto-derived from the Zod model/sibling FK column if omitted\n /** FK field on the child model pointing back to the parent, e.g. `\"workId\"`. Defaults to `${parentModel}Id`. */\n foreignKey: z.string().optional(),\n /** Override the Prisma relation field name when it differs from the column id. */\n relation: z.string().optional(),\n /** Override the display order in form views. Lower values come first. */\n position: z.number().optional(), // default: source order\n /**\n * Value to pre-fill this field with on the create form. Injected into the\n * generated form view's JSON Schema as `properties[id].default`, which\n * `parseValue({})` (see `@ghentcdh/crouton-vue`'s `form-def.ts`) applies when\n * opening a blank record. Not applicable to `format: \"relation\"` fields —\n * relation columns are excluded from the picked data schema entirely.\n *\n * Supports dynamic default tokens evaluated at form-open time:\n * - `\"$now\"` — current datetime ISO string\n * - `\"$today\"` — current date ISO string (date only, e.g. `\"2025-03-14\"`)\n * - `\"$user\"` — current user object (requires `defaults: { '$user': ... }` on `CroutonPlugin` config, or `useCrouton().setDefault('$user', ...)`)\n */\n defaultValue: z.unknown().optional(),\n options: z.union([RelationFieldInputOptionsSchema, z.unknown()]).optional(),\n /** Nested array detail layout (renders via `detailFixed`). */\n detail: DetailConfigSchema.optional(),\n});\n\nexport type FieldInput = z.infer<typeof FieldInputSchema>;\n\n/**\n * A per-context override of a column's field config. Structurally identical to\n * {@link FieldInputSchema} — every key is optional — so a variant can override\n * just what it needs (typically a single `options` key) and inherit the rest\n * from the level below it via {@link mergeFieldVariant}.\n */\nexport const FieldVariantSchema = FieldInputSchema;\nexport type FieldVariant = z.infer<typeof FieldVariantSchema>;\n\n/** Drop keys whose value is explicitly `null` (used to \"delete\" an inherited key). */\nconst stripNull = (obj: Record<string, unknown>): Record<string, unknown> => {\n const out: Record<string, unknown> = {};\n for (const [k, v] of Object.entries(obj)) if (v !== null) out[k] = v;\n return out;\n};\n\n/**\n * Layer a variant over a base field config (deep-merge, one level into `options`).\n *\n * - `override` wins key-by-key; `base` supplies everything the override omits.\n * - `options` is merged one level deep so a variant can tweak `options.display`\n * without repeating `format`, `resource`, `relationType`, etc.\n * - a `null` value in the override deletes that inherited key (top-level or in\n * `options`).\n *\n * Returns `base` unchanged when there is no override, and `override` when there\n * is no base — so `mergeFieldVariant(x, undefined) === x`.\n */\nexport const mergeFieldVariant = (\n base: FieldInput | undefined,\n override: FieldVariant | undefined,\n): FieldInput | undefined => {\n if (!base) return override;\n if (!override) return base;\n\n const merged = stripNull({ ...base, ...override }) as FieldInput;\n\n if (base.options || override.options) {\n const mergedOptions = stripNull({\n ...(base.options as Record<string, unknown> | undefined),\n ...(override.options as Record<string, unknown> | undefined),\n });\n merged.options = mergedOptions;\n }\n\n return merged;\n};\n","/**\n * Name derivations. The most error-prone one is `clientAccessor`: the value\n * crouton puts in `resource.json.model` must equal the PrismaClient property,\n * which Prisma derives by lower-casing the first character of the model name\n * (the rest is preserved). Getting this wrong silently breaks every query.\n */\n\n/**\n * Derive a human-readable label from an id.\n * `\"field_label\"` → `\"Field label\"`, `\"fieldLabel\"` → `\"Field label\"`.\n *\n * Kept local (mirrors `labelFromId` in `@ghentcdh/crouton-core`) so the engine\n * has no runtime dependency on core — only type-only imports, which keeps the\n * bundle lean and avoids pulling core's peer deps (zod, jsonforms) into it.\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\ntype LabelObj = {\n id: string;\n label?: string;\n};\nexport const normalizeLabel = <L extends LabelObj>(obj: L): L => {\n return { label: labelFromId(obj.id), ...obj };\n};\n","import { z } from 'zod';\n\nimport { ColumnTypeSchema } from './ColumnType.schema';\nimport { FieldInputSchema, FieldVariantSchema } from './FieldInput.schema';\n\n// Used by showWhen / hideWhen / disabledWhen\nexport const WhenConditionSchema = z.object({\n field: z.string(), // required\n eq: z.unknown().optional(),\n neq: z.unknown().optional(),\n exists: z.boolean().optional(),\n notExists: z.boolean().optional(),\n});\n\n// ── Columns ───────────────────────────────────────────────────────────\n\nexport const JsonColumnSchema = z.object({\n id: z.string(), // required in array form; implied by the map key in map form\n column: z.string().optional(), // default: same as `id`\n label: z.string().optional(), // default: title-cased version of `id`\n hiddenInTable: z.boolean().default(false), // default: false\n hiddenInForm: z.boolean().default(false), // default: false\n hiddenInView: z.boolean().default(false), // default: false\n sortable: z.boolean().default(false), // default: false\n defaultSort: z.boolean().default(false), // default: false\n searchable: z.boolean().default(false), // default: false\n filterable: z.boolean().default(false), // default: false\n createable: z.boolean().default(true), // default: true (only `false` excludes it)\n updateable: z.boolean().default(true), // default: true (only `false` excludes it)\n hideLabel: z.boolean().default(false), // default: false\n showWhen: WhenConditionSchema.optional(),\n hideWhen: WhenConditionSchema.optional(),\n disabledWhen: WhenConditionSchema.optional(),\n displayKey: z.string().optional(), // e.g. \"author.name\" for nested display\n sortId: z.string().optional(), // overrides the sort\n\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: z.string().optional(), // name of a shared enum in crouton.enums.json\n idField: z.boolean().default(false), // default: false — exactly one column should set this\n showInLookup: z.boolean().default(false), // default: false\n /**\n * Data type of the column, as a shorthand name (`\"string\"`, `\"integer\"`, …)\n * or a full JSON Schema fragment:\n *\n * ```json\n * \"type\": {\n * \"type\": \"object\",\n * \"properties\": { \"id\": { \"type\": \"string\" }, \"name\": { \"type\": \"string\" } }\n * }\n * ```\n *\n * Required on every column of a `kind: \"custom\"` resource, where it is the\n * only source of the resource's json_schema. Optional on a `prisma`\n * resource, whose schema is derived from the Zod model.\n */\n type: ColumnTypeSchema.optional(),\n /**\n * Whether the form requires a value.\n *\n * A prisma resource derives `required` from its Zod model, so this is an\n * override in either direction: `true` adds the column to the form schema's\n * `required` array, `false` removes it, and omitting it leaves the model's\n * answer alone. A `kind: \"custom\"` resource has no model, so this is the only\n * way to mark one of its fields required.\n *\n * Applies to the **form** view only — a required filter input would make the\n * filter panel unsubmittable, and the table and view schemas are read-only.\n * Ignored on the id column and on columns that are neither createable nor\n * updateable, since the form cannot supply a value for those.\n */\n required: z.boolean().optional(),\n /**\n * @deprecated Use `type` instead. Retained because it is still consumed by\n * the boolean predicate and the schema-less sub-resource view builder.\n */\n columnType: z.string().default('string'), // default: 'string'\n fieldInput: FieldInputSchema.optional(),\n /**\n * Optional per-context override for the read-only VIEW ui. Same shape as\n * `fieldInput`; every key optional. Falls back to `fieldInput` (deep-merged\n * one level into `options`). Resolved at read time by the transformer.\n */\n fieldView: FieldVariantSchema.optional(),\n /**\n * Optional per-context override for the TABLE ui. Same shape as `fieldInput`;\n * every key optional. Falls back to `fieldView`, then `fieldInput`.\n * Resolved at read time by the transformer.\n */\n fieldTable: FieldVariantSchema.optional(),\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: z.string().optional(), // path to another resource.json expanded as virtual sub-columns\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: z.record(z.string(), z.record(z.string(), z.unknown())).optional(), // per-sub-column overrides, only used with `extend`\n});\n\nexport type JsonColumn = z.infer<typeof JsonColumnSchema>;\nexport type JsonColumnInput = z.input<typeof JsonColumnSchema>;\n","import { z } from 'zod';\n\n/**\n * Column data types.\n *\n * A column's `type` is either a shorthand string or a JSON Schema fragment.\n * For a `kind: \"custom\"` resource these are the *only* source of the resource's\n * json_schema — there is no Prisma model to derive it from.\n */\n\n/** Shorthand names, expanded to a JSON Schema fragment by `columnTypeToJsonSchema`. */\nexport const ColumnTypeShorthandSchema = z.enum([\n 'string',\n 'number',\n 'integer',\n 'boolean',\n 'date',\n 'date-time',\n 'object',\n 'array',\n]);\n\nexport type ColumnTypeShorthand = z.infer<typeof ColumnTypeShorthandSchema>;\n\n/**\n * A JSON Schema fragment describing one column.\n *\n * Deliberately a permissive subset: enough to express the shapes the form and\n * table layers can render (scalars, nested objects, arrays, enums, nullables)\n * without re-implementing all of JSON Schema. Unknown keys pass through so a\n * fragment can carry vendor extensions (`x-*`).\n */\nexport type JsonSchemaFragment = {\n type?: string | string[] | JsonSchemaFragment;\n format?: string;\n enum?: unknown[];\n const?: unknown;\n nullable?: boolean;\n properties?: Record<string, JsonSchemaFragment>;\n required?: string[] | boolean;\n items?: JsonSchemaFragment;\n additionalProperties?: boolean | JsonSchemaFragment;\n title?: string;\n description?: string;\n default?: unknown;\n minimum?: number;\n maximum?: number;\n minLength?: number;\n maxLength?: number;\n pattern?: string;\n [key: string]: unknown;\n};\n\nexport const JsonSchemaFragmentSchema: z.ZodType<JsonSchemaFragment> = z.lazy(\n () =>\n z\n .object({\n type: z\n .union([z.string(), z.array(z.string()), z.lazy(() => JsonSchemaFragmentSchema)])\n .optional(),\n format: z.string().optional(),\n enum: z.array(z.unknown()).optional(),\n const: z.unknown().optional(),\n nullable: z.boolean().optional(),\n properties: z.record(z.string(), JsonSchemaFragmentSchema).optional(),\n required: z.union([z.array(z.string()), z.boolean()]).optional(),\n items: JsonSchemaFragmentSchema.optional(),\n additionalProperties: z\n .union([z.boolean(), JsonSchemaFragmentSchema])\n .optional(),\n title: z.string().optional(),\n description: z.string().optional(),\n default: z.unknown().optional(),\n minimum: z.number().optional(),\n maximum: z.number().optional(),\n minLength: z.number().optional(),\n maxLength: z.number().optional(),\n pattern: z.string().optional(),\n })\n .catchall(z.unknown()),\n);\n\n/** Either a shorthand name or a full JSON Schema fragment. */\nexport const ColumnTypeSchema = z.union([\n ColumnTypeShorthandSchema,\n JsonSchemaFragmentSchema,\n]);\n\nexport type ColumnType = z.infer<typeof ColumnTypeSchema>;\n\nconst SHORTHAND_FRAGMENTS: Record<ColumnTypeShorthand, JsonSchemaFragment> = {\n string: { type: 'string' },\n number: { type: 'number' },\n integer: { type: 'integer' },\n boolean: { type: 'boolean' },\n date: { type: 'string', format: 'date' },\n 'date-time': { type: 'string', format: 'date-time' },\n object: { type: 'object' },\n array: { type: 'array' },\n};\n\nconst isShorthand = (type: ColumnType): type is ColumnTypeShorthand =>\n typeof type === 'string';\n\n/**\n * Shorthands that are not JSON Schema types, and so need expanding wherever they\n * appear — including inside a fragment, where `\"type\"` is otherwise passed\n * through verbatim.\n *\n * `\"type\": \"date\"` is a crouton spelling of `{ type: \"string\", format: \"date\" }`.\n * Left alone at depth it reaches the frontend as an unknown type: the date\n * renderer tests `format`, the string renderer tests `type === 'string'`, so a\n * nested `\"date\"` matches nothing and the control silently fails to render.\n * Every other shorthand happens to be a real JSON Schema type already.\n */\nconst NESTED_SHORTHANDS: Record<string, JsonSchemaFragment> = {\n date: SHORTHAND_FRAGMENTS.date,\n 'date-time': SHORTHAND_FRAGMENTS['date-time'],\n};\n\n/**\n * Expand crouton shorthands at every depth and return a fresh object graph.\n *\n * Copying matters as much as expanding: the fragment comes straight off the\n * loaded resource config, and callers go on to mutate what they get back\n * (`applySchemaTransforms` adds `minLength`, `injectFieldDefaults` adds\n * `default`). Handing out the config's own nested objects would let a view build\n * rewrite the config it was built from.\n */\nconst normalizeFragment = (\n fragment: JsonSchemaFragment,\n): JsonSchemaFragment => {\n const out: JsonSchemaFragment = { ...fragment };\n\n if (typeof out.type === 'string') {\n const expanded = NESTED_SHORTHANDS[out.type];\n if (expanded) {\n out.type = expanded.type;\n // An explicit `format` wins — the shorthand only fills the blank.\n if (out.format === undefined) out.format = expanded.format;\n }\n }\n\n // Flatten nested-schema-as-type: { type: { type: \"object\", properties: {...} } }\n // → { type: \"object\", properties: {...}, ...other_fields }\n if (out.type && typeof out.type === 'object' && !Array.isArray(out.type)) {\n Object.assign(out, out.type);\n }\n\n if (out.properties) {\n const existingRequired = Array.isArray(out.required) ? out.required : [];\n const hoistedRequired: string[] = [...existingRequired];\n\n out.properties = Object.fromEntries(\n Object.entries(out.properties).map(([key, value]) => {\n let v = { ...value };\n // Hoist required: true from individual property into parent required array\n if (v.required === true) {\n hoistedRequired.push(key);\n const { required: _r, ...rest } = v;\n v = rest as JsonSchemaFragment;\n }\n return [key, normalizeFragment(v)];\n }),\n );\n\n if (hoistedRequired.length > 0) {\n out.required = hoistedRequired;\n } else {\n delete out.required;\n }\n }\n\n if (out.items) out.items = normalizeFragment(out.items as JsonSchemaFragment);\n if (out.additionalProperties && typeof out.additionalProperties === 'object') {\n out.additionalProperties = normalizeFragment(out.additionalProperties as JsonSchemaFragment);\n }\n\n return out;\n};\n\n/** Expand a column `type` into a JSON Schema fragment. */\nexport const columnTypeToJsonSchema = (\n type: ColumnType | undefined,\n): JsonSchemaFragment => {\n if (type === undefined) return { type: 'string' };\n if (isShorthand(type)) return { ...SHORTHAND_FRAGMENTS[type] };\n return normalizeFragment(type);\n};\n\n/**\n * The effective JSON Schema `type` of a column, as a single string.\n *\n * Union types (`[\"string\", \"null\"]`) collapse to their first non-null member,\n * matching how the table layer picks a cell renderer.\n */\nexport const columnTypeName = (type: ColumnType | undefined): string => {\n const fragment = columnTypeToJsonSchema(type);\n const raw = fragment.type;\n if (Array.isArray(raw)) return raw.find((t) => t !== 'null') ?? 'string';\n if (typeof raw === 'string') return raw;\n // No explicit type but nested properties/items present — infer it.\n if (fragment.properties) return 'object';\n if (fragment.items) return 'array';\n return 'string';\n};\n\n/** `true` when the column holds a nested object with declared properties. */\nexport const isObjectColumnType = (type: ColumnType | undefined): boolean =>\n columnTypeName(type) === 'object';\n\n/** `true` when the column holds an array. */\nexport const isArrayColumnType = (type: ColumnType | undefined): boolean =>\n columnTypeName(type) === 'array';\n","import { z } from 'zod';\n\n/**\n * Declares that a resource is only addressable underneath a parent.\n *\n * Set on the **child**, which then mounts its own controller at\n * `<parent.route>/:<parent.param>/<route>` and serves every operation from\n * there. Nothing is configured on the parent, and the parent does not need to\n * exist as a crouton resource at all.\n *\n * ```jsonc\n * { \"kind\": \"custom\", \"name\": \"expense\", \"route\": \"expense\",\n * \"parent\": { \"route\": \"group\", \"param\": \"groupId\" } }\n * // → GET group/:groupId/expense\n * // → GET group/:groupId/expense/:id\n * // → POST group/:groupId/expense …\n * ```\n *\n * Nesting is *exclusive*: no top-level route is registered, so the parent id is\n * always present and a query can never accidentally run unscoped.\n *\n * Only valid on a `kind: \"custom\"` resource. Prisma-backed nesting is derived\n * from relation columns on the parent instead — see `buildSubResources`.\n */\nexport const ParentRefSchema = z.object({\n /** Route segment of the parent, e.g. `\"group\"`. */\n route: z.string(),\n /**\n * Name of the path parameter carrying the parent id, e.g. `\"groupId\"`.\n * Avoid `\"id\"` — that is the child's own id in `/:id` routes.\n */\n param: z.string().default('parentId'),\n /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */\n idType: z.enum(['string', 'number']).optional(),\n});\n\nexport type ParentRef = z.infer<typeof ParentRefSchema>;\n\n/** Controller path for a resource, nested under its parent when it has one. */\nexport const resourceControllerPath = (\n route: string,\n parent: ParentRef | undefined,\n): string => (parent ? `${parent.route}/:${parent.param}/${route}` : route);\n","import { z } from 'zod';\n\n/**\n * Where a resource's data comes from.\n *\n * - `prisma` — the default. Backed by a Prisma model (`model` is required) and\n * a Zod model schema in `schema.ts`. The framework generates the whole data\n * access layer.\n * - `custom` — configuration only. There is no Prisma model and no\n * `schema.ts`; the JSON model is assembled from the column `type`s, and the\n * developer implements the operations in a sibling `repository.ts`.\n */\nexport const ResourceKindSchema = z.enum(['prisma', 'custom']).default('prisma');\n\nexport type ResourceKind = z.infer<typeof ResourceKindSchema>;\n\n/** `true` when the resource's data access is supplied by a user `repository.ts`. */\nexport const isCustomKind = (kind: ResourceKind | undefined): boolean =>\n kind === 'custom';\n","import z from 'zod';\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 const SidebarGroupSchema = z.object({\n /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */\n label: z.string().optional(),\n /** Controls the order of this group among top-level sidebar items. */\n position: z.number().optional(),\n});\n\nexport type SidebarGroupConfig = z.infer<typeof SidebarGroupSchema>;\n\nexport const SidebarSchema = z.object({\n hide: z.boolean().default(false), // default: false\n position: z.number().optional(), // default: sorted alphabetically after positioned entries\n label: z.string().optional(), // default: resource `title`\n\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: z.string().optional(), // must match a key in `sidebarGroups` (crouton.json)\n});\n\nexport type Sidebar = z.infer<typeof SidebarSchema>;\n","import { z } from 'zod';\n// ── Table-level (global) actions ────────────────────────────────────\n\n// Used by row-action / table-action `condition`\nconst ActionConditionSchema = z.object({\n /** Row field to evaluate. */\n field: z.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: z\n .enum(['eq', 'neq', 'gt', 'gte', 'lt', 'lte', 'exists', 'notExists'])\n .default('eq'), // default: 'eq'\n /** Comparison value. Not required for `exists` / `notExists`. */\n value: z.unknown().optional(), // not required for exists/notExists\n});\n\nconst ActionSchema = z.object({\n type: z.string(),\n /** Unique identifier for the action. */\n id: z.string(), // required\n /** Human-readable button label. */\n label: z.string(),\n /** MDI icon name, e.g. `\"mdi:open-in-new\"`. */\n icon: z.string().optional(),\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip: z.string().optional(), // default: falls back to `label`\n condition: ActionConditionSchema.optional(),\n});\n\ntype Action = z.infer<typeof ActionSchema>;\n\nexport const JsonProcedureActionSchema = ActionSchema.extend({\n type: z.literal('procedure').default('procedure'), // default: 'procedure'\n /**\n * Filename (without extension) inside the resource's `actions/` directory\n * that exports the table-action procedure, e.g. `\"syncZotero\"`.\n */\n procedure: z.string(), // required\n /** HTTP method for the frontend. Defaults to `\"post\"`. */\n method: z.string().optional().default('post'), // default: 'post'\n /** Static query / body params passed to the endpoint. */\n data: z.record(z.string(), z.unknown()).optional(),\n});\n\n/** Action that opens a URL in a new browser tab — no backend call. */\nexport const JsonLinkActionSchema = ActionSchema.extend({\n /** Optional condition evaluated per row. Button is hidden when the condition is false. */\n type: z.literal('link').default('link'), // required\n /** URL to open. May contain `{env.VAR}` placeholders. */\n href: z.string(), // required,\n blank: z.boolean().optional().default(true),\n});\n\nconst transformAction = <A extends Action>(action: A) => {\n const label = action.label;\n\n return {\n tooltip: label,\n ...action,\n };\n};\n\nexport const JsonActionSchema = z\n .union([JsonProcedureActionSchema, JsonLinkActionSchema])\n .transform(transformAction);\n\nexport type JsonActionCondition = z.infer<typeof ActionConditionSchema>;\nexport type JsonAction = z.infer<typeof JsonActionSchema>;\nexport type JsonLinkAction = z.infer<typeof JsonLinkActionSchema>;\nexport type JsonProcedureAction = z.infer<typeof JsonProcedureActionSchema>;\n","import type { ZodType } from 'zod';\n\n// Hardcoded to avoid a circular dep with ResourceJson.schema.ts.\n// Update when a key is added to or removed from ResourceJsonShape.\nconst CORE_RESOURCE_KEYS = new Set([\n '$schema', 'schemaVersion', 'draft', 'kind', 'id', 'name', 'route', 'model', 'tag',\n 'title', 'table', 'idType', 'database', 'parent', 'sidebar', 'display',\n 'security', 'operations', 'columns', 'calculatedColumns', 'actions',\n 'tableActions', 'modalSize', 'include', 'extensions',\n]);\n\nconst registry = new Map<string, ZodType>();\n\nexport const registerResourceExtension = (name: string, schema: ZodType): void => {\n if (CORE_RESOURCE_KEYS.has(name))\n throw new Error(`Extension \"${name}\" shadows a core resource key.`);\n registry.set(name, schema);\n};\n\nexport const registerResourceExtensions = (map: Record<string, ZodType> = {}): void =>\n Object.entries(map).forEach(([k, s]) => registerResourceExtension(k, s));\n\nexport const getResourceExtensions = (): ReadonlyMap<string, ZodType> => registry;\n\nexport const clearResourceExtensions = (): void => registry.clear();\n","import { z } from 'zod';\n\n// ── Include ───────────────────────────────────────────────────────────\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 const JsonIncludeEntrySchema: z.ZodType<any> = z.lazy(() =>\n z.union([\n z.string(), // plain relation name → `{ [name]: true }`\n z.object({\n relation: z.string(), // required\n include: z.array(JsonIncludeEntrySchema).optional(), // nested includes;\n /** Prisma-format orderBy clause applied to the included records. */\n orderBy: z.record(z.string(), z.unknown()).optional(),\n }),\n ]),\n);\n\nexport type JsonIncludeEntry = z.infer<typeof JsonIncludeEntrySchema>;\n","/**\n * resource.json schema versioning.\n *\n * `schemaVersion` is a monotonic integer stamped on every `resource.json`. It is\n * **decoupled from the crouton package semver** on purpose — bump it only when the\n * resource.json *shape* changes in a way that needs a migration, and ship a matching\n * step in `./migrations`. This keeps the migration chain one-step-per-bump with no\n * version-range math.\n *\n * Files written before versioning existed carry no field and are treated as the\n * baseline. Because `CURRENT_RESOURCE_VERSION` starts equal to the baseline, shipping\n * the versioning machinery is a pure no-op for every existing file until the first\n * real shape change lands (`CURRENT_RESOURCE_VERSION = 2` + a `1 → 2` migration).\n */\n\n/** Version assumed for a `resource.json` that has no `schemaVersion` field. */\nexport const BASELINE_RESOURCE_VERSION = 1;\n\n/**\n * The version the running crouton understands. Bump by 1 whenever resource.json's\n * shape changes, and add a migration step (`from: N, to: N + 1`) in `./migrations`.\n */\nexport const CURRENT_RESOURCE_VERSION = 1;\n","import { z } from 'zod';\n\nimport { SecuritySchema } from './Security.schema';\n\n// ── Operations ────────────────────────────────────────────────────────\n\n/** An operation served by an external API instead of crouton. */\nconst ExternalOpEntry = z.object({\n uri: z.string(),\n method: z.string().optional(),\n security: SecuritySchema.optional(),\n});\n\nexport type ExternalOpEntry = z.infer<typeof ExternalOpEntry>;\n\n/** A standard operation entry: plain boolean, external route object, or security config. */\nconst OpEntry = z.union([\n z.boolean(),\n ExternalOpEntry,\n z.object({ security: SecuritySchema.optional() }),\n]);\n\nexport const JsonOperationsSchema = z.object({\n findAll: OpEntry.default(true), // default: true — only explicit `false` disables it\n findOne: OpEntry.default(true), // default: true\n create: OpEntry.default(true), // default: true\n update: OpEntry.default(true), // default: true\n patch: OpEntry.default(true), // default: true\n delete: OpEntry.default(true), // default: true\n});\n\nexport type JsonResourceOperations = z.infer<typeof JsonOperationsSchema>;\nexport type JsonResourceOperationsInput = z.input<typeof JsonOperationsSchema>;\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<\n 'findAll' | 'findOne' | 'create' | 'update' | 'patch' | 'delete',\n boolean\n >\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: 'put' },\n }),\n ...(ops.patch && {\n patch: { uri: `${baseUri}/${idPlaceholder}`, method: 'patch' },\n }),\n ...(ops.delete && {\n delete: { uri: `${baseUri}/${idPlaceholder}`, method: 'delete' },\n }),\n };\n};\n","import { z } from 'zod';\n\n/** Public route, or one/more named guards that must all pass (AND). */\nexport const SecuritySchema = z.union([\n z.object({ public: z.literal(true) }),\n z.object({ guard: z.union([z.string(), z.array(z.string()).min(1)]) }),\n]);\n\nexport type SecurityConfig = z.infer<typeof SecuritySchema>;\n","/**\n * Types for the resource.json migration engine.\n *\n * Migrations operate on the **raw** (pre-`ResourceJsonSchema.transform`) object so the\n * result can be written back byte-stably and validated with Zod afterwards — never on a\n * transformed config (which would normalize columns map→array and inject defaults, and\n * so explode diffs). Each step is a pure function returning a new object.\n */\n\nexport type RawResourceJson = Record<string, unknown>;\n\nexport interface ResourceMigration {\n /** Version this step upgrades FROM. */\n readonly from: number;\n /** Version this step upgrades TO — must equal `from + 1`. */\n readonly to: number;\n /** Human-readable summary, surfaced in logs. */\n readonly description: string;\n /** Pure transform: given a raw object at `from`, return a new raw object at `to`. */\n migrate(raw: RawResourceJson): RawResourceJson;\n}\n\nexport interface MigrationResult {\n /** The migrated object, with `schemaVersion` set to `to`. */\n raw: RawResourceJson;\n /** Version the input was at. */\n from: number;\n /** Version the output is at (the requested target). */\n to: number;\n /** Descriptions of the steps applied, in order (empty when already current). */\n applied: string[];\n}\n\n/** No registered step bridges some gap in the chain (or the file is newer than crouton). */\nexport class MigrationPathError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MigrationPathError';\n }\n}\n\n/** A migration step threw while transforming the object. */\nexport class MigrationStepError extends Error {\n constructor(message: string) {\n super(message);\n this.name = 'MigrationStepError';\n }\n}\n","/**\n * The resource.json migration engine.\n *\n * `MIGRATIONS` is an ordered, contiguous chain of single-version steps. `runResourceMigrations`\n * upgrades a raw object from its current `schemaVersion` up to a target (default\n * `CURRENT_RESOURCE_VERSION`), applying each step in turn. It is pure — no fs, no env — so it\n * can be unit-tested in isolation and reused by both the API loader and the CLI.\n */\n\nimport { BASELINE_RESOURCE_VERSION, CURRENT_RESOURCE_VERSION } from '../version';\nimport {\n MigrationPathError,\n type MigrationResult,\n MigrationStepError,\n type RawResourceJson,\n type ResourceMigration,\n} from './types';\n\n/**\n * Ordered, contiguous migration steps. Append one (`from: N, to: N + 1`) every time\n * `CURRENT_RESOURCE_VERSION` is bumped. A gap is a programming error caught by the spec.\n */\nexport const MIGRATIONS: ResourceMigration[] = [\n // Example (add when the first real shape change lands and CURRENT_RESOURCE_VERSION becomes 2):\n // migration_0001to0002,\n];\n\n/** Read a raw object's version, treating a missing/invalid field as the baseline. */\nexport const resourceVersionOf = (raw: RawResourceJson): number => {\n const v = raw['schemaVersion'];\n return typeof v === 'number' && Number.isInteger(v) ? v : BASELINE_RESOURCE_VERSION;\n};\n\n/**\n * Upgrade `raw` from its current version up to `target`.\n *\n * - Already at `target` → returns it unchanged (no `schemaVersion` rewrite), `applied: []`.\n * - Newer than `target` → `MigrationPathError` (crouton is too old; never down-migrate).\n * - A gap with no registered step → `MigrationPathError`.\n * - A step throws → `MigrationStepError`.\n *\n * On success the returned object leads with `schemaVersion: target` for a readable diff.\n */\nexport const runResourceMigrations = (\n raw: RawResourceJson,\n target: number = CURRENT_RESOURCE_VERSION,\n migrations: ResourceMigration[] = MIGRATIONS,\n): MigrationResult => {\n const from = resourceVersionOf(raw);\n\n if (from === target) return { raw, from, to: target, applied: [] };\n\n if (from > target) {\n throw new MigrationPathError(\n `resource.json is version ${from} but this crouton only understands up to ${target} — upgrade crouton`,\n );\n }\n\n let current = raw;\n const applied: string[] = [];\n\n for (let v = from; v < target; v++) {\n const step = migrations.find((m) => m.from === v && m.to === v + 1);\n if (!step) {\n throw new MigrationPathError(`no migration path from version ${v} to ${v + 1}`);\n }\n try {\n current = step.migrate(current);\n } catch (err) {\n throw new MigrationStepError(\n `migration ${v}→${v + 1} (${step.description}) failed: ${(err as Error).message}`,\n );\n }\n applied.push(step.description);\n }\n\n // Lead with schemaVersion so the written file is diff-friendly.\n const { schemaVersion: _old, ...rest } = current;\n return { raw: { schemaVersion: target, ...rest }, from, to: target, applied };\n};\n\nexport * from './types';\n","import type { JsonColumn } from './Column';\nimport { type FieldInput, mergeFieldVariant } from './FieldInput.schema';\n\n/**\n * Resolve the field config that drives each rendering context, applying the\n * `fieldInput → fieldView → fieldTable` fallback chain. These are the single\n * source of truth for the fallback; every consumer (transformer, view builders)\n * goes through them so the three-way behaviour can't drift.\n *\n * form ← fieldInput (base, unchanged)\n * view ← fieldView, then fieldInput\n * table ← fieldTable, then fieldView, then fieldInput\n *\n * Merging is deep one level into `options` (see {@link mergeFieldVariant}).\n */\nexport const resolveFormField = (c: JsonColumn): FieldInput | undefined =>\n c.fieldInput;\n\nexport const resolveViewField = (c: JsonColumn): FieldInput | undefined =>\n mergeFieldVariant(c.fieldInput, c.fieldView);\n\nexport const resolveTableField = (c: JsonColumn): FieldInput | undefined =>\n mergeFieldVariant(resolveViewField(c), c.fieldTable);\n","import type { JsonColumn } from '../resource/Column';\nimport {\n isArrayColumnType,\n isObjectColumnType,\n} from '../resource/ColumnType.schema';\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/** Returns `true` when the column declares a nested object `type`. */\nexport const isObjectColumn = (col: JsonColumn): boolean =>\n isObjectColumnType(col.type);\n\n/** Returns `true` when the column declares an array `type`. */\nexport const isArrayColumn = (col: JsonColumn): boolean =>\n isArrayColumnType(col.type);\n\n/**\n * Returns `true` when an object column can render as a `RecordCell`.\n *\n * Requires a `displayKey`: `RecordCell` shows one nested key, so without one\n * there is nothing meaningful to display and the column is better served by the\n * generic object cell.\n */\nexport const isObjectCell = (col: JsonColumn): boolean =>\n isObjectColumn(col) && !!col.displayKey;\n","import type { ViewColumnConfig } from './view.schema';\nimport type { JsonColumn } from '../resource/Column';\n\n\n/** Resolve the sort position for a column: `fieldInput.position`, then natural index. */\nexport const 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. */\nexport const 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\nexport type FieldContext = 'form' | 'view' | 'table';\n\n/**\n * Return a copy of the column whose `fieldInput` is the resolved variant for the\n * given rendering context, so downstream builders (which all read `fieldInput`)\n * render the right config without any signature change.\n *\n * After the transformer's `resolveColumnFieldVariants` prefill, `fieldView` and\n * `fieldTable` are already the fully-resolved variants; the `?? col.fieldInput`\n * guard covers TS-authored `resource.ts` resources that bypass the transformer.\n */\nexport const columnForContext = (\n col: JsonColumn,\n ctx: FieldContext,\n): JsonColumn => {\n if (ctx === 'view') return { ...col, fieldInput: col.fieldView ?? col.fieldInput };\n if (ctx === 'table') return { ...col, fieldInput: col.fieldTable ?? col.fieldInput };\n return col; // form / filter → base fieldInput\n};\n\nexport const 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","import type { JsonColumn } from '../resource/Column';\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","import { isNullableProperty } from '../schema.utils';\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/**\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\n/**\n * Apply all standard JSON schema post-processing transforms.\n * Ensures every code path that produces a JSON schema gets the same treatment:\n * additional properties allowed, nullable fields dropped from required, and\n * empty strings rejected.\n */\nexport const applySchemaTransforms = (schema: Record<string, unknown>): void => {\n allowAdditionalProperties(schema);\n dropNullableFromRequired(schema);\n enforceRequiredMinLength(schema);\n};\n","\nimport {\n isBoolean,\n isDateRange,\n isObjectCell,\n isRecordCell,\n} from './column-predicates';\nimport { deriveSortId } from './sort.helpers';\nimport type { JsonColumn } from '../resource/Column';\nimport { BooleanCellBuilder, TableBuilder, TextCellBuilder } from '../table/table.builder';\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', 'customComponent'] 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) || isObjectCell(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 // An object column with a displayKey renders the same way as a relation:\n // one nested key out of an object value.\n ...((isRecordCell(col) || isObjectCell(col)) && { type: 'RecordCell' }),\n ...(isDateRange(col) && { type: 'Control' }),\n };\n });\n\n return layout as Record<string, unknown>;\n};\n","import { isArrayColumn, isObjectColumn } from './column-predicates';\nimport { ControlBuilder } from '../layout/control.builder';\nimport { LayoutBuilder } from '../layout/layout.builder';\nimport type { JsonColumn } from '../resource/Column';\nimport { columnTypeName, columnTypeToJsonSchema } from '../resource/ColumnType.schema';\nimport type { DetailConfig } from '../resource/FieldInput.schema';\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 *\n * Kept for backwards compatibility (re-exported from `crud/builder`). The form builder\n * now applies rules through `ControlBuilder.showWhen/hideWhen/disableWhen` instead —\n * see `applyColumnRule`.\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/** Apply a column's conditional rule to a control builder, in the builder chain. */\nconst applyColumnRule = (\n control: ControlBuilder<any>,\n col: JsonColumn,\n): void => {\n if (col.disabledWhen) {\n control.disableWhen(\n `#/properties/${col.disabledWhen.field}`,\n buildConditionSchema(col.disabledWhen),\n );\n return;\n }\n const when = col.showWhen ?? col.hideWhen;\n if (!when) return;\n const scope = `#/properties/${when.field}`;\n const schema = buildConditionSchema(when);\n if (col.showWhen) control.showWhen(scope, schema);\n else control.hideWhen(scope, schema);\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\n/**\n * Renderer format for a column with no explicit `fieldInput.type`, derived from\n * its declared `type`. Scalars keep the historical `text` default.\n */\nconst defaultControlFormat = (col: JsonColumn): string => {\n if (isObjectColumn(col)) return 'object';\n if (isArrayColumn(col)) return 'array';\n const typeName = columnTypeName(col.type);\n if (typeName === 'number' || typeName === 'integer') return typeName;\n const format = columnTypeToJsonSchema(col.type).format;\n if (format === 'date') return 'date';\n if (format === 'date-time') return 'dateTime';\n return 'text';\n};\n\nexport const buildFormControl = (col: JsonColumn): ControlBuilder<any> => {\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 (\n fieldInput?.format !== 'date-range' &&\n (fieldInput?.type === 'date' || fieldInput?.format === 'dateTime')\n ) {\n // Explicit branch (like date-range below) so the datepicker's date options\n // — withTime / min / max / locale — survive into the uischema. Without it\n // these fall through the generic else and are silently dropped.\n const options: any = { ...(fieldInput.options as object | undefined) };\n if (!options.colspan) options.colspan = 12;\n const format = fieldInput.format === 'dateTime' ? 'dateTime' : 'date';\n control.control(format, options).width('full');\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 // Drive the renderer off the column's declared shape when no widget is\n // named. Without this an object/array column falls through to `text`, whose\n // tester requires a string schema, and no renderer matches at all.\n const type = fieldInput?.type ?? defaultControlFormat(col);\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 // Label and conditional rules are expressed in the builder chain — no post-build mutation.\n if (col.label) control.label(col.label);\n applyColumnRule(control, col);\n\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 for (const col of cols) layout.addControl(buildFormControl(col));\n return layout.build() as unknown as Record<string, unknown>;\n};\n","import type { ViewColumnConfig, ViewConfig } from './view.schema';\nimport type { CalculatedColumn } from '../resource/CalculatedColumn.schema';\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","import { type ZodObject, type ZodRawShape, toJSONSchema } from 'zod';\n\n\nimport { isRelation } from './column-predicates';\nimport {\n columnToJsonSchemaProperty,\n columnTypeSchemaSource,\n} from './column-type-schema.source';\nimport { columnForContext, sortByPosition, toViewColumn } from './column.utils';\nimport { buildFormUiSchema } from './form-schema.builder';\nimport { jsonSchemaOpts } from './json-schema.opts';\nimport { orderTableColumnsFromLayout } from './layout-table-order';\nimport { buildFormUiSchemaFromLayout } from './layout-ui-schema.builder';\nimport { applySchemaTransforms } from './schema-transforms';\nimport { resolveDefaultSort } from './sort.helpers';\nimport { buildTableUiSchema } from './table-schema.builder';\nimport type { ViewConfig } from './view.schema';\nimport type { JsonColumn } from '../resource/Column';\nimport type { Layout } from '../resource/Layout.schema';\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 */\nexport const 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 =\n (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(\n (opts['fromLabel'] as string) ?? `${base} (from)`,\n );\n properties[`${col.id}->${toField}`] = dateProp(\n (opts['toLabel'] as string) ?? `${base} (to)`,\n );\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 = (\n col.fieldInput?.options as Record<string, unknown> | undefined\n )?.['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 (\n ft === 'number' ||\n prop.type === 'number' ||\n prop.type === 'integer'\n ) {\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/**\n * Copy each column's `fieldInput.defaultValue` (when set) onto the matching\n * JSON Schema property as `default`. Consumed by the frontend's\n * `form.parseValue({})` (see `@ghentcdh/crouton-vue`'s `form-def.ts`) to\n * pre-fill a blank create-form record. Relation columns never reach here —\n * `buildView` filters them out of the picked schema before this runs.\n */\nconst injectFieldDefaults = (\n jsonSchema: Record<string, unknown>,\n columns: JsonColumn[],\n): void => {\n const properties = jsonSchema.properties as\n | Record<string, Record<string, unknown>>\n | undefined;\n if (!properties) return;\n for (const col of columns) {\n if (col.fieldInput?.defaultValue === undefined) continue;\n const prop = properties[col.id];\n if (prop) prop.default = col.fieldInput.defaultValue;\n }\n};\n\n// ── View building ─────────────────────────────────────────────────────────\n\n/**\n * Produces the `json_schema` for one view from the columns that belong in it.\n *\n * Two implementations exist: `zodSchemaSource` picks a mask off the resource's\n * Zod model schema (prisma resources), and `columnTypeSchemaSource` assembles\n * properties from each column's declared `type` (custom resources, which have\n * no `schema.ts`). Returning `undefined` skips the view entirely.\n */\nexport type ViewJsonSchemaSource = (\n schemaCols: JsonColumn[],\n) => Record<string, unknown> | undefined;\n\n/** Build a view's json_schema by picking a mask off the resource's Zod schema. */\nexport const zodSchemaSource =\n (schema: ZodObject<ZodRawShape>): ViewJsonSchemaSource =>\n (schemaCols) => {\n const schemaKeys = new Set(Object.keys(schema.shape));\n const schemaIds = schemaCols\n .map((c) => c.id)\n .filter((id) => schemaKeys.has(id));\n if (!schemaIds.length) return undefined;\n const mask = Object.fromEntries(schemaIds.map((id) => [id, true as const]));\n const picked = schema.pick(mask as any);\n try {\n return toJSONSchema(picked, {\n target: 'draft-07',\n ...jsonSchemaOpts,\n }) as Record<string, unknown>;\n } catch {\n // Zod v4 bug: z.record() inside z.union() inside z.lazy() crashes toJSONSchema.\n // Skip this field's JSON schema contribution — the column's type will be used instead.\n return undefined;\n }\n };\n\n/**\n * Apply column-level `required` to a form's `json_schema`.\n *\n * For a prisma resource the Zod model has already produced a `required` array and\n * a column overrides it in either direction; for a `kind: \"custom\"` resource\n * there is no model, so this is the only source of `required`.\n *\n * `undefined` leaves the schema's own answer alone — which is why the column flag\n * is optional rather than defaulting to `false`.\n */\n/**\n * Every JSON Schema type except `null`.\n *\n * A typeless property — what an autocomplete column emits, since the shape of its\n * `{ value, label }` envelope depends on the widget's `storeValue` option — becomes\n * `unknown` once the form converts the schema to Zod, and `unknown` accepts\n * `undefined` and `null`. Listing it in `required` therefore validated nothing:\n * the control showed its required marker and an empty field still submitted.\n *\n * Constraining the type to \"anything but null\" is what makes the requirement bite\n * without claiming to know the envelope's shape. `not: { type: 'null' }` would say\n * it more directly but Zod cannot represent `not`.\n */\nconst NON_NULL_TYPES = ['object', 'array', 'string', 'number', 'boolean'];\n\n/** Keys that already constrain a property's shape enough to reject null. */\nconst SHAPE_KEYS = ['type', 'enum', 'const', 'anyOf', 'oneOf', 'allOf', '$ref'];\n\nconst applyRequiredColumns = (\n jsonSchema: Record<string, unknown>,\n columns: JsonColumn[] | undefined,\n): void => {\n if (!columns?.length) return;\n const properties = jsonSchema['properties'] as\n | Record<string, unknown>\n | undefined;\n if (!properties) return;\n\n const required = new Set(\n Array.isArray(jsonSchema['required'])\n ? (jsonSchema['required'] as string[])\n : [],\n );\n\n for (const col of columns) {\n if (col.required === undefined) continue;\n if (!(col.id in properties)) continue;\n if (!col.required) {\n required.delete(col.id);\n continue;\n }\n // Same exclusion `buildView` applies to the model's own `required`: a field\n // the form cannot edit must not be demanded, or every submit fails on a value\n // the user has no way to provide.\n if (col.idField) continue;\n if (col.createable === false && col.updateable === false) continue;\n required.add(col.id);\n\n // A typeless property cannot be required in any meaningful sense — see\n // NON_NULL_TYPES. Give it just enough of a type to reject an empty value.\n const property = properties[col.id];\n if (\n property &&\n typeof property === 'object' &&\n !SHAPE_KEYS.some((key) => key in (property as Record<string, unknown>))\n ) {\n (property as Record<string, unknown>)['type'] = [...NON_NULL_TYPES];\n }\n }\n\n if (required.size) jsonSchema['required'] = [...required];\n else delete jsonSchema['required'];\n};\n\nconst buildView = (\n source: ViewJsonSchemaSource | 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 (!source || !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 // Relation columns are managed via sub-resource endpoints — exclude from\n // the schema pick so their complex Zod definitions (z.lazy arrays) don't\n // produce validation constraints on the parent. With additionalProperties\n // enabled, relation data in the payload still passes validation.\n const schemaCols = (schemaVisible\n ? columns.filter((c) => visible(c) || schemaVisible(c))\n : visibleCols\n ).filter((c) => !isRelation(c));\n\n const jsonSchema = source(schemaCols);\n if (!jsonSchema) return undefined;\n applySchemaTransforms(jsonSchema);\n injectFieldDefaults(jsonSchema, visibleCols);\n\n // Drop idField and explicitly non-editable fields from `required` so\n // hidden-but-schema-included fields don't cause validation failures.\n if (schemaVisible) {\n const nonEditableIds = new Set(\n schemaCols\n .filter((c) => c.idField || (c.createable === false && c.updateable === false))\n .map((c) => c.id),\n );\n const required = jsonSchema['required'] as string[] | undefined;\n if (Array.isArray(required) && nonEditableIds.size) {\n jsonSchema['required'] = required.filter((k) => !nonEditableIds.has(k));\n }\n }\n\n return {\n json_schema: jsonSchema,\n ui_schema: buildUiSchema(visibleCols),\n columns: visibleCols.map(toViewColumn),\n };\n};\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/**\n * Build table / form / filter / view schemas from column definitions and a\n * json_schema source.\n *\n * Shared by the Zod-backed path (`buildViews`) and the column-type path\n * (`buildViewsFromColumnTypes`) so both produce identical view shapes —\n * default sort, filter hints, and the `required` trimming all behave the same\n * regardless of where the properties came from.\n */\nexport const buildViewsWithSource = (\n source: ViewJsonSchemaSource | undefined,\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined => {\n const views: Record<string, ViewConfig> = {};\n\n const tableCols = columns?.map((c) => columnForContext(c, 'table'));\n let table = buildView(\n source,\n tableCols,\n (c) => !c.hiddenInTable,\n buildTableUiSchema,\n true,\n );\n if (table) {\n table.defaultSort = resolveDefaultSort(\n table.columns as JsonColumn[],\n columns,\n );\n if (layout?.table) table = orderTableColumnsFromLayout(table, layout.table);\n views.table = table;\n } else if (columns !== undefined) {\n views.table = emptyTableView();\n }\n\n const formUiBuilder = layout?.form\n ? (cols: JsonColumn[]) => buildFormUiSchemaFromLayout(layout.form!, cols)\n : buildFormUiSchema;\n const form = buildView(\n source,\n columns,\n (c) => !c.hiddenInForm,\n formUiBuilder,\n true,\n (c) => !c.idField && (c.createable === true || c.updateable === true),\n );\n if (form) {\n applyRequiredColumns(form.json_schema as Record<string, unknown>, columns);\n views.form = form;\n }\n\n const filter = buildView(\n source,\n columns,\n (c) => !!c.filterable,\n buildFormUiSchema,\n true,\n );\n if (filter) {\n patchFilterProperties(\n filter.json_schema as Record<string, any>,\n columns?.filter((c) => !!c.filterable),\n );\n views.filter = filter;\n }\n\n const viewCols = columns?.map((c) => columnForContext(c, 'view'));\n const viewUiBuilder = layout?.view\n ? (cols: JsonColumn[]) => buildFormUiSchemaFromLayout(layout.view!, cols)\n : buildFormUiSchema;\n const view = buildView(\n source,\n viewCols,\n (c) => !c.hiddenInView,\n viewUiBuilder,\n true,\n );\n if (view) views.view = view;\n\n return Object.keys(views).length ? views : undefined;\n};\n\n/**\n * Build table / form / filter / view schemas from a Zod schema + column definitions.\n *\n * When `schema` is absent (no schema.ts), falls back to `columnTypeSchemaSource`\n * so column `type` declarations are the single source of truth — same behaviour\n * as `buildViewsFromColumnTypes`, now available for any kind, not just \"custom\".\n */\nexport const buildViews = (\n schema: ZodObject<ZodRawShape> | undefined,\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined =>\n buildViewsWithSource(schema ? zodSchemaSource(schema) : columnTypeSchemaSource, columns, layout);\n\n/**\n * Build table / form / filter / view schemas for a resource with no Zod model\n * schema, deriving every property from the columns' declared `type`.\n *\n * This is the `kind: \"custom\"` path: there is no `schema.ts` to pick from, so\n * the column configuration is the single source of truth for the json model.\n *\n * Note there is no `required` array — a custom resource declares shapes, not\n * obligations, and validating a payload is the `repository.ts` author's job.\n */\nexport const buildViewsFromColumnTypes = (\n columns: JsonColumn[] | undefined,\n layout?: Layout,\n): Record<string, ViewConfig> | undefined =>\n buildViewsWithSource(columnTypeSchemaSource, columns, layout);\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 // Only nest when `column` introduces genuine grouping (extend columns).\n // When column === id the data is flat — nesting would be self-referential.\n if (c.column && c.column !== c.id) {\n if (!properties[c.column]) {\n properties[c.column] = {\n type: 'object',\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] = {\n type: 'object',\n properties: {},\n };\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 if (c.type !== undefined) {\n // A declared `type` is the whole point of a column config that has no\n // Zod model behind it — honour it here exactly as `columnTypeSchemaSource`\n // does, rather than falling through to the `string` default below.\n properties[c.id] = columnToJsonSchemaProperty(c);\n } else {\n const opts = c.fieldInput?.options as\n Record<string, unknown> | undefined;\n const isObject =\n opts?.emitObject === true || c.fieldInput?.type === 'autocomplete';\n properties[c.id] = {\n ...(isObject ? {} : { type: c.columnType ?? 'string' }),\n title: c.label ?? c.id,\n ...(c.fieldInput?.defaultValue !== undefined\n ? { default: c.fieldInput.defaultValue }\n : {}),\n };\n }\n }\n const schema: Record<string, unknown> = { type: 'object', properties };\n applySchemaTransforms(schema);\n return schema;\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 || col.column === col.id) 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(\n columns.filter((c) => !c.hiddenInTable).map((c) => columnForContext(c, 'table')),\n );\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) {\n applyRequiredColumns(form.json_schema as Record<string, unknown>, formCols);\n views.form = form;\n }\n\n const viewCols = sortByPosition(\n columns.filter((c) => !c.hiddenInView).map((c) => columnForContext(c, 'view')),\n );\n const viewView = makeView(viewCols, buildFormUiSchema);\n if (viewView) views.view = viewView;\n\n return Object.keys(views).length ? views : undefined;\n};\n","import { isAutocomplete } from './column-predicates';\nimport type { JsonColumn } from '../resource/Column';\nimport {\n type JsonSchemaFragment,\n columnTypeToJsonSchema,\n} from '../resource/ColumnType.schema';\n\n/**\n * Assemble a view's `json_schema` from the columns' declared `type`s.\n *\n * This is the `kind: \"custom\"` counterpart to `zodSchemaSource`: a custom\n * resource has no `schema.ts`, so the column configuration is the only\n * description of the data shape.\n *\n * A column's property is its `type` fragment (shorthand expanded), enriched\n * with:\n * - `title` from the column label, so the form and filter layers show a proper\n * heading without a second lookup;\n * - `default` from `fieldInput.defaultValue`, matching the Zod path where\n * `injectFieldDefaults` does the same;\n * - `enum` from `fieldInput.options.values`, so an enum-backed select validates\n * against its own option list.\n *\n * An autocomplete column with no declared `type` is emitted as a typeless\n * property, matching `buildViewsFromColumns`: the value is a `{value, label}`\n * envelope whose exact shape depends on the widget's `storeValue` option.\n */\nconst optionValues = (col: JsonColumn): unknown[] | undefined => {\n const values = (col.fieldInput?.options as Record<string, unknown> | undefined)\n ?.['values'];\n if (!Array.isArray(values)) return undefined;\n // Options are either primitives or `{ value, label }` envelopes.\n const unwrapped = values.map((v) =>\n v && typeof v === 'object' && 'value' in (v as Record<string, unknown>)\n ? (v as Record<string, unknown>).value\n : v,\n );\n return unwrapped.length ? unwrapped : undefined;\n};\n\n/** JSON Schema property for a single column, derived from its `type`. */\nexport const columnToJsonSchemaProperty = (\n col: JsonColumn,\n): JsonSchemaFragment => {\n const property: JsonSchemaFragment =\n col.type === undefined && isAutocomplete(col)\n ? {}\n : { ...columnTypeToJsonSchema(col.type) };\n\n if (property.title === undefined) property.title = col.label ?? col.id;\n\n if (\n col.fieldInput?.defaultValue !== undefined &&\n property.default === undefined\n ) {\n property.default = col.fieldInput.defaultValue;\n }\n\n if (property.enum === undefined) {\n const values = optionValues(col);\n if (values) property.enum = values;\n }\n\n return property;\n};\n\n/**\n * `ViewJsonSchemaSource` for resources without a Zod model schema.\n *\n * Returns `undefined` when no column contributes a property, so the caller\n * skips the view — same contract as `zodSchemaSource`.\n */\nexport const columnTypeSchemaSource = (\n schemaCols: JsonColumn[],\n): Record<string, unknown> | undefined => {\n if (!schemaCols.length) return undefined;\n\n const properties: Record<string, JsonSchemaFragment> = {};\n for (const col of schemaCols) {\n properties[col.id] = columnToJsonSchemaProperty(col);\n }\n\n return { type: 'object', properties };\n};\n","import type { ZodType } from 'zod';\nimport { z } from 'zod';\n\ntype ToJSONSchemaParams = NonNullable<\n // eslint-disable-next-line @typescript-eslint/consistent-type-imports\n Parameters<typeof import('zod').toJSONSchema>[1]\n>;\ntype OverrideContext = Parameters<\n NonNullable<ToJSONSchemaParams['override']>\n>[0];\n\n/**\n * Detect if a ZodCustom schema wraps a `z.instanceof(Cls)` where `Cls.name`\n * matches the given name. Uses a single `safeParse(null)` to extract the\n * `expected` field from the validation error — lightweight and works even\n * when the class reference is unreachable (closure-captured as `cls`).\n */\nconst isInstanceOf = (zodSchema: unknown, className: string): boolean => {\n if (!(zodSchema instanceof z.ZodCustom)) return false;\n const result = (zodSchema as z.ZodCustom<unknown>).safeParse(null);\n if (result.success) return false;\n const issue = result.error.issues[0] as { expected?: string; message?: string };\n // When z.instanceof(Cls) has no custom message, Zod emits { expected: 'Cls.name' }.\n // When a custom message is provided (e.g. zod-prisma-types does this), Zod emits\n // { code: 'custom', message: '...' } with no `expected` — so also check the message.\n return issue?.expected === className || (issue?.message?.includes(className) ?? false);\n};\n\nconst jsonSchemaOverride = ({ zodSchema, jsonSchema }: OverrideContext) => {\n if (zodSchema instanceof z.ZodDate) {\n jsonSchema.type = 'string';\n jsonSchema.format = 'date-time';\n }\n // Prisma BigInt fields use z.bigint() which has no JSON schema equivalent.\n // Patch to { type: \"integer\" } so the frontend treats them as whole numbers.\n if (zodSchema instanceof z.ZodBigInt) {\n jsonSchema.type = 'integer';\n }\n // Prisma Decimal fields use z.instanceof(Prisma.Decimal) which produces\n // an empty JSON schema ({}). Patch to { type: \"number\" } so the frontend\n // renders a number input with proper validation.\n // Prisma 7+ bundles the class as 'Decimal2'; check both names.\n if (isInstanceOf(zodSchema, 'Decimal') || isInstanceOf(zodSchema, 'Decimal2')) {\n jsonSchema.type = 'number';\n }\n // Prisma Bytes fields use z.instanceof(Buffer) which produces an empty\n // JSON schema. Patch to { type: \"string\" } since binary data is typically\n // base64-encoded when serialized to JSON.\n if (isInstanceOf(zodSchema, 'Buffer')) {\n jsonSchema.type = 'string';\n }\n};\n\ntype ZodTypeInternal = ZodType & { _zod?: { def?: { type?: string; innerType?: ZodType } } };\n\n/** Strip optional/nullable/default/readonly wrappers to reach the core type. */\nconst unwrap = (schema: ZodType): ZodType => {\n let s: ZodTypeInternal = schema;\n let t: string | undefined = s._zod?.def?.type;\n while (t === 'optional' || t === 'nullable' || t === 'default' || t === 'readonly') {\n s = (s._zod?.def?.innerType ?? s) as ZodTypeInternal;\n t = s._zod?.def?.type;\n }\n return s;\n};\n\n/**\n * Returns true when `zodType` (after unwrapping) is a `z.instanceof(Prisma.Decimal)`.\n * Checks both 'Decimal' (Prisma ≤6) and 'Decimal2' (Prisma 7+ runtime bundle).\n */\nexport const isDecimalField = (zodType: ZodType): boolean => {\n const inner = unwrap(zodType);\n return isInstanceOf(inner, 'Decimal') || isInstanceOf(inner, 'Decimal2');\n};\n\nexport const jsonSchemaOpts = {\n unrepresentable: 'any' as const,\n override: jsonSchemaOverride,\n};\n","import { buildFormControl } from './form-schema.builder';\nimport { LayoutBuilder } from '../layout/layout.builder';\nimport type { JsonColumn } from '../resource/Column';\nimport type { LayoutControl, LayoutNode } from '../resource/Layout.schema';\n\nconst buildContainerForNode = (node: LayoutNode): LayoutBuilder<any> => {\n const type = node.type ?? 'grid';\n let builder: LayoutBuilder<any>;\n switch (type) {\n case 'collapse':\n builder = LayoutBuilder.collapse<any>();\n if (node.title) builder.title(node.title);\n if (node.titleKey) builder.titleKey(node.titleKey);\n break;\n case 'group':\n builder = LayoutBuilder.group<any>();\n if (node.title) builder.title(node.title);\n if (node.titleKey) builder.titleKey(node.titleKey);\n break;\n case 'horizontal':\n builder = LayoutBuilder.horizontal<any>();\n break;\n case 'vertical':\n builder = LayoutBuilder.vertical<any>();\n break;\n default:\n builder = LayoutBuilder.grid<any>(node.columns);\n }\n if (node.colspan !== undefined) builder.colspan(node.colspan);\n if (node.rowspan !== undefined) builder.rowspan(node.rowspan);\n if (node.label) builder.label(node.label);\n return builder;\n};\n\nconst resolveControlId = (ctrl: LayoutControl): string =>\n typeof ctrl === 'string' ? ctrl : ctrl.id;\n\nconst applyControlOverrides = (\n base: ReturnType<typeof buildFormControl>,\n ctrl: LayoutControl,\n): ReturnType<typeof buildFormControl> => {\n if (typeof ctrl === 'string') return base;\n if (ctrl.colspan !== undefined) base.colspan(ctrl.colspan);\n if (ctrl.rowspan !== undefined) base.rowspan(ctrl.rowspan);\n if (ctrl.width !== undefined) base.width(ctrl.width as any);\n if (ctrl.label !== undefined) base.label(ctrl.label);\n if (ctrl.hideLabel) base.hideLabel();\n if (ctrl.type !== undefined || ctrl.options !== undefined) {\n base.control(ctrl.type ?? 'text', ctrl.options as any);\n }\n return base;\n};\n\nconst buildNodeInto = (\n node: LayoutNode,\n colMap: Map<string, JsonColumn>,\n warn: (msg: string) => void,\n seenIds: Set<string>,\n): LayoutBuilder<any> => {\n const container = buildContainerForNode(node);\n\n // Controls first, then nested items\n if (node.controls?.length) {\n for (const ctrl of node.controls) {\n const id = resolveControlId(ctrl);\n const col = colMap.get(id);\n if (!col) {\n warn(`layout: unknown or hidden column id \"${id}\" — skipping`);\n continue;\n }\n if (typeof ctrl !== 'string') {\n if (ctrl.colspan !== undefined && (ctrl as any).rowspan !== undefined) {\n // table context: warn on span overrides\n }\n }\n seenIds.add(id);\n const control = buildFormControl(col);\n container.addControl(applyControlOverrides(control, ctrl));\n }\n }\n\n if (node.items?.length) {\n for (const item of node.items) {\n const child = buildNodeInto(item, colMap, warn, seenIds);\n container.addControl(child);\n }\n }\n\n return container;\n};\n\n/**\n * Build a form/view UI schema from an author-declared layout node tree.\n * Falls back to source-order grid for any visible columns not referenced.\n */\nexport const buildFormUiSchemaFromLayout = (\n node: LayoutNode,\n cols: JsonColumn[],\n warn: (msg: string) => void = console.warn,\n): Record<string, unknown> => {\n const colMap = new Map(cols.map((c) => [c.id, c]));\n const seenIds = new Set<string>();\n\n const root = buildNodeInto(node, colMap, warn, seenIds);\n\n // Append unreferenced columns to preserve backward-compat\n const unreferenced = cols.filter((c) => !seenIds.has(c.id));\n if (unreferenced.length) {\n for (const col of unreferenced) {\n warn(`layout: column \"${col.id}\" not referenced in layout — appending`);\n root.addControl(buildFormControl(col));\n }\n }\n\n return root.build() as unknown as Record<string, unknown>;\n};\n\n/**\n * Flatten the layout node tree depth-first into an ordered list of control ids.\n * Used by the table ordering step.\n */\nexport const flattenLayoutControlIds = (node: LayoutNode): string[] => {\n const ids: string[] = [];\n const visit = (n: LayoutNode): void => {\n for (const ctrl of n.controls ?? []) {\n const id = typeof ctrl === 'string' ? ctrl : ctrl.id;\n if (typeof ctrl !== 'string') {\n const c = ctrl as { colspan?: number; rowspan?: number };\n if ((c.colspan !== undefined || c.rowspan !== undefined)) {\n // ponytail: span on table controls silently ignored — table is flat\n }\n }\n ids.push(id);\n }\n for (const item of n.items ?? []) visit(item);\n };\n visit(node);\n return ids;\n};\n","import { flattenLayoutControlIds } from './layout-ui-schema.builder';\nimport type { ViewConfig } from './view.schema';\nimport type { LayoutNode } from '../resource/Layout.schema';\n\n/**\n * Reorder a table view's elements and columns to match the `layout.table` declaration.\n * Unreferenced visible columns keep their relative order at the end.\n */\nexport const orderTableColumnsFromLayout = (\n view: ViewConfig,\n node: LayoutNode,\n warn: (msg: string) => void = console.warn,\n): ViewConfig => {\n const orderedIds = flattenLayoutControlIds(node);\n if (!orderedIds.length) return view;\n\n const elements: any[] = (view.ui_schema as any)?.elements ?? [];\n const columns: any[] = view.columns ?? [];\n\n const elementById = new Map(\n elements.map((el) => {\n const id = (el.scope as string | undefined)?.replace('#/properties/', '');\n return [id, el];\n }),\n );\n const columnById = new Map(columns.map((c: any) => [c.id, c]));\n\n const knownIds = new Set([...elementById.keys()].filter(Boolean) as string[]);\n\n const reorderedElements: any[] = [];\n const reorderedColumns: any[] = [];\n const seen = new Set<string>();\n\n for (const id of orderedIds) {\n if (!knownIds.has(id)) {\n warn(`layout.table: column \"${id}\" not found in visible table columns — skipping`);\n continue;\n }\n seen.add(id);\n const el = elementById.get(id);\n if (el) reorderedElements.push(el);\n const col = columnById.get(id);\n if (col) reorderedColumns.push(col);\n }\n\n // Append unreferenced visible columns in their original relative order\n for (const el of elements) {\n const id = (el.scope as string | undefined)?.replace('#/properties/', '');\n if (id && !seen.has(id)) {\n reorderedElements.push(el);\n const col = columnById.get(id);\n if (col) reorderedColumns.push(col);\n }\n }\n\n return {\n ...view,\n ui_schema: { ...(view.ui_schema as any), elements: reorderedElements },\n columns: reorderedColumns,\n };\n};\n","import { z } from 'zod';\n\nimport { FieldInputSchema } from '../resource/FieldInput.schema';\n\nexport const ViewColumnConfigSchema = z.object({\n id: z.string(),\n label: z.string().optional(),\n sortable: z.boolean().optional(),\n searchable: z.boolean().optional(),\n fieldInput: FieldInputSchema.optional(),\n});\n\nexport type ViewColumnConfig = z.infer<typeof ViewColumnConfigSchema>;\n\nexport const ViewConfigSchema = z.object({\n // TODO why we have both?\n json_schema: z.record(z.string(), z.unknown()).optional(),\n ui_schema: z.record(z.string(), z.unknown()).optional(),\n // TODO why we have both?\n ui: z.record(z.string(), z.unknown()).optional(),\n data: z.record(z.string(), z.unknown()).optional(),\n columns: z.array(ViewColumnConfigSchema),\n defaultSort: z.string().optional(),\n});\n\nexport type ViewConfig = z.infer<typeof ViewConfigSchema>;\n\nconst viewDefList = ['table', 'view', 'form'] as const;\nexport const ViewDefEnum = z.enum(viewDefList);\nexport type ViewDef = (typeof viewDefList)[number];\n","import { z } from 'zod';\n\nimport type { JsonColumn } from '../resource';\n\nconst EnumEntrySchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport type EnumEntry = z.infer<typeof EnumEntrySchema>;\n\nexport const EnumRegistrySchema = z\n .record(z.string(), z.array(EnumEntrySchema))\n .default({});\n\nexport type EnumRegistry = z.infer<typeof EnumRegistrySchema>;\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 =\n (col.fieldInput.options as Record<string, unknown> | undefined) ?? {};\n if (!('values' in options)) options.values = values;\n if (!('emitObject' in options)) options.emitObject = true;\n if (!('displayKey' in options)) options.displayKey = 'label';\n col.fieldInput.options = options;\n }\n};\n","import { ZodArray, ZodNullable, type ZodObject, ZodOptional, type ZodRawShape } from 'zod';\n\nimport type { JsonColumn, RelationType } from '../resource';\n\nexport const unwrapZodType = (type: any): any => {\n if (type instanceof ZodOptional || type instanceof ZodNullable) {\n return unwrapZodType(type.unwrap());\n }\n return type;\n};\n\nexport const 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\nexport const 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\nexport const 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;\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","import { z } from 'zod';\n\nimport { ResourceJsonShape } from '../resource';\nimport { ViewConfigSchema } from '../view';\nimport { CompiledSubResourceConfigSchema } from './compiled-sub-resource.schema';\nimport { DefinitionSchema } from './definition.schema';\nimport { LookupSchema } from './lookup.schema';\nimport { ValueLabelColumnSchema } from './value-label-column';\n\nexport const CompiledResourceSchema = ResourceJsonShape.extend({\n route: z.string(),\n valueLabelColumns: z.array(ValueLabelColumnSchema).default([]),\n subResources: z.lazy(() => z.array(CompiledSubResourceConfigSchema)).default([]),\n lookup: LookupSchema.optional(),\n views: z.record(z.string(), ViewConfigSchema),\n definition: DefinitionSchema,\n idField: z.string(),\n idType: z.enum(['string', 'number']).default('string'),\n});\n\nexport type CompiledResource = z.infer<typeof CompiledResourceSchema>;\n","import { z } from 'zod';\n\nimport { JsonOperationsSchema } from '../data-source';\nimport {\n CalculatedColumnSchema,\n JsonActionSchema,\n JsonDisplaySchema,\n JsonIncludeEntrySchema,\n} from '../resource';\nimport { ViewConfigSchema } from '../view';\nimport { ValueLabelColumnSchema } from './value-label-column';\n\nexport const CompiledSubResourceConfigSchema = z.object({\n column: z.string(),\n relation: z.string(),\n childRoute: z.string(),\n childKind: z.enum(['prisma', 'custom']).default('prisma'),\n childDir: z.string().optional(),\n childModel: z.string(),\n foreignKey: z.string(),\n name: z.string().optional(),\n title: z.string().optional(),\n idField: z.string().optional(),\n idType: z.enum(['string', 'number']).optional(),\n views: z.record(z.string(), ViewConfigSchema).optional(),\n operations: JsonOperationsSchema,\n actions: z.array(JsonActionSchema).optional(),\n modalSize: z.enum(['xs', 'sm', 'lg', 'xl']).optional(),\n display: JsonDisplaySchema.optional(),\n include: z.array(JsonIncludeEntrySchema).optional(),\n calculatedColumns: z.array(CalculatedColumnSchema).optional(),\n includeInFindOne: z.boolean().optional(),\n hiddenInTable: z.boolean().optional(),\n findOneOrderBy: z.record(z.string(), z.unknown()).optional(),\n valueLabelColumns: z.array(ValueLabelColumnSchema).optional(),\n relationType: z.enum(['oneToMany', 'manyToOne']).optional(),\n});\n\nexport type CompiledSubResourceConfig = z.infer<typeof CompiledSubResourceConfigSchema>;\n","import z from 'zod';\n/**\n * Shape of a `data-source.json`. The `type`/`name`/`default` keys are also read by crouton-api at runtime;\n * the rest are codegen-only.\n */\nexport const DataSourceShape = z.object({\n /** Datasource name (folder + `name` in data-source.json). */\n name: z.string(),\n /**\n * Env var holding the connection URL. Required for Prisma adapters; optional\n * for custom adapters whose connection config may differ (secrets file, SDK\n * key, etc.).\n */\n urlEnv: z.string().optional(),\n /** Import path for this datasource's generated Zod types (for resource `schema.ts`). */\n generatedTypesImport: z.string().optional(),\n /** Datasource type tag. Default `postgres`. */\n type: z.string().default('postgres'),\n /** Mark this as the default datasource. Default `false`. */\n default: z.boolean().default(false),\n /**\n * Adapter kind. `\"prisma\"` (default) expects `index.ts` to default-export a\n * `PrismaClient`; `\"custom\"` expects it to default-export a `DataSourceAdapter`.\n */\n adapter: z.enum(['prisma', 'custom']).default('prisma'),\n /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */\n prismaSchema: z.string().optional(),\n /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */\n prismaConfig: z.string().optional(),\n /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */\n zodOutput: z.string().optional(),\n /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */\n clientOutput: z.string().optional(),\n});\n\nexport const transformDataSource = <D extends z.infer<typeof DataSourceShape>>(\n data: D,\n) => {\n const name = data.name ?? 'name';\n\n return {\n ...data,\n generatedTypesImport:\n data.generatedTypesImport ?? `@your-scope/generated/${name}`,\n prismaSchema: data.prismaSchema ?? `prisma/${name}/schema.prisma`,\n prismaConfig: data.prismaConfig ?? `prisma/${name}/prisma.config.ts`,\n zodOutput: data.zodOutput ?? `generated/${name}/src`,\n clientOutput: data.clientOutput ?? `generated/${name}/client`,\n };\n};\n\nexport const DataSourceSchema = DataSourceShape.transform(transformDataSource);\n\nexport type DataSource = z.infer<typeof DataSourceSchema>;\n","import { z } from 'zod';\n\nconst ValueSchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport const ValueLabelColumnSchema = z.object({\n field: z.string(),\n values: z.array(ValueSchema).default([]),\n enumName: z.string().optional(),\n});\n\nexport type ValueLabelColumn = z.infer<typeof ValueLabelColumnSchema>;\n","import { z } from 'zod';\n\nimport { SchemaInputSchema } from './schema-input';\nimport { SecuritySchema } from '../data-source/Security.schema';\n\n\nexport type { JsonSchemaInput, SchemaInput } from './schema-input';\n\nconst ExternalOperationDefSchema = z.object({\n uri: z.string(),\n method: z.string().optional(),\n});\n\nconst OperationDefSchema = z.union([\n z.literal(true),\n ExternalOperationDefSchema,\n z.object({\n schema: SchemaInputSchema.optional(),\n security: SecuritySchema.optional(),\n }),\n]);\n\nexport type OperationDef = z.infer<typeof OperationDefSchema>;\n\nexport type PatchOperationDef = z.infer<typeof OperationDefSchema>;\n\nexport const ResourceDefinitionSchema = z.object({\n findAll: OperationDefSchema.optional(),\n findOne: OperationDefSchema.optional(),\n create: OperationDefSchema.optional(),\n update: OperationDefSchema.optional(),\n patch: OperationDefSchema.optional(),\n delete: OperationDefSchema.optional(),\n});\n\nexport type ResourceDefinition = z.infer<typeof ResourceDefinitionSchema>;\n\nconst DefinitionCallbackSchema = z.function({\n input: [],\n output: ResourceDefinitionSchema,\n});\n\nexport type DefinitionCallback = () => ResourceDefinition;\n\nexport const DefinitionSchema = z.union([\n ResourceDefinitionSchema,\n DefinitionCallbackSchema,\n]);\n","import { ZodObject, type ZodRawShape, z } from 'zod';\n\nexport const JsonSchemaInputSchema = z.object({\n type: z.literal('object'),\n properties: z.record(z.string(), z.unknown()),\n required: z.array(z.string()).optional(),\n additionalProperties: z.boolean().optional(),\n});\n\nexport type JsonSchemaInput = z.infer<typeof JsonSchemaInputSchema>;\n\nexport const SchemaInputSchema = z.union([\n z.custom<ZodObject<ZodRawShape>>((val) => val instanceof ZodObject),\n JsonSchemaInputSchema,\n]);\n\nexport type SchemaInput = z.infer<typeof SchemaInputSchema>;\n","import { z } from 'zod';\n\nexport const LookupSchema = z.object({\n key: z.string(),\n label: z.string().optional(),\n});\n\nexport type LookupConfig = z.infer<typeof LookupSchema>;\n","import { ZodObject, type ZodRawShape, toJSONSchema } from 'zod';\n\nimport type { JsonSchemaInput, SchemaInput } from './schema-input';\nimport { isNullableProperty } from '../schema.utils';\nimport { jsonSchemaOpts } from '../view/json-schema.opts';\n\n\nexport const isZodSchema = (\n schema: SchemaInput,\n): schema is ZodObject<ZodRawShape> => schema instanceof ZodObject;\n\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\nexport const toJsonSchema = (schema: SchemaInput): JsonSchemaInput => {\n if (isZodSchema(schema)) {\n let jsonSchema: Record<string, any>;\n try {\n jsonSchema = toJSONSchema(schema, {\n target: 'openApi3',\n ...jsonSchemaOpts,\n }) as Record<string, any>;\n } catch {\n return { type: 'object' } as JsonSchemaInput;\n }\n dropNullableFromRequired(jsonSchema);\n return jsonSchema as JsonSchemaInput;\n }\n return schema;\n};\n","import { z } from 'zod';\n\nimport { JsonOperationsSchema } from '../data-source/Operations.schema';\nimport { SidebarGroupSchema } from '../resource';\n\nexport const RulesetSchema = z.object({\n hideIdInTable: z.boolean().default(true),\n hideIdInForm: z.boolean().default(true),\n hideIdInView: z.boolean().default(true),\n hideTimestamps: z.boolean().default(true),\n hideForeignKeys: z.boolean().default(true),\n includeRelations: z.boolean().default(true),\n hideRelationsInTable: z.boolean().default(true),\n showRelationsInForm: z.boolean().default(true),\n enumValueLabel: z.boolean().default(true),\n sharedEnums: z.boolean().default(true),\n defaultOperations: JsonOperationsSchema.default(\n JsonOperationsSchema.parse({}),\n ),\n});\n\nexport type Ruleset = z.infer<typeof RulesetSchema>;\n\nexport const I18nConfigSchema = z.object({\n /** Default / fallback language. */\n defaultLanguage: z.string().default('en'),\n /** All supported language codes. */\n languages: z.array(z.string()).min(1),\n /** Directory containing `<lang>.json` bundles, relative to project root. */\n translationsDir: z.string().default('translations'),\n});\n\nexport type I18nConfig = z.infer<typeof I18nConfigSchema>;\n\nexport const CroutonConfigSchema = z.object({\n /**\n * Application title served to the frontend via `GET /_app/layout`.\n * Displayed in the admin sidebar header.\n */\n title: z.string(),\n /** Where resource directories live, relative to the project root. */\n resourcesDir: z.string(),\n /** Where datasource folders live (each with a `data-source.json`). */\n dataSourcesDir: z.string(),\n /**\n * Template for a model's Zod export name. `{Model}` → Prisma model name.\n * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema\n * emitted by zod-prisma-types when `createRelationValuesTypes` is on).\n */\n schemaExportName: z.string().default('{Model}WithRelationsSchema'),\n /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */\n enumsFile: z.string().default('crouton.enums.json'),\n /** Optional overrides of the default visibility ruleset. */\n rules: RulesetSchema.default(RulesetSchema.parse({})),\n /**\n * Sidebar group definitions, keyed by group slug (e.g. `\"metadata\"`).\n * Resources reference a group via `sidebar.group` in their `resource.json`.\n */\n sidebarGroups: z.record(z.string(), SidebarGroupSchema).default({}),\n /**\n * Whether form fields are saved automatically as the user edits them.\n * @default true\n */\n autoSave: z.boolean().default(true),\n /** Optional i18n / translation configuration. */\n i18n: I18nConfigSchema.optional(),\n});\n\nexport type CroutonConfig = z.infer<typeof CroutonConfigSchema>;\n","export const CONFIG_FILES = ['crouton.json', 'crouton.mjs', 'crouton.js'];\n","import { z } from 'zod';\n\nconst NestedStringRecord: z.ZodType<Record<string, unknown>> = z.lazy(() =>\n z.record(z.string(), z.union([z.string(), NestedStringRecord])),\n);\n\nexport const TranslationBundleSchema = z\n .object({\n app: z\n .object({\n title: z.string().optional(),\n })\n .optional(),\n sidebarGroups: z.record(z.string(), z.string()).optional(),\n resources: z\n .record(\n z.string(),\n z\n .object({\n title: z.string().optional(),\n sidebar: z.string().optional(),\n columns: z.record(z.string(), z.string()).optional(),\n actions: z.record(z.string(), z.string()).optional(),\n subResources: z\n .record(\n z.string(),\n z\n .object({\n title: z.string().optional(),\n columns: z.record(z.string(), z.string()).optional(),\n })\n .optional(),\n )\n .optional(),\n })\n .optional(),\n )\n .optional(),\n enums: z.record(z.string(), z.record(z.string(), z.string())).optional(),\n ui: NestedStringRecord.optional(),\n validation: z.record(z.string(), z.string()).optional(),\n })\n .passthrough();\n\nexport type TranslationBundle = z.infer<typeof TranslationBundleSchema>;\n","export const resourceTitleKey = (resource: string): string =>\n `resources.${resource}.title`;\n\nexport const resourceSidebarKey = (resource: string): string =>\n `resources.${resource}.sidebar`;\n\nexport const columnKey = (resource: string, column: string): string =>\n `resources.${resource}.columns.${column}`;\n\nexport const actionKey = (resource: string, action: string): string =>\n `resources.${resource}.actions.${action}`;\n\nexport const subResourceTitleKey = (\n resource: string,\n sub: string,\n): string => `resources.${resource}.subResources.${sub}.title`;\n\nexport const subResourceColumnKey = (\n resource: string,\n sub: string,\n column: string,\n): string => `resources.${resource}.subResources.${sub}.columns.${column}`;\n\nexport const enumKey = (enumName: string, value: string): string =>\n `enums.${enumName}.${value}`;\n\nexport const sidebarGroupKey = (group: string): string =>\n `sidebarGroups.${group}`;\n\nexport const uiKey = (path: string): string => `ui.${path}`;\n\nexport const validationKey = (code: string): string =>\n `validation.${code}`;\n","import type { TranslationBundle } from './Translations.schema';\n\nexport type Translator = (path: string, fallback?: string) => string;\n\nconst getNestedValue = (\n obj: Record<string, unknown>,\n path: string,\n): string | undefined => {\n const keys = path.split('.');\n let current: unknown = obj;\n for (const key of keys) {\n if (current == null || typeof current !== 'object') return undefined;\n current = (current as Record<string, unknown>)[key];\n }\n if (typeof current === 'string' && current !== '') return current;\n return undefined;\n};\n\nexport const createTranslator = (\n bundles: Record<string, TranslationBundle>,\n language: string,\n defaultLanguage = 'en',\n): Translator => {\n const langBundle = bundles[language];\n const defaultBundle =\n language !== defaultLanguage ? bundles[defaultLanguage] : undefined;\n\n return (path: string, fallback?: string): string => {\n if (langBundle) {\n const value = getNestedValue(\n langBundle as unknown as Record<string, unknown>,\n path,\n );\n if (value !== undefined) return value;\n }\n\n if (defaultBundle) {\n const value = getNestedValue(\n defaultBundle as unknown as Record<string, unknown>,\n path,\n );\n if (value !== undefined) return value;\n }\n\n return fallback ?? path;\n };\n};\n","type LanguageEntry = { tag: string; q: number };\n\nconst parseAcceptLanguage = (header: string): LanguageEntry[] => {\n const entries: LanguageEntry[] = [];\n\n for (const part of header.split(',')) {\n const trimmed = part.trim();\n if (!trimmed) continue;\n\n const [tag, ...params] = trimmed.split(';');\n let q = 1;\n for (const param of params) {\n const match = param.trim().match(/^q\\s*=\\s*([0-9.]+)$/);\n if (match) {\n q = parseFloat(match[1]);\n if (isNaN(q)) q = 0;\n }\n }\n entries.push({ tag: tag.trim().toLowerCase(), q });\n }\n\n return entries.sort((a, b) => b.q - a.q);\n};\n\nexport const resolveLanguage = (\n acceptLanguage: string | undefined | null,\n supported: readonly string[],\n defaultLanguage: string,\n): string => {\n if (!acceptLanguage) return defaultLanguage;\n\n const supportedLower = supported.map((s) => s.toLowerCase());\n const entries = parseAcceptLanguage(acceptLanguage);\n\n for (const { tag, q } of entries) {\n if (q <= 0) continue;\n\n if (tag === '*') return defaultLanguage;\n\n // exact match\n const exactIdx = supportedLower.indexOf(tag);\n if (exactIdx !== -1) return supported[exactIdx];\n\n // base tag match: \"nl-BE\" → \"nl\"\n const base = tag.split('-')[0];\n const baseIdx = supportedLower.indexOf(base);\n if (baseIdx !== -1) return supported[baseIdx];\n }\n\n return defaultLanguage;\n};\n","import { type DynamicModule, Module } from '@nestjs/common';\nimport { APP_FILTER, APP_INTERCEPTOR } from '@nestjs/core';\n\nimport { registerResourceExtensions } from '@ghentcdh/crouton-core';\n\nimport type { CroutonAppConfig } from './crud/app-config';\nimport { createAppLayoutController } from './crud/app-layout';\nimport { type LoadedConfig, loadConfig } from './crud/config/read';\nimport { CroutonValidationExceptionFilter } from './crud/crouton-validation.filter';\nimport { createCrudController } from './crud/crud-controller.factory';\nimport { validateCustomRepository } from './crud/custom-repository';\nimport type { DataSourceAdapter, DataSourceEntry } from './crud/data-source';\nimport { DataSourceRegistry, loadDataSourcesFromDir } from './crud/data-source';\nimport { IS_DEV } from './crud/dev-mode';\nimport { DevResourcesController } from './crud/dev-tools/dev-resources.controller';\nimport { loadEnumRegistry } from './crud/enum-registry';\nimport { NoCacheInterceptor } from './crud/interceptors/no-cache.interceptor';\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 { type Resource } from './crud/resource/ResourceConfig.schema';\nimport { resourceLoadErrorsRegistry } from './crud/resource/resource-load-errors.registry';\nimport { ResourceConfigRegistry } from './crud/resource-config.registry';\nimport { CroutonSecurityGuard, SecurityGuardRegistry } from './crud/security';\nimport { createStatusController } from './crud/status';\nimport { LanguageInterceptor, TranslationRegistry } from './crud/translation';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\n@Module({\n controllers: [],\n providers: [],\n exports: [],\n})\nexport class CroutonApiModule {\n async onModuleInit() {\n // BigInt has no toJSON — JSON.stringify throws \"Do not know how to serialize a BigInt\".\n // Patch once so every response containing BigInt fields (e.g. Prisma Int8 / BigInt columns) works.\n if (!(BigInt.prototype as any).toJSON) {\n (BigInt.prototype as any).toJSON = function () {\n return Number(this);\n };\n }\n // Decimal: Prisma.Decimal.prototype.toJSON returns a string by default (\"80\" instead of 80).\n // Patch to emit numbers — consistent with BigInt fix and jsonSchemaOpts (Decimal → type:\"number\").\n // Import from runtime/client (stable, no generated client needed) with a fallback for older Prisma.\n try {\n const { Decimal } = await import('@prisma/client/runtime/client');\n (Decimal.prototype as any).toJSON = function () {\n return parseFloat(this.toString());\n };\n } catch {\n // @prisma/client runtime not reachable — Decimal fields will serialize as strings\n }\n }\n\n private static forResources(\n configs: Resource[],\n dataSources: DataSourceEntry[],\n loader: ResourceConfigLoader,\n appConfig: CroutonAppConfig,\n config: LoadedConfig,\n ): DynamicModule {\n const { baseUrl, prefix, security } = appConfig;\n const dataSourceRegistry = new DataSourceRegistry(dataSources);\n\n // Security guard registry: maps guard names to their NestJS guard classes.\n const guardRegistry = new SecurityGuardRegistry(security?.guards ?? {});\n const moduleDefaultSecurity = security?.default;\n\n // Load enum registry\n const startDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);\n\n // Validate that each resource can actually serve what it advertises:\n // a prisma resource needs its model on the client, a custom resource needs\n // a repository.ts implementing every enabled operation. Failures are\n // skipped and recorded so they appear on the status page instead of\n // crashing the server.\n const validConfigs: Resource[] = [];\n for (const c of configs) {\n // Resolve the datasource adapter to determine data-access strategy.\n // Dispatch branches on the adapter kind, not on config.kind.\n // config.kind controls schema source only (prisma = schema.ts, custom = columns).\n let adapter: DataSourceAdapter | undefined;\n if (c.database || dataSourceRegistry.entries().length > 0) {\n try {\n adapter = dataSourceRegistry.resolveAdapter(c.database);\n } catch (e: any) {\n // A named datasource that doesn't exist is always an error.\n // No datasource at all is ok for kind=custom or custom-adapter resources.\n if (c.database) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: e.message ?? String(e),\n });\n continue;\n }\n }\n }\n\n const adapterIsCustom = adapter ? adapter.kind !== 'prisma' : false;\n const hasRepository = !!c.repository;\n // Adapter exposes the CRUD surface → factory routes through it; no repository.ts needed.\n const adapterHasCrud = !!(adapter?.findAll && adapter.count);\n\n if (adapterHasCrud && !hasRepository) {\n // Adapter guarantees CRUD; skip validateCustomRepository.\n validConfigs.push(c);\n continue;\n }\n\n // A per-resource repository.ts or a custom-adapter datasource without CRUD surface →\n // validate that the enabled operations can be served.\n if (hasRepository || adapterIsCustom || c.kind === 'custom') {\n let adapterClient: unknown = adapter?.client;\n // kind=custom on a prisma adapter: the adapter client is a PrismaClient, not\n // a repository — don't pass it as a fallback repository to the validator.\n if (!adapterIsCustom && !hasRepository) {\n adapterClient = undefined;\n }\n const problem = validateCustomRepository(\n c,\n c.repository,\n adapterClient,\n );\n if (problem) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: problem,\n });\n continue;\n }\n validConfigs.push(c);\n continue;\n }\n\n // Prisma adapter, no per-resource repository.ts: validate model.\n if (!c.model) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error:\n `\"model\" is required for resource \"${c.name}\" on a Prisma datasource. ` +\n 'Set \"model\" to the Prisma model name, or set adapter: \"custom\" on the datasource.',\n });\n continue;\n }\n if (adapter && adapter.supports && !adapter.supports(c.model)) {\n resourceLoadErrorsRegistry.record({\n name: c.name,\n path: c.route,\n error: `Model \"${c.model}\" not found on the provided PrismaClient. Check the resource config for \"${c.name}\".`,\n });\n continue;\n }\n validConfigs.push(c);\n }\n\n const configRegistry = new ResourceConfigRegistry(loader, validConfigs);\n\n // Translation registry: wire up when i18n is configured.\n let translationRegistry: TranslationRegistry | undefined;\n if (config.i18n) {\n const translationsDir = join(\n config.configDir,\n config.i18n.translationsDir,\n );\n translationRegistry = new TranslationRegistry(\n translationsDir,\n config.i18n,\n );\n configRegistry.setTranslationRegistry(translationRegistry);\n }\n\n const controllers = [\n ...validConfigs.map((c) =>\n createCrudController(\n c,\n baseUrl,\n moduleDefaultSecurity,\n !!security,\n prefix,\n appConfig.schemaEnricher,\n ),\n ),\n createAppLayoutController(\n configs,\n config.sidebarGroups,\n config.title,\n config.autoSave ?? true,\n translationRegistry,\n config.i18n,\n prefix,\n ),\n // Only registered (and thus only visible in Swagger/routing) when the\n // visual resource builder is enabled — see dev-resources.controller.ts.\n ...(IS_DEV ? [DevResourcesController] : []),\n createStatusController(enumRegistry, translationRegistry, prefix),\n ];\n\n return {\n module: CroutonApiModule,\n controllers,\n exports: [ResourceConfigRegistry],\n providers: [\n { provide: APP_INTERCEPTOR, useClass: NoCacheInterceptor },\n { provide: APP_FILTER, useClass: CroutonValidationExceptionFilter },\n { provide: DataSourceRegistry, useValue: dataSourceRegistry },\n { provide: ResourceConfigRegistry, useValue: configRegistry },\n // Security providers only registered when security is configured;\n // without guards the dispatching guard is never applied (see factory).\n ...(security\n ? [\n { provide: SecurityGuardRegistry, useValue: guardRegistry },\n CroutonSecurityGuard,\n ...guardRegistry.classes(),\n ]\n : []),\n ...(translationRegistry\n ? [\n {\n provide: TranslationRegistry,\n useValue: translationRegistry,\n },\n {\n provide: APP_INTERCEPTOR,\n useFactory: () => new LanguageInterceptor(translationRegistry!),\n },\n ]\n : []),\n ],\n };\n }\n\n static async forResourceDir(\n dirPath: string,\n dataSourcesPath: string,\n appConfig: CroutonAppConfig,\n ): Promise<DynamicModule> {\n // Register extensions before parsing resource.json files — ordering contract.\n if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);\n const config = await loadConfig();\n const loader = new FileSystemResourceConfigLoader(\n dirPath,\n appConfig.baseUrl,\n config.enumsFile,\n );\n const configs = await loadResourceConfigsFromDir(\n dirPath,\n appConfig.baseUrl,\n config.enumsFile,\n );\n const dataSources = await loadDataSourcesFromDir(dataSourcesPath);\n\n return CroutonApiModule.forResources(\n configs,\n dataSources,\n loader,\n appConfig,\n config,\n );\n }\n\n static async forLoader(\n loader: ResourceConfigLoader,\n configs: Resource[],\n dataSources: DataSourceEntry[],\n appConfig: CroutonAppConfig,\n ): Promise<DynamicModule> {\n const config = await loadConfig();\n return CroutonApiModule.forResources(\n configs,\n dataSources,\n loader,\n appConfig,\n config,\n );\n }\n}\n","import { z } from 'zod';\n\n// ─── Sidebar node types ───────────────────────────────────────────────────────\n\nexport const SidebarLeafSchema = z.object({\n kind: z.literal('item').default('item'),\n id: z.string(),\n label: z.string(),\n position: z.number().optional(),\n});\n\nexport type SidebarLeaf = z.infer<typeof SidebarLeafSchema>;\n\nexport const SidebarGroupSchema = z.object({\n kind: z.literal('group').default('group'),\n id: z.string(),\n label: z.string(),\n position: z.number().optional(),\n children: z.array(SidebarLeafSchema).default([]),\n});\n\nexport type SidebarGroup = z.infer<typeof SidebarGroupSchema>;\n\nexport const SidebarNodeSchema = z.discriminatedUnion('kind', [\n SidebarLeafSchema,\n SidebarGroupSchema,\n]);\n\nexport type SidebarNode = z.infer<typeof SidebarNodeSchema>;\n","import { type SidebarGroupConfig, labelFromId } from '@ghentcdh/crouton-core';\n\nimport {\n type SidebarGroup,\n type SidebarLeaf,\n SidebarLeafSchema,\n type SidebarNode,\n} from './app-layout.types';\nimport { type Resource } from '../resource/ResourceConfig.schema'; // ─── Sort helper ─────────────────────────────────────────────────────────────\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\nexport const buildLayoutPayload = (\n configs: Resource[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n isDev = false,\n) => {\n const visible = configs.filter(\n (c) =>\n c.sidebar?.hide !== true &&\n c.views?.['table'] &&\n // A resource nested under a parent has no standalone route, so a sidebar\n // entry for it would resolve to `<name>/schemas` and 404. It is reached\n // from its parent's detail view instead.\n !c.parent,\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 = SidebarLeafSchema.parse({\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, isDev };\n};\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport {\n type I18nConfig,\n type SidebarGroupConfig,\n sidebarGroupKey,\n} from '@ghentcdh/crouton-core';\n\nimport { IS_DEV } from '../dev-mode';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport { ResourceConfigRegistry } from '../resource-config.registry';\nimport { buildLayoutPayload } from './app-layout.builder';\nimport { getRequestLanguage } from '../translation/language.context';\nimport { type TranslationRegistry } from '../translation/translation.registry';\n\nexport const createAppLayoutController = (\n configs: Resource[],\n sidebarGroups: Record<string, SidebarGroupConfig> = {},\n title?: string,\n autoSave = true,\n translationRegistry?: TranslationRegistry,\n i18nConfig?: I18nConfig,\n prefix?: string,\n) => {\n const layoutPayload = buildLayoutPayload(\n configs,\n sidebarGroups,\n title,\n autoSave,\n IS_DEV,\n );\n\n @Controller(prefix ? `${prefix}/_app` : '_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 const language = getRequestLanguage();\n\n let payload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getAll(language);\n payload = buildLayoutPayload(\n fresh,\n language\n ? translateSidebarGroups(sidebarGroups, language, translationRegistry)\n : sidebarGroups,\n language ? translateTitle(title, language, translationRegistry) : title,\n autoSave,\n IS_DEV,\n );\n } else {\n payload = layoutPayload;\n }\n\n // Append i18n metadata + ui dictionary when translations are active\n if (translationRegistry?.active && i18nConfig) {\n const lang = language ?? i18nConfig.defaultLanguage;\n const bundle = translationRegistry.bundleFor(lang);\n return {\n ...payload,\n i18n: {\n languages: i18nConfig.languages,\n defaultLanguage: i18nConfig.defaultLanguage,\n current: lang,\n },\n ...(bundle.ui && { ui: bundle.ui }),\n };\n }\n\n return payload;\n }\n\n @Get('translations')\n @ApiOperation({\n summary: 'Get ui + validation translation dictionaries',\n })\n @ApiResponse({\n status: 200,\n description: 'Translation dictionaries for the current language',\n })\n getTranslations() {\n if (!translationRegistry?.active || !i18nConfig) {\n return { ui: {}, validation: {} };\n }\n const language = getRequestLanguage() ?? i18nConfig.defaultLanguage;\n const bundle = translationRegistry.bundleFor(language);\n return {\n ui: bundle.ui ?? {},\n validation: bundle.validation ?? {},\n };\n }\n }\n\n Reflect.defineMetadata(\n 'design:paramtypes',\n [ResourceConfigRegistry],\n AppLayoutController,\n );\n\n return AppLayoutController;\n};\n\n/** Translate sidebar group labels using the translator. */\nconst translateSidebarGroups = (\n groups: Record<string, SidebarGroupConfig>,\n language: string,\n registry?: TranslationRegistry,\n): Record<string, SidebarGroupConfig> => {\n if (!registry?.active) return groups;\n const t = registry.translatorFor(language);\n const translated: Record<string, SidebarGroupConfig> = {};\n for (const [slug, cfg] of Object.entries(groups)) {\n const label = t(sidebarGroupKey(slug), cfg.label);\n translated[slug] = label !== cfg.label ? { ...cfg, label } : cfg;\n }\n return translated;\n};\n\n/** Translate app title using app.title key. */\nconst translateTitle = (\n title: string | undefined,\n language: string,\n registry?: TranslationRegistry,\n): string | undefined => {\n if (!title || !registry?.active) return title;\n const t = registry.translatorFor(language);\n return t('app.title', title);\n};","/**\n * Parses a boolean-ish env var value. Accepts \"true\"/\"1\"/\"yes\" (case-insensitive)\n * as truthy; everything else — including `undefined` (unset) — is falsy.\n */\nconst parseBooleanEnv = (value: string | undefined): boolean =>\n !!value && ['true', '1', 'yes'].includes(value.trim().toLowerCase());\n\n/**\n * `true` when the visual resource builder (and its dev-only hot-reload\n * behavior for schemas/layout/resource.json) should be enabled.\n *\n * Read from the `CROUTON_SCHEMA_EDITOR` env var — set it in the consuming\n * app's `.env` file (loaded via `dotenv/config` in `main.ts`, as the\n * generated app templates already do). Defaults to `false` when unset, so\n * production deployments never expose these endpoints unless explicitly\n * opted in.\n */\nexport const IS_DEV = parseBooleanEnv(process.env['CROUTON_SCHEMA_EDITOR']);\n","import { Injectable } from '@nestjs/common';\n\nimport { IS_DEV } from './dev-mode';\nimport type { ResourceConfigLoader } from './loader/resource-config.loader';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { localizeResource } from './translation/localize-resource';\nimport type { TranslationRegistry } from './translation/translation.registry';\n\n@Injectable()\nexport class ResourceConfigRegistry<R extends Resource = Resource> {\n private configs: R[];\n private translationRegistry?: TranslationRegistry;\n\n /**\n * Per-language memo: `Map<language, Map<route, R>>`.\n * Cleared whenever the underlying configs reload (dev mode).\n */\n private localizedCache = new Map<string, Map<string, R>>();\n\n constructor(\n private readonly loader: ResourceConfigLoader,\n initialConfigs: R[],\n ) {\n this.configs = initialConfigs;\n }\n\n setTranslationRegistry(registry: TranslationRegistry): void {\n this.translationRegistry = registry;\n }\n\n async getAll(language?: string): Promise<R[]> {\n if (IS_DEV) {\n this.configs = (await this.loader.loadAll()) as R[];\n this.localizedCache.clear();\n }\n if (!language || !this.translationRegistry?.active) {\n return this.configs;\n }\n return this.configs.map((c) => this.getLocalized(c, language));\n }\n\n async getByRoute(route: string, language?: string): Promise<R | undefined> {\n if (IS_DEV) {\n const fresh = await this.loader.loadByRoute(route);\n this.localizedCache.clear();\n if (!fresh) return undefined;\n if (language && this.translationRegistry?.active) {\n return this.localize(fresh as R, language);\n }\n return fresh as R;\n }\n const config = this.configs.find((c) => c.route === route);\n if (!config) return undefined;\n if (language && this.translationRegistry?.active) {\n return this.getLocalized(config, language);\n }\n return config;\n }\n\n async findById(id: string, language?: string): Promise<R | undefined> {\n const all = await this.getAll(language);\n return all.find((c) => c.id === id);\n }\n\n /**\n * On-disk directory containing `route`'s `resource.json`, if known.\n * Only meaningful after a load has populated the loader's internal map —\n * callers in dev mode should call `getByRoute`/`getAll` first in the same\n * request to guarantee freshness.\n */\n getResourceDir(route: string): string | undefined {\n return this.loader.getResourceDir(route);\n }\n\n private getLocalized(config: R, language: string): R {\n let langMap = this.localizedCache.get(language);\n if (!langMap) {\n langMap = new Map();\n this.localizedCache.set(language, langMap);\n }\n let localized = langMap.get(config.route);\n if (!localized) {\n localized = this.localize(config, language);\n langMap.set(config.route, localized);\n }\n return localized;\n }\n\n private localize(config: R, language: string): R {\n if (!this.translationRegistry) return config;\n const t = this.translationRegistry.translatorFor(language);\n return localizeResource(config, t) as R;\n }\n}\n","import {\n type ResourceJson,\n buildResourceJsonSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\nexport type ResolveResource = { json: ResourceJson; dir: string };\n\nexport type ReadResourceJsonResult =\n | { success: true; data: ResolveResource }\n | { success: false; error: string };\n\nexport const readResourceJson = (jsonPath: string): ReadResourceJsonResult | undefined => {\n if (!existsSync(jsonPath)) return undefined;\n\n let fileContent: unknown;\n try {\n fileContent = JSON.parse(readFileSync(jsonPath, 'utf-8'));\n } catch (err) {\n return {\n success: false,\n error: `Invalid JSON in ${jsonPath}: ${(err as Error).message}`,\n };\n }\n\n const resource = buildResourceJsonSchema().safeParse(fileContent);\n if (resource.error) {\n return {\n success: false,\n error: `Resource cannot be parsed ${jsonPath}: ${resource.error.message}`,\n };\n }\n\n return {\n success: true,\n data: {\n json: resource.data,\n dir: dirname(jsonPath),\n },\n };\n};\n\nexport const readResourceJsonFromPath = (resourcePath: string) => {\n if (resourcePath.endsWith('.json')) {\n return readResourceJson(resourcePath);\n }\n\n const jsonPath = resolve(dirname(resourcePath), 'resource.json');\n\n return readResourceJson(jsonPath);\n};","import { type ResolveResource, readResourceJson } from '../resource/ReadResourceJson';\nimport { existsSync } from 'node:fs';\nimport { dirname, resolve } from 'node:path';\n\n/**\n * Outcome of resolving a relation column's `resource` path.\n *\n * The two failure modes are worth distinguishing: a path that points at nothing\n * is a typo or a moved directory, while a file that exists but does not parse is\n * a broken child config. Collapsing both into `undefined` — which is what\n * `resolveChildResource` does — leaves the caller unable to say which, and the\n * sub-resource builder then silently invents a Prisma-backed child. See\n * `buildSubResources`.\n */\nexport type ChildResourceResolution =\n | { ok: true; value: ResolveResource }\n | { ok: false; reason: 'missing'; attempted: string[] }\n | { ok: false; reason: 'invalid'; error: string };\n\n/**\n * Resolve `fieldInput.resource` (e.g. `\"./author.resource\"`) relative to the\n * parent resource's directory, reporting *why* it failed.\n *\n * Convention: `\"./author.resource\"` → sibling directory `author/resource.json`.\n * A path ending in `.json` is resolved against the parent directory directly.\n */\nexport const resolveChildResourceDetailed = (\n resourcePath: string,\n parentDir: string,\n): ChildResourceResolution => {\n const attempted: string[] = [];\n try {\n // Direct .json file reference (e.g. \"./content/resource.json\") — resolved\n // relative to parentDir itself.\n if (resourcePath.endsWith('.json')) {\n const directPath = resolve(parentDir, resourcePath);\n attempted.push(directPath);\n if (existsSync(directPath)) {\n const result = readResourceJson(directPath);\n if (result?.success) return { ok: true, value: result.data };\n return {\n ok: false,\n reason: 'invalid',\n error: result?.error ?? `Could not read ${directPath}`,\n };\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(\n dirname(parentDir),\n childName,\n 'resource.json',\n );\n attempted.push(childJsonPath);\n\n const result = readResourceJson(childJsonPath);\n if (result?.success) return { ok: true, value: result.data };\n if (result) return { ok: false, reason: 'invalid', error: result.error };\n\n return { ok: false, reason: 'missing', attempted };\n } catch (err) {\n return { ok: false, reason: 'invalid', error: (err as Error).message };\n }\n};\n\n/**\n * Resolve `fieldInput.resource` and return the child `resource.json` contents\n * AND the child's directory (needed so the child can resolve its own `extend`\n * paths), or `undefined` if it could not be resolved.\n *\n * Prefer {@link resolveChildResourceDetailed} where the failure reason matters.\n */\nexport const resolveChildResource = (\n resourcePath: string,\n parentDir: string,\n): ResolveResource | undefined => {\n const resolution = resolveChildResourceDetailed(resourcePath, parentDir);\n return resolution.ok ? resolution.value : undefined;\n};\n","import {\n type JsonColumn,\n resolveTableField,\n resolveViewField,\n} from '@ghentcdh/crouton-core';\n\nimport { resolveChildResource } from './resource-resolver';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\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 */\nexport const 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 = resolved.json.columns; // 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 */\nexport const 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 [\n {\n field: c.column ?? c.id,\n values: opts.values,\n ...(c.enum && { enumName: c.enum }),\n },\n ];\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 */\nexport const 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 * Prefill each column's `fieldView`/`fieldTable` with the fully-resolved variant\n * (the `fieldInput → fieldView → fieldTable` cascade). After this runs, every\n * consumer sees resolved variants without re-implementing the fallback.\n *\n * MUST run AFTER URI/relation enrichment (the last column transform in\n * `fromJson`), so the resolved view/table variants inherit the injected\n * `uri`/`resourceUri`/`resource`/`schemasUri` options and derived `relationType`\n * that enrichment only lands on `fieldInput`. Do not move it earlier.\n */\nexport const resolveColumnFieldVariants = (\n cols: JsonColumn[] | undefined,\n): JsonColumn[] | undefined =>\n cols?.map((col) => {\n const fieldView = resolveViewField(col);\n const fieldTable = resolveTableField(col);\n return {\n ...col,\n ...(fieldView && { fieldView }),\n ...(fieldTable && { fieldTable }),\n };\n });","/**\n * Apply translations to a Resource config.\n *\n * Patches column labels, resource title, sidebar label, action labels,\n * and the corresponding JSON Schema `title` properties in views —\n * without rebuilding views from scratch (no Zod schema needed).\n */\n\nimport type { JsonColumn, Translator, ViewConfig } from '@ghentcdh/crouton-core';\nimport {\n actionKey,\n columnKey,\n enumKey,\n resourceSidebarKey,\n resourceTitleKey,\n subResourceColumnKey,\n subResourceTitleKey,\n} from '@ghentcdh/crouton-core';\n\nimport { buildValueLabelColumns } from '../adapter/column-transforms';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\n\n/** Deep-clone a plain object (JSON-safe). */\nconst clone = <T>(obj: T): T => JSON.parse(JSON.stringify(obj));\n\n/**\n * Shallow-clone a Resource, deep-cloning only the JSON-safe parts that\n * will be mutated during translation. Fields like `definition` (Zod schema)\n * may contain circular references and are never translated, so they are\n * copied by reference.\n */\nconst cloneResource = (config: Resource): Resource => {\n const { definition, ...rest } = config as Record<string, unknown>;\n const localized = clone(rest) as Resource;\n if (definition) (localized as Record<string, unknown>).definition = definition;\n return localized;\n};\n\n/**\n * Translate enum option labels for columns that reference a shared enum.\n * Mutates the cloned column's `fieldInput.options.values[].label` in place.\n */\nconst translateEnumOptions = (\n columns: JsonColumn[] | undefined,\n t: Translator,\n): void => {\n if (!columns) return;\n for (const col of columns) {\n if (!col.enum) continue;\n const opts = col.fieldInput?.options as\n | { values?: { value: unknown; label: string }[] }\n | undefined;\n if (!Array.isArray(opts?.values)) continue;\n for (const entry of opts!.values!) {\n entry.label = t(\n enumKey(col.enum!, String(entry.value)),\n entry.label,\n );\n }\n }\n};\n\n/**\n * Translate labels in pre-built `valueLabelColumns` entries that carry an\n * `enumName`. Used for sub-resources where the original `JsonColumn` (with\n * its `col.enum` property) is no longer available.\n */\nconst translateValueLabelEntries = (\n vlCols: ValueLabelColumn[] | undefined,\n t: Translator,\n): void => {\n if (!vlCols) return;\n for (const vlc of vlCols) {\n if (!vlc.enumName) continue;\n for (const entry of vlc.values) {\n entry.label = t(\n enumKey(vlc.enumName, String(entry.value)),\n entry.label,\n );\n }\n }\n};\n\n/**\n * Patch `json_schema.properties[key].title` for each column whose label\n * was translated. This keeps the JSON Schema titles in sync with the\n * translated column labels without rebuilding views.\n */\nconst patchViewTitles = (\n views: Record<string, ViewConfig> | undefined,\n columnLabels: Map<string, string>,\n): Record<string, ViewConfig> | undefined => {\n if (!views) return views;\n\n const patched: Record<string, ViewConfig> = {};\n for (const [viewName, view] of Object.entries(views)) {\n const patchedView = clone(view);\n\n // Patch json_schema.properties[col].title\n const props = (patchedView.json_schema as Record<string, unknown>)?.properties;\n if (props && typeof props === 'object') {\n for (const [key, prop] of Object.entries(\n props as Record<string, Record<string, unknown>>,\n )) {\n const translated = columnLabels.get(key);\n if (translated && prop && typeof prop === 'object') {\n prop.title = translated;\n }\n }\n }\n\n // Patch view.columns[].label\n if (patchedView.columns) {\n patchedView.columns = patchedView.columns.map((vc) => {\n const translated = columnLabels.get(vc.id);\n return translated ? { ...vc, label: translated } : vc;\n });\n }\n\n // Patch ui_schema elements' options.label\n const patchUiElements = (elements: unknown[]): void => {\n for (const el of elements) {\n if (!el || typeof el !== 'object') continue;\n const element = el as Record<string, unknown>;\n const scope = element.scope as string | undefined;\n if (scope) {\n const match = /^#\\/properties\\/([^/]+)/.exec(scope);\n if (match) {\n const translated = columnLabels.get(match[1]);\n if (translated) {\n const opts = element.options as Record<string, unknown> | undefined;\n if (opts && typeof opts === 'object') opts.label = translated;\n }\n }\n }\n const nested = element.elements as unknown[] | undefined;\n if (Array.isArray(nested)) patchUiElements(nested);\n }\n };\n const uiSchema = patchedView.ui_schema as Record<string, unknown> | undefined;\n const uiElements = uiSchema?.elements as unknown[] | undefined;\n if (Array.isArray(uiElements)) patchUiElements(uiElements);\n\n patched[viewName] = patchedView;\n }\n return patched;\n};\n\n/**\n * Produce a localized clone of a Resource. The original is never mutated.\n *\n * What is translated:\n * - `title`, `sidebar.label`\n * - `columns[].label`\n * - `views` JSON Schema `title` properties + `columns[].label`\n * - `actions[].label`, `tableActions[].label`\n * - `subResources[].title`, `subResources[].columns.label`, `subResources[].views`\n *\n * What is NOT translated (identity):\n * - `definition`, `hooks`, `repository`, `include`, `lookup`, URIs\n */\nexport const localizeResource = (\n config: Resource,\n t: Translator,\n): Resource => {\n const name = config.name;\n const localized = cloneResource(config);\n\n // Title\n localized.title = t(\n resourceTitleKey(name),\n config.title ?? config.tag,\n );\n\n // Sidebar label\n if (localized.sidebar) {\n const sidebarTranslation = t(\n resourceSidebarKey(name),\n config.sidebar?.label,\n );\n // Only set if we got a real translation (not the path back)\n if (sidebarTranslation !== resourceSidebarKey(name)) {\n localized.sidebar = { ...localized.sidebar, label: sidebarTranslation };\n }\n }\n\n // Columns\n const columnLabels = new Map<string, string>();\n const columns = localized.columns as unknown as JsonColumn[] | undefined;\n if (columns) {\n for (const col of columns) {\n const translated = t(\n columnKey(name, col.id),\n col.label ?? col.id,\n );\n col.label = translated;\n columnLabels.set(col.id, translated);\n }\n\n // Translate enum option labels and rebuild valueLabelColumns\n translateEnumOptions(columns, t);\n localized.valueLabelColumns = buildValueLabelColumns(columns);\n }\n\n // Views — patch JSON Schema titles + view column labels\n if (localized.views) {\n localized.views = patchViewTitles(localized.views, columnLabels) as Resource['views'];\n }\n\n // Actions\n if (localized.actions) {\n for (const a of localized.actions) {\n a.label = t(actionKey(name, a.id), a.label);\n }\n }\n if (localized.tableActions) {\n for (const a of localized.tableActions) {\n a.label = t(actionKey(name, a.id), a.label);\n }\n }\n\n // Sub-resources\n if (localized.subResources) {\n for (const sub of localized.subResources as SubResourceConfig[]) {\n const subName = sub.name ?? sub.childRoute;\n sub.title = t(\n subResourceTitleKey(name, subName),\n sub.title ?? subName,\n );\n\n // Sub-resource view columns\n const subColumnLabels = new Map<string, string>();\n if (sub.views) {\n for (const view of Object.values(sub.views)) {\n if (view.columns) {\n for (const vc of view.columns) {\n const translated = t(\n subResourceColumnKey(name, subName, vc.id),\n vc.label ?? vc.id,\n );\n vc.label = translated;\n subColumnLabels.set(vc.id, translated);\n }\n }\n }\n sub.views = patchViewTitles(\n sub.views as Record<string, ViewConfig>,\n subColumnLabels,\n ) as typeof sub.views;\n }\n\n // Translate enum option labels in sub-resource valueLabelColumns\n translateValueLabelEntries(sub.valueLabelColumns, t);\n }\n }\n\n return localized;\n};\n","/**\n * Per-request language context using AsyncLocalStorage.\n *\n * The LanguageInterceptor stores the resolved language; downstream code\n * reads it via `getRequestLanguage()` without threading a parameter\n * through every function signature.\n *\n * Outside a request scope (tests, CLI), returns the default language.\n */\n\nimport { AsyncLocalStorage } from 'node:async_hooks';\n\nconst languageStore = new AsyncLocalStorage<string>();\n\n/** Run a callback within a language context. */\nexport const runWithLanguage = <T>(language: string, fn: () => T): T =>\n languageStore.run(language, fn);\n\n/** Get the current request's resolved language, or `defaultLanguage` if none. */\nexport const getRequestLanguage = (defaultLanguage = 'en'): string =>\n languageStore.getStore() ?? defaultLanguage;\n","import {\n CONFIG_FILES,\n type CroutonConfig,\n CroutonConfigSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { access, readFile } from 'node:fs/promises';\nimport { dirname, join, resolve, resolve as pathResolve } from 'node:path';\n\nconst fileExists = async (p: string): Promise<boolean> => {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Walk up from `cwd` to find `crouton.json`. */\nexport const findConfigPath = async (\n cwd: string,\n): Promise<string | undefined> => {\n let dir = resolve(cwd);\n\n while (true) {\n for (const name of CONFIG_FILES) {\n const candidate = join(dir, name);\n if (await fileExists(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n};\n\nexport type LoadedConfig = CroutonConfig & {\n /** Absolute directory containing the resolved crouton config file. */\n configDir: string;\n};\n\n/** Load + validate `crouton.json`. Throws if none is found. */\nexport const loadConfig = async (): Promise<LoadedConfig> => {\n const cwd = pathResolve(process.cwd());\n const path = await findConfigPath(cwd);\n if (!path) {\n throw new Error(\n `No crouton config found (looked for ${CONFIG_FILES.join(', ')} up from ${cwd}).`,\n );\n }\n let config: CroutonConfig;\n if (path.endsWith('.json')) {\n config = JSON.parse(await readFile(path, 'utf-8')) as CroutonConfig;\n } else {\n const mod = (await import(path)) as {\n default?: CroutonConfig;\n } & CroutonConfig;\n config = mod.default ?? mod;\n }\n\n const parsed = CroutonConfigSchema.parse(config);\n return { ...parsed, configDir: dirname(path) };\n};\n","import {\n type ArgumentsHost,\n Catch,\n type ExceptionFilter,\n Inject,\n Optional,\n} from '@nestjs/common';\n\nimport { validationKey } from '@ghentcdh/crouton-core';\n\nimport { CroutonValidationError } from './crouton-validation.error';\nimport { getRequestLanguage } from './translation/language.context';\nimport { TranslationRegistry } from './translation/translation.registry';\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 * When a `TranslationRegistry` is available, error messages are translated\n * using `validation.<code>` keys with `{field}` interpolation.\n */\n@Catch(CroutonValidationError)\nexport class CroutonValidationExceptionFilter implements ExceptionFilter {\n constructor(\n @Optional()\n @Inject(TranslationRegistry)\n private readonly translationRegistry?: TranslationRegistry,\n ) {}\n\n catch(exception: CroutonValidationError, host: ArgumentsHost): void {\n const res = host.switchToHttp().getResponse<{\n status: (code: number) => { json: (body: unknown) => void };\n }>();\n\n const errors = this.translateErrors(exception.errors);\n\n res.status(400).json({\n statusCode: 400,\n message: errors,\n error: 'Bad Request',\n });\n }\n\n private translateErrors(\n errors: CroutonValidationError['errors'],\n ): Array<{ field: string; message: string }> {\n if (!this.translationRegistry) return errors;\n const language = getRequestLanguage();\n if (!language) return errors;\n\n const t = this.translationRegistry.translatorFor(language);\n\n return errors.map(({ field, message, code }) => {\n if (!code) return { field, message };\n const key = validationKey(code);\n const translated = t(key, '');\n if (!translated) return { field, message };\n // Interpolate {field} placeholder\n return {\n field,\n message: translated.replace(/\\{field\\}/g, field),\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<{\n field: string;\n message: string;\n /** Zod issue code (e.g. `invalid_type`, `too_small`). */\n code?: string;\n }>,\n ) {\n super('Validation failed');\n this.name = 'CroutonValidationError';\n }\n}\n","/**\n * Read per-language translation bundles from disk.\n * Mirrors `enum-registry.loader.ts`.\n */\n\nimport type { TranslationBundle } from '@ghentcdh/crouton-core';\n\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport const loadTranslationBundles = (\n translationsDir: string,\n): Record<string, TranslationBundle> => {\n if (!existsSync(translationsDir)) return {};\n\n const bundles: Record<string, TranslationBundle> = {};\n const entries = readdirSync(translationsDir, { withFileTypes: true });\n\n for (const entry of entries) {\n if (!entry.isFile() || !entry.name.endsWith('.json')) continue;\n const lang = entry.name.replace(/\\.json$/, '');\n try {\n bundles[lang] = JSON.parse(\n readFileSync(join(translationsDir, entry.name), 'utf-8'),\n ) as TranslationBundle;\n } catch {\n /* skip malformed files */\n }\n }\n\n return bundles;\n};\n","/**\n * Translation registry: holds per-language bundles and provides a\n * `translatorFor(language)` factory. Loaded once at boot; dev mode\n * reloads from disk on each request.\n */\n\nimport {\n type I18nConfig,\n type TranslationBundle,\n type Translator,\n createTranslator,\n} from '@ghentcdh/crouton-core';\n\nimport { IS_DEV } from '../dev-mode';\nimport { loadTranslationBundles } from './translation.loader';\n\nexport class TranslationRegistry {\n private bundles: Record<string, TranslationBundle>;\n\n constructor(\n private readonly translationsDir: string,\n private readonly i18nConfig: I18nConfig,\n ) {\n this.bundles = loadTranslationBundles(translationsDir);\n }\n\n get languages(): readonly string[] {\n return this.i18nConfig.languages;\n }\n\n get defaultLanguage(): string {\n return this.i18nConfig.defaultLanguage;\n }\n\n /** Whether i18n is active (at least one bundle loaded). */\n get active(): boolean {\n return Object.keys(this.bundles).length > 0;\n }\n\n translatorFor(language: string): Translator {\n if (IS_DEV) {\n this.bundles = loadTranslationBundles(this.translationsDir);\n }\n return createTranslator(\n this.bundles,\n language,\n this.i18nConfig.defaultLanguage,\n );\n }\n\n /** Raw bundle for a language (falls back to default). */\n bundleFor(language: string): TranslationBundle {\n if (IS_DEV) {\n this.bundles = loadTranslationBundles(this.translationsDir);\n }\n return (\n this.bundles[language] ??\n this.bundles[this.i18nConfig.defaultLanguage] ??\n {}\n );\n }\n}\n","import { Body, Controller, SetMetadata, type Type, UseGuards } from '@nestjs/common';\nimport { ApiTags } from '@nestjs/swagger';\n\nimport { type SecurityConfig, resourceControllerPath } from '@ghentcdh/crouton-core';\n\nimport { type CrudRepository, createCrudRepository } from './crud-repository.factory';\nimport { type CrudOperation, isOperationEnabled, resolveDefinition, schemaFor, securityFor, securityForSub } from './crud.config';\nimport { DataSourceRegistry } from './data-source';\nimport type { OperationContext } from './operations/operation-context';\nimport { registerEndpoints } from './operations/register-endpoints';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { ResourceConfigRegistry } from './resource-config.registry';\nimport { isZodSchema } from './schema.utils';\nimport { CROUTON_SECURITY, CroutonSecurityGuard } from './security';\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 */\nexport function createCrudController(\n config: Resource,\n baseUrl?: string,\n moduleDefaultSecurity?: SecurityConfig,\n securityEnabled = false,\n prefix?: string,\n schemaEnricher?: <T extends Record<string, unknown>>(schema: T) => Record<string, unknown>,\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 explicitPatchSchema = schemaFor(definition, 'patch');\n const patchSchema =\n explicitPatchSchema ??\n (updateSchema && isZodSchema(updateSchema)\n ? (updateSchema as any).partial()\n : undefined) ??\n updateSchema;\n const bodyDecorator = (\n schema?: ReturnType<typeof schemaFor>,\n options?: ZodValidationPipeOptions,\n ): ParameterDecorator => {\n if (!schema) return Body();\n if (isZodSchema(schema))\n return Body(new ZodValidationPipe(schema, options));\n return Body();\n };\n\n const resolveClient = (\n registry: DataSourceRegistry,\n resource: Resource,\n ): any => {\n try {\n return registry.resolve(resource.database);\n } catch (e) {\n // A resource with no datasource at all (kind=custom or custom adapter) is valid —\n // the repository receives undefined as its client.\n if (resource.kind === 'custom') return undefined;\n try {\n const adapter = registry.resolveAdapter(resource.database);\n if (adapter.kind !== 'prisma') return adapter.client;\n } catch {\n // fall through to re-throw original\n }\n throw e;\n }\n };\n\n class CrudControllerBase {\n protected readonly repo: CrudRepository;\n protected readonly configRegistry: ResourceConfigRegistry;\n constructor(\n registry: DataSourceRegistry,\n configRegistry: ResourceConfigRegistry,\n ) {\n // A custom resource may legitimately run in a project with no\n // datasources at all, so a resolve failure is not fatal for it — the\n // repository simply receives `ctx.prisma === undefined`.\n const prisma = resolveClient(registry, config);\n this.repo = createCrudRepository(prisma, config, registry, configRegistry);\n this.configRegistry = configRegistry;\n }\n }\n\n const secure = (methodName: string, op: CrudOperation, sub?: SubResourceConfig): void => {\n const sec = sub\n ? securityForSub(config, sub, op, moduleDefaultSecurity)\n : securityFor(config, definition, op, moduleDefaultSecurity);\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(\n CrudControllerBase.prototype,\n methodName,\n Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName)!,\n );\n }\n };\n\n const ctx: OperationContext = {\n cls: CrudControllerBase,\n config,\n definition,\n listSchema,\n oneSchema,\n createSchema,\n updateSchema,\n patchSchema,\n idParamMeta: {\n name: 'id',\n type: idType === 'number' ? 'number' : 'string',\n },\n bodyDecorator,\n baseUrl,\n moduleDefaultSecurity,\n secure,\n schemaEnricher,\n };\n\n registerEndpoints(ctx);\n\n // ── Class-level decorators ─────────────────────────────────────────────\n // A resource that declares a `parent` is reachable ONLY underneath it, so the\n // whole controller moves to `<parent.route>/:<param>/<route>`; every operation\n // route (``, `:id`, `schemas`, …) inherits the prefix, and the parent id is\n // available to handlers through the request they already receive.\n const controllerPath = resourceControllerPath(route, config.parent);\n Controller(prefix ? `${prefix}/${controllerPath}` : controllerPath)(CrudControllerBase);\n // Only apply the dispatching guard when the module has security configured.\n // Without this, the guard's DI dependencies would fail to resolve in\n // projects that do not configure security at all.\n if (securityEnabled) {\n UseGuards(CroutonSecurityGuard)(CrudControllerBase);\n }\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 { NotFoundException } from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport { resolveDefinition, schemaFor } from './crud.config';\nimport {\n type DataSourceResolver,\n createCustomRepository,\n} from './custom-repository';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { PrismaDataSourceAdapter } from './data-source/prisma.adapter';\nimport { applyAfterFindAll, applyBeforeFindAll, decorateRow, decorateRows, postWrite, prepareWrite } from './hooks';\nimport { ReadRepository } from './read.repository';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { type SubResourceConfig } from './resource/SubResource.schema';\nimport type { ResourceConfigRegistry } from './resource-config.registry';\nimport { toSelectFields } from './schema.utils';\nimport { resolveValueLabelColumns } from './translation';\nimport { WriteRepository, stripSubResourceKeys } 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: ListRequest, request?: any): Promise<T[]>;\n count(filter: string[], q?: string): Promise<number>;\n /**\n * Fetch rows *and* their total count in a single call.\n *\n * Optional: the Prisma-backed repository leaves it undefined and callers fall\n * back to `findAll` + `count`. Repositories whose backend cannot count\n * separately (e.g. a remote HTTP API returning `{items, total}`) implement\n * this instead.\n */\n findAllWithCount?(\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }>;\n findOne(id: number | string, request?: any): Promise<T>;\n findAllByParent(\n parentId: string | number,\n childRoute: string,\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }>;\n findOneChild(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T>;\n createChild(\n parentId: string | number,\n sub: SubResourceConfig,\n data: unknown,\n request?: any,\n ): Promise<T>;\n updateChild(\n sub: SubResourceConfig,\n childId: string | number,\n data: unknown,\n request?: any,\n ): Promise<T>;\n deleteChild(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T>;\n create(data: unknown, request?: any): Promise<T>;\n update(id: number | string, data: unknown, request?: any): Promise<T>;\n patch(id: number | string, data: unknown, request?: any): Promise<T>;\n delete(id: number | string, request?: any): 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 * A `kind: \"custom\"` resource short-circuits to `createCustomRepository`, which\n * delegates to the user's `repository.ts`.\n *\n * Resource-level hooks (`beforeWrite`/`afterWrite`/`afterRead`) and valueLabel\n * decoration are applied here in the factory wrapper — the repositories perform\n * pure data access so both Prisma and custom adapters share the same hook path.\n *\n * @param prisma - Full PrismaClient instance (may be `undefined` for a custom\n * resource in a project with no datasources).\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: Resource,\n dataSources?: DataSourceResolver,\n configRegistry?: ResourceConfigRegistry,\n): CrudRepository<T> {\n const fallbackDataSources: DataSourceResolver = dataSources ?? {\n resolve: () => prisma,\n entries: () => [],\n };\n\n // A per-resource repository.ts always takes precedence over the datasource adapter.\n if (config.repository) {\n return createCustomRepository<T>(\n prisma,\n config,\n fallbackDataSources,\n config.repository,\n configRegistry,\n );\n }\n\n const resolvedAdapter = dataSources?.resolveAdapter?.(config.database);\n\n // For kind:custom resources there is no Prisma model; use the resource name as the\n // model key passed to adapter methods so they can route to the right collection.\n const adapterModelKey = config.model ?? config.name;\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 // If the adapter exposes the CRUD surface, route through it regardless of adapter\n // kind or resource kind. Covers:\n // - kind:prisma + adapter:prisma (PrismaDataSourceAdapter or subclass override)\n // - kind:custom + adapter:custom (no repository.ts needed)\n // - kind:prisma + adapter:custom (custom backend with generated schema)\n if (resolvedAdapter?.findAll && resolvedAdapter.count) {\n const baseCtx = { config, op: 'n/a', offset: 0, listSelect, oneSelect, configRegistry };\n const ctx = (request?: any, op = 'findAll', id?: string | number) => ({\n ...baseCtx, op, request, ...(id !== undefined && { id }),\n });\n\n const mkDecorateFindAll = (adapter: DataSourceAdapter) =>\n async (rows: any[], request?: any): Promise<any[]> => {\n const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);\n const target = vlCols === config.valueLabelColumns ? config : { hooks: config.hooks, valueLabelColumns: vlCols };\n const decorated = await decorateRows(rows, 'findAll', target, adapter, request);\n return applyAfterFindAll(decorated, config, adapter, request);\n };\n const decorateFindAll = mkDecorateFindAll(resolvedAdapter);\n const applyBefore = (params: ListRequest, request?: any) =>\n applyBeforeFindAll(params, config, resolvedAdapter, request);\n const decorateFindOne = (row: any, request?: any) => decorateRow(row, 'findOne', config, resolvedAdapter, request);\n const prepareData = (data: unknown, op: 'create'|'update'|'patch', id?: string|number, request?: any) =>\n prepareWrite(data, op, config, resolvedAdapter, id, request);\n const postData = (result: any, op: 'create'|'update'|'patch'|'delete', id?: string|number, request?: any) =>\n postWrite(result, op, config, resolvedAdapter, id, request);\n const toId = (id: string | number): string | number =>\n (config.idType ?? 'string') === 'number' ? +id : String(id);\n\n const adapterFindAllByParent = async (\n parentId: string | number,\n childRoute: string,\n params: ListRequest,\n request?: any,\n ): Promise<{ data: T[]; count: number }> => {\n if (resolvedAdapter.findAllByParent) {\n const sub = config.subResources?.find((s) => s.childRoute === childRoute);\n if (!sub) throw new Error(`No sub-resource \"${childRoute}\" on \"${config.name}\"`);\n return resolvedAdapter.findAllByParent(adapterModelKey, parentId, sub, params, ctx(request, 'findAll'));\n }\n // Fallback: only available when prisma model exists (Prisma adapter).\n if (!config.model) throw new Error(`Adapter for \"${config.name}\" does not implement findAllByParent`);\n const prismaModel = prisma[config.model];\n const reader = new ReadRepository<T>(prismaModel, resolvedAdapter, config, listSelect, oneSelect, configRegistry);\n return reader.findAllByParent(parentId, childRoute, params, request);\n };\n\n const adapterFindOneChild = async (\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<T> => {\n if (resolvedAdapter.findOneChild) {\n const row = await resolvedAdapter.findOneChild(adapterModelKey, sub, childId, parentId, ctx(request, 'findOne', childId));\n if (row === null || row === undefined) throw new NotFoundException(`${sub.childRoute} with id ${childId} not found`);\n return row;\n }\n if (!config.model) throw new Error(`Adapter for \"${config.name}\" does not implement findOneChild`);\n const prismaModel = prisma[config.model];\n const reader = new ReadRepository<T>(prismaModel, resolvedAdapter, config, listSelect, oneSelect, configRegistry);\n return reader.findOneChild(sub, childId, parentId, request);\n };\n\n const prismaModel = config.model ? prisma?.[config.model] : undefined;\n const writer = prismaModel ? new WriteRepository<T>(prismaModel, resolvedAdapter, config) : undefined;\n\n return {\n prisma,\n findAllWithCount: async (params, request) => {\n const effectiveParams = await applyBefore(params, request);\n const { data, count } = await resolvedAdapter.findAll!(adapterModelKey, effectiveParams, { ...ctx(request, 'findAll'), offset: offsetOf(effectiveParams) });\n return { data: await decorateFindAll(data, request), count };\n },\n findAll: async (params, request) => {\n const effectiveParams = await applyBefore(params, request);\n const { data } = await resolvedAdapter.findAll!(adapterModelKey, effectiveParams, { ...ctx(request, 'findAll'), offset: offsetOf(effectiveParams) });\n return decorateFindAll(data, request);\n },\n count: (filter, q) => resolvedAdapter.count!(adapterModelKey, filter, { ...baseCtx, q }),\n findOne: async (id, request) => {\n const row = await resolvedAdapter.findOne!(adapterModelKey, id, ctx(request, 'findOne', id));\n if (row === null || row === undefined) throw new NotFoundException(`${config.name} with id ${id} not found`);\n return decorateFindOne(row, request);\n },\n findAllByParent: adapterFindAllByParent,\n findOneChild: adapterFindOneChild,\n create: async (data, request) => {\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'create', undefined, request);\n const result = await resolvedAdapter.create!(adapterModelKey, prepared, ctx(request, 'create'));\n return postData(result, 'create', undefined, request);\n },\n update: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'update', coercedId, request);\n const result = await resolvedAdapter.update!(adapterModelKey, id, prepared, ctx(request, 'update', coercedId));\n return postData(result, 'update', coercedId, request);\n },\n patch: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'patch', coercedId, request);\n const patchOrUpdate = (resolvedAdapter.patch ?? resolvedAdapter.update)!.bind(resolvedAdapter);\n const result = await patchOrUpdate(adapterModelKey, id, prepared, ctx(request, 'patch', coercedId));\n return postData(result, 'patch', coercedId, request);\n },\n delete: async (id, request) => {\n const coercedId = toId(id);\n const result = await resolvedAdapter.delete!(adapterModelKey, id, ctx(request, 'delete', coercedId));\n return postData(result, 'delete', coercedId, request);\n },\n createChild: writer\n ? writer.createChild.bind(writer)\n : () => Promise.reject(new Error(`createChild not supported for \"${config.name}\" (no Prisma model)`)),\n updateChild: writer\n ? writer.updateChild.bind(writer)\n : () => Promise.reject(new Error(`updateChild not supported for \"${config.name}\" (no Prisma model)`)),\n deleteChild: writer\n ? writer.deleteChild.bind(writer)\n : () => Promise.reject(new Error(`deleteChild not supported for \"${config.name}\" (no Prisma model)`)),\n };\n }\n\n // If non-prisma adapter has no CRUD surface, fall back to createCustomRepository\n // (requires adapter.client that implements ops, or a repository.ts was already handled above).\n if (resolvedAdapter && resolvedAdapter.kind !== 'prisma') {\n return createCustomRepository<T>(\n resolvedAdapter.client as any,\n config,\n fallbackDataSources,\n undefined,\n configRegistry,\n );\n }\n\n // ── Legacy Prisma path ────────────────────────────────────────────────────\n // Used when no registry is provided (unit tests, direct factory calls).\n // The resolved adapter path above covers all production scenarios.\n\n if (!config.model) {\n throw new Error(\n `Resource \"${config.name}\" has no \"model\". A prisma-backed resource must ` +\n 'name its Prisma model, or point to a datasource with adapter: \"custom\".',\n );\n }\n const legacyModel = prisma[config.model];\n if (!legacyModel) {\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 // Wrap the raw prisma client in an adapter so hooks receive a `DataSourceAdapter`.\n const adapter: DataSourceAdapter = new PrismaDataSourceAdapter(prisma);\n\n const reader = new ReadRepository<T>(\n legacyModel,\n adapter,\n config,\n listSelect,\n oneSelect,\n configRegistry,\n );\n const writer = new WriteRepository<T>(legacyModel, adapter, config);\n\n // ── Resource-level decoration helpers ────────────────────────────────────\n const decorateFindAll = async (rows: any[], request?: any): Promise<any[]> => {\n const vlCols = await resolveValueLabelColumns(\n config.route,\n config.valueLabelColumns,\n configRegistry,\n );\n const target =\n vlCols === config.valueLabelColumns\n ? config\n : { hooks: config.hooks, valueLabelColumns: vlCols };\n const decorated = await decorateRows(rows, 'findAll', target, adapter, request);\n return applyAfterFindAll(decorated, config, adapter, request);\n };\n\n const decorateFindOne = (row: any, request?: any): Promise<any> =>\n decorateRow(row, 'findOne', config, adapter, request);\n\n const prepareData = (\n data: unknown,\n op: 'create' | 'update' | 'patch',\n id?: string | number,\n request?: any,\n ) => prepareWrite(data, op, config, adapter, id, request);\n\n const postData = (\n result: any,\n op: 'create' | 'update' | 'patch' | 'delete',\n id?: string | number,\n request?: any,\n ) => postWrite(result, op, config, adapter, id, request);\n\n const toId = (id: string | number): string | number =>\n (config.idType ?? 'string') === 'number' ? +id : String(id);\n\n return {\n prisma,\n findAll: async (params, request) => {\n const effectiveParams = await applyBeforeFindAll(params, config, adapter, request);\n return decorateFindAll(await reader.findAll(effectiveParams, request), request);\n },\n count: reader.count.bind(reader),\n findOne: async (id, request) =>\n decorateFindOne(await reader.findOne(id, request), request),\n findAllByParent: reader.findAllByParent.bind(reader),\n findOneChild: reader.findOneChild.bind(reader),\n create: async (data, request) => {\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'create', undefined, request);\n const result = await writer.create(prepared, request);\n return postData(result, 'create', undefined, request);\n },\n update: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'update', coercedId, request);\n const result = await writer.update(id, prepared, request);\n return postData(result, 'update', coercedId, request);\n },\n patch: async (id, data, request) => {\n const coercedId = toId(id);\n const stripped = stripSubResourceKeys(config, data);\n const prepared = await prepareData(stripped, 'patch', coercedId, request);\n const result = await writer.patch(id, prepared, request);\n return postData(result, 'patch', coercedId, request);\n },\n delete: async (id, request) => {\n const coercedId = toId(id);\n const result = await writer.delete(id, request);\n return postData(result, 'delete', coercedId, request);\n },\n createChild: writer.createChild.bind(writer),\n updateChild: writer.updateChild.bind(writer),\n deleteChild: writer.deleteChild.bind(writer),\n };\n}\n","import { z } from 'zod';\n\nimport type { JsonActionCondition } from '@ghentcdh/crouton-core';\n\n// ── Shared metadata ────────────────────────────────────────────────────────\n\nexport const ActionMetadataSchema = z.object({\n /** URL segment used in the endpoint. */\n id: z.string(),\n /** Human-readable label shown as a button. */\n label: z.string().optional(),\n /** MDI icon name, e.g. `\"mdi:open-in-new\"`. */\n icon: z.string().optional(),\n /** Tooltip text. Falls back to `label` when omitted. */\n tooltip: z.string().optional(),\n /** Per-row condition — button is hidden when false. */\n condition: z.custom<JsonActionCondition>().optional(),\n});\n\n// ── Link actions (same for row and table) ──────────────────────────────────\n\nexport const ResourceLinkActionSchema = ActionMetadataSchema.extend({\n type: z.literal('link'),\n /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */\n href: z.string(),\n});\n\n// ── Procedure actions — row-level ──────────────────────────────────────────\n\nexport const ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n /** HTTP method for the endpoint. Defaults to `\"post\"`. */\n method: z.string().optional(),\n /** Static data payload merged into the request body by the frontend. */\n data: z.record(z.string(), z.unknown()).optional(),\n /** Procedure called with `(prisma, recordId)`. */\n procedure: z.custom<(prisma: any, recordId: string | number) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\n// ── Procedure actions — table-level ────────────────────────────────────────\n\nexport const ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({\n type: z.literal('procedure').optional(),\n /** HTTP method for the endpoint. Defaults to `\"post\"`. */\n method: z.string().optional(),\n /** Static data payload merged into the request body by the frontend. */\n data: z.record(z.string(), z.unknown()).optional(),\n /** Procedure called with `(prisma)` — no record id. */\n procedure: z.custom<(prisma: any) => Promise<any>>(\n (v) => typeof v === 'function',\n ),\n});\n\n// ── Union types ────────────────────────────────────────────────────────────\n\nexport type ResourceLinkAction = z.infer<typeof ResourceLinkActionSchema>;\nexport type ResourceRowProcedureAction = z.infer<\n typeof ResourceRowProcedureActionSchema\n>;\nexport type ResourceTableProcedureAction = z.infer<\n typeof ResourceTableProcedureActionSchema\n>;\n\nexport const ResourceRowActionSchema = z.union([\n ResourceRowProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceRowAction = z.infer<typeof ResourceRowActionSchema>;\n\nexport const ResourceTableActionSchema = z.union([\n ResourceTableProcedureActionSchema,\n ResourceLinkActionSchema,\n]);\nexport type ResourceTableAction = z.infer<typeof ResourceTableActionSchema>;\n// ── Type guards ────────────────────────────────────────────────────────────\n\nexport const isRowProcedureAction = (\n action: ResourceRowAction,\n): action is ResourceRowProcedureAction => action.type !== 'link';\n\nexport const isTableProcedureAction = (\n action: ResourceTableAction,\n): action is ResourceTableProcedureAction => action.type !== 'link';\n","import { IS_DEV } from '../dev-mode';\nimport { existsSync } from 'node:fs';\nimport { createRequire } from 'node:module';\nimport { join } from 'node:path';\nimport { pathToFileURL } from 'node:url';\n\n// createRequire works in both CJS and ESM contexts, unlike bare `require`.\n// In CJS contexts (nodemon + @swc-node/register), import.meta.url is undefined,\n// so fall back to __filename which is always available in CJS.\nconst _require = createRequire(import.meta.url ?? __filename);\n\n// True when running under an ESM loader that handles .ts files (e.g. tsx/esm via\n// `node --import tsx/esm`). In this context require() does NOT handle .ts files —\n// only import() does. In a plain CJS context (import.meta.url undefined),\n// require() is patched by @swc-node/register and is the correct choice.\nconst IS_ESM = typeof import.meta !== 'undefined' && typeof import.meta.url === 'string';\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/**\n * Dynamically import a default export, returning `undefined` on failure.\n *\n * Failures are reported through `onError` when supplied, and logged otherwise.\n * Without that, a broken user file (syntax error, bad import) is\n * indistinguishable from a missing one — which made `hooks.ts` fail silently.\n */\nexport const importDefault = async <T>(\n filePath: string,\n onError?: (error: unknown, filePath: string) => void,\n): 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 if (IS_ESM) {\n // ESM mode (node --import tsx/esm): require() does not handle .ts files.\n // Use import() with a file:// URL so the tsx ESM loader intercepts it.\n // nodemon restarts the whole process on file changes, no cache-busting needed.\n const mod = await import(pathToFileURL(filePath).href);\n return (mod.default ?? mod) as T;\n } else {\n // CJS mode (nodemon + @swc-node/register): require() is patched to handle .ts.\n const mod = _require(filePath) as { default?: T };\n return mod.default;\n }\n } catch (error) {\n if (onError) onError(error, filePath);\n else console.error(`[crouton] Failed to import ${filePath}:`, error);\n return undefined;\n }\n};\n","import type { JsonAction } from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from './action.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport { join } from 'node:path';\n\n/**\n * Resolve each declared action into a runtime action object.\n *\n * - `type: \"link\"` actions pass through as-is (no file to load).\n * - Procedure actions import their function from `{basePath}/actions/{procedure}.ts`.\n *\n * The `scope` parameter controls the procedure signature:\n * - `\"row\"` → `(prisma, recordId) => Promise`\n * - `\"table\"` → `(prisma) => Promise`\n *\n * All metadata fields (icon, tooltip, condition) are passed through for both scopes.\n */\nexport const loadActions = async <S extends 'row' | 'table'>(\n jsonActions: JsonAction[],\n basePath: string,\n scope: S,\n): Promise<S extends 'row' ? ResourceRowAction[] : ResourceTableAction[]> => {\n const tag = scope === 'row' ? 'actions' : 'tableActions';\n const results: (ResourceRowAction | ResourceTableAction)[] = [];\n\n for (const action of jsonActions) {\n if (action.type === 'link') {\n results.push(action);\n continue;\n }\n\n const file = findModule(join(basePath, 'actions'), action.procedure);\n if (!file) {\n console.warn(\n `[${tag}] Procedure file not found for \"${action.id}\" in ${basePath}/actions/`,\n );\n continue;\n }\n const mod = await importDefault<(...args: any[]) => Promise<any>>(file);\n if (!mod) {\n console.warn(`[${tag}] No default export in ${file}`);\n continue;\n }\n\n results.push({ ...action, procedure: mod } as\n ResourceRowAction | ResourceTableAction);\n }\n\n return results as any;\n};\n","import { type JsonResourceOperations, type SecurityConfig } from '@ghentcdh/crouton-core';\n\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { type ResourceDefinition } from './resource/defintion.schema';\nimport { type SchemaInput } from './resource/json.schema';\n\nexport { isRowProcedureAction, isTableProcedureAction } from './action';\n\nexport type CrudOperation =\n 'findAll' | 'findOne' | 'create' | 'update' | 'patch' | 'delete';\n\n// ─── helpers ────────────────────────────────────────────────────────────────\n\nexport const resolveDefinition = (config: Resource): ResourceDefinition => {\n const def = config.definition;\n return typeof def === 'function' ? def() : def;\n};\n\nexport const isOperationEnabled = (\n def: ResourceDefinition | JsonResourceOperations,\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 isOperationExternal = (\n def: ResourceDefinition | JsonResourceOperations,\n op: CrudOperation,\n): boolean => {\n const entry = def[op];\n return typeof entry === 'object' && entry !== null && 'uri' in entry;\n};\n\nexport const externalRouteFor = (\n def: ResourceDefinition | JsonResourceOperations,\n op: CrudOperation,\n): string | undefined => {\n const entry = def[op];\n if (typeof entry === 'object' && entry !== null && 'uri' in entry) {\n return (entry as { uri: string }).uri;\n }\n return undefined;\n};\n\n// ─── security ────────────────────────────────────────────────────────────────\n\n/** Extract security from an operation entry (works for both JSON and typed defs). */\nconst opSecurity = (entry: unknown): SecurityConfig | undefined => {\n if (!entry || entry === true) return undefined;\n return (entry as { security?: SecurityConfig }).security;\n};\n\n/** Effective security for one operation: op-level → resource global → module default. */\nexport const securityFor = (\n config: Resource,\n def: ResourceDefinition,\n op: CrudOperation,\n moduleDefault?: SecurityConfig,\n): SecurityConfig | undefined =>\n opSecurity(def[op]) ?? config.security ?? moduleDefault;\n\n/** Same precedence for sub-resources: op-level → parent global → module default. */\nexport const securityForSub = (\n config: Resource,\n sub: SubResourceConfig,\n op: CrudOperation,\n moduleDefault?: SecurityConfig,\n): SecurityConfig | undefined => {\n const entry = sub.operations[op];\n return opSecurity(entry) ?? config.security ?? moduleDefault;\n};\n","import { z } from 'zod';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { Resource } from '../resource/ResourceConfig.schema';\n\n/**\n * Contract for a `kind: \"custom\"` resource's `repository.ts`.\n *\n * The file default-exports an object implementing whichever operations the\n * resource enables. Discovery is by convention, like `hooks.ts` — see\n * `custom-repository.loader`.\n *\n * Hand-written interfaces, deliberately not `z.infer` of a Zod object:\n * `ResourceHooks` takes that shortcut and its `PRISMACLIENT` generic is erased\n * by the inference, so `ctx.prisma` is always `any` in a hook file. Here the\n * generics survive, and `CustomRepository<Row, PrismaClient>` gives a typed\n * `ctx.prisma`.\n */\n\n/** Operations a custom repository can implement. */\nexport type CustomOp =\n | 'findAll'\n | 'findOne'\n | 'create'\n | 'update'\n | 'patch'\n | 'delete';\n\nexport interface CustomRepositoryContext<PRISMA = any> {\n /**\n * Resolved datasource client for this resource — the one named by the\n * resource's `database`, or the project default.\n *\n * `undefined` when the project has no datasources at all, which is a valid\n * setup for a backend whose resources are all custom.\n */\n prisma: PRISMA;\n /** Escape hatch for a resource that reads from more than one database. */\n dataSources: {\n resolve(name?: string): any;\n entries(): { name: string; client: any }[];\n };\n /** The fully resolved resource config, including columns and views. */\n config: Resource;\n /** Which operation is executing. */\n op: CustomOp;\n /**\n * Zero-based row offset derived from `page`/`pageSize`, for backends that\n * paginate by offset rather than page number.\n */\n offset: number;\n /** Record id, on the operations that address one. */\n id?: string | number;\n /**\n * The incoming HTTP request, when the controller layer supplies one.\n * Same value hooks receive as `ctx.request` — use it for auth/tenant context.\n */\n request?: any;\n /**\n * Set when the resource declares a `parent`, i.e. it is mounted at\n * `<route>/:<param>/…`. The id is read from the path on every request, so it\n * is always present for a nested resource.\n *\n * The parent-aware operations receive the same id as their first argument;\n * this is here for the cases where you want it inside a shared helper.\n */\n parent?: { route: string; param: string; id: string | number };\n}\n\n/** Rows plus the total matching count, used to build the list envelope. */\nexport interface CustomListResult<T = any> {\n data: T[];\n count: number;\n}\n\n/**\n * Operations for a resource that declares a `parent`.\n *\n * A nested resource is *only* reachable under its parent, so these replace the\n * unnested operations rather than supplementing them — the parent id is always\n * available, and a query can never accidentally run across every parent.\n */\nexport interface CustomParentRepository<T = any, PRISMA = any> {\n /** List the children of one parent. Returns rows *and* the total count. */\n findAllByParent?(\n parentId: string | number,\n params: ListRequest,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<CustomListResult<T>>;\n /** Fetch one child of one parent. Return `null`/`undefined` for a 404. */\n findOneByParent?(\n parentId: string | number,\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T | null | undefined>;\n createByParent?(\n parentId: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n updateByParent?(\n parentId: string | number,\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n /** Falls back to `updateByParent` when not implemented. */\n patchByParent?(\n parentId: string | number,\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n deleteByParent?(\n parentId: string | number,\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n}\n\nexport interface CustomRepository<T = any, PRISMA = any>\n extends CustomParentRepository<T, PRISMA> {\n /**\n * List rows. Must return the total `count` as well — the framework builds the\n * `{ data, request: { count, totalPages, ... } }` envelope from it.\n *\n * `params.filter` holds raw `field:value:operator` strings; `parseFilterString`\n * is exported from crouton-api if you want to reuse the grammar.\n */\n findAll?(\n params: ListRequest,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<CustomListResult<T>>;\n /** Fetch one row. Return `null`/`undefined` to produce a 404. */\n findOne?(\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T | null | undefined>;\n create?(data: any, ctx: CustomRepositoryContext<PRISMA>): Promise<T>;\n update?(\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n /**\n * Partial update. Falls back to `update` when not implemented, matching the\n * Prisma repository where `patch` is `update` with a partial schema.\n */\n patch?(\n id: string | number,\n data: any,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n delete?(\n id: string | number,\n ctx: CustomRepositoryContext<PRISMA>,\n ): Promise<T>;\n}\n\n/** Every operation a custom repository may implement, in registration order. */\nexport const CUSTOM_OPS: readonly CustomOp[] = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n] as const;\n\n/** Parent-aware method name for an operation, used by a nested resource. */\nexport const PARENT_METHOD: Record<CustomOp, keyof CustomParentRepository> = {\n findAll: 'findAllByParent',\n findOne: 'findOneByParent',\n create: 'createByParent',\n update: 'updateByParent',\n patch: 'patchByParent',\n delete: 'deleteByParent',\n} as const;\n\n/**\n * Loose schema for embedding the loaded repository on `ResourceSchema`.\n *\n * `z.custom` holds the functions without Zod trying to describe them, the same\n * trick `ResourceHooksSchema` uses. The *public* type above is what consumers\n * annotate their file with.\n */\nexport const CustomRepositorySchema = z.custom<CustomRepository>(\n (value) => typeof value === 'object' && value !== null,\n);\n","export interface ResourceLoadError {\n name: string;\n path: string;\n error: string;\n /** Version found on disk (for schema-version / migration failures). */\n version?: number;\n /** Version crouton expected (`CURRENT_RESOURCE_VERSION`). */\n expectedVersion?: number;\n}\n\nclass ResourceLoadErrorsRegistry {\n private errors: ResourceLoadError[] = [];\n\n record(e: ResourceLoadError) {\n this.errors.push(e);\n }\n\n getAll() {\n return [...this.errors];\n }\n\n clear() {\n this.errors = [];\n }\n}\n\nexport const resourceLoadErrorsRegistry = new ResourceLoadErrorsRegistry();","import type { CustomRepository } from './custom-repository.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\n\nexport const REPOSITORY_MODULE = 'repository';\n\n/**\n * Load a custom resource's `repository.ts`.\n *\n * Discovery mirrors `loadResourceHooks`: fixed filename, `.ts` then `.js`, no\n * declaration in resource.json. Unlike the hooks loader this distinguishes\n * \"absent\" from \"broken\" — an import failure is recorded on the load-error\n * registry (and so shown on the status page) rather than silently yielding\n * `undefined`, which would read as a missing file.\n */\nexport const loadCustomRepository = async (\n basePath: string,\n resourceName: string,\n): Promise<CustomRepository | undefined> => {\n const file = findModule(basePath, REPOSITORY_MODULE);\n if (!file) return undefined;\n\n let failure: unknown;\n const repository = await importDefault<CustomRepository>(file, (error) => {\n failure = error;\n });\n\n if (failure !== undefined) {\n resourceLoadErrorsRegistry.record({\n name: resourceName,\n path: file,\n error: `Failed to import ${REPOSITORY_MODULE}: ${\n failure instanceof Error ? failure.message : String(failure)\n }`,\n });\n return undefined;\n }\n\n if (repository && typeof repository !== 'object') {\n resourceLoadErrorsRegistry.record({\n name: resourceName,\n path: file,\n error: `${REPOSITORY_MODULE} must default-export an object of operation functions.`,\n });\n return undefined;\n }\n\n return repository;\n};\n\n/**\n * Attach each custom sub-resource's `repository.ts` to its `SubResourceConfig`.\n *\n * A sub-resource is declared by a relation column on the parent and served by\n * the parent's controller, but a `kind: \"custom\"` child owns its own data\n * access — so the parent's repository delegates to this. Mirrors\n * `loadSubResourceHooks`, which attaches child hooks the same way.\n *\n * Mutates in place, because `buildSubResources` has already produced the\n * configs by the time the loader can resolve the child directories.\n */\nexport const loadSubResourceRepositories = async (\n subResources: { childKind?: string; childDir?: string; childRoute: string; repository?: unknown }[],\n parentName: string,\n): Promise<void> => {\n for (const sub of subResources) {\n if (sub.childKind !== 'custom') continue;\n if (!sub.childDir) {\n resourceLoadErrorsRegistry.record({\n name: parentName,\n path: sub.childRoute,\n error:\n `Sub-resource \"${sub.childRoute}\" is a custom resource but its directory could not be resolved, ` +\n 'so its repository.ts cannot be loaded. Check the relation column\\'s \"resource\" path.',\n });\n continue;\n }\n const repository = await loadCustomRepository(\n sub.childDir,\n `${parentName}.${sub.childRoute}`,\n );\n if (repository) sub.repository = repository;\n }\n};\n","import {\n BadRequestException,\n NotFoundException,\n NotImplementedException,\n} from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport {\n type CustomListResult,\n type CustomOp,\n type CustomRepository,\n type CustomRepositoryContext,\n PARENT_METHOD,\n} from './custom-repository.types';\nimport { DEFAULT_ID_FIELD, DEFAULT_ID_TYPE } from '../constants';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\nimport { PrismaDataSourceAdapter } from '../data-source/prisma.adapter';\nimport { decorateRow, decorateRows, postWrite, prepareWrite } from '../hooks';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { resolveValueLabelColumns } from '../translation';\n\n/** Minimal view of `DataSourceRegistry`, kept structural to avoid a cycle. */\nexport type DataSourceResolver = {\n resolve(name?: string): any;\n entries(): { name: string; client: unknown }[];\n /** Resolve the full adapter for a datasource (optional — not all callers supply it). */\n resolveAdapter?(name?: string): DataSourceAdapter;\n};\n\nconst unsupported = (config: Resource, op: CustomOp): never => {\n const method = config.parent ? PARENT_METHOD[op] : op;\n throw new NotImplementedException(\n `Resource \"${config.name}\" enables \"${op}\" but its repository.ts does not implement \"${method}\".`,\n );\n};\n\n/**\n * Adapt a user-supplied `CustomRepository` to the full `CrudRepository`\n * interface the controllers depend on.\n *\n * Responsibilities that stay with the framework rather than the user:\n * - id coercion per `idType`, so a numeric key arrives as a number;\n * - lifecycle hooks and the `{value,label}` envelope, via the shared helpers —\n * so `hooks.ts` behaves the same on a custom resource;\n * - 404 on a missing row, so the user returns `null` instead of throwing;\n * - `patch` falling back to `update`, matching the Prisma repository.\n *\n * Sub-resource operations are not part of the contract yet: nested child routes\n * are derived from Prisma relations. They throw rather than silently returning\n * nothing.\n */\nexport const createCustomRepository = <T = any>(\n prisma: any,\n config: Resource,\n dataSources: DataSourceResolver,\n repository: CustomRepository<T> | undefined,\n configRegistry?: ResourceConfigRegistry,\n): CrudRepository<T> => {\n // Wrap the raw prisma client in an adapter so hook contexts receive `dataSource`.\n const adapter = new PrismaDataSourceAdapter(prisma);\n\n // Fall back to the adapter client when it implements CustomRepository directly\n // (no repository.ts required).\n const repo = repository ?? (prisma && typeof prisma === 'object' ? (prisma as CustomRepository) : {});\n const idField = config.idField ?? DEFAULT_ID_FIELD;\n\n const toId = (id: string | number): string | number =>\n (config.idType ?? DEFAULT_ID_TYPE) === 'number' ? +id : String(id);\n\n const parentRef = config.parent;\n\n /**\n * Parent id for a nested resource, read from the request path.\n *\n * A nested resource registers no unnested route, so the param is always\n * present in practice. Missing means the repository was called outside the\n * controller — fail loudly rather than silently querying across all parents.\n */\n const parentIdFrom = (request: any): string | number => {\n const raw = request?.params?.[parentRef!.param];\n if (raw === undefined || raw === null || raw === '') {\n throw new BadRequestException(\n `Resource \"${config.name}\" is nested under \"${parentRef!.route}\" but no \"${parentRef!.param}\" was supplied.`,\n );\n }\n return (parentRef!.idType ?? 'string') === 'number' ? +raw : String(raw);\n };\n\n const parentCtx = (\n request: any,\n parentId: string | number,\n ): { parent: NonNullable<CustomRepositoryContext['parent']> } => ({\n parent: { route: parentRef!.route, param: parentRef!.param, id: parentId },\n });\n\n /**\n * The parent for a hook context — same shape hooks get on a sub-resource, so a\n * `hooks.ts` reads `ctx.parent.id` regardless of which way the resource nests.\n * `undefined` when the resource is not nested, or when the request carries no\n * parent id to read (a hook must not be handed a fabricated one).\n */\n const parentHookCtx = (request: any) => {\n if (!parentRef) return undefined;\n const raw = request?.params?.[parentRef.param];\n if (raw === undefined || raw === null || raw === '') return undefined;\n return {\n route: parentRef.route,\n param: parentRef.param,\n id: (parentRef.idType ?? 'string') === 'number' ? +raw : String(raw),\n };\n };\n\n const ctx = (\n op: CustomOp,\n params?: ListRequest,\n id?: string | number,\n request?: any,\n ): CustomRepositoryContext => ({\n prisma,\n dataSources,\n config,\n op,\n offset: params ? offsetOf(params) : 0,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n });\n\n const findAllWithCount = async (\n params: ListRequest,\n request?: any,\n ): Promise<CustomListResult<T>> => {\n let result: CustomListResult<T> | undefined;\n\n if (parentRef) {\n if (!repo.findAllByParent) unsupported(config, 'findAll');\n const parentId = parentIdFrom(request);\n result = await repo.findAllByParent!(parentId, params, {\n ...ctx('findAll', params, undefined, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.findAll) unsupported(config, 'findAll');\n result = await repo.findAll!(\n params,\n ctx('findAll', params, undefined, request),\n );\n }\n\n const vlCols = await resolveValueLabelColumns(\n config.route,\n config.valueLabelColumns,\n configRegistry,\n );\n const target =\n vlCols === config.valueLabelColumns\n ? config\n : { hooks: config.hooks, valueLabelColumns: vlCols };\n const data = await decorateRows(\n result?.data ?? [],\n 'findAll',\n target,\n adapter,\n request,\n parentHookCtx(request),\n );\n return { data, count: result?.count ?? data.length };\n };\n\n const findOne = async (id: string | number, request?: any): Promise<T> => {\n let row: T | null | undefined;\n\n if (parentRef) {\n if (!repo.findOneByParent) unsupported(config, 'findOne');\n const parentId = parentIdFrom(request);\n row = await repo.findOneByParent!(parentId, toId(id), {\n ...ctx('findOne', undefined, id, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.findOne) unsupported(config, 'findOne');\n row = await repo.findOne!(\n toId(id),\n ctx('findOne', undefined, id, request),\n );\n }\n\n if (row === null || row === undefined) {\n throw new NotFoundException(`${config.name} with id ${id} not found`);\n }\n return decorateRow(\n row,\n 'findOne',\n config,\n adapter,\n request,\n parentHookCtx(request),\n );\n };\n\n const write = async (\n op: 'create' | 'update' | 'patch',\n data: unknown,\n id?: string | number,\n request?: any,\n ): Promise<T> => {\n const coercedId = id !== undefined ? toId(id) : undefined;\n\n // `patch` falls back to `update` in both flavours: the Prisma repository\n // treats patch as an update with a partial schema, so a repository that\n // only implements the update variant behaves consistently.\n const prepared = () =>\n prepareWrite(\n data,\n op,\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n\n let result: T;\n\n if (parentRef) {\n const fn =\n op === 'create'\n ? repo.createByParent\n : op === 'update'\n ? repo.updateByParent\n : (repo.patchByParent ?? repo.updateByParent);\n if (!fn) unsupported(config, op);\n\n const parentId = parentIdFrom(request);\n const nestedCtx = {\n ...ctx(op, undefined, coercedId, request),\n ...parentCtx(request, parentId),\n };\n const body = await prepared();\n\n result =\n op === 'create'\n ? await (fn as NonNullable<CustomRepository<T>['createByParent']>)(\n parentId,\n body,\n nestedCtx,\n )\n : await (fn as NonNullable<CustomRepository<T>['updateByParent']>)(\n parentId,\n coercedId!,\n body,\n nestedCtx,\n );\n } else {\n const fn = (\n op === 'create'\n ? repo.create\n : op === 'update'\n ? repo.update\n : (repo.patch ?? repo.update)\n )?.bind(repo);\n if (!fn) unsupported(config, op);\n\n const body = await prepared();\n\n result =\n op === 'create'\n ? await (fn as NonNullable<CustomRepository<T>['create']>)(\n body,\n ctx('create', undefined, undefined, request),\n )\n : await (fn as NonNullable<CustomRepository<T>['update']>)(\n coercedId!,\n body,\n ctx(op, undefined, coercedId, request),\n );\n }\n\n return postWrite(\n result,\n op,\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n };\n\n // Async so callers get a rejected promise rather than a synchronous throw,\n // matching every other method's `Promise<T>` signature.\n const notAChildRepository = async (): Promise<never> => {\n throw new NotImplementedException(\n `Resource \"${config.name}\" is a custom resource; nested sub-resource routes are not supported. ` +\n 'Expose the child collection as its own resource instead.',\n );\n };\n\n return {\n prisma,\n // Preferred by register-findall: one round trip returns rows and count.\n findAllWithCount,\n findAll: async (params, request) =>\n (await findAllWithCount(params, request)).data,\n count: async (filter) =>\n (\n await findAllWithCount({\n page: 1,\n pageSize: 1,\n sort: idField,\n sortDir: 'asc',\n filter: filter ?? [],\n })\n ).count,\n findOne,\n create: (data, request) => write('create', data, undefined, request),\n update: (id, data, request) => write('update', data, id, request),\n patch: (id, data, request) => write('patch', data, id, request),\n delete: async (id, request) => {\n const coercedId = toId(id);\n let result: T;\n\n if (parentRef) {\n if (!repo.deleteByParent) unsupported(config, 'delete');\n const parentId = parentIdFrom(request);\n result = await repo.deleteByParent!(parentId, coercedId, {\n ...ctx('delete', undefined, coercedId, request),\n ...parentCtx(request, parentId),\n });\n } else {\n if (!repo.delete) unsupported(config, 'delete');\n result = await repo.delete!(\n coercedId,\n ctx('delete', undefined, coercedId, request),\n );\n }\n return postWrite(\n result,\n 'delete',\n config,\n adapter,\n coercedId,\n request,\n parentHookCtx(request),\n );\n },\n findAllByParent: notAChildRepository,\n findOneChild: notAChildRepository,\n createChild: notAChildRepository,\n updateChild: notAChildRepository,\n deleteChild: notAChildRepository,\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","import { NotFoundException } from '@nestjs/common';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { AdapterCrudContext, DataSourceAdapter } from './data-source.adapter';\nimport { ReadRepository } from '../read.repository';\nimport { WriteRepository } from '../write.repository';\n\nconst DB_CHECK_TIMEOUT_MS = 3_000;\n\n/**\n * Default adapter: wraps a generated PrismaClient.\n *\n * Phase 1: lifecycle wrapper.\n * Phase 2: full CRUD surface — each method delegates to ReadRepository /\n * WriteRepository so subclasses can override individual operations without\n * re-implementing the rest.\n *\n * Extend this class to build a composable adapter:\n *\n * ```ts\n * export default class AnnotationAdapter extends PrismaDataSourceAdapter {\n * constructor() { super(prisma); }\n *\n * override async findAll(model, params, ctx) {\n * const result = await super.findAll(model, params, ctx);\n * return { ...result, data: decorateWithAnnotations(result.data) };\n * }\n * }\n * ```\n */\nexport class PrismaDataSourceAdapter implements DataSourceAdapter {\n readonly kind = 'prisma' as const;\n readonly client: unknown;\n\n constructor(prismaClient: unknown) {\n this.client = prismaClient;\n }\n\n supports(model: string): boolean {\n return typeof (this.client as any)?.[model] !== 'undefined';\n }\n\n async healthCheck(): Promise<void> {\n const c = this.client as any;\n await Promise.race([\n c.$queryRaw`SELECT 1`,\n new Promise<never>((_, reject) =>\n setTimeout(() => reject(new Error('Database health check timed out')), DB_CHECK_TIMEOUT_MS),\n ),\n ]);\n }\n\n async disconnect(): Promise<void> {\n const c = this.client as any;\n if (typeof c?.$disconnect === 'function') {\n await c.$disconnect();\n }\n }\n\n // ── CRUD surface (Phase 2) ────────────────────────────────────────────────\n // Each method resolves the Prisma delegate, constructs the appropriate\n // repository, and delegates. Subclasses may override any of these.\n\n private prismaModel(model: string): any {\n const delegate = (this.client as any)?.[model];\n if (!delegate)\n throw new Error(`Model \"${model}\" not found on the provided PrismaClient.`);\n return delegate;\n }\n\n async findAll(model: string, params: ListRequest, ctx: AdapterCrudContext): Promise<{ data: any[]; count: number }> {\n const prismaModel = this.prismaModel(model);\n const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n const [data, count] = await Promise.all([\n reader.findAll(params, ctx.request),\n reader.count(params.filter ?? [], (params as any).q),\n ]);\n return { data, count };\n }\n\n async count(model: string, filter: string[], ctx: AdapterCrudContext): Promise<number> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, undefined, undefined, ctx.configRegistry);\n return reader.count(filter, ctx.q);\n }\n\n async findOne(model: string, id: string | number, ctx: AdapterCrudContext): Promise<any | null> {\n const prismaModel = this.prismaModel(model);\n const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n try {\n return await reader.findOne(id, ctx.request);\n } catch (e: any) {\n if (e instanceof NotFoundException) return null;\n throw e;\n }\n }\n\n async create(model: string, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).create(data, ctx.request);\n }\n\n async update(model: string, id: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).update(id, data, ctx.request);\n }\n\n async patch(model: string, id: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).patch(id, data, ctx.request);\n }\n\n async delete(model: string, id: string | number, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).delete(id, ctx.request);\n }\n\n async findAllByParent(model: string, parentId: string | number, sub: any, params: ListRequest, ctx: AdapterCrudContext): Promise<{ data: any[]; count: number }> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n return reader.findAllByParent(parentId, sub.childRoute, params, ctx.request);\n }\n\n async findOneChild(model: string, sub: any, childId: string | number, parentId: string | number | undefined, ctx: AdapterCrudContext): Promise<any | null> {\n const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);\n try {\n return await reader.findOneChild(sub, childId, parentId, ctx.request);\n } catch (e: any) {\n if (e instanceof NotFoundException) return null;\n throw e;\n }\n }\n\n async createChild(model: string, parentId: string | number, sub: any, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).createChild(parentId, sub, data, ctx.request);\n }\n\n async updateChild(model: string, sub: any, childId: string | number, data: unknown, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).updateChild(sub, childId, data, ctx.request);\n }\n\n async deleteChild(model: string, sub: any, childId: string | number, parentId: string | number | undefined, ctx: AdapterCrudContext): Promise<any> {\n return new WriteRepository(this.prismaModel(model), this, ctx.config).deleteChild(sub, childId, parentId, ctx.request);\n }\n}\n","import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport {\n type ListRequest,\n Operator,\n type OperatorType,\n buildSort,\n offsetOf,\n} from '@ghentcdh/crouton-core';\n\nimport {\n childCtx,\n childRepositoryFn,\n} from './custom-repository/child-delegate';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport { type SubResourceConfig } from './resource/SubResource.schema';\nimport type { ValueLabelColumn } from './resource/valueLabel';\nimport { applyValueLabelColumns } from './resource/valueLabel.apply';\nimport type { ResourceConfigRegistry } from './resource-config.registry';\nimport {\n buildChildSortClause,\n buildFindOneIncludes,\n buildIncludeClause,\n mergeCalculatedColumnsForRows,\n} from './sql.helpers';\nimport { resolveValueLabelColumns } from './translation';\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\n ? parts.slice(1, -1).join(':')\n : parts.slice(1).join(':');\n const operator: OperatorType = hasOperator\n ? (lastPart as OperatorType)\n : '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 = (\n path: string[],\n condition: unknown,\n): 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>) => ({\n [column]: { path, ...extra },\n });\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 = (\n value: string,\n operator: OperatorType,\n): 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(\n field.split('.'),\n operatorToCondition(value, operator),\n ),\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// Re-exported for backwards compatibility; the implementation now lives in\n// resource/valueLabel.apply so non-Prisma repositories can share it.\nexport { applyValueLabelColumns };\n\n/**\n * Handles all read operations for a resource — list, count, detail, and sub-resource queries.\n * Pure data access: hooks and valueLabel decoration are applied by the factory wrapper.\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 adapter - The datasource adapter; `adapter.client` is the raw PrismaClient.\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 private get prisma(): any {\n return this.adapter.client;\n }\n\n constructor(\n private readonly prismaModel: any,\n private readonly adapter: DataSourceAdapter,\n private readonly config: Resource,\n private readonly listSelect: Record<string, any> | undefined,\n private readonly oneSelect: Record<string, any> | undefined,\n private readonly configRegistry?: ResourceConfigRegistry,\n ) {}\n\n /**\n * Physical table name for raw SQL (calculated columns).\n *\n * `table` overrides `model` for a `@@map`-ed Prisma model. Empty for a custom\n * resource, which cannot have calculated columns.\n */\n private get tableName(): string {\n return this.config.table ?? this.config.model ?? '';\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 /**\n * The parent a *child* read is scoped to, for the hook context.\n *\n * A sub-resource is served by the parent's controller, so its parent id arrives\n * as the parent's own `:id` — hence `param: 'id'`. `undefined` when no parent id\n * was supplied, so a hook is never handed a fabricated one.\n */\n private parentHookContext(parentId: string | number | undefined) {\n if (parentId === undefined || parentId === null || parentId === '') {\n return undefined;\n }\n return {\n route: this.config.route,\n param: 'id',\n id: this.toId(parentId),\n };\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 * Resource-level `afterRead` and valueLabel decoration are NOT applied here — the\n * factory wrapper handles them so both Prisma and custom adapters use the same path.\n */\n async findAll(params: ListRequest, request?: any): Promise<T[]> {\n const subResources = this.config.subResources ?? [];\n const projection = this.projection('findAll');\n\n const vlCols = await resolveValueLabelColumns(\n this.config.route,\n this.config.valueLabelColumns,\n this.configRegistry,\n );\n const filterWhere = this.buildWhere(params.filter);\n const searchWhere = this.buildSearchOrWhere((params as any).q);\n const where = filterWhere && searchWhere\n ? { AND: [filterWhere, searchWhere] }\n : filterWhere ?? searchWhere;\n const query: Record<string, any> = {\n where,\n take: params.pageSize,\n skip: offsetOf(params),\n orderBy: this.safeSort(\n sanitizeValueLabelSort(params.sort, vlCols),\n params.sortDir,\n ),\n };\n\n // A `kind: \"custom\"` child is served by its own repository.ts and has no\n // Prisma relation of that name, so it must stay out of every Prisma-shaped\n // clause below — `_count`, `include`, and the configInclude filter alike.\n // Asking for a relation the model does not have fails the whole query.\n const prismaSubResources = subResources.filter(\n (s) => s.childKind !== 'custom',\n );\n\n const oneToManySubResources = prismaSubResources.filter(\n (s) => s.relationType !== 'manyToOne',\n );\n\n // The count fills a table cell, so a column the table never renders does not\n // need one. Skipping it keeps `_count` off the query entirely when every\n // relation is hidden.\n const countableSubResources = oneToManySubResources.filter(\n (s) => !s.hiddenInTable,\n );\n\n // Include manyToOne relations (e.g. author) so they appear in list view.\n const manyToOneIncludes = prismaSubResources\n .filter((s) => s.relationType === 'manyToOne')\n .map((s) => s.relation);\n const flatIncludes = manyToOneIncludes.length\n ? Object.fromEntries(manyToOneIncludes.map((r) => [r, true]))\n : undefined;\n const configInclude = buildIncludeClause(this.config.include);\n // Exclude every oneToMany sub-resource from configInclude in findAll: a\n // counted one would have its records overwritten by the count mapping below,\n // and an uncounted one is hidden from the table, so fetching whole child rows\n // per page would be cost for nothing. Deliberately not narrowed to the\n // counted set — that would silently turn a `_count` into a full child fetch\n // the moment a column is hidden.\n // Custom children join this set too: they cannot be Prisma-included at all,\n // so an entry naming one in `config.include` has to be dropped rather than\n // passed through to fail the query.\n const countableRelations = new Set([\n ...oneToManySubResources.map((s) => s.relation),\n ...subResources\n .filter((s) => s.childKind === 'custom')\n .map((s) => s.relation),\n ]);\n const filteredConfigInclude = configInclude\n ? Object.fromEntries(Object.entries(configInclude).filter(([key]) => !countableRelations.has(key)))\n : undefined;\n const safeConfigInclude = filteredConfigInclude && Object.keys(filteredConfigInclude).length ? filteredConfigInclude : undefined;\n const mergedInclude =\n flatIncludes || safeConfigInclude\n ? { ...flatIncludes, ...safeConfigInclude }\n : undefined;\n\n const countClause = countableSubResources.length\n ? { select: Object.fromEntries(countableSubResources.map((s) => [s.relation, true])) }\n : undefined;\n\n if (projection.select) {\n query.select = {\n ...projection.select,\n ...(countClause && { _count: countClause }),\n ...mergedInclude,\n };\n } else {\n if (countClause) query._count = countClause;\n if (mergedInclude) query.include = mergedInclude;\n }\n\n const rows = await this.prismaModel.findMany(query);\n\n const mapped = countableSubResources.length\n ? rows.map((row: any) => {\n const { _count, ...rest } = row;\n if (!_count) return rest;\n const counts = Object.fromEntries(\n countableSubResources.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.tableName,\n this.prisma,\n this.config.idField ?? 'id',\n );\n // Resource-level afterRead + valueLabel decoration is applied by the factory wrapper.\n return withCalc;\n }\n\n private buildSearchOrWhere(q: string | undefined): Record<string, unknown> | undefined {\n const lookup = this.config.lookup;\n const labels = lookup?.labels?.length ? lookup.labels : (lookup?.label ? [lookup.label] : undefined);\n if (!q || !labels?.length) return undefined;\n return {\n OR: labels.map((path) => buildNestedPath(path.split('.'), { contains: q })),\n };\n }\n\n /** Count records matching the given filter strings and optional free-text search. */\n count(filter: string[], q?: string): Promise<number> {\n const filterWhere = this.buildWhere(filter);\n const searchWhere = this.buildSearchOrWhere(q);\n const where = filterWhere && searchWhere\n ? { AND: [filterWhere, searchWhere] }\n : filterWhere ?? searchWhere;\n return this.prismaModel.count({ where });\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 * Resource-level `afterRead` decoration is applied by the factory wrapper.\n * @throws {NotFoundException} When no record exists for the given id.\n */\n async findOne(id: number | string, request?: any): Promise<T> {\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 const mergedInclude = buildFindOneIncludes(\n this.config.subResources ?? [],\n buildIncludeClause(this.config.include),\n );\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.tableName,\n this.prisma,\n this.config.idField ?? 'id',\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 sub.idField ?? 'id',\n );\n enriched = { ...enriched, [sub.relation]: enrichedNested };\n }\n\n // Resource-level afterRead decoration is applied by the factory wrapper.\n return enriched;\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: ListRequest,\n request?: any,\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 if (sub.childKind === 'custom') {\n const findAll = childRepositoryFn(sub, 'findAll', this.config.name);\n const result = await findAll(\n this.toId(parentId),\n params,\n childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op: 'findAll',\n parentId: this.toId(parentId),\n params,\n request,\n }),\n );\n const rows = result?.data ?? [];\n const decorated = sub.hooks?.afterRead\n ? await Promise.all(\n rows.map((row: any) =>\n sub.hooks!.afterRead!(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findAll',\n request,\n parent: this.parentHookContext(parentId),\n }),\n ),\n )\n : rows;\n const subVlCols = await resolveValueLabelColumns(\n this.config.route,\n sub.valueLabelColumns,\n this.configRegistry,\n sub.childRoute,\n );\n const labeled = subVlCols?.length\n ? decorated.map((r: any) =>\n applyValueLabelColumns(r, subVlCols),\n )\n : decorated;\n return { data: labeled, count: result?.count ?? labeled.length };\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 subVlCols = await resolveValueLabelColumns(\n this.config.route,\n sub.valueLabelColumns,\n this.configRegistry,\n sub.childRoute,\n );\n const childSort = orderableChildSort(\n sanitizeValueLabelSort(params.sort, subVlCols),\n childModel,\n sub,\n );\n\n const [data, count] = await Promise.all([\n childModel.findMany({\n where,\n take: params.pageSize,\n skip: offsetOf(params),\n orderBy: childSort\n ? buildChildSortClause(childSort, params.sortDir)\n : 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 sub.idField ?? 'id',\n )\n : data;\n\n const decorated = sub.hooks?.afterRead\n ? await Promise.all(\n withCalc.map((row: any) =>\n sub.hooks!.afterRead!(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findAll',\n request,\n parent: this.parentHookContext(parentId),\n }),\n ),\n )\n : withCalc;\n\n const labeled = subVlCols?.length\n ? decorated.map((r: any) =>\n applyValueLabelColumns(r, subVlCols),\n )\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 request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n if (parentId === undefined) {\n throw new BadRequestException(\n `Sub-resource \"${sub.childRoute}\" of \"${this.config.name}\" requires a parent id.`,\n );\n }\n const findOne = childRepositoryFn(sub, 'findOne', this.config.name);\n const row = await findOne(\n this.toId(parentId),\n (sub.idType ?? 'string') === 'number' ? +childId : String(childId),\n childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op: 'findOne',\n parentId: this.toId(parentId),\n id: childId,\n request,\n }),\n );\n if (row === null || row === undefined) {\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n }\n return sub.hooks?.afterRead\n ? sub.hooks.afterRead(row, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findOne',\n request,\n parent: this.parentHookContext(parentId),\n })\n : row;\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 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 sub.idField ?? 'id',\n )\n : [record];\n\n // findOne (single child) keeps the scalar — see decorateOne.\n if (sub.hooks?.afterRead)\n return sub.hooks.afterRead(withCalc, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'findOne',\n request,\n parent: this.parentHookContext(parentId),\n });\n return withCalc;\n }\n}\n","import { NotImplementedException } from '@nestjs/common';\n\nimport { type ListRequest, offsetOf } from '@ghentcdh/crouton-core';\n\nimport { type CustomOp, PARENT_METHOD } from './custom-repository.types';\nimport type { Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\n/**\n * Delegation to a **custom sub-resource's** own repository.\n *\n * A sub-resource is declared by a relation column on the parent and served\n * through the parent's controller, but a `kind: \"custom\"` child owns its data\n * access and has no Prisma model to query. The parent's repositories therefore\n * call the child's `repository.ts` instead of `prisma[childModel]`.\n *\n * The child implements the same parent-aware operations a top-level nested\n * resource does (`findAllByParent`, `createByParent`, …), so one contract covers\n * both ways of nesting.\n *\n * Shared by ReadRepository and WriteRepository so the two cannot drift.\n */\n\n/** Resolve the child's method for `op`, or throw naming what is missing. */\nexport const childRepositoryFn = (\n sub: SubResourceConfig,\n op: CustomOp,\n parentName: string,\n): ((...args: any[]) => Promise<any>) => {\n const repo = sub.repository as Record<string, any> | undefined;\n const method = PARENT_METHOD[op];\n\n if (!repo) {\n throw new NotImplementedException(\n `Sub-resource \"${sub.childRoute}\" of \"${parentName}\" is a custom resource but no repository.ts was loaded for it.`,\n );\n }\n\n // `patch` falls back to the update variant, matching every other path.\n const fn =\n repo[method] ??\n (op === 'patch' ? repo[PARENT_METHOD.update] : undefined);\n\n if (typeof fn !== 'function') {\n throw new NotImplementedException(\n `Sub-resource \"${sub.childRoute}\" of \"${parentName}\" does not implement \"${method}\" in its repository.ts.`,\n );\n }\n return fn.bind(repo);\n};\n\n/** Context handed to a custom child's repository. */\nexport const childCtx = ({\n parentConfig,\n prisma,\n op,\n parentId,\n params,\n id,\n request,\n}: {\n parentConfig: Resource;\n prisma: any;\n op: CustomOp;\n parentId: string | number;\n params?: ListRequest;\n id?: string | number;\n request?: any;\n}): any => ({\n prisma,\n dataSources: { resolve: () => prisma, entries: () => [] },\n config: parentConfig,\n op,\n offset: params ? offsetOf(params) : 0,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n // Served under the parent's `:id`, so that is the param name here — unlike a\n // top-level nested resource, which names its own param.\n parent: { route: parentConfig.route, param: 'id', id: parentId },\n});\n\n/**\n * Parent id for a child write.\n *\n * `updateChild`/`deleteChild` are called without it — the route binds it as\n * `:id`, so it is read back off the request the handler already receives.\n */\nexport const parentIdFromRequest = (\n request: any,\n fallback?: string | number,\n): string | number | undefined => {\n const raw = request?.params?.id;\n return raw === undefined || raw === null || raw === '' ? fallback : raw;\n};\n","import { fromValueLabel, toValueLabel } from '@ghentcdh/crouton-core';\n\nimport type { ValueLabelColumn } from './valueLabel';\n\n/**\n * Value-label envelope transforms, shared by every repository implementation.\n *\n * Lives here rather than inside `read.repository` / `write.repository` so the\n * custom-repository adapter can apply exactly the same treatment without\n * importing a repository (which would be a cycle).\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/** Unwrap `{ value, label }` fields back to their scalar before persistence. */\nexport const normalizeValueLabels = (\n data: unknown,\n cols: ValueLabelColumn[] | undefined,\n): unknown => {\n if (!data || typeof data !== 'object' || Array.isArray(data) || !cols?.length)\n 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","import { buildSort } from '@ghentcdh/crouton-core';\nimport type { CalculatedColumn, JsonIncludeEntry } from '@ghentcdh/crouton-core';\n\nimport type { SubResourceConfig } from './resource/SubResource.schema';\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 = (\n col: CalculatedColumn,\n tableName: string,\n ids: unknown[],\n idField: string,\n): string => {\n const alias = col.alias ?? col.id;\n const placeholders = ids.map((_, i) => `$${i + 1}`).join(', ');\n // The key column is aliased to `id` so the caller can merge on a stable name\n // regardless of what the resource's primary key is called.\n return `SELECT main.\"${idField}\" AS id, ${castExpression(col)} AS \"${alias}\" FROM \"${tableName}\" main WHERE main.\"${idField}\" 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 *\n * @param idField - Primary key column of `tableName`. Defaults to `'id'`.\n */\nexport const mergeCalculatedColumnsForRows = async (\n rows: any[],\n calcCols: CalculatedColumn[],\n tableName: string,\n prisma: any,\n idField = 'id',\n): Promise<any[]> => {\n if (!calcCols.length || !rows.length) return rows;\n\n const ids = rows.map((r) => r[idField]);\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, idField);\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[idField])] ?? 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\n/**\n * Build the merged Prisma `include` clause for `findOne`.\n *\n * Auto-included sub-resources (`includeInFindOne`) are merged with explicit\n * `configInclude` entries. `configInclude` wins when both specify the same relation.\n *\n * A `kind: \"custom\"` child is skipped: it is reached through its own\n * `repository.ts`, so there is no Prisma relation of that name to include and\n * asking for one fails the entire query.\n */\nexport const buildFindOneIncludes = (\n subResources: SubResourceConfig[],\n configInclude: Record<string, unknown> | undefined,\n): Record<string, unknown> | undefined => {\n const autoSubs = subResources.filter(\n (s) => s.includeInFindOne && s.childKind !== 'custom',\n );\n const flatIncludes = autoSubs.length\n ? Object.fromEntries(\n autoSubs.map((s) =>\n s.findOneOrderBy\n ? [s.relation, { orderBy: s.findOneOrderBy }]\n : [s.relation, true],\n ),\n )\n : undefined;\n\n if (!flatIncludes && !configInclude) return undefined;\n return { ...flatIncludes, ...configInclude };\n};\n","/**\n * NestJS interceptor: parse `Accept-Language`, resolve against supported\n * languages, store in AsyncLocalStorage, set `Vary` and `Content-Language`\n * response headers.\n */\n\nimport {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport type { Observable } from 'rxjs';\n\nimport { resolveLanguage } from '@ghentcdh/crouton-core';\n\nimport { runWithLanguage } from './language.context';\nimport { type TranslationRegistry } from './translation.registry';\n\n@Injectable()\nexport class LanguageInterceptor implements NestInterceptor {\n constructor(private readonly registry: TranslationRegistry) {}\n\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n const http = context.switchToHttp();\n const request = http.getRequest();\n const response = http.getResponse();\n\n const acceptLanguage = request.headers['accept-language'] as\n | string\n | undefined;\n const resolved = resolveLanguage(\n acceptLanguage,\n this.registry.languages,\n this.registry.defaultLanguage,\n );\n\n response.setHeader('Vary', 'Accept-Language');\n response.setHeader('Content-Language', resolved);\n\n return runWithLanguage(resolved, () => next.handle());\n }\n}\n","import type { ValueLabelColumn } from '../resource/valueLabel';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { getRequestLanguage } from './language.context';\n\n/**\n * Resolve value-label columns for the current request language.\n *\n * When a language is active and the config registry holds a localized config,\n * the localized `valueLabelColumns` (with translated enum labels) are returned.\n * Otherwise the boot-time columns are returned unchanged.\n *\n * @param route - Resource route (used to look up the localized config).\n * @param bootTimeCols - The valueLabelColumns from the boot-time config.\n * @param configRegistry - Optional config registry for localized lookup.\n * @param childRoute - When set, resolve the sub-resource's valueLabelColumns instead.\n */\nexport const resolveValueLabelColumns = async (\n route: string,\n bootTimeCols: ValueLabelColumn[] | undefined,\n configRegistry?: ResourceConfigRegistry,\n childRoute?: string,\n): Promise<ValueLabelColumn[] | undefined> => {\n if (!configRegistry) return bootTimeCols;\n const language = getRequestLanguage();\n if (!language) return bootTimeCols;\n const localized = await configRegistry.getByRoute(route, language);\n if (!localized) return bootTimeCols;\n if (!childRoute) return localized.valueLabelColumns ?? bootTimeCols;\n const sub = (localized.subResources ?? []).find(\n (s) => s.childRoute === childRoute,\n );\n return sub?.valueLabelColumns ?? bootTimeCols;\n};\n","import { BadRequestException, NotFoundException } from '@nestjs/common';\n\nimport type { JsonIncludeEntry } from '@ghentcdh/crouton-core';\n\nimport { DEFAULT_ID_FIELD, PRISMA_NOT_FOUND_CODE } from './constants';\nimport {\n childCtx,\n childRepositoryFn,\n parentIdFromRequest,\n} from './custom-repository/child-delegate';\nimport type { DataSourceAdapter } from './data-source/data-source.adapter';\nimport { type Resource } from './resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from './resource/SubResource.schema';\nimport { normalizeValueLabels } from './resource/valueLabel.apply';\n\n/** Extract the top-level relation names from a `JsonIncludeEntry[]` (for payload stripping). */\nconst includeRelationNames = (\n include: JsonIncludeEntry[] | undefined,\n): Set<string> =>\n new Set((include ?? []).map((e) => (typeof e === 'string' ? e : e.relation)));\n\n/** Prisma nested-write keywords that indicate a relation mutation rather than read-only join data. */\nconst PRISMA_RELATION_WRITE_KEYS = new Set([\n 'connect',\n 'connectOrCreate',\n 'create',\n 'createMany',\n 'set',\n 'disconnect',\n 'update',\n 'updateMany',\n 'upsert',\n 'delete',\n 'deleteMany',\n]);\n\n/** Returns `true` when `value` looks like a Prisma relation write (e.g. `{ connect: { id } }`). */\nconst isPrismaRelationWrite = (value: unknown): boolean => {\n if (!value || typeof value !== 'object' || Array.isArray(value)) return false;\n return Object.keys(value).some((k) => PRISMA_RELATION_WRITE_KEYS.has(k));\n};\n\n/** Remove sub-resource count columns from a write payload. Module-level so the factory can use it. */\nexport const stripSubResourceKeys = (config: Resource, data: unknown): unknown => {\n if (!data || typeof data !== 'object' || Array.isArray(data)) return data;\n const subKeys = new Set((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\nconst stripNonCreateableChildFields = (\n sub: SubResourceConfig,\n data: unknown,\n): 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(\n ([k]) => !nonCreateable.has(k),\n ),\n );\n};\n\n/**\n * Handles all write operations for a resource — create, update, patch, delete, and child mutations.\n *\n * Resource-level `beforeWrite`/`afterWrite` hooks are NOT applied here for the core operations\n * (create, update, patch, delete) — they are applied by the factory wrapper so Prisma and custom\n * adapters share the same hook path. Sub-resource hooks are still applied inline.\n *\n * Prisma `P2025` (record not found) errors are mapped to `NotFoundException`.\n */\nexport class WriteRepository<T = any> {\n private get prisma(): any {\n return this.adapter.client;\n }\n\n constructor(\n private readonly prismaModel: any,\n private readonly adapter: DataSourceAdapter,\n private readonly config: Resource,\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 /**\n * The parent a *child* write is scoped to, for the hook context.\n *\n * A sub-resource is served by the parent's controller, so its parent id arrives\n * as the parent's own `:id` — hence `param: 'id'`. A resource that declares\n * `parent` names its own param and goes through the custom adapter instead.\n */\n private parentHookContext(parentId: string | number) {\n return {\n route: this.config.route,\n param: 'id',\n id: this.toId(parentId),\n };\n }\n\n /**\n * Create a record. The data has already been stripped of sub-resource keys,\n * normalized, and run through `beforeWrite` by the factory wrapper.\n */\n async create(data: unknown, _request?: any): Promise<T> {\n return this.prismaModel.create({ data });\n }\n\n /**\n * Update a record. The data has already been stripped, normalized, and hooked\n * by the factory wrapper.\n */\n async update(id: number | string, data: unknown, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.update({\n where: { [idField]: this.toId(id) },\n data,\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n /**\n * Partial-update a record. Same contract as `update`.\n */\n async patch(id: number | string, data: unknown, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.update({\n where: { [idField]: this.toId(id) },\n data,\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n async delete(id: number | string, _request?: any): Promise<T> {\n const idField = this.config.idField ?? 'id';\n try {\n return await this.prismaModel.delete({\n where: { [idField]: this.toId(id) },\n });\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE) throw this.notFound(id);\n throw e;\n }\n }\n\n /**\n * Write to a **custom** sub-resource by delegating to the child's own\n * repository.\n *\n * The child has no Prisma model, so `prisma[childModel]` is not an option.\n * Value-label normalisation and the child's `beforeWrite`/`afterWrite` hooks\n * still apply, so a custom child behaves like a Prisma one from the caller's\n * point of view.\n */\n private async delegateChildWrite(\n sub: SubResourceConfig,\n op: 'create' | 'update' | 'patch' | 'delete',\n parentId: string | number | undefined,\n childId: string | number | undefined,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (parentId === undefined) {\n throw new BadRequestException(\n `Sub-resource \"${sub.childRoute}\" of \"${this.config.name}\" requires a parent id.`,\n );\n }\n\n const fn = childRepositoryFn(sub, op, this.config.name);\n const id =\n childId === undefined\n ? undefined\n : (sub.idType ?? 'string') === 'number'\n ? +childId\n : String(childId);\n\n const ctx = childCtx({\n parentConfig: this.config,\n prisma: this.prisma,\n op,\n parentId: this.toId(parentId),\n id,\n request,\n });\n\n let payload: unknown;\n if (op !== 'delete') {\n const stripped =\n op === 'create' ? stripNonCreateableChildFields(sub, data) : data;\n const normalized = normalizeValueLabels(stripped, sub.valueLabelColumns);\n payload = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(normalized, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: op === 'patch' ? 'patch' : op,\n ...(id !== undefined && { id }),\n request,\n parent: ctx.parent,\n })\n : normalized;\n }\n\n const result =\n op === 'create'\n ? await fn(this.toId(parentId), payload, ctx)\n : op === 'delete'\n ? await fn(this.toId(parentId), id, ctx)\n : await fn(this.toId(parentId), id, payload, ctx);\n\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: op === 'patch' ? 'patch' : op,\n ...(id !== undefined && { id }),\n request,\n })\n : result;\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(\n parentId: string | number,\n sub: SubResourceConfig,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(sub, 'create', parentId, undefined, data, request);\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 stripped = stripNonCreateableChildFields(sub, data);\n const normalized = normalizeValueLabels(\n stripped,\n sub.valueLabelColumns,\n ) as object;\n const payload = { ...normalized, [sub.foreignKey]: this.toId(parentId) };\n const prepared = sub.hooks?.beforeWrite\n ? await sub.hooks.beforeWrite(payload, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'create',\n request,\n parent: this.parentHookContext(parentId),\n })\n : payload;\n\n const includeKeys = includeRelationNames(sub.include);\n const preparedEntries = prepared as Record<string, unknown>;\n const prismaData = {\n ...Object.fromEntries(\n Object.entries(preparedEntries).filter(\n ([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v),\n ),\n ),\n ...(sub.foreignKey in preparedEntries\n ? { [sub.foreignKey]: this.toId(parentId) }\n : {}),\n };\n const result = await childModel.create({ data: prismaData });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'create',\n request,\n })\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(\n sub: SubResourceConfig,\n childId: string | number,\n data: unknown,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(\n sub,\n 'update',\n parentIdFromRequest(request),\n childId,\n data,\n request,\n );\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 id =\n (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, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'update',\n id,\n request,\n parent: this.parentHookContext(parentIdFromRequest(request) ?? id),\n })\n : normalized;\n\n const includeKeys = includeRelationNames(sub.include);\n const prepared = Object.fromEntries(\n Object.entries(afterHook as Record<string, unknown>).filter(\n ([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v),\n ),\n );\n try {\n const result = await childModel.update({\n where: { [sub.idField ?? DEFAULT_ID_FIELD]: id },\n data: prepared,\n });\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'update',\n id,\n request,\n })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\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(\n sub: SubResourceConfig,\n childId: string | number,\n parentId?: string | number,\n request?: any,\n ): Promise<any> {\n if (sub.childKind === 'custom') {\n return this.delegateChildWrite(\n sub,\n 'delete',\n parentIdFromRequest(request, parentId),\n childId,\n undefined,\n request,\n );\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 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 try {\n const result = await childModel.deleteMany({ where });\n if (result.count === 0)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n return sub.hooks?.afterWrite\n ? sub.hooks.afterWrite(result, {\n dataSource: this.adapter,\n prisma: this.prisma,\n op: 'delete',\n id,\n request,\n })\n : result;\n } catch (e: any) {\n if (e?.code === PRISMA_NOT_FOUND_CODE)\n throw new NotFoundException(\n `${sub.childRoute} with id ${childId} not found`,\n );\n throw e;\n }\n }\n}\n","import { z } from 'zod';\n\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\n\nexport const WriteOpSchema = z.enum(['create', 'update', 'patch', 'delete']);\nexport type WriteOp = z.infer<typeof WriteOpSchema>;\n\nexport const ReadOpSchema = z.enum(['findAll', 'findOne']);\nexport type ReadOp = z.infer<typeof ReadOpSchema>;\n\n/**\n * The parent a nested read or write is scoped to.\n *\n * Present whenever the resource is reached under a parent — as a sub-resource\n * declared by a relation column on the parent (`param` is the parent's own `id`),\n * or as a resource that declares `parent` and mounts its own controller beneath\n * it (`param` is the name it chose, e.g. `groupId`). Absent on a top-level write.\n *\n * Deliberately the same shape as `CustomRepositoryContext.parent`, so a hook and a\n * `repository.ts` read the parent identically.\n */\nexport interface ParentHookContext {\n route: string;\n param: string;\n id: string | number;\n}\n\nexport interface WriteHookContext<PRISMACLIENT = unknown> {\n /** The datasource adapter for this resource. Use `dataSource.client` to reach the raw backend. */\n dataSource: DataSourceAdapter;\n /**\n * Raw Prisma client — backward-compatible alias for `dataSource.client`.\n * `undefined` on a non-Prisma datasource.\n * @deprecated prefer `dataSource.client`\n */\n prisma: PRISMACLIENT;\n op: WriteOp;\n id?: string | number;\n request?: any;\n parent?: ParentHookContext;\n}\n\nexport interface ReadHookContext<PRISMACLIENT = unknown> {\n /** The datasource adapter for this resource. Use `dataSource.client` to reach the raw backend. */\n dataSource: DataSourceAdapter;\n /**\n * Raw Prisma client — backward-compatible alias for `dataSource.client`.\n * `undefined` on a non-Prisma datasource.\n * @deprecated prefer `dataSource.client`\n */\n prisma: PRISMACLIENT;\n op: ReadOp;\n request?: any;\n parent?: ParentHookContext;\n}\n\nexport const ResourceHooksSchema = z.object({\n beforeWrite: z\n .custom<(data: any, ctx: WriteHookContext<any>) => Promise<any> | any>()\n .optional(),\n afterWrite: z\n .custom<(result: any, ctx: WriteHookContext<any>) => Promise<any> | any>()\n .optional(),\n afterRead: z\n .custom<(row: any, ctx: ReadHookContext<any>) => Promise<any> | any>()\n .optional(),\n beforeFindAll: z\n .custom<(params: ListRequest, ctx: ReadHookContext<any>) => Promise<ListRequest> | ListRequest>()\n .optional(),\n afterFindAll: z\n .custom<(rows: any[], ctx: ReadHookContext<any>) => Promise<any[]> | any[]>()\n .optional(),\n});\n\n/**\n * Hand-written interface so the `PRISMACLIENT` generic is preserved.\n * `z.infer<typeof ResourceHooksSchema>` erases it (Zod wraps every custom()\n * in `ZodType<T>`, discarding the generic), making `ctx.prisma` always `any`.\n */\nexport interface ResourceHooks<PRISMACLIENT = any> {\n beforeWrite?: (data: any, ctx: WriteHookContext<PRISMACLIENT>) => Promise<any> | any;\n afterWrite?: (result: any, ctx: WriteHookContext<PRISMACLIENT>) => Promise<any> | any;\n afterRead?: (row: any, ctx: ReadHookContext<PRISMACLIENT>) => Promise<any> | any;\n beforeFindAll?: (params: ListRequest, ctx: ReadHookContext<PRISMACLIENT>) => Promise<ListRequest> | ListRequest;\n afterFindAll?: (rows: any[], ctx: ReadHookContext<PRISMACLIENT>) => Promise<any[]> | any[];\n}\n","import type { ResourceHooks } from './hooks.types';\nimport { findModule, importDefault } from '../loader/module.loader';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { join } from 'node:path';\n\nexport const loadResourceHooks = async (\n basePath: string,\n): Promise<ResourceHooks | undefined> => {\n const file = findModule(basePath, 'hooks');\n return file ? importDefault<ResourceHooks>(file) : undefined;\n};\n\n/**\n * Attach each sub-resource's hooks.\n *\n * Two locations, checked in order:\n *\n * 1. `<parent>/hooks/<childName>.ts` — the original convention, which keeps every\n * child's hooks together under the parent that serves them.\n * 2. `<childDir>/hooks.ts` — the child's own directory, same filename a top-level\n * resource uses.\n *\n * The second exists because a child with its own directory already keeps\n * `resource.json` and (for `kind: \"custom\"`) `repository.ts` there, so putting\n * `hooks.ts` beside them is the obvious guess — and until it was supported that\n * file was silently ignored, with no error and no status-page entry.\n *\n * The parent-scoped location wins when both are present, so nothing that relied on\n * convention 1 changes behaviour.\n */\nexport const loadSubResourceHooks = async (\n subResources: SubResourceConfig[],\n basePath: string,\n): Promise<void> => {\n for (const sub of subResources) {\n const file =\n (sub.name ? findModule(join(basePath, 'hooks'), sub.name) : undefined) ??\n (sub.childDir ? findModule(sub.childDir, 'hooks') : undefined);\n if (!file) continue;\n const hooks = await importDefault<ResourceHooks>(file);\n if (hooks) (sub as any).hooks = hooks;\n }\n};","import type { ListRequest } from '@ghentcdh/crouton-core';\n\nimport type {\n ParentHookContext,\n ReadOp,\n ResourceHooks,\n WriteOp,\n} from './hooks.types';\nimport type { DataSourceAdapter } from '../data-source/data-source.adapter';\nimport type { ValueLabelColumn } from '../resource/valueLabel';\nimport {\n applyValueLabelColumns,\n normalizeValueLabels,\n} from '../resource/valueLabel.apply';\n\n/**\n * Lifecycle-hook application, extracted so every repository implementation\n * treats hooks identically.\n *\n * All four helpers now accept a `DataSourceAdapter` instead of a raw Prisma\n * client. The adapter is forwarded into the hook context as `dataSource`; the\n * raw client is available as `ctx.prisma` (= `adapter.client`) for backward\n * compatibility with existing hook files.\n */\n\nexport type HookTarget = {\n hooks?: ResourceHooks;\n valueLabelColumns?: ValueLabelColumn[];\n};\n\nconst hookCtxRead = (adapter: DataSourceAdapter, op: ReadOp, request?: any, parent?: ParentHookContext) => ({\n dataSource: adapter,\n prisma: adapter.client,\n op,\n request,\n ...(parent && { parent }),\n});\n\nconst hookCtxWrite = (\n adapter: DataSourceAdapter,\n op: WriteOp,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n) => ({\n dataSource: adapter,\n prisma: adapter.client,\n op,\n ...(id !== undefined && { id }),\n ...(request !== undefined && { request }),\n ...(parent && { parent }),\n});\n\n/**\n * `afterRead` for a list, plus the `{ value, label }` envelope.\n *\n * The envelope is applied on list reads only — `findOne` feeds the form/detail\n * view, where the select control maps the stored scalar to its label itself and\n * submits the scalar back.\n */\nexport const decorateRows = async (\n rows: any[],\n op: ReadOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any[]> => {\n const hook = target.hooks?.afterRead;\n const ctx = hookCtxRead(adapter, op, request, parent);\n const hooked = hook\n ? await Promise.all(rows.map((row) => hook(row, ctx)))\n : rows;\n const cols = target.valueLabelColumns;\n return cols?.length\n ? hooked.map((r) => applyValueLabelColumns(r, cols))\n : hooked;\n};\n\n/** `afterRead` for a single row. Deliberately no value-label envelope. */\nexport const decorateRow = async (\n row: any,\n op: ReadOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const hook = target.hooks?.afterRead;\n return hook ? hook(row, hookCtxRead(adapter, op, request, parent)) : row;\n};\n\n/** Unwrap value-label envelopes, then run `beforeWrite`. */\nexport const prepareWrite = async (\n data: any,\n op: WriteOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const normalized = normalizeValueLabels(data, target.valueLabelColumns);\n const hook = target.hooks?.beforeWrite;\n return hook\n ? hook(normalized, hookCtxWrite(adapter, op, id, request, parent))\n : normalized;\n};\n\n/** Run `beforeFindAll` to transform query params before the DB query. */\nexport const applyBeforeFindAll = async (\n params: ListRequest,\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<ListRequest> => {\n const hook = target.hooks?.beforeFindAll;\n return hook ? hook(params, hookCtxRead(adapter, 'findAll', request, parent)) : params;\n};\n\n/** Run `afterFindAll` on the full result list, after per-row `afterRead` decoration. */\nexport const applyAfterFindAll = async (\n rows: any[],\n target: HookTarget,\n adapter: DataSourceAdapter,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any[]> => {\n const hook = target.hooks?.afterFindAll;\n return hook ? hook(rows, hookCtxRead(adapter, 'findAll', request, parent)) : rows;\n};\n\n/** Run `afterWrite` on the persisted result. */\nexport const postWrite = async (\n result: any,\n op: WriteOp,\n target: HookTarget,\n adapter: DataSourceAdapter,\n id?: string | number,\n request?: any,\n parent?: ParentHookContext,\n): Promise<any> => {\n const hook = target.hooks?.afterWrite;\n return hook ? hook(result, hookCtxWrite(adapter, op, id, request, parent)) : result;\n};\n","import {\n CUSTOM_OPS,\n type CustomParentRepository,\n type CustomRepository,\n PARENT_METHOD,\n} from './custom-repository.types';\nimport { type CrudOperation, isOperationEnabled, isOperationExternal, resolveDefinition } from '../crud.config';\nimport { type Resource } from '../resource/ResourceConfig.schema';\n\n/**\n * Check that a custom resource can actually serve what it advertises.\n *\n * Returns a human-readable problem, or `undefined` when the resource is sound.\n * Callers record the message on the load-error registry so it surfaces on the\n * status page — the same treatment a prisma resource gets when its model is\n * missing from the client. Failing at load time beats a 501 on first request.\n */\nexport const validateCustomRepository = (\n config: Resource,\n repository: CustomRepository | undefined,\n adapterClient?: unknown,\n): string | undefined => {\n const definition = resolveDefinition(config);\n const enabled = CUSTOM_OPS.filter((op) =>\n isOperationEnabled(definition, op as CrudOperation) &&\n !isOperationExternal(definition, op as CrudOperation),\n );\n\n // A nested resource is only reachable under its parent, so it implements the\n // parent-aware variants instead of the unnested ones.\n const nested = !!config.parent;\n const methodFor = (op: (typeof CUSTOM_OPS)[number]) =>\n nested ? PARENT_METHOD[op] : op;\n\n if (!repository) {\n if (enabled.length === 0) return undefined;\n // If the datasource adapter client implements all required methods it acts\n // as the repository — no repository.ts needed.\n if (adapterClient && typeof adapterClient === 'object') {\n const missing = enabled.filter(\n (op) => typeof (adapterClient as Record<string, unknown>)[methodFor(op)] !== 'function',\n );\n if (missing.length === 0) return undefined;\n }\n return (\n 'No repository.ts found. A custom resource implements its own data access; ' +\n `create ${config.name}/repository.ts with a default export implementing: ` +\n `${enabled.map(methodFor).join(', ')}.`\n );\n }\n\n const implemented = (name: keyof CustomRepository | keyof CustomParentRepository) =>\n typeof (repository as Record<string, unknown>)[name as string] === 'function';\n\n // `patch` is satisfied by `update` — the adapter falls back, matching the\n // Prisma repository where patch is an update with a partial schema.\n const missing = enabled.filter((op) =>\n op === 'patch'\n ? !implemented(methodFor('patch')) && !implemented(methodFor('update'))\n : !implemented(methodFor(op)),\n );\n\n if (missing.length) {\n const names = missing.map(methodFor);\n return (\n `repository.ts does not implement ${names.join(', ')}` +\n (nested\n ? ` (this resource is nested under \"${config.parent!.route}\", so it implements the parent-aware operations)` +\n '. '\n : '. ') +\n 'Either implement them or disable the operation in resource.json ' +\n `(\"operations\": { \"${missing[0]}\": false }).`\n );\n }\n\n return undefined;\n};\n","import {\n ZodObject,\n type ZodRawShape,\n type ZodType,\n toJSONSchema,\n} from 'zod';\n\nimport { isNullableProperty, jsonSchemaOpts } from '@ghentcdh/crouton-core';\n\nimport { type JsonSchemaInput, type SchemaInput } from './resource/json.schema';\n\nexport function isZodSchema(\n schema: SchemaInput,\n): schema is ZodObject<ZodRawShape> {\n return schema instanceof ZodObject;\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 let jsonSchema: Record<string, any>;\n try {\n jsonSchema = toJSONSchema(schema, {\n target: 'openApi3',\n ...jsonSchemaOpts,\n }) as Record<string, any>;\n } catch {\n // Zod v4 bug: z.record() inside z.union() inside z.lazy() crashes toJSONSchema\n // (e.g. Prisma JsonValue schema). Fall back to a permissive object schema.\n return { type: 'object' } as JsonSchemaInput;\n }\n\n dropNullableFromRequired(jsonSchema);\n\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 { Injectable, type OnModuleDestroy } from '@nestjs/common';\n\nimport type { DataSourceAdapter } from './data-source.adapter';\nimport type { DataSourceEntry } from './data-source.types';\n\n@Injectable()\nexport class DataSourceRegistry implements OnModuleDestroy {\n private readonly adapters = new Map<string, DataSourceAdapter>();\n private defaultName: string | undefined;\n\n constructor(entries: DataSourceEntry[]) {\n for (const entry of entries) {\n this.adapters.set(entry.config.name, entry.adapter);\n if (entry.config.default) {\n this.defaultName = entry.config.name;\n }\n }\n if (!this.defaultName && entries.length > 0) {\n this.defaultName = entries[0].config.name;\n }\n }\n\n resolveAdapter(name?: string): DataSourceAdapter {\n const key = name ?? this.defaultName;\n if (!key) throw new Error('No default data source configured');\n const adapter = this.adapters.get(key);\n if (!adapter) throw new Error(`Data source \"${key}\" not found in registry`);\n return adapter;\n }\n\n /** Returns the raw backend client for escape-hatch usage (`ctx.prisma`, action procedures). */\n resolveClient(name?: string): unknown {\n return this.resolveAdapter(name).client;\n }\n\n /**\n * Backward-compatible alias — returns the raw client, same as `resolveClient`.\n * Prefer `resolveAdapter` for new code.\n */\n resolve(name?: string): unknown {\n return this.resolveClient(name);\n }\n\n entries(): { name: string; adapter: DataSourceAdapter; client: unknown }[] {\n return [...this.adapters.entries()].map(([name, adapter]) => ({\n name,\n adapter,\n client: adapter.client,\n }));\n }\n\n async onModuleDestroy() {\n await this.disconnectAll();\n }\n\n /**\n * Disconnect every datasource. Called by `onModuleDestroy` and also by the\n * dev \"restart backend\" action before `process.exit()`.\n */\n async disconnectAll(): Promise<void> {\n for (const adapter of this.adapters.values()) {\n await adapter.disconnect?.();\n }\n }\n}\n","import { DataSourceSchema } from '@ghentcdh/crouton-core';\n\nimport type { DataSourceAdapter } from './data-source.adapter';\nimport type { DataSourceEntry } from './data-source.types';\nimport { PrismaDataSourceAdapter } from './prisma.adapter';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { existsSync, readFileSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\n/**\n * Scan a directory for data-source subdirectories and load their configs + adapters.\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 let _config: unknown;\n try {\n _config = JSON.parse(readFileSync(jsonFile, 'utf-8'));\n } catch (err) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: `Invalid JSON in ${jsonFile}: ${(err as Error).message}`,\n });\n continue;\n }\n\n const datasource = DataSourceSchema.safeParse(_config);\n\n if (!datasource.success) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: `Invalid datasource schema: ${jsonFile}: ${datasource.error.message}`,\n });\n continue;\n }\n const config = datasource.data;\n\n const indexFile = findModule(basePath, 'index');\n\n if (!indexFile) continue;\n\n let adapter: DataSourceAdapter;\n try {\n const mod = await import(indexFile);\n const exported = mod.default;\n if (!exported) continue;\n\n if (config.adapter === 'custom') {\n // index.ts may default-export a DataSourceAdapter instance or a class\n // that extends PrismaDataSourceAdapter (or any DataSourceAdapter).\n if (typeof exported === 'function') {\n // Class export: `export default class MyAdapter extends PrismaDataSourceAdapter { ... }`\n const instance = new exported() as DataSourceAdapter;\n if (typeof instance.kind !== 'string') {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Custom datasource \"${dir}\": default-exported class must produce a DataSourceAdapter (object with a \"kind\" string field).`,\n });\n continue;\n }\n adapter = instance;\n } else if (typeof exported === 'object' && typeof exported.kind === 'string') {\n adapter = exported as DataSourceAdapter;\n } else {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Custom datasource \"${dir}\": index.ts must default-export a DataSourceAdapter instance or class (with a \"kind\" string field).`,\n });\n continue;\n }\n } else {\n // Default: prisma — wrap the exported PrismaClient.\n adapter = new PrismaDataSourceAdapter(exported);\n }\n } catch (err) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: indexFile,\n error: `Failed to load datasource adapter: ${(err as Error).message}`,\n });\n continue;\n }\n\n results.push({ config, adapter });\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 type { DataSourceAdapter } from './data-source.adapter';\n\n/**\n * In-memory reference adapter — useful for tests and as a template for custom\n * adapters. Not intended for production use.\n *\n * Seed model rows with `seed(model, rows)` before the test; `supports(model)`\n * returns `true` for every seeded model.\n */\nexport class InMemoryDataSourceAdapter implements DataSourceAdapter {\n readonly kind = 'in-memory' as const;\n readonly client = undefined;\n\n private readonly store = new Map<string, unknown[]>();\n\n seed(model: string, rows: unknown[]): this {\n this.store.set(model, rows);\n return this;\n }\n\n supports(model: string): boolean {\n return this.store.has(model);\n }\n\n async disconnect(): Promise<void> {\n // no-op\n }\n}\n","import { Param, Post, SetMetadata } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isRowProcedureAction, isTableProcedureAction } from '../crud.config';\nimport { CROUTON_SECURITY } from '../security';\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(isRowProcedureAction);\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 const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\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(isTableProcedureAction);\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 const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\n }\n};\n","import {\n type CanActivate,\n type ExecutionContext,\n Injectable,\n} from '@nestjs/common';\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- runtime DI requires value imports\nimport { ModuleRef, Reflector } from '@nestjs/core';\n\nimport type { SecurityConfig } from '@ghentcdh/crouton-core';\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports -- runtime DI requires value import\nimport { SecurityGuardRegistry } from './security-guard.registry';\n\nexport const CROUTON_SECURITY = 'crouton:security';\n\n@Injectable()\nexport class CroutonSecurityGuard implements CanActivate {\n constructor(\n private readonly reflector: Reflector,\n private readonly registry: SecurityGuardRegistry,\n private readonly moduleRef: ModuleRef,\n ) {}\n\n async canActivate(context: ExecutionContext): Promise<boolean> {\n const sec = this.reflector.get<SecurityConfig | undefined>(\n CROUTON_SECURITY,\n context.getHandler(),\n );\n\n // No metadata or explicitly public → allow.\n if (!sec || 'public' in sec) return true;\n\n const names = Array.isArray(sec.guard) ? sec.guard : [sec.guard];\n for (const name of names) {\n const cls = this.registry.resolve(name);\n const guard = this.moduleRef.get(cls, { strict: false });\n const ok = await guard.canActivate(context);\n if (!ok) return false;\n }\n return true;\n }\n}\n","import { type CanActivate, Injectable, type Type } from '@nestjs/common';\n\n@Injectable()\nexport class SecurityGuardRegistry {\n constructor(\n private readonly guards: Record<string, Type<CanActivate>> = {},\n ) {}\n\n resolve(name: string): Type<CanActivate> {\n const g = this.guards[name];\n if (!g)\n throw new Error(\n `Unknown security guard \"${name}\". Register it in security.guards.`,\n );\n return g;\n }\n\n classes(): Type<CanActivate>[] {\n return Object.values(this.guards);\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 { Body, Param, Post, Req } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultCreate = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'create')) return null;\n if (isOperationExternal(ctx.definition, 'create')) return null;\n const { cls, config, createSchema, bodyDecorator } = ctx;\n const methodName = 'create';\n\n return {\n route: '',\n methodName,\n name: config.name,\n createFn: function (this: { repo: CrudRepository }, body: any, req: any) {\n return this.repo.create(body, req);\n },\n decorators: () => {\n bodyDecorator(createSchema, { coerceNullableUndefinedToNull: true })(\n cls.prototype,\n methodName,\n 0,\n );\n Req()(cls.prototype, methodName, 1);\n },\n };\n};\n\nconst childCreate = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'create')) return null;\n const { cls } = ctx;\n const methodName = `createChild_${sub.childRoute}`;\n\n const createFn = async function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.createChild(id, sub, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Body()(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n route: `:id/${sub.childRoute}`,\n methodName,\n name: sub.childRoute,\n createFn,\n decorators,\n };\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 = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childCreate(sub) : defaultCreate;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.createFn);\n const d = desc(cls, methodName);\n Post(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Create a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 201, description: `${name} created` })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'create', sub);\n};\n","import { Delete, Param, Req } from '@nestjs/common';\nimport { ApiOperation, ApiParam, ApiResponse } from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { type SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultDelete = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'delete')) return null;\n if (isOperationExternal(ctx.definition, 'delete')) return null;\n const { config } = ctx;\n const methodName = 'delete';\n const { name } = config;\n\n return {\n route: ':id',\n methodName,\n name,\n decorators: () => {\n //\n },\n deleteFn: function (this: { repo: CrudRepository }, id: string, req: any) {\n return this.repo.delete(id, req);\n },\n };\n};\n\nexport const deleteChild =\n (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'delete')) return null;\n const { cls } = ctx;\n const methodName = `deleteChild_${sub.childRoute}`;\n\n const deleteFn = async function (\n this: { repo: CrudRepository },\n childId: string,\n parentId: string,\n req: any,\n ) {\n return this.repo.deleteChild(sub, childId, parentId, req);\n };\n\n const decorators = () => {\n Param('childId')(cls.prototype, methodName, 0);\n // The parent id was declared but never bound, so `parentId` always\n // arrived undefined and the foreign-key guard in `deleteChild` — the one\n // that is supposed to prevent cross-parent deletions — never engaged.\n Param('id')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n deleteFn,\n decorators,\n };\n };\n\n/** Register `DELETE /:id`. No-ops when `delete` is disabled. */\nexport const registerDelete = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? deleteChild(sub) : defaultDelete;\n const { cls } = ctx;\n\n const properties = operationFn(ctx);\n if (!properties) return;\n const { methodName, route, name } = properties;\n\n def(cls, methodName, properties.deleteFn);\n const d = desc(cls, methodName);\n Delete(route)(cls.prototype, methodName, d);\n Param('id')(cls.prototype, methodName, 0);\n ApiOperation({ summary: `Delete ${name} record` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({ status: 200 })(cls.prototype, methodName, d);\n properties.decorators();\n if (!sub) Req()(cls.prototype, methodName, 1);\n ctx.secure(methodName, 'delete', sub);\n};\n","import { Get, Param, Query, Req } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { RequestDtoNoOffset } from '../request.dto';\nimport { type SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { childSchemas } from './register-schemas';\n\nconst _findAll = async (\n repo: CrudRepository,\n params: any,\n request?: any,\n) => {\n // Repositories that cannot count separately (custom repositories backed by a\n // remote API) implement `findAllWithCount` and return both in one round trip.\n const { data, count } = repo.findAllWithCount\n ? await repo.findAllWithCount(params, request)\n : await Promise.all([\n repo.findAll(params, request),\n repo.count(params.filter ?? [], params.q),\n ]).then(([data, count]) => ({ data, count }));\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: {\n count,\n page: params.page,\n pageSize: params.pageSize,\n totalPages,\n sort: params.sort,\n sortDir: params.sortDir,\n filter: params.filter,\n },\n };\n};\nconst findAllByParent = async (\n repo: CrudRepository,\n id: string,\n childRoute: string,\n params: any,\n request?: any,\n) => {\n const { data, count } = await repo.findAllByParent(\n id,\n childRoute,\n params,\n request,\n );\n const totalPages = Math.max(1, Math.ceil(count / params.pageSize));\n return {\n data,\n request: {\n count,\n page: params.page,\n pageSize: params.pageSize,\n totalPages,\n sort: params.sort,\n sortDir: params.sortDir,\n filter: params.filter,\n },\n };\n};\n\nconst defaultFindAll = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'findAll')) return;\n if (isOperationExternal(ctx.definition, 'findAll')) return;\n\n const { config } = ctx;\n const findAll = async function (\n this: { repo: CrudRepository },\n params: any,\n req: any,\n ) {\n return _findAll(this.repo, params, req);\n };\n\n return {\n route: '',\n name: config.name,\n methodName: 'findAll',\n findAll,\n listSchema: ctx.listSchema,\n decorators: () => {\n //\n },\n };\n};\n\nconst childFindAll = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'findAll')) return;\n\n const { cls } = ctx;\n const methodName = `findAllBy_${sub.childRoute}`;\n\n const findAll = async function (\n this: { repo: CrudRepository },\n params: any,\n id: string,\n req: any,\n ) {\n return findAllByParent(this.repo, id, sub.childRoute, params, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n name: sub.childRoute,\n methodName,\n findAll,\n route: `:id/${sub.childRoute}`,\n decorators,\n listSchema: ctx.listSchema,\n };\n};\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 = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childFindAll(sub) : defaultFindAll;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name, listSchema } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.findAll);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n Query(new ZodValidationPipe(RequestDtoNoOffset.schema as any))(\n cls.prototype,\n methodName,\n 0,\n );\n if (!sub) Req()(cls.prototype, methodName, 1);\n ApiOperation({ summary: `List all ${name}s` })(cls.prototype, methodName, d);\n ApiResponse({\n status: 200,\n description: `Array of ${name}`,\n ...(listSchema && {\n schema: { type: 'array', items: toJsonSchema(listSchema) },\n }),\n })(cls.prototype, methodName, d);\n\n properties.decorators();\n ctx.secure(methodName, 'findAll', sub);\n};\n","import { createZodDto } from 'nestjs-zod';\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 { isDecimalField } from '@ghentcdh/crouton-core';\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 /** Top-level field names whose unwrapped type is a Prisma Decimal. */\n private readonly decimalKeys: readonly string[];\n /** Prisma Decimal constructor resolved once per pipe instance; null if unavailable. */\n private readonly decimalCtor: (new (v: number | string) => object) | null;\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\n // Resolve Decimal ctor once; skip coercion entirely if @prisma/client is unavailable.\n \n let decimalCtor: (new (v: number | string) => object) | null = null;\n try {\n decimalCtor = require('@prisma/client/runtime/client').Decimal;\n } catch {\n // @prisma/client not available — Decimal coercion disabled, falls back to today's behaviour\n }\n this.decimalCtor = decimalCtor;\n\n this.decimalKeys = decimalCtor\n ? Object.entries(schema.shape)\n .filter(([, field]) => isDecimalField(field as ZodType))\n .map(([key]) => key)\n : [];\n this.coerceUndefinedToNull = options.coerceNullableUndefinedToNull ?? false;\n }\n\n transform(value: unknown) {\n const stripped = this.stripEmptyStrings(value);\n const coerced = this.coerceNullable(stripped);\n const input = this.coerceDecimals(coerced);\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 /**\n * Coerce `number` / `string` values on Decimal fields to `Prisma.Decimal`.\n * `null` / `undefined` / omitted keys are left untouched (PATCH-safe).\n * An invalid numeric string is left as-is so Zod emits a proper validation error.\n * Known limitation: only top-level fields are coerced (nested Decimals in relations/arrays\n * are out of scope — matches how nullableKeys works today).\n */\n private coerceDecimals(value: unknown): unknown {\n if (\n !this.decimalCtor ||\n this.decimalKeys.length === 0 ||\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.decimalKeys) {\n const v = out[key];\n if (v == null) continue;\n if (typeof v !== 'number' && typeof v !== 'string') continue;\n try {\n out[key] = new this.decimalCtor(v);\n } catch {\n // leave raw value — Zod will emit the correct validation error\n }\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 code: e.code,\n }));\n }\n}\n","import { Get, Param, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiParam,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport type { OperationContext } from './operation-context';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport { def, desc } from './decorator.utils';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\n\nconst defaultFindOne = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'findOne')) return null;\n if (isOperationExternal(ctx.definition, 'findOne')) return null;\n const { cls, config } = ctx;\n const methodName = 'findOne';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n findOneFn: function (this: { repo: CrudRepository }, id: string, req: any) {\n return this.repo.findOne(id, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n Req()(cls.prototype, methodName, 1);\n },\n };\n};\n\nconst childFindOne = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'findOne')) return null;\n const { cls } = ctx;\n const methodName = `findOneChild_${sub.childRoute}`;\n\n const findOneFn = async function (\n this: { repo: CrudRepository },\n parentId: string,\n childId: string,\n req: any,\n ) {\n return this.repo.findOneChild(sub, childId, parentId, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n findOneFn,\n decorators,\n };\n};\n\n/** Register `GET /:id`. No-ops when `findOne` is disabled. */\nexport const registerFindOne = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childFindOne(sub) : defaultFindOne;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.findOneFn);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Get one ${name} by id` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiParam(ctx.idParamMeta)(cls.prototype, methodName, d);\n ApiResponse({\n status: 200,\n description: `The ${name}`,\n ...(ctx.oneSchema && { schema: toJsonSchema(ctx.oneSchema) }),\n })(cls.prototype, methodName, d);\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'findOne', sub);\n};\n","import { Body, Param, Patch, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultPatch = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'patch')) return null;\n if (isOperationExternal(ctx.definition, 'patch')) return null;\n const { cls, config, patchSchema, bodyDecorator } = ctx;\n const methodName = 'patch';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n patchFn: function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.patch(id, body, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n bodyDecorator(patchSchema)(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n },\n };\n};\n\nconst childPatch = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'patch')) return null;\n const { cls } = ctx;\n const methodName = `patchChild_${sub.childRoute}`;\n\n const patchFn = async function (\n this: { repo: CrudRepository },\n _id: string,\n childId: string,\n body: any,\n req: any,\n ) {\n return this.repo.updateChild(sub, childId, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Body()(cls.prototype, methodName, 2);\n Req()(cls.prototype, methodName, 3);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n patchFn,\n decorators,\n };\n};\n\n/** Register `PATCH /:id`. No-ops when `patch` is disabled. */\nexport const registerPatch = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childPatch(sub) : defaultPatch;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.patchFn);\n const d = desc(cls, methodName);\n Patch(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Update a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${name} updated` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'patch', sub);\n};\n","\nimport {\n BadRequestException,\n Body,\n ForbiddenException,\n Get,\n NotFoundException,\n Patch, Put,\n SetMetadata,\n} from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { IS_DEV } from '../dev-mode';\nimport {\n type PatchResourceJson,\n PatchResourceJsonSchema,\n} from '../resource/PatchResourceJson.schema';\nimport {\n applyColumnPatch,\n readRawResourceJson,\n validateResourceJson,\n writeRawResourceJson,\n} from '../resource/WriteResourceJson';\nimport { type ResourceConfigRegistry } from '../resource-config.registry';\nimport { CROUTON_SECURITY } from '../security';\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport {\n buildDefinitionPayload,\n buildEditableColumnsPayload,\n buildResourceJsonPayload,\n} from './payload-builders';\nimport { getRequestLanguage } from '../translation/language.context';\nimport { ZodValidationPipe } from '../zod-validation.pipe';\nimport { join } from 'node:path';\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, schemaEnricher } = ctx;\n const { route, name } = config;\n const definitionPayload = buildDefinitionPayload(config);\n\n def(\n cls,\n 'getDefinition',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n const language = getRequestLanguage();\n let payload = definitionPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildDefinitionPayload(fresh);\n }\n if (!schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n );\n const d = desc(cls, 'getDefinition');\n Get('definition')(cls.prototype, 'getDefinition', d);\n ApiOperation({ summary: `Get the resource definition for ${name}` })(\n cls.prototype,\n 'getDefinition',\n d,\n );\n ApiResponse({\n status: 200,\n description: `Definition (operations + schemas) for ${name}`,\n })(cls.prototype, 'getDefinition', d);\n\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, 'getDefinition', d);\n }\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, schemaEnricher } = ctx;\n const { route, name } = config;\n const resourceJsonPayload = buildResourceJsonPayload(config, baseUrl);\n\n def(\n cls,\n 'getResourceJson',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n const language = getRequestLanguage();\n let payload = resourceJsonPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildResourceJsonPayload(fresh, baseUrl);\n }\n if (!schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n );\n const d = desc(cls, 'getResourceJson');\n Get('resource.json')(cls.prototype, 'getResourceJson', d);\n ApiOperation({ summary: `Get resource descriptor for ${name}` })(\n cls.prototype,\n 'getResourceJson',\n d,\n );\n ApiResponse({\n status: 200,\n description: `Resource descriptor (operations + JSON Schema) for ${name}`,\n })(cls.prototype, 'getResourceJson', d);\n\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, 'getResourceJson', d);\n }\n};\n\n/**\n * Register `GET /resource-columns` — dev-only endpoint backing the visual\n * resource builder's editor UI. Returns the raw, editable column list (see\n * `buildEditableColumnsPayload`), rebuilt from the live config registry on\n * every request so it reflects any on-disk edits (including ones made by\n * this same builder, or by hand, or by `crouton update resources`).\n */\nexport const registerResourceColumnsEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'getResourceColumns',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The resource schema editor is only available when the backend is running in local dev mode.',\n );\n }\n const fresh = await this.configRegistry.getByRoute(route);\n return buildEditableColumnsPayload(fresh ?? config);\n },\n );\n const d = desc(cls, 'getResourceColumns');\n Get('resource-columns')(cls.prototype, 'getResourceColumns', d);\n ApiOperation({\n summary: `Dev-only: get the editable column list for ${name}`,\n })(cls.prototype, 'getResourceColumns', d);\n ApiResponse({\n status: 200,\n description: `Editable column list for ${name}`,\n })(cls.prototype, 'getResourceColumns', d);\n};\n\n/**\n * Register `PATCH /resource.json` — dev-only endpoint backing the visual\n * resource builder. Patches column display attributes (label, column,\n * hiddenInTable, hiddenInForm, hiddenInView, position, colspan) on the\n * resource's on-disk `resource.json` and returns the freshly reloaded\n * resource descriptor.\n *\n * Hard-gated to `IS_DEV`: refuses with 403 in any non-dev environment, since\n * writing to source files must never happen against a production deployment.\n */\nexport const registerResourceJsonPatchEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'patchResourceJson',\n async function (\n this: { configRegistry: ResourceConfigRegistry },\n body: PatchResourceJson,\n ) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'Editing resource.json is only available when the backend is running in local dev mode.',\n );\n }\n\n // Refresh the registry first so `getResourceDir` reflects the current on-disk layout.\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const jsonPath = join(dir, 'resource.json');\n const raw = readRawResourceJson(jsonPath);\n if (!raw) {\n throw new NotFoundException(`resource.json not found at ${jsonPath}`);\n }\n\n const merged = applyColumnPatch(raw, body);\n const validated = validateResourceJson(merged);\n if (!validated.success) {\n throw new BadRequestException(validated.error.issues);\n }\n\n writeRawResourceJson(jsonPath, merged);\n\n const fresh = await this.configRegistry.getByRoute(route);\n return buildEditableColumnsPayload(fresh ?? config);\n },\n );\n const d = desc(cls, 'patchResourceJson');\n Patch('resource.json')(cls.prototype, 'patchResourceJson', d);\n Body(new ZodValidationPipe(PatchResourceJsonSchema))(\n cls.prototype,\n 'patchResourceJson',\n 0,\n );\n ApiOperation({\n summary: `Dev-only: patch column layout in resource.json for ${name}`,\n })(cls.prototype, 'patchResourceJson', d);\n ApiResponse({\n status: 200,\n description: `Updated resource descriptor for ${name}`,\n })(cls.prototype, 'patchResourceJson', d);\n};\n\n/**\n * Register `GET /resource-json-raw` — dev-only endpoint returning the raw,\n * untransformed resource.json as-is (no schema defaults applied). Backs the\n * standalone resource.json editor component's initial load.\n */\nexport const registerResourceJsonRawGetEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'getResourceJsonRaw',\n async function (this: { configRegistry: ResourceConfigRegistry }) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The resource JSON editor is only available when the backend is running in local dev mode.',\n );\n }\n\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const jsonPath = join(dir, 'resource.json');\n const raw = readRawResourceJson(jsonPath);\n if (!raw) {\n throw new NotFoundException(`resource.json not found at ${jsonPath}`);\n }\n\n return raw;\n },\n );\n const d = desc(cls, 'getResourceJsonRaw');\n Get('resource-json-raw')(cls.prototype, 'getResourceJsonRaw', d);\n ApiOperation({\n summary: `Dev-only: get the raw resource.json for ${name}`,\n })(cls.prototype, 'getResourceJsonRaw', d);\n ApiResponse({\n status: 200,\n description: `Raw resource.json for ${name}`,\n })(cls.prototype, 'getResourceJsonRaw', d);\n};\n\n/**\n * Register `PUT /resource-json-raw` — dev-only endpoint that replaces the\n * entire resource.json with the provided body. Validates through\n * `ResourceJsonSchema` before writing. Backs the standalone resource.json\n * editor component's save action.\n */\nexport const registerResourceJsonRawPutEndpoint = (\n ctx: OperationContext,\n): void => {\n const { cls, config } = ctx;\n const { route, name } = config;\n\n def(\n cls,\n 'putResourceJsonRaw',\n async function (\n this: { configRegistry: ResourceConfigRegistry },\n body: Record<string, unknown>,\n ) {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'Editing resource.json is only available when the backend is running in local dev mode.',\n );\n }\n\n await this.configRegistry.getByRoute(route);\n const dir = this.configRegistry.getResourceDir(route);\n if (!dir) {\n throw new NotFoundException(\n `No resource.json on disk for \"${name}\" (route \"${route}\").`,\n );\n }\n\n const validated = validateResourceJson(body);\n if (!validated.success) {\n throw new BadRequestException(validated.error.issues);\n }\n\n const jsonPath = join(dir, 'resource.json');\n writeRawResourceJson(jsonPath, body);\n\n return body;\n },\n );\n const d = desc(cls, 'putResourceJsonRaw');\n Put('resource-json-raw')(cls.prototype, 'putResourceJsonRaw', d);\n Body()(cls.prototype, 'putResourceJsonRaw', 0);\n ApiOperation({\n summary: `Dev-only: replace the full resource.json for ${name}`,\n })(cls.prototype, 'putResourceJsonRaw', d);\n ApiResponse({\n status: 200,\n description: `Updated raw resource.json for ${name}`,\n })(cls.prototype, 'putResourceJsonRaw', d);\n};\n","import { z } from 'zod';\n\n/**\n * A per-context field-variant patch (`fieldInput`/`fieldView`/`fieldTable`).\n * Mirrors crouton-core's `FieldVariantSchema` shape loosely — `options` is a\n * catchall since a column's real option set depends on its `format`/`type`\n * (relation vs. plain vs. custom render) and the visual builder can't know\n * that ahead of time.\n *\n * Every key accepts `null`, matching `mergeFieldVariant`'s (crouton-core)\n * \"a `null` value deletes an inherited key\" convention — this is how the\n * editor's \"reset to inherited\" action works: it sends `null` for a key so\n * the column falls back to whatever the level below it (`fieldView` →\n * `fieldInput`, or `fieldTable` → `fieldView` → `fieldInput`) resolves to,\n * rather than pinning a copy of the resolved value at this level.\n */\nconst FieldVariantPatchSchema = z\n .object({\n type: z.string().nullable().optional(),\n format: z.string().nullable().optional(),\n resource: z.string().nullable().optional(),\n position: z.number().nullable().optional(),\n options: z.record(z.string(), z.unknown().nullable()).optional(),\n })\n .partial();\n\nexport type FieldVariantPatch = z.infer<typeof FieldVariantPatchSchema>;\n\n/**\n * Request body for `PATCH <route>/resource.json` — the visual resource\n * builder's edit endpoint (dev-mode only, see `dev-mode.ts`).\n *\n * Covers the display attributes the visual builder exposes: label/column,\n * visibility (`hiddenInTable/Form/View`), and the three field-variant\n * patches. Adding/removing columns is still out of scope — see\n * `FIELD_VARIANTS_EDITOR_PLAN.md`.\n */\nexport const PatchColumnSchema = z\n .object({\n label: z.string().optional(),\n column: z.string().optional(),\n hiddenInTable: z.boolean().optional(),\n hiddenInForm: z.boolean().optional(),\n hiddenInView: z.boolean().optional(),\n fieldInput: FieldVariantPatchSchema.optional(),\n fieldView: FieldVariantPatchSchema.optional(),\n fieldTable: FieldVariantPatchSchema.optional(),\n })\n .partial();\n\nexport type PatchColumn = z.infer<typeof PatchColumnSchema>;\n\nexport const PatchResourceJsonSchema = z.object({\n columns: z.record(z.string(), PatchColumnSchema),\n});\n\nexport type PatchResourceJson = z.infer<typeof PatchResourceJsonSchema>;\n","\nimport {\n type FieldInput,\n type FieldVariant,\n buildResourceJsonSchema,\n mergeFieldVariant,\n} from '@ghentcdh/crouton-core';\n\nimport type {\n PatchColumn,\n PatchResourceJson,\n} from './PatchResourceJson.schema';\nimport { existsSync, readFileSync, writeFileSync } from 'node:fs';\n\n/**\n * Backs the visual resource builder's `PATCH <route>/resource.json` endpoint.\n *\n * Deliberately does NOT reuse `readResourceJson` (`ReadResourceJson.ts`) for the\n * read side: that helper runs the file through `ResourceJsonSchema`, whose\n * `.transform()` normalizes `columns` from map-form to an array and fills in\n * every default. Round-tripping through it would silently rewrite a hand-written\n * map-form resource.json into array form and inject defaults for every\n * untouched field — the opposite of the \"leave every untouched key byte-stable\"\n * goal (see `VISUAL_RESOURCE_BUILDER_PLAN.md`, Phase 1). Instead this module\n * reads the raw JSON, patches only the touched leaf fields, and writes the\n * result back verbatim. `ResourceJsonSchema` is still used, but only to\n * *validate* the merged result before writing — never to shape what's written.\n */\nexport type RawResourceJson = Record<string, unknown>;\n\nexport const readRawResourceJson = (\n jsonPath: string,\n): RawResourceJson | undefined => {\n if (!existsSync(jsonPath)) return undefined;\n return JSON.parse(readFileSync(jsonPath, 'utf-8'));\n};\n\nconst FIELD_VARIANT_KEYS = ['fieldInput', 'fieldView', 'fieldTable'] as const;\ntype FieldVariantKey = (typeof FIELD_VARIANT_KEYS)[number];\n\n/**\n * Merges each of `fieldInput`/`fieldView`/`fieldTable` present on the patch\n * into the column's existing raw value for that key, via crouton-core's\n * `mergeFieldVariant` — the same function that resolves the\n * `fieldInput → fieldView → fieldTable` fallback chain elsewhere, so a patch\n * follows identical \"deep-merge one level into `options`, `null` deletes an\n * inherited key\" semantics instead of a second bespoke implementation.\n */\nconst mergeColumn = (\n existing: Record<string, unknown>,\n patch: PatchColumn,\n): Record<string, unknown> => {\n const { fieldInput, fieldView, fieldTable, ...rest } = patch;\n const variantPatches: Partial<Record<FieldVariantKey, unknown>> = {\n fieldInput,\n fieldView,\n fieldTable,\n };\n\n const merged: Record<string, unknown> = { ...existing, ...rest };\n for (const key of FIELD_VARIANT_KEYS) {\n const variantPatch = variantPatches[key];\n if (!variantPatch) continue;\n merged[key] = mergeFieldVariant(\n existing[key] as FieldInput | undefined,\n variantPatch as FieldVariant,\n );\n }\n return merged;\n};\n\n/**\n * Applies a column patch to a raw (untransformed) resource.json object,\n * preserving whichever column shape (id-keyed map or array) the file already\n * uses, and leaving every other top-level key and every untouched column\n * field byte-stable. Only patches columns that already exist — the visual\n * builder's MVP does not add or remove columns (see optional phases in\n * `VISUAL_RESOURCE_BUILDER_PLAN.md`).\n */\nexport const applyColumnPatch = (\n raw: RawResourceJson,\n patch: PatchResourceJson,\n): RawResourceJson => {\n const columns = raw['columns'];\n\n if (Array.isArray(columns)) {\n const updated = columns.map((col: Record<string, unknown>) => {\n const columnPatch = patch.columns[col['id'] as string];\n return columnPatch ? mergeColumn(col, columnPatch) : col;\n });\n return { ...raw, columns: updated };\n }\n\n if (columns && typeof columns === 'object') {\n const updated: Record<string, unknown> = { ...columns };\n for (const [id, columnPatch] of Object.entries(patch.columns)) {\n if (!(id in updated)) continue;\n updated[id] = mergeColumn(\n updated[id] as Record<string, unknown>,\n columnPatch,\n );\n }\n return { ...raw, columns: updated };\n }\n\n return raw;\n};\n\n/**\n * Mirrors `@ghentcdh/crouton-codegen`'s `serializeResourceJson` (2-space JSON,\n * trailing newline, relies on object key insertion order for minimal diffs).\n * Kept inline here rather than adding crouton-api's first runtime dependency\n * on crouton-codegen (which brings in `@prisma/internals`) for a one-line\n * formatter — see the \"reuse\" note in `VISUAL_RESOURCE_BUILDER_PLAN.md`.\n */\nexport const serializeResourceJson = (config: unknown): string =>\n `${JSON.stringify(config, null, 2)}\\n`;\n\n/** Validates a merged raw resource.json before it's written to disk. */\nexport const validateResourceJson = (raw: unknown) =>\n buildResourceJsonSchema().safeParse(raw);\n\nexport const writeRawResourceJson = (\n jsonPath: string,\n raw: RawResourceJson,\n): void => {\n writeFileSync(jsonPath, serializeResourceJson(raw), 'utf-8');\n};\n","import {\n type FieldInput,\n type JsonColumn,\n buildSubResourceOperations,\n getResourceExtensions,\n resolveTableField,\n resolveViewField,\n} from '@ghentcdh/crouton-core';\n\nimport { type ResourceRowAction } from '../action';\nimport {\n externalRouteFor,\n isOperationEnabled,\n isOperationExternal,\n resolveDefinition,\n schemaFor,\n} from '../crud.config';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { toJsonSchema } from '../schema.utils';\n\n// ── Internal helpers ──────────────────────────────────────────────────────\n\nconst pickExtensions = (config: Resource) =>\n Object.fromEntries([...getResourceExtensions().keys()].filter(k => (config as Record<string, unknown>)[k] !== undefined).map(k => [k, (config as Record<string, unknown>)[k]]));\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\nconst RESOURCE_OPS = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\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: 'put',\n patch: 'patch',\n delete: 'delete',\n};\nconst OP_SUFFIX: Record<ResourceOp, string> = {\n findAll: '',\n findOne: '/{id}',\n create: '',\n update: '/{id}',\n patch: '/{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((op) => {\n const extUri = externalRouteFor(definition, op);\n const uri = extUri ? resolveEnvPlaceholders(extUri) : `${baseUri}${OP_SUFFIX[op]}`;\n const entry = definition[op];\n const method =\n (extUri && typeof entry === 'object' && entry !== null && 'method' in entry\n ? (entry as { method?: string }).method\n : undefined) ?? OP_METHOD[op];\n return [op, { uri, method }];\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: Resource,\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 patchSchema = schemaFor(definition, 'patch');\n const operations = (\n [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n ] as const\n ).filter((op) => isOperationEnabled(definition, op));\n\n return {\n name,\n route,\n idType,\n tag,\n operations,\n display: config.display,\n schemas: {\n ...(listSchema && { findAll: toJsonSchema(listSchema) }),\n ...(oneSchema && { findOne: toJsonSchema(oneSchema) }),\n ...(createSchema && { create: toJsonSchema(createSchema) }),\n ...(updateSchema && { update: toJsonSchema(updateSchema) }),\n ...(patchSchema && { patch: toJsonSchema(patchSchema) }),\n },\n ...pickExtensions(config),\n };\n};\n\n/** Build the payload for `GET /resource.json` — URI, enabled operations, and optional form schema. */\nexport const buildResourceJsonPayload = (\n config: Resource,\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 if (!isOperationExternal(definition, 'findAll')) {\n operations.lookup = `${uri}?q={text}`;\n }\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 {\n id: config.id ?? route,\n uri,\n operations,\n schema,\n ...pickExtensions(config),\n };\n};\n\nconst _resolveActions = (\n baseUrl: string[],\n actions: ResourceRowAction[] | undefined,\n) => {\n if (!actions?.length) return [];\n const resolved = actions.map((a) =>\n a.type === 'link'\n ? {\n ...a,\n href: resolveEnvPlaceholders(a.href),\n }\n : {\n ...a,\n uri: baseUrl.map((b) => (b === '{actionId}' ? a.id : b)).join('/'),\n method: a.method ?? 'post',\n },\n );\n return resolved;\n};\n\nexport const resolveActions = (\n baseUrl: string,\n actions: ResourceRowAction[] | undefined,\n) => {\n return _resolveActions([baseUrl, 'procedure', '{actionId}', '{id}'], actions);\n};\n\nexport const resolveTableActions = (\n baseUrl: string,\n actions: ResourceRowAction[] | undefined,\n) => {\n return _resolveActions([baseUrl, 'table-action', '{actionId}'], actions);\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: Resource,\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 // A nested resource is served under its parent, so its URIs carry the parent\n // id as a `{param}` placeholder — the same substitution the frontend already\n // performs for sub-resource URIs via replaceUriParams.\n const baseUri = config.parent\n ? `${baseUrl}/${config.parent.route}/{${config.parent.param}}/${config.route}`\n : `${baseUrl}/${config.route}`;\n const operations: Record<string, unknown> = buildResourceOperations(\n definition,\n baseUri,\n );\n if (isOperationEnabled(definition, 'findAll') && !isOperationExternal(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 const baseAction = `${baseUri}${config.route}`;\n return {\n id: config.id ?? config.route,\n name: config.name,\n route: config.route,\n uri: baseUri,\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 actions: resolveActions(baseAction, config.actions),\n tableActions: resolveActions(baseAction, config.tableActions),\n ...pickExtensions(config),\n };\n};\n\n/**\n * Build the payload for a sub-resource's `GET /<child>/schemas` endpoint.\n * Returns `undefined` when the sub-resource has no views configured.\n */\nexport const buildSubResourceViewsPayload = (\n config: Resource,\n sub: SubResourceConfig,\n baseUrl?: string,\n): Record<string, unknown> | undefined => {\n if (!sub.views) return undefined;\n const { route } = config;\n const childUri = `${baseUrl}/${route}/{parent.id}/${sub.childRoute}`;\n\n return {\n id: `${route}/${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 ...(sub.display && { display: sub.display }),\n operations: buildSubResourceOperations(\n sub.operations,\n childUri,\n sub.idField ?? 'id',\n ),\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 actions: resolveActions(`${baseUrl}/${sub.childRoute}`, sub.actions),\n };\n};\n\n/**\n * A rendering-context's field config as exposed to the visual builder: the\n * resolved value (walking the `fieldInput → fieldView → fieldTable` fallback\n * chain, via crouton-core's `resolveViewField`/`resolveTableField` — so the\n * editor shows what will actually render) plus whether this column has its\n * own override at this level. `hasOverride: false` means the value shown is\n * pure inheritance from the level below; saving with no changes here should\n * leave it that way rather than pinning a copy into `fieldView`/`fieldTable`.\n */\nexport type EditableFieldVariant = {\n resolved: FieldInput | undefined;\n hasOverride: boolean;\n};\n\nexport type EditableColumn = {\n id: string;\n label?: string;\n column: string;\n hiddenInTable: boolean;\n hiddenInForm: boolean;\n hiddenInView: boolean;\n /** The base level — always \"owned\" by this column, no fallback/override distinction. */\n form: FieldInput | undefined;\n view: EditableFieldVariant;\n table: EditableFieldVariant;\n};\n\n/**\n * Build the payload for `GET /resource-columns` — the raw, editable column\n * list backing the visual resource builder (dev-mode only). Unlike\n * `buildResourceJsonPayload`/`buildViewsPayload`, which expose columns only\n * as compiled JSON Schema + JSONForms UI Schema, this returns the plain\n * per-column attributes the editor lets a developer change directly, split\n * per rendering context (form/view/table) so the editor can offer a tab per\n * context instead of one flat fieldInput-only row.\n *\n * `config.columns` is typed as the pre-normalization map form on `Resource`\n * (inherited from `ResourceJsonShape`), but at runtime it always holds the\n * post-`ResourceJsonSchema`-transform array form (`JsonColumn[]`) — the same\n * assumption other adapter code in this package already relies on.\n */\nexport const buildEditableColumnsPayload = (\n config: Resource,\n): {\n id: string;\n route: string;\n columns: EditableColumn[];\n} => {\n const columns = (config.columns as unknown as JsonColumn[] | undefined) ?? [];\n\n return {\n id: config.name,\n route: config.route,\n columns: columns.map((c) => ({\n id: c.id,\n label: c.label,\n column: c.column ?? c.id,\n hiddenInTable: c.hiddenInTable,\n hiddenInForm: c.hiddenInForm,\n hiddenInView: c.hiddenInView,\n form: c.fieldInput,\n view: { resolved: resolveViewField(c), hasOverride: c.fieldView != null },\n table: {\n resolved: resolveTableField(c),\n hasOverride: c.fieldTable != null,\n },\n })),\n };\n};\n","import { Get, SetMetadata } from '@nestjs/common';\nimport { ApiOperation, ApiResponse } from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport {\n buildSubResourceViewsPayload,\n buildViewsPayload,\n} from './payload-builders';\nimport { IS_DEV } from '../dev-mode';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport type { ResourceConfigRegistry } from '../resource-config.registry';\nimport { CROUTON_SECURITY } from '../security';\nimport { getRequestLanguage } from '../translation/language.context';\n\nexport const defaultSchemas = (ctx: OperationContext) => {\n const { config, baseUrl, schemaEnricher } = ctx;\n const { route, name } = config;\n const viewsPayload = buildViewsPayload(config, baseUrl);\n\n return {\n route: 'schemas',\n methodName: 'getSchemas',\n name,\n schemasFn: async function (this: {\n configRegistry: ResourceConfigRegistry;\n }) {\n const language = getRequestLanguage();\n let payload = viewsPayload;\n if (IS_DEV || language) {\n const fresh = await this.configRegistry.getByRoute(route, language);\n if (fresh) payload = buildViewsPayload(fresh, baseUrl) ?? viewsPayload;\n }\n if (!payload || !schemaEnricher) return payload;\n return { ...payload, ...schemaEnricher(payload) };\n },\n decorators: () => {\n //\n },\n };\n};\n\nconst childSchemas = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!sub.views) return null;\n const { config, baseUrl } = ctx;\n const { route } = config;\n const schemasPayload = buildSubResourceViewsPayload(config, sub, baseUrl);\n\n return {\n route: `${sub.childRoute}/schemas`,\n methodName: `getSchemas_${sub.childRoute}`,\n name: sub.childRoute,\n schemasFn: async function (this: {\n configRegistry: ResourceConfigRegistry;\n }) {\n const language = getRequestLanguage();\n if (IS_DEV || language) {\n const localizedParent = await this.configRegistry.getByRoute(route, language);\n if (localizedParent) {\n const localizedSub = (localizedParent.subResources ?? []).find(\n (s) => s.childRoute === sub.childRoute,\n );\n if (localizedSub) {\n return buildSubResourceViewsPayload(localizedParent, localizedSub, baseUrl) ?? schemasPayload;\n }\n }\n }\n return schemasPayload;\n },\n decorators: () => {\n //\n },\n };\n};\n\n/** Register `GET /schemas`. */\nexport const registerSchemas = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childSchemas(sub) : defaultSchemas;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.schemasFn);\n const d = desc(cls, methodName);\n Get(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Get view schemas for ${name}` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiResponse({ status: 200, description: `View schemas for ${name}` })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n\n // Schema endpoints follow resource-level global security.\n const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;\n if (sec) {\n SetMetadata(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);\n }\n};\n","import { Body, Param, Put, Req } from '@nestjs/common';\nimport {\n ApiNotFoundResponse,\n ApiOperation,\n ApiResponse,\n} from '@nestjs/swagger';\n\nimport { def, desc } from './decorator.utils';\nimport type { OperationContext } from './operation-context';\nimport type { CrudRepository } from '../crud-repository.factory';\nimport { isOperationEnabled, isOperationExternal } from '../crud.config';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nconst defaultUpdate = (ctx: OperationContext) => {\n if (!isOperationEnabled(ctx.definition, 'update')) return null;\n if (isOperationExternal(ctx.definition, 'update')) return null;\n const { cls, config, updateSchema, bodyDecorator } = ctx;\n const methodName = 'update';\n\n return {\n route: ':id',\n methodName,\n name: config.name,\n updateFn: function (\n this: { repo: CrudRepository },\n id: string,\n body: any,\n req: any,\n ) {\n return this.repo.update(id, body, req);\n },\n decorators: () => {\n Param('id')(cls.prototype, methodName, 0);\n bodyDecorator(updateSchema)(cls.prototype, methodName, 1);\n Req()(cls.prototype, methodName, 2);\n },\n };\n};\n\nconst childUpdate = (sub: SubResourceConfig) => (ctx: OperationContext) => {\n if (!isOperationEnabled(sub.operations, 'update')) return null;\n const { cls } = ctx;\n const methodName = `updateChild_${sub.childRoute}`;\n\n const updateFn = async function (\n this: { repo: CrudRepository },\n _id: string,\n childId: string,\n body: any,\n req: any,\n ) {\n return this.repo.updateChild(sub, childId, body, req);\n };\n\n const decorators = () => {\n Param('id')(cls.prototype, methodName, 0);\n Param('childId')(cls.prototype, methodName, 1);\n Body()(cls.prototype, methodName, 2);\n Req()(cls.prototype, methodName, 3);\n };\n\n return {\n route: `:id/${sub.childRoute}/:childId`,\n methodName,\n name: sub.childRoute,\n updateFn,\n decorators,\n };\n};\n\n/** Register `PUT /:id`. No-ops when `update` is disabled. */\nexport const registerUpdate = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n const operationFn = sub ? childUpdate(sub) : defaultUpdate;\n const properties = operationFn(ctx);\n if (!properties) return;\n\n const { methodName, route, name } = properties;\n const { cls } = ctx;\n\n def(cls, methodName, properties.updateFn);\n const d = desc(cls, methodName);\n Put(route)(cls.prototype, methodName, d);\n ApiOperation({ summary: `Replace a ${name}` })(cls.prototype, methodName, d);\n ApiResponse({ status: 200, description: `${name} replaced` })(\n cls.prototype,\n methodName,\n d,\n );\n ApiNotFoundResponse({ description: 'Not found' })(\n cls.prototype,\n methodName,\n d,\n );\n\n properties.decorators();\n ctx.secure(methodName, 'update', sub);\n};\n","import { type OperationContext } from './operation-context';\nimport {\n registerActionRoutes,\n registerTableActionRoutes,\n} from './register-actions';\nimport { registerCreate } from './register-create';\nimport { registerDelete } from './register-delete';\nimport { registerFindAll } from './register-findall';\nimport { registerFindOne } from './register-findone';\nimport { registerPatch } from './register-patch';\nimport {\n registerDefinitionEndpoint,\n registerResourceColumnsEndpoint,\n registerResourceJsonEndpoint,\n registerResourceJsonPatchEndpoint,\n registerResourceJsonRawGetEndpoint,\n registerResourceJsonRawPutEndpoint,\n} from './register-schema-endpoints';\nimport { registerSchemas } from './register-schemas';\nimport { registerUpdate } from './register-update';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\n\nexport const registerEndpoints = (ctx: OperationContext): void => {\n // ── Register operations (order matters: static routes before :id routes) ──\n //first register subresource routes\n registerSubResourceRoutes(ctx);\n //register other routes\n registerFindAll(ctx);\n\n registerResourceJsonRawGetEndpoint(ctx);\n registerResourceJsonRawPutEndpoint(ctx);\n registerResourceJsonPatchEndpoint(ctx);\n registerResourceJsonEndpoint(ctx);\n registerResourceColumnsEndpoint(ctx);\n\n registerDefinitionEndpoint(ctx);\n registerEndpoint(ctx);\n\n registerActionRoutes(ctx);\n registerTableActionRoutes(ctx);\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 registerEndpoint(ctx, sub);\n }\n};\n\nexport const registerEndpoint = (\n ctx: OperationContext,\n sub?: SubResourceConfig,\n): void => {\n registerSchemas(ctx, sub);\n registerFindAll(ctx, sub);\n registerFindOne(ctx, sub);\n registerCreate(ctx, sub);\n registerUpdate(ctx, sub);\n registerPatch(ctx, sub);\n registerDelete(ctx, sub);\n};\n","import {\n BadRequestException,\n Body,\n Controller,\n ForbiddenException,\n Get,\n NotFoundException,\n Param,\n Patch,\n Post,\n} from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport {\n type ApplyContext,\n type DbModel,\n type LoadedConfig,\n apply as applyDiff,\n buildResourceDiff,\n buildResourceDiffs,\n commit,\n introspect,\n isGitDirty,\n listResourceNames,\n loadConfig,\n loadDatasources,\n makeRelationResolver,\n makeSchemaExportName,\n pullAndGenerate,\n readExistingResource,\n recommendedResolver,\n resolve as resolveDiff,\n resolveDatasource,\n resolveFromRoot,\n resolveRuleset,\n} from '@ghentcdh/crouton-codegen';\nimport { type DataSource } from '@ghentcdh/crouton-core';\n\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { DataSourceRegistry } from '../data-source';\nimport { IS_DEV } from '../dev-mode';\nimport {\n type ResourceFlagPatch,\n applyResourceFlagPatch,\n resolveResourcePath,\n} from '../resource/ResourceFlags';\nimport {\n readRawResourceJson,\n validateResourceJson,\n writeRawResourceJson,\n} from '../resource/WriteResourceJson';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\n// eslint-disable-next-line @typescript-eslint/consistent-type-imports\nimport { ResourceConfigRegistry } from '../resource-config.registry';\n\n/**\n * Dev-only endpoints that reuse the `@ghentcdh/crouton-codegen` engine\n * (already built for the `crouton update resources` CLI command) directly\n * from a running backend request, so the visual resource builder can\n * generate a resource.json for a new DB table, or preview/apply a full\n * database sync, without shelling out to the CLI.\n *\n * Hard-gated to `IS_DEV` (`CROUTON_SCHEMA_EDITOR` env var) both at the\n * controller-registration level (see `crouton-api.module.ts`) and again on\n * every handler here, mirroring the pattern used by the schema editor's\n * PATCH/GET endpoints in `register-schema-endpoints.ts`.\n *\n * `pull` and `restart` (below) are the two handlers that go beyond reading\n * files: `pull` touches the live database and the Prisma schema file (needs\n * real DB credentials, mutates `schema.prisma` in place, backed up first,\n * mirroring the CLI); `restart` exits this very process. Every other handler\n * here only reads the Prisma client/Zod types already generated on disk.\n *\n * Note that `pull` regenerating the Prisma client on disk does not affect\n * *this* running process — `DataSourceRegistry` holds a client instance\n * built once at boot, so brand-new models exist in `schema.prisma` (and thus\n * in `GET models`) before they're actually usable here. See\n * `isAvailableOnClient` below; the backend needs an actual restart before a\n * newly pulled model can be generated/synced without throwing.\n */\n@Controller('_app/resources')\n@ApiTags('Dev tools')\nexport class DevResourcesController {\n constructor(\n private readonly dataSourceRegistry: DataSourceRegistry,\n private readonly resourceConfigRegistry: ResourceConfigRegistry,\n ) {}\n\n private assertDev(): void {\n if (!IS_DEV) {\n throw new ForbiddenException(\n 'The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.',\n );\n }\n }\n\n /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */\n private async loadProject(\n datasourceName?: string,\n ): Promise<{ loaded: LoadedConfig; ds: DataSource; schemaPath: string }> {\n let loaded: LoadedConfig;\n try {\n loaded = await loadConfig(process.cwd());\n } catch (e) {\n throw new NotFoundException(\n (e as Error).message ?? 'No crouton.json config found.',\n );\n }\n\n const datasources = await loadDatasources(loaded);\n let ds: DataSource;\n try {\n ds = resolveDatasource(datasources, datasourceName);\n } catch (e) {\n throw new BadRequestException((e as Error).message);\n }\n\n const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);\n return { loaded, ds, schemaPath };\n }\n\n private async introspectModels(schemaPath: string): Promise<DbModel[]> {\n try {\n return await introspect({ schemaPath });\n } catch (e) {\n throw new BadRequestException(\n `Failed to read Prisma schema at ${schemaPath}: ${(e as Error).message}`,\n );\n }\n }\n\n private buildApplyContext(\n loaded: LoadedConfig,\n ds: DataSource,\n ): ApplyContext {\n return {\n resourcesDir: resolveFromRoot(loaded.root, loaded.config.resourcesDir),\n generatedTypesImport: ds.generatedTypesImport,\n schemaExportName: makeSchemaExportName(loaded.config),\n };\n }\n\n /**\n * True when `clientAccessor` exists on the *currently running* Prisma\n * client for this datasource. `DataSourceRegistry` holds a client instance\n * built once at process boot (see `data-source.registry.ts`); `prisma\n * generate` rewrites the generated client code on disk, but can't change\n * the shape of an already-instantiated object in a running Node process.\n * A model added by `pull` therefore exists in `schema.prisma` (and shows up\n * here via `introspect`, which reads that file directly) before it exists\n * on this live client — using it before a restart throws \"Model ... not\n * found on the provided PrismaClient\" from `createCrudRepository`.\n */\n private isAvailableOnClient(ds: DataSource, clientAccessor: string): boolean {\n try {\n const client = this.dataSourceRegistry.resolve(ds.name);\n return typeof client?.[clientAccessor] !== 'undefined';\n } catch {\n return false;\n }\n }\n\n @Get('models')\n @ApiOperation({\n summary:\n 'Dev-only: list DB models from the Prisma schema, flagging which already have a resource.json and whether the running backend can actually use them yet',\n })\n @ApiResponse({\n status: 200,\n description: 'DB models and their resource/client status',\n })\n async listModels(): Promise<{\n models: {\n prismaName: string;\n clientAccessor: string;\n hasResource: boolean;\n availableOnClient: boolean;\n }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject();\n const models = await this.introspectModels(schemaPath);\n const existing = new Set(await listResourceNames(loaded));\n\n return {\n models: models.map((m) => ({\n prismaName: m.prismaName,\n clientAccessor: m.clientAccessor,\n hasResource: existing.has(m.clientAccessor),\n availableOnClient: this.isAvailableOnClient(ds, m.clientAccessor),\n })),\n };\n }\n\n @Post('restart')\n @ApiOperation({\n summary:\n 'Dev-only: exit this process so a dev watcher/process manager (nodemon, `nest start --watch`, pm2, a Docker restart policy, ...) restarts it with a fresh Prisma client. Does nothing useful if this process isn\\'t supervised by one of those.',\n })\n @ApiResponse({\n status: 200,\n description: 'Restart scheduled — the connection will drop shortly after',\n })\n restart(): { restarting: true } {\n this.assertDev();\n // Give Nest/Express time to flush this response over the socket before\n // the process disappears — the frontend needs to see `{ restarting:\n // true }` to know the exit was intentional, not a crash mid-request.\n // A non-zero exit code is used deliberately: pm2, Docker restart\n // policies, and most \"restart on crash\" nodemon configs treat that as\n // \"needs a restart\" more reliably than a clean (0) exit, which several\n // tools instead read as \"stopped on purpose, leave it stopped\".\n setTimeout(() => {\n this.dataSourceRegistry\n .disconnectAll()\n .catch(() => undefined)\n .finally(() => process.exit(1));\n }, 250);\n return { restarting: true };\n }\n\n @Post('pull')\n @ApiOperation({\n summary:\n 'Dev-only: run `prisma db pull` + case-format + `prisma generate` for a datasource, refreshing schema.prisma and the generated Prisma client/Zod types from the live database',\n })\n @ApiResponse({\n status: 200,\n description:\n 'Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes',\n })\n async pull(\n @Body() body: { datasource?: string; confirm?: boolean } = {},\n ): Promise<{\n requiresConfirmation?: boolean;\n dirtyFile?: string;\n ok?: boolean;\n /**\n * Always true on success: this process's Prisma client was built at boot\n * and can't pick up model changes from a fresh `prisma generate` without\n * restarting — see `isAvailableOnClient` above.\n */\n restartRequired?: boolean;\n backupPath?: string;\n dbPull?: { ok: boolean; output: string };\n caseFormat?: { ok: boolean; output: string };\n normalizeSchema?: { ok: boolean; renamed: number };\n generate?: { ok: boolean; output: string };\n zodImportsFixed?: number;\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const prismaConfigPath = resolveFromRoot(loaded.root, ds.prismaConfig);\n\n // `db pull` overwrites schema.prisma — same uncommitted-changes guard the\n // CLI shows as an interactive confirm, surfaced here as a flag so the\n // frontend can show its own confirmation before retrying with confirm: true.\n if (!body.confirm && (await isGitDirty(loaded.root, schemaPath))) {\n return { requiresConfirmation: true, dirtyFile: ds.prismaSchema };\n }\n\n const zodDir = ds.zodOutput ? resolveFromRoot(loaded.root, ds.zodOutput) : undefined;\n const result = await pullAndGenerate({\n root: loaded.root,\n prismaConfigPath,\n schemaPath,\n zodOutputDir: zodDir,\n });\n\n if (!result.ok) {\n throw new BadRequestException(`prisma db pull failed:\\n${result.dbPull.output}`);\n }\n\n return {\n ok: true,\n restartRequired: true,\n backupPath: result.backupPath,\n dbPull: result.dbPull,\n caseFormat: result.caseFormat,\n normalizeSchema: result.normalizeSchema,\n generate: result.generate,\n zodImportsFixed: result.zodImportsFixed,\n };\n }\n\n @Post('sync')\n @ApiOperation({\n summary:\n 'Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)',\n })\n @ApiResponse({ status: 200, description: 'Files written for this resource' })\n async sync(@Body() body: { model: string; datasource?: string }): Promise<{\n resource: string;\n isNew: boolean;\n written: string[];\n skipped: string[];\n }> {\n this.assertDev();\n if (!body?.model) {\n throw new BadRequestException('\"model\" is required.');\n }\n\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const models = await this.introspectModels(schemaPath);\n const model = models.find(\n (m) => m.prismaName === body.model || m.clientAccessor === body.model,\n );\n if (!model) {\n throw new NotFoundException(\n `Model \"${body.model}\" not found in ${schemaPath}.`,\n );\n }\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diff = await buildResourceDiff(model, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const resolved = await resolveDiff(diff, recommendedResolver);\n const plan = applyDiff(resolved, this.buildApplyContext(loaded, ds));\n const result = await commit(plan);\n\n return { resource: diff.name, isNew: diff.isNew, ...result };\n }\n\n @Post('plan')\n @ApiOperation({\n summary:\n 'Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults — computes what would change, writes nothing',\n })\n @ApiResponse({ status: 200, description: 'Proposed per-resource changes' })\n async plan(\n @Body() body: { models?: string[]; datasource?: string } = {},\n ): Promise<{\n resources: {\n resource: string;\n model: string;\n isNew: boolean;\n decisions: unknown[];\n files: { path: string; action: string }[];\n notes: string[];\n }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const allModels = await this.introspectModels(schemaPath);\n const models = body.models?.length\n ? allModels.filter(\n (m) =>\n body.models!.includes(m.prismaName) ||\n body.models!.includes(m.clientAccessor),\n )\n : allModels;\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diffs = await buildResourceDiffs(models, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const applyCtx = this.buildApplyContext(loaded, ds);\n\n const resources: {\n resource: string;\n model: string;\n isNew: boolean;\n decisions: unknown[];\n files: { path: string; action: string }[];\n notes: string[];\n }[] = [];\n\n for (const diff of diffs) {\n const resolved = await resolveDiff(diff, recommendedResolver);\n const writePlan = applyDiff(resolved, applyCtx);\n // No-op diffs (nothing to write, nothing to warn about) are omitted —\n // re-running against an unchanged DB schema should show an empty list.\n if (writePlan.files.length === 0 && writePlan.notes.length === 0)\n continue;\n\n resources.push({\n resource: diff.name,\n model: diff.model,\n isNew: diff.isNew,\n decisions: diff.decisions,\n files: writePlan.files.map((f) => ({ path: f.path, action: f.action })),\n notes: writePlan.notes,\n });\n }\n\n return { resources };\n }\n\n @Post('apply')\n @ApiOperation({\n summary:\n 'Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults',\n })\n @ApiResponse({ status: 200, description: 'Per-resource commit results' })\n async apply(\n @Body() body: { resources?: string[]; datasource?: string } = {},\n ): Promise<{\n results: { resource: string; written: string[]; skipped: string[] }[];\n }> {\n this.assertDev();\n const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);\n const allModels = await this.introspectModels(schemaPath);\n // `resources` filters by resource/directory name (== clientAccessor for\n // new resources) — matches what /plan returns as `resource`.\n const models = body.resources?.length\n ? allModels.filter((m) => body.resources!.includes(m.clientAccessor))\n : allModels;\n\n const resolveRelationResource = await makeRelationResolver(loaded);\n const diffs = await buildResourceDiffs(models, {\n database: ds.name,\n ruleset: resolveRuleset(loaded.config),\n resolveRelationResource,\n readExisting: (name) => readExistingResource(loaded, name),\n });\n const applyCtx = this.buildApplyContext(loaded, ds);\n\n const results: {\n resource: string;\n written: string[];\n skipped: string[];\n }[] = [];\n for (const diff of diffs) {\n const resolved = await resolveDiff(diff, recommendedResolver);\n const writePlan = applyDiff(resolved, applyCtx);\n if (writePlan.files.length === 0) continue;\n const result = await commit(writePlan);\n results.push({ resource: diff.name, ...result });\n }\n\n return { results };\n }\n\n // ─── Visibility & flag endpoints ────────────────────────────────────\n\n @Get('visibility')\n @ApiOperation({\n summary:\n 'Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)',\n })\n @ApiResponse({ status: 200, description: 'Resource visibility list' })\n async visibility(): Promise<{\n resources: {\n name: string;\n path: string;\n state: 'in-menu' | 'hidden' | 'draft' | 'error';\n group?: string;\n position?: number;\n editable: boolean;\n }[];\n }> {\n this.assertDev();\n\n const loaded = await this.resourceConfigRegistry.getAll();\n const fromLoaded = loaded.map((c) => ({\n name: c.name,\n path: c.route,\n state: (c.sidebar?.hide ? 'hidden' : 'in-menu') as\n | 'in-menu'\n | 'hidden',\n group: c.sidebar?.group,\n position: c.sidebar?.position,\n editable: true,\n }));\n\n const drafts = resourceLoadReportRegistry.getByState('draft').map((d) => ({\n name: d.name,\n path: d.path,\n state: 'draft' as const,\n group: undefined,\n position: undefined,\n editable: !d.path.endsWith('.ts'),\n }));\n\n const errors = resourceLoadErrorsRegistry.getAll().map((e) => ({\n name: e.name,\n path: e.path,\n state: 'error' as const,\n group: undefined,\n position: undefined,\n editable: !e.path.endsWith('.ts'),\n }));\n\n return { resources: [...fromLoaded, ...drafts, ...errors] };\n }\n\n @Post(':name/publish')\n @ApiOperation({\n summary:\n 'Dev-only: publish a draft resource (removes `draft: true` from resource.json)',\n })\n @ApiResponse({ status: 200, description: 'Resource published' })\n async publish(@Param('name') name: string): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, { draft: false });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Post(':name/remove-from-menu')\n @ApiOperation({\n summary:\n 'Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)',\n })\n @ApiResponse({ status: 200, description: 'Resource removed from menu' })\n async removeFromMenu(@Param('name') name: string): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, {\n sidebar: { hide: true },\n });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Post(':name/add-to-menu')\n @ApiOperation({\n summary:\n 'Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label',\n })\n @ApiResponse({ status: 200, description: 'Resource added to menu' })\n async addToMenu(\n @Param('name') name: string,\n @Body() body: { group?: string; position?: number; label?: string } = {},\n ): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const sidebarPatch: ResourceFlagPatch['sidebar'] = { hide: false };\n if (body.group !== undefined) sidebarPatch!.group = body.group;\n if (body.position !== undefined) sidebarPatch!.position = body.position;\n if (body.label !== undefined) sidebarPatch!.label = body.label;\n\n const patched = applyResourceFlagPatch(raw, {\n draft: false,\n sidebar: sidebarPatch,\n });\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n\n @Patch(':name/flags')\n @ApiOperation({\n summary:\n 'Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)',\n })\n @ApiResponse({ status: 200, description: 'Flags updated' })\n async updateFlags(\n @Param('name') name: string,\n @Body() body: ResourceFlagPatch,\n ): Promise<{ ok: true }> {\n this.assertDev();\n const { loaded } = await this.loadProject();\n const resourcesDir = resolveFromRoot(\n loaded.root,\n loaded.config.resourcesDir,\n );\n const jsonPath = resolveResourcePath(resourcesDir, name);\n\n const raw = readRawResourceJson(jsonPath);\n if (!raw) throw new NotFoundException(`Resource \"${name}\" not found.`);\n if (jsonPath.endsWith('.ts'))\n throw new ForbiddenException('TypeScript resources cannot be edited.');\n\n const patched = applyResourceFlagPatch(raw, body);\n const result = validateResourceJson(patched);\n if (!result.success) {\n throw new BadRequestException(\n `Validation failed: ${result.error.message}`,\n );\n }\n writeRawResourceJson(jsonPath, patched);\n return { ok: true };\n }\n}\n","import { labelFromId } from '@ghentcdh/crouton-core';\n\nexport { labelFromId };\n\n/**\n * PrismaClient accessor for a model name.\n * `Language` → `language`, `InternalAuthor` → `internalAuthor`,\n * `metadata_config` → `metadata_config` (first char already lower-case).\n */\nexport const clientAccessor = (prismaModelName: string): string => {\n if (!prismaModelName) return prismaModelName;\n return prismaModelName.charAt(0).toLowerCase() + prismaModelName.slice(1);\n};\n\nexport interface ResourceNames {\n /** Directory + route + resource `name`. */\n name: string;\n route: string;\n /** resource.json `model` (PrismaClient accessor). */\n model: string;\n tag: string;\n title: string;\n}\n\n/**\n * Derive the resource identity fields from a Prisma model name.\n * Mirrors the `new_polities` convention: `name`/`route`/`model` are the client\n * accessor; `tag` is the Prisma model name; `title` is a humanized label.\n */\nexport const resourceNames = (prismaModelName: string): ResourceNames => {\n const accessor = clientAccessor(prismaModelName);\n return {\n name: accessor,\n route: accessor,\n model: accessor,\n tag: prismaModelName,\n title: labelFromId(accessor),\n };\n};\n\nconst TIMESTAMP_NAME =\n /^(created|updated|inserted|modified|deleted)_?at$|^(created|updated)$/i;\n\n/** Heuristic: is this field a created/updated style timestamp? */\nexport const isTimestampField = (opts: {\n name: string;\n type: string;\n isUpdatedAt: boolean;\n}): boolean => {\n if (opts.type !== 'DateTime') return false;\n if (opts.isUpdatedAt) return true;\n return TIMESTAMP_NAME.test(opts.name);\n};\n\n/** Map a Prisma scalar/enum type to a `fieldInput.type` control hint. */\nexport const fieldInputType = (prismaType: string, isEnum: boolean): string => {\n if (isEnum) return 'select';\n switch (prismaType) {\n case 'Boolean':\n return 'boolean';\n case 'Int':\n case 'BigInt':\n case 'Float':\n case 'Decimal':\n return 'number';\n case 'DateTime':\n return 'date';\n case 'Json':\n return 'json';\n case 'String':\n default:\n return 'string';\n }\n};\n\n/**\n * Control type for a scalar column, taking the field name into account.\n * `description`-style string fields default to a `textarea`.\n */\nexport const scalarFieldInputType = (\n name: string,\n prismaType: string,\n): string => {\n if (prismaType === 'String' && /description/i.test(name)) return 'textarea';\n return fieldInputType(prismaType, false);\n};\n\n/** Infer the resource `idType` from the primary-key Prisma type. */\nexport const idTypeFor = (\n prismaType: string | undefined,\n): 'string' | 'number' => {\n if (prismaType === 'Int' || prismaType === 'BigInt') return 'number';\n return 'string';\n};\n","/**\n * introspect: Prisma schema → normalized `DbModel[]`.\n *\n * The pure normalizer `dmmfToDbModels` is separated from the Prisma call so it\n * can be unit-tested with a hand-built DMMF and so a Prisma version bump only\n * touches `loadDmmf`.\n */\n\nimport type { RelationType } from '@ghentcdh/crouton-core';\n\nimport type { DbField, DbFieldKind, DbModel } from './db-model';\nimport { idTypeFor, isTimestampField } from './naming';\n\n// ─── Minimal DMMF shapes (only what we consume) ──────────────────────────────\n\nexport interface DmmfField {\n name: string;\n kind: 'scalar' | 'object' | 'enum' | 'unsupported';\n type: string;\n isList: boolean;\n isRequired: boolean;\n isId: boolean;\n isUnique: boolean;\n isUpdatedAt: boolean;\n hasDefaultValue: boolean;\n /**\n * Raw Prisma DMMF default: a literal (string/number/boolean/array) for\n * `@default(\"x\")` / `@default(0)` / `@default(true)` / `@default([...])`,\n * or a `{ name, args }` descriptor for a function call like `autoincrement()`,\n * `now()`, `uuid()`, `cuid()`, or `dbgenerated(...)`. Only present when\n * `hasDefaultValue` is true.\n */\n default?: unknown;\n relationName?: string;\n relationFromFields?: string[];\n relationToFields?: string[];\n}\n\nexport interface DmmfModel {\n name: string;\n dbName?: string | null;\n primaryKey?: { name?: string | null; fields: string[] } | null;\n fields: DmmfField[];\n}\n\nexport interface DmmfEnum {\n name: string;\n values: { name: string }[];\n}\n\nexport interface DmmfDatamodel {\n models: DmmfModel[];\n enums: DmmfEnum[];\n}\n\nexport interface Dmmf {\n datamodel: DmmfDatamodel;\n}\n\n// ─── relation cardinality ────────────────────────────────────────────────────\n\ninterface RelationSide {\n model: string;\n isList: boolean;\n}\n\n/** Index relation fields by `relationName` so each side can see its counterpart. */\nconst indexRelations = (models: DmmfModel[]): Map<string, RelationSide[]> => {\n const index = new Map<string, RelationSide[]>();\n for (const model of models) {\n for (const field of model.fields) {\n if (field.kind !== 'object' || !field.relationName) continue;\n const list = index.get(field.relationName) ?? [];\n list.push({ model: model.name, isList: field.isList });\n index.set(field.relationName, list);\n }\n }\n return index;\n};\n\nconst resolveRelationType = (\n field: DmmfField,\n index: Map<string, RelationSide[]>,\n): RelationType => {\n const sides = field.relationName ? index.get(field.relationName) ?? [] : [];\n // Counterpart = the side declared on the related model (`field.type`).\n // (For self-relations both sides share a model; fall back to any other side.)\n const counterpart =\n sides.find((s) => s.model === field.type) ?? sides.find((s) => s.isList !== field.isList);\n const otherIsList = counterpart?.isList ?? false;\n if (field.isList) return otherIsList ? 'manyToMany' : 'oneToMany';\n return otherIsList ? 'manyToOne' : 'oneToOne';\n};\n\n// ─── default value normalization ─────────────────────────────────────────────\n\n/**\n * A Prisma DMMF default is either a literal (representable as-is) or a\n * `{ name, args }` function-call descriptor (`autoincrement()`, `now()`,\n * `uuid()`, `cuid()`, `dbgenerated(...)`, `sequence(...)`, ...). Only literals\n * make sense to echo back into `fieldInput.defaultValue` — a function call has\n * no fixed value to pre-fill a create form with, and is usually DB/server\n * generated anyway (ids, timestamps).\n */\nconst literalDefault = (\n value: unknown,\n): string | number | boolean | (string | number | boolean)[] | undefined => {\n if (value === undefined || value === null) return undefined;\n if (typeof value === 'string' || typeof value === 'number' || typeof value === 'boolean') {\n return value;\n }\n if (Array.isArray(value) && value.every((v) => ['string', 'number', 'boolean'].includes(typeof v))) {\n return value as (string | number | boolean)[];\n }\n return undefined; // function-call descriptor ({ name, args }) or unrepresentable\n};\n\n// ─── normalizer ──────────────────────────────────────────────────────────────\n\n/** Pure: DMMF datamodel → normalized `DbModel[]`. */\nexport const dmmfToDbModels = (dmmf: Dmmf): DbModel[] => {\n const { models, enums } = dmmf.datamodel;\n const enumNames = new Set(enums.map((e) => e.name));\n const relationIndex = indexRelations(models);\n\n return models.map((model) => {\n // FK scalar columns = every scalar referenced by a relation's relationFromFields.\n const fkFields = new Set<string>();\n for (const f of model.fields) {\n if (f.kind === 'object' && f.relationFromFields) {\n for (const name of f.relationFromFields) fkFields.add(name);\n }\n }\n\n const idFieldDef = model.fields.find((f) => f.isId);\n const hasCompositeId = !!model.primaryKey && model.primaryKey.fields.length > 1;\n const idField = idFieldDef?.name;\n const idType = idFieldDef ? idTypeFor(idFieldDef.type) : undefined;\n\n const fields: DbField[] = model.fields.map((f) => {\n const isEnum = f.kind === 'enum' || enumNames.has(f.type);\n let kind: DbFieldKind;\n if (f.isId) kind = 'id';\n else if (f.kind === 'object') kind = 'relation';\n else if (fkFields.has(f.name)) kind = 'foreignKey';\n else if (isEnum) kind = 'enum';\n else kind = 'scalar';\n\n const field: DbField = {\n name: f.name,\n kind,\n type: f.type,\n isList: f.isList,\n isRequired: f.isRequired,\n isId: f.isId,\n isUnique: f.isUnique,\n isUpdatedAt: f.isUpdatedAt,\n hasDefault: f.hasDefaultValue,\n ...(f.hasDefaultValue && literalDefault(f.default) !== undefined\n ? { defaultValue: literalDefault(f.default) }\n : {}),\n isTimestamp:\n kind === 'scalar' &&\n isTimestampField({ name: f.name, type: f.type, isUpdatedAt: f.isUpdatedAt }),\n };\n\n if (kind === 'relation') {\n field.relationName = f.relationName;\n field.relationModel = f.type;\n field.relationFromFields = f.relationFromFields;\n field.relationToFields = f.relationToFields;\n field.relationType = resolveRelationType(f, relationIndex);\n }\n if (isEnum) {\n field.enumValues = enums.find((e) => e.name === f.type)?.values.map((v) => v.name);\n }\n return field;\n });\n\n return {\n prismaName: model.name,\n clientAccessor: model.name.charAt(0).toLowerCase() + model.name.slice(1),\n tableName: model.dbName ?? undefined,\n idField,\n idType,\n hasCompositeId,\n fields,\n };\n });\n};\n\n// ─── Prisma loader (impure, lazy) ────────────────────────────────────────────\n\nexport type DmmfLoader = (schemaPath: string) => Promise<Dmmf>;\n\ninterface PrismaInternals {\n getSchemaWithPath: (opts: {\n schemaPath: { cliProvidedPath: string };\n }) => Promise<{ schemas: [string, string][] }>;\n getDMMF: (opts: { datamodel: [string, string][] }) => Promise<Dmmf>;\n}\n\n/**\n * Default loader: lazily imports `@prisma/internals` (resolved from the consumer\n * project's Prisma install) and parses the schema file. The import specifier is\n * indirected through a variable so a TypeScript build does not require\n * `@prisma/internals` to be installed in the crouton workspace. Kept out of the\n * pure path so tests can inject a fake.\n */\nexport const loadDmmf: DmmfLoader = async (schemaPath: string) => {\n const specifier = '@prisma/internals';\n let internals: PrismaInternals;\n try {\n // `@prisma/internals` is CommonJS: under Node ESM its API lands on\n // `.default`, while bundler/TS interop may expose it directly — handle both.\n const mod = (await import(specifier)) as { default?: PrismaInternals } & PrismaInternals;\n internals = (mod.default ?? mod) as PrismaInternals;\n } catch {\n throw new Error(\n 'Could not load \\'@prisma/internals\\'. Ensure Prisma is installed in the project ' +\n '(it ships with the `prisma` CLI / `@prisma/client`).',\n );\n }\n const loaded = await internals.getSchemaWithPath({\n schemaPath: { cliProvidedPath: schemaPath },\n });\n return internals.getDMMF({ datamodel: loaded.schemas });\n};\n\nexport interface IntrospectOptions {\n schemaPath: string;\n loader?: DmmfLoader;\n}\n\n/** Read + normalize a Prisma schema into `DbModel[]`. */\nexport const introspect = async (opts: IntrospectOptions): Promise<DbModel[]> => {\n const loader = opts.loader ?? loadDmmf;\n const dmmf = await loader(opts.schemaPath);\n return dmmfToDbModels(dmmf);\n};\n","/**\n * classify: a `DbModel` + `Ruleset` → a fully generated `ResourceDraft`.\n *\n * Encodes the default visibility rules (decided with the user):\n * - primary key: hidden in table/form/view, marked `idField`\n * - created/updated timestamps: hidden in table+form, non-editable\n * - foreign-key scalars: hidden in table+form, non-editable\n * - relations: hidden in table always; unresolved (no sibling resource) hidden\n * everywhere. Resolved relations render in the form by cardinality via\n * `fieldInput.options.display`: the owning (forward) side — `manyToOne` /\n * `oneToOne`, e.g. `groupMembers.group` — as an `autocomplete` picker, and\n * the collection (reverse) side — `oneToMany` / `manyToMany`, e.g.\n * `groups.groupMembers` — as a sub-resource `table`.\n */\n\nimport { type JsonColumnInput, type ResourceJsonInput, type Ruleset, RulesetSchema } from '@ghentcdh/crouton-core';\n\nimport type { DbModel } from './db-model';\nimport type { ResourceDraft } from './draft';\nimport { resourceNames, scalarFieldInputType } from './naming';\n\nexport const defaultRuleset = (): Ruleset => RulesetSchema.parse({});\n\nexport interface ClassifyContext {\n /** Datasource name stamped on `database`. */\n database?: string;\n ruleset?: Ruleset;\n /**\n * Resolve the relative `resource` path for a relation's target model, or\n * `undefined` if no such resource exists (relation left hidden + unwired).\n */\n resolveRelationResource?: (targetModel: string) => string | undefined;\n}\n\ntype Column = Partial<Omit<JsonColumnInput, 'id'>>;\n\nexport const classify = (\n model: DbModel,\n ctx: ClassifyContext = {},\n): ResourceDraft => {\n const ruleset = ctx.ruleset ?? defaultRuleset();\n const names = resourceNames(model.prismaName);\n const columnOrder: string[] = [];\n const columns: Record<string, Column> = {};\n const unwiredRelations: { field: string; targetModel: string }[] = [];\n let position = 0;\n\n for (const field of model.fields) {\n // Relations are ignored by default — they are not real DB columns and can't\n // be ordered/filtered like scalars (a relation column in `orderBy` is a\n // Prisma validation error). Skip them entirely unless explicitly enabled.\n if (field.kind === 'relation' && !ruleset.includeRelations) continue;\n\n let col: Column;\n\n if (field.kind === 'id') {\n col = {\n idField: true,\n hiddenInTable: ruleset.hideIdInTable,\n hiddenInForm: ruleset.hideIdInForm,\n hiddenInView: ruleset.hideIdInView,\n };\n } else if (field.isTimestamp) {\n col = ruleset.hideTimestamps\n ? {\n hiddenInTable: true,\n hiddenInForm: true,\n createable: false,\n updateable: false,\n }\n : {\n fieldInput: {\n type: 'date',\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else if (field.kind === 'foreignKey') {\n col = ruleset.hideForeignKeys\n ? {\n hiddenInTable: true,\n hiddenInForm: true,\n createable: false,\n updateable: false,\n }\n : {\n fieldInput: {\n type: 'text',\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else if (field.kind === 'relation') {\n const target = ctx.resolveRelationResource?.(field.relationModel ?? '');\n // A relation renders in the form according to its cardinality:\n // - manyToOne / oneToOne (a single FK reference) → an autocomplete\n // picker on the owning (forward) side.\n // - oneToMany / manyToMany (a collection) → a sub-resource table listing\n // the related rows.\n // `options.display` drives the frontend `RelationControlRenderer`; without\n // it the control falls back to an inert \"Configure autocomplete\" state.\n // Relations are always hidden in the table (a relation column can't be\n // ordered/filtered like a scalar), but are shown in form + view.\n const isCollectionSide =\n field.relationType === 'oneToMany' || field.relationType === 'manyToMany';\n const display = isCollectionSide ? 'table' : 'autocomplete';\n if (ruleset.showRelationsInForm && target) {\n col = {\n hiddenInTable: ruleset.hideRelationsInTable,\n fieldInput: {\n format: 'relation',\n resource: target,\n relationType: field.relationType,\n options: { display },\n },\n };\n } else {\n col = { hiddenInTable: true, hiddenInForm: true, hiddenInView: true };\n unwiredRelations.push({\n field: field.name,\n targetModel: field.relationModel ?? '',\n });\n }\n } else if (field.kind === 'enum') {\n const options: Record<string, unknown> = {};\n if (ruleset.enumValueLabel) options.emitObject = true;\n if (!ruleset.sharedEnums) {\n options.values = (field.enumValues ?? []).map((v) => ({\n label: v,\n value: v,\n }));\n }\n col = {\n ...(ruleset.enumValueLabel ? { displayKey: 'label' } : {}),\n ...(ruleset.sharedEnums ? { enum: field.type } : {}),\n fieldInput: {\n type: 'select',\n position: position++,\n options,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n } else {\n col = {\n fieldInput: {\n type: scalarFieldInputType(field.name, field.type),\n position: position++,\n ...(field.defaultValue !== undefined\n ? { defaultValue: field.defaultValue }\n : {}),\n },\n };\n }\n\n columns[field.name] = col;\n columnOrder.push(field.name);\n }\n\n const config: ResourceJsonInput = {\n name: names.name,\n route: names.route,\n model: names.model,\n tag: names.tag,\n title: names.title,\n ...(model.idType ? { idType: model.idType } : {}),\n ...(ctx.database ? { database: ctx.database } : {}),\n sidebar: { hide: false },\n operations: ruleset.defaultOperations,\n columns,\n };\n\n const hasRelations = model.fields.some((f) => f.kind === 'relation');\n return {\n name: names.name,\n prismaName: model.prismaName,\n config,\n hasRelations,\n columnOrder,\n unwiredRelations,\n };\n};\n","/** Small framework-free helpers shared by the engine stages. */\n\nimport type { JsonColumnInput, ResourceJsonInput } from '@ghentcdh/crouton-core';\n\nimport { access } from 'node:fs/promises';\n\n/** Check whether a file exists (async). */\nexport const fileExists = async (p: string): Promise<boolean> => {\n try {\n await access(p);\n return true;\n } catch {\n return false;\n }\n};\n\n/** Deep clone that preserves object key insertion order (JSON-safe configs). */\nexport const clone = <T>(value: T): T => JSON.parse(JSON.stringify(value)) as T;\n\n/** Order-insensitive structural equality (sorts object keys before compare). */\nexport const deepEqual = (a: unknown, b: unknown): boolean => {\n if (a === b) return true;\n if (typeof a !== typeof b) return false;\n if (a === null || b === null) return a === b;\n if (Array.isArray(a) || Array.isArray(b)) {\n if (!Array.isArray(a) || !Array.isArray(b) || a.length !== b.length)\n return false;\n return a.every((v, i) => deepEqual(v, b[i]));\n }\n if (typeof a === 'object') {\n const ao = a as Record<string, unknown>;\n const bo = b as Record<string, unknown>;\n const ak = Object.keys(ao).sort();\n const bk = Object.keys(bo).sort();\n if (ak.length !== bk.length || ak.some((k, i) => k !== bk[i])) return false;\n return ak.every((k) => deepEqual(ao[k], bo[k]));\n }\n return false;\n};\n\n/**\n * Normalize a `columns` value (array | map | undefined) into ordered\n * `[id, columnWithoutId][]` entries. Preserves declaration order.\n */\nexport const columnEntries = (\n columns: ResourceJsonInput['columns'],\n): [string, Omit<JsonColumnInput, 'id'>][] => {\n if (!columns) return [];\n if (Array.isArray(columns)) {\n return columns.map(({ id, ...rest }) => [id, rest]);\n }\n return Object.entries(columns);\n};\n\n/** Build a `columns` map object from ordered entries (stable order). */\nexport const columnsMapFromEntries = (\n entries: [string, Omit<JsonColumnInput, 'id'>][],\n): Record<string, Omit<JsonColumnInput, 'id'>> => {\n const out: Record<string, Omit<JsonColumnInput, 'id'>> = {};\n for (const [id, col] of entries) out[id] = col;\n return out;\n};\n","/**\n * diff: reconcile a generated `ResourceDraft` against an existing resource.json.\n *\n * Produces serializable `Decision`s with recommended defaults:\n * - new resource → `addToSidebar` (recommended yes)\n * - DB field not in config → `addColumn` (recommended add)\n * - config field not in DB → `removeColumn` (recommended keep — never auto-delete)\n * - field in both, changed → `reconcileColumn` (recommended keep)\n * - field in both, identical → no decision (keeps the run idempotent)\n */\n\nimport type { ResourceJsonInput } from '@ghentcdh/crouton-core';\n\nimport type { Decision, ResourceDiff } from './decision';\nimport type { ResourceDraft } from './draft';\nimport { columnEntries, deepEqual } from './util';\n\nexport interface DiffInput {\n draft: ResourceDraft;\n existing?: ResourceJsonInput | null;\n hasSchemaFile?: boolean;\n}\n\nexport const diff = ({\n draft,\n existing,\n hasSchemaFile = false,\n}: DiffInput): ResourceDiff => {\n const decisions: Decision[] = [];\n const isNew = !existing;\n\n if (isNew) {\n decisions.push({\n id: 'sidebar',\n kind: 'addToSidebar',\n recommended: 'yes',\n options: ['yes', 'no'],\n context: `New resource \"${draft.name}\"`,\n });\n } else {\n const draftMap = new Map(columnEntries(draft.config.columns));\n const existingMap = new Map(columnEntries(existing.columns));\n\n // DB-driven columns (draft order) vs existing.\n for (const id of draft.columnOrder) {\n const draftCol = draftMap.get(id);\n if (!draftCol) continue;\n if (!existingMap.has(id)) {\n decisions.push({\n id: `add:${id}`,\n kind: 'addColumn',\n field: id,\n recommended: 'add',\n options: ['add', 'skip'],\n });\n } else if (!deepEqual(draftCol, existingMap.get(id))) {\n decisions.push({\n id: `reconcile:${id}`,\n kind: 'reconcileColumn',\n field: id,\n recommended: 'keep',\n options: ['keep', 'overwrite', 'merge'],\n context: 'Differs from generated defaults',\n });\n }\n }\n\n // Existing columns no longer present in the DB schema.\n for (const [id] of existingMap) {\n if (!draftMap.has(id)) {\n decisions.push({\n id: `remove:${id}`,\n kind: 'removeColumn',\n field: id,\n recommended: 'keep',\n options: ['keep', 'remove'],\n context: 'Not found in the database schema',\n });\n }\n }\n }\n\n return {\n name: draft.name,\n // Codegen only ever drafts prisma-backed resources, so `model` is set.\n model: draft.config.model ?? draft.name,\n isNew,\n decisions,\n draft,\n existing: existing ?? undefined,\n hasSchemaFile,\n };\n};\n","/**\n * resolve: turn a `ResourceDiff` into a `ResolvedDiff` by collecting a choice\n * per decision. The engine never prompts — a `DecisionResolver` supplies the\n * choices. The CLI plugs in an interactive resolver; a backend can plug in an\n * auto-policy or request-driven resolver.\n */\n\nimport type { Decision, ResolvedDiff, ResourceDiff } from './decision';\n\nexport interface DecisionResolver {\n /**\n * Resolve the given decisions to `{ decisionId → choice }`. Implementations\n * must return a choice for every decision (fall back to `decision.recommended`).\n */\n resolve(\n decisions: Decision[],\n diff: ResourceDiff,\n ): Promise<Record<string, string>> | Record<string, string>;\n}\n\n/** Non-interactive resolver: always picks each decision's recommended choice. */\nexport const recommendedResolver: DecisionResolver = {\n resolve(decisions) {\n const out: Record<string, string> = {};\n for (const d of decisions) out[d.id] = d.recommended;\n return out;\n },\n};\n\nexport const resolve = async (\n diff: ResourceDiff,\n resolver: DecisionResolver = recommendedResolver,\n): Promise<ResolvedDiff> => {\n const raw = await resolver.resolve(diff.decisions, diff);\n const resolutions = new Map<string, string>();\n for (const d of diff.decisions) {\n resolutions.set(d.id, raw[d.id] ?? d.recommended);\n }\n return { diff, resolutions };\n};\n","/**\n * serialize: deterministic text for the generated files.\n *\n * resource.json is emitted as 2-space JSON relying on object key insertion\n * order (the engine builds objects in a stable order and preserves existing\n * order when updating), so re-runs produce minimal git diffs and are idempotent.\n */\n\nimport { CURRENT_RESOURCE_VERSION, type ResourceJsonInput } from '@ghentcdh/crouton-core';\n\n/** Canonical, versioned JSON Schema URL — matches the path published by the docs site. */\nexport const RESOURCE_SCHEMA_URL = `https://ghentcdh.github.io/crouton/schema/v${CURRENT_RESOURCE_VERSION}/resource.schema.json`;\n\n/**\n * Prepend `$schema` / `schemaVersion` (and, when set, `draft` / `kind`) so every generated\n * `resource.json` validates + autocompletes in editors and is born at the current version.\n *\n * `$schema` and `schemaVersion` are always (re)stamped to current — any existing values are\n * dropped and re-added at the front for a stable, diff-friendly key order. `draft` is set from\n * `opts.draft` when provided (new-resource default), otherwise the config's existing `draft`\n * value is preserved (so an update never flips it). `kind` is preserved as-is and hoisted to a\n * fixed position; it is never inferred or removed, so an update cannot turn a custom resource\n * back into a prisma one.\n */\nexport const withResourceHeader = (\n config: ResourceJsonInput,\n opts: { draft?: boolean } = {},\n): Record<string, unknown> => {\n const {\n $schema: _schema,\n schemaVersion: _version,\n draft: existingDraft,\n kind: existingKind,\n ...rest\n } = config as Record<string, unknown>;\n const draft = opts.draft !== undefined ? opts.draft : (existingDraft as boolean | undefined);\n\n return {\n $schema: RESOURCE_SCHEMA_URL,\n schemaVersion: CURRENT_RESOURCE_VERSION,\n ...(draft !== undefined ? { draft } : {}),\n ...(existingKind !== undefined ? { kind: existingKind } : {}),\n ...rest,\n };\n};\n\nexport const serializeResourceJson = (\n config: ResourceJsonInput | Record<string, unknown>,\n): string => `${JSON.stringify(config, null, 2)}\\n`;\n\n/**\n * Content for a resource's `schema.ts` — a default re-export of the model's\n * generated Zod schema. `exportName` / `importPath` come from project config.\n */\nexport const serializeSchemaTs = (\n exportName: string,\n importPath: string,\n): string =>\n `import { ${exportName} } from '${importPath}';\\n\\nexport default ${exportName};\\n`;\n","/**\n * apply: a `ResolvedDiff` → a `WritePlan` (full file contents, no disk I/O).\n *\n * Merges resolved decisions into the existing config, preserving every key the\n * tool didn't touch (actions, calculatedColumns, include, custom fieldInput,\n * sub-resources, …). `commit` performs the actual writes.\n */\n\nimport type { JsonColumnInput } from '@ghentcdh/crouton-core';\n\nimport type { ResolvedDiff } from './decision';\nimport {\n serializeResourceJson,\n serializeSchemaTs,\n withResourceHeader,\n} from './serialize';\nimport { clone, columnEntries, columnsMapFromEntries, deepEqual } from './util';\nimport type { WritePlan } from './write-plan';\n\nconst joinPath = (...parts: string[]): string =>\n parts.join('/').replace(/\\/+/g, '/');\n\nexport interface ApplyContext {\n /** Where resource directories live (e.g. `apps/backend/src/app/resources`). */\n resourcesDir: string;\n /** Import path for the generated Zod types (e.g. `@new-polities/generated/types`). */\n generatedTypesImport: string;\n /** Export name for a model's Zod schema. Default `<PrismaName>WithRelationsSchema`. */\n schemaExportName?: (prismaName: string) => string;\n /**\n * Whether a newly-scaffolded resource is written with `draft: true` (so it isn't served\n * until reviewed). Falls back to `true` when the caller omits it — used by the dev-tools\n * \"create resource\" endpoint, which has no CLI-style flag/prompt of its own. The `crouton\n * update resources` CLI always resolves and passes an explicit value (default `false`,\n * see `resolveDraftOption` in `crouton-cli/src/update/runner.ts`).\n */\n draft?: boolean;\n}\n\ntype Column = Omit<JsonColumnInput, 'id'>;\n\nexport const apply = (resolved: ResolvedDiff, ctx: ApplyContext): WritePlan => {\n const { diff, resolutions } = resolved;\n const exportNameFor = ctx.schemaExportName ?? ((p: string) => `${p}WithRelationsSchema`);\n const dir = joinPath(ctx.resourcesDir, diff.name);\n const notes = diff.draft.unwiredRelations.map(\n (r) => `Relation \"${r.field}\" → model \"${r.targetModel}\": target resource not found; left hidden.`,\n );\n const files: WritePlan['files'] = [];\n\n if (diff.isNew) {\n const config = clone(diff.draft.config);\n const addToSidebar = (resolutions.get('sidebar') ?? 'yes') !== 'no';\n config.sidebar = { hide: !addToSidebar };\n const draft = ctx.draft ?? true; // new resources are drafts unless --no-draft\n files.push({\n path: joinPath(dir, 'resource.json'),\n contents: serializeResourceJson(withResourceHeader(config, { draft })),\n action: 'create',\n });\n } else {\n const existing = clone(diff.existing!);\n const draftMap = new Map<string, Column>(columnEntries(diff.draft.config.columns));\n const entries = columnEntries(existing.columns);\n const indexOf = (id: string) => entries.findIndex(([eid]) => eid === id);\n\n for (const decision of diff.decisions) {\n const choice = resolutions.get(decision.id) ?? decision.recommended;\n const field = decision.field;\n if (!field) continue;\n\n if (decision.kind === 'addColumn' && choice === 'add') {\n const col = draftMap.get(field);\n if (col && indexOf(field) === -1) entries.push([field, col]);\n } else if (decision.kind === 'reconcileColumn') {\n const i = indexOf(field);\n if (i === -1) continue;\n if (choice === 'overwrite') {\n const col = draftMap.get(field);\n if (col) entries[i] = [field, col];\n } else if (choice === 'merge') {\n const col = draftMap.get(field);\n if (col) entries[i] = [field, { ...col, ...entries[i][1] }];\n }\n // 'keep' → leave as-is\n } else if (decision.kind === 'removeColumn' && choice === 'remove') {\n const i = indexOf(field);\n if (i !== -1) entries.splice(i, 1);\n }\n }\n\n const config = { ...existing, columns: columnsMapFromEntries(entries) };\n // Only write when something actually changed — keep \"adjusted files only\".\n // The header (re-stamped $schema/schemaVersion) is applied at serialize time only, so\n // it doesn't by itself trigger a rewrite; an existing `draft` value is preserved.\n if (!deepEqual(config, diff.existing)) {\n files.push({\n path: joinPath(dir, 'resource.json'),\n contents: serializeResourceJson(withResourceHeader(config)),\n action: 'update',\n });\n }\n }\n\n // schema.ts is created only when absent; never clobber a hand-written one.\n if (!diff.hasSchemaFile) {\n // zod-prisma-types only emits `…WithRelationsSchema` for models that have\n // relations; relation-less models only have the plain `…Schema`. Fall back\n // so the generated import always resolves to a real export.\n const exportName = diff.draft.hasRelations\n ? exportNameFor(diff.draft.prismaName)\n : `${diff.draft.prismaName}Schema`;\n files.push({\n path: joinPath(dir, 'schema.ts'),\n contents: serializeSchemaTs(exportName, ctx.generatedTypesImport),\n action: 'create',\n });\n }\n\n return { resource: diff.name, files, notes };\n};\n","/**\n * commit: the only side-effectful stage — write a `WritePlan` to disk.\n *\n * `create` actions never overwrite an existing file (so a hand-written\n * `schema.ts` is safe); `update` actions write unconditionally. `dryRun`\n * computes the result without touching disk.\n */\n\nimport { fileExists } from './util';\nimport type { WritePlan } from './write-plan';\nimport { mkdir, writeFile } from 'node:fs/promises';\nimport { dirname } from 'node:path';\n\n\nexport interface CommitOptions {\n dryRun?: boolean;\n}\n\nexport interface CommitResult {\n written: string[];\n skipped: string[];\n}\n\nexport const commit = async (\n plan: WritePlan,\n opts: CommitOptions = {},\n): Promise<CommitResult> => {\n const written: string[] = [];\n const skipped: string[] = [];\n\n for (const file of plan.files) {\n if (file.action === 'create' && (await fileExists(file.path))) {\n skipped.push(file.path);\n continue;\n }\n if (!opts.dryRun) {\n await mkdir(dirname(file.path), { recursive: true });\n await writeFile(file.path, file.contents, 'utf-8');\n }\n written.push(file.path);\n }\n\n return { written, skipped };\n};\n","/**\n * Project configuration.\n *\n * `crouton.json` (project root) holds only project-wide settings — paths, the\n * schema export-name template, the enum registry, sidebar groups, ruleset\n * overrides. Datasources are NOT listed here: each is self-describing in its own\n * `<dataSourcesDir>/<name>/data-source.json` and discovered by scanning that\n * directory. Every datasource carries its own Prisma schema, generated zod\n * import, zod output, and Prisma config (for multi-datasource projects).\n */\n\nimport {\n CONFIG_FILES,\n type CroutonConfig,\n type DataSource,\n DataSourceSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, isAbsolute, join, resolve } from 'node:path';\n\n\nexport interface LoadedConfig {\n config: CroutonConfig;\n /** Absolute path to `crouton.json`. */\n path: string;\n /** Absolute project root (config file directory). */\n root: string;\n}\n\n/** Walk up from `cwd` to find `crouton.json`. */\nexport const findConfigPath = async (\n cwd: string,\n): Promise<string | undefined> => {\n let dir = resolve(cwd);\n\n while (true) {\n for (const name of CONFIG_FILES) {\n const candidate = join(dir, name);\n if (await fileExists(candidate)) return candidate;\n }\n const parent = dirname(dir);\n if (parent === dir) return undefined;\n dir = parent;\n }\n};\n\n/** Load + validate `crouton.json`. Throws if none is found. */\nexport const loadConfig = async (cwd: string): Promise<LoadedConfig> => {\n const path = await findConfigPath(cwd);\n if (!path) {\n throw new Error(\n `No crouton config found (looked for ${CONFIG_FILES.join(', ')} up from ${cwd}).`,\n );\n }\n let config: CroutonConfig;\n if (path.endsWith('.json')) {\n config = JSON.parse(await readFile(path, 'utf-8')) as CroutonConfig;\n } else {\n const mod = (await import(path)) as {\n default?: CroutonConfig;\n } & CroutonConfig;\n config = mod.default ?? mod;\n }\n validateConfig(config, path);\n return { config, path, root: dirname(path) };\n};\n\nexport const validateConfig = (\n config: CroutonConfig,\n path = '<config>',\n): void => {\n if (!config.resourcesDir)\n throw new Error(`${path}: \"resourcesDir\" is required.`);\n if (!config.dataSourcesDir)\n throw new Error(`${path}: \"dataSourcesDir\" is required.`);\n};\n\n/** Default Prisma config path for a datasource: `prisma/<name>/prisma.config.ts`. */\nexport const defaultPrismaConfig = (name: string): string =>\n `prisma/${name}/prisma.config.ts`;\n\n/**\n * Discover datasources by scanning `dataSourcesDir`: each subdirectory with a\n * `data-source.json` becomes a `ResolvedDatasource`. The datasource `name`\n * defaults to the folder name; `prismaConfig` defaults to `prisma/<name>/prisma.config.ts`.\n */\nexport const loadDatasources = async (\n loaded: LoadedConfig,\n): Promise<DataSource[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.dataSourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const datasources: DataSource[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'data-source.json');\n if (!(await fileExists(jsonPath))) continue;\n const ds_json = JSON.parse(await readFile(jsonPath, 'utf-8'));\n const name = ds_json.name ?? e.name;\n if (!ds_json.prismaSchema || !ds_json.generatedTypesImport) {\n const missing = [\n !ds_json.prismaSchema && '\"prismaSchema\"',\n !ds_json.generatedTypesImport && '\"generatedTypesImport\"',\n ]\n .filter(Boolean)\n .join(' and ');\n throw new Error(\n `${jsonPath}: datasource \"${name}\" is missing ${missing}. ` +\n 'A v2 data-source.json must be self-describing — add prismaSchema, urlEnv, ' +\n 'generatedTypesImport, zodOutput and prismaConfig (see `crouton create-datasource`).',\n );\n }\n datasources.push(\n DataSourceSchema.parse({\n ...ds_json,\n name,\n prismaConfig: ds_json.prismaConfig ?? defaultPrismaConfig(name),\n }),\n );\n }\n validateDatasources(datasources);\n return datasources;\n};\n\nexport const validateDatasources = (datasources: DataSource[]): void => {\n if (datasources.length === 0) {\n throw new Error(\n 'No datasources found (no data-source.json under the data-sources dir).',\n );\n }\n const defaults = datasources.filter((d) => d.default);\n if (defaults.length > 1) {\n throw new Error(\n `Only one datasource may be marked \"default\" (found: ${defaults.map((d) => d.name).join(', ')}).`,\n );\n }\n};\n\n/**\n * Resolve which discovered datasource to use:\n * - explicit `name` → must exist\n * - else the one marked `default`\n * - else the only one\n * - else ambiguous → throw (the CLI prompts before calling this)\n */\nexport const resolveDatasource = (\n datasources: DataSource[],\n name?: string,\n): DataSource => {\n if (name) {\n const found = datasources.find((d) => d.name === name);\n if (!found) {\n throw new Error(\n `Unknown datasource \"${name}\". Available: ${datasources.map((d) => d.name).join(', ')}.`,\n );\n }\n return found;\n }\n const def = datasources.find((d) => d.default);\n if (def) return def;\n if (datasources.length === 1) return datasources[0];\n throw new Error(\n `Multiple datasources found (${datasources.map((d) => d.name).join(', ')}); specify which one to use.`,\n );\n};\n\n/** Build the `(prismaName) → exportName` function from the config template. */\nexport const makeSchemaExportName = (\n config: CroutonConfig,\n): ((prismaName: string) => string) => {\n const template = config.schemaExportName ?? '{Model}WithRelationsSchema';\n return (prismaName: string) => template.replace('{Model}', prismaName);\n};\n\n/** Resolve a config path (possibly relative) against the project root. */\nexport const resolveFromRoot = (root: string, p: string): string =>\n isAbsolute(p) ? p : join(root, p);\n","/**\n * Scaffolding: best-effort project proposal for a new-style crouton project.\n *\n * Scans an existing project for Prisma configs, datasource folders, and\n * resource directories and returns a proposed `crouton.json` + per-datasource\n * `data-source.json`. Returned, not written — the CLI shows it and offers to save.\n */\n\nimport { z } from 'zod';\n\nimport {\n type CroutonConfig,\n CroutonConfigSchema,\n type DataSource,\n DataSourceShape,\n transformDataSource,\n} from '@ghentcdh/crouton-core';\n\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { dirname, join } from 'node:path';\n\n\nexport const ScallfoldDatasourceSchema = DataSourceShape.extend({\n /** Folder name under `dataSourcesDir`. */ folder: z\n .string()\n .default('default'),\n}).transform(transformDataSource);\n\nexport type ScaffoldDatasource = z.infer<typeof ScallfoldDatasourceSchema>;\n\nexport interface ScaffoldResult {\n config: CroutonConfig;\n /** Proposed `data-source.json` per discovered datasource folder. */\n datasources: ScaffoldDatasource[];\n notes: string[];\n}\n\nconst firstExisting = async (\n root: string,\n candidates: string[],\n): Promise<string | undefined> => {\n for (const c of candidates) {\n if (await fileExists(join(root, c))) return c;\n }\n return undefined;\n};\n\n/**\n * Best-effort proposal for a new-style project: a `crouton.json` (paths only)\n * plus a self-describing `data-source.json` per discovered datasource folder.\n * Returned, not written — the CLI shows it and offers to save.\n */\nexport const scaffoldConfigFromProject = async (\n root: string,\n): Promise<ScaffoldResult> => {\n const notes: string[] = [];\n\n let urlEnv: string | undefined;\n const prismaConfigFile = await firstExisting(root, [\n 'prisma.config.ts',\n 'prisma.config.js',\n 'prisma.config.mjs',\n ]);\n if (prismaConfigFile) {\n const text = await readFile(join(root, prismaConfigFile), 'utf-8');\n urlEnv = /env\\(\\s*[\"']([^\"']+)[\"']\\s*\\)/.exec(text)?.[1];\n }\n if (!urlEnv)\n notes.push(\n 'Could not detect a DB URL env var; set \"urlEnv\" per datasource manually.',\n );\n\n const dataSourcesDir =\n (await firstExisting(root, [\n 'apps/backend/src/app/data-sources',\n 'src/app/data-sources',\n 'data-sources',\n ])) ?? 'src/app/data-sources';\n\n const resourcesDir =\n (await firstExisting(root, [\n 'apps/backend/src/app/resources',\n 'src/app/resources',\n 'resources',\n ])) ?? join(dirname(dataSourcesDir), 'resources');\n\n // Detect a generated-types import from an existing resource schema.ts.\n let detectedImport: string | undefined;\n if (await fileExists(join(root, resourcesDir))) {\n const dirs = await readdir(join(root, resourcesDir), {\n withFileTypes: true,\n });\n for (const d of dirs) {\n if (!d.isDirectory()) continue;\n const schemaTs = join(root, resourcesDir, d.name, 'schema.ts');\n if (await fileExists(schemaTs)) {\n const m = /from\\s+[\"']([^\"']+)[\"']/.exec(\n await readFile(schemaTs, 'utf-8'),\n );\n if (m) {\n detectedImport = m[1];\n break;\n }\n }\n }\n }\n\n const datasources: ScaffoldDatasource[] = [];\n if (await fileExists(join(root, dataSourcesDir))) {\n const entries = await readdir(join(root, dataSourcesDir), {\n withFileTypes: true,\n });\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const existing = join(root, dataSourcesDir, e.name, 'data-source.json');\n const prev: Partial<DataSource> = (await fileExists(existing))\n ? JSON.parse(await readFile(existing, 'utf-8'))\n : {};\n const name = prev.name ?? e.name;\n datasources.push(\n ScallfoldDatasourceSchema.parse({\n folder: e.name,\n type: prev.type,\n name,\n default: prev.default,\n prismaSchema: prev.prismaSchema,\n urlEnv: prev.urlEnv ?? urlEnv ?? '',\n generatedTypesImport: prev.generatedTypesImport ?? detectedImport,\n zodOutput: prev.zodOutput,\n prismaConfig: prev.prismaConfig,\n }),\n );\n }\n }\n if (datasources.length === 0) {\n datasources.push(\n ScallfoldDatasourceSchema.parse({\n name: 'default',\n default: true,\n urlEnv,\n generatedTypesImport: detectedImport ?? '@your-scope/generated/default',\n }),\n );\n notes.push(\n 'No data-sources found; proposed a single \"default\" datasource.',\n );\n } else if (!datasources.some((d) => d.default)) {\n datasources[0].default = true;\n }\n\n return {\n config: CroutonConfigSchema.parse({\n title: 'Crouton',\n resourcesDir,\n dataSourcesDir,\n }),\n datasources,\n notes,\n };\n};","/**\n * Pure scaffolder for a new datasource: given the desired settings, produce the\n * full set of files (project-root-relative paths + contents) that make a\n * datasource self-describing and ready for `crouton update resources`.\n *\n * No disk I/O — the CLI (or a backend dev endpoint) collects the inputs, calls\n * this, and writes the returned files. Every generated datasource gets its own\n * Prisma schema, Prisma client output, and zod output so multiple datasources\n * never collide (the Prisma-7 multi-datasource requirement).\n */\n\nimport { defaultPrismaConfig } from './config';\nimport { dirname, posix, relative } from 'node:path';\n\n\nexport interface DatasourceScaffoldOptions {\n /** Datasource name (folder + `name` in data-source.json). */\n name: string;\n /** Where datasource folders live, relative to project root (from crouton.json). */\n dataSourcesDir: string;\n /**\n * Env var holding the connection URL. Required for Prisma; optional for\n * custom adapters whose connection config may not use an env var.\n */\n urlEnv?: string;\n /**\n * Adapter kind. `\"prisma\"` (default) generates the full Prisma scaffold;\n * `\"custom\"` emits only `data-source.json` + an `index.ts` adapter stub.\n */\n adapter?: 'prisma' | 'custom';\n /** Import path for this datasource's generated Zod types (for resource `schema.ts`). Prisma only. */\n generatedTypesImport?: string;\n /** Import path for this datasource's generated Prisma client. When set, used instead of a relative path in data-source index.ts. */\n generatedClientImport?: string;\n /** Datasource type tag. Default `postgres`. */\n type?: string;\n /** Mark this as the default datasource. Default `false`. */\n default?: boolean;\n /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */\n prismaSchema?: string;\n /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */\n prismaConfig?: string;\n /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */\n zodOutput?: string;\n /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */\n clientOutput?: string;\n}\n\nexport interface ScaffoldFile {\n /** Path relative to the project root. */\n path: string;\n contents: string;\n}\n\nexport interface DatasourceScaffold {\n files: ScaffoldFile[];\n /** The fully-resolved settings (after defaults), e.g. for printing a summary. */\n resolved: {\n name: string;\n adapter: 'prisma' | 'custom';\n default: boolean;\n urlEnv?: string;\n type?: string;\n generatedTypesImport?: string;\n prismaSchema?: string;\n prismaConfig?: string;\n zodOutput?: string;\n clientOutput?: string;\n };\n notes: string[];\n}\n\nconst PRISMA_PROVIDERS: Record<string, string> = {\n postgres: 'postgresql',\n postgresql: 'postgresql',\n mysql: 'mysql',\n mariadb: 'mysql',\n sqlite: 'sqlite',\n sqlserver: 'sqlserver',\n mssql: 'sqlserver',\n mongodb: 'mongodb',\n cockroachdb: 'cockroachdb',\n};\n\nconst toPascalCase = (s: string): string =>\n s.replace(/[-_](.)/g, (_, c: string) => c.toUpperCase()).replace(/^(.)/, (_, c: string) => c.toUpperCase());\n\n/** Posix-style relative import from one project-relative dir/file to another dir. */\nconst relImport = (fromDir: string, toDir: string): string => {\n const rel = relative(fromDir, toDir).split(/[\\\\/]/).join(posix.sep);\n return rel.startsWith('.') ? rel : `./${rel}`;\n};\n\nexport const buildDatasourceFiles = (opts: DatasourceScaffoldOptions): DatasourceScaffold => {\n const name = opts.name;\n const isDefault = opts.default === true;\n const adapter = opts.adapter ?? 'prisma';\n const dsDir = posix.join(opts.dataSourcesDir, name);\n\n // ── Custom adapter path ───────────────────────────────────────────────────\n if (adapter === 'custom') {\n const dataSourceJson: Record<string, unknown> = {\n adapter: 'custom',\n name,\n ...(opts.urlEnv ? { urlEnv: opts.urlEnv } : {}),\n ...(isDefault ? { default: true } : {}),\n };\n\n const indexTs = `import { PrismaDataSourceAdapter } from '@ghentcdh/crouton-api';\nimport type { AdapterCrudContext } from '@ghentcdh/crouton-api';\nimport type { ListRequest } from '@ghentcdh/crouton-core';\n\n/**\n * ${name} datasource adapter.\n *\n * Extends PrismaDataSourceAdapter so every Prisma-backed method is available\n * by default. Override only the methods you need to customise.\n *\n * Example — enrich findAll results:\n *\n * override async findAll(model: string, params: ListRequest, ctx: AdapterCrudContext) {\n * const result = await super.findAll(model, params, ctx);\n * return { ...result, data: result.data.map(decorate) };\n * }\n *\n * To use a non-Prisma backend, remove the super() call and implement methods directly.\n */\nexport default class ${toPascalCase(name)}Adapter extends PrismaDataSourceAdapter {\n constructor() {\n // Replace with your own client if not using Prisma.\n super(null);\n }\n}\n`;\n\n const notes: string[] = [];\n if (opts.urlEnv) notes.push(`Add ${opts.urlEnv} to your .env (and .env.example).`);\n notes.push(`Implement your adapter in ${posix.join(dsDir, 'index.ts')} — override only the methods you need.`);\n notes.push('Pass your client to super() in the constructor, or replace super() with direct calls for a non-Prisma backend.');\n\n return {\n files: [\n { path: posix.join(dsDir, 'data-source.json'), contents: `${JSON.stringify(dataSourceJson, null, 2)}\\n` },\n { path: posix.join(dsDir, 'index.ts'), contents: indexTs },\n ],\n resolved: { name, urlEnv: opts.urlEnv, adapter: 'custom', default: isDefault },\n notes,\n };\n }\n\n // ── Prisma adapter path (default) ─────────────────────────────────────────\n const type = opts.type ?? 'postgres';\n const provider = PRISMA_PROVIDERS[type.toLowerCase()] ?? 'postgresql';\n\n const prismaSchema = opts.prismaSchema ?? `prisma/${name}/schema.prisma`;\n const prismaConfig = opts.prismaConfig ?? defaultPrismaConfig(name);\n const zodOutput = opts.zodOutput ?? `generated/${name}/src`;\n const clientOutput = opts.clientOutput ?? `generated/${name}/client`;\n\n const schemaDir = dirname(prismaSchema);\n const migrationsDir = posix.join(schemaDir, 'migrations');\n\n // ── data-source.json ──────────────────────────────────────────────────────\n const dataSourceJson: Record<string, unknown> = {\n type,\n name,\n ...(isDefault ? { default: true } : {}),\n prismaSchema,\n urlEnv: opts.urlEnv,\n generatedTypesImport: opts.generatedTypesImport,\n zodOutput,\n clientOutput,\n prismaConfig,\n };\n\n // ── index.ts (runtime PrismaClient) ───────────────────────────────────────\n const clientImport = opts.generatedClientImport ?? relImport(dsDir, clientOutput);\n const indexTs = `import { PrismaClient } from '${clientImport}';\nimport { PrismaPg } from '@prisma/adapter-pg';\n\nconst connectionString = process.env.${opts.urlEnv} ?? '';\n// ?schema=<name> in the URL is a Prisma extension; pg ignores it — set search_path explicitly.\nconst _schema = new URLSearchParams((connectionString.split('?')[1]) ?? '').get('schema');\n\nconst adapter = new PrismaPg({\n connectionString,\n ...(_schema && _schema !== 'public' ? { options: \\`--search_path=\\${_schema}\\` } : {}),\n});\nconst client = new PrismaClient({ adapter });\n\nexport default client;\n`;\n\n // ── prisma/<name>/schema.prisma ───────────────────────────────────────────\n const relClient = relImport(schemaDir, clientOutput);\n const relZod = relImport(schemaDir, zodOutput);\n const schemaPrisma = `generator client {\n provider = \"prisma-client-js\"\n output = \"${relClient}\"\n}\n\ngenerator crouton {\n provider = \"crouton-prisma\"\n zodOutput = \"${relZod}\"\n}\n\ndatasource db {\n provider = \"${provider}\"\n // url is provided by ${prismaConfig} (Prisma 7 forbids \\`url\\` here)\n}\n`;\n\n // ── prisma/<name>/prisma.config.ts ────────────────────────────────────────\n // Paths must be relative to the config file, not the project root.\n const configDir = dirname(prismaConfig);\n const relSchema = relImport(configDir, prismaSchema);\n const relMigrations = relImport(configDir, migrationsDir);\n\n const prismaConfigTs = `// Generated by \\`crouton create-datasource\\`.\nimport { defineConfig, env } from 'prisma/config';\n\nexport default defineConfig({\n schema: '${relSchema}',\n migrations: {\n path: '${relMigrations}',\n },\n datasource: {\n url: env('${opts.urlEnv}'),\n },\n});\n`;\n\n const files: ScaffoldFile[] = [\n { path: posix.join(dsDir, 'data-source.json'), contents: `${JSON.stringify(dataSourceJson, null, 2)}\\n` },\n { path: posix.join(dsDir, 'index.ts'), contents: indexTs },\n { path: prismaSchema, contents: schemaPrisma },\n { path: prismaConfig, contents: prismaConfigTs },\n ];\n\n const notes = [\n `Add ${opts.urlEnv} to your .env (and .env.example).`,\n `Map ${opts.generatedTypesImport} to ${zodOutput} in your tsconfig paths / workspace.`,\n `Run \\`crouton update resources --datasource ${name}\\` to introspect and generate resources.`,\n ];\n\n return {\n files,\n resolved: { name, type, adapter: 'prisma', default: isDefault, urlEnv: opts.urlEnv, generatedTypesImport: opts.generatedTypesImport, prismaSchema, prismaConfig, zodOutput, clientOutput },\n notes,\n };\n};\n","/**\n * Filesystem glue between the engine and a crouton project on disk:\n * reading existing resource configs, listing resources, and resolving relation\n * targets to sibling resource files.\n */\n\nimport {\n type ResourceJson,\n type ResourceJsonInput,\n buildResourceJsonSchema,\n} from '@ghentcdh/crouton-core';\n\nimport { type LoadedConfig, resolveFromRoot } from './config';\nimport { clientAccessor } from './naming';\nimport { fileExists } from './util';\nimport { readFile, readdir } from 'node:fs/promises';\nimport { join } from 'node:path';\n\n/** Absolute path to a resource directory. */\nexport const resourceDir = (loaded: LoadedConfig, name: string): string =>\n join(resolveFromRoot(loaded.root, loaded.config.resourcesDir), name);\n\nexport interface ExistingResource {\n config: ResourceJsonInput | null;\n hasSchemaFile: boolean;\n}\n\n/** Read an existing `resource.json` (if any) and detect a sibling `schema.ts`. */\nexport const readExistingResource = async (\n loaded: LoadedConfig,\n name: string,\n): Promise<ExistingResource> => {\n const dir = resourceDir(loaded, name);\n const jsonPath = join(dir, 'resource.json');\n const config = (await fileExists(jsonPath))\n ? (JSON.parse(await readFile(jsonPath, 'utf-8')) as ResourceJsonInput)\n : null;\n const hasSchemaFile =\n (await fileExists(join(dir, 'schema.ts'))) ||\n (await fileExists(join(dir, 'schema.js')));\n return { config, hasSchemaFile };\n};\n\n/** `true` when a resource.json on disk declares `kind: \"custom\"`. */\nexport const isCustomResourceFile = async (\n jsonPath: string,\n): Promise<boolean> => {\n try {\n const parsed = JSON.parse(await readFile(jsonPath, 'utf-8')) as {\n kind?: string;\n };\n return parsed?.kind === 'custom';\n } catch {\n // Unreadable/malformed: let the normal pipeline report it.\n return false;\n }\n};\n\n/**\n * Names of resource directories that contain a `resource.json`.\n *\n * Custom resources are excluded: they have no Prisma model, so the\n * introspect → diff pipeline would see every column as \"not found in the\n * database schema\" and offer to remove it.\n */\nexport const listResourceNames = async (\n loaded: LoadedConfig,\n): Promise<string[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const names: string[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'resource.json');\n if (!(await fileExists(jsonPath))) continue;\n if (await isCustomResourceFile(jsonPath)) continue;\n names.push(e.name);\n }\n return names;\n};\n\n/**\n * Names of all resource directories (including custom resources).\n * Used for translation generation where every resource is translatable.\n */\nexport const listAllResourceNames = async (\n loaded: LoadedConfig,\n): Promise<string[]> => {\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n if (!(await fileExists(base))) return [];\n const entries = await readdir(base, { withFileTypes: true });\n const names: string[] = [];\n for (const e of entries) {\n if (!e.isDirectory()) continue;\n const jsonPath = join(base, e.name, 'resource.json');\n if (!(await fileExists(jsonPath))) continue;\n names.push(e.name);\n }\n return names;\n};\n\n/**\n * Read and parse all `resource.json` files (including custom resources).\n * Invalid files are silently skipped.\n */\nexport const readAllResourceJsons = async (\n loaded: LoadedConfig,\n): Promise<ResourceJson[]> => {\n const names = await listAllResourceNames(loaded);\n const base = resolveFromRoot(loaded.root, loaded.config.resourcesDir);\n const results: ResourceJson[] = [];\n for (const name of names) {\n try {\n const raw = JSON.parse(\n await readFile(join(base, name, 'resource.json'), 'utf-8'),\n );\n const parsed = buildResourceJsonSchema().safeParse(raw);\n if (parsed.success) results.push(parsed.data);\n } catch {\n /* skip unreadable */\n }\n }\n return results;\n};\n\n/**\n * Build a relation resolver: a relation's target model is \"wired\" when a\n * sibling resource directory exists for it. Returns the relative path used in\n * `fieldInput.resource` (`../<target>/resource.json`), else `undefined`.\n */\nexport const makeRelationResolver = async (\n loaded: LoadedConfig,\n): Promise<(targetModel: string) => string | undefined> => {\n const known = new Set(await listResourceNames(loaded));\n return (targetModel: string) => {\n const accessor = clientAccessor(targetModel);\n return known.has(accessor) ? `../${accessor}/resource.json` : undefined;\n };\n};\n","/**\n * Orchestrator: tie `introspect` output to per-model `classify` + `diff`.\n *\n * Dependencies (existing-config reader, relation resolver, ruleset, database)\n * are injected so this composes cleanly and stays unit-testable without disk.\n */\n\nimport { type CroutonConfig, type Ruleset, RulesetSchema } from '@ghentcdh/crouton-core';\n\nimport { classify } from './classify';\nimport type { DbModel } from './db-model';\nimport type { ResourceDiff } from './decision';\nimport { diff } from './diff';\nimport { resourceNames } from './naming';\nimport type { ExistingResource } from './project';\n\nexport interface BuildDiffsDeps {\n /** Datasource name stamped on generated resources. */\n database?: string;\n ruleset?: Ruleset;\n resolveRelationResource?: (targetModel: string) => string | undefined;\n /** Read the on-disk resource (by directory/route name). */\n readExisting: (name: string) => Promise<ExistingResource>;\n}\n\n/** Merge a config's rule overrides over the defaults. */\nexport const resolveRuleset = (\n config?: Pick<CroutonConfig, 'rules'>,\n): Ruleset => RulesetSchema.parse(config?.rules ?? {});\n\n/** Build the `ResourceDiff` for a single model. */\nexport const buildResourceDiff = async (\n model: DbModel,\n deps: BuildDiffsDeps,\n): Promise<ResourceDiff> => {\n const draft = classify(model, {\n database: deps.database,\n ruleset: deps.ruleset,\n resolveRelationResource: deps.resolveRelationResource,\n });\n const { name } = resourceNames(model.prismaName);\n const { config, hasSchemaFile } = await deps.readExisting(name);\n return diff({ draft, existing: config, hasSchemaFile });\n};\n\n/** Build diffs for many models (sequentially; introspection is already done). */\nexport const buildResourceDiffs = async (\n models: DbModel[],\n deps: BuildDiffsDeps,\n): Promise<ResourceDiff[]> => {\n const diffs: ResourceDiff[] = [];\n for (const model of models) diffs.push(await buildResourceDiff(model, deps));\n return diffs;\n};\n","/**\n * Thin wrappers around the project's Prisma CLI plus git/backup safety for the\n * destructive `db pull` step.\n *\n * Shared by both `crouton-cli` (interactive terminal) and `crouton-api`\n * (dev-mode endpoint). Only uses `node:child_process` / `node:fs` — no\n * framework-specific dependencies.\n */\n\nimport { spawn } from 'node:child_process';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { copyFile, readFile, readdir, writeFile } from 'node:fs/promises';\nimport { createRequire } from 'node:module';\nimport { dirname, join } from 'node:path';\n\n/**\n * Load a .env file from `dir` (or the nearest parent that has one) into\n * `process.env` so that prisma commands inherit DATABASE_URL etc.\n * Uses `dotenv` if available; skips silently otherwise.\n */\nconst loadDotenv = (dir: string): void => {\n try {\n const _require = createRequire(import.meta.url);\n const dotenv = _require('dotenv') as { config: (opts?: { path?: string }) => void };\n let d = dir;\n for (let i = 0; i < 6; i++) {\n if (readdirSync(d).includes('.env')) {\n dotenv.config({ path: join(d, '.env') });\n return;\n }\n const parent = dirname(d);\n if (parent === d) break;\n d = parent;\n }\n } catch { /* dotenv not available or no .env — prisma will read env vars directly */ }\n};\n\n/**\n * Resolve a CLI binary from the project's node_modules first, then fall back\n * to `npx <name>`. Prevents version mismatches where npx downloads a newer\n * major version that has different command names.\n */\nconst resolveBin = (name: string, cwd: string): [string, string[]] => {\n let d = cwd;\n for (let i = 0; i < 6; i++) {\n const bin = join(d, 'node_modules', '.bin', name);\n if (existsSync(bin)) return [bin, []];\n const parent = dirname(d);\n if (parent === d) break;\n d = parent;\n }\n return ['npx', [name]];\n};\n\nconst run = (\n cmd: string,\n args: string[],\n cwd: string,\n): Promise<{ code: number; stdout: string; stderr: string }> =>\n new Promise((resolve) => {\n const child = spawn(cmd, args, { cwd, shell: process.platform === 'win32' });\n let stdout = '';\n let stderr = '';\n child.stdout?.on('data', (d) => (stdout += d.toString()));\n child.stderr?.on('data', (d) => (stderr += d.toString()));\n child.on('error', (err) => resolve({ code: 1, stdout, stderr: stderr + String(err) }));\n child.on('close', (code) => resolve({ code: code ?? 0, stdout, stderr }));\n });\n\n/** True when the given path has uncommitted changes (or git is unavailable → treated as clean). */\nexport const isGitDirty = async (cwd: string, path: string): Promise<boolean> => {\n const { code, stdout } = await run('git', ['status', '--porcelain', '--', path], cwd);\n if (code !== 0) return false; // not a git repo / git missing — don't block\n return stdout.trim().length > 0;\n};\n\n/** Back up a schema file to `<schema>.bak` before a destructive pull. */\nexport const backupSchema = async (schemaPath: string): Promise<string> => {\n const dest = `${schemaPath}.bak`;\n await copyFile(schemaPath, dest);\n return dest;\n};\n\nexport interface PrismaRunResult {\n ok: boolean;\n output: string;\n}\n\n/** Introspect the live database into the schema file. */\nexport const prismaDbPull = async (cwd: string, prismaConfig: string): Promise<PrismaRunResult> => {\n const [bin, prefix] = resolveBin('prisma', cwd);\n const { code, stdout, stderr } = await run(bin, [...prefix, 'db', 'pull', '--config', prismaConfig], cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/** `prisma-case-format` — PascalCase models + camelCase fields with @@map/@map annotations. */\nexport const prismaCaseFormat = async (cwd: string, schemaPath: string): Promise<PrismaRunResult> => {\n // Resolve bin from crouton's own node_modules to avoid ad-hoc npx download failures\n let binPath: string | undefined;\n try {\n const _require = createRequire(import.meta.url);\n binPath = _require.resolve('prisma-case-format/bin/cli.js');\n } catch { /* fall back to npx */ }\n\n const [cmd, args] = binPath\n ? [process.execPath, [binPath, '--file', schemaPath]]\n : ['npx', ['prisma-case-format', '--file', schemaPath]];\n const { code, stdout, stderr } = await run(cmd, args, cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/** `prisma generate` for a datasource's config (triggers the `crouton-prisma` generator). */\nexport const prismaGenerate = async (cwd: string, prismaConfig: string): Promise<PrismaRunResult> => {\n const [bin, prefix] = resolveBin('prisma', cwd);\n const { code, stdout, stderr } = await run(bin, [...prefix, 'generate', '--config', prismaConfig], cwd);\n return { ok: code === 0, output: `${stdout}\\n${stderr}`.trim() };\n};\n\n/**\n * zod-prisma-types sometimes omits `import { z } from 'zod'` in generated\n * schema files. Scan the output directory and inject the import where missing.\n */\nexport const fixZodImports = async (zodOutputDir: string): Promise<number> => {\n let fixed = 0;\n const walk = async (dir: string): Promise<void> => {\n let entries;\n try {\n entries = await readdir(dir, { withFileTypes: true });\n } catch {\n return;\n }\n for (const entry of entries) {\n const full = join(dir, entry.name);\n if (entry.isDirectory()) {\n await walk(full);\n } else if (entry.name.endsWith('.ts')) {\n const src = await readFile(full, 'utf-8');\n if (src.includes('z.') && !src.includes('from \\'zod\\'') && !src.includes('from \"zod\"')) {\n await writeFile(full, `import { z } from 'zod';\\n${src}`, 'utf-8');\n fixed++;\n }\n }\n }\n };\n await walk(zodOutputDir);\n return fixed;\n};\n\nexport interface PullAndGenerateInput {\n root: string;\n prismaConfigPath: string;\n schemaPath: string;\n}\n\nexport interface PullAndGenerateResult {\n ok: boolean;\n backupPath: string;\n dbPull: PrismaRunResult;\n caseFormat?: PrismaRunResult;\n normalizeSchema?: { ok: boolean; renamed: number };\n generate?: PrismaRunResult;\n}\n\n/**\n * Full pull-and-generate pipeline: backup → dbPull → caseFormat →\n * normalizeSchema → generate.\n *\n * Returns a structured result; callers handle UI / error presentation.\n * `dbPull` failure is fatal (returns early with `ok: false`); subsequent\n * step failures are recorded but non-fatal.\n *\n * zod post-processing (fixZodImports) is now owned by the crouton-prisma\n * generator and runs inside `prismaGenerate`.\n */\nexport const pullAndGenerate = async (\n input: PullAndGenerateInput,\n): Promise<PullAndGenerateResult> => {\n const { root, prismaConfigPath, schemaPath } = input;\n loadDotenv(root);\n const backupPath = await backupSchema(schemaPath);\n const dbPull = await prismaDbPull(root, prismaConfigPath);\n if (!dbPull.ok) return { ok: false, backupPath, dbPull };\n const caseFormat = await prismaCaseFormat(root, schemaPath);\n const normalized = await normalizeSchema(schemaPath);\n const generate = await prismaGenerate(root, prismaConfigPath);\n return { ok: true, backupPath, dbPull, caseFormat, normalizeSchema: { ok: true, renamed: normalized.renamed }, generate };\n};\n\ninterface NormalizeConfig {\n renames: Record<string, Record<string, string>>;\n}\n\n/**\n * Rename ugly auto-generated relation field names in a Prisma schema using a\n * `normalize-schema.json` config file placed next to the schema.\n */\nexport const normalizeSchema = async (\n schemaPath: string,\n configDir?: string,\n): Promise<{ renamed: number }> => {\n const dir = configDir ?? dirname(schemaPath);\n const configPath = join(dir, 'normalize-schema.json');\n\n if (!existsSync(configPath)) return { renamed: 0 };\n\n const config: NormalizeConfig = JSON.parse(\n await readFile(configPath, 'utf-8'),\n );\n let schema = await readFile(schemaPath, 'utf-8');\n let renamed = 0;\n\n for (const [modelName, fields] of Object.entries(config.renames)) {\n // Match the model block: `model ModelName { ... }`\n const modelRe = new RegExp(\n `(model\\\\s+${modelName}\\\\s*\\\\{)(.*?)(^})`,\n 'ms',\n );\n schema = schema.replace(modelRe, (_, head: string, body: string, tail: string) => {\n for (const [ugly, clean] of Object.entries(fields)) {\n // Replace field name at start of line (after optional whitespace)\n const fieldRe = new RegExp(`^(\\\\s+)${ugly}\\\\b`, 'gm');\n const replaced = body.replace(fieldRe, `$1${clean}`);\n if (replaced !== body) {\n body = replaced;\n renamed++;\n }\n }\n return `${head}${body}${tail}`;\n });\n }\n\n if (renamed > 0) {\n await writeFile(schemaPath, schema, 'utf-8');\n }\n\n return { renamed };\n};","import type { RawResourceJson } from './WriteResourceJson';\nimport { resolve } from 'node:path';\n\nexport interface ResourceFlagPatch {\n draft?: boolean;\n sidebar?: {\n hide?: boolean;\n group?: string;\n position?: number;\n label?: string;\n };\n}\n\n/**\n * Applies flag changes to a raw resource.json object. Removes keys that are\n * at their schema default (publish = delete `draft`, un-hide = delete\n * `sidebar.hide`, empty sidebar object = delete `sidebar`) so the file stays\n * minimal.\n */\nexport const applyResourceFlagPatch = (\n raw: RawResourceJson,\n patch: ResourceFlagPatch,\n): RawResourceJson => {\n const result = { ...raw };\n\n // --- draft ---\n if (patch.draft !== undefined) {\n if (patch.draft) {\n result['draft'] = true;\n } else {\n delete result['draft'];\n }\n }\n\n // --- sidebar ---\n if (patch.sidebar !== undefined) {\n const existing =\n raw['sidebar'] && typeof raw['sidebar'] === 'object'\n ? { ...(raw['sidebar'] as Record<string, unknown>) }\n : {};\n\n if (patch.sidebar.hide !== undefined) {\n if (patch.sidebar.hide) {\n existing['hide'] = true;\n } else {\n delete existing['hide'];\n }\n }\n if (patch.sidebar.group !== undefined) {\n existing['group'] = patch.sidebar.group;\n }\n if (patch.sidebar.position !== undefined) {\n existing['position'] = patch.sidebar.position;\n }\n if (patch.sidebar.label !== undefined) {\n existing['label'] = patch.sidebar.label;\n }\n\n // Drop sidebar key entirely when it's empty (matches schema default).\n if (Object.keys(existing).length === 0) {\n delete result['sidebar'];\n } else {\n result['sidebar'] = existing;\n }\n }\n\n return result;\n};\n\n/**\n * Resolves `<resourcesDir>/<name>/resource.json` with a path-traversal guard.\n * Throws if the resolved path escapes `resourcesDir`.\n */\nexport const resolveResourcePath = (\n resourcesDir: string,\n name: string,\n): string => {\n const resolved = resolve(resourcesDir, name, 'resource.json');\n if (!resolved.startsWith(resolve(resourcesDir) + '/')) {\n throw new Error(`Invalid resource name: \"${name}\"`);\n }\n return resolved;\n};\n","/**\n * Non-error notices from the resource load pass, complementing `resourceLoadErrorsRegistry`\n * (which holds failures). Records resources that were auto-migrated on disk (`migrated`) or\n * are present but intentionally not served (`draft`), so the status page can show them\n * distinctly from hard errors. Like the errors registry it's a per-load singleton, cleared\n * at the start of every `loadResourceConfigsFromDir`.\n */\n\nexport interface MigratedResourceNotice {\n state: 'migrated';\n name: string;\n path: string;\n from: number;\n to: number;\n}\n\nexport interface DraftResourceNotice {\n state: 'draft';\n name: string;\n path: string;\n version?: number;\n}\n\nexport interface WarningResourceNotice {\n state: 'warning';\n name: string;\n path: string;\n warning: string;\n}\n\nexport type ResourceLoadNotice = MigratedResourceNotice | DraftResourceNotice | WarningResourceNotice;\n\nclass ResourceLoadReportRegistry {\n private notices: ResourceLoadNotice[] = [];\n\n record(n: ResourceLoadNotice) {\n this.notices.push(n);\n }\n\n getAll() {\n return [...this.notices];\n }\n\n getByState<S extends ResourceLoadNotice['state']>(\n state: S,\n ): Extract<ResourceLoadNotice, { state: S }>[] {\n return this.notices.filter(\n (n): n is Extract<ResourceLoadNotice, { state: S }> => n.state === state,\n );\n }\n\n clear() {\n this.notices = [];\n }\n}\n\nexport const resourceLoadReportRegistry = new ResourceLoadReportRegistry();\n","import { z } from 'zod';\n\nexport const EnumEntrySchema = z.object({\n value: z.unknown(),\n label: z.string(),\n});\n\nexport type EnumEntry = z.infer<typeof EnumEntrySchema>;\n\nexport const EnumRegistrySchema = z\n .record(z.string(), z.array(EnumEntrySchema))\n .default({});\n\nexport type EnumRegistry = z.infer<typeof EnumRegistrySchema>;\n","import { type EnumRegistry, EnumRegistrySchema } from './enum-registry.types';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\n\n\nconst ENUMS_FILE = 'crouton.enums.json';\n\nexport const loadEnumRegistry = (\n startDir: string,\n enumsFile?: string,\n): 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 EnumRegistrySchema.parse(undefined);\n try {\n return EnumRegistrySchema.parse(JSON.parse(readFileSync(file, 'utf-8')));\n } catch {\n return EnumRegistrySchema.parse(undefined);\n }\n};","import type { JsonColumn } from '@ghentcdh/crouton-core';\n\nimport { type EnumRegistry } from './enum-registry.types';\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 =\n (col.fieldInput.options as Record<string, unknown> | undefined) ?? {};\n if (!('values' in options)) options.values = values;\n if (!('emitObject' in options)) options.emitObject = true;\n if (!('displayKey' in options)) options.displayKey = 'label';\n col.fieldInput.options = options;\n }\n};","import {\n type CallHandler,\n type ExecutionContext,\n Injectable,\n type NestInterceptor,\n} from '@nestjs/common';\nimport type { Observable } from 'rxjs';\n\n@Injectable()\nexport class NoCacheInterceptor implements NestInterceptor {\n intercept(context: ExecutionContext, next: CallHandler): Observable<unknown> {\n const response = context.switchToHttp().getResponse();\n response.setHeader('Cache-Control', 'no-cache, no-store, must-revalidate');\n response.setHeader('Pragma', 'no-cache');\n response.setHeader('Expires', '0');\n return next.handle();\n }\n}\n","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport { type JsonColumn, type JsonResourceOperations, isRelation } from '@ghentcdh/crouton-core';\n\nimport { type OperationDef, type ResourceDefinition } from '../resource/defintion.schema';\nimport { type SchemaInput } from '../resource/json.schema';\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 baseFilter = (c: JsonColumn) =>\n !isRelation(c) && (filter ? filter(c) : true);\n const schemaKeys = new Set(Object.keys(schema.shape));\n const filtered = columns.filter((c) => baseFilter(c) && schemaKeys.has(c.id));\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 | Record<string, unknown> | 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 if (typeof enabled === 'object' && enabled !== null && 'uri' in enabled) {\n return { uri: enabled['uri'] as string, ...(enabled['method'] ? { method: enabled['method'] as string } : {}) };\n }\n return schema ? { schema } : true;\n};\n\nexport const buildResourceDefinitions = (\n schema: ZodObject<ZodRawShape> | undefined,\n operations: JsonResourceOperations,\n enrichedColumns: JsonColumn[] | undefined,\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\n const definition: ResourceDefinition = {\n ...(opWithSchema(operations.findAll, picked) && {\n findAll: opWithSchema(operations.findAll, picked)!,\n }),\n ...(opWithSchema(operations.findOne, picked) && {\n findOne: opWithSchema(operations.findOne, picked)!,\n }),\n ...(opWithSchema(operations.create, createSchema) && {\n create: opWithSchema(operations.create, createSchema)!,\n }),\n ...(opWithSchema(operations.update, updateSchema) && {\n update: opWithSchema(operations.update, updateSchema)!,\n }),\n ...(opWithSchema(operations.patch as any, undefined) && {\n patch: opWithSchema(operations.patch as any, undefined)!,\n }),\n ...(opWithSchema(operations.delete as any, undefined) && {\n delete: opWithSchema(operations.delete as any, undefined)!,\n }),\n };\n\n return definition;\n};\n","import { ZodArray, ZodNullable, type ZodObject, ZodOptional, type ZodRawShape } from 'zod';\n\nimport type { JsonColumn, RelationType } from '@ghentcdh/crouton-core';\n\n/** Recursively unwrap Optional / Nullable wrappers to reach the inner Zod type. */\nexport const 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 */\nexport const 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 * 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 */\nexport const 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 * 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 */\nexport const 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};","import type { JsonColumn, JsonIncludeEntry, RelationFieldInputOptions } from '@ghentcdh/crouton-core';\n\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { buildChildSortClause } from '../sql.helpers';\nimport { deriveRelationTypeFromColumns } from './relation-type';\nimport { resolveChildResource } from './resource-resolver';\n\n/**\n * Return a new columns array with `uri`, `resourceUri`, and `resource` (schemas URL)\n * injected into `fieldInput.options` for relation columns.\n */\nexport const 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 resource:\n sub.relationType === 'manyToOne'\n ? `${base}/${sub.childRoute}/schemas`\n : `${base}/${parentRoute}/${sub.childRoute}/schemas`,\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 */\nexport const 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\n .replace(/^\\.\\.?\\//, '')\n .replace(/\\/resource\\.json$/, '')\n .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 * 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 */\nexport const 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 * 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 */\nexport const 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\n 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","import type { JsonColumn, JsonIncludeEntry, RelationFieldInputOptions } from '@ghentcdh/crouton-core';\nimport {\n buildViewsFromColumns,\n injectCalculatedColumns,\n injectCalculatedColumnsToView,\n} from '@ghentcdh/crouton-core';\n\nimport { type EnumRegistry, injectEnumValues } from '../enum-registry';\nimport { enrichNestedRelationColumns } from './column-enrichment';\nimport { applyRelationFormatDefault, buildValueLabelColumns, expandExtendColumns } from './column-transforms';\nimport type { SubResourceConfig } from '../resource/SubResource.schema';\nimport { buildChildSortClause } from '../sql.helpers';\nimport { deriveRelationTypeFromColumns } from './relation-type';\nimport { resolveChildResourceDetailed } from './resource-resolver';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\n\n/**\n * A relation column may point at another service rather than a local child\n * config. Those still render (autocomplete against the remote resource) but are\n * not managed as sub-resources, so they are skipped without complaint.\n */\nconst REMOTE_RESOURCE = /^https?:\\/\\//i;\n\n/**\n * Build `SubResourceConfig` entries for columns with `fieldInput.format === \"action\"`.\n */\nexport const 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 .flatMap((c) => {\n const resourcePath = c.fieldInput!.resource!;\n if (REMOTE_RESOURCE.test(resourcePath)) return [];\n\n const resolution = resolveChildResourceDetailed(resourcePath, parentDir);\n\n // A child that cannot be resolved used to fall through as a Prisma-backed\n // sub-resource named after the column, which registers `:id/<column>`\n // routes that fail at request time with `Prisma model \"<column>\" not\n // found`. Report it at load time and register nothing instead.\n if (!resolution.ok) {\n resourceLoadErrorsRegistry.record({\n name: parentRoute,\n path: resourcePath,\n error:\n resolution.reason === 'missing'\n ? `Relation column \"${c.id}\" points at \"${resourcePath}\", but no resource.json was found there (looked in: ${resolution.attempted.join(', ')}). Sub-resource routes for it were not registered.`\n : `Relation column \"${c.id}\" points at \"${resourcePath}\", which could not be read: ${resolution.error} Sub-resource routes for it were not registered.`,\n });\n return [];\n }\n\n const childJson = resolution.value.json;\n const childDir = resolution.value.dir;\n\n // `parent` mounts the child's own controller under the parent route. Also\n // declaring it as a sub-resource registers a second, competing handler for\n // the same path off the parent's controller — one of the two silently wins.\n if (childJson.parent) {\n resourceLoadErrorsRegistry.record({\n name: parentRoute,\n path: resourcePath,\n error:\n `Relation column \"${c.id}\" declares \"${childJson.name}\" as a sub-resource, but that resource also declares \"parent\": { \"route\": \"${childJson.parent.route}\" }. ` +\n 'The two ways of nesting are mutually exclusive — remove the \"parent\" block to embed it in this resource, or remove this relation column to keep its own nested controller. Sub-resource routes for it were not registered.',\n });\n return [];\n }\n\n const childRoute =\n childJson.route ??\n resourcePath\n .replace(/^\\.\\.?\\//, '')\n .replace(/\\/resource\\.json$/, '')\n .replace(/\\.resource$/, '');\n\n const rawChildColumns = childJson?.columns;\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 // Auto-derive includes for manyToOne child relations (mirrors main resource logic in read.repository)\n const autoIncludes: string[] = (enrichedChildColumns ?? [])\n .filter(\n (col) =>\n col.fieldInput?.format === 'relation' &&\n (col.fieldInput.relationType ??\n deriveRelationTypeFromColumns(col, enrichedChildColumns!)) ===\n 'manyToOne',\n )\n .map((col) => col.fieldInput?.relation ?? col.id);\n const explicitIncludes: JsonIncludeEntry[] = childJson?.include ?? [];\n const explicitNames = new Set(\n explicitIncludes.map((e) =>\n typeof e === 'string' ? e : e.relation,\n ),\n );\n const mergedIncludes: JsonIncludeEntry[] = [\n ...explicitIncludes,\n ...autoIncludes.filter((name) => !explicitNames.has(name)),\n ];\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 const childKind = childJson?.kind === 'custom' ? 'custom' : 'prisma';\n\n return {\n column: c.id,\n relation: c.fieldInput?.relation ?? c.id,\n childRoute,\n childKind,\n ...(childDir && { childDir }),\n // A custom child has no Prisma model. Leave it empty rather than\n // falling back to the column id, which would produce a bogus\n // `prisma[<column>]` lookup at query time.\n // Use the child resource's declared model name so plural column ids\n // (e.g. \"books\") resolve to the correct Prisma delegate (prisma.book).\n // ponytail: charAt toLowerCase is cheap; Prisma model names are always PascalCase\n childModel:\n childKind === 'custom'\n ? ''\n : childJson?.model\n ? childJson.model.charAt(0).toLowerCase() + childJson.model.slice(1)\n : c.id,\n foreignKey: c.fieldInput?.foreignKey ?? `${parentModel}Id`,\n name: childJson?.name ?? childRoute,\n title: childJson?.title ?? childJson?.tag ?? childRoute,\n idField: childLookupKey,\n idType: childJson?.idType ?? 'string',\n ...(c.hiddenInTable && { hiddenInTable: true }),\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 patch: childOps.patch !== false,\n delete: childOps.delete !== false,\n },\n ...(childJson?.actions?.length && { actions: childJson.actions }),\n ...(childJson?.modalSize && { modalSize: childJson.modalSize }),\n ...(childJson?.display && { display: childJson.display }),\n ...(mergedIncludes.length && { include: mergedIncludes }),\n ...(childJson?.calculatedColumns?.length && {\n calculatedColumns: childJson.calculatedColumns,\n }),\n ...((c.hiddenInForm === false || c.hiddenInView === false) && {\n includeInFindOne: true,\n ...(() => {\n const opts = c.fieldInput?.options as RelationFieldInputOptions | undefined;\n if (opts?.sort) return { findOneOrderBy: buildChildSortClause(opts.sort, opts.sortDir) };\n return {};\n })(),\n }),\n ...(buildValueLabelColumns(childColumns).length && {\n valueLabelColumns: buildValueLabelColumns(childColumns),\n }),\n relationType: c.fieldInput?.relationType ?? deriveRelationTypeFromColumns(c, columns!),\n } satisfies SubResourceConfig;\n });\n};","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport type {\n CalculatedColumn,\n JsonColumn,\n ResourceJson,\n} from '@ghentcdh/crouton-core';\nimport {\n buildViews,\n getResourceExtensions,\n injectCalculatedColumns,\n injectCalculatedColumnsToView,\n} from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from '../action';\nimport { buildResourceDefinitions } from '../builder/schema.helpers';\nimport type { CustomRepository } from '../custom-repository';\nimport { type EnumRegistry, injectEnumValues } from '../enum-registry';\nimport type { ResourceHooks } from '../hooks';\nimport {\n enrichActionColumns,\n enrichIncludeWithSort,\n enrichResourceRefColumns,\n} from './column-enrichment';\nimport {\n applyRelationFormatDefault,\n buildValueLabelColumns,\n expandExtendColumns,\n resolveColumnFieldVariants,\n} from './column-transforms';\nimport { enrichRelationTypes } from './relation-type';\nimport { resolveChildResource } from './resource-resolver';\nimport { buildSubResources } from './sub-resource.builder';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport type { LookupConfig } from '../resource/lookup.schema';\n\nconst pickExtensions = (obj: Record<string, unknown>) =>\n Object.fromEntries([...getResourceExtensions().keys()].filter(k => obj[k] !== undefined).map(k => [k, obj[k]]));\n\nexport const fromJson = (\n json: ResourceJson,\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?: ResourceRowAction[],\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 /** Data access for a `kind: \"custom\"` resource, loaded from `repository.ts`. */\n repository?: CustomRepository,\n): Resource => {\n const isCustom = json.kind === 'custom';\n const rawColumns = expandExtendColumns(json.columns, dirPath);\n const columns = enrichRelationTypes(\n applyRelationFormatDefault(rawColumns) ?? rawColumns,\n schema,\n );\n injectEnumValues(columns, enums);\n\n // Sub-resources are served by nested Prisma queries against the child model,\n // which a custom resource has no equivalent of. Relation columns still render\n // (autocomplete/link) — they just aren't managed through child routes here.\n const subResources = isCustom\n ? []\n : buildSubResources(\n columns,\n json.route,\n json.model ?? '',\n dirPath,\n enums,\n baseUrl,\n );\n // Resolve fieldView/fieldTable variants LAST, after URI/relation enrichment,\n // so the resolved variants inherit the injected relation/resource options.\n const enrichedColumns = resolveColumnFieldVariants(\n enrichResourceRefColumns(\n enrichActionColumns(columns, json.route, subResources, baseUrl),\n dirPath,\n baseUrl,\n ) ?? columns,\n )!;\n\n const calculatedColumns: CalculatedColumn[] = json.calculatedColumns ?? [];\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, dirPath);\n const enrichedInclude = enrichIncludeWithSort(json.include, enrichedColumns);\n const definition = buildResourceDefinitions(\n schema,\n json.operations,\n enrichedColumns,\n );\n\n return {\n ...json,\n name: json.name,\n route: json.route,\n model: json.model,\n tag: json.tag,\n sidebar: json.sidebar,\n display: json.display,\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 ...(repository && { repository }),\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 ...pickExtensions(json as Record<string, unknown>),\n };\n};\n\nconst buildLookup = (\n columns: JsonColumn[] | undefined,\n dirPath?: string,\n): LookupConfig | undefined => {\n if (!columns) return undefined;\n\n const keyCol = columns.find((c) => c.idField);\n const searchCols = columns.filter((c) => c.showInLookup || c.searchable);\n\n if (!keyCol && !searchCols.length) return undefined;\n\n const labels = searchCols.map((col) => {\n if (col.fieldInput?.relationType === 'manyToOne' && col.fieldInput?.resource && dirPath) {\n const relationName = col.id.replace(/Id$/, '');\n const child = resolveChildResource(col.fieldInput.resource, dirPath);\n const childColumns = child ? expandExtendColumns(child.json.columns, dirPath) : undefined;\n const displayCol = childColumns?.find((c) => !c.idField && !c.hiddenInTable);\n if (displayCol) return `${relationName}.${displayCol.id}`;\n }\n return col.id;\n });\n\n return {\n key: keyCol?.id ?? 'id',\n ...(labels.length && { label: labels[0], labels }),\n };\n};\n","/**\n * Load-time migration for a single `resource.json`.\n *\n * Auto-migration is a DEV-ONLY capability: it rewrites the checked-in file, so it needs a\n * writable, version-controlled checkout (the diff is meant to be reviewed and committed).\n * Outside dev, an out-of-date file is reported as a failure rather than silently rewritten\n * or run against stale config — the normal flow is that dev migrates + commits, so prod only\n * ever sees files already at `CURRENT_RESOURCE_VERSION`.\n *\n * Operates on the RAW object (via `WriteResourceJson`'s raw-preserving helpers) so a rewrite\n * stays a minimal, byte-stable diff; validation with Zod happens only after migrating.\n */\n\nimport {\n BASELINE_RESOURCE_VERSION,\n CURRENT_RESOURCE_VERSION,\n MigrationPathError,\n MigrationStepError,\n resourceVersionOf,\n runResourceMigrations,\n} from '@ghentcdh/crouton-core';\n\nimport {\n readRawResourceJson,\n serializeResourceJson,\n validateResourceJson,\n} from './WriteResourceJson';\nimport { writeFileSync } from 'node:fs';\n\nexport type MigrateOutcome =\n | { status: 'current'; version: number }\n | { status: 'migrated'; from: number; to: number; written: boolean }\n | { status: 'failed'; version: number; expected: number; error: string };\n\nexport const migrateResourceJsonFile = (\n jsonPath: string,\n opts: { isDev: boolean },\n): MigrateOutcome => {\n // If the file is missing or not valid JSON, don't fail here — pass through so the normal\n // reader (`readResourceJson`) reports the parse error verbatim, exactly as before.\n let raw: Record<string, unknown> | undefined;\n try {\n raw = readRawResourceJson(jsonPath);\n } catch {\n return { status: 'current', version: BASELINE_RESOURCE_VERSION };\n }\n if (!raw) return { status: 'current', version: BASELINE_RESOURCE_VERSION };\n\n const from = resourceVersionOf(raw);\n if (from === CURRENT_RESOURCE_VERSION) {\n return { status: 'current', version: from };\n }\n\n // Out of date (or newer). Migration only runs in the dev environment.\n if (!opts.isDev) {\n return {\n status: 'failed',\n version: from,\n expected: CURRENT_RESOURCE_VERSION,\n error:\n `resource.json is version ${from} but crouton expects ${CURRENT_RESOURCE_VERSION}; ` +\n 'auto-migration only runs in the dev environment — run crouton in dev to upgrade and commit it',\n };\n }\n\n try {\n const result = runResourceMigrations(raw);\n const validation = validateResourceJson(result.raw);\n if (!validation.success) {\n return {\n status: 'failed',\n version: from,\n expected: CURRENT_RESOURCE_VERSION,\n error: `migrated resource.json (v${from}→v${result.to}) is invalid: ${validation.error.message}`,\n };\n }\n writeFileSync(jsonPath, serializeResourceJson(result.raw), 'utf-8');\n return { status: 'migrated', from: result.from, to: result.to, written: true };\n } catch (err) {\n // MigrationPathError / MigrationStepError (or anything unexpected) → surfaced on status page.\n const error =\n err instanceof MigrationPathError || err instanceof MigrationStepError\n ? (err as Error).message\n : `migration failed: ${(err as Error).message}`;\n return { status: 'failed', version: from, expected: CURRENT_RESOURCE_VERSION, error };\n }\n};\n","import { type CrudOperation, isOperationEnabled, resolveDefinition } from '../crud.config';\nimport type { Resource } from './ResourceConfig.schema';\nimport { validateCustomRepository } from '../custom-repository/custom-repository.validate';\n\nconst ALL_OPS: readonly CrudOperation[] = [\n 'findAll',\n 'findOne',\n 'create',\n 'update',\n 'patch',\n 'delete',\n];\n\n/**\n * Run structural checks on a fully-built Resource config before it is served.\n * Returns errors (→ resourceLoadErrorsRegistry) and warnings (→ resourceLoadReportRegistry).\n *\n * @param repositoryFileExistsOnDisk - pass true when a repository.ts file exists next to\n * a prisma resource, so the validator can warn that it will be ignored.\n */\nexport const validateResourceConfig = (\n config: Resource,\n opts?: { repositoryFileExistsOnDisk?: boolean },\n): { errors: string[]; warnings: string[] } => {\n const errors: string[] = [];\n const warnings: string[] = [];\n\n const definition = resolveDefinition(config);\n const enabledOps = ALL_OPS.filter((op) => isOperationEnabled(definition, op));\n\n if (enabledOps.length === 0) {\n warnings.push('All operations are disabled — this resource serves nothing.');\n }\n\n if (config.kind === 'custom') {\n if (config.database) {\n warnings.push(\n '\"database\" is set alongside kind: \"custom\" — it selects the client injected as ' +\n 'ctx.prisma, but data access still comes from repository.ts.',\n );\n }\n\n const repoError = validateCustomRepository(config, config.repository);\n if (repoError) errors.push(repoError);\n } else {\n if (opts?.repositoryFileExistsOnDisk) {\n warnings.push(\n 'repository.ts is present on a prisma resource and will be ignored — ' +\n 'set kind: \"custom\" if you want to use it for data access.',\n );\n }\n }\n\n return { errors, warnings };\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 * A `kind: \"custom\"` resource has no `schema.ts` — its json model is built\n * from the column `type`s — and supplies data access in `repository.ts`.\n *\n * `resource.ts` / `hooks.ts` / `schema.ts` / `repository.ts` do **not** import\n * from each other — this loader is the only place that stitches them together.\n */\n\nimport type { ZodObject, ZodRawShape } from 'zod';\n\nimport { loadActions } from '../action';\nimport { fromJson } from '../adapter';\nimport {\n loadCustomRepository,\n loadSubResourceRepositories,\n} from '../custom-repository';\nimport { IS_DEV } from '../dev-mode';\nimport { loadEnumRegistry } from '../enum-registry';\nimport { findModule, importDefault } from './module.loader';\nimport { loadResourceHooks, loadSubResourceHooks } from '../hooks';\nimport { migrateResourceJsonFile } from '../resource/MigrateResourceJson';\nimport { readResourceJson } from '../resource/ReadResourceJson';\nimport { type Resource } from '../resource/ResourceConfig.schema';\nimport { validateResourceConfig } from '../resource/resource-config.validator';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\nimport { existsSync, readdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nexport const loadResourceConfigsFromDir = async (\n dirPath: string,\n baseUrl?: string,\n enumsFile?: string,\n onResourceDir?: (route: string, dir: string) => void,\n): Promise<Resource[]> => {\n if (!existsSync(dirPath)) return [];\n\n resourceLoadErrorsRegistry.clear();\n resourceLoadReportRegistry.clear();\n\n const enums = loadEnumRegistry(dirPath, enumsFile);\n const entries = readdirSync(dirPath, { withFileTypes: true });\n const dirs = entries\n .filter((e: { isDirectory(): boolean }) => e.isDirectory())\n .map((e: { name: string }) => e.name);\n const configs: Resource[] = [];\n\n for (const dir of dirs) {\n const basePath = join(dirPath, dir);\n\n const schemaFile = findModule(basePath, 'schema');\n const schema = schemaFile\n ? await importDefault<ZodObject<ZodRawShape>>(schemaFile)\n : undefined;\n\n const hooks = await loadResourceHooks(basePath);\n\n const jsonFile = join(basePath, 'resource.json');\n if (existsSync(jsonFile)) {\n // Bring the file to the current schema version first. In dev this rewrites it on\n // disk; elsewhere an out-of-date file is reported as a failure (not migrated).\n const migration = migrateResourceJsonFile(jsonFile, { isDev: IS_DEV });\n if (migration.status === 'failed') {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: migration.error,\n version: migration.version,\n expectedVersion: migration.expected,\n });\n continue;\n }\n if (migration.status === 'migrated') {\n resourceLoadReportRegistry.record({\n state: 'migrated',\n name: dir,\n path: jsonFile,\n from: migration.from,\n to: migration.to,\n });\n // eslint-disable-next-line no-console\n console.info(\n `[crouton] migrated ${jsonFile}: v${migration.from} → v${migration.to}`,\n );\n }\n\n const result = readResourceJson(jsonFile);\n\n if (!result || !result.success) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: jsonFile,\n error: result?.error ?? `Failed to read ${jsonFile}`,\n });\n continue;\n }\n\n const json = result.data.json;\n\n // Draft resources live in the repo but are not loaded/served. They are still\n // migrated above (in dev) so they stay current until the flag is flipped.\n if (json.draft) {\n resourceLoadReportRegistry.record({\n state: 'draft',\n name: dir,\n path: jsonFile,\n version: json.schemaVersion,\n });\n continue;\n }\n // Custom resources own their data access; prisma resources never load a\n // repository, so a stray repository.ts on one is simply ignored.\n const errorsBeforeRepo = resourceLoadErrorsRegistry.getAll().length;\n const repository =\n json.kind === 'custom'\n ? await loadCustomRepository(basePath, json.name)\n : undefined;\n // If the repository.ts file exists but failed to import, an error was already\n // recorded by loadCustomRepository. Skip further validation to avoid a double error.\n const repositoryImportFailed = resourceLoadErrorsRegistry.getAll().length > errorsBeforeRepo;\n\n const actions = await loadActions(json.actions ?? [], basePath, 'row');\n const tableActions = await loadActions(\n json.tableActions ?? [],\n basePath,\n 'table',\n );\n const config = fromJson(\n json,\n schema,\n hooks,\n basePath,\n baseUrl,\n actions,\n tableActions,\n enums,\n repository,\n );\n\n if (repositoryImportFailed) continue;\n\n const repositoryFileExistsOnDisk =\n json.kind !== 'custom' && !!findModule(basePath, 'repository');\n const { errors, warnings } = validateResourceConfig(config, { repositoryFileExistsOnDisk });\n\n if (errors.length > 0) {\n for (const error of errors) {\n resourceLoadErrorsRegistry.record({ name: dir, path: jsonFile, error });\n }\n continue;\n }\n\n for (const warning of warnings) {\n resourceLoadReportRegistry.record({ state: 'warning', name: config.name, path: jsonFile, warning });\n }\n\n await loadSubResourceHooks(config.subResources ?? [], basePath);\n // A custom sub-resource brings its own data access; the parent's\n // repository delegates to it instead of querying a Prisma model.\n await loadSubResourceRepositories(config.subResources ?? [], config.name);\n onResourceDir?.(config.route, basePath);\n configs.push(config);\n continue;\n }\n\n const tsFile = findModule(basePath, 'resource');\n if (tsFile) {\n const config = await importDefault<Resource>(tsFile);\n if (!config) {\n resourceLoadErrorsRegistry.record({\n name: dir,\n path: tsFile,\n error: 'resource.ts has no default export — add `export default { name, route, ... }`.',\n });\n continue;\n }\n if (config.draft) {\n resourceLoadReportRegistry.record({\n state: 'draft',\n name: dir,\n path: tsFile,\n version: config.schemaVersion,\n });\n continue;\n }\n\n const merged = hooks ? { ...config, hooks } : config;\n const { errors, warnings } = validateResourceConfig(merged);\n\n if (errors.length > 0) {\n for (const error of errors) {\n resourceLoadErrorsRegistry.record({ name: dir, path: tsFile, error });\n }\n continue;\n }\n\n for (const warning of warnings) {\n resourceLoadReportRegistry.record({ state: 'warning', name: merged.name, path: tsFile, warning });\n }\n\n configs.push(merged);\n }\n }\n\n return configs;\n};\n","import { type Resource } from '../resource/ResourceConfig.schema';\n\nexport abstract class ResourceConfigLoader {\n abstract loadAll(): Promise<Resource[]>;\n abstract loadByRoute(route: string): Promise<Resource | undefined>;\n /**\n * On-disk directory containing this resource's `resource.json`, if the\n * loader knows one (populated as a side effect of the last `loadAll()`).\n * Returns `undefined` for loaders with no filesystem concept (e.g. a\n * resource defined purely via `resource.ts`) or before any load has run.\n */\n getResourceDir(_route: string): string | undefined {\n return undefined;\n }\n}\n","import { loadResourceConfigsFromDir } from './index';\n\nimport { ResourceConfigLoader } from './resource-config.loader';\nimport { type Resource } from '../resource/ResourceConfig.schema';\n\nexport class FileSystemResourceConfigLoader extends ResourceConfigLoader {\n private dirsByRoute = new Map<string, string>();\n\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<Resource[]> {\n const dirsByRoute = new Map<string, string>();\n const configs = await loadResourceConfigsFromDir(\n this.dirPath,\n this.baseUrl,\n this.enumsFile,\n (route, dir) => dirsByRoute.set(route, dir),\n );\n this.dirsByRoute = dirsByRoute;\n return configs;\n }\n\n async loadByRoute(route: string): Promise<Resource | undefined> {\n const configs = await this.loadAll();\n return configs.find((c) => c.route === route);\n }\n\n override getResourceDir(route: string): string | undefined {\n return this.dirsByRoute.get(route);\n }\n}\n","import { CURRENT_RESOURCE_VERSION } from '@ghentcdh/crouton-core';\n\nimport { CUSTOM_OPS } from '../custom-repository';\nimport type { DataSourceRegistry } from '../data-source';\nimport type {\n CroutonStatus,\n DatabaseStatus,\n EnumGroup,\n EnumSections,\n I18nStatus,\n ResourceStatus,\n StatusSummary,\n} from './status.types';\nimport type { EnumRegistry } from '../enum-registry/enum-registry.types';\nimport type { Resource } from '../resource/ResourceConfig.schema';\nimport { resourceLoadErrorsRegistry } from '../resource/resource-load-errors.registry';\nimport { resourceLoadReportRegistry } from '../resource/resource-load-report.registry';\nimport type { TranslationRegistry } from '../translation/translation.registry';\nimport { existsSync, readFileSync } from 'node:fs';\nimport { dirname, join } from 'node:path';\nimport { fileURLToPath } from 'node:url';\n\nconst CONNECTION_STRING_PATTERN =\n /(?:postgresql|postgres|mysql|mongodb|sqlserver|sqlite):\\/\\/[^\\s\"')]+/gi;\n\nconst stripConnectionStrings = (message: string): string =>\n message.replace(CONNECTION_STRING_PATTERN, '[REDACTED]');\n\nexport const getCroutonVersion = (): string => {\n try {\n const startDir =\n typeof __dirname !== 'undefined'\n ? __dirname\n : dirname(fileURLToPath(import.meta.url));\n\n let dir = startDir;\n while (dir !== dirname(dir)) {\n const pkgPath = join(dir, 'package.json');\n if (existsSync(pkgPath)) {\n const pkg = JSON.parse(readFileSync(pkgPath, 'utf-8'));\n if (pkg.name === '@ghentcdh/crouton-api') return pkg.version;\n }\n dir = dirname(dir);\n }\n } catch {\n // ignore\n }\n return 'unknown';\n};\n\nexport const getVersion = (): string =>\n process.env['APP_VERSION'] ?? 'unknown';\n\nexport const getEnvironment = (): string =>\n process.env['ENVIRONMENT'] ?? process.env['NODE_ENV'] ?? 'unknown';\n\nexport const checkDatabases = async (\n registry: DataSourceRegistry,\n): Promise<DatabaseStatus[]> => {\n const results: DatabaseStatus[] = [];\n\n for (const { name, adapter } of registry.entries()) {\n try {\n await adapter.healthCheck?.();\n results.push({ name, connected: true });\n } catch (err) {\n results.push({\n name,\n connected: false,\n error: stripConnectionStrings((err as Error).message),\n });\n }\n }\n\n return results;\n};\n\nexport const getResourceStatus = (\n loadedConfigs: Resource[],\n): ResourceStatus[] => {\n const warningsByName = new Map<string, string[]>();\n for (const w of resourceLoadReportRegistry.getByState('warning')) {\n const existing = warningsByName.get(w.name) ?? [];\n existing.push(w.warning);\n warningsByName.set(w.name, existing);\n }\n\n const valid: ResourceStatus[] = loadedConfigs.map((c) => ({\n name: c.name,\n path: c.route,\n valid: true,\n version: c.schemaVersion ?? CURRENT_RESOURCE_VERSION,\n kind: c.kind ?? 'prisma',\n // Which operations the user's repository.ts actually implements.\n ...(c.kind === 'custom' && c.repository\n ? {\n customOperations: CUSTOM_OPS.filter(\n (op) => typeof (c.repository as any)?.[op] === 'function',\n ),\n }\n : {}),\n ...(c.sidebar?.hide ? { hidden: true } : {}),\n ...(warningsByName.has(c.name) ? { warnings: warningsByName.get(c.name) } : {}),\n }));\n\n const failed: ResourceStatus[] = resourceLoadErrorsRegistry\n .getAll()\n .map((e) => ({\n name: e.name,\n path: e.path,\n valid: false,\n error: e.error,\n version: e.version,\n expectedVersion: e.expectedVersion,\n }));\n\n // Drafts are present-but-not-served — informational, not errors (valid: true).\n const draft: ResourceStatus[] = resourceLoadReportRegistry\n .getByState('draft')\n .map((d) => ({\n name: d.name,\n path: d.path,\n valid: true,\n draft: true,\n version: d.version,\n }));\n\n return [...valid, ...failed, ...draft];\n};\n\nexport const buildSummary = (\n databases: DatabaseStatus[],\n resources: ResourceStatus[],\n): StatusSummary => {\n const databaseErrors = databases.filter((d) => !d.connected).length;\n const resourceErrors = resources.filter((r) => !r.valid).length;\n const warningCount = resources.reduce((acc, r) => acc + (r.warnings?.length ?? 0), 0);\n\n return {\n ok: databaseErrors === 0 && resourceErrors === 0,\n databaseErrors,\n resourceErrors,\n warningCount,\n };\n};\n\n/**\n * Extract built-in enums from Zod schema definitions.\n * These are system-level enums used throughout the framework.\n */\nconst getSystemEnums = (): EnumGroup[] => {\n return [\n {\n name: 'RelationType',\n category: 'Relationships',\n values: [\n { value: 'oneToOne', label: 'One to One' },\n { value: 'manyToOne', label: 'Many to One' },\n { value: 'oneToMany', label: 'One to Many' },\n { value: 'manyToMany', label: 'Many to Many' },\n ],\n },\n {\n name: 'DetailLayout',\n category: 'Layout',\n values: [\n { value: 'collapse', label: 'Collapse' },\n { value: 'row', label: 'Row' },\n ],\n },\n {\n name: 'SortDirection',\n category: 'Sorting',\n values: [\n { value: 'asc', label: 'Ascending' },\n { value: 'desc', label: 'Descending' },\n ],\n },\n {\n name: 'DisplayMode',\n category: 'Display',\n values: [\n { value: 'page', label: 'Page' },\n { value: 'modal', label: 'Modal' },\n ],\n },\n {\n name: 'ModalSize',\n category: 'Display',\n values: [\n { value: 'xs', label: 'Extra Small' },\n { value: 'sm', label: 'Small' },\n { value: 'lg', label: 'Large' },\n { value: 'xl', label: 'Extra Large' },\n ],\n },\n ];\n};\n\n/**\n * Convert project enum registry into EnumGroup format.\n * Groups enums from crouton.enums.json by generic category.\n */\nconst getProjectEnums = (enumRegistry: EnumRegistry): EnumGroup[] => {\n if (!enumRegistry) return [];\n return Object.entries(enumRegistry).map(([name, entries]) => ({\n name,\n category: 'Project',\n values: entries.map((entry) => ({\n value: entry.value,\n label: entry.label,\n })),\n }));\n};\n\n/**\n * Collect all enums (system and project) for display on status page.\n */\nconst getEnums = (enumRegistry: EnumRegistry): EnumSections => {\n return {\n system: getSystemEnums(),\n project: getProjectEnums(enumRegistry),\n };\n};\n\n/** Count leaf string keys in a nested object, and how many are empty. */\nconst countKeys = (\n obj: Record<string, unknown>,\n prefix = '',\n): { total: number; empty: number } => {\n let total = 0;\n let empty = 0;\n for (const [, v] of Object.entries(obj)) {\n if (typeof v === 'string') {\n total++;\n if (v === '') empty++;\n } else if (v && typeof v === 'object' && !Array.isArray(v)) {\n const sub = countKeys(v as Record<string, unknown>, prefix);\n total += sub.total;\n empty += sub.empty;\n }\n }\n return { total, empty };\n};\n\nconst getI18nStatus = (\n translationRegistry?: TranslationRegistry,\n): I18nStatus | undefined => {\n if (!translationRegistry?.active) return undefined;\n const languages = [...translationRegistry.languages];\n const bundles = languages.map((language) => {\n const bundle = translationRegistry.bundleFor(language);\n const { total, empty } = countKeys(bundle as Record<string, unknown>);\n return { language, keyCount: total, emptyKeys: empty };\n });\n return {\n active: true,\n defaultLanguage: translationRegistry.defaultLanguage,\n languages,\n bundles,\n };\n};\n\nexport const buildStatus = async (\n registry: DataSourceRegistry,\n loadedConfigs: Resource[],\n enumRegistry: EnumRegistry,\n translationRegistry?: TranslationRegistry,\n): Promise<CroutonStatus> => {\n const databases = await checkDatabases(registry);\n const resources = getResourceStatus(loadedConfigs);\n const summary = buildSummary(databases, resources);\n\n return {\n version: getVersion(),\n croutonVersion: getCroutonVersion(),\n environment: getEnvironment(),\n summary,\n databases,\n resources,\n enums: getEnums(enumRegistry),\n ...(translationRegistry?.active && {\n i18n: getI18nStatus(translationRegistry),\n }),\n };\n};\n","import { Controller, Get } from '@nestjs/common';\nimport { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';\n\nimport { DataSourceRegistry } from '../data-source';\nimport { ResourceConfigRegistry } from '../resource-config.registry';\nimport { buildStatus } from './status.service';\nimport type { EnumRegistry } from '../enum-registry/enum-registry.types';\nimport type { TranslationRegistry } from '../translation/translation.registry';\n\nexport const createStatusController = (\n enumRegistry: EnumRegistry,\n translationRegistry?: TranslationRegistry,\n prefix?: string,\n) => {\n @Controller(prefix ? `${prefix}/crouton` : 'crouton')\n @ApiTags('Status')\n class StatusController {\n constructor(\n public readonly dataSourceRegistry: DataSourceRegistry,\n public readonly configRegistry: ResourceConfigRegistry,\n ) {}\n\n @Get('status.json')\n @ApiOperation({ summary: 'Crouton system status (db, resources, version)' })\n @ApiResponse({ status: 200, description: 'System status' })\n async getStatus() {\n const configs = await this.configRegistry.getAll();\n return buildStatus(\n this.dataSourceRegistry,\n configs,\n enumRegistry,\n translationRegistry,\n );\n }\n }\n\n Reflect.defineMetadata(\n 'design:paramtypes',\n [DataSourceRegistry, ResourceConfigRegistry],\n StatusController,\n );\n\n return StatusController;\n};\n","import type { ZodObject, ZodRawShape } from 'zod';\n\nimport { buildResourceJsonSchema, registerResourceExtensions } from '@ghentcdh/crouton-core';\n\nimport type { ResourceRowAction, ResourceTableAction } from './action';\nimport { fromJson } from './adapter';\nimport type { CroutonAppConfig } from './app-config';\nimport type { EnumRegistry } from './enum-registry';\nimport type { ResourceHooks } from './hooks';\nimport {\n buildDefinitionPayload,\n buildResourceJsonPayload,\n buildViewsPayload,\n} from './operations/payload-builders';\n\nexport type ParseSchemaView = 'schemas' | 'definition' | 'resource.json';\n\nexport interface ParseSchemaInput {\n /** Raw resource.json (validated internally) or an already-parsed ResourceJson. */\n json: unknown;\n /** Sibling schema.ts default export. Required for prisma resources; omit for kind:\"custom\". */\n schema?: ZodObject<ZodRawShape>;\n /** Enables sibling-resource features (extend columns, resource-ref options, sub-resources). */\n dirPath?: string;\n enums?: EnumRegistry;\n hooks?: ResourceHooks;\n actions?: ResourceRowAction[];\n tableActions?: ResourceTableAction[];\n}\n\nexport type ParseAppConfig = Pick<\n CroutonAppConfig,\n 'baseUrl' | 'prefix' | 'extensions' | 'schemaEnricher'\n>;\n\n/**\n * Compile a single resource to its schema payload without booting a Nest module.\n *\n * `prefix` is accepted for API parity with `forResourceDir` but ignored here —\n * only `baseUrl` affects URIs in the payload.\n *\n * Returns `undefined` for `view: 'schemas'` when the resource declares no views.\n *\n * Without `dirPath`, features that read sibling files are skipped: extend columns,\n * resource-ref column options, and sub-resource views.\n */\nexport const parseSchema = (\n input: ParseSchemaInput | unknown,\n appConfig: ParseAppConfig,\n view: ParseSchemaView = 'schemas',\n): Record<string, unknown> | undefined => {\n if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);\n\n const normalized: ParseSchemaInput =\n input !== null &&\n typeof input === 'object' &&\n 'json' in (input as object)\n ? (input as ParseSchemaInput)\n : { json: input };\n\n const parseResult = buildResourceJsonSchema().safeParse(normalized.json);\n if (!parseResult.success) {\n throw new Error(\n `Resource cannot be parsed: ${parseResult.error.message}`,\n );\n }\n\n const resource = fromJson(\n parseResult.data,\n normalized.schema,\n normalized.hooks,\n normalized.dirPath,\n appConfig.baseUrl,\n normalized.actions,\n normalized.tableActions,\n normalized.enums ?? {},\n undefined,\n );\n\n let payload: Record<string, unknown> | undefined;\n if (view === 'schemas') {\n payload = buildViewsPayload(resource, appConfig.baseUrl);\n } else if (view === 'definition') {\n payload = buildDefinitionPayload(resource);\n } else {\n payload = buildResourceJsonPayload(resource, appConfig.baseUrl);\n }\n\n if (payload && appConfig.schemaEnricher) {\n payload = { ...payload, ...appConfig.schemaEnricher(payload) };\n }\n\n return payload;\n};\n"],"mappings":"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","names":["ResourceConfigLoader","externalRouteFor","isOperationEnabled","isOperationExternal","resolveDefinition","schemaFor","getImportMetaUrl","document","URL","__filename","href","currentScript","tagName","toUpperCase","src","baseURI","importMetaUrl","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","q","RequestSchemaWithOffset","transform","schema","offset","offsetOf","params","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","isNullableProperty","property","prop","Array","isArray","includes","anyOf","some","s","Builder","type","ElementBuilder","options","_rule","label","opt","colspan","rowspan","showWhen","scope","schema","rule","hideWhen","disableWhen","effect","condition","patch","baseFields","Object","keys","length","ContainerBuilder","children","addControl","arg","push","resolveShortcut","addControls","first","rest","name","entries","builder","buildElements","map","child","build","ControlType","number","string","integer","autocomplete","textArea","markdown","array","object","custom","select","mutliSelect","toggle","boolean","link","relation","date","dateTime","dateRange","ControlBuilder","ElementBuilder","_detail","scope","type","opt","format","styles","asObject","property","properties","asCustom","builder","setCustomRender","customRender","detail","layoutBuilder","label","elementLabelProp","addAction","action","actions","options","push","detailFixed","hideActions","layout","labelKey","readonly","dataField","control","width","named","isNamed","includes","wrapper","customLabel","placeHolder","placeholder","hideLabel","build","undefined","_rule","rule","LayoutType","Horizontal","Vertical","Grid","Collapse","Group","LayoutBuilder","ContainerBuilder","type","horizontal","LayoutType","Horizontal","vertical","Vertical","grid","columns","layout","Grid","undefined","opt","collapse","Collapse","group","Group","title","titleKey","addControl","arg","options","resolveShortcut","name","control","ControlBuilder","properties","rest","Object","keys","length","build","elements","buildElements","baseFields","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","ContainerBuilder","LayoutType","Horizontal","init","resolveShortcut","name","elements","buildElements","baseFields","import_zod","ActionMetadataSchema","z","object","id","string","label","optional","icon","tooltip","condition","custom","ResourceLinkActionSchema","extend","type","literal","href","ResourceRowProcedureActionSchema","method","data","record","unknown","procedure","v","ResourceTableProcedureActionSchema","ResourceRowActionSchema","union","ResourceTableActionSchema","import_zod","LayoutControlSchema","z","union","string","object","id","colspan","number","int","min","max","optional","rowspan","width","label","hideLabel","boolean","type","options","record","unknown","LayoutNodeSchema","lazy","enum","columns","title","titleKey","controls","array","items","LayoutSchema","form","view","table","import_zod","import_zod","import_zod","RelationType","z","enum","DetailControlSchema","object","property","string","type","optional","options","record","unknown","hideLabel","boolean","width","DetailConfigSchema","layout","titleKey","controls","array","RelationFieldInputOptionsSchema","colspan","number","default","sort","sortDir","direction","displayKey","resource","catchall","FieldInputSchema","customRender","format","relationType","foreignKey","relation","position","defaultValue","union","detail","FieldVariantSchema","stripNull","obj","out","k","v","Object","entries","mergeFieldVariant","base","override","merged","mergedOptions","labelFromId","id","words","replace","trim","charAt","toUpperCase","slice","toLowerCase","normalizeLabel","obj","label","CalculatedColumnSchema","z","object","id","string","alias","label","optional","sqlExpression","type","enum","position","number","hiddenInTable","boolean","hiddenInView","fieldInput","FieldInputSchema","transform","normalizeLabel","import_zod","import_zod","ColumnTypeShorthandSchema","z","enum","JsonSchemaFragmentSchema","lazy","object","type","union","string","array","optional","format","unknown","const","nullable","boolean","properties","record","required","items","additionalProperties","title","description","default","minimum","number","maximum","minLength","maxLength","pattern","catchall","ColumnTypeSchema","SHORTHAND_FRAGMENTS","integer","date","isShorthand","NESTED_SHORTHANDS","normalizeFragment","fragment","out","expanded","undefined","Array","isArray","Object","assign","existingRequired","hoistedRequired","fromEntries","entries","map","key","value","v","push","_r","rest","length","columnTypeToJsonSchema","columnTypeName","raw","find","t","isObjectColumnType","isArrayColumnType","WhenConditionSchema","z","object","field","string","eq","unknown","optional","neq","exists","boolean","notExists","JsonColumnSchema","id","column","label","hiddenInTable","default","hiddenInForm","hiddenInView","sortable","defaultSort","searchable","filterable","createable","updateable","hideLabel","showWhen","hideWhen","disabledWhen","displayKey","sortId","enum","idField","showInLookup","type","ColumnTypeSchema","required","columnType","fieldInput","FieldInputSchema","fieldView","FieldVariantSchema","fieldTable","extend","columns","record","import_zod","ParentRefSchema","z","object","route","string","param","default","idType","enum","optional","resourceControllerPath","parent","import_zod","ResourceKindSchema","z","enum","default","import_zod","SidebarGroupSchema","z","object","label","string","optional","position","number","SidebarSchema","hide","boolean","default","group","import_zod","ActionConditionSchema","z","object","field","string","op","enum","default","value","unknown","optional","ActionSchema","type","id","label","icon","tooltip","condition","JsonProcedureActionSchema","extend","literal","procedure","method","data","record","JsonLinkActionSchema","href","blank","boolean","transformAction","action","JsonActionSchema","union","transform","CORE_RESOURCE_KEYS","Set","registry","Map","registerResourceExtension","name","schema","has","Error","set","registerResourceExtensions","map","Object","entries","forEach","k","s","getResourceExtensions","import_zod","JsonIncludeEntrySchema","z","lazy","union","string","object","relation","include","array","optional","orderBy","record","unknown","BASELINE_RESOURCE_VERSION","CURRENT_RESOURCE_VERSION","import_zod","import_zod","SecuritySchema","z","union","object","public","literal","guard","string","array","min","ExternalOpEntry","z","object","uri","string","method","optional","security","SecuritySchema","OpEntry","union","boolean","JsonOperationsSchema","findAll","default","findOne","create","update","patch","delete","buildSubResourceOperations","ops","baseUri","idField","idPlaceholder","JsonColumnsMapSchema","z","record","string","JsonColumnSchema","omit","id","catchall","unknown","ColumnsSchema","JsonDisplaySchema","object","mode","enum","default","customComponent","nullable","optional","normalizeColumns","columns","undefined","raw","Array","isArray","Object","entries","map","col","label","labelFromId","ResourceJsonShape","$schema","schemaVersion","number","int","positive","draft","boolean","kind","ResourceKindSchema","name","route","model","tag","title","table","idType","database","parent","ParentRefSchema","sidebar","SidebarSchema","parse","display","security","SecuritySchema","operations","JsonOperationsSchema","calculatedColumns","array","CalculatedColumnSchema","actions","JsonActionSchema","tableActions","modalSize","include","JsonIncludeEntrySchema","layout","LayoutSchema","refineByKind","obj","ctx","addIssue","code","path","message","length","fieldInput","format","type","param","buildResourceJsonSchema","ext","getResourceExtensions","extShape","fromEntries","schema","shape","size","extend","preprocess","superRefine","transform","BASELINE_RESOURCE_VERSION","defaultOps","findAll","findOne","create","update","patch","delete","ResourceJsonSchema","MigrationPathError","Error","message","name","MigrationStepError","MIGRATIONS","resourceVersionOf","raw","v","Number","isInteger","BASELINE_RESOURCE_VERSION","runResourceMigrations","target","CURRENT_RESOURCE_VERSION","migrations","from","to","applied","MigrationPathError","current","step","find","m","migrate","err","MigrationStepError","description","message","push","schemaVersion","_old","rest","resolveViewField","c","mergeFieldVariant","fieldInput","fieldView","resolveTableField","fieldTable","isBoolean","col","fieldInput","type","columnType","isRelation","format","isAutocomplete","isRecordCell","isDateRange","isObjectColumn","isObjectColumnType","isArrayColumn","isArrayColumnType","isObjectCell","displayKey","colPosition","col","i","fieldInput","position","sortByPosition","cols","map","sort","a","b","columnForContext","ctx","fieldView","fieldTable","toViewColumn","id","label","sortable","searchable","deriveSortId","col","sortable","sortId","base","column","id","fi","fieldInput","opts","options","isRelation","format","relationType","type","resource","key","displayKey","undefined","labelKey","path","includes","endsWith","slice","length","isValueLabel","enum","emitObject","resolveDefaultSort","tableCols","allColumns","isSortable","c","sortCol","find","defaultSort","idField","allowAdditionalProperties","schema","props","value","Object","values","dropNullableFromRequired","required","Array","isArray","filter","key","isNullableProperty","enforceRequiredMinLength","prop","applySchemaTransforms","SHARED_CELL_OPTION_KEYS","pickSharedCellOptions","col","options","fieldInput","Object","fromEntries","filter","key","undefined","map","buildTableUiSchema","cols","layout","TableBuilder","init","addControls","cellBuilder","isBoolean","BooleanCellBuilder","TextCellBuilder","builder","properties","id","displayKey","sortId","setSortId","build","colMap","c","elements","el","scope","replace","fieldInputOptions","isRecordCell","isDateRange","isObjectCell","dataPathOption","column","dataPath","derivedSortId","deriveSortId","sortOptions","sortable","relationTypeOption","relationType","format","label","type","buildConditionSchema","when","notExists","not","minLength","exists","neq","undefined","const","eq","applyColumnRule","control","col","disabledWhen","disableWhen","field","buildConditionSchema","when","showWhen","hideWhen","scope","schema","buildDetailLayout","detail","inner","layout","LayoutBuilder","collapse","horizontal","addControls","controls","map","dc","ctrl","ControlBuilder","properties","property","type","markdown","options","hideLabel","width","titleKey","defaultControlFormat","isObjectColumn","isArrayColumn","typeName","columnTypeName","format","columnTypeToJsonSchema","buildFormControl","id","fieldInput","colspan","relationType","detailLayout","detailFixed","undefined","customRender","setCustomRender","label","buildFormUiSchema","cols","grid","addControl","build","isVisibleInMode","c","mode","hiddenInTable","hiddenInView","buildCalculatedElement","type","scope","id","options","label","fieldInput","format","calcPosition","position","injectCalculatedColumnsIntoView","viewConfig","calculated","length","visible","filter","jsonSchema","json_schema","properties","title","uiSchema","ui_schema","existing","elements","tagged","map","el","i","pos","Infinity","sort","a","b","t","columns","entry","undefined","splice","push","injectCalculatedColumns","tableView","injectCalculatedColumnsToView","import_zod","optionValues","col","values","fieldInput","options","Array","isArray","undefined","unwrapped","map","v","value","length","columnToJsonSchemaProperty","property","type","isAutocomplete","columnTypeToJsonSchema","title","label","id","defaultValue","default","enum","columnTypeSchemaSource","schemaCols","properties","import_zod","isInstanceOf","zodSchema","className","z","ZodCustom","result","safeParse","success","issue","error","issues","expected","message","includes","jsonSchemaOverride","jsonSchema","ZodDate","type","format","ZodBigInt","unwrap","schema","s","t","_zod","def","innerType","isDecimalField","zodType","inner","jsonSchemaOpts","unrepresentable","override","buildContainerForNode","node","type","builder","LayoutBuilder","collapse","title","titleKey","group","horizontal","vertical","grid","columns","colspan","undefined","rowspan","label","resolveControlId","ctrl","id","applyControlOverrides","base","width","hideLabel","options","control","buildNodeInto","colMap","warn","seenIds","container","controls","length","col","get","add","buildFormControl","addControl","items","item","child","buildFormUiSchemaFromLayout","cols","console","Map","map","c","Set","root","unreferenced","filter","has","build","flattenLayoutControlIds","ids","visit","n","push","orderTableColumnsFromLayout","view","node","warn","console","orderedIds","flattenLayoutControlIds","length","elements","ui_schema","columns","elementById","Map","map","el","id","scope","replace","columnById","c","knownIds","Set","keys","filter","Boolean","reorderedElements","reorderedColumns","seen","has","add","get","push","col","patchFilterProperties","jsonSchema","columns","length","properties","col","fieldInput","format","id","opts","options","base","label","fromField","toField","dateProp","title","type","prop","values","ft","enum","injectFieldDefaults","defaultValue","undefined","default","zodSchemaSource","schema","schemaCols","schemaKeys","Set","Object","keys","shape","schemaIds","map","c","filter","has","mask","fromEntries","picked","pick","toJSONSchema","target","jsonSchemaOpts","NON_NULL_TYPES","SHAPE_KEYS","applyRequiredColumns","required","Array","isArray","delete","idField","createable","updateable","add","property","some","key","size","buildView","source","visible","buildUiSchema","sort","schemaVisible","visibleCols","sortByPosition","isRelation","applySchemaTransforms","nonEditableIds","k","json_schema","ui_schema","toViewColumn","emptyTableView","additionalProperties","buildTableUiSchema","buildViewsWithSource","layout","views","tableCols","columnForContext","table","hiddenInTable","defaultSort","resolveDefaultSort","orderTableColumnsFromLayout","formUiBuilder","form","cols","buildFormUiSchemaFromLayout","buildFormUiSchema","hiddenInForm","filterable","viewCols","viewUiBuilder","view","hiddenInView","buildViews","columnTypeSchemaSource","buildViewsFromColumns","columns","length","undefined","buildJsonSchema","cols","properties","c","column","id","type","keyPath","displayKey","split","target","i","segment","title","label","columnToJsonSchemaProperty","opts","fieldInput","options","isObject","emitObject","columnType","defaultValue","default","schema","applySchemaTransforms","fixNestedScopes","uiSchema","colMap","Object","fromEntries","map","elements","el","scope","replace","col","propPath","k","join","makeView","visible","buildUiSchema","json_schema","ui_schema","toViewColumn","views","tableCols","sortByPosition","filter","hiddenInTable","columnForContext","table","buildTableUiSchema","defaultSort","resolveDefaultSort","emptyTableView","formCols","hiddenInForm","form","buildFormUiSchema","applyRequiredColumns","viewCols","hiddenInView","viewView","view","keys","import_zod","ViewColumnConfigSchema","z","object","id","string","label","optional","sortable","boolean","searchable","fieldInput","FieldInputSchema","ViewConfigSchema","json_schema","record","unknown","ui_schema","ui","data","columns","array","defaultSort","viewDefList","ViewDefEnum","enum","import_zod","EnumEntrySchema","z","object","value","unknown","label","string","EnumRegistrySchema","record","array","default","import_zod","import_zod","import_zod","import_zod","DataSourceShape","z","object","name","string","urlEnv","optional","generatedTypesImport","type","default","boolean","adapter","enum","prismaSchema","prismaConfig","zodOutput","clientOutput","transformDataSource","data","DataSourceSchema","transform","import_zod","ValueSchema","z","object","value","unknown","label","string","ValueLabelColumnSchema","field","values","array","default","enumName","optional","CompiledSubResourceConfigSchema","z","object","column","string","relation","childRoute","childKind","enum","default","childDir","optional","childModel","foreignKey","name","title","idField","idType","views","record","ViewConfigSchema","operations","JsonOperationsSchema","actions","array","JsonActionSchema","modalSize","display","JsonDisplaySchema","include","JsonIncludeEntrySchema","calculatedColumns","CalculatedColumnSchema","includeInFindOne","boolean","hiddenInTable","findOneOrderBy","unknown","valueLabelColumns","ValueLabelColumnSchema","relationType","import_zod","import_zod","JsonSchemaInputSchema","z","object","type","literal","properties","record","string","unknown","required","array","optional","additionalProperties","boolean","SchemaInputSchema","union","custom","val","ZodObject","ExternalOperationDefSchema","z","object","uri","string","method","optional","OperationDefSchema","union","literal","schema","SchemaInputSchema","security","SecuritySchema","ResourceDefinitionSchema","findAll","findOne","create","update","patch","delete","DefinitionCallbackSchema","function","input","output","DefinitionSchema","import_zod","LookupSchema","z","object","key","string","label","optional","CompiledResourceSchema","ResourceJsonShape","extend","route","z","string","valueLabelColumns","array","ValueLabelColumnSchema","default","subResources","lazy","CompiledSubResourceConfigSchema","lookup","LookupSchema","optional","views","record","ViewConfigSchema","definition","DefinitionSchema","idField","idType","enum","import_zod","import_zod","RulesetSchema","z","object","hideIdInTable","boolean","default","hideIdInForm","hideIdInView","hideTimestamps","hideForeignKeys","includeRelations","hideRelationsInTable","showRelationsInForm","enumValueLabel","sharedEnums","defaultOperations","JsonOperationsSchema","parse","I18nConfigSchema","defaultLanguage","string","languages","array","min","translationsDir","CroutonConfigSchema","title","resourcesDir","dataSourcesDir","schemaExportName","enumsFile","rules","sidebarGroups","record","SidebarGroupSchema","autoSave","i18n","optional","CONFIG_FILES","import_zod","NestedStringRecord","z","lazy","record","string","union","TranslationBundleSchema","object","app","title","optional","sidebarGroups","resources","sidebar","columns","actions","subResources","enums","ui","validation","passthrough","resourceTitleKey","resource","resourceSidebarKey","columnKey","column","actionKey","action","subResourceTitleKey","sub","subResourceColumnKey","enumKey","enumName","value","sidebarGroupKey","group","validationKey","code","getNestedValue","obj","path","keys","split","current","key","undefined","createTranslator","bundles","language","defaultLanguage","langBundle","defaultBundle","fallback","value","parseAcceptLanguage","header","entries","part","split","trimmed","trim","tag","params","q","param","match","parseFloat","isNaN","push","toLowerCase","sort","a","b","resolveLanguage","acceptLanguage","supported","defaultLanguage","supportedLower","map","s","exactIdx","indexOf","base","baseIdx","import_common","import_core","import_zod","SidebarLeafSchema","z","object","kind","literal","default","id","string","label","position","number","optional","SidebarGroupSchema","children","array","SidebarNodeSchema","discriminatedUnion","byPosition","a","b","position","label","localeCompare","buildLayoutPayload","configs","sidebarGroups","title","autoSave","isDev","visible","filter","c","sidebar","hide","views","parent","topLevel","groupMap","Map","Object","entries","map","slug","cfg","labelFromId","children","leaf","SidebarLeafSchema","parse","id","name","tag","groupSlug","group","has","set","get","push","groups","g","length","kind","sort","import_common","parseBooleanEnv","value","includes","trim","toLowerCase","IS_DEV","process","env","readResourceJson","jsonPath","existsSync","undefined","fileContent","JSON","parse","readFileSync","err","success","error","message","resource","buildResourceJsonSchema","safeParse","data","json","dir","dirname","import_node_fs","import_node_path","resolveChildResourceDetailed","resourcePath","parentDir","attempted","endsWith","directPath","resolve","push","existsSync","result","readResourceJson","success","ok","value","data","reason","error","childName","replace","childJsonPath","dirname","err","message","resolveChildResource","resolution","undefined","expandExtendColumns","columns","dirPath","result","col","extend","push","resolved","resolveChildResource","console","warn","id","refColumns","json","parentColumnKey","column","refCol","idField","virtualId","displayKey","hiddenInTable","hiddenInForm","hiddenInView","override","virtualCol","label","columnType","undefined","sortable","fieldInput","buildValueLabelColumns","flatMap","c","opts","options","emitObject","Array","isArray","values","field","enum","enumName","applyRelationFormatDefault","cols","map","fi","resource","format","type","resolveColumnFieldVariants","fieldView","resolveViewField","fieldTable","resolveTableField","clone","obj","JSON","parse","stringify","cloneResource","config","definition","rest","localized","translateEnumOptions","columns","t","col","enum","opts","fieldInput","options","Array","isArray","values","entry","label","enumKey","String","value","translateValueLabelEntries","vlCols","vlc","enumName","patchViewTitles","views","columnLabels","patched","viewName","view","Object","entries","patchedView","props","json_schema","properties","key","prop","translated","get","title","map","vc","id","patchUiElements","elements","el","element","scope","match","exec","nested","uiSchema","ui_schema","uiElements","localizeResource","name","resourceTitleKey","tag","sidebar","sidebarTranslation","resourceSidebarKey","Map","columnKey","set","valueLabelColumns","buildValueLabelColumns","actions","a","actionKey","tableActions","subResources","sub","subName","childRoute","subResourceTitleKey","subColumnLabels","subResourceColumnKey","ResourceConfigRegistry","configs","translationRegistry","localizedCache","Map","loader","initialConfigs","setTranslationRegistry","registry","getAll","language","IS_DEV","loadAll","clear","active","map","c","getLocalized","getByRoute","route","fresh","loadByRoute","undefined","localize","config","find","findById","id","all","getResourceDir","langMap","get","set","localized","t","translatorFor","localizeResource","languageStore","AsyncLocalStorage","runWithLanguage","language","fn","run","getRequestLanguage","defaultLanguage","getStore","createAppLayoutController","configs","sidebarGroups","title","autoSave","translationRegistry","i18nConfig","prefix","layoutPayload","buildLayoutPayload","IS_DEV","AppLayoutController","configRegistry","getLayout","language","getRequestLanguage","payload","fresh","getAll","translateSidebarGroups","translateTitle","active","lang","defaultLanguage","bundle","bundleFor","i18n","languages","current","ui","getTranslations","validation","summary","status","description","Reflect","defineMetadata","ResourceConfigRegistry","groups","registry","t","translatorFor","translated","slug","cfg","Object","entries","label","sidebarGroupKey","import_node_path","fileExists","p","access","findConfigPath","cwd","dir","resolve","name","CONFIG_FILES","candidate","join","parent","dirname","undefined","loadConfig","pathResolve","process","path","Error","config","endsWith","JSON","parse","readFile","mod","default","parsed","CroutonConfigSchema","configDir","import_common","CroutonValidationError","Error","errors","name","import_node_fs","import_node_path","loadTranslationBundles","translationsDir","existsSync","bundles","entries","readdirSync","withFileTypes","entry","isFile","name","endsWith","lang","replace","JSON","parse","readFileSync","join","TranslationRegistry","bundles","translationsDir","i18nConfig","loadTranslationBundles","languages","defaultLanguage","active","Object","keys","length","translatorFor","language","IS_DEV","createTranslator","bundleFor","CroutonValidationExceptionFilter","translationRegistry","catch","exception","host","res","switchToHttp","getResponse","errors","translateErrors","status","json","statusCode","message","error","language","getRequestLanguage","t","translatorFor","map","field","code","key","validationKey","translated","replace","import_common","import_swagger","import_common","import_zod","ActionMetadataSchema","z","object","id","string","label","optional","icon","tooltip","condition","custom","ResourceLinkActionSchema","extend","type","literal","href","ResourceRowProcedureActionSchema","method","data","record","unknown","procedure","v","ResourceTableProcedureActionSchema","ResourceRowActionSchema","union","ResourceTableActionSchema","isRowProcedureAction","action","isTableProcedureAction","import_node_fs","import_node_path","_require","createRequire","__filename","IS_ESM","findModule","dir","name","ext","p","join","existsSync","undefined","IS_VITE","globalThis","__vite_ssr_import__","importDefault","filePath","onError","importPath","IS_DEV","Date","now","mod","default","pathToFileURL","href","error","console","import_node_path","loadActions","jsonActions","basePath","scope","tag","results","action","type","push","file","findModule","join","procedure","console","warn","id","mod","importDefault","resolveDefinition","config","def","definition","isOperationEnabled","op","schemaFor","entry","undefined","schema","isOperationExternal","externalRouteFor","uri","opSecurity","security","securityFor","moduleDefault","securityForSub","sub","operations","import_zod","CUSTOM_OPS","PARENT_METHOD","findAll","findOne","create","update","patch","delete","CustomRepositorySchema","z","custom","value","ResourceLoadErrorsRegistry","errors","record","e","push","getAll","clear","resourceLoadErrorsRegistry","REPOSITORY_MODULE","loadCustomRepository","basePath","resourceName","file","findModule","undefined","failure","repository","importDefault","error","resourceLoadErrorsRegistry","record","name","path","Error","message","String","loadSubResourceRepositories","subResources","parentName","sub","childKind","childDir","childRoute","import_common","PRISMA_NOT_FOUND_CODE","DEFAULT_ID_TYPE","DEFAULT_ID_FIELD","import_common","import_common","import_common","childRepositoryFn","sub","op","parentName","repo","repository","method","PARENT_METHOD","NotImplementedException","childRoute","fn","update","undefined","bind","childCtx","parentConfig","prisma","parentId","params","id","request","dataSources","resolve","entries","config","offset","offsetOf","parent","route","param","parentIdFromRequest","fallback","raw","applyValueLabelColumns","row","cols","length","out","field","values","toValueLabel","normalizeValueLabels","data","Array","isArray","fromValueLabel","castExpression","col","type","sqlExpression","defaultValueForType","coerceColumnValue","v","Boolean","undefined","String","Number","buildCalculatedColumnSql","tableName","ids","idField","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","buildFindOneIncludes","subResources","configInclude","autoSubs","filter","s","includeInFindOne","childKind","flatIncludes","findOneOrderBy","import_common","LanguageInterceptor","registry","intercept","context","next","http","switchToHttp","request","getRequest","response","getResponse","acceptLanguage","headers","resolved","resolveLanguage","languages","defaultLanguage","setHeader","runWithLanguage","handle","resolveValueLabelColumns","route","bootTimeCols","configRegistry","childRoute","language","getRequestLanguage","localized","getByRoute","valueLabelColumns","sub","subResources","find","s","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","ReadRepository","prisma","adapter","client","prismaModel","config","listSelect","oneSelect","configRegistry","tableName","table","model","toId","id","idType","String","buildWhere","filter","buildFilterWhere","projection","op","select","safeSort","sort","sortDir","undefined","buildSort","parentHookContext","parentId","route","param","findAll","params","request","subResources","vlCols","resolveValueLabelColumns","valueLabelColumns","filterWhere","searchWhere","buildSearchOrWhere","q","where","AND","query","take","pageSize","skip","offsetOf","orderBy","sanitizeValueLabelSort","prismaSubResources","s","childKind","oneToManySubResources","relationType","countableSubResources","hiddenInTable","manyToOneIncludes","map","relation","flatIncludes","length","Object","fromEntries","r","configInclude","buildIncludeClause","include","countableRelations","Set","filteredConfigInclude","entries","key","has","safeConfigInclude","keys","mergedInclude","countClause","_count","rows","findMany","mapped","row","rest","counts","column","withCalc","mergeCalculatedColumnsForRows","calculatedColumns","idField","lookup","labels","label","OR","path","buildNestedPath","split","contains","count","findOne","buildFindOneIncludes","record","findUnique","NotFoundException","name","enriched","sub","nested","Array","isArray","enrichedNested","childModel","findAllByParent","childRoute","find","Error","childRepositoryFn","result","childCtx","parentConfig","data","decorated","hooks","afterRead","Promise","all","dataSource","parent","subVlCols","labeled","applyValueLabelColumns","foreignKey","includeClause","childSort","orderableChildSort","buildChildSortClause","findOneChild","childId","BadRequestException","findFirst","import_common","includeRelationNames","include","Set","map","e","relation","PRISMA_RELATION_WRITE_KEYS","isPrismaRelationWrite","value","Array","isArray","Object","keys","some","k","has","stripSubResourceKeys","config","data","subKeys","subResources","s","column","size","fromEntries","entries","filter","stripNonCreateableChildFields","sub","nonCreateable","views","form","columns","c","createable","id","WriteRepository","prisma","adapter","client","prismaModel","toId","idType","String","notFound","NotFoundException","name","parentHookContext","parentId","route","param","create","_request","update","idField","where","code","PRISMA_NOT_FOUND_CODE","patch","delete","delegateChildWrite","op","childId","request","undefined","BadRequestException","childRoute","fn","childRepositoryFn","ctx","childCtx","parentConfig","payload","stripped","normalized","normalizeValueLabels","valueLabelColumns","hooks","beforeWrite","dataSource","parent","result","afterWrite","createChild","childKind","childModel","Error","foreignKey","prepared","includeKeys","preparedEntries","prismaData","v","updateChild","parentIdFromRequest","afterHook","DEFAULT_ID_FIELD","deleteChild","deleteMany","count","DB_CHECK_TIMEOUT_MS","PrismaDataSourceAdapter","kind","client","prismaClient","supports","model","healthCheck","c","Promise","race","$queryRaw","_","reject","setTimeout","Error","disconnect","$disconnect","prismaModel","delegate","findAll","params","ctx","reader","ReadRepository","config","listSelect","oneSelect","configRegistry","data","count","all","request","filter","q","undefined","findOne","id","e","NotFoundException","create","WriteRepository","update","patch","delete","findAllByParent","parentId","sub","childRoute","findOneChild","childId","createChild","updateChild","deleteChild","import_zod","WriteOpSchema","z","enum","ReadOpSchema","ResourceHooksSchema","object","beforeWrite","custom","optional","afterWrite","afterRead","beforeFindAll","afterFindAll","import_node_path","loadResourceHooks","basePath","file","findModule","importDefault","undefined","loadSubResourceHooks","subResources","sub","name","join","childDir","hooks","hookCtxRead","adapter","op","request","parent","dataSource","prisma","client","hookCtxWrite","id","undefined","decorateRows","rows","target","hook","hooks","afterRead","ctx","hooked","Promise","all","map","row","cols","valueLabelColumns","length","r","applyValueLabelColumns","decorateRow","prepareWrite","data","normalized","normalizeValueLabels","beforeWrite","applyBeforeFindAll","params","beforeFindAll","applyAfterFindAll","afterFindAll","postWrite","result","afterWrite","unsupported","config","op","method","parent","PARENT_METHOD","NotImplementedException","name","createCustomRepository","prisma","dataSources","repository","configRegistry","adapter","PrismaDataSourceAdapter","repo","idField","DEFAULT_ID_FIELD","toId","id","idType","DEFAULT_ID_TYPE","String","parentRef","parentIdFrom","request","raw","params","param","undefined","BadRequestException","route","parentCtx","parentId","parentHookCtx","ctx","offset","offsetOf","findAllWithCount","result","findAllByParent","findAll","vlCols","resolveValueLabelColumns","valueLabelColumns","target","hooks","data","decorateRows","count","length","findOne","row","findOneByParent","NotFoundException","decorateRow","write","coercedId","prepared","prepareWrite","fn","createByParent","updateByParent","patchByParent","nestedCtx","body","create","update","patch","bind","postWrite","notAChildRepository","filter","page","pageSize","sort","sortDir","delete","deleteByParent","findOneChild","createChild","updateChild","deleteChild","validateCustomRepository","config","repository","adapterClient","definition","resolveDefinition","enabled","CUSTOM_OPS","filter","op","isOperationEnabled","isOperationExternal","nested","parent","methodFor","PARENT_METHOD","length","undefined","missing","name","map","join","implemented","names","route","import_zod","isZodSchema","schema","ZodObject","dropNullableFromRequired","jsonSchema","properties","required","Array","isArray","filter","key","isNullableProperty","toJsonSchema","toJSONSchema","target","jsonSchemaOpts","type","unwrap","s","t","_zod","def","innerType","typeOf","toSelectFields","Object","keys","reduce","acc","result","value","entries","shape","inner","select","element","createCrudRepository","prisma","config","dataSources","configRegistry","fallbackDataSources","resolve","entries","repository","createCustomRepository","resolvedAdapter","resolveAdapter","database","adapterModelKey","model","name","definition","resolveDefinition","listSchema","schemaFor","oneSchema","listSelect","toSelectFields","undefined","oneSelect","findAll","count","baseCtx","op","offset","ctx","request","id","mkDecorateFindAll","adapter","rows","vlCols","resolveValueLabelColumns","route","valueLabelColumns","target","hooks","decorated","decorateRows","applyAfterFindAll","decorateFindAll","applyBefore","params","applyBeforeFindAll","decorateFindOne","row","decorateRow","prepareData","data","prepareWrite","postData","result","postWrite","toId","idType","String","adapterFindAllByParent","parentId","childRoute","findAllByParent","sub","subResources","find","s","Error","prismaModel","reader","ReadRepository","adapterFindOneChild","childId","findOneChild","NotFoundException","writer","WriteRepository","findAllWithCount","effectiveParams","offsetOf","filter","q","findOne","create","stripped","stripSubResourceKeys","prepared","update","coercedId","patch","patchOrUpdate","bind","delete","createChild","Promise","reject","updateChild","deleteChild","kind","client","legacyModel","PrismaDataSourceAdapter","import_common","DataSourceRegistry","adapters","Map","defaultName","entries","entry","set","config","name","adapter","default","length","resolveAdapter","key","Error","get","resolveClient","client","resolve","map","onModuleDestroy","disconnectAll","values","disconnect","import_node_fs","import_node_path","loadDataSourcesFromDir","dirPath","existsSync","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","name","results","dir","basePath","join","jsonFile","_config","JSON","parse","readFileSync","err","resourceLoadErrorsRegistry","record","path","error","message","datasource","DataSourceSchema","safeParse","success","config","data","indexFile","findModule","adapter","mod","exported","default","instance","kind","PrismaDataSourceAdapter","push","ext","p","undefined","InMemoryDataSourceAdapter","kind","client","undefined","store","Map","seed","model","rows","set","supports","has","disconnect","import_common","import_swagger","import_common","import_common","SecurityGuardRegistry","guards","resolve","name","g","Error","classes","Object","values","CROUTON_SECURITY","CroutonSecurityGuard","reflector","registry","moduleRef","canActivate","context","sec","get","getHandler","names","Array","isArray","guard","name","cls","resolve","strict","ok","def","cls","method","fn","Object","defineProperty","prototype","value","writable","configurable","desc","getOwnPropertyDescriptor","registerActionRoutes","ctx","cls","config","name","procedureActions","actions","filter","isRowProcedureAction","action","methodName","id","def","recordId","procedure","repo","prisma","d","desc","Post","prototype","Param","ApiOperation","summary","label","ApiParam","type","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","registerTableActionRoutes","tableActions","isTableProcedureAction","import_common","import_swagger","defaultCreate","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","createSchema","bodyDecorator","methodName","route","name","createFn","body","req","repo","create","decorators","coerceNullableUndefinedToNull","prototype","Req","childCreate","sub","operations","childRoute","id","createChild","Param","Body","registerCreate","operationFn","properties","def","d","desc","Post","ApiOperation","summary","ApiResponse","status","description","secure","import_common","import_swagger","defaultDelete","ctx","isOperationEnabled","definition","isOperationExternal","config","methodName","name","route","decorators","deleteFn","id","req","repo","delete","deleteChild","sub","operations","cls","childRoute","childId","parentId","Param","prototype","Req","registerDelete","operationFn","properties","def","d","desc","Delete","ApiOperation","summary","ApiParam","idParamMeta","ApiResponse","status","secure","import_common","import_swagger","RequestDtoNoOffset","createZodDto","RequestSchema","RequestDto","RequestSchemaWithOffset","ZodValidationPipe","nullableKeys","decimalKeys","decimalCtor","coerceUndefinedToNull","schema","options","Object","entries","shape","filter","field","safeParse","success","map","key","require","Decimal","isDecimalField","coerceNullableUndefinedToNull","transform","value","stripped","stripEmptyStrings","coerced","coerceNullable","input","coerceDecimals","result","CroutonValidationError","formatErrors","error","data","Array","isArray","out","keys","includes","undefined","length","v","issues","e","path","join","message","code","_findAll","repo","params","request","data","count","findAllWithCount","Promise","all","findAll","filter","q","then","totalPages","Math","max","ceil","pageSize","page","sort","sortDir","findAllByParent","id","childRoute","defaultFindAll","ctx","isOperationEnabled","definition","isOperationExternal","config","req","route","name","methodName","listSchema","decorators","childFindAll","sub","operations","cls","Param","prototype","Req","registerFindAll","operationFn","properties","def","d","desc","Get","Query","ZodValidationPipe","RequestDtoNoOffset","schema","ApiOperation","summary","ApiResponse","status","description","type","items","toJsonSchema","secure","import_common","import_swagger","defaultFindOne","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","methodName","route","name","findOneFn","id","req","repo","findOne","decorators","Param","prototype","Req","childFindOne","sub","operations","childRoute","parentId","childId","findOneChild","registerFindOne","operationFn","properties","def","d","desc","Get","ApiOperation","summary","ApiParam","idParamMeta","ApiResponse","status","description","oneSchema","schema","toJsonSchema","ApiNotFoundResponse","secure","import_common","import_swagger","defaultPatch","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","patchSchema","bodyDecorator","methodName","route","name","patchFn","id","body","req","repo","patch","decorators","Param","prototype","Req","childPatch","sub","operations","childRoute","_id","childId","updateChild","Body","registerPatch","operationFn","properties","def","d","desc","Patch","ApiOperation","summary","ApiResponse","status","description","ApiNotFoundResponse","secure","import_common","import_swagger","import_zod","FieldVariantPatchSchema","z","object","type","string","nullable","optional","format","resource","position","number","options","record","unknown","partial","PatchColumnSchema","label","column","hiddenInTable","boolean","hiddenInForm","hiddenInView","fieldInput","fieldView","fieldTable","PatchResourceJsonSchema","columns","import_node_fs","readRawResourceJson","jsonPath","existsSync","undefined","JSON","parse","readFileSync","FIELD_VARIANT_KEYS","mergeColumn","existing","patch","fieldInput","fieldView","fieldTable","rest","variantPatches","merged","key","variantPatch","mergeFieldVariant","applyColumnPatch","raw","columns","Array","isArray","updated","map","col","columnPatch","id","Object","entries","serializeResourceJson","config","stringify","validateResourceJson","buildResourceJsonSchema","safeParse","writeRawResourceJson","writeFileSync","pickExtensions","config","Object","fromEntries","getResourceExtensions","keys","filter","k","undefined","map","resolveEnvPlaceholders","value","replace","match","varName","process","env","RESOURCE_OPS","OP_METHOD","findAll","findOne","create","update","patch","delete","OP_SUFFIX","buildResourceOperations","definition","baseUri","op","isOperationEnabled","extUri","externalRouteFor","uri","entry","method","buildDefinitionPayload","route","name","tag","idType","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","patchSchema","operations","display","schemas","toJsonSchema","buildResourceJsonPayload","baseUrl","isOperationExternal","lookup","form","views","schema","json_schema","data","ui","ui_schema","id","_resolveActions","actions","length","resolved","a","type","href","b","join","resolveActions","buildViewsPayload","config","baseUrl","views","Object","keys","length","undefined","definition","resolveDefinition","baseUri","parent","route","param","operations","buildResourceOperations","isOperationEnabled","isOperationExternal","schemas","fromEntries","entries","map","key","v","data","json_schema","ui","ui_schema","defaultSort","baseAction","id","name","uri","title","tag","idField","lookup","idType","modalSize","display","actions","resolveActions","tableActions","pickExtensions","buildSubResourceViewsPayload","sub","childUri","childRoute","buildSubResourceOperations","buildEditableColumnsPayload","columns","c","label","column","hiddenInTable","hiddenInForm","hiddenInView","form","fieldInput","view","resolved","resolveViewField","hasOverride","fieldView","table","resolveTableField","fieldTable","import_node_path","registerDefinitionEndpoint","ctx","cls","config","schemaEnricher","route","name","definitionPayload","buildDefinitionPayload","def","language","getRequestLanguage","payload","IS_DEV","fresh","configRegistry","getByRoute","d","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","registerResourceJsonEndpoint","baseUrl","resourceJsonPayload","buildResourceJsonPayload","registerResourceColumnsEndpoint","ForbiddenException","buildEditableColumnsPayload","registerResourceJsonPatchEndpoint","body","dir","getResourceDir","NotFoundException","jsonPath","join","raw","readRawResourceJson","merged","applyColumnPatch","validated","validateResourceJson","success","BadRequestException","error","issues","writeRawResourceJson","Patch","Body","ZodValidationPipe","PatchResourceJsonSchema","registerResourceJsonRawGetEndpoint","registerResourceJsonRawPutEndpoint","Put","import_common","import_swagger","defaultSchemas","ctx","config","baseUrl","schemaEnricher","route","name","viewsPayload","buildViewsPayload","methodName","schemasFn","language","getRequestLanguage","payload","IS_DEV","fresh","configRegistry","getByRoute","decorators","childSchemas","sub","views","schemasPayload","buildSubResourceViewsPayload","childRoute","localizedParent","localizedSub","subResources","find","s","registerSchemas","operationFn","properties","cls","def","d","desc","Get","prototype","ApiOperation","summary","ApiResponse","status","description","sec","security","moduleDefaultSecurity","SetMetadata","CROUTON_SECURITY","import_common","import_swagger","defaultUpdate","ctx","isOperationEnabled","definition","isOperationExternal","cls","config","updateSchema","bodyDecorator","methodName","route","name","updateFn","id","body","req","repo","update","decorators","Param","prototype","Req","childUpdate","sub","operations","childRoute","_id","childId","updateChild","Body","registerUpdate","operationFn","properties","def","d","desc","Put","ApiOperation","summary","ApiResponse","status","description","ApiNotFoundResponse","secure","registerEndpoints","ctx","registerSubResourceRoutes","registerFindAll","registerResourceJsonRawGetEndpoint","registerResourceJsonRawPutEndpoint","registerResourceJsonPatchEndpoint","registerResourceJsonEndpoint","registerResourceColumnsEndpoint","registerDefinitionEndpoint","registerEndpoint","registerActionRoutes","registerTableActionRoutes","sub","config","subResources","registerSchemas","registerFindOne","registerCreate","registerUpdate","registerPatch","registerDelete","createCrudController","config","baseUrl","moduleDefaultSecurity","securityEnabled","prefix","schemaEnricher","route","name","tag","idType","definition","resolveDefinition","listSchema","schemaFor","oneSchema","createSchema","updateSchema","explicitPatchSchema","patchSchema","isZodSchema","partial","undefined","bodyDecorator","schema","options","Body","ZodValidationPipe","resolveClient","registry","resource","resolve","database","e","kind","adapter","resolveAdapter","client","CrudControllerBase","repo","configRegistry","prisma","createCrudRepository","secure","methodName","op","sub","sec","securityForSub","securityFor","SetMetadata","CROUTON_SECURITY","prototype","Object","getOwnPropertyDescriptor","ctx","cls","idParamMeta","type","registerEndpoints","controllerPath","resourceControllerPath","parent","Controller","UseGuards","CroutonSecurityGuard","ApiTags","defineProperty","value","charAt","toUpperCase","slice","Reflect","defineMetadata","DataSourceRegistry","ResourceConfigRegistry","import_common","import_swagger","clientAccessor","prismaModelName","charAt","toLowerCase","slice","resourceNames","accessor","name","route","model","tag","title","labelFromId","TIMESTAMP_NAME","isTimestampField","opts","type","isUpdatedAt","test","fieldInputType","prismaType","isEnum","scalarFieldInputType","idTypeFor","indexRelations","models","index","Map","model","field","fields","kind","relationName","list","get","push","name","isList","set","resolveRelationType","sides","counterpart","find","s","type","otherIsList","literalDefault","value","undefined","Array","isArray","every","v","includes","dmmfToDbModels","dmmf","enums","datamodel","enumNames","Set","map","e","relationIndex","fkFields","f","relationFromFields","add","idFieldDef","isId","hasCompositeId","primaryKey","length","idField","idType","idTypeFor","isEnum","has","isRequired","isUnique","isUpdatedAt","hasDefault","hasDefaultValue","default","defaultValue","isTimestamp","isTimestampField","relationModel","relationToFields","relationType","enumValues","values","prismaName","clientAccessor","charAt","toLowerCase","slice","tableName","dbName","loadDmmf","schemaPath","specifier","internals","mod","Error","loaded","getSchemaWithPath","cliProvidedPath","getDMMF","schemas","introspect","opts","loader","defaultRuleset","RulesetSchema","parse","classify","model","ctx","ruleset","names","resourceNames","prismaName","columnOrder","columns","unwiredRelations","position","field","fields","kind","includeRelations","col","idField","hiddenInTable","hideIdInTable","hiddenInForm","hideIdInForm","hiddenInView","hideIdInView","isTimestamp","hideTimestamps","createable","updateable","fieldInput","type","defaultValue","undefined","hideForeignKeys","target","resolveRelationResource","relationModel","isCollectionSide","relationType","display","showRelationsInForm","hideRelationsInTable","format","resource","options","push","name","targetModel","enumValueLabel","emitObject","sharedEnums","values","enumValues","map","v","label","value","displayKey","enum","scalarFieldInputType","config","route","tag","title","idType","database","sidebar","hide","operations","defaultOperations","hasRelations","some","f","import_promises","fileExists","p","access","clone","value","JSON","parse","stringify","deepEqual","a","b","Array","isArray","length","every","v","i","ao","bo","ak","Object","keys","sort","bk","some","k","columnEntries","columns","map","id","rest","entries","columnsMapFromEntries","out","col","diff","draft","existing","hasSchemaFile","decisions","isNew","push","id","kind","recommended","options","context","name","draftMap","Map","columnEntries","config","columns","existingMap","columnOrder","draftCol","get","has","field","deepEqual","model","undefined","recommendedResolver","resolve","decisions","out","d","id","recommended","diff","resolver","raw","resolutions","Map","set","RESOURCE_SCHEMA_URL","CURRENT_RESOURCE_VERSION","withResourceHeader","config","opts","$schema","_schema","schemaVersion","_version","draft","existingDraft","kind","existingKind","rest","undefined","serializeResourceJson","JSON","stringify","serializeSchemaTs","exportName","importPath","joinPath","parts","join","replace","apply","resolved","ctx","diff","resolutions","exportNameFor","schemaExportName","p","dir","resourcesDir","name","notes","draft","unwiredRelations","map","r","field","targetModel","files","isNew","config","clone","addToSidebar","get","sidebar","hide","push","path","contents","serializeResourceJson","withResourceHeader","action","existing","draftMap","Map","columnEntries","columns","entries","indexOf","id","findIndex","eid","decision","decisions","choice","recommended","kind","col","i","splice","columnsMapFromEntries","deepEqual","hasSchemaFile","exportName","hasRelations","prismaName","serializeSchemaTs","generatedTypesImport","resource","import_promises","import_node_path","commit","plan","opts","written","skipped","file","files","action","fileExists","path","push","dryRun","mkdir","dirname","recursive","writeFile","contents","import_promises","import_node_path","findConfigPath","cwd","dir","resolve","name","CONFIG_FILES","candidate","join","fileExists","parent","dirname","undefined","loadConfig","path","Error","config","endsWith","JSON","parse","readFile","mod","default","validateConfig","root","resourcesDir","dataSourcesDir","defaultPrismaConfig","loadDatasources","loaded","base","resolveFromRoot","entries","readdir","withFileTypes","datasources","e","isDirectory","jsonPath","ds_json","prismaSchema","generatedTypesImport","missing","filter","Boolean","push","DataSourceSchema","prismaConfig","validateDatasources","length","defaults","d","map","resolveDatasource","found","find","def","makeSchemaExportName","template","schemaExportName","prismaName","replace","p","isAbsolute","import_zod","import_promises","import_node_path","ScallfoldDatasourceSchema","DataSourceShape","extend","folder","z","string","default","transform","transformDataSource","import_node_path","import_promises","import_node_path","resourceDir","loaded","name","join","resolveFromRoot","root","config","resourcesDir","readExistingResource","dir","jsonPath","fileExists","JSON","parse","readFile","hasSchemaFile","isCustomResourceFile","parsed","kind","listResourceNames","base","entries","readdir","withFileTypes","names","e","isDirectory","push","makeRelationResolver","loaded","known","Set","listResourceNames","targetModel","accessor","clientAccessor","has","undefined","resolveRuleset","config","RulesetSchema","parse","rules","buildResourceDiff","model","deps","draft","classify","database","ruleset","resolveRelationResource","name","resourceNames","prismaName","hasSchemaFile","readExisting","diff","existing","buildResourceDiffs","models","diffs","push","import_node_fs","import_promises","import_node_module","import_node_path","loadDotenv","dir","_require","createRequire","dotenv","d","i","readdirSync","includes","config","path","join","parent","dirname","resolveBin","name","cwd","bin","existsSync","run","cmd","args","Promise","resolve","child","spawn","shell","process","platform","stdout","stderr","on","toString","err","code","String","isGitDirty","trim","length","backupSchema","schemaPath","dest","copyFile","prismaDbPull","prismaConfig","prefix","ok","output","prismaCaseFormat","binPath","execPath","prismaGenerate","pullAndGenerate","input","root","prismaConfigPath","schemaPath","loadDotenv","backupPath","backupSchema","dbPull","prismaDbPull","ok","caseFormat","prismaCaseFormat","normalized","normalizeSchema","generate","prismaGenerate","renamed","configDir","dir","dirname","configPath","join","existsSync","config","JSON","parse","readFile","schema","modelName","fields","Object","entries","renames","modelRe","RegExp","replace","_","head","body","tail","ugly","clean","fieldRe","replaced","writeFile","import_node_path","applyResourceFlagPatch","raw","patch","result","draft","undefined","sidebar","existing","hide","group","position","label","Object","keys","length","resolveResourcePath","resourcesDir","name","resolved","resolve","startsWith","Error","ResourceLoadReportRegistry","notices","record","n","push","getAll","getByState","state","filter","clear","resourceLoadReportRegistry","DevResourcesController","dataSourceRegistry","resourceConfigRegistry","assertDev","IS_DEV","ForbiddenException","loadProject","datasourceName","loaded","loadConfig","process","cwd","e","NotFoundException","message","datasources","loadDatasources","ds","resolveDatasource","BadRequestException","schemaPath","resolveFromRoot","root","prismaSchema","introspectModels","introspect","buildApplyContext","resourcesDir","config","generatedTypesImport","schemaExportName","makeSchemaExportName","isAvailableOnClient","clientAccessor","client","resolve","name","listModels","models","existing","Set","listResourceNames","map","m","prismaName","hasResource","has","availableOnClient","restart","setTimeout","disconnectAll","catch","undefined","finally","exit","restarting","pull","body","datasource","prismaConfigPath","prismaConfig","confirm","isGitDirty","requiresConfirmation","dirtyFile","zodDir","zodOutput","result","pullAndGenerate","zodOutputDir","ok","dbPull","output","restartRequired","backupPath","caseFormat","normalizeSchema","generate","zodImportsFixed","sync","model","find","resolveRelationResource","makeRelationResolver","diff","buildResourceDiff","database","ruleset","resolveRuleset","readExisting","readExistingResource","resolved","resolveDiff","recommendedResolver","plan","applyDiff","commit","resource","isNew","allModels","length","filter","includes","diffs","buildResourceDiffs","applyCtx","resources","writePlan","files","notes","push","decisions","f","path","action","apply","results","visibility","getAll","fromLoaded","c","route","state","sidebar","hide","group","position","editable","drafts","resourceLoadReportRegistry","getByState","d","endsWith","errors","resourceLoadErrorsRegistry","publish","jsonPath","resolveResourcePath","raw","readRawResourceJson","patched","applyResourceFlagPatch","draft","validateResourceJson","success","error","writeRawResourceJson","removeFromMenu","addToMenu","sidebarPatch","label","updateFlags","summary","status","description","import_zod","EnumEntrySchema","z","object","value","unknown","label","string","EnumRegistrySchema","record","array","default","import_node_fs","import_node_path","ENUMS_FILE","loadEnumRegistry","startDir","enumsFile","file","dir","candidate","join","existsSync","parent","dirname","EnumRegistrySchema","parse","undefined","JSON","readFileSync","injectEnumValues","columns","enums","col","enum","values","fieldInput","type","options","emitObject","displayKey","import_common","NoCacheInterceptor","intercept","context","next","response","switchToHttp","getResponse","setHeader","handle","pickByColumns","schema","columns","filter","undefined","length","baseFilter","c","isRelation","schemaKeys","Set","Object","keys","shape","filtered","has","id","mask","fromEntries","map","pick","opWithSchema","enabled","uri","method","buildResourceDefinitions","operations","enrichedColumns","picked","createSchema","idField","createable","updateSchema","updateable","definition","findAll","findOne","create","update","patch","delete","import_zod","unwrapZodType","type","ZodOptional","ZodNullable","unwrap","deriveRelationType","schema","columnId","undefined","field","shape","inner","ZodArray","deriveRelationTypeFromColumns","col","cols","base","column","id","fkNames","Set","some","c","has","enrichRelationTypes","columns","map","fi","fieldInput","isRelationField","format","relationType","derived","enrichActionColumns","columns","parentRoute","subResources","baseUrl","base","map","col","fieldInput","format","sub","find","s","column","id","options","uri","childRoute","resourceUri","resource","relationType","enrichResourceRefColumns","parentDir","childResolved","resolveChildResource","json","route","replace","schemasUri","enrichNestedRelationColumns","cols","dir","resolved","targetRoute","deriveRelationTypeFromColumns","enrichIncludeWithSort","include","length","entry","relationName","relation","c","opts","sort","orderBy","buildChildSortClause","sortDir","REMOTE_RESOURCE","buildSubResources","columns","parentRoute","parentModel","parentDir","enums","baseUrl","filter","c","fieldInput","format","resource","flatMap","resourcePath","test","resolution","resolveChildResourceDetailed","ok","resourceLoadErrorsRegistry","record","name","path","error","reason","id","attempted","join","childJson","value","json","childDir","dir","parent","route","childRoute","replace","rawChildColumns","expandedChildColumns","expandExtendColumns","undefined","childColumns","applyRelationFormatDefault","injectEnumValues","enrichedChildColumns","enrichNestedRelationColumns","autoIncludes","col","relationType","deriveRelationTypeFromColumns","map","relation","explicitIncludes","include","explicitNames","Set","e","mergedIncludes","has","childLookupKey","find","idField","childCalculatedColumns","calculatedColumns","childViews","buildViewsFromColumns","length","table","injectCalculatedColumns","view","injectCalculatedColumnsToView","childOps","operations","childKind","kind","column","childModel","model","charAt","toLowerCase","slice","foreignKey","title","tag","idType","hiddenInTable","views","findAll","findOne","create","update","patch","delete","actions","modalSize","display","hiddenInForm","hiddenInView","includeInFindOne","opts","options","sort","findOneOrderBy","buildChildSortClause","sortDir","buildValueLabelColumns","valueLabelColumns","pickExtensions","obj","Object","fromEntries","getResourceExtensions","keys","filter","k","undefined","map","fromJson","json","schema","hooks","dirPath","baseUrl","actions","tableActions","enums","repository","isCustom","kind","rawColumns","expandExtendColumns","columns","enrichRelationTypes","applyRelationFormatDefault","injectEnumValues","subResources","buildSubResources","route","model","enrichedColumns","resolveColumnFieldVariants","enrichResourceRefColumns","enrichActionColumns","calculatedColumns","views","buildViews","length","table","injectCalculatedColumns","view","injectCalculatedColumnsToView","lookup","buildLookup","enrichedInclude","enrichIncludeWithSort","include","definition","buildResourceDefinitions","operations","name","tag","sidebar","display","idType","key","idField","database","modalSize","buildValueLabelColumns","valueLabelColumns","keyCol","find","c","searchCols","showInLookup","searchable","labels","col","fieldInput","relationType","resource","relationName","id","replace","child","resolveChildResource","childColumns","displayCol","hiddenInTable","label","import_node_fs","migrateResourceJsonFile","jsonPath","opts","raw","readRawResourceJson","status","version","BASELINE_RESOURCE_VERSION","from","resourceVersionOf","CURRENT_RESOURCE_VERSION","isDev","expected","error","result","runResourceMigrations","validation","validateResourceJson","success","to","message","writeFileSync","serializeResourceJson","written","err","MigrationPathError","MigrationStepError","ALL_OPS","validateResourceConfig","config","opts","errors","warnings","definition","resolveDefinition","enabledOps","filter","op","isOperationEnabled","length","push","kind","database","repoError","validateCustomRepository","repository","repositoryFileExistsOnDisk","import_node_fs","import_node_path","loadResourceConfigsFromDir","dirPath","baseUrl","enumsFile","onResourceDir","existsSync","resourceLoadErrorsRegistry","clear","resourceLoadReportRegistry","enums","loadEnumRegistry","entries","readdirSync","withFileTypes","dirs","filter","e","isDirectory","map","name","configs","dir","basePath","join","schemaFile","findModule","schema","importDefault","undefined","hooks","loadResourceHooks","jsonFile","migration","migrateResourceJsonFile","isDev","IS_DEV","status","record","path","error","version","expectedVersion","expected","state","from","to","console","info","result","readResourceJson","success","json","data","draft","schemaVersion","errorsBeforeRepo","getAll","length","repository","kind","loadCustomRepository","repositoryImportFailed","actions","loadActions","tableActions","config","fromJson","repositoryFileExistsOnDisk","errors","warnings","validateResourceConfig","warning","loadSubResourceHooks","subResources","loadSubResourceRepositories","route","push","tsFile","merged","ResourceConfigLoader","getResourceDir","_route","undefined","FileSystemResourceConfigLoader","ResourceConfigLoader","dirsByRoute","Map","dirPath","baseUrl","enumsFile","loadAll","configs","loadResourceConfigsFromDir","route","dir","set","loadByRoute","find","c","getResourceDir","get","import_node_fs","import_node_path","import_node_url","CONNECTION_STRING_PATTERN","stripConnectionStrings","message","replace","getCroutonVersion","startDir","__dirname","dirname","fileURLToPath","dir","pkgPath","join","existsSync","pkg","JSON","parse","readFileSync","name","version","getVersion","process","env","getEnvironment","checkDatabases","registry","results","adapter","entries","healthCheck","push","connected","err","error","getResourceStatus","loadedConfigs","warningsByName","Map","w","resourceLoadReportRegistry","getByState","existing","get","warning","set","valid","map","c","path","route","schemaVersion","CURRENT_RESOURCE_VERSION","kind","repository","customOperations","CUSTOM_OPS","filter","op","sidebar","hide","hidden","has","warnings","failed","resourceLoadErrorsRegistry","getAll","e","expectedVersion","draft","d","buildSummary","databases","resources","databaseErrors","length","resourceErrors","r","warningCount","reduce","acc","ok","getSystemEnums","category","values","value","label","getProjectEnums","enumRegistry","Object","entry","getEnums","system","project","countKeys","obj","prefix","total","empty","v","Array","isArray","sub","getI18nStatus","translationRegistry","active","undefined","languages","bundles","language","bundle","bundleFor","keyCount","emptyKeys","defaultLanguage","buildStatus","summary","croutonVersion","environment","enums","i18n","import_common","import_swagger","createStatusController","enumRegistry","translationRegistry","prefix","StatusController","dataSourceRegistry","configRegistry","getStatus","configs","getAll","buildStatus","summary","status","description","Reflect","defineMetadata","DataSourceRegistry","ResourceConfigRegistry","import_node_path","import_node_url","CroutonApiModule","onModuleInit","BigInt","prototype","toJSON","Number","Decimal","parseFloat","toString","forResources","configs","dataSources","loader","appConfig","config","baseUrl","prefix","security","dataSourceRegistry","DataSourceRegistry","guardRegistry","SecurityGuardRegistry","guards","moduleDefaultSecurity","default","startDir","__dirname","dirname","fileURLToPath","enumRegistry","loadEnumRegistry","enumsFile","validConfigs","c","adapter","database","entries","length","resolveAdapter","e","resourceLoadErrorsRegistry","record","name","path","route","error","message","String","adapterIsCustom","kind","hasRepository","repository","adapterHasCrud","findAll","count","push","adapterClient","client","undefined","problem","validateCustomRepository","model","supports","configRegistry","ResourceConfigRegistry","translationRegistry","i18n","translationsDir","join","configDir","TranslationRegistry","setTranslationRegistry","controllers","map","createCrudController","schemaEnricher","createAppLayoutController","sidebarGroups","title","autoSave","IS_DEV","DevResourcesController","createStatusController","module","exports","providers","provide","APP_INTERCEPTOR","useClass","NoCacheInterceptor","APP_FILTER","CroutonValidationExceptionFilter","useValue","CroutonSecurityGuard","classes","useFactory","LanguageInterceptor","forResourceDir","dirPath","dataSourcesPath","extensions","registerResourceExtensions","loadConfig","FileSystemResourceConfigLoader","loadResourceConfigsFromDir","loadDataSourcesFromDir","forLoader","parseSchema","input","appConfig","view","extensions","registerResourceExtensions","normalized","json","parseResult","buildResourceJsonSchema","safeParse","success","Error","error","message","resource","fromJson","data","schema","hooks","dirPath","baseUrl","actions","tableActions","enums","undefined","payload","buildViewsPayload","buildDefinitionPayload","buildResourceJsonPayload","schemaEnricher"]}
|