@ghentcdh/crouton-api 0.0.1-alpha.52 → 0.0.1-alpha.54

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
@@ -1359,15 +1359,21 @@ var init_Security_schema = __esm({
1359
1359
  });
1360
1360
 
1361
1361
  // ../crouton-core/src/lib/data-source/Operations.schema.ts
1362
- var import_zod18, OpEntry, BoolOrUpsertSchema, JsonOperationsSchema, buildSubResourceOperations;
1362
+ var import_zod18, ExternalOpEntry, OpEntry, BoolOrUpsertSchema, JsonOperationsSchema, buildSubResourceOperations;
1363
1363
  var init_Operations_schema = __esm({
1364
1364
  "../crouton-core/src/lib/data-source/Operations.schema.ts"() {
1365
1365
  "use strict";
1366
1366
  init_cjs_shims();
1367
1367
  import_zod18 = require("zod");
1368
1368
  init_Security_schema();
1369
+ ExternalOpEntry = import_zod18.z.object({
1370
+ uri: import_zod18.z.string(),
1371
+ method: import_zod18.z.string().optional(),
1372
+ security: SecuritySchema.optional()
1373
+ });
1369
1374
  OpEntry = import_zod18.z.union([
1370
1375
  import_zod18.z.boolean(),
1376
+ ExternalOpEntry,
1371
1377
  import_zod18.z.object({
1372
1378
  security: SecuritySchema.optional()
1373
1379
  })
@@ -1603,14 +1609,6 @@ var init_ResourceJson_schema = __esm({
1603
1609
  ],
1604
1610
  message: '"parent" is only supported on a custom resource. A prisma resource is nested by declaring a relation column on its parent.'
1605
1611
  });
1606
- } else if (obj.model === void 0) {
1607
- ctx.addIssue({
1608
- code: "custom",
1609
- path: [
1610
- "model"
1611
- ],
1612
- message: '"model" is required for a prisma-backed resource. Set "kind": "custom" for a resource with no Prisma model.'
1613
- });
1614
1612
  }
1615
1613
  }, "refineByKind");
1616
1614
  buildResourceJsonSchema = /* @__PURE__ */ __name(() => {
@@ -1625,10 +1623,10 @@ var init_ResourceJson_schema = __esm({
1625
1623
  return import_zod19.z.preprocess((raw) => {
1626
1624
  if (raw && typeof raw === "object" && !Array.isArray(raw)) {
1627
1625
  const obj = raw;
1628
- if (obj["kind"] === void 0) {
1626
+ if (obj["kind"] === void 0 && obj["model"] !== void 0) {
1629
1627
  return {
1630
1628
  ...obj,
1631
- kind: obj["model"] !== void 0 ? "prisma" : "custom"
1629
+ kind: "prisma"
1632
1630
  };
1633
1631
  }
1634
1632
  }
@@ -2841,7 +2839,7 @@ var init_schema_input = __esm({
2841
2839
  });
2842
2840
 
2843
2841
  // ../crouton-core/src/lib/compile/definition.schema.ts
2844
- var import_zod29, OperationDefSchema, UpsertOperationDefSchema, ResourceDefinitionSchema, DefinitionCallbackSchema, DefinitionSchema;
2842
+ var import_zod29, ExternalOperationDefSchema, OperationDefSchema, UpsertOperationDefSchema, ResourceDefinitionSchema, DefinitionCallbackSchema, DefinitionSchema;
2845
2843
  var init_definition_schema = __esm({
2846
2844
  "../crouton-core/src/lib/compile/definition.schema.ts"() {
2847
2845
  "use strict";
@@ -2849,8 +2847,13 @@ var init_definition_schema = __esm({
2849
2847
  import_zod29 = require("zod");
2850
2848
  init_schema_input();
2851
2849
  init_Security_schema();
2850
+ ExternalOperationDefSchema = import_zod29.z.object({
2851
+ uri: import_zod29.z.string(),
2852
+ method: import_zod29.z.string().optional()
2853
+ });
2852
2854
  OperationDefSchema = import_zod29.z.union([
2853
2855
  import_zod29.z.literal(true),
2856
+ ExternalOperationDefSchema,
2854
2857
  import_zod29.z.object({
2855
2858
  schema: SchemaInputSchema.optional(),
2856
2859
  security: SecuritySchema.optional()
@@ -3309,6 +3312,36 @@ var init_module_loader = __esm({
3309
3312
  }
3310
3313
  });
3311
3314
 
3315
+ // src/lib/crud/resource/valueLabel.apply.ts
3316
+ var applyValueLabelColumns, normalizeValueLabels;
3317
+ var init_valueLabel_apply = __esm({
3318
+ "src/lib/crud/resource/valueLabel.apply.ts"() {
3319
+ "use strict";
3320
+ init_cjs_shims();
3321
+ init_src();
3322
+ applyValueLabelColumns = /* @__PURE__ */ __name((row, cols) => {
3323
+ if (!row || !cols?.length) return row;
3324
+ const out = {
3325
+ ...row
3326
+ };
3327
+ for (const { field, values } of cols) {
3328
+ if (field in out) out[field] = toValueLabel(out[field], values);
3329
+ }
3330
+ return out;
3331
+ }, "applyValueLabelColumns");
3332
+ normalizeValueLabels = /* @__PURE__ */ __name((data, cols) => {
3333
+ if (!data || typeof data !== "object" || Array.isArray(data) || !cols?.length) return data;
3334
+ const out = {
3335
+ ...data
3336
+ };
3337
+ for (const { field } of cols) {
3338
+ if (field in out) out[field] = fromValueLabel(out[field]);
3339
+ }
3340
+ return out;
3341
+ }, "normalizeValueLabels");
3342
+ }
3343
+ });
3344
+
3312
3345
  // src/lib/crud/hooks/hooks.types.ts
3313
3346
  var import_zod38, WriteOpSchema, ReadOpSchema, ResourceHooksSchema;
3314
3347
  var init_hooks_types = __esm({
@@ -3358,36 +3391,6 @@ var init_hooks_loader = __esm({
3358
3391
  }
3359
3392
  });
3360
3393
 
3361
- // src/lib/crud/resource/valueLabel.apply.ts
3362
- var applyValueLabelColumns, normalizeValueLabels;
3363
- var init_valueLabel_apply = __esm({
3364
- "src/lib/crud/resource/valueLabel.apply.ts"() {
3365
- "use strict";
3366
- init_cjs_shims();
3367
- init_src();
3368
- applyValueLabelColumns = /* @__PURE__ */ __name((row, cols) => {
3369
- if (!row || !cols?.length) return row;
3370
- const out = {
3371
- ...row
3372
- };
3373
- for (const { field, values } of cols) {
3374
- if (field in out) out[field] = toValueLabel(out[field], values);
3375
- }
3376
- return out;
3377
- }, "applyValueLabelColumns");
3378
- normalizeValueLabels = /* @__PURE__ */ __name((data, cols) => {
3379
- if (!data || typeof data !== "object" || Array.isArray(data) || !cols?.length) return data;
3380
- const out = {
3381
- ...data
3382
- };
3383
- for (const { field } of cols) {
3384
- if (field in out) out[field] = fromValueLabel(out[field]);
3385
- }
3386
- return out;
3387
- }, "normalizeValueLabels");
3388
- }
3389
- });
3390
-
3391
3394
  // src/lib/crud/hooks/hooks.apply.ts
3392
3395
  var hookCtxRead, hookCtxWrite, decorateRows, decorateRow, prepareWrite, postWrite;
3393
3396
  var init_hooks_apply = __esm({
@@ -3484,7 +3487,9 @@ __export(index_exports, {
3484
3487
  buildViews: () => buildViews,
3485
3488
  decorateRow: () => decorateRow,
3486
3489
  decorateRows: () => decorateRows,
3490
+ externalRouteFor: () => externalRouteFor2,
3487
3491
  isOperationEnabled: () => isOperationEnabled2,
3492
+ isOperationExternal: () => isOperationExternal2,
3488
3493
  isRowProcedureAction: () => isRowProcedureAction,
3489
3494
  isTableProcedureAction: () => isTableProcedureAction,
3490
3495
  loadDataSourcesFromDir: () => loadDataSourcesFromDir,
@@ -3507,7 +3512,7 @@ init_src();
3507
3512
 
3508
3513
  // src/lib/crouton-api.module.ts
3509
3514
  init_cjs_shims();
3510
- var import_common24 = require("@nestjs/common");
3515
+ var import_common26 = require("@nestjs/common");
3511
3516
  var import_core2 = require("@nestjs/core");
3512
3517
  init_src();
3513
3518
 
@@ -4365,12 +4370,14 @@ CroutonValidationExceptionFilter = _ts_decorate3([
4365
4370
 
4366
4371
  // src/lib/crud/crud-controller.factory.ts
4367
4372
  init_cjs_shims();
4368
- var import_common21 = require("@nestjs/common");
4373
+ var import_common23 = require("@nestjs/common");
4369
4374
  var import_swagger11 = require("@nestjs/swagger");
4370
4375
  init_src();
4371
4376
 
4372
4377
  // src/lib/crud/crud-repository.factory.ts
4373
4378
  init_cjs_shims();
4379
+ var import_common10 = require("@nestjs/common");
4380
+ init_src();
4374
4381
 
4375
4382
  // src/lib/crud/crud.config.ts
4376
4383
  init_cjs_shims();
@@ -4468,6 +4475,17 @@ var schemaFor2 = /* @__PURE__ */ __name((def2, op) => {
4468
4475
  if (!entry || entry === true) return void 0;
4469
4476
  return entry.schema;
4470
4477
  }, "schemaFor");
4478
+ var isOperationExternal2 = /* @__PURE__ */ __name((def2, op) => {
4479
+ const entry = def2[op];
4480
+ return typeof entry === "object" && entry !== null && "uri" in entry;
4481
+ }, "isOperationExternal");
4482
+ var externalRouteFor2 = /* @__PURE__ */ __name((def2, op) => {
4483
+ const entry = def2[op];
4484
+ if (typeof entry === "object" && entry !== null && "uri" in entry) {
4485
+ return entry.uri;
4486
+ }
4487
+ return void 0;
4488
+ }, "externalRouteFor");
4471
4489
  var upsertOnFor2 = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
4472
4490
  var opSecurity = /* @__PURE__ */ __name((entry) => {
4473
4491
  if (!entry || entry === true) return void 0;
@@ -4573,7 +4591,7 @@ var loadSubResourceRepositories = /* @__PURE__ */ __name(async (subResources, pa
4573
4591
 
4574
4592
  // src/lib/crud/custom-repository/custom-repository.adapter.ts
4575
4593
  init_cjs_shims();
4576
- var import_common5 = require("@nestjs/common");
4594
+ var import_common9 = require("@nestjs/common");
4577
4595
  init_src();
4578
4596
 
4579
4597
  // src/lib/crud/constants.ts
@@ -4584,343 +4602,59 @@ var DEFAULT_ID_FIELD = "id";
4584
4602
 
4585
4603
  // src/lib/crud/data-source/prisma.adapter.ts
4586
4604
  init_cjs_shims();
4587
- var DB_CHECK_TIMEOUT_MS = 3e3;
4588
- var PrismaDataSourceAdapter = class {
4589
- static {
4590
- __name(this, "PrismaDataSourceAdapter");
4591
- }
4592
- kind = "prisma";
4593
- client;
4594
- constructor(prismaClient) {
4595
- this.client = prismaClient;
4596
- }
4597
- supports(model) {
4598
- return typeof this.client?.[model] !== "undefined";
4599
- }
4600
- async healthCheck() {
4601
- const c = this.client;
4602
- await Promise.race([
4603
- c.$queryRaw`SELECT 1`,
4604
- new Promise((_, reject) => setTimeout(() => reject(new Error("Database health check timed out")), DB_CHECK_TIMEOUT_MS))
4605
- ]);
4606
- }
4607
- async disconnect() {
4608
- const c = this.client;
4609
- if (typeof c?.$disconnect === "function") {
4610
- await c.$disconnect();
4611
- }
4612
- }
4613
- };
4614
-
4615
- // src/lib/crud/custom-repository/custom-repository.adapter.ts
4616
- init_hooks();
4605
+ var import_common8 = require("@nestjs/common");
4617
4606
 
4618
- // src/lib/crud/translation/index.ts
4607
+ // src/lib/crud/read.repository.ts
4619
4608
  init_cjs_shims();
4609
+ var import_common6 = require("@nestjs/common");
4610
+ init_src();
4620
4611
 
4621
- // src/lib/crud/translation/language.interceptor.ts
4612
+ // src/lib/crud/custom-repository/child-delegate.ts
4622
4613
  init_cjs_shims();
4623
4614
  var import_common4 = require("@nestjs/common");
4624
4615
  init_src();
4625
- function _ts_decorate4(decorators, target, key, desc2) {
4626
- var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4627
- if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4628
- r = Reflect.decorate(decorators, target, key, desc2);
4629
- } else {
4630
- for (var i = decorators.length - 1; i >= 0; i--) {
4631
- if (d = decorators[i]) {
4632
- r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4633
- }
4634
- }
4635
- }
4636
- return c > 3 && r && Object.defineProperty(target, key, r), r;
4637
- }
4638
- __name(_ts_decorate4, "_ts_decorate");
4639
- function _ts_metadata4(metadataKey, metadataValue) {
4640
- if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4641
- return Reflect.metadata(metadataKey, metadataValue);
4642
- }
4643
- }
4644
- __name(_ts_metadata4, "_ts_metadata");
4645
- var LanguageInterceptor = class {
4646
- static {
4647
- __name(this, "LanguageInterceptor");
4616
+ var childRepositoryFn = /* @__PURE__ */ __name((sub, op, parentName) => {
4617
+ const repo = sub.repository;
4618
+ const method = PARENT_METHOD[op];
4619
+ if (!repo) {
4620
+ throw new import_common4.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" is a custom resource but no repository.ts was loaded for it.`);
4648
4621
  }
4649
- registry;
4650
- constructor(registry2) {
4651
- this.registry = registry2;
4622
+ const fn = repo[method] ?? (op === "patch" ? repo[PARENT_METHOD.update] : void 0);
4623
+ if (typeof fn !== "function") {
4624
+ throw new import_common4.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" does not implement "${method}" in its repository.ts.`);
4652
4625
  }
4653
- intercept(context, next) {
4654
- const http = context.switchToHttp();
4655
- const request = http.getRequest();
4656
- const response = http.getResponse();
4657
- const acceptLanguage = request.headers["accept-language"];
4658
- const resolved = resolveLanguage(acceptLanguage, this.registry.languages, this.registry.defaultLanguage);
4659
- response.setHeader("Vary", "Accept-Language");
4660
- response.setHeader("Content-Language", resolved);
4661
- return runWithLanguage(resolved, () => next.handle());
4626
+ return fn.bind(repo);
4627
+ }, "childRepositoryFn");
4628
+ var childCtx = /* @__PURE__ */ __name(({ parentConfig, prisma, op, parentId, params, id, request }) => ({
4629
+ prisma,
4630
+ dataSources: {
4631
+ resolve: /* @__PURE__ */ __name(() => prisma, "resolve"),
4632
+ entries: /* @__PURE__ */ __name(() => [], "entries")
4633
+ },
4634
+ config: parentConfig,
4635
+ op,
4636
+ offset: params ? offsetOf(params) : 0,
4637
+ ...id !== void 0 && {
4638
+ id
4639
+ },
4640
+ ...request !== void 0 && {
4641
+ request
4642
+ },
4643
+ // Served under the parent's `:id`, so that is the param name here — unlike a
4644
+ // top-level nested resource, which names its own param.
4645
+ parent: {
4646
+ route: parentConfig.route,
4647
+ param: "id",
4648
+ id: parentId
4662
4649
  }
4663
- };
4664
- LanguageInterceptor = _ts_decorate4([
4665
- (0, import_common4.Injectable)(),
4666
- _ts_metadata4("design:type", Function),
4667
- _ts_metadata4("design:paramtypes", [
4668
- typeof TranslationRegistry === "undefined" ? Object : TranslationRegistry
4669
- ])
4670
- ], LanguageInterceptor);
4650
+ }), "childCtx");
4651
+ var parentIdFromRequest = /* @__PURE__ */ __name((request, fallback) => {
4652
+ const raw = request?.params?.id;
4653
+ return raw === void 0 || raw === null || raw === "" ? fallback : raw;
4654
+ }, "parentIdFromRequest");
4671
4655
 
4672
- // src/lib/crud/translation/resolve-value-labels.ts
4673
- init_cjs_shims();
4674
- var resolveValueLabelColumns = /* @__PURE__ */ __name(async (route, bootTimeCols, configRegistry, childRoute) => {
4675
- if (!configRegistry) return bootTimeCols;
4676
- const language = getRequestLanguage();
4677
- if (!language) return bootTimeCols;
4678
- const localized = await configRegistry.getByRoute(route, language);
4679
- if (!localized) return bootTimeCols;
4680
- if (!childRoute) return localized.valueLabelColumns ?? bootTimeCols;
4681
- const sub = (localized.subResources ?? []).find((s) => s.childRoute === childRoute);
4682
- return sub?.valueLabelColumns ?? bootTimeCols;
4683
- }, "resolveValueLabelColumns");
4684
-
4685
- // src/lib/crud/custom-repository/custom-repository.adapter.ts
4686
- var unsupported = /* @__PURE__ */ __name((config, op) => {
4687
- const method = config.parent ? PARENT_METHOD[op] : op;
4688
- throw new import_common5.NotImplementedException(`Resource "${config.name}" enables "${op}" but its repository.ts does not implement "${method}".`);
4689
- }, "unsupported");
4690
- var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources, repository, configRegistry) => {
4691
- const adapter = new PrismaDataSourceAdapter(prisma);
4692
- const repo = repository ?? (prisma && typeof prisma === "object" ? prisma : {});
4693
- const idField = config.idField ?? DEFAULT_ID_FIELD;
4694
- const toId = /* @__PURE__ */ __name((id) => (config.idType ?? DEFAULT_ID_TYPE) === "number" ? +id : String(id), "toId");
4695
- const parentRef = config.parent;
4696
- const parentIdFrom = /* @__PURE__ */ __name((request) => {
4697
- const raw = request?.params?.[parentRef.param];
4698
- if (raw === void 0 || raw === null || raw === "") {
4699
- throw new import_common5.BadRequestException(`Resource "${config.name}" is nested under "${parentRef.route}" but no "${parentRef.param}" was supplied.`);
4700
- }
4701
- return (parentRef.idType ?? "string") === "number" ? +raw : String(raw);
4702
- }, "parentIdFrom");
4703
- const parentCtx = /* @__PURE__ */ __name((request, parentId) => ({
4704
- parent: {
4705
- route: parentRef.route,
4706
- param: parentRef.param,
4707
- id: parentId
4708
- }
4709
- }), "parentCtx");
4710
- const parentHookCtx = /* @__PURE__ */ __name((request) => {
4711
- if (!parentRef) return void 0;
4712
- const raw = request?.params?.[parentRef.param];
4713
- if (raw === void 0 || raw === null || raw === "") return void 0;
4714
- return {
4715
- route: parentRef.route,
4716
- param: parentRef.param,
4717
- id: (parentRef.idType ?? "string") === "number" ? +raw : String(raw)
4718
- };
4719
- }, "parentHookCtx");
4720
- const ctx = /* @__PURE__ */ __name((op, params, id, request) => ({
4721
- prisma,
4722
- dataSources,
4723
- config,
4724
- op,
4725
- offset: params ? offsetOf(params) : 0,
4726
- ...id !== void 0 && {
4727
- id
4728
- },
4729
- ...request !== void 0 && {
4730
- request
4731
- }
4732
- }), "ctx");
4733
- const findAllWithCount = /* @__PURE__ */ __name(async (params, request) => {
4734
- let result;
4735
- if (parentRef) {
4736
- if (!repo.findAllByParent) unsupported(config, "findAll");
4737
- const parentId = parentIdFrom(request);
4738
- result = await repo.findAllByParent(parentId, params, {
4739
- ...ctx("findAll", params, void 0, request),
4740
- ...parentCtx(request, parentId)
4741
- });
4742
- } else {
4743
- if (!repo.findAll) unsupported(config, "findAll");
4744
- result = await repo.findAll(params, ctx("findAll", params, void 0, request));
4745
- }
4746
- const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);
4747
- const target = vlCols === config.valueLabelColumns ? config : {
4748
- hooks: config.hooks,
4749
- valueLabelColumns: vlCols
4750
- };
4751
- const data = await decorateRows(result?.data ?? [], "findAll", target, adapter, request, parentHookCtx(request));
4752
- return {
4753
- data,
4754
- count: result?.count ?? data.length
4755
- };
4756
- }, "findAllWithCount");
4757
- const findOne = /* @__PURE__ */ __name(async (id, request) => {
4758
- let row;
4759
- if (parentRef) {
4760
- if (!repo.findOneByParent) unsupported(config, "findOne");
4761
- const parentId = parentIdFrom(request);
4762
- row = await repo.findOneByParent(parentId, toId(id), {
4763
- ...ctx("findOne", void 0, id, request),
4764
- ...parentCtx(request, parentId)
4765
- });
4766
- } else {
4767
- if (!repo.findOne) unsupported(config, "findOne");
4768
- row = await repo.findOne(toId(id), ctx("findOne", void 0, id, request));
4769
- }
4770
- if (row === null || row === void 0) {
4771
- throw new import_common5.NotFoundException(`${config.name} with id ${id} not found`);
4772
- }
4773
- return decorateRow(row, "findOne", config, adapter, request, parentHookCtx(request));
4774
- }, "findOne");
4775
- const write = /* @__PURE__ */ __name(async (op, data, id, request) => {
4776
- const coercedId = id !== void 0 ? toId(id) : void 0;
4777
- const prepared = /* @__PURE__ */ __name(() => prepareWrite(data, op, config, adapter, coercedId, request, parentHookCtx(request)), "prepared");
4778
- let result;
4779
- if (parentRef) {
4780
- const fn = op === "create" ? repo.createByParent : op === "update" ? repo.updateByParent : repo.patchByParent ?? repo.updateByParent;
4781
- if (!fn) unsupported(config, op);
4782
- const parentId = parentIdFrom(request);
4783
- const nestedCtx = {
4784
- ...ctx(op, void 0, coercedId, request),
4785
- ...parentCtx(request, parentId)
4786
- };
4787
- const body = await prepared();
4788
- result = op === "create" ? await fn(parentId, body, nestedCtx) : await fn(parentId, coercedId, body, nestedCtx);
4789
- } else {
4790
- const fn = op === "create" ? repo.create : op === "update" ? repo.update : repo.patch ?? repo.update;
4791
- if (!fn) unsupported(config, op);
4792
- const body = await prepared();
4793
- result = op === "create" ? await fn(body, ctx("create", void 0, void 0, request)) : await fn(coercedId, body, ctx(op, void 0, coercedId, request));
4794
- }
4795
- return postWrite(result, op, config, adapter, coercedId, request, parentHookCtx(request));
4796
- }, "write");
4797
- const notAChildRepository = /* @__PURE__ */ __name(async () => {
4798
- 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.`);
4799
- }, "notAChildRepository");
4800
- return {
4801
- prisma,
4802
- // Preferred by register-findall: one round trip returns rows and count.
4803
- findAllWithCount,
4804
- findAll: /* @__PURE__ */ __name(async (params, request) => (await findAllWithCount(params, request)).data, "findAll"),
4805
- count: /* @__PURE__ */ __name(async (filter) => (await findAllWithCount({
4806
- page: 1,
4807
- pageSize: 1,
4808
- sort: idField,
4809
- sortDir: "asc",
4810
- filter: filter ?? []
4811
- })).count, "count"),
4812
- findOne,
4813
- create: /* @__PURE__ */ __name((data, request) => write("create", data, void 0, request), "create"),
4814
- update: /* @__PURE__ */ __name((id, data, request) => write("update", data, id, request), "update"),
4815
- patch: /* @__PURE__ */ __name((id, data, request) => write("patch", data, id, request), "patch"),
4816
- delete: /* @__PURE__ */ __name(async (id, request) => {
4817
- const coercedId = toId(id);
4818
- let result;
4819
- if (parentRef) {
4820
- if (!repo.deleteByParent) unsupported(config, "delete");
4821
- const parentId = parentIdFrom(request);
4822
- result = await repo.deleteByParent(parentId, coercedId, {
4823
- ...ctx("delete", void 0, coercedId, request),
4824
- ...parentCtx(request, parentId)
4825
- });
4826
- } else {
4827
- if (!repo.delete) unsupported(config, "delete");
4828
- result = await repo.delete(coercedId, ctx("delete", void 0, coercedId, request));
4829
- }
4830
- return postWrite(result, "delete", config, adapter, coercedId, request, parentHookCtx(request));
4831
- }, "delete"),
4832
- upsert: /* @__PURE__ */ __name(async () => {
4833
- throw new import_common5.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
4834
- }, "upsert"),
4835
- upsertMany: /* @__PURE__ */ __name(async () => {
4836
- throw new import_common5.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
4837
- }, "upsertMany"),
4838
- findAllByParent: notAChildRepository,
4839
- findOneChild: notAChildRepository,
4840
- createChild: notAChildRepository,
4841
- updateChild: notAChildRepository,
4842
- deleteChild: notAChildRepository
4843
- };
4844
- }, "createCustomRepository");
4845
-
4846
- // src/lib/crud/custom-repository/custom-repository.validate.ts
4847
- init_cjs_shims();
4848
- var validateCustomRepository = /* @__PURE__ */ __name((config, repository, adapterClient) => {
4849
- const definition = resolveDefinition2(config);
4850
- const enabled = CUSTOM_OPS.filter((op) => isOperationEnabled2(definition, op));
4851
- const nested = !!config.parent;
4852
- const methodFor = /* @__PURE__ */ __name((op) => nested ? PARENT_METHOD[op] : op, "methodFor");
4853
- if (!repository) {
4854
- if (enabled.length === 0) return void 0;
4855
- if (adapterClient && typeof adapterClient === "object") {
4856
- const missing2 = enabled.filter((op) => typeof adapterClient[methodFor(op)] !== "function");
4857
- if (missing2.length === 0) return void 0;
4858
- }
4859
- return `No repository.ts found. A custom resource implements its own data access; create ${config.name}/repository.ts with a default export implementing: ${enabled.map(methodFor).join(", ")}.`;
4860
- }
4861
- const implemented = /* @__PURE__ */ __name((name) => typeof repository[name] === "function", "implemented");
4862
- const missing = enabled.filter((op) => op === "patch" ? !implemented(methodFor("patch")) && !implemented(methodFor("update")) : !implemented(methodFor(op)));
4863
- if (missing.length) {
4864
- const names = missing.map(methodFor);
4865
- return `repository.ts does not implement ${names.join(", ")}` + (nested ? ` (this resource is nested under "${config.parent.route}", so it implements the parent-aware operations). ` : ". ") + `Either implement them or disable the operation in resource.json ("operations": { "${missing[0]}": false }).`;
4866
- }
4867
- return void 0;
4868
- }, "validateCustomRepository");
4869
-
4870
- // src/lib/crud/crud-repository.factory.ts
4871
- init_hooks();
4872
-
4873
- // src/lib/crud/read.repository.ts
4874
- init_cjs_shims();
4875
- var import_common7 = require("@nestjs/common");
4876
- init_src();
4877
-
4878
- // src/lib/crud/custom-repository/child-delegate.ts
4879
- init_cjs_shims();
4880
- var import_common6 = require("@nestjs/common");
4881
- init_src();
4882
- var childRepositoryFn = /* @__PURE__ */ __name((sub, op, parentName) => {
4883
- const repo = sub.repository;
4884
- const method = PARENT_METHOD[op];
4885
- if (!repo) {
4886
- throw new import_common6.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" is a custom resource but no repository.ts was loaded for it.`);
4887
- }
4888
- const fn = repo[method] ?? (op === "patch" ? repo[PARENT_METHOD.update] : void 0);
4889
- if (typeof fn !== "function") {
4890
- throw new import_common6.NotImplementedException(`Sub-resource "${sub.childRoute}" of "${parentName}" does not implement "${method}" in its repository.ts.`);
4891
- }
4892
- return fn.bind(repo);
4893
- }, "childRepositoryFn");
4894
- var childCtx = /* @__PURE__ */ __name(({ parentConfig, prisma, op, parentId, params, id, request }) => ({
4895
- prisma,
4896
- dataSources: {
4897
- resolve: /* @__PURE__ */ __name(() => prisma, "resolve"),
4898
- entries: /* @__PURE__ */ __name(() => [], "entries")
4899
- },
4900
- config: parentConfig,
4901
- op,
4902
- offset: params ? offsetOf(params) : 0,
4903
- ...id !== void 0 && {
4904
- id
4905
- },
4906
- ...request !== void 0 && {
4907
- request
4908
- },
4909
- // Served under the parent's `:id`, so that is the param name here — unlike a
4910
- // top-level nested resource, which names its own param.
4911
- parent: {
4912
- route: parentConfig.route,
4913
- param: "id",
4914
- id: parentId
4915
- }
4916
- }), "childCtx");
4917
- var parentIdFromRequest = /* @__PURE__ */ __name((request, fallback) => {
4918
- const raw = request?.params?.id;
4919
- return raw === void 0 || raw === null || raw === "" ? fallback : raw;
4920
- }, "parentIdFromRequest");
4921
-
4922
- // src/lib/crud/read.repository.ts
4923
- init_valueLabel_apply();
4656
+ // src/lib/crud/read.repository.ts
4657
+ init_valueLabel_apply();
4924
4658
 
4925
4659
  // src/lib/crud/sql.helpers.ts
4926
4660
  init_cjs_shims();
@@ -5052,6 +4786,73 @@ var buildFindOneIncludes = /* @__PURE__ */ __name((subResources, configInclude)
5052
4786
  };
5053
4787
  }, "buildFindOneIncludes");
5054
4788
 
4789
+ // src/lib/crud/translation/index.ts
4790
+ init_cjs_shims();
4791
+
4792
+ // src/lib/crud/translation/language.interceptor.ts
4793
+ init_cjs_shims();
4794
+ var import_common5 = require("@nestjs/common");
4795
+ init_src();
4796
+ function _ts_decorate4(decorators, target, key, desc2) {
4797
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4798
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4799
+ r = Reflect.decorate(decorators, target, key, desc2);
4800
+ } else {
4801
+ for (var i = decorators.length - 1; i >= 0; i--) {
4802
+ if (d = decorators[i]) {
4803
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4804
+ }
4805
+ }
4806
+ }
4807
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4808
+ }
4809
+ __name(_ts_decorate4, "_ts_decorate");
4810
+ function _ts_metadata4(metadataKey, metadataValue) {
4811
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4812
+ return Reflect.metadata(metadataKey, metadataValue);
4813
+ }
4814
+ }
4815
+ __name(_ts_metadata4, "_ts_metadata");
4816
+ var LanguageInterceptor = class {
4817
+ static {
4818
+ __name(this, "LanguageInterceptor");
4819
+ }
4820
+ registry;
4821
+ constructor(registry2) {
4822
+ this.registry = registry2;
4823
+ }
4824
+ intercept(context, next) {
4825
+ const http = context.switchToHttp();
4826
+ const request = http.getRequest();
4827
+ const response = http.getResponse();
4828
+ const acceptLanguage = request.headers["accept-language"];
4829
+ const resolved = resolveLanguage(acceptLanguage, this.registry.languages, this.registry.defaultLanguage);
4830
+ response.setHeader("Vary", "Accept-Language");
4831
+ response.setHeader("Content-Language", resolved);
4832
+ return runWithLanguage(resolved, () => next.handle());
4833
+ }
4834
+ };
4835
+ LanguageInterceptor = _ts_decorate4([
4836
+ (0, import_common5.Injectable)(),
4837
+ _ts_metadata4("design:type", Function),
4838
+ _ts_metadata4("design:paramtypes", [
4839
+ typeof TranslationRegistry === "undefined" ? Object : TranslationRegistry
4840
+ ])
4841
+ ], LanguageInterceptor);
4842
+
4843
+ // src/lib/crud/translation/resolve-value-labels.ts
4844
+ init_cjs_shims();
4845
+ var resolveValueLabelColumns = /* @__PURE__ */ __name(async (route, bootTimeCols, configRegistry, childRoute) => {
4846
+ if (!configRegistry) return bootTimeCols;
4847
+ const language = getRequestLanguage();
4848
+ if (!language) return bootTimeCols;
4849
+ const localized = await configRegistry.getByRoute(route, language);
4850
+ if (!localized) return bootTimeCols;
4851
+ if (!childRoute) return localized.valueLabelColumns ?? bootTimeCols;
4852
+ const sub = (localized.subResources ?? []).find((s) => s.childRoute === childRoute);
4853
+ return sub?.valueLabelColumns ?? bootTimeCols;
4854
+ }, "resolveValueLabelColumns");
4855
+
5055
4856
  // src/lib/crud/read.repository.ts
5056
4857
  var parseFilterString = /* @__PURE__ */ __name((raw) => {
5057
4858
  const parts = raw.split(":");
@@ -5347,7 +5148,7 @@ var ReadRepository = class {
5347
5148
  }
5348
5149
  }
5349
5150
  const record = await this.prismaModel.findUnique(query);
5350
- if (!record) throw new import_common7.NotFoundException(`${this.config.name} with id ${id} not found`);
5151
+ if (!record) throw new import_common6.NotFoundException(`${this.config.name} with id ${id} not found`);
5351
5152
  const [withCalc] = await mergeCalculatedColumnsForRows([
5352
5153
  record
5353
5154
  ], this.config.calculatedColumns ?? [], this.tableName, this.prisma, this.config.idField ?? "id");
@@ -5441,7 +5242,7 @@ var ReadRepository = class {
5441
5242
  async findOneChild(sub, childId, parentId, request) {
5442
5243
  if (sub.childKind === "custom") {
5443
5244
  if (parentId === void 0) {
5444
- throw new import_common7.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
5245
+ throw new import_common6.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
5445
5246
  }
5446
5247
  const findOne = childRepositoryFn(sub, "findOne", this.config.name);
5447
5248
  const row = await findOne(this.toId(parentId), (sub.idType ?? "string") === "number" ? +childId : String(childId), childCtx({
@@ -5453,7 +5254,7 @@ var ReadRepository = class {
5453
5254
  request
5454
5255
  }));
5455
5256
  if (row === null || row === void 0) {
5456
- throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5257
+ throw new import_common6.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5457
5258
  }
5458
5259
  return sub.hooks?.afterRead ? sub.hooks.afterRead(row, {
5459
5260
  dataSource: this.adapter,
@@ -5478,7 +5279,7 @@ var ReadRepository = class {
5478
5279
  include: includeClause
5479
5280
  }
5480
5281
  });
5481
- if (!record) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5282
+ if (!record) throw new import_common6.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5482
5283
  const [withCalc] = sub.calculatedColumns?.length ? await mergeCalculatedColumnsForRows([
5483
5284
  record
5484
5285
  ], sub.calculatedColumns, sub.childModel, this.prisma, sub.idField ?? "id") : [
@@ -5495,87 +5296,9 @@ var ReadRepository = class {
5495
5296
  }
5496
5297
  };
5497
5298
 
5498
- // src/lib/crud/schema.utils.ts
5299
+ // src/lib/crud/write.repository.ts
5499
5300
  init_cjs_shims();
5500
- var import_zod39 = require("zod");
5501
- init_src();
5502
- function isZodSchema(schema) {
5503
- return schema instanceof import_zod39.ZodObject;
5504
- }
5505
- __name(isZodSchema, "isZodSchema");
5506
- var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
5507
- const anyOf = property?.["anyOf"];
5508
- return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
5509
- }, "isNullableProperty");
5510
- var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
5511
- const { properties, required } = jsonSchema;
5512
- if (!properties || !Array.isArray(required)) return;
5513
- jsonSchema.required = required.filter((key) => !isNullableProperty2(properties[key]));
5514
- }, "dropNullableFromRequired");
5515
- function toJsonSchema2(schema) {
5516
- if (isZodSchema(schema)) {
5517
- let jsonSchema;
5518
- try {
5519
- jsonSchema = (0, import_zod39.toJSONSchema)(schema, {
5520
- target: "openApi3",
5521
- ...jsonSchemaOpts
5522
- });
5523
- } catch {
5524
- return {
5525
- type: "object"
5526
- };
5527
- }
5528
- dropNullableFromRequired2(jsonSchema);
5529
- return jsonSchema;
5530
- }
5531
- return schema;
5532
- }
5533
- __name(toJsonSchema2, "toJsonSchema");
5534
- var unwrap = /* @__PURE__ */ __name((schema) => {
5535
- let s = schema;
5536
- let t = s?._zod?.def?.type;
5537
- while (t === "optional" || t === "nullable" || t === "default" || t === "readonly") {
5538
- s = s._zod.def.innerType;
5539
- t = s?._zod?.def?.type;
5540
- }
5541
- return s;
5542
- }, "unwrap");
5543
- var typeOf = /* @__PURE__ */ __name((schema) => schema?._zod?.def?.type, "typeOf");
5544
- function toSelectFields(schema) {
5545
- if (!isZodSchema(schema)) {
5546
- return Object.keys(schema.properties).reduce((acc, key) => {
5547
- acc[key] = true;
5548
- return acc;
5549
- }, {});
5550
- }
5551
- const result = {};
5552
- for (const [key, value] of Object.entries(schema.shape)) {
5553
- const inner = unwrap(value);
5554
- const t = typeOf(inner);
5555
- if (t === "object") {
5556
- result[key] = {
5557
- select: toSelectFields(inner)
5558
- };
5559
- continue;
5560
- }
5561
- if (t === "array") {
5562
- const element = unwrap(inner._zod.def.element);
5563
- if (typeOf(element) === "object") {
5564
- result[key] = {
5565
- select: toSelectFields(element)
5566
- };
5567
- continue;
5568
- }
5569
- }
5570
- result[key] = true;
5571
- }
5572
- return result;
5573
- }
5574
- __name(toSelectFields, "toSelectFields");
5575
-
5576
- // src/lib/crud/write.repository.ts
5577
- init_cjs_shims();
5578
- var import_common8 = require("@nestjs/common");
5301
+ var import_common7 = require("@nestjs/common");
5579
5302
  init_valueLabel_apply();
5580
5303
  var includeRelationNames = /* @__PURE__ */ __name((include) => new Set((include ?? []).map((e) => typeof e === "string" ? e : e.relation)), "includeRelationNames");
5581
5304
  var PRISMA_RELATION_WRITE_KEYS = /* @__PURE__ */ new Set([
@@ -5626,11 +5349,11 @@ var WriteRepository = class {
5626
5349
  return (this.config.idType ?? "string") === "number" ? +id : String(id);
5627
5350
  }
5628
5351
  notFound(id) {
5629
- return new import_common8.NotFoundException(`${this.config.name} with id ${id} not found`);
5352
+ return new import_common7.NotFoundException(`${this.config.name} with id ${id} not found`);
5630
5353
  }
5631
5354
  upsertWhere(data) {
5632
5355
  const keys = upsertOnFor2(resolveDefinition2(this.config));
5633
- if (!keys) throw new import_common8.BadRequestException(`${this.config.name} has no upsertOn configured`);
5356
+ if (!keys) throw new import_common7.BadRequestException(`${this.config.name} has no upsertOn configured`);
5634
5357
  if (typeof keys === "string") return {
5635
5358
  [keys]: data[keys]
5636
5359
  };
@@ -5748,7 +5471,7 @@ var WriteRepository = class {
5748
5471
  */
5749
5472
  async delegateChildWrite(sub, op, parentId, childId, data, request) {
5750
5473
  if (parentId === void 0) {
5751
- throw new import_common8.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
5474
+ throw new import_common7.BadRequestException(`Sub-resource "${sub.childRoute}" of "${this.config.name}" requires a parent id.`);
5752
5475
  }
5753
5476
  const fn = childRepositoryFn(sub, op, this.config.name);
5754
5477
  const id = childId === void 0 ? void 0 : (sub.idType ?? "string") === "number" ? +childId : String(childId);
@@ -5836,98 +5559,581 @@ var WriteRepository = class {
5836
5559
  if (sub.childKind === "custom") {
5837
5560
  return this.delegateChildWrite(sub, "update", parentIdFromRequest(request), childId, data, request);
5838
5561
  }
5839
- const childModel = this.prisma[sub.childModel];
5840
- if (!childModel) throw new Error(`Prisma model "${sub.childModel}" not found`);
5841
- const id = (sub.idType ?? "string") === "number" ? +childId : String(childId);
5842
- const normalized = normalizeValueLabels(data, sub.valueLabelColumns);
5843
- const afterHook = sub.hooks?.beforeWrite ? await sub.hooks.beforeWrite(normalized, {
5844
- dataSource: this.adapter,
5845
- prisma: this.prisma,
5846
- op: "update",
5847
- id,
5848
- request,
5849
- parent: this.parentHookContext(parentIdFromRequest(request) ?? id)
5850
- }) : normalized;
5851
- const includeKeys = includeRelationNames(sub.include);
5852
- const prepared = Object.fromEntries(Object.entries(afterHook).filter(([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v)));
5562
+ const childModel = this.prisma[sub.childModel];
5563
+ if (!childModel) throw new Error(`Prisma model "${sub.childModel}" not found`);
5564
+ const id = (sub.idType ?? "string") === "number" ? +childId : String(childId);
5565
+ const normalized = normalizeValueLabels(data, sub.valueLabelColumns);
5566
+ const afterHook = sub.hooks?.beforeWrite ? await sub.hooks.beforeWrite(normalized, {
5567
+ dataSource: this.adapter,
5568
+ prisma: this.prisma,
5569
+ op: "update",
5570
+ id,
5571
+ request,
5572
+ parent: this.parentHookContext(parentIdFromRequest(request) ?? id)
5573
+ }) : normalized;
5574
+ const includeKeys = includeRelationNames(sub.include);
5575
+ const prepared = Object.fromEntries(Object.entries(afterHook).filter(([k, v]) => !includeKeys.has(k) || isPrismaRelationWrite(v)));
5576
+ try {
5577
+ const result = await childModel.update({
5578
+ where: {
5579
+ [sub.idField ?? DEFAULT_ID_FIELD]: id
5580
+ },
5581
+ data: prepared
5582
+ });
5583
+ return sub.hooks?.afterWrite ? sub.hooks.afterWrite(result, {
5584
+ dataSource: this.adapter,
5585
+ prisma: this.prisma,
5586
+ op: "update",
5587
+ id,
5588
+ request
5589
+ }) : result;
5590
+ } catch (e) {
5591
+ if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5592
+ throw e;
5593
+ }
5594
+ }
5595
+ /**
5596
+ * Delete a child record. When `parentId` is supplied the foreign key is included in the `where`
5597
+ * clause to prevent cross-parent deletions.
5598
+ * @throws {NotFoundException} When no matching record is found.
5599
+ */
5600
+ async deleteChild(sub, childId, parentId, request) {
5601
+ if (sub.childKind === "custom") {
5602
+ return this.delegateChildWrite(sub, "delete", parentIdFromRequest(request, parentId), childId, void 0, request);
5603
+ }
5604
+ const childModel = this.prisma[sub.childModel];
5605
+ if (!childModel) throw new Error(`Prisma model "${sub.childModel}" not found`);
5606
+ const id = (sub.idType ?? "string") === "number" ? +childId : String(childId);
5607
+ const idField = sub.idField ?? "id";
5608
+ const where = {
5609
+ [idField]: id
5610
+ };
5611
+ if (parentId !== void 0) where[sub.foreignKey] = this.toId(parentId);
5612
+ try {
5613
+ const result = await childModel.deleteMany({
5614
+ where
5615
+ });
5616
+ if (result.count === 0) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5617
+ return sub.hooks?.afterWrite ? sub.hooks.afterWrite(result, {
5618
+ dataSource: this.adapter,
5619
+ prisma: this.prisma,
5620
+ op: "delete",
5621
+ id,
5622
+ request
5623
+ }) : result;
5624
+ } catch (e) {
5625
+ if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common7.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5626
+ throw e;
5627
+ }
5628
+ }
5629
+ };
5630
+
5631
+ // src/lib/crud/data-source/prisma.adapter.ts
5632
+ var DB_CHECK_TIMEOUT_MS = 3e3;
5633
+ var PrismaDataSourceAdapter = class {
5634
+ static {
5635
+ __name(this, "PrismaDataSourceAdapter");
5636
+ }
5637
+ kind = "prisma";
5638
+ client;
5639
+ constructor(prismaClient) {
5640
+ this.client = prismaClient;
5641
+ }
5642
+ supports(model) {
5643
+ return typeof this.client?.[model] !== "undefined";
5644
+ }
5645
+ async healthCheck() {
5646
+ const c = this.client;
5647
+ await Promise.race([
5648
+ c.$queryRaw`SELECT 1`,
5649
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Database health check timed out")), DB_CHECK_TIMEOUT_MS))
5650
+ ]);
5651
+ }
5652
+ async disconnect() {
5653
+ const c = this.client;
5654
+ if (typeof c?.$disconnect === "function") {
5655
+ await c.$disconnect();
5656
+ }
5657
+ }
5658
+ // ── CRUD surface (Phase 2) ────────────────────────────────────────────────
5659
+ // Each method resolves the Prisma delegate, constructs the appropriate
5660
+ // repository, and delegates. Subclasses may override any of these.
5661
+ prismaModel(model) {
5662
+ const delegate = this.client?.[model];
5663
+ if (!delegate) throw new Error(`Model "${model}" not found on the provided PrismaClient.`);
5664
+ return delegate;
5665
+ }
5666
+ async findAll(model, params, ctx) {
5667
+ const prismaModel = this.prismaModel(model);
5668
+ const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);
5669
+ const [data, count] = await Promise.all([
5670
+ reader.findAll(params, ctx.request),
5671
+ reader.count(params.filter ?? [])
5672
+ ]);
5673
+ return {
5674
+ data,
5675
+ count
5676
+ };
5677
+ }
5678
+ async count(model, filter, ctx) {
5679
+ const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, void 0, void 0, ctx.configRegistry);
5680
+ return reader.count(filter);
5681
+ }
5682
+ async findOne(model, id, ctx) {
5683
+ const prismaModel = this.prismaModel(model);
5684
+ const reader = new ReadRepository(prismaModel, this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);
5685
+ try {
5686
+ return await reader.findOne(id, ctx.request);
5687
+ } catch (e) {
5688
+ if (e instanceof import_common8.NotFoundException) return null;
5689
+ throw e;
5690
+ }
5691
+ }
5692
+ async create(model, data, ctx) {
5693
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).create(data, ctx.request);
5694
+ }
5695
+ async update(model, id, data, ctx) {
5696
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).update(id, data, ctx.request);
5697
+ }
5698
+ async patch(model, id, data, ctx) {
5699
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).patch(id, data, ctx.request);
5700
+ }
5701
+ async delete(model, id, ctx) {
5702
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).delete(id, ctx.request);
5703
+ }
5704
+ async findAllByParent(model, parentId, sub, params, ctx) {
5705
+ const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);
5706
+ return reader.findAllByParent(parentId, sub.childRoute, params, ctx.request);
5707
+ }
5708
+ async findOneChild(model, sub, childId, parentId, ctx) {
5709
+ const reader = new ReadRepository(this.prismaModel(model), this, ctx.config, ctx.listSelect, ctx.oneSelect, ctx.configRegistry);
5710
+ try {
5711
+ return await reader.findOneChild(sub, childId, parentId, ctx.request);
5712
+ } catch (e) {
5713
+ if (e instanceof import_common8.NotFoundException) return null;
5714
+ throw e;
5715
+ }
5716
+ }
5717
+ async createChild(model, parentId, sub, data, ctx) {
5718
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).createChild(parentId, sub, data, ctx.request);
5719
+ }
5720
+ async updateChild(model, sub, childId, data, ctx) {
5721
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).updateChild(sub, childId, data, ctx.request);
5722
+ }
5723
+ async deleteChild(model, sub, childId, parentId, ctx) {
5724
+ return new WriteRepository(this.prismaModel(model), this, ctx.config).deleteChild(sub, childId, parentId, ctx.request);
5725
+ }
5726
+ };
5727
+
5728
+ // src/lib/crud/custom-repository/custom-repository.adapter.ts
5729
+ init_hooks();
5730
+ var unsupported = /* @__PURE__ */ __name((config, op) => {
5731
+ const method = config.parent ? PARENT_METHOD[op] : op;
5732
+ throw new import_common9.NotImplementedException(`Resource "${config.name}" enables "${op}" but its repository.ts does not implement "${method}".`);
5733
+ }, "unsupported");
5734
+ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources, repository, configRegistry) => {
5735
+ const adapter = new PrismaDataSourceAdapter(prisma);
5736
+ const repo = repository ?? (prisma && typeof prisma === "object" ? prisma : {});
5737
+ const idField = config.idField ?? DEFAULT_ID_FIELD;
5738
+ const toId = /* @__PURE__ */ __name((id) => (config.idType ?? DEFAULT_ID_TYPE) === "number" ? +id : String(id), "toId");
5739
+ const parentRef = config.parent;
5740
+ const parentIdFrom = /* @__PURE__ */ __name((request) => {
5741
+ const raw = request?.params?.[parentRef.param];
5742
+ if (raw === void 0 || raw === null || raw === "") {
5743
+ throw new import_common9.BadRequestException(`Resource "${config.name}" is nested under "${parentRef.route}" but no "${parentRef.param}" was supplied.`);
5744
+ }
5745
+ return (parentRef.idType ?? "string") === "number" ? +raw : String(raw);
5746
+ }, "parentIdFrom");
5747
+ const parentCtx = /* @__PURE__ */ __name((request, parentId) => ({
5748
+ parent: {
5749
+ route: parentRef.route,
5750
+ param: parentRef.param,
5751
+ id: parentId
5752
+ }
5753
+ }), "parentCtx");
5754
+ const parentHookCtx = /* @__PURE__ */ __name((request) => {
5755
+ if (!parentRef) return void 0;
5756
+ const raw = request?.params?.[parentRef.param];
5757
+ if (raw === void 0 || raw === null || raw === "") return void 0;
5758
+ return {
5759
+ route: parentRef.route,
5760
+ param: parentRef.param,
5761
+ id: (parentRef.idType ?? "string") === "number" ? +raw : String(raw)
5762
+ };
5763
+ }, "parentHookCtx");
5764
+ const ctx = /* @__PURE__ */ __name((op, params, id, request) => ({
5765
+ prisma,
5766
+ dataSources,
5767
+ config,
5768
+ op,
5769
+ offset: params ? offsetOf(params) : 0,
5770
+ ...id !== void 0 && {
5771
+ id
5772
+ },
5773
+ ...request !== void 0 && {
5774
+ request
5775
+ }
5776
+ }), "ctx");
5777
+ const findAllWithCount = /* @__PURE__ */ __name(async (params, request) => {
5778
+ let result;
5779
+ if (parentRef) {
5780
+ if (!repo.findAllByParent) unsupported(config, "findAll");
5781
+ const parentId = parentIdFrom(request);
5782
+ result = await repo.findAllByParent(parentId, params, {
5783
+ ...ctx("findAll", params, void 0, request),
5784
+ ...parentCtx(request, parentId)
5785
+ });
5786
+ } else {
5787
+ if (!repo.findAll) unsupported(config, "findAll");
5788
+ result = await repo.findAll(params, ctx("findAll", params, void 0, request));
5789
+ }
5790
+ const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);
5791
+ const target = vlCols === config.valueLabelColumns ? config : {
5792
+ hooks: config.hooks,
5793
+ valueLabelColumns: vlCols
5794
+ };
5795
+ const data = await decorateRows(result?.data ?? [], "findAll", target, adapter, request, parentHookCtx(request));
5796
+ return {
5797
+ data,
5798
+ count: result?.count ?? data.length
5799
+ };
5800
+ }, "findAllWithCount");
5801
+ const findOne = /* @__PURE__ */ __name(async (id, request) => {
5802
+ let row;
5803
+ if (parentRef) {
5804
+ if (!repo.findOneByParent) unsupported(config, "findOne");
5805
+ const parentId = parentIdFrom(request);
5806
+ row = await repo.findOneByParent(parentId, toId(id), {
5807
+ ...ctx("findOne", void 0, id, request),
5808
+ ...parentCtx(request, parentId)
5809
+ });
5810
+ } else {
5811
+ if (!repo.findOne) unsupported(config, "findOne");
5812
+ row = await repo.findOne(toId(id), ctx("findOne", void 0, id, request));
5813
+ }
5814
+ if (row === null || row === void 0) {
5815
+ throw new import_common9.NotFoundException(`${config.name} with id ${id} not found`);
5816
+ }
5817
+ return decorateRow(row, "findOne", config, adapter, request, parentHookCtx(request));
5818
+ }, "findOne");
5819
+ const write = /* @__PURE__ */ __name(async (op, data, id, request) => {
5820
+ const coercedId = id !== void 0 ? toId(id) : void 0;
5821
+ const prepared = /* @__PURE__ */ __name(() => prepareWrite(data, op, config, adapter, coercedId, request, parentHookCtx(request)), "prepared");
5822
+ let result;
5823
+ if (parentRef) {
5824
+ const fn = op === "create" ? repo.createByParent : op === "update" ? repo.updateByParent : repo.patchByParent ?? repo.updateByParent;
5825
+ if (!fn) unsupported(config, op);
5826
+ const parentId = parentIdFrom(request);
5827
+ const nestedCtx = {
5828
+ ...ctx(op, void 0, coercedId, request),
5829
+ ...parentCtx(request, parentId)
5830
+ };
5831
+ const body = await prepared();
5832
+ result = op === "create" ? await fn(parentId, body, nestedCtx) : await fn(parentId, coercedId, body, nestedCtx);
5833
+ } else {
5834
+ const fn = op === "create" ? repo.create : op === "update" ? repo.update : repo.patch ?? repo.update;
5835
+ if (!fn) unsupported(config, op);
5836
+ const body = await prepared();
5837
+ result = op === "create" ? await fn(body, ctx("create", void 0, void 0, request)) : await fn(coercedId, body, ctx(op, void 0, coercedId, request));
5838
+ }
5839
+ return postWrite(result, op, config, adapter, coercedId, request, parentHookCtx(request));
5840
+ }, "write");
5841
+ const notAChildRepository = /* @__PURE__ */ __name(async () => {
5842
+ throw new import_common9.NotImplementedException(`Resource "${config.name}" is a custom resource; nested sub-resource routes are not supported. Expose the child collection as its own resource instead.`);
5843
+ }, "notAChildRepository");
5844
+ return {
5845
+ prisma,
5846
+ // Preferred by register-findall: one round trip returns rows and count.
5847
+ findAllWithCount,
5848
+ findAll: /* @__PURE__ */ __name(async (params, request) => (await findAllWithCount(params, request)).data, "findAll"),
5849
+ count: /* @__PURE__ */ __name(async (filter) => (await findAllWithCount({
5850
+ page: 1,
5851
+ pageSize: 1,
5852
+ sort: idField,
5853
+ sortDir: "asc",
5854
+ filter: filter ?? []
5855
+ })).count, "count"),
5856
+ findOne,
5857
+ create: /* @__PURE__ */ __name((data, request) => write("create", data, void 0, request), "create"),
5858
+ update: /* @__PURE__ */ __name((id, data, request) => write("update", data, id, request), "update"),
5859
+ patch: /* @__PURE__ */ __name((id, data, request) => write("patch", data, id, request), "patch"),
5860
+ delete: /* @__PURE__ */ __name(async (id, request) => {
5861
+ const coercedId = toId(id);
5862
+ let result;
5863
+ if (parentRef) {
5864
+ if (!repo.deleteByParent) unsupported(config, "delete");
5865
+ const parentId = parentIdFrom(request);
5866
+ result = await repo.deleteByParent(parentId, coercedId, {
5867
+ ...ctx("delete", void 0, coercedId, request),
5868
+ ...parentCtx(request, parentId)
5869
+ });
5870
+ } else {
5871
+ if (!repo.delete) unsupported(config, "delete");
5872
+ result = await repo.delete(coercedId, ctx("delete", void 0, coercedId, request));
5873
+ }
5874
+ return postWrite(result, "delete", config, adapter, coercedId, request, parentHookCtx(request));
5875
+ }, "delete"),
5876
+ upsert: /* @__PURE__ */ __name(async () => {
5877
+ throw new import_common9.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
5878
+ }, "upsert"),
5879
+ upsertMany: /* @__PURE__ */ __name(async () => {
5880
+ throw new import_common9.NotImplementedException(`Resource "${config.name}" is a custom resource; upsert is not part of the repository contract.`);
5881
+ }, "upsertMany"),
5882
+ findAllByParent: notAChildRepository,
5883
+ findOneChild: notAChildRepository,
5884
+ createChild: notAChildRepository,
5885
+ updateChild: notAChildRepository,
5886
+ deleteChild: notAChildRepository
5887
+ };
5888
+ }, "createCustomRepository");
5889
+
5890
+ // src/lib/crud/custom-repository/custom-repository.validate.ts
5891
+ init_cjs_shims();
5892
+ var validateCustomRepository = /* @__PURE__ */ __name((config, repository, adapterClient) => {
5893
+ const definition = resolveDefinition2(config);
5894
+ const enabled = CUSTOM_OPS.filter((op) => isOperationEnabled2(definition, op) && !isOperationExternal2(definition, op));
5895
+ const nested = !!config.parent;
5896
+ const methodFor = /* @__PURE__ */ __name((op) => nested ? PARENT_METHOD[op] : op, "methodFor");
5897
+ if (!repository) {
5898
+ if (enabled.length === 0) return void 0;
5899
+ if (adapterClient && typeof adapterClient === "object") {
5900
+ const missing2 = enabled.filter((op) => typeof adapterClient[methodFor(op)] !== "function");
5901
+ if (missing2.length === 0) return void 0;
5902
+ }
5903
+ return `No repository.ts found. A custom resource implements its own data access; create ${config.name}/repository.ts with a default export implementing: ${enabled.map(methodFor).join(", ")}.`;
5904
+ }
5905
+ const implemented = /* @__PURE__ */ __name((name) => typeof repository[name] === "function", "implemented");
5906
+ const missing = enabled.filter((op) => op === "patch" ? !implemented(methodFor("patch")) && !implemented(methodFor("update")) : !implemented(methodFor(op)));
5907
+ if (missing.length) {
5908
+ const names = missing.map(methodFor);
5909
+ return `repository.ts does not implement ${names.join(", ")}` + (nested ? ` (this resource is nested under "${config.parent.route}", so it implements the parent-aware operations). ` : ". ") + `Either implement them or disable the operation in resource.json ("operations": { "${missing[0]}": false }).`;
5910
+ }
5911
+ return void 0;
5912
+ }, "validateCustomRepository");
5913
+
5914
+ // src/lib/crud/crud-repository.factory.ts
5915
+ init_hooks();
5916
+
5917
+ // src/lib/crud/schema.utils.ts
5918
+ init_cjs_shims();
5919
+ var import_zod39 = require("zod");
5920
+ init_src();
5921
+ function isZodSchema(schema) {
5922
+ return schema instanceof import_zod39.ZodObject;
5923
+ }
5924
+ __name(isZodSchema, "isZodSchema");
5925
+ var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
5926
+ const anyOf = property?.["anyOf"];
5927
+ return Array.isArray(anyOf) && anyOf.some((s) => s?.["type"] === "null");
5928
+ }, "isNullableProperty");
5929
+ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
5930
+ const { properties, required } = jsonSchema;
5931
+ if (!properties || !Array.isArray(required)) return;
5932
+ jsonSchema.required = required.filter((key) => !isNullableProperty2(properties[key]));
5933
+ }, "dropNullableFromRequired");
5934
+ function toJsonSchema2(schema) {
5935
+ if (isZodSchema(schema)) {
5936
+ let jsonSchema;
5853
5937
  try {
5854
- const result = await childModel.update({
5855
- where: {
5856
- [sub.idField ?? DEFAULT_ID_FIELD]: id
5857
- },
5858
- data: prepared
5938
+ jsonSchema = (0, import_zod39.toJSONSchema)(schema, {
5939
+ target: "openApi3",
5940
+ ...jsonSchemaOpts
5859
5941
  });
5860
- return sub.hooks?.afterWrite ? sub.hooks.afterWrite(result, {
5861
- dataSource: this.adapter,
5862
- prisma: this.prisma,
5863
- op: "update",
5864
- id,
5865
- request
5866
- }) : result;
5867
- } catch (e) {
5868
- if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5869
- throw e;
5942
+ } catch {
5943
+ return {
5944
+ type: "object"
5945
+ };
5870
5946
  }
5947
+ dropNullableFromRequired2(jsonSchema);
5948
+ return jsonSchema;
5871
5949
  }
5872
- /**
5873
- * Delete a child record. When `parentId` is supplied the foreign key is included in the `where`
5874
- * clause to prevent cross-parent deletions.
5875
- * @throws {NotFoundException} When no matching record is found.
5876
- */
5877
- async deleteChild(sub, childId, parentId, request) {
5878
- if (sub.childKind === "custom") {
5879
- return this.delegateChildWrite(sub, "delete", parentIdFromRequest(request, parentId), childId, void 0, request);
5950
+ return schema;
5951
+ }
5952
+ __name(toJsonSchema2, "toJsonSchema");
5953
+ var unwrap = /* @__PURE__ */ __name((schema) => {
5954
+ let s = schema;
5955
+ let t = s?._zod?.def?.type;
5956
+ while (t === "optional" || t === "nullable" || t === "default" || t === "readonly") {
5957
+ s = s._zod.def.innerType;
5958
+ t = s?._zod?.def?.type;
5959
+ }
5960
+ return s;
5961
+ }, "unwrap");
5962
+ var typeOf = /* @__PURE__ */ __name((schema) => schema?._zod?.def?.type, "typeOf");
5963
+ function toSelectFields(schema) {
5964
+ if (!isZodSchema(schema)) {
5965
+ return Object.keys(schema.properties).reduce((acc, key) => {
5966
+ acc[key] = true;
5967
+ return acc;
5968
+ }, {});
5969
+ }
5970
+ const result = {};
5971
+ for (const [key, value] of Object.entries(schema.shape)) {
5972
+ const inner = unwrap(value);
5973
+ const t = typeOf(inner);
5974
+ if (t === "object") {
5975
+ result[key] = {
5976
+ select: toSelectFields(inner)
5977
+ };
5978
+ continue;
5880
5979
  }
5881
- const childModel = this.prisma[sub.childModel];
5882
- if (!childModel) throw new Error(`Prisma model "${sub.childModel}" not found`);
5883
- const id = (sub.idType ?? "string") === "number" ? +childId : String(childId);
5884
- const idField = sub.idField ?? "id";
5885
- const where = {
5886
- [idField]: id
5887
- };
5888
- if (parentId !== void 0) where[sub.foreignKey] = this.toId(parentId);
5889
- try {
5890
- const result = await childModel.deleteMany({
5891
- where
5892
- });
5893
- if (result.count === 0) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5894
- return sub.hooks?.afterWrite ? sub.hooks.afterWrite(result, {
5895
- dataSource: this.adapter,
5896
- prisma: this.prisma,
5897
- op: "delete",
5898
- id,
5899
- request
5900
- }) : result;
5901
- } catch (e) {
5902
- if (e?.code === PRISMA_NOT_FOUND_CODE) throw new import_common8.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
5903
- throw e;
5980
+ if (t === "array") {
5981
+ const element = unwrap(inner._zod.def.element);
5982
+ if (typeOf(element) === "object") {
5983
+ result[key] = {
5984
+ select: toSelectFields(element)
5985
+ };
5986
+ continue;
5987
+ }
5904
5988
  }
5989
+ result[key] = true;
5905
5990
  }
5906
- };
5991
+ return result;
5992
+ }
5993
+ __name(toSelectFields, "toSelectFields");
5907
5994
 
5908
5995
  // src/lib/crud/crud-repository.factory.ts
5909
5996
  function createCrudRepository(prisma, config, dataSources, configRegistry) {
5910
- if (config.kind === "custom") {
5911
- return createCustomRepository(prisma, config, dataSources ?? {
5912
- resolve: /* @__PURE__ */ __name(() => prisma, "resolve"),
5913
- entries: /* @__PURE__ */ __name(() => [], "entries")
5914
- }, config.repository, configRegistry);
5915
- }
5916
- if (!config.model) {
5917
- 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.`);
5918
- }
5919
- const model = prisma[config.model];
5920
- if (!model) {
5921
- throw new Error(`Model "${config.model}" not found on the provided PrismaClient. Check the resource config for "${config.name}".`);
5997
+ const fallbackDataSources = dataSources ?? {
5998
+ resolve: /* @__PURE__ */ __name(() => prisma, "resolve"),
5999
+ entries: /* @__PURE__ */ __name(() => [], "entries")
6000
+ };
6001
+ if (config.repository) {
6002
+ return createCustomRepository(prisma, config, fallbackDataSources, config.repository, configRegistry);
5922
6003
  }
6004
+ const resolvedAdapter = dataSources?.resolveAdapter?.(config.database);
6005
+ const adapterModelKey = config.model ?? config.name;
5923
6006
  const definition = resolveDefinition2(config);
5924
6007
  const listSchema = schemaFor2(definition, "findAll");
5925
6008
  const oneSchema = schemaFor2(definition, "findOne");
5926
6009
  const listSelect = listSchema ? toSelectFields(listSchema) : void 0;
5927
6010
  const oneSelect = oneSchema ? toSelectFields(oneSchema) : listSelect;
6011
+ if (resolvedAdapter?.findAll && resolvedAdapter.count) {
6012
+ const baseCtx = {
6013
+ config,
6014
+ op: "n/a",
6015
+ offset: 0,
6016
+ listSelect,
6017
+ oneSelect,
6018
+ configRegistry
6019
+ };
6020
+ const ctx = /* @__PURE__ */ __name((request, op = "findAll", id) => ({
6021
+ ...baseCtx,
6022
+ op,
6023
+ request,
6024
+ ...id !== void 0 && {
6025
+ id
6026
+ }
6027
+ }), "ctx");
6028
+ const mkDecorateFindAll = /* @__PURE__ */ __name((adapter2) => async (rows, request) => {
6029
+ const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);
6030
+ const target = vlCols === config.valueLabelColumns ? config : {
6031
+ hooks: config.hooks,
6032
+ valueLabelColumns: vlCols
6033
+ };
6034
+ return decorateRows(rows, "findAll", target, adapter2, request);
6035
+ }, "mkDecorateFindAll");
6036
+ const decorateFindAll2 = mkDecorateFindAll(resolvedAdapter);
6037
+ const decorateFindOne2 = /* @__PURE__ */ __name((row, request) => decorateRow(row, "findOne", config, resolvedAdapter, request), "decorateFindOne");
6038
+ const prepareData2 = /* @__PURE__ */ __name((data, op, id, request) => prepareWrite(data, op, config, resolvedAdapter, id, request), "prepareData");
6039
+ const postData2 = /* @__PURE__ */ __name((result, op, id, request) => postWrite(result, op, config, resolvedAdapter, id, request), "postData");
6040
+ const toId2 = /* @__PURE__ */ __name((id) => (config.idType ?? "string") === "number" ? +id : String(id), "toId");
6041
+ const adapterFindAllByParent = /* @__PURE__ */ __name(async (parentId, childRoute, params, request) => {
6042
+ if (resolvedAdapter.findAllByParent) {
6043
+ const sub = config.subResources?.find((s) => s.childRoute === childRoute);
6044
+ if (!sub) throw new Error(`No sub-resource "${childRoute}" on "${config.name}"`);
6045
+ return resolvedAdapter.findAllByParent(adapterModelKey, parentId, sub, params, ctx(request, "findAll"));
6046
+ }
6047
+ if (!config.model) throw new Error(`Adapter for "${config.name}" does not implement findAllByParent`);
6048
+ const prismaModel2 = prisma[config.model];
6049
+ const reader2 = new ReadRepository(prismaModel2, resolvedAdapter, config, listSelect, oneSelect, configRegistry);
6050
+ return reader2.findAllByParent(parentId, childRoute, params, request);
6051
+ }, "adapterFindAllByParent");
6052
+ const adapterFindOneChild = /* @__PURE__ */ __name(async (sub, childId, parentId, request) => {
6053
+ if (resolvedAdapter.findOneChild) {
6054
+ const row = await resolvedAdapter.findOneChild(adapterModelKey, sub, childId, parentId, ctx(request, "findOne", childId));
6055
+ if (row === null || row === void 0) throw new import_common10.NotFoundException(`${sub.childRoute} with id ${childId} not found`);
6056
+ return row;
6057
+ }
6058
+ if (!config.model) throw new Error(`Adapter for "${config.name}" does not implement findOneChild`);
6059
+ const prismaModel2 = prisma[config.model];
6060
+ const reader2 = new ReadRepository(prismaModel2, resolvedAdapter, config, listSelect, oneSelect, configRegistry);
6061
+ return reader2.findOneChild(sub, childId, parentId, request);
6062
+ }, "adapterFindOneChild");
6063
+ const prismaModel = config.model ? prisma?.[config.model] : void 0;
6064
+ const writer2 = prismaModel ? new WriteRepository(prismaModel, resolvedAdapter, config) : void 0;
6065
+ return {
6066
+ prisma,
6067
+ findAllWithCount: /* @__PURE__ */ __name(async (params, request) => {
6068
+ const { data, count } = await resolvedAdapter.findAll(adapterModelKey, params, {
6069
+ ...ctx(request, "findAll"),
6070
+ offset: offsetOf(params)
6071
+ });
6072
+ return {
6073
+ data: await decorateFindAll2(data, request),
6074
+ count
6075
+ };
6076
+ }, "findAllWithCount"),
6077
+ findAll: /* @__PURE__ */ __name(async (params, request) => {
6078
+ const { data } = await resolvedAdapter.findAll(adapterModelKey, params, {
6079
+ ...ctx(request, "findAll"),
6080
+ offset: offsetOf(params)
6081
+ });
6082
+ return decorateFindAll2(data, request);
6083
+ }, "findAll"),
6084
+ count: /* @__PURE__ */ __name((filter) => resolvedAdapter.count(adapterModelKey, filter, baseCtx), "count"),
6085
+ findOne: /* @__PURE__ */ __name(async (id, request) => {
6086
+ const row = await resolvedAdapter.findOne(adapterModelKey, id, ctx(request, "findOne", id));
6087
+ if (row === null || row === void 0) throw new import_common10.NotFoundException(`${config.name} with id ${id} not found`);
6088
+ return decorateFindOne2(row, request);
6089
+ }, "findOne"),
6090
+ findAllByParent: adapterFindAllByParent,
6091
+ findOneChild: adapterFindOneChild,
6092
+ create: /* @__PURE__ */ __name(async (data, request) => {
6093
+ const stripped = stripSubResourceKeys(config, data);
6094
+ const prepared = await prepareData2(stripped, "create", void 0, request);
6095
+ const result = await resolvedAdapter.create(adapterModelKey, prepared, ctx(request, "create"));
6096
+ return postData2(result, "create", void 0, request);
6097
+ }, "create"),
6098
+ update: /* @__PURE__ */ __name(async (id, data, request) => {
6099
+ const coercedId = toId2(id);
6100
+ const stripped = stripSubResourceKeys(config, data);
6101
+ const prepared = await prepareData2(stripped, "update", coercedId, request);
6102
+ const result = await resolvedAdapter.update(adapterModelKey, id, prepared, ctx(request, "update", coercedId));
6103
+ return postData2(result, "update", coercedId, request);
6104
+ }, "update"),
6105
+ patch: /* @__PURE__ */ __name(async (id, data, request) => {
6106
+ const coercedId = toId2(id);
6107
+ const stripped = stripSubResourceKeys(config, data);
6108
+ const prepared = await prepareData2(stripped, "patch", coercedId, request);
6109
+ const result = await (resolvedAdapter.patch ?? resolvedAdapter.update)(adapterModelKey, id, prepared, ctx(request, "patch", coercedId));
6110
+ return postData2(result, "patch", coercedId, request);
6111
+ }, "patch"),
6112
+ upsert: writer2 ? writer2.upsert.bind(writer2) : () => Promise.reject(new Error(`upsert not supported for "${config.name}" (no Prisma model)`)),
6113
+ upsertMany: writer2 ? writer2.upsertMany.bind(writer2) : () => Promise.reject(new Error(`upsertMany not supported for "${config.name}" (no Prisma model)`)),
6114
+ delete: /* @__PURE__ */ __name(async (id, request) => {
6115
+ const coercedId = toId2(id);
6116
+ const result = await resolvedAdapter.delete(adapterModelKey, id, ctx(request, "delete", coercedId));
6117
+ return postData2(result, "delete", coercedId, request);
6118
+ }, "delete"),
6119
+ createChild: writer2 ? writer2.createChild.bind(writer2) : () => Promise.reject(new Error(`createChild not supported for "${config.name}" (no Prisma model)`)),
6120
+ updateChild: writer2 ? writer2.updateChild.bind(writer2) : () => Promise.reject(new Error(`updateChild not supported for "${config.name}" (no Prisma model)`)),
6121
+ deleteChild: writer2 ? writer2.deleteChild.bind(writer2) : () => Promise.reject(new Error(`deleteChild not supported for "${config.name}" (no Prisma model)`))
6122
+ };
6123
+ }
6124
+ if (resolvedAdapter && resolvedAdapter.kind !== "prisma") {
6125
+ return createCustomRepository(resolvedAdapter.client, config, fallbackDataSources, void 0, configRegistry);
6126
+ }
6127
+ if (!config.model) {
6128
+ throw new Error(`Resource "${config.name}" has no "model". A prisma-backed resource must name its Prisma model, or point to a datasource with adapter: "custom".`);
6129
+ }
6130
+ const legacyModel = prisma[config.model];
6131
+ if (!legacyModel) {
6132
+ throw new Error(`Model "${config.model}" not found on the provided PrismaClient. Check the resource config for "${config.name}".`);
6133
+ }
5928
6134
  const adapter = new PrismaDataSourceAdapter(prisma);
5929
- const reader = new ReadRepository(model, adapter, config, listSelect, oneSelect, configRegistry);
5930
- const writer = new WriteRepository(model, adapter, config);
6135
+ const reader = new ReadRepository(legacyModel, adapter, config, listSelect, oneSelect, configRegistry);
6136
+ const writer = new WriteRepository(legacyModel, adapter, config);
5931
6137
  const decorateFindAll = /* @__PURE__ */ __name(async (rows, request) => {
5932
6138
  const vlCols = await resolveValueLabelColumns(config.route, config.valueLabelColumns, configRegistry);
5933
6139
  const target = vlCols === config.valueLabelColumns ? config : {
@@ -5986,7 +6192,7 @@ init_cjs_shims();
5986
6192
 
5987
6193
  // src/lib/crud/data-source/data-source.registry.ts
5988
6194
  init_cjs_shims();
5989
- var import_common9 = require("@nestjs/common");
6195
+ var import_common11 = require("@nestjs/common");
5990
6196
  function _ts_decorate5(decorators, target, key, desc2) {
5991
6197
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
5992
6198
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -6065,7 +6271,7 @@ var DataSourceRegistry = class {
6065
6271
  }
6066
6272
  };
6067
6273
  DataSourceRegistry = _ts_decorate5([
6068
- (0, import_common9.Injectable)(),
6274
+ (0, import_common11.Injectable)(),
6069
6275
  _ts_metadata5("design:type", Function),
6070
6276
  _ts_metadata5("design:paramtypes", [
6071
6277
  Array
@@ -6117,15 +6323,27 @@ var loadDataSourcesFromDir = /* @__PURE__ */ __name(async (dirPath) => {
6117
6323
  const exported = mod.default;
6118
6324
  if (!exported) continue;
6119
6325
  if (config.adapter === "custom") {
6120
- if (typeof exported !== "object" || typeof exported.kind !== "string") {
6326
+ if (typeof exported === "function") {
6327
+ const instance = new exported();
6328
+ if (typeof instance.kind !== "string") {
6329
+ resourceLoadErrorsRegistry.record({
6330
+ name: dir,
6331
+ path: indexFile,
6332
+ error: `Custom datasource "${dir}": default-exported class must produce a DataSourceAdapter (object with a "kind" string field).`
6333
+ });
6334
+ continue;
6335
+ }
6336
+ adapter = instance;
6337
+ } else if (typeof exported === "object" && typeof exported.kind === "string") {
6338
+ adapter = exported;
6339
+ } else {
6121
6340
  resourceLoadErrorsRegistry.record({
6122
6341
  name: dir,
6123
6342
  path: indexFile,
6124
- error: `Custom datasource "${dir}": index.ts must default-export a DataSourceAdapter (object with a "kind" string field).`
6343
+ error: `Custom datasource "${dir}": index.ts must default-export a DataSourceAdapter instance or class (with a "kind" string field).`
6125
6344
  });
6126
6345
  continue;
6127
6346
  }
6128
- adapter = exported;
6129
6347
  } else {
6130
6348
  adapter = new PrismaDataSourceAdapter(exported);
6131
6349
  }
@@ -6180,7 +6398,7 @@ init_cjs_shims();
6180
6398
 
6181
6399
  // src/lib/crud/operations/register-actions.ts
6182
6400
  init_cjs_shims();
6183
- var import_common12 = require("@nestjs/common");
6401
+ var import_common14 = require("@nestjs/common");
6184
6402
  var import_swagger2 = require("@nestjs/swagger");
6185
6403
 
6186
6404
  // src/lib/crud/security/index.ts
@@ -6188,12 +6406,12 @@ init_cjs_shims();
6188
6406
 
6189
6407
  // src/lib/crud/security/crouton-security.guard.ts
6190
6408
  init_cjs_shims();
6191
- var import_common11 = require("@nestjs/common");
6409
+ var import_common13 = require("@nestjs/common");
6192
6410
  var import_core = require("@nestjs/core");
6193
6411
 
6194
6412
  // src/lib/crud/security/security-guard.registry.ts
6195
6413
  init_cjs_shims();
6196
- var import_common10 = require("@nestjs/common");
6414
+ var import_common12 = require("@nestjs/common");
6197
6415
  function _ts_decorate6(decorators, target, key, desc2) {
6198
6416
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
6199
6417
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
@@ -6232,7 +6450,7 @@ var SecurityGuardRegistry = class {
6232
6450
  }
6233
6451
  };
6234
6452
  SecurityGuardRegistry = _ts_decorate6([
6235
- (0, import_common10.Injectable)(),
6453
+ (0, import_common12.Injectable)(),
6236
6454
  _ts_metadata6("design:type", Function),
6237
6455
  _ts_metadata6("design:paramtypes", [
6238
6456
  typeof Record === "undefined" ? Object : Record
@@ -6291,7 +6509,7 @@ var CroutonSecurityGuard = class {
6291
6509
  }
6292
6510
  };
6293
6511
  CroutonSecurityGuard = _ts_decorate7([
6294
- (0, import_common11.Injectable)(),
6512
+ (0, import_common13.Injectable)(),
6295
6513
  _ts_metadata7("design:type", Function),
6296
6514
  _ts_metadata7("design:paramtypes", [
6297
6515
  typeof import_core.Reflector === "undefined" ? Object : import_core.Reflector,
@@ -6322,8 +6540,8 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
6322
6540
  return action.procedure(this.repo.prisma, recordId);
6323
6541
  });
6324
6542
  const d = desc(cls, methodName);
6325
- (0, import_common12.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
6326
- (0, import_common12.Param)("recordId")(cls.prototype, methodName, 0);
6543
+ (0, import_common14.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
6544
+ (0, import_common14.Param)("recordId")(cls.prototype, methodName, 0);
6327
6545
  (0, import_swagger2.ApiOperation)({
6328
6546
  summary: `Execute action "${action.label}" on a ${name}`
6329
6547
  })(cls.prototype, methodName, d);
@@ -6337,7 +6555,7 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
6337
6555
  })(cls.prototype, methodName, d);
6338
6556
  const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
6339
6557
  if (sec) {
6340
- (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6558
+ (0, import_common14.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6341
6559
  }
6342
6560
  }
6343
6561
  }, "registerActionRoutes");
@@ -6351,7 +6569,7 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
6351
6569
  return action.procedure(this.repo.prisma);
6352
6570
  });
6353
6571
  const d = desc(cls, methodName);
6354
- (0, import_common12.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
6572
+ (0, import_common14.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
6355
6573
  (0, import_swagger2.ApiOperation)({
6356
6574
  summary: `Execute table action "${action.label ?? action.id}" on ${name}`
6357
6575
  })(cls.prototype, methodName, d);
@@ -6361,17 +6579,18 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
6361
6579
  })(cls.prototype, methodName, d);
6362
6580
  const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
6363
6581
  if (sec) {
6364
- (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6582
+ (0, import_common14.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6365
6583
  }
6366
6584
  }
6367
6585
  }, "registerTableActionRoutes");
6368
6586
 
6369
6587
  // src/lib/crud/operations/register-create.ts
6370
6588
  init_cjs_shims();
6371
- var import_common13 = require("@nestjs/common");
6589
+ var import_common15 = require("@nestjs/common");
6372
6590
  var import_swagger3 = require("@nestjs/swagger");
6373
6591
  var defaultCreate = /* @__PURE__ */ __name((ctx) => {
6374
6592
  if (!isOperationEnabled2(ctx.definition, "create")) return null;
6593
+ if (isOperationExternal2(ctx.definition, "create")) return null;
6375
6594
  const { cls, config, createSchema, bodyDecorator } = ctx;
6376
6595
  const methodName = "create";
6377
6596
  return {
@@ -6385,7 +6604,7 @@ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
6385
6604
  bodyDecorator(createSchema, {
6386
6605
  coerceNullableUndefinedToNull: true
6387
6606
  })(cls.prototype, methodName, 0);
6388
- (0, import_common13.Req)()(cls.prototype, methodName, 1);
6607
+ (0, import_common15.Req)()(cls.prototype, methodName, 1);
6389
6608
  }, "decorators")
6390
6609
  };
6391
6610
  }, "defaultCreate");
@@ -6397,9 +6616,9 @@ var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
6397
6616
  return this.repo.createChild(id, sub, body, req);
6398
6617
  }, "createFn");
6399
6618
  const decorators = /* @__PURE__ */ __name(() => {
6400
- (0, import_common13.Param)("id")(cls.prototype, methodName, 0);
6401
- (0, import_common13.Body)()(cls.prototype, methodName, 1);
6402
- (0, import_common13.Req)()(cls.prototype, methodName, 2);
6619
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
6620
+ (0, import_common15.Body)()(cls.prototype, methodName, 1);
6621
+ (0, import_common15.Req)()(cls.prototype, methodName, 2);
6403
6622
  }, "decorators");
6404
6623
  return {
6405
6624
  route: `:id/${sub.childRoute}`,
@@ -6417,7 +6636,7 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
6417
6636
  const { cls } = ctx;
6418
6637
  def(cls, methodName, properties.createFn);
6419
6638
  const d = desc(cls, methodName);
6420
- (0, import_common13.Post)(route)(cls.prototype, methodName, d);
6639
+ (0, import_common15.Post)(route)(cls.prototype, methodName, d);
6421
6640
  (0, import_swagger3.ApiOperation)({
6422
6641
  summary: `Create a ${name}`
6423
6642
  })(cls.prototype, methodName, d);
@@ -6431,10 +6650,11 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
6431
6650
 
6432
6651
  // src/lib/crud/operations/register-delete.ts
6433
6652
  init_cjs_shims();
6434
- var import_common14 = require("@nestjs/common");
6653
+ var import_common16 = require("@nestjs/common");
6435
6654
  var import_swagger4 = require("@nestjs/swagger");
6436
6655
  var defaultDelete = /* @__PURE__ */ __name((ctx) => {
6437
6656
  if (!isOperationEnabled2(ctx.definition, "delete")) return null;
6657
+ if (isOperationExternal2(ctx.definition, "delete")) return null;
6438
6658
  const { config } = ctx;
6439
6659
  const methodName = "delete";
6440
6660
  const { name } = config;
@@ -6457,9 +6677,9 @@ var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
6457
6677
  return this.repo.deleteChild(sub, childId, parentId, req);
6458
6678
  }, "deleteFn");
6459
6679
  const decorators = /* @__PURE__ */ __name(() => {
6460
- (0, import_common14.Param)("childId")(cls.prototype, methodName, 0);
6461
- (0, import_common14.Param)("id")(cls.prototype, methodName, 1);
6462
- (0, import_common14.Req)()(cls.prototype, methodName, 2);
6680
+ (0, import_common16.Param)("childId")(cls.prototype, methodName, 0);
6681
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 1);
6682
+ (0, import_common16.Req)()(cls.prototype, methodName, 2);
6463
6683
  }, "decorators");
6464
6684
  return {
6465
6685
  route: `:id/${sub.childRoute}/:childId`,
@@ -6477,8 +6697,8 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
6477
6697
  const { methodName, route, name } = properties;
6478
6698
  def(cls, methodName, properties.deleteFn);
6479
6699
  const d = desc(cls, methodName);
6480
- (0, import_common14.Delete)(route)(cls.prototype, methodName, d);
6481
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
6700
+ (0, import_common16.Delete)(route)(cls.prototype, methodName, d);
6701
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
6482
6702
  (0, import_swagger4.ApiOperation)({
6483
6703
  summary: `Delete ${name} record`
6484
6704
  })(cls.prototype, methodName, d);
@@ -6487,13 +6707,13 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
6487
6707
  status: 200
6488
6708
  })(cls.prototype, methodName, d);
6489
6709
  properties.decorators();
6490
- if (!sub) (0, import_common14.Req)()(cls.prototype, methodName, 1);
6710
+ if (!sub) (0, import_common16.Req)()(cls.prototype, methodName, 1);
6491
6711
  ctx.secure(methodName, "delete", sub);
6492
6712
  }, "registerDelete");
6493
6713
 
6494
6714
  // src/lib/crud/operations/register-findall.ts
6495
6715
  init_cjs_shims();
6496
- var import_common15 = require("@nestjs/common");
6716
+ var import_common17 = require("@nestjs/common");
6497
6717
  var import_swagger5 = require("@nestjs/swagger");
6498
6718
 
6499
6719
  // src/lib/crud/request.dto.ts
@@ -6629,6 +6849,7 @@ var findAllByParent = /* @__PURE__ */ __name(async (repo, id, childRoute, params
6629
6849
  }, "findAllByParent");
6630
6850
  var defaultFindAll = /* @__PURE__ */ __name((ctx) => {
6631
6851
  if (!isOperationEnabled2(ctx.definition, "findAll")) return;
6852
+ if (isOperationExternal2(ctx.definition, "findAll")) return;
6632
6853
  const { config } = ctx;
6633
6854
  const lookupLabel = config.lookup?.label;
6634
6855
  const findAll = /* @__PURE__ */ __name(async function(params, q, req) {
@@ -6652,8 +6873,8 @@ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
6652
6873
  return findAllByParent(this.repo, id, sub.childRoute, params, req);
6653
6874
  }, "findAll");
6654
6875
  const decorators = /* @__PURE__ */ __name(() => {
6655
- (0, import_common15.Param)("id")(cls.prototype, methodName, 2);
6656
- (0, import_common15.Req)()(cls.prototype, methodName, 3);
6876
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 2);
6877
+ (0, import_common17.Req)()(cls.prototype, methodName, 3);
6657
6878
  }, "decorators");
6658
6879
  return {
6659
6880
  name: sub.childRoute,
@@ -6672,10 +6893,10 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
6672
6893
  const { cls } = ctx;
6673
6894
  def(cls, methodName, properties.findAll);
6674
6895
  const d = desc(cls, methodName);
6675
- (0, import_common15.Get)(route)(cls.prototype, methodName, d);
6676
- (0, import_common15.Query)(new ZodValidationPipe(RequestDtoNoOffset.schema))(cls.prototype, methodName, 0);
6677
- (0, import_common15.Query)("q")(cls.prototype, methodName, 1);
6678
- if (!sub) (0, import_common15.Req)()(cls.prototype, methodName, 2);
6896
+ (0, import_common17.Get)(route)(cls.prototype, methodName, d);
6897
+ (0, import_common17.Query)(new ZodValidationPipe(RequestDtoNoOffset.schema))(cls.prototype, methodName, 0);
6898
+ (0, import_common17.Query)("q")(cls.prototype, methodName, 1);
6899
+ if (!sub) (0, import_common17.Req)()(cls.prototype, methodName, 2);
6679
6900
  (0, import_swagger5.ApiOperation)({
6680
6901
  summary: `List all ${name}s`
6681
6902
  })(cls.prototype, methodName, d);
@@ -6695,10 +6916,11 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
6695
6916
 
6696
6917
  // src/lib/crud/operations/register-findone.ts
6697
6918
  init_cjs_shims();
6698
- var import_common16 = require("@nestjs/common");
6919
+ var import_common18 = require("@nestjs/common");
6699
6920
  var import_swagger6 = require("@nestjs/swagger");
6700
6921
  var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
6701
6922
  if (!isOperationEnabled2(ctx.definition, "findOne")) return null;
6923
+ if (isOperationExternal2(ctx.definition, "findOne")) return null;
6702
6924
  const { cls, config } = ctx;
6703
6925
  const methodName = "findOne";
6704
6926
  return {
@@ -6709,8 +6931,8 @@ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
6709
6931
  return this.repo.findOne(id, req);
6710
6932
  }, "findOneFn"),
6711
6933
  decorators: /* @__PURE__ */ __name(() => {
6712
- (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
6713
- (0, import_common16.Req)()(cls.prototype, methodName, 1);
6934
+ (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
6935
+ (0, import_common18.Req)()(cls.prototype, methodName, 1);
6714
6936
  }, "decorators")
6715
6937
  };
6716
6938
  }, "defaultFindOne");
@@ -6722,9 +6944,9 @@ var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
6722
6944
  return this.repo.findOneChild(sub, childId, parentId, req);
6723
6945
  }, "findOneFn");
6724
6946
  const decorators = /* @__PURE__ */ __name(() => {
6725
- (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
6726
- (0, import_common16.Param)("childId")(cls.prototype, methodName, 1);
6727
- (0, import_common16.Req)()(cls.prototype, methodName, 2);
6947
+ (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
6948
+ (0, import_common18.Param)("childId")(cls.prototype, methodName, 1);
6949
+ (0, import_common18.Req)()(cls.prototype, methodName, 2);
6728
6950
  }, "decorators");
6729
6951
  return {
6730
6952
  route: `:id/${sub.childRoute}/:childId`,
@@ -6742,7 +6964,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
6742
6964
  const { cls } = ctx;
6743
6965
  def(cls, methodName, properties.findOneFn);
6744
6966
  const d = desc(cls, methodName);
6745
- (0, import_common16.Get)(route)(cls.prototype, methodName, d);
6967
+ (0, import_common18.Get)(route)(cls.prototype, methodName, d);
6746
6968
  (0, import_swagger6.ApiOperation)({
6747
6969
  summary: `Get one ${name} by id`
6748
6970
  })(cls.prototype, methodName, d);
@@ -6763,10 +6985,11 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
6763
6985
 
6764
6986
  // src/lib/crud/operations/register-patch.ts
6765
6987
  init_cjs_shims();
6766
- var import_common17 = require("@nestjs/common");
6988
+ var import_common19 = require("@nestjs/common");
6767
6989
  var import_swagger7 = require("@nestjs/swagger");
6768
6990
  var defaultPatch = /* @__PURE__ */ __name((ctx) => {
6769
6991
  if (!isOperationEnabled2(ctx.definition, "patch")) return null;
6992
+ if (isOperationExternal2(ctx.definition, "patch")) return null;
6770
6993
  const { cls, config, patchSchema, bodyDecorator } = ctx;
6771
6994
  const methodName = "patch";
6772
6995
  return {
@@ -6777,9 +7000,9 @@ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
6777
7000
  return this.repo.patch(id, body, req);
6778
7001
  }, "patchFn"),
6779
7002
  decorators: /* @__PURE__ */ __name(() => {
6780
- (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
7003
+ (0, import_common19.Param)("id")(cls.prototype, methodName, 0);
6781
7004
  bodyDecorator(patchSchema)(cls.prototype, methodName, 1);
6782
- (0, import_common17.Req)()(cls.prototype, methodName, 2);
7005
+ (0, import_common19.Req)()(cls.prototype, methodName, 2);
6783
7006
  }, "decorators")
6784
7007
  };
6785
7008
  }, "defaultPatch");
@@ -6791,10 +7014,10 @@ var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
6791
7014
  return this.repo.updateChild(sub, childId, body, req);
6792
7015
  }, "patchFn");
6793
7016
  const decorators = /* @__PURE__ */ __name(() => {
6794
- (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
6795
- (0, import_common17.Param)("childId")(cls.prototype, methodName, 1);
6796
- (0, import_common17.Body)()(cls.prototype, methodName, 2);
6797
- (0, import_common17.Req)()(cls.prototype, methodName, 3);
7017
+ (0, import_common19.Param)("id")(cls.prototype, methodName, 0);
7018
+ (0, import_common19.Param)("childId")(cls.prototype, methodName, 1);
7019
+ (0, import_common19.Body)()(cls.prototype, methodName, 2);
7020
+ (0, import_common19.Req)()(cls.prototype, methodName, 3);
6798
7021
  }, "decorators");
6799
7022
  return {
6800
7023
  route: `:id/${sub.childRoute}/:childId`,
@@ -6812,7 +7035,7 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
6812
7035
  const { cls } = ctx;
6813
7036
  def(cls, methodName, properties.patchFn);
6814
7037
  const d = desc(cls, methodName);
6815
- (0, import_common17.Patch)(route)(cls.prototype, methodName, d);
7038
+ (0, import_common19.Patch)(route)(cls.prototype, methodName, d);
6816
7039
  (0, import_swagger7.ApiOperation)({
6817
7040
  summary: `Update a ${name}`
6818
7041
  })(cls.prototype, methodName, d);
@@ -6829,7 +7052,7 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
6829
7052
 
6830
7053
  // src/lib/crud/operations/register-schema-endpoints.ts
6831
7054
  init_cjs_shims();
6832
- var import_common18 = require("@nestjs/common");
7055
+ var import_common20 = require("@nestjs/common");
6833
7056
  var import_swagger8 = require("@nestjs/swagger");
6834
7057
  init_dev_mode();
6835
7058
 
@@ -6956,13 +7179,19 @@ var OP_SUFFIX = {
6956
7179
  patch: "/{id}",
6957
7180
  delete: "/{id}"
6958
7181
  };
6959
- var buildResourceOperations = /* @__PURE__ */ __name((definition, baseUri) => Object.fromEntries(RESOURCE_OPS.filter((op) => isOperationEnabled2(definition, op)).map((op) => [
6960
- op,
6961
- {
6962
- uri: `${baseUri}${OP_SUFFIX[op]}`,
6963
- method: OP_METHOD[op]
6964
- }
6965
- ])), "buildResourceOperations");
7182
+ var buildResourceOperations = /* @__PURE__ */ __name((definition, baseUri) => Object.fromEntries(RESOURCE_OPS.filter((op) => isOperationEnabled2(definition, op)).map((op) => {
7183
+ const extUri = externalRouteFor2(definition, op);
7184
+ const uri = extUri ? resolveEnvPlaceholders(extUri) : `${baseUri}${OP_SUFFIX[op]}`;
7185
+ const entry = definition[op];
7186
+ const method = (extUri && typeof entry === "object" && entry !== null && "method" in entry ? entry.method : void 0) ?? OP_METHOD[op];
7187
+ return [
7188
+ op,
7189
+ {
7190
+ uri,
7191
+ method
7192
+ }
7193
+ ];
7194
+ })), "buildResourceOperations");
6966
7195
  var buildDefinitionPayload2 = /* @__PURE__ */ __name((config) => {
6967
7196
  const { route, name, tag, idType = "string" } = config;
6968
7197
  const definition = resolveDefinition2(config);
@@ -7020,7 +7249,9 @@ var buildResourceJsonPayload2 = /* @__PURE__ */ __name((config, baseUrl) => {
7020
7249
  op,
7021
7250
  isOperationEnabled2(definition, op)
7022
7251
  ]));
7023
- operations.lookup = `${uri}?q={text}`;
7252
+ if (!isOperationExternal2(definition, "findAll")) {
7253
+ operations.lookup = `${uri}?q={text}`;
7254
+ }
7024
7255
  const form = config.views?.["form"];
7025
7256
  const schema = form?.json_schema ? {
7026
7257
  data: form.json_schema,
@@ -7059,7 +7290,7 @@ var buildViewsPayload2 = /* @__PURE__ */ __name((config, baseUrl) => {
7059
7290
  const definition = resolveDefinition2(config);
7060
7291
  const baseUri = config.parent ? `${baseUrl}/${config.parent.route}/{${config.parent.param}}/${config.route}` : `${baseUrl}/${config.route}`;
7061
7292
  const operations = buildResourceOperations(definition, baseUri);
7062
- if (isOperationEnabled2(definition, "findAll")) {
7293
+ if (isOperationEnabled2(definition, "findAll") && !isOperationExternal2(definition, "findAll")) {
7063
7294
  operations["lookup"] = `${baseUri}?q={text}`;
7064
7295
  }
7065
7296
  const schemas = Object.fromEntries(Object.entries(config.views).map(([key, v]) => [
@@ -7166,7 +7397,7 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
7166
7397
  };
7167
7398
  });
7168
7399
  const d = desc(cls, "getDefinition");
7169
- (0, import_common18.Get)("definition")(cls.prototype, "getDefinition", d);
7400
+ (0, import_common20.Get)("definition")(cls.prototype, "getDefinition", d);
7170
7401
  (0, import_swagger8.ApiOperation)({
7171
7402
  summary: `Get the resource definition for ${name}`
7172
7403
  })(cls.prototype, "getDefinition", d);
@@ -7176,7 +7407,7 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
7176
7407
  })(cls.prototype, "getDefinition", d);
7177
7408
  const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
7178
7409
  if (sec) {
7179
- (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getDefinition", d);
7410
+ (0, import_common20.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getDefinition", d);
7180
7411
  }
7181
7412
  }, "registerDefinitionEndpoint");
7182
7413
  var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
@@ -7197,7 +7428,7 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
7197
7428
  };
7198
7429
  });
7199
7430
  const d = desc(cls, "getResourceJson");
7200
- (0, import_common18.Get)("resource.json")(cls.prototype, "getResourceJson", d);
7431
+ (0, import_common20.Get)("resource.json")(cls.prototype, "getResourceJson", d);
7201
7432
  (0, import_swagger8.ApiOperation)({
7202
7433
  summary: `Get resource descriptor for ${name}`
7203
7434
  })(cls.prototype, "getResourceJson", d);
@@ -7207,7 +7438,7 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
7207
7438
  })(cls.prototype, "getResourceJson", d);
7208
7439
  const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
7209
7440
  if (sec) {
7210
- (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getResourceJson", d);
7441
+ (0, import_common20.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getResourceJson", d);
7211
7442
  }
7212
7443
  }, "registerResourceJsonEndpoint");
7213
7444
  var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
@@ -7215,13 +7446,13 @@ var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
7215
7446
  const { route, name } = config;
7216
7447
  def(cls, "getResourceColumns", async function() {
7217
7448
  if (!IS_DEV) {
7218
- throw new import_common18.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
7449
+ throw new import_common20.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
7219
7450
  }
7220
7451
  const fresh = await this.configRegistry.getByRoute(route);
7221
7452
  return buildEditableColumnsPayload(fresh ?? config);
7222
7453
  });
7223
7454
  const d = desc(cls, "getResourceColumns");
7224
- (0, import_common18.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
7455
+ (0, import_common20.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
7225
7456
  (0, import_swagger8.ApiOperation)({
7226
7457
  summary: `Dev-only: get the editable column list for ${name}`
7227
7458
  })(cls.prototype, "getResourceColumns", d);
@@ -7235,30 +7466,30 @@ var registerResourceJsonPatchEndpoint = /* @__PURE__ */ __name((ctx) => {
7235
7466
  const { route, name } = config;
7236
7467
  def(cls, "patchResourceJson", async function(body) {
7237
7468
  if (!IS_DEV) {
7238
- throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
7469
+ throw new import_common20.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
7239
7470
  }
7240
7471
  await this.configRegistry.getByRoute(route);
7241
7472
  const dir = this.configRegistry.getResourceDir(route);
7242
7473
  if (!dir) {
7243
- throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7474
+ throw new import_common20.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7244
7475
  }
7245
7476
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
7246
7477
  const raw = readRawResourceJson(jsonPath);
7247
7478
  if (!raw) {
7248
- throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
7479
+ throw new import_common20.NotFoundException(`resource.json not found at ${jsonPath}`);
7249
7480
  }
7250
7481
  const merged = applyColumnPatch(raw, body);
7251
7482
  const validated = validateResourceJson(merged);
7252
7483
  if (!validated.success) {
7253
- throw new import_common18.BadRequestException(validated.error.issues);
7484
+ throw new import_common20.BadRequestException(validated.error.issues);
7254
7485
  }
7255
7486
  writeRawResourceJson(jsonPath, merged);
7256
7487
  const fresh = await this.configRegistry.getByRoute(route);
7257
7488
  return buildEditableColumnsPayload(fresh ?? config);
7258
7489
  });
7259
7490
  const d = desc(cls, "patchResourceJson");
7260
- (0, import_common18.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
7261
- (0, import_common18.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
7491
+ (0, import_common20.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
7492
+ (0, import_common20.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
7262
7493
  (0, import_swagger8.ApiOperation)({
7263
7494
  summary: `Dev-only: patch column layout in resource.json for ${name}`
7264
7495
  })(cls.prototype, "patchResourceJson", d);
@@ -7272,22 +7503,22 @@ var registerResourceJsonRawGetEndpoint = /* @__PURE__ */ __name((ctx) => {
7272
7503
  const { route, name } = config;
7273
7504
  def(cls, "getResourceJsonRaw", async function() {
7274
7505
  if (!IS_DEV) {
7275
- throw new import_common18.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
7506
+ throw new import_common20.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
7276
7507
  }
7277
7508
  await this.configRegistry.getByRoute(route);
7278
7509
  const dir = this.configRegistry.getResourceDir(route);
7279
7510
  if (!dir) {
7280
- throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7511
+ throw new import_common20.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7281
7512
  }
7282
7513
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
7283
7514
  const raw = readRawResourceJson(jsonPath);
7284
7515
  if (!raw) {
7285
- throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
7516
+ throw new import_common20.NotFoundException(`resource.json not found at ${jsonPath}`);
7286
7517
  }
7287
7518
  return raw;
7288
7519
  });
7289
7520
  const d = desc(cls, "getResourceJsonRaw");
7290
- (0, import_common18.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
7521
+ (0, import_common20.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
7291
7522
  (0, import_swagger8.ApiOperation)({
7292
7523
  summary: `Dev-only: get the raw resource.json for ${name}`
7293
7524
  })(cls.prototype, "getResourceJsonRaw", d);
@@ -7301,24 +7532,24 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
7301
7532
  const { route, name } = config;
7302
7533
  def(cls, "putResourceJsonRaw", async function(body) {
7303
7534
  if (!IS_DEV) {
7304
- throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
7535
+ throw new import_common20.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
7305
7536
  }
7306
7537
  await this.configRegistry.getByRoute(route);
7307
7538
  const dir = this.configRegistry.getResourceDir(route);
7308
7539
  if (!dir) {
7309
- throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7540
+ throw new import_common20.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
7310
7541
  }
7311
7542
  const validated = validateResourceJson(body);
7312
7543
  if (!validated.success) {
7313
- throw new import_common18.BadRequestException(validated.error.issues);
7544
+ throw new import_common20.BadRequestException(validated.error.issues);
7314
7545
  }
7315
7546
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
7316
7547
  writeRawResourceJson(jsonPath, body);
7317
7548
  return body;
7318
7549
  });
7319
7550
  const d = desc(cls, "putResourceJsonRaw");
7320
- (0, import_common18.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
7321
- (0, import_common18.Body)()(cls.prototype, "putResourceJsonRaw", 0);
7551
+ (0, import_common20.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
7552
+ (0, import_common20.Body)()(cls.prototype, "putResourceJsonRaw", 0);
7322
7553
  (0, import_swagger8.ApiOperation)({
7323
7554
  summary: `Dev-only: replace the full resource.json for ${name}`
7324
7555
  })(cls.prototype, "putResourceJsonRaw", d);
@@ -7330,7 +7561,7 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
7330
7561
 
7331
7562
  // src/lib/crud/operations/register-schemas.ts
7332
7563
  init_cjs_shims();
7333
- var import_common19 = require("@nestjs/common");
7564
+ var import_common21 = require("@nestjs/common");
7334
7565
  var import_swagger9 = require("@nestjs/swagger");
7335
7566
  init_dev_mode();
7336
7567
  var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
@@ -7381,7 +7612,7 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
7381
7612
  const { cls } = ctx;
7382
7613
  def(cls, methodName, properties.schemasFn);
7383
7614
  const d = desc(cls, methodName);
7384
- (0, import_common19.Get)(route)(cls.prototype, methodName, d);
7615
+ (0, import_common21.Get)(route)(cls.prototype, methodName, d);
7385
7616
  (0, import_swagger9.ApiOperation)({
7386
7617
  summary: `Get view schemas for ${name}`
7387
7618
  })(cls.prototype, methodName, d);
@@ -7392,16 +7623,17 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
7392
7623
  properties.decorators();
7393
7624
  const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
7394
7625
  if (sec) {
7395
- (0, import_common19.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
7626
+ (0, import_common21.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
7396
7627
  }
7397
7628
  }, "registerSchemas");
7398
7629
 
7399
7630
  // src/lib/crud/operations/register-update.ts
7400
7631
  init_cjs_shims();
7401
- var import_common20 = require("@nestjs/common");
7632
+ var import_common22 = require("@nestjs/common");
7402
7633
  var import_swagger10 = require("@nestjs/swagger");
7403
7634
  var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
7404
7635
  if (!isOperationEnabled2(ctx.definition, "update")) return null;
7636
+ if (isOperationExternal2(ctx.definition, "update")) return null;
7405
7637
  const { cls, config, updateSchema, bodyDecorator } = ctx;
7406
7638
  const methodName = "update";
7407
7639
  return {
@@ -7412,9 +7644,9 @@ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
7412
7644
  return this.repo.update(id, body, req);
7413
7645
  }, "updateFn"),
7414
7646
  decorators: /* @__PURE__ */ __name(() => {
7415
- (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
7647
+ (0, import_common22.Param)("id")(cls.prototype, methodName, 0);
7416
7648
  bodyDecorator(updateSchema)(cls.prototype, methodName, 1);
7417
- (0, import_common20.Req)()(cls.prototype, methodName, 2);
7649
+ (0, import_common22.Req)()(cls.prototype, methodName, 2);
7418
7650
  }, "decorators")
7419
7651
  };
7420
7652
  }, "defaultUpdate");
@@ -7426,10 +7658,10 @@ var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
7426
7658
  return this.repo.updateChild(sub, childId, body, req);
7427
7659
  }, "updateFn");
7428
7660
  const decorators = /* @__PURE__ */ __name(() => {
7429
- (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
7430
- (0, import_common20.Param)("childId")(cls.prototype, methodName, 1);
7431
- (0, import_common20.Body)()(cls.prototype, methodName, 2);
7432
- (0, import_common20.Req)()(cls.prototype, methodName, 3);
7661
+ (0, import_common22.Param)("id")(cls.prototype, methodName, 0);
7662
+ (0, import_common22.Param)("childId")(cls.prototype, methodName, 1);
7663
+ (0, import_common22.Body)()(cls.prototype, methodName, 2);
7664
+ (0, import_common22.Req)()(cls.prototype, methodName, 3);
7433
7665
  }, "decorators");
7434
7666
  return {
7435
7667
  route: `:id/${sub.childRoute}/:childId`,
@@ -7447,7 +7679,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
7447
7679
  const { cls } = ctx;
7448
7680
  def(cls, methodName, properties.updateFn);
7449
7681
  const d = desc(cls, methodName);
7450
- (0, import_common20.Put)(route)(cls.prototype, methodName, d);
7682
+ (0, import_common22.Put)(route)(cls.prototype, methodName, d);
7451
7683
  (0, import_swagger10.ApiOperation)({
7452
7684
  summary: `Replace a ${name}`
7453
7685
  })(cls.prototype, methodName, d);
@@ -7506,15 +7738,20 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7506
7738
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
7507
7739
  }
7508
7740
  const bodyDecorator = /* @__PURE__ */ __name((schema, options) => {
7509
- if (!schema) return (0, import_common21.Body)();
7510
- if (isZodSchema(schema)) return (0, import_common21.Body)(new ZodValidationPipe(schema, options));
7511
- return (0, import_common21.Body)();
7741
+ if (!schema) return (0, import_common23.Body)();
7742
+ if (isZodSchema(schema)) return (0, import_common23.Body)(new ZodValidationPipe(schema, options));
7743
+ return (0, import_common23.Body)();
7512
7744
  }, "bodyDecorator");
7513
7745
  const resolveClient = /* @__PURE__ */ __name((registry2, resource) => {
7514
7746
  try {
7515
7747
  return registry2.resolve(resource.database);
7516
7748
  } catch (e) {
7517
7749
  if (resource.kind === "custom") return void 0;
7750
+ try {
7751
+ const adapter = registry2.resolveAdapter(resource.database);
7752
+ if (adapter.kind !== "prisma") return adapter.client;
7753
+ } catch {
7754
+ }
7518
7755
  throw e;
7519
7756
  }
7520
7757
  }, "resolveClient");
@@ -7533,7 +7770,7 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7533
7770
  const secure = /* @__PURE__ */ __name((methodName, op, sub) => {
7534
7771
  const sec = sub ? securityForSub(config, sub, op, moduleDefaultSecurity) : securityFor(config, definition, op, moduleDefaultSecurity);
7535
7772
  if (sec) {
7536
- (0, import_common21.SetMetadata)(CROUTON_SECURITY, sec)(CrudControllerBase.prototype, methodName, Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName));
7773
+ (0, import_common23.SetMetadata)(CROUTON_SECURITY, sec)(CrudControllerBase.prototype, methodName, Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName));
7537
7774
  }
7538
7775
  }, "secure");
7539
7776
  const ctx = {
@@ -7558,9 +7795,9 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7558
7795
  };
7559
7796
  registerEndpoints(ctx);
7560
7797
  const controllerPath = resourceControllerPath(route, config.parent);
7561
- (0, import_common21.Controller)(prefix ? `${prefix}/${controllerPath}` : controllerPath)(CrudControllerBase);
7798
+ (0, import_common23.Controller)(prefix ? `${prefix}/${controllerPath}` : controllerPath)(CrudControllerBase);
7562
7799
  if (securityEnabled) {
7563
- (0, import_common21.UseGuards)(CroutonSecurityGuard)(CrudControllerBase);
7800
+ (0, import_common23.UseGuards)(CroutonSecurityGuard)(CrudControllerBase);
7564
7801
  }
7565
7802
  (0, import_swagger11.ApiTags)(tag)(CrudControllerBase);
7566
7803
  Object.defineProperty(CrudControllerBase, "name", {
@@ -7579,7 +7816,7 @@ init_dev_mode();
7579
7816
 
7580
7817
  // src/lib/crud/dev-tools/dev-resources.controller.ts
7581
7818
  init_cjs_shims();
7582
- var import_common22 = require("@nestjs/common");
7819
+ var import_common24 = require("@nestjs/common");
7583
7820
  var import_swagger12 = require("@nestjs/swagger");
7584
7821
 
7585
7822
  // ../crouton-codegen/src/index.ts
@@ -8688,7 +8925,7 @@ var DevResourcesController = class {
8688
8925
  }
8689
8926
  assertDev() {
8690
8927
  if (!IS_DEV) {
8691
- throw new import_common22.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
8928
+ throw new import_common24.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
8692
8929
  }
8693
8930
  }
8694
8931
  /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */
@@ -8697,14 +8934,14 @@ var DevResourcesController = class {
8697
8934
  try {
8698
8935
  loaded = await loadConfig2(process.cwd());
8699
8936
  } catch (e) {
8700
- throw new import_common22.NotFoundException(e.message ?? "No crouton.json config found.");
8937
+ throw new import_common24.NotFoundException(e.message ?? "No crouton.json config found.");
8701
8938
  }
8702
8939
  const datasources = await loadDatasources(loaded);
8703
8940
  let ds;
8704
8941
  try {
8705
8942
  ds = resolveDatasource(datasources, datasourceName);
8706
8943
  } catch (e) {
8707
- throw new import_common22.BadRequestException(e.message);
8944
+ throw new import_common24.BadRequestException(e.message);
8708
8945
  }
8709
8946
  const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);
8710
8947
  return {
@@ -8719,7 +8956,7 @@ var DevResourcesController = class {
8719
8956
  schemaPath
8720
8957
  });
8721
8958
  } catch (e) {
8722
- throw new import_common22.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
8959
+ throw new import_common24.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
8723
8960
  }
8724
8961
  }
8725
8962
  buildApplyContext(loaded, ds) {
@@ -8789,7 +9026,7 @@ var DevResourcesController = class {
8789
9026
  zodOutputDir: zodDir
8790
9027
  });
8791
9028
  if (!result.ok) {
8792
- throw new import_common22.BadRequestException(`prisma db pull failed:
9029
+ throw new import_common24.BadRequestException(`prisma db pull failed:
8793
9030
  ${result.dbPull.output}`);
8794
9031
  }
8795
9032
  return {
@@ -8806,13 +9043,13 @@ ${result.dbPull.output}`);
8806
9043
  async sync(body) {
8807
9044
  this.assertDev();
8808
9045
  if (!body?.model) {
8809
- throw new import_common22.BadRequestException('"model" is required.');
9046
+ throw new import_common24.BadRequestException('"model" is required.');
8810
9047
  }
8811
9048
  const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);
8812
9049
  const models = await this.introspectModels(schemaPath);
8813
9050
  const model = models.find((m) => m.prismaName === body.model || m.clientAccessor === body.model);
8814
9051
  if (!model) {
8815
- throw new import_common22.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
9052
+ throw new import_common24.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
8816
9053
  }
8817
9054
  const resolveRelationResource = await makeRelationResolver(loaded);
8818
9055
  const diff2 = await buildResourceDiff(model, {
@@ -8934,14 +9171,14 @@ ${result.dbPull.output}`);
8934
9171
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
8935
9172
  const jsonPath = resolveResourcePath(resourcesDir, name);
8936
9173
  const raw = readRawResourceJson(jsonPath);
8937
- if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
8938
- if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
9174
+ if (!raw) throw new import_common24.NotFoundException(`Resource "${name}" not found.`);
9175
+ if (jsonPath.endsWith(".ts")) throw new import_common24.ForbiddenException("TypeScript resources cannot be edited.");
8939
9176
  const patched = applyResourceFlagPatch(raw, {
8940
9177
  draft: false
8941
9178
  });
8942
9179
  const result = validateResourceJson(patched);
8943
9180
  if (!result.success) {
8944
- throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
9181
+ throw new import_common24.BadRequestException(`Validation failed: ${result.error.message}`);
8945
9182
  }
8946
9183
  writeRawResourceJson(jsonPath, patched);
8947
9184
  return {
@@ -8954,8 +9191,8 @@ ${result.dbPull.output}`);
8954
9191
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
8955
9192
  const jsonPath = resolveResourcePath(resourcesDir, name);
8956
9193
  const raw = readRawResourceJson(jsonPath);
8957
- if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
8958
- if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
9194
+ if (!raw) throw new import_common24.NotFoundException(`Resource "${name}" not found.`);
9195
+ if (jsonPath.endsWith(".ts")) throw new import_common24.ForbiddenException("TypeScript resources cannot be edited.");
8959
9196
  const patched = applyResourceFlagPatch(raw, {
8960
9197
  sidebar: {
8961
9198
  hide: true
@@ -8963,7 +9200,7 @@ ${result.dbPull.output}`);
8963
9200
  });
8964
9201
  const result = validateResourceJson(patched);
8965
9202
  if (!result.success) {
8966
- throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
9203
+ throw new import_common24.BadRequestException(`Validation failed: ${result.error.message}`);
8967
9204
  }
8968
9205
  writeRawResourceJson(jsonPath, patched);
8969
9206
  return {
@@ -8976,8 +9213,8 @@ ${result.dbPull.output}`);
8976
9213
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
8977
9214
  const jsonPath = resolveResourcePath(resourcesDir, name);
8978
9215
  const raw = readRawResourceJson(jsonPath);
8979
- if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
8980
- if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
9216
+ if (!raw) throw new import_common24.NotFoundException(`Resource "${name}" not found.`);
9217
+ if (jsonPath.endsWith(".ts")) throw new import_common24.ForbiddenException("TypeScript resources cannot be edited.");
8981
9218
  const sidebarPatch = {
8982
9219
  hide: false
8983
9220
  };
@@ -8990,7 +9227,7 @@ ${result.dbPull.output}`);
8990
9227
  });
8991
9228
  const result = validateResourceJson(patched);
8992
9229
  if (!result.success) {
8993
- throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
9230
+ throw new import_common24.BadRequestException(`Validation failed: ${result.error.message}`);
8994
9231
  }
8995
9232
  writeRawResourceJson(jsonPath, patched);
8996
9233
  return {
@@ -9003,12 +9240,12 @@ ${result.dbPull.output}`);
9003
9240
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
9004
9241
  const jsonPath = resolveResourcePath(resourcesDir, name);
9005
9242
  const raw = readRawResourceJson(jsonPath);
9006
- if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
9007
- if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
9243
+ if (!raw) throw new import_common24.NotFoundException(`Resource "${name}" not found.`);
9244
+ if (jsonPath.endsWith(".ts")) throw new import_common24.ForbiddenException("TypeScript resources cannot be edited.");
9008
9245
  const patched = applyResourceFlagPatch(raw, body);
9009
9246
  const result = validateResourceJson(patched);
9010
9247
  if (!result.success) {
9011
- throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
9248
+ throw new import_common24.BadRequestException(`Validation failed: ${result.error.message}`);
9012
9249
  }
9013
9250
  writeRawResourceJson(jsonPath, patched);
9014
9251
  return {
@@ -9017,7 +9254,7 @@ ${result.dbPull.output}`);
9017
9254
  }
9018
9255
  };
9019
9256
  _ts_decorate8([
9020
- (0, import_common22.Get)("models"),
9257
+ (0, import_common24.Get)("models"),
9021
9258
  (0, import_swagger12.ApiOperation)({
9022
9259
  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"
9023
9260
  }),
@@ -9030,7 +9267,7 @@ _ts_decorate8([
9030
9267
  _ts_metadata8("design:returntype", Promise)
9031
9268
  ], DevResourcesController.prototype, "listModels", null);
9032
9269
  _ts_decorate8([
9033
- (0, import_common22.Post)("restart"),
9270
+ (0, import_common24.Post)("restart"),
9034
9271
  (0, import_swagger12.ApiOperation)({
9035
9272
  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."
9036
9273
  }),
@@ -9043,7 +9280,7 @@ _ts_decorate8([
9043
9280
  _ts_metadata8("design:returntype", Object)
9044
9281
  ], DevResourcesController.prototype, "restart", null);
9045
9282
  _ts_decorate8([
9046
- (0, import_common22.Post)("pull"),
9283
+ (0, import_common24.Post)("pull"),
9047
9284
  (0, import_swagger12.ApiOperation)({
9048
9285
  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"
9049
9286
  }),
@@ -9051,7 +9288,7 @@ _ts_decorate8([
9051
9288
  status: 200,
9052
9289
  description: "Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes"
9053
9290
  }),
9054
- _ts_param2(0, (0, import_common22.Body)()),
9291
+ _ts_param2(0, (0, import_common24.Body)()),
9055
9292
  _ts_metadata8("design:type", Function),
9056
9293
  _ts_metadata8("design:paramtypes", [
9057
9294
  Object
@@ -9059,7 +9296,7 @@ _ts_decorate8([
9059
9296
  _ts_metadata8("design:returntype", Promise)
9060
9297
  ], DevResourcesController.prototype, "pull", null);
9061
9298
  _ts_decorate8([
9062
- (0, import_common22.Post)("sync"),
9299
+ (0, import_common24.Post)("sync"),
9063
9300
  (0, import_swagger12.ApiOperation)({
9064
9301
  summary: "Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)"
9065
9302
  }),
@@ -9067,7 +9304,7 @@ _ts_decorate8([
9067
9304
  status: 200,
9068
9305
  description: "Files written for this resource"
9069
9306
  }),
9070
- _ts_param2(0, (0, import_common22.Body)()),
9307
+ _ts_param2(0, (0, import_common24.Body)()),
9071
9308
  _ts_metadata8("design:type", Function),
9072
9309
  _ts_metadata8("design:paramtypes", [
9073
9310
  Object
@@ -9075,7 +9312,7 @@ _ts_decorate8([
9075
9312
  _ts_metadata8("design:returntype", Promise)
9076
9313
  ], DevResourcesController.prototype, "sync", null);
9077
9314
  _ts_decorate8([
9078
- (0, import_common22.Post)("plan"),
9315
+ (0, import_common24.Post)("plan"),
9079
9316
  (0, import_swagger12.ApiOperation)({
9080
9317
  summary: "Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults \u2014 computes what would change, writes nothing"
9081
9318
  }),
@@ -9083,7 +9320,7 @@ _ts_decorate8([
9083
9320
  status: 200,
9084
9321
  description: "Proposed per-resource changes"
9085
9322
  }),
9086
- _ts_param2(0, (0, import_common22.Body)()),
9323
+ _ts_param2(0, (0, import_common24.Body)()),
9087
9324
  _ts_metadata8("design:type", Function),
9088
9325
  _ts_metadata8("design:paramtypes", [
9089
9326
  Object
@@ -9091,7 +9328,7 @@ _ts_decorate8([
9091
9328
  _ts_metadata8("design:returntype", Promise)
9092
9329
  ], DevResourcesController.prototype, "plan", null);
9093
9330
  _ts_decorate8([
9094
- (0, import_common22.Post)("apply"),
9331
+ (0, import_common24.Post)("apply"),
9095
9332
  (0, import_swagger12.ApiOperation)({
9096
9333
  summary: "Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults"
9097
9334
  }),
@@ -9099,7 +9336,7 @@ _ts_decorate8([
9099
9336
  status: 200,
9100
9337
  description: "Per-resource commit results"
9101
9338
  }),
9102
- _ts_param2(0, (0, import_common22.Body)()),
9339
+ _ts_param2(0, (0, import_common24.Body)()),
9103
9340
  _ts_metadata8("design:type", Function),
9104
9341
  _ts_metadata8("design:paramtypes", [
9105
9342
  Object
@@ -9107,7 +9344,7 @@ _ts_decorate8([
9107
9344
  _ts_metadata8("design:returntype", Promise)
9108
9345
  ], DevResourcesController.prototype, "apply", null);
9109
9346
  _ts_decorate8([
9110
- (0, import_common22.Get)("visibility"),
9347
+ (0, import_common24.Get)("visibility"),
9111
9348
  (0, import_swagger12.ApiOperation)({
9112
9349
  summary: "Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)"
9113
9350
  }),
@@ -9120,7 +9357,7 @@ _ts_decorate8([
9120
9357
  _ts_metadata8("design:returntype", Promise)
9121
9358
  ], DevResourcesController.prototype, "visibility", null);
9122
9359
  _ts_decorate8([
9123
- (0, import_common22.Post)(":name/publish"),
9360
+ (0, import_common24.Post)(":name/publish"),
9124
9361
  (0, import_swagger12.ApiOperation)({
9125
9362
  summary: "Dev-only: publish a draft resource (removes `draft: true` from resource.json)"
9126
9363
  }),
@@ -9128,7 +9365,7 @@ _ts_decorate8([
9128
9365
  status: 200,
9129
9366
  description: "Resource published"
9130
9367
  }),
9131
- _ts_param2(0, (0, import_common22.Param)("name")),
9368
+ _ts_param2(0, (0, import_common24.Param)("name")),
9132
9369
  _ts_metadata8("design:type", Function),
9133
9370
  _ts_metadata8("design:paramtypes", [
9134
9371
  String
@@ -9136,7 +9373,7 @@ _ts_decorate8([
9136
9373
  _ts_metadata8("design:returntype", Promise)
9137
9374
  ], DevResourcesController.prototype, "publish", null);
9138
9375
  _ts_decorate8([
9139
- (0, import_common22.Post)(":name/remove-from-menu"),
9376
+ (0, import_common24.Post)(":name/remove-from-menu"),
9140
9377
  (0, import_swagger12.ApiOperation)({
9141
9378
  summary: "Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)"
9142
9379
  }),
@@ -9144,7 +9381,7 @@ _ts_decorate8([
9144
9381
  status: 200,
9145
9382
  description: "Resource removed from menu"
9146
9383
  }),
9147
- _ts_param2(0, (0, import_common22.Param)("name")),
9384
+ _ts_param2(0, (0, import_common24.Param)("name")),
9148
9385
  _ts_metadata8("design:type", Function),
9149
9386
  _ts_metadata8("design:paramtypes", [
9150
9387
  String
@@ -9152,7 +9389,7 @@ _ts_decorate8([
9152
9389
  _ts_metadata8("design:returntype", Promise)
9153
9390
  ], DevResourcesController.prototype, "removeFromMenu", null);
9154
9391
  _ts_decorate8([
9155
- (0, import_common22.Post)(":name/add-to-menu"),
9392
+ (0, import_common24.Post)(":name/add-to-menu"),
9156
9393
  (0, import_swagger12.ApiOperation)({
9157
9394
  summary: "Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label"
9158
9395
  }),
@@ -9160,8 +9397,8 @@ _ts_decorate8([
9160
9397
  status: 200,
9161
9398
  description: "Resource added to menu"
9162
9399
  }),
9163
- _ts_param2(0, (0, import_common22.Param)("name")),
9164
- _ts_param2(1, (0, import_common22.Body)()),
9400
+ _ts_param2(0, (0, import_common24.Param)("name")),
9401
+ _ts_param2(1, (0, import_common24.Body)()),
9165
9402
  _ts_metadata8("design:type", Function),
9166
9403
  _ts_metadata8("design:paramtypes", [
9167
9404
  String,
@@ -9170,7 +9407,7 @@ _ts_decorate8([
9170
9407
  _ts_metadata8("design:returntype", Promise)
9171
9408
  ], DevResourcesController.prototype, "addToMenu", null);
9172
9409
  _ts_decorate8([
9173
- (0, import_common22.Patch)(":name/flags"),
9410
+ (0, import_common24.Patch)(":name/flags"),
9174
9411
  (0, import_swagger12.ApiOperation)({
9175
9412
  summary: "Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)"
9176
9413
  }),
@@ -9178,8 +9415,8 @@ _ts_decorate8([
9178
9415
  status: 200,
9179
9416
  description: "Flags updated"
9180
9417
  }),
9181
- _ts_param2(0, (0, import_common22.Param)("name")),
9182
- _ts_param2(1, (0, import_common22.Body)()),
9418
+ _ts_param2(0, (0, import_common24.Param)("name")),
9419
+ _ts_param2(1, (0, import_common24.Body)()),
9183
9420
  _ts_metadata8("design:type", Function),
9184
9421
  _ts_metadata8("design:paramtypes", [
9185
9422
  String,
@@ -9188,7 +9425,7 @@ _ts_decorate8([
9188
9425
  _ts_metadata8("design:returntype", Promise)
9189
9426
  ], DevResourcesController.prototype, "updateFlags", null);
9190
9427
  DevResourcesController = _ts_decorate8([
9191
- (0, import_common22.Controller)("_app/resources"),
9428
+ (0, import_common24.Controller)("_app/resources"),
9192
9429
  (0, import_swagger12.ApiTags)("Dev tools"),
9193
9430
  _ts_metadata8("design:type", Function),
9194
9431
  _ts_metadata8("design:paramtypes", [
@@ -9285,6 +9522,14 @@ var pickByColumns = /* @__PURE__ */ __name((schema, columns, filter) => {
9285
9522
  }, "pickByColumns");
9286
9523
  var opWithSchema = /* @__PURE__ */ __name((enabled, schema) => {
9287
9524
  if (enabled === false) return void 0;
9525
+ if (typeof enabled === "object" && enabled !== null && "uri" in enabled) {
9526
+ return {
9527
+ uri: enabled["uri"],
9528
+ ...enabled["method"] ? {
9529
+ method: enabled["method"]
9530
+ } : {}
9531
+ };
9532
+ }
9288
9533
  return schema ? {
9289
9534
  schema
9290
9535
  } : true;
@@ -9324,11 +9569,11 @@ var buildResourceDefinitions2 = /* @__PURE__ */ __name((schema, operations, enri
9324
9569
  ...upsertOp(operations.upsert, createSchema) && {
9325
9570
  upsert: upsertOp(operations.upsert, createSchema)
9326
9571
  },
9327
- ...operations.patch !== false && {
9328
- patch: true
9572
+ ...opWithSchema(operations.patch, void 0) && {
9573
+ patch: opWithSchema(operations.patch, void 0)
9329
9574
  },
9330
- ...operations.delete !== false && {
9331
- delete: true
9575
+ ...opWithSchema(operations.delete, void 0) && {
9576
+ delete: opWithSchema(operations.delete, void 0)
9332
9577
  }
9333
9578
  };
9334
9579
  return definition;
@@ -10251,7 +10496,7 @@ var buildStatus = /* @__PURE__ */ __name(async (registry2, loadedConfigs, enumRe
10251
10496
 
10252
10497
  // src/lib/crud/status/status.controller.ts
10253
10498
  init_cjs_shims();
10254
- var import_common23 = require("@nestjs/common");
10499
+ var import_common25 = require("@nestjs/common");
10255
10500
  var import_swagger13 = require("@nestjs/swagger");
10256
10501
  function _ts_decorate9(decorators, target, key, desc2) {
10257
10502
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
@@ -10290,7 +10535,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
10290
10535
  }
10291
10536
  };
10292
10537
  _ts_decorate9([
10293
- (0, import_common23.Get)("status.json"),
10538
+ (0, import_common25.Get)("status.json"),
10294
10539
  (0, import_swagger13.ApiOperation)({
10295
10540
  summary: "Crouton system status (db, resources, version)"
10296
10541
  }),
@@ -10303,7 +10548,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
10303
10548
  _ts_metadata9("design:returntype", Promise)
10304
10549
  ], StatusController.prototype, "getStatus", null);
10305
10550
  StatusController = _ts_decorate9([
10306
- (0, import_common23.Controller)(prefix ? `${prefix}/crouton` : "crouton"),
10551
+ (0, import_common25.Controller)(prefix ? `${prefix}/crouton` : "crouton"),
10307
10552
  (0, import_swagger13.ApiTags)("Status"),
10308
10553
  _ts_metadata9("design:type", Function),
10309
10554
  _ts_metadata9("design:paramtypes", [
@@ -10355,12 +10600,12 @@ var CroutonApiModule = class _CroutonApiModule {
10355
10600
  const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);
10356
10601
  const validConfigs = [];
10357
10602
  for (const c of configs) {
10358
- if (c.kind === "custom") {
10359
- let adapterClient;
10360
- if (c.database) {
10361
- try {
10362
- adapterClient = dataSourceRegistry.resolveAdapter(c.database).client;
10363
- } catch (e) {
10603
+ let adapter;
10604
+ if (c.database || dataSourceRegistry.entries().length > 0) {
10605
+ try {
10606
+ adapter = dataSourceRegistry.resolveAdapter(c.database);
10607
+ } catch (e) {
10608
+ if (c.database) {
10364
10609
  resourceLoadErrorsRegistry.record({
10365
10610
  name: c.name,
10366
10611
  path: c.route,
@@ -10369,6 +10614,19 @@ var CroutonApiModule = class _CroutonApiModule {
10369
10614
  continue;
10370
10615
  }
10371
10616
  }
10617
+ }
10618
+ const adapterIsCustom = adapter ? adapter.kind !== "prisma" : false;
10619
+ const hasRepository = !!c.repository;
10620
+ const adapterHasCrud = !!(adapter?.findAll && adapter.count);
10621
+ if (adapterHasCrud && !hasRepository) {
10622
+ validConfigs.push(c);
10623
+ continue;
10624
+ }
10625
+ if (hasRepository || adapterIsCustom || c.kind === "custom") {
10626
+ let adapterClient = adapter?.client;
10627
+ if (!adapterIsCustom && !hasRepository) {
10628
+ adapterClient = void 0;
10629
+ }
10372
10630
  const problem = validateCustomRepository(c, c.repository, adapterClient);
10373
10631
  if (problem) {
10374
10632
  resourceLoadErrorsRegistry.record({
@@ -10381,29 +10639,19 @@ var CroutonApiModule = class _CroutonApiModule {
10381
10639
  validConfigs.push(c);
10382
10640
  continue;
10383
10641
  }
10384
- try {
10385
- const adapter = dataSourceRegistry.resolveAdapter(c.database);
10386
- if (c.model && adapter.supports && !adapter.supports(c.model)) {
10387
- resourceLoadErrorsRegistry.record({
10388
- name: c.name,
10389
- path: c.route,
10390
- error: `Model "${c.model}" not found on the provided PrismaClient. Check the resource config for "${c.name}".`
10391
- });
10392
- continue;
10393
- }
10394
- if (!c.model) {
10395
- resourceLoadErrorsRegistry.record({
10396
- name: c.name,
10397
- path: c.route,
10398
- error: `Model "${c.model}" not found on the provided PrismaClient. Check the resource config for "${c.name}".`
10399
- });
10400
- continue;
10401
- }
10402
- } catch (e) {
10642
+ if (!c.model) {
10643
+ resourceLoadErrorsRegistry.record({
10644
+ name: c.name,
10645
+ path: c.route,
10646
+ error: `"model" is required for resource "${c.name}" on a Prisma datasource. Set "model" to the Prisma model name, or set adapter: "custom" on the datasource.`
10647
+ });
10648
+ continue;
10649
+ }
10650
+ if (adapter && adapter.supports && !adapter.supports(c.model)) {
10403
10651
  resourceLoadErrorsRegistry.record({
10404
10652
  name: c.name,
10405
10653
  path: c.route,
10406
- error: e.message ?? String(e)
10654
+ error: `Model "${c.model}" not found on the provided PrismaClient. Check the resource config for "${c.name}".`
10407
10655
  });
10408
10656
  continue;
10409
10657
  }
@@ -10482,7 +10730,7 @@ var CroutonApiModule = class _CroutonApiModule {
10482
10730
  }
10483
10731
  };
10484
10732
  CroutonApiModule = _ts_decorate10([
10485
- (0, import_common24.Module)({
10733
+ (0, import_common26.Module)({
10486
10734
  controllers: [],
10487
10735
  providers: [],
10488
10736
  exports: []
@@ -10540,7 +10788,9 @@ init_hooks();
10540
10788
  buildViews,
10541
10789
  decorateRow,
10542
10790
  decorateRows,
10791
+ externalRouteFor,
10543
10792
  isOperationEnabled,
10793
+ isOperationExternal,
10544
10794
  isRowProcedureAction,
10545
10795
  isTableProcedureAction,
10546
10796
  loadDataSourcesFromDir,