@ghentcdh/crouton-api 0.0.1-alpha.42 → 0.0.1-alpha.46

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
@@ -31,13 +31,16 @@ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: tru
31
31
  // src/index.ts
32
32
  var index_exports = {};
33
33
  __export(index_exports, {
34
+ CROUTON_SECURITY: () => CROUTON_SECURITY,
34
35
  CroutonApiModule: () => CroutonApiModule,
36
+ CroutonSecurityGuard: () => CroutonSecurityGuard,
35
37
  DataSourceRegistry: () => DataSourceRegistry,
36
38
  FileSystemResourceConfigLoader: () => FileSystemResourceConfigLoader,
37
39
  ReadOpSchema: () => ReadOpSchema,
38
40
  ResourceConfigLoader: () => ResourceConfigLoader2,
39
41
  ResourceConfigRegistry: () => ResourceConfigRegistry,
40
42
  ResourceHooksSchema: () => ResourceHooksSchema,
43
+ SecurityGuardRegistry: () => SecurityGuardRegistry,
41
44
  WriteOpSchema: () => WriteOpSchema,
42
45
  buildFilterWhere: () => buildFilterWhere,
43
46
  buildViews: () => buildViews,
@@ -55,6 +58,8 @@ __export(index_exports, {
55
58
  prepareWrite: () => prepareWrite,
56
59
  resolveDefinition: () => resolveDefinition,
57
60
  schemaFor: () => schemaFor,
61
+ securityFor: () => securityFor,
62
+ securityForSub: () => securityForSub,
58
63
  upsertOnFor: () => upsertOnFor
59
64
  });
60
65
  module.exports = __toCommonJS(index_exports);
@@ -619,85 +624,150 @@ var transformDataSource = /* @__PURE__ */ __name((data) => {
619
624
  var DataSourceSchema = DataSourceShape.transform(transformDataSource);
620
625
 
621
626
  // ../crouton-core/src/lib/data-source/Operations.schema.ts
627
+ var import_zod9 = require("zod");
628
+
629
+ // ../crouton-core/src/lib/data-source/Security.schema.ts
622
630
  var import_zod8 = require("zod");
623
- var BoolOrUpsertSchema = import_zod8.z.union([
624
- import_zod8.z.boolean(),
631
+ var SecuritySchema = import_zod8.z.union([
625
632
  import_zod8.z.object({
626
- upsertOn: import_zod8.z.union([
633
+ public: import_zod8.z.literal(true)
634
+ }),
635
+ import_zod8.z.object({
636
+ guard: import_zod8.z.union([
627
637
  import_zod8.z.string(),
628
- import_zod8.z.array(import_zod8.z.string())
638
+ import_zod8.z.array(import_zod8.z.string()).min(1)
629
639
  ])
630
640
  })
631
641
  ]);
632
- var JsonOperationsSchema = import_zod8.z.object({
633
- findAll: import_zod8.z.boolean().default(true),
634
- findOne: import_zod8.z.boolean().default(true),
635
- create: import_zod8.z.boolean().default(true),
636
- update: import_zod8.z.boolean().default(true),
637
- patch: import_zod8.z.boolean().default(true),
642
+
643
+ // ../crouton-core/src/lib/data-source/Operations.schema.ts
644
+ var OpEntry = import_zod9.z.union([
645
+ import_zod9.z.boolean(),
646
+ import_zod9.z.object({
647
+ security: SecuritySchema.optional()
648
+ })
649
+ ]);
650
+ var BoolOrUpsertSchema = import_zod9.z.union([
651
+ import_zod9.z.boolean(),
652
+ import_zod9.z.object({
653
+ upsertOn: import_zod9.z.union([
654
+ import_zod9.z.string(),
655
+ import_zod9.z.array(import_zod9.z.string())
656
+ ]),
657
+ security: SecuritySchema.optional()
658
+ })
659
+ ]);
660
+ var JsonOperationsSchema = import_zod9.z.object({
661
+ findAll: OpEntry.default(true),
662
+ findOne: OpEntry.default(true),
663
+ create: OpEntry.default(true),
664
+ update: OpEntry.default(true),
665
+ patch: OpEntry.default(true),
638
666
  upsert: BoolOrUpsertSchema.default(false),
639
- delete: import_zod8.z.boolean().default(true)
667
+ delete: OpEntry.default(true)
640
668
  });
669
+ var buildSubResourceOperations = /* @__PURE__ */ __name((ops, baseUri, idField = "id") => {
670
+ if (!ops) return {};
671
+ const idPlaceholder = `{${idField}}`;
672
+ return {
673
+ ...ops.findAll && {
674
+ findAll: {
675
+ uri: baseUri,
676
+ method: "get"
677
+ }
678
+ },
679
+ ...ops.findOne && {
680
+ findOne: {
681
+ uri: `${baseUri}/${idPlaceholder}`,
682
+ method: "get"
683
+ }
684
+ },
685
+ ...ops.create && {
686
+ create: {
687
+ uri: baseUri,
688
+ method: "post"
689
+ }
690
+ },
691
+ ...ops.update && {
692
+ update: {
693
+ uri: `${baseUri}/${idPlaceholder}`,
694
+ method: "put"
695
+ }
696
+ },
697
+ ...ops.patch && {
698
+ patch: {
699
+ uri: `${baseUri}/${idPlaceholder}`,
700
+ method: "patch"
701
+ }
702
+ },
703
+ ...ops.delete && {
704
+ delete: {
705
+ uri: `${baseUri}/${idPlaceholder}`,
706
+ method: "delete"
707
+ }
708
+ }
709
+ };
710
+ }, "buildSubResourceOperations");
641
711
 
642
712
  // ../crouton-core/src/lib/resource/ResourceJson.schema.ts
643
- var import_zod18 = require("zod");
713
+ var import_zod19 = require("zod");
644
714
 
645
715
  // ../crouton-core/src/lib/resource/CalculatedColumn.schema.ts
646
- var import_zod10 = require("zod");
716
+ var import_zod11 = require("zod");
647
717
 
648
718
  // ../crouton-core/src/lib/resource/FieldInput.schema.ts
649
- var import_zod9 = require("zod");
650
- var RelationType = import_zod9.z.enum([
719
+ var import_zod10 = require("zod");
720
+ var RelationType = import_zod10.z.enum([
651
721
  "oneToOne",
652
722
  "manyToOne",
653
723
  "oneToMany",
654
724
  "manyToMany"
655
725
  ]);
656
- var DetailControlSchema = import_zod9.z.object({
657
- property: import_zod9.z.string(),
658
- type: import_zod9.z.string().optional(),
659
- options: import_zod9.z.record(import_zod9.z.string(), import_zod9.z.unknown()).optional(),
660
- hideLabel: import_zod9.z.boolean().optional(),
661
- width: import_zod9.z.string().optional()
726
+ var DetailControlSchema = import_zod10.z.object({
727
+ property: import_zod10.z.string(),
728
+ type: import_zod10.z.string().optional(),
729
+ options: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.unknown()).optional(),
730
+ hideLabel: import_zod10.z.boolean().optional(),
731
+ width: import_zod10.z.string().optional()
662
732
  });
663
- var DetailConfigSchema = import_zod9.z.object({
664
- layout: import_zod9.z.enum([
733
+ var DetailConfigSchema = import_zod10.z.object({
734
+ layout: import_zod10.z.enum([
665
735
  "collapse",
666
736
  "row"
667
737
  ]),
668
- titleKey: import_zod9.z.string().optional(),
669
- controls: import_zod9.z.array(DetailControlSchema)
738
+ titleKey: import_zod10.z.string().optional(),
739
+ controls: import_zod10.z.array(DetailControlSchema)
670
740
  });
671
- var RelationFieldInputOptionsSchema = import_zod9.z.object({
672
- colspan: import_zod9.z.number().optional().default(12),
741
+ var RelationFieldInputOptionsSchema = import_zod10.z.object({
742
+ colspan: import_zod10.z.number().optional().default(12),
673
743
  /** Field to sort related records by, e.g. `"title"` or `"author.name"`. */
674
- sort: import_zod9.z.string().optional(),
744
+ sort: import_zod10.z.string().optional(),
675
745
  /** Sort direction. Defaults to `"asc"` when omitted. */
676
- sortDir: import_zod9.z.enum([
746
+ sortDir: import_zod10.z.enum([
677
747
  "asc",
678
748
  "desc"
679
749
  ]).optional(),
680
750
  /** CSS flex direction for the relation control button layout. */
681
- direction: import_zod9.z.string().optional(),
751
+ direction: import_zod10.z.string().optional(),
682
752
  /** Key used as the display label in the relation control. */
683
- displayKey: import_zod9.z.string().optional(),
753
+ displayKey: import_zod10.z.string().optional(),
684
754
  /** Path to the related resource (resolved to a URI at load time). */
685
- resource: import_zod9.z.string().optional()
686
- }).catchall(import_zod9.z.unknown());
687
- var FieldInputSchema = import_zod9.z.object({
688
- type: import_zod9.z.string().optional(),
689
- customRender: import_zod9.z.string().optional(),
755
+ resource: import_zod10.z.string().optional()
756
+ }).catchall(import_zod10.z.unknown());
757
+ var FieldInputSchema = import_zod10.z.object({
758
+ type: import_zod10.z.string().optional(),
759
+ customRender: import_zod10.z.string().optional(),
690
760
  /**
691
761
  * Render format hint for the frontend (e.g. `"relation"` for sub-resource
692
762
  * relations). When `format` is `"relation"`, `resource` must also be set.
693
763
  */
694
- format: import_zod9.z.string().optional(),
764
+ format: import_zod10.z.string().optional(),
695
765
  /**
696
766
  * Relative path to the child resource definition, e.g. `"./author.resource"`.
697
767
  * Only used when `format` is `"relation"`. Resolved at load time to inject
698
768
  * sub-resource URIs into `options`.
699
769
  */
700
- resource: import_zod9.z.string().optional(),
770
+ resource: import_zod10.z.string().optional(),
701
771
  /**
702
772
  * Cardinality of the relation. Used by the frontend to determine the correct
703
773
  * renderer and behaviour (e.g. single-select vs multi-select).
@@ -706,11 +776,11 @@ var FieldInputSchema = import_zod9.z.object({
706
776
  */
707
777
  relationType: RelationType.optional(),
708
778
  /** FK field on the child model pointing back to the parent, e.g. `"workId"`. Defaults to `${parentModel}Id`. */
709
- foreignKey: import_zod9.z.string().optional(),
779
+ foreignKey: import_zod10.z.string().optional(),
710
780
  /** Override the Prisma relation field name when it differs from the column id. */
711
- relation: import_zod9.z.string().optional(),
781
+ relation: import_zod10.z.string().optional(),
712
782
  /** Override the display order in form views. Lower values come first. */
713
- position: import_zod9.z.number().optional(),
783
+ position: import_zod10.z.number().optional(),
714
784
  /**
715
785
  * Value to pre-fill this field with on the create form. Injected into the
716
786
  * generated form view's JSON Schema as `properties[id].default`, which
@@ -718,10 +788,10 @@ var FieldInputSchema = import_zod9.z.object({
718
788
  * opening a blank record. Not applicable to `format: "relation"` fields —
719
789
  * relation columns are excluded from the picked data schema entirely.
720
790
  */
721
- defaultValue: import_zod9.z.unknown().optional(),
722
- options: import_zod9.z.union([
791
+ defaultValue: import_zod10.z.unknown().optional(),
792
+ options: import_zod10.z.union([
723
793
  RelationFieldInputOptionsSchema,
724
- import_zod9.z.unknown()
794
+ import_zod10.z.unknown()
725
795
  ]).optional(),
726
796
  /** Nested array detail layout (renders via `detailFixed`). */
727
797
  detail: DetailConfigSchema.optional()
@@ -762,16 +832,16 @@ var normalizeLabel = /* @__PURE__ */ __name((obj) => {
762
832
  }, "normalizeLabel");
763
833
 
764
834
  // ../crouton-core/src/lib/resource/CalculatedColumn.schema.ts
765
- var CalculatedColumnSchema = import_zod10.z.object({
835
+ var CalculatedColumnSchema = import_zod11.z.object({
766
836
  /** Column identifier used in the response payload and UI schema. */
767
- id: import_zod10.z.string(),
837
+ id: import_zod11.z.string(),
768
838
  /** SQL alias — must match `id`. */
769
- alias: import_zod10.z.string(),
839
+ alias: import_zod11.z.string(),
770
840
  /** Human-readable label shown in the table header. */
771
- label: import_zod10.z.string().optional(),
772
- sqlExpression: import_zod10.z.string(),
841
+ label: import_zod11.z.string().optional(),
842
+ sqlExpression: import_zod11.z.string(),
773
843
  /** JSON schema / cast type for the computed value. Defaults to `"number"`. `"string"` skips CAST. */
774
- type: import_zod10.z.enum([
844
+ type: import_zod11.z.enum([
775
845
  "number",
776
846
  "boolean",
777
847
  "string"
@@ -782,9 +852,9 @@ var CalculatedColumnSchema = import_zod10.z.object({
782
852
  * `position: N` places this column before the element currently at index N.
783
853
  * Can also be set via `fieldInput.position` (takes precedence).
784
854
  */
785
- position: import_zod10.z.number().optional(),
786
- hiddenInTable: import_zod10.z.boolean().optional(),
787
- hiddenInView: import_zod10.z.boolean().optional(),
855
+ position: import_zod11.z.number().optional(),
856
+ hiddenInTable: import_zod11.z.boolean().optional(),
857
+ hiddenInView: import_zod11.z.boolean().optional(),
788
858
  /**
789
859
  * Field input options for rendering in form / view schemas.
790
860
  * Supports `colspan`, `format`, and any other options passed to the Control renderer.
@@ -794,11 +864,11 @@ var CalculatedColumnSchema = import_zod10.z.object({
794
864
  }).transform(normalizeLabel);
795
865
 
796
866
  // ../crouton-core/src/lib/resource/Column.ts
797
- var import_zod12 = require("zod");
867
+ var import_zod13 = require("zod");
798
868
 
799
869
  // ../crouton-core/src/lib/resource/ColumnType.schema.ts
800
- var import_zod11 = require("zod");
801
- var ColumnTypeShorthandSchema = import_zod11.z.enum([
870
+ var import_zod12 = require("zod");
871
+ var ColumnTypeShorthandSchema = import_zod12.z.enum([
802
872
  "string",
803
873
  "number",
804
874
  "integer",
@@ -808,32 +878,32 @@ var ColumnTypeShorthandSchema = import_zod11.z.enum([
808
878
  "object",
809
879
  "array"
810
880
  ]);
811
- var JsonSchemaFragmentSchema = import_zod11.z.lazy(() => import_zod11.z.object({
812
- type: import_zod11.z.union([
813
- import_zod11.z.string(),
814
- import_zod11.z.array(import_zod11.z.string())
881
+ var JsonSchemaFragmentSchema = import_zod12.z.lazy(() => import_zod12.z.object({
882
+ type: import_zod12.z.union([
883
+ import_zod12.z.string(),
884
+ import_zod12.z.array(import_zod12.z.string())
815
885
  ]).optional(),
816
- format: import_zod11.z.string().optional(),
817
- enum: import_zod11.z.array(import_zod11.z.unknown()).optional(),
818
- const: import_zod11.z.unknown().optional(),
819
- nullable: import_zod11.z.boolean().optional(),
820
- properties: import_zod11.z.record(import_zod11.z.string(), JsonSchemaFragmentSchema).optional(),
821
- required: import_zod11.z.array(import_zod11.z.string()).optional(),
886
+ format: import_zod12.z.string().optional(),
887
+ enum: import_zod12.z.array(import_zod12.z.unknown()).optional(),
888
+ const: import_zod12.z.unknown().optional(),
889
+ nullable: import_zod12.z.boolean().optional(),
890
+ properties: import_zod12.z.record(import_zod12.z.string(), JsonSchemaFragmentSchema).optional(),
891
+ required: import_zod12.z.array(import_zod12.z.string()).optional(),
822
892
  items: JsonSchemaFragmentSchema.optional(),
823
- additionalProperties: import_zod11.z.union([
824
- import_zod11.z.boolean(),
893
+ additionalProperties: import_zod12.z.union([
894
+ import_zod12.z.boolean(),
825
895
  JsonSchemaFragmentSchema
826
896
  ]).optional(),
827
- title: import_zod11.z.string().optional(),
828
- description: import_zod11.z.string().optional(),
829
- default: import_zod11.z.unknown().optional(),
830
- minimum: import_zod11.z.number().optional(),
831
- maximum: import_zod11.z.number().optional(),
832
- minLength: import_zod11.z.number().optional(),
833
- maxLength: import_zod11.z.number().optional(),
834
- pattern: import_zod11.z.string().optional()
835
- }).catchall(import_zod11.z.unknown()));
836
- var ColumnTypeSchema = import_zod11.z.union([
897
+ title: import_zod12.z.string().optional(),
898
+ description: import_zod12.z.string().optional(),
899
+ default: import_zod12.z.unknown().optional(),
900
+ minimum: import_zod12.z.number().optional(),
901
+ maximum: import_zod12.z.number().optional(),
902
+ minLength: import_zod12.z.number().optional(),
903
+ maxLength: import_zod12.z.number().optional(),
904
+ pattern: import_zod12.z.string().optional()
905
+ }).catchall(import_zod12.z.unknown()));
906
+ var ColumnTypeSchema = import_zod12.z.union([
837
907
  ColumnTypeShorthandSchema,
838
908
  JsonSchemaFragmentSchema
839
909
  ]);
@@ -915,40 +985,40 @@ var isObjectColumnType = /* @__PURE__ */ __name((type) => columnTypeName(type) =
915
985
  var isArrayColumnType = /* @__PURE__ */ __name((type) => columnTypeName(type) === "array", "isArrayColumnType");
916
986
 
917
987
  // ../crouton-core/src/lib/resource/Column.ts
918
- var WhenConditionSchema = import_zod12.z.object({
919
- field: import_zod12.z.string(),
920
- eq: import_zod12.z.unknown().optional(),
921
- neq: import_zod12.z.unknown().optional(),
922
- exists: import_zod12.z.boolean().optional(),
923
- notExists: import_zod12.z.boolean().optional()
988
+ var WhenConditionSchema = import_zod13.z.object({
989
+ field: import_zod13.z.string(),
990
+ eq: import_zod13.z.unknown().optional(),
991
+ neq: import_zod13.z.unknown().optional(),
992
+ exists: import_zod13.z.boolean().optional(),
993
+ notExists: import_zod13.z.boolean().optional()
924
994
  });
925
- var JsonColumnSchema = import_zod12.z.object({
926
- id: import_zod12.z.string(),
927
- column: import_zod12.z.string().optional(),
928
- label: import_zod12.z.string().optional(),
929
- hiddenInTable: import_zod12.z.boolean().default(false),
930
- hiddenInForm: import_zod12.z.boolean().default(false),
931
- hiddenInView: import_zod12.z.boolean().default(false),
932
- sortable: import_zod12.z.boolean().default(false),
933
- defaultSort: import_zod12.z.boolean().default(false),
934
- searchable: import_zod12.z.boolean().default(false),
935
- filterable: import_zod12.z.boolean().default(false),
936
- createable: import_zod12.z.boolean().default(true),
937
- updateable: import_zod12.z.boolean().default(true),
938
- hideLabel: import_zod12.z.boolean().default(false),
995
+ var JsonColumnSchema = import_zod13.z.object({
996
+ id: import_zod13.z.string(),
997
+ column: import_zod13.z.string().optional(),
998
+ label: import_zod13.z.string().optional(),
999
+ hiddenInTable: import_zod13.z.boolean().default(false),
1000
+ hiddenInForm: import_zod13.z.boolean().default(false),
1001
+ hiddenInView: import_zod13.z.boolean().default(false),
1002
+ sortable: import_zod13.z.boolean().default(false),
1003
+ defaultSort: import_zod13.z.boolean().default(false),
1004
+ searchable: import_zod13.z.boolean().default(false),
1005
+ filterable: import_zod13.z.boolean().default(false),
1006
+ createable: import_zod13.z.boolean().default(true),
1007
+ updateable: import_zod13.z.boolean().default(true),
1008
+ hideLabel: import_zod13.z.boolean().default(false),
939
1009
  showWhen: WhenConditionSchema.optional(),
940
1010
  hideWhen: WhenConditionSchema.optional(),
941
1011
  disabledWhen: WhenConditionSchema.optional(),
942
- displayKey: import_zod12.z.string().optional(),
943
- sortId: import_zod12.z.string().optional(),
1012
+ displayKey: import_zod13.z.string().optional(),
1013
+ sortId: import_zod13.z.string().optional(),
944
1014
  /**
945
1015
  * Name of a shared enum in the project enum registry (`crouton.enums.json`).
946
1016
  * At load time the loader injects that enum's `{ value, label }[]` into
947
1017
  * `fieldInput.options.values`, so columns don't duplicate the option list.
948
1018
  */
949
- enum: import_zod12.z.string().optional(),
950
- idField: import_zod12.z.boolean().default(false),
951
- showInLookup: import_zod12.z.boolean().default(false),
1019
+ enum: import_zod13.z.string().optional(),
1020
+ idField: import_zod13.z.boolean().default(false),
1021
+ showInLookup: import_zod13.z.boolean().default(false),
952
1022
  /**
953
1023
  * Data type of the column, as a shorthand name (`"string"`, `"integer"`, …)
954
1024
  * or a full JSON Schema fragment:
@@ -979,12 +1049,12 @@ var JsonColumnSchema = import_zod12.z.object({
979
1049
  * Ignored on the id column and on columns that are neither createable nor
980
1050
  * updateable, since the form cannot supply a value for those.
981
1051
  */
982
- required: import_zod12.z.boolean().optional(),
1052
+ required: import_zod13.z.boolean().optional(),
983
1053
  /**
984
1054
  * @deprecated Use `type` instead. Retained because it is still consumed by
985
1055
  * the boolean predicate and the schema-less sub-resource view builder.
986
1056
  */
987
- columnType: import_zod12.z.string().default("string"),
1057
+ columnType: import_zod13.z.string().default("string"),
988
1058
  fieldInput: FieldInputSchema.optional(),
989
1059
  /**
990
1060
  * Optional per-context override for the read-only VIEW ui. Same shape as
@@ -1008,27 +1078,27 @@ var JsonColumnSchema = import_zod12.z.object({
1008
1078
  * Visibility (`hiddenInTable/Form/View`) on this column is inherited by all sub-columns as a
1009
1079
  * default; the referenced resource's own column visibility further restricts it.
1010
1080
  */
1011
- extend: import_zod12.z.string().optional(),
1081
+ extend: import_zod13.z.string().optional(),
1012
1082
  /**
1013
1083
  * Per-sub-column overrides when using `extend`.
1014
1084
  * Key: the virtual column id (`"{extendId}_{refColId}"`) or just the referenced column id.
1015
1085
  * Value: any `JsonColumn` fields to merge over the generated virtual column.
1016
1086
  */
1017
- columns: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown())).optional()
1087
+ columns: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown())).optional()
1018
1088
  });
1019
1089
 
1020
1090
  // ../crouton-core/src/lib/resource/ParentRef.schema.ts
1021
- var import_zod13 = require("zod");
1022
- var ParentRefSchema = import_zod13.z.object({
1091
+ var import_zod14 = require("zod");
1092
+ var ParentRefSchema = import_zod14.z.object({
1023
1093
  /** Route segment of the parent, e.g. `"group"`. */
1024
- route: import_zod13.z.string(),
1094
+ route: import_zod14.z.string(),
1025
1095
  /**
1026
1096
  * Name of the path parameter carrying the parent id, e.g. `"groupId"`.
1027
1097
  * Avoid `"id"` — that is the child's own id in `/:id` routes.
1028
1098
  */
1029
- param: import_zod13.z.string().default("parentId"),
1099
+ param: import_zod14.z.string().default("parentId"),
1030
1100
  /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */
1031
- idType: import_zod13.z.enum([
1101
+ idType: import_zod14.z.enum([
1032
1102
  "string",
1033
1103
  "number"
1034
1104
  ]).optional()
@@ -1036,37 +1106,37 @@ var ParentRefSchema = import_zod13.z.object({
1036
1106
  var resourceControllerPath = /* @__PURE__ */ __name((route, parent) => parent ? `${parent.route}/:${parent.param}/${route}` : route, "resourceControllerPath");
1037
1107
 
1038
1108
  // ../crouton-core/src/lib/resource/ResourceKind.ts
1039
- var import_zod14 = require("zod");
1040
- var ResourceKindSchema = import_zod14.z.enum([
1109
+ var import_zod15 = require("zod");
1110
+ var ResourceKindSchema = import_zod15.z.enum([
1041
1111
  "prisma",
1042
1112
  "custom"
1043
1113
  ]).default("prisma");
1044
1114
 
1045
1115
  // ../crouton-core/src/lib/resource/Sidebar.schema.ts
1046
- var import_zod15 = __toESM(require("zod"), 1);
1047
- var SidebarGroupSchema = import_zod15.default.object({
1116
+ var import_zod16 = __toESM(require("zod"), 1);
1117
+ var SidebarGroupSchema = import_zod16.default.object({
1048
1118
  /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
1049
- label: import_zod15.default.string().optional(),
1119
+ label: import_zod16.default.string().optional(),
1050
1120
  /** Controls the order of this group among top-level sidebar items. */
1051
- position: import_zod15.default.number().optional()
1121
+ position: import_zod16.default.number().optional()
1052
1122
  });
1053
- var SidebarSchema = import_zod15.default.object({
1054
- hide: import_zod15.default.boolean().default(false),
1055
- position: import_zod15.default.number().optional(),
1056
- label: import_zod15.default.string().optional(),
1123
+ var SidebarSchema = import_zod16.default.object({
1124
+ hide: import_zod16.default.boolean().default(false),
1125
+ position: import_zod16.default.number().optional(),
1126
+ label: import_zod16.default.string().optional(),
1057
1127
  /**
1058
1128
  * Slug of the group this resource belongs to.
1059
1129
  * Must match a key in `sidebarGroups` in `crouton.json`.
1060
1130
  * Resources with the same `group` are nested under a shared collapsible section.
1061
1131
  */
1062
- group: import_zod15.default.string().optional()
1132
+ group: import_zod16.default.string().optional()
1063
1133
  });
1064
1134
 
1065
1135
  // ../crouton-core/src/lib/resource/TableAction.schema.ts
1066
- var import_zod16 = require("zod");
1067
- var ActionConditionSchema = import_zod16.z.object({
1136
+ var import_zod17 = require("zod");
1137
+ var ActionConditionSchema = import_zod17.z.object({
1068
1138
  /** Row field to evaluate. */
1069
- field: import_zod16.z.string(),
1139
+ field: import_zod17.z.string(),
1070
1140
  /**
1071
1141
  * Comparison operator. Defaults to `"eq"`.
1072
1142
  * - `eq` / `neq` — strict equality
@@ -1074,7 +1144,7 @@ var ActionConditionSchema = import_zod16.z.object({
1074
1144
  * - `exists` — field is not null / undefined / empty string
1075
1145
  * - `notExists` — field is null / undefined / empty string
1076
1146
  */
1077
- op: import_zod16.z.enum([
1147
+ op: import_zod17.z.enum([
1078
1148
  "eq",
1079
1149
  "neq",
1080
1150
  "gt",
@@ -1085,38 +1155,38 @@ var ActionConditionSchema = import_zod16.z.object({
1085
1155
  "notExists"
1086
1156
  ]).default("eq"),
1087
1157
  /** Comparison value. Not required for `exists` / `notExists`. */
1088
- value: import_zod16.z.unknown().optional()
1158
+ value: import_zod17.z.unknown().optional()
1089
1159
  });
1090
- var ActionSchema = import_zod16.z.object({
1091
- type: import_zod16.z.string(),
1160
+ var ActionSchema = import_zod17.z.object({
1161
+ type: import_zod17.z.string(),
1092
1162
  /** Unique identifier for the action. */
1093
- id: import_zod16.z.string(),
1163
+ id: import_zod17.z.string(),
1094
1164
  /** Human-readable button label. */
1095
- label: import_zod16.z.string(),
1165
+ label: import_zod17.z.string(),
1096
1166
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
1097
- icon: import_zod16.z.string().optional(),
1167
+ icon: import_zod17.z.string().optional(),
1098
1168
  /** Tooltip text. Falls back to `label` when omitted. */
1099
- tooltip: import_zod16.z.string().optional(),
1169
+ tooltip: import_zod17.z.string().optional(),
1100
1170
  condition: ActionConditionSchema.optional()
1101
1171
  });
1102
1172
  var JsonProcedureActionSchema = ActionSchema.extend({
1103
- type: import_zod16.z.literal("procedure").default("procedure"),
1173
+ type: import_zod17.z.literal("procedure").default("procedure"),
1104
1174
  /**
1105
1175
  * Filename (without extension) inside the resource's `actions/` directory
1106
1176
  * that exports the table-action procedure, e.g. `"syncZotero"`.
1107
1177
  */
1108
- procedure: import_zod16.z.string(),
1178
+ procedure: import_zod17.z.string(),
1109
1179
  /** HTTP method for the frontend. Defaults to `"post"`. */
1110
- method: import_zod16.z.string().optional().default("post"),
1180
+ method: import_zod17.z.string().optional().default("post"),
1111
1181
  /** Static query / body params passed to the endpoint. */
1112
- data: import_zod16.z.record(import_zod16.z.string(), import_zod16.z.unknown()).optional()
1182
+ data: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()
1113
1183
  });
1114
1184
  var JsonLinkActionSchema = ActionSchema.extend({
1115
1185
  /** Optional condition evaluated per row. Button is hidden when the condition is false. */
1116
- type: import_zod16.z.literal("link").default("link"),
1186
+ type: import_zod17.z.literal("link").default("link"),
1117
1187
  /** URL to open. May contain `{env.VAR}` placeholders. */
1118
- href: import_zod16.z.string(),
1119
- blank: import_zod16.z.boolean().optional().default(true)
1188
+ href: import_zod17.z.string(),
1189
+ blank: import_zod17.z.boolean().optional().default(true)
1120
1190
  });
1121
1191
  var transformAction = /* @__PURE__ */ __name((action) => {
1122
1192
  const label = action.label;
@@ -1125,20 +1195,20 @@ var transformAction = /* @__PURE__ */ __name((action) => {
1125
1195
  ...action
1126
1196
  };
1127
1197
  }, "transformAction");
1128
- var JsonActionSchema = import_zod16.z.union([
1198
+ var JsonActionSchema = import_zod17.z.union([
1129
1199
  JsonProcedureActionSchema,
1130
1200
  JsonLinkActionSchema
1131
1201
  ]).transform(transformAction);
1132
1202
 
1133
1203
  // ../crouton-core/src/lib/resource/include.schema.ts
1134
- var import_zod17 = require("zod");
1135
- var JsonIncludeEntrySchema = import_zod17.z.lazy(() => import_zod17.z.union([
1136
- import_zod17.z.string(),
1137
- import_zod17.z.object({
1138
- relation: import_zod17.z.string(),
1139
- include: import_zod17.z.array(JsonIncludeEntrySchema).optional(),
1204
+ var import_zod18 = require("zod");
1205
+ var JsonIncludeEntrySchema = import_zod18.z.lazy(() => import_zod18.z.union([
1206
+ import_zod18.z.string(),
1207
+ import_zod18.z.object({
1208
+ relation: import_zod18.z.string(),
1209
+ include: import_zod18.z.array(JsonIncludeEntrySchema).optional(),
1140
1210
  /** Prisma-format orderBy clause applied to the included records. */
1141
- orderBy: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()
1211
+ orderBy: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
1142
1212
  })
1143
1213
  ]));
1144
1214
 
@@ -1147,16 +1217,16 @@ var BASELINE_RESOURCE_VERSION = 1;
1147
1217
  var CURRENT_RESOURCE_VERSION = 1;
1148
1218
 
1149
1219
  // ../crouton-core/src/lib/resource/ResourceJson.schema.ts
1150
- var JsonColumnsMapSchema = import_zod18.z.record(import_zod18.z.string(), JsonColumnSchema.omit({
1220
+ var JsonColumnsMapSchema = import_zod19.z.record(import_zod19.z.string(), JsonColumnSchema.omit({
1151
1221
  id: true
1152
- }).catchall(import_zod18.z.unknown()));
1222
+ }).catchall(import_zod19.z.unknown()));
1153
1223
  var ColumnsSchema = JsonColumnsMapSchema;
1154
- var JsonDisplaySchema = import_zod18.z.object({
1155
- mode: import_zod18.z.enum([
1224
+ var JsonDisplaySchema = import_zod19.z.object({
1225
+ mode: import_zod19.z.enum([
1156
1226
  "page",
1157
1227
  "modal"
1158
1228
  ]).default("modal"),
1159
- customComponent: import_zod18.z.string().nullable().optional().default(null)
1229
+ customComponent: import_zod19.z.string().nullable().optional().default(null)
1160
1230
  });
1161
1231
  var normalizeColumns = /* @__PURE__ */ __name((columns) => {
1162
1232
  if (!columns) return void 0;
@@ -1169,46 +1239,46 @@ var normalizeColumns = /* @__PURE__ */ __name((columns) => {
1169
1239
  label: col.label ?? labelFromId(col.id)
1170
1240
  }));
1171
1241
  }, "normalizeColumns");
1172
- var ResourceJsonShape = import_zod18.z.object({
1242
+ var ResourceJsonShape = import_zod19.z.object({
1173
1243
  /**
1174
1244
  * URL of the generated JSON Schema, for editor autocomplete/validation. Declared so the
1175
1245
  * key is *allowed* (not stripped, and not flagged by the very schema it points at).
1176
1246
  * Ignored at runtime.
1177
1247
  */
1178
- $schema: import_zod18.z.string().optional(),
1248
+ $schema: import_zod19.z.string().optional(),
1179
1249
  /**
1180
1250
  * resource.json shape version. Missing ⇒ baseline (see `./version`). Auto-migrated
1181
1251
  * toward `CURRENT_RESOURCE_VERSION` on load in the dev environment.
1182
1252
  */
1183
- schemaVersion: import_zod18.z.number().int().positive().optional(),
1253
+ schemaVersion: import_zod19.z.number().int().positive().optional(),
1184
1254
  /** When `true`, the resource lives in the repo but is NOT loaded/served (work in progress). */
1185
- draft: import_zod18.z.boolean().optional().default(false),
1255
+ draft: import_zod19.z.boolean().optional().default(false),
1186
1256
  /**
1187
1257
  * Where the data comes from. `prisma` (the default) is backed by a Prisma
1188
1258
  * model plus a `schema.ts`; `custom` is configuration only and the developer
1189
1259
  * supplies a `repository.ts`. See `./ResourceKind`.
1190
1260
  */
1191
1261
  kind: ResourceKindSchema,
1192
- name: import_zod18.z.string(),
1193
- route: import_zod18.z.string(),
1262
+ name: import_zod19.z.string(),
1263
+ route: import_zod19.z.string(),
1194
1264
  /**
1195
1265
  * Prisma model name. Required when `kind` is `prisma` (enforced by the
1196
1266
  * refinement on `ResourceJsonSchema`), and must be absent when `kind` is
1197
1267
  * `custom` — there is no Prisma delegate to address.
1198
1268
  */
1199
- model: import_zod18.z.string().optional(),
1200
- tag: import_zod18.z.string(),
1201
- title: import_zod18.z.string().optional(),
1202
- table: import_zod18.z.string().optional(),
1269
+ model: import_zod19.z.string().optional(),
1270
+ tag: import_zod19.z.string(),
1271
+ title: import_zod19.z.string().optional(),
1272
+ table: import_zod19.z.string().optional(),
1203
1273
  /**
1204
1274
  * Type of the resource's primary key, used to coerce `:id` route params.
1205
1275
  * Written by codegen from the Prisma model; defaults to `'string'`.
1206
1276
  */
1207
- idType: import_zod18.z.enum([
1277
+ idType: import_zod19.z.enum([
1208
1278
  "string",
1209
1279
  "number"
1210
1280
  ]).optional(),
1211
- database: import_zod18.z.string().optional(),
1281
+ database: import_zod19.z.string().optional(),
1212
1282
  /**
1213
1283
  * Mount this resource under a parent route instead of at the top level —
1214
1284
  * see `./ParentRef.schema`. Only valid on a `kind: "custom"` resource.
@@ -1216,14 +1286,16 @@ var ResourceJsonShape = import_zod18.z.object({
1216
1286
  parent: ParentRefSchema.optional(),
1217
1287
  sidebar: SidebarSchema.default(SidebarSchema.parse({})),
1218
1288
  display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})),
1289
+ /** Global security block — applies to every operation unless overridden per-operation. */
1290
+ security: SecuritySchema.optional(),
1219
1291
  operations: JsonOperationsSchema,
1220
1292
  columns: ColumnsSchema.default(ColumnsSchema.parse({})),
1221
- calculatedColumns: import_zod18.z.array(CalculatedColumnSchema).default([]),
1222
- actions: import_zod18.z.array(JsonActionSchema).default([]),
1293
+ calculatedColumns: import_zod19.z.array(CalculatedColumnSchema).default([]),
1294
+ actions: import_zod19.z.array(JsonActionSchema).default([]),
1223
1295
  /** Global table-level actions (no record id). Shown as toolbar buttons. */
1224
- tableActions: import_zod18.z.array(JsonActionSchema).default([]),
1296
+ tableActions: import_zod19.z.array(JsonActionSchema).default([]),
1225
1297
  /** Modal width when opening a form for this resource. */
1226
- modalSize: import_zod18.z.enum([
1298
+ modalSize: import_zod19.z.enum([
1227
1299
  "xs",
1228
1300
  "sm",
1229
1301
  "lg",
@@ -1236,7 +1308,7 @@ var ResourceJsonShape = import_zod18.z.object({
1236
1308
  * `{ "relation": "text_author", "include": ["author"] }` →
1237
1309
  * `include: { text_author: { include: { author: true } } }`
1238
1310
  */
1239
- include: import_zod18.z.array(JsonIncludeEntrySchema).default([])
1311
+ include: import_zod19.z.array(JsonIncludeEntrySchema).default([])
1240
1312
  });
1241
1313
  var refineByKind = /* @__PURE__ */ __name((obj, ctx) => {
1242
1314
  if (obj.kind === "custom") {
@@ -1381,58 +1453,58 @@ var resolveViewField = /* @__PURE__ */ __name((c) => mergeFieldVariant(c.fieldIn
1381
1453
  var resolveTableField = /* @__PURE__ */ __name((c) => mergeFieldVariant(resolveViewField(c), c.fieldTable), "resolveTableField");
1382
1454
 
1383
1455
  // ../crouton-core/src/lib/config/CroutonConfig.schema.ts
1384
- var import_zod19 = require("zod");
1385
- var RulesetSchema = import_zod19.z.object({
1386
- hideIdInTable: import_zod19.z.boolean().default(true),
1387
- hideIdInForm: import_zod19.z.boolean().default(true),
1388
- hideIdInView: import_zod19.z.boolean().default(true),
1389
- hideTimestamps: import_zod19.z.boolean().default(true),
1390
- hideForeignKeys: import_zod19.z.boolean().default(true),
1391
- includeRelations: import_zod19.z.boolean().default(true),
1392
- hideRelationsInTable: import_zod19.z.boolean().default(true),
1393
- showRelationsInForm: import_zod19.z.boolean().default(true),
1394
- enumValueLabel: import_zod19.z.boolean().default(true),
1395
- sharedEnums: import_zod19.z.boolean().default(true),
1456
+ var import_zod20 = require("zod");
1457
+ var RulesetSchema = import_zod20.z.object({
1458
+ hideIdInTable: import_zod20.z.boolean().default(true),
1459
+ hideIdInForm: import_zod20.z.boolean().default(true),
1460
+ hideIdInView: import_zod20.z.boolean().default(true),
1461
+ hideTimestamps: import_zod20.z.boolean().default(true),
1462
+ hideForeignKeys: import_zod20.z.boolean().default(true),
1463
+ includeRelations: import_zod20.z.boolean().default(true),
1464
+ hideRelationsInTable: import_zod20.z.boolean().default(true),
1465
+ showRelationsInForm: import_zod20.z.boolean().default(true),
1466
+ enumValueLabel: import_zod20.z.boolean().default(true),
1467
+ sharedEnums: import_zod20.z.boolean().default(true),
1396
1468
  defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
1397
1469
  });
1398
- var I18nConfigSchema = import_zod19.z.object({
1470
+ var I18nConfigSchema = import_zod20.z.object({
1399
1471
  /** Default / fallback language. */
1400
- defaultLanguage: import_zod19.z.string().default("en"),
1472
+ defaultLanguage: import_zod20.z.string().default("en"),
1401
1473
  /** All supported language codes. */
1402
- languages: import_zod19.z.array(import_zod19.z.string()).min(1),
1474
+ languages: import_zod20.z.array(import_zod20.z.string()).min(1),
1403
1475
  /** Directory containing `<lang>.json` bundles, relative to project root. */
1404
- translationsDir: import_zod19.z.string().default("translations")
1476
+ translationsDir: import_zod20.z.string().default("translations")
1405
1477
  });
1406
- var CroutonConfigSchema = import_zod19.z.object({
1478
+ var CroutonConfigSchema = import_zod20.z.object({
1407
1479
  /**
1408
1480
  * Application title served to the frontend via `GET /_app/layout`.
1409
1481
  * Displayed in the admin sidebar header.
1410
1482
  */
1411
- title: import_zod19.z.string(),
1483
+ title: import_zod20.z.string(),
1412
1484
  /** Where resource directories live, relative to the project root. */
1413
- resourcesDir: import_zod19.z.string(),
1485
+ resourcesDir: import_zod20.z.string(),
1414
1486
  /** Where datasource folders live (each with a `data-source.json`). */
1415
- dataSourcesDir: import_zod19.z.string(),
1487
+ dataSourcesDir: import_zod20.z.string(),
1416
1488
  /**
1417
1489
  * Template for a model's Zod export name. `{Model}` → Prisma model name.
1418
1490
  * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema
1419
1491
  * emitted by zod-prisma-types when `createRelationValuesTypes` is on).
1420
1492
  */
1421
- schemaExportName: import_zod19.z.string().default("{Model}WithRelationsSchema"),
1493
+ schemaExportName: import_zod20.z.string().default("{Model}WithRelationsSchema"),
1422
1494
  /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
1423
- enumsFile: import_zod19.z.string().default("crouton.enums.json"),
1495
+ enumsFile: import_zod20.z.string().default("crouton.enums.json"),
1424
1496
  /** Optional overrides of the default visibility ruleset. */
1425
1497
  rules: RulesetSchema.default(RulesetSchema.parse({})),
1426
1498
  /**
1427
1499
  * Sidebar group definitions, keyed by group slug (e.g. `"metadata"`).
1428
1500
  * Resources reference a group via `sidebar.group` in their `resource.json`.
1429
1501
  */
1430
- sidebarGroups: import_zod19.z.record(import_zod19.z.string(), SidebarGroupSchema).default({}),
1502
+ sidebarGroups: import_zod20.z.record(import_zod20.z.string(), SidebarGroupSchema).default({}),
1431
1503
  /**
1432
1504
  * Whether form fields are saved automatically as the user edits them.
1433
1505
  * @default true
1434
1506
  */
1435
- autoSave: import_zod19.z.boolean().default(true),
1507
+ autoSave: import_zod20.z.boolean().default(true),
1436
1508
  /** Optional i18n / translation configuration. */
1437
1509
  i18n: I18nConfigSchema.optional()
1438
1510
  });
@@ -1820,7 +1892,7 @@ var injectCalculatedColumns = /* @__PURE__ */ __name((tableView, calculated) =>
1820
1892
  var injectCalculatedColumnsToView = /* @__PURE__ */ __name((viewConfig, calculated) => injectCalculatedColumnsIntoView(viewConfig, calculated, "view"), "injectCalculatedColumnsToView");
1821
1893
 
1822
1894
  // ../crouton-core/src/lib/view/view.builder.ts
1823
- var import_zod21 = require("zod");
1895
+ var import_zod22 = require("zod");
1824
1896
 
1825
1897
  // ../crouton-core/src/lib/view/column-type-schema.source.ts
1826
1898
  var optionValues = /* @__PURE__ */ __name((col) => {
@@ -1856,18 +1928,18 @@ var columnTypeSchemaSource = /* @__PURE__ */ __name((schemaCols) => {
1856
1928
  }, "columnTypeSchemaSource");
1857
1929
 
1858
1930
  // ../crouton-core/src/lib/view/json-schema.opts.ts
1859
- var import_zod20 = require("zod");
1931
+ var import_zod21 = require("zod");
1860
1932
  var isInstanceOf = /* @__PURE__ */ __name((zodSchema, className) => {
1861
- if (!(zodSchema instanceof import_zod20.z.ZodCustom)) return false;
1933
+ if (!(zodSchema instanceof import_zod21.z.ZodCustom)) return false;
1862
1934
  const result = zodSchema.safeParse(null);
1863
1935
  return !result.success && result.error.issues[0]?.expected === className;
1864
1936
  }, "isInstanceOf");
1865
1937
  var jsonSchemaOverride = /* @__PURE__ */ __name(({ zodSchema, jsonSchema }) => {
1866
- if (zodSchema instanceof import_zod20.z.ZodDate) {
1938
+ if (zodSchema instanceof import_zod21.z.ZodDate) {
1867
1939
  jsonSchema.type = "string";
1868
1940
  jsonSchema.format = "date-time";
1869
1941
  }
1870
- if (zodSchema instanceof import_zod20.z.ZodBigInt) {
1942
+ if (zodSchema instanceof import_zod21.z.ZodBigInt) {
1871
1943
  jsonSchema.type = "integer";
1872
1944
  }
1873
1945
  if (isInstanceOf(zodSchema, "Decimal")) {
@@ -1941,7 +2013,7 @@ var zodSchemaSource = /* @__PURE__ */ __name((schema) => (schemaCols) => {
1941
2013
  true
1942
2014
  ]));
1943
2015
  const picked = schema.pick(mask);
1944
- return (0, import_zod21.toJSONSchema)(picked, {
2016
+ return (0, import_zod22.toJSONSchema)(picked, {
1945
2017
  target: "draft-07",
1946
2018
  ...jsonSchemaOpts
1947
2019
  });
@@ -2148,45 +2220,55 @@ var buildViewsFromColumns = /* @__PURE__ */ __name((columns) => {
2148
2220
  }, "buildViewsFromColumns");
2149
2221
 
2150
2222
  // ../crouton-core/src/lib/view/view.schema.ts
2151
- var import_zod22 = require("zod");
2152
- var ViewColumnConfigSchema = import_zod22.z.object({
2153
- id: import_zod22.z.string(),
2154
- label: import_zod22.z.string().optional(),
2155
- sortable: import_zod22.z.boolean().optional(),
2156
- searchable: import_zod22.z.boolean().optional(),
2223
+ var import_zod23 = require("zod");
2224
+ var ViewColumnConfigSchema = import_zod23.z.object({
2225
+ id: import_zod23.z.string(),
2226
+ label: import_zod23.z.string().optional(),
2227
+ sortable: import_zod23.z.boolean().optional(),
2228
+ searchable: import_zod23.z.boolean().optional(),
2157
2229
  fieldInput: FieldInputSchema.optional()
2158
2230
  });
2159
- var ViewConfigSchema = import_zod22.z.object({
2160
- json_schema: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()),
2161
- ui_schema: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()),
2162
- columns: import_zod22.z.array(ViewColumnConfigSchema),
2163
- defaultSort: import_zod22.z.string().optional()
2231
+ var ViewConfigSchema = import_zod23.z.object({
2232
+ // TODO why we have both?
2233
+ json_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2234
+ ui_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2235
+ // TODO why we have both?
2236
+ ui: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2237
+ data: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2238
+ columns: import_zod23.z.array(ViewColumnConfigSchema),
2239
+ defaultSort: import_zod23.z.string().optional()
2164
2240
  });
2241
+ var viewDefList = [
2242
+ "table",
2243
+ "view",
2244
+ "form"
2245
+ ];
2246
+ var ViewDefEnum = import_zod23.z.enum(viewDefList);
2165
2247
 
2166
2248
  // ../crouton-core/src/lib/i18n/Translations.schema.ts
2167
- var import_zod23 = require("zod");
2168
- var NestedStringRecord = import_zod23.z.lazy(() => import_zod23.z.record(import_zod23.z.string(), import_zod23.z.union([
2169
- import_zod23.z.string(),
2249
+ var import_zod24 = require("zod");
2250
+ var NestedStringRecord = import_zod24.z.lazy(() => import_zod24.z.record(import_zod24.z.string(), import_zod24.z.union([
2251
+ import_zod24.z.string(),
2170
2252
  NestedStringRecord
2171
2253
  ])));
2172
- var TranslationBundleSchema = import_zod23.z.object({
2173
- app: import_zod23.z.object({
2174
- title: import_zod23.z.string().optional()
2254
+ var TranslationBundleSchema = import_zod24.z.object({
2255
+ app: import_zod24.z.object({
2256
+ title: import_zod24.z.string().optional()
2175
2257
  }).optional(),
2176
- sidebarGroups: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2177
- resources: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.object({
2178
- title: import_zod23.z.string().optional(),
2179
- sidebar: import_zod23.z.string().optional(),
2180
- columns: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2181
- actions: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional(),
2182
- subResources: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.object({
2183
- title: import_zod23.z.string().optional(),
2184
- columns: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional()
2258
+ sidebarGroups: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2259
+ resources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2260
+ title: import_zod24.z.string().optional(),
2261
+ sidebar: import_zod24.z.string().optional(),
2262
+ columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2263
+ actions: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2264
+ subResources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2265
+ title: import_zod24.z.string().optional(),
2266
+ columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
2185
2267
  }).optional()).optional()
2186
2268
  }).optional()).optional(),
2187
- enums: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string())).optional(),
2269
+ enums: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string())).optional(),
2188
2270
  ui: NestedStringRecord.optional(),
2189
- validation: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional()
2271
+ validation: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
2190
2272
  }).passthrough();
2191
2273
 
2192
2274
  // ../crouton-core/src/lib/i18n/translation-keys.ts
@@ -2266,25 +2348,25 @@ var resolveLanguage = /* @__PURE__ */ __name((acceptLanguage, supported, default
2266
2348
  }, "resolveLanguage");
2267
2349
 
2268
2350
  // src/lib/crouton-api.module.ts
2269
- var import_common22 = require("@nestjs/common");
2270
- var import_core = require("@nestjs/core");
2351
+ var import_common24 = require("@nestjs/common");
2352
+ var import_core2 = require("@nestjs/core");
2271
2353
 
2272
2354
  // src/lib/crud/app-layout/app-layout.types.ts
2273
- var import_zod24 = require("zod");
2274
- var SidebarLeafSchema = import_zod24.z.object({
2275
- kind: import_zod24.z.literal("item").default("item"),
2276
- id: import_zod24.z.string(),
2277
- label: import_zod24.z.string(),
2278
- position: import_zod24.z.number().optional()
2355
+ var import_zod25 = require("zod");
2356
+ var SidebarLeafSchema = import_zod25.z.object({
2357
+ kind: import_zod25.z.literal("item").default("item"),
2358
+ id: import_zod25.z.string(),
2359
+ label: import_zod25.z.string(),
2360
+ position: import_zod25.z.number().optional()
2279
2361
  });
2280
- var SidebarGroupSchema2 = import_zod24.z.object({
2281
- kind: import_zod24.z.literal("group").default("group"),
2282
- id: import_zod24.z.string(),
2283
- label: import_zod24.z.string(),
2284
- position: import_zod24.z.number().optional(),
2285
- children: import_zod24.z.array(SidebarLeafSchema).default([])
2362
+ var SidebarGroupSchema2 = import_zod25.z.object({
2363
+ kind: import_zod25.z.literal("group").default("group"),
2364
+ id: import_zod25.z.string(),
2365
+ label: import_zod25.z.string(),
2366
+ position: import_zod25.z.number().optional(),
2367
+ children: import_zod25.z.array(SidebarLeafSchema).default([])
2286
2368
  });
2287
- var SidebarNodeSchema = import_zod24.z.discriminatedUnion("kind", [
2369
+ var SidebarNodeSchema = import_zod25.z.discriminatedUnion("kind", [
2288
2370
  SidebarLeafSchema,
2289
2371
  SidebarGroupSchema2
2290
2372
  ]);
@@ -2543,6 +2625,12 @@ var resolveColumnFieldVariants = /* @__PURE__ */ __name((cols) => cols?.map((col
2543
2625
 
2544
2626
  // src/lib/crud/translation/localize-resource.ts
2545
2627
  var clone = /* @__PURE__ */ __name((obj) => JSON.parse(JSON.stringify(obj)), "clone");
2628
+ var cloneResource = /* @__PURE__ */ __name((config) => {
2629
+ const { definition, ...rest } = config;
2630
+ const localized = clone(rest);
2631
+ if (definition) localized.definition = definition;
2632
+ return localized;
2633
+ }, "cloneResource");
2546
2634
  var translateEnumOptions = /* @__PURE__ */ __name((columns, t) => {
2547
2635
  if (!columns) return;
2548
2636
  for (const col of columns) {
@@ -2592,7 +2680,7 @@ var patchViewTitles = /* @__PURE__ */ __name((views, columnLabels) => {
2592
2680
  }, "patchViewTitles");
2593
2681
  var localizeResource = /* @__PURE__ */ __name((config, t) => {
2594
2682
  const name = config.name;
2595
- const localized = clone(config);
2683
+ const localized = cloneResource(config);
2596
2684
  localized.title = t(resourceTitleKey(name), config.title ?? config.tag);
2597
2685
  if (localized.sidebar) {
2598
2686
  const sidebarTranslation = t(resourceSidebarKey(name), config.sidebar?.label);
@@ -2926,7 +3014,11 @@ var loadConfig = /* @__PURE__ */ __name(async () => {
2926
3014
  const mod = await import(path);
2927
3015
  config = mod.default ?? mod;
2928
3016
  }
2929
- return CroutonConfigSchema.parse(config);
3017
+ const parsed = CroutonConfigSchema.parse(config);
3018
+ return {
3019
+ ...parsed,
3020
+ configDir: (0, import_node_path3.dirname)(path)
3021
+ };
2930
3022
  }, "loadConfig");
2931
3023
 
2932
3024
  // src/lib/crud/crouton-validation.filter.ts
@@ -3080,51 +3172,51 @@ CroutonValidationExceptionFilter = _ts_decorate3([
3080
3172
  ], CroutonValidationExceptionFilter);
3081
3173
 
3082
3174
  // src/lib/crud/crud-controller.factory.ts
3083
- var import_common19 = require("@nestjs/common");
3175
+ var import_common21 = require("@nestjs/common");
3084
3176
  var import_swagger11 = require("@nestjs/swagger");
3085
3177
 
3086
3178
  // src/lib/crud/action/action.types.ts
3087
- var import_zod25 = require("zod");
3088
- var ActionMetadataSchema = import_zod25.z.object({
3179
+ var import_zod26 = require("zod");
3180
+ var ActionMetadataSchema = import_zod26.z.object({
3089
3181
  /** URL segment used in the endpoint. */
3090
- id: import_zod25.z.string(),
3182
+ id: import_zod26.z.string(),
3091
3183
  /** Human-readable label shown as a button. */
3092
- label: import_zod25.z.string().optional(),
3184
+ label: import_zod26.z.string().optional(),
3093
3185
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
3094
- icon: import_zod25.z.string().optional(),
3186
+ icon: import_zod26.z.string().optional(),
3095
3187
  /** Tooltip text. Falls back to `label` when omitted. */
3096
- tooltip: import_zod25.z.string().optional(),
3188
+ tooltip: import_zod26.z.string().optional(),
3097
3189
  /** Per-row condition — button is hidden when false. */
3098
- condition: import_zod25.z.custom().optional()
3190
+ condition: import_zod26.z.custom().optional()
3099
3191
  });
3100
3192
  var ResourceLinkActionSchema = ActionMetadataSchema.extend({
3101
- type: import_zod25.z.literal("link"),
3193
+ type: import_zod26.z.literal("link"),
3102
3194
  /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */
3103
- href: import_zod25.z.string()
3195
+ href: import_zod26.z.string()
3104
3196
  });
3105
3197
  var ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
3106
- type: import_zod25.z.literal("procedure").optional(),
3198
+ type: import_zod26.z.literal("procedure").optional(),
3107
3199
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3108
- method: import_zod25.z.string().optional(),
3200
+ method: import_zod26.z.string().optional(),
3109
3201
  /** Static data payload merged into the request body by the frontend. */
3110
- data: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.unknown()).optional(),
3202
+ data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
3111
3203
  /** Procedure called with `(prisma, recordId)`. */
3112
- procedure: import_zod25.z.custom((v) => typeof v === "function")
3204
+ procedure: import_zod26.z.custom((v) => typeof v === "function")
3113
3205
  });
3114
3206
  var ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
3115
- type: import_zod25.z.literal("procedure").optional(),
3207
+ type: import_zod26.z.literal("procedure").optional(),
3116
3208
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3117
- method: import_zod25.z.string().optional(),
3209
+ method: import_zod26.z.string().optional(),
3118
3210
  /** Static data payload merged into the request body by the frontend. */
3119
- data: import_zod25.z.record(import_zod25.z.string(), import_zod25.z.unknown()).optional(),
3211
+ data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
3120
3212
  /** Procedure called with `(prisma)` — no record id. */
3121
- procedure: import_zod25.z.custom((v) => typeof v === "function")
3213
+ procedure: import_zod26.z.custom((v) => typeof v === "function")
3122
3214
  });
3123
- var ResourceRowActionSchema = import_zod25.z.union([
3215
+ var ResourceRowActionSchema = import_zod26.z.union([
3124
3216
  ResourceRowProcedureActionSchema,
3125
3217
  ResourceLinkActionSchema
3126
3218
  ]);
3127
- var ResourceTableActionSchema = import_zod25.z.union([
3219
+ var ResourceTableActionSchema = import_zod26.z.union([
3128
3220
  ResourceTableProcedureActionSchema,
3129
3221
  ResourceLinkActionSchema
3130
3222
  ]);
@@ -3204,9 +3296,18 @@ var schemaFor = /* @__PURE__ */ __name((def2, op) => {
3204
3296
  return entry.schema;
3205
3297
  }, "schemaFor");
3206
3298
  var upsertOnFor = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
3299
+ var opSecurity = /* @__PURE__ */ __name((entry) => {
3300
+ if (!entry || entry === true) return void 0;
3301
+ return entry.security;
3302
+ }, "opSecurity");
3303
+ var securityFor = /* @__PURE__ */ __name((config, def2, op, moduleDefault) => opSecurity(def2[op]) ?? config.security ?? moduleDefault, "securityFor");
3304
+ var securityForSub = /* @__PURE__ */ __name((config, sub, op, moduleDefault) => {
3305
+ const entry = sub.operations[op];
3306
+ return opSecurity(entry) ?? config.security ?? moduleDefault;
3307
+ }, "securityForSub");
3207
3308
 
3208
3309
  // src/lib/crud/custom-repository/custom-repository.types.ts
3209
- var import_zod26 = require("zod");
3310
+ var import_zod27 = require("zod");
3210
3311
  var CUSTOM_OPS = [
3211
3312
  "findAll",
3212
3313
  "findOne",
@@ -3223,7 +3324,7 @@ var PARENT_METHOD = {
3223
3324
  patch: "patchByParent",
3224
3325
  delete: "deleteByParent"
3225
3326
  };
3226
- var CustomRepositorySchema = import_zod26.z.custom((value) => typeof value === "object" && value !== null);
3327
+ var CustomRepositorySchema = import_zod27.z.custom((value) => typeof value === "object" && value !== null);
3227
3328
 
3228
3329
  // src/lib/crud/resource/resource-load-errors.registry.ts
3229
3330
  var ResourceLoadErrorsRegistry = class ResourceLoadErrorsRegistry2 {
@@ -3297,22 +3398,22 @@ var DEFAULT_ID_TYPE = "string";
3297
3398
  var DEFAULT_ID_FIELD = "id";
3298
3399
 
3299
3400
  // src/lib/crud/hooks/hooks.types.ts
3300
- var import_zod27 = require("zod");
3301
- var WriteOpSchema = import_zod27.z.enum([
3401
+ var import_zod28 = require("zod");
3402
+ var WriteOpSchema = import_zod28.z.enum([
3302
3403
  "create",
3303
3404
  "update",
3304
3405
  "patch",
3305
3406
  "upsert",
3306
3407
  "delete"
3307
3408
  ]);
3308
- var ReadOpSchema = import_zod27.z.enum([
3409
+ var ReadOpSchema = import_zod28.z.enum([
3309
3410
  "findAll",
3310
3411
  "findOne"
3311
3412
  ]);
3312
- var ResourceHooksSchema = import_zod27.z.object({
3313
- beforeWrite: import_zod27.z.custom().optional(),
3314
- afterWrite: import_zod27.z.custom().optional(),
3315
- afterRead: import_zod27.z.custom().optional()
3413
+ var ResourceHooksSchema = import_zod28.z.object({
3414
+ beforeWrite: import_zod28.z.custom().optional(),
3415
+ afterWrite: import_zod28.z.custom().optional(),
3416
+ afterRead: import_zod28.z.custom().optional()
3316
3417
  });
3317
3418
 
3318
3419
  // src/lib/crud/hooks/hooks.loader.ts
@@ -4260,9 +4361,9 @@ var ReadRepository = class {
4260
4361
  };
4261
4362
 
4262
4363
  // src/lib/crud/schema.utils.ts
4263
- var import_zod28 = require("zod");
4364
+ var import_zod29 = require("zod");
4264
4365
  function isZodSchema(schema) {
4265
- return schema instanceof import_zod28.ZodObject;
4366
+ return schema instanceof import_zod29.ZodObject;
4266
4367
  }
4267
4368
  __name(isZodSchema, "isZodSchema");
4268
4369
  var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
@@ -4276,7 +4377,7 @@ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
4276
4377
  }, "dropNullableFromRequired");
4277
4378
  function toJsonSchema(schema) {
4278
4379
  if (isZodSchema(schema)) {
4279
- const jsonSchema = (0, import_zod28.toJSONSchema)(schema, {
4380
+ const jsonSchema = (0, import_zod29.toJSONSchema)(schema, {
4280
4381
  target: "openApi3",
4281
4382
  ...jsonSchemaOpts
4282
4383
  });
@@ -4831,9 +4932,121 @@ var findModule2 = /* @__PURE__ */ __name((dir, name) => {
4831
4932
  }, "findModule");
4832
4933
 
4833
4934
  // src/lib/crud/operations/register-actions.ts
4834
- var import_common10 = require("@nestjs/common");
4935
+ var import_common12 = require("@nestjs/common");
4835
4936
  var import_swagger2 = require("@nestjs/swagger");
4836
4937
 
4938
+ // src/lib/crud/security/crouton-security.guard.ts
4939
+ var import_common11 = require("@nestjs/common");
4940
+ var import_core = require("@nestjs/core");
4941
+
4942
+ // src/lib/crud/security/security-guard.registry.ts
4943
+ var import_common10 = require("@nestjs/common");
4944
+ function _ts_decorate6(decorators, target, key, desc2) {
4945
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4946
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4947
+ r = Reflect.decorate(decorators, target, key, desc2);
4948
+ } else {
4949
+ for (var i = decorators.length - 1; i >= 0; i--) {
4950
+ if (d = decorators[i]) {
4951
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4952
+ }
4953
+ }
4954
+ }
4955
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4956
+ }
4957
+ __name(_ts_decorate6, "_ts_decorate");
4958
+ function _ts_metadata6(metadataKey, metadataValue) {
4959
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4960
+ return Reflect.metadata(metadataKey, metadataValue);
4961
+ }
4962
+ }
4963
+ __name(_ts_metadata6, "_ts_metadata");
4964
+ var SecurityGuardRegistry = class {
4965
+ static {
4966
+ __name(this, "SecurityGuardRegistry");
4967
+ }
4968
+ guards;
4969
+ constructor(guards = {}) {
4970
+ this.guards = guards;
4971
+ }
4972
+ resolve(name) {
4973
+ const g = this.guards[name];
4974
+ if (!g) throw new Error(`Unknown security guard "${name}". Register it in security.guards.`);
4975
+ return g;
4976
+ }
4977
+ classes() {
4978
+ return Object.values(this.guards);
4979
+ }
4980
+ };
4981
+ SecurityGuardRegistry = _ts_decorate6([
4982
+ (0, import_common10.Injectable)(),
4983
+ _ts_metadata6("design:type", Function),
4984
+ _ts_metadata6("design:paramtypes", [
4985
+ typeof Record === "undefined" ? Object : Record
4986
+ ])
4987
+ ], SecurityGuardRegistry);
4988
+
4989
+ // src/lib/crud/security/crouton-security.guard.ts
4990
+ function _ts_decorate7(decorators, target, key, desc2) {
4991
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4992
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4993
+ r = Reflect.decorate(decorators, target, key, desc2);
4994
+ } else {
4995
+ for (var i = decorators.length - 1; i >= 0; i--) {
4996
+ if (d = decorators[i]) {
4997
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4998
+ }
4999
+ }
5000
+ }
5001
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
5002
+ }
5003
+ __name(_ts_decorate7, "_ts_decorate");
5004
+ function _ts_metadata7(metadataKey, metadataValue) {
5005
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
5006
+ return Reflect.metadata(metadataKey, metadataValue);
5007
+ }
5008
+ }
5009
+ __name(_ts_metadata7, "_ts_metadata");
5010
+ var CROUTON_SECURITY = "crouton:security";
5011
+ var CroutonSecurityGuard = class {
5012
+ static {
5013
+ __name(this, "CroutonSecurityGuard");
5014
+ }
5015
+ reflector;
5016
+ registry;
5017
+ moduleRef;
5018
+ constructor(reflector, registry, moduleRef) {
5019
+ this.reflector = reflector;
5020
+ this.registry = registry;
5021
+ this.moduleRef = moduleRef;
5022
+ }
5023
+ async canActivate(context) {
5024
+ const sec = this.reflector.get(CROUTON_SECURITY, context.getHandler());
5025
+ if (!sec || "public" in sec) return true;
5026
+ const names = Array.isArray(sec.guard) ? sec.guard : [
5027
+ sec.guard
5028
+ ];
5029
+ for (const name of names) {
5030
+ const cls = this.registry.resolve(name);
5031
+ const guard = this.moduleRef.get(cls, {
5032
+ strict: false
5033
+ });
5034
+ const ok = await guard.canActivate(context);
5035
+ if (!ok) return false;
5036
+ }
5037
+ return true;
5038
+ }
5039
+ };
5040
+ CroutonSecurityGuard = _ts_decorate7([
5041
+ (0, import_common11.Injectable)(),
5042
+ _ts_metadata7("design:type", Function),
5043
+ _ts_metadata7("design:paramtypes", [
5044
+ typeof import_core.Reflector === "undefined" ? Object : import_core.Reflector,
5045
+ typeof SecurityGuardRegistry === "undefined" ? Object : SecurityGuardRegistry,
5046
+ typeof import_core.ModuleRef === "undefined" ? Object : import_core.ModuleRef
5047
+ ])
5048
+ ], CroutonSecurityGuard);
5049
+
4837
5050
  // src/lib/crud/operations/decorator.utils.ts
4838
5051
  var def = /* @__PURE__ */ __name((cls, method, fn) => {
4839
5052
  Object.defineProperty(cls.prototype, method, {
@@ -4855,8 +5068,8 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
4855
5068
  return action.procedure(this.repo.prisma, recordId);
4856
5069
  });
4857
5070
  const d = desc(cls, methodName);
4858
- (0, import_common10.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
4859
- (0, import_common10.Param)("recordId")(cls.prototype, methodName, 0);
5071
+ (0, import_common12.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
5072
+ (0, import_common12.Param)("recordId")(cls.prototype, methodName, 0);
4860
5073
  (0, import_swagger2.ApiOperation)({
4861
5074
  summary: `Execute action "${action.label}" on a ${name}`
4862
5075
  })(cls.prototype, methodName, d);
@@ -4868,6 +5081,10 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
4868
5081
  status: 200,
4869
5082
  description: `Action "${action.id}" result`
4870
5083
  })(cls.prototype, methodName, d);
5084
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5085
+ if (sec) {
5086
+ (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
5087
+ }
4871
5088
  }
4872
5089
  }, "registerActionRoutes");
4873
5090
  var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
@@ -4880,7 +5097,7 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4880
5097
  return action.procedure(this.repo.prisma);
4881
5098
  });
4882
5099
  const d = desc(cls, methodName);
4883
- (0, import_common10.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
5100
+ (0, import_common12.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
4884
5101
  (0, import_swagger2.ApiOperation)({
4885
5102
  summary: `Execute table action "${action.label ?? action.id}" on ${name}`
4886
5103
  })(cls.prototype, methodName, d);
@@ -4888,11 +5105,15 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4888
5105
  status: 200,
4889
5106
  description: `Table action "${action.id}" result`
4890
5107
  })(cls.prototype, methodName, d);
5108
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5109
+ if (sec) {
5110
+ (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
5111
+ }
4891
5112
  }
4892
5113
  }, "registerTableActionRoutes");
4893
5114
 
4894
5115
  // src/lib/crud/operations/register-create.ts
4895
- var import_common11 = require("@nestjs/common");
5116
+ var import_common13 = require("@nestjs/common");
4896
5117
  var import_swagger3 = require("@nestjs/swagger");
4897
5118
  var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4898
5119
  if (!isOperationEnabled(ctx.definition, "create")) return null;
@@ -4909,7 +5130,7 @@ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4909
5130
  bodyDecorator(createSchema, {
4910
5131
  coerceNullableUndefinedToNull: true
4911
5132
  })(cls.prototype, methodName, 0);
4912
- (0, import_common11.Req)()(cls.prototype, methodName, 1);
5133
+ (0, import_common13.Req)()(cls.prototype, methodName, 1);
4913
5134
  }, "decorators")
4914
5135
  };
4915
5136
  }, "defaultCreate");
@@ -4921,9 +5142,9 @@ var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
4921
5142
  return this.repo.createChild(id, sub, body, req);
4922
5143
  }, "createFn");
4923
5144
  const decorators = /* @__PURE__ */ __name(() => {
4924
- (0, import_common11.Param)("id")(cls.prototype, methodName, 0);
4925
- (0, import_common11.Body)()(cls.prototype, methodName, 1);
4926
- (0, import_common11.Req)()(cls.prototype, methodName, 2);
5145
+ (0, import_common13.Param)("id")(cls.prototype, methodName, 0);
5146
+ (0, import_common13.Body)()(cls.prototype, methodName, 1);
5147
+ (0, import_common13.Req)()(cls.prototype, methodName, 2);
4927
5148
  }, "decorators");
4928
5149
  return {
4929
5150
  route: `:id/${sub.childRoute}`,
@@ -4941,7 +5162,7 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4941
5162
  const { cls } = ctx;
4942
5163
  def(cls, methodName, properties.createFn);
4943
5164
  const d = desc(cls, methodName);
4944
- (0, import_common11.Post)(route)(cls.prototype, methodName, d);
5165
+ (0, import_common13.Post)(route)(cls.prototype, methodName, d);
4945
5166
  (0, import_swagger3.ApiOperation)({
4946
5167
  summary: `Create a ${name}`
4947
5168
  })(cls.prototype, methodName, d);
@@ -4950,10 +5171,11 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4950
5171
  description: `${name} created`
4951
5172
  })(cls.prototype, methodName, d);
4952
5173
  properties.decorators();
5174
+ ctx.secure(methodName, "create", sub);
4953
5175
  }, "registerCreate");
4954
5176
 
4955
5177
  // src/lib/crud/operations/register-delete.ts
4956
- var import_common12 = require("@nestjs/common");
5178
+ var import_common14 = require("@nestjs/common");
4957
5179
  var import_swagger4 = require("@nestjs/swagger");
4958
5180
  var defaultDelete = /* @__PURE__ */ __name((ctx) => {
4959
5181
  if (!isOperationEnabled(ctx.definition, "delete")) return null;
@@ -4979,9 +5201,9 @@ var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
4979
5201
  return this.repo.deleteChild(sub, childId, parentId2, req);
4980
5202
  }, "deleteFn");
4981
5203
  const decorators = /* @__PURE__ */ __name(() => {
4982
- (0, import_common12.Param)("childId")(cls.prototype, methodName, 0);
4983
- (0, import_common12.Param)("id")(cls.prototype, methodName, 1);
4984
- (0, import_common12.Req)()(cls.prototype, methodName, 2);
5204
+ (0, import_common14.Param)("childId")(cls.prototype, methodName, 0);
5205
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 1);
5206
+ (0, import_common14.Req)()(cls.prototype, methodName, 2);
4985
5207
  }, "decorators");
4986
5208
  return {
4987
5209
  route: `:id/${sub.childRoute}/:childId`,
@@ -4999,8 +5221,8 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
4999
5221
  const { methodName, route, name } = properties;
5000
5222
  def(cls, methodName, properties.deleteFn);
5001
5223
  const d = desc(cls, methodName);
5002
- (0, import_common12.Delete)(route)(cls.prototype, methodName, d);
5003
- (0, import_common12.Param)("id")(cls.prototype, methodName, 0);
5224
+ (0, import_common14.Delete)(route)(cls.prototype, methodName, d);
5225
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5004
5226
  (0, import_swagger4.ApiOperation)({
5005
5227
  summary: `Delete ${name} record`
5006
5228
  })(cls.prototype, methodName, d);
@@ -5009,11 +5231,12 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
5009
5231
  status: 200
5010
5232
  })(cls.prototype, methodName, d);
5011
5233
  properties.decorators();
5012
- if (!sub) (0, import_common12.Req)()(cls.prototype, methodName, 1);
5234
+ if (!sub) (0, import_common14.Req)()(cls.prototype, methodName, 1);
5235
+ ctx.secure(methodName, "delete", sub);
5013
5236
  }, "registerDelete");
5014
5237
 
5015
5238
  // src/lib/crud/operations/register-findall.ts
5016
- var import_common13 = require("@nestjs/common");
5239
+ var import_common15 = require("@nestjs/common");
5017
5240
  var import_swagger5 = require("@nestjs/swagger");
5018
5241
 
5019
5242
  // src/lib/crud/request.dto.ts
@@ -5169,8 +5392,8 @@ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
5169
5392
  return findAllByParent(this.repo, id, sub.childRoute, params, req);
5170
5393
  }, "findAll");
5171
5394
  const decorators = /* @__PURE__ */ __name(() => {
5172
- (0, import_common13.Param)("id")(cls.prototype, methodName, 2);
5173
- (0, import_common13.Req)()(cls.prototype, methodName, 3);
5395
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 2);
5396
+ (0, import_common15.Req)()(cls.prototype, methodName, 3);
5174
5397
  }, "decorators");
5175
5398
  return {
5176
5399
  name: sub.childRoute,
@@ -5189,10 +5412,10 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
5189
5412
  const { cls } = ctx;
5190
5413
  def(cls, methodName, properties.findAll);
5191
5414
  const d = desc(cls, methodName);
5192
- (0, import_common13.Get)(route)(cls.prototype, methodName, d);
5193
- (0, import_common13.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
5194
- (0, import_common13.Query)("q")(cls.prototype, methodName, 1);
5195
- if (!sub) (0, import_common13.Req)()(cls.prototype, methodName, 2);
5415
+ (0, import_common15.Get)(route)(cls.prototype, methodName, d);
5416
+ (0, import_common15.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
5417
+ (0, import_common15.Query)("q")(cls.prototype, methodName, 1);
5418
+ if (!sub) (0, import_common15.Req)()(cls.prototype, methodName, 2);
5196
5419
  (0, import_swagger5.ApiOperation)({
5197
5420
  summary: `List all ${name}s`
5198
5421
  })(cls.prototype, methodName, d);
@@ -5207,10 +5430,11 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
5207
5430
  }
5208
5431
  })(cls.prototype, methodName, d);
5209
5432
  properties.decorators();
5433
+ ctx.secure(methodName, "findAll", sub);
5210
5434
  }, "registerFindAll");
5211
5435
 
5212
5436
  // src/lib/crud/operations/register-findone.ts
5213
- var import_common14 = require("@nestjs/common");
5437
+ var import_common16 = require("@nestjs/common");
5214
5438
  var import_swagger6 = require("@nestjs/swagger");
5215
5439
  var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
5216
5440
  if (!isOperationEnabled(ctx.definition, "findOne")) return null;
@@ -5224,8 +5448,8 @@ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
5224
5448
  return this.repo.findOne(id, req);
5225
5449
  }, "findOneFn"),
5226
5450
  decorators: /* @__PURE__ */ __name(() => {
5227
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5228
- (0, import_common14.Req)()(cls.prototype, methodName, 1);
5451
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
5452
+ (0, import_common16.Req)()(cls.prototype, methodName, 1);
5229
5453
  }, "decorators")
5230
5454
  };
5231
5455
  }, "defaultFindOne");
@@ -5237,9 +5461,9 @@ var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
5237
5461
  return this.repo.findOneChild(sub, childId, parentId2, req);
5238
5462
  }, "findOneFn");
5239
5463
  const decorators = /* @__PURE__ */ __name(() => {
5240
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5241
- (0, import_common14.Param)("childId")(cls.prototype, methodName, 1);
5242
- (0, import_common14.Req)()(cls.prototype, methodName, 2);
5464
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
5465
+ (0, import_common16.Param)("childId")(cls.prototype, methodName, 1);
5466
+ (0, import_common16.Req)()(cls.prototype, methodName, 2);
5243
5467
  }, "decorators");
5244
5468
  return {
5245
5469
  route: `:id/${sub.childRoute}/:childId`,
@@ -5257,7 +5481,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
5257
5481
  const { cls } = ctx;
5258
5482
  def(cls, methodName, properties.findOneFn);
5259
5483
  const d = desc(cls, methodName);
5260
- (0, import_common14.Get)(route)(cls.prototype, methodName, d);
5484
+ (0, import_common16.Get)(route)(cls.prototype, methodName, d);
5261
5485
  (0, import_swagger6.ApiOperation)({
5262
5486
  summary: `Get one ${name} by id`
5263
5487
  })(cls.prototype, methodName, d);
@@ -5273,10 +5497,11 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
5273
5497
  description: "Not found"
5274
5498
  })(cls.prototype, methodName, d);
5275
5499
  properties.decorators();
5500
+ ctx.secure(methodName, "findOne", sub);
5276
5501
  }, "registerFindOne");
5277
5502
 
5278
5503
  // src/lib/crud/operations/register-patch.ts
5279
- var import_common15 = require("@nestjs/common");
5504
+ var import_common17 = require("@nestjs/common");
5280
5505
  var import_swagger7 = require("@nestjs/swagger");
5281
5506
  var defaultPatch = /* @__PURE__ */ __name((ctx) => {
5282
5507
  if (!isOperationEnabled(ctx.definition, "patch")) return null;
@@ -5290,9 +5515,9 @@ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
5290
5515
  return this.repo.patch(id, body, req);
5291
5516
  }, "patchFn"),
5292
5517
  decorators: /* @__PURE__ */ __name(() => {
5293
- (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
5518
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5294
5519
  bodyDecorator(patchSchema)(cls.prototype, methodName, 1);
5295
- (0, import_common15.Req)()(cls.prototype, methodName, 2);
5520
+ (0, import_common17.Req)()(cls.prototype, methodName, 2);
5296
5521
  }, "decorators")
5297
5522
  };
5298
5523
  }, "defaultPatch");
@@ -5304,10 +5529,10 @@ var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
5304
5529
  return this.repo.updateChild(sub, childId, body, req);
5305
5530
  }, "patchFn");
5306
5531
  const decorators = /* @__PURE__ */ __name(() => {
5307
- (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
5308
- (0, import_common15.Param)("childId")(cls.prototype, methodName, 1);
5309
- (0, import_common15.Body)()(cls.prototype, methodName, 2);
5310
- (0, import_common15.Req)()(cls.prototype, methodName, 3);
5532
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5533
+ (0, import_common17.Param)("childId")(cls.prototype, methodName, 1);
5534
+ (0, import_common17.Body)()(cls.prototype, methodName, 2);
5535
+ (0, import_common17.Req)()(cls.prototype, methodName, 3);
5311
5536
  }, "decorators");
5312
5537
  return {
5313
5538
  route: `:id/${sub.childRoute}/:childId`,
@@ -5325,7 +5550,7 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
5325
5550
  const { cls } = ctx;
5326
5551
  def(cls, methodName, properties.patchFn);
5327
5552
  const d = desc(cls, methodName);
5328
- (0, import_common15.Patch)(route)(cls.prototype, methodName, d);
5553
+ (0, import_common17.Patch)(route)(cls.prototype, methodName, d);
5329
5554
  (0, import_swagger7.ApiOperation)({
5330
5555
  summary: `Update a ${name}`
5331
5556
  })(cls.prototype, methodName, d);
@@ -5337,33 +5562,34 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
5337
5562
  description: "Not found"
5338
5563
  })(cls.prototype, methodName, d);
5339
5564
  properties.decorators();
5565
+ ctx.secure(methodName, "patch", sub);
5340
5566
  }, "registerPatch");
5341
5567
 
5342
5568
  // src/lib/crud/operations/register-schema-endpoints.ts
5343
- var import_common16 = require("@nestjs/common");
5569
+ var import_common18 = require("@nestjs/common");
5344
5570
  var import_swagger8 = require("@nestjs/swagger");
5345
5571
 
5346
5572
  // src/lib/crud/resource/PatchResourceJson.schema.ts
5347
- var import_zod29 = require("zod");
5348
- var FieldVariantPatchSchema = import_zod29.z.object({
5349
- type: import_zod29.z.string().nullable().optional(),
5350
- format: import_zod29.z.string().nullable().optional(),
5351
- resource: import_zod29.z.string().nullable().optional(),
5352
- position: import_zod29.z.number().nullable().optional(),
5353
- options: import_zod29.z.record(import_zod29.z.string(), import_zod29.z.unknown().nullable()).optional()
5573
+ var import_zod30 = require("zod");
5574
+ var FieldVariantPatchSchema = import_zod30.z.object({
5575
+ type: import_zod30.z.string().nullable().optional(),
5576
+ format: import_zod30.z.string().nullable().optional(),
5577
+ resource: import_zod30.z.string().nullable().optional(),
5578
+ position: import_zod30.z.number().nullable().optional(),
5579
+ options: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown().nullable()).optional()
5354
5580
  }).partial();
5355
- var PatchColumnSchema = import_zod29.z.object({
5356
- label: import_zod29.z.string().optional(),
5357
- column: import_zod29.z.string().optional(),
5358
- hiddenInTable: import_zod29.z.boolean().optional(),
5359
- hiddenInForm: import_zod29.z.boolean().optional(),
5360
- hiddenInView: import_zod29.z.boolean().optional(),
5581
+ var PatchColumnSchema = import_zod30.z.object({
5582
+ label: import_zod30.z.string().optional(),
5583
+ column: import_zod30.z.string().optional(),
5584
+ hiddenInTable: import_zod30.z.boolean().optional(),
5585
+ hiddenInForm: import_zod30.z.boolean().optional(),
5586
+ hiddenInView: import_zod30.z.boolean().optional(),
5361
5587
  fieldInput: FieldVariantPatchSchema.optional(),
5362
5588
  fieldView: FieldVariantPatchSchema.optional(),
5363
5589
  fieldTable: FieldVariantPatchSchema.optional()
5364
5590
  }).partial();
5365
- var PatchResourceJsonSchema = import_zod29.z.object({
5366
- columns: import_zod29.z.record(import_zod29.z.string(), PatchColumnSchema)
5591
+ var PatchResourceJsonSchema = import_zod30.z.object({
5592
+ columns: import_zod30.z.record(import_zod30.z.string(), PatchColumnSchema)
5367
5593
  });
5368
5594
 
5369
5595
  // src/lib/crud/resource/WriteResourceJson.ts
@@ -5431,48 +5657,6 @@ var writeRawResourceJson = /* @__PURE__ */ __name((jsonPath, raw) => {
5431
5657
 
5432
5658
  // src/lib/crud/operations/payload-builders.ts
5433
5659
  var resolveEnvPlaceholders = /* @__PURE__ */ __name((value) => value.replace(/\{env\.([^}]+)\}/g, (match, varName) => process.env[varName] ?? match), "resolveEnvPlaceholders");
5434
- var buildSubResourceOperations = /* @__PURE__ */ __name((ops, baseUri, idField = "id") => {
5435
- if (!ops) return {};
5436
- const idPlaceholder = `{${idField}}`;
5437
- return {
5438
- ...ops.findAll && {
5439
- findAll: {
5440
- uri: baseUri,
5441
- method: "get"
5442
- }
5443
- },
5444
- ...ops.findOne && {
5445
- findOne: {
5446
- uri: `${baseUri}/${idPlaceholder}`,
5447
- method: "get"
5448
- }
5449
- },
5450
- ...ops.create && {
5451
- create: {
5452
- uri: baseUri,
5453
- method: "post"
5454
- }
5455
- },
5456
- ...ops.update && {
5457
- update: {
5458
- uri: `${baseUri}/${idPlaceholder}`,
5459
- method: "put"
5460
- }
5461
- },
5462
- ...ops.patch && {
5463
- patch: {
5464
- uri: `${baseUri}/${idPlaceholder}`,
5465
- method: "patch"
5466
- }
5467
- },
5468
- ...ops.delete && {
5469
- delete: {
5470
- uri: `${baseUri}/${idPlaceholder}`,
5471
- method: "delete"
5472
- }
5473
- }
5474
- };
5475
- }, "buildSubResourceOperations");
5476
5660
  var RESOURCE_OPS = [
5477
5661
  "findAll",
5478
5662
  "findOne",
@@ -5699,7 +5883,7 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
5699
5883
  return definitionPayload;
5700
5884
  });
5701
5885
  const d = desc(cls, "getDefinition");
5702
- (0, import_common16.Get)("definition")(cls.prototype, "getDefinition", d);
5886
+ (0, import_common18.Get)("definition")(cls.prototype, "getDefinition", d);
5703
5887
  (0, import_swagger8.ApiOperation)({
5704
5888
  summary: `Get the resource definition for ${name}`
5705
5889
  })(cls.prototype, "getDefinition", d);
@@ -5707,6 +5891,10 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
5707
5891
  status: 200,
5708
5892
  description: `Definition (operations + schemas) for ${name}`
5709
5893
  })(cls.prototype, "getDefinition", d);
5894
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5895
+ if (sec) {
5896
+ (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getDefinition", d);
5897
+ }
5710
5898
  }, "registerDefinitionEndpoint");
5711
5899
  var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5712
5900
  const { cls, config, baseUrl } = ctx;
@@ -5721,7 +5909,7 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5721
5909
  return resourceJsonPayload;
5722
5910
  });
5723
5911
  const d = desc(cls, "getResourceJson");
5724
- (0, import_common16.Get)("resource.json")(cls.prototype, "getResourceJson", d);
5912
+ (0, import_common18.Get)("resource.json")(cls.prototype, "getResourceJson", d);
5725
5913
  (0, import_swagger8.ApiOperation)({
5726
5914
  summary: `Get resource descriptor for ${name}`
5727
5915
  })(cls.prototype, "getResourceJson", d);
@@ -5729,19 +5917,23 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5729
5917
  status: 200,
5730
5918
  description: `Resource descriptor (operations + JSON Schema) for ${name}`
5731
5919
  })(cls.prototype, "getResourceJson", d);
5920
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5921
+ if (sec) {
5922
+ (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getResourceJson", d);
5923
+ }
5732
5924
  }, "registerResourceJsonEndpoint");
5733
5925
  var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
5734
5926
  const { cls, config } = ctx;
5735
5927
  const { route, name } = config;
5736
5928
  def(cls, "getResourceColumns", async function() {
5737
5929
  if (!IS_DEV) {
5738
- throw new import_common16.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
5930
+ throw new import_common18.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
5739
5931
  }
5740
5932
  const fresh = await this.configRegistry.getByRoute(route);
5741
5933
  return buildEditableColumnsPayload(fresh ?? config);
5742
5934
  });
5743
5935
  const d = desc(cls, "getResourceColumns");
5744
- (0, import_common16.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5936
+ (0, import_common18.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5745
5937
  (0, import_swagger8.ApiOperation)({
5746
5938
  summary: `Dev-only: get the editable column list for ${name}`
5747
5939
  })(cls.prototype, "getResourceColumns", d);
@@ -5755,30 +5947,30 @@ var registerResourceJsonPatchEndpoint = /* @__PURE__ */ __name((ctx) => {
5755
5947
  const { route, name } = config;
5756
5948
  def(cls, "patchResourceJson", async function(body) {
5757
5949
  if (!IS_DEV) {
5758
- throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5950
+ throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5759
5951
  }
5760
5952
  await this.configRegistry.getByRoute(route);
5761
5953
  const dir = this.configRegistry.getResourceDir(route);
5762
5954
  if (!dir) {
5763
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5955
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5764
5956
  }
5765
5957
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5766
5958
  const raw = readRawResourceJson(jsonPath);
5767
5959
  if (!raw) {
5768
- throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5960
+ throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
5769
5961
  }
5770
5962
  const merged = applyColumnPatch(raw, body);
5771
5963
  const validated = validateResourceJson(merged);
5772
5964
  if (!validated.success) {
5773
- throw new import_common16.BadRequestException(validated.error.issues);
5965
+ throw new import_common18.BadRequestException(validated.error.issues);
5774
5966
  }
5775
5967
  writeRawResourceJson(jsonPath, merged);
5776
5968
  const fresh = await this.configRegistry.getByRoute(route);
5777
5969
  return buildEditableColumnsPayload(fresh ?? config);
5778
5970
  });
5779
5971
  const d = desc(cls, "patchResourceJson");
5780
- (0, import_common16.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
5781
- (0, import_common16.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
5972
+ (0, import_common18.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
5973
+ (0, import_common18.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
5782
5974
  (0, import_swagger8.ApiOperation)({
5783
5975
  summary: `Dev-only: patch column layout in resource.json for ${name}`
5784
5976
  })(cls.prototype, "patchResourceJson", d);
@@ -5792,22 +5984,22 @@ var registerResourceJsonRawGetEndpoint = /* @__PURE__ */ __name((ctx) => {
5792
5984
  const { route, name } = config;
5793
5985
  def(cls, "getResourceJsonRaw", async function() {
5794
5986
  if (!IS_DEV) {
5795
- throw new import_common16.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
5987
+ throw new import_common18.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
5796
5988
  }
5797
5989
  await this.configRegistry.getByRoute(route);
5798
5990
  const dir = this.configRegistry.getResourceDir(route);
5799
5991
  if (!dir) {
5800
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5992
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5801
5993
  }
5802
5994
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5803
5995
  const raw = readRawResourceJson(jsonPath);
5804
5996
  if (!raw) {
5805
- throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5997
+ throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
5806
5998
  }
5807
5999
  return raw;
5808
6000
  });
5809
6001
  const d = desc(cls, "getResourceJsonRaw");
5810
- (0, import_common16.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
6002
+ (0, import_common18.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
5811
6003
  (0, import_swagger8.ApiOperation)({
5812
6004
  summary: `Dev-only: get the raw resource.json for ${name}`
5813
6005
  })(cls.prototype, "getResourceJsonRaw", d);
@@ -5821,24 +6013,24 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5821
6013
  const { route, name } = config;
5822
6014
  def(cls, "putResourceJsonRaw", async function(body) {
5823
6015
  if (!IS_DEV) {
5824
- throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
6016
+ throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5825
6017
  }
5826
6018
  await this.configRegistry.getByRoute(route);
5827
6019
  const dir = this.configRegistry.getResourceDir(route);
5828
6020
  if (!dir) {
5829
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
6021
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5830
6022
  }
5831
6023
  const validated = validateResourceJson(body);
5832
6024
  if (!validated.success) {
5833
- throw new import_common16.BadRequestException(validated.error.issues);
6025
+ throw new import_common18.BadRequestException(validated.error.issues);
5834
6026
  }
5835
6027
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5836
6028
  writeRawResourceJson(jsonPath, body);
5837
6029
  return body;
5838
6030
  });
5839
6031
  const d = desc(cls, "putResourceJsonRaw");
5840
- (0, import_common16.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
5841
- (0, import_common16.Body)()(cls.prototype, "putResourceJsonRaw", 0);
6032
+ (0, import_common18.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
6033
+ (0, import_common18.Body)()(cls.prototype, "putResourceJsonRaw", 0);
5842
6034
  (0, import_swagger8.ApiOperation)({
5843
6035
  summary: `Dev-only: replace the full resource.json for ${name}`
5844
6036
  })(cls.prototype, "putResourceJsonRaw", d);
@@ -5849,7 +6041,7 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5849
6041
  }, "registerResourceJsonRawPutEndpoint");
5850
6042
 
5851
6043
  // src/lib/crud/operations/register-schemas.ts
5852
- var import_common17 = require("@nestjs/common");
6044
+ var import_common19 = require("@nestjs/common");
5853
6045
  var import_swagger9 = require("@nestjs/swagger");
5854
6046
  var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
5855
6047
  const { config, baseUrl } = ctx;
@@ -5894,7 +6086,7 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5894
6086
  const { cls } = ctx;
5895
6087
  def(cls, methodName, properties.schemasFn);
5896
6088
  const d = desc(cls, methodName);
5897
- (0, import_common17.Get)(route)(cls.prototype, methodName, d);
6089
+ (0, import_common19.Get)(route)(cls.prototype, methodName, d);
5898
6090
  (0, import_swagger9.ApiOperation)({
5899
6091
  summary: `Get view schemas for ${name}`
5900
6092
  })(cls.prototype, methodName, d);
@@ -5903,10 +6095,14 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5903
6095
  description: `View schemas for ${name}`
5904
6096
  })(cls.prototype, methodName, d);
5905
6097
  properties.decorators();
6098
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
6099
+ if (sec) {
6100
+ (0, import_common19.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6101
+ }
5906
6102
  }, "registerSchemas");
5907
6103
 
5908
6104
  // src/lib/crud/operations/register-update.ts
5909
- var import_common18 = require("@nestjs/common");
6105
+ var import_common20 = require("@nestjs/common");
5910
6106
  var import_swagger10 = require("@nestjs/swagger");
5911
6107
  var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5912
6108
  if (!isOperationEnabled(ctx.definition, "update")) return null;
@@ -5920,9 +6116,9 @@ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5920
6116
  return this.repo.update(id, body, req);
5921
6117
  }, "updateFn"),
5922
6118
  decorators: /* @__PURE__ */ __name(() => {
5923
- (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
6119
+ (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
5924
6120
  bodyDecorator(updateSchema)(cls.prototype, methodName, 1);
5925
- (0, import_common18.Req)()(cls.prototype, methodName, 2);
6121
+ (0, import_common20.Req)()(cls.prototype, methodName, 2);
5926
6122
  }, "decorators")
5927
6123
  };
5928
6124
  }, "defaultUpdate");
@@ -5934,10 +6130,10 @@ var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
5934
6130
  return this.repo.updateChild(sub, childId, body, req);
5935
6131
  }, "updateFn");
5936
6132
  const decorators = /* @__PURE__ */ __name(() => {
5937
- (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
5938
- (0, import_common18.Param)("childId")(cls.prototype, methodName, 1);
5939
- (0, import_common18.Body)()(cls.prototype, methodName, 2);
5940
- (0, import_common18.Req)()(cls.prototype, methodName, 3);
6133
+ (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
6134
+ (0, import_common20.Param)("childId")(cls.prototype, methodName, 1);
6135
+ (0, import_common20.Body)()(cls.prototype, methodName, 2);
6136
+ (0, import_common20.Req)()(cls.prototype, methodName, 3);
5941
6137
  }, "decorators");
5942
6138
  return {
5943
6139
  route: `:id/${sub.childRoute}/:childId`,
@@ -5955,7 +6151,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
5955
6151
  const { cls } = ctx;
5956
6152
  def(cls, methodName, properties.updateFn);
5957
6153
  const d = desc(cls, methodName);
5958
- (0, import_common18.Put)(route)(cls.prototype, methodName, d);
6154
+ (0, import_common20.Put)(route)(cls.prototype, methodName, d);
5959
6155
  (0, import_swagger10.ApiOperation)({
5960
6156
  summary: `Replace a ${name}`
5961
6157
  })(cls.prototype, methodName, d);
@@ -5967,6 +6163,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
5967
6163
  description: "Not found"
5968
6164
  })(cls.prototype, methodName, d);
5969
6165
  properties.decorators();
6166
+ ctx.secure(methodName, "update", sub);
5970
6167
  }, "registerUpdate");
5971
6168
 
5972
6169
  // src/lib/crud/operations/register-endpoints.ts
@@ -5999,7 +6196,7 @@ var registerEndpoint = /* @__PURE__ */ __name((ctx, sub) => {
5999
6196
  }, "registerEndpoint");
6000
6197
 
6001
6198
  // src/lib/crud/crud-controller.factory.ts
6002
- function createCrudController(config, baseUrl) {
6199
+ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEnabled = false) {
6003
6200
  const { route, name, tag, idType = "string" } = config;
6004
6201
  const definition = resolveDefinition(config);
6005
6202
  const listSchema = schemaFor(definition, "findAll");
@@ -6013,9 +6210,9 @@ function createCrudController(config, baseUrl) {
6013
6210
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
6014
6211
  }
6015
6212
  const bodyDecorator = /* @__PURE__ */ __name((schema, options) => {
6016
- if (!schema) return (0, import_common19.Body)();
6017
- if (isZodSchema(schema)) return (0, import_common19.Body)(new ZodValidationPipe(schema, options));
6018
- return (0, import_common19.Body)();
6213
+ if (!schema) return (0, import_common21.Body)();
6214
+ if (isZodSchema(schema)) return (0, import_common21.Body)(new ZodValidationPipe(schema, options));
6215
+ return (0, import_common21.Body)();
6019
6216
  }, "bodyDecorator");
6020
6217
  const resolveClient = /* @__PURE__ */ __name((registry, resource) => {
6021
6218
  try {
@@ -6037,6 +6234,12 @@ function createCrudController(config, baseUrl) {
6037
6234
  this.configRegistry = configRegistry;
6038
6235
  }
6039
6236
  };
6237
+ const secure = /* @__PURE__ */ __name((methodName, op, sub) => {
6238
+ const sec = sub ? securityForSub(config, sub, op, moduleDefaultSecurity) : securityFor(config, definition, op, moduleDefaultSecurity);
6239
+ if (sec) {
6240
+ (0, import_common21.SetMetadata)(CROUTON_SECURITY, sec)(CrudControllerBase.prototype, methodName, Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName));
6241
+ }
6242
+ }, "secure");
6040
6243
  const ctx = {
6041
6244
  cls: CrudControllerBase,
6042
6245
  config,
@@ -6052,10 +6255,15 @@ function createCrudController(config, baseUrl) {
6052
6255
  type: idType === "number" ? "number" : "string"
6053
6256
  },
6054
6257
  bodyDecorator,
6055
- baseUrl
6258
+ baseUrl,
6259
+ moduleDefaultSecurity,
6260
+ secure
6056
6261
  };
6057
6262
  registerEndpoints(ctx);
6058
- (0, import_common19.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
6263
+ (0, import_common21.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
6264
+ if (securityEnabled) {
6265
+ (0, import_common21.UseGuards)(CroutonSecurityGuard)(CrudControllerBase);
6266
+ }
6059
6267
  (0, import_swagger11.ApiTags)(tag)(CrudControllerBase);
6060
6268
  Object.defineProperty(CrudControllerBase, "name", {
6061
6269
  value: `${name.charAt(0).toUpperCase() + name.slice(1)}Controller`
@@ -6069,7 +6277,7 @@ function createCrudController(config, baseUrl) {
6069
6277
  __name(createCrudController, "createCrudController");
6070
6278
 
6071
6279
  // src/lib/crud/dev-tools/dev-resources.controller.ts
6072
- var import_common20 = require("@nestjs/common");
6280
+ var import_common22 = require("@nestjs/common");
6073
6281
  var import_swagger12 = require("@nestjs/swagger");
6074
6282
 
6075
6283
  // ../crouton-codegen/src/naming.ts
@@ -6765,12 +6973,12 @@ var makeSchemaExportName = /* @__PURE__ */ __name((config) => {
6765
6973
  var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path11.isAbsolute)(p) ? p : (0, import_node_path11.join)(root, p), "resolveFromRoot");
6766
6974
 
6767
6975
  // ../crouton-codegen/src/scaffold.ts
6768
- var import_zod30 = require("zod");
6976
+ var import_zod31 = require("zod");
6769
6977
  var import_promises5 = require("fs/promises");
6770
6978
  var import_node_path12 = require("path");
6771
6979
  var ScallfoldDatasourceSchema = DataSourceShape.extend({
6772
6980
  /** Folder name under `dataSourcesDir`. */
6773
- folder: import_zod30.z.string().default("default")
6981
+ folder: import_zod31.z.string().default("default")
6774
6982
  }).transform(transformDataSource);
6775
6983
 
6776
6984
  // ../crouton-codegen/src/datasource-scaffold.ts
@@ -7087,7 +7295,7 @@ var ResourceLoadReportRegistry = class ResourceLoadReportRegistry2 {
7087
7295
  var resourceLoadReportRegistry = new ResourceLoadReportRegistry();
7088
7296
 
7089
7297
  // src/lib/crud/dev-tools/dev-resources.controller.ts
7090
- function _ts_decorate6(decorators, target, key, desc2) {
7298
+ function _ts_decorate8(decorators, target, key, desc2) {
7091
7299
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
7092
7300
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
7093
7301
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -7100,13 +7308,13 @@ function _ts_decorate6(decorators, target, key, desc2) {
7100
7308
  }
7101
7309
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7102
7310
  }
7103
- __name(_ts_decorate6, "_ts_decorate");
7104
- function _ts_metadata6(metadataKey, metadataValue) {
7311
+ __name(_ts_decorate8, "_ts_decorate");
7312
+ function _ts_metadata8(metadataKey, metadataValue) {
7105
7313
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
7106
7314
  return Reflect.metadata(metadataKey, metadataValue);
7107
7315
  }
7108
7316
  }
7109
- __name(_ts_metadata6, "_ts_metadata");
7317
+ __name(_ts_metadata8, "_ts_metadata");
7110
7318
  function _ts_param2(paramIndex, decorator) {
7111
7319
  return function(target, key) {
7112
7320
  decorator(target, key, paramIndex);
@@ -7125,7 +7333,7 @@ var DevResourcesController = class {
7125
7333
  }
7126
7334
  assertDev() {
7127
7335
  if (!IS_DEV) {
7128
- throw new import_common20.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
7336
+ throw new import_common22.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
7129
7337
  }
7130
7338
  }
7131
7339
  /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */
@@ -7134,14 +7342,14 @@ var DevResourcesController = class {
7134
7342
  try {
7135
7343
  loaded = await loadConfig2(process.cwd());
7136
7344
  } catch (e) {
7137
- throw new import_common20.NotFoundException(e.message ?? "No crouton.json config found.");
7345
+ throw new import_common22.NotFoundException(e.message ?? "No crouton.json config found.");
7138
7346
  }
7139
7347
  const datasources = await loadDatasources(loaded);
7140
7348
  let ds;
7141
7349
  try {
7142
7350
  ds = resolveDatasource(datasources, datasourceName);
7143
7351
  } catch (e) {
7144
- throw new import_common20.BadRequestException(e.message);
7352
+ throw new import_common22.BadRequestException(e.message);
7145
7353
  }
7146
7354
  const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);
7147
7355
  return {
@@ -7156,7 +7364,7 @@ var DevResourcesController = class {
7156
7364
  schemaPath
7157
7365
  });
7158
7366
  } catch (e) {
7159
- throw new import_common20.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
7367
+ throw new import_common22.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
7160
7368
  }
7161
7369
  }
7162
7370
  buildApplyContext(loaded, ds) {
@@ -7226,7 +7434,7 @@ var DevResourcesController = class {
7226
7434
  zodOutputDir: zodDir
7227
7435
  });
7228
7436
  if (!result.ok) {
7229
- throw new import_common20.BadRequestException(`prisma db pull failed:
7437
+ throw new import_common22.BadRequestException(`prisma db pull failed:
7230
7438
  ${result.dbPull.output}`);
7231
7439
  }
7232
7440
  return {
@@ -7243,13 +7451,13 @@ ${result.dbPull.output}`);
7243
7451
  async sync(body) {
7244
7452
  this.assertDev();
7245
7453
  if (!body?.model) {
7246
- throw new import_common20.BadRequestException('"model" is required.');
7454
+ throw new import_common22.BadRequestException('"model" is required.');
7247
7455
  }
7248
7456
  const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);
7249
7457
  const models = await this.introspectModels(schemaPath);
7250
7458
  const model = models.find((m) => m.prismaName === body.model || m.clientAccessor === body.model);
7251
7459
  if (!model) {
7252
- throw new import_common20.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
7460
+ throw new import_common22.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
7253
7461
  }
7254
7462
  const resolveRelationResource = await makeRelationResolver(loaded);
7255
7463
  const diff2 = await buildResourceDiff(model, {
@@ -7371,14 +7579,14 @@ ${result.dbPull.output}`);
7371
7579
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7372
7580
  const jsonPath = resolveResourcePath(resourcesDir, name);
7373
7581
  const raw = readRawResourceJson(jsonPath);
7374
- if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7375
- if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
7582
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7583
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7376
7584
  const patched = applyResourceFlagPatch(raw, {
7377
7585
  draft: false
7378
7586
  });
7379
7587
  const result = validateResourceJson(patched);
7380
7588
  if (!result.success) {
7381
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7589
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7382
7590
  }
7383
7591
  writeRawResourceJson(jsonPath, patched);
7384
7592
  return {
@@ -7391,8 +7599,8 @@ ${result.dbPull.output}`);
7391
7599
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7392
7600
  const jsonPath = resolveResourcePath(resourcesDir, name);
7393
7601
  const raw = readRawResourceJson(jsonPath);
7394
- if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7395
- if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
7602
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7603
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7396
7604
  const patched = applyResourceFlagPatch(raw, {
7397
7605
  sidebar: {
7398
7606
  hide: true
@@ -7400,7 +7608,7 @@ ${result.dbPull.output}`);
7400
7608
  });
7401
7609
  const result = validateResourceJson(patched);
7402
7610
  if (!result.success) {
7403
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7611
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7404
7612
  }
7405
7613
  writeRawResourceJson(jsonPath, patched);
7406
7614
  return {
@@ -7413,8 +7621,8 @@ ${result.dbPull.output}`);
7413
7621
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7414
7622
  const jsonPath = resolveResourcePath(resourcesDir, name);
7415
7623
  const raw = readRawResourceJson(jsonPath);
7416
- if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7417
- if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
7624
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7625
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7418
7626
  const sidebarPatch = {
7419
7627
  hide: false
7420
7628
  };
@@ -7427,7 +7635,7 @@ ${result.dbPull.output}`);
7427
7635
  });
7428
7636
  const result = validateResourceJson(patched);
7429
7637
  if (!result.success) {
7430
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7638
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7431
7639
  }
7432
7640
  writeRawResourceJson(jsonPath, patched);
7433
7641
  return {
@@ -7440,12 +7648,12 @@ ${result.dbPull.output}`);
7440
7648
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7441
7649
  const jsonPath = resolveResourcePath(resourcesDir, name);
7442
7650
  const raw = readRawResourceJson(jsonPath);
7443
- if (!raw) throw new import_common20.NotFoundException(`Resource "${name}" not found.`);
7444
- if (jsonPath.endsWith(".ts")) throw new import_common20.ForbiddenException("TypeScript resources cannot be edited.");
7651
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7652
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7445
7653
  const patched = applyResourceFlagPatch(raw, body);
7446
7654
  const result = validateResourceJson(patched);
7447
7655
  if (!result.success) {
7448
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7656
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7449
7657
  }
7450
7658
  writeRawResourceJson(jsonPath, patched);
7451
7659
  return {
@@ -7453,8 +7661,8 @@ ${result.dbPull.output}`);
7453
7661
  };
7454
7662
  }
7455
7663
  };
7456
- _ts_decorate6([
7457
- (0, import_common20.Get)("models"),
7664
+ _ts_decorate8([
7665
+ (0, import_common22.Get)("models"),
7458
7666
  (0, import_swagger12.ApiOperation)({
7459
7667
  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"
7460
7668
  }),
@@ -7462,12 +7670,12 @@ _ts_decorate6([
7462
7670
  status: 200,
7463
7671
  description: "DB models and their resource/client status"
7464
7672
  }),
7465
- _ts_metadata6("design:type", Function),
7466
- _ts_metadata6("design:paramtypes", []),
7467
- _ts_metadata6("design:returntype", Promise)
7673
+ _ts_metadata8("design:type", Function),
7674
+ _ts_metadata8("design:paramtypes", []),
7675
+ _ts_metadata8("design:returntype", Promise)
7468
7676
  ], DevResourcesController.prototype, "listModels", null);
7469
- _ts_decorate6([
7470
- (0, import_common20.Post)("restart"),
7677
+ _ts_decorate8([
7678
+ (0, import_common22.Post)("restart"),
7471
7679
  (0, import_swagger12.ApiOperation)({
7472
7680
  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."
7473
7681
  }),
@@ -7475,12 +7683,12 @@ _ts_decorate6([
7475
7683
  status: 200,
7476
7684
  description: "Restart scheduled \u2014 the connection will drop shortly after"
7477
7685
  }),
7478
- _ts_metadata6("design:type", Function),
7479
- _ts_metadata6("design:paramtypes", []),
7480
- _ts_metadata6("design:returntype", Object)
7686
+ _ts_metadata8("design:type", Function),
7687
+ _ts_metadata8("design:paramtypes", []),
7688
+ _ts_metadata8("design:returntype", Object)
7481
7689
  ], DevResourcesController.prototype, "restart", null);
7482
- _ts_decorate6([
7483
- (0, import_common20.Post)("pull"),
7690
+ _ts_decorate8([
7691
+ (0, import_common22.Post)("pull"),
7484
7692
  (0, import_swagger12.ApiOperation)({
7485
7693
  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"
7486
7694
  }),
@@ -7488,15 +7696,15 @@ _ts_decorate6([
7488
7696
  status: 200,
7489
7697
  description: "Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes"
7490
7698
  }),
7491
- _ts_param2(0, (0, import_common20.Body)()),
7492
- _ts_metadata6("design:type", Function),
7493
- _ts_metadata6("design:paramtypes", [
7699
+ _ts_param2(0, (0, import_common22.Body)()),
7700
+ _ts_metadata8("design:type", Function),
7701
+ _ts_metadata8("design:paramtypes", [
7494
7702
  Object
7495
7703
  ]),
7496
- _ts_metadata6("design:returntype", Promise)
7704
+ _ts_metadata8("design:returntype", Promise)
7497
7705
  ], DevResourcesController.prototype, "pull", null);
7498
- _ts_decorate6([
7499
- (0, import_common20.Post)("sync"),
7706
+ _ts_decorate8([
7707
+ (0, import_common22.Post)("sync"),
7500
7708
  (0, import_swagger12.ApiOperation)({
7501
7709
  summary: "Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)"
7502
7710
  }),
@@ -7504,15 +7712,15 @@ _ts_decorate6([
7504
7712
  status: 200,
7505
7713
  description: "Files written for this resource"
7506
7714
  }),
7507
- _ts_param2(0, (0, import_common20.Body)()),
7508
- _ts_metadata6("design:type", Function),
7509
- _ts_metadata6("design:paramtypes", [
7715
+ _ts_param2(0, (0, import_common22.Body)()),
7716
+ _ts_metadata8("design:type", Function),
7717
+ _ts_metadata8("design:paramtypes", [
7510
7718
  Object
7511
7719
  ]),
7512
- _ts_metadata6("design:returntype", Promise)
7720
+ _ts_metadata8("design:returntype", Promise)
7513
7721
  ], DevResourcesController.prototype, "sync", null);
7514
- _ts_decorate6([
7515
- (0, import_common20.Post)("plan"),
7722
+ _ts_decorate8([
7723
+ (0, import_common22.Post)("plan"),
7516
7724
  (0, import_swagger12.ApiOperation)({
7517
7725
  summary: "Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults \u2014 computes what would change, writes nothing"
7518
7726
  }),
@@ -7520,15 +7728,15 @@ _ts_decorate6([
7520
7728
  status: 200,
7521
7729
  description: "Proposed per-resource changes"
7522
7730
  }),
7523
- _ts_param2(0, (0, import_common20.Body)()),
7524
- _ts_metadata6("design:type", Function),
7525
- _ts_metadata6("design:paramtypes", [
7731
+ _ts_param2(0, (0, import_common22.Body)()),
7732
+ _ts_metadata8("design:type", Function),
7733
+ _ts_metadata8("design:paramtypes", [
7526
7734
  Object
7527
7735
  ]),
7528
- _ts_metadata6("design:returntype", Promise)
7736
+ _ts_metadata8("design:returntype", Promise)
7529
7737
  ], DevResourcesController.prototype, "plan", null);
7530
- _ts_decorate6([
7531
- (0, import_common20.Post)("apply"),
7738
+ _ts_decorate8([
7739
+ (0, import_common22.Post)("apply"),
7532
7740
  (0, import_swagger12.ApiOperation)({
7533
7741
  summary: "Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults"
7534
7742
  }),
@@ -7536,15 +7744,15 @@ _ts_decorate6([
7536
7744
  status: 200,
7537
7745
  description: "Per-resource commit results"
7538
7746
  }),
7539
- _ts_param2(0, (0, import_common20.Body)()),
7540
- _ts_metadata6("design:type", Function),
7541
- _ts_metadata6("design:paramtypes", [
7747
+ _ts_param2(0, (0, import_common22.Body)()),
7748
+ _ts_metadata8("design:type", Function),
7749
+ _ts_metadata8("design:paramtypes", [
7542
7750
  Object
7543
7751
  ]),
7544
- _ts_metadata6("design:returntype", Promise)
7752
+ _ts_metadata8("design:returntype", Promise)
7545
7753
  ], DevResourcesController.prototype, "apply", null);
7546
- _ts_decorate6([
7547
- (0, import_common20.Get)("visibility"),
7754
+ _ts_decorate8([
7755
+ (0, import_common22.Get)("visibility"),
7548
7756
  (0, import_swagger12.ApiOperation)({
7549
7757
  summary: "Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)"
7550
7758
  }),
@@ -7552,12 +7760,12 @@ _ts_decorate6([
7552
7760
  status: 200,
7553
7761
  description: "Resource visibility list"
7554
7762
  }),
7555
- _ts_metadata6("design:type", Function),
7556
- _ts_metadata6("design:paramtypes", []),
7557
- _ts_metadata6("design:returntype", Promise)
7763
+ _ts_metadata8("design:type", Function),
7764
+ _ts_metadata8("design:paramtypes", []),
7765
+ _ts_metadata8("design:returntype", Promise)
7558
7766
  ], DevResourcesController.prototype, "visibility", null);
7559
- _ts_decorate6([
7560
- (0, import_common20.Post)(":name/publish"),
7767
+ _ts_decorate8([
7768
+ (0, import_common22.Post)(":name/publish"),
7561
7769
  (0, import_swagger12.ApiOperation)({
7562
7770
  summary: "Dev-only: publish a draft resource (removes `draft: true` from resource.json)"
7563
7771
  }),
@@ -7565,15 +7773,15 @@ _ts_decorate6([
7565
7773
  status: 200,
7566
7774
  description: "Resource published"
7567
7775
  }),
7568
- _ts_param2(0, (0, import_common20.Param)("name")),
7569
- _ts_metadata6("design:type", Function),
7570
- _ts_metadata6("design:paramtypes", [
7776
+ _ts_param2(0, (0, import_common22.Param)("name")),
7777
+ _ts_metadata8("design:type", Function),
7778
+ _ts_metadata8("design:paramtypes", [
7571
7779
  String
7572
7780
  ]),
7573
- _ts_metadata6("design:returntype", Promise)
7781
+ _ts_metadata8("design:returntype", Promise)
7574
7782
  ], DevResourcesController.prototype, "publish", null);
7575
- _ts_decorate6([
7576
- (0, import_common20.Post)(":name/remove-from-menu"),
7783
+ _ts_decorate8([
7784
+ (0, import_common22.Post)(":name/remove-from-menu"),
7577
7785
  (0, import_swagger12.ApiOperation)({
7578
7786
  summary: "Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)"
7579
7787
  }),
@@ -7581,15 +7789,15 @@ _ts_decorate6([
7581
7789
  status: 200,
7582
7790
  description: "Resource removed from menu"
7583
7791
  }),
7584
- _ts_param2(0, (0, import_common20.Param)("name")),
7585
- _ts_metadata6("design:type", Function),
7586
- _ts_metadata6("design:paramtypes", [
7792
+ _ts_param2(0, (0, import_common22.Param)("name")),
7793
+ _ts_metadata8("design:type", Function),
7794
+ _ts_metadata8("design:paramtypes", [
7587
7795
  String
7588
7796
  ]),
7589
- _ts_metadata6("design:returntype", Promise)
7797
+ _ts_metadata8("design:returntype", Promise)
7590
7798
  ], DevResourcesController.prototype, "removeFromMenu", null);
7591
- _ts_decorate6([
7592
- (0, import_common20.Post)(":name/add-to-menu"),
7799
+ _ts_decorate8([
7800
+ (0, import_common22.Post)(":name/add-to-menu"),
7593
7801
  (0, import_swagger12.ApiOperation)({
7594
7802
  summary: "Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label"
7595
7803
  }),
@@ -7597,17 +7805,17 @@ _ts_decorate6([
7597
7805
  status: 200,
7598
7806
  description: "Resource added to menu"
7599
7807
  }),
7600
- _ts_param2(0, (0, import_common20.Param)("name")),
7601
- _ts_param2(1, (0, import_common20.Body)()),
7602
- _ts_metadata6("design:type", Function),
7603
- _ts_metadata6("design:paramtypes", [
7808
+ _ts_param2(0, (0, import_common22.Param)("name")),
7809
+ _ts_param2(1, (0, import_common22.Body)()),
7810
+ _ts_metadata8("design:type", Function),
7811
+ _ts_metadata8("design:paramtypes", [
7604
7812
  String,
7605
7813
  Object
7606
7814
  ]),
7607
- _ts_metadata6("design:returntype", Promise)
7815
+ _ts_metadata8("design:returntype", Promise)
7608
7816
  ], DevResourcesController.prototype, "addToMenu", null);
7609
- _ts_decorate6([
7610
- (0, import_common20.Patch)(":name/flags"),
7817
+ _ts_decorate8([
7818
+ (0, import_common22.Patch)(":name/flags"),
7611
7819
  (0, import_swagger12.ApiOperation)({
7612
7820
  summary: "Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)"
7613
7821
  }),
@@ -7615,32 +7823,32 @@ _ts_decorate6([
7615
7823
  status: 200,
7616
7824
  description: "Flags updated"
7617
7825
  }),
7618
- _ts_param2(0, (0, import_common20.Param)("name")),
7619
- _ts_param2(1, (0, import_common20.Body)()),
7620
- _ts_metadata6("design:type", Function),
7621
- _ts_metadata6("design:paramtypes", [
7826
+ _ts_param2(0, (0, import_common22.Param)("name")),
7827
+ _ts_param2(1, (0, import_common22.Body)()),
7828
+ _ts_metadata8("design:type", Function),
7829
+ _ts_metadata8("design:paramtypes", [
7622
7830
  String,
7623
7831
  typeof ResourceFlagPatch === "undefined" ? Object : ResourceFlagPatch
7624
7832
  ]),
7625
- _ts_metadata6("design:returntype", Promise)
7833
+ _ts_metadata8("design:returntype", Promise)
7626
7834
  ], DevResourcesController.prototype, "updateFlags", null);
7627
- DevResourcesController = _ts_decorate6([
7628
- (0, import_common20.Controller)("_app/resources"),
7835
+ DevResourcesController = _ts_decorate8([
7836
+ (0, import_common22.Controller)("_app/resources"),
7629
7837
  (0, import_swagger12.ApiTags)("Dev tools"),
7630
- _ts_metadata6("design:type", Function),
7631
- _ts_metadata6("design:paramtypes", [
7838
+ _ts_metadata8("design:type", Function),
7839
+ _ts_metadata8("design:paramtypes", [
7632
7840
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
7633
7841
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
7634
7842
  ])
7635
7843
  ], DevResourcesController);
7636
7844
 
7637
7845
  // src/lib/crud/enum-registry/enum-registry.types.ts
7638
- var import_zod31 = require("zod");
7639
- var EnumEntrySchema = import_zod31.z.object({
7640
- value: import_zod31.z.unknown(),
7641
- label: import_zod31.z.string()
7846
+ var import_zod32 = require("zod");
7847
+ var EnumEntrySchema = import_zod32.z.object({
7848
+ value: import_zod32.z.unknown(),
7849
+ label: import_zod32.z.string()
7642
7850
  });
7643
- var EnumRegistrySchema = import_zod31.z.record(import_zod31.z.string(), import_zod31.z.array(EnumEntrySchema)).default({});
7851
+ var EnumRegistrySchema = import_zod32.z.record(import_zod32.z.string(), import_zod32.z.array(EnumEntrySchema)).default({});
7644
7852
 
7645
7853
  // src/lib/crud/enum-registry/enum-registry.loader.ts
7646
7854
  var import_node_fs8 = require("fs");
@@ -7720,11 +7928,40 @@ var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
7720
7928
  }
7721
7929
  return void 0;
7722
7930
  }, "upsertOp");
7931
+ var buildResourceDefinitions = /* @__PURE__ */ __name((schema, operations, enrichedColumns) => {
7932
+ const picked = pickByColumns(schema, enrichedColumns);
7933
+ const createSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.createable !== false);
7934
+ const updateSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.updateable !== false);
7935
+ const definition = {
7936
+ ...opWithSchema(operations.findAll, picked) && {
7937
+ findAll: opWithSchema(operations.findAll, picked)
7938
+ },
7939
+ ...opWithSchema(operations.findOne, picked) && {
7940
+ findOne: opWithSchema(operations.findOne, picked)
7941
+ },
7942
+ ...opWithSchema(operations.create, createSchema) && {
7943
+ create: opWithSchema(operations.create, createSchema)
7944
+ },
7945
+ ...opWithSchema(operations.update, updateSchema) && {
7946
+ update: opWithSchema(operations.update, updateSchema)
7947
+ },
7948
+ ...upsertOp(operations.upsert, createSchema) && {
7949
+ upsert: upsertOp(operations.upsert, createSchema)
7950
+ },
7951
+ ...operations.patch !== false && {
7952
+ patch: true
7953
+ },
7954
+ ...operations.delete !== false && {
7955
+ delete: true
7956
+ }
7957
+ };
7958
+ return definition;
7959
+ }, "buildResourceDefinitions");
7723
7960
 
7724
7961
  // src/lib/crud/adapter/relation-type.ts
7725
- var import_zod32 = require("zod");
7962
+ var import_zod33 = require("zod");
7726
7963
  var unwrapZodType = /* @__PURE__ */ __name((type) => {
7727
- if (type instanceof import_zod32.ZodOptional || type instanceof import_zod32.ZodNullable) {
7964
+ if (type instanceof import_zod33.ZodOptional || type instanceof import_zod33.ZodNullable) {
7728
7965
  return unwrapZodType(type.unwrap());
7729
7966
  }
7730
7967
  return type;
@@ -7734,7 +7971,7 @@ var deriveRelationType = /* @__PURE__ */ __name((schema, columnId) => {
7734
7971
  const field = schema.shape[columnId];
7735
7972
  if (!field) return void 0;
7736
7973
  const inner = unwrapZodType(field);
7737
- return inner instanceof import_zod32.ZodArray ? "oneToMany" : "manyToOne";
7974
+ return inner instanceof import_zod33.ZodArray ? "oneToMany" : "manyToOne";
7738
7975
  }, "deriveRelationType");
7739
7976
  var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
7740
7977
  const base = col.column ?? col.id;
@@ -7977,9 +8214,6 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
7977
8214
  const subResources = isCustom ? [] : buildSubResources(columns, json.route, json.model ?? "", dirPath, enums, baseUrl);
7978
8215
  const enrichedColumns = resolveColumnFieldVariants(enrichResourceRefColumns(enrichActionColumns(columns, json.route, subResources, baseUrl), dirPath, baseUrl) ?? columns);
7979
8216
  const calculatedColumns = json.calculatedColumns ?? [];
7980
- const picked = pickByColumns(schema, enrichedColumns);
7981
- const createSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.createable !== false);
7982
- const updateSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.updateable !== false);
7983
8217
  let views = isCustom ? buildViewsFromColumnTypes(enrichedColumns) : buildViews(schema, enrichedColumns);
7984
8218
  if (views && calculatedColumns.length) {
7985
8219
  views = {
@@ -7995,29 +8229,7 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
7995
8229
  }
7996
8230
  const lookup = buildLookup(enrichedColumns);
7997
8231
  const enrichedInclude = enrichIncludeWithSort(json.include, enrichedColumns);
7998
- const definition = {
7999
- ...opWithSchema(json.operations.findAll, picked) && {
8000
- findAll: opWithSchema(json.operations.findAll, picked)
8001
- },
8002
- ...opWithSchema(json.operations.findOne, picked) && {
8003
- findOne: opWithSchema(json.operations.findOne, picked)
8004
- },
8005
- ...opWithSchema(json.operations.create, createSchema) && {
8006
- create: opWithSchema(json.operations.create, createSchema)
8007
- },
8008
- ...opWithSchema(json.operations.update, updateSchema) && {
8009
- update: opWithSchema(json.operations.update, updateSchema)
8010
- },
8011
- ...upsertOp(json.operations.upsert, createSchema) && {
8012
- upsert: upsertOp(json.operations.upsert, createSchema)
8013
- },
8014
- ...json.operations.patch !== false && {
8015
- patch: true
8016
- },
8017
- ...json.operations.delete !== false && {
8018
- delete: true
8019
- }
8020
- };
8232
+ const definition = buildResourceDefinitions(schema, json.operations, enrichedColumns);
8021
8233
  return {
8022
8234
  ...json,
8023
8235
  name: json.name,
@@ -8541,9 +8753,9 @@ var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumReg
8541
8753
  }, "buildStatus");
8542
8754
 
8543
8755
  // src/lib/crud/status/status.controller.ts
8544
- var import_common21 = require("@nestjs/common");
8756
+ var import_common23 = require("@nestjs/common");
8545
8757
  var import_swagger13 = require("@nestjs/swagger");
8546
- function _ts_decorate7(decorators, target, key, desc2) {
8758
+ function _ts_decorate9(decorators, target, key, desc2) {
8547
8759
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8548
8760
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8549
8761
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -8556,13 +8768,13 @@ function _ts_decorate7(decorators, target, key, desc2) {
8556
8768
  }
8557
8769
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8558
8770
  }
8559
- __name(_ts_decorate7, "_ts_decorate");
8560
- function _ts_metadata7(metadataKey, metadataValue) {
8771
+ __name(_ts_decorate9, "_ts_decorate");
8772
+ function _ts_metadata9(metadataKey, metadataValue) {
8561
8773
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
8562
8774
  return Reflect.metadata(metadataKey, metadataValue);
8563
8775
  }
8564
8776
  }
8565
- __name(_ts_metadata7, "_ts_metadata");
8777
+ __name(_ts_metadata9, "_ts_metadata");
8566
8778
  var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRegistry) => {
8567
8779
  let StatusController = class StatusController {
8568
8780
  static {
@@ -8579,8 +8791,8 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8579
8791
  return buildStatus(this.dataSourceRegistry, configs, enumRegistry, translationRegistry);
8580
8792
  }
8581
8793
  };
8582
- _ts_decorate7([
8583
- (0, import_common21.Get)("status.json"),
8794
+ _ts_decorate9([
8795
+ (0, import_common23.Get)("status.json"),
8584
8796
  (0, import_swagger13.ApiOperation)({
8585
8797
  summary: "Crouton system status (db, resources, version)"
8586
8798
  }),
@@ -8588,15 +8800,15 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8588
8800
  status: 200,
8589
8801
  description: "System status"
8590
8802
  }),
8591
- _ts_metadata7("design:type", Function),
8592
- _ts_metadata7("design:paramtypes", []),
8593
- _ts_metadata7("design:returntype", Promise)
8803
+ _ts_metadata9("design:type", Function),
8804
+ _ts_metadata9("design:paramtypes", []),
8805
+ _ts_metadata9("design:returntype", Promise)
8594
8806
  ], StatusController.prototype, "getStatus", null);
8595
- StatusController = _ts_decorate7([
8596
- (0, import_common21.Controller)("crouton"),
8807
+ StatusController = _ts_decorate9([
8808
+ (0, import_common23.Controller)("crouton"),
8597
8809
  (0, import_swagger13.ApiTags)("Status"),
8598
- _ts_metadata7("design:type", Function),
8599
- _ts_metadata7("design:paramtypes", [
8810
+ _ts_metadata9("design:type", Function),
8811
+ _ts_metadata9("design:paramtypes", [
8600
8812
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
8601
8813
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
8602
8814
  ])
@@ -8611,7 +8823,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8611
8823
  // src/lib/crouton-api.module.ts
8612
8824
  var import_node_path20 = require("path");
8613
8825
  var import_node_url2 = require("url");
8614
- function _ts_decorate8(decorators, target, key, desc2) {
8826
+ function _ts_decorate10(decorators, target, key, desc2) {
8615
8827
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8616
8828
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8617
8829
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -8624,7 +8836,7 @@ function _ts_decorate8(decorators, target, key, desc2) {
8624
8836
  }
8625
8837
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8626
8838
  }
8627
- __name(_ts_decorate8, "_ts_decorate");
8839
+ __name(_ts_decorate10, "_ts_decorate");
8628
8840
  var CroutonApiModule = class _CroutonApiModule {
8629
8841
  static {
8630
8842
  __name(this, "CroutonApiModule");
@@ -8636,8 +8848,11 @@ var CroutonApiModule = class _CroutonApiModule {
8636
8848
  };
8637
8849
  }
8638
8850
  }
8639
- static forResources(configs, dataSources, loader, { baseUrl }, config) {
8851
+ static forResources(configs, dataSources, loader, appConfig, config) {
8852
+ const { baseUrl, security } = appConfig;
8640
8853
  const dataSourceRegistry = new DataSourceRegistry(dataSources);
8854
+ const guardRegistry = new SecurityGuardRegistry(security?.guards ?? {});
8855
+ const moduleDefaultSecurity = security?.default;
8641
8856
  const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path20.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
8642
8857
  const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);
8643
8858
  const validConfigs = [];
@@ -8690,12 +8905,12 @@ var CroutonApiModule = class _CroutonApiModule {
8690
8905
  const configRegistry = new ResourceConfigRegistry(loader, validConfigs);
8691
8906
  let translationRegistry;
8692
8907
  if (config.i18n) {
8693
- const translationsDir = (0, import_node_path20.join)(process.cwd(), config.i18n.translationsDir);
8908
+ const translationsDir = (0, import_node_path20.join)(config.configDir, config.i18n.translationsDir);
8694
8909
  translationRegistry = new TranslationRegistry2(translationsDir, config.i18n);
8695
8910
  configRegistry.setTranslationRegistry(translationRegistry);
8696
8911
  }
8697
8912
  const controllers = [
8698
- ...validConfigs.map((c) => createCrudController(c, baseUrl)),
8913
+ ...validConfigs.map((c) => createCrudController(c, baseUrl, moduleDefaultSecurity, !!security)),
8699
8914
  createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true, translationRegistry, config.i18n),
8700
8915
  // Only registered (and thus only visible in Swagger/routing) when the
8701
8916
  // visual resource builder is enabled — see dev-resources.controller.ts.
@@ -8709,7 +8924,7 @@ var CroutonApiModule = class _CroutonApiModule {
8709
8924
  controllers,
8710
8925
  providers: [
8711
8926
  {
8712
- provide: import_core.APP_FILTER,
8927
+ provide: import_core2.APP_FILTER,
8713
8928
  useClass: CroutonValidationExceptionFilter
8714
8929
  },
8715
8930
  {
@@ -8720,35 +8935,43 @@ var CroutonApiModule = class _CroutonApiModule {
8720
8935
  provide: ResourceConfigRegistry,
8721
8936
  useValue: configRegistry
8722
8937
  },
8938
+ // Security providers only registered when security is configured;
8939
+ // without guards the dispatching guard is never applied (see factory).
8940
+ ...security ? [
8941
+ {
8942
+ provide: SecurityGuardRegistry,
8943
+ useValue: guardRegistry
8944
+ },
8945
+ CroutonSecurityGuard,
8946
+ ...guardRegistry.classes()
8947
+ ] : [],
8723
8948
  ...translationRegistry ? [
8724
8949
  {
8725
8950
  provide: TranslationRegistry2,
8726
8951
  useValue: translationRegistry
8727
8952
  },
8728
8953
  {
8729
- provide: import_core.APP_INTERCEPTOR,
8954
+ provide: import_core2.APP_INTERCEPTOR,
8730
8955
  useFactory: /* @__PURE__ */ __name(() => new LanguageInterceptor(translationRegistry), "useFactory")
8731
8956
  }
8732
8957
  ] : []
8733
8958
  ]
8734
8959
  };
8735
8960
  }
8736
- static async forResourceDir(dirPath, dataSourcesPath, { baseUrl }) {
8961
+ static async forResourceDir(dirPath, dataSourcesPath, appConfig) {
8737
8962
  const config = await loadConfig();
8738
- const loader = new FileSystemResourceConfigLoader(dirPath, baseUrl, config.enumsFile);
8739
- const configs = await loadResourceConfigsFromDir(dirPath, baseUrl, config.enumsFile);
8963
+ const loader = new FileSystemResourceConfigLoader(dirPath, appConfig.baseUrl, config.enumsFile);
8964
+ const configs = await loadResourceConfigsFromDir(dirPath, appConfig.baseUrl, config.enumsFile);
8740
8965
  const dataSources = await loadDataSourcesFromDir(dataSourcesPath);
8741
- return _CroutonApiModule.forResources(configs, dataSources, loader, {
8742
- baseUrl
8743
- }, config);
8966
+ return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
8744
8967
  }
8745
8968
  static async forLoader(loader, configs, dataSources, appConfig) {
8746
8969
  const config = await loadConfig();
8747
8970
  return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
8748
8971
  }
8749
8972
  };
8750
- CroutonApiModule = _ts_decorate8([
8751
- (0, import_common22.Module)({
8973
+ CroutonApiModule = _ts_decorate10([
8974
+ (0, import_common24.Module)({
8752
8975
  controllers: [],
8753
8976
  providers: [],
8754
8977
  exports: []
@@ -8756,13 +8979,16 @@ CroutonApiModule = _ts_decorate8([
8756
8979
  ], CroutonApiModule);
8757
8980
  // Annotate the CommonJS export names for ESM import in node:
8758
8981
  0 && (module.exports = {
8982
+ CROUTON_SECURITY,
8759
8983
  CroutonApiModule,
8984
+ CroutonSecurityGuard,
8760
8985
  DataSourceRegistry,
8761
8986
  FileSystemResourceConfigLoader,
8762
8987
  ReadOpSchema,
8763
8988
  ResourceConfigLoader,
8764
8989
  ResourceConfigRegistry,
8765
8990
  ResourceHooksSchema,
8991
+ SecurityGuardRegistry,
8766
8992
  WriteOpSchema,
8767
8993
  buildFilterWhere,
8768
8994
  buildViews,
@@ -8780,6 +9006,8 @@ CroutonApiModule = _ts_decorate8([
8780
9006
  prepareWrite,
8781
9007
  resolveDefinition,
8782
9008
  schemaFor,
9009
+ securityFor,
9010
+ securityForSub,
8783
9011
  upsertOnFor
8784
9012
  });
8785
9013
  //# sourceMappingURL=index.cjs.map