@ghentcdh/crouton-api 0.0.1-alpha.40 → 0.0.1-alpha.41

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
@@ -59,7 +59,7 @@ __export(index_exports, {
59
59
  });
60
60
  module.exports = __toCommonJS(index_exports);
61
61
 
62
- // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.0.1__@swc+core@1.15.43_@swc+h_ec0dcc88aa461a763e37ec5746d3e7df/node_modules/tsup/assets/cjs_shims.js
62
+ // ../../node_modules/.pnpm/tsup@8.5.1_@microsoft+api-extractor@7.58.8_@types+node@26.4.0__@swc+core@1.16.1_@swc+he_53e7170f1cd8909962d4b3404cf3712f/node_modules/tsup/assets/cjs_shims.js
63
63
  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");
64
64
  var importMetaUrl = /* @__PURE__ */ getImportMetaUrl();
65
65
 
@@ -1395,6 +1395,14 @@ var RulesetSchema = import_zod19.z.object({
1395
1395
  sharedEnums: import_zod19.z.boolean().default(true),
1396
1396
  defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
1397
1397
  });
1398
+ var I18nConfigSchema = import_zod19.z.object({
1399
+ /** Default / fallback language. */
1400
+ defaultLanguage: import_zod19.z.string().default("en"),
1401
+ /** All supported language codes. */
1402
+ languages: import_zod19.z.array(import_zod19.z.string()).min(1),
1403
+ /** Directory containing `<lang>.json` bundles, relative to project root. */
1404
+ translationsDir: import_zod19.z.string().default("translations")
1405
+ });
1398
1406
  var CroutonConfigSchema = import_zod19.z.object({
1399
1407
  /**
1400
1408
  * Application title served to the frontend via `GET /_app/layout`.
@@ -1424,7 +1432,9 @@ var CroutonConfigSchema = import_zod19.z.object({
1424
1432
  * Whether form fields are saved automatically as the user edits them.
1425
1433
  * @default true
1426
1434
  */
1427
- autoSave: import_zod19.z.boolean().default(true)
1435
+ autoSave: import_zod19.z.boolean().default(true),
1436
+ /** Optional i18n / translation configuration. */
1437
+ i18n: I18nConfigSchema.optional()
1428
1438
  });
1429
1439
 
1430
1440
  // ../crouton-core/src/lib/config/readConfig.ts
@@ -2153,26 +2163,128 @@ var ViewConfigSchema = import_zod22.z.object({
2153
2163
  defaultSort: import_zod22.z.string().optional()
2154
2164
  });
2155
2165
 
2166
+ // ../crouton-core/src/lib/i18n/Translations.schema.ts
2167
+ var import_zod23 = require("zod");
2168
+ var NestedStringRecord = import_zod23.z.lazy(() => import_zod23.z.record(import_zod23.z.string(), import_zod23.z.union([
2169
+ import_zod23.z.string(),
2170
+ NestedStringRecord
2171
+ ])));
2172
+ var TranslationBundleSchema = import_zod23.z.object({
2173
+ app: import_zod23.z.object({
2174
+ title: import_zod23.z.string().optional()
2175
+ }).optional(),
2176
+ sidebarGroups: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2177
+ resources: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.object({
2178
+ title: import_zod23.z.string().optional(),
2179
+ sidebar: import_zod23.z.string().optional(),
2180
+ columns: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2181
+ actions: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2182
+ subResources: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.object({
2183
+ title: import_zod23.z.string().optional(),
2184
+ columns: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional()
2185
+ }).optional()).optional()
2186
+ }).optional()).optional(),
2187
+ enums: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string())).optional(),
2188
+ ui: NestedStringRecord.optional(),
2189
+ validation: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional()
2190
+ }).passthrough();
2191
+
2192
+ // ../crouton-core/src/lib/i18n/translation-keys.ts
2193
+ var resourceTitleKey = /* @__PURE__ */ __name((resource) => `resources.${resource}.title`, "resourceTitleKey");
2194
+ var resourceSidebarKey = /* @__PURE__ */ __name((resource) => `resources.${resource}.sidebar`, "resourceSidebarKey");
2195
+ var columnKey = /* @__PURE__ */ __name((resource, column) => `resources.${resource}.columns.${column}`, "columnKey");
2196
+ var actionKey = /* @__PURE__ */ __name((resource, action) => `resources.${resource}.actions.${action}`, "actionKey");
2197
+ var subResourceTitleKey = /* @__PURE__ */ __name((resource, sub) => `resources.${resource}.subResources.${sub}.title`, "subResourceTitleKey");
2198
+ var subResourceColumnKey = /* @__PURE__ */ __name((resource, sub, column) => `resources.${resource}.subResources.${sub}.columns.${column}`, "subResourceColumnKey");
2199
+ var enumKey = /* @__PURE__ */ __name((enumName, value) => `enums.${enumName}.${value}`, "enumKey");
2200
+ var sidebarGroupKey = /* @__PURE__ */ __name((group) => `sidebarGroups.${group}`, "sidebarGroupKey");
2201
+ var validationKey = /* @__PURE__ */ __name((code) => `validation.${code}`, "validationKey");
2202
+
2203
+ // ../crouton-core/src/lib/i18n/translator.ts
2204
+ var getNestedValue = /* @__PURE__ */ __name((obj, path) => {
2205
+ const keys = path.split(".");
2206
+ let current = obj;
2207
+ for (const key of keys) {
2208
+ if (current == null || typeof current !== "object") return void 0;
2209
+ current = current[key];
2210
+ }
2211
+ if (typeof current === "string" && current !== "") return current;
2212
+ return void 0;
2213
+ }, "getNestedValue");
2214
+ var createTranslator = /* @__PURE__ */ __name((bundles, language, defaultLanguage = "en") => {
2215
+ const langBundle = bundles[language];
2216
+ const defaultBundle = language !== defaultLanguage ? bundles[defaultLanguage] : void 0;
2217
+ return (path, fallback) => {
2218
+ if (langBundle) {
2219
+ const value = getNestedValue(langBundle, path);
2220
+ if (value !== void 0) return value;
2221
+ }
2222
+ if (defaultBundle) {
2223
+ const value = getNestedValue(defaultBundle, path);
2224
+ if (value !== void 0) return value;
2225
+ }
2226
+ return fallback ?? path;
2227
+ };
2228
+ }, "createTranslator");
2229
+
2230
+ // ../crouton-core/src/lib/i18n/negotiate.ts
2231
+ var parseAcceptLanguage = /* @__PURE__ */ __name((header) => {
2232
+ const entries = [];
2233
+ for (const part of header.split(",")) {
2234
+ const trimmed = part.trim();
2235
+ if (!trimmed) continue;
2236
+ const [tag, ...params] = trimmed.split(";");
2237
+ let q = 1;
2238
+ for (const param of params) {
2239
+ const match = param.trim().match(/^q\s*=\s*([0-9.]+)$/);
2240
+ if (match) {
2241
+ q = parseFloat(match[1]);
2242
+ if (isNaN(q)) q = 0;
2243
+ }
2244
+ }
2245
+ entries.push({
2246
+ tag: tag.trim().toLowerCase(),
2247
+ q
2248
+ });
2249
+ }
2250
+ return entries.sort((a, b) => b.q - a.q);
2251
+ }, "parseAcceptLanguage");
2252
+ var resolveLanguage = /* @__PURE__ */ __name((acceptLanguage, supported, defaultLanguage) => {
2253
+ if (!acceptLanguage) return defaultLanguage;
2254
+ const supportedLower = supported.map((s) => s.toLowerCase());
2255
+ const entries = parseAcceptLanguage(acceptLanguage);
2256
+ for (const { tag, q } of entries) {
2257
+ if (q <= 0) continue;
2258
+ if (tag === "*") return defaultLanguage;
2259
+ const exactIdx = supportedLower.indexOf(tag);
2260
+ if (exactIdx !== -1) return supported[exactIdx];
2261
+ const base = tag.split("-")[0];
2262
+ const baseIdx = supportedLower.indexOf(base);
2263
+ if (baseIdx !== -1) return supported[baseIdx];
2264
+ }
2265
+ return defaultLanguage;
2266
+ }, "resolveLanguage");
2267
+
2156
2268
  // src/lib/crouton-api.module.ts
2157
- var import_common21 = require("@nestjs/common");
2269
+ var import_common22 = require("@nestjs/common");
2158
2270
  var import_core = require("@nestjs/core");
2159
2271
 
2160
2272
  // src/lib/crud/app-layout/app-layout.types.ts
2161
- var import_zod23 = require("zod");
2162
- var SidebarLeafSchema = import_zod23.z.object({
2163
- kind: import_zod23.z.literal("item").default("item"),
2164
- id: import_zod23.z.string(),
2165
- label: import_zod23.z.string(),
2166
- position: import_zod23.z.number().optional()
2273
+ var import_zod24 = require("zod");
2274
+ var SidebarLeafSchema = import_zod24.z.object({
2275
+ kind: import_zod24.z.literal("item").default("item"),
2276
+ id: import_zod24.z.string(),
2277
+ label: import_zod24.z.string(),
2278
+ position: import_zod24.z.number().optional()
2167
2279
  });
2168
- var SidebarGroupSchema2 = import_zod23.z.object({
2169
- kind: import_zod23.z.literal("group").default("group"),
2170
- id: import_zod23.z.string(),
2171
- label: import_zod23.z.string(),
2172
- position: import_zod23.z.number().optional(),
2173
- children: import_zod23.z.array(SidebarLeafSchema).default([])
2280
+ var SidebarGroupSchema2 = import_zod24.z.object({
2281
+ kind: import_zod24.z.literal("group").default("group"),
2282
+ id: import_zod24.z.string(),
2283
+ label: import_zod24.z.string(),
2284
+ position: import_zod24.z.number().optional(),
2285
+ children: import_zod24.z.array(SidebarLeafSchema).default([])
2174
2286
  });
2175
- var SidebarNodeSchema = import_zod23.z.discriminatedUnion("kind", [
2287
+ var SidebarNodeSchema = import_zod24.z.discriminatedUnion("kind", [
2176
2288
  SidebarLeafSchema,
2177
2289
  SidebarGroupSchema2
2178
2290
  ]);
@@ -2252,15 +2364,311 @@ var IS_DEV = parseBooleanEnv(process.env["CROUTON_SCHEMA_EDITOR"]);
2252
2364
 
2253
2365
  // src/lib/crud/resource-config.registry.ts
2254
2366
  var import_common = require("@nestjs/common");
2367
+
2368
+ // src/lib/crud/resource/ReadResourceJson.ts
2369
+ var import_node_fs = require("fs");
2370
+ var import_node_path = require("path");
2371
+ var readResourceJson = /* @__PURE__ */ __name((jsonPath) => {
2372
+ if (!(0, import_node_fs.existsSync)(jsonPath)) return void 0;
2373
+ let fileContent;
2374
+ try {
2375
+ fileContent = JSON.parse((0, import_node_fs.readFileSync)(jsonPath, "utf-8"));
2376
+ } catch (err) {
2377
+ return {
2378
+ success: false,
2379
+ error: `Invalid JSON in ${jsonPath}: ${err.message}`
2380
+ };
2381
+ }
2382
+ const resource = ResourceJsonSchema.safeParse(fileContent);
2383
+ if (resource.error) {
2384
+ return {
2385
+ success: false,
2386
+ error: `Resource cannot be parsed ${jsonPath}: ${resource.error.message}`
2387
+ };
2388
+ }
2389
+ return {
2390
+ success: true,
2391
+ data: {
2392
+ json: resource.data,
2393
+ dir: (0, import_node_path.dirname)(jsonPath)
2394
+ }
2395
+ };
2396
+ }, "readResourceJson");
2397
+
2398
+ // src/lib/crud/adapter/resource-resolver.ts
2399
+ var import_node_fs2 = require("fs");
2400
+ var import_node_path2 = require("path");
2401
+ var resolveChildResourceDetailed = /* @__PURE__ */ __name((resourcePath, parentDir) => {
2402
+ const attempted = [];
2403
+ try {
2404
+ if (resourcePath.endsWith(".json")) {
2405
+ const directPath = (0, import_node_path2.resolve)(parentDir, resourcePath);
2406
+ attempted.push(directPath);
2407
+ if ((0, import_node_fs2.existsSync)(directPath)) {
2408
+ const result2 = readResourceJson(directPath);
2409
+ if (result2?.success) return {
2410
+ ok: true,
2411
+ value: result2.data
2412
+ };
2413
+ return {
2414
+ ok: false,
2415
+ reason: "invalid",
2416
+ error: result2?.error ?? `Could not read ${directPath}`
2417
+ };
2418
+ }
2419
+ }
2420
+ const childName = resourcePath.replace(/^\.\//, "").replace(/\.resource$/, "");
2421
+ const childJsonPath = (0, import_node_path2.resolve)((0, import_node_path2.dirname)(parentDir), childName, "resource.json");
2422
+ attempted.push(childJsonPath);
2423
+ const result = readResourceJson(childJsonPath);
2424
+ if (result?.success) return {
2425
+ ok: true,
2426
+ value: result.data
2427
+ };
2428
+ if (result) return {
2429
+ ok: false,
2430
+ reason: "invalid",
2431
+ error: result.error
2432
+ };
2433
+ return {
2434
+ ok: false,
2435
+ reason: "missing",
2436
+ attempted
2437
+ };
2438
+ } catch (err) {
2439
+ return {
2440
+ ok: false,
2441
+ reason: "invalid",
2442
+ error: err.message
2443
+ };
2444
+ }
2445
+ }, "resolveChildResourceDetailed");
2446
+ var resolveChildResource = /* @__PURE__ */ __name((resourcePath, parentDir) => {
2447
+ const resolution = resolveChildResourceDetailed(resourcePath, parentDir);
2448
+ return resolution.ok ? resolution.value : void 0;
2449
+ }, "resolveChildResource");
2450
+
2451
+ // src/lib/crud/adapter/column-transforms.ts
2452
+ var expandExtendColumns = /* @__PURE__ */ __name((columns, dirPath) => {
2453
+ if (!dirPath) return columns;
2454
+ const result = [];
2455
+ for (const col of columns) {
2456
+ if (!col.extend) {
2457
+ result.push(col);
2458
+ continue;
2459
+ }
2460
+ const resolved = resolveChildResource(col.extend, dirPath);
2461
+ if (!resolved) {
2462
+ console.warn(`[extend] Could not resolve "${col.extend}" for column "${col.id}" \u2014 keeping as-is`);
2463
+ result.push(col);
2464
+ continue;
2465
+ }
2466
+ const refColumns = resolved.json.columns;
2467
+ const parentColumnKey = col.column ?? col.id;
2468
+ for (const refCol of refColumns) {
2469
+ if (refCol.idField) continue;
2470
+ const virtualId = `${col.id}_${refCol.id}`;
2471
+ const displayKey = refCol.displayKey ? `${refCol.id}.${refCol.displayKey}` : refCol.id;
2472
+ const hiddenInTable = col.hiddenInTable === true || refCol.hiddenInTable === true ? true : col.hiddenInTable ?? refCol.hiddenInTable;
2473
+ const hiddenInForm = col.hiddenInForm === true || refCol.hiddenInForm === true ? true : col.hiddenInForm ?? refCol.hiddenInForm;
2474
+ const hiddenInView = col.hiddenInView === true || refCol.hiddenInView === true ? true : col.hiddenInView ?? refCol.hiddenInView;
2475
+ const override = col.columns?.[virtualId] ?? col.columns?.[refCol.id] ?? {};
2476
+ const virtualCol = {
2477
+ id: virtualId,
2478
+ column: parentColumnKey,
2479
+ displayKey,
2480
+ label: refCol.label ?? refCol.id,
2481
+ columnType: "object",
2482
+ ...hiddenInTable !== void 0 && {
2483
+ hiddenInTable
2484
+ },
2485
+ ...hiddenInForm !== void 0 && {
2486
+ hiddenInForm
2487
+ },
2488
+ ...hiddenInView !== void 0 && {
2489
+ hiddenInView
2490
+ },
2491
+ ...refCol.sortable != null && {
2492
+ sortable: refCol.sortable
2493
+ },
2494
+ ...refCol.fieldInput && {
2495
+ fieldInput: refCol.fieldInput
2496
+ },
2497
+ ...override
2498
+ };
2499
+ result.push(virtualCol);
2500
+ }
2501
+ }
2502
+ return result;
2503
+ }, "expandExtendColumns");
2504
+ var buildValueLabelColumns = /* @__PURE__ */ __name((columns) => (columns ?? []).flatMap((c) => {
2505
+ const opts = c.fieldInput?.options;
2506
+ if (!opts?.emitObject || !Array.isArray(opts.values)) return [];
2507
+ return [
2508
+ {
2509
+ field: c.column ?? c.id,
2510
+ values: opts.values,
2511
+ ...c.enum && {
2512
+ enumName: c.enum
2513
+ }
2514
+ }
2515
+ ];
2516
+ }), "buildValueLabelColumns");
2517
+ var applyRelationFormatDefault = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
2518
+ const fi = col.fieldInput;
2519
+ if (fi && fi.resource && !fi.format && !fi.type) {
2520
+ return {
2521
+ ...col,
2522
+ fieldInput: {
2523
+ ...fi,
2524
+ format: "relation"
2525
+ }
2526
+ };
2527
+ }
2528
+ return col;
2529
+ }), "applyRelationFormatDefault");
2530
+ var resolveColumnFieldVariants = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
2531
+ const fieldView = resolveViewField(col);
2532
+ const fieldTable = resolveTableField(col);
2533
+ return {
2534
+ ...col,
2535
+ ...fieldView && {
2536
+ fieldView
2537
+ },
2538
+ ...fieldTable && {
2539
+ fieldTable
2540
+ }
2541
+ };
2542
+ }), "resolveColumnFieldVariants");
2543
+
2544
+ // src/lib/crud/translation/localize-resource.ts
2545
+ var clone = /* @__PURE__ */ __name((obj) => JSON.parse(JSON.stringify(obj)), "clone");
2546
+ var translateEnumOptions = /* @__PURE__ */ __name((columns, t) => {
2547
+ if (!columns) return;
2548
+ for (const col of columns) {
2549
+ if (!col.enum) continue;
2550
+ const opts = col.fieldInput?.options;
2551
+ if (!Array.isArray(opts?.values)) continue;
2552
+ for (const entry of opts.values) {
2553
+ entry.label = t(enumKey(col.enum, String(entry.value)), entry.label);
2554
+ }
2555
+ }
2556
+ }, "translateEnumOptions");
2557
+ var translateValueLabelEntries = /* @__PURE__ */ __name((vlCols, t) => {
2558
+ if (!vlCols) return;
2559
+ for (const vlc of vlCols) {
2560
+ if (!vlc.enumName) continue;
2561
+ for (const entry of vlc.values) {
2562
+ entry.label = t(enumKey(vlc.enumName, String(entry.value)), entry.label);
2563
+ }
2564
+ }
2565
+ }, "translateValueLabelEntries");
2566
+ var patchViewTitles = /* @__PURE__ */ __name((views, columnLabels) => {
2567
+ if (!views) return views;
2568
+ const patched = {};
2569
+ for (const [viewName, view] of Object.entries(views)) {
2570
+ const patchedView = clone(view);
2571
+ const props = patchedView.json_schema?.properties;
2572
+ if (props && typeof props === "object") {
2573
+ for (const [key, prop] of Object.entries(props)) {
2574
+ const translated = columnLabels.get(key);
2575
+ if (translated && prop && typeof prop === "object") {
2576
+ prop.title = translated;
2577
+ }
2578
+ }
2579
+ }
2580
+ if (patchedView.columns) {
2581
+ patchedView.columns = patchedView.columns.map((vc) => {
2582
+ const translated = columnLabels.get(vc.id);
2583
+ return translated ? {
2584
+ ...vc,
2585
+ label: translated
2586
+ } : vc;
2587
+ });
2588
+ }
2589
+ patched[viewName] = patchedView;
2590
+ }
2591
+ return patched;
2592
+ }, "patchViewTitles");
2593
+ var localizeResource = /* @__PURE__ */ __name((config, t) => {
2594
+ const name = config.name;
2595
+ const localized = clone(config);
2596
+ localized.title = t(resourceTitleKey(name), config.title ?? config.tag);
2597
+ if (localized.sidebar) {
2598
+ const sidebarTranslation = t(resourceSidebarKey(name), config.sidebar?.label);
2599
+ if (sidebarTranslation !== resourceSidebarKey(name)) {
2600
+ localized.sidebar = {
2601
+ ...localized.sidebar,
2602
+ label: sidebarTranslation
2603
+ };
2604
+ }
2605
+ }
2606
+ const columnLabels = /* @__PURE__ */ new Map();
2607
+ const columns = localized.columns;
2608
+ if (columns) {
2609
+ for (const col of columns) {
2610
+ const translated = t(columnKey(name, col.id), col.label ?? col.id);
2611
+ col.label = translated;
2612
+ columnLabels.set(col.id, translated);
2613
+ }
2614
+ translateEnumOptions(columns, t);
2615
+ localized.valueLabelColumns = buildValueLabelColumns(columns);
2616
+ }
2617
+ if (localized.views) {
2618
+ localized.views = patchViewTitles(localized.views, columnLabels);
2619
+ }
2620
+ if (localized.actions) {
2621
+ for (const a of localized.actions) {
2622
+ a.label = t(actionKey(name, a.id), a.label);
2623
+ }
2624
+ }
2625
+ if (localized.tableActions) {
2626
+ for (const a of localized.tableActions) {
2627
+ a.label = t(actionKey(name, a.id), a.label);
2628
+ }
2629
+ }
2630
+ if (localized.subResources) {
2631
+ for (const sub of localized.subResources) {
2632
+ const subName = sub.name ?? sub.childRoute;
2633
+ sub.title = t(subResourceTitleKey(name, subName), sub.title ?? subName);
2634
+ const subColumnLabels = /* @__PURE__ */ new Map();
2635
+ if (sub.views) {
2636
+ for (const view of Object.values(sub.views)) {
2637
+ if (view.columns) {
2638
+ for (const vc of view.columns) {
2639
+ const translated = t(subResourceColumnKey(name, subName, vc.id), vc.label ?? vc.id);
2640
+ vc.label = translated;
2641
+ subColumnLabels.set(vc.id, translated);
2642
+ }
2643
+ }
2644
+ }
2645
+ sub.views = patchViewTitles(sub.views, subColumnLabels);
2646
+ }
2647
+ translateValueLabelEntries(sub.valueLabelColumns, t);
2648
+ }
2649
+ }
2650
+ return localized;
2651
+ }, "localizeResource");
2652
+
2653
+ // src/lib/crud/resource-config.registry.ts
2255
2654
  function _ts_decorate(decorators, target, key, desc2) {
2256
2655
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
2257
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
2258
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2656
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2657
+ r = Reflect.decorate(decorators, target, key, desc2);
2658
+ } else {
2659
+ for (var i = decorators.length - 1; i >= 0; i--) {
2660
+ if (d = decorators[i]) {
2661
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2662
+ }
2663
+ }
2664
+ }
2259
2665
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2260
2666
  }
