@ghentcdh/crouton-api 0.0.1-alpha.37 → 0.0.1-alpha.38

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 CHANGED
@@ -52,157 +52,6 @@ module.exports = __toCommonJS(index_exports);
52
52
  var getImportMetaUrl = /* @__PURE__ */ __name(() => typeof document === "undefined" ? new URL(`file:${__filename}`).href : document.currentScript && document.currentScript.tagName.toUpperCase() === "SCRIPT" ? document.currentScript.src : new URL("main.js", document.baseURI).href, "getImportMetaUrl");
53
53
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
54
54
 
55
- // src/lib/crud/builder/column-predicates.ts
56
- var isBoolean = /* @__PURE__ */ __name((col) => col.fieldInput?.type === "boolean" || col.columnType === "boolean", "isBoolean");
57
- var isRelation = /* @__PURE__ */ __name((col) => col.fieldInput?.format === "relation", "isRelation");
58
- var isAutocomplete = /* @__PURE__ */ __name((col) => col.fieldInput?.type === "autocomplete", "isAutocomplete");
59
- var isRecordCell = /* @__PURE__ */ __name((col) => isRelation(col) || isAutocomplete(col), "isRecordCell");
60
- var isDateRange = /* @__PURE__ */ __name((col) => col.fieldInput?.format === "date-range", "isDateRange");
61
-
62
- // src/lib/crud/builder/column.utils.ts
63
- var colPosition = /* @__PURE__ */ __name((col, i) => col.fieldInput?.position ?? i, "colPosition");
64
- var sortByPosition = /* @__PURE__ */ __name((cols) => cols.map((col, i) => ({
65
- col,
66
- i
67
- })).sort((a, b) => colPosition(a.col, a.i) - colPosition(b.col, b.i)).map(({ col }) => col), "sortByPosition");
68
- var columnForContext = /* @__PURE__ */ __name((col, ctx) => {
69
- if (ctx === "view") return {
70
- ...col,
71
- fieldInput: col.fieldView ?? col.fieldInput
72
- };
73
- if (ctx === "table") return {
74
- ...col,
75
- fieldInput: col.fieldTable ?? col.fieldInput
76
- };
77
- return col;
78
- }, "columnForContext");
79
- var toViewColumn = /* @__PURE__ */ __name((col) => ({
80
- id: col.id,
81
- ...col.label && {
82
- label: col.label
83
- },
84
- ...col.sortable != null && {
85
- sortable: col.sortable
86
- },
87
- ...col.searchable != null && {
88
- searchable: col.searchable
89
- },
90
- ...col.fieldInput && {
91
- fieldInput: col.fieldInput
92
- }
93
- }), "toViewColumn");
94
-
95
- // src/lib/crud/builder/sort.helpers.ts
96
- var deriveSortId = /* @__PURE__ */ __name((col) => {
97
- if (col.sortable === false) return null;
98
- if (col.sortId) return col.sortId;
99
- const base = col.column ?? col.id;
100
- const fi = col.fieldInput;
101
- const opts = fi?.options ?? {};
102
- const isRelation2 = fi?.format === "relation" || !!fi?.relationType || fi?.type === "autocomplete" || typeof opts.resource === "string";
103
- if (isRelation2) {
104
- const key = (typeof col.displayKey === "string" ? col.displayKey : void 0) ?? (typeof opts.displayKey === "string" ? opts.displayKey : void 0) ?? (typeof opts.labelKey === "string" ? opts.labelKey : void 0);
105
- if (!key) return null;
106
- const path2 = key.includes(".") ? key : `${base}.${key}`;
107
- return path2.endsWith(".label") ? path2.slice(0, -".label".length) : path2;
108
- }
109
- if (!col.displayKey) return base;
110
- const path = `${base}.${col.displayKey}`;
111
- const isValueLabel = !!col.enum || opts.emitObject === true;
112
- if (isValueLabel && path.endsWith(".label")) return path.slice(0, -".label".length);
113
- return path;
114
- }, "deriveSortId");
115
- var resolveDefaultSort = /* @__PURE__ */ __name((tableCols, allColumns) => {
116
- const isSortable = /* @__PURE__ */ __name((c) => c.sortable !== false, "isSortable");
117
- const sortCol = tableCols.find((c) => c.defaultSort && isSortable(c)) ?? tableCols.find(isSortable) ?? allColumns?.find((c) => c.idField);
118
- return sortCol ? deriveSortId(sortCol) ?? sortCol.id : void 0;
119
- }, "resolveDefaultSort");
120
-
121
- // src/lib/crud/builder/schema-transforms.ts
122
- var allowAdditionalProperties = /* @__PURE__ */ __name((schema) => {
123
- if (schema["type"] === "object") {
124
- schema["additionalProperties"] = true;
125
- const props = schema["properties"];
126
- if (props) {
127
- for (const value of Object.values(props)) {
128
- allowAdditionalProperties(value);
129
- }
130
- }
131
- }
132
- if (schema["type"] === "array" && schema["items"]) {
133
- allowAdditionalProperties(schema["items"]);
134
- }
135
- }, "allowAdditionalProperties");
136
- var isNullableProperty = /* @__PURE__ */ __name((prop) => {
137
- const anyOf = prop?.["anyOf"];
138
- return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
139
- }, "isNullableProperty");
140
- var dropNullableFromRequired = /* @__PURE__ */ __name((schema) => {
141
- if (schema["type"] !== "object") return;
142
- const props = schema["properties"];
143
- if (!props) return;
144
- const required = schema["required"];
145
- if (Array.isArray(required)) {
146
- schema["required"] = required.filter((key) => !isNullableProperty(props[key]));
147
- }
148
- for (const value of Object.values(props)) {
149
- dropNullableFromRequired(value);
150
- }
151
- }, "dropNullableFromRequired");
152
- var enforceRequiredMinLength = /* @__PURE__ */ __name((schema) => {
153
- if (schema["type"] !== "object") return;
154
- const props = schema["properties"];
155
- if (!props) return;
156
- for (const prop of Object.values(props)) {
157
- if (prop?.["type"] === "string" && !("minLength" in prop)) {
158
- prop["minLength"] = 1;
159
- } else if (prop?.["type"] === "object") {
160
- enforceRequiredMinLength(prop);
161
- }
162
- }
163
- }, "enforceRequiredMinLength");
164
- var applySchemaTransforms = /* @__PURE__ */ __name((schema) => {
165
- allowAdditionalProperties(schema);
166
- dropNullableFromRequired(schema);
167
- enforceRequiredMinLength(schema);
168
- }, "applySchemaTransforms");
169
-
170
- // src/lib/crud/builder/schema.helpers.ts
171
- var pickByColumns = /* @__PURE__ */ __name((schema, columns, filter) => {
172
- if (!schema) return void 0;
173
- if (!columns?.length) return schema;
174
- const baseFilter = /* @__PURE__ */ __name((c) => !isRelation(c) && (filter ? filter(c) : true), "baseFilter");
175
- const schemaKeys = new Set(Object.keys(schema.shape));
176
- const filtered = columns.filter((c) => baseFilter(c) && schemaKeys.has(c.id));
177
- if (!filtered.length) return void 0;
178
- const mask = Object.fromEntries(filtered.map((c) => [
179
- c.id,
180
- true
181
- ]));
182
- return schema.pick(mask);
183
- }, "pickByColumns");
184
- var opWithSchema = /* @__PURE__ */ __name((enabled, schema) => {
185
- if (enabled === false) return void 0;
186
- return schema ? {
187
- schema
188
- } : true;
189
- }, "opWithSchema");
190
- var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
191
- if (!entry) return void 0;
192
- if (entry === true) {
193
- throw new Error("`operations.upsert` must be an object with `upsertOn`, not `true`.");
194
- }
195
- if (typeof entry === "object") {
196
- return {
197
- upsertOn: entry.upsertOn,
198
- ...schema && {
199
- schema
200
- }
201
- };
202
- }
203
- return void 0;
204
- }, "upsertOp");
205
-
206
55
  // ../crouton-core/src/lib/request.model.ts
207
56
  var import_zod2 = require("zod");
208
57
 
@@ -334,10 +183,10 @@ var ElementBuilder = class extends Builder {
334
183
  return this;
335
184
  }
336
185
  /** Merge a patch into the typed options bag. */
