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

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: () => SecurityGuardRegistry2,
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,108 @@ 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([
632
+ import_zod8.z.object({
633
+ public: import_zod8.z.literal(true)
634
+ }),
625
635
  import_zod8.z.object({
626
- upsertOn: import_zod8.z.union([
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
  });
641
669
 
642
670
  // ../crouton-core/src/lib/resource/ResourceJson.schema.ts
643
- var import_zod18 = require("zod");
671
+ var import_zod19 = require("zod");
644
672
 
645
673
  // ../crouton-core/src/lib/resource/CalculatedColumn.schema.ts
646
- var import_zod10 = require("zod");
674
+ var import_zod11 = require("zod");
647
675
 
648
676
  // ../crouton-core/src/lib/resource/FieldInput.schema.ts
649
- var import_zod9 = require("zod");
650
- var RelationType = import_zod9.z.enum([
677
+ var import_zod10 = require("zod");
678
+ var RelationType = import_zod10.z.enum([
651
679
  "oneToOne",
652
680
  "manyToOne",
653
681
  "oneToMany",
654
682
  "manyToMany"
655
683
  ]);
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()
684
+ var DetailControlSchema = import_zod10.z.object({
685
+ property: import_zod10.z.string(),
686
+ type: import_zod10.z.string().optional(),
687
+ options: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.unknown()).optional(),
688
+ hideLabel: import_zod10.z.boolean().optional(),
689
+ width: import_zod10.z.string().optional()
662
690
  });
663
- var DetailConfigSchema = import_zod9.z.object({
664
- layout: import_zod9.z.enum([
691
+ var DetailConfigSchema = import_zod10.z.object({
692
+ layout: import_zod10.z.enum([
665
693
  "collapse",
666
694
  "row"
667
695
  ]),
668
- titleKey: import_zod9.z.string().optional(),
669
- controls: import_zod9.z.array(DetailControlSchema)
696
+ titleKey: import_zod10.z.string().optional(),
697
+ controls: import_zod10.z.array(DetailControlSchema)
670
698
  });
671
- var RelationFieldInputOptionsSchema = import_zod9.z.object({
672
- colspan: import_zod9.z.number().optional().default(12),
699
+ var RelationFieldInputOptionsSchema = import_zod10.z.object({
700
+ colspan: import_zod10.z.number().optional().default(12),
673
701
  /** Field to sort related records by, e.g. `"title"` or `"author.name"`. */
674
- sort: import_zod9.z.string().optional(),
702
+ sort: import_zod10.z.string().optional(),
675
703
  /** Sort direction. Defaults to `"asc"` when omitted. */
676
- sortDir: import_zod9.z.enum([
704
+ sortDir: import_zod10.z.enum([
677
705
  "asc",
678
706
  "desc"
679
707
  ]).optional(),
680
708
  /** CSS flex direction for the relation control button layout. */
681
- direction: import_zod9.z.string().optional(),
709
+ direction: import_zod10.z.string().optional(),
682
710
  /** Key used as the display label in the relation control. */
683
- displayKey: import_zod9.z.string().optional(),
711
+ displayKey: import_zod10.z.string().optional(),
684
712
  /** 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(),
713
+ resource: import_zod10.z.string().optional()
714
+ }).catchall(import_zod10.z.unknown());
715
+ var FieldInputSchema = import_zod10.z.object({
716
+ type: import_zod10.z.string().optional(),
717
+ customRender: import_zod10.z.string().optional(),
690
718
  /**
691
719
  * Render format hint for the frontend (e.g. `"relation"` for sub-resource
692
720
  * relations). When `format` is `"relation"`, `resource` must also be set.
693
721
  */
694
- format: import_zod9.z.string().optional(),
722
+ format: import_zod10.z.string().optional(),
695
723
  /**
696
724
  * Relative path to the child resource definition, e.g. `"./author.resource"`.
697
725
  * Only used when `format` is `"relation"`. Resolved at load time to inject
698
726
  * sub-resource URIs into `options`.
699
727
  */
700
- resource: import_zod9.z.string().optional(),
728
+ resource: import_zod10.z.string().optional(),
701
729
  /**
702
730
  * Cardinality of the relation. Used by the frontend to determine the correct
703
731
  * renderer and behaviour (e.g. single-select vs multi-select).
@@ -706,11 +734,11 @@ var FieldInputSchema = import_zod9.z.object({
706
734
  */
707
735
  relationType: RelationType.optional(),
708
736
  /** 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(),
737
+ foreignKey: import_zod10.z.string().optional(),
710
738
  /** Override the Prisma relation field name when it differs from the column id. */
711
- relation: import_zod9.z.string().optional(),
739
+ relation: import_zod10.z.string().optional(),
712
740
  /** Override the display order in form views. Lower values come first. */
713
- position: import_zod9.z.number().optional(),
741
+ position: import_zod10.z.number().optional(),
714
742
  /**
715
743
  * Value to pre-fill this field with on the create form. Injected into the
716
744
  * generated form view's JSON Schema as `properties[id].default`, which
@@ -718,10 +746,10 @@ var FieldInputSchema = import_zod9.z.object({
718
746
  * opening a blank record. Not applicable to `format: "relation"` fields —
719
747
  * relation columns are excluded from the picked data schema entirely.
720
748
  */
721
- defaultValue: import_zod9.z.unknown().optional(),
722
- options: import_zod9.z.union([
749
+ defaultValue: import_zod10.z.unknown().optional(),
750
+ options: import_zod10.z.union([
723
751
  RelationFieldInputOptionsSchema,
724
- import_zod9.z.unknown()
752
+ import_zod10.z.unknown()
725
753
  ]).optional(),
726
754
  /** Nested array detail layout (renders via `detailFixed`). */
727
755
  detail: DetailConfigSchema.optional()
@@ -762,16 +790,16 @@ var normalizeLabel = /* @__PURE__ */ __name((obj) => {
762
790
  }, "normalizeLabel");
763
791
 
764
792
  // ../crouton-core/src/lib/resource/CalculatedColumn.schema.ts
765
- var CalculatedColumnSchema = import_zod10.z.object({
793
+ var CalculatedColumnSchema = import_zod11.z.object({
766
794
  /** Column identifier used in the response payload and UI schema. */
767
- id: import_zod10.z.string(),
795
+ id: import_zod11.z.string(),
768
796
  /** SQL alias — must match `id`. */
769
- alias: import_zod10.z.string(),
797
+ alias: import_zod11.z.string(),
770
798
  /** Human-readable label shown in the table header. */
771
- label: import_zod10.z.string().optional(),
772
- sqlExpression: import_zod10.z.string(),
799
+ label: import_zod11.z.string().optional(),
800
+ sqlExpression: import_zod11.z.string(),
773
801
  /** JSON schema / cast type for the computed value. Defaults to `"number"`. `"string"` skips CAST. */
774
- type: import_zod10.z.enum([
802
+ type: import_zod11.z.enum([
775
803
  "number",
776
804
  "boolean",
777
805
  "string"
@@ -782,9 +810,9 @@ var CalculatedColumnSchema = import_zod10.z.object({
782
810
  * `position: N` places this column before the element currently at index N.
783
811
  * Can also be set via `fieldInput.position` (takes precedence).
784
812
  */
785
- position: import_zod10.z.number().optional(),
786
- hiddenInTable: import_zod10.z.boolean().optional(),
787
- hiddenInView: import_zod10.z.boolean().optional(),
813
+ position: import_zod11.z.number().optional(),
814
+ hiddenInTable: import_zod11.z.boolean().optional(),
815
+ hiddenInView: import_zod11.z.boolean().optional(),
788
816
  /**
789
817
  * Field input options for rendering in form / view schemas.
790
818
  * Supports `colspan`, `format`, and any other options passed to the Control renderer.
@@ -794,11 +822,11 @@ var CalculatedColumnSchema = import_zod10.z.object({
794
822
  }).transform(normalizeLabel);
795
823
 
796
824
  // ../crouton-core/src/lib/resource/Column.ts
797
- var import_zod12 = require("zod");
825
+ var import_zod13 = require("zod");
798
826
 
799
827
  // ../crouton-core/src/lib/resource/ColumnType.schema.ts
800
- var import_zod11 = require("zod");
801
- var ColumnTypeShorthandSchema = import_zod11.z.enum([
828
+ var import_zod12 = require("zod");
829
+ var ColumnTypeShorthandSchema = import_zod12.z.enum([
802
830
  "string",
803
831
  "number",
804
832
  "integer",
@@ -808,32 +836,32 @@ var ColumnTypeShorthandSchema = import_zod11.z.enum([
808
836
  "object",
809
837
  "array"
810
838
  ]);
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())
839
+ var JsonSchemaFragmentSchema = import_zod12.z.lazy(() => import_zod12.z.object({
840
+ type: import_zod12.z.union([
841
+ import_zod12.z.string(),
842
+ import_zod12.z.array(import_zod12.z.string())
815
843
  ]).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(),
844
+ format: import_zod12.z.string().optional(),
845
+ enum: import_zod12.z.array(import_zod12.z.unknown()).optional(),
846
+ const: import_zod12.z.unknown().optional(),
847
+ nullable: import_zod12.z.boolean().optional(),
848
+ properties: import_zod12.z.record(import_zod12.z.string(), JsonSchemaFragmentSchema).optional(),
849
+ required: import_zod12.z.array(import_zod12.z.string()).optional(),
822
850
  items: JsonSchemaFragmentSchema.optional(),
823
- additionalProperties: import_zod11.z.union([
824
- import_zod11.z.boolean(),
851
+ additionalProperties: import_zod12.z.union([
852
+ import_zod12.z.boolean(),
825
853
  JsonSchemaFragmentSchema
826
854
  ]).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([
855
+ title: import_zod12.z.string().optional(),
856
+ description: import_zod12.z.string().optional(),
857
+ default: import_zod12.z.unknown().optional(),
858
+ minimum: import_zod12.z.number().optional(),
859
+ maximum: import_zod12.z.number().optional(),
860
+ minLength: import_zod12.z.number().optional(),
861
+ maxLength: import_zod12.z.number().optional(),
862
+ pattern: import_zod12.z.string().optional()
863
+ }).catchall(import_zod12.z.unknown()));
864
+ var ColumnTypeSchema = import_zod12.z.union([
837
865
  ColumnTypeShorthandSchema,
838
866
  JsonSchemaFragmentSchema
839
867
  ]);
@@ -915,40 +943,40 @@ var isObjectColumnType = /* @__PURE__ */ __name((type) => columnTypeName(type) =
915
943
  var isArrayColumnType = /* @__PURE__ */ __name((type) => columnTypeName(type) === "array", "isArrayColumnType");
916
944
 
917
945
  // ../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()
946
+ var WhenConditionSchema = import_zod13.z.object({
947
+ field: import_zod13.z.string(),
948
+ eq: import_zod13.z.unknown().optional(),
949
+ neq: import_zod13.z.unknown().optional(),
950
+ exists: import_zod13.z.boolean().optional(),
951
+ notExists: import_zod13.z.boolean().optional()
924
952
  });
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),
953
+ var JsonColumnSchema = import_zod13.z.object({
954
+ id: import_zod13.z.string(),
955
+ column: import_zod13.z.string().optional(),
956
+ label: import_zod13.z.string().optional(),
957
+ hiddenInTable: import_zod13.z.boolean().default(false),
958
+ hiddenInForm: import_zod13.z.boolean().default(false),
959
+ hiddenInView: import_zod13.z.boolean().default(false),
960
+ sortable: import_zod13.z.boolean().default(false),
961
+ defaultSort: import_zod13.z.boolean().default(false),
962
+ searchable: import_zod13.z.boolean().default(false),
963
+ filterable: import_zod13.z.boolean().default(false),
964
+ createable: import_zod13.z.boolean().default(true),
965
+ updateable: import_zod13.z.boolean().default(true),
966
+ hideLabel: import_zod13.z.boolean().default(false),
939
967
  showWhen: WhenConditionSchema.optional(),
940
968
  hideWhen: WhenConditionSchema.optional(),
941
969
  disabledWhen: WhenConditionSchema.optional(),
942
- displayKey: import_zod12.z.string().optional(),
943
- sortId: import_zod12.z.string().optional(),
970
+ displayKey: import_zod13.z.string().optional(),
971
+ sortId: import_zod13.z.string().optional(),
944
972
  /**
945
973
  * Name of a shared enum in the project enum registry (`crouton.enums.json`).
946
974
  * At load time the loader injects that enum's `{ value, label }[]` into
947
975
  * `fieldInput.options.values`, so columns don't duplicate the option list.
948
976
  */
949
- enum: import_zod12.z.string().optional(),
950
- idField: import_zod12.z.boolean().default(false),
951
- showInLookup: import_zod12.z.boolean().default(false),
977
+ enum: import_zod13.z.string().optional(),
978
+ idField: import_zod13.z.boolean().default(false),
979
+ showInLookup: import_zod13.z.boolean().default(false),
952
980
  /**
953
981
  * Data type of the column, as a shorthand name (`"string"`, `"integer"`, …)
954
982
  * or a full JSON Schema fragment:
@@ -979,12 +1007,12 @@ var JsonColumnSchema = import_zod12.z.object({
979
1007
  * Ignored on the id column and on columns that are neither createable nor
980
1008
  * updateable, since the form cannot supply a value for those.
981
1009
  */
982
- required: import_zod12.z.boolean().optional(),
1010
+ required: import_zod13.z.boolean().optional(),
983
1011
  /**
984
1012
  * @deprecated Use `type` instead. Retained because it is still consumed by
985
1013
  * the boolean predicate and the schema-less sub-resource view builder.
986
1014
  */
987
- columnType: import_zod12.z.string().default("string"),
1015
+ columnType: import_zod13.z.string().default("string"),
988
1016
  fieldInput: FieldInputSchema.optional(),
989
1017
  /**
990
1018
  * Optional per-context override for the read-only VIEW ui. Same shape as
@@ -1008,27 +1036,27 @@ var JsonColumnSchema = import_zod12.z.object({
1008
1036
  * Visibility (`hiddenInTable/Form/View`) on this column is inherited by all sub-columns as a
1009
1037
  * default; the referenced resource's own column visibility further restricts it.
1010
1038
  */
1011
- extend: import_zod12.z.string().optional(),
1039
+ extend: import_zod13.z.string().optional(),
1012
1040
  /**
1013
1041
  * Per-sub-column overrides when using `extend`.
1014
1042
  * Key: the virtual column id (`"{extendId}_{refColId}"`) or just the referenced column id.
1015
1043
  * Value: any `JsonColumn` fields to merge over the generated virtual column.
1016
1044
  */
1017
- columns: import_zod12.z.record(import_zod12.z.string(), import_zod12.z.record(import_zod12.z.string(), import_zod12.z.unknown())).optional()
1045
+ columns: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown())).optional()
1018
1046
  });
1019
1047
 
1020
1048
  // ../crouton-core/src/lib/resource/ParentRef.schema.ts
1021
- var import_zod13 = require("zod");
1022
- var ParentRefSchema = import_zod13.z.object({
1049
+ var import_zod14 = require("zod");
1050
+ var ParentRefSchema = import_zod14.z.object({
1023
1051
  /** Route segment of the parent, e.g. `"group"`. */
1024
- route: import_zod13.z.string(),
1052
+ route: import_zod14.z.string(),
1025
1053
  /**
1026
1054
  * Name of the path parameter carrying the parent id, e.g. `"groupId"`.
1027
1055
  * Avoid `"id"` — that is the child's own id in `/:id` routes.
1028
1056
  */
1029
- param: import_zod13.z.string().default("parentId"),
1057
+ param: import_zod14.z.string().default("parentId"),
1030
1058
  /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */
1031
- idType: import_zod13.z.enum([
1059
+ idType: import_zod14.z.enum([
1032
1060
  "string",
1033
1061
  "number"
1034
1062
  ]).optional()
@@ -1036,37 +1064,37 @@ var ParentRefSchema = import_zod13.z.object({
1036
1064
  var resourceControllerPath = /* @__PURE__ */ __name((route, parent) => parent ? `${parent.route}/:${parent.param}/${route}` : route, "resourceControllerPath");
1037
1065
 
1038
1066
  // ../crouton-core/src/lib/resource/ResourceKind.ts
1039
- var import_zod14 = require("zod");
1040
- var ResourceKindSchema = import_zod14.z.enum([
1067
+ var import_zod15 = require("zod");
1068
+ var ResourceKindSchema = import_zod15.z.enum([
1041
1069
  "prisma",
1042
1070
  "custom"
1043
1071
  ]).default("prisma");
1044
1072
 
1045
1073
  // ../crouton-core/src/lib/resource/Sidebar.schema.ts
1046
- var import_zod15 = __toESM(require("zod"), 1);
1047
- var SidebarGroupSchema = import_zod15.default.object({
1074
+ var import_zod16 = __toESM(require("zod"), 1);
1075
+ var SidebarGroupSchema = import_zod16.default.object({
1048
1076
  /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
1049
- label: import_zod15.default.string().optional(),
1077
+ label: import_zod16.default.string().optional(),
1050
1078
  /** Controls the order of this group among top-level sidebar items. */
1051
- position: import_zod15.default.number().optional()
1079
+ position: import_zod16.default.number().optional()
1052
1080
  });
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(),
1081
+ var SidebarSchema = import_zod16.default.object({
1082
+ hide: import_zod16.default.boolean().default(false),
1083
+ position: import_zod16.default.number().optional(),
1084
+ label: import_zod16.default.string().optional(),
1057
1085
  /**
1058
1086
  * Slug of the group this resource belongs to.
1059
1087
  * Must match a key in `sidebarGroups` in `crouton.json`.
1060
1088
  * Resources with the same `group` are nested under a shared collapsible section.
1061
1089
  */
1062
- group: import_zod15.default.string().optional()
1090
+ group: import_zod16.default.string().optional()
1063
1091
  });
1064
1092
 
1065
1093
  // ../crouton-core/src/lib/resource/TableAction.schema.ts
1066
- var import_zod16 = require("zod");
1067
- var ActionConditionSchema = import_zod16.z.object({
1094
+ var import_zod17 = require("zod");
1095
+ var ActionConditionSchema = import_zod17.z.object({
1068
1096
  /** Row field to evaluate. */
1069
- field: import_zod16.z.string(),
1097
+ field: import_zod17.z.string(),
1070
1098
  /**
1071
1099
  * Comparison operator. Defaults to `"eq"`.
1072
1100
  * - `eq` / `neq` — strict equality
@@ -1074,7 +1102,7 @@ var ActionConditionSchema = import_zod16.z.object({
1074
1102
  * - `exists` — field is not null / undefined / empty string
1075
1103
  * - `notExists` — field is null / undefined / empty string
1076
1104
  */
1077
- op: import_zod16.z.enum([
1105
+ op: import_zod17.z.enum([
1078
1106
  "eq",
1079
1107
  "neq",
1080
1108
  "gt",
@@ -1085,38 +1113,38 @@ var ActionConditionSchema = import_zod16.z.object({
1085
1113
  "notExists"
1086
1114
  ]).default("eq"),
1087
1115
  /** Comparison value. Not required for `exists` / `notExists`. */
1088
- value: import_zod16.z.unknown().optional()
1116
+ value: import_zod17.z.unknown().optional()
1089
1117
  });
1090
- var ActionSchema = import_zod16.z.object({
1091
- type: import_zod16.z.string(),
1118
+ var ActionSchema = import_zod17.z.object({
1119
+ type: import_zod17.z.string(),
1092
1120
  /** Unique identifier for the action. */
1093
- id: import_zod16.z.string(),
1121
+ id: import_zod17.z.string(),
1094
1122
  /** Human-readable button label. */
1095
- label: import_zod16.z.string(),
1123
+ label: import_zod17.z.string(),
1096
1124
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
1097
- icon: import_zod16.z.string().optional(),
1125
+ icon: import_zod17.z.string().optional(),
1098
1126
  /** Tooltip text. Falls back to `label` when omitted. */
1099
- tooltip: import_zod16.z.string().optional(),
1127
+ tooltip: import_zod17.z.string().optional(),
1100
1128
  condition: ActionConditionSchema.optional()
1101
1129
  });
1102
1130
  var JsonProcedureActionSchema = ActionSchema.extend({
1103
- type: import_zod16.z.literal("procedure").default("procedure"),
1131
+ type: import_zod17.z.literal("procedure").default("procedure"),
1104
1132
  /**
1105
1133
  * Filename (without extension) inside the resource's `actions/` directory
1106
1134
  * that exports the table-action procedure, e.g. `"syncZotero"`.
1107
1135
  */
1108
- procedure: import_zod16.z.string(),
1136
+ procedure: import_zod17.z.string(),
1109
1137
  /** HTTP method for the frontend. Defaults to `"post"`. */
1110
- method: import_zod16.z.string().optional().default("post"),
1138
+ method: import_zod17.z.string().optional().default("post"),
1111
1139
  /** Static query / body params passed to the endpoint. */
1112
- data: import_zod16.z.record(import_zod16.z.string(), import_zod16.z.unknown()).optional()
1140
+ data: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()
1113
1141
  });
1114
1142
  var JsonLinkActionSchema = ActionSchema.extend({
1115
1143
  /** Optional condition evaluated per row. Button is hidden when the condition is false. */
1116
- type: import_zod16.z.literal("link").default("link"),
1144
+ type: import_zod17.z.literal("link").default("link"),
1117
1145
  /** URL to open. May contain `{env.VAR}` placeholders. */
1118
- href: import_zod16.z.string(),
1119
- blank: import_zod16.z.boolean().optional().default(true)
1146
+ href: import_zod17.z.string(),
1147
+ blank: import_zod17.z.boolean().optional().default(true)
1120
1148
  });
1121
1149
  var transformAction = /* @__PURE__ */ __name((action) => {
1122
1150
  const label = action.label;
@@ -1125,20 +1153,20 @@ var transformAction = /* @__PURE__ */ __name((action) => {
1125
1153
  ...action
1126
1154
  };
1127
1155
  }, "transformAction");
1128
- var JsonActionSchema = import_zod16.z.union([
1156
+ var JsonActionSchema = import_zod17.z.union([
1129
1157
  JsonProcedureActionSchema,
1130
1158
  JsonLinkActionSchema
1131
1159
  ]).transform(transformAction);
1132
1160
 
1133
1161
  // ../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(),
1162
+ var import_zod18 = require("zod");
1163
+ var JsonIncludeEntrySchema = import_zod18.z.lazy(() => import_zod18.z.union([
1164
+ import_zod18.z.string(),
1165
+ import_zod18.z.object({
1166
+ relation: import_zod18.z.string(),
1167
+ include: import_zod18.z.array(JsonIncludeEntrySchema).optional(),
1140
1168
  /** Prisma-format orderBy clause applied to the included records. */
1141
- orderBy: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()
1169
+ orderBy: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
1142
1170
  })
1143
1171
  ]));
1144
1172
 
@@ -1147,16 +1175,16 @@ var BASELINE_RESOURCE_VERSION = 1;
1147
1175
  var CURRENT_RESOURCE_VERSION = 1;
1148
1176
 
1149
1177
  // ../crouton-core/src/lib/resource/ResourceJson.schema.ts
1150
- var JsonColumnsMapSchema = import_zod18.z.record(import_zod18.z.string(), JsonColumnSchema.omit({
1178
+ var JsonColumnsMapSchema = import_zod19.z.record(import_zod19.z.string(), JsonColumnSchema.omit({
1151
1179
  id: true
1152
- }).catchall(import_zod18.z.unknown()));
1180
+ }).catchall(import_zod19.z.unknown()));
1153
1181
  var ColumnsSchema = JsonColumnsMapSchema;
1154
- var JsonDisplaySchema = import_zod18.z.object({
1155
- mode: import_zod18.z.enum([
1182
+ var JsonDisplaySchema = import_zod19.z.object({
1183
+ mode: import_zod19.z.enum([
1156
1184
  "page",
1157
1185
  "modal"
1158
1186
  ]).default("modal"),
1159
- customComponent: import_zod18.z.string().nullable().optional().default(null)
1187
+ customComponent: import_zod19.z.string().nullable().optional().default(null)
1160
1188
  });
1161
1189
  var normalizeColumns = /* @__PURE__ */ __name((columns) => {
1162
1190
  if (!columns) return void 0;
@@ -1169,46 +1197,46 @@ var normalizeColumns = /* @__PURE__ */ __name((columns) => {
1169
1197
  label: col.label ?? labelFromId(col.id)
1170
1198
  }));
1171
1199
  }, "normalizeColumns");
1172
- var ResourceJsonShape = import_zod18.z.object({
1200
+ var ResourceJsonShape = import_zod19.z.object({
1173
1201
  /**
1174
1202
  * URL of the generated JSON Schema, for editor autocomplete/validation. Declared so the
1175
1203
  * key is *allowed* (not stripped, and not flagged by the very schema it points at).
1176
1204
  * Ignored at runtime.
1177
1205
  */
1178
- $schema: import_zod18.z.string().optional(),
1206
+ $schema: import_zod19.z.string().optional(),
1179
1207
  /**
1180
1208
  * resource.json shape version. Missing ⇒ baseline (see `./version`). Auto-migrated
1181
1209
  * toward `CURRENT_RESOURCE_VERSION` on load in the dev environment.
1182
1210
  */
1183
- schemaVersion: import_zod18.z.number().int().positive().optional(),
1211
+ schemaVersion: import_zod19.z.number().int().positive().optional(),
1184
1212
  /** 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),
1213
+ draft: import_zod19.z.boolean().optional().default(false),
1186
1214
  /**
1187
1215
  * Where the data comes from. `prisma` (the default) is backed by a Prisma
1188
1216
  * model plus a `schema.ts`; `custom` is configuration only and the developer
1189
1217
  * supplies a `repository.ts`. See `./ResourceKind`.
1190
1218
  */
1191
1219
  kind: ResourceKindSchema,
1192
- name: import_zod18.z.string(),
1193
- route: import_zod18.z.string(),
1220
+ name: import_zod19.z.string(),
1221
+ route: import_zod19.z.string(),
1194
1222
  /**
1195
1223
  * Prisma model name. Required when `kind` is `prisma` (enforced by the
1196
1224
  * refinement on `ResourceJsonSchema`), and must be absent when `kind` is
1197
1225
  * `custom` — there is no Prisma delegate to address.
1198
1226
  */
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(),
1227
+ model: import_zod19.z.string().optional(),
1228
+ tag: import_zod19.z.string(),
1229
+ title: import_zod19.z.string().optional(),
1230
+ table: import_zod19.z.string().optional(),
1203
1231
  /**
1204
1232
  * Type of the resource's primary key, used to coerce `:id` route params.
1205
1233
  * Written by codegen from the Prisma model; defaults to `'string'`.
1206
1234
  */
1207
- idType: import_zod18.z.enum([
1235
+ idType: import_zod19.z.enum([
1208
1236
  "string",
1209
1237
  "number"
1210
1238
  ]).optional(),
1211
- database: import_zod18.z.string().optional(),
1239
+ database: import_zod19.z.string().optional(),
1212
1240
  /**
1213
1241
  * Mount this resource under a parent route instead of at the top level —
1214
1242
  * see `./ParentRef.schema`. Only valid on a `kind: "custom"` resource.
@@ -1216,14 +1244,16 @@ var ResourceJsonShape = import_zod18.z.object({
1216
1244
  parent: ParentRefSchema.optional(),
1217
1245
  sidebar: SidebarSchema.default(SidebarSchema.parse({})),
1218
1246
  display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})),
1247
+ /** Global security block — applies to every operation unless overridden per-operation. */
1248
+ security: SecuritySchema.optional(),
1219
1249
  operations: JsonOperationsSchema,
1220
1250
  columns: ColumnsSchema.default(ColumnsSchema.parse({})),
1221
- calculatedColumns: import_zod18.z.array(CalculatedColumnSchema).default([]),
1222
- actions: import_zod18.z.array(JsonActionSchema).default([]),
1251
+ calculatedColumns: import_zod19.z.array(CalculatedColumnSchema).default([]),
1252
+ actions: import_zod19.z.array(JsonActionSchema).default([]),
1223
1253
  /** Global table-level actions (no record id). Shown as toolbar buttons. */
1224
- tableActions: import_zod18.z.array(JsonActionSchema).default([]),
1254
+ tableActions: import_zod19.z.array(JsonActionSchema).default([]),
1225
1255
  /** Modal width when opening a form for this resource. */
1226
- modalSize: import_zod18.z.enum([
1256
+ modalSize: import_zod19.z.enum([
1227
1257
  "xs",
1228
1258
  "sm",
1229
1259
  "lg",
@@ -1236,7 +1266,7 @@ var ResourceJsonShape = import_zod18.z.object({
1236
1266
  * `{ "relation": "text_author", "include": ["author"] }` →
1237
1267
  * `include: { text_author: { include: { author: true } } }`
1238
1268
  */
1239
- include: import_zod18.z.array(JsonIncludeEntrySchema).default([])
1269
+ include: import_zod19.z.array(JsonIncludeEntrySchema).default([])
1240
1270
  });
1241
1271
  var refineByKind = /* @__PURE__ */ __name((obj, ctx) => {
1242
1272
  if (obj.kind === "custom") {
@@ -1381,58 +1411,58 @@ var resolveViewField = /* @__PURE__ */ __name((c) => mergeFieldVariant(c.fieldIn
1381
1411
  var resolveTableField = /* @__PURE__ */ __name((c) => mergeFieldVariant(resolveViewField(c), c.fieldTable), "resolveTableField");
1382
1412
 
1383
1413
  // ../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),
1414
+ var import_zod20 = require("zod");
1415
+ var RulesetSchema = import_zod20.z.object({
1416
+ hideIdInTable: import_zod20.z.boolean().default(true),
1417
+ hideIdInForm: import_zod20.z.boolean().default(true),
1418
+ hideIdInView: import_zod20.z.boolean().default(true),
1419
+ hideTimestamps: import_zod20.z.boolean().default(true),
1420
+ hideForeignKeys: import_zod20.z.boolean().default(true),
1421
+ includeRelations: import_zod20.z.boolean().default(true),
1422
+ hideRelationsInTable: import_zod20.z.boolean().default(true),
1423
+ showRelationsInForm: import_zod20.z.boolean().default(true),
1424
+ enumValueLabel: import_zod20.z.boolean().default(true),
1425
+ sharedEnums: import_zod20.z.boolean().default(true),
1396
1426
  defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
1397
1427
  });
1398
- var I18nConfigSchema = import_zod19.z.object({
1428
+ var I18nConfigSchema = import_zod20.z.object({
1399
1429
  /** Default / fallback language. */
1400
- defaultLanguage: import_zod19.z.string().default("en"),
1430
+ defaultLanguage: import_zod20.z.string().default("en"),
1401
1431
  /** All supported language codes. */
1402
- languages: import_zod19.z.array(import_zod19.z.string()).min(1),
1432
+ languages: import_zod20.z.array(import_zod20.z.string()).min(1),
1403
1433
  /** Directory containing `<lang>.json` bundles, relative to project root. */
1404
- translationsDir: import_zod19.z.string().default("translations")
1434
+ translationsDir: import_zod20.z.string().default("translations")
1405
1435
  });
1406
- var CroutonConfigSchema = import_zod19.z.object({
1436
+ var CroutonConfigSchema = import_zod20.z.object({
1407
1437
  /**
1408
1438
  * Application title served to the frontend via `GET /_app/layout`.
1409
1439
  * Displayed in the admin sidebar header.
1410
1440
  */
1411
- title: import_zod19.z.string(),
1441
+ title: import_zod20.z.string(),
1412
1442
  /** Where resource directories live, relative to the project root. */
1413
- resourcesDir: import_zod19.z.string(),
1443
+ resourcesDir: import_zod20.z.string(),
1414
1444
  /** Where datasource folders live (each with a `data-source.json`). */
1415
- dataSourcesDir: import_zod19.z.string(),
1445
+ dataSourcesDir: import_zod20.z.string(),
1416
1446
  /**
1417
1447
  * Template for a model's Zod export name. `{Model}` → Prisma model name.
1418
1448
  * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema
1419
1449
  * emitted by zod-prisma-types when `createRelationValuesTypes` is on).
1420
1450
  */
1421
- schemaExportName: import_zod19.z.string().default("{Model}WithRelationsSchema"),
1451
+ schemaExportName: import_zod20.z.string().default("{Model}WithRelationsSchema"),
1422
1452
  /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
1423
- enumsFile: import_zod19.z.string().default("crouton.enums.json"),
1453
+ enumsFile: import_zod20.z.string().default("crouton.enums.json"),
1424
1454
  /** Optional overrides of the default visibility ruleset. */
1425
1455
  rules: RulesetSchema.default(RulesetSchema.parse({})),
1426
1456
  /**
1427
1457
  * Sidebar group definitions, keyed by group slug (e.g. `"metadata"`).
1428
1458
  * Resources reference a group via `sidebar.group` in their `resource.json`.
1429
1459
  */
1430
- sidebarGroups: import_zod19.z.record(import_zod19.z.string(), SidebarGroupSchema).default({}),
1460
+ sidebarGroups: import_zod20.z.record(import_zod20.z.string(), SidebarGroupSchema).default({}),
1431
1461
  /**
1432
1462
  * Whether form fields are saved automatically as the user edits them.
1433
1463
  * @default true
1434
1464
  */
1435
- autoSave: import_zod19.z.boolean().default(true),
1465
+ autoSave: import_zod20.z.boolean().default(true),
1436
1466
  /** Optional i18n / translation configuration. */
1437
1467
  i18n: I18nConfigSchema.optional()
1438
1468
  });
@@ -1820,7 +1850,7 @@ var injectCalculatedColumns = /* @__PURE__ */ __name((tableView, calculated) =>
1820
1850
  var injectCalculatedColumnsToView = /* @__PURE__ */ __name((viewConfig, calculated) => injectCalculatedColumnsIntoView(viewConfig, calculated, "view"), "injectCalculatedColumnsToView");
1821
1851
 
1822
1852
  // ../crouton-core/src/lib/view/view.builder.ts
1823
- var import_zod21 = require("zod");
1853
+ var import_zod22 = require("zod");
1824
1854
 
1825
1855
  // ../crouton-core/src/lib/view/column-type-schema.source.ts
1826
1856
  var optionValues = /* @__PURE__ */ __name((col) => {
@@ -1856,18 +1886,18 @@ var columnTypeSchemaSource = /* @__PURE__ */ __name((schemaCols) => {
1856
1886
  }, "columnTypeSchemaSource");
1857
1887
 
1858
1888
  // ../crouton-core/src/lib/view/json-schema.opts.ts
1859
- var import_zod20 = require("zod");
1889
+ var import_zod21 = require("zod");
1860
1890
  var isInstanceOf = /* @__PURE__ */ __name((zodSchema, className) => {
1861
- if (!(zodSchema instanceof import_zod20.z.ZodCustom)) return false;
1891
+ if (!(zodSchema instanceof import_zod21.z.ZodCustom)) return false;
1862
1892
  const result = zodSchema.safeParse(null);
1863
1893
  return !result.success && result.error.issues[0]?.expected === className;
1864
1894
  }, "isInstanceOf");
1865
1895
  var jsonSchemaOverride = /* @__PURE__ */ __name(({ zodSchema, jsonSchema }) => {
1866
- if (zodSchema instanceof import_zod20.z.ZodDate) {
1896
+ if (zodSchema instanceof import_zod21.z.ZodDate) {
1867
1897
  jsonSchema.type = "string";
1868
1898
  jsonSchema.format = "date-time";
1869
1899
  }
1870
- if (zodSchema instanceof import_zod20.z.ZodBigInt) {
1900
+ if (zodSchema instanceof import_zod21.z.ZodBigInt) {
1871
1901
  jsonSchema.type = "integer";
1872
1902
  }
1873
1903
  if (isInstanceOf(zodSchema, "Decimal")) {
@@ -1941,7 +1971,7 @@ var zodSchemaSource = /* @__PURE__ */ __name((schema) => (schemaCols) => {
1941
1971
  true
1942
1972
  ]));
1943
1973
  const picked = schema.pick(mask);
1944
- return (0, import_zod21.toJSONSchema)(picked, {
1974
+ return (0, import_zod22.toJSONSchema)(picked, {
1945
1975
  target: "draft-07",
1946
1976
  ...jsonSchemaOpts
1947
1977
  });
@@ -2148,45 +2178,45 @@ var buildViewsFromColumns = /* @__PURE__ */ __name((columns) => {
2148
2178
  }, "buildViewsFromColumns");
2149
2179
 
2150
2180
  // ../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(),
2181
+ var import_zod23 = require("zod");
2182
+ var ViewColumnConfigSchema = import_zod23.z.object({
2183
+ id: import_zod23.z.string(),
2184
+ label: import_zod23.z.string().optional(),
2185
+ sortable: import_zod23.z.boolean().optional(),
2186
+ searchable: import_zod23.z.boolean().optional(),
2157
2187
  fieldInput: FieldInputSchema.optional()
2158
2188
  });
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()
2189
+ var ViewConfigSchema = import_zod23.z.object({
2190
+ json_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()),
2191
+ ui_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()),
2192
+ columns: import_zod23.z.array(ViewColumnConfigSchema),
2193
+ defaultSort: import_zod23.z.string().optional()
2164
2194
  });
2165
2195
 
2166
2196
  // ../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(),
2197
+ var import_zod24 = require("zod");
2198
+ var NestedStringRecord = import_zod24.z.lazy(() => import_zod24.z.record(import_zod24.z.string(), import_zod24.z.union([
2199
+ import_zod24.z.string(),
2170
2200
  NestedStringRecord
2171
2201
  ])));
2172
- var TranslationBundleSchema = import_zod23.z.object({
2173
- app: import_zod23.z.object({
2174
- title: import_zod23.z.string().optional()
2202
+ var TranslationBundleSchema = import_zod24.z.object({
2203
+ app: import_zod24.z.object({
2204
+ title: import_zod24.z.string().optional()
2175
2205
  }).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()
2206
+ sidebarGroups: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2207
+ resources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2208
+ title: import_zod24.z.string().optional(),
2209
+ sidebar: import_zod24.z.string().optional(),
2210
+ columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2211
+ actions: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2212
+ subResources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2213
+ title: import_zod24.z.string().optional(),
2214
+ columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
2185
2215
  }).optional()).optional()
2186
2216
  }).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(),
2217
+ enums: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string())).optional(),
2188
2218
  ui: NestedStringRecord.optional(),
2189
- validation: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.string()).optional()
2219
+ validation: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
2190
2220
  }).passthrough();
2191
2221
 
2192
2222
  // ../crouton-core/src/lib/i18n/translation-keys.ts
@@ -2266,25 +2296,25 @@ var resolveLanguage = /* @__PURE__ */ __name((acceptLanguage, supported, default
2266
2296
  }, "resolveLanguage");
2267
2297
 
2268
2298
  // src/lib/crouton-api.module.ts
2269
- var import_common22 = require("@nestjs/common");
2299
+ var import_common24 = require("@nestjs/common");
2270
2300
  var import_core = require("@nestjs/core");
2271
2301
 
2272
2302
  // 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()
2303
+ var import_zod25 = require("zod");
2304
+ var SidebarLeafSchema = import_zod25.z.object({
2305
+ kind: import_zod25.z.literal("item").default("item"),
2306
+ id: import_zod25.z.string(),
2307
+ label: import_zod25.z.string(),
2308
+ position: import_zod25.z.number().optional()
2279
2309
  });
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([])
2310
+ var SidebarGroupSchema2 = import_zod25.z.object({
2311
+ kind: import_zod25.z.literal("group").default("group"),
2312
+ id: import_zod25.z.string(),
2313
+ label: import_zod25.z.string(),
2314
+ position: import_zod25.z.number().optional(),
2315
+ children: import_zod25.z.array(SidebarLeafSchema).default([])
2286
2316
  });
2287
- var SidebarNodeSchema = import_zod24.z.discriminatedUnion("kind", [
2317
+ var SidebarNodeSchema = import_zod25.z.discriminatedUnion("kind", [
2288
2318
  SidebarLeafSchema,
2289
2319
  SidebarGroupSchema2
2290
2320
  ]);
@@ -2926,7 +2956,11 @@ var loadConfig = /* @__PURE__ */ __name(async () => {
2926
2956
  const mod = await import(path);
2927
2957
  config = mod.default ?? mod;
2928
2958
  }
2929
- return CroutonConfigSchema.parse(config);
2959
+ const parsed = CroutonConfigSchema.parse(config);
2960
+ return {
2961
+ ...parsed,
2962
+ configDir: (0, import_node_path3.dirname)(path)
2963
+ };
2930
2964
  }, "loadConfig");
2931
2965
 
2932
2966
  // src/lib/crud/crouton-validation.filter.ts
@@ -3080,51 +3114,51 @@ CroutonValidationExceptionFilter = _ts_decorate3([
3080
3114
  ], CroutonValidationExceptionFilter);
3081
3115
 
3082
3116
  // src/lib/crud/crud-controller.factory.ts
3083
- var import_common19 = require("@nestjs/common");
3117
+ var import_common21 = require("@nestjs/common");
3084
3118
  var import_swagger11 = require("@nestjs/swagger");
3085
3119
 
3086
3120
  // src/lib/crud/action/action.types.ts
3087
- var import_zod25 = require("zod");
3088
- var ActionMetadataSchema = import_zod25.z.object({
3121
+ var import_zod26 = require("zod");
3122
+ var ActionMetadataSchema = import_zod26.z.object({
3089
3123
  /** URL segment used in the endpoint. */
3090
- id: import_zod25.z.string(),
3124
+ id: import_zod26.z.string(),
3091
3125
  /** Human-readable label shown as a button. */
3092
- label: import_zod25.z.string().optional(),
3126
+ label: import_zod26.z.string().optional(),
3093
3127
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
3094
- icon: import_zod25.z.string().optional(),
3128
+ icon: import_zod26.z.string().optional(),
3095
3129
  /** Tooltip text. Falls back to `label` when omitted. */
3096
- tooltip: import_zod25.z.string().optional(),
3130
+ tooltip: import_zod26.z.string().optional(),
3097
3131
  /** Per-row condition — button is hidden when false. */
3098
- condition: import_zod25.z.custom().optional()
3132
+ condition: import_zod26.z.custom().optional()
3099
3133
  });
3100
3134
  var ResourceLinkActionSchema = ActionMetadataSchema.extend({
3101
- type: import_zod25.z.literal("link"),
3135
+ type: import_zod26.z.literal("link"),
3102
3136
  /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */
3103
- href: import_zod25.z.string()
3137
+ href: import_zod26.z.string()
3104
3138
  });
3105
3139
  var ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
3106
- type: import_zod25.z.literal("procedure").optional(),
3140
+ type: import_zod26.z.literal("procedure").optional(),
3107
3141
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3108
- method: import_zod25.z.string().optional(),
3142
+ method: import_zod26.z.string().optional(),
3109
3143
  /** 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(),
3144
+ data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
3111
3145
  /** Procedure called with `(prisma, recordId)`. */
3112
- procedure: import_zod25.z.custom((v) => typeof v === "function")
3146
+ procedure: import_zod26.z.custom((v) => typeof v === "function")
3113
3147
  });
3114
3148
  var ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
3115
- type: import_zod25.z.literal("procedure").optional(),
3149
+ type: import_zod26.z.literal("procedure").optional(),
3116
3150
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3117
- method: import_zod25.z.string().optional(),
3151
+ method: import_zod26.z.string().optional(),
3118
3152
  /** 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(),
3153
+ data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
3120
3154
  /** Procedure called with `(prisma)` — no record id. */
3121
- procedure: import_zod25.z.custom((v) => typeof v === "function")
3155
+ procedure: import_zod26.z.custom((v) => typeof v === "function")
3122
3156
  });
3123
- var ResourceRowActionSchema = import_zod25.z.union([
3157
+ var ResourceRowActionSchema = import_zod26.z.union([
3124
3158
  ResourceRowProcedureActionSchema,
3125
3159
  ResourceLinkActionSchema
3126
3160
  ]);
3127
- var ResourceTableActionSchema = import_zod25.z.union([
3161
+ var ResourceTableActionSchema = import_zod26.z.union([
3128
3162
  ResourceTableProcedureActionSchema,
3129
3163
  ResourceLinkActionSchema
3130
3164
  ]);
@@ -3204,9 +3238,18 @@ var schemaFor = /* @__PURE__ */ __name((def2, op) => {
3204
3238
  return entry.schema;
3205
3239
  }, "schemaFor");
3206
3240
  var upsertOnFor = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
3241
+ var opSecurity = /* @__PURE__ */ __name((entry) => {
3242
+ if (!entry || entry === true) return void 0;
3243
+ return entry.security;
3244
+ }, "opSecurity");
3245
+ var securityFor = /* @__PURE__ */ __name((config, def2, op, moduleDefault) => opSecurity(def2[op]) ?? config.security ?? moduleDefault, "securityFor");
3246
+ var securityForSub = /* @__PURE__ */ __name((config, sub, op, moduleDefault) => {
3247
+ const entry = sub.operations[op];
3248
+ return opSecurity(entry) ?? config.security ?? moduleDefault;
3249
+ }, "securityForSub");
3207
3250
 
3208
3251
  // src/lib/crud/custom-repository/custom-repository.types.ts
3209
- var import_zod26 = require("zod");
3252
+ var import_zod27 = require("zod");
3210
3253
  var CUSTOM_OPS = [
3211
3254
  "findAll",
3212
3255
  "findOne",
@@ -3223,7 +3266,7 @@ var PARENT_METHOD = {
3223
3266
  patch: "patchByParent",
3224
3267
  delete: "deleteByParent"
3225
3268
  };
3226
- var CustomRepositorySchema = import_zod26.z.custom((value) => typeof value === "object" && value !== null);
3269
+ var CustomRepositorySchema = import_zod27.z.custom((value) => typeof value === "object" && value !== null);
3227
3270
 
3228
3271
  // src/lib/crud/resource/resource-load-errors.registry.ts
3229
3272
  var ResourceLoadErrorsRegistry = class ResourceLoadErrorsRegistry2 {
@@ -3297,22 +3340,22 @@ var DEFAULT_ID_TYPE = "string";
3297
3340
  var DEFAULT_ID_FIELD = "id";
3298
3341
 
3299
3342
  // src/lib/crud/hooks/hooks.types.ts
3300
- var import_zod27 = require("zod");
3301
- var WriteOpSchema = import_zod27.z.enum([
3343
+ var import_zod28 = require("zod");
3344
+ var WriteOpSchema = import_zod28.z.enum([
3302
3345
  "create",
3303
3346
  "update",
3304
3347
  "patch",
3305
3348
  "upsert",
3306
3349
  "delete"
3307
3350
  ]);
3308
- var ReadOpSchema = import_zod27.z.enum([
3351
+ var ReadOpSchema = import_zod28.z.enum([
3309
3352
  "findAll",
3310
3353
  "findOne"
3311
3354
  ]);
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()
3355
+ var ResourceHooksSchema = import_zod28.z.object({
3356
+ beforeWrite: import_zod28.z.custom().optional(),
3357
+ afterWrite: import_zod28.z.custom().optional(),
3358
+ afterRead: import_zod28.z.custom().optional()
3316
3359
  });
3317
3360
 
3318
3361
  // src/lib/crud/hooks/hooks.loader.ts
@@ -4260,9 +4303,9 @@ var ReadRepository = class {
4260
4303
  };
4261
4304
 
4262
4305
  // src/lib/crud/schema.utils.ts
4263
- var import_zod28 = require("zod");
4306
+ var import_zod29 = require("zod");
4264
4307
  function isZodSchema(schema) {
4265
- return schema instanceof import_zod28.ZodObject;
4308
+ return schema instanceof import_zod29.ZodObject;
4266
4309
  }
4267
4310
  __name(isZodSchema, "isZodSchema");
4268
4311
  var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
@@ -4276,7 +4319,7 @@ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
4276
4319
  }, "dropNullableFromRequired");
4277
4320
  function toJsonSchema(schema) {
4278
4321
  if (isZodSchema(schema)) {
4279
- const jsonSchema = (0, import_zod28.toJSONSchema)(schema, {
4322
+ const jsonSchema = (0, import_zod29.toJSONSchema)(schema, {
4280
4323
  target: "openApi3",
4281
4324
  ...jsonSchemaOpts
4282
4325
  });
@@ -4831,9 +4874,118 @@ var findModule2 = /* @__PURE__ */ __name((dir, name) => {
4831
4874
  }, "findModule");
4832
4875
 
4833
4876
  // src/lib/crud/operations/register-actions.ts
4834
- var import_common10 = require("@nestjs/common");
4877
+ var import_common12 = require("@nestjs/common");
4835
4878
  var import_swagger2 = require("@nestjs/swagger");
4836
4879
 
4880
+ // src/lib/crud/security/crouton-security.guard.ts
4881
+ var import_common10 = require("@nestjs/common");
4882
+ function _ts_decorate6(decorators, target, key, desc2) {
4883
+ var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
4884
+ if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
4885
+ r = Reflect.decorate(decorators, target, key, desc2);
4886
+ } else {
4887
+ for (var i = decorators.length - 1; i >= 0; i--) {
4888
+ if (d = decorators[i]) {
4889
+ r = (c < 3 ? d(r) : c > 3 ? d(target, key, r) : d(target, key)) || r;
4890
+ }
4891
+ }
4892
+ }
4893
+ return c > 3 && r && Object.defineProperty(target, key, r), r;
4894
+ }
4895
+ __name(_ts_decorate6, "_ts_decorate");
4896
+ function _ts_metadata6(metadataKey, metadataValue) {
4897
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4898
+ return Reflect.metadata(metadataKey, metadataValue);
4899
+ }
4900
+ }
4901
+ __name(_ts_metadata6, "_ts_metadata");
4902
+ var CROUTON_SECURITY = "crouton:security";
4903
+ var CroutonSecurityGuard = class {
4904
+ static {
4905
+ __name(this, "CroutonSecurityGuard");
4906
+ }
4907
+ reflector;
4908
+ registry;
4909
+ moduleRef;
4910
+ constructor(reflector, registry, moduleRef) {
4911
+ this.reflector = reflector;
4912
+ this.registry = registry;
4913
+ this.moduleRef = moduleRef;
4914
+ }
4915
+ async canActivate(context) {
4916
+ const sec = this.reflector.get(CROUTON_SECURITY, context.getHandler());
4917
+ if (!sec || "public" in sec) return true;
4918
+ const names = Array.isArray(sec.guard) ? sec.guard : [
4919
+ sec.guard
4920
+ ];
4921
+ for (const name of names) {
4922
+ const cls = this.registry.resolve(name);
4923
+ const guard = this.moduleRef.get(cls, {
4924
+ strict: false
4925
+ });
4926
+ const ok = await guard.canActivate(context);
4927
+ if (!ok) return false;
4928
+ }
4929
+ return true;
4930
+ }
4931
+ };
4932
+ CroutonSecurityGuard = _ts_decorate6([
4933
+ (0, import_common10.Injectable)(),
4934
+ _ts_metadata6("design:type", Function),
4935
+ _ts_metadata6("design:paramtypes", [
4936
+ typeof Reflector === "undefined" ? Object : Reflector,
4937
+ typeof SecurityGuardRegistry === "undefined" ? Object : SecurityGuardRegistry,
4938
+ typeof ModuleRef === "undefined" ? Object : ModuleRef
4939
+ ])
4940
+ ], CroutonSecurityGuard);
4941
+
4942
+ // src/lib/crud/security/security-guard.registry.ts
4943
+ var import_common11 = require("@nestjs/common");
4944
+ function _ts_decorate7(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_decorate7, "_ts_decorate");
4958
+ function _ts_metadata7(metadataKey, metadataValue) {
4959
+ if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
4960
+ return Reflect.metadata(metadataKey, metadataValue);
4961
+ }
4962
+ }
4963
+ __name(_ts_metadata7, "_ts_metadata");
4964
+ var SecurityGuardRegistry2 = 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
+ SecurityGuardRegistry2 = _ts_decorate7([
4982
+ (0, import_common11.Injectable)(),
4983
+ _ts_metadata7("design:type", Function),
4984
+ _ts_metadata7("design:paramtypes", [
4985
+ typeof Record === "undefined" ? Object : Record
4986
+ ])
4987
+ ], SecurityGuardRegistry2);
4988
+
4837
4989
  // src/lib/crud/operations/decorator.utils.ts
4838
4990
  var def = /* @__PURE__ */ __name((cls, method, fn) => {
4839
4991
  Object.defineProperty(cls.prototype, method, {
@@ -4855,8 +5007,8 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
4855
5007
  return action.procedure(this.repo.prisma, recordId);
4856
5008
  });
4857
5009
  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);
5010
+ (0, import_common12.Post)(`procedure/${action.id}/:recordId`)(cls.prototype, methodName, d);
5011
+ (0, import_common12.Param)("recordId")(cls.prototype, methodName, 0);
4860
5012
  (0, import_swagger2.ApiOperation)({
4861
5013
  summary: `Execute action "${action.label}" on a ${name}`
4862
5014
  })(cls.prototype, methodName, d);
@@ -4868,6 +5020,10 @@ var registerActionRoutes = /* @__PURE__ */ __name((ctx) => {
4868
5020
  status: 200,
4869
5021
  description: `Action "${action.id}" result`
4870
5022
  })(cls.prototype, methodName, d);
5023
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5024
+ if (sec) {
5025
+ (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
5026
+ }
4871
5027
  }
4872
5028
  }, "registerActionRoutes");
4873
5029
  var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
@@ -4880,7 +5036,7 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4880
5036
  return action.procedure(this.repo.prisma);
4881
5037
  });
4882
5038
  const d = desc(cls, methodName);
4883
- (0, import_common10.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
5039
+ (0, import_common12.Post)(`table-action/${action.id}`)(cls.prototype, methodName, d);
4884
5040
  (0, import_swagger2.ApiOperation)({
4885
5041
  summary: `Execute table action "${action.label ?? action.id}" on ${name}`
4886
5042
  })(cls.prototype, methodName, d);
@@ -4888,11 +5044,15 @@ var registerTableActionRoutes = /* @__PURE__ */ __name((ctx) => {
4888
5044
  status: 200,
4889
5045
  description: `Table action "${action.id}" result`
4890
5046
  })(cls.prototype, methodName, d);
5047
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5048
+ if (sec) {
5049
+ (0, import_common12.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
5050
+ }
4891
5051
  }
4892
5052
  }, "registerTableActionRoutes");
4893
5053
 
4894
5054
  // src/lib/crud/operations/register-create.ts
4895
- var import_common11 = require("@nestjs/common");
5055
+ var import_common13 = require("@nestjs/common");
4896
5056
  var import_swagger3 = require("@nestjs/swagger");
4897
5057
  var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4898
5058
  if (!isOperationEnabled(ctx.definition, "create")) return null;
@@ -4909,7 +5069,7 @@ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
4909
5069
  bodyDecorator(createSchema, {
4910
5070
  coerceNullableUndefinedToNull: true
4911
5071
  })(cls.prototype, methodName, 0);
4912
- (0, import_common11.Req)()(cls.prototype, methodName, 1);
5072
+ (0, import_common13.Req)()(cls.prototype, methodName, 1);
4913
5073
  }, "decorators")
4914
5074
  };
4915
5075
  }, "defaultCreate");
@@ -4921,9 +5081,9 @@ var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
4921
5081
  return this.repo.createChild(id, sub, body, req);
4922
5082
  }, "createFn");
4923
5083
  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);
5084
+ (0, import_common13.Param)("id")(cls.prototype, methodName, 0);
5085
+ (0, import_common13.Body)()(cls.prototype, methodName, 1);
5086
+ (0, import_common13.Req)()(cls.prototype, methodName, 2);
4927
5087
  }, "decorators");
4928
5088
  return {
4929
5089
  route: `:id/${sub.childRoute}`,
@@ -4941,7 +5101,7 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4941
5101
  const { cls } = ctx;
4942
5102
  def(cls, methodName, properties.createFn);
4943
5103
  const d = desc(cls, methodName);
4944
- (0, import_common11.Post)(route)(cls.prototype, methodName, d);
5104
+ (0, import_common13.Post)(route)(cls.prototype, methodName, d);
4945
5105
  (0, import_swagger3.ApiOperation)({
4946
5106
  summary: `Create a ${name}`
4947
5107
  })(cls.prototype, methodName, d);
@@ -4950,10 +5110,11 @@ var registerCreate = /* @__PURE__ */ __name((ctx, sub) => {
4950
5110
  description: `${name} created`
4951
5111
  })(cls.prototype, methodName, d);
4952
5112
  properties.decorators();
5113
+ ctx.secure(methodName, "create", sub);
4953
5114
  }, "registerCreate");
4954
5115
 
4955
5116
  // src/lib/crud/operations/register-delete.ts
4956
- var import_common12 = require("@nestjs/common");
5117
+ var import_common14 = require("@nestjs/common");
4957
5118
  var import_swagger4 = require("@nestjs/swagger");
4958
5119
  var defaultDelete = /* @__PURE__ */ __name((ctx) => {
4959
5120
  if (!isOperationEnabled(ctx.definition, "delete")) return null;
@@ -4979,9 +5140,9 @@ var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
4979
5140
  return this.repo.deleteChild(sub, childId, parentId2, req);
4980
5141
  }, "deleteFn");
4981
5142
  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);
5143
+ (0, import_common14.Param)("childId")(cls.prototype, methodName, 0);
5144
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 1);
5145
+ (0, import_common14.Req)()(cls.prototype, methodName, 2);
4985
5146
  }, "decorators");
4986
5147
  return {
4987
5148
  route: `:id/${sub.childRoute}/:childId`,
@@ -4999,8 +5160,8 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
4999
5160
  const { methodName, route, name } = properties;
5000
5161
  def(cls, methodName, properties.deleteFn);
5001
5162
  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);
5163
+ (0, import_common14.Delete)(route)(cls.prototype, methodName, d);
5164
+ (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5004
5165
  (0, import_swagger4.ApiOperation)({
5005
5166
  summary: `Delete ${name} record`
5006
5167
  })(cls.prototype, methodName, d);
@@ -5009,11 +5170,12 @@ var registerDelete = /* @__PURE__ */ __name((ctx, sub) => {
5009
5170
  status: 200
5010
5171
  })(cls.prototype, methodName, d);
5011
5172
  properties.decorators();
5012
- if (!sub) (0, import_common12.Req)()(cls.prototype, methodName, 1);
5173
+ if (!sub) (0, import_common14.Req)()(cls.prototype, methodName, 1);
5174
+ ctx.secure(methodName, "delete", sub);
5013
5175
  }, "registerDelete");
5014
5176
 
5015
5177
  // src/lib/crud/operations/register-findall.ts
5016
- var import_common13 = require("@nestjs/common");
5178
+ var import_common15 = require("@nestjs/common");
5017
5179
  var import_swagger5 = require("@nestjs/swagger");
5018
5180
 
5019
5181
  // src/lib/crud/request.dto.ts
@@ -5169,8 +5331,8 @@ var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
5169
5331
  return findAllByParent(this.repo, id, sub.childRoute, params, req);
5170
5332
  }, "findAll");
5171
5333
  const decorators = /* @__PURE__ */ __name(() => {
5172
- (0, import_common13.Param)("id")(cls.prototype, methodName, 2);
5173
- (0, import_common13.Req)()(cls.prototype, methodName, 3);
5334
+ (0, import_common15.Param)("id")(cls.prototype, methodName, 2);
5335
+ (0, import_common15.Req)()(cls.prototype, methodName, 3);
5174
5336
  }, "decorators");
5175
5337
  return {
5176
5338
  name: sub.childRoute,
@@ -5189,10 +5351,10 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
5189
5351
  const { cls } = ctx;
5190
5352
  def(cls, methodName, properties.findAll);
5191
5353
  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);
5354
+ (0, import_common15.Get)(route)(cls.prototype, methodName, d);
5355
+ (0, import_common15.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
5356
+ (0, import_common15.Query)("q")(cls.prototype, methodName, 1);
5357
+ if (!sub) (0, import_common15.Req)()(cls.prototype, methodName, 2);
5196
5358
  (0, import_swagger5.ApiOperation)({
5197
5359
  summary: `List all ${name}s`
5198
5360
  })(cls.prototype, methodName, d);
@@ -5207,10 +5369,11 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
5207
5369
  }
5208
5370
  })(cls.prototype, methodName, d);
5209
5371
  properties.decorators();
5372
+ ctx.secure(methodName, "findAll", sub);
5210
5373
  }, "registerFindAll");
5211
5374
 
5212
5375
  // src/lib/crud/operations/register-findone.ts
5213
- var import_common14 = require("@nestjs/common");
5376
+ var import_common16 = require("@nestjs/common");
5214
5377
  var import_swagger6 = require("@nestjs/swagger");
5215
5378
  var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
5216
5379
  if (!isOperationEnabled(ctx.definition, "findOne")) return null;
@@ -5224,8 +5387,8 @@ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
5224
5387
  return this.repo.findOne(id, req);
5225
5388
  }, "findOneFn"),
5226
5389
  decorators: /* @__PURE__ */ __name(() => {
5227
- (0, import_common14.Param)("id")(cls.prototype, methodName, 0);
5228
- (0, import_common14.Req)()(cls.prototype, methodName, 1);
5390
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
5391
+ (0, import_common16.Req)()(cls.prototype, methodName, 1);
5229
5392
  }, "decorators")
5230
5393
  };
5231
5394
  }, "defaultFindOne");
@@ -5237,9 +5400,9 @@ var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
5237
5400
  return this.repo.findOneChild(sub, childId, parentId2, req);
5238
5401
  }, "findOneFn");
5239
5402
  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);
5403
+ (0, import_common16.Param)("id")(cls.prototype, methodName, 0);
5404
+ (0, import_common16.Param)("childId")(cls.prototype, methodName, 1);
5405
+ (0, import_common16.Req)()(cls.prototype, methodName, 2);
5243
5406
  }, "decorators");
5244
5407
  return {
5245
5408
  route: `:id/${sub.childRoute}/:childId`,
@@ -5257,7 +5420,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
5257
5420
  const { cls } = ctx;
5258
5421
  def(cls, methodName, properties.findOneFn);
5259
5422
  const d = desc(cls, methodName);
5260
- (0, import_common14.Get)(route)(cls.prototype, methodName, d);
5423
+ (0, import_common16.Get)(route)(cls.prototype, methodName, d);
5261
5424
  (0, import_swagger6.ApiOperation)({
5262
5425
  summary: `Get one ${name} by id`
5263
5426
  })(cls.prototype, methodName, d);
@@ -5273,10 +5436,11 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
5273
5436
  description: "Not found"
5274
5437
  })(cls.prototype, methodName, d);
5275
5438
  properties.decorators();
5439
+ ctx.secure(methodName, "findOne", sub);
5276
5440
  }, "registerFindOne");
5277
5441
 
5278
5442
  // src/lib/crud/operations/register-patch.ts
5279
- var import_common15 = require("@nestjs/common");
5443
+ var import_common17 = require("@nestjs/common");
5280
5444
  var import_swagger7 = require("@nestjs/swagger");
5281
5445
  var defaultPatch = /* @__PURE__ */ __name((ctx) => {
5282
5446
  if (!isOperationEnabled(ctx.definition, "patch")) return null;
@@ -5290,9 +5454,9 @@ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
5290
5454
  return this.repo.patch(id, body, req);
5291
5455
  }, "patchFn"),
5292
5456
  decorators: /* @__PURE__ */ __name(() => {
5293
- (0, import_common15.Param)("id")(cls.prototype, methodName, 0);
5457
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5294
5458
  bodyDecorator(patchSchema)(cls.prototype, methodName, 1);
5295
- (0, import_common15.Req)()(cls.prototype, methodName, 2);
5459
+ (0, import_common17.Req)()(cls.prototype, methodName, 2);
5296
5460
  }, "decorators")
5297
5461
  };
5298
5462
  }, "defaultPatch");
@@ -5304,10 +5468,10 @@ var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
5304
5468
  return this.repo.updateChild(sub, childId, body, req);
5305
5469
  }, "patchFn");
5306
5470
  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);
5471
+ (0, import_common17.Param)("id")(cls.prototype, methodName, 0);
5472
+ (0, import_common17.Param)("childId")(cls.prototype, methodName, 1);
5473
+ (0, import_common17.Body)()(cls.prototype, methodName, 2);
5474
+ (0, import_common17.Req)()(cls.prototype, methodName, 3);
5311
5475
  }, "decorators");
5312
5476
  return {
5313
5477
  route: `:id/${sub.childRoute}/:childId`,
@@ -5325,7 +5489,7 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
5325
5489
  const { cls } = ctx;
5326
5490
  def(cls, methodName, properties.patchFn);
5327
5491
  const d = desc(cls, methodName);
5328
- (0, import_common15.Patch)(route)(cls.prototype, methodName, d);
5492
+ (0, import_common17.Patch)(route)(cls.prototype, methodName, d);
5329
5493
  (0, import_swagger7.ApiOperation)({
5330
5494
  summary: `Update a ${name}`
5331
5495
  })(cls.prototype, methodName, d);
@@ -5337,33 +5501,34 @@ var registerPatch = /* @__PURE__ */ __name((ctx, sub) => {
5337
5501
  description: "Not found"
5338
5502
  })(cls.prototype, methodName, d);
5339
5503
  properties.decorators();
5504
+ ctx.secure(methodName, "patch", sub);
5340
5505
  }, "registerPatch");
5341
5506
 
5342
5507
  // src/lib/crud/operations/register-schema-endpoints.ts
5343
- var import_common16 = require("@nestjs/common");
5508
+ var import_common18 = require("@nestjs/common");
5344
5509
  var import_swagger8 = require("@nestjs/swagger");
5345
5510
 
5346
5511
  // 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()
5512
+ var import_zod30 = require("zod");
5513
+ var FieldVariantPatchSchema = import_zod30.z.object({
5514
+ type: import_zod30.z.string().nullable().optional(),
5515
+ format: import_zod30.z.string().nullable().optional(),
5516
+ resource: import_zod30.z.string().nullable().optional(),
5517
+ position: import_zod30.z.number().nullable().optional(),
5518
+ options: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown().nullable()).optional()
5354
5519
  }).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(),
5520
+ var PatchColumnSchema = import_zod30.z.object({
5521
+ label: import_zod30.z.string().optional(),
5522
+ column: import_zod30.z.string().optional(),
5523
+ hiddenInTable: import_zod30.z.boolean().optional(),
5524
+ hiddenInForm: import_zod30.z.boolean().optional(),
5525
+ hiddenInView: import_zod30.z.boolean().optional(),
5361
5526
  fieldInput: FieldVariantPatchSchema.optional(),
5362
5527
  fieldView: FieldVariantPatchSchema.optional(),
5363
5528
  fieldTable: FieldVariantPatchSchema.optional()
5364
5529
  }).partial();
5365
- var PatchResourceJsonSchema = import_zod29.z.object({
5366
- columns: import_zod29.z.record(import_zod29.z.string(), PatchColumnSchema)
5530
+ var PatchResourceJsonSchema = import_zod30.z.object({
5531
+ columns: import_zod30.z.record(import_zod30.z.string(), PatchColumnSchema)
5367
5532
  });
5368
5533
 
5369
5534
  // src/lib/crud/resource/WriteResourceJson.ts
@@ -5699,7 +5864,7 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
5699
5864
  return definitionPayload;
5700
5865
  });
5701
5866
  const d = desc(cls, "getDefinition");
5702
- (0, import_common16.Get)("definition")(cls.prototype, "getDefinition", d);
5867
+ (0, import_common18.Get)("definition")(cls.prototype, "getDefinition", d);
5703
5868
  (0, import_swagger8.ApiOperation)({
5704
5869
  summary: `Get the resource definition for ${name}`
5705
5870
  })(cls.prototype, "getDefinition", d);
@@ -5707,6 +5872,10 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
5707
5872
  status: 200,
5708
5873
  description: `Definition (operations + schemas) for ${name}`
5709
5874
  })(cls.prototype, "getDefinition", d);
5875
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5876
+ if (sec) {
5877
+ (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getDefinition", d);
5878
+ }
5710
5879
  }, "registerDefinitionEndpoint");
5711
5880
  var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5712
5881
  const { cls, config, baseUrl } = ctx;
@@ -5721,7 +5890,7 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5721
5890
  return resourceJsonPayload;
5722
5891
  });
5723
5892
  const d = desc(cls, "getResourceJson");
5724
- (0, import_common16.Get)("resource.json")(cls.prototype, "getResourceJson", d);
5893
+ (0, import_common18.Get)("resource.json")(cls.prototype, "getResourceJson", d);
5725
5894
  (0, import_swagger8.ApiOperation)({
5726
5895
  summary: `Get resource descriptor for ${name}`
5727
5896
  })(cls.prototype, "getResourceJson", d);
@@ -5729,19 +5898,23 @@ var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
5729
5898
  status: 200,
5730
5899
  description: `Resource descriptor (operations + JSON Schema) for ${name}`
5731
5900
  })(cls.prototype, "getResourceJson", d);
5901
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
5902
+ if (sec) {
5903
+ (0, import_common18.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, "getResourceJson", d);
5904
+ }
5732
5905
  }, "registerResourceJsonEndpoint");
5733
5906
  var registerResourceColumnsEndpoint = /* @__PURE__ */ __name((ctx) => {
5734
5907
  const { cls, config } = ctx;
5735
5908
  const { route, name } = config;
5736
5909
  def(cls, "getResourceColumns", async function() {
5737
5910
  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.");
5911
+ throw new import_common18.ForbiddenException("The resource schema editor is only available when the backend is running in local dev mode.");
5739
5912
  }
5740
5913
  const fresh = await this.configRegistry.getByRoute(route);
5741
5914
  return buildEditableColumnsPayload(fresh ?? config);
5742
5915
  });
5743
5916
  const d = desc(cls, "getResourceColumns");
5744
- (0, import_common16.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5917
+ (0, import_common18.Get)("resource-columns")(cls.prototype, "getResourceColumns", d);
5745
5918
  (0, import_swagger8.ApiOperation)({
5746
5919
  summary: `Dev-only: get the editable column list for ${name}`
5747
5920
  })(cls.prototype, "getResourceColumns", d);
@@ -5755,30 +5928,30 @@ var registerResourceJsonPatchEndpoint = /* @__PURE__ */ __name((ctx) => {
5755
5928
  const { route, name } = config;
5756
5929
  def(cls, "patchResourceJson", async function(body) {
5757
5930
  if (!IS_DEV) {
5758
- throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5931
+ throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5759
5932
  }
5760
5933
  await this.configRegistry.getByRoute(route);
5761
5934
  const dir = this.configRegistry.getResourceDir(route);
5762
5935
  if (!dir) {
5763
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5936
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5764
5937
  }
5765
5938
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5766
5939
  const raw = readRawResourceJson(jsonPath);
5767
5940
  if (!raw) {
5768
- throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5941
+ throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
5769
5942
  }
5770
5943
  const merged = applyColumnPatch(raw, body);
5771
5944
  const validated = validateResourceJson(merged);
5772
5945
  if (!validated.success) {
5773
- throw new import_common16.BadRequestException(validated.error.issues);
5946
+ throw new import_common18.BadRequestException(validated.error.issues);
5774
5947
  }
5775
5948
  writeRawResourceJson(jsonPath, merged);
5776
5949
  const fresh = await this.configRegistry.getByRoute(route);
5777
5950
  return buildEditableColumnsPayload(fresh ?? config);
5778
5951
  });
5779
5952
  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);
5953
+ (0, import_common18.Patch)("resource.json")(cls.prototype, "patchResourceJson", d);
5954
+ (0, import_common18.Body)(new ZodValidationPipe(PatchResourceJsonSchema))(cls.prototype, "patchResourceJson", 0);
5782
5955
  (0, import_swagger8.ApiOperation)({
5783
5956
  summary: `Dev-only: patch column layout in resource.json for ${name}`
5784
5957
  })(cls.prototype, "patchResourceJson", d);
@@ -5792,22 +5965,22 @@ var registerResourceJsonRawGetEndpoint = /* @__PURE__ */ __name((ctx) => {
5792
5965
  const { route, name } = config;
5793
5966
  def(cls, "getResourceJsonRaw", async function() {
5794
5967
  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.");
5968
+ throw new import_common18.ForbiddenException("The resource JSON editor is only available when the backend is running in local dev mode.");
5796
5969
  }
5797
5970
  await this.configRegistry.getByRoute(route);
5798
5971
  const dir = this.configRegistry.getResourceDir(route);
5799
5972
  if (!dir) {
5800
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5973
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5801
5974
  }
5802
5975
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5803
5976
  const raw = readRawResourceJson(jsonPath);
5804
5977
  if (!raw) {
5805
- throw new import_common16.NotFoundException(`resource.json not found at ${jsonPath}`);
5978
+ throw new import_common18.NotFoundException(`resource.json not found at ${jsonPath}`);
5806
5979
  }
5807
5980
  return raw;
5808
5981
  });
5809
5982
  const d = desc(cls, "getResourceJsonRaw");
5810
- (0, import_common16.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
5983
+ (0, import_common18.Get)("resource-json-raw")(cls.prototype, "getResourceJsonRaw", d);
5811
5984
  (0, import_swagger8.ApiOperation)({
5812
5985
  summary: `Dev-only: get the raw resource.json for ${name}`
5813
5986
  })(cls.prototype, "getResourceJsonRaw", d);
@@ -5821,24 +5994,24 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5821
5994
  const { route, name } = config;
5822
5995
  def(cls, "putResourceJsonRaw", async function(body) {
5823
5996
  if (!IS_DEV) {
5824
- throw new import_common16.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5997
+ throw new import_common18.ForbiddenException("Editing resource.json is only available when the backend is running in local dev mode.");
5825
5998
  }
5826
5999
  await this.configRegistry.getByRoute(route);
5827
6000
  const dir = this.configRegistry.getResourceDir(route);
5828
6001
  if (!dir) {
5829
- throw new import_common16.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
6002
+ throw new import_common18.NotFoundException(`No resource.json on disk for "${name}" (route "${route}").`);
5830
6003
  }
5831
6004
  const validated = validateResourceJson(body);
5832
6005
  if (!validated.success) {
5833
- throw new import_common16.BadRequestException(validated.error.issues);
6006
+ throw new import_common18.BadRequestException(validated.error.issues);
5834
6007
  }
5835
6008
  const jsonPath = (0, import_node_path9.join)(dir, "resource.json");
5836
6009
  writeRawResourceJson(jsonPath, body);
5837
6010
  return body;
5838
6011
  });
5839
6012
  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);
6013
+ (0, import_common18.Put)("resource-json-raw")(cls.prototype, "putResourceJsonRaw", d);
6014
+ (0, import_common18.Body)()(cls.prototype, "putResourceJsonRaw", 0);
5842
6015
  (0, import_swagger8.ApiOperation)({
5843
6016
  summary: `Dev-only: replace the full resource.json for ${name}`
5844
6017
  })(cls.prototype, "putResourceJsonRaw", d);
@@ -5849,7 +6022,7 @@ var registerResourceJsonRawPutEndpoint = /* @__PURE__ */ __name((ctx) => {
5849
6022
  }, "registerResourceJsonRawPutEndpoint");
5850
6023
 
5851
6024
  // src/lib/crud/operations/register-schemas.ts
5852
- var import_common17 = require("@nestjs/common");
6025
+ var import_common19 = require("@nestjs/common");
5853
6026
  var import_swagger9 = require("@nestjs/swagger");
5854
6027
  var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
5855
6028
  const { config, baseUrl } = ctx;
@@ -5894,7 +6067,7 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5894
6067
  const { cls } = ctx;
5895
6068
  def(cls, methodName, properties.schemasFn);
5896
6069
  const d = desc(cls, methodName);
5897
- (0, import_common17.Get)(route)(cls.prototype, methodName, d);
6070
+ (0, import_common19.Get)(route)(cls.prototype, methodName, d);
5898
6071
  (0, import_swagger9.ApiOperation)({
5899
6072
  summary: `Get view schemas for ${name}`
5900
6073
  })(cls.prototype, methodName, d);
@@ -5903,10 +6076,14 @@ var registerSchemas = /* @__PURE__ */ __name((ctx, sub) => {
5903
6076
  description: `View schemas for ${name}`
5904
6077
  })(cls.prototype, methodName, d);
5905
6078
  properties.decorators();
6079
+ const sec = ctx.config.security ?? ctx.moduleDefaultSecurity;
6080
+ if (sec) {
6081
+ (0, import_common19.SetMetadata)(CROUTON_SECURITY, sec)(cls.prototype, methodName, d);
6082
+ }
5906
6083
  }, "registerSchemas");
5907
6084
 
5908
6085
  // src/lib/crud/operations/register-update.ts
5909
- var import_common18 = require("@nestjs/common");
6086
+ var import_common20 = require("@nestjs/common");
5910
6087
  var import_swagger10 = require("@nestjs/swagger");
5911
6088
  var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5912
6089
  if (!isOperationEnabled(ctx.definition, "update")) return null;
@@ -5920,9 +6097,9 @@ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
5920
6097
  return this.repo.update(id, body, req);
5921
6098
  }, "updateFn"),
5922
6099
  decorators: /* @__PURE__ */ __name(() => {
5923
- (0, import_common18.Param)("id")(cls.prototype, methodName, 0);
6100
+ (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
5924
6101
  bodyDecorator(updateSchema)(cls.prototype, methodName, 1);
5925
- (0, import_common18.Req)()(cls.prototype, methodName, 2);
6102
+ (0, import_common20.Req)()(cls.prototype, methodName, 2);
5926
6103
  }, "decorators")
5927
6104
  };
5928
6105
  }, "defaultUpdate");
@@ -5934,10 +6111,10 @@ var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
5934
6111
  return this.repo.updateChild(sub, childId, body, req);
5935
6112
  }, "updateFn");
5936
6113
  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);
6114
+ (0, import_common20.Param)("id")(cls.prototype, methodName, 0);
6115
+ (0, import_common20.Param)("childId")(cls.prototype, methodName, 1);
6116
+ (0, import_common20.Body)()(cls.prototype, methodName, 2);
6117
+ (0, import_common20.Req)()(cls.prototype, methodName, 3);
5941
6118
  }, "decorators");
5942
6119
  return {
5943
6120
  route: `:id/${sub.childRoute}/:childId`,
@@ -5955,7 +6132,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
5955
6132
  const { cls } = ctx;
5956
6133
  def(cls, methodName, properties.updateFn);
5957
6134
  const d = desc(cls, methodName);
5958
- (0, import_common18.Put)(route)(cls.prototype, methodName, d);
6135
+ (0, import_common20.Put)(route)(cls.prototype, methodName, d);
5959
6136
  (0, import_swagger10.ApiOperation)({
5960
6137
  summary: `Replace a ${name}`
5961
6138
  })(cls.prototype, methodName, d);
@@ -5967,6 +6144,7 @@ var registerUpdate = /* @__PURE__ */ __name((ctx, sub) => {
5967
6144
  description: "Not found"
5968
6145
  })(cls.prototype, methodName, d);
5969
6146
  properties.decorators();
6147
+ ctx.secure(methodName, "update", sub);
5970
6148
  }, "registerUpdate");
5971
6149
 
5972
6150
  // src/lib/crud/operations/register-endpoints.ts
@@ -5999,7 +6177,7 @@ var registerEndpoint = /* @__PURE__ */ __name((ctx, sub) => {
5999
6177
  }, "registerEndpoint");
6000
6178
 
6001
6179
  // src/lib/crud/crud-controller.factory.ts
6002
- function createCrudController(config, baseUrl) {
6180
+ function createCrudController(config, baseUrl, moduleDefaultSecurity) {
6003
6181
  const { route, name, tag, idType = "string" } = config;
6004
6182
  const definition = resolveDefinition(config);
6005
6183
  const listSchema = schemaFor(definition, "findAll");
@@ -6013,9 +6191,9 @@ function createCrudController(config, baseUrl) {
6013
6191
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
6014
6192
  }
6015
6193
  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)();
6194
+ if (!schema) return (0, import_common21.Body)();
6195
+ if (isZodSchema(schema)) return (0, import_common21.Body)(new ZodValidationPipe(schema, options));
6196
+ return (0, import_common21.Body)();
6019
6197
  }, "bodyDecorator");
6020
6198
  const resolveClient = /* @__PURE__ */ __name((registry, resource) => {
6021
6199
  try {
@@ -6037,6 +6215,12 @@ function createCrudController(config, baseUrl) {
6037
6215
  this.configRegistry = configRegistry;
6038
6216
  }
6039
6217
  };
6218
+ const secure = /* @__PURE__ */ __name((methodName, op, sub) => {
6219
+ const sec = sub ? securityForSub(config, sub, op, moduleDefaultSecurity) : securityFor(config, definition, op, moduleDefaultSecurity);
6220
+ if (sec) {
6221
+ (0, import_common21.SetMetadata)(CROUTON_SECURITY, sec)(CrudControllerBase.prototype, methodName, Object.getOwnPropertyDescriptor(CrudControllerBase.prototype, methodName));
6222
+ }
6223
+ }, "secure");
6040
6224
  const ctx = {
6041
6225
  cls: CrudControllerBase,
6042
6226
  config,
@@ -6052,10 +6236,13 @@ function createCrudController(config, baseUrl) {
6052
6236
  type: idType === "number" ? "number" : "string"
6053
6237
  },
6054
6238
  bodyDecorator,
6055
- baseUrl
6239
+ baseUrl,
6240
+ moduleDefaultSecurity,
6241
+ secure
6056
6242
  };
6057
6243
  registerEndpoints(ctx);
6058
- (0, import_common19.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
6244
+ (0, import_common21.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
6245
+ (0, import_common21.UseGuards)(CroutonSecurityGuard)(CrudControllerBase);
6059
6246
  (0, import_swagger11.ApiTags)(tag)(CrudControllerBase);
6060
6247
  Object.defineProperty(CrudControllerBase, "name", {
6061
6248
  value: `${name.charAt(0).toUpperCase() + name.slice(1)}Controller`
@@ -6069,7 +6256,7 @@ function createCrudController(config, baseUrl) {
6069
6256
  __name(createCrudController, "createCrudController");
6070
6257
 
6071
6258
  // src/lib/crud/dev-tools/dev-resources.controller.ts
6072
- var import_common20 = require("@nestjs/common");
6259
+ var import_common22 = require("@nestjs/common");
6073
6260
  var import_swagger12 = require("@nestjs/swagger");
6074
6261
 
6075
6262
  // ../crouton-codegen/src/naming.ts
@@ -6765,12 +6952,12 @@ var makeSchemaExportName = /* @__PURE__ */ __name((config) => {
6765
6952
  var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path11.isAbsolute)(p) ? p : (0, import_node_path11.join)(root, p), "resolveFromRoot");
6766
6953
 
6767
6954
  // ../crouton-codegen/src/scaffold.ts
6768
- var import_zod30 = require("zod");
6955
+ var import_zod31 = require("zod");
6769
6956
  var import_promises5 = require("fs/promises");
6770
6957
  var import_node_path12 = require("path");
6771
6958
  var ScallfoldDatasourceSchema = DataSourceShape.extend({
6772
6959
  /** Folder name under `dataSourcesDir`. */
6773
- folder: import_zod30.z.string().default("default")
6960
+ folder: import_zod31.z.string().default("default")
6774
6961
  }).transform(transformDataSource);
6775
6962
 
6776
6963
  // ../crouton-codegen/src/datasource-scaffold.ts
@@ -7087,7 +7274,7 @@ var ResourceLoadReportRegistry = class ResourceLoadReportRegistry2 {
7087
7274
  var resourceLoadReportRegistry = new ResourceLoadReportRegistry();
7088
7275
 
7089
7276
  // src/lib/crud/dev-tools/dev-resources.controller.ts
7090
- function _ts_decorate6(decorators, target, key, desc2) {
7277
+ function _ts_decorate8(decorators, target, key, desc2) {
7091
7278
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
7092
7279
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
7093
7280
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -7100,13 +7287,13 @@ function _ts_decorate6(decorators, target, key, desc2) {
7100
7287
  }
7101
7288
  return c > 3 && r && Object.defineProperty(target, key, r), r;
7102
7289
  }
7103
- __name(_ts_decorate6, "_ts_decorate");
7104
- function _ts_metadata6(metadataKey, metadataValue) {
7290
+ __name(_ts_decorate8, "_ts_decorate");
7291
+ function _ts_metadata8(metadataKey, metadataValue) {
7105
7292
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
7106
7293
  return Reflect.metadata(metadataKey, metadataValue);
7107
7294
  }
7108
7295
  }
7109
- __name(_ts_metadata6, "_ts_metadata");
7296
+ __name(_ts_metadata8, "_ts_metadata");
7110
7297
  function _ts_param2(paramIndex, decorator) {
7111
7298
  return function(target, key) {
7112
7299
  decorator(target, key, paramIndex);
@@ -7125,7 +7312,7 @@ var DevResourcesController = class {
7125
7312
  }
7126
7313
  assertDev() {
7127
7314
  if (!IS_DEV) {
7128
- throw new import_common20.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
7315
+ throw new import_common22.ForbiddenException("The database sync tools are only available when CROUTON_SCHEMA_EDITOR is enabled.");
7129
7316
  }
7130
7317
  }
7131
7318
  /** Loads project config + resolves the datasource + Prisma schema path. Throws 404/400 with a clear message on misconfiguration. */
@@ -7134,14 +7321,14 @@ var DevResourcesController = class {
7134
7321
  try {
7135
7322
  loaded = await loadConfig2(process.cwd());
7136
7323
  } catch (e) {
7137
- throw new import_common20.NotFoundException(e.message ?? "No crouton.json config found.");
7324
+ throw new import_common22.NotFoundException(e.message ?? "No crouton.json config found.");
7138
7325
  }
7139
7326
  const datasources = await loadDatasources(loaded);
7140
7327
  let ds;
7141
7328
  try {
7142
7329
  ds = resolveDatasource(datasources, datasourceName);
7143
7330
  } catch (e) {
7144
- throw new import_common20.BadRequestException(e.message);
7331
+ throw new import_common22.BadRequestException(e.message);
7145
7332
  }
7146
7333
  const schemaPath = resolveFromRoot(loaded.root, ds.prismaSchema);
7147
7334
  return {
@@ -7156,7 +7343,7 @@ var DevResourcesController = class {
7156
7343
  schemaPath
7157
7344
  });
7158
7345
  } catch (e) {
7159
- throw new import_common20.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
7346
+ throw new import_common22.BadRequestException(`Failed to read Prisma schema at ${schemaPath}: ${e.message}`);
7160
7347
  }
7161
7348
  }
7162
7349
  buildApplyContext(loaded, ds) {
@@ -7226,7 +7413,7 @@ var DevResourcesController = class {
7226
7413
  zodOutputDir: zodDir
7227
7414
  });
7228
7415
  if (!result.ok) {
7229
- throw new import_common20.BadRequestException(`prisma db pull failed:
7416
+ throw new import_common22.BadRequestException(`prisma db pull failed:
7230
7417
  ${result.dbPull.output}`);
7231
7418
  }
7232
7419
  return {
@@ -7243,13 +7430,13 @@ ${result.dbPull.output}`);
7243
7430
  async sync(body) {
7244
7431
  this.assertDev();
7245
7432
  if (!body?.model) {
7246
- throw new import_common20.BadRequestException('"model" is required.');
7433
+ throw new import_common22.BadRequestException('"model" is required.');
7247
7434
  }
7248
7435
  const { loaded, ds, schemaPath } = await this.loadProject(body.datasource);
7249
7436
  const models = await this.introspectModels(schemaPath);
7250
7437
  const model = models.find((m) => m.prismaName === body.model || m.clientAccessor === body.model);
7251
7438
  if (!model) {
7252
- throw new import_common20.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
7439
+ throw new import_common22.NotFoundException(`Model "${body.model}" not found in ${schemaPath}.`);
7253
7440
  }
7254
7441
  const resolveRelationResource = await makeRelationResolver(loaded);
7255
7442
  const diff2 = await buildResourceDiff(model, {
@@ -7371,14 +7558,14 @@ ${result.dbPull.output}`);
7371
7558
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7372
7559
  const jsonPath = resolveResourcePath(resourcesDir, name);
7373
7560
  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.");
7561
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7562
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7376
7563
  const patched = applyResourceFlagPatch(raw, {
7377
7564
  draft: false
7378
7565
  });
7379
7566
  const result = validateResourceJson(patched);
7380
7567
  if (!result.success) {
7381
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7568
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7382
7569
  }
7383
7570
  writeRawResourceJson(jsonPath, patched);
7384
7571
  return {
@@ -7391,8 +7578,8 @@ ${result.dbPull.output}`);
7391
7578
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7392
7579
  const jsonPath = resolveResourcePath(resourcesDir, name);
7393
7580
  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.");
7581
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7582
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7396
7583
  const patched = applyResourceFlagPatch(raw, {
7397
7584
  sidebar: {
7398
7585
  hide: true
@@ -7400,7 +7587,7 @@ ${result.dbPull.output}`);
7400
7587
  });
7401
7588
  const result = validateResourceJson(patched);
7402
7589
  if (!result.success) {
7403
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7590
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7404
7591
  }
7405
7592
  writeRawResourceJson(jsonPath, patched);
7406
7593
  return {
@@ -7413,8 +7600,8 @@ ${result.dbPull.output}`);
7413
7600
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7414
7601
  const jsonPath = resolveResourcePath(resourcesDir, name);
7415
7602
  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.");
7603
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7604
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7418
7605
  const sidebarPatch = {
7419
7606
  hide: false
7420
7607
  };
@@ -7427,7 +7614,7 @@ ${result.dbPull.output}`);
7427
7614
  });
7428
7615
  const result = validateResourceJson(patched);
7429
7616
  if (!result.success) {
7430
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7617
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7431
7618
  }
7432
7619
  writeRawResourceJson(jsonPath, patched);
7433
7620
  return {
@@ -7440,12 +7627,12 @@ ${result.dbPull.output}`);
7440
7627
  const resourcesDir = resolveFromRoot(loaded.root, loaded.config.resourcesDir);
7441
7628
  const jsonPath = resolveResourcePath(resourcesDir, name);
7442
7629
  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.");
7630
+ if (!raw) throw new import_common22.NotFoundException(`Resource "${name}" not found.`);
7631
+ if (jsonPath.endsWith(".ts")) throw new import_common22.ForbiddenException("TypeScript resources cannot be edited.");
7445
7632
  const patched = applyResourceFlagPatch(raw, body);
7446
7633
  const result = validateResourceJson(patched);
7447
7634
  if (!result.success) {
7448
- throw new import_common20.BadRequestException(`Validation failed: ${result.error.message}`);
7635
+ throw new import_common22.BadRequestException(`Validation failed: ${result.error.message}`);
7449
7636
  }
7450
7637
  writeRawResourceJson(jsonPath, patched);
7451
7638
  return {
@@ -7453,8 +7640,8 @@ ${result.dbPull.output}`);
7453
7640
  };
7454
7641
  }
7455
7642
  };
7456
- _ts_decorate6([
7457
- (0, import_common20.Get)("models"),
7643
+ _ts_decorate8([
7644
+ (0, import_common22.Get)("models"),
7458
7645
  (0, import_swagger12.ApiOperation)({
7459
7646
  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
7647
  }),
@@ -7462,12 +7649,12 @@ _ts_decorate6([
7462
7649
  status: 200,
7463
7650
  description: "DB models and their resource/client status"
7464
7651
  }),
7465
- _ts_metadata6("design:type", Function),
7466
- _ts_metadata6("design:paramtypes", []),
7467
- _ts_metadata6("design:returntype", Promise)
7652
+ _ts_metadata8("design:type", Function),
7653
+ _ts_metadata8("design:paramtypes", []),
7654
+ _ts_metadata8("design:returntype", Promise)
7468
7655
  ], DevResourcesController.prototype, "listModels", null);
7469
- _ts_decorate6([
7470
- (0, import_common20.Post)("restart"),
7656
+ _ts_decorate8([
7657
+ (0, import_common22.Post)("restart"),
7471
7658
  (0, import_swagger12.ApiOperation)({
7472
7659
  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
7660
  }),
@@ -7475,12 +7662,12 @@ _ts_decorate6([
7475
7662
  status: 200,
7476
7663
  description: "Restart scheduled \u2014 the connection will drop shortly after"
7477
7664
  }),
7478
- _ts_metadata6("design:type", Function),
7479
- _ts_metadata6("design:paramtypes", []),
7480
- _ts_metadata6("design:returntype", Object)
7665
+ _ts_metadata8("design:type", Function),
7666
+ _ts_metadata8("design:paramtypes", []),
7667
+ _ts_metadata8("design:returntype", Object)
7481
7668
  ], DevResourcesController.prototype, "restart", null);
7482
- _ts_decorate6([
7483
- (0, import_common20.Post)("pull"),
7669
+ _ts_decorate8([
7670
+ (0, import_common22.Post)("pull"),
7484
7671
  (0, import_swagger12.ApiOperation)({
7485
7672
  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
7673
  }),
@@ -7488,15 +7675,15 @@ _ts_decorate6([
7488
7675
  status: 200,
7489
7676
  description: "Result of each step, or requiresConfirmation if schema.prisma has uncommitted changes"
7490
7677
  }),
7491
- _ts_param2(0, (0, import_common20.Body)()),
7492
- _ts_metadata6("design:type", Function),
7493
- _ts_metadata6("design:paramtypes", [
7678
+ _ts_param2(0, (0, import_common22.Body)()),
7679
+ _ts_metadata8("design:type", Function),
7680
+ _ts_metadata8("design:paramtypes", [
7494
7681
  Object
7495
7682
  ]),
7496
- _ts_metadata6("design:returntype", Promise)
7683
+ _ts_metadata8("design:returntype", Promise)
7497
7684
  ], DevResourcesController.prototype, "pull", null);
7498
- _ts_decorate6([
7499
- (0, import_common20.Post)("sync"),
7685
+ _ts_decorate8([
7686
+ (0, import_common22.Post)("sync"),
7500
7687
  (0, import_swagger12.ApiOperation)({
7501
7688
  summary: "Dev-only: generate or update a single resource.json from its DB model, using recommended defaults (non-interactive)"
7502
7689
  }),
@@ -7504,15 +7691,15 @@ _ts_decorate6([
7504
7691
  status: 200,
7505
7692
  description: "Files written for this resource"
7506
7693
  }),
7507
- _ts_param2(0, (0, import_common20.Body)()),
7508
- _ts_metadata6("design:type", Function),
7509
- _ts_metadata6("design:paramtypes", [
7694
+ _ts_param2(0, (0, import_common22.Body)()),
7695
+ _ts_metadata8("design:type", Function),
7696
+ _ts_metadata8("design:paramtypes", [
7510
7697
  Object
7511
7698
  ]),
7512
- _ts_metadata6("design:returntype", Promise)
7699
+ _ts_metadata8("design:returntype", Promise)
7513
7700
  ], DevResourcesController.prototype, "sync", null);
7514
- _ts_decorate6([
7515
- (0, import_common20.Post)("plan"),
7701
+ _ts_decorate8([
7702
+ (0, import_common22.Post)("plan"),
7516
7703
  (0, import_swagger12.ApiOperation)({
7517
7704
  summary: "Dev-only: dry-run introspect + diff across all (or selected) DB models using recommended defaults \u2014 computes what would change, writes nothing"
7518
7705
  }),
@@ -7520,15 +7707,15 @@ _ts_decorate6([
7520
7707
  status: 200,
7521
7708
  description: "Proposed per-resource changes"
7522
7709
  }),
7523
- _ts_param2(0, (0, import_common20.Body)()),
7524
- _ts_metadata6("design:type", Function),
7525
- _ts_metadata6("design:paramtypes", [
7710
+ _ts_param2(0, (0, import_common22.Body)()),
7711
+ _ts_metadata8("design:type", Function),
7712
+ _ts_metadata8("design:paramtypes", [
7526
7713
  Object
7527
7714
  ]),
7528
- _ts_metadata6("design:returntype", Promise)
7715
+ _ts_metadata8("design:returntype", Promise)
7529
7716
  ], DevResourcesController.prototype, "plan", null);
7530
- _ts_decorate6([
7531
- (0, import_common20.Post)("apply"),
7717
+ _ts_decorate8([
7718
+ (0, import_common22.Post)("apply"),
7532
7719
  (0, import_swagger12.ApiOperation)({
7533
7720
  summary: "Dev-only: commit resource.json/schema.ts changes to disk for the given resources (or all, if omitted), using recommended defaults"
7534
7721
  }),
@@ -7536,15 +7723,15 @@ _ts_decorate6([
7536
7723
  status: 200,
7537
7724
  description: "Per-resource commit results"
7538
7725
  }),
7539
- _ts_param2(0, (0, import_common20.Body)()),
7540
- _ts_metadata6("design:type", Function),
7541
- _ts_metadata6("design:paramtypes", [
7726
+ _ts_param2(0, (0, import_common22.Body)()),
7727
+ _ts_metadata8("design:type", Function),
7728
+ _ts_metadata8("design:paramtypes", [
7542
7729
  Object
7543
7730
  ]),
7544
- _ts_metadata6("design:returntype", Promise)
7731
+ _ts_metadata8("design:returntype", Promise)
7545
7732
  ], DevResourcesController.prototype, "apply", null);
7546
- _ts_decorate6([
7547
- (0, import_common20.Get)("visibility"),
7733
+ _ts_decorate8([
7734
+ (0, import_common22.Get)("visibility"),
7548
7735
  (0, import_swagger12.ApiOperation)({
7549
7736
  summary: "Dev-only: list all resources with their menu visibility state (in-menu, hidden, draft, error)"
7550
7737
  }),
@@ -7552,12 +7739,12 @@ _ts_decorate6([
7552
7739
  status: 200,
7553
7740
  description: "Resource visibility list"
7554
7741
  }),
7555
- _ts_metadata6("design:type", Function),
7556
- _ts_metadata6("design:paramtypes", []),
7557
- _ts_metadata6("design:returntype", Promise)
7742
+ _ts_metadata8("design:type", Function),
7743
+ _ts_metadata8("design:paramtypes", []),
7744
+ _ts_metadata8("design:returntype", Promise)
7558
7745
  ], DevResourcesController.prototype, "visibility", null);
7559
- _ts_decorate6([
7560
- (0, import_common20.Post)(":name/publish"),
7746
+ _ts_decorate8([
7747
+ (0, import_common22.Post)(":name/publish"),
7561
7748
  (0, import_swagger12.ApiOperation)({
7562
7749
  summary: "Dev-only: publish a draft resource (removes `draft: true` from resource.json)"
7563
7750
  }),
@@ -7565,15 +7752,15 @@ _ts_decorate6([
7565
7752
  status: 200,
7566
7753
  description: "Resource published"
7567
7754
  }),
7568
- _ts_param2(0, (0, import_common20.Param)("name")),
7569
- _ts_metadata6("design:type", Function),
7570
- _ts_metadata6("design:paramtypes", [
7755
+ _ts_param2(0, (0, import_common22.Param)("name")),
7756
+ _ts_metadata8("design:type", Function),
7757
+ _ts_metadata8("design:paramtypes", [
7571
7758
  String
7572
7759
  ]),
7573
- _ts_metadata6("design:returntype", Promise)
7760
+ _ts_metadata8("design:returntype", Promise)
7574
7761
  ], DevResourcesController.prototype, "publish", null);
7575
- _ts_decorate6([
7576
- (0, import_common20.Post)(":name/remove-from-menu"),
7762
+ _ts_decorate8([
7763
+ (0, import_common22.Post)(":name/remove-from-menu"),
7577
7764
  (0, import_swagger12.ApiOperation)({
7578
7765
  summary: "Dev-only: hide a resource from the sidebar menu (sets `sidebar.hide: true` in resource.json)"
7579
7766
  }),
@@ -7581,15 +7768,15 @@ _ts_decorate6([
7581
7768
  status: 200,
7582
7769
  description: "Resource removed from menu"
7583
7770
  }),
7584
- _ts_param2(0, (0, import_common20.Param)("name")),
7585
- _ts_metadata6("design:type", Function),
7586
- _ts_metadata6("design:paramtypes", [
7771
+ _ts_param2(0, (0, import_common22.Param)("name")),
7772
+ _ts_metadata8("design:type", Function),
7773
+ _ts_metadata8("design:paramtypes", [
7587
7774
  String
7588
7775
  ]),
7589
- _ts_metadata6("design:returntype", Promise)
7776
+ _ts_metadata8("design:returntype", Promise)
7590
7777
  ], DevResourcesController.prototype, "removeFromMenu", null);
7591
- _ts_decorate6([
7592
- (0, import_common20.Post)(":name/add-to-menu"),
7778
+ _ts_decorate8([
7779
+ (0, import_common22.Post)(":name/add-to-menu"),
7593
7780
  (0, import_swagger12.ApiOperation)({
7594
7781
  summary: "Dev-only: publish + un-hide a resource and optionally set sidebar group/position/label"
7595
7782
  }),
@@ -7597,17 +7784,17 @@ _ts_decorate6([
7597
7784
  status: 200,
7598
7785
  description: "Resource added to menu"
7599
7786
  }),
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", [
7787
+ _ts_param2(0, (0, import_common22.Param)("name")),
7788
+ _ts_param2(1, (0, import_common22.Body)()),
7789
+ _ts_metadata8("design:type", Function),
7790
+ _ts_metadata8("design:paramtypes", [
7604
7791
  String,
7605
7792
  Object
7606
7793
  ]),
7607
- _ts_metadata6("design:returntype", Promise)
7794
+ _ts_metadata8("design:returntype", Promise)
7608
7795
  ], DevResourcesController.prototype, "addToMenu", null);
7609
- _ts_decorate6([
7610
- (0, import_common20.Patch)(":name/flags"),
7796
+ _ts_decorate8([
7797
+ (0, import_common22.Patch)(":name/flags"),
7611
7798
  (0, import_swagger12.ApiOperation)({
7612
7799
  summary: "Dev-only: set arbitrary resource flags (draft, sidebar.hide, group, position, label)"
7613
7800
  }),
@@ -7615,32 +7802,32 @@ _ts_decorate6([
7615
7802
  status: 200,
7616
7803
  description: "Flags updated"
7617
7804
  }),
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", [
7805
+ _ts_param2(0, (0, import_common22.Param)("name")),
7806
+ _ts_param2(1, (0, import_common22.Body)()),
7807
+ _ts_metadata8("design:type", Function),
7808
+ _ts_metadata8("design:paramtypes", [
7622
7809
  String,
7623
7810
  typeof ResourceFlagPatch === "undefined" ? Object : ResourceFlagPatch
7624
7811
  ]),
7625
- _ts_metadata6("design:returntype", Promise)
7812
+ _ts_metadata8("design:returntype", Promise)
7626
7813
  ], DevResourcesController.prototype, "updateFlags", null);
7627
- DevResourcesController = _ts_decorate6([
7628
- (0, import_common20.Controller)("_app/resources"),
7814
+ DevResourcesController = _ts_decorate8([
7815
+ (0, import_common22.Controller)("_app/resources"),
7629
7816
  (0, import_swagger12.ApiTags)("Dev tools"),
7630
- _ts_metadata6("design:type", Function),
7631
- _ts_metadata6("design:paramtypes", [
7817
+ _ts_metadata8("design:type", Function),
7818
+ _ts_metadata8("design:paramtypes", [
7632
7819
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
7633
7820
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
7634
7821
  ])
7635
7822
  ], DevResourcesController);
7636
7823
 
7637
7824
  // 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()
7825
+ var import_zod32 = require("zod");
7826
+ var EnumEntrySchema = import_zod32.z.object({
7827
+ value: import_zod32.z.unknown(),
7828
+ label: import_zod32.z.string()
7642
7829
  });
7643
- var EnumRegistrySchema = import_zod31.z.record(import_zod31.z.string(), import_zod31.z.array(EnumEntrySchema)).default({});
7830
+ var EnumRegistrySchema = import_zod32.z.record(import_zod32.z.string(), import_zod32.z.array(EnumEntrySchema)).default({});
7644
7831
 
7645
7832
  // src/lib/crud/enum-registry/enum-registry.loader.ts
7646
7833
  var import_node_fs8 = require("fs");
@@ -7722,9 +7909,9 @@ var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
7722
7909
  }, "upsertOp");
7723
7910
 
7724
7911
  // src/lib/crud/adapter/relation-type.ts
7725
- var import_zod32 = require("zod");
7912
+ var import_zod33 = require("zod");
7726
7913
  var unwrapZodType = /* @__PURE__ */ __name((type) => {
7727
- if (type instanceof import_zod32.ZodOptional || type instanceof import_zod32.ZodNullable) {
7914
+ if (type instanceof import_zod33.ZodOptional || type instanceof import_zod33.ZodNullable) {
7728
7915
  return unwrapZodType(type.unwrap());
7729
7916
  }
7730
7917
  return type;
@@ -7734,7 +7921,7 @@ var deriveRelationType = /* @__PURE__ */ __name((schema, columnId) => {
7734
7921
  const field = schema.shape[columnId];
7735
7922
  if (!field) return void 0;
7736
7923
  const inner = unwrapZodType(field);
7737
- return inner instanceof import_zod32.ZodArray ? "oneToMany" : "manyToOne";
7924
+ return inner instanceof import_zod33.ZodArray ? "oneToMany" : "manyToOne";
7738
7925
  }, "deriveRelationType");
7739
7926
  var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
7740
7927
  const base = col.column ?? col.id;
@@ -8541,9 +8728,9 @@ var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumReg
8541
8728
  }, "buildStatus");
8542
8729
 
8543
8730
  // src/lib/crud/status/status.controller.ts
8544
- var import_common21 = require("@nestjs/common");
8731
+ var import_common23 = require("@nestjs/common");
8545
8732
  var import_swagger13 = require("@nestjs/swagger");
8546
- function _ts_decorate7(decorators, target, key, desc2) {
8733
+ function _ts_decorate9(decorators, target, key, desc2) {
8547
8734
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8548
8735
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8549
8736
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -8556,13 +8743,13 @@ function _ts_decorate7(decorators, target, key, desc2) {
8556
8743
  }
8557
8744
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8558
8745
  }
8559
- __name(_ts_decorate7, "_ts_decorate");
8560
- function _ts_metadata7(metadataKey, metadataValue) {
8746
+ __name(_ts_decorate9, "_ts_decorate");
8747
+ function _ts_metadata9(metadataKey, metadataValue) {
8561
8748
  if (typeof Reflect === "object" && typeof Reflect.metadata === "function") {
8562
8749
  return Reflect.metadata(metadataKey, metadataValue);
8563
8750
  }
8564
8751
  }
8565
- __name(_ts_metadata7, "_ts_metadata");
8752
+ __name(_ts_metadata9, "_ts_metadata");
8566
8753
  var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRegistry) => {
8567
8754
  let StatusController = class StatusController {
8568
8755
  static {
@@ -8579,8 +8766,8 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8579
8766
  return buildStatus(this.dataSourceRegistry, configs, enumRegistry, translationRegistry);
8580
8767
  }
8581
8768
  };
8582
- _ts_decorate7([
8583
- (0, import_common21.Get)("status.json"),
8769
+ _ts_decorate9([
8770
+ (0, import_common23.Get)("status.json"),
8584
8771
  (0, import_swagger13.ApiOperation)({
8585
8772
  summary: "Crouton system status (db, resources, version)"
8586
8773
  }),
@@ -8588,15 +8775,15 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8588
8775
  status: 200,
8589
8776
  description: "System status"
8590
8777
  }),
8591
- _ts_metadata7("design:type", Function),
8592
- _ts_metadata7("design:paramtypes", []),
8593
- _ts_metadata7("design:returntype", Promise)
8778
+ _ts_metadata9("design:type", Function),
8779
+ _ts_metadata9("design:paramtypes", []),
8780
+ _ts_metadata9("design:returntype", Promise)
8594
8781
  ], StatusController.prototype, "getStatus", null);
8595
- StatusController = _ts_decorate7([
8596
- (0, import_common21.Controller)("crouton"),
8782
+ StatusController = _ts_decorate9([
8783
+ (0, import_common23.Controller)("crouton"),
8597
8784
  (0, import_swagger13.ApiTags)("Status"),
8598
- _ts_metadata7("design:type", Function),
8599
- _ts_metadata7("design:paramtypes", [
8785
+ _ts_metadata9("design:type", Function),
8786
+ _ts_metadata9("design:paramtypes", [
8600
8787
  typeof DataSourceRegistry === "undefined" ? Object : DataSourceRegistry,
8601
8788
  typeof ResourceConfigRegistry === "undefined" ? Object : ResourceConfigRegistry
8602
8789
  ])
@@ -8611,7 +8798,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
8611
8798
  // src/lib/crouton-api.module.ts
8612
8799
  var import_node_path20 = require("path");
8613
8800
  var import_node_url2 = require("url");
8614
- function _ts_decorate8(decorators, target, key, desc2) {
8801
+ function _ts_decorate10(decorators, target, key, desc2) {
8615
8802
  var c = arguments.length, r = c < 3 ? target : desc2 === null ? desc2 = Object.getOwnPropertyDescriptor(target, key) : desc2, d;
8616
8803
  if (typeof Reflect === "object" && typeof Reflect.decorate === "function") {
8617
8804
  r = Reflect.decorate(decorators, target, key, desc2);
@@ -8624,7 +8811,7 @@ function _ts_decorate8(decorators, target, key, desc2) {
8624
8811
  }
8625
8812
  return c > 3 && r && Object.defineProperty(target, key, r), r;
8626
8813
  }
8627
- __name(_ts_decorate8, "_ts_decorate");
8814
+ __name(_ts_decorate10, "_ts_decorate");
8628
8815
  var CroutonApiModule = class _CroutonApiModule {
8629
8816
  static {
8630
8817
  __name(this, "CroutonApiModule");
@@ -8636,8 +8823,11 @@ var CroutonApiModule = class _CroutonApiModule {
8636
8823
  };
8637
8824
  }
8638
8825
  }
8639
- static forResources(configs, dataSources, loader, { baseUrl }, config) {
8826
+ static forResources(configs, dataSources, loader, appConfig, config) {
8827
+ const { baseUrl, security } = appConfig;
8640
8828
  const dataSourceRegistry = new DataSourceRegistry(dataSources);
8829
+ const guardRegistry = new SecurityGuardRegistry2(security?.guards ?? {});
8830
+ const moduleDefaultSecurity = security?.default;
8641
8831
  const startDir = typeof __dirname !== "undefined" ? __dirname : (0, import_node_path20.dirname)((0, import_node_url2.fileURLToPath)(importMetaUrl));
8642
8832
  const enumRegistry = loadEnumRegistry(startDir, config.enumsFile);
8643
8833
  const validConfigs = [];
@@ -8690,12 +8880,12 @@ var CroutonApiModule = class _CroutonApiModule {
8690
8880
  const configRegistry = new ResourceConfigRegistry(loader, validConfigs);
8691
8881
  let translationRegistry;
8692
8882
  if (config.i18n) {
8693
- const translationsDir = (0, import_node_path20.join)(process.cwd(), config.i18n.translationsDir);
8883
+ const translationsDir = (0, import_node_path20.join)(config.configDir, config.i18n.translationsDir);
8694
8884
  translationRegistry = new TranslationRegistry2(translationsDir, config.i18n);
8695
8885
  configRegistry.setTranslationRegistry(translationRegistry);
8696
8886
  }
8697
8887
  const controllers = [
8698
- ...validConfigs.map((c) => createCrudController(c, baseUrl)),
8888
+ ...validConfigs.map((c) => createCrudController(c, baseUrl, moduleDefaultSecurity)),
8699
8889
  createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true, translationRegistry, config.i18n),
8700
8890
  // Only registered (and thus only visible in Swagger/routing) when the
8701
8891
  // visual resource builder is enabled — see dev-resources.controller.ts.
@@ -8720,6 +8910,12 @@ var CroutonApiModule = class _CroutonApiModule {
8720
8910
  provide: ResourceConfigRegistry,
8721
8911
  useValue: configRegistry
8722
8912
  },
8913
+ {
8914
+ provide: SecurityGuardRegistry2,
8915
+ useValue: guardRegistry
8916
+ },
8917
+ CroutonSecurityGuard,
8918
+ ...guardRegistry.classes(),
8723
8919
  ...translationRegistry ? [
8724
8920
  {
8725
8921
  provide: TranslationRegistry2,
@@ -8733,22 +8929,20 @@ var CroutonApiModule = class _CroutonApiModule {
8733
8929
  ]
8734
8930
  };
8735
8931
  }
8736
- static async forResourceDir(dirPath, dataSourcesPath, { baseUrl }) {
8932
+ static async forResourceDir(dirPath, dataSourcesPath, appConfig) {
8737
8933
  const config = await loadConfig();
8738
- const loader = new FileSystemResourceConfigLoader(dirPath, baseUrl, config.enumsFile);
8739
- const configs = await loadResourceConfigsFromDir(dirPath, baseUrl, config.enumsFile);
8934
+ const loader = new FileSystemResourceConfigLoader(dirPath, appConfig.baseUrl, config.enumsFile);
8935
+ const configs = await loadResourceConfigsFromDir(dirPath, appConfig.baseUrl, config.enumsFile);
8740
8936
  const dataSources = await loadDataSourcesFromDir(dataSourcesPath);
8741
- return _CroutonApiModule.forResources(configs, dataSources, loader, {
8742
- baseUrl
8743
- }, config);
8937
+ return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
8744
8938
  }
8745
8939
  static async forLoader(loader, configs, dataSources, appConfig) {
8746
8940
  const config = await loadConfig();
8747
8941
  return _CroutonApiModule.forResources(configs, dataSources, loader, appConfig, config);
8748
8942
  }
8749
8943
  };
8750
- CroutonApiModule = _ts_decorate8([
8751
- (0, import_common22.Module)({
8944
+ CroutonApiModule = _ts_decorate10([
8945
+ (0, import_common24.Module)({
8752
8946
  controllers: [],
8753
8947
  providers: [],
8754
8948
  exports: []
@@ -8756,13 +8950,16 @@ CroutonApiModule = _ts_decorate8([
8756
8950
  ], CroutonApiModule);
8757
8951
  // Annotate the CommonJS export names for ESM import in node:
8758
8952
  0 && (module.exports = {
8953
+ CROUTON_SECURITY,
8759
8954
  CroutonApiModule,
8955
+ CroutonSecurityGuard,
8760
8956
  DataSourceRegistry,
8761
8957
  FileSystemResourceConfigLoader,
8762
8958
  ReadOpSchema,
8763
8959
  ResourceConfigLoader,
8764
8960
  ResourceConfigRegistry,
8765
8961
  ResourceHooksSchema,
8962
+ SecurityGuardRegistry,
8766
8963
  WriteOpSchema,
8767
8964
  buildFilterWhere,
8768
8965
  buildViews,
@@ -8780,6 +8977,8 @@ CroutonApiModule = _ts_decorate8([
8780
8977
  prepareWrite,
8781
8978
  resolveDefinition,
8782
8979
  schemaFor,
8980
+ securityFor,
8981
+ securityForSub,
8783
8982
  upsertOnFor
8784
8983
  });
8785
8984
  //# sourceMappingURL=index.cjs.map