2261
2667
  __name(_ts_decorate, "_ts_decorate");
2262
- function _ts_metadata(k, v) {
2263
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2668
+ function _ts_metadata(metadataKey, metadataValue) {
2669
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2670
+ return Reflect.metadata(metadataKey, metadataValue);
2671
+ }
2264
2672
  }
2265
2673
  __name(_ts_metadata, "_ts_metadata");
2266
2674
  var ResourceConfigRegistry = class {
@@ -2269,21 +2677,45 @@ var ResourceConfigRegistry = class {
2269
2677
  }
2270
2678
  loader;
2271
2679
  configs;
2680
+ translationRegistry;
2681
+ /**
2682
+ * Per-language memo: `Map<language, Map<route, Resource>>`.
2683
+ * Cleared whenever the underlying configs reload (dev mode).
2684
+ */
2685
+ localizedCache = /* @__PURE__ */ new Map();
2272
2686
  constructor(loader, initialConfigs) {
2273
2687
  this.loader = loader;
2274
2688
  this.configs = initialConfigs;
2275
2689
  }
2276
- async getAll() {
2690
+ setTranslationRegistry(registry) {
2691
+ this.translationRegistry = registry;
2692
+ }
2693
+ async getAll(language) {
2277
2694
  if (IS_DEV) {
2278
2695
  this.configs = await this.loader.loadAll();
2696
+ this.localizedCache.clear();
2697
+ }
2698
+ if (!language || !this.translationRegistry?.active) {
2699
+ return this.configs;
2279
2700
  }
2280
- return this.configs;
2701
+ return this.configs.map((c) => this.getLocalized(c, language));
2281
2702
  }
2282
- async getByRoute(route) {
2703
+ async getByRoute(route, language) {
2283
2704
  if (IS_DEV) {
2284
- return this.loader.loadByRoute(route);
2705
+ const fresh = await this.loader.loadByRoute(route);
2706
+ this.localizedCache.clear();
2707
+ if (!fresh) return void 0;
2708
+ if (language && this.translationRegistry?.active) {
2709
+ return this.localize(fresh, language);
2710
+ }
2711
+ return fresh;
2285
2712
  }
2286
- return this.configs.find((c) => c.route === route);
2713
+ const config = this.configs.find((c) => c.route === route);
2714
+ if (!config) return void 0;
2715
+ if (language && this.translationRegistry?.active) {
2716
+ return this.getLocalized(config, language);
2717
+ }
2718
+ return config;
2287
2719
  }
2288
2720
  /**
2289
2721
  * On-disk directory containing `route`'s `resource.json`, if known.
@@ -2294,6 +2726,24 @@ var ResourceConfigRegistry = class {
2294
2726
  getResourceDir(route) {
2295
2727
  return this.loader.getResourceDir(route);
2296
2728
  }
2729
+ getLocalized(config, language) {
2730
+ let langMap = this.localizedCache.get(language);
2731
+ if (!langMap) {
2732
+ langMap = /* @__PURE__ */ new Map();
2733
+ this.localizedCache.set(language, langMap);
2734
+ }
2735
+ let localized = langMap.get(config.route);
2736
+ if (!localized) {
2737
+ localized = this.localize(config, language);
2738
+ langMap.set(config.route, localized);
2739
+ }
2740
+ return localized;
2741
+ }
2742
+ localize(config, language) {
2743
+ if (!this.translationRegistry) return config;
2744
+ const t = this.translationRegistry.translatorFor(language);
2745
+ return localizeResource(config, t);
2746
+ }
2297
2747
  };
2298
2748
  ResourceConfigRegistry = _ts_decorate([
2299
2749
  (0, import_common.Injectable)(),
@@ -2304,19 +2754,34 @@ ResourceConfigRegistry = _ts_decorate([
2304
2754
  ])
2305
2755
  ], ResourceConfigRegistry);
2306
2756
 
2757
+ // src/lib/crud/translation/language.context.ts
2758
+ var import_node_async_hooks = require("async_hooks");
2759
+ var languageStore = new import_node_async_hooks.AsyncLocalStorage();
2760
+ var runWithLanguage = /* @__PURE__ */ __name((language, fn) => languageStore.run(language, fn), "runWithLanguage");
2761
+ var getRequestLanguage = /* @__PURE__ */ __name((defaultLanguage = "en") => languageStore.getStore() ?? defaultLanguage, "getRequestLanguage");
2762
+
2307
2763
  // src/lib/crud/app-layout/app-layout.controller.ts
2308
2764
  function _ts_decorate2(decorators, target, key, desc2) {
2309
2765
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
2310
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
2311
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2766
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
2767
+ r = Reflect.decorate(decorators, target, key, desc2);
2768
+ } else {
2769
+ for (var i = decorators.length - 1; i >= 0; i--) {
2770
+ if (d = decorators[i]) {
2771
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
2772
+ }
2773
+ }
2774
+ }
2312
2775
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2313
2776
  }
2314
2777
  __name(_ts_decorate2, "_ts_decorate");
2315
- function _ts_metadata2(k, v) {
2316
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
2778
+ function _ts_metadata2(metadataKey, metadataValue) {
2779
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
2780
+ return Reflect.metadata(metadataKey, metadataValue);
2781
+ }
2317
2782
  }
2318
2783
  __name(_ts_metadata2, "_ts_metadata");
2319
- var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups = {}, title, autoSave = true) => {
2784
+ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups = {}, title, autoSave = true, translationRegistry, i18nConfig) => {
2320
2785
  const layoutPayload = buildLayoutPayload(configs, sidebarGroups, title, autoSave, IS_DEV);
2321
2786
  let AppLayoutController = class AppLayoutController {
2322
2787
  static {
@@ -2327,11 +2792,44 @@ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups =
2327
2792
  this.configRegistry = configRegistry;
2328
2793
  }
2329
2794
  async getLayout() {
2330
- if (IS_DEV) {
2331
- const fresh = await this.configRegistry.getAll();
2332
- return buildLayoutPayload(fresh, sidebarGroups, title, autoSave, IS_DEV);
2795
+ const language = getRequestLanguage();
2796
+ let payload;
2797
+ if (IS_DEV || language) {
2798
+ const fresh = await this.configRegistry.getAll(language);
2799
+ payload = buildLayoutPayload(fresh, language ? translateSidebarGroups(sidebarGroups, language, translationRegistry) : sidebarGroups, language ? translateTitle(title, language, translationRegistry) : title, autoSave, IS_DEV);
2800
+ } else {
2801
+ payload = layoutPayload;
2333
2802
  }
2334
- return layoutPayload;
2803
+ if (translationRegistry?.active && i18nConfig) {
2804
+ const lang = language ?? i18nConfig.defaultLanguage;
2805
+ const bundle = translationRegistry.bundleFor(lang);
2806
+ return {
2807
+ ...payload,
2808
+ i18n: {
2809
+ languages: i18nConfig.languages,
2810
+ defaultLanguage: i18nConfig.defaultLanguage,
2811
+ current: lang
2812
+ },
2813
+ ...bundle.ui && {
2814
+ ui: bundle.ui
2815
+ }
2816
+ };
2817
+ }
2818
+ return payload;
2819
+ }
2820
+ getTranslations() {
2821
+ if (!translationRegistry?.active || !i18nConfig) {
2822
+ return {
2823
+ ui: {},
2824
+ validation: {}
2825
+ };
2826
+ }
2827
+ const language = getRequestLanguage() ?? i18nConfig.defaultLanguage;
2828
+ const bundle = translationRegistry.bundleFor(language);
2829
+ return {
2830
+ ui: bundle.ui ?? {},
2831
+ validation: bundle.validation ?? {}
2832
+ };
2335
2833
  }
2336
2834
  };
2337
2835
  _ts_decorate2([
@@ -2347,6 +2845,19 @@ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups =
2347
2845
  _ts_metadata2("design:paramtypes", []),
2348
2846
  _ts_metadata2("design:returntype", Promise)
2349
2847
  ], AppLayoutController.prototype, "getLayout", null);
2848
+ _ts_decorate2([
2849
+ (0, import_common2.Get)("translations"),
2850
+ (0, import_swagger.ApiOperation)({
2851
+ summary: "Get ui + validation translation dictionaries"
2852
+ }),
2853
+ (0, import_swagger.ApiResponse)({
2854
+ status: 200,
2855
+ description: "Translation dictionaries for the current language"
2856
+ }),
2857
+ _ts_metadata2("design:type", Function),
2858
+ _ts_metadata2("design:paramtypes", []),
2859
+ _ts_metadata2("design:returntype", void 0)
2860
+ ], AppLayoutController.prototype, "getTranslations", null);
2350
2861
  AppLayoutController = _ts_decorate2([
2351
2862
  (0, import_common2.Controller)("_app"),
2352
2863
  (0, import_swagger.ApiTags)("App"),
@@ -2360,10 +2871,28 @@ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups =
2360
2871
  ], AppLayoutController);
2361
2872
  return AppLayoutController;
2362
2873
  }, "createAppLayoutController");
2874
+ var translateSidebarGroups = /* @__PURE__ */ __name((groups, language, registry) => {
2875
+ if (!registry?.active) return groups;
2876
+ const t = registry.translatorFor(language);
2877
+ const translated = {};
2878
+ for (const [slug, cfg] of Object.entries(groups)) {
2879
+ const label = t(sidebarGroupKey(slug), cfg.label);
2880
+ translated[slug] = label !== cfg.label ? {
2881
+ ...cfg,
2882
+ label
2883
+ } : cfg;
2884
+ }
2885
+ return translated;
2886
+ }, "translateSidebarGroups");
2887
+ var translateTitle = /* @__PURE__ */ __name((title, language, registry) => {
2888
+ if (!title || !registry?.active) return title;
2889
+ const t = registry.translatorFor(language);
2890
+ return t("app.title", title);
2891
+ }, "translateTitle");
2363
2892
 
2364
2893
  // src/lib/crud/config/read.ts
2365
2894
  var import_promises = require("fs/promises");
2366
- var import_node_path = require("path");
2895
+ var import_node_path3 = require("path");
2367
2896
  var fileExists = /* @__PURE__ */ __name(async (p) => {
2368
2897
  try {
2369
2898
  await (0, import_promises.access)(p);
@@ -2373,19 +2902,19 @@ var fileExists = /* @__PURE__ */ __name(async (p) => {
2373
2902
  }
2374
2903
  }, "fileExists");
2375
2904
  var findConfigPath = /* @__PURE__ */ __name(async (cwd) => {
2376
- let dir = (0, import_node_path.resolve)(cwd);
2905
+ let dir = (0, import_node_path3.resolve)(cwd);
2377
2906
  while (true) {
2378
2907
  for (const name of CONFIG_FILES) {
2379
- const candidate = (0, import_node_path.join)(dir, name);
2908
+ const candidate = (0, import_node_path3.join)(dir, name);
2380
2909
  if (await fileExists(candidate)) return candidate;
2381
2910
  }
2382
- const parent = (0, import_node_path.dirname)(dir);
2911
+ const parent = (0, import_node_path3.dirname)(dir);
2383
2912
  if (parent === dir) return void 0;
2384
2913
  dir = parent;
2385
2914
  }
2386
2915
  }, "findConfigPath");
2387
2916
  var loadConfig = /* @__PURE__ */ __name(async () => {
2388
- const cwd = (0, import_node_path.resolve)(process.cwd());
2917
+ const cwd = (0, import_node_path3.resolve)(process.cwd());
2389
2918
  const path = await findConfigPath(cwd);
2390
2919
  if (!path) {
2391
2920
  throw new Error(`No crouton config found (looked for ${CONFIG_FILES.join(", ")} up from ${cwd}).`);
@@ -2415,77 +2944,187 @@ var CroutonValidationError = class extends Error {
2415
2944
  }
2416
2945
  };
2417
2946
 
2947
+ // src/lib/crud/translation/translation.loader.ts
2948
+ var import_node_fs3 = require("fs");
2949
+ var import_node_path4 = require("path");
2950
+ var loadTranslationBundles = /* @__PURE__ */ __name((translationsDir) => {
2951
+ if (!(0, import_node_fs3.existsSync)(translationsDir)) return {};
2952
+ const bundles = {};
2953
+ const entries = (0, import_node_fs3.readdirSync)(translationsDir, {
2954
+ withFileTypes: true
2955
+ });
2956
+ for (const entry of entries) {
2957
+ if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
2958
+ const lang = entry.name.replace(/\.json$/, "");
2959
+ try {
2960
+ bundles[lang] = JSON.parse((0, import_node_fs3.readFileSync)((0, import_node_path4.join)(translationsDir, entry.name), "utf-8"));
2961
+ } catch {
2962
+ }
2963
+ }
2964
+ return bundles;
2965
+ }, "loadTranslationBundles");
2966
+
2967
+ // src/lib/crud/translation/translation.registry.ts
2968
+ var TranslationRegistry2 = class {
2969
+ static {
2970
+ __name(this, "TranslationRegistry");
2971
+ }
2972
+ translationsDir;
2973
+ i18nConfig;
2974
+ bundles;
2975
+ constructor(translationsDir, i18nConfig) {
2976
+ this.translationsDir = translationsDir;
2977
+ this.i18nConfig = i18nConfig;
2978
+ this.bundles = loadTranslationBundles(translationsDir);
2979
+ }
2980
+ get languages() {
2981
+ return this.i18nConfig.languages;
2982
+ }
2983
+ get defaultLanguage() {
2984
+ return this.i18nConfig.defaultLanguage;
2985
+ }
2986
+ /** Whether i18n is active (at least one bundle loaded). */
2987
+ get active() {
2988
+ return Object.keys(this.bundles).length > 0;
2989
+ }
2990
+ translatorFor(language) {
2991
+ if (IS_DEV) {
2992
+ this.bundles = loadTranslationBundles(this.translationsDir);
2993
+ }
2994
+ return createTranslator(this.bundles, language, this.i18nConfig.defaultLanguage);
2995
+ }
2996
+ /** Raw bundle for a language (falls back to default). */
2997
+ bundleFor(language) {
2998
+ if (IS_DEV) {
2999
+ this.bundles = loadTranslationBundles(this.translationsDir);
3000
+ }
3001
+ return this.bundles[language] ?? this.bundles[this.i18nConfig.defaultLanguage] ?? {};
3002
+ }
3003
+ };
3004
+
2418
3005
  // src/lib/crud/crouton-validation.filter.ts
2419
3006
  function _ts_decorate3(decorators, target, key, desc2) {
2420
3007
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
2421
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
2422
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3008
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
3009
+ r = Reflect.decorate(decorators, target, key, desc2);
3010
+ } else {
3011
+ for (var i = decorators.length - 1; i >= 0; i--) {
3012
+ if (d = decorators[i]) {
3013
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3014
+ }
3015
+ }
3016
+ }
2423
3017
  return c > 3 && r && Object.defineProperty(target, key, r), r;
2424
3018
  }
2425
3019
  __name(_ts_decorate3, "_ts_decorate");
3020
+ function _ts_metadata3(metadataKey, metadataValue) {
3021
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
3022
+ return Reflect.metadata(metadataKey, metadataValue);
3023
+ }
3024
+ }
3025
+ __name(_ts_metadata3, "_ts_metadata");
3026
+ function _ts_param(paramIndex, decorator) {
3027
+ return function(target, key) {
3028
+ decorator(target, key, paramIndex);
3029
+ };
3030
+ }
3031
+ __name(_ts_param, "_ts_param");
2426
3032
  var CroutonValidationExceptionFilter = class {
2427
3033
  static {
2428
3034
  __name(this, "CroutonValidationExceptionFilter");
2429
3035
  }
3036
+ translationRegistry;
3037
+ constructor(translationRegistry) {
3038
+ this.translationRegistry = translationRegistry;
3039
+ }
2430
3040
  catch(exception, host) {
2431
3041
  const res = host.switchToHttp().getResponse();
3042
+ const errors = this.translateErrors(exception.errors);
2432
3043
  res.status(400).json({
2433
3044
  statusCode: 400,
2434
- message: exception.errors,
3045
+ message: errors,
2435
3046
  error: "Bad Request"
2436
3047
  });
2437
3048
  }
3049
+ translateErrors(errors) {
3050
+ if (!this.translationRegistry) return errors;
3051
+ const language = getRequestLanguage();
3052
+ if (!language) return errors;
3053
+ const t = this.translationRegistry.translatorFor(language);
3054
+ return errors.map(({ field, message, code }) => {
3055
+ if (!code) return {
3056
+ field,
3057
+ message
3058
+ };
3059
+ const key = validationKey(code);
3060
+ const translated = t(key, "");
3061
+ if (!translated) return {
3062
+ field,
3063
+ message
3064
+ };
3065
+ return {
3066
+ field,
3067
+ message: translated.replace(/\{field\}/g, field)
3068
+ };
3069
+ });
3070
+ }
2438
3071
  };
2439
3072
  CroutonValidationExceptionFilter = _ts_decorate3([
2440
- (0, import_common3.Catch)(CroutonValidationError)
3073
+ (0, import_common3.Catch)(CroutonValidationError),
3074
+ _ts_param(0, (0, import_common3.Optional)()),
3075
+ _ts_param(0, (0, import_common3.Inject)(TranslationRegistry2)),
3076
+ _ts_metadata3("design:type", Function),
3077
+ _ts_metadata3("design:paramtypes", [
3078
+ typeof TranslationRegistry2 === "undefined" ? Object : TranslationRegistry2
3079
+ ])
2441
3080
  ], CroutonValidationExceptionFilter);
2442
3081
 
2443
3082
  // src/lib/crud/crud-controller.factory.ts
2444
- var import_common18 = require("@nestjs/common");
3083
+ var import_common19 = require("@nestjs/common");
2445
3084
  var import_swagger11 = require("@nestjs/swagger");
2446
3085
 
2447
3086
  // src/lib/crud/action/action.types.ts
2448
- var import_zod24 = require("zod");
2449
- var ActionMetadataSchema = import_zod24.z.object({
3087
+ var import_zod25 = require("zod");
3088
+ var ActionMetadataSchema = import_zod25.z.object({
2450
3089
  /** URL segment used in the endpoint. */
2451
- id: import_zod24.z.string(),
3090
+ id: import_zod25.z.string(),
2452
3091
  /** Human-readable label shown as a button. */
2453
- label: import_zod24.z.string().optional(),
3092
+ label: import_zod25.z.string().optional(),
2454
3093
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
2455
- icon: import_zod24.z.string().optional(),
3094
+ icon: import_zod25.z.string().optional(),
2456
3095
  /** Tooltip text. Falls back to `label` when omitted. */
2457
- tooltip: import_zod24.z.string().optional(),
3096
+ tooltip: import_zod25.z.string().optional(),
2458
3097
  /** Per-row condition — button is hidden when false. */
2459
- condition: import_zod24.z.custom().optional()
3098
+ condition: import_zod25.z.custom().optional()
2460
3099
  });
2461
3100
  var ResourceLinkActionSchema = ActionMetadataSchema.extend({
2462
- type: import_zod24.z.literal("link"),
3101
+ type: import_zod25.z.literal("link"),
2463
3102
  /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */
2464
- href: import_zod24.z.string()
3103
+ href: import_zod25.z.string()
2465
3104
  });
2466
3105
  var ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
2467
- type: import_zod24.z.literal("procedure").optional(),
3106
+ type: import_zod25.z.literal("procedure").optional(),
2468
3107
  /** HTTP method for the endpoint. Defaults to `"post"`. */
2469
- method: import_zod24.z.string().optional(),
3108
+ method: import_zod25.z.string().optional(),
2470
3109
  /** Static data payload merged into the request body by the frontend. */
2471
- data: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.unknown()).optional(),
3110
+ data: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.unknown()).optional(),
2472
3111
  /** Procedure called with `(prisma, recordId)`. */
2473
- procedure: import_zod24.z.custom((v) => typeof v === "function")
3112
+ procedure: import_zod25.z.custom((v) => typeof v === "function")
2474
3113
  });
2475
3114
  var ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
2476
- type: import_zod24.z.literal("procedure").optional(),
3115
+ type: import_zod25.z.literal("procedure").optional(),
2477
3116
  /** HTTP method for the endpoint. Defaults to `"post"`. */