337
- opt(patch2) {
186
+ opt(patch) {
338
187
  this.options = {
339
188
  ...this.options,
340
- ...patch2
189
+ ...patch
341
190
  };
342
191
  return this;
343
192
  }
@@ -835,6 +684,8 @@ var FieldInputSchema = import_zod9.z.object({
835
684
  relationType: RelationType.optional(),
836
685
  /** FK field on the child model pointing back to the parent, e.g. `"workId"`. Defaults to `${parentModel}Id`. */
837
686
  foreignKey: import_zod9.z.string().optional(),
687
+ /** Override the Prisma relation field name when it differs from the column id. */
688
+ relation: import_zod9.z.string().optional(),
838
689
  /** Override the display order in form views. Lower values come first. */
839
690
  position: import_zod9.z.number().optional(),
840
691
  options: import_zod9.z.union([
@@ -1284,103 +1135,218 @@ var CONFIG_FILES = [
1284
1135
  "crouton.js"
1285
1136
  ];
1286
1137
 
1287
- // src/lib/crud/builder/table-schema.builder.ts
1288
- var SHARED_CELL_OPTION_KEYS = [
1289
- "values",
1290
- "storeValue",
1291
- "uri",
1292
- "resourceUri",
1293
- "schemasUri",
1294
- "customComponent"
1295
- ];
1296
- var pickSharedCellOptions = /* @__PURE__ */ __name((col) => {
1297
- const options = col.fieldInput?.options ?? {};
1298
- return Object.fromEntries(SHARED_CELL_OPTION_KEYS.filter((key) => options[key] !== void 0).map((key) => [
1299
- key,
1300
- options[key]
1301
- ]));
1302
- }, "pickSharedCellOptions");
1303
- var buildTableUiSchema = /* @__PURE__ */ __name((cols) => {
1304
- const layout = TableBuilder.init().addControls(...cols.map((col) => {
1305
- const cellBuilder = isBoolean(col) ? BooleanCellBuilder : TextCellBuilder;
1306
- let builder = cellBuilder.properties(col.id);
1307
- if (col.displayKey) builder = builder.key(col.displayKey);
1308
- if (col.sortId) builder = builder.setSortId(col.sortId);
1309
- return builder;
1310
- })).build();
1311
- const colMap = Object.fromEntries(cols.map((c) => [
1312
- c.id,
1313
- c
1314
- ]));
1315
- layout.elements = layout.elements.map((el) => {
1316
- const id = el.scope?.replace("#/properties/", "");
1317
- const col = id ? colMap[id] : void 0;
1318
- if (!col) return el;
1319
- const fieldInputOptions = isRecordCell(col) || isDateRange(col) ? col.fieldInput?.options ?? {} : pickSharedCellOptions(col);
1320
- const dataPathOption = col.column ? {
1321
- dataPath: col.column
1322
- } : {};
1323
- const derivedSortId = isRecordCell(col) || isDateRange(col) ? null : deriveSortId(col);
1324
- const sortOptions = derivedSortId ? {
1325
- sortId: derivedSortId
1326
- } : {
1327
- sortable: false
1328
- };
1329
- const relationTypeOption = col.fieldInput?.relationType ? {
1330
- relationType: col.fieldInput.relationType
1331
- } : {};
1332
- return {
1333
- ...el,
1334
- options: {
1335
- ...el.options ?? {},
1336
- ...fieldInputOptions,
1337
- ...dataPathOption,
1338
- ...sortOptions,
1339
- ...relationTypeOption,
1340
- ...isDateRange(col) && {
1341
- format: "date-range"
1342
- },
1343
- label: col.label
1344
- },
1345
- ...isRecordCell(col) && {
1346
- type: "RecordCell"
1347
- },
1348
- ...isDateRange(col) && {
1349
- type: "Control"
1350
- }
1351
- };
1352
- });
1353
- return layout;
1354
- }, "buildTableUiSchema");
1138
+ // ../crouton-core/src/lib/view/column-predicates.ts
1139
+ var isBoolean = /* @__PURE__ */ __name((col) => col.fieldInput?.type === "boolean" || col.columnType === "boolean", "isBoolean");
1140
+ var isRelation = /* @__PURE__ */ __name((col) => col.fieldInput?.format === "relation", "isRelation");
1141
+ var isAutocomplete = /* @__PURE__ */ __name((col) => col.fieldInput?.type === "autocomplete", "isAutocomplete");
1142
+ var isRecordCell = /* @__PURE__ */ __name((col) => isRelation(col) || isAutocomplete(col), "isRecordCell");
1143
+ var isDateRange = /* @__PURE__ */ __name((col) => col.fieldInput?.format === "date-range", "isDateRange");
1355
1144
 
1356
- // src/lib/crud/builder/form-schema.builder.ts
1357
- var buildConditionSchema = /* @__PURE__ */ __name((when) => {
1358
- if (when.notExists) return {
1359
- not: {
1360
- minLength: 1
1361
- }
1362
- };
1363
- if (when.exists) return {
1364
- minLength: 1
1365
- };
1366
- if (when.neq !== void 0) return {
1367
- not: {
1368
- const: when.neq
1369
- }
1145
+ // ../crouton-core/src/lib/view/column.utils.ts
1146
+ var colPosition = /* @__PURE__ */ __name((col, i) => col.fieldInput?.position ?? i, "colPosition");
1147
+ var sortByPosition = /* @__PURE__ */ __name((cols) => cols.map((col, i) => ({
1148
+ col,
1149
+ i
1150
+ })).sort((a, b) => colPosition(a.col, a.i) - colPosition(b.col, b.i)).map(({ col }) => col), "sortByPosition");
1151
+ var columnForContext = /* @__PURE__ */ __name((col, ctx) => {
1152
+ if (ctx === "view") return {
1153
+ ...col,
1154
+ fieldInput: col.fieldView ?? col.fieldInput
1370
1155
  };
1371
- return {
1372
- const: when.eq
1156
+ if (ctx === "table") return {
1157
+ ...col,
1158
+ fieldInput: col.fieldTable ?? col.fieldInput
1373
1159
  };
1374
- }, "buildConditionSchema");
1375
- var applyColumnRule = /* @__PURE__ */ __name((control, col) => {
1376
- if (col.disabledWhen) {
1377
- control.disableWhen(`#/properties/${col.disabledWhen.field}`, buildConditionSchema(col.disabledWhen));
1378
- return;
1379
- }
1380
- const when = col.showWhen ?? col.hideWhen;
1381
- if (!when) return;
1382
- const scope = `#/properties/${when.field}`;
1383
- const schema = buildConditionSchema(when);
1160
+ return col;
1161
+ }, "columnForContext");
1162
+ var toViewColumn = /* @__PURE__ */ __name((col) => ({
1163
+ id: col.id,
1164
+ ...col.label && {
1165
+ label: col.label
1166
+ },
1167
+ ...col.sortable != null && {
1168
+ sortable: col.sortable
1169
+ },
1170
+ ...col.searchable != null && {
1171
+ searchable: col.searchable
1172
+ },
1173
+ ...col.fieldInput && {
1174
+ fieldInput: col.fieldInput
1175
+ }
1176
+ }), "toViewColumn");
1177
+
1178
+ // ../crouton-core/src/lib/view/sort.helpers.ts
1179
+ var deriveSortId = /* @__PURE__ */ __name((col) => {
1180
+ if (col.sortable === false) return null;
1181
+ if (col.sortId) return col.sortId;
1182
+ const base = col.column ?? col.id;
1183
+ const fi = col.fieldInput;
1184
+ const opts = fi?.options ?? {};
1185
+ const isRelation2 = fi?.format === "relation" || !!fi?.relationType || fi?.type === "autocomplete" || typeof opts.resource === "string";
1186
+ if (isRelation2) {
1187
+ const key = (typeof col.displayKey === "string" ? col.displayKey : void 0) ?? (typeof opts.displayKey === "string" ? opts.displayKey : void 0) ?? (typeof opts.labelKey === "string" ? opts.labelKey : void 0);
1188
+ if (!key) return null;
1189
+ const path2 = key.includes(".") ? key : `${base}.${key}`;
1190
+ return path2.endsWith(".label") ? path2.slice(0, -".label".length) : path2;
1191
+ }
1192
+ if (!col.displayKey) return base;
1193
+ const path = `${base}.${col.displayKey}`;
1194
+ const isValueLabel = !!col.enum || opts.emitObject === true;
1195
+ if (isValueLabel && path.endsWith(".label")) return path.slice(0, -".label".length);
1196
+ return path;
1197
+ }, "deriveSortId");
1198
+ var resolveDefaultSort = /* @__PURE__ */ __name((tableCols, allColumns) => {
1199
+ const isSortable = /* @__PURE__ */ __name((c) => c.sortable !== false, "isSortable");
1200
+ const sortCol = tableCols.find((c) => c.defaultSort && isSortable(c)) ?? tableCols.find(isSortable) ?? allColumns?.find((c) => c.idField);
1201
+ return sortCol ? deriveSortId(sortCol) ?? sortCol.id : void 0;
1202
+ }, "resolveDefaultSort");
1203
+
1204
+ // ../crouton-core/src/lib/view/schema-transforms.ts
1205
+ var allowAdditionalProperties = /* @__PURE__ */ __name((schema) => {
1206
+ if (schema["type"] === "object") {
1207
+ schema["additionalProperties"] = true;
1208
+ const props = schema["properties"];
1209
+ if (props) {
1210
+ for (const value of Object.values(props)) {
1211
+ allowAdditionalProperties(value);
1212
+ }
1213
+ }
1214
+ }
1215
+ if (schema["type"] === "array" && schema["items"]) {
1216
+ allowAdditionalProperties(schema["items"]);
1217
+ }
1218
+ }, "allowAdditionalProperties");
1219
+ var isNullableProperty = /* @__PURE__ */ __name((prop) => {
1220
+ const anyOf = prop?.["anyOf"];
1221
+ return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
1222
+ }, "isNullableProperty");
1223
+ var dropNullableFromRequired = /* @__PURE__ */ __name((schema) => {
1224
+ if (schema["type"] !== "object") return;
1225
+ const props = schema["properties"];
1226
+ if (!props) return;
1227
+ const required = schema["required"];
1228
+ if (Array.isArray(required)) {
1229
+ schema["required"] = required.filter((key) => !isNullableProperty(props[key]));
1230
+ }
1231
+ for (const value of Object.values(props)) {
1232
+ dropNullableFromRequired(value);
1233
+ }
1234
+ }, "dropNullableFromRequired");
1235
+ var enforceRequiredMinLength = /* @__PURE__ */ __name((schema) => {
1236
+ if (schema["type"] !== "object") return;
1237
+ const props = schema["properties"];
1238
+ if (!props) return;
1239
+ for (const prop of Object.values(props)) {
1240
+ if (prop?.["type"] === "string" && !("minLength" in prop)) {
1241
+ prop["minLength"] = 1;
1242
+ } else if (prop?.["type"] === "object") {
1243
+ enforceRequiredMinLength(prop);
1244
+ }
1245
+ }
1246
+ }, "enforceRequiredMinLength");
1247
+ var applySchemaTransforms = /* @__PURE__ */ __name((schema) => {
1248
+ allowAdditionalProperties(schema);
1249
+ dropNullableFromRequired(schema);
1250
+ enforceRequiredMinLength(schema);
1251
+ }, "applySchemaTransforms");
1252
+
1253
+ // ../crouton-core/src/lib/view/table-schema.builder.ts
1254
+ var SHARED_CELL_OPTION_KEYS = [
1255
+ "values",
1256
+ "storeValue",
1257
+ "uri",
1258
+ "resourceUri",
1259
+ "schemasUri",
1260
+ "customComponent"
1261
+ ];
1262
+ var pickSharedCellOptions = /* @__PURE__ */ __name((col) => {
1263
+ const options = col.fieldInput?.options ?? {};
1264
+ return Object.fromEntries(SHARED_CELL_OPTION_KEYS.filter((key) => options[key] !== void 0).map((key) => [
1265
+ key,
1266
+ options[key]
1267
+ ]));
1268
+ }, "pickSharedCellOptions");
1269
+ var buildTableUiSchema = /* @__PURE__ */ __name((cols) => {
1270
+ const layout = TableBuilder.init().addControls(...cols.map((col) => {
1271
+ const cellBuilder = isBoolean(col) ? BooleanCellBuilder : TextCellBuilder;
1272
+ let builder = cellBuilder.properties(col.id);
1273
+ if (col.displayKey) builder = builder.key(col.displayKey);
1274
+ if (col.sortId) builder = builder.setSortId(col.sortId);
1275
+ return builder;
1276
+ })).build();
1277
+ const colMap = Object.fromEntries(cols.map((c) => [
1278
+ c.id,
1279
+ c
1280
+ ]));
1281
+ layout.elements = layout.elements.map((el) => {
1282
+ const id = el.scope?.replace("#/properties/", "");
1283
+ const col = id ? colMap[id] : void 0;
1284
+ if (!col) return el;
1285
+ const fieldInputOptions = isRecordCell(col) || isDateRange(col) ? col.fieldInput?.options ?? {} : pickSharedCellOptions(col);
1286
+ const dataPathOption = col.column ? {
1287
+ dataPath: col.column
1288
+ } : {};
1289
+ const derivedSortId = isRecordCell(col) || isDateRange(col) ? null : deriveSortId(col);
1290
+ const sortOptions = derivedSortId ? {
1291
+ sortId: derivedSortId
1292
+ } : {
1293
+ sortable: false
1294
+ };
1295
+ const relationTypeOption = col.fieldInput?.relationType ? {
1296
+ relationType: col.fieldInput.relationType
1297
+ } : {};
1298
+ return {
1299
+ ...el,
1300
+ options: {
1301
+ ...el.options ?? {},
1302
+ ...fieldInputOptions,
1303
+ ...dataPathOption,
1304
+ ...sortOptions,
1305
+ ...relationTypeOption,
1306
+ ...isDateRange(col) && {
1307
+ format: "date-range"
1308
+ },
1309
+ label: col.label
1310
+ },
1311
+ ...isRecordCell(col) && {
1312
+ type: "RecordCell"
1313
+ },
1314
+ ...isDateRange(col) && {
1315
+ type: "Control"
1316
+ }
1317
+ };
1318
+ });
1319
+ return layout;
1320
+ }, "buildTableUiSchema");
1321
+
1322
+ // ../crouton-core/src/lib/view/form-schema.builder.ts
1323
+ var buildConditionSchema = /* @__PURE__ */ __name((when) => {
1324
+ if (when.notExists) return {
1325
+ not: {
1326
+ minLength: 1
1327
+ }
1328
+ };
1329
+ if (when.exists) return {
1330
+ minLength: 1
1331
+ };
1332
+ if (when.neq !== void 0) return {
1333
+ not: {
1334
+ const: when.neq
1335
+ }
1336
+ };
1337
+ return {
1338
+ const: when.eq
1339
+ };
1340
+ }, "buildConditionSchema");
1341
+ var applyColumnRule = /* @__PURE__ */ __name((control, col) => {
1342
+ if (col.disabledWhen) {
1343
+ control.disableWhen(`#/properties/${col.disabledWhen.field}`, buildConditionSchema(col.disabledWhen));
1344
+ return;
1345
+ }
1346
+ const when = col.showWhen ?? col.hideWhen;
1347
+ if (!when) return;
1348
+ const scope = `#/properties/${when.field}`;
1349
+ const schema = buildConditionSchema(when);
1384
1350
  if (col.showWhen) control.showWhen(scope, schema);
1385
1351
  else control.hideWhen(scope, schema);
1386
1352
  }, "applyColumnRule");
@@ -1447,7 +1413,7 @@ var buildFormUiSchema = /* @__PURE__ */ __name((cols) => {
1447
1413
  return layout.build();
1448
1414
  }, "buildFormUiSchema");
1449
1415
 
1450
- // src/lib/crud/builder/calculated-columns.builder.ts
1416
+ // ../crouton-core/src/lib/view/calculated-columns.builder.ts
1451
1417
  var isVisibleInMode = /* @__PURE__ */ __name((c, mode) => mode === "table" ? !c.hiddenInTable : !c.hiddenInView, "isVisibleInMode");
1452
1418
  var buildCalculatedElement = /* @__PURE__ */ __name((c, mode) => mode === "table" ? {
1453
1419
  type: c.type === "boolean" ? "BooleanCell" : "TextCell",
@@ -1527,10 +1493,10 @@ var injectCalculatedColumnsIntoView = /* @__PURE__ */ __name((viewConfig, calcul
1527
1493
  var injectCalculatedColumns = /* @__PURE__ */ __name((tableView, calculated) => injectCalculatedColumnsIntoView(tableView, calculated, "table"), "injectCalculatedColumns");
1528
1494
  var injectCalculatedColumnsToView = /* @__PURE__ */ __name((viewConfig, calculated) => injectCalculatedColumnsIntoView(viewConfig, calculated, "view"), "injectCalculatedColumnsToView");
1529
1495
 
1530
- // src/lib/crud/builder/view.builder.ts
1496
+ // ../crouton-core/src/lib/view/view.builder.ts
1531
1497
  var import_zod18 = require("zod");
1532
1498
 
1533
- // src/lib/crud/schema.utils.ts
1499
+ // ../crouton-core/src/lib/view/json-schema.opts.ts
1534
1500
  var import_zod17 = require("zod");
1535
1501
  var dateOverride = /* @__PURE__ */ __name(({ zodSchema, jsonSchema }) => {
1536
1502
  if (zodSchema instanceof import_zod17.z.ZodDate) {
@@ -1542,74 +1508,8 @@ var jsonSchemaOpts = {
1542
1508
  unrepresentable: "any",
1543
1509
  override: dateOverride
1544
1510
  };
1545
- function isZodSchema(schema) {
1546
- return schema instanceof import_zod17.ZodObject;
1547
- }
1548
- __name(isZodSchema, "isZodSchema");
1549
- var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
1550
- const anyOf = property?.["anyOf"];
1551
- return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
1552
- }, "isNullableProperty");
1553
- var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
1554
- const { properties, required } = jsonSchema;
1555
- if (!properties || !Array.isArray(required)) return;
1556
- jsonSchema.required = required.filter((key) => !isNullableProperty2(properties[key]));
1557
- }, "dropNullableFromRequired");
1558
- function toJsonSchema(schema) {
1559
- if (isZodSchema(schema)) {
1560
- const jsonSchema = (0, import_zod17.toJSONSchema)(schema, {
1561
- target: "openApi3",
1562
- ...jsonSchemaOpts
1563
- });
1564
- dropNullableFromRequired2(jsonSchema);
1565
- return jsonSchema;
1566
- }
1567
- return schema;
1568
- }
1569
- __name(toJsonSchema, "toJsonSchema");
1570
- var unwrap = /* @__PURE__ */ __name((schema) => {
1571
- let s = schema;
1572
- let t = s?._zod?.def?.type;
1573
- while (t === "optional" || t === "nullable" || t === "default" || t === "readonly") {
1574
- s = s._zod.def.innerType;
1575
- t = s?._zod?.def?.type;
1576
- }
1577
- return s;
1578
- }, "unwrap");
1579
- var typeOf = /* @__PURE__ */ __name((schema) => schema?._zod?.def?.type, "typeOf");
1580
- function toSelectFields(schema) {
1581
- if (!isZodSchema(schema)) {
1582
- return Object.keys(schema.properties).reduce((acc, key) => {
1583
- acc[key] = true;
1584
- return acc;
1585
- }, {});
1586
- }
1587
- const result = {};
1588
- for (const [key, value] of Object.entries(schema.shape)) {
1589
- const inner = unwrap(value);
1590
- const t = typeOf(inner);
1591
- if (t === "object") {
1592
- result[key] = {
1593
- select: toSelectFields(inner)
1594
- };
1595
- continue;
1596
- }
1597
- if (t === "array") {
1598
- const element = unwrap(inner._zod.def.element);
1599
- if (typeOf(element) === "object") {
1600
- result[key] = {
1601
- select: toSelectFields(element)
1602
- };
1603
- continue;
1604
- }
1605
- }
1606
- result[key] = true;
1607
- }
1608
- return result;
1609
- }
1610
- __name(toSelectFields, "toSelectFields");
1611
1511
 
1612
- // src/lib/crud/builder/view.builder.ts
1512
+ // ../crouton-core/src/lib/view/view.builder.ts
1613
1513
  var patchFilterProperties = /* @__PURE__ */ __name((jsonSchema, columns) => {
1614
1514
  if (!columns?.length) return;
1615
1515
  const properties = jsonSchema.properties;
@@ -1715,7 +1615,7 @@ var buildViewsFromColumns = /* @__PURE__ */ __name((columns) => {
1715
1615
  const buildJsonSchema = /* @__PURE__ */ __name((cols) => {
1716
1616
  const properties = {};
1717
1617
  for (const c of cols) {
1718
- if (c.column) {
1618
+ if (c.column && c.column !== c.id) {
1719
1619
  if (!properties[c.column]) {
1720
1620
  properties[c.column] = {
1721
1621
  type: "object",
@@ -1768,7 +1668,7 @@ var buildViewsFromColumns = /* @__PURE__ */ __name((columns) => {
1768
1668
  elements: elements.map((el) => {
1769
1669
  const id = el.scope?.replace("#/properties/", "");
1770
1670
  const col = id ? colMap[id] : void 0;
1771
- if (!col?.column) return el;
1671
+ if (!col?.column || col.column === col.id) return el;
1772
1672
  const keyPath = (col.displayKey ?? col.id).split(".");
1773
1673
  const propPath = keyPath.map((k) => `properties/${k}`).join("/");
1774
1674
  return {
@@ -1804,26 +1704,42 @@ var buildViewsFromColumns = /* @__PURE__ */ __name((columns) => {
1804
1704
  return Object.keys(views).length ? views : void 0;
1805
1705
  }, "buildViewsFromColumns");
1806
1706
 
1707
+ // ../crouton-core/src/lib/view/view.schema.ts
1708
+ var import_zod19 = require("zod");
1709
+ var ViewColumnConfigSchema = import_zod19.z.object({
1710
+ id: import_zod19.z.string(),
1711
+ label: import_zod19.z.string().optional(),
1712
+ sortable: import_zod19.z.boolean().optional(),
1713
+ searchable: import_zod19.z.boolean().optional(),
1714
+ fieldInput: FieldInputSchema.optional()
1715
+ });
1716
+ var ViewConfigSchema = import_zod19.z.object({
1717
+ json_schema: import_zod19.z.record(import_zod19.z.string(), import_zod19.z.unknown()),
1718
+ ui_schema: import_zod19.z.record(import_zod19.z.string(), import_zod19.z.unknown()),
1719
+ columns: import_zod19.z.array(ViewColumnConfigSchema),
1720
+ defaultSort: import_zod19.z.string().optional()
1721
+ });
1722
+
1807
1723
  // src/lib/crouton-api.module.ts
1808
- var import_common14 = require("@nestjs/common");
1724
+ var import_common19 = require("@nestjs/common");
1809
1725
  var import_core = require("@nestjs/core");
1810
1726
 
1811
1727
  // src/lib/crud/app-layout/app-layout.types.ts
1812
- var import_zod19 = require("zod");
1813
- var SidebarLeafSchema = import_zod19.z.object({
1814
- kind: import_zod19.z.literal("item").default("item"),
1815
- id: import_zod19.z.string(),
1816
- label: import_zod19.z.string(),
1817
- position: import_zod19.z.number().optional()
1728
+ var import_zod20 = require("zod");
1729
+ var SidebarLeafSchema = import_zod20.z.object({
1730
+ kind: import_zod20.z.literal("item").default("item"),
1731
+ id: import_zod20.z.string(),
1732
+ label: import_zod20.z.string(),
1733
+ position: import_zod20.z.number().optional()
1818
1734
  });
1819
- var SidebarGroupSchema2 = import_zod19.z.object({
1820
- kind: import_zod19.z.literal("group").default("group"),
1821
- id: import_zod19.z.string(),
1822
- label: import_zod19.z.string(),
1823
- position: import_zod19.z.number().optional(),
1824
- children: import_zod19.z.array(SidebarLeafSchema).default([])
1735
+ var SidebarGroupSchema2 = import_zod20.z.object({
1736
+ kind: import_zod20.z.literal("group").default("group"),
1737
+ id: import_zod20.z.string(),
1738
+ label: import_zod20.z.string(),
1739
+ position: import_zod20.z.number().optional(),
1740
+ children: import_zod20.z.array(SidebarLeafSchema).default([])
1825
1741
  });
1826
- var SidebarNodeSchema = import_zod19.z.discriminatedUnion("kind", [
1742
+ var SidebarNodeSchema = import_zod20.z.discriminatedUnion("kind", [
1827
1743
  SidebarLeafSchema,
1828
1744
  SidebarGroupSchema2
1829
1745
  ]);
@@ -2089,51 +2005,51 @@ CroutonValidationExceptionFilter = _ts_decorate3([
2089
2005
  ], CroutonValidationExceptionFilter);
2090
2006
 
2091
2007
  // src/lib/crud/crud-controller.factory.ts
2092
- var import_common11 = require("@nestjs/common");
2093
- var import_swagger6 = require("@nestjs/swagger");
2008
+ var import_common16 = require("@nestjs/common");
2009
+ var import_swagger11 = require("@nestjs/swagger");
2094
2010
 
2095
2011
  // src/lib/crud/action/action.types.ts
2096
- var import_zod20 = require("zod");
2097
- var ActionMetadataSchema = import_zod20.z.object({
2012
+ var import_zod21 = require("zod");
2013
+ var ActionMetadataSchema = import_zod21.z.object({
2098
2014
  /** URL segment used in the endpoint. */
2099
- id: import_zod20.z.string(),
2015
+ id: import_zod21.z.string(),
2100
2016
  /** Human-readable label shown as a button. */
2101
- label: import_zod20.z.string().optional(),
2017
+ label: import_zod21.z.string().optional(),
2102
2018
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
2103
- icon: import_zod20.z.string().optional(),
2019
+ icon: import_zod21.z.string().optional(),
2104
2020
  /** Tooltip text. Falls back to `label` when omitted. */
2105
- tooltip: import_zod20.z.string().optional(),
2021
+ tooltip: import_zod21.z.string().optional(),
2106
2022
  /** Per-row condition — button is hidden when false. */
2107
- condition: import_zod20.z.custom().optional()
2023
+ condition: import_zod21.z.custom().optional()
2108
2024
  });
2109
2025
  var ResourceLinkActionSchema = ActionMetadataSchema.extend({
2110
- type: import_zod20.z.literal("link"),
2026
+ type: import_zod21.z.literal("link"),
2111
2027
  /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */
2112
- href: import_zod20.z.string()
2028
+ href: import_zod21.z.string()
2113
2029
  });
2114
2030
  var ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
2115
- type: import_zod20.z.literal("procedure").optional(),
2031
+ type: import_zod21.z.literal("procedure").optional(),
2116
2032
  /** HTTP method for the endpoint. Defaults to `"post"`. */
2117
- method: import_zod20.z.string().optional(),
2033
+ method: import_zod21.z.string().optional(),
2118
2034
  /** Static data payload merged into the request body by the frontend. */
2119
- data: import_zod20.z.record(import_zod20.z.string(), import_zod20.z.unknown()).optional(),
2035
+ data: import_zod21.z.record(import_zod21.z.string(), import_zod21.z.unknown()).optional(),
2120
2036
  /** Procedure called with `(prisma, recordId)`. */
2121
- procedure: import_zod20.z.custom((v) => typeof v === "function")
2037
+ procedure: import_zod21.z.custom((v) => typeof v === "function")
2122
2038
  });
2123
2039
  var ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
2124
- type: import_zod20.z.literal("procedure").optional(),
2040
+ type: import_zod21.z.literal("procedure").optional(),
2125
2041
  /** HTTP method for the endpoint. Defaults to `"post"`. */
2126
- method: import_zod20.z.string().optional(),
2042
+ method: import_zod21.z.string().optional(),
2127
2043
  /** Static data payload merged into the request body by the frontend. */
2128
- data: import_zod20.z.record(import_zod20.z.string(), import_zod20.z.unknown()).optional(),
2044
+ data: import_zod21.z.record(import_zod21.z.string(), import_zod21.z.unknown()).optional(),
2129
2045
  /** Procedure called with `(prisma)` — no record id. */
2130
- procedure: import_zod20.z.custom((v) => typeof v === "function")
2046
+ procedure: import_zod21.z.custom((v) => typeof v === "function")
2131
2047
  });
2132
- var ResourceRowActionSchema = import_zod20.z.union([
2048
+ var ResourceRowActionSchema = import_zod21.z.union([
2133
2049
  ResourceRowProcedureActionSchema,
2134
2050
  ResourceLinkActionSchema
2135
2051
  ]);
2136
- var ResourceTableActionSchema = import_zod20.z.union([
2052
+ var ResourceTableActionSchema = import_zod21.z.union([
2137
2053
  ResourceTableProcedureActionSchema,
2138
2054
  ResourceLinkActionSchema
2139
2055
  ]);
@@ -2325,6 +2241,23 @@ var buildChildSortClause = /* @__PURE__ */ __name((sort, sortDir) => {
2325
2241
  [part]: acc
2326
2242
  }, {});
2327
2243
  }, "buildChildSortClause");
2244
+ var buildFindOneIncludes = /* @__PURE__ */ __name((subResources, configInclude) => {
2245
+ const autoSubs = subResources.filter((s) => s.includeInFindOne);
2246
+ const flatIncludes = autoSubs.length ? Object.fromEntries(autoSubs.map((s) => s.findOneOrderBy ? [
2247
+ s.relation,
2248
+ {
2249
+ orderBy: s.findOneOrderBy
2250
+ }
2251
+ ] : [
2252
+ s.relation,
2253
+ true
2254
+ ])) : void 0;
2255
+ if (!flatIncludes && !configInclude) return void 0;
2256
+ return {
2257
+ ...flatIncludes,
2258
+ ...configInclude
2259
+ };
2260
+ }, "buildFindOneIncludes");
2328
2261
 
2329
2262
  // src/lib/crud/read.repository.ts
2330
2263
  var parseFilterString = /* @__PURE__ */ __name((raw) => {
@@ -2587,7 +2520,6 @@ var ReadRepository = class {
2587
2520
  * @throws {NotFoundException} When no record exists for the given id.
2588
2521
  */
2589
2522
  async findOne(id) {
2590
- const formIncludes = (this.config.subResources ?? []).filter((s) => s.includeInFindOne).map((s) => s.relation);
2591
2523
  const projection = this.projection("findOne");
2592
2524
  const idField = this.config.idField ?? "id";
2593
2525
  const query = {
@@ -2596,15 +2528,7 @@ var ReadRepository = class {
2596
2528
  },
2597
2529
  ...projection
2598
2530
  };
2599
- const flatIncludes = formIncludes.length ? Object.fromEntries(formIncludes.map((r) => [
2600
- r,
2601
- true
2602
- ])) : void 0;
2603
- const configInclude = buildIncludeClause(this.config.include);
2604
- const mergedInclude = flatIncludes || configInclude ? {
2605
- ...flatIncludes,
2606
- ...configInclude
2607
- } : void 0;
2531
+ const mergedInclude = buildFindOneIncludes(this.config.subResources ?? [], buildIncludeClause(this.config.include));
2608
2532
  if (mergedInclude) {
2609
2533
  if (projection.select) {
2610
2534
  query.select = {
@@ -2708,6 +2632,75 @@ var ReadRepository = class {
2708
2632
  }
2709
2633
  };
2710
2634
 
2635
+ // src/lib/crud/schema.utils.ts
2636
+ var import_zod22 = require("zod");
2637
+ function isZodSchema(schema) {
2638
+ return schema instanceof import_zod22.ZodObject;
2639
+ }
2640
+ __name(isZodSchema, "isZodSchema");
2641
+ var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
2642
+ const anyOf = property?.["anyOf"];
2643
+ return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
2644
+ }, "isNullableProperty");
2645
+ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
2646
+ const { properties, required } = jsonSchema;
2647
+ if (!properties || !Array.isArray(required)) return;
2648
+ jsonSchema.required = required.filter((key) => !isNullableProperty2(properties[key]));
2649
+ }, "dropNullableFromRequired");
2650
+ function toJsonSchema(schema) {
2651
+ if (isZodSchema(schema)) {
2652
+ const jsonSchema = (0, import_zod22.toJSONSchema)(schema, {
2653
+ target: "openApi3",
2654
+ ...jsonSchemaOpts
2655
+ });
2656
+ dropNullableFromRequired2(jsonSchema);
2657
+ return jsonSchema;
2658
+ }
2659
+ return schema;
2660
+ }
2661
+ __name(toJsonSchema, "toJsonSchema");
2662
+ var unwrap = /* @__PURE__ */ __name((schema) => {
2663
+ let s = schema;
2664
+ let t = s?._zod?.def?.type;
2665
+ while (t === "optional" || t === "nullable" || t === "default" || t === "readonly") {
2666
+ s = s._zod.def.innerType;
2667
+ t = s?._zod?.def?.type;
2668
+ }
2669
+ return s;
2670
+ }, "unwrap");
2671
+ var typeOf = /* @__PURE__ */ __name((schema) => schema?._zod?.def?.type, "typeOf");
2672
+ function toSelectFields(schema) {
2673
+ if (!isZodSchema(schema)) {
2674
+ return Object.keys(schema.properties).reduce((acc, key) => {
2675
+ acc[key] = true;
2676
+ return acc;
2677
+ }, {});
2678
+ }
2679
+ const result = {};
2680
+ for (const [key, value] of Object.entries(schema.shape)) {
2681
+ const inner = unwrap(value);
2682
+ const t = typeOf(inner);
2683
+ if (t === "object") {
2684
+ result[key] = {
2685
+ select: toSelectFields(inner)
2686
+ };
2687
+ continue;
2688
+ }
2689
+ if (t === "array") {
2690
+ const element = unwrap(inner._zod.def.element);
2691
+ if (typeOf(element) === "object") {
2692
+ result[key] = {
2693
+ select: toSelectFields(element)
2694
+ };
2695
+ continue;
2696
+ }
2697
+ }
2698
+ result[key] = true;
2699
+ }
2700
+ return result;
2701
+ }
2702
+ __name(toSelectFields, "toSelectFields");
2703
+
2711
2704
  // src/lib/crud/write.repository.ts
2712
2705
  var import_common5 = require("@nestjs/common");
2713
2706
 
@@ -3202,9 +3195,125 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
3202
3195
  }
3203
3196
  }, "registerTableActionRoutes");
3204
3197
 
3205
- // src/lib/crud/operations/register-crud.ts
3198
+ // src/lib/crud/operations/register-create.ts
3206
3199
  var import_common8 = require("@nestjs/common");
3207
3200
  var import_swagger3 = require("@nestjs/swagger");
3201
+ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
3202
+ if (!isOperationEnabled(ctx.definition, "create")) return null;
3203
+ const { cls, config, createSchema, bodyDecorator } = ctx;
3204
+ const methodName = "create";
3205
+ return {
3206
+ route: "",
3207
+ methodName,
3208
+ name: config.name,
3209
+ createFn: /* @__PURE__ */ __name(function(body) {
3210
+ return this.repo.create(body);
3211
+ }, "createFn"),
3212
+ decorators: /* @__PURE__ */ __name(() => {
3213
+ bodyDecorator(createSchema, {
3214
+ coerceNullableUndefinedToNull: true
3215
+ })(cls.prototype, methodName, 0);
3216
+ }, "decorators")
3217
+ };
3218
+ }, "defaultCreate");
3219
+ var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
3220
+ if (!isOperationEnabled(sub.operations, "create")) return null;
3221
+ const { cls } = ctx;
3222
+ const methodName = `createChild_${sub.childRoute}`;
3223
+ const createFn = /* @__PURE__ */ __name(async function(id, body) {
3224
+ return this.repo.createChild(id, sub, body);
3225
+ }, "createFn");
3226
+ const decorators = /* @__PURE__ */ __name(() => {
3227
+ (0, import_common8.Param)("id")(cls.prototype, methodName, 0);
3228
+ (0, import_common8.Body)()(cls.prototype, methodName, 1);
3229
+ }, "decorators");
3230
+ return {
3231
+ route: `:id/${sub.childRoute}`,
3232
+ methodName,
3233
+ name: sub.childRoute,
3234
+ createFn,
3235
+ decorators
3236
+ };
3237
+ }, "childCreate");
3238
+ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
3239
+ const operationFn = sub ? childCreate(sub) : defaultCreate;
3240
+ const properties = operationFn(ctx);
3241
+ if (!properties) return;
3242
+ const { methodName, route, name } = properties;
3243
+ const { cls } = ctx;
3244
+ def(cls, methodName, properties.createFn);
3245
+ const d = desc(cls, methodName);
3246
+ (0, import_common8.Post)(route)(cls.prototype, methodName, d);
3247
+ (0, import_swagger3.ApiOperation)({
3248
+ summary: `Create a ${name}`
3249
+ })(cls.prototype, methodName, d);
3250
+ (0, import_swagger3.ApiResponse)({
3251
+ status: 201,
3252
+ description: `${name} created`
3253
+ })(cls.prototype, methodName, d);
3254
+ properties.decorators();
3255
+ }, "registerCreate");
3256
+
3257
+ // src/lib/crud/operations/register-delete.ts
3258
+ var import_common9 = require("@nestjs/common");
3259
+ var import_swagger4 = require("@nestjs/swagger");
3260
+ var defaultDelete = /* @__PURE__ */ __name((ctx) => {
3261
+ if (!isOperationEnabled(ctx.definition, "delete")) return null;
3262
+ const { config } = ctx;
3263
+ const methodName = "delete";
3264
+ const { name } = config;
3265
+ return {
3266
+ route: ":id",
3267
+ methodName,
3268
+ name,
3269
+ decorators: /* @__PURE__ */ __name(() => {
3270
+ }, "decorators"),
3271
+ deleteFn: /* @__PURE__ */ __name(function(id) {
3272
+ return this.repo.delete(id);
3273
+ }, "deleteFn")
3274
+ };
3275
+ }, "defaultDelete");
3276
+ var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
3277
+ if (!isOperationEnabled(sub.operations, "delete")) return null;
3278
+ const { cls } = ctx;
3279
+ const methodName = `deleteChild_${sub.childRoute}`;
3280
+ const deleteFn = /* @__PURE__ */ __name(async function(childId, parentId) {
3281
+ return this.repo.deleteChild(sub, childId, parentId);
3282
+ }, "deleteFn");
3283
+ const decorators = /* @__PURE__ */ __name(() => {
3284
+ (0, import_common9.Param)("childId")(cls.prototype, methodName, 0);
3285
+ }, "decorators");
3286
+ return {
3287
+ route: `:id/${sub.childRoute}/:childId`,
3288
+ methodName,
3289
+ name: sub.childRoute,
3290
+ deleteFn,
3291
+ decorators
3292
+ };
3293
+ }, "deleteChild");
3294
+ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
3295
+ const operationFn = sub ? deleteChild(sub) : defaultDelete;
3296
+ const { cls } = ctx;
3297
+ const properties = operationFn(ctx);
3298
+ if (!properties) return;
3299
+ const { methodName, route, name } = properties;
3300
+ def(cls, methodName, properties.deleteFn);
3301
+ const d = desc(cls, methodName);
3302
+ (0, import_common9.Delete)(route)(cls.prototype, methodName, d);
3303
+ (0, import_common9.Param)("id")(cls.prototype, methodName, 0);
3304
+ (0, import_swagger4.ApiOperation)({
3305
+ summary: `Delete ${name} record`
3306
+ })(cls.prototype, methodName, d);
3307
+ (0, import_swagger4.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
3308
+ (0, import_swagger4.ApiResponse)({
3309
+ status: 200
3310
+ })(cls.prototype, methodName, d);
3311
+ properties.decorators();
3312
+ }, "registerDelete");
3313
+
3314
+ // src/lib/crud/operations/register-findall.ts
3315
+ var import_common10 = require("@nestjs/common");
3316
+ var import_swagger5 = require("@nestjs/swagger");
3208
3317
 
3209
3318
  // src/lib/crud/request.dto.ts
3210
3319
  var import_zod_nestjs = require("@anatine/zod-nestjs");
@@ -3285,8 +3394,8 @@ var ZodValidationPipe = class {
3285
3394
  }
3286
3395
  };
3287
3396
 
3288
- // src/lib/crud/operations/register-crud.ts
3289
- var findAll = /* @__PURE__ */ __name(async (repo, params, q, lookupLabel) => {
3397
+ // src/lib/crud/operations/register-findall.ts
3398
+ var _findAll = /* @__PURE__ */ __name(async (repo, params, q, lookupLabel) => {
3290
3399
  const effectiveParams = {
3291
3400
  ...params
3292
3401
  };
@@ -3313,41 +3422,74 @@ var findAll = /* @__PURE__ */ __name(async (repo, params, q, lookupLabel) => {
3313
3422
  filter: params.filter
3314
3423
  }
3315
3424
  };
3316
- }, "findAll");
3317
- var findOne = /* @__PURE__ */ __name(async (repo, id) => {
3318
- return repo.findOne(id);
3319
- }, "findOne");
3320
- var create = /* @__PURE__ */ __name(async (repo, body) => {
3321
- return repo.create(body);
3322
- }, "create");
3323
- var update = /* @__PURE__ */ __name(async (repo, id, body) => {
3324
- return repo.update(id, body);
3325
- }, "update");
3326
- var patch = /* @__PURE__ */ __name(async (repo, id, body) => {
3327
- return repo.patch(id, body);
3328
- }, "patch");
3329
- var upsert = /* @__PURE__ */ __name(async (repo, body) => {
3330
- return repo.upsert(body);
3331
- }, "upsert");
3332
- var del = /* @__PURE__ */ __name(async (repo, id) => {
3333
- return repo.delete(id);
3334
- }, "del");
3335
- var registerFindAll = /* @__PURE__ */ __name((ctx) => {
3425
+ }, "_findAll");
3426
+ var findAllByParent = /* @__PURE__ */ __name(async (repo, id, childRoute, params) => {
3427
+ const { data, count } = await repo.findAllByParent(id, childRoute, params);
3428
+ const totalPages = Math.max(1, Math.ceil(count / params.pageSize));
3429
+ return {
3430
+ data,
3431
+ request: {
3432
+ count,
3433
+ page: params.page,
3434
+ pageSize: params.pageSize,
3435
+ totalPages,
3436
+ sort: params.sort,
3437
+ sortDir: params.sortDir,
3438
+ filter: params.filter
3439
+ }
3440
+ };
3441
+ }, "findAllByParent");
3442
+ var defaultFindAll = /* @__PURE__ */ __name((ctx) => {
3336
3443
  if (!isOperationEnabled(ctx.definition, "findAll")) return;
3337
- const { cls, config, listSchema } = ctx;
3338
- const { name } = config;
3444
+ const { config } = ctx;
3339
3445
  const lookupLabel = config.lookup?.label;
3340
- def(cls, "findAll", async function(params, q) {
3341
- return findAll(this.repo, params, q, lookupLabel);
3342
- });
3343
- const d = desc(cls, "findAll");
3344
- (0, import_common8.Get)()(cls.prototype, "findAll", d);
3345
- (0, import_common8.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, "findAll", 0);
3346
- (0, import_common8.Query)("q")(cls.prototype, "findAll", 1);
3347
- (0, import_swagger3.ApiOperation)({
3446
+ const findAll = /* @__PURE__ */ __name(async function(params, q) {
3447
+ return _findAll(this.repo, params, q, lookupLabel);
3448
+ }, "findAll");
3449
+ return {
3450
+ route: "",
3451
+ name: config.name,
3452
+ methodName: "findAll",
3453
+ findAll,
3454
+ listSchema: ctx.listSchema,
3455
+ decorators: /* @__PURE__ */ __name(() => {
3456
+ }, "decorators")
3457
+ };
3458
+ }, "defaultFindAll");
3459
+ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
3460
+ if (!isOperationEnabled(sub.operations, "findAll")) return;
3461
+ const { cls } = ctx;
3462
+ const methodName = `findAllBy_${sub.childRoute}`;
3463
+ const findAll = /* @__PURE__ */ __name(async function(params, q, id) {
3464
+ return findAllByParent(this.repo, id, sub.childRoute, params);
3465
+ }, "findAll");
3466
+ const decorators = /* @__PURE__ */ __name(() => {
3467
+ (0, import_common10.Param)("id")(cls.prototype, methodName, 2);
3468
+ }, "decorators");
3469
+ return {
3470
+ name: sub.childRoute,
3471
+ methodName,
3472
+ findAll,
3473
+ route: `:id/${sub.childRoute}`,
3474
+ decorators,
3475
+ listSchema: ctx.listSchema
3476
+ };
3477
+ }, "childFindAll");
3478
+ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
3479
+ const operationFn = sub ? childFindAll(sub) : defaultFindAll;
3480
+ const properties = operationFn(ctx);
3481
+ if (!properties) return;
3482
+ const { methodName, route, name, listSchema } = properties;
3483
+ const { cls } = ctx;
3484
+ def(cls, methodName, properties.findAll);
3485
+ const d = desc(cls, methodName);
3486
+ (0, import_common10.Get)(route)(cls.prototype, methodName, d);
3487
+ (0, import_common10.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
3488
+ (0, import_common10.Query)("q")(cls.prototype, methodName, 1);
3489
+ (0, import_swagger5.ApiOperation)({
3348
3490
  summary: `List all ${name}s`
3349
- })(cls.prototype, "findAll", d);
3350
- (0, import_swagger3.ApiResponse)({
3491
+ })(cls.prototype, methodName, d);
3492
+ (0, import_swagger5.ApiResponse)({
3351
3493
  status: 200,
3352
3494
  description: `Array of ${name}`,
3353
3495
  ...listSchema && {
@@ -3356,179 +3498,161 @@ var registerFindAll = /* @__PURE__ */ __name((ctx) => {
3356
3498
  items: toJsonSchema(listSchema)
3357
3499
  }
3358
3500
  }
3359
- })(cls.prototype, "findAll", d);
3501
+ })(cls.prototype, methodName, d);
3502
+ properties.decorators();
3360
3503
  }, "registerFindAll");
3361
- var registerFindOne = /* @__PURE__ */ __name((ctx) => {
3362
- if (!isOperationEnabled(ctx.definition, "findOne")) return;
3363
- const { cls, config, oneSchema, idParamMeta } = ctx;
3364
- const { name } = config;
3365
- def(cls, "findOne", function(id) {
3366
- return findOne(this.repo, id);
3367
- });
3368
- const d = desc(cls, "findOne");
3369
- (0, import_common8.Get)(":id")(cls.prototype, "findOne", d);
3370
- (0, import_common8.Param)("id")(cls.prototype, "findOne", 0);
3371
- (0, import_swagger3.ApiOperation)({
3504
+
3505
+ // src/lib/crud/operations/register-findone.ts
3506
+ var import_common11 = require("@nestjs/common");
3507
+ var import_swagger6 = require("@nestjs/swagger");
3508
+ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
3509
+ if (!isOperationEnabled(ctx.definition, "findOne")) return null;
3510
+ const { cls, config } = ctx;
3511
+ const methodName = "findOne";
3512
+ return {
3513
+ route: ":id",
3514
+ methodName,
3515
+ name: config.name,
3516
+ findOneFn: /* @__PURE__ */ __name(function(id) {
3517
+ return this.repo.findOne(id);
3518
+ }, "findOneFn"),
3519
+ decorators: /* @__PURE__ */ __name(() => {
3520
+ (0, import_common11.Param)("id")(cls.prototype, methodName, 0);
3521
+ }, "decorators")
3522
+ };
3523
+ }, "defaultFindOne");
3524
+ var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
3525
+ if (!isOperationEnabled(sub.operations, "findOne")) return null;
3526
+ const { cls } = ctx;
3527
+ const methodName = `findOneChild_${sub.childRoute}`;
3528
+ const findOneFn = /* @__PURE__ */ __name(async function(parentId, childId) {
3529
+ return this.repo.findOneChild(sub, childId, parentId);
3530
+ }, "findOneFn");
3531
+ const decorators = /* @__PURE__ */ __name(() => {
3532
+ (0, import_common11.Param)("id")(cls.prototype, methodName, 0);
3533
+ (0, import_common11.Param)("childId")(cls.prototype, methodName, 1);
3534
+ }, "decorators");
3535
+ return {
3536
+ route: `:id/${sub.childRoute}/:childId`,
3537
+ methodName,
3538
+ name: sub.childRoute,
3539
+ findOneFn,
3540
+ decorators
3541
+ };
3542
+ }, "childFindOne");
3543
+ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
3544
+ const operationFn = sub ? childFindOne(sub) : defaultFindOne;
3545
+ const properties = operationFn(ctx);
3546
+ if (!properties) return;
3547
+ const { methodName, route, name } = properties;
3548
+ const { cls } = ctx;
3549
+ def(cls, methodName, properties.findOneFn);
3550
+ const d = desc(cls, methodName);
3551
+ (0, import_common11.Get)(route)(cls.prototype, methodName, d);
3552
+ (0, import_swagger6.ApiOperation)({
3372
3553
  summary: `Get one ${name} by id`
3373
- })(cls.prototype, "findOne", d);
3374
- (0, import_swagger3.ApiParam)(idParamMeta)(cls.prototype, "findOne", d);
3375
- (0, import_swagger3.ApiResponse)({
3554
+ })(cls.prototype, methodName, d);
3555
+ (0, import_swagger6.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
3556
+ (0, import_swagger6.ApiResponse)({
3376
3557
  status: 200,
3377
3558
  description: `The ${name}`,
3378
- ...oneSchema && {
3379
- schema: toJsonSchema(oneSchema)
3559
+ ...ctx.oneSchema && {
3560
+ schema: toJsonSchema(ctx.oneSchema)
3380
3561
  }
3381
- })(cls.prototype, "findOne", d);
3382
- (0, import_swagger3.ApiNotFoundResponse)({
3562
+ })(cls.prototype, methodName, d);
3563
+ (0, import_swagger6.ApiNotFoundResponse)({
3383
3564
  description: "Not found"
3384
- })(cls.prototype, "findOne", d);
3565
+ })(cls.prototype, methodName, d);
3566
+ properties.decorators();
3385
3567
  }, "registerFindOne");
3386
- var registerCreate = /* @__PURE__ */ __name((ctx) => {
3387
- if (!isOperationEnabled(ctx.definition, "create")) return;
3388
- const { cls, config, createSchema, bodyDecorator } = ctx;
3389
- const { name } = config;
3390
- def(cls, "create", function(body) {
3391
- return create(this.repo, body);
3392
- });
3393
- const d = desc(cls, "create");
3394
- (0, import_common8.Post)()(cls.prototype, "create", d);
3395
- bodyDecorator(createSchema, {
3396
- coerceNullableUndefinedToNull: true
3397
- })(cls.prototype, "create", 0);
3398
- (0, import_swagger3.ApiOperation)({
3399
- summary: `Create a ${name}`
3400
- })(cls.prototype, "create", d);
3401
- if (createSchema) (0, import_swagger3.ApiBody)({
3402
- schema: toJsonSchema(createSchema)
3403
- })(cls.prototype, "create", d);
3404
- (0, import_swagger3.ApiResponse)({
3405
- status: 201,
3406
- description: `${name} created`
3407
- })(cls.prototype, "create", d);
3408
- }, "registerCreate");
3409
- var registerUpdate = /* @__PURE__ */ __name((ctx) => {
3410
- if (!isOperationEnabled(ctx.definition, "update")) return;
3411
- const { cls, config, updateSchema, idParamMeta, bodyDecorator } = ctx;
3412
- const { name } = config;
3413
- def(cls, "update", function(id, body) {
3414
- return update(this.repo, id, body);
3415
- });
3416
- const d = desc(cls, "update");
3417
- (0, import_common8.Put)(":id")(cls.prototype, "update", d);
3418
- (0, import_common8.Param)("id")(cls.prototype, "update", 0);
3419
- bodyDecorator(updateSchema)(cls.prototype, "update", 1);
3420
- (0, import_swagger3.ApiOperation)({
3421
- summary: `Replace a ${name}`
3422
- })(cls.prototype, "update", d);
3423
- (0, import_swagger3.ApiParam)(idParamMeta)(cls.prototype, "update", d);
3424
- if (updateSchema) (0, import_swagger3.ApiBody)({
3425
- schema: toJsonSchema(updateSchema)
3426
- })(cls.prototype, "update", d);
3427
- (0, import_swagger3.ApiResponse)({
3428
- status: 200,
3429
- description: `${name} replaced`
3430
- })(cls.prototype, "update", d);
3431
- (0, import_swagger3.ApiNotFoundResponse)({
3432
- description: "Not found"
3433
- })(cls.prototype, "update", d);
3434
- }, "registerUpdate");
3435
- var registerPatch = /* @__PURE__ */ __name((ctx) => {
3436
- if (!isOperationEnabled(ctx.definition, "patch")) return;
3437
- const { cls, config, patchSchema, idParamMeta, bodyDecorator } = ctx;
3438
- const { name } = config;
3439
- def(cls, "patch", function(id, body) {
3440
- return patch(this.repo, id, body);
3441
- });
3442
- const d = desc(cls, "patch");
3443
- (0, import_common8.Patch)(":id")(cls.prototype, "patch", d);
3444
- (0, import_common8.Param)("id")(cls.prototype, "patch", 0);
3445
- bodyDecorator(patchSchema)(cls.prototype, "patch", 1);
3446
- (0, import_swagger3.ApiOperation)({
3568
+
3569
+ // src/lib/crud/operations/register-patch.ts
3570
+ var import_common12 = require("@nestjs/common");
3571
+ var import_swagger7 = require("@nestjs/swagger");
3572
+ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
3573
+ if (!isOperationEnabled(ctx.definition, "patch")) return null;
3574
+ const { cls, config, patchSchema, bodyDecorator } = ctx;
3575
+ const methodName = "patch";
3576
+ return {
3577
+ route: ":id",
3578
+ methodName,
3579
+ name: config.name,
3580
+ patchFn: /* @__PURE__ */ __name(function(id, body) {
3581
+ return this.repo.patch(id, body);
3582
+ }, "patchFn"),
3583
+ decorators: /* @__PURE__ */ __name(() => {
3584
+ (0, import_common12.Param)("id")(cls.prototype, methodName, 0);
3585
+ bodyDecorator(patchSchema)(cls.prototype, methodName, 1);
3586
+ }, "decorators")
3587
+ };
3588
+ }, "defaultPatch");
3589
+ var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
3590
+ if (!isOperationEnabled(sub.operations, "patch")) return null;
3591
+ const { cls } = ctx;
3592
+ const methodName = `patchChild_${sub.childRoute}`;
3593
+ const patchFn = /* @__PURE__ */ __name(async function(_id, childId, body) {
3594
+ return this.repo.updateChild(sub, childId, body);
3595
+ }, "patchFn");
3596
+ const decorators = /* @__PURE__ */ __name(() => {
3597
+ (0, import_common12.Param)("id")(cls.prototype, methodName, 0);
3598
+ (0, import_common12.Param)("childId")(cls.prototype, methodName, 1);
3599
+ (0, import_common12.Body)()(cls.prototype, methodName, 2);
3600
+ }, "decorators");
3601
+ return {
3602
+ route: `:id/${sub.childRoute}/:childId`,
3603
+ methodName,
3604
+ name: sub.childRoute,
3605
+ patchFn,
3606
+ decorators
3607
+ };
3608
+ }, "childPatch");
3609
+ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
3610
+ const operationFn = sub ? childPatch(sub) : defaultPatch;
3611
+ const properties = operationFn(ctx);
3612
+ if (!properties) return;
3613
+ const { methodName, route, name } = properties;
3614
+ const { cls } = ctx;
3615
+ def(cls, methodName, properties.patchFn);
3616
+ const d = desc(cls, methodName);
3617
+ (0, import_common12.Patch)(route)(cls.prototype, methodName, d);
3618
+ (0, import_swagger7.ApiOperation)({
3447
3619
  summary: `Update a ${name}`
3448
- })(cls.prototype, "patch", d);
3449
- (0, import_swagger3.ApiParam)(idParamMeta)(cls.prototype, "patch", d);
3450
- if (patchSchema) (0, import_swagger3.ApiBody)({
3451
- schema: toJsonSchema(patchSchema)
3452
- })(cls.prototype, "patch", d);
3453
- (0, import_swagger3.ApiResponse)({
3620
+ })(cls.prototype, methodName, d);
3621
+ (0, import_swagger7.ApiResponse)({
3454
3622
  status: 200,
3455
3623
  description: `${name} updated`
3456
- })(cls.prototype, "patch", d);
3457
- (0, import_swagger3.ApiNotFoundResponse)({
3624
+ })(cls.prototype, methodName, d);
3625
+ (0, import_swagger7.ApiNotFoundResponse)({
3458
3626
  description: "Not found"
3459
- })(cls.prototype, "patch", d);
3627
+ })(cls.prototype, methodName, d);
3628
+ properties.decorators();
3460
3629
  }, "registerPatch");
3461
- var registerUpsert = /* @__PURE__ */ __name((ctx) => {
3462
- if (!isOperationEnabled(ctx.definition, "upsert")) return;
3463
- const { cls, config, upsertSchema, bodyDecorator } = ctx;
3464
- const { name } = config;
3465
- def(cls, "upsert", function(body) {
3466
- return upsert(this.repo, body);
3467
- });
3468
- const d = desc(cls, "upsert");
3469
- (0, import_common8.Put)()(cls.prototype, "upsert", d);
3470
- bodyDecorator(upsertSchema, {
3471
- coerceNullableUndefinedToNull: true
3472
- })(cls.prototype, "upsert", 0);
3473
- (0, import_swagger3.ApiOperation)({
3474
- summary: `Upsert a ${name}`
3475
- })(cls.prototype, "upsert", d);
3476
- if (upsertSchema) (0, import_swagger3.ApiBody)({
3477
- schema: toJsonSchema(upsertSchema)
3478
- })(cls.prototype, "upsert", d);
3479
- (0, import_swagger3.ApiResponse)({
3480
- status: 200,
3481
- description: `${name} upserted`
3482
- })(cls.prototype, "upsert", d);
3483
- }, "registerUpsert");
3484
- var registerDelete = /* @__PURE__ */ __name((ctx) => {
3485
- if (!isOperationEnabled(ctx.definition, "delete")) return;
3486
- const { cls, config, idParamMeta } = ctx;
3487
- const { name } = config;
3488
- def(cls, "delete", function(id) {
3489
- return del(this.repo, id);
3490
- });
3491
- const d = desc(cls, "delete");
3492
- (0, import_common8.Delete)(":id")(cls.prototype, "delete", d);
3493
- (0, import_common8.Param)("id")(cls.prototype, "delete", 0);
3494
- (0, import_swagger3.ApiOperation)({
3495
- summary: `Delete a ${name}`
3496
- })(cls.prototype, "delete", d);
3497
- (0, import_swagger3.ApiParam)(idParamMeta)(cls.prototype, "delete", d);
3498
- (0, import_swagger3.ApiResponse)({
3499
- status: 200,
3500
- description: `${name} deleted`
3501
- })(cls.prototype, "delete", d);
3502
- (0, import_swagger3.ApiNotFoundResponse)({
3503
- description: "Not found"
3504
- })(cls.prototype, "delete", d);
3505
- }, "registerDelete");
3506
3630
 
3507
3631
  // src/lib/crud/operations/register-schema-endpoints.ts
3508
- var import_common9 = require("@nestjs/common");
3509
- var import_swagger4 = require("@nestjs/swagger");
3632
+ var import_common13 = require("@nestjs/common");
3633
+ var import_swagger8 = require("@nestjs/swagger");
3510
3634
 
3511
3635
  // src/lib/crud/resource/PatchResourceJson.schema.ts
3512
- var import_zod21 = require("zod");
3513
- var FieldVariantPatchSchema = import_zod21.z.object({
3514
- type: import_zod21.z.string().nullable().optional(),
3515
- format: import_zod21.z.string().nullable().optional(),
3516
- resource: import_zod21.z.string().nullable().optional(),
3517
- position: import_zod21.z.number().nullable().optional(),
3518
- options: import_zod21.z.record(import_zod21.z.string(), import_zod21.z.unknown().nullable()).optional()
3636
+ var import_zod23 = require("zod");
3637
+ var FieldVariantPatchSchema = import_zod23.z.object({
3638
+ type: import_zod23.z.string().nullable().optional(),
3639
+ format: import_zod23.z.string().nullable().optional(),
3640
+ resource: import_zod23.z.string().nullable().optional(),
3641
+ position: import_zod23.z.number().nullable().optional(),
3642
+ options: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown().nullable()).optional()
3519
3643
  }).partial();
3520
- var PatchColumnSchema = import_zod21.z.object({
3521
- label: import_zod21.z.string().optional(),
3522
- column: import_zod21.z.string().optional(),
3523
- hiddenInTable: import_zod21.z.boolean().optional(),
3524
- hiddenInForm: import_zod21.z.boolean().optional(),
3525
- hiddenInView: import_zod21.z.boolean().optional(),
3644
+ var PatchColumnSchema = import_zod23.z.object({
3645
+ label: import_zod23.z.string().optional(),
3646
+ column: import_zod23.z.string().optional(),
3647
+ hiddenInTable: import_zod23.z.boolean().optional(),
3648
+ hiddenInForm: import_zod23.z.boolean().optional(),
3649
+ hiddenInView: import_zod23.z.boolean().optional(),
3526
3650
  fieldInput: FieldVariantPatchSchema.optional(),
3527
3651
  fieldView: FieldVariantPatchSchema.optional(),
3528
3652
  fieldTable: FieldVariantPatchSchema.optional()
3529
3653
  }).partial();
3530
- var PatchResourceJsonSchema = import_zod21.z.object({
3531
- columns: import_zod21.z.record(import_zod21.z.string(), PatchColumnSchema)
3654
+ var PatchResourceJsonSchema = import_zod23.z.object({
3655
+ columns: import_zod23.z.record(import_zod23.z.string(), PatchColumnSchema)
3532
3656
  });
3533
3657
 
3534
3658
  // src/lib/crud/resource/WriteResourceJson.ts
@@ -3542,8 +3666,8 @@ var FIELD_VARIANT_KEYS = [
3542
3666
  "fieldView",
3543
3667
  "fieldTable"
3544
3668
  ];
3545
- var mergeColumn = /* @__PURE__ */ __name((existing, patch2) => {
3546
- const { fieldInput, fieldView, fieldTable, ...rest } = patch2;
3669
+ var mergeColumn = /* @__PURE__ */ __name((existing, patch) => {
3670
+ const { fieldInput, fieldView, fieldTable, ...rest } = patch;
3547
3671
  const variantPatches = {
3548
3672
  fieldInput,
3549
3673
  fieldView,
@@ -3560,11 +3684,11 @@ var mergeColumn = /* @__PURE__ */ __name((existing, patch2) => {
3560
3684
  }
3561
3685
  return merged;
3562
3686
  }, "mergeColumn");
3563
- var applyColumnPatch = /* @__PURE__ */ __name((raw, patch2) => {
3687
+ var applyColumnPatch = /* @__PURE__ */ __name((raw, patch) => {
3564
3688
  const columns = raw["columns"];
3565
3689
  if (Array.isArray(columns)) {
3566
3690
  const updated = columns.map((col) => {
3567
- const columnPatch = patch2.columns[col["id"]];
3691
+ const columnPatch = patch.columns[col["id"]];
3568
3692
  return columnPatch ? mergeColumn(col, columnPatch) : col;
3569
3693
  });
3570
3694
  return {
@@ -3576,7 +3700,7 @@ var applyColumnPatch = /* @__PURE__ */ __name((raw, patch2) => {
3576
3700
  const updated = {
3577
3701
  ...columns
3578
3702
  };
3579
- for (const [id, columnPatch] of Object.entries(patch2.columns)) {
3703
+ for (const [id, columnPatch] of Object.entries(patch.columns)) {
3580
3704
  if (!(id in updated)) continue;
3581
3705
  updated[id] = mergeColumn(updated[id], columnPatch);
3582
3706
  }
@@ -3795,6 +3919,35 @@ var buildViewsPayload = /* @__PURE__ */ __name((config, baseUrl) => {
3795
3919
  tableActions: resolveActions(baseAction, config.tableActions)
3796
3920
  };
3797
3921
  }, "buildViewsPayload");
3922
+ var buildSubResourceViewsPayload = /* @__PURE__ */ __name((config, sub, baseUrl) => {
3923
+ if (!sub.views) return void 0;
3924
+ const { route } = config;
3925
+ const childUri = `${baseUrl}/${route}/{parent.id}/${sub.childRoute}`;
3926
+ return {
3927
+ id: `${route}/${sub.childRoute}`,
3928
+ name: sub.name ?? sub.childRoute,
3929
+ route: sub.childRoute,
3930
+ uri: childUri,
3931
+ title: sub.title ?? sub.childRoute,
3932
+ idField: sub.idField ?? "id",
3933
+ idType: sub.idType ?? "string",
3934
+ ...sub.modalSize && {
3935
+ modalSize: sub.modalSize
3936
+ },
3937
+ operations: buildSubResourceOperations(sub.operations, childUri, sub.idField ?? "id"),
3938
+ schemas: Object.fromEntries(Object.entries(sub.views).map(([key, v]) => [
3939
+ key,
3940
+ {
3941
+ data: v.json_schema,
3942
+ ui: v.ui_schema,
3943
+ ...v.defaultSort !== void 0 && {
3944
+ defaultSort: v.defaultSort
3945
+ }
3946
+ }
3947
+ ])),
3948
+ actions: resolveActions(`${baseUrl}/${sub.childRoute}`, sub.actions)
3949
+ };
3950
+ }, "buildSubResourceViewsPayload");
3798
3951
  var buildEditableColumnsPayload = /* @__PURE__ */ __name((config) => {
3799
3952
  const columns = config.columns ?? [];
3800
3953
  return {
@@ -3834,36 +3987,15 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
3834
3987
  return definitionPayload;
3835
3988
  });
3836
3989
  const d = desc(cls, "getDefinition");
3837
- (0, import_common9.Get)("definition")(cls.prototype, "getDefinition", d);
3838
- (0, import_swagger4.ApiOperation)({
3990
+ (0, import_common13.Get)("definition")(cls.prototype, "getDefinition", d);
3991
+ (0, import_swagger8.ApiOperation)({
3839
3992
  summary: `Get the resource definition for ${name}`
3840
3993
  })(cls.prototype, "getDefinition", d);
3841
- (0, import_swagger4.ApiResponse)({
3994
+ (0, import_swagger8.ApiResponse)({
3842
3995
  status: 200,
3843
3996
  description: `Definition (operations + schemas) for ${name}`
3844
3997
  })(cls.prototype, "getDefinition", d);
3845
3998
  }, "registerDefinitionEndpoint");
3846
- var registerSchemasEndpoint = /* @__PURE__ */ __name((ctx) => {
3847
- const { cls, config, baseUrl } = ctx;
3848
- const { route, name } = config;
3849
- const viewsPayload = buildViewsPayload(config, baseUrl);
3850
- def(cls, "getSchemas", async function() {
3851
- if (IS_DEV) {
3852
- const fresh = await this.configRegistry.getByRoute(route);
3853
- if (fresh) return buildViewsPayload(fresh, baseUrl) ?? viewsPayload;
3854
- }
3855
- return viewsPayload;
3856
- });
3857
- const d = desc(cls, "getSchemas");
3858
- (0, import_common9.Get)("schemas")(cls.prototype, "getSchemas", d);
3859
- (0, import_swagger4.ApiOperation)({
3860
- summary: `Get view schemas (table/form) for ${name}`
3861
- })(cls.prototype, "getSchemas", d);
3862
- (0, import_swagger4.ApiResponse)({
3863
- status: 200,
3864
- description: `View schemas for ${name}`
3865
- })(cls.prototype, "getSchemas", d);
3866
- }, "registerSchemasEndpoint");
3867
3999
  var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
3868
4000
  const { cls, config, baseUrl } = ctx;
3869
4001
  const { route, name } = config;
@@ -3876,11 +4008,11 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
3876
4008
  return resourceJsonPayload;
3877
4009
  });
3878
4010
  const d = desc(cls, "getResourceJson");
3879
- (0, import_common9.Get)("resource.json")(cls.prototype, "getResourceJson", d);
3880
- (0, import_swagger4.ApiOperation)({
4011
+ (0, import_common13.Get)("resource.json")(cls.prototype, "getResourceJson", d);
4012
+ (0, import_swagger8.ApiOperation)({
3881
4013
  summary: `Get resource descriptor for ${name}`
3882
4014
  })(cls.prototype, "getResourceJson", d);
3883
- (0, import_swagger4.ApiResponse)({
4015
+ (0, import_swagger8.ApiResponse)({
3884
4016
  status: 200,
3885
4017
  description: `Resource descriptor (operations + JSON Schema) for ${name}`
3886
4018
  })(cls.prototype, "getResourceJson", d);
@@ -3890,17 +4022,17 @@ var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
3890
4022
  const { route, name } = config;
3891
4023
  def(cls, "getResourceColumns", async function() {
3892
4024
  if (!IS_DEV) {
3893
- throw new import_common9.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
4025
+ throw new import_common13.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
3894
4026
  }
3895
4027
  const fresh = await this.configRegistry.getByRoute(route);
3896
4028
  return buildEditableColumnsPayload(fresh ?? config);
3897
4029
  });
3898
4030
  const d = desc(cls, "getResourceColumns");
3899
- (0, import_common9.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
3900
- (0, import_swagger4.ApiOperation)({
4031
+ (0, import_common13.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
4032
+ (0, import_swagger8.ApiOperation)({
3901
4033
  summary: `Dev-only: get the editable column list for ${name}`
3902
4034
  })(cls.prototype, "getResourceColumns", d);
3903
- (0, import_swagger4.ApiResponse)({
4035
+ (0, import_swagger8.ApiResponse)({
3904
4036
  status: 200,
3905
4037
  description: `Editable column list for ${name}`
3906
4038
  })(cls.prototype, "getResourceColumns", d);
@@ -3910,34 +4042,34 @@ var registerResourceJsonPatchEndpoint = /* @__PURE__ */ __name((ctx) => {
3910
4042
  const { route, name } = config;
3911
4043
  def(cls, "patchResourceJson", async function(body) {
3912
4044
  if (!IS_DEV) {
3913
- throw new import_common9.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
4045
+ throw new import_common13.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
3914
4046
  }
3915
4047
  await this.configRegistry.getByRoute(route);
3916
4048
  const dir = this.configRegistry.getResourceDir(route);
3917
4049
  if (!dir) {
3918
- throw new import_common9.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
4050
+ throw new import_common13.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
3919
4051
  }
3920
4052
  const jsonPath = (0, import_node_path5.join)(dir, "resource.json");
3921
4053
  const raw = readRawResourceJson(jsonPath);
3922
4054
  if (!raw) {
3923
- throw new import_common9.NotFoundException(`resource.json not found at ${jsonPath}`);
4055
+ throw new import_common13.NotFoundException(`resource.json not found at ${jsonPath}`);
3924
4056
  }
3925
4057
  const merged = applyColumnPatch(raw, body);
3926
4058
  const validated = validateResourceJson(merged);
3927
4059
  if (!validated.success) {
3928
- throw new import_common9.BadRequestException(validated.error.issues);
4060
+ throw new import_common13.BadRequestException(validated.error.issues);
3929
4061
  }
3930
4062
  writeRawResourceJson(jsonPath, merged);
3931
4063
  const fresh = await this.configRegistry.getByRoute(route);
3932
4064
  return buildEditableColumnsPayload(fresh ?? config);
3933
4065
  });
3934
4066
  const d = desc(cls, "patchResourceJson");
3935
- (0, import_common9.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
3936
- (0, import_common9.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
3937
- (0, import_swagger4.ApiOperation)({
4067
+ (0, import_common13.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
4068
+ (0, import_common13.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
4069
+ (0, import_swagger8.ApiOperation)({
3938
4070
  summary: `Dev-only: patch column layout in resource.json for ${name}`
3939
4071
  })(cls.prototype, "patchResourceJson", d);
3940
- (0, import_swagger4.ApiResponse)({
4072
+ (0, import_swagger8.ApiResponse)({
3941
4073
  status: 200,
3942
4074
  description: `Updated resource descriptor for ${name}`
3943
4075
  })(cls.prototype, "patchResourceJson", d);
@@ -3947,26 +4079,26 @@ var registerResourceJsonRawGetEndpoint = /* @__PURE__ */ __name((ctx) => {
3947
4079
  const { route, name } = config;
3948
4080
  def(cls, "getResourceJsonRaw", async function() {
3949
4081
  if (!IS_DEV) {
3950
- throw new import_common9.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
4082
+ throw new import_common13.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
3951
4083
  }
3952
4084
  await this.configRegistry.getByRoute(route);
3953
4085
  const dir = this.configRegistry.getResourceDir(route);
3954
4086
  if (!dir) {
3955
- throw new import_common9.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
4087
+ throw new import_common13.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
3956
4088
  }
3957
4089
  const jsonPath = (0, import_node_path5.join)(dir, "resource.json");
3958
4090
  const raw = readRawResourceJson(jsonPath);
3959
4091
  if (!raw) {
3960
- throw new import_common9.NotFoundException(`resource.json not found at ${jsonPath}`);
4092
+ throw new import_common13.NotFoundException(`resource.json not found at ${jsonPath}`);
3961
4093
  }
3962
4094
  return raw;
3963
4095
  });
3964
4096
  const d = desc(cls, "getResourceJsonRaw");
3965
- (0, import_common9.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
3966
- (0, import_swagger4.ApiOperation)({
4097
+ (0, import_common13.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
4098
+ (0, import_swagger8.ApiOperation)({
3967
4099
  summary: `Dev-only: get the raw resource.json for ${name}`
3968
4100
  })(cls.prototype, "getResourceJsonRaw", d);
3969
- (0, import_swagger4.ApiResponse)({
4101
+ (0, import_swagger8.ApiResponse)({
3970
4102
  status: 200,
3971
4103
  description: `Raw resource.json for ${name}`
3972
4104
  })(cls.prototype, "getResourceJsonRaw", d);
@@ -3976,243 +4108,179 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
3976
4108
  const { route, name } = config;
3977
4109
  def(cls, "putResourceJsonRaw", async function(body) {
3978
4110
  if (!IS_DEV) {
3979
- throw new import_common9.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
4111
+ throw new import_common13.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
3980
4112
  }
3981
4113
  await this.configRegistry.getByRoute(route);
3982
4114
  const dir = this.configRegistry.getResourceDir(route);
3983
4115
  if (!dir) {
3984
- throw new import_common9.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
4116
+ throw new import_common13.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
3985
4117
  }
3986
4118
  const validated = validateResourceJson(body);
3987
4119
  if (!validated.success) {
3988
- throw new import_common9.BadRequestException(validated.error.issues);
4120
+ throw new import_common13.BadRequestException(validated.error.issues);
3989
4121
  }
3990
4122
  const jsonPath = (0, import_node_path5.join)(dir, "resource.json");
3991
4123
  writeRawResourceJson(jsonPath, body);
3992
4124
  return body;
3993
4125
  });
3994
4126
  const d = desc(cls, "putResourceJsonRaw");
3995
- (0, import_common9.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
3996
- (0, import_common9.Body)()(cls.prototype, "putResourceJsonRaw", 0);
3997
- (0, import_swagger4.ApiOperation)({
4127
+ (0, import_common13.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
4128
+ (0, import_common13.Body)()(cls.prototype, "putResourceJsonRaw", 0);
4129
+ (0, import_swagger8.ApiOperation)({
3998
4130
  summary: `Dev-only: replace the full resource.json for ${name}`
3999
4131
  })(cls.prototype, "putResourceJsonRaw", d);
4000
- (0, import_swagger4.ApiResponse)({
4132
+ (0, import_swagger8.ApiResponse)({
4001
4133
  status: 200,
4002
4134
  description: `Updated raw resource.json for ${name}`
4003
4135
  })(cls.prototype, "putResourceJsonRaw", d);
4004
4136
  }, "registerResourceJsonRawPutEndpoint");
4005
4137
 
4006
- // src/lib/crud/operations/register-sub-resources.ts
4007
- var import_common10 = require("@nestjs/common");
4008
- var import_swagger5 = require("@nestjs/swagger");
4009
- var findAllByParent = /* @__PURE__ */ __name(async (repo, id, childRoute, params) => {
4010
- const { data, count } = await repo.findAllByParent(id, childRoute, params);
4011
- const totalPages = Math.max(1, Math.ceil(count / params.pageSize));
4138
+ // src/lib/crud/operations/register-schemas.ts
4139
+ var import_common14 = require("@nestjs/common");
4140
+ var import_swagger9 = require("@nestjs/swagger");
4141
+ var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
4142
+ const { config, baseUrl } = ctx;
4143
+ const { route, name } = config;
4144
+ const viewsPayload = buildViewsPayload(config, baseUrl);
4012
4145
  return {
4013
- data,
4014
- request: {
4015
- count,
4016
- page: params.page,
4017
- pageSize: params.pageSize,
4018
- totalPages,
4019
- sort: params.sort,
4020
- sortDir: params.sortDir,
4021
- filter: params.filter
4022
- }
4023
- };
4024
- }, "findAllByParent");
4025
- var createChild = /* @__PURE__ */ __name(async (repo, id, sub, body) => {
4026
- return repo.createChild(id, sub, body);
4027
- }, "createChild");
4028
- var findOneChild = /* @__PURE__ */ __name(async (repo, sub, childId, parentId) => {
4029
- return repo.findOneChild(sub, childId, parentId);
4030
- }, "findOneChild");
4031
- var updateChild = /* @__PURE__ */ __name(async (repo, sub, childId, body) => {
4032
- return repo.updateChild(sub, childId, body);
4033
- }, "updateChild");
4034
- var deleteChild = /* @__PURE__ */ __name(async (repo, sub, childId, parentId) => {
4035
- return repo.deleteChild(sub, childId, parentId);
4036
- }, "deleteChild");
4037
- var registerSubResourceSchemas = /* @__PURE__ */ __name((ctx, sub) => {
4038
- if (!sub.views) return;
4039
- const { cls, config, baseUrl } = ctx;
4040
- const { route } = config;
4041
- const methodName = `getSchemas_${sub.childRoute}`;
4042
- const childUri = `${baseUrl}/${route}/{parent.id}/${sub.childRoute}`;
4043
- const schemasPayload = {
4044
- id: sub.name ?? sub.childRoute,
4045
- name: sub.name ?? sub.childRoute,
4046
- route: sub.childRoute,
4047
- uri: childUri,
4048
- title: sub.title ?? sub.childRoute,
4049
- idField: sub.idField ?? "id",
4050
- idType: sub.idType ?? "string",
4051
- ...sub.modalSize && {
4052
- modalSize: sub.modalSize
4053
- },
4054
- operations: buildSubResourceOperations(sub.operations, childUri, sub.idField ?? "id"),
4055
- schemas: Object.fromEntries(Object.entries(sub.views).map(([key, v]) => [
4056
- key,
4057
- {
4058
- data: v.json_schema,
4059
- ui: v.ui_schema,
4060
- ...v.defaultSort !== void 0 && {
4061
- defaultSort: v.defaultSort
4062
- }
4146
+ route: "schemas",
4147
+ methodName: "getSchemas",
4148
+ name,
4149
+ schemasFn: /* @__PURE__ */ __name(async function() {
4150
+ if (IS_DEV) {
4151
+ const fresh = await this.configRegistry.getByRoute(route);
4152
+ if (fresh) return buildViewsPayload(fresh, baseUrl) ?? viewsPayload;
4063
4153
  }
4064
- ])),
4065
- actions: resolveActions(`${baseUrl}/${sub.childRoute}`, sub.actions)
4154
+ return viewsPayload;
4155
+ }, "schemasFn"),
4156
+ decorators: /* @__PURE__ */ __name(() => {
4157
+ }, "decorators")
4066
4158
  };
4067
- def(cls, methodName, async function() {
4068
- return schemasPayload;
4069
- });
4070
- const ds = desc(cls, methodName);
4071
- (0, import_common10.Get)(`${sub.childRoute}/schemas`)(cls.prototype, methodName, ds);
4072
- (0, import_swagger5.ApiOperation)({
4073
- summary: `Get schemas for ${sub.childRoute}`
4074
- })(cls.prototype, methodName, ds);
4075
- (0, import_swagger5.ApiResponse)({
4076
- status: 200,
4077
- description: `View schemas for ${sub.childRoute}`
4078
- })(cls.prototype, methodName, ds);
4079
- }, "registerSubResourceSchemas");
4080
- var registerSubResourceFindAll = /* @__PURE__ */ __name((ctx, sub) => {
4081
- if (sub.operations?.findAll === false) return;
4082
- const { cls, config } = ctx;
4083
- const { name } = config;
4084
- const idParamMeta = ctx.idParamMeta;
4085
- const methodName = `findAllBy_${sub.childRoute}`;
4086
- def(cls, methodName, async function(id, params) {
4087
- return findAllByParent(this.repo, id, sub.childRoute, params);
4088
- });
4089
- const d = desc(cls, methodName);
4090
- (0, import_common10.Get)(`:id/${sub.childRoute}`)(cls.prototype, methodName, d);
4091
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4092
- (0, import_common10.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 1);
4093
- (0, import_swagger5.ApiOperation)({
4094
- summary: `List ${sub.childRoute} for a ${name}`
4095
- })(cls.prototype, methodName, d);
4096
- (0, import_swagger5.ApiParam)(idParamMeta)(cls.prototype, methodName, d);
4097
- (0, import_swagger5.ApiResponse)({
4098
- status: 200,
4099
- description: `${sub.childRoute} list`
4100
- })(cls.prototype, methodName, d);
4101
- }, "registerSubResourceFindAll");
4102
- var registerSubResourceCreate = /* @__PURE__ */ __name((ctx, sub) => {
4103
- if (!sub.operations?.create) return;
4104
- const { cls, config } = ctx;
4105
- const { name } = config;
4106
- const methodName = `createChild_${sub.childRoute}`;
4107
- def(cls, methodName, async function(id, body) {
4108
- return createChild(this.repo, id, sub, body);
4109
- });
4110
- const d = desc(cls, methodName);
4111
- (0, import_common10.Post)(`:id/${sub.childRoute}`)(cls.prototype, methodName, d);
4112
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4113
- (0, import_common10.Body)()(cls.prototype, methodName, 1);
4114
- (0, import_swagger5.ApiOperation)({
4115
- summary: `Create ${sub.childRoute} for a ${name}`
4116
- })(cls.prototype, methodName, d);
4117
- (0, import_swagger5.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
4118
- (0, import_swagger5.ApiResponse)({
4119
- status: 201,
4120
- description: `${sub.childRoute} created`
4121
- })(cls.prototype, methodName, d);
4122
- }, "registerSubResourceCreate");
4123
- var registerSubResourceFindOne = /* @__PURE__ */ __name((ctx, sub) => {
4124
- if (!sub.operations?.findOne) return;
4125
- const { cls } = ctx;
4126
- const methodName = `findOneChild_${sub.childRoute}`;
4127
- def(cls, methodName, async function(parentId, childId) {
4128
- return findOneChild(this.repo, sub, childId, parentId);
4129
- });
4130
- const d = desc(cls, methodName);
4131
- (0, import_common10.Get)(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);
4132
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4133
- (0, import_common10.Param)("childId")(cls.prototype, methodName, 1);
4134
- (0, import_swagger5.ApiOperation)({
4135
- summary: `Get a ${sub.childRoute} record`
4136
- })(cls.prototype, methodName, d);
4137
- (0, import_swagger5.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
4138
- (0, import_swagger5.ApiResponse)({
4139
- status: 200,
4140
- description: `${sub.childRoute} record`
4141
- })(cls.prototype, methodName, d);
4142
- }, "registerSubResourceFindOne");
4143
- var registerSubResourceUpdate = /* @__PURE__ */ __name((ctx, sub) => {
4144
- if (!sub.operations?.update) return;
4145
- const { cls } = ctx;
4146
- const methodName = `updateChild_${sub.childRoute}`;
4147
- def(cls, methodName, async function(_id, childId, body) {
4148
- return updateChild(this.repo, sub, childId, body);
4149
- });
4150
- const d = desc(cls, methodName);
4151
- (0, import_common10.Put)(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);
4152
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4153
- (0, import_common10.Param)("childId")(cls.prototype, methodName, 1);
4154
- (0, import_common10.Body)()(cls.prototype, methodName, 2);
4155
- (0, import_swagger5.ApiOperation)({
4156
- summary: `Replace a ${sub.childRoute} record`
4157
- })(cls.prototype, methodName, d);
4158
- (0, import_swagger5.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
4159
- (0, import_swagger5.ApiResponse)({
4160
- status: 200,
4161
- description: `${sub.childRoute} replaced`
4162
- })(cls.prototype, methodName, d);
4163
- }, "registerSubResourceUpdate");
4164
- var registerSubResourcePatch = /* @__PURE__ */ __name((ctx, sub) => {
4165
- if (!sub.operations?.patch) return;
4159
+ }, "defaultSchemas");
4160
+ var childSchemas = /* @__PURE__ */ __name((sub) => (ctx) => {
4161
+ if (!sub.views) return null;
4162
+ const { config, baseUrl } = ctx;
4163
+ const schemasPayload = buildSubResourceViewsPayload(config, sub, baseUrl);
4164
+ return {
4165
+ route: `${sub.childRoute}/schemas`,
4166
+ methodName: `getSchemas_${sub.childRoute}`,
4167
+ name: sub.childRoute,
4168
+ schemasFn: /* @__PURE__ */ __name(async function() {
4169
+ return schemasPayload;
4170
+ }, "schemasFn"),
4171
+ decorators: /* @__PURE__ */ __name(() => {
4172
+ }, "decorators")
4173
+ };
4174
+ }, "childSchemas");
4175
+ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
4176
+ const operationFn = sub ? childSchemas(sub) : defaultSchemas;
4177
+ const properties = operationFn(ctx);
4178
+ if (!properties) return;
4179
+ const { methodName, route, name } = properties;
4166
4180
  const { cls } = ctx;
4167
- const methodName = `patchChild_${sub.childRoute}`;
4168
- def(cls, methodName, async function(_id, childId, body) {
4169
- return updateChild(this.repo, sub, childId, body);
4170
- });
4181
+ def(cls, methodName, properties.schemasFn);
4171
4182
  const d = desc(cls, methodName);
4172
- (0, import_common10.Patch)(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);
4173
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4174
- (0, import_common10.Param)("childId")(cls.prototype, methodName, 1);
4175
- (0, import_common10.Body)()(cls.prototype, methodName, 2);
4176
- (0, import_swagger5.ApiOperation)({
4177
- summary: `Update a ${sub.childRoute} record`
4183
+ (0, import_common14.Get)(route)(cls.prototype, methodName, d);
4184
+ (0, import_swagger9.ApiOperation)({
4185
+ summary: `Get view schemas for ${name}`
4178
4186
  })(cls.prototype, methodName, d);
4179
- (0, import_swagger5.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
4180
- (0, import_swagger5.ApiResponse)({
4187
+ (0, import_swagger9.ApiResponse)({
4181
4188
  status: 200,
4182
- description: `${sub.childRoute} updated`
4189
+ description: `View schemas for ${name}`
4183
4190
  })(cls.prototype, methodName, d);
4184
- }, "registerSubResourcePatch");
4185
- var registerSubResourceDelete = /* @__PURE__ */ __name((ctx, sub) => {
4186
- if (!sub.operations?.delete) return;
4191
+ properties.decorators();
4192
+ }, "registerSchemas");
4193
+
4194
+ // src/lib/crud/operations/register-update.ts
4195
+ var import_common15 = require("@nestjs/common");
4196
+ var import_swagger10 = require("@nestjs/swagger");
4197
+ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
4198
+ if (!isOperationEnabled(ctx.definition, "update")) return null;
4199
+ const { cls, config, updateSchema, bodyDecorator } = ctx;
4200
+ const methodName = "update";
4201
+ return {
4202
+ route: ":id",
4203
+ methodName,
4204
+ name: config.name,
4205
+ updateFn: /* @__PURE__ */ __name(function(id, body) {
4206
+ return this.repo.update(id, body);
4207
+ }, "updateFn"),
4208
+ decorators: /* @__PURE__ */ __name(() => {
4209
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
4210
+ bodyDecorator(updateSchema)(cls.prototype, methodName, 1);
4211
+ }, "decorators")
4212
+ };
4213
+ }, "defaultUpdate");
4214
+ var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
4215
+ if (!isOperationEnabled(sub.operations, "update")) return null;
4187
4216
  const { cls } = ctx;
4188
- const methodName = `deleteChild_${sub.childRoute}`;
4189
- def(cls, methodName, async function(parentId, childId) {
4190
- return deleteChild(this.repo, sub, childId, parentId);
4191
- });
4217
+ const methodName = `updateChild_${sub.childRoute}`;
4218
+ const updateFn = /* @__PURE__ */ __name(async function(_id, childId, body) {
4219
+ return this.repo.updateChild(sub, childId, body);
4220
+ }, "updateFn");
4221
+ const decorators = /* @__PURE__ */ __name(() => {
4222
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
4223
+ (0, import_common15.Param)("childId")(cls.prototype, methodName, 1);
4224
+ (0, import_common15.Body)()(cls.prototype, methodName, 2);
4225
+ }, "decorators");
4226
+ return {
4227
+ route: `:id/${sub.childRoute}/:childId`,
4228
+ methodName,
4229
+ name: sub.childRoute,
4230
+ updateFn,
4231
+ decorators
4232
+ };
4233
+ }, "childUpdate");
4234
+ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
4235
+ const operationFn = sub ? childUpdate(sub) : defaultUpdate;
4236
+ const properties = operationFn(ctx);
4237
+ if (!properties) return;
4238
+ const { methodName, route, name } = properties;
4239
+ const { cls } = ctx;
4240
+ def(cls, methodName, properties.updateFn);
4192
4241
  const d = desc(cls, methodName);
4193
- (0, import_common10.Delete)(`:id/${sub.childRoute}/:childId`)(cls.prototype, methodName, d);
4194
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4195
- (0, import_common10.Param)("childId")(cls.prototype, methodName, 1);
4196
- (0, import_swagger5.ApiOperation)({
4197
- summary: `Delete ${sub.childRoute} record`
4242
+ (0, import_common15.Put)(route)(cls.prototype, methodName, d);
4243
+ (0, import_swagger10.ApiOperation)({
4244
+ summary: `Replace a ${name}`
4198
4245
  })(cls.prototype, methodName, d);
4199
- (0, import_swagger5.ApiParam)(ctx.idParamMeta)(cls.prototype, methodName, d);
4200
- (0, import_swagger5.ApiResponse)({
4246
+ (0, import_swagger10.ApiResponse)({
4201
4247
  status: 200,
4202
- description: `${sub.childRoute} deleted`
4248
+ description: `${name} replaced`
4249
+ })(cls.prototype, methodName, d);
4250
+ (0, import_swagger10.ApiNotFoundResponse)({
4251
+ description: "Not found"
4203
4252
  })(cls.prototype, methodName, d);
4204
- }, "registerSubResourceDelete");
4253
+ properties.decorators();
4254
+ }, "registerUpdate");
4255
+
4256
+ // src/lib/crud/operations/register-endpoints.ts
4257
+ var registerEndpoints = /* @__PURE__ */ __name((ctx) => {
4258
+ registerSubResourceRoutes(ctx);
4259
+ registerFindAll(ctx);
4260
+ registerResourceJsonRawGetEndpoint(ctx);
4261
+ registerResourceJsonRawPutEndpoint(ctx);
4262
+ registerResourceJsonPatchEndpoint(ctx);
4263
+ registerResourceJsonEndpoint(ctx);
4264
+ registerResourceColumnsEndpoint(ctx);
4265
+ registerDefinitionEndpoint(ctx);
4266
+ registerEndpoint(ctx);
4267
+ registerActionRoutes(ctx);
4268
+ registerTableActionRoutes(ctx);
4269
+ }, "registerEndpoints");
4205
4270
  var registerSubResourceRoutes = /* @__PURE__ */ __name((ctx) => {
4206
4271
  for (const sub of ctx.config.subResources ?? []) {
4207
- registerSubResourceSchemas(ctx, sub);
4208
- registerSubResourceFindAll(ctx, sub);
4209
- registerSubResourceCreate(ctx, sub);
4210
- registerSubResourceFindOne(ctx, sub);
4211
- registerSubResourceUpdate(ctx, sub);
4212
- registerSubResourcePatch(ctx, sub);
4213
- registerSubResourceDelete(ctx, sub);
4272
+ registerEndpoint(ctx, sub);
4214
4273
  }
4215
4274
  }, "registerSubResourceRoutes");
4275
+ var registerEndpoint = /* @__PURE__ */ __name((ctx, sub) => {
4276
+ registerSchemas(ctx, sub);
4277
+ registerFindAll(ctx, sub);
4278
+ registerFindOne(ctx, sub);
4279
+ registerCreate(ctx, sub);
4280
+ registerUpdate(ctx, sub);
4281
+ registerPatch(ctx, sub);
4282
+ registerDelete(ctx, sub);
4283
+ }, "registerEndpoint");
4216
4284
 
4217
4285
  // src/lib/crud/crud-controller.factory.ts
4218
4286
  function createCrudController(config, baseUrl) {
@@ -4229,9 +4297,9 @@ function createCrudController(config, baseUrl) {
4229
4297
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
4230
4298
  }
4231
4299
  const bodyDecorator = /* @__PURE__ */ __name((schema, options) => {
4232
- if (!schema) return (0, import_common11.Body)();
4233
- if (isZodSchema(schema)) return (0, import_common11.Body)(new ZodValidationPipe(schema, options));
4234
- return (0, import_common11.Body)();
4300
+ if (!schema) return (0, import_common16.Body)();
4301
+ if (isZodSchema(schema)) return (0, import_common16.Body)(new ZodValidationPipe(schema, options));
4302
+ return (0, import_common16.Body)();
4235
4303
  }, "bodyDecorator");
4236
4304
  let CrudControllerBase = class CrudControllerBase {
4237
4305
  static {
@@ -4262,25 +4330,9 @@ function createCrudController(config, baseUrl) {
4262
4330
  bodyDecorator,
4263
4331
  baseUrl
4264
4332
  };
4265
- registerFindAll(ctx);
4266
- registerDefinitionEndpoint(ctx);
4267
- registerSchemasEndpoint(ctx);
4268
- registerResourceJsonEndpoint(ctx);
4269
- registerResourceColumnsEndpoint(ctx);
4270
- registerResourceJsonPatchEndpoint(ctx);
4271
- registerResourceJsonRawGetEndpoint(ctx);
4272
- registerResourceJsonRawPutEndpoint(ctx);
4273
- registerActionRoutes(ctx);
4274
- registerTableActionRoutes(ctx);
4275
- registerSubResourceRoutes(ctx);
4276
- registerFindOne(ctx);
4277
- registerCreate(ctx);
4278
- registerUpdate(ctx);
4279
- registerPatch(ctx);
4280
- registerUpsert(ctx);
4281
- registerDelete(ctx);
4282
- (0, import_common11.Controller)(route)(CrudControllerBase);
4283
- (0, import_swagger6.ApiTags)(tag)(CrudControllerBase);
4333
+ registerEndpoints(ctx);
4334
+ (0, import_common16.Controller)(route)(CrudControllerBase);
4335
+ (0, import_swagger11.ApiTags)(tag)(CrudControllerBase);
4284
4336
  Object.defineProperty(CrudControllerBase, "name", {
4285
4337
  value: `${name.charAt(0).toUpperCase() + name.slice(1)}Controller`
4286
4338
  });
@@ -4293,8 +4345,8 @@ function createCrudController(config, baseUrl) {
4293
4345
  __name(createCrudController, "createCrudController");
4294
4346
 
4295
4347
  // src/lib/crud/dev-tools/dev-resources.controller.ts
4296
- var import_common12 = require("@nestjs/common");
4297
- var import_swagger7 = require("@nestjs/swagger");
4348
+ var import_common17 = require("@nestjs/common");
4349
+ var import_swagger12 = require("@nestjs/swagger");
4298
4350
 
4299
4351
  // ../crouton-codegen/src/naming.ts
4300
4352
  var clientAccessor = /* @__PURE__ */ __name((prismaModelName) => {
@@ -4952,12 +5004,12 @@ var makeSchemaExportName = /* @__PURE__ */ __name((config) => {
4952
5004
  var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path7.isAbsolute)(p) ? p : (0, import_node_path7.join)(root, p), "resolveFromRoot");
4953
5005
 
4954
5006
  // ../crouton-codegen/src/scaffold.ts
4955
- var import_zod22 = require("zod");
5007
+ var import_zod24 = require("zod");
4956
5008
  var import_promises5 = require("fs/promises");
4957
5009
  var import_node_path8 = require("path");
4958
5010
  var ScallfoldDatasourceSchema = DataSourceShape.extend({
4959
5011
  /** Folder name under `dataSourcesDir`. */
4960
- folder: import_zod22.z.string().default("default")
5012
+ folder: import_zod24.z.string().default("default")
4961
5013
  }).transform(transformDataSource);
4962
5014
 
4963
5015
  // ../crouton-codegen/src/datasource-scaffold.ts
@@ -5026,7 +5078,7 @@ var import_node_child_process = require("child_process");
5026
5078
  var import_node_fs4 = require("fs");
5027
5079
  var import_promises7 = require("fs/promises");
5028
5080
  var import_node_path11 = require("path");
5029
- var run = /* @__PURE__ */ __name((cmd, args, cwd) => new Promise((resolve6) => {
5081
+ var run = /* @__PURE__ */ __name((cmd, args, cwd) => new Promise((resolve7) => {
5030
5082
  const child = (0, import_node_child_process.spawn)(cmd, args, {
5031
5083
  cwd,
5032
5084
  shell: process.platform === "win32"
@@ -5035,12 +5087,12 @@ var run = /* @__PURE__ */ __name((cmd, args, cwd) => new Promise((resolve6) => {
5035
5087
  let stderr = "";
5036
5088
  child.stdout?.on("data", (d) => stdout += d.toString());
5037
5089
  child.stderr?.on("data", (d) => stderr += d.toString());
5038
- child.on("error", (err) => resolve6({
5090
+ child.on("error", (err) => resolve7({
5039
5091
  code: 1,
5040
5092
  stdout,
5041
5093
  stderr: stderr + String(err)
5042
5094
  }));
5043
- child.on("close", (code) => resolve6({
5095
+ child.on("close", (code) => resolve7({
5044
5096
  code: code ?? 0,
5045
5097
  stdout,
5046
5098
  stderr
@@ -5191,6 +5243,78 @@ var normalizeSchema = /* @__PURE__ */ __name(async (schemaPath, configDir) => {
5191
5243
  };
5192
5244
  }, "normalizeSchema");
5193
5245
 
5246
+ // src/lib/crud/resource/ResourceFlags.ts
5247
+ var import_node_path12 = require("path");
5248
+ var applyResourceFlagPatch = /* @__PURE__ */ __name((raw, patch) => {
5249
+ const result = {
5250
+ ...raw
5251
+ };
5252
+ if (patch.draft !== void 0) {
5253
+ if (patch.draft) {
5254
+ result["draft"] = true;
5255
+ } else {
5256
+ delete result["draft"];
5257
+ }
5258
+ }
5259
+ if (patch.sidebar !== void 0) {
5260
+ const existing = raw["sidebar"] && typeof raw["sidebar"] === "object" ? {
5261
+ ...raw["sidebar"]
5262
+ } : {};
5263
+ if (patch.sidebar.hide !== void 0) {
5264
+ if (patch.sidebar.hide) {
5265
+ existing["hide"] = true;
5266
+ } else {
5267
+ delete existing["hide"];
5268
+ }
5269
+ }
5270
+ if (patch.sidebar.group !== void 0) {
5271
+ existing["group"] = patch.sidebar.group;
5272
+ }
5273
+ if (patch.sidebar.position !== void 0) {
5274
+ existing["position"] = patch.sidebar.position;
5275
+ }
5276
+ if (patch.sidebar.label !== void 0) {
5277
+ existing["label"] = patch.sidebar.label;
5278
+ }
5279
+ if (Object.keys(existing).length === 0) {
5280
+ delete result["sidebar"];
5281
+ } else {
5282
+ result["sidebar"] = existing;
5283
+ }
5284
+ }
5285
+ return result;
5286
+ }, "applyResourceFlagPatch");
5287
+ var resolveResourcePath = /* @__PURE__ */ __name((resourcesDir, name) => {
5288
+ const resolved = (0, import_node_path12.resolve)(resourcesDir, name, "resource.json");
5289
+ if (!resolved.startsWith((0, import_node_path12.resolve)(resourcesDir) + "/")) {
5290
+ throw new Error(`Invalid resource name: "${name}"`);
5291
+ }
5292
+ return resolved;
5293
+ }, "resolveResourcePath");
5294
+
5295
+ // src/lib/crud/resource/resource-load-report.registry.ts
5296
+ var ResourceLoadReportRegistry = class ResourceLoadReportRegistry2 {
5297
+ static {
5298
+ __name(this, "ResourceLoadReportRegistry");
5299
+ }
5300
+ notices = [];
5301
+ record(n) {
5302
+ this.notices.push(n);
5303
+ }
5304
+ getAll() {
5305
+ return [
5306
+ ...this.notices
5307
+ ];
5308
+ }
5309
+ getByState(state) {
5310
+ return this.notices.filter((n) => n.state === state);
5311
+ }
5312
+ clear() {
5313
+ this.notices = [];
5314
+ }
5315
+ };
5316
+ var resourceLoadReportRegistry = new ResourceLoadReportRegistry();
5317
+
5194
5318
  // src/lib/crud/dev-tools/dev-resources.controller.ts
5195
5319
  function _ts_decorate5(decorators, target, key, desc2) {
5196
5320
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
@@ -5214,12 +5338,14 @@ var DevResourcesController = class {
5214
5338
  __name(this, "DevResourcesController");
5215
5339
  }
5216
5340
  dataSourceRegistry;
5217
- constructor(dataSourceRegistry) {
5341
+ resourceConfigRegistry;
5342
+ constructor(dataSourceRegistry, resourceConfigRegistry) {
5218
5343
  this.dataSourceRegistry = dataSourceRegistry;
5344
+ this.resourceConfigRegistry = resourceConfigRegistry;
5219
5345
  }
5220
5346
  assertDev() {
5221
5347
  if (!IS_DEV) {
5222
- throw new import_common12.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
5348
+ throw new import_common17.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
5223
5349
  }
5224
5350
  }
5225
5351
  /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */
@@ -5228,14 +5354,14 @@ var DevResourcesController = class {
5228
5354
  try {
5229
5355
  loaded = await loadConfig2(process.cwd());
5230
5356
  } catch (e) {
5231
- throw new import_common12.NotFoundException(e.message ?? "No crouton.json config found.");
5357
+ throw new import_common17.NotFoundException(e.message ?? "No crouton.json config found.");
5232
5358
  }
5233
5359
  const datasources = await loadDatasources(loaded);
5234
5360
  let ds;
5235
5361
  try {
5236
5362
  ds = resolveDatasource(datasources, datasourceName);
5237
5363
  } catch (e) {
5238
- throw new import_common12.BadRequestException(e.message);
5364
+ throw new import_common17.BadRequestException(e.message);
5239
5365
  }
5240
5366
  const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);
5241
5367
  return {
@@ -5250,7 +5376,7 @@ var DevResourcesController = class {
5250
5376
  schemaPath
5251
5377
  });
5252
5378
  } catch (e) {
5253
- throw new import_common12.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
5379
+ throw new import_common17.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
5254
5380
  }
5255
5381
  }
5256
5382
  buildApplyContext(loaded, ds) {
@@ -5320,7 +5446,7 @@ var DevResourcesController = class {
5320
5446
  zodOutputDir: zodDir
5321
5447
  });
5322
5448
  if (!result.ok) {
5323
- throw new import_common12.BadRequestException(`prisma db pull failed:
5449
+ throw new import_common17.BadRequestException(`prisma db pull failed:
5324
5450
  ${result.dbPull.output}`);
5325
5451
  }
5326
5452
  return {
@@ -5337,13 +5463,13 @@ ${result.dbPull.output}`);
5337
5463
  async sync(body) {
5338
5464
  this.assertDev();
5339
5465
  if (!body?.model) {
5340
- throw new import_common12.BadRequestException('"model" is required.');
5466
+ throw new import_common17.BadRequestException('"model" is required.');
5341
5467
  }
5342
5468
  const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);
5343
5469
  const models = await this.introspectModels(schemaPath);
5344
5470
  const model = models.find((m) => m.prismaName === body.model || m.clientAccessor === body.model);
5345
5471
  if (!model) {
5346
- throw new import_common12.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
5472
+ throw new import_common17.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
5347
5473
  }
5348
5474
  const resolveRelationResource = await makeRelationResolver(loaded);
5349
5475
  const diff2 = await buildResourceDiff(model, {
@@ -5423,13 +5549,136 @@ ${result.dbPull.output}`);
5423
5549
  results
5424
5550
  };
5425
5551
  }
5552
+ // ─── Visibility & flag endpoints ────────────────────────────────────
5553
+ async visibility() {
5554
+ this.assertDev();
5555
+ const loaded = await this.resourceConfigRegistry.getAll();
5556
+ const fromLoaded = loaded.map((c) => ({
5557
+ name: c.name,
5558
+ path: c.route,
5559
+ state: c.sidebar?.hide ? "hidden" : "in-menu",
5560
+ group: c.sidebar?.group,
5561
+ position: c.sidebar?.position,
5562
+ editable: true
5563
+ }));
5564
+ const drafts = resourceLoadReportRegistry.getByState("draft").map((d) => ({
5565
+ name: d.name,
5566
+ path: d.path,
5567
+ state: "draft",
5568
+ group: void 0,
5569
+ position: void 0,
5570
+ editable: !d.path.endsWith(".ts")
5571
+ }));
5572
+ const errors = resourceLoadErrorsRegistry.getAll().map((e) => ({
5573
+ name: e.name,
5574
+ path: e.path,
5575
+ state: "error",
5576
+ group: void 0,
5577
+ position: void 0,
5578
+ editable: !e.path.endsWith(".ts")
5579
+ }));
5580
+ return {
5581
+ resources: [
5582
+ ...fromLoaded,
5583
+ ...drafts,
5584
+ ...errors
5585
+ ]
5586
+ };
5587
+ }
5588
+ async publish(name) {
5589
+ this.assertDev();
5590
+ const { loaded } = await this.loadProject();
5591
+ const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
5592
+ const jsonPath = resolveResourcePath(resourcesDir, name);
5593
+ const raw = readRawResourceJson(jsonPath);
5594
+ if (!raw) throw new import_common17.NotFoundException(`Resource "${name}" not found.`);
5595
+ if (jsonPath.endsWith(".ts")) throw new import_common17.ForbiddenException("TypeScript resources cannot be edited.");
5596
+ const patched = applyResourceFlagPatch(raw, {
5597
+ draft: false
5598
+ });
5599
+ const result = validateResourceJson(patched);
5600
+ if (!result.success) {
5601
+ throw new import_common17.BadRequestException(`Validation failed: ${result.error.message}`);
5602
+ }
5603
+ writeRawResourceJson(jsonPath, patched);
5604
+ return {
5605
+ ok: true
5606
+ };
5607
+ }
5608
+ async removeFromMenu(name) {
5609
+ this.assertDev();
5610
+ const { loaded } = await this.loadProject();
5611
+ const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
5612
+ const jsonPath = resolveResourcePath(resourcesDir, name);
5613
+ const raw = readRawResourceJson(jsonPath);
5614
+ if (!raw) throw new import_common17.NotFoundException(`Resource "${name}" not found.`);
5615
+ if (jsonPath.endsWith(".ts")) throw new import_common17.ForbiddenException("TypeScript resources cannot be edited.");
5616
+ const patched = applyResourceFlagPatch(raw, {
5617
+ sidebar: {
5618
+ hide: true
5619
+ }
5620
+ });
5621
+ const result = validateResourceJson(patched);
5622
+ if (!result.success) {
5623
+ throw new import_common17.BadRequestException(`Validation failed: ${result.error.message}`);
5624
+ }
5625
+ writeRawResourceJson(jsonPath, patched);
5626
+ return {
5627
+ ok: true
5628
+ };
5629
+ }
5630
+ async addToMenu(name, body = {}) {
5631
+ this.assertDev();
5632
+ const { loaded } = await this.loadProject();
5633
+ const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
5634
+ const jsonPath = resolveResourcePath(resourcesDir, name);
5635
+ const raw = readRawResourceJson(jsonPath);
5636
+ if (!raw) throw new import_common17.NotFoundException(`Resource "${name}" not found.`);
5637
+ if (jsonPath.endsWith(".ts")) throw new import_common17.ForbiddenException("TypeScript resources cannot be edited.");
5638
+ const sidebarPatch = {
5639
+ hide: false
5640
+ };
5641
+ if (body.group !== void 0) sidebarPatch.group = body.group;
5642
+ if (body.position !== void 0) sidebarPatch.position = body.position;
5643
+ if (body.label !== void 0) sidebarPatch.label = body.label;
5644
+ const patched = applyResourceFlagPatch(raw, {
5645
+ draft: false,
5646
+ sidebar: sidebarPatch
5647
+ });
5648
+ const result = validateResourceJson(patched);
5649
+ if (!result.success) {
5650
+ throw new import_common17.BadRequestException(`Validation failed: ${result.error.message}`);
5651
+ }
5652
+ writeRawResourceJson(jsonPath, patched);
5653
+ return {
5654
+ ok: true
5655
+ };
5656
+ }
5657
+ async updateFlags(name, body) {
5658
+ this.assertDev();
5659
+ const { loaded } = await this.loadProject();
5660
+ const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
5661
+ const jsonPath = resolveResourcePath(resourcesDir, name);
5662
+ const raw = readRawResourceJson(jsonPath);
5663
+ if (!raw) throw new import_common17.NotFoundException(`Resource "${name}" not found.`);
5664
+ if (jsonPath.endsWith(".ts")) throw new import_common17.ForbiddenException("TypeScript resources cannot be edited.");
5665
+ const patched = applyResourceFlagPatch(raw, body);
5666
+ const result = validateResourceJson(patched);
5667
+ if (!result.success) {
5668
+ throw new import_common17.BadRequestException(`Validation failed: ${result.error.message}`);
5669
+ }
5670
+ writeRawResourceJson(jsonPath, patched);
5671
+ return {
5672
+ ok: true
5673
+ };
5674
+ }
5426
5675
  };
5427
5676
  _ts_decorate5([
5428
- (0, import_common12.Get)("models"),
5429
- (0, import_swagger7.ApiOperation)({
5677
+ (0, import_common17.Get)("models"),
5678
+ (0, import_swagger12.ApiOperation)({
5430
5679
  summary: "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"
5431
5680
  }),
5432
- (0, import_swagger7.ApiResponse)({
5681
+ (0, import_swagger12.ApiResponse)({
5433
5682
  status: 200,
5434
5683
  description: "DB models and their resource/client status"
5435
5684
  }),
@@ -5438,11 +5687,11 @@ _ts_decorate5([
5438
5687
  _ts_metadata4("design:returntype", Promise)
5439
5688
  ], DevResourcesController.prototype, "listModels", null);
5440
5689
  _ts_decorate5([
5441
- (0, import_common12.Post)("restart"),
5442
- (0, import_swagger7.ApiOperation)({
5690
+ (0, import_common17.Post)("restart"),
5691
+ (0, import_swagger12.ApiOperation)({
5443
5692
  summary: "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."
5444
5693
  }),
5445
- (0, import_swagger7.ApiResponse)({
5694
+ (0, import_swagger12.ApiResponse)({
5446
5695
  status: 200,
5447
5696
  description: "Restart scheduled \u2014 the connection will drop shortly after"
5448
5697
  }),
@@ -5451,15 +5700,15 @@ _ts_decorate5([
5451
5700
  _ts_metadata4("design:returntype", Object)
5452
5701
  ], DevResourcesController.prototype, "restart", null);
5453
5702
  _ts_decorate5([
5454
- (0, import_common12.Post)("pull"),
5455
- (0, import_swagger7.ApiOperation)({
5703
+ (0, import_common17.Post)("pull"),
5704
+ (0, import_swagger12.ApiOperation)({
5456
5705
  summary: "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"
5457
5706
  }),
5458
- (0, import_swagger7.ApiResponse)({
5707
+ (0, import_swagger12.ApiResponse)({
5459
5708
  status: 200,
5460
5709
  description: "Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes"
5461
5710
  }),
5462
- _ts_param(0, (0, import_common12.Body)()),
5711
+ _ts_param(0, (0, import_common17.Body)()),
5463
5712
  _ts_metadata4("design:type", Function),
5464
5713
  _ts_metadata4("design:paramtypes", [
5465
5714
  Object
@@ -5467,15 +5716,15 @@ _ts_decorate5([
5467
5716
  _ts_metadata4("design:returntype", Promise)
5468
5717
  ], DevResourcesController.prototype, "pull", null);
5469
5718
  _ts_decorate5([
5470
- (0, import_common12.Post)("sync"),
5471
- (0, import_swagger7.ApiOperation)({
5719
+ (0, import_common17.Post)("sync"),
5720
+ (0, import_swagger12.ApiOperation)({
5472
5721
  summary: "Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)"
5473
5722
  }),
5474
- (0, import_swagger7.ApiResponse)({
5723
+ (0, import_swagger12.ApiResponse)({
5475
5724
  status: 200,
5476
5725
  description: "Files written for this resource"
5477
5726
  }),
5478
- _ts_param(0, (0, import_common12.Body)()),
5727
+ _ts_param(0, (0, import_common17.Body)()),
5479
5728
  _ts_metadata4("design:type", Function),
5480
5729
  _ts_metadata4("design:paramtypes", [
5481
5730
  Object
@@ -5483,15 +5732,15 @@ _ts_decorate5([
5483
5732
  _ts_metadata4("design:returntype", Promise)
5484
5733
  ], DevResourcesController.prototype, "sync", null);
5485
5734
  _ts_decorate5([
5486
- (0, import_common12.Post)("plan"),
5487
- (0, import_swagger7.ApiOperation)({
5735
+ (0, import_common17.Post)("plan"),
5736
+ (0, import_swagger12.ApiOperation)({
5488
5737
  summary: "Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults \u2014 computes what would change, writes nothing"
5489
5738
  }),
5490
- (0, import_swagger7.ApiResponse)({
5739
+ (0, import_swagger12.ApiResponse)({
5491
5740
  status: 200,
5492
5741
  description: "Proposed per-resource changes"
5493
5742
  }),
5494
- _ts_param(0, (0, import_common12.Body)()),
5743
+ _ts_param(0, (0, import_common17.Body)()),
5495
5744
  _ts_metadata4("design:type", Function),
5496
5745
  _ts_metadata4("design:paramtypes", [
5497
5746
  Object
@@ -5499,53 +5748,171 @@ _ts_decorate5([
5499
5748
  _ts_metadata4("design:returntype", Promise)
5500
5749
  ], DevResourcesController.prototype, "plan", null);
5501
5750
  _ts_decorate5([
5502
- (0, import_common12.Post)("apply"),
5503
- (0, import_swagger7.ApiOperation)({
5751
+ (0, import_common17.Post)("apply"),
5752
+ (0, import_swagger12.ApiOperation)({
5504
5753
  summary: "Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults"
5505
5754
  }),
5506
- (0, import_swagger7.ApiResponse)({
5755
+ (0, import_swagger12.ApiResponse)({
5507
5756
  status: 200,
5508
5757
  description: "Per-resource commit results"
5509
5758
  }),
5510
- _ts_param(0, (0, import_common12.Body)()),
5759
+ _ts_param(0, (0, import_common17.Body)()),
5511
5760
  _ts_metadata4("design:type", Function),
5512
5761
  _ts_metadata4("design:paramtypes", [
5513
5762
  Object
5514
5763
  ]),
5515
5764
  _ts_metadata4("design:returntype", Promise)
5516
5765
  ], DevResourcesController.prototype, "apply", null);
5766
+ _ts_decorate5([
5767
+ (0, import_common17.Get)("visibility"),
5768
+ (0, import_swagger12.ApiOperation)({
5769
+ summary: "Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)"
5770
+ }),
5771
+ (0, import_swagger12.ApiResponse)({
5772
+ status: 200,
5773
+ description: "Resource visibility list"
5774
+ }),
5775
+ _ts_metadata4("design:type", Function),
5776
+ _ts_metadata4("design:paramtypes", []),
5777
+ _ts_metadata4("design:returntype", Promise)
5778
+ ], DevResourcesController.prototype, "visibility", null);
5779
+ _ts_decorate5([
5780
+ (0, import_common17.Post)(":name/publish"),
5781
+ (0, import_swagger12.ApiOperation)({
5782
+ summary: "Dev-only: publish a draft resource (removes `draft: true` from resource.json)"
5783
+ }),
5784
+ (0, import_swagger12.ApiResponse)({
5785
+ status: 200,
5786
+ description: "Resource published"
5787
+ }),
5788
+ _ts_param(0, (0, import_common17.Param)("name")),
5789
+ _ts_metadata4("design:type", Function),
5790
+ _ts_metadata4("design:paramtypes", [
5791
+ String
5792
+ ]),
5793
+ _ts_metadata4("design:returntype", Promise)
5794
+ ], DevResourcesController.prototype, "publish", null);
5795
+ _ts_decorate5([
5796
+ (0, import_common17.Post)(":name/remove-from-menu"),
5797
+ (0, import_swagger12.ApiOperation)({
5798
+ summary: "Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)"
5799
+ }),
5800
+ (0, import_swagger12.ApiResponse)({
5801
+ status: 200,
5802
+ description: "Resource removed from menu"
5803
+ }),
5804
+ _ts_param(0, (0, import_common17.Param)("name")),
5805
+ _ts_metadata4("design:type", Function),
5806
+ _ts_metadata4("design:paramtypes", [
5807
+ String
5808
+ ]),
5809
+ _ts_metadata4("design:returntype", Promise)
5810
+ ], DevResourcesController.prototype, "removeFromMenu", null);
5811
+ _ts_decorate5([
5812
+ (0, import_common17.Post)(":name/add-to-menu"),
5813
+ (0, import_swagger12.ApiOperation)({
5814
+ summary: "Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label"
5815
+ }),
5816
+ (0, import_swagger12.ApiResponse)({
5817
+ status: 200,
5818
+ description: "Resource added to menu"
5819
+ }),
5820
+ _ts_param(0, (0, import_common17.Param)("name")),
5821
+ _ts_param(1, (0, import_common17.Body)()),
5822
+ _ts_metadata4("design:type", Function),
5823
+ _ts_metadata4("design:paramtypes", [
5824
+ String,
5825
+ Object
5826
+ ]),
5827
+ _ts_metadata4("design:returntype", Promise)
5828
+ ], DevResourcesController.prototype, "addToMenu", null);
5829
+ _ts_decorate5([
5830
+ (0, import_common17.Patch)(":name/flags"),
5831
+ (0, import_swagger12.ApiOperation)({
5832
+ summary: "Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)"
5833
+ }),
5834
+ (0, import_swagger12.ApiResponse)({
5835
+ status: 200,
5836
+ description: "Flags updated"
5837
+ }),
5838
+ _ts_param(0, (0, import_common17.Param)("name")),
5839
+ _ts_param(1, (0, import_common17.Body)()),
5840
+ _ts_metadata4("design:type", Function),
5841
+ _ts_metadata4("design:paramtypes", [
5842
+ String,
5843
+ typeof ResourceFlagPatch === "undefined" ? Object : ResourceFlagPatch
5844
+ ]),
5845
+ _ts_metadata4("design:returntype", Promise)
5846
+ ], DevResourcesController.prototype, "updateFlags", null);
5517
5847
  DevResourcesController = _ts_decorate5([
5518
- (0, import_common12.Controller)("_app/resources"),
5519
- (0, import_swagger7.ApiTags)("Dev tools"),
5848
+ (0, import_common17.Controller)("_app/resources"),
5849
+ (0, import_swagger12.ApiTags)("Dev tools"),
5520
5850
  _ts_metadata4("design:type", Function),
5521
5851
  _ts_metadata4("design:paramtypes", [
5522
- typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry
5852
+ typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
5853
+ typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
5523
5854
  ])
5524
5855
  ], DevResourcesController);
5525
5856
 
5857
+ // src/lib/crud/builder/schema.helpers.ts
5858
+ var pickByColumns = /* @__PURE__ */ __name((schema, columns, filter) => {
5859
+ if (!schema) return void 0;
5860
+ if (!columns?.length) return schema;
5861
+ const baseFilter = /* @__PURE__ */ __name((c) => !isRelation(c) && (filter ? filter(c) : true), "baseFilter");
5862
+ const schemaKeys = new Set(Object.keys(schema.shape));
5863
+ const filtered = columns.filter((c) => baseFilter(c) && schemaKeys.has(c.id));
5864
+ if (!filtered.length) return void 0;
5865
+ const mask = Object.fromEntries(filtered.map((c) => [
5866
+ c.id,
5867
+ true
5868
+ ]));
5869
+ return schema.pick(mask);
5870
+ }, "pickByColumns");
5871
+ var opWithSchema = /* @__PURE__ */ __name((enabled, schema) => {
5872
+ if (enabled === false) return void 0;
5873
+ return schema ? {
5874
+ schema
5875
+ } : true;
5876
+ }, "opWithSchema");
5877
+ var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
5878
+ if (!entry) return void 0;
5879
+ if (entry === true) {
5880
+ throw new Error("`operations.upsert` must be an object with `upsertOn`, not `true`.");
5881
+ }
5882
+ if (typeof entry === "object") {
5883
+ return {
5884
+ upsertOn: entry.upsertOn,
5885
+ ...schema && {
5886
+ schema
5887
+ }
5888
+ };
5889
+ }
5890
+ return void 0;
5891
+ }, "upsertOp");
5892
+
5526
5893
  // src/lib/crud/enum-registry/enum-registry.types.ts
5527
- var import_zod23 = require("zod");
5528
- var EnumEntrySchema = import_zod23.z.object({
5529
- value: import_zod23.z.unknown(),
5530
- label: import_zod23.z.string()
5894
+ var import_zod25 = require("zod");
5895
+ var EnumEntrySchema = import_zod25.z.object({
5896
+ value: import_zod25.z.unknown(),
5897
+ label: import_zod25.z.string()
5531
5898
  });
5532
- var EnumRegistrySchema = import_zod23.z.record(import_zod23.z.string(), import_zod23.z.array(EnumEntrySchema)).default({});
5899
+ var EnumRegistrySchema = import_zod25.z.record(import_zod25.z.string(), import_zod25.z.array(EnumEntrySchema)).default({});
5533
5900
 
5534
5901
  // src/lib/crud/enum-registry/enum-registry.loader.ts
5535
5902
  var import_node_fs5 = require("fs");
5536
- var import_node_path12 = require("path");
5903
+ var import_node_path13 = require("path");
5537
5904
  var ENUMS_FILE = "crouton.enums.json";
5538
5905
  var loadEnumRegistry = /* @__PURE__ */ __name((startDir, enumsFile) => {
5539
5906
  let file = enumsFile;
5540
5907
  if (!file) {
5541
5908
  let dir = startDir;
5542
5909
  while (true) {
5543
- const candidate = (0, import_node_path12.join)(dir, ENUMS_FILE);
5910
+ const candidate = (0, import_node_path13.join)(dir, ENUMS_FILE);
5544
5911
  if ((0, import_node_fs5.existsSync)(candidate)) {
5545
5912
  file = candidate;
5546
5913
  break;
5547
5914
  }
5548
- const parent = (0, import_node_path12.dirname)(dir);
5915
+ const parent = (0, import_node_path13.dirname)(dir);
5549
5916
  if (parent === dir) break;
5550
5917
  dir = parent;
5551
5918
  }
@@ -5575,9 +5942,9 @@ var injectEnumValues = /* @__PURE__ */ __name((columns, enums) => {
5575
5942
  }, "injectEnumValues");
5576
5943
 
5577
5944
  // src/lib/crud/adapter/relation-type.ts
5578
- var import_zod24 = require("zod");
5945
+ var import_zod26 = require("zod");
5579
5946
  var unwrapZodType = /* @__PURE__ */ __name((type) => {
5580
- if (type instanceof import_zod24.ZodOptional || type instanceof import_zod24.ZodNullable) {
5947
+ if (type instanceof import_zod26.ZodOptional || type instanceof import_zod26.ZodNullable) {
5581
5948
  return unwrapZodType(type.unwrap());
5582
5949
  }
5583
5950
  return type;
@@ -5587,7 +5954,7 @@ var deriveRelationType = /* @__PURE__ */ __name((schema, columnId) => {
5587
5954
  const field = schema.shape[columnId];
5588
5955
  if (!field) return void 0;
5589
5956
  const inner = unwrapZodType(field);
5590
- return inner instanceof import_zod24.ZodArray ? "oneToMany" : "manyToOne";
5957
+ return inner instanceof import_zod26.ZodArray ? "oneToMany" : "manyToOne";
5591
5958
  }, "deriveRelationType");
5592
5959
  var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
5593
5960
  const base = col.column ?? col.id;
@@ -5619,7 +5986,7 @@ var enrichRelationTypes = /* @__PURE__ */ __name((columns, schema) => {
5619
5986
 
5620
5987
  // src/lib/crud/resource/ReadResourceJson.ts
5621
5988
  var import_node_fs6 = require("fs");
5622
- var import_node_path13 = require("path");
5989
+ var import_node_path14 = require("path");
5623
5990
  var readResourceJson = /* @__PURE__ */ __name((jsonPath) => {
5624
5991
  if (!(0, import_node_fs6.existsSync)(jsonPath)) return void 0;
5625
5992
  let fileContent;
@@ -5642,26 +6009,26 @@ var readResourceJson = /* @__PURE__ */ __name((jsonPath) => {
5642
6009
  success: true,
5643
6010
  data: {
5644
6011
  json: resource.data,
5645
- dir: (0, import_node_path13.dirname)(jsonPath)
6012
+ dir: (0, import_node_path14.dirname)(jsonPath)
5646
6013
  }
5647
6014
  };
5648
6015
  }, "readResourceJson");
5649
6016
 
5650
6017
  // src/lib/crud/adapter/resource-resolver.ts
5651
6018
  var import_node_fs7 = require("fs");
5652
- var import_node_path14 = require("path");
6019
+ var import_node_path15 = require("path");
5653
6020
  var unwrap2 = /* @__PURE__ */ __name((result) => {
5654
6021
  if (result?.success) return result.data;
5655
6022
  return void 0;
5656
6023
  }, "unwrap");
5657
6024
  var resolveChildResource = /* @__PURE__ */ __name((resourcePath, parentDir) => {
5658
- const directPath = (0, import_node_path14.resolve)(parentDir, resourcePath);
6025
+ const directPath = (0, import_node_path15.resolve)(parentDir, resourcePath);
5659
6026
  try {
5660
6027
  if (resourcePath.endsWith(".json") && (0, import_node_fs7.existsSync)(directPath)) {
5661
6028
  return unwrap2(readResourceJson(directPath));
5662
6029
  }
5663
6030
  const childName = resourcePath.replace(/^\.\//, "").replace(/\.resource$/, "");
5664
- const childJsonPath = (0, import_node_path14.resolve)((0, import_node_path14.dirname)(parentDir), childName, "resource.json");
6031
+ const childJsonPath = (0, import_node_path15.resolve)((0, import_node_path15.dirname)(parentDir), childName, "resource.json");
5665
6032
  return unwrap2(readResourceJson(childJsonPath));
5666
6033
  } catch {
5667
6034
  return void 0;
@@ -5875,7 +6242,7 @@ var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentMode
5875
6242
  const childOps = childJson?.operations ?? {};
5876
6243
  return {
5877
6244
  column: c.id,
5878
- relation: c.id,
6245
+ relation: c.fieldInput?.relation ?? c.id,
5879
6246
  childRoute,
5880
6247
  childModel: c.id,
5881
6248
  foreignKey: c.fieldInput?.foreignKey ?? `${parentModel}Id`,
@@ -5908,7 +6275,14 @@ var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentMode
5908
6275
  calculatedColumns: childJson.calculatedColumns
5909
6276
  },
5910
6277
  ...(c.hiddenInForm === false || c.hiddenInView === false) && {
5911
- includeInFindOne: true
6278
+ includeInFindOne: true,
6279
+ ...(() => {
6280
+ const opts = c.fieldInput?.options;
6281
+ if (opts?.sort) return {
6282
+ findOneOrderBy: buildChildSortClause(opts.sort, opts.sortDir)
6283
+ };
6284
+ return {};
6285
+ })()
5912
6286
  },
5913
6287
  ...buildValueLabelColumns(childColumns).length && {
5914
6288
  valueLabelColumns: buildValueLabelColumns(childColumns)
@@ -6031,33 +6405,33 @@ var buildLookup = /* @__PURE__ */ __name((columns) => {
6031
6405
  }, "buildLookup");
6032
6406
 
6033
6407
  // src/lib/crud/hooks/hooks.types.ts
6034
- var import_zod25 = require("zod");
6035
- var WriteOpSchema = import_zod25.z.enum([
6408
+ var import_zod27 = require("zod");
6409
+ var WriteOpSchema = import_zod27.z.enum([
6036
6410
  "create",
6037
6411
  "update",
6038
6412
  "patch",
6039
6413
  "upsert",
6040
6414
  "delete"
6041
6415
  ]);
6042
- var ReadOpSchema = import_zod25.z.enum([
6416
+ var ReadOpSchema = import_zod27.z.enum([
6043
6417
  "findAll",
6044
6418
  "findOne"
6045
6419
  ]);
6046
- var ResourceHooksSchema = import_zod25.z.object({
6047
- beforeWrite: import_zod25.z.custom().optional(),
6048
- afterWrite: import_zod25.z.custom().optional(),
6049
- afterRead: import_zod25.z.custom().optional()
6420
+ var ResourceHooksSchema = import_zod27.z.object({
6421
+ beforeWrite: import_zod27.z.custom().optional(),
6422
+ afterWrite: import_zod27.z.custom().optional(),
6423
+ afterRead: import_zod27.z.custom().optional()
6050
6424
  });
6051
6425
 
6052
6426
  // src/lib/crud/hooks/hooks.loader.ts
6053
- var import_node_path15 = require("path");
6427
+ var import_node_path16 = require("path");
6054
6428
  var loadResourceHooks = /* @__PURE__ */ __name(async (basePath) => {
6055
6429
  const file = findModule(basePath, "hooks");
6056
6430
  return file ? importDefault(file) : void 0;
6057
6431
  }, "loadResourceHooks");
6058
6432
  var loadSubResourceHooks = /* @__PURE__ */ __name(async (subResources, basePath) => {
6059
6433
  for (const sub of subResources) {
6060
- const file = sub.name ? findModule((0, import_node_path15.join)(basePath, "hooks"), sub.name) : void 0;
6434
+ const file = sub.name ? findModule((0, import_node_path16.join)(basePath, "hooks"), sub.name) : void 0;
6061
6435
  if (!file) continue;
6062
6436
  const hooks = await importDefault(file);
6063
6437
  if (hooks) sub.hooks = hooks;
@@ -6124,32 +6498,9 @@ var migrateResourceJsonFile = /* @__PURE__ */ __name((jsonPath, opts) => {
6124
6498
  }
6125
6499
  }, "migrateResourceJsonFile");
6126
6500
 
6127
- // src/lib/crud/resource/resource-load-report.registry.ts
6128
- var ResourceLoadReportRegistry = class ResourceLoadReportRegistry2 {
6129
- static {
6130
- __name(this, "ResourceLoadReportRegistry");
6131
- }
6132
- notices = [];
6133
- record(n) {
6134
- this.notices.push(n);
6135
- }
6136
- getAll() {
6137
- return [
6138
- ...this.notices
6139
- ];
6140
- }
6141
- getByState(state) {
6142
- return this.notices.filter((n) => n.state === state);
6143
- }
6144
- clear() {
6145
- this.notices = [];
6146
- }
6147
- };
6148
- var resourceLoadReportRegistry = new ResourceLoadReportRegistry();
6149
-
6150
6501
  // src/lib/crud/loader/index.ts
6151
6502
  var import_node_fs9 = require("fs");
6152
- var import_node_path16 = require("path");
6503
+ var import_node_path17 = require("path");
6153
6504
  var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl, enumsFile, onResourceDir) => {
6154
6505
  if (!(0, import_node_fs9.existsSync)(dirPath)) return [];
6155
6506
  resourceLoadErrorsRegistry.clear();
@@ -6161,11 +6512,11 @@ var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl,
6161
6512
  const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
6162
6513
  const configs = [];
6163
6514
  for (const dir of dirs) {
6164
- const basePath = (0, import_node_path16.join)(dirPath, dir);
6515
+ const basePath = (0, import_node_path17.join)(dirPath, dir);
6165
6516
  const schemaFile = findModule(basePath, "schema");
6166
6517
  const schema = schemaFile ? await importDefault(schemaFile) : void 0;
6167
6518
  const hooks = await loadResourceHooks(basePath);
6168
- const jsonFile = (0, import_node_path16.join)(basePath, "resource.json");
6519
+ const jsonFile = (0, import_node_path17.join)(basePath, "resource.json");
6169
6520
  if ((0, import_node_fs9.existsSync)(jsonFile)) {
6170
6521
  const migration = migrateResourceJsonFile(jsonFile, {
6171
6522
  isDev: IS_DEV
@@ -6284,22 +6635,22 @@ var FileSystemResourceConfigLoader = class extends ResourceConfigLoader2 {
6284
6635
 
6285
6636
  // src/lib/crud/status/status.service.ts
6286
6637
  var import_node_fs10 = require("fs");
6287
- var import_node_path17 = require("path");
6638
+ var import_node_path18 = require("path");
6288
6639
  var import_node_url = require("url");
6289
6640
  var DB_CHECK_TIMEOUT_MS = 3e3;
6290
6641
  var CONNECTION_STRING_PATTERN = /(?:postgresql|postgres|mysql|mongodb|sqlserver|sqlite):\/\/[^\s"')]+/gi;
6291
6642
  var stripConnectionStrings = /* @__PURE__ */ __name((message) => message.replace(CONNECTION_STRING_PATTERN, "[REDACTED]"), "stripConnectionStrings");
6292
6643
  var getCroutonVersion = /* @__PURE__ */ __name(() => {
6293
6644
  try {
6294
- const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path17.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
6645
+ const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path18.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
6295
6646
  let dir = startDir;
6296
- while (dir !== (0, import_node_path17.dirname)(dir)) {
6297
- const pkgPath = (0, import_node_path17.join)(dir, "package.json");
6647
+ while (dir !== (0, import_node_path18.dirname)(dir)) {
6648
+ const pkgPath = (0, import_node_path18.join)(dir, "package.json");
6298
6649
  if ((0, import_node_fs10.existsSync)(pkgPath)) {
6299
6650
  const pkg = JSON.parse((0, import_node_fs10.readFileSync)(pkgPath, "utf-8"));
6300
6651
  if (pkg.name === "@ghentcdh/crouton-api") return pkg.version;
6301
6652
  }
6302
- dir = (0, import_node_path17.dirname)(dir);
6653
+ dir = (0, import_node_path18.dirname)(dir);
6303
6654
  }
6304
6655
  } catch {
6305
6656
  }
@@ -6335,7 +6686,10 @@ var getResourceStatus = /* @__PURE__ */ __name((loadedConfigs) => {
6335
6686
  name: c.name,
6336
6687
  path: c.route,
6337
6688
  valid: true,
6338
- version: c.schemaVersion ?? CURRENT_RESOURCE_VERSION
6689
+ version: c.schemaVersion ?? CURRENT_RESOURCE_VERSION,
6690
+ ...c.sidebar?.hide ? {
6691
+ hidden: true
6692
+ } : {}
6339
6693
  }));
6340
6694
  const failed = resourceLoadErrorsRegistry.getAll().map((e) => ({
6341
6695
  name: e.name,
@@ -6382,8 +6736,8 @@ var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs) => {
6382
6736
  }, "buildStatus");
6383
6737
 
6384
6738
  // src/lib/crud/status/status.controller.ts
6385
- var import_common13 = require("@nestjs/common");
6386
- var import_swagger8 = require("@nestjs/swagger");
6739
+ var import_common18 = require("@nestjs/common");
6740
+ var import_swagger13 = require("@nestjs/swagger");
6387
6741
  function _ts_decorate6(decorators, target, key, desc2) {
6388
6742
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
6389
6743
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
@@ -6412,11 +6766,11 @@ var createStatusController = /* @__PURE__ */ __name(() => {
6412
6766
  }
6413
6767
  };
6414
6768
  _ts_decorate6([
6415
- (0, import_common13.Get)("status.json"),
6416
- (0, import_swagger8.ApiOperation)({
6769
+ (0, import_common18.Get)("status.json"),
6770
+ (0, import_swagger13.ApiOperation)({
6417
6771
  summary: "Crouton system status (db, resources, version)"
6418
6772
  }),
6419
- (0, import_swagger8.ApiResponse)({
6773
+ (0, import_swagger13.ApiResponse)({
6420
6774
  status: 200,
6421
6775
  description: "System status"
6422
6776
  }),
@@ -6425,8 +6779,8 @@ var createStatusController = /* @__PURE__ */ __name(() => {
6425
6779
  _ts_metadata5("design:returntype", Promise)
6426
6780
  ], StatusController.prototype, "getStatus", null);
6427
6781
  StatusController = _ts_decorate6([
6428
- (0, import_common13.Controller)("crouton"),
6429
- (0, import_swagger8.ApiTags)("Status"),
6782
+ (0, import_common18.Controller)("crouton"),
6783
+ (0, import_swagger13.ApiTags)("Status"),
6430
6784
  _ts_metadata5("design:type", Function),
6431
6785
  _ts_metadata5("design:paramtypes", [
6432
6786
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
@@ -6528,7 +6882,7 @@ var CroutonApiModule = class _CroutonApiModule {
6528
6882
  }
6529
6883
  };
6530
6884
  CroutonApiModule = _ts_decorate7([
6531
- (0, import_common14.Module)({
6885
+ (0, import_common19.Module)({
6532
6886
  controllers: [],
6533
6887
  providers: [],
6534
6888
  exports: []