2478
- method: import_zod24.z.string().optional(),
3117
+ method: import_zod25.z.string().optional(),
2479
3118
  /** Static data payload merged into the request body by the frontend. */
2480
- data: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.unknown()).optional(),
3119
+ data: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.unknown()).optional(),
2481
3120
  /** Procedure called with `(prisma)` — no record id. */
2482
- procedure: import_zod24.z.custom((v) => typeof v === "function")
3121
+ procedure: import_zod25.z.custom((v) => typeof v === "function")
2483
3122
  });
2484
- var ResourceRowActionSchema = import_zod24.z.union([
3123
+ var ResourceRowActionSchema = import_zod25.z.union([
2485
3124
  ResourceRowProcedureActionSchema,
2486
3125
  ResourceLinkActionSchema
2487
3126
  ]);
2488
- var ResourceTableActionSchema = import_zod24.z.union([
3127
+ var ResourceTableActionSchema = import_zod25.z.union([
2489
3128
  ResourceTableProcedureActionSchema,
2490
3129
  ResourceLinkActionSchema
2491
3130
  ]);
@@ -2493,17 +3132,17 @@ var isRowProcedureAction = /* @__PURE__ */ __name((action) => action.type !== "l
2493
3132
  var isTableProcedureAction = /* @__PURE__ */ __name((action) => action.type !== "link", "isTableProcedureAction");
2494
3133
 
2495
3134
  // src/lib/crud/loader/module.loader.ts
2496
- var import_node_fs = require("fs");
3135
+ var import_node_fs4 = require("fs");
2497
3136
  var import_node_module = require("module");
2498
- var import_node_path2 = require("path");
3137
+ var import_node_path5 = require("path");
2499
3138
  var _require = (0, import_node_module.createRequire)(importMetaUrl ?? __filename);
2500
3139
  var findModule = /* @__PURE__ */ __name((dir, name) => {
2501
3140
  for (const ext of [
2502
3141
  ".ts",
2503
3142
  ".js"
2504
3143
  ]) {
2505
- const p = (0, import_node_path2.join)(dir, `${name}${ext}`);
2506
- if ((0, import_node_fs.existsSync)(p)) return p;
3144
+ const p = (0, import_node_path5.join)(dir, `${name}${ext}`);
3145
+ if ((0, import_node_fs4.existsSync)(p)) return p;
2507
3146
  }
2508
3147
  return void 0;
2509
3148
  }, "findModule");
@@ -2526,7 +3165,7 @@ var importDefault = /* @__PURE__ */ __name(async (filePath, onError) => {
2526
3165
  }, "importDefault");
2527
3166
 
2528
3167
  // src/lib/crud/action/action.loader.ts
2529
- var import_node_path3 = require("path");
3168
+ var import_node_path6 = require("path");
2530
3169
  var loadActions = /* @__PURE__ */ __name(async (jsonActions, basePath, scope) => {
2531
3170
  const tag = scope === "row" ? "actions" : "tableActions";
2532
3171
  const results = [];
@@ -2535,7 +3174,7 @@ var loadActions = /* @__PURE__ */ __name(async (jsonActions, basePath, scope) =>
2535
3174
  results.push(action);
2536
3175
  continue;
2537
3176
  }
2538
- const file = findModule((0, import_node_path3.join)(basePath, "actions"), action.procedure);
3177
+ const file = findModule((0, import_node_path6.join)(basePath, "actions"), action.procedure);
2539
3178
  if (!file) {
2540
3179
  console.warn(`[${tag}] Procedure file not found for "${action.id}" in ${basePath}/actions/`);
2541
3180
  continue;
@@ -2567,7 +3206,7 @@ var schemaFor = /* @__PURE__ */ __name((def2, op) => {
2567
3206
  var upsertOnFor = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
2568
3207
 
2569
3208
  // src/lib/crud/custom-repository/custom-repository.types.ts
2570
- var import_zod25 = require("zod");
3209
+ var import_zod26 = require("zod");
2571
3210
  var CUSTOM_OPS = [
2572
3211
  "findAll",
2573
3212
  "findOne",
@@ -2584,7 +3223,7 @@ var PARENT_METHOD = {
2584
3223
  patch: "patchByParent",
2585
3224
  delete: "deleteByParent"
2586
3225
  };
2587
- var CustomRepositorySchema = import_zod25.z.custom((value) => typeof value === "object" && value !== null);
3226
+ var CustomRepositorySchema = import_zod26.z.custom((value) => typeof value === "object" && value !== null);
2588
3227
 
2589
3228
  // src/lib/crud/resource/resource-load-errors.registry.ts
2590
3229
  var ResourceLoadErrorsRegistry = class ResourceLoadErrorsRegistry2 {
@@ -2650,7 +3289,7 @@ var loadSubResourceRepositories = /* @__PURE__ */ __name(async (subResources, pa
2650
3289
  }, "loadSubResourceRepositories");
2651
3290
 
2652
3291
  // src/lib/crud/custom-repository/custom-repository.adapter.ts
2653
- var import_common4 = require("@nestjs/common");
3292
+ var import_common5 = require("@nestjs/common");
2654
3293
 
2655
3294
  // src/lib/crud/constants.ts
2656
3295
  var PRISMA_NOT_FOUND_CODE = "P2025";
@@ -2658,33 +3297,33 @@ var DEFAULT_ID_TYPE = "string";
2658
3297
  var DEFAULT_ID_FIELD = "id";
2659
3298
 
2660
3299
  // src/lib/crud/hooks/hooks.types.ts
2661
- var import_zod26 = require("zod");
2662
- var WriteOpSchema = import_zod26.z.enum([
3300
+ var import_zod27 = require("zod");
3301
+ var WriteOpSchema = import_zod27.z.enum([
2663
3302
  "create",
2664
3303
  "update",
2665
3304
  "patch",
2666
3305
  "upsert",
2667
3306
  "delete"
2668
3307
  ]);
2669
- var ReadOpSchema = import_zod26.z.enum([
3308
+ var ReadOpSchema = import_zod27.z.enum([
2670
3309
  "findAll",
2671
3310
  "findOne"
2672
3311
  ]);
2673
- var ResourceHooksSchema = import_zod26.z.object({
2674
- beforeWrite: import_zod26.z.custom().optional(),
2675
- afterWrite: import_zod26.z.custom().optional(),
2676
- afterRead: import_zod26.z.custom().optional()
3312
+ var ResourceHooksSchema = import_zod27.z.object({
3313
+ beforeWrite: import_zod27.z.custom().optional(),
3314
+ afterWrite: import_zod27.z.custom().optional(),
3315
+ afterRead: import_zod27.z.custom().optional()
2677
3316
  });
2678
3317
 
2679
3318
  // src/lib/crud/hooks/hooks.loader.ts
2680
- var import_node_path4 = require("path");
3319
+ var import_node_path7 = require("path");
2681
3320
  var loadResourceHooks = /* @__PURE__ */ __name(async (basePath) => {
2682
3321
  const file = findModule(basePath, "hooks");
2683
3322
  return file ? importDefault(file) : void 0;
2684
3323
  }, "loadResourceHooks");
2685
3324
  var loadSubResourceHooks = /* @__PURE__ */ __name(async (subResources, basePath) => {
2686
3325
  for (const sub of subResources) {
2687
- const file = (sub.name ? findModule((0, import_node_path4.join)(basePath, "hooks"), sub.name) : void 0) ?? (sub.childDir ? findModule(sub.childDir, "hooks") : void 0);
3326
+ const file = (sub.name ? findModule((0, import_node_path7.join)(basePath, "hooks"), sub.name) : void 0) ?? (sub.childDir ? findModule(sub.childDir, "hooks") : void 0);
2688
3327
  if (!file) continue;
2689
3328
  const hooks = await importDefault(file);
2690
3329
  if (hooks) sub.hooks = hooks;
@@ -2764,12 +3403,73 @@ var postWrite = /* @__PURE__ */ __name(async (result, op, target, prisma, id, re
2764
3403
  }) : result;
2765
3404
  }, "postWrite");
2766
3405
 
3406
+ // src/lib/crud/translation/language.interceptor.ts
3407
+ var import_common4 = require("@nestjs/common");
3408
+ function _ts_decorate4(decorators, target, key, desc2) {
3409
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
3410
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
3411
+ r = Reflect.decorate(decorators, target, key, desc2);
3412
+ } else {
3413
+ for (var i = decorators.length - 1; i >= 0; i--) {
3414
+ if (d = decorators[i]) {
3415
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
3416
+ }
3417
+ }
3418
+ }
3419
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
3420
+ }
3421
+ __name(_ts_decorate4, "_ts_decorate");
3422
+ function _ts_metadata4(metadataKey, metadataValue) {
3423
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
3424
+ return Reflect.metadata(metadataKey, metadataValue);
3425
+ }
3426
+ }
3427
+ __name(_ts_metadata4, "_ts_metadata");
3428
+ var LanguageInterceptor = class {
3429
+ static {
3430
+ __name(this, "LanguageInterceptor");
3431
+ }
3432
+ registry;
3433
+ constructor(registry) {
3434
+ this.registry = registry;
3435
+ }
3436
+ intercept(context, next) {
3437
+ const http = context.switchToHttp();
3438
+ const request = http.getRequest();
3439
+ const response = http.getResponse();
3440
+ const acceptLanguage = request.headers["accept-language"];
3441
+ const resolved = resolveLanguage(acceptLanguage, this.registry.languages, this.registry.defaultLanguage);
3442
+ response.setHeader("Vary", "Accept-Language");
3443
+ response.setHeader("Content-Language", resolved);
3444
+ return runWithLanguage(resolved, () => next.handle());
3445
+ }
3446
+ };
3447
+ LanguageInterceptor = _ts_decorate4([
3448
+ (0, import_common4.Injectable)(),
3449
+ _ts_metadata4("design:type", Function),
3450
+ _ts_metadata4("design:paramtypes", [
3451
+ typeof TranslationRegistry === "undefined" ? Object : TranslationRegistry
3452
+ ])
3453
+ ], LanguageInterceptor);
3454
+
3455
+ // src/lib/crud/translation/resolve-value-labels.ts
3456
+ var resolveValueLabelColumns = /* @__PURE__ */ __name(async (route, bootTimeCols, configRegistry, childRoute) => {
3457
+ if (!configRegistry) return bootTimeCols;
3458
+ const language = getRequestLanguage();
3459
+ if (!language) return bootTimeCols;
3460
+ const localized = await configRegistry.getByRoute(route, language);
3461
+ if (!localized) return bootTimeCols;
3462
+ if (!childRoute) return localized.valueLabelColumns ?? bootTimeCols;
3463
+ const sub = (localized.subResources ?? []).find((s) => s.childRoute === childRoute);
3464
+ return sub?.valueLabelColumns ?? bootTimeCols;
3465
+ }, "resolveValueLabelColumns");
3466
+
2767
3467
  // src/lib/crud/custom-repository/custom-repository.adapter.ts
2768
3468
  var unsupported = /* @__PURE__ */ __name((config, op) => {
2769
3469
  const method = config.parent ? PARENT_METHOD[op] : op;
2770
- throw new import_common4.NotImplementedException(`Resource "${config.name}" enables "${op}" but its repository.ts does not implement "${method}".`);
3470
+ throw new import_common5.NotImplementedException(`Resource "${config.name}" enables "${op}" but its repository.ts does not implement "${method}".`);
2771
3471
  }, "unsupported");
2772
- var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources, repository) => {
3472
+ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources, repository, configRegistry) => {
2773
3473
  const repo = repository ?? {};
2774
3474
  const idField = config.idField ?? DEFAULT_ID_FIELD;
2775
3475
  const toId = /* @__PURE__ */ __name((id) => (config.idType ?? DEFAULT_ID_TYPE) === "number" ? +id : String(id), "toId");
@@ -2777,7 +3477,7 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
2777
3477
  const parentIdFrom = /* @__PURE__ */ __name((request) => {
2778
3478
  const raw = request?.params?.[parentRef.param];
2779
3479
  if (raw === void 0 || raw === null || raw === "") {
2780
- throw new import_common4.BadRequestException(`Resource "${config.name}" is nested under "${parentRef.route}" but no "${parentRef.param}" was supplied.`);
3480
+ throw new import_common5.BadRequestException(`Resource "${config.name}" is nested under "${parentRef.route}" but no "${parentRef.param}" was supplied.`);
2781
3481
  }
2782
3482
  return (parentRef.idType ?? "string") === "number" ? +raw : String(raw);
2783
3483
  }, "parentIdFrom");
@@ -2824,7 +3524,12 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
2824
3524
  if (!repo.findAll) unsupported(config, "findAll");
2825
3525
  result = await repo.findAll(params, ctx("findAll", params, void 0, request));
2826
3526
  }
2827
- const data = await decorateRows(result?.data ?? [], "findAll", config, prisma, request, parentHookCtx(request));
3527
+ const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);
3528
+ const target = vlCols === config.valueLabelColumns ? config : {
3529
+ hooks: config.hooks,
3530
+ valueLabelColumns: vlCols
3531
+ };
3532
+ const data = await decorateRows(result?.data ?? [], "findAll", target, prisma, request, parentHookCtx(request));
2828
3533
  return {
2829
3534
  data,
2830
3535
  count: result?.count ?? data.length
@@ -2844,7 +3549,7 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
2844
3549
  row = await repo.findOne(toId(id), ctx("findOne", void 0, id, request));
2845
3550
  }
2846
3551
  if (row === null || row === void 0) {
2847
- throw new import_common4.NotFoundException(`${config.name} with id ${id} not found`);
3552
+ throw new import_common5.NotFoundException(`${config.name} with id ${id} not found`);
2848
3553
  }
2849
3554
  return decorateRow(row, "findOne", config, prisma, request, parentHookCtx(request));
2850
3555
  }, "findOne");
@@ -2871,7 +3576,7 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
2871
3576
  return postWrite(result, op, config, prisma, coercedId, request, parentHookCtx(request));
2872
3577
  }, "write");
2873
3578
  const notAChildRepository = /* @__PURE__ */ __name(async () => {
2874
- throw new import_common4.NotImplementedException(`Resource "${config.name}" is a custom resource; nested sub-resource routes are not supported. Expose the child collection as its own resource instead.`);
3579
+ throw new import_common5.NotImplementedException(`Resource "${config.name}" is a custom resource; nested sub-resource routes are not supported. Expose the child collection as its own resource instead.`);
2875
3580
  }, "notAChildRepository");
2876
3581
  return {
2877
3582
  prisma,
@@ -2906,10 +3611,10 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
2906
3611
  return postWrite(result, "delete", config, prisma, coercedId, request, parentHookCtx(request));
2907
3612
  }, "delete"),
2908
3613
  upsert: /* @__PURE__ */ __name(async () => {
2909
- throw new import_common4.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
3614
+ throw new import_common5.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
2910
3615
  }, "upsert"),
2911
3616
  upsertMany: /* @__PURE__ */ __name(async () => {
2912
- throw new import_common4.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
3617
+ throw new import_common5.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
2913
3618
  }, "upsertMany"),
2914
3619
  findAllByParent: notAChildRepository,
2915
3620
  findOneChild: notAChildRepository,
@@ -2938,19 +3643,19 @@ var validateCustomRepository = /* @__PURE__ */ __name((config, repository) => {
2938
3643
  }, "validateCustomRepository");
2939
3644
 
2940
3645
  // src/lib/crud/read.repository.ts
2941
- var import_common6 = require("@nestjs/common");
3646
+ var import_common7 = require("@nestjs/common");
2942
3647
 
2943
3648
  // src/lib/crud/custom-repository/child-delegate.ts
2944
- var import_common5 = require("@nestjs/common");
3649
+ var import_common6 = require("@nestjs/common");
2945
3650
  var childRepositoryFn = /* @__PURE__ */ __name((sub, op, parentName) => {
2946
3651
  const repo = sub.repository;
2947
3652
  const method = PARENT_METHOD[op];
2948
3653
  if (!repo) {
2949
- throw new import_common5.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" is a custom resource but no repository.ts was loaded for it.`);
3654
+ throw new import_common6.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" is a custom resource but no repository.ts was loaded for it.`);
2950
3655
  }
2951
3656
  const fn = repo[method] ?? (op === "patch" ? repo[PARENT_METHOD.update] : void 0);
2952
3657
  if (typeof fn !== "function") {
2953
- throw new import_common5.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" does not implement "${method}" in its repository.ts.`);
3658
+ throw new import_common6.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" does not implement "${method}" in its repository.ts.`);
2954
3659
  }
2955
3660
  return fn.bind(repo);
2956
3661
  }, "childRepositoryFn");
@@ -3247,12 +3952,14 @@ var ReadRepository = class {
3247
3952
  config;
3248
3953
  listSelect;
3249
3954
  oneSelect;
3250
- constructor(prismaModel, prisma, config, listSelect, oneSelect) {
3955
+ configRegistry;
3956
+ constructor(prismaModel, prisma, config, listSelect, oneSelect, configRegistry) {
3251
3957
  this.prismaModel = prismaModel;
3252
3958
  this.prisma = prisma;
3253
3959
  this.config = config;
3254
3960
  this.listSelect = listSelect;
3255
3961
  this.oneSelect = oneSelect;
3962
+ this.configRegistry = configRegistry;
3256
3963
  }
3257
3964
  /**
3258
3965
  * Physical table name for raw SQL (calculated columns).
@@ -3298,7 +4005,12 @@ var ReadRepository = class {
3298
4005
  };
3299
4006
  }
3300
4007
  async decorate(rows, op, request) {
3301
- return decorateRows(rows, op, this.config, this.prisma, request);
4008
+ const vlCols = await resolveValueLabelColumns(this.config.route, this.config.valueLabelColumns, this.configRegistry);
4009
+ const target = vlCols === this.config.valueLabelColumns ? this.config : {
4010
+ hooks: this.config.hooks,
4011
+ valueLabelColumns: vlCols
4012
+ };
4013
+ return decorateRows(rows, op, target, this.prisma, request);
3302
4014
  }
3303
4015
  async decorateOne(row, op, request) {
3304
4016
  return decorateRow(row, op, this.config, this.prisma, request);
@@ -3310,11 +4022,12 @@ var ReadRepository = class {
3310
4022
  async findAll(params, request) {
3311
4023
  const subResources = this.config.subResources ?? [];
3312
4024
  const projection = this.projection("findAll");
4025
+ const vlCols = await resolveValueLabelColumns(this.config.route, this.config.valueLabelColumns, this.configRegistry);
3313
4026
  const query = {
3314
4027
  where: this.buildWhere(params.filter),
3315
4028
  take: params.pageSize,
3316
4029
  skip: offsetOf(params),
3317
- orderBy: this.safeSort(sanitizeValueLabelSort(params.sort, this.config.valueLabelColumns), params.sortDir)
4030
+ orderBy: this.safeSort(sanitizeValueLabelSort(params.sort, vlCols), params.sortDir)
3318
4031
  };
3319
4032
  const prismaSubResources = subResources.filter((s) => s.childKind !== "custom");
3320
4033
  const oneToManySubResources = prismaSubResources.filter((s) => s.relationType !== "manyToOne");
@@ -3402,7 +4115,7 @@ var ReadRepository = class {
3402
4115
  }
3403
4116
  }
3404
4117
  const record = await this.prismaModel.findUnique(query);
3405
- if (!record) throw new import_common6.NotFoundException(`${this.config.name} with id ${id} not found`);
4118
+ if (!record) throw new import_common7.NotFoundException(`${this.config.name} with id ${id} not found`);
3406
4119
  const [withCalc] = await mergeCalculatedColumnsForRows([
3407
4120
  record
3408
4121
  ], this.config.calculatedColumns ?? [], this.tableName, this.prisma, this.config.idField ?? "id");
@@ -3444,7 +4157,8 @@ var ReadRepository = class {
3444
4157
  request,
3445
4158
  parent: this.parentHookContext(parentId2)
3446
4159
  }))) : rows;
3447
- const labeled2 = sub.valueLabelColumns?.length ? decorated2.map((r) => applyValueLabelColumns(r, sub.valueLabelColumns)) : decorated2;
4160
+ const subVlCols2 = await resolveValueLabelColumns(this.config.route, sub.valueLabelColumns, this.configRegistry, sub.childRoute);
4161
+ const labeled2 = subVlCols2?.length ? decorated2.map((r) => applyValueLabelColumns(r, subVlCols2)) : decorated2;
3448
4162
  return {
3449
4163
  data: labeled2,
3450
4164
  count: result?.count ?? labeled2.length
@@ -3457,7 +4171,8 @@ var ReadRepository = class {
3457
4171
  [sub.foreignKey]: this.toId(parentId2)
3458
4172
  };
3459
4173
  const includeClause = buildIncludeClause(sub.include);
3460
- const childSort = orderableChildSort(sanitizeValueLabelSort(params.sort, sub.valueLabelColumns), childModel, sub);
4174
+ const subVlCols = await resolveValueLabelColumns(this.config.route, sub.valueLabelColumns, this.configRegistry, sub.childRoute);
4175
+ const childSort = orderableChildSort(sanitizeValueLabelSort(params.sort, subVlCols), childModel, sub);
3461
4176
  const [data, count] = await Promise.all([
3462
4177
  childModel.findMany({
3463
4178
  where,
@@ -3479,7 +4194,7 @@ var ReadRepository = class {
3479
4194
  request,
3480
4195
  parent: this.parentHookContext(parentId2)
3481
4196
  }))) : withCalc;
3482
- const labeled = sub.valueLabelColumns?.length ? decorated.map((r) => applyValueLabelColumns(r, sub.valueLabelColumns)) : decorated;
4197
+ const labeled = subVlCols?.length ? decorated.map((r) => applyValueLabelColumns(r, subVlCols)) : decorated;
3483
4198
  return {
3484
4199
  data: labeled,
3485
4200
  count
@@ -3492,7 +4207,7 @@ var ReadRepository = class {
3492
4207
  async findOneChild(sub, childId, parentId2, request) {
3493
4208
  if (sub.childKind === "custom") {
3494
4209
  if (parentId2 === void 0) {
3495
- throw new import_common6.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
4210
+ throw new import_common7.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
3496
4211
  }
3497
4212
  const findOne = childRepositoryFn(sub, "findOne", this.config.name);
3498
4213
  const row = await findOne(this.toId(parentId2), (sub.idType ?? "string") === "number" ? +childId : String(childId), childCtx({
@@ -3504,7 +4219,7 @@ var ReadRepository = class {
3504
4219
  request
3505
4220
  }));
3506
4221
  if (row === null || row === void 0) {
3507
- throw new import_common6.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
4222
+ throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
3508
4223
  }
3509
4224
  return sub.hooks?.afterRead ? sub.hooks.afterRead(row, {
3510
4225
  prisma: this.prisma,
@@ -3528,7 +4243,7 @@ var ReadRepository = class {
3528
4243
  include: includeClause
3529
4244
  }
3530
4245
  });
3531
- if (!record) throw new import_common6.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
4246
+ if (!record) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
3532
4247
  const [withCalc] = sub.calculatedColumns?.length ? await mergeCalculatedColumnsForRows([
3533
4248
  record
3534
4249
  ], sub.calculatedColumns, sub.childModel, this.prisma, sub.idField ?? "id") : [
@@ -3545,9 +4260,9 @@ var ReadRepository = class {
3545
4260
  };
3546
4261
 
3547
4262
  // src/lib/crud/schema.utils.ts
3548
- var import_zod27 = require("zod");
4263
+ var import_zod28 = require("zod");
3549
4264
  function isZodSchema(schema) {
3550
- return schema instanceof import_zod27.ZodObject;
4265
+ return schema instanceof import_zod28.ZodObject;
3551
4266
  }
3552
4267
  __name(isZodSchema, "isZodSchema");
3553
4268
  var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
@@ -3561,7 +4276,7 @@ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
3561
4276
  }, "dropNullableFromRequired");
3562
4277
  function toJsonSchema(schema) {
3563
4278
  if (isZodSchema(schema)) {
3564
- const jsonSchema = (0, import_zod27.toJSONSchema)(schema, {
4279
+ const jsonSchema = (0, import_zod28.toJSONSchema)(schema, {
3565
4280
  target: "openApi3",
3566
4281
  ...jsonSchemaOpts
3567
4282
  });
@@ -3614,7 +4329,7 @@ function toSelectFields(schema) {
3614
4329
  __name(toSelectFields, "toSelectFields");
3615
4330
 
3616
4331
  // src/lib/crud/write.repository.ts
3617
- var import_common7 = require("@nestjs/common");
4332
+ var import_common8 = require("@nestjs/common");
3618
4333
  var includeRelationNames = /* @__PURE__ */ __name((include) => new Set((include ?? []).map((e) => typeof e === "string" ? e : e.relation)), "includeRelationNames");
3619
4334
  var PRISMA_RELATION_WRITE_KEYS = /* @__PURE__ */ new Set([
3620
4335
  "connect",
@@ -3649,7 +4364,7 @@ var WriteRepository = class {
3649
4364
  return (this.config.idType ?? "string") === "number" ? +id : String(id);
3650
4365
  }
3651
4366
  notFound(id) {
3652
- return new import_common7.NotFoundException(`${this.config.name} with id ${id} not found`);
4367
+ return new import_common8.NotFoundException(`${this.config.name} with id ${id} not found`);
3653
4368
  }
3654
4369
  stripSubResourceKeys(data) {
3655
4370
  if (!data || typeof data !== "object" || Array.isArray(data)) return data;
@@ -3685,7 +4400,7 @@ var WriteRepository = class {
3685
4400
  }
3686
4401
  upsertWhere(data) {
3687
4402
  const keys = upsertOnFor(resolveDefinition(this.config));
3688
- if (!keys) throw new import_common7.BadRequestException(`${this.config.name} has no upsertOn configured`);
4403
+ if (!keys) throw new import_common8.BadRequestException(`${this.config.name} has no upsertOn configured`);
3689
4404
  if (typeof keys === "string") return {
3690
4405
  [keys]: data[keys]
3691
4406
  };
@@ -3777,7 +4492,7 @@ var WriteRepository = class {
3777
4492
  */
3778
4493
  async delegateChildWrite(sub, op, parentId1, childId, data, request) {
3779
4494
  if (parentId1 === void 0) {
3780
- throw new import_common7.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
4495
+ throw new import_common8.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
3781
4496
  }
3782
4497
  const fn = childRepositoryFn(sub, op, this.config.name);
3783
4498
  const id = childId === void 0 ? void 0 : (sub.idType ?? "string") === "number" ? +childId : String(childId);
@@ -3888,7 +4603,7 @@ var WriteRepository = class {
3888
4603
  request
3889
4604
  }) : result;
3890
4605
  } catch (e) {
3891
- if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
4606
+ if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
3892
4607
  throw e;
3893
4608
  }
3894
4609
  }
@@ -3913,7 +4628,7 @@ var WriteRepository = class {
3913
4628
  const result = await childModel.deleteMany({
3914
4629
  where
3915
4630
  });
3916
- if (result.count === 0) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
4631
+ if (result.count === 0) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
3917
4632
  return sub.hooks?.afterWrite ? sub.hooks.afterWrite(result, {
3918
4633
  prisma: this.prisma,
3919
4634
  op: "delete",
@@ -3921,19 +4636,19 @@ var WriteRepository = class {
3921
4636
  request
3922
4637
  }) : result;
3923
4638
  } catch (e) {
3924
- if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
4639
+ if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
3925
4640
  throw e;
3926
4641
  }
3927
4642
  }
3928
4643
  };
3929
4644
 
3930
4645
  // src/lib/crud/crud-repository.factory.ts
3931
- function createCrudRepository(prisma, config, dataSources) {
4646
+ function createCrudRepository(prisma, config, dataSources, configRegistry) {
3932
4647
  if (config.kind === "custom") {
3933
4648
  return createCustomRepository(prisma, config, dataSources ?? {
3934
4649
  resolve: /* @__PURE__ */ __name(() => prisma, "resolve"),
3935
4650
  entries: /* @__PURE__ */ __name(() => [], "entries")
3936
- }, config.repository);
4651
+ }, config.repository, configRegistry);
3937
4652
  }
3938
4653
  if (!config.model) {
3939
4654
  throw new Error(`Resource "${config.name}" has no "model". A prisma-backed resource must name its Prisma model; set "kind": "custom" for a resource with no model.`);
@@ -3947,7 +4662,7 @@ function createCrudRepository(prisma, config, dataSources) {
3947
4662
  const oneSchema = schemaFor(definition, "findOne");
3948
4663
  const listSelect = listSchema ? toSelectFields(listSchema) : void 0;
3949
4664
  const oneSelect = oneSchema ? toSelectFields(oneSchema) : listSelect;
3950
- const reader = new ReadRepository(model, prisma, config, listSelect, oneSelect);
4665
+ const reader = new ReadRepository(model, prisma, config, listSelect, oneSelect, configRegistry);
3951
4666
  const writer = new WriteRepository(model, prisma, config);
3952
4667
  return {
3953
4668
  prisma,
@@ -3970,18 +4685,27 @@ function createCrudRepository(prisma, config, dataSources) {
3970
4685
  __name(createCrudRepository, "createCrudRepository");
3971
4686
 
3972
4687
  // src/lib/crud/data-source/data-source.registry.ts
3973
- var import_common8 = require("@nestjs/common");
3974
- function _ts_decorate4(decorators, target, key, desc2) {
4688
+ var import_common9 = require("@nestjs/common");
4689
+ function _ts_decorate5(decorators, target, key, desc2) {
3975
4690
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
3976
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
3977
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4691
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4692
+ r = Reflect.decorate(decorators, target, key, desc2);
4693
+ } else {
4694
+ for (var i = decorators.length - 1; i >= 0; i--) {
4695
+ if (d = decorators[i]) {
4696
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4697
+ }
4698
+ }
4699
+ }
3978
4700
  return c > 3 && r && Object.defineProperty(target, key, r), r;
3979
4701
  }
3980
- __name(_ts_decorate4, "_ts_decorate");
3981
- function _ts_metadata3(k, v) {
3982
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
4702
+ __name(_ts_decorate5, "_ts_decorate");
4703
+ function _ts_metadata5(metadataKey, metadataValue) {
4704
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4705
+ return Reflect.metadata(metadataKey, metadataValue);
4706
+ }
3983
4707
  }
3984
- __name(_ts_metadata3, "_ts_metadata");
4708
+ __name(_ts_metadata5, "_ts_metadata");
3985
4709
  var DataSourceRegistry = class {
3986
4710
  static {
3987
4711
  __name(this, "DataSourceRegistry");
@@ -4040,31 +4764,31 @@ var DataSourceRegistry = class {
4040
4764
  }
4041
4765
  }
4042
4766
  };
4043
- DataSourceRegistry = _ts_decorate4([
4044
- (0, import_common8.Injectable)(),
4045
- _ts_metadata3("design:type", Function),
4046
- _ts_metadata3("design:paramtypes", [
4767
+ DataSourceRegistry = _ts_decorate5([
4768
+ (0, import_common9.Injectable)(),
4769
+ _ts_metadata5("design:type", Function),
4770
+ _ts_metadata5("design:paramtypes", [
4047
4771
  Array
4048
4772
  ])
4049
4773
  ], DataSourceRegistry);
4050
4774
 
4051
4775
  // src/lib/crud/data-source/data-source.loader.ts
4052
- var import_node_fs2 = require("fs");
4053
- var import_node_path5 = require("path");
4776
+ var import_node_fs5 = require("fs");
4777
+ var import_node_path8 = require("path");
4054
4778
  var loadDataSourcesFromDir = /* @__PURE__ */ __name(async (dirPath) => {
4055
- if (!(0, import_node_fs2.existsSync)(dirPath)) return [];
4056
- const entries = (0, import_node_fs2.readdirSync)(dirPath, {
4779
+ if (!(0, import_node_fs5.existsSync)(dirPath)) return [];
4780
+ const entries = (0, import_node_fs5.readdirSync)(dirPath, {
4057
4781
  withFileTypes: true
4058
4782
  });
4059
4783
  const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
4060
4784
  const results = [];
4061
4785
  for (const dir of dirs) {
4062
- const basePath = (0, import_node_path5.join)(dirPath, dir);
4063
- const jsonFile = (0, import_node_path5.join)(basePath, "data-source.json");
4064
- if (!(0, import_node_fs2.existsSync)(jsonFile)) continue;
4786
+ const basePath = (0, import_node_path8.join)(dirPath, dir);
4787
+ const jsonFile = (0, import_node_path8.join)(basePath, "data-source.json");
4788
+ if (!(0, import_node_fs5.existsSync)(jsonFile)) continue;
4065
4789
  let _config;
4066
4790
  try {
4067
- _config = JSON.parse((0, import_node_fs2.readFileSync)(jsonFile, "utf-8"));
4791
+ _config = JSON.parse((0, import_node_fs5.readFileSync)(jsonFile, "utf-8"));
4068
4792
  } catch (err) {
4069
4793
  resourceLoadErrorsRegistry.record({
4070
4794
  name: dir,
@@ -4100,14 +4824,14 @@ var findModule2 = /* @__PURE__ */ __name((dir, name) => {
4100
4824
  ".ts",
4101
4825
  ".js"
4102
4826
  ]) {
4103
- const p = (0, import_node_path5.join)(dir, `${name}${ext}`);
4104
- if ((0, import_node_fs2.existsSync)(p)) return p;
4827
+ const p = (0, import_node_path8.join)(dir, `${name}${ext}`);
4828
+ if ((0, import_node_fs5.existsSync)(p)) return p;
4105
4829
  }
4106
4830
  return void 0;
4107
4831
  }, "findModule");
4108
4832
 
4109
4833
  // src/lib/crud/operations/register-actions.ts
4110
- var import_common9 = require("@nestjs/common");
4834
+ var import_common10 = require("@nestjs/common");
4111
4835
  var import_swagger2 = require("@nestjs/swagger");
4112
4836
 
4113
4837
  // src/lib/crud/operations/decorator.utils.ts
@@ -4131,8 +4855,8 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
4131
4855
  return action.procedure(this.repo.prisma, recordId);
4132
4856
  });
4133
4857
  const d = desc(cls, methodName);
4134
- (0, import_common9.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
4135
- (0, import_common9.Param)("recordId")(cls.prototype, methodName, 0);
4858
+ (0, import_common10.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
4859
+ (0, import_common10.Param)("recordId")(cls.prototype, methodName, 0);
4136
4860
  (0, import_swagger2.ApiOperation)({
4137
4861
  summary: `Execute action "${action.label}" on a ${name}`
4138
4862
  })(cls.prototype, methodName, d);
@@ -4156,7 +4880,7 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4156
4880
  return action.procedure(this.repo.prisma);
4157
4881
  });
4158
4882
  const d = desc(cls, methodName);
4159
- (0, import_common9.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
4883
+ (0, import_common10.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
4160
4884
  (0, import_swagger2.ApiOperation)({
4161
4885
  summary: `Execute table action "${action.label ?? action.id}" on ${name}`
4162
4886
  })(cls.prototype, methodName, d);
@@ -4168,7 +4892,7 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4168
4892
  }, "registerTableActionRoutes");
4169
4893
 
4170
4894
  // src/lib/crud/operations/register-create.ts
4171
- var import_common10 = require("@nestjs/common");
4895
+ var import_common11 = require("@nestjs/common");
4172
4896
  var import_swagger3 = require("@nestjs/swagger");
4173
4897
  var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4174
4898
  if (!isOperationEnabled(ctx.definition, "create")) return null;
@@ -4185,7 +4909,7 @@ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4185
4909
  bodyDecorator(createSchema, {
4186
4910
  coerceNullableUndefinedToNull: true
4187
4911
  })(cls.prototype, methodName, 0);
4188
- (0, import_common10.Req)()(cls.prototype, methodName, 1);
4912
+ (0, import_common11.Req)()(cls.prototype, methodName, 1);
4189
4913
  }, "decorators")
4190
4914
  };
4191
4915
  }, "defaultCreate");
@@ -4197,9 +4921,9 @@ var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
4197
4921
  return this.repo.createChild(id, sub, body, req);
4198
4922
  }, "createFn");
4199
4923
  const decorators = /* @__PURE__ */ __name(() => {
4200
- (0, import_common10.Param)("id")(cls.prototype, methodName, 0);
4201
- (0, import_common10.Body)()(cls.prototype, methodName, 1);
4202
- (0, import_common10.Req)()(cls.prototype, methodName, 2);
4924
+ (0, import_common11.Param)("id")(cls.prototype, methodName, 0);
4925
+ (0, import_common11.Body)()(cls.prototype, methodName, 1);
4926
+ (0, import_common11.Req)()(cls.prototype, methodName, 2);
4203
4927
  }, "decorators");
4204
4928
  return {
4205
4929
  route: `:id/${sub.childRoute}`,
@@ -4217,7 +4941,7 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4217
4941
  const { cls } = ctx;
4218
4942
  def(cls, methodName, properties.createFn);
4219
4943
  const d = desc(cls, methodName);
4220
- (0, import_common10.Post)(route)(cls.prototype, methodName, d);
4944
+ (0, import_common11.Post)(route)(cls.prototype, methodName, d);
4221
4945
  (0, import_swagger3.ApiOperation)({
4222
4946
  summary: `Create a ${name}`
4223
4947
  })(cls.prototype, methodName, d);
@@ -4229,7 +4953,7 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4229
4953
  }, "registerCreate");
4230
4954
 
4231
4955
  // src/lib/crud/operations/register-delete.ts
4232
- var import_common11 = require("@nestjs/common");
4956
+ var import_common12 = require("@nestjs/common");
4233
4957
  var import_swagger4 = require("@nestjs/swagger");
4234
4958
  var defaultDelete = /* @__PURE__ */ __name((ctx) => {
4235
4959
  if (!isOperationEnabled(ctx.definition, "delete")) return null;
@@ -4255,9 +4979,9 @@ var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
4255
4979
  return this.repo.deleteChild(sub, childId, parentId2, req);
4256
4980
  }, "deleteFn");
4257
4981
  const decorators = /* @__PURE__ */ __name(() => {
4258
- (0, import_common11.Param)("childId")(cls.prototype, methodName, 0);
4259
- (0, import_common11.Param)("id")(cls.prototype, methodName, 1);
4260
- (0, import_common11.Req)()(cls.prototype, methodName, 2);
4982
+ (0, import_common12.Param)("childId")(cls.prototype, methodName, 0);
4983
+ (0, import_common12.Param)("id")(cls.prototype, methodName, 1);
4984
+ (0, import_common12.Req)()(cls.prototype, methodName, 2);
4261
4985
  }, "decorators");
4262
4986
  return {
4263
4987
  route: `:id/${sub.childRoute}/:childId`,
@@ -4275,8 +4999,8 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
4275
4999
  const { methodName, route, name } = properties;
4276
5000
  def(cls, methodName, properties.deleteFn);
4277
5001
  const d = desc(cls, methodName);
4278
- (0, import_common11.Delete)(route)(cls.prototype, methodName, d);
4279
- (0, import_common11.Param)("id")(cls.prototype, methodName, 0);
5002
+ (0, import_common12.Delete)(route)(cls.prototype, methodName, d);
5003
+ (0, import_common12.Param)("id")(cls.prototype, methodName, 0);
4280
5004
  (0, import_swagger4.ApiOperation)({
4281
5005
  summary: `Delete ${name} record`
4282
5006
  })(cls.prototype, methodName, d);
@@ -4285,11 +5009,11 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
4285
5009
  status: 200
4286
5010
  })(cls.prototype, methodName, d);
4287
5011
  properties.decorators();
4288
- if (!sub) (0, import_common11.Req)()(cls.prototype, methodName, 1);
5012
+ if (!sub) (0, import_common12.Req)()(cls.prototype, methodName, 1);
4289
5013
  }, "registerDelete");
4290
5014
 
4291
5015
  // src/lib/crud/operations/register-findall.ts
4292
- var import_common12 = require("@nestjs/common");
5016
+ var import_common13 = require("@nestjs/common");
4293
5017
  var import_swagger5 = require("@nestjs/swagger");
4294
5018
 
4295
5019
  // src/lib/crud/request.dto.ts
@@ -4366,7 +5090,8 @@ var ZodValidationPipe = class {
4366
5090
  formatErrors(error) {
4367
5091
  return error.issues.map((e) => ({
4368
5092
  field: e.path.join("."),
4369
- message: e.message
5093
+ message: e.message,
5094
+ code: e.code
4370
5095
  }));
4371
5096
  }
4372
5097
  };
@@ -4444,8 +5169,8 @@ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
4444
5169
  return findAllByParent(this.repo, id, sub.childRoute, params, req);
4445
5170
  }, "findAll");
4446
5171
  const decorators = /* @__PURE__ */ __name(() => {
4447
- (0, import_common12.Param)("id")(cls.prototype, methodName, 2);
4448
- (0, import_common12.Req)()(cls.prototype, methodName, 3);
5172
+ (0, import_common13.Param)("id")(cls.prototype, methodName, 2);
5173
+ (0, import_common13.Req)()(cls.prototype, methodName, 3);
4449
5174
  }, "decorators");
4450
5175
  return {
4451
5176
  name: sub.childRoute,
@@ -4464,10 +5189,10 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
4464
5189
  const { cls } = ctx;
4465
5190
  def(cls, methodName, properties.findAll);
4466
5191
  const d = desc(cls, methodName);
4467
- (0, import_common12.Get)(route)(cls.prototype, methodName, d);
4468
- (0, import_common12.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
4469
- (0, import_common12.Query)("q")(cls.prototype, methodName, 1);
4470
- if (!sub) (0, import_common12.Req)()(cls.prototype, methodName, 2);
5192
+ (0, import_common13.Get)(route)(cls.prototype, methodName, d);
5193
+ (0, import_common13.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
5194
+ (0, import_common13.Query)("q")(cls.prototype, methodName, 1);
5195
+ if (!sub) (0, import_common13.Req)()(cls.prototype, methodName, 2);
4471
5196
  (0, import_swagger5.ApiOperation)({
4472
5197
  summary: `List all ${name}s`
4473
5198
  })(cls.prototype, methodName, d);
@@ -4485,7 +5210,7 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
4485
5210
  }, "registerFindAll");
4486
5211
 
4487
5212
  // src/lib/crud/operations/register-findone.ts
4488
- var import_common13 = require("@nestjs/common");
5213
+ var import_common14 = require("@nestjs/common");
4489
5214
  var import_swagger6 = require("@nestjs/swagger");
4490
5215
  var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
4491
5216
  if (!isOperationEnabled(ctx.definition, "findOne")) return null;
@@ -4499,8 +5224,8 @@ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
4499
5224
  return this.repo.findOne(id, req);
4500
5225
  }, "findOneFn"),
4501
5226
  decorators: /* @__PURE__ */ __name(() => {
4502
- (0, import_common13.Param)("id")(cls.prototype, methodName, 0);
4503
- (0, import_common13.Req)()(cls.prototype, methodName, 1);
5227
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5228
+ (0, import_common14.Req)()(cls.prototype, methodName, 1);
4504
5229
  }, "decorators")
4505
5230
  };
4506
5231
  }, "defaultFindOne");
@@ -4512,9 +5237,9 @@ var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
4512
5237
  return this.repo.findOneChild(sub, childId, parentId2, req);
4513
5238
  }, "findOneFn");
4514
5239
  const decorators = /* @__PURE__ */ __name(() => {
4515
- (0, import_common13.Param)("id")(cls.prototype, methodName, 0);
4516
- (0, import_common13.Param)("childId")(cls.prototype, methodName, 1);
4517
- (0, import_common13.Req)()(cls.prototype, methodName, 2);
5240
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5241
+ (0, import_common14.Param)("childId")(cls.prototype, methodName, 1);
5242
+ (0, import_common14.Req)()(cls.prototype, methodName, 2);
4518
5243
  }, "decorators");
4519
5244
  return {
4520
5245
  route: `:id/${sub.childRoute}/:childId`,
@@ -4532,7 +5257,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
4532
5257
  const { cls } = ctx;
4533
5258
  def(cls, methodName, properties.findOneFn);
4534
5259
  const d = desc(cls, methodName);
4535
- (0, import_common13.Get)(route)(cls.prototype, methodName, d);
5260
+ (0, import_common14.Get)(route)(cls.prototype, methodName, d);
4536
5261
  (0, import_swagger6.ApiOperation)({
4537
5262
  summary: `Get one ${name} by id`
4538
5263
  })(cls.prototype, methodName, d);
@@ -4551,7 +5276,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
4551
5276
  }, "registerFindOne");
4552
5277
 
4553
5278
  // src/lib/crud/operations/register-patch.ts
4554
- var import_common14 = require("@nestjs/common");
5279
+ var import_common15 = require("@nestjs/common");
4555
5280
  var import_swagger7 = require("@nestjs/swagger");
4556
5281
  var defaultPatch = /* @__PURE__ */ __name((ctx) => {
4557
5282
  if (!isOperationEnabled(ctx.definition, "patch")) return null;
@@ -4565,9 +5290,9 @@ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
4565
5290
  return this.repo.patch(id, body, req);
4566
5291
  }, "patchFn"),
4567
5292
  decorators: /* @__PURE__ */ __name(() => {
4568
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5293
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
4569
5294
  bodyDecorator(patchSchema)(cls.prototype, methodName, 1);
4570
- (0, import_common14.Req)()(cls.prototype, methodName, 2);
5295
+ (0, import_common15.Req)()(cls.prototype, methodName, 2);
4571
5296
  }, "decorators")
4572
5297
  };
4573
5298
  }, "defaultPatch");
@@ -4579,10 +5304,10 @@ var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
4579
5304
  return this.repo.updateChild(sub, childId, body, req);
4580
5305
  }, "patchFn");
4581
5306
  const decorators = /* @__PURE__ */ __name(() => {
4582
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
4583
- (0, import_common14.Param)("childId")(cls.prototype, methodName, 1);
4584
- (0, import_common14.Body)()(cls.prototype, methodName, 2);
4585
- (0, import_common14.Req)()(cls.prototype, methodName, 3);
5307
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
5308
+ (0, import_common15.Param)("childId")(cls.prototype, methodName, 1);
5309
+ (0, import_common15.Body)()(cls.prototype, methodName, 2);
5310
+ (0, import_common15.Req)()(cls.prototype, methodName, 3);
4586
5311
  }, "decorators");
4587
5312
  return {
4588
5313
  route: `:id/${sub.childRoute}/:childId`,
@@ -4600,7 +5325,7 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
4600
5325
  const { cls } = ctx;
4601
5326
  def(cls, methodName, properties.patchFn);
4602
5327
  const d = desc(cls, methodName);
4603
- (0, import_common14.Patch)(route)(cls.prototype, methodName, d);
5328
+ (0, import_common15.Patch)(route)(cls.prototype, methodName, d);
4604
5329
  (0, import_swagger7.ApiOperation)({
4605
5330
  summary: `Update a ${name}`
4606
5331
  })(cls.prototype, methodName, d);
@@ -4615,37 +5340,37 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
4615
5340
  }, "registerPatch");
4616
5341
 
4617
5342
  // src/lib/crud/operations/register-schema-endpoints.ts
4618
- var import_common15 = require("@nestjs/common");
5343
+ var import_common16 = require("@nestjs/common");
4619
5344
  var import_swagger8 = require("@nestjs/swagger");
4620
5345
 
4621
5346
  // src/lib/crud/resource/PatchResourceJson.schema.ts
4622
- var import_zod28 = require("zod");
4623
- var FieldVariantPatchSchema = import_zod28.z.object({
4624
- type: import_zod28.z.string().nullable().optional(),
4625
- format: import_zod28.z.string().nullable().optional(),
4626
- resource: import_zod28.z.string().nullable().optional(),
4627
- position: import_zod28.z.number().nullable().optional(),
4628
- options: import_zod28.z.record(import_zod28.z.string(), import_zod28.z.unknown().nullable()).optional()
5347
+ var import_zod29 = require("zod");
5348
+ var FieldVariantPatchSchema = import_zod29.z.object({
5349
+ type: import_zod29.z.string().nullable().optional(),
5350
+ format: import_zod29.z.string().nullable().optional(),
5351
+ resource: import_zod29.z.string().nullable().optional(),
5352
+ position: import_zod29.z.number().nullable().optional(),
5353
+ options: import_zod29.z.record(import_zod29.z.string(), import_zod29.z.unknown().nullable()).optional()
4629
5354
  }).partial();
4630
- var PatchColumnSchema = import_zod28.z.object({
4631
- label: import_zod28.z.string().optional(),
4632
- column: import_zod28.z.string().optional(),
4633
- hiddenInTable: import_zod28.z.boolean().optional(),
4634
- hiddenInForm: import_zod28.z.boolean().optional(),
4635
- hiddenInView: import_zod28.z.boolean().optional(),
5355
+ var PatchColumnSchema = import_zod29.z.object({
5356
+ label: import_zod29.z.string().optional(),
5357
+ column: import_zod29.z.string().optional(),
5358
+ hiddenInTable: import_zod29.z.boolean().optional(),
5359
+ hiddenInForm: import_zod29.z.boolean().optional(),
5360
+ hiddenInView: import_zod29.z.boolean().optional(),
4636
5361
  fieldInput: FieldVariantPatchSchema.optional(),
4637
5362
  fieldView: FieldVariantPatchSchema.optional(),
4638
5363
  fieldTable: FieldVariantPatchSchema.optional()
4639
5364
  }).partial();
4640
- var PatchResourceJsonSchema = import_zod28.z.object({
4641
- columns: import_zod28.z.record(import_zod28.z.string(), PatchColumnSchema)
5365
+ var PatchResourceJsonSchema = import_zod29.z.object({
5366
+ columns: import_zod29.z.record(import_zod29.z.string(), PatchColumnSchema)
4642
5367
  });
4643
5368
 
4644
5369
  // src/lib/crud/resource/WriteResourceJson.ts
4645
- var import_node_fs3 = require("fs");
5370
+ var import_node_fs6 = require("fs");
4646
5371
  var readRawResourceJson = /* @__PURE__ */ __name((jsonPath) => {
4647
- if (!(0, import_node_fs3.existsSync)(jsonPath)) return void 0;
4648
- return JSON.parse((0, import_node_fs3.readFileSync)(jsonPath, "utf-8"));
5372
+ if (!(0, import_node_fs6.existsSync)(jsonPath)) return void 0;
5373
+ return JSON.parse((0, import_node_fs6.readFileSync)(jsonPath, "utf-8"));
4649
5374
  }, "readRawResourceJson");
4650
5375
  var FIELD_VARIANT_KEYS = [
4651
5376
  "fieldInput",
@@ -4701,7 +5426,7 @@ var serializeResourceJson = /* @__PURE__ */ __name((config) => `${JSON.stringify
4701
5426
  `, "serializeResourceJson");
4702
5427
  var validateResourceJson = /* @__PURE__ */ __name((raw) => ResourceJsonSchema.safeParse(raw), "validateResourceJson");
4703
5428
  var writeRawResourceJson = /* @__PURE__ */ __name((jsonPath, raw) => {
4704
- (0, import_node_fs3.writeFileSync)(jsonPath, serializeResourceJson(raw), "utf-8");
5429
+ (0, import_node_fs6.writeFileSync)(jsonPath, serializeResourceJson(raw), "utf-8");
4705
5430
  }, "writeRawResourceJson");
4706
5431
 
4707
5432
  // src/lib/crud/operations/payload-builders.ts
@@ -4960,20 +5685,21 @@ var buildEditableColumnsPayload = /* @__PURE__ */ __name((config) => {
4960
5685
  }, "buildEditableColumnsPayload");
4961
5686
 
4962
5687
  // src/lib/crud/operations/register-schema-endpoints.ts
4963
- var import_node_path6 = require("path");
5688
+ var import_node_path9 = require("path");
4964
5689
  var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
4965
5690
  const { cls, config } = ctx;
4966
5691
  const { route, name } = config;
4967
5692
  const definitionPayload = buildDefinitionPayload(config);
4968
5693
  def(cls, "getDefinition", async function() {
4969
- if (IS_DEV) {
4970
- const fresh = await this.configRegistry.getByRoute(route);
5694
+ const language = getRequestLanguage();
5695
+ if (IS_DEV || language) {
5696
+ const fresh = await this.configRegistry.getByRoute(route, language);
4971
5697
  if (fresh) return buildDefinitionPayload(fresh);
4972
5698
  }
4973
5699
  return definitionPayload;
4974
5700
  });
4975
5701
  const d = desc(cls, "getDefinition");
4976
- (0, import_common15.Get)("definition")(cls.prototype, "getDefinition", d);
5702
+ (0, import_common16.Get)("definition")(cls.prototype, "getDefinition", d);
4977
5703
  (0, import_swagger8.ApiOperation)({
4978
5704
  summary: `Get the resource definition for ${name}`
4979
5705
  })(cls.prototype, "getDefinition", d);
@@ -4987,14 +5713,15 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
4987
5713
  const { route, name } = config;
4988
5714
  const resourceJsonPayload = buildResourceJsonPayload(config, baseUrl);
4989
5715
  def(cls, "getResourceJson", async function() {
4990
- if (IS_DEV) {
4991
- const fresh = await this.configRegistry.getByRoute(route);
5716
+ const language = getRequestLanguage();
5717
+ if (IS_DEV || language) {
5718
+ const fresh = await this.configRegistry.getByRoute(route, language);
4992
5719
  if (fresh) return buildResourceJsonPayload(fresh, baseUrl);
4993
5720
  }
4994
5721
  return resourceJsonPayload;
4995
5722
  });
4996
5723
  const d = desc(cls, "getResourceJson");
4997
- (0, import_common15.Get)("resource.json")(cls.prototype, "getResourceJson", d);
5724
+ (0, import_common16.Get)("resource.json")(cls.prototype, "getResourceJson", d);
4998
5725
  (0, import_swagger8.ApiOperation)({
4999
5726
  summary: `Get resource descriptor for ${name}`
5000
5727
  })(cls.prototype, "getResourceJson", d);
@@ -5008,13 +5735,13 @@ var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
5008
5735
  const { route, name } = config;
5009
5736
  def(cls, "getResourceColumns", async function() {
5010
5737
  if (!IS_DEV) {
5011
- throw new import_common15.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
5738
+ throw new import_common16.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
5012
5739
  }
5013
5740
  const fresh = await this.configRegistry.getByRoute(route);
5014
5741
  return buildEditableColumnsPayload(fresh ?? config);
5015
5742
  });
5016
5743
  const d = desc(cls, "getResourceColumns");
5017
- (0, import_common15.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5744
+ (0, import_common16.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5018
5745
  (0, import_swagger8.ApiOperation)({
5019
5746
  summary: `Dev-only: get the editable column list for ${name}`
5020
5747
  })(cls.prototype, "getResourceColumns", d);
@@ -5028,30 +5755,30 @@ var registerResourceJsonPatchEndpoint = /* @__PURE__ */ __name((ctx) => {
5028
5755
  const { route, name } = config;
5029
5756
  def(cls, "patchResourceJson", async function(body) {
5030
5757
  if (!IS_DEV) {
5031
- throw new import_common15.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5758
+ throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5032
5759
  }
5033
5760
  await this.configRegistry.getByRoute(route);
5034
5761
  const dir = this.configRegistry.getResourceDir(route);
5035
5762
  if (!dir) {
5036
- throw new import_common15.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5763
+ throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5037
5764
  }
5038
- const jsonPath = (0, import_node_path6.join)(dir, "resource.json");
5765
+ const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5039
5766
  const raw = readRawResourceJson(jsonPath);
5040
5767
  if (!raw) {
5041
- throw new import_common15.NotFoundException(`resource.json not found at ${jsonPath}`);
5768
+ throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5042
5769
  }
5043
5770
  const merged = applyColumnPatch(raw, body);
5044
5771
  const validated = validateResourceJson(merged);
5045
5772
  if (!validated.success) {
5046
- throw new import_common15.BadRequestException(validated.error.issues);
5773
+ throw new import_common16.BadRequestException(validated.error.issues);
5047
5774
  }
5048
5775
  writeRawResourceJson(jsonPath, merged);
5049
5776
  const fresh = await this.configRegistry.getByRoute(route);
5050
5777
  return buildEditableColumnsPayload(fresh ?? config);
5051
5778
  });
5052
5779
  const d = desc(cls, "patchResourceJson");
5053
- (0, import_common15.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
5054
- (0, import_common15.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
5780
+ (0, import_common16.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
5781
+ (0, import_common16.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
5055
5782
  (0, import_swagger8.ApiOperation)({
5056
5783
  summary: `Dev-only: patch column layout in resource.json for ${name}`
5057
5784
  })(cls.prototype, "patchResourceJson", d);
@@ -5065,22 +5792,22 @@ var registerResourceJsonRawGetEndpoint = /* @__PURE__ */ __name((ctx) => {
5065
5792
  const { route, name } = config;
5066
5793
  def(cls, "getResourceJsonRaw", async function() {
5067
5794
  if (!IS_DEV) {
5068
- throw new import_common15.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
5795
+ throw new import_common16.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
5069
5796
  }
5070
5797
  await this.configRegistry.getByRoute(route);
5071
5798
  const dir = this.configRegistry.getResourceDir(route);
5072
5799
  if (!dir) {
5073
- throw new import_common15.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5800
+ throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5074
5801
  }
5075
- const jsonPath = (0, import_node_path6.join)(dir, "resource.json");
5802
+ const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5076
5803
  const raw = readRawResourceJson(jsonPath);
5077
5804
  if (!raw) {
5078
- throw new import_common15.NotFoundException(`resource.json not found at ${jsonPath}`);
5805
+ throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5079
5806
  }
5080
5807
  return raw;
5081
5808
  });
5082
5809
  const d = desc(cls, "getResourceJsonRaw");
5083
- (0, import_common15.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
5810
+ (0, import_common16.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
5084
5811
  (0, import_swagger8.ApiOperation)({
5085
5812
  summary: `Dev-only: get the raw resource.json for ${name}`
5086
5813
  })(cls.prototype, "getResourceJsonRaw", d);
@@ -5094,24 +5821,24 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5094
5821
  const { route, name } = config;
5095
5822
  def(cls, "putResourceJsonRaw", async function(body) {
5096
5823
  if (!IS_DEV) {
5097
- throw new import_common15.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5824
+ throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5098
5825
  }
5099
5826
  await this.configRegistry.getByRoute(route);
5100
5827
  const dir = this.configRegistry.getResourceDir(route);
5101
5828
  if (!dir) {
5102
- throw new import_common15.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5829
+ throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5103
5830
  }
5104
5831
  const validated = validateResourceJson(body);
5105
5832
  if (!validated.success) {
5106
- throw new import_common15.BadRequestException(validated.error.issues);
5833
+ throw new import_common16.BadRequestException(validated.error.issues);
5107
5834
  }
5108
- const jsonPath = (0, import_node_path6.join)(dir, "resource.json");
5835
+ const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5109
5836
  writeRawResourceJson(jsonPath, body);
5110
5837
  return body;
5111
5838
  });
5112
5839
  const d = desc(cls, "putResourceJsonRaw");
5113
- (0, import_common15.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
5114
- (0, import_common15.Body)()(cls.prototype, "putResourceJsonRaw", 0);
5840
+ (0, import_common16.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
5841
+ (0, import_common16.Body)()(cls.prototype, "putResourceJsonRaw", 0);
5115
5842
  (0, import_swagger8.ApiOperation)({
5116
5843
  summary: `Dev-only: replace the full resource.json for ${name}`
5117
5844
  })(cls.prototype, "putResourceJsonRaw", d);
@@ -5122,7 +5849,7 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5122
5849
  }, "registerResourceJsonRawPutEndpoint");
5123
5850
 
5124
5851
  // src/lib/crud/operations/register-schemas.ts
5125
- var import_common16 = require("@nestjs/common");
5852
+ var import_common17 = require("@nestjs/common");
5126
5853
  var import_swagger9 = require("@nestjs/swagger");
5127
5854
  var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
5128
5855
  const { config, baseUrl } = ctx;
@@ -5133,8 +5860,9 @@ var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
5133
5860
  methodName: "getSchemas",
5134
5861
  name,
5135
5862
  schemasFn: /* @__PURE__ */ __name(async function() {
5136
- if (IS_DEV) {
5137
- const fresh = await this.configRegistry.getByRoute(route);
5863
+ const language = getRequestLanguage();
5864
+ if (IS_DEV || language) {
5865
+ const fresh = await this.configRegistry.getByRoute(route, language);
5138
5866
  if (fresh) return buildViewsPayload(fresh, baseUrl) ?? viewsPayload;
5139
5867
  }
5140
5868
  return viewsPayload;
@@ -5166,7 +5894,7 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5166
5894
  const { cls } = ctx;
5167
5895
  def(cls, methodName, properties.schemasFn);
5168
5896
  const d = desc(cls, methodName);
5169
- (0, import_common16.Get)(route)(cls.prototype, methodName, d);
5897
+ (0, import_common17.Get)(route)(cls.prototype, methodName, d);
5170
5898
  (0, import_swagger9.ApiOperation)({
5171
5899
  summary: `Get view schemas for ${name}`
5172
5900
  })(cls.prototype, methodName, d);
@@ -5178,7 +5906,7 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5178
5906
  }, "registerSchemas");
5179
5907
 
5180
5908
  // src/lib/crud/operations/register-update.ts
5181
- var import_common17 = require("@nestjs/common");
5909
+ var import_common18 = require("@nestjs/common");
5182
5910
  var import_swagger10 = require("@nestjs/swagger");
5183
5911
  var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5184
5912
  if (!isOperationEnabled(ctx.definition, "update")) return null;
@@ -5192,9 +5920,9 @@ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5192
5920
  return this.repo.update(id, body, req);
5193
5921
  }, "updateFn"),
5194
5922
  decorators: /* @__PURE__ */ __name(() => {
5195
- (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5923
+ (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
5196
5924
  bodyDecorator(updateSchema)(cls.prototype, methodName, 1);
5197
- (0, import_common17.Req)()(cls.prototype, methodName, 2);
5925
+ (0, import_common18.Req)()(cls.prototype, methodName, 2);
5198
5926
  }, "decorators")
5199
5927
  };
5200
5928
  }, "defaultUpdate");
@@ -5206,10 +5934,10 @@ var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
5206
5934
  return this.repo.updateChild(sub, childId, body, req);
5207
5935
  }, "updateFn");
5208
5936
  const decorators = /* @__PURE__ */ __name(() => {
5209
- (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5210
- (0, import_common17.Param)("childId")(cls.prototype, methodName, 1);
5211
- (0, import_common17.Body)()(cls.prototype, methodName, 2);
5212
- (0, import_common17.Req)()(cls.prototype, methodName, 3);
5937
+ (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
5938
+ (0, import_common18.Param)("childId")(cls.prototype, methodName, 1);
5939
+ (0, import_common18.Body)()(cls.prototype, methodName, 2);
5940
+ (0, import_common18.Req)()(cls.prototype, methodName, 3);
5213
5941
  }, "decorators");
5214
5942
  return {
5215
5943
  route: `:id/${sub.childRoute}/:childId`,
@@ -5227,7 +5955,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
5227
5955
  const { cls } = ctx;
5228
5956
  def(cls, methodName, properties.updateFn);
5229
5957
  const d = desc(cls, methodName);
5230
- (0, import_common17.Put)(route)(cls.prototype, methodName, d);
5958
+ (0, import_common18.Put)(route)(cls.prototype, methodName, d);
5231
5959
  (0, import_swagger10.ApiOperation)({
5232
5960
  summary: `Replace a ${name}`
5233
5961
  })(cls.prototype, methodName, d);
@@ -5285,9 +6013,9 @@ function createCrudController(config, baseUrl) {
5285
6013
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
5286
6014
  }
5287
6015
  const bodyDecorator = /* @__PURE__ */ __name((schema, options) => {
5288
- if (!schema) return (0, import_common18.Body)();
5289
- if (isZodSchema(schema)) return (0, import_common18.Body)(new ZodValidationPipe(schema, options));
5290
- return (0, import_common18.Body)();
6016
+ if (!schema) return (0, import_common19.Body)();
6017
+ if (isZodSchema(schema)) return (0, import_common19.Body)(new ZodValidationPipe(schema, options));
6018
+ return (0, import_common19.Body)();
5291
6019
  }, "bodyDecorator");
5292
6020
  const resolveClient = /* @__PURE__ */ __name((registry, resource) => {
5293
6021
  try {
@@ -5305,7 +6033,7 @@ function createCrudController(config, baseUrl) {
5305
6033
  configRegistry;
5306
6034
  constructor(registry, configRegistry) {
5307
6035
  const prisma = resolveClient(registry, config);
5308
- this.repo = createCrudRepository(prisma, config, registry);
6036
+ this.repo = createCrudRepository(prisma, config, registry, configRegistry);
5309
6037
  this.configRegistry = configRegistry;
5310
6038
  }
5311
6039
  };
@@ -5327,7 +6055,7 @@ function createCrudController(config, baseUrl) {
5327
6055
  baseUrl
5328
6056
  };
5329
6057
  registerEndpoints(ctx);
5330
- (0, import_common18.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
6058
+ (0, import_common19.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
5331
6059
  (0, import_swagger11.ApiTags)(tag)(CrudControllerBase);
5332
6060
  Object.defineProperty(CrudControllerBase, "name", {
5333
6061
  value: `${name.charAt(0).toUpperCase() + name.slice(1)}Controller`
@@ -5341,7 +6069,7 @@ function createCrudController(config, baseUrl) {
5341
6069
  __name(createCrudController, "createCrudController");
5342
6070
 
5343
6071
  // src/lib/crud/dev-tools/dev-resources.controller.ts
5344
- var import_common19 = require("@nestjs/common");
6072
+ var import_common20 = require("@nestjs/common");
5345
6073
  var import_swagger12 = require("@nestjs/swagger");
5346
6074
 
5347
6075
  // ../crouton-codegen/src/naming.ts
@@ -5673,7 +6401,7 @@ var fileExists2 = /* @__PURE__ */ __name(async (p) => {
5673
6401
  return false;
5674
6402
  }
5675
6403
  }, "fileExists");
5676
- var clone = /* @__PURE__ */ __name((value) => JSON.parse(JSON.stringify(value)), "clone");
6404
+ var clone2 = /* @__PURE__ */ __name((value) => JSON.parse(JSON.stringify(value)), "clone");
5677
6405
  var deepEqual = /* @__PURE__ */ __name((a, b) => {
5678
6406
  if (a === b) return true;
5679
6407
  if (typeof a !== typeof b) return false;
@@ -5791,7 +6519,7 @@ var recommendedResolver = {
5791
6519
  return out;
5792
6520
  }
5793
6521
  };
5794
- var resolve2 = /* @__PURE__ */ __name(async (diff2, resolver = recommendedResolver) => {
6522
+ var resolve4 = /* @__PURE__ */ __name(async (diff2, resolver = recommendedResolver) => {
5795
6523
  const raw = await resolver.resolve(diff2.decisions, diff2);
5796
6524
  const resolutions = /* @__PURE__ */ new Map();
5797
6525
  for (const d of diff2.decisions) {
@@ -5836,7 +6564,7 @@ var apply = /* @__PURE__ */ __name((resolved, ctx) => {
5836
6564
  const notes = diff2.draft.unwiredRelations.map((r) => `Relation "${r.field}" \u2192 model "${r.targetModel}": target resource not found; left hidden.`);
5837
6565
  const files = [];
5838
6566
  if (diff2.isNew) {
5839
- const config = clone(diff2.draft.config);
6567
+ const config = clone2(diff2.draft.config);
5840
6568
  const addToSidebar = (resolutions.get("sidebar") ?? "yes") !== "no";
5841
6569
  config.sidebar = {
5842
6570
  hide: !addToSidebar
@@ -5850,7 +6578,7 @@ var apply = /* @__PURE__ */ __name((resolved, ctx) => {
5850
6578
  action: "create"
5851
6579
  });
5852
6580
  } else {
5853
- const existing = clone(diff2.existing);
6581
+ const existing = clone2(diff2.existing);
5854
6582
  const draftMap = new Map(columnEntries(diff2.draft.config.columns));
5855
6583
  const entries = columnEntries(existing.columns);
5856
6584
  const indexOf = /* @__PURE__ */ __name((id) => entries.findIndex(([eid]) => eid === id), "indexOf");
@@ -5917,7 +6645,7 @@ var apply = /* @__PURE__ */ __name((resolved, ctx) => {
5917
6645
 
5918
6646
  // ../crouton-codegen/src/commit.ts
5919
6647
  var import_promises3 = require("fs/promises");
5920
- var import_node_path7 = require("path");
6648
+ var import_node_path10 = require("path");
5921
6649
  var commit = /* @__PURE__ */ __name(async (plan, opts = {}) => {
5922
6650
  const written = [];
5923
6651
  const skipped = [];
@@ -5927,7 +6655,7 @@ var commit = /* @__PURE__ */ __name(async (plan, opts = {}) => {
5927
6655
  continue;
5928
6656
  }
5929
6657
  if (!opts.dryRun) {
5930
- await (0, import_promises3.mkdir)((0, import_node_path7.dirname)(file.path), {
6658
+ await (0, import_promises3.mkdir)((0, import_node_path10.dirname)(file.path), {
5931
6659
  recursive: true
5932
6660
  });
5933
6661
  await (0, import_promises3.writeFile)(file.path, file.contents, "utf-8");
@@ -5942,15 +6670,15 @@ var commit = /* @__PURE__ */ __name(async (plan, opts = {}) => {
5942
6670
 
5943
6671
  // ../crouton-codegen/src/config.ts
5944
6672
  var import_promises4 = require("fs/promises");
5945
- var import_node_path8 = require("path");
6673
+ var import_node_path11 = require("path");
5946
6674
  var findConfigPath2 = /* @__PURE__ */ __name(async (cwd) => {
5947
- let dir = (0, import_node_path8.resolve)(cwd);
6675
+ let dir = (0, import_node_path11.resolve)(cwd);
5948
6676
  while (true) {
5949
6677
  for (const name of CONFIG_FILES) {
5950
- const candidate = (0, import_node_path8.join)(dir, name);
6678
+ const candidate = (0, import_node_path11.join)(dir, name);
5951
6679
  if (await fileExists2(candidate)) return candidate;
5952
6680
  }
5953
- const parent = (0, import_node_path8.dirname)(dir);
6681
+ const parent = (0, import_node_path11.dirname)(dir);
5954
6682
  if (parent === dir) return void 0;
5955
6683
  dir = parent;
5956
6684
  }
@@ -5971,7 +6699,7 @@ var loadConfig2 = /* @__PURE__ */ __name(async (cwd) => {
5971
6699
  return {
5972
6700
  config,
5973
6701
  path,
5974
- root: (0, import_node_path8.dirname)(path)
6702
+ root: (0, import_node_path11.dirname)(path)
5975
6703
  };
5976
6704
  }, "loadConfig");
5977
6705
  var validateConfig = /* @__PURE__ */ __name((config, path = "<config>") => {
@@ -5988,7 +6716,7 @@ var loadDatasources = /* @__PURE__ */ __name(async (loaded) => {
5988
6716
  const datasources = [];
5989
6717
  for (const e of entries) {
5990
6718
  if (!e.isDirectory()) continue;
5991
- const jsonPath = (0, import_node_path8.join)(base, e.name, "data-source.json");
6719
+ const jsonPath = (0, import_node_path11.join)(base, e.name, "data-source.json");
5992
6720
  if (!await fileExists2(jsonPath)) continue;
5993
6721
  const ds_json = JSON.parse(await (0, import_promises4.readFile)(jsonPath, "utf-8"));
5994
6722
  const name = ds_json.name ?? e.name;
@@ -6034,29 +6762,29 @@ var makeSchemaExportName = /* @__PURE__ */ __name((config) => {
6034
6762
  const template = config.schemaExportName ?? "{Model}WithRelationsSchema";
6035
6763
  return (prismaName) => template.replace("{Model}", prismaName);
6036
6764
  }, "makeSchemaExportName");
6037
- var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path8.isAbsolute)(p) ? p : (0, import_node_path8.join)(root, p), "resolveFromRoot");
6765
+ var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path11.isAbsolute)(p) ? p : (0, import_node_path11.join)(root, p), "resolveFromRoot");
6038
6766
 
6039
6767
  // ../crouton-codegen/src/scaffold.ts
6040
- var import_zod29 = require("zod");
6768
+ var import_zod30 = require("zod");
6041
6769
  var import_promises5 = require("fs/promises");
6042
- var import_node_path9 = require("path");
6770
+ var import_node_path12 = require("path");
6043
6771
  var ScallfoldDatasourceSchema = DataSourceShape.extend({
6044
6772
  /** Folder name under `dataSourcesDir`. */
6045
- folder: import_zod29.z.string().default("default")
6773
+ folder: import_zod30.z.string().default("default")
6046
6774
  }).transform(transformDataSource);
6047
6775
 
6048
6776
  // ../crouton-codegen/src/datasource-scaffold.ts
6049
- var import_node_path10 = require("path");
6777
+ var import_node_path13 = require("path");
6050
6778
 
6051
6779
  // ../crouton-codegen/src/project.ts
6052
6780
  var import_promises6 = require("fs/promises");
6053
- var import_node_path11 = require("path");
6054
- var resourceDir = /* @__PURE__ */ __name((loaded, name) => (0, import_node_path11.join)(resolveFromRoot(loaded.root, loaded.config.resourcesDir), name), "resourceDir");
6781
+ var import_node_path14 = require("path");
6782
+ var resourceDir = /* @__PURE__ */ __name((loaded, name) => (0, import_node_path14.join)(resolveFromRoot(loaded.root, loaded.config.resourcesDir), name), "resourceDir");
6055
6783
  var readExistingResource = /* @__PURE__ */ __name(async (loaded, name) => {
6056
6784
  const dir = resourceDir(loaded, name);
6057
- const jsonPath = (0, import_node_path11.join)(dir, "resource.json");
6785
+ const jsonPath = (0, import_node_path14.join)(dir, "resource.json");
6058
6786
  const config = await fileExists2(jsonPath) ? JSON.parse(await (0, import_promises6.readFile)(jsonPath, "utf-8")) : null;
6059
- const hasSchemaFile = await fileExists2((0, import_node_path11.join)(dir, "schema.ts")) || await fileExists2((0, import_node_path11.join)(dir, "schema.js"));
6787
+ const hasSchemaFile = await fileExists2((0, import_node_path14.join)(dir, "schema.ts")) || await fileExists2((0, import_node_path14.join)(dir, "schema.js"));
6060
6788
  return {
6061
6789
  config,
6062
6790
  hasSchemaFile
@@ -6079,7 +6807,7 @@ var listResourceNames = /* @__PURE__ */ __name(async (loaded) => {
6079
6807
  const names = [];
6080
6808
  for (const e of entries) {
6081
6809
  if (!e.isDirectory()) continue;
6082
- const jsonPath = (0, import_node_path11.join)(base, e.name, "resource.json");
6810
+ const jsonPath = (0, import_node_path14.join)(base, e.name, "resource.json");
6083
6811
  if (!await fileExists2(jsonPath)) continue;
6084
6812
  if (await isCustomResourceFile(jsonPath)) continue;
6085
6813
  names.push(e.name);
@@ -6118,9 +6846,9 @@ var buildResourceDiffs = /* @__PURE__ */ __name(async (models, deps) => {
6118
6846
 
6119
6847
  // ../crouton-codegen/src/prisma-shell.ts
6120
6848
  var import_node_child_process = require("child_process");
6121
- var import_node_fs4 = require("fs");
6849
+ var import_node_fs7 = require("fs");
6122
6850
  var import_promises7 = require("fs/promises");
6123
- var import_node_path12 = require("path");
6851
+ var import_node_path15 = require("path");
6124
6852
  var run = /* @__PURE__ */ __name((cmd, args, cwd) => new Promise((resolve7) => {
6125
6853
  const child = (0, import_node_child_process.spawn)(cmd, args, {
6126
6854
  cwd,
@@ -6207,7 +6935,7 @@ var fixZodImports = /* @__PURE__ */ __name(async (zodOutputDir) => {
6207
6935
  return;
6208
6936
  }
6209
6937
  for (const entry of entries) {
6210
- const full = (0, import_node_path12.join)(dir, entry.name);
6938
+ const full = (0, import_node_path15.join)(dir, entry.name);
6211
6939
  if (entry.isDirectory()) {
6212
6940
  await walk(full);
6213
6941
  } else if (entry.name.endsWith(".ts")) {
@@ -6256,9 +6984,9 @@ var pullAndGenerate = /* @__PURE__ */ __name(async (input) => {
6256
6984
  };
6257
6985
  }, "pullAndGenerate");
6258
6986
  var normalizeSchema = /* @__PURE__ */ __name(async (schemaPath, configDir) => {
6259
- const dir = configDir ?? (0, import_node_path12.dirname)(schemaPath);
6260
- const configPath = (0, import_node_path12.join)(dir, "normalize-schema.json");
6261
- if (!(0, import_node_fs4.existsSync)(configPath)) return {
6987
+ const dir = configDir ?? (0, import_node_path15.dirname)(schemaPath);
6988
+ const configPath = (0, import_node_path15.join)(dir, "normalize-schema.json");
6989
+ if (!(0, import_node_fs7.existsSync)(configPath)) return {
6262
6990
  renamed: 0
6263
6991
  };
6264
6992
  const config = JSON.parse(await (0, import_promises7.readFile)(configPath, "utf-8"));
@@ -6287,7 +7015,7 @@ var normalizeSchema = /* @__PURE__ */ __name(async (schemaPath, configDir) => {
6287
7015
  }, "normalizeSchema");
6288
7016
 
6289
7017
  // src/lib/crud/resource/ResourceFlags.ts
6290
- var import_node_path13 = require("path");
7018
+ var import_node_path16 = require("path");
6291
7019
  var applyResourceFlagPatch = /* @__PURE__ */ __name((raw, patch) => {
6292
7020
  const result = {
6293
7021
  ...raw
@@ -6328,8 +7056,8 @@ var applyResourceFlagPatch = /* @__PURE__ */ __name((raw, patch) => {
6328
7056
  return result;
6329
7057
  }, "applyResourceFlagPatch");
6330
7058
  var resolveResourcePath = /* @__PURE__ */ __name((resourcesDir, name) => {
6331
- const resolved = (0, import_node_path13.resolve)(resourcesDir, name, "resource.json");
6332
- if (!resolved.startsWith((0, import_node_path13.resolve)(resourcesDir) + "/")) {
7059
+ const resolved = (0, import_node_path16.resolve)(resourcesDir, name, "resource.json");
7060
+ if (!resolved.startsWith((0, import_node_path16.resolve)(resourcesDir) + "/")) {
6333
7061
  throw new Error(`Invalid resource name: "${name}"`);
6334
7062
  }
6335
7063
  return resolved;
@@ -6359,23 +7087,32 @@ var ResourceLoadReportRegistry = class ResourceLoadReportRegistry2 {
6359
7087
  var resourceLoadReportRegistry = new ResourceLoadReportRegistry();
6360
7088
 
6361
7089
  // src/lib/crud/dev-tools/dev-resources.controller.ts
6362
- function _ts_decorate5(decorators, target, key, desc2) {
7090
+ function _ts_decorate6(decorators, target, key, desc2) {
6363
7091
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
6364
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
6365
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7092
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
7093
+ r = Reflect.decorate(decorators, target, key, desc2);
7094
+ } else {
7095
+ for (var i = decorators.length - 1; i >= 0; i--) {
7096
+ if (d = decorators[i]) {
7097
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
7098
+ }
7099
+ }
7100
+ }
6366
7101
  return c > 3 && r && Object.defineProperty(target, key, r), r;
6367
7102
  }
6368
- __name(_ts_decorate5, "_ts_decorate");
6369
- function _ts_metadata4(k, v) {
6370
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
7103
+ __name(_ts_decorate6, "_ts_decorate");
7104
+ function _ts_metadata6(metadataKey, metadataValue) {
7105
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
7106
+ return Reflect.metadata(metadataKey, metadataValue);
7107
+ }
6371
7108
  }
6372
- __name(_ts_metadata4, "_ts_metadata");
6373
- function _ts_param(paramIndex, decorator) {
7109
+ __name(_ts_metadata6, "_ts_metadata");
7110
+ function _ts_param2(paramIndex, decorator) {
6374
7111
  return function(target, key) {
6375
7112
  decorator(target, key, paramIndex);
6376
7113
  };
6377
7114
  }
6378
- __name(_ts_param, "_ts_param");
7115
+ __name(_ts_param2, "_ts_param");
6379
7116
  var DevResourcesController = class {
6380
7117
  static {
6381
7118
  __name(this, "DevResourcesController");
@@ -6388,7 +7125,7 @@ var DevResourcesController = class {
6388
7125
  }
6389
7126
  assertDev() {
6390
7127
  if (!IS_DEV) {
6391
- throw new import_common19.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
7128
+ throw new import_common20.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
6392
7129
  }
6393
7130
  }
6394
7131
  /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */
@@ -6397,14 +7134,14 @@ var DevResourcesController = class {
6397
7134
  try {
6398
7135
  loaded = await loadConfig2(process.cwd());
6399
7136
  } catch (e) {
6400
- throw new import_common19.NotFoundException(e.message ?? "No crouton.json config found.");
7137
+ throw new import_common20.NotFoundException(e.message ?? "No crouton.json config found.");
6401
7138
  }
6402
7139
  const datasources = await loadDatasources(loaded);
6403
7140
  let ds;
6404
7141
  try {
6405
7142
  ds = resolveDatasource(datasources, datasourceName);
6406
7143
  } catch (e) {
6407
- throw new import_common19.BadRequestException(e.message);
7144
+ throw new import_common20.BadRequestException(e.message);
6408
7145
  }
6409
7146
  const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);
6410
7147
  return {
@@ -6419,7 +7156,7 @@ var DevResourcesController = class {
6419
7156
  schemaPath
6420
7157
  });
6421
7158
  } catch (e) {
6422
- throw new import_common19.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
7159
+ throw new import_common20.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
6423
7160
  }
6424
7161
  }
6425
7162
  buildApplyContext(loaded, ds) {
@@ -6489,7 +7226,7 @@ var DevResourcesController = class {
6489
7226
  zodOutputDir: zodDir
6490
7227
  });
6491
7228
  if (!result.ok) {
6492
- throw new import_common19.BadRequestException(`prisma db pull failed:
7229
+ throw new import_common20.BadRequestException(`prisma db pull failed:
6493
7230
  ${result.dbPull.output}`);
6494
7231
  }
6495
7232
  return {
@@ -6506,13 +7243,13 @@ ${result.dbPull.output}`);
6506
7243
  async sync(body) {
6507
7244
  this.assertDev();
6508
7245
  if (!body?.model) {
6509
- throw new import_common19.BadRequestException('"model" is required.');
7246
+ throw new import_common20.BadRequestException('"model" is required.');
6510
7247
  }
6511
7248
  const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);
6512
7249
  const models = await this.introspectModels(schemaPath);
6513
7250
  const model = models.find((m) => m.prismaName === body.model || m.clientAccessor === body.model);
6514
7251
  if (!model) {
6515
- throw new import_common19.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
7252
+ throw new import_common20.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
6516
7253
  }
6517
7254
  const resolveRelationResource = await makeRelationResolver(loaded);
6518
7255
  const diff2 = await buildResourceDiff(model, {
@@ -6521,7 +7258,7 @@ ${result.dbPull.output}`);
6521
7258
  resolveRelationResource,
6522
7259
  readExisting: /* @__PURE__ */ __name((name) => readExistingResource(loaded, name), "readExisting")
6523
7260
  });
6524
- const resolved = await resolve2(diff2, recommendedResolver);
7261
+ const resolved = await resolve4(diff2, recommendedResolver);
6525
7262
  const plan = apply(resolved, this.buildApplyContext(loaded, ds));
6526
7263
  const result = await commit(plan);
6527
7264
  return {
@@ -6545,7 +7282,7 @@ ${result.dbPull.output}`);
6545
7282
  const applyCtx = this.buildApplyContext(loaded, ds);
6546
7283
  const resources = [];
6547
7284
  for (const diff2 of diffs) {
6548
- const resolved = await resolve2(diff2, recommendedResolver);
7285
+ const resolved = await resolve4(diff2, recommendedResolver);
6549
7286
  const writePlan = apply(resolved, applyCtx);
6550
7287
  if (writePlan.files.length === 0 && writePlan.notes.length === 0) continue;
6551
7288
  resources.push({
@@ -6579,7 +7316,7 @@ ${result.dbPull.output}`);
6579
7316
  const applyCtx = this.buildApplyContext(loaded, ds);
6580
7317
  const results = [];
6581
7318
  for (const diff2 of diffs) {
6582
- const resolved = await resolve2(diff2, recommendedResolver);
7319
+ const resolved = await resolve4(diff2, recommendedResolver);
6583
7320
  const writePlan = apply(resolved, applyCtx);
6584
7321
  if (writePlan.files.length === 0) continue;
6585
7322
  const result = await commit(writePlan);
@@ -6634,14 +7371,14 @@ ${result.dbPull.output}`);
6634
7371
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
6635
7372
  const jsonPath = resolveResourcePath(resourcesDir, name);
6636
7373
  const raw = readRawResourceJson(jsonPath);
6637
- if (!raw) throw new import_common19.NotFoundException(`Resource "${name}" not found.`);
6638
- if (jsonPath.endsWith(".ts")) throw new import_common19.ForbiddenException("TypeScript resources cannot be edited.");
7374
+ if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7375
+ if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
6639
7376
  const patched = applyResourceFlagPatch(raw, {
6640
7377
  draft: false
6641
7378
  });
6642
7379
  const result = validateResourceJson(patched);
6643
7380
  if (!result.success) {
6644
- throw new import_common19.BadRequestException(`Validation failed: ${result.error.message}`);
7381
+ throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
6645
7382
  }
6646
7383
  writeRawResourceJson(jsonPath, patched);
6647
7384
  return {
@@ -6654,8 +7391,8 @@ ${result.dbPull.output}`);
6654
7391
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
6655
7392
  const jsonPath = resolveResourcePath(resourcesDir, name);
6656
7393
  const raw = readRawResourceJson(jsonPath);
6657
- if (!raw) throw new import_common19.NotFoundException(`Resource "${name}" not found.`);
6658
- if (jsonPath.endsWith(".ts")) throw new import_common19.ForbiddenException("TypeScript resources cannot be edited.");
7394
+ if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7395
+ if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
6659
7396
  const patched = applyResourceFlagPatch(raw, {
6660
7397
  sidebar: {
6661
7398
  hide: true
@@ -6663,7 +7400,7 @@ ${result.dbPull.output}`);
6663
7400
  });
6664
7401
  const result = validateResourceJson(patched);
6665
7402
  if (!result.success) {
6666
- throw new import_common19.BadRequestException(`Validation failed: ${result.error.message}`);
7403
+ throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
6667
7404
  }
6668
7405
  writeRawResourceJson(jsonPath, patched);
6669
7406
  return {
@@ -6676,8 +7413,8 @@ ${result.dbPull.output}`);
6676
7413
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
6677
7414
  const jsonPath = resolveResourcePath(resourcesDir, name);
6678
7415
  const raw = readRawResourceJson(jsonPath);
6679
- if (!raw) throw new import_common19.NotFoundException(`Resource "${name}" not found.`);
6680
- if (jsonPath.endsWith(".ts")) throw new import_common19.ForbiddenException("TypeScript resources cannot be edited.");
7416
+ if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7417
+ if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
6681
7418
  const sidebarPatch = {
6682
7419
  hide: false
6683
7420
  };
@@ -6690,7 +7427,7 @@ ${result.dbPull.output}`);
6690
7427
  });
6691
7428
  const result = validateResourceJson(patched);
6692
7429
  if (!result.success) {
6693
- throw new import_common19.BadRequestException(`Validation failed: ${result.error.message}`);
7430
+ throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
6694
7431
  }
6695
7432
  writeRawResourceJson(jsonPath, patched);
6696
7433
  return {
@@ -6703,12 +7440,12 @@ ${result.dbPull.output}`);
6703
7440
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
6704
7441
  const jsonPath = resolveResourcePath(resourcesDir, name);
6705
7442
  const raw = readRawResourceJson(jsonPath);
6706
- if (!raw) throw new import_common19.NotFoundException(`Resource "${name}" not found.`);
6707
- if (jsonPath.endsWith(".ts")) throw new import_common19.ForbiddenException("TypeScript resources cannot be edited.");
7443
+ if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7444
+ if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
6708
7445
  const patched = applyResourceFlagPatch(raw, body);
6709
7446
  const result = validateResourceJson(patched);
6710
7447
  if (!result.success) {
6711
- throw new import_common19.BadRequestException(`Validation failed: ${result.error.message}`);
7448
+ throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
6712
7449
  }
6713
7450
  writeRawResourceJson(jsonPath, patched);
6714
7451
  return {
@@ -6716,8 +7453,8 @@ ${result.dbPull.output}`);
6716
7453
  };
6717
7454
  }
6718
7455
  };
6719
- _ts_decorate5([
6720
- (0, import_common19.Get)("models"),
7456
+ _ts_decorate6([
7457
+ (0, import_common20.Get)("models"),
6721
7458
  (0, import_swagger12.ApiOperation)({
6722
7459
  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"
6723
7460
  }),
@@ -6725,12 +7462,12 @@ _ts_decorate5([
6725
7462
  status: 200,
6726
7463
  description: "DB models and their resource/client status"
6727
7464
  }),
6728
- _ts_metadata4("design:type", Function),
6729
- _ts_metadata4("design:paramtypes", []),
6730
- _ts_metadata4("design:returntype", Promise)
7465
+ _ts_metadata6("design:type", Function),
7466
+ _ts_metadata6("design:paramtypes", []),
7467
+ _ts_metadata6("design:returntype", Promise)
6731
7468
  ], DevResourcesController.prototype, "listModels", null);
6732
- _ts_decorate5([
6733
- (0, import_common19.Post)("restart"),
7469
+ _ts_decorate6([
7470
+ (0, import_common20.Post)("restart"),
6734
7471
  (0, import_swagger12.ApiOperation)({
6735
7472
  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."
6736
7473
  }),
@@ -6738,12 +7475,12 @@ _ts_decorate5([
6738
7475
  status: 200,
6739
7476
  description: "Restart scheduled \u2014 the connection will drop shortly after"
6740
7477
  }),
6741
- _ts_metadata4("design:type", Function),
6742
- _ts_metadata4("design:paramtypes", []),
6743
- _ts_metadata4("design:returntype", Object)
7478
+ _ts_metadata6("design:type", Function),
7479
+ _ts_metadata6("design:paramtypes", []),
7480
+ _ts_metadata6("design:returntype", Object)
6744
7481
  ], DevResourcesController.prototype, "restart", null);
6745
- _ts_decorate5([
6746
- (0, import_common19.Post)("pull"),
7482
+ _ts_decorate6([
7483
+ (0, import_common20.Post)("pull"),
6747
7484
  (0, import_swagger12.ApiOperation)({
6748
7485
  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"
6749
7486
  }),
@@ -6751,15 +7488,15 @@ _ts_decorate5([
6751
7488
  status: 200,
6752
7489
  description: "Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes"
6753
7490
  }),
6754
- _ts_param(0, (0, import_common19.Body)()),
6755
- _ts_metadata4("design:type", Function),
6756
- _ts_metadata4("design:paramtypes", [
7491
+ _ts_param2(0, (0, import_common20.Body)()),
7492
+ _ts_metadata6("design:type", Function),
7493
+ _ts_metadata6("design:paramtypes", [
6757
7494
  Object
6758
7495
  ]),
6759
- _ts_metadata4("design:returntype", Promise)
7496
+ _ts_metadata6("design:returntype", Promise)
6760
7497
  ], DevResourcesController.prototype, "pull", null);
6761
- _ts_decorate5([
6762
- (0, import_common19.Post)("sync"),
7498
+ _ts_decorate6([
7499
+ (0, import_common20.Post)("sync"),
6763
7500
  (0, import_swagger12.ApiOperation)({
6764
7501
  summary: "Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)"
6765
7502
  }),
@@ -6767,15 +7504,15 @@ _ts_decorate5([
6767
7504
  status: 200,
6768
7505
  description: "Files written for this resource"
6769
7506
  }),
6770
- _ts_param(0, (0, import_common19.Body)()),
6771
- _ts_metadata4("design:type", Function),
6772
- _ts_metadata4("design:paramtypes", [
7507
+ _ts_param2(0, (0, import_common20.Body)()),
7508
+ _ts_metadata6("design:type", Function),
7509
+ _ts_metadata6("design:paramtypes", [
6773
7510
  Object
6774
7511
  ]),
6775
- _ts_metadata4("design:returntype", Promise)
7512
+ _ts_metadata6("design:returntype", Promise)
6776
7513
  ], DevResourcesController.prototype, "sync", null);
6777
- _ts_decorate5([
6778
- (0, import_common19.Post)("plan"),
7514
+ _ts_decorate6([
7515
+ (0, import_common20.Post)("plan"),
6779
7516
  (0, import_swagger12.ApiOperation)({
6780
7517
  summary: "Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults \u2014 computes what would change, writes nothing"
6781
7518
  }),
@@ -6783,15 +7520,15 @@ _ts_decorate5([
6783
7520
  status: 200,
6784
7521
  description: "Proposed per-resource changes"
6785
7522
  }),
6786
- _ts_param(0, (0, import_common19.Body)()),
6787
- _ts_metadata4("design:type", Function),
6788
- _ts_metadata4("design:paramtypes", [
7523
+ _ts_param2(0, (0, import_common20.Body)()),
7524
+ _ts_metadata6("design:type", Function),
7525
+ _ts_metadata6("design:paramtypes", [
6789
7526
  Object
6790
7527
  ]),
6791
- _ts_metadata4("design:returntype", Promise)
7528
+ _ts_metadata6("design:returntype", Promise)
6792
7529
  ], DevResourcesController.prototype, "plan", null);
6793
- _ts_decorate5([
6794
- (0, import_common19.Post)("apply"),
7530
+ _ts_decorate6([
7531
+ (0, import_common20.Post)("apply"),
6795
7532
  (0, import_swagger12.ApiOperation)({
6796
7533
  summary: "Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults"
6797
7534
  }),
@@ -6799,15 +7536,15 @@ _ts_decorate5([
6799
7536
  status: 200,
6800
7537
  description: "Per-resource commit results"
6801
7538
  }),
6802
- _ts_param(0, (0, import_common19.Body)()),
6803
- _ts_metadata4("design:type", Function),
6804
- _ts_metadata4("design:paramtypes", [
7539
+ _ts_param2(0, (0, import_common20.Body)()),
7540
+ _ts_metadata6("design:type", Function),
7541
+ _ts_metadata6("design:paramtypes", [
6805
7542
  Object
6806
7543
  ]),
6807
- _ts_metadata4("design:returntype", Promise)
7544
+ _ts_metadata6("design:returntype", Promise)
6808
7545
  ], DevResourcesController.prototype, "apply", null);
6809
- _ts_decorate5([
6810
- (0, import_common19.Get)("visibility"),
7546
+ _ts_decorate6([
7547
+ (0, import_common20.Get)("visibility"),
6811
7548
  (0, import_swagger12.ApiOperation)({
6812
7549
  summary: "Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)"
6813
7550
  }),
@@ -6815,12 +7552,12 @@ _ts_decorate5([
6815
7552
  status: 200,
6816
7553
  description: "Resource visibility list"
6817
7554
  }),
6818
- _ts_metadata4("design:type", Function),
6819
- _ts_metadata4("design:paramtypes", []),
6820
- _ts_metadata4("design:returntype", Promise)
7555
+ _ts_metadata6("design:type", Function),
7556
+ _ts_metadata6("design:paramtypes", []),
7557
+ _ts_metadata6("design:returntype", Promise)
6821
7558
  ], DevResourcesController.prototype, "visibility", null);
6822
- _ts_decorate5([
6823
- (0, import_common19.Post)(":name/publish"),
7559
+ _ts_decorate6([
7560
+ (0, import_common20.Post)(":name/publish"),
6824
7561
  (0, import_swagger12.ApiOperation)({
6825
7562
  summary: "Dev-only: publish a draft resource (removes `draft: true` from resource.json)"
6826
7563
  }),
@@ -6828,15 +7565,15 @@ _ts_decorate5([
6828
7565
  status: 200,
6829
7566
  description: "Resource published"
6830
7567
  }),
6831
- _ts_param(0, (0, import_common19.Param)("name")),
6832
- _ts_metadata4("design:type", Function),
6833
- _ts_metadata4("design:paramtypes", [
7568
+ _ts_param2(0, (0, import_common20.Param)("name")),
7569
+ _ts_metadata6("design:type", Function),
7570
+ _ts_metadata6("design:paramtypes", [
6834
7571
  String
6835
7572
  ]),
6836
- _ts_metadata4("design:returntype", Promise)
7573
+ _ts_metadata6("design:returntype", Promise)
6837
7574
  ], DevResourcesController.prototype, "publish", null);
6838
- _ts_decorate5([
6839
- (0, import_common19.Post)(":name/remove-from-menu"),
7575
+ _ts_decorate6([
7576
+ (0, import_common20.Post)(":name/remove-from-menu"),
6840
7577
  (0, import_swagger12.ApiOperation)({
6841
7578
  summary: "Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)"
6842
7579
  }),
@@ -6844,15 +7581,15 @@ _ts_decorate5([
6844
7581
  status: 200,
6845
7582
  description: "Resource removed from menu"
6846
7583
  }),
6847
- _ts_param(0, (0, import_common19.Param)("name")),
6848
- _ts_metadata4("design:type", Function),
6849
- _ts_metadata4("design:paramtypes", [
7584
+ _ts_param2(0, (0, import_common20.Param)("name")),
7585
+ _ts_metadata6("design:type", Function),
7586
+ _ts_metadata6("design:paramtypes", [
6850
7587
  String
6851
7588
  ]),
6852
- _ts_metadata4("design:returntype", Promise)
7589
+ _ts_metadata6("design:returntype", Promise)
6853
7590
  ], DevResourcesController.prototype, "removeFromMenu", null);
6854
- _ts_decorate5([
6855
- (0, import_common19.Post)(":name/add-to-menu"),
7591
+ _ts_decorate6([
7592
+ (0, import_common20.Post)(":name/add-to-menu"),
6856
7593
  (0, import_swagger12.ApiOperation)({
6857
7594
  summary: "Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label"
6858
7595
  }),
@@ -6860,17 +7597,17 @@ _ts_decorate5([
6860
7597
  status: 200,
6861
7598
  description: "Resource added to menu"
6862
7599
  }),
6863
- _ts_param(0, (0, import_common19.Param)("name")),
6864
- _ts_param(1, (0, import_common19.Body)()),
6865
- _ts_metadata4("design:type", Function),
6866
- _ts_metadata4("design:paramtypes", [
7600
+ _ts_param2(0, (0, import_common20.Param)("name")),
7601
+ _ts_param2(1, (0, import_common20.Body)()),
7602
+ _ts_metadata6("design:type", Function),
7603
+ _ts_metadata6("design:paramtypes", [
6867
7604
  String,
6868
7605
  Object
6869
7606
  ]),
6870
- _ts_metadata4("design:returntype", Promise)
7607
+ _ts_metadata6("design:returntype", Promise)
6871
7608
  ], DevResourcesController.prototype, "addToMenu", null);
6872
- _ts_decorate5([
6873
- (0, import_common19.Patch)(":name/flags"),
7609
+ _ts_decorate6([
7610
+ (0, import_common20.Patch)(":name/flags"),
6874
7611
  (0, import_swagger12.ApiOperation)({
6875
7612
  summary: "Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)"
6876
7613
  }),
@@ -6878,55 +7615,55 @@ _ts_decorate5([
6878
7615
  status: 200,
6879
7616
  description: "Flags updated"
6880
7617
  }),
6881
- _ts_param(0, (0, import_common19.Param)("name")),
6882
- _ts_param(1, (0, import_common19.Body)()),
6883
- _ts_metadata4("design:type", Function),
6884
- _ts_metadata4("design:paramtypes", [
7618
+ _ts_param2(0, (0, import_common20.Param)("name")),
7619
+ _ts_param2(1, (0, import_common20.Body)()),
7620
+ _ts_metadata6("design:type", Function),
7621
+ _ts_metadata6("design:paramtypes", [
6885
7622
  String,
6886
7623
  typeof ResourceFlagPatch === "undefined" ? Object : ResourceFlagPatch
6887
7624
  ]),
6888
- _ts_metadata4("design:returntype", Promise)
7625
+ _ts_metadata6("design:returntype", Promise)
6889
7626
  ], DevResourcesController.prototype, "updateFlags", null);
6890
- DevResourcesController = _ts_decorate5([
6891
- (0, import_common19.Controller)("_app/resources"),
7627
+ DevResourcesController = _ts_decorate6([
7628
+ (0, import_common20.Controller)("_app/resources"),
6892
7629
  (0, import_swagger12.ApiTags)("Dev tools"),
6893
- _ts_metadata4("design:type", Function),
6894
- _ts_metadata4("design:paramtypes", [
7630
+ _ts_metadata6("design:type", Function),
7631
+ _ts_metadata6("design:paramtypes", [
6895
7632
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
6896
7633
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
6897
7634
  ])
6898
7635
  ], DevResourcesController);
6899
7636
 
6900
7637
  // src/lib/crud/enum-registry/enum-registry.types.ts
6901
- var import_zod30 = require("zod");
6902
- var EnumEntrySchema = import_zod30.z.object({
6903
- value: import_zod30.z.unknown(),
6904
- label: import_zod30.z.string()
7638
+ var import_zod31 = require("zod");
7639
+ var EnumEntrySchema = import_zod31.z.object({
7640
+ value: import_zod31.z.unknown(),
7641
+ label: import_zod31.z.string()
6905
7642
  });
6906
- var EnumRegistrySchema = import_zod30.z.record(import_zod30.z.string(), import_zod30.z.array(EnumEntrySchema)).default({});
7643
+ var EnumRegistrySchema = import_zod31.z.record(import_zod31.z.string(), import_zod31.z.array(EnumEntrySchema)).default({});
6907
7644
 
6908
7645
  // src/lib/crud/enum-registry/enum-registry.loader.ts
6909
- var import_node_fs5 = require("fs");
6910
- var import_node_path14 = require("path");
7646
+ var import_node_fs8 = require("fs");
7647
+ var import_node_path17 = require("path");
6911
7648
  var ENUMS_FILE = "crouton.enums.json";
6912
7649
  var loadEnumRegistry = /* @__PURE__ */ __name((startDir, enumsFile) => {
6913
7650
  let file = enumsFile;
6914
7651
  if (!file) {
6915
7652
  let dir = startDir;
6916
7653
  while (true) {
6917
- const candidate = (0, import_node_path14.join)(dir, ENUMS_FILE);
6918
- if ((0, import_node_fs5.existsSync)(candidate)) {
7654
+ const candidate = (0, import_node_path17.join)(dir, ENUMS_FILE);
7655
+ if ((0, import_node_fs8.existsSync)(candidate)) {
6919
7656
  file = candidate;
6920
7657
  break;
6921
7658
  }
6922
- const parent = (0, import_node_path14.dirname)(dir);
7659
+ const parent = (0, import_node_path17.dirname)(dir);
6923
7660
  if (parent === dir) break;
6924
7661
  dir = parent;
6925
7662
  }
6926
7663
  }
6927
- if (!file || !(0, import_node_fs5.existsSync)(file)) return EnumRegistrySchema.parse(void 0);
7664
+ if (!file || !(0, import_node_fs8.existsSync)(file)) return EnumRegistrySchema.parse(void 0);
6928
7665
  try {
6929
- return EnumRegistrySchema.parse(JSON.parse((0, import_node_fs5.readFileSync)(file, "utf-8")));
7666
+ return EnumRegistrySchema.parse(JSON.parse((0, import_node_fs8.readFileSync)(file, "utf-8")));
6930
7667
  } catch {
6931
7668
  return EnumRegistrySchema.parse(void 0);
6932
7669
  }
@@ -6985,9 +7722,9 @@ var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
6985
7722
  }, "upsertOp");
6986
7723
 
6987
7724
  // src/lib/crud/adapter/relation-type.ts
6988
- var import_zod31 = require("zod");
7725
+ var import_zod32 = require("zod");
6989
7726
  var unwrapZodType = /* @__PURE__ */ __name((type) => {
6990
- if (type instanceof import_zod31.ZodOptional || type instanceof import_zod31.ZodNullable) {
7727
+ if (type instanceof import_zod32.ZodOptional || type instanceof import_zod32.ZodNullable) {
6991
7728
  return unwrapZodType(type.unwrap());
6992
7729
  }
6993
7730
  return type;
@@ -6997,7 +7734,7 @@ var deriveRelationType = /* @__PURE__ */ __name((schema, columnId) => {
6997
7734
  const field = schema.shape[columnId];
6998
7735
  if (!field) return void 0;
6999
7736
  const inner = unwrapZodType(field);
7000
- return inner instanceof import_zod31.ZodArray ? "oneToMany" : "manyToOne";
7737
+ return inner instanceof import_zod32.ZodArray ? "oneToMany" : "manyToOne";
7001
7738
  }, "deriveRelationType");
7002
7739
  var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
7003
7740
  const base = col.column ?? col.id;
@@ -7027,89 +7764,6 @@ var enrichRelationTypes = /* @__PURE__ */ __name((columns, schema) => {
7027
7764
  });
7028
7765
  }, "enrichRelationTypes");
7029
7766
 
7030
- // src/lib/crud/resource/ReadResourceJson.ts
7031
- var import_node_fs6 = require("fs");
7032
- var import_node_path15 = require("path");
7033
- var readResourceJson = /* @__PURE__ */ __name((jsonPath) => {
7034
- if (!(0, import_node_fs6.existsSync)(jsonPath)) return void 0;
7035
- let fileContent;
7036
- try {
7037
- fileContent = JSON.parse((0, import_node_fs6.readFileSync)(jsonPath, "utf-8"));
7038
- } catch (err) {
7039
- return {
7040
- success: false,
7041
- error: `Invalid JSON in ${jsonPath}: ${err.message}`
7042
- };
7043
- }
7044
- const resource = ResourceJsonSchema.safeParse(fileContent);
7045
- if (resource.error) {
7046
- return {
7047
- success: false,
7048
- error: `Resource cannot be parsed ${jsonPath}: ${resource.error.message}`
7049
- };
7050
- }
7051
- return {
7052
- success: true,
7053
- data: {
7054
- json: resource.data,
7055
- dir: (0, import_node_path15.dirname)(jsonPath)
7056
- }
7057
- };
7058
- }, "readResourceJson");
7059
-
7060
- // src/lib/crud/adapter/resource-resolver.ts
7061
- var import_node_fs7 = require("fs");
7062
- var import_node_path16 = require("path");
7063
- var resolveChildResourceDetailed = /* @__PURE__ */ __name((resourcePath, parentDir) => {
7064
- const attempted = [];
7065
- try {
7066
- if (resourcePath.endsWith(".json")) {
7067
- const directPath = (0, import_node_path16.resolve)(parentDir, resourcePath);
7068
- attempted.push(directPath);
7069
- if ((0, import_node_fs7.existsSync)(directPath)) {
7070
- const result2 = readResourceJson(directPath);
7071
- if (result2?.success) return {
7072
- ok: true,
7073
- value: result2.data
7074
- };
7075
- return {
7076
- ok: false,
7077
- reason: "invalid",
7078
- error: result2?.error ?? `Could not read ${directPath}`
7079
- };
7080
- }
7081
- }
7082
- const childName = resourcePath.replace(/^\.\//, "").replace(/\.resource$/, "");
7083
- const childJsonPath = (0, import_node_path16.resolve)((0, import_node_path16.dirname)(parentDir), childName, "resource.json");
7084
- attempted.push(childJsonPath);
7085
- const result = readResourceJson(childJsonPath);
7086
- if (result?.success) return {
7087
- ok: true,
7088
- value: result.data
7089
- };
7090
- if (result) return {
7091
- ok: false,
7092
- reason: "invalid",
7093
- error: result.error
7094
- };
7095
- return {
7096
- ok: false,
7097
- reason: "missing",
7098
- attempted
7099
- };
7100
- } catch (err) {
7101
- return {
7102
- ok: false,
7103
- reason: "invalid",
7104
- error: err.message
7105
- };
7106
- }
7107
- }, "resolveChildResourceDetailed");
7108
- var resolveChildResource = /* @__PURE__ */ __name((resourcePath, parentDir) => {
7109
- const resolution = resolveChildResourceDetailed(resourcePath, parentDir);
7110
- return resolution.ok ? resolution.value : void 0;
7111
- }, "resolveChildResource");
7112
-
7113
7767
  // src/lib/crud/adapter/column-enrichment.ts
7114
7768
  var enrichActionColumns = /* @__PURE__ */ __name((columns, parentRoute, subResources, baseUrl) => {
7115
7769
  if (!columns) return columns;
@@ -7196,96 +7850,6 @@ var enrichIncludeWithSort = /* @__PURE__ */ __name((include, columns) => {
7196
7850
  });
7197
7851
  }, "enrichIncludeWithSort");
7198
7852
 
7199
- // src/lib/crud/adapter/column-transforms.ts
7200
- var expandExtendColumns = /* @__PURE__ */ __name((columns, dirPath) => {
7201
- if (!dirPath) return columns;
7202
- const result = [];
7203
- for (const col of columns) {
7204
- if (!col.extend) {
7205
- result.push(col);
7206
- continue;
7207
- }
7208
- const resolved = resolveChildResource(col.extend, dirPath);
7209
- if (!resolved) {
7210
- console.warn(`[extend] Could not resolve "${col.extend}" for column "${col.id}" \u2014 keeping as-is`);
7211
- result.push(col);
7212
- continue;
7213
- }
7214
- const refColumns = resolved.json.columns;
7215
- const parentColumnKey = col.column ?? col.id;
7216
- for (const refCol of refColumns) {
7217
- if (refCol.idField) continue;
7218
- const virtualId = `${col.id}_${refCol.id}`;
7219
- const displayKey = refCol.displayKey ? `${refCol.id}.${refCol.displayKey}` : refCol.id;
7220
- const hiddenInTable = col.hiddenInTable === true || refCol.hiddenInTable === true ? true : col.hiddenInTable ?? refCol.hiddenInTable;
7221
- const hiddenInForm = col.hiddenInForm === true || refCol.hiddenInForm === true ? true : col.hiddenInForm ?? refCol.hiddenInForm;
7222
- const hiddenInView = col.hiddenInView === true || refCol.hiddenInView === true ? true : col.hiddenInView ?? refCol.hiddenInView;
7223
- const override = col.columns?.[virtualId] ?? col.columns?.[refCol.id] ?? {};
7224
- const virtualCol = {
7225
- id: virtualId,
7226
- column: parentColumnKey,
7227
- displayKey,
7228
- label: refCol.label ?? refCol.id,
7229
- columnType: "object",
7230
- ...hiddenInTable !== void 0 && {
7231
- hiddenInTable
7232
- },
7233
- ...hiddenInForm !== void 0 && {
7234
- hiddenInForm
7235
- },
7236
- ...hiddenInView !== void 0 && {
7237
- hiddenInView
7238
- },
7239
- ...refCol.sortable != null && {
7240
- sortable: refCol.sortable
7241
- },
7242
- ...refCol.fieldInput && {
7243
- fieldInput: refCol.fieldInput
7244
- },
7245
- ...override
7246
- };
7247
- result.push(virtualCol);
7248
- }
7249
- }
7250
- return result;
7251
- }, "expandExtendColumns");
7252
- var buildValueLabelColumns = /* @__PURE__ */ __name((columns) => (columns ?? []).flatMap((c) => {
7253
- const opts = c.fieldInput?.options;
7254
- if (!opts?.emitObject || !Array.isArray(opts.values)) return [];
7255
- return [
7256
- {
7257
- field: c.column ?? c.id,
7258
- values: opts.values
7259
- }
7260
- ];
7261
- }), "buildValueLabelColumns");
7262
- var applyRelationFormatDefault = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
7263
- const fi = col.fieldInput;
7264
- if (fi && fi.resource && !fi.format && !fi.type) {
7265
- return {
7266
- ...col,
7267
- fieldInput: {
7268
- ...fi,
7269
- format: "relation"
7270
- }
7271
- };
7272
- }
7273
- return col;
7274
- }), "applyRelationFormatDefault");
7275
- var resolveColumnFieldVariants = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
7276
- const fieldView = resolveViewField(col);
7277
- const fieldTable = resolveTableField(col);
7278
- return {
7279
- ...col,
7280
- ...fieldView && {
7281
- fieldView
7282
- },
7283
- ...fieldTable && {
7284
- fieldTable
7285
- }
7286
- };
7287
- }), "resolveColumnFieldVariants");
7288
-
7289
7853
  // src/lib/crud/adapter/sub-resource.builder.ts
7290
7854
  var REMOTE_RESOURCE = /^https?:\/\//i;
7291
7855
  var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentModel, parentDir, enums = {}, baseUrl) => {
@@ -7521,7 +8085,7 @@ var buildLookup = /* @__PURE__ */ __name((columns) => {
7521
8085
  }, "buildLookup");
7522
8086
 
7523
8087
  // src/lib/crud/resource/MigrateResourceJson.ts
7524
- var import_node_fs8 = require("fs");
8088
+ var import_node_fs9 = require("fs");
7525
8089
  var migrateResourceJsonFile = /* @__PURE__ */ __name((jsonPath, opts) => {
7526
8090
  let raw;
7527
8091
  try {
@@ -7562,7 +8126,7 @@ var migrateResourceJsonFile = /* @__PURE__ */ __name((jsonPath, opts) => {
7562
8126
  error: `migrated resource.json (v${from}\u2192v${result.to}) is invalid: ${validation.error.message}`
7563
8127
  };
7564
8128
  }
7565
- (0, import_node_fs8.writeFileSync)(jsonPath, serializeResourceJson(result.raw), "utf-8");
8129
+ (0, import_node_fs9.writeFileSync)(jsonPath, serializeResourceJson(result.raw), "utf-8");
7566
8130
  return {
7567
8131
  status: "migrated",
7568
8132
  from: result.from,
@@ -7581,25 +8145,25 @@ var migrateResourceJsonFile = /* @__PURE__ */ __name((jsonPath, opts) => {
7581
8145
  }, "migrateResourceJsonFile");
7582
8146
 
7583
8147
  // src/lib/crud/loader/index.ts
7584
- var import_node_fs9 = require("fs");
7585
- var import_node_path17 = require("path");
8148
+ var import_node_fs10 = require("fs");
8149
+ var import_node_path18 = require("path");
7586
8150
  var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl, enumsFile, onResourceDir) => {
7587
- if (!(0, import_node_fs9.existsSync)(dirPath)) return [];
8151
+ if (!(0, import_node_fs10.existsSync)(dirPath)) return [];
7588
8152
  resourceLoadErrorsRegistry.clear();
7589
8153
  resourceLoadReportRegistry.clear();
7590
8154
  const enums = loadEnumRegistry(dirPath, enumsFile);
7591
- const entries = (0, import_node_fs9.readdirSync)(dirPath, {
8155
+ const entries = (0, import_node_fs10.readdirSync)(dirPath, {
7592
8156
  withFileTypes: true
7593
8157
  });
7594
8158
  const dirs = entries.filter((e) => e.isDirectory()).map((e) => e.name);
7595
8159
  const configs = [];
7596
8160
  for (const dir of dirs) {
7597
- const basePath = (0, import_node_path17.join)(dirPath, dir);
8161
+ const basePath = (0, import_node_path18.join)(dirPath, dir);
7598
8162
  const schemaFile = findModule(basePath, "schema");
7599
8163
  const schema = schemaFile ? await importDefault(schemaFile) : void 0;
7600
8164
  const hooks = await loadResourceHooks(basePath);
7601
- const jsonFile = (0, import_node_path17.join)(basePath, "resource.json");
7602
- if ((0, import_node_fs9.existsSync)(jsonFile)) {
8165
+ const jsonFile = (0, import_node_path18.join)(basePath, "resource.json");
8166
+ if ((0, import_node_fs10.existsSync)(jsonFile)) {
7603
8167
  const migration = migrateResourceJsonFile(jsonFile, {
7604
8168
  isDev: IS_DEV
7605
8169
  });
@@ -7718,23 +8282,23 @@ var FileSystemResourceConfigLoader = class extends ResourceConfigLoader2 {
7718
8282
  };
7719
8283
 
7720
8284
  // src/lib/crud/status/status.service.ts
7721
- var import_node_fs10 = require("fs");
7722
- var import_node_path18 = require("path");
8285
+ var import_node_fs11 = require("fs");
8286
+ var import_node_path19 = require("path");
7723
8287
  var import_node_url = require("url");
7724
8288
  var DB_CHECK_TIMEOUT_MS = 3e3;
7725
8289
  var CONNECTION_STRING_PATTERN = /(?:postgresql|postgres|mysql|mongodb|sqlserver|sqlite):\/\/[^\s"')]+/gi;
7726
8290
  var stripConnectionStrings = /* @__PURE__ */ __name((message) => message.replace(CONNECTION_STRING_PATTERN, "[REDACTED]"), "stripConnectionStrings");
7727
8291
  var getCroutonVersion = /* @__PURE__ */ __name(() => {
7728
8292
  try {
7729
- const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path18.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
8293
+ const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path19.dirname)((0, import_node_url.fileURLToPath)(importMetaUrl));
7730
8294
  let dir = startDir;
7731
- while (dir !== (0, import_node_path18.dirname)(dir)) {
7732
- const pkgPath = (0, import_node_path18.join)(dir, "package.json");
7733
- if ((0, import_node_fs10.existsSync)(pkgPath)) {
7734
- const pkg = JSON.parse((0, import_node_fs10.readFileSync)(pkgPath, "utf-8"));
8295
+ while (dir !== (0, import_node_path19.dirname)(dir)) {
8296
+ const pkgPath = (0, import_node_path19.join)(dir, "package.json");
8297
+ if ((0, import_node_fs11.existsSync)(pkgPath)) {
8298
+ const pkg = JSON.parse((0, import_node_fs11.readFileSync)(pkgPath, "utf-8"));
7735
8299
  if (pkg.name === "@ghentcdh/crouton-api") return pkg.version;
7736
8300
  }
7737
- dir = (0, import_node_path18.dirname)(dir);
8301
+ dir = (0, import_node_path19.dirname)(dir);
7738
8302
  }
7739
8303
  } catch {
7740
8304
  }
@@ -7919,7 +8483,46 @@ var getEnums = /* @__PURE__ */ __name((enumRegistry) => {
7919
8483
  project: getProjectEnums(enumRegistry)
7920
8484
  };
7921
8485
  }, "getEnums");
7922
- var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumRegistry) => {
8486
+ var countKeys = /* @__PURE__ */ __name((obj, prefix = "") => {
8487
+ let total = 0;
8488
+ let empty = 0;
8489
+ for (const [, v] of Object.entries(obj)) {
8490
+ if (typeof v === "string") {
8491
+ total++;
8492
+ if (v === "") empty++;
8493
+ } else if (v && typeof v === "object" && !Array.isArray(v)) {
8494
+ const sub = countKeys(v, prefix);
8495
+ total += sub.total;
8496
+ empty += sub.empty;
8497
+ }
8498
+ }
8499
+ return {
8500
+ total,
8501
+ empty
8502
+ };
8503
+ }, "countKeys");
8504
+ var getI18nStatus = /* @__PURE__ */ __name((translationRegistry) => {
8505
+ if (!translationRegistry?.active) return void 0;
8506
+ const languages = [
8507
+ ...translationRegistry.languages
8508
+ ];
8509
+ const bundles = languages.map((language) => {
8510
+ const bundle = translationRegistry.bundleFor(language);
8511
+ const { total, empty } = countKeys(bundle);
8512
+ return {
8513
+ language,
8514
+ keyCount: total,
8515
+ emptyKeys: empty
8516
+ };
8517
+ });
8518
+ return {
8519
+ active: true,
8520
+ defaultLanguage: translationRegistry.defaultLanguage,
8521
+ languages,
8522
+ bundles
8523
+ };
8524
+ }, "getI18nStatus");
8525
+ var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumRegistry, translationRegistry) => {
7923
8526
  const databases = await checkDatabases(registry);
7924
8527
  const resources = getResourceStatus(loadedConfigs);
7925
8528
  const summary = buildSummary(databases, resources);
@@ -7930,25 +8533,37 @@ var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumReg
7930
8533
  summary,
7931
8534
  databases,
7932
8535
  resources,
7933
- enums: getEnums(enumRegistry)
8536
+ enums: getEnums(enumRegistry),
8537
+ ...translationRegistry?.active && {
8538
+ i18n: getI18nStatus(translationRegistry)
8539
+ }
7934
8540
  };
7935
8541
  }, "buildStatus");
7936
8542
 
7937
8543
  // src/lib/crud/status/status.controller.ts
7938
- var import_common20 = require("@nestjs/common");
8544
+ var import_common21 = require("@nestjs/common");
7939
8545
  var import_swagger13 = require("@nestjs/swagger");
7940
- function _ts_decorate6(decorators, target, key, desc2) {
8546
+ function _ts_decorate7(decorators, target, key, desc2) {
7941
8547
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
7942
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
7943
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8548
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8549
+ r = Reflect.decorate(decorators, target, key, desc2);
8550
+ } else {
8551
+ for (var i = decorators.length - 1; i >= 0; i--) {
8552
+ if (d = decorators[i]) {
8553
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8554
+ }
8555
+ }
8556
+ }
7944
8557
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7945
8558
  }
7946
- __name(_ts_decorate6, "_ts_decorate");
7947
- function _ts_metadata5(k, v) {
7948
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") return Reflect.metadata(k, v);
8559
+ __name(_ts_decorate7, "_ts_decorate");
8560
+ function _ts_metadata7(metadataKey, metadataValue) {
8561
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
8562
+ return Reflect.metadata(metadataKey, metadataValue);
8563
+ }
7949
8564
  }
7950
- __name(_ts_metadata5, "_ts_metadata");
7951
- var createStatusController = /* @__PURE__ */ __name((enumRegistry) => {
8565
+ __name(_ts_metadata7, "_ts_metadata");
8566
+ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRegistry) => {
7952
8567
  let StatusController = class StatusController {
7953
8568
  static {
7954
8569
  __name(this, "StatusController");
@@ -7961,11 +8576,11 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry) => {
7961
8576
  }
7962
8577
  async getStatus() {
7963
8578
  const configs = await this.configRegistry.getAll();
7964
- return buildStatus(this.dataSourceRegistry, configs, enumRegistry);
8579
+ return buildStatus(this.dataSourceRegistry, configs, enumRegistry, translationRegistry);
7965
8580
  }
7966
8581
  };
7967
- _ts_decorate6([
7968
- (0, import_common20.Get)("status.json"),
8582
+ _ts_decorate7([
8583
+ (0, import_common21.Get)("status.json"),
7969
8584
  (0, import_swagger13.ApiOperation)({
7970
8585
  summary: "Crouton system status (db, resources, version)"
7971
8586
  }),
@@ -7973,15 +8588,15 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry) => {
7973
8588
  status: 200,
7974
8589
  description: "System status"
7975
8590
  }),
7976
- _ts_metadata5("design:type", Function),
7977
- _ts_metadata5("design:paramtypes", []),
7978
- _ts_metadata5("design:returntype", Promise)
8591
+ _ts_metadata7("design:type", Function),
8592
+ _ts_metadata7("design:paramtypes", []),
8593
+ _ts_metadata7("design:returntype", Promise)
7979
8594
  ], StatusController.prototype, "getStatus", null);
7980
- StatusController = _ts_decorate6([
7981
- (0, import_common20.Controller)("crouton"),
8595
+ StatusController = _ts_decorate7([
8596
+ (0, import_common21.Controller)("crouton"),
7982
8597
  (0, import_swagger13.ApiTags)("Status"),
7983
- _ts_metadata5("design:type", Function),
7984
- _ts_metadata5("design:paramtypes", [
8598
+ _ts_metadata7("design:type", Function),
8599
+ _ts_metadata7("design:paramtypes", [
7985
8600
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
7986
8601
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
7987
8602
  ])
@@ -7994,15 +8609,22 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry) => {
7994
8609
  }, "createStatusController");
7995
8610
 
7996
8611
  // src/lib/crouton-api.module.ts
7997
- var import_node_path19 = require("path");
8612
+ var import_node_path20 = require("path");
7998
8613
  var import_node_url2 = require("url");
7999
- function _ts_decorate7(decorators, target, key, desc2) {
8614
+ function _ts_decorate8(decorators, target, key, desc2) {
8000
8615
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8001
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") r = Reflect.decorate(decorators, target, key, desc2);
8002
- else for (var i = decorators.length - 1; i >= 0; i--) if (d = decorators[i]) r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8616
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8617
+ r = Reflect.decorate(decorators, target, key, desc2);
8618
+ } else {
8619
+ for (var i = decorators.length - 1; i >= 0; i--) {
8620
+ if (d = decorators[i]) {
8621
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
8622
+ }
8623
+ }
8624
+ }
8003
8625
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8004
8626
  }
8005
- __name(_ts_decorate7, "_ts_decorate");
8627
+ __name(_ts_decorate8, "_ts_decorate");
8006
8628
  var CroutonApiModule = class _CroutonApiModule {
8007
8629
  static {
8008
8630
  __name(this, "CroutonApiModule");
@@ -8016,7 +8638,7 @@ var CroutonApiModule = class _CroutonApiModule {
8016
8638
  }
8017
8639
  static forResources(configs, dataSources, loader, { baseUrl }, config) {
8018
8640
  const dataSourceRegistry = new DataSourceRegistry(dataSources);
8019
- const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path19.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
8641
+ const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path20.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
8020
8642
  const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);
8021
8643
  const validConfigs = [];
8022
8644
  for (const c of configs) {
@@ -8066,15 +8688,21 @@ var CroutonApiModule = class _CroutonApiModule {
8066
8688
  validConfigs.push(c);
8067
8689
  }
8068
8690
  const configRegistry = new ResourceConfigRegistry(loader, validConfigs);
8691
+ let translationRegistry;
8692
+ if (config.i18n) {
8693
+ const translationsDir = (0, import_node_path20.join)(process.cwd(), config.i18n.translationsDir);
8694
+ translationRegistry = new TranslationRegistry2(translationsDir, config.i18n);
8695
+ configRegistry.setTranslationRegistry(translationRegistry);
8696
+ }
8069
8697
  const controllers = [
8070
8698
  ...validConfigs.map((c) => createCrudController(c, baseUrl)),
8071
- createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true),
8699
+ createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true, translationRegistry, config.i18n),
8072
8700
  // Only registered (and thus only visible in Swagger/routing) when the
8073
8701
  // visual resource builder is enabled — see dev-resources.controller.ts.
8074
8702
  ...IS_DEV ? [
8075
8703
  DevResourcesController
8076
8704
  ] : [],
8077
- createStatusController(enumRegistry)
8705
+ createStatusController(enumRegistry, translationRegistry)
8078
8706
  ];
8079
8707
  return {
8080
8708
  module: _CroutonApiModule,
@@ -8091,7 +8719,17 @@ var CroutonApiModule = class _CroutonApiModule {
8091
8719
  {
8092
8720
  provide: ResourceConfigRegistry,
8093
8721
  useValue: configRegistry
8094
- }
8722
+ },
8723
+ ...translationRegistry ? [
8724
+ {
8725
+ provide: TranslationRegistry2,
8726
+ useValue: translationRegistry
8727
+ },
8728
+ {
8729
+ provide: import_core.APP_INTERCEPTOR,
8730
+ useFactory: /* @__PURE__ */ __name(() => new LanguageInterceptor(translationRegistry), "useFactory")
8731
+ }
8732
+ ] : []
8095
8733
  ]
8096
8734
  };
8097
8735
  }
@@ -8109,8 +8747,8 @@ var CroutonApiModule = class _CroutonApiModule {
8109
8747
  return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
8110
8748
  }
8111
8749
  };
8112
- CroutonApiModule = _ts_decorate7([
8113
- (0, import_common21.Module)({
8750
+ CroutonApiModule = _ts_decorate8([
8751
+ (0, import_common22.Module)({
8114
8752
  controllers: [],
8115
8753
  providers: [],
8116
8754
  exports: []