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

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
@@ -672,228 +672,105 @@ var init_table_utils = __esm({
672
672
  }
673
673
  });
674
674
 
675
- // ../crouton-core/src/lib/data-source/DataSourceSchema.ts
676
- var import_zod7, DataSourceShape, transformDataSource, DataSourceSchema;
677
- var init_DataSourceSchema = __esm({
678
- "../crouton-core/src/lib/data-source/DataSourceSchema.ts"() {
675
+ // ../crouton-core/src/lib/compile/action.types.ts
676
+ var import_zod7, ActionMetadataSchema, ResourceLinkActionSchema, ResourceRowProcedureActionSchema, ResourceTableProcedureActionSchema, ResourceRowActionSchema, ResourceTableActionSchema;
677
+ var init_action_types = __esm({
678
+ "../crouton-core/src/lib/compile/action.types.ts"() {
679
679
  "use strict";
680
680
  init_cjs_shims();
681
- import_zod7 = __toESM(require("zod"), 1);
682
- DataSourceShape = import_zod7.default.object({
683
- /** Datasource name (folder + `name` in data-source.json). */
684
- name: import_zod7.default.string(),
685
- /**
686
- * Env var holding the connection URL. Required for Prisma adapters; optional
687
- * for custom adapters whose connection config may differ (secrets file, SDK
688
- * key, etc.).
689
- */
690
- urlEnv: import_zod7.default.string().optional(),
691
- /** Import path for this datasource's generated Zod types (for resource `schema.ts`). */
692
- generatedTypesImport: import_zod7.default.string().optional(),
693
- /** Datasource type tag. Default `postgres`. */
694
- type: import_zod7.default.string().default("postgres"),
695
- /** Mark this as the default datasource. Default `false`. */
696
- default: import_zod7.default.boolean().default(false),
697
- /**
698
- * Adapter kind. `"prisma"` (default) expects `index.ts` to default-export a
699
- * `PrismaClient`; `"custom"` expects it to default-export a `DataSourceAdapter`.
700
- */
701
- adapter: import_zod7.default.enum([
702
- "prisma",
703
- "custom"
704
- ]).default("prisma"),
705
- /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */
706
- prismaSchema: import_zod7.default.string().optional(),
707
- /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */
708
- prismaConfig: import_zod7.default.string().optional(),
709
- /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */
710
- zodOutput: import_zod7.default.string().optional(),
711
- /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */
712
- clientOutput: import_zod7.default.string().optional()
681
+ import_zod7 = require("zod");
682
+ ActionMetadataSchema = import_zod7.z.object({
683
+ id: import_zod7.z.string(),
684
+ label: import_zod7.z.string().optional(),
685
+ icon: import_zod7.z.string().optional(),
686
+ tooltip: import_zod7.z.string().optional(),
687
+ condition: import_zod7.z.custom().optional()
713
688
  });
714
- transformDataSource = /* @__PURE__ */ __name((data) => {
715
- const name = data.name ?? "name";
716
- return {
717
- ...data,
718
- generatedTypesImport: data.generatedTypesImport ?? `@your-scope/generated/${name}`,
719
- prismaSchema: data.prismaSchema ?? `prisma/${name}/schema.prisma`,
720
- prismaConfig: data.prismaConfig ?? `prisma/${name}/prisma.config.ts`,
721
- zodOutput: data.zodOutput ?? `generated/${name}/src`,
722
- clientOutput: data.clientOutput ?? `generated/${name}/client`
723
- };
724
- }, "transformDataSource");
725
- DataSourceSchema = DataSourceShape.transform(transformDataSource);
726
- }
727
- });
728
-
729
- // ../crouton-core/src/lib/data-source/Security.schema.ts
730
- var import_zod8, SecuritySchema;
731
- var init_Security_schema = __esm({
732
- "../crouton-core/src/lib/data-source/Security.schema.ts"() {
733
- "use strict";
734
- init_cjs_shims();
735
- import_zod8 = require("zod");
736
- SecuritySchema = import_zod8.z.union([
737
- import_zod8.z.object({
738
- public: import_zod8.z.literal(true)
739
- }),
740
- import_zod8.z.object({
741
- guard: import_zod8.z.union([
742
- import_zod8.z.string(),
743
- import_zod8.z.array(import_zod8.z.string()).min(1)
744
- ])
745
- })
746
- ]);
747
- }
748
- });
749
-
750
- // ../crouton-core/src/lib/data-source/Operations.schema.ts
751
- var import_zod9, OpEntry, BoolOrUpsertSchema, JsonOperationsSchema, buildSubResourceOperations;
752
- var init_Operations_schema = __esm({
753
- "../crouton-core/src/lib/data-source/Operations.schema.ts"() {
754
- "use strict";
755
- init_cjs_shims();
756
- import_zod9 = require("zod");
757
- init_Security_schema();
758
- OpEntry = import_zod9.z.union([
759
- import_zod9.z.boolean(),
760
- import_zod9.z.object({
761
- security: SecuritySchema.optional()
762
- })
689
+ ResourceLinkActionSchema = ActionMetadataSchema.extend({
690
+ type: import_zod7.z.literal("link"),
691
+ href: import_zod7.z.string()
692
+ });
693
+ ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
694
+ type: import_zod7.z.literal("procedure").optional(),
695
+ method: import_zod7.z.string().optional(),
696
+ data: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).optional(),
697
+ procedure: import_zod7.z.custom((v) => typeof v === "function")
698
+ });
699
+ ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
700
+ type: import_zod7.z.literal("procedure").optional(),
701
+ method: import_zod7.z.string().optional(),
702
+ data: import_zod7.z.record(import_zod7.z.string(), import_zod7.z.unknown()).optional(),
703
+ procedure: import_zod7.z.custom((v) => typeof v === "function")
704
+ });
705
+ ResourceRowActionSchema = import_zod7.z.union([
706
+ ResourceRowProcedureActionSchema,
707
+ ResourceLinkActionSchema
763
708
  ]);
764
- BoolOrUpsertSchema = import_zod9.z.union([
765
- import_zod9.z.boolean(),
766
- import_zod9.z.object({
767
- upsertOn: import_zod9.z.union([
768
- import_zod9.z.string(),
769
- import_zod9.z.array(import_zod9.z.string())
770
- ]),
771
- security: SecuritySchema.optional()
772
- })
709
+ ResourceTableActionSchema = import_zod7.z.union([
710
+ ResourceTableProcedureActionSchema,
711
+ ResourceLinkActionSchema
773
712
  ]);
774
- JsonOperationsSchema = import_zod9.z.object({
775
- findAll: OpEntry.default(true),
776
- findOne: OpEntry.default(true),
777
- create: OpEntry.default(true),
778
- update: OpEntry.default(true),
779
- patch: OpEntry.default(true),
780
- upsert: BoolOrUpsertSchema.default(false),
781
- delete: OpEntry.default(true)
782
- });
783
- buildSubResourceOperations = /* @__PURE__ */ __name((ops, baseUri, idField = "id") => {
784
- if (!ops) return {};
785
- const idPlaceholder = `{${idField}}`;
786
- return {
787
- ...ops.findAll && {
788
- findAll: {
789
- uri: baseUri,
790
- method: "get"
791
- }
792
- },
793
- ...ops.findOne && {
794
- findOne: {
795
- uri: `${baseUri}/${idPlaceholder}`,
796
- method: "get"
797
- }
798
- },
799
- ...ops.create && {
800
- create: {
801
- uri: baseUri,
802
- method: "post"
803
- }
804
- },
805
- ...ops.update && {
806
- update: {
807
- uri: `${baseUri}/${idPlaceholder}`,
808
- method: "put"
809
- }
810
- },
811
- ...ops.patch && {
812
- patch: {
813
- uri: `${baseUri}/${idPlaceholder}`,
814
- method: "patch"
815
- }
816
- },
817
- ...ops.delete && {
818
- delete: {
819
- uri: `${baseUri}/${idPlaceholder}`,
820
- method: "delete"
821
- }
822
- }
823
- };
824
- }, "buildSubResourceOperations");
825
- }
826
- });
827
-
828
- // ../crouton-core/src/lib/data-source/index.ts
829
- var init_data_source = __esm({
830
- "../crouton-core/src/lib/data-source/index.ts"() {
831
- "use strict";
832
- init_cjs_shims();
833
- init_DataSourceSchema();
834
- init_Operations_schema();
835
- init_Security_schema();
836
713
  }
837
714
  });
838
715
 
839
716
  // ../crouton-core/src/lib/resource/FieldInput.schema.ts
840
- var import_zod10, RelationType, DetailControlSchema, DetailConfigSchema, RelationFieldInputOptionsSchema, FieldInputSchema, FieldVariantSchema, stripNull, mergeFieldVariant;
717
+ var import_zod8, RelationType, DetailControlSchema, DetailConfigSchema, RelationFieldInputOptionsSchema, FieldInputSchema, FieldVariantSchema, stripNull, mergeFieldVariant;
841
718
  var init_FieldInput_schema = __esm({
842
719
  "../crouton-core/src/lib/resource/FieldInput.schema.ts"() {
843
720
  "use strict";
844
721
  init_cjs_shims();
845
- import_zod10 = require("zod");
846
- RelationType = import_zod10.z.enum([
722
+ import_zod8 = require("zod");
723
+ RelationType = import_zod8.z.enum([
847
724
  "oneToOne",
848
725
  "manyToOne",
849
726
  "oneToMany",
850
727
  "manyToMany"
851
728
  ]);
852
- DetailControlSchema = import_zod10.z.object({
853
- property: import_zod10.z.string(),
854
- type: import_zod10.z.string().optional(),
855
- options: import_zod10.z.record(import_zod10.z.string(), import_zod10.z.unknown()).optional(),
856
- hideLabel: import_zod10.z.boolean().optional(),
857
- width: import_zod10.z.string().optional()
729
+ DetailControlSchema = import_zod8.z.object({
730
+ property: import_zod8.z.string(),
731
+ type: import_zod8.z.string().optional(),
732
+ options: import_zod8.z.record(import_zod8.z.string(), import_zod8.z.unknown()).optional(),
733
+ hideLabel: import_zod8.z.boolean().optional(),
734
+ width: import_zod8.z.string().optional()
858
735
  });
859
- DetailConfigSchema = import_zod10.z.object({
860
- layout: import_zod10.z.enum([
736
+ DetailConfigSchema = import_zod8.z.object({
737
+ layout: import_zod8.z.enum([
861
738
  "collapse",
862
739
  "row"
863
740
  ]),
864
- titleKey: import_zod10.z.string().optional(),
865
- controls: import_zod10.z.array(DetailControlSchema)
741
+ titleKey: import_zod8.z.string().optional(),
742
+ controls: import_zod8.z.array(DetailControlSchema)
866
743
  });
867
- RelationFieldInputOptionsSchema = import_zod10.z.object({
868
- colspan: import_zod10.z.number().optional().default(12),
744
+ RelationFieldInputOptionsSchema = import_zod8.z.object({
745
+ colspan: import_zod8.z.number().optional().default(12),
869
746
  /** Field to sort related records by, e.g. `"title"` or `"author.name"`. */
870
- sort: import_zod10.z.string().optional(),
747
+ sort: import_zod8.z.string().optional(),
871
748
  /** Sort direction. Defaults to `"asc"` when omitted. */
872
- sortDir: import_zod10.z.enum([
749
+ sortDir: import_zod8.z.enum([
873
750
  "asc",
874
751
  "desc"
875
752
  ]).optional(),
876
753
  /** CSS flex direction for the relation control button layout. */
877
- direction: import_zod10.z.string().optional(),
754
+ direction: import_zod8.z.string().optional(),
878
755
  /** Key used as the display label in the relation control. */
879
- displayKey: import_zod10.z.string().optional(),
756
+ displayKey: import_zod8.z.string().optional(),
880
757
  /** Path to the related resource (resolved to a URI at load time). */
881
- resource: import_zod10.z.string().optional()
882
- }).catchall(import_zod10.z.unknown());
883
- FieldInputSchema = import_zod10.z.object({
884
- type: import_zod10.z.string().optional(),
885
- customRender: import_zod10.z.string().optional(),
758
+ resource: import_zod8.z.string().optional()
759
+ }).catchall(import_zod8.z.unknown());
760
+ FieldInputSchema = import_zod8.z.object({
761
+ type: import_zod8.z.string().optional(),
762
+ customRender: import_zod8.z.string().optional(),
886
763
  /**
887
764
  * Render format hint for the frontend (e.g. `"relation"` for sub-resource
888
765
  * relations). When `format` is `"relation"`, `resource` must also be set.
889
766
  */
890
- format: import_zod10.z.string().optional(),
767
+ format: import_zod8.z.string().optional(),
891
768
  /**
892
769
  * Relative path to the child resource definition, e.g. `"./author.resource"`.
893
770
  * Only used when `format` is `"relation"`. Resolved at load time to inject
894
771
  * sub-resource URIs into `options`.
895
772
  */
896
- resource: import_zod10.z.string().optional(),
773
+ resource: import_zod8.z.string().optional(),
897
774
  /**
898
775
  * Cardinality of the relation. Used by the frontend to determine the correct
899
776
  * renderer and behaviour (e.g. single-select vs multi-select).
@@ -902,11 +779,11 @@ var init_FieldInput_schema = __esm({
902
779
  */
903
780
  relationType: RelationType.optional(),
904
781
  /** FK field on the child model pointing back to the parent, e.g. `"workId"`. Defaults to `${parentModel}Id`. */
905
- foreignKey: import_zod10.z.string().optional(),
782
+ foreignKey: import_zod8.z.string().optional(),
906
783
  /** Override the Prisma relation field name when it differs from the column id. */
907
- relation: import_zod10.z.string().optional(),
784
+ relation: import_zod8.z.string().optional(),
908
785
  /** Override the display order in form views. Lower values come first. */
909
- position: import_zod10.z.number().optional(),
786
+ position: import_zod8.z.number().optional(),
910
787
  /**
911
788
  * Value to pre-fill this field with on the create form. Injected into the
912
789
  * generated form view's JSON Schema as `properties[id].default`, which
@@ -914,10 +791,10 @@ var init_FieldInput_schema = __esm({
914
791
  * opening a blank record. Not applicable to `format: "relation"` fields —
915
792
  * relation columns are excluded from the picked data schema entirely.
916
793
  */
917
- defaultValue: import_zod10.z.unknown().optional(),
918
- options: import_zod10.z.union([
794
+ defaultValue: import_zod8.z.unknown().optional(),
795
+ options: import_zod8.z.union([
919
796
  RelationFieldInputOptionsSchema,
920
- import_zod10.z.unknown()
797
+ import_zod8.z.unknown()
921
798
  ]).optional(),
922
799
  /** Nested array detail layout (renders via `detailFixed`). */
923
800
  detail: DetailConfigSchema.optional()
@@ -967,24 +844,24 @@ var init_label_helper = __esm({
967
844
  });
968
845
 
969
846
  // ../crouton-core/src/lib/resource/CalculatedColumn.schema.ts
970
- var import_zod11, CalculatedColumnSchema;
847
+ var import_zod9, CalculatedColumnSchema;
971
848
  var init_CalculatedColumn_schema = __esm({
972
849
  "../crouton-core/src/lib/resource/CalculatedColumn.schema.ts"() {
973
850
  "use strict";
974
851
  init_cjs_shims();
975
- import_zod11 = require("zod");
852
+ import_zod9 = require("zod");
976
853
  init_FieldInput_schema();
977
854
  init_label_helper();
978
- CalculatedColumnSchema = import_zod11.z.object({
855
+ CalculatedColumnSchema = import_zod9.z.object({
979
856
  /** Column identifier used in the response payload and UI schema. */
980
- id: import_zod11.z.string(),
857
+ id: import_zod9.z.string(),
981
858
  /** SQL alias — must match `id`. */
982
- alias: import_zod11.z.string(),
859
+ alias: import_zod9.z.string(),
983
860
  /** Human-readable label shown in the table header. */
984
- label: import_zod11.z.string().optional(),
985
- sqlExpression: import_zod11.z.string(),
861
+ label: import_zod9.z.string().optional(),
862
+ sqlExpression: import_zod9.z.string(),
986
863
  /** JSON schema / cast type for the computed value. Defaults to `"number"`. `"string"` skips CAST. */
987
- type: import_zod11.z.enum([
864
+ type: import_zod9.z.enum([
988
865
  "number",
989
866
  "boolean",
990
867
  "string"
@@ -995,9 +872,9 @@ var init_CalculatedColumn_schema = __esm({
995
872
  * `position: N` places this column before the element currently at index N.
996
873
  * Can also be set via `fieldInput.position` (takes precedence).
997
874
  */
998
- position: import_zod11.z.number().optional(),
999
- hiddenInTable: import_zod11.z.boolean().optional(),
1000
- hiddenInView: import_zod11.z.boolean().optional(),
875
+ position: import_zod9.z.number().optional(),
876
+ hiddenInTable: import_zod9.z.boolean().optional(),
877
+ hiddenInView: import_zod9.z.boolean().optional(),
1001
878
  /**
1002
879
  * Field input options for rendering in form / view schemas.
1003
880
  * Supports `colspan`, `format`, and any other options passed to the Control renderer.
@@ -1009,13 +886,13 @@ var init_CalculatedColumn_schema = __esm({
1009
886
  });
1010
887
 
1011
888
  // ../crouton-core/src/lib/resource/ColumnType.schema.ts
1012
- var import_zod12, ColumnTypeShorthandSchema, JsonSchemaFragmentSchema, ColumnTypeSchema, SHORTHAND_FRAGMENTS, isShorthand, NESTED_SHORTHANDS, normalizeFragment, columnTypeToJsonSchema, columnTypeName, isObjectColumnType, isArrayColumnType;
889
+ var import_zod10, ColumnTypeShorthandSchema, JsonSchemaFragmentSchema, ColumnTypeSchema, SHORTHAND_FRAGMENTS, isShorthand, NESTED_SHORTHANDS, normalizeFragment, columnTypeToJsonSchema, columnTypeName, isObjectColumnType, isArrayColumnType;
1013
890
  var init_ColumnType_schema = __esm({
1014
891
  "../crouton-core/src/lib/resource/ColumnType.schema.ts"() {
1015
892
  "use strict";
1016
893
  init_cjs_shims();
1017
- import_zod12 = require("zod");
1018
- ColumnTypeShorthandSchema = import_zod12.z.enum([
894
+ import_zod10 = require("zod");
895
+ ColumnTypeShorthandSchema = import_zod10.z.enum([
1019
896
  "string",
1020
897
  "number",
1021
898
  "integer",
@@ -1025,32 +902,32 @@ var init_ColumnType_schema = __esm({
1025
902
  "object",
1026
903
  "array"
1027
904
  ]);
1028
- JsonSchemaFragmentSchema = import_zod12.z.lazy(() => import_zod12.z.object({
1029
- type: import_zod12.z.union([
1030
- import_zod12.z.string(),
1031
- import_zod12.z.array(import_zod12.z.string())
905
+ JsonSchemaFragmentSchema = import_zod10.z.lazy(() => import_zod10.z.object({
906
+ type: import_zod10.z.union([
907
+ import_zod10.z.string(),
908
+ import_zod10.z.array(import_zod10.z.string())
1032
909
  ]).optional(),
1033
- format: import_zod12.z.string().optional(),
1034
- enum: import_zod12.z.array(import_zod12.z.unknown()).optional(),
1035
- const: import_zod12.z.unknown().optional(),
1036
- nullable: import_zod12.z.boolean().optional(),
1037
- properties: import_zod12.z.record(import_zod12.z.string(), JsonSchemaFragmentSchema).optional(),
1038
- required: import_zod12.z.array(import_zod12.z.string()).optional(),
910
+ format: import_zod10.z.string().optional(),
911
+ enum: import_zod10.z.array(import_zod10.z.unknown()).optional(),
912
+ const: import_zod10.z.unknown().optional(),
913
+ nullable: import_zod10.z.boolean().optional(),
914
+ properties: import_zod10.z.record(import_zod10.z.string(), JsonSchemaFragmentSchema).optional(),
915
+ required: import_zod10.z.array(import_zod10.z.string()).optional(),
1039
916
  items: JsonSchemaFragmentSchema.optional(),
1040
- additionalProperties: import_zod12.z.union([
1041
- import_zod12.z.boolean(),
917
+ additionalProperties: import_zod10.z.union([
918
+ import_zod10.z.boolean(),
1042
919
  JsonSchemaFragmentSchema
1043
920
  ]).optional(),
1044
- title: import_zod12.z.string().optional(),
1045
- description: import_zod12.z.string().optional(),
1046
- default: import_zod12.z.unknown().optional(),
1047
- minimum: import_zod12.z.number().optional(),
1048
- maximum: import_zod12.z.number().optional(),
1049
- minLength: import_zod12.z.number().optional(),
1050
- maxLength: import_zod12.z.number().optional(),
1051
- pattern: import_zod12.z.string().optional()
1052
- }).catchall(import_zod12.z.unknown()));
1053
- ColumnTypeSchema = import_zod12.z.union([
921
+ title: import_zod10.z.string().optional(),
922
+ description: import_zod10.z.string().optional(),
923
+ default: import_zod10.z.unknown().optional(),
924
+ minimum: import_zod10.z.number().optional(),
925
+ maximum: import_zod10.z.number().optional(),
926
+ minLength: import_zod10.z.number().optional(),
927
+ maxLength: import_zod10.z.number().optional(),
928
+ pattern: import_zod10.z.string().optional()
929
+ }).catchall(import_zod10.z.unknown()));
930
+ ColumnTypeSchema = import_zod10.z.union([
1054
931
  ColumnTypeShorthandSchema,
1055
932
  JsonSchemaFragmentSchema
1056
933
  ]);
@@ -1134,48 +1011,48 @@ var init_ColumnType_schema = __esm({
1134
1011
  });
1135
1012
 
1136
1013
  // ../crouton-core/src/lib/resource/Column.ts
1137
- var import_zod13, WhenConditionSchema, JsonColumnSchema;
1014
+ var import_zod11, WhenConditionSchema, JsonColumnSchema;
1138
1015
  var init_Column = __esm({
1139
1016
  "../crouton-core/src/lib/resource/Column.ts"() {
1140
1017
  "use strict";
1141
1018
  init_cjs_shims();
1142
- import_zod13 = require("zod");
1019
+ import_zod11 = require("zod");
1143
1020
  init_ColumnType_schema();
1144
1021
  init_FieldInput_schema();
1145
- WhenConditionSchema = import_zod13.z.object({
1146
- field: import_zod13.z.string(),
1147
- eq: import_zod13.z.unknown().optional(),
1148
- neq: import_zod13.z.unknown().optional(),
1149
- exists: import_zod13.z.boolean().optional(),
1150
- notExists: import_zod13.z.boolean().optional()
1022
+ WhenConditionSchema = import_zod11.z.object({
1023
+ field: import_zod11.z.string(),
1024
+ eq: import_zod11.z.unknown().optional(),
1025
+ neq: import_zod11.z.unknown().optional(),
1026
+ exists: import_zod11.z.boolean().optional(),
1027
+ notExists: import_zod11.z.boolean().optional()
1151
1028
  });
1152
- JsonColumnSchema = import_zod13.z.object({
1153
- id: import_zod13.z.string(),
1154
- column: import_zod13.z.string().optional(),
1155
- label: import_zod13.z.string().optional(),
1156
- hiddenInTable: import_zod13.z.boolean().default(false),
1157
- hiddenInForm: import_zod13.z.boolean().default(false),
1158
- hiddenInView: import_zod13.z.boolean().default(false),
1159
- sortable: import_zod13.z.boolean().default(false),
1160
- defaultSort: import_zod13.z.boolean().default(false),
1161
- searchable: import_zod13.z.boolean().default(false),
1162
- filterable: import_zod13.z.boolean().default(false),
1163
- createable: import_zod13.z.boolean().default(true),
1164
- updateable: import_zod13.z.boolean().default(true),
1165
- hideLabel: import_zod13.z.boolean().default(false),
1029
+ JsonColumnSchema = import_zod11.z.object({
1030
+ id: import_zod11.z.string(),
1031
+ column: import_zod11.z.string().optional(),
1032
+ label: import_zod11.z.string().optional(),
1033
+ hiddenInTable: import_zod11.z.boolean().default(false),
1034
+ hiddenInForm: import_zod11.z.boolean().default(false),
1035
+ hiddenInView: import_zod11.z.boolean().default(false),
1036
+ sortable: import_zod11.z.boolean().default(false),
1037
+ defaultSort: import_zod11.z.boolean().default(false),
1038
+ searchable: import_zod11.z.boolean().default(false),
1039
+ filterable: import_zod11.z.boolean().default(false),
1040
+ createable: import_zod11.z.boolean().default(true),
1041
+ updateable: import_zod11.z.boolean().default(true),
1042
+ hideLabel: import_zod11.z.boolean().default(false),
1166
1043
  showWhen: WhenConditionSchema.optional(),
1167
1044
  hideWhen: WhenConditionSchema.optional(),
1168
1045
  disabledWhen: WhenConditionSchema.optional(),
1169
- displayKey: import_zod13.z.string().optional(),
1170
- sortId: import_zod13.z.string().optional(),
1046
+ displayKey: import_zod11.z.string().optional(),
1047
+ sortId: import_zod11.z.string().optional(),
1171
1048
  /**
1172
1049
  * Name of a shared enum in the project enum registry (`crouton.enums.json`).
1173
1050
  * At load time the loader injects that enum's `{ value, label }[]` into
1174
1051
  * `fieldInput.options.values`, so columns don't duplicate the option list.
1175
1052
  */
1176
- enum: import_zod13.z.string().optional(),
1177
- idField: import_zod13.z.boolean().default(false),
1178
- showInLookup: import_zod13.z.boolean().default(false),
1053
+ enum: import_zod11.z.string().optional(),
1054
+ idField: import_zod11.z.boolean().default(false),
1055
+ showInLookup: import_zod11.z.boolean().default(false),
1179
1056
  /**
1180
1057
  * Data type of the column, as a shorthand name (`"string"`, `"integer"`, …)
1181
1058
  * or a full JSON Schema fragment:
@@ -1206,12 +1083,12 @@ var init_Column = __esm({
1206
1083
  * Ignored on the id column and on columns that are neither createable nor
1207
1084
  * updateable, since the form cannot supply a value for those.
1208
1085
  */
1209
- required: import_zod13.z.boolean().optional(),
1086
+ required: import_zod11.z.boolean().optional(),
1210
1087
  /**
1211
1088
  * @deprecated Use `type` instead. Retained because it is still consumed by
1212
1089
  * the boolean predicate and the schema-less sub-resource view builder.
1213
1090
  */
1214
- columnType: import_zod13.z.string().default("string"),
1091
+ columnType: import_zod11.z.string().default("string"),
1215
1092
  fieldInput: FieldInputSchema.optional(),
1216
1093
  /**
1217
1094
  * Optional per-context override for the read-only VIEW ui. Same shape as
@@ -1235,34 +1112,34 @@ var init_Column = __esm({
1235
1112
  * Visibility (`hiddenInTable/Form/View`) on this column is inherited by all sub-columns as a
1236
1113
  * default; the referenced resource's own column visibility further restricts it.
1237
1114
  */
1238
- extend: import_zod13.z.string().optional(),
1115
+ extend: import_zod11.z.string().optional(),
1239
1116
  /**
1240
1117
  * Per-sub-column overrides when using `extend`.
1241
1118
  * Key: the virtual column id (`"{extendId}_{refColId}"`) or just the referenced column id.
1242
1119
  * Value: any `JsonColumn` fields to merge over the generated virtual column.
1243
1120
  */
1244
- columns: import_zod13.z.record(import_zod13.z.string(), import_zod13.z.record(import_zod13.z.string(), import_zod13.z.unknown())).optional()
1121
+ columns: import_zod11.z.record(import_zod11.z.string(), import_zod11.z.record(import_zod11.z.string(), import_zod11.z.unknown())).optional()
1245
1122
  });
1246
1123
  }
1247
1124
  });
1248
1125
 
1249
1126
  // ../crouton-core/src/lib/resource/ParentRef.schema.ts
1250
- var import_zod14, ParentRefSchema, resourceControllerPath;
1127
+ var import_zod12, ParentRefSchema, resourceControllerPath;
1251
1128
  var init_ParentRef_schema = __esm({
1252
1129
  "../crouton-core/src/lib/resource/ParentRef.schema.ts"() {
1253
1130
  "use strict";
1254
1131
  init_cjs_shims();
1255
- import_zod14 = require("zod");
1256
- ParentRefSchema = import_zod14.z.object({
1132
+ import_zod12 = require("zod");
1133
+ ParentRefSchema = import_zod12.z.object({
1257
1134
  /** Route segment of the parent, e.g. `"group"`. */
1258
- route: import_zod14.z.string(),
1135
+ route: import_zod12.z.string(),
1259
1136
  /**
1260
1137
  * Name of the path parameter carrying the parent id, e.g. `"groupId"`.
1261
1138
  * Avoid `"id"` — that is the child's own id in `/:id` routes.
1262
1139
  */
1263
- param: import_zod14.z.string().default("parentId"),
1140
+ param: import_zod12.z.string().default("parentId"),
1264
1141
  /** Type of the parent id, used to coerce the path param. Defaults to `'string'`. */
1265
- idType: import_zod14.z.enum([
1142
+ idType: import_zod12.z.enum([
1266
1143
  "string",
1267
1144
  "number"
1268
1145
  ]).optional()
@@ -1272,13 +1149,13 @@ var init_ParentRef_schema = __esm({
1272
1149
  });
1273
1150
 
1274
1151
  // ../crouton-core/src/lib/resource/ResourceKind.ts
1275
- var import_zod15, ResourceKindSchema;
1152
+ var import_zod13, ResourceKindSchema;
1276
1153
  var init_ResourceKind = __esm({
1277
1154
  "../crouton-core/src/lib/resource/ResourceKind.ts"() {
1278
1155
  "use strict";
1279
1156
  init_cjs_shims();
1280
- import_zod15 = require("zod");
1281
- ResourceKindSchema = import_zod15.z.enum([
1157
+ import_zod13 = require("zod");
1158
+ ResourceKindSchema = import_zod13.z.enum([
1282
1159
  "prisma",
1283
1160
  "custom"
1284
1161
  ]).default("prisma");
@@ -1286,42 +1163,42 @@ var init_ResourceKind = __esm({
1286
1163
  });
1287
1164
 
1288
1165
  // ../crouton-core/src/lib/resource/Sidebar.schema.ts
1289
- var import_zod16, SidebarGroupSchema, SidebarSchema;
1166
+ var import_zod14, SidebarGroupSchema, SidebarSchema;
1290
1167
  var init_Sidebar_schema = __esm({
1291
1168
  "../crouton-core/src/lib/resource/Sidebar.schema.ts"() {
1292
1169
  "use strict";
1293
1170
  init_cjs_shims();
1294
- import_zod16 = __toESM(require("zod"), 1);
1295
- SidebarGroupSchema = import_zod16.default.object({
1171
+ import_zod14 = __toESM(require("zod"), 1);
1172
+ SidebarGroupSchema = import_zod14.default.object({
1296
1173
  /** Human-readable heading shown in the sidebar. Defaults to a title-cased version of the slug. */
1297
- label: import_zod16.default.string().optional(),
1174
+ label: import_zod14.default.string().optional(),
1298
1175
  /** Controls the order of this group among top-level sidebar items. */
1299
- position: import_zod16.default.number().optional()
1176
+ position: import_zod14.default.number().optional()
1300
1177
  });
1301
- SidebarSchema = import_zod16.default.object({
1302
- hide: import_zod16.default.boolean().default(false),
1303
- position: import_zod16.default.number().optional(),
1304
- label: import_zod16.default.string().optional(),
1178
+ SidebarSchema = import_zod14.default.object({
1179
+ hide: import_zod14.default.boolean().default(false),
1180
+ position: import_zod14.default.number().optional(),
1181
+ label: import_zod14.default.string().optional(),
1305
1182
  /**
1306
1183
  * Slug of the group this resource belongs to.
1307
1184
  * Must match a key in `sidebarGroups` in `crouton.json`.
1308
1185
  * Resources with the same `group` are nested under a shared collapsible section.
1309
1186
  */
1310
- group: import_zod16.default.string().optional()
1187
+ group: import_zod14.default.string().optional()
1311
1188
  });
1312
1189
  }
1313
1190
  });
1314
1191
 
1315
1192
  // ../crouton-core/src/lib/resource/TableAction.schema.ts
1316
- var import_zod17, ActionConditionSchema, ActionSchema, JsonProcedureActionSchema, JsonLinkActionSchema, transformAction, JsonActionSchema;
1193
+ var import_zod15, ActionConditionSchema, ActionSchema, JsonProcedureActionSchema, JsonLinkActionSchema, transformAction, JsonActionSchema;
1317
1194
  var init_TableAction_schema = __esm({
1318
1195
  "../crouton-core/src/lib/resource/TableAction.schema.ts"() {
1319
1196
  "use strict";
1320
1197
  init_cjs_shims();
1321
- import_zod17 = require("zod");
1322
- ActionConditionSchema = import_zod17.z.object({
1198
+ import_zod15 = require("zod");
1199
+ ActionConditionSchema = import_zod15.z.object({
1323
1200
  /** Row field to evaluate. */
1324
- field: import_zod17.z.string(),
1201
+ field: import_zod15.z.string(),
1325
1202
  /**
1326
1203
  * Comparison operator. Defaults to `"eq"`.
1327
1204
  * - `eq` / `neq` — strict equality
@@ -1329,7 +1206,7 @@ var init_TableAction_schema = __esm({
1329
1206
  * - `exists` — field is not null / undefined / empty string
1330
1207
  * - `notExists` — field is null / undefined / empty string
1331
1208
  */
1332
- op: import_zod17.z.enum([
1209
+ op: import_zod15.z.enum([
1333
1210
  "eq",
1334
1211
  "neq",
1335
1212
  "gt",
@@ -1340,38 +1217,38 @@ var init_TableAction_schema = __esm({
1340
1217
  "notExists"
1341
1218
  ]).default("eq"),
1342
1219
  /** Comparison value. Not required for `exists` / `notExists`. */
1343
- value: import_zod17.z.unknown().optional()
1220
+ value: import_zod15.z.unknown().optional()
1344
1221
  });
1345
- ActionSchema = import_zod17.z.object({
1346
- type: import_zod17.z.string(),
1222
+ ActionSchema = import_zod15.z.object({
1223
+ type: import_zod15.z.string(),
1347
1224
  /** Unique identifier for the action. */
1348
- id: import_zod17.z.string(),
1225
+ id: import_zod15.z.string(),
1349
1226
  /** Human-readable button label. */
1350
- label: import_zod17.z.string(),
1227
+ label: import_zod15.z.string(),
1351
1228
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
1352
- icon: import_zod17.z.string().optional(),
1229
+ icon: import_zod15.z.string().optional(),
1353
1230
  /** Tooltip text. Falls back to `label` when omitted. */
1354
- tooltip: import_zod17.z.string().optional(),
1231
+ tooltip: import_zod15.z.string().optional(),
1355
1232
  condition: ActionConditionSchema.optional()
1356
1233
  });
1357
1234
  JsonProcedureActionSchema = ActionSchema.extend({
1358
- type: import_zod17.z.literal("procedure").default("procedure"),
1235
+ type: import_zod15.z.literal("procedure").default("procedure"),
1359
1236
  /**
1360
1237
  * Filename (without extension) inside the resource's `actions/` directory
1361
1238
  * that exports the table-action procedure, e.g. `"syncZotero"`.
1362
1239
  */
1363
- procedure: import_zod17.z.string(),
1240
+ procedure: import_zod15.z.string(),
1364
1241
  /** HTTP method for the frontend. Defaults to `"post"`. */
1365
- method: import_zod17.z.string().optional().default("post"),
1242
+ method: import_zod15.z.string().optional().default("post"),
1366
1243
  /** Static query / body params passed to the endpoint. */
1367
- data: import_zod17.z.record(import_zod17.z.string(), import_zod17.z.unknown()).optional()
1244
+ data: import_zod15.z.record(import_zod15.z.string(), import_zod15.z.unknown()).optional()
1368
1245
  });
1369
1246
  JsonLinkActionSchema = ActionSchema.extend({
1370
1247
  /** Optional condition evaluated per row. Button is hidden when the condition is false. */
1371
- type: import_zod17.z.literal("link").default("link"),
1248
+ type: import_zod15.z.literal("link").default("link"),
1372
1249
  /** URL to open. May contain `{env.VAR}` placeholders. */
1373
- href: import_zod17.z.string(),
1374
- blank: import_zod17.z.boolean().optional().default(true)
1250
+ href: import_zod15.z.string(),
1251
+ blank: import_zod15.z.boolean().optional().default(true)
1375
1252
  });
1376
1253
  transformAction = /* @__PURE__ */ __name((action) => {
1377
1254
  const label = action.label;
@@ -1380,27 +1257,70 @@ var init_TableAction_schema = __esm({
1380
1257
  ...action
1381
1258
  };
1382
1259
  }, "transformAction");
1383
- JsonActionSchema = import_zod17.z.union([
1260
+ JsonActionSchema = import_zod15.z.union([
1384
1261
  JsonProcedureActionSchema,
1385
1262
  JsonLinkActionSchema
1386
1263
  ]).transform(transformAction);
1387
1264
  }
1388
1265
  });
1389
1266
 
1267
+ // ../crouton-core/src/lib/resource/extensions.ts
1268
+ var CORE_RESOURCE_KEYS, registry, registerResourceExtension, registerResourceExtensions, getResourceExtensions;
1269
+ var init_extensions = __esm({
1270
+ "../crouton-core/src/lib/resource/extensions.ts"() {
1271
+ "use strict";
1272
+ init_cjs_shims();
1273
+ CORE_RESOURCE_KEYS = /* @__PURE__ */ new Set([
1274
+ "$schema",
1275
+ "schemaVersion",
1276
+ "draft",
1277
+ "kind",
1278
+ "id",
1279
+ "name",
1280
+ "route",
1281
+ "model",
1282
+ "tag",
1283
+ "title",
1284
+ "table",
1285
+ "idType",
1286
+ "database",
1287
+ "parent",
1288
+ "sidebar",
1289
+ "display",
1290
+ "security",
1291
+ "operations",
1292
+ "columns",
1293
+ "calculatedColumns",
1294
+ "actions",
1295
+ "tableActions",
1296
+ "modalSize",
1297
+ "include",
1298
+ "extensions"
1299
+ ]);
1300
+ registry = /* @__PURE__ */ new Map();
1301
+ registerResourceExtension = /* @__PURE__ */ __name((name, schema) => {
1302
+ if (CORE_RESOURCE_KEYS.has(name)) throw new Error(`Extension "${name}" shadows a core resource key.`);
1303
+ registry.set(name, schema);
1304
+ }, "registerResourceExtension");
1305
+ registerResourceExtensions = /* @__PURE__ */ __name((map = {}) => Object.entries(map).forEach(([k, s]) => registerResourceExtension(k, s)), "registerResourceExtensions");
1306
+ getResourceExtensions = /* @__PURE__ */ __name(() => registry, "getResourceExtensions");
1307
+ }
1308
+ });
1309
+
1390
1310
  // ../crouton-core/src/lib/resource/include.schema.ts
1391
- var import_zod18, JsonIncludeEntrySchema;
1311
+ var import_zod16, JsonIncludeEntrySchema;
1392
1312
  var init_include_schema = __esm({
1393
1313
  "../crouton-core/src/lib/resource/include.schema.ts"() {
1394
1314
  "use strict";
1395
1315
  init_cjs_shims();
1396
- import_zod18 = require("zod");
1397
- JsonIncludeEntrySchema = import_zod18.z.lazy(() => import_zod18.z.union([
1398
- import_zod18.z.string(),
1399
- import_zod18.z.object({
1400
- relation: import_zod18.z.string(),
1401
- include: import_zod18.z.array(JsonIncludeEntrySchema).optional(),
1316
+ import_zod16 = require("zod");
1317
+ JsonIncludeEntrySchema = import_zod16.z.lazy(() => import_zod16.z.union([
1318
+ import_zod16.z.string(),
1319
+ import_zod16.z.object({
1320
+ relation: import_zod16.z.string(),
1321
+ include: import_zod16.z.array(JsonIncludeEntrySchema).optional(),
1402
1322
  /** Prisma-format orderBy clause applied to the included records. */
1403
- orderBy: import_zod18.z.record(import_zod18.z.string(), import_zod18.z.unknown()).optional()
1323
+ orderBy: import_zod16.z.record(import_zod16.z.string(), import_zod16.z.unknown()).optional()
1404
1324
  })
1405
1325
  ]));
1406
1326
  }
@@ -1417,8 +1337,107 @@ var init_version = __esm({
1417
1337
  }
1418
1338
  });
1419
1339
 
1340
+ // ../crouton-core/src/lib/data-source/Security.schema.ts
1341
+ var import_zod17, SecuritySchema;
1342
+ var init_Security_schema = __esm({
1343
+ "../crouton-core/src/lib/data-source/Security.schema.ts"() {
1344
+ "use strict";
1345
+ init_cjs_shims();
1346
+ import_zod17 = require("zod");
1347
+ SecuritySchema = import_zod17.z.union([
1348
+ import_zod17.z.object({
1349
+ public: import_zod17.z.literal(true)
1350
+ }),
1351
+ import_zod17.z.object({
1352
+ guard: import_zod17.z.union([
1353
+ import_zod17.z.string(),
1354
+ import_zod17.z.array(import_zod17.z.string()).min(1)
1355
+ ])
1356
+ })
1357
+ ]);
1358
+ }
1359
+ });
1360
+
1361
+ // ../crouton-core/src/lib/data-source/Operations.schema.ts
1362
+ var import_zod18, OpEntry, BoolOrUpsertSchema, JsonOperationsSchema, buildSubResourceOperations;
1363
+ var init_Operations_schema = __esm({
1364
+ "../crouton-core/src/lib/data-source/Operations.schema.ts"() {
1365
+ "use strict";
1366
+ init_cjs_shims();
1367
+ import_zod18 = require("zod");
1368
+ init_Security_schema();
1369
+ OpEntry = import_zod18.z.union([
1370
+ import_zod18.z.boolean(),
1371
+ import_zod18.z.object({
1372
+ security: SecuritySchema.optional()
1373
+ })
1374
+ ]);
1375
+ BoolOrUpsertSchema = import_zod18.z.union([
1376
+ import_zod18.z.boolean(),
1377
+ import_zod18.z.object({
1378
+ upsertOn: import_zod18.z.union([
1379
+ import_zod18.z.string(),
1380
+ import_zod18.z.array(import_zod18.z.string())
1381
+ ]),
1382
+ security: SecuritySchema.optional()
1383
+ })
1384
+ ]);
1385
+ JsonOperationsSchema = import_zod18.z.object({
1386
+ findAll: OpEntry.default(true),
1387
+ findOne: OpEntry.default(true),
1388
+ create: OpEntry.default(true),
1389
+ update: OpEntry.default(true),
1390
+ patch: OpEntry.default(true),
1391
+ upsert: BoolOrUpsertSchema.default(false),
1392
+ delete: OpEntry.default(true)
1393
+ });
1394
+ buildSubResourceOperations = /* @__PURE__ */ __name((ops, baseUri, idField = "id") => {
1395
+ if (!ops) return {};
1396
+ const idPlaceholder = `{${idField}}`;
1397
+ return {
1398
+ ...ops.findAll && {
1399
+ findAll: {
1400
+ uri: baseUri,
1401
+ method: "get"
1402
+ }
1403
+ },
1404
+ ...ops.findOne && {
1405
+ findOne: {
1406
+ uri: `${baseUri}/${idPlaceholder}`,
1407
+ method: "get"
1408
+ }
1409
+ },
1410
+ ...ops.create && {
1411
+ create: {
1412
+ uri: baseUri,
1413
+ method: "post"
1414
+ }
1415
+ },
1416
+ ...ops.update && {
1417
+ update: {
1418
+ uri: `${baseUri}/${idPlaceholder}`,
1419
+ method: "put"
1420
+ }
1421
+ },
1422
+ ...ops.patch && {
1423
+ patch: {
1424
+ uri: `${baseUri}/${idPlaceholder}`,
1425
+ method: "patch"
1426
+ }
1427
+ },
1428
+ ...ops.delete && {
1429
+ delete: {
1430
+ uri: `${baseUri}/${idPlaceholder}`,
1431
+ method: "delete"
1432
+ }
1433
+ }
1434
+ };
1435
+ }, "buildSubResourceOperations");
1436
+ }
1437
+ });
1438
+
1420
1439
  // ../crouton-core/src/lib/resource/ResourceJson.schema.ts
1421
- var import_zod19, JsonColumnsMapSchema, ColumnsSchema, JsonDisplaySchema, normalizeColumns, ResourceJsonShape, refineByKind, ResourceJsonSchema;
1440
+ var import_zod19, JsonColumnsMapSchema, ColumnsSchema, JsonDisplaySchema, normalizeColumns, ResourceJsonShape, refineByKind, buildResourceJsonSchema, ResourceJsonSchema;
1422
1441
  var init_ResourceJson_schema = __esm({
1423
1442
  "../crouton-core/src/lib/resource/ResourceJson.schema.ts"() {
1424
1443
  "use strict";
@@ -1430,6 +1449,7 @@ var init_ResourceJson_schema = __esm({
1430
1449
  init_ResourceKind();
1431
1450
  init_Sidebar_schema();
1432
1451
  init_TableAction_schema();
1452
+ init_extensions();
1433
1453
  init_include_schema();
1434
1454
  init_version();
1435
1455
  init_Operations_schema();
@@ -1478,14 +1498,15 @@ var init_ResourceJson_schema = __esm({
1478
1498
  */
1479
1499
  kind: ResourceKindSchema,
1480
1500
  name: import_zod19.z.string(),
1481
- route: import_zod19.z.string(),
1501
+ route: import_zod19.z.string().optional(),
1502
+ id: import_zod19.z.string().optional(),
1482
1503
  /**
1483
1504
  * Prisma model name. Required when `kind` is `prisma` (enforced by the
1484
1505
  * refinement on `ResourceJsonSchema`), and must be absent when `kind` is
1485
1506
  * `custom` — there is no Prisma delegate to address.
1486
1507
  */
1487
1508
  model: import_zod19.z.string().optional(),
1488
- tag: import_zod19.z.string(),
1509
+ tag: import_zod19.z.string().optional().default("Crouton"),
1489
1510
  title: import_zod19.z.string().optional(),
1490
1511
  table: import_zod19.z.string().optional(),
1491
1512
  /**
@@ -1506,8 +1527,8 @@ var init_ResourceJson_schema = __esm({
1506
1527
  display: JsonDisplaySchema.default(JsonDisplaySchema.parse({})),
1507
1528
  /** Global security block — applies to every operation unless overridden per-operation. */
1508
1529
  security: SecuritySchema.optional(),
1509
- operations: JsonOperationsSchema,
1510
- columns: ColumnsSchema.default(ColumnsSchema.parse({})),
1530
+ operations: JsonOperationsSchema.optional(),
1531
+ columns: ColumnsSchema.optional().default(ColumnsSchema.parse({})),
1511
1532
  calculatedColumns: import_zod19.z.array(CalculatedColumnSchema).default([]),
1512
1533
  actions: import_zod19.z.array(JsonActionSchema).default([]),
1513
1534
  /** Global table-level actions (no record id). Shown as toolbar buttons. */
@@ -1592,16 +1613,49 @@ var init_ResourceJson_schema = __esm({
1592
1613
  });
1593
1614
  }
1594
1615
  }, "refineByKind");
1595
- ResourceJsonSchema = ResourceJsonShape.superRefine(refineByKind).transform((obj) => {
1596
- const title = obj.title ?? labelFromId(obj.name);
1597
- const schemaVersion = obj.schemaVersion ?? BASELINE_RESOURCE_VERSION;
1598
- return {
1599
- title,
1600
- ...obj,
1601
- schemaVersion,
1602
- columns: normalizeColumns(obj.columns)
1603
- };
1604
- });
1616
+ buildResourceJsonSchema = /* @__PURE__ */ __name(() => {
1617
+ const ext = getResourceExtensions();
1618
+ const extShape = Object.fromEntries([
1619
+ ...ext
1620
+ ].map(([name, schema]) => [
1621
+ name,
1622
+ schema.optional()
1623
+ ]));
1624
+ const shape = ext.size ? ResourceJsonShape.extend(extShape) : ResourceJsonShape;
1625
+ return import_zod19.z.preprocess((raw) => {
1626
+ if (raw && typeof raw === "object" && !Array.isArray(raw)) {
1627
+ const obj = raw;
1628
+ if (obj["kind"] === void 0) {
1629
+ return {
1630
+ ...obj,
1631
+ kind: obj["model"] !== void 0 ? "prisma" : "custom"
1632
+ };
1633
+ }
1634
+ }
1635
+ return raw;
1636
+ }, shape.superRefine(refineByKind).transform((obj) => {
1637
+ const title = obj.title ?? labelFromId(obj.name);
1638
+ const schemaVersion = obj.schemaVersion ?? BASELINE_RESOURCE_VERSION;
1639
+ const defaultOps = obj.kind === "custom" ? JsonOperationsSchema.parse({
1640
+ findAll: false,
1641
+ findOne: false,
1642
+ create: false,
1643
+ update: false,
1644
+ patch: false,
1645
+ delete: false
1646
+ }) : JsonOperationsSchema.parse({});
1647
+ return {
1648
+ title,
1649
+ ...obj,
1650
+ id: obj.id ?? obj.name,
1651
+ route: obj.route ?? obj.id ?? obj.name ?? "",
1652
+ schemaVersion,
1653
+ columns: normalizeColumns(obj.columns),
1654
+ operations: obj.operations ?? defaultOps
1655
+ };
1656
+ }));
1657
+ }, "buildResourceJsonSchema");
1658
+ ResourceJsonSchema = buildResourceJsonSchema();
1605
1659
  }
1606
1660
  });
1607
1661
 
@@ -1703,6 +1757,7 @@ var init_resource = __esm({
1703
1757
  "use strict";
1704
1758
  init_cjs_shims();
1705
1759
  init_ResourceJson_schema();
1760
+ init_extensions();
1706
1761
  init_version();
1707
1762
  init_migrations();
1708
1763
  init_Sidebar_schema();
@@ -1718,96 +1773,6 @@ var init_resource = __esm({
1718
1773
  }
1719
1774
  });
1720
1775
 
1721
- // ../crouton-core/src/lib/config/CroutonConfig.schema.ts
1722
- var import_zod20, RulesetSchema, I18nConfigSchema, CroutonConfigSchema;
1723
- var init_CroutonConfig_schema = __esm({
1724
- "../crouton-core/src/lib/config/CroutonConfig.schema.ts"() {
1725
- "use strict";
1726
- init_cjs_shims();
1727
- import_zod20 = require("zod");
1728
- init_Operations_schema();
1729
- init_resource();
1730
- RulesetSchema = import_zod20.z.object({
1731
- hideIdInTable: import_zod20.z.boolean().default(true),
1732
- hideIdInForm: import_zod20.z.boolean().default(true),
1733
- hideIdInView: import_zod20.z.boolean().default(true),
1734
- hideTimestamps: import_zod20.z.boolean().default(true),
1735
- hideForeignKeys: import_zod20.z.boolean().default(true),
1736
- includeRelations: import_zod20.z.boolean().default(true),
1737
- hideRelationsInTable: import_zod20.z.boolean().default(true),
1738
- showRelationsInForm: import_zod20.z.boolean().default(true),
1739
- enumValueLabel: import_zod20.z.boolean().default(true),
1740
- sharedEnums: import_zod20.z.boolean().default(true),
1741
- defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
1742
- });
1743
- I18nConfigSchema = import_zod20.z.object({
1744
- /** Default / fallback language. */
1745
- defaultLanguage: import_zod20.z.string().default("en"),
1746
- /** All supported language codes. */
1747
- languages: import_zod20.z.array(import_zod20.z.string()).min(1),
1748
- /** Directory containing `<lang>.json` bundles, relative to project root. */
1749
- translationsDir: import_zod20.z.string().default("translations")
1750
- });
1751
- CroutonConfigSchema = import_zod20.z.object({
1752
- /**
1753
- * Application title served to the frontend via `GET /_app/layout`.
1754
- * Displayed in the admin sidebar header.
1755
- */
1756
- title: import_zod20.z.string(),
1757
- /** Where resource directories live, relative to the project root. */
1758
- resourcesDir: import_zod20.z.string(),
1759
- /** Where datasource folders live (each with a `data-source.json`). */
1760
- dataSourcesDir: import_zod20.z.string(),
1761
- /**
1762
- * Template for a model's Zod export name. `{Model}` → Prisma model name.
1763
- * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema
1764
- * emitted by zod-prisma-types when `createRelationValuesTypes` is on).
1765
- */
1766
- schemaExportName: import_zod20.z.string().default("{Model}WithRelationsSchema"),
1767
- /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
1768
- enumsFile: import_zod20.z.string().default("crouton.enums.json"),
1769
- /** Optional overrides of the default visibility ruleset. */
1770
- rules: RulesetSchema.default(RulesetSchema.parse({})),
1771
- /**
1772
- * Sidebar group definitions, keyed by group slug (e.g. `"metadata"`).
1773
- * Resources reference a group via `sidebar.group` in their `resource.json`.
1774
- */
1775
- sidebarGroups: import_zod20.z.record(import_zod20.z.string(), SidebarGroupSchema).default({}),
1776
- /**
1777
- * Whether form fields are saved automatically as the user edits them.
1778
- * @default true
1779
- */
1780
- autoSave: import_zod20.z.boolean().default(true),
1781
- /** Optional i18n / translation configuration. */
1782
- i18n: I18nConfigSchema.optional()
1783
- });
1784
- }
1785
- });
1786
-
1787
- // ../crouton-core/src/lib/config/readConfig.ts
1788
- var CONFIG_FILES;
1789
- var init_readConfig = __esm({
1790
- "../crouton-core/src/lib/config/readConfig.ts"() {
1791
- "use strict";
1792
- init_cjs_shims();
1793
- CONFIG_FILES = [
1794
- "crouton.json",
1795
- "crouton.mjs",
1796
- "crouton.js"
1797
- ];
1798
- }
1799
- });
1800
-
1801
- // ../crouton-core/src/lib/config/index.ts
1802
- var init_config = __esm({
1803
- "../crouton-core/src/lib/config/index.ts"() {
1804
- "use strict";
1805
- init_cjs_shims();
1806
- init_CroutonConfig_schema();
1807
- init_readConfig();
1808
- }
1809
- });
1810
-
1811
1776
  // ../crouton-core/src/lib/view/column-predicates.ts
1812
1777
  var isBoolean, isRelation, isAutocomplete, isRecordCell, isDateRange, isObjectColumn, isArrayColumn, isObjectCell;
1813
1778
  var init_column_predicates = __esm({
@@ -2282,23 +2247,23 @@ var init_column_type_schema_source = __esm({
2282
2247
  });
2283
2248
 
2284
2249
  // ../crouton-core/src/lib/view/json-schema.opts.ts
2285
- var import_zod21, isInstanceOf, jsonSchemaOverride, jsonSchemaOpts;
2250
+ var import_zod20, isInstanceOf, jsonSchemaOverride, jsonSchemaOpts;
2286
2251
  var init_json_schema_opts = __esm({
2287
2252
  "../crouton-core/src/lib/view/json-schema.opts.ts"() {
2288
2253
  "use strict";
2289
2254
  init_cjs_shims();
2290
- import_zod21 = require("zod");
2255
+ import_zod20 = require("zod");
2291
2256
  isInstanceOf = /* @__PURE__ */ __name((zodSchema, className) => {
2292
- if (!(zodSchema instanceof import_zod21.z.ZodCustom)) return false;
2257
+ if (!(zodSchema instanceof import_zod20.z.ZodCustom)) return false;
2293
2258
  const result = zodSchema.safeParse(null);
2294
2259
  return !result.success && result.error.issues[0]?.expected === className;
2295
2260
  }, "isInstanceOf");
2296
2261
  jsonSchemaOverride = /* @__PURE__ */ __name(({ zodSchema, jsonSchema }) => {
2297
- if (zodSchema instanceof import_zod21.z.ZodDate) {
2262
+ if (zodSchema instanceof import_zod20.z.ZodDate) {
2298
2263
  jsonSchema.type = "string";
2299
2264
  jsonSchema.format = "date-time";
2300
2265
  }
2301
- if (zodSchema instanceof import_zod21.z.ZodBigInt) {
2266
+ if (zodSchema instanceof import_zod20.z.ZodBigInt) {
2302
2267
  jsonSchema.type = "integer";
2303
2268
  }
2304
2269
  if (isInstanceOf(zodSchema, "Decimal")) {
@@ -2316,12 +2281,12 @@ var init_json_schema_opts = __esm({
2316
2281
  });
2317
2282
 
2318
2283
  // ../crouton-core/src/lib/view/view.builder.ts
2319
- var import_zod22, patchFilterProperties, injectFieldDefaults, zodSchemaSource, NON_NULL_TYPES, SHAPE_KEYS, applyRequiredColumns, buildView, emptyTableView, buildViewsWithSource, buildViews, buildViewsFromColumnTypes, buildViewsFromColumns;
2284
+ var import_zod21, patchFilterProperties, injectFieldDefaults, zodSchemaSource, NON_NULL_TYPES, SHAPE_KEYS, applyRequiredColumns, buildView, emptyTableView, buildViewsWithSource, buildViews, buildViewsFromColumnTypes, buildViewsFromColumns;
2320
2285
  var init_view_builder = __esm({
2321
2286
  "../crouton-core/src/lib/view/view.builder.ts"() {
2322
2287
  "use strict";
2323
2288
  init_cjs_shims();
2324
- import_zod22 = require("zod");
2289
+ import_zod21 = require("zod");
2325
2290
  init_column_predicates();
2326
2291
  init_column_type_schema_source();
2327
2292
  init_column_utils();
@@ -2389,7 +2354,7 @@ var init_view_builder = __esm({
2389
2354
  ]));
2390
2355
  const picked = schema.pick(mask);
2391
2356
  try {
2392
- return (0, import_zod22.toJSONSchema)(picked, {
2357
+ return (0, import_zod21.toJSONSchema)(picked, {
2393
2358
  target: "draft-07",
2394
2359
  ...jsonSchemaOpts
2395
2360
  });
@@ -2477,7 +2442,7 @@ var init_view_builder = __esm({
2477
2442
  if (table) {
2478
2443
  table.defaultSort = resolveDefaultSort(table.columns, columns);
2479
2444
  views.table = table;
2480
- } else if (columns?.length) {
2445
+ } else if (columns !== void 0) {
2481
2446
  views.table = emptyTableView();
2482
2447
  }
2483
2448
  const form = buildView(source, columns, (c) => !c.hiddenInForm, buildFormUiSchema, true, (c) => !c.idField && (c.createable === true || c.updateable === true));
@@ -2600,88 +2565,552 @@ var init_view_builder = __esm({
2600
2565
  }
2601
2566
  });
2602
2567
 
2603
- // ../crouton-core/src/lib/view/view.schema.ts
2604
- var import_zod23, ViewColumnConfigSchema, ViewConfigSchema, viewDefList, ViewDefEnum;
2605
- var init_view_schema = __esm({
2606
- "../crouton-core/src/lib/view/view.schema.ts"() {
2568
+ // ../crouton-core/src/lib/view/view.schema.ts
2569
+ var import_zod22, ViewColumnConfigSchema, ViewConfigSchema, viewDefList, ViewDefEnum;
2570
+ var init_view_schema = __esm({
2571
+ "../crouton-core/src/lib/view/view.schema.ts"() {
2572
+ "use strict";
2573
+ init_cjs_shims();
2574
+ import_zod22 = require("zod");
2575
+ init_FieldInput_schema();
2576
+ ViewColumnConfigSchema = import_zod22.z.object({
2577
+ id: import_zod22.z.string(),
2578
+ label: import_zod22.z.string().optional(),
2579
+ sortable: import_zod22.z.boolean().optional(),
2580
+ searchable: import_zod22.z.boolean().optional(),
2581
+ fieldInput: FieldInputSchema.optional()
2582
+ });
2583
+ ViewConfigSchema = import_zod22.z.object({
2584
+ // TODO why we have both?
2585
+ json_schema: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()).optional(),
2586
+ ui_schema: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()).optional(),
2587
+ // TODO why we have both?
2588
+ ui: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()).optional(),
2589
+ data: import_zod22.z.record(import_zod22.z.string(), import_zod22.z.unknown()).optional(),
2590
+ columns: import_zod22.z.array(ViewColumnConfigSchema),
2591
+ defaultSort: import_zod22.z.string().optional()
2592
+ });
2593
+ viewDefList = [
2594
+ "table",
2595
+ "view",
2596
+ "form"
2597
+ ];
2598
+ ViewDefEnum = import_zod22.z.enum(viewDefList);
2599
+ }
2600
+ });
2601
+
2602
+ // ../crouton-core/src/lib/view/index.ts
2603
+ var init_view = __esm({
2604
+ "../crouton-core/src/lib/view/index.ts"() {
2605
+ "use strict";
2606
+ init_cjs_shims();
2607
+ init_column_predicates();
2608
+ init_column_utils();
2609
+ init_sort_helpers();
2610
+ init_schema_transforms();
2611
+ init_table_schema_builder();
2612
+ init_form_schema_builder();
2613
+ init_calculated_columns_builder();
2614
+ init_view_builder();
2615
+ init_column_type_schema_source();
2616
+ init_view_schema();
2617
+ init_json_schema_opts();
2618
+ }
2619
+ });
2620
+
2621
+ // ../crouton-core/src/lib/compile/column-enrichment.ts
2622
+ var init_column_enrichment = __esm({
2623
+ "../crouton-core/src/lib/compile/column-enrichment.ts"() {
2624
+ "use strict";
2625
+ init_cjs_shims();
2626
+ }
2627
+ });
2628
+
2629
+ // ../crouton-core/src/lib/compile/column-transforms.ts
2630
+ var init_column_transforms = __esm({
2631
+ "../crouton-core/src/lib/compile/column-transforms.ts"() {
2632
+ "use strict";
2633
+ init_cjs_shims();
2634
+ init_resource();
2635
+ }
2636
+ });
2637
+
2638
+ // ../crouton-core/src/lib/compile/enum-registry.ts
2639
+ var import_zod23, EnumEntrySchema, EnumRegistrySchema;
2640
+ var init_enum_registry = __esm({
2641
+ "../crouton-core/src/lib/compile/enum-registry.ts"() {
2642
+ "use strict";
2643
+ init_cjs_shims();
2644
+ import_zod23 = require("zod");
2645
+ EnumEntrySchema = import_zod23.z.object({
2646
+ value: import_zod23.z.unknown(),
2647
+ label: import_zod23.z.string()
2648
+ });
2649
+ EnumRegistrySchema = import_zod23.z.record(import_zod23.z.string(), import_zod23.z.array(EnumEntrySchema)).default({});
2650
+ }
2651
+ });
2652
+
2653
+ // ../crouton-core/src/lib/compile/relation-type.ts
2654
+ var import_zod24;
2655
+ var init_relation_type = __esm({
2656
+ "../crouton-core/src/lib/compile/relation-type.ts"() {
2657
+ "use strict";
2658
+ init_cjs_shims();
2659
+ import_zod24 = require("zod");
2660
+ }
2661
+ });
2662
+
2663
+ // ../crouton-core/src/lib/compile/schema.helpers.ts
2664
+ var init_schema_helpers = __esm({
2665
+ "../crouton-core/src/lib/compile/schema.helpers.ts"() {
2666
+ "use strict";
2667
+ init_cjs_shims();
2668
+ init_view();
2669
+ }
2670
+ });
2671
+
2672
+ // ../crouton-core/src/lib/compile/compile-resource.ts
2673
+ var init_compile_resource = __esm({
2674
+ "../crouton-core/src/lib/compile/compile-resource.ts"() {
2675
+ "use strict";
2676
+ init_cjs_shims();
2677
+ init_resource();
2678
+ init_view();
2679
+ init_column_enrichment();
2680
+ init_column_transforms();
2681
+ init_enum_registry();
2682
+ init_relation_type();
2683
+ init_schema_helpers();
2684
+ }
2685
+ });
2686
+
2687
+ // ../crouton-core/src/lib/data-source/DataSourceSchema.ts
2688
+ var import_zod25, DataSourceShape, transformDataSource, DataSourceSchema;
2689
+ var init_DataSourceSchema = __esm({
2690
+ "../crouton-core/src/lib/data-source/DataSourceSchema.ts"() {
2691
+ "use strict";
2692
+ init_cjs_shims();
2693
+ import_zod25 = __toESM(require("zod"), 1);
2694
+ DataSourceShape = import_zod25.default.object({
2695
+ /** Datasource name (folder + `name` in data-source.json). */
2696
+ name: import_zod25.default.string(),
2697
+ /**
2698
+ * Env var holding the connection URL. Required for Prisma adapters; optional
2699
+ * for custom adapters whose connection config may differ (secrets file, SDK
2700
+ * key, etc.).
2701
+ */
2702
+ urlEnv: import_zod25.default.string().optional(),
2703
+ /** Import path for this datasource's generated Zod types (for resource `schema.ts`). */
2704
+ generatedTypesImport: import_zod25.default.string().optional(),
2705
+ /** Datasource type tag. Default `postgres`. */
2706
+ type: import_zod25.default.string().default("postgres"),
2707
+ /** Mark this as the default datasource. Default `false`. */
2708
+ default: import_zod25.default.boolean().default(false),
2709
+ /**
2710
+ * Adapter kind. `"prisma"` (default) expects `index.ts` to default-export a
2711
+ * `PrismaClient`; `"custom"` expects it to default-export a `DataSourceAdapter`.
2712
+ */
2713
+ adapter: import_zod25.default.enum([
2714
+ "prisma",
2715
+ "custom"
2716
+ ]).default("prisma"),
2717
+ /** Prisma schema path, relative to project root. Default `prisma/<name>/schema.prisma`. */
2718
+ prismaSchema: import_zod25.default.string().optional(),
2719
+ /** Prisma config path, relative to project root. Default `prisma/<name>/prisma.config.ts`. */
2720
+ prismaConfig: import_zod25.default.string().optional(),
2721
+ /** zod-prisma-types output dir, relative to project root. Default `generated/<name>/src`. */
2722
+ zodOutput: import_zod25.default.string().optional(),
2723
+ /** Prisma client output dir, relative to project root. Default `generated/<name>/client`. */
2724
+ clientOutput: import_zod25.default.string().optional()
2725
+ });
2726
+ transformDataSource = /* @__PURE__ */ __name((data) => {
2727
+ const name = data.name ?? "name";
2728
+ return {
2729
+ ...data,
2730
+ generatedTypesImport: data.generatedTypesImport ?? `@your-scope/generated/${name}`,
2731
+ prismaSchema: data.prismaSchema ?? `prisma/${name}/schema.prisma`,
2732
+ prismaConfig: data.prismaConfig ?? `prisma/${name}/prisma.config.ts`,
2733
+ zodOutput: data.zodOutput ?? `generated/${name}/src`,
2734
+ clientOutput: data.clientOutput ?? `generated/${name}/client`
2735
+ };
2736
+ }, "transformDataSource");
2737
+ DataSourceSchema = DataSourceShape.transform(transformDataSource);
2738
+ }
2739
+ });
2740
+
2741
+ // ../crouton-core/src/lib/data-source/index.ts
2742
+ var init_data_source = __esm({
2743
+ "../crouton-core/src/lib/data-source/index.ts"() {
2744
+ "use strict";
2745
+ init_cjs_shims();
2746
+ init_DataSourceSchema();
2747
+ init_Operations_schema();
2748
+ init_Security_schema();
2749
+ }
2750
+ });
2751
+
2752
+ // ../crouton-core/src/lib/compile/value-label-column.ts
2753
+ var import_zod26, ValueSchema, ValueLabelColumnSchema;
2754
+ var init_value_label_column = __esm({
2755
+ "../crouton-core/src/lib/compile/value-label-column.ts"() {
2607
2756
  "use strict";
2608
2757
  init_cjs_shims();
2609
- import_zod23 = require("zod");
2610
- init_FieldInput_schema();
2611
- ViewColumnConfigSchema = import_zod23.z.object({
2612
- id: import_zod23.z.string(),
2613
- label: import_zod23.z.string().optional(),
2614
- sortable: import_zod23.z.boolean().optional(),
2615
- searchable: import_zod23.z.boolean().optional(),
2616
- fieldInput: FieldInputSchema.optional()
2758
+ import_zod26 = require("zod");
2759
+ ValueSchema = import_zod26.z.object({
2760
+ value: import_zod26.z.unknown(),
2761
+ label: import_zod26.z.string()
2617
2762
  });
2618
- ViewConfigSchema = import_zod23.z.object({
2619
- // TODO why we have both?
2620
- json_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2621
- ui_schema: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2622
- // TODO why we have both?
2623
- ui: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2624
- data: import_zod23.z.record(import_zod23.z.string(), import_zod23.z.unknown()).optional(),
2625
- columns: import_zod23.z.array(ViewColumnConfigSchema),
2626
- defaultSort: import_zod23.z.string().optional()
2763
+ ValueLabelColumnSchema = import_zod26.z.object({
2764
+ field: import_zod26.z.string(),
2765
+ values: import_zod26.z.array(ValueSchema).default([]),
2766
+ enumName: import_zod26.z.string().optional()
2627
2767
  });
2628
- viewDefList = [
2629
- "table",
2630
- "view",
2631
- "form"
2632
- ];
2633
- ViewDefEnum = import_zod23.z.enum(viewDefList);
2634
2768
  }
2635
2769
  });
2636
2770
 
2637
- // ../crouton-core/src/lib/view/index.ts
2638
- var init_view = __esm({
2639
- "../crouton-core/src/lib/view/index.ts"() {
2771
+ // ../crouton-core/src/lib/compile/compiled-sub-resource.schema.ts
2772
+ var import_zod27, CompiledSubResourceConfigSchema;
2773
+ var init_compiled_sub_resource_schema = __esm({
2774
+ "../crouton-core/src/lib/compile/compiled-sub-resource.schema.ts"() {
2640
2775
  "use strict";
2641
2776
  init_cjs_shims();
2642
- init_column_predicates();
2643
- init_column_utils();
2644
- init_sort_helpers();
2645
- init_schema_transforms();
2646
- init_table_schema_builder();
2647
- init_form_schema_builder();
2648
- init_calculated_columns_builder();
2649
- init_view_builder();
2650
- init_column_type_schema_source();
2651
- init_view_schema();
2777
+ import_zod27 = require("zod");
2778
+ init_data_source();
2779
+ init_resource();
2780
+ init_view();
2781
+ init_value_label_column();
2782
+ CompiledSubResourceConfigSchema = import_zod27.z.object({
2783
+ column: import_zod27.z.string(),
2784
+ relation: import_zod27.z.string(),
2785
+ childRoute: import_zod27.z.string(),
2786
+ childKind: import_zod27.z.enum([
2787
+ "prisma",
2788
+ "custom"
2789
+ ]).default("prisma"),
2790
+ childDir: import_zod27.z.string().optional(),
2791
+ childModel: import_zod27.z.string(),
2792
+ foreignKey: import_zod27.z.string(),
2793
+ name: import_zod27.z.string().optional(),
2794
+ title: import_zod27.z.string().optional(),
2795
+ idField: import_zod27.z.string().optional(),
2796
+ idType: import_zod27.z.enum([
2797
+ "string",
2798
+ "number"
2799
+ ]).optional(),
2800
+ views: import_zod27.z.record(import_zod27.z.string(), ViewConfigSchema).optional(),
2801
+ operations: JsonOperationsSchema,
2802
+ actions: import_zod27.z.array(JsonActionSchema).optional(),
2803
+ modalSize: import_zod27.z.enum([
2804
+ "xs",
2805
+ "sm",
2806
+ "lg",
2807
+ "xl"
2808
+ ]).optional(),
2809
+ include: import_zod27.z.array(JsonIncludeEntrySchema).optional(),
2810
+ calculatedColumns: import_zod27.z.array(CalculatedColumnSchema).optional(),
2811
+ includeInFindOne: import_zod27.z.boolean().optional(),
2812
+ hiddenInTable: import_zod27.z.boolean().optional(),
2813
+ findOneOrderBy: import_zod27.z.record(import_zod27.z.string(), import_zod27.z.unknown()).optional(),
2814
+ valueLabelColumns: import_zod27.z.array(ValueLabelColumnSchema).optional(),
2815
+ relationType: import_zod27.z.enum([
2816
+ "oneToMany",
2817
+ "manyToOne"
2818
+ ]).optional()
2819
+ });
2820
+ }
2821
+ });
2822
+
2823
+ // ../crouton-core/src/lib/compile/schema-input.ts
2824
+ var import_zod28, JsonSchemaInputSchema, SchemaInputSchema;
2825
+ var init_schema_input = __esm({
2826
+ "../crouton-core/src/lib/compile/schema-input.ts"() {
2827
+ "use strict";
2828
+ init_cjs_shims();
2829
+ import_zod28 = require("zod");
2830
+ JsonSchemaInputSchema = import_zod28.z.object({
2831
+ type: import_zod28.z.literal("object"),
2832
+ properties: import_zod28.z.record(import_zod28.z.string(), import_zod28.z.unknown()),
2833
+ required: import_zod28.z.array(import_zod28.z.string()).optional(),
2834
+ additionalProperties: import_zod28.z.boolean().optional()
2835
+ });
2836
+ SchemaInputSchema = import_zod28.z.union([
2837
+ import_zod28.z.custom((val) => val instanceof import_zod28.ZodObject),
2838
+ JsonSchemaInputSchema
2839
+ ]);
2840
+ }
2841
+ });
2842
+
2843
+ // ../crouton-core/src/lib/compile/definition.schema.ts
2844
+ var import_zod29, OperationDefSchema, UpsertOperationDefSchema, ResourceDefinitionSchema, DefinitionCallbackSchema, DefinitionSchema;
2845
+ var init_definition_schema = __esm({
2846
+ "../crouton-core/src/lib/compile/definition.schema.ts"() {
2847
+ "use strict";
2848
+ init_cjs_shims();
2849
+ import_zod29 = require("zod");
2850
+ init_schema_input();
2851
+ init_Security_schema();
2852
+ OperationDefSchema = import_zod29.z.union([
2853
+ import_zod29.z.literal(true),
2854
+ import_zod29.z.object({
2855
+ schema: SchemaInputSchema.optional(),
2856
+ security: SecuritySchema.optional()
2857
+ })
2858
+ ]);
2859
+ UpsertOperationDefSchema = import_zod29.z.object({
2860
+ schema: SchemaInputSchema.optional(),
2861
+ upsertOn: import_zod29.z.union([
2862
+ import_zod29.z.string(),
2863
+ import_zod29.z.array(import_zod29.z.string())
2864
+ ]),
2865
+ security: SecuritySchema.optional()
2866
+ });
2867
+ ResourceDefinitionSchema = import_zod29.z.object({
2868
+ findAll: OperationDefSchema.optional(),
2869
+ findOne: OperationDefSchema.optional(),
2870
+ create: OperationDefSchema.optional(),
2871
+ update: OperationDefSchema.optional(),
2872
+ patch: OperationDefSchema.optional(),
2873
+ upsert: UpsertOperationDefSchema.optional(),
2874
+ delete: OperationDefSchema.optional()
2875
+ });
2876
+ DefinitionCallbackSchema = import_zod29.z.function({
2877
+ input: [],
2878
+ output: ResourceDefinitionSchema
2879
+ });
2880
+ DefinitionSchema = import_zod29.z.union([
2881
+ ResourceDefinitionSchema,
2882
+ DefinitionCallbackSchema
2883
+ ]);
2884
+ }
2885
+ });
2886
+
2887
+ // ../crouton-core/src/lib/compile/lookup.schema.ts
2888
+ var import_zod30, LookupSchema;
2889
+ var init_lookup_schema = __esm({
2890
+ "../crouton-core/src/lib/compile/lookup.schema.ts"() {
2891
+ "use strict";
2892
+ init_cjs_shims();
2893
+ import_zod30 = require("zod");
2894
+ LookupSchema = import_zod30.z.object({
2895
+ key: import_zod30.z.string(),
2896
+ label: import_zod30.z.string().optional()
2897
+ });
2898
+ }
2899
+ });
2900
+
2901
+ // ../crouton-core/src/lib/compile/compiled-resource.schema.ts
2902
+ var import_zod31, CompiledResourceSchema;
2903
+ var init_compiled_resource_schema = __esm({
2904
+ "../crouton-core/src/lib/compile/compiled-resource.schema.ts"() {
2905
+ "use strict";
2906
+ init_cjs_shims();
2907
+ import_zod31 = require("zod");
2908
+ init_resource();
2909
+ init_view();
2910
+ init_compiled_sub_resource_schema();
2911
+ init_definition_schema();
2912
+ init_lookup_schema();
2913
+ init_value_label_column();
2914
+ CompiledResourceSchema = ResourceJsonShape.extend({
2915
+ route: import_zod31.z.string(),
2916
+ valueLabelColumns: import_zod31.z.array(ValueLabelColumnSchema).default([]),
2917
+ subResources: import_zod31.z.lazy(() => import_zod31.z.array(CompiledSubResourceConfigSchema)).default([]),
2918
+ lookup: LookupSchema.optional(),
2919
+ views: import_zod31.z.record(import_zod31.z.string(), ViewConfigSchema),
2920
+ definition: DefinitionSchema,
2921
+ idField: import_zod31.z.string(),
2922
+ idType: import_zod31.z.enum([
2923
+ "string",
2924
+ "number"
2925
+ ]).default("string")
2926
+ });
2927
+ }
2928
+ });
2929
+
2930
+ // ../crouton-core/src/lib/compile/crud-config.ts
2931
+ var init_crud_config = __esm({
2932
+ "../crouton-core/src/lib/compile/crud-config.ts"() {
2933
+ "use strict";
2934
+ init_cjs_shims();
2935
+ }
2936
+ });
2937
+
2938
+ // ../crouton-core/src/lib/compile/to-json-schema.ts
2939
+ var import_zod32;
2940
+ var init_to_json_schema = __esm({
2941
+ "../crouton-core/src/lib/compile/to-json-schema.ts"() {
2942
+ "use strict";
2943
+ init_cjs_shims();
2944
+ import_zod32 = require("zod");
2652
2945
  init_json_schema_opts();
2653
2946
  }
2654
2947
  });
2655
2948
 
2949
+ // ../crouton-core/src/lib/compile/payload-builders.ts
2950
+ var init_payload_builders = __esm({
2951
+ "../crouton-core/src/lib/compile/payload-builders.ts"() {
2952
+ "use strict";
2953
+ init_cjs_shims();
2954
+ init_data_source();
2955
+ init_resource();
2956
+ init_crud_config();
2957
+ init_to_json_schema();
2958
+ }
2959
+ });
2960
+
2961
+ // ../crouton-core/src/lib/compile/parse-schema.ts
2962
+ var init_parse_schema = __esm({
2963
+ "../crouton-core/src/lib/compile/parse-schema.ts"() {
2964
+ "use strict";
2965
+ init_cjs_shims();
2966
+ init_resource();
2967
+ init_compile_resource();
2968
+ init_payload_builders();
2969
+ }
2970
+ });
2971
+
2972
+ // ../crouton-core/src/lib/compile/index.ts
2973
+ var init_compile = __esm({
2974
+ "../crouton-core/src/lib/compile/index.ts"() {
2975
+ "use strict";
2976
+ init_cjs_shims();
2977
+ init_action_types();
2978
+ init_compile_resource();
2979
+ init_compiled_resource_schema();
2980
+ init_compiled_sub_resource_schema();
2981
+ init_crud_config();
2982
+ init_definition_schema();
2983
+ init_enum_registry();
2984
+ init_lookup_schema();
2985
+ init_parse_schema();
2986
+ init_payload_builders();
2987
+ init_relation_type();
2988
+ init_schema_helpers();
2989
+ init_schema_input();
2990
+ init_to_json_schema();
2991
+ init_value_label_column();
2992
+ }
2993
+ });
2994
+
2995
+ // ../crouton-core/src/lib/config/CroutonConfig.schema.ts
2996
+ var import_zod33, RulesetSchema, I18nConfigSchema, CroutonConfigSchema;
2997
+ var init_CroutonConfig_schema = __esm({
2998
+ "../crouton-core/src/lib/config/CroutonConfig.schema.ts"() {
2999
+ "use strict";
3000
+ init_cjs_shims();
3001
+ import_zod33 = require("zod");
3002
+ init_Operations_schema();
3003
+ init_resource();
3004
+ RulesetSchema = import_zod33.z.object({
3005
+ hideIdInTable: import_zod33.z.boolean().default(true),
3006
+ hideIdInForm: import_zod33.z.boolean().default(true),
3007
+ hideIdInView: import_zod33.z.boolean().default(true),
3008
+ hideTimestamps: import_zod33.z.boolean().default(true),
3009
+ hideForeignKeys: import_zod33.z.boolean().default(true),
3010
+ includeRelations: import_zod33.z.boolean().default(true),
3011
+ hideRelationsInTable: import_zod33.z.boolean().default(true),
3012
+ showRelationsInForm: import_zod33.z.boolean().default(true),
3013
+ enumValueLabel: import_zod33.z.boolean().default(true),
3014
+ sharedEnums: import_zod33.z.boolean().default(true),
3015
+ defaultOperations: JsonOperationsSchema.default(JsonOperationsSchema.parse({}))
3016
+ });
3017
+ I18nConfigSchema = import_zod33.z.object({
3018
+ /** Default / fallback language. */
3019
+ defaultLanguage: import_zod33.z.string().default("en"),
3020
+ /** All supported language codes. */
3021
+ languages: import_zod33.z.array(import_zod33.z.string()).min(1),
3022
+ /** Directory containing `<lang>.json` bundles, relative to project root. */
3023
+ translationsDir: import_zod33.z.string().default("translations")
3024
+ });
3025
+ CroutonConfigSchema = import_zod33.z.object({
3026
+ /**
3027
+ * Application title served to the frontend via `GET /_app/layout`.
3028
+ * Displayed in the admin sidebar header.
3029
+ */
3030
+ title: import_zod33.z.string(),
3031
+ /** Where resource directories live, relative to the project root. */
3032
+ resourcesDir: import_zod33.z.string(),
3033
+ /** Where datasource folders live (each with a `data-source.json`). */
3034
+ dataSourcesDir: import_zod33.z.string(),
3035
+ /**
3036
+ * Template for a model's Zod export name. `{Model}` → Prisma model name.
3037
+ * Defaults to `{Model}WithRelationsSchema` (the relations-aware schema
3038
+ * emitted by zod-prisma-types when `createRelationValuesTypes` is on).
3039
+ */
3040
+ schemaExportName: import_zod33.z.string().default("{Model}WithRelationsSchema"),
3041
+ /** Path to the shared enum registry, relative to project root. Default `crouton.enums.json`. */
3042
+ enumsFile: import_zod33.z.string().default("crouton.enums.json"),
3043
+ /** Optional overrides of the default visibility ruleset. */
3044
+ rules: RulesetSchema.default(RulesetSchema.parse({})),
3045
+ /**
3046
+ * Sidebar group definitions, keyed by group slug (e.g. `"metadata"`).
3047
+ * Resources reference a group via `sidebar.group` in their `resource.json`.
3048
+ */
3049
+ sidebarGroups: import_zod33.z.record(import_zod33.z.string(), SidebarGroupSchema).default({}),
3050
+ /**
3051
+ * Whether form fields are saved automatically as the user edits them.
3052
+ * @default true
3053
+ */
3054
+ autoSave: import_zod33.z.boolean().default(true),
3055
+ /** Optional i18n / translation configuration. */
3056
+ i18n: I18nConfigSchema.optional()
3057
+ });
3058
+ }
3059
+ });
3060
+
3061
+ // ../crouton-core/src/lib/config/readConfig.ts
3062
+ var CONFIG_FILES;
3063
+ var init_readConfig = __esm({
3064
+ "../crouton-core/src/lib/config/readConfig.ts"() {
3065
+ "use strict";
3066
+ init_cjs_shims();
3067
+ CONFIG_FILES = [
3068
+ "crouton.json",
3069
+ "crouton.mjs",
3070
+ "crouton.js"
3071
+ ];
3072
+ }
3073
+ });
3074
+
3075
+ // ../crouton-core/src/lib/config/index.ts
3076
+ var init_config = __esm({
3077
+ "../crouton-core/src/lib/config/index.ts"() {
3078
+ "use strict";
3079
+ init_cjs_shims();
3080
+ init_CroutonConfig_schema();
3081
+ init_readConfig();
3082
+ }
3083
+ });
3084
+
2656
3085
  // ../crouton-core/src/lib/i18n/Translations.schema.ts
2657
- var import_zod24, NestedStringRecord, TranslationBundleSchema;
3086
+ var import_zod34, NestedStringRecord, TranslationBundleSchema;
2658
3087
  var init_Translations_schema = __esm({
2659
3088
  "../crouton-core/src/lib/i18n/Translations.schema.ts"() {
2660
3089
  "use strict";
2661
3090
  init_cjs_shims();
2662
- import_zod24 = require("zod");
2663
- NestedStringRecord = import_zod24.z.lazy(() => import_zod24.z.record(import_zod24.z.string(), import_zod24.z.union([
2664
- import_zod24.z.string(),
3091
+ import_zod34 = require("zod");
3092
+ NestedStringRecord = import_zod34.z.lazy(() => import_zod34.z.record(import_zod34.z.string(), import_zod34.z.union([
3093
+ import_zod34.z.string(),
2665
3094
  NestedStringRecord
2666
3095
  ])));
2667
- TranslationBundleSchema = import_zod24.z.object({
2668
- app: import_zod24.z.object({
2669
- title: import_zod24.z.string().optional()
3096
+ TranslationBundleSchema = import_zod34.z.object({
3097
+ app: import_zod34.z.object({
3098
+ title: import_zod34.z.string().optional()
2670
3099
  }).optional(),
2671
- sidebarGroups: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2672
- resources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2673
- title: import_zod24.z.string().optional(),
2674
- sidebar: import_zod24.z.string().optional(),
2675
- columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2676
- actions: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional(),
2677
- subResources: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.object({
2678
- title: import_zod24.z.string().optional(),
2679
- columns: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
3100
+ sidebarGroups: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string()).optional(),
3101
+ resources: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.object({
3102
+ title: import_zod34.z.string().optional(),
3103
+ sidebar: import_zod34.z.string().optional(),
3104
+ columns: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string()).optional(),
3105
+ actions: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string()).optional(),
3106
+ subResources: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.object({
3107
+ title: import_zod34.z.string().optional(),
3108
+ columns: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string()).optional()
2680
3109
  }).optional()).optional()
2681
3110
  }).optional()).optional(),
2682
- enums: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string())).optional(),
3111
+ enums: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string())).optional(),
2683
3112
  ui: NestedStringRecord.optional(),
2684
- validation: import_zod24.z.record(import_zod24.z.string(), import_zod24.z.string()).optional()
3113
+ validation: import_zod34.z.record(import_zod34.z.string(), import_zod34.z.string()).optional()
2685
3114
  }).passthrough();
2686
3115
  }
2687
3116
  });
@@ -2814,6 +3243,7 @@ var init_src = __esm({
2814
3243
  init_base_builder();
2815
3244
  init_table_builder();
2816
3245
  init_table_utils();
3246
+ init_compile();
2817
3247
  init_data_source();
2818
3248
  init_resource();
2819
3249
  init_config();
@@ -2880,27 +3310,27 @@ var init_module_loader = __esm({
2880
3310
  });
2881
3311
 
2882
3312
  // src/lib/crud/hooks/hooks.types.ts
2883
- var import_zod28, WriteOpSchema, ReadOpSchema, ResourceHooksSchema;
3313
+ var import_zod38, WriteOpSchema, ReadOpSchema, ResourceHooksSchema;
2884
3314
  var init_hooks_types = __esm({
2885
3315
  "src/lib/crud/hooks/hooks.types.ts"() {
2886
3316
  "use strict";
2887
3317
  init_cjs_shims();
2888
- import_zod28 = require("zod");
2889
- WriteOpSchema = import_zod28.z.enum([
3318
+ import_zod38 = require("zod");
3319
+ WriteOpSchema = import_zod38.z.enum([
2890
3320
  "create",
2891
3321
  "update",
2892
3322
  "patch",
2893
3323
  "upsert",
2894
3324
  "delete"
2895
3325
  ]);
2896
- ReadOpSchema = import_zod28.z.enum([
3326
+ ReadOpSchema = import_zod38.z.enum([
2897
3327
  "findAll",
2898
3328
  "findOne"
2899
3329
  ]);
2900
- ResourceHooksSchema = import_zod28.z.object({
2901
- beforeWrite: import_zod28.z.custom().optional(),
2902
- afterWrite: import_zod28.z.custom().optional(),
2903
- afterRead: import_zod28.z.custom().optional()
3330
+ ResourceHooksSchema = import_zod38.z.object({
3331
+ beforeWrite: import_zod38.z.custom().optional(),
3332
+ afterWrite: import_zod38.z.custom().optional(),
3333
+ afterRead: import_zod38.z.custom().optional()
2904
3334
  });
2905
3335
  }
2906
3336
  });
@@ -3054,7 +3484,7 @@ __export(index_exports, {
3054
3484
  buildViews: () => buildViews,
3055
3485
  decorateRow: () => decorateRow,
3056
3486
  decorateRows: () => decorateRows,
3057
- isOperationEnabled: () => isOperationEnabled,
3487
+ isOperationEnabled: () => isOperationEnabled2,
3058
3488
  isRowProcedureAction: () => isRowProcedureAction,
3059
3489
  isTableProcedureAction: () => isTableProcedureAction,
3060
3490
  loadDataSourcesFromDir: () => loadDataSourcesFromDir,
@@ -3062,13 +3492,14 @@ __export(index_exports, {
3062
3492
  loadResourceHooks: () => loadResourceHooks,
3063
3493
  loadSubResourceHooks: () => loadSubResourceHooks,
3064
3494
  parseFilterString: () => parseFilterString,
3495
+ parseSchema: () => parseSchema,
3065
3496
  postWrite: () => postWrite,
3066
3497
  prepareWrite: () => prepareWrite,
3067
- resolveDefinition: () => resolveDefinition,
3068
- schemaFor: () => schemaFor,
3498
+ resolveDefinition: () => resolveDefinition2,
3499
+ schemaFor: () => schemaFor2,
3069
3500
  securityFor: () => securityFor,
3070
3501
  securityForSub: () => securityForSub,
3071
- upsertOnFor: () => upsertOnFor
3502
+ upsertOnFor: () => upsertOnFor2
3072
3503
  });
3073
3504
  module.exports = __toCommonJS(index_exports);
3074
3505
  init_cjs_shims();
@@ -3078,27 +3509,28 @@ init_src();
3078
3509
  init_cjs_shims();
3079
3510
  var import_common24 = require("@nestjs/common");
3080
3511
  var import_core2 = require("@nestjs/core");
3512
+ init_src();
3081
3513
 
3082
3514
  // src/lib/crud/app-layout/index.ts
3083
3515
  init_cjs_shims();
3084
3516
 
3085
3517
  // src/lib/crud/app-layout/app-layout.types.ts
3086
3518
  init_cjs_shims();
3087
- var import_zod25 = require("zod");
3088
- var SidebarLeafSchema = import_zod25.z.object({
3089
- kind: import_zod25.z.literal("item").default("item"),
3090
- id: import_zod25.z.string(),
3091
- label: import_zod25.z.string(),
3092
- position: import_zod25.z.number().optional()
3519
+ var import_zod35 = require("zod");
3520
+ var SidebarLeafSchema = import_zod35.z.object({
3521
+ kind: import_zod35.z.literal("item").default("item"),
3522
+ id: import_zod35.z.string(),
3523
+ label: import_zod35.z.string(),
3524
+ position: import_zod35.z.number().optional()
3093
3525
  });
3094
- var SidebarGroupSchema2 = import_zod25.z.object({
3095
- kind: import_zod25.z.literal("group").default("group"),
3096
- id: import_zod25.z.string(),
3097
- label: import_zod25.z.string(),
3098
- position: import_zod25.z.number().optional(),
3099
- children: import_zod25.z.array(SidebarLeafSchema).default([])
3526
+ var SidebarGroupSchema2 = import_zod35.z.object({
3527
+ kind: import_zod35.z.literal("group").default("group"),
3528
+ id: import_zod35.z.string(),
3529
+ label: import_zod35.z.string(),
3530
+ position: import_zod35.z.number().optional(),
3531
+ children: import_zod35.z.array(SidebarLeafSchema).default([])
3100
3532
  });
3101
- var SidebarNodeSchema = import_zod25.z.discriminatedUnion("kind", [
3533
+ var SidebarNodeSchema = import_zod35.z.discriminatedUnion("kind", [
3102
3534
  SidebarLeafSchema,
3103
3535
  SidebarGroupSchema2
3104
3536
  ]);
@@ -3205,7 +3637,7 @@ var readResourceJson = /* @__PURE__ */ __name((jsonPath) => {
3205
3637
  error: `Invalid JSON in ${jsonPath}: ${err.message}`
3206
3638
  };
3207
3639
  }
3208
- const resource = ResourceJsonSchema.safeParse(fileContent);
3640
+ const resource = buildResourceJsonSchema().safeParse(fileContent);
3209
3641
  if (resource.error) {
3210
3642
  return {
3211
3643
  success: false,
@@ -3327,7 +3759,7 @@ var expandExtendColumns = /* @__PURE__ */ __name((columns, dirPath) => {
3327
3759
  }
3328
3760
  return result;
3329
3761
  }, "expandExtendColumns");
3330
- var buildValueLabelColumns = /* @__PURE__ */ __name((columns) => (columns ?? []).flatMap((c) => {
3762
+ var buildValueLabelColumns2 = /* @__PURE__ */ __name((columns) => (columns ?? []).flatMap((c) => {
3331
3763
  const opts = c.fieldInput?.options;
3332
3764
  if (!opts?.emitObject || !Array.isArray(opts.values)) return [];
3333
3765
  return [
@@ -3340,7 +3772,7 @@ var buildValueLabelColumns = /* @__PURE__ */ __name((columns) => (columns ?? [])
3340
3772
  }
3341
3773
  ];
3342
3774
  }), "buildValueLabelColumns");
3343
- var applyRelationFormatDefault = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
3775
+ var applyRelationFormatDefault2 = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
3344
3776
  const fi = col.fieldInput;
3345
3777
  if (fi && fi.resource && !fi.format && !fi.type) {
3346
3778
  return {
@@ -3353,7 +3785,7 @@ var applyRelationFormatDefault = /* @__PURE__ */ __name((cols) => cols?.map((col
3353
3785
  }
3354
3786
  return col;
3355
3787
  }), "applyRelationFormatDefault");
3356
- var resolveColumnFieldVariants = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
3788
+ var resolveColumnFieldVariants2 = /* @__PURE__ */ __name((cols) => cols?.map((col) => {
3357
3789
  const fieldView = resolveViewField(col);
3358
3790
  const fieldTable = resolveTableField(col);
3359
3791
  return {
@@ -3444,7 +3876,7 @@ var localizeResource = /* @__PURE__ */ __name((config, t) => {
3444
3876
  columnLabels.set(col.id, translated);
3445
3877
  }
3446
3878
  translateEnumOptions(columns, t);
3447
- localized.valueLabelColumns = buildValueLabelColumns(columns);
3879
+ localized.valueLabelColumns = buildValueLabelColumns2(columns);
3448
3880
  }
3449
3881
  if (localized.views) {
3450
3882
  localized.views = patchViewTitles(localized.views, columnLabels);
@@ -3511,7 +3943,7 @@ var ResourceConfigRegistry = class {
3511
3943
  configs;
3512
3944
  translationRegistry;
3513
3945
  /**
3514
- * Per-language memo: `Map<language, Map<route, Resource>>`.
3946
+ * Per-language memo: `Map<language, Map<route, R>>`.
3515
3947
  * Cleared whenever the underlying configs reload (dev mode).
3516
3948
  */
3517
3949
  localizedCache = /* @__PURE__ */ new Map();
@@ -3519,8 +3951,8 @@ var ResourceConfigRegistry = class {
3519
3951
  this.loader = loader;
3520
3952
  this.configs = initialConfigs;
3521
3953
  }
3522
- setTranslationRegistry(registry) {
3523
- this.translationRegistry = registry;
3954
+ setTranslationRegistry(registry2) {
3955
+ this.translationRegistry = registry2;
3524
3956
  }
3525
3957
  async getAll(language) {
3526
3958
  if (IS_DEV) {
@@ -3549,6 +3981,10 @@ var ResourceConfigRegistry = class {
3549
3981
  }
3550
3982
  return config;
3551
3983
  }
3984
+ async findById(id, language) {
3985
+ const all = await this.getAll(language);
3986
+ return all.find((c) => c.id === id);
3987
+ }
3552
3988
  /**
3553
3989
  * On-disk directory containing `route`'s `resource.json`, if known.
3554
3990
  * Only meaningful after a load has populated the loader's internal map —
@@ -3614,7 +4050,7 @@ function _ts_metadata2(metadataKey, metadataValue) {
3614
4050
  }
3615
4051
  }
3616
4052
  __name(_ts_metadata2, "_ts_metadata");
3617
- var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups = {}, title, autoSave = true, translationRegistry, i18nConfig) => {
4053
+ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups = {}, title, autoSave = true, translationRegistry, i18nConfig, prefix) => {
3618
4054
  const layoutPayload = buildLayoutPayload(configs, sidebarGroups, title, autoSave, IS_DEV);
3619
4055
  let AppLayoutController = class AppLayoutController {
3620
4056
  static {
@@ -3692,7 +4128,7 @@ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups =
3692
4128
  _ts_metadata2("design:returntype", void 0)
3693
4129
  ], AppLayoutController.prototype, "getTranslations", null);
3694
4130
  AppLayoutController = _ts_decorate2([
3695
- (0, import_common2.Controller)("_app"),
4131
+ (0, import_common2.Controller)(prefix ? `${prefix}/_app` : "_app"),
3696
4132
  (0, import_swagger.ApiTags)("App"),
3697
4133
  _ts_metadata2("design:type", Function),
3698
4134
  _ts_metadata2("design:paramtypes", [
@@ -3704,9 +4140,9 @@ var createAppLayoutController = /* @__PURE__ */ __name((configs, sidebarGroups =
3704
4140
  ], AppLayoutController);
3705
4141
  return AppLayoutController;
3706
4142
  }, "createAppLayoutController");
3707
- var translateSidebarGroups = /* @__PURE__ */ __name((groups, language, registry) => {
3708
- if (!registry?.active) return groups;
3709
- const t = registry.translatorFor(language);
4143
+ var translateSidebarGroups = /* @__PURE__ */ __name((groups, language, registry2) => {
4144
+ if (!registry2?.active) return groups;
4145
+ const t = registry2.translatorFor(language);
3710
4146
  const translated = {};
3711
4147
  for (const [slug, cfg] of Object.entries(groups)) {
3712
4148
  const label = t(sidebarGroupKey(slug), cfg.label);
@@ -3717,9 +4153,9 @@ var translateSidebarGroups = /* @__PURE__ */ __name((groups, language, registry)
3717
4153
  }
3718
4154
  return translated;
3719
4155
  }, "translateSidebarGroups");
3720
- var translateTitle = /* @__PURE__ */ __name((title, language, registry) => {
3721
- if (!title || !registry?.active) return title;
3722
- const t = registry.translatorFor(language);
4156
+ var translateTitle = /* @__PURE__ */ __name((title, language, registry2) => {
4157
+ if (!title || !registry2?.active) return title;
4158
+ const t = registry2.translatorFor(language);
3723
4159
  return t("app.title", title);
3724
4160
  }, "translateTitle");
3725
4161
 
@@ -3944,49 +4380,49 @@ init_cjs_shims();
3944
4380
 
3945
4381
  // src/lib/crud/action/action.types.ts
3946
4382
  init_cjs_shims();
3947
- var import_zod26 = require("zod");
3948
- var ActionMetadataSchema = import_zod26.z.object({
4383
+ var import_zod36 = require("zod");
4384
+ var ActionMetadataSchema2 = import_zod36.z.object({
3949
4385
  /** URL segment used in the endpoint. */
3950
- id: import_zod26.z.string(),
4386
+ id: import_zod36.z.string(),
3951
4387
  /** Human-readable label shown as a button. */
3952
- label: import_zod26.z.string().optional(),
4388
+ label: import_zod36.z.string().optional(),
3953
4389
  /** MDI icon name, e.g. `"mdi:open-in-new"`. */
3954
- icon: import_zod26.z.string().optional(),
4390
+ icon: import_zod36.z.string().optional(),
3955
4391
  /** Tooltip text. Falls back to `label` when omitted. */
3956
- tooltip: import_zod26.z.string().optional(),
4392
+ tooltip: import_zod36.z.string().optional(),
3957
4393
  /** Per-row condition — button is hidden when false. */
3958
- condition: import_zod26.z.custom().optional()
4394
+ condition: import_zod36.z.custom().optional()
3959
4395
  });
3960
- var ResourceLinkActionSchema = ActionMetadataSchema.extend({
3961
- type: import_zod26.z.literal("link"),
4396
+ var ResourceLinkActionSchema2 = ActionMetadataSchema2.extend({
4397
+ type: import_zod36.z.literal("link"),
3962
4398
  /** URL to open. May contain `{id}` or `{env.VAR}` placeholders. */
3963
- href: import_zod26.z.string()
4399
+ href: import_zod36.z.string()
3964
4400
  });
3965
- var ResourceRowProcedureActionSchema = ActionMetadataSchema.extend({
3966
- type: import_zod26.z.literal("procedure").optional(),
4401
+ var ResourceRowProcedureActionSchema2 = ActionMetadataSchema2.extend({
4402
+ type: import_zod36.z.literal("procedure").optional(),
3967
4403
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3968
- method: import_zod26.z.string().optional(),
4404
+ method: import_zod36.z.string().optional(),
3969
4405
  /** Static data payload merged into the request body by the frontend. */
3970
- data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
4406
+ data: import_zod36.z.record(import_zod36.z.string(), import_zod36.z.unknown()).optional(),
3971
4407
  /** Procedure called with `(prisma, recordId)`. */
3972
- procedure: import_zod26.z.custom((v) => typeof v === "function")
4408
+ procedure: import_zod36.z.custom((v) => typeof v === "function")
3973
4409
  });
3974
- var ResourceTableProcedureActionSchema = ActionMetadataSchema.extend({
3975
- type: import_zod26.z.literal("procedure").optional(),
4410
+ var ResourceTableProcedureActionSchema2 = ActionMetadataSchema2.extend({
4411
+ type: import_zod36.z.literal("procedure").optional(),
3976
4412
  /** HTTP method for the endpoint. Defaults to `"post"`. */
3977
- method: import_zod26.z.string().optional(),
4413
+ method: import_zod36.z.string().optional(),
3978
4414
  /** Static data payload merged into the request body by the frontend. */
3979
- data: import_zod26.z.record(import_zod26.z.string(), import_zod26.z.unknown()).optional(),
4415
+ data: import_zod36.z.record(import_zod36.z.string(), import_zod36.z.unknown()).optional(),
3980
4416
  /** Procedure called with `(prisma)` — no record id. */
3981
- procedure: import_zod26.z.custom((v) => typeof v === "function")
4417
+ procedure: import_zod36.z.custom((v) => typeof v === "function")
3982
4418
  });
3983
- var ResourceRowActionSchema = import_zod26.z.union([
3984
- ResourceRowProcedureActionSchema,
3985
- ResourceLinkActionSchema
4419
+ var ResourceRowActionSchema2 = import_zod36.z.union([
4420
+ ResourceRowProcedureActionSchema2,
4421
+ ResourceLinkActionSchema2
3986
4422
  ]);
3987
- var ResourceTableActionSchema = import_zod26.z.union([
3988
- ResourceTableProcedureActionSchema,
3989
- ResourceLinkActionSchema
4423
+ var ResourceTableActionSchema2 = import_zod36.z.union([
4424
+ ResourceTableProcedureActionSchema2,
4425
+ ResourceLinkActionSchema2
3990
4426
  ]);
3991
4427
  var isRowProcedureAction = /* @__PURE__ */ __name((action) => action.type !== "link", "isRowProcedureAction");
3992
4428
  var isTableProcedureAction = /* @__PURE__ */ __name((action) => action.type !== "link", "isTableProcedureAction");
@@ -4022,17 +4458,17 @@ var loadActions = /* @__PURE__ */ __name(async (jsonActions, basePath, scope) =>
4022
4458
  }, "loadActions");
4023
4459
 
4024
4460
  // src/lib/crud/crud.config.ts
4025
- var resolveDefinition = /* @__PURE__ */ __name((config) => {
4461
+ var resolveDefinition2 = /* @__PURE__ */ __name((config) => {
4026
4462
  const def2 = config.definition;
4027
4463
  return typeof def2 === "function" ? def2() : def2;
4028
4464
  }, "resolveDefinition");
4029
- var isOperationEnabled = /* @__PURE__ */ __name((def2, op) => def2[op] != null, "isOperationEnabled");
4030
- var schemaFor = /* @__PURE__ */ __name((def2, op) => {
4465
+ var isOperationEnabled2 = /* @__PURE__ */ __name((def2, op) => def2[op] != null, "isOperationEnabled");
4466
+ var schemaFor2 = /* @__PURE__ */ __name((def2, op) => {
4031
4467
  const entry = def2[op];
4032
4468
  if (!entry || entry === true) return void 0;
4033
4469
  return entry.schema;
4034
4470
  }, "schemaFor");
4035
- var upsertOnFor = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
4471
+ var upsertOnFor2 = /* @__PURE__ */ __name((def2) => def2.upsert?.upsertOn, "upsertOnFor");
4036
4472
  var opSecurity = /* @__PURE__ */ __name((entry) => {
4037
4473
  if (!entry || entry === true) return void 0;
4038
4474
  return entry.security;
@@ -4048,7 +4484,7 @@ init_cjs_shims();
4048
4484
 
4049
4485
  // src/lib/crud/custom-repository/custom-repository.types.ts
4050
4486
  init_cjs_shims();
4051
- var import_zod27 = require("zod");
4487
+ var import_zod37 = require("zod");
4052
4488
  var CUSTOM_OPS = [
4053
4489
  "findAll",
4054
4490
  "findOne",
@@ -4065,7 +4501,7 @@ var PARENT_METHOD = {
4065
4501
  patch: "patchByParent",
4066
4502
  delete: "deleteByParent"
4067
4503
  };
4068
- var CustomRepositorySchema = import_zod27.z.custom((value) => typeof value === "object" && value !== null);
4504
+ var CustomRepositorySchema = import_zod37.z.custom((value) => typeof value === "object" && value !== null);
4069
4505
 
4070
4506
  // src/lib/crud/custom-repository/custom-repository.loader.ts
4071
4507
  init_cjs_shims();
@@ -4148,6 +4584,7 @@ var DEFAULT_ID_FIELD = "id";
4148
4584
 
4149
4585
  // src/lib/crud/data-source/prisma.adapter.ts
4150
4586
  init_cjs_shims();
4587
+ var DB_CHECK_TIMEOUT_MS = 3e3;
4151
4588
  var PrismaDataSourceAdapter = class {
4152
4589
  static {
4153
4590
  __name(this, "PrismaDataSourceAdapter");
@@ -4160,6 +4597,13 @@ var PrismaDataSourceAdapter = class {
4160
4597
  supports(model) {
4161
4598
  return typeof this.client?.[model] !== "undefined";
4162
4599
  }
4600
+ async healthCheck() {
4601
+ const c = this.client;
4602
+ await Promise.race([
4603
+ c.$queryRaw`SELECT 1`,
4604
+ new Promise((_, reject) => setTimeout(() => reject(new Error("Database health check timed out")), DB_CHECK_TIMEOUT_MS))
4605
+ ]);
4606
+ }
4163
4607
  async disconnect() {
4164
4608
  const c = this.client;
4165
4609
  if (typeof c?.$disconnect === "function") {
@@ -4203,8 +4647,8 @@ var LanguageInterceptor = class {
4203
4647
  __name(this, "LanguageInterceptor");
4204
4648
  }
4205
4649
  registry;
4206
- constructor(registry) {
4207
- this.registry = registry;
4650
+ constructor(registry2) {
4651
+ this.registry = registry2;
4208
4652
  }
4209
4653
  intercept(context, next) {
4210
4654
  const http = context.switchToHttp();
@@ -4245,7 +4689,7 @@ var unsupported = /* @__PURE__ */ __name((config, op) => {
4245
4689
  }, "unsupported");
4246
4690
  var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources, repository, configRegistry) => {
4247
4691
  const adapter = new PrismaDataSourceAdapter(prisma);
4248
- const repo = repository ?? {};
4692
+ const repo = repository ?? (prisma && typeof prisma === "object" ? prisma : {});
4249
4693
  const idField = config.idField ?? DEFAULT_ID_FIELD;
4250
4694
  const toId = /* @__PURE__ */ __name((id) => (config.idType ?? DEFAULT_ID_TYPE) === "number" ? +id : String(id), "toId");
4251
4695
  const parentRef = config.parent;
@@ -4401,13 +4845,18 @@ var createCustomRepository = /* @__PURE__ */ __name((prisma, config, dataSources
4401
4845
 
4402
4846
  // src/lib/crud/custom-repository/custom-repository.validate.ts
4403
4847
  init_cjs_shims();
4404
- var validateCustomRepository = /* @__PURE__ */ __name((config, repository) => {
4405
- const definition = resolveDefinition(config);
4406
- const enabled = CUSTOM_OPS.filter((op) => isOperationEnabled(definition, op));
4848
+ var validateCustomRepository = /* @__PURE__ */ __name((config, repository, adapterClient) => {
4849
+ const definition = resolveDefinition2(config);
4850
+ const enabled = CUSTOM_OPS.filter((op) => isOperationEnabled2(definition, op));
4407
4851
  const nested = !!config.parent;
4408
4852
  const methodFor = /* @__PURE__ */ __name((op) => nested ? PARENT_METHOD[op] : op, "methodFor");
4409
4853
  if (!repository) {
4410
- return `No repository.ts found. A custom resource implements its own data access; create ${config.name}/repository.ts with a default export implementing: ${enabled.map(methodFor).join(", ") || "no operations"}.`;
4854
+ if (enabled.length === 0) return void 0;
4855
+ if (adapterClient && typeof adapterClient === "object") {
4856
+ const missing2 = enabled.filter((op) => typeof adapterClient[methodFor(op)] !== "function");
4857
+ if (missing2.length === 0) return void 0;
4858
+ }
4859
+ return `No repository.ts found. A custom resource implements its own data access; create ${config.name}/repository.ts with a default export implementing: ${enabled.map(methodFor).join(", ")}.`;
4411
4860
  }
4412
4861
  const implemented = /* @__PURE__ */ __name((name) => typeof repository[name] === "function", "implemented");
4413
4862
  const missing = enabled.filter((op) => op === "patch" ? !implemented(methodFor("patch")) && !implemented(methodFor("update")) : !implemented(methodFor(op)));
@@ -5048,10 +5497,10 @@ var ReadRepository = class {
5048
5497
 
5049
5498
  // src/lib/crud/schema.utils.ts
5050
5499
  init_cjs_shims();
5051
- var import_zod29 = require("zod");
5500
+ var import_zod39 = require("zod");
5052
5501
  init_src();
5053
5502
  function isZodSchema(schema) {
5054
- return schema instanceof import_zod29.ZodObject;
5503
+ return schema instanceof import_zod39.ZodObject;
5055
5504
  }
5056
5505
  __name(isZodSchema, "isZodSchema");
5057
5506
  var isNullableProperty2 = /* @__PURE__ */ __name((property) => {
@@ -5063,11 +5512,11 @@ var dropNullableFromRequired2 = /* @__PURE__ */ __name((jsonSchema) => {
5063
5512
  if (!properties || !Array.isArray(required)) return;
5064
5513
  jsonSchema.required = required.filter((key) => !isNullableProperty2(properties[key]));
5065
5514
  }, "dropNullableFromRequired");
5066
- function toJsonSchema(schema) {
5515
+ function toJsonSchema2(schema) {
5067
5516
  if (isZodSchema(schema)) {
5068
5517
  let jsonSchema;
5069
5518
  try {
5070
- jsonSchema = (0, import_zod29.toJSONSchema)(schema, {
5519
+ jsonSchema = (0, import_zod39.toJSONSchema)(schema, {
5071
5520
  target: "openApi3",
5072
5521
  ...jsonSchemaOpts
5073
5522
  });
@@ -5081,7 +5530,7 @@ function toJsonSchema(schema) {
5081
5530
  }
5082
5531
  return schema;
5083
5532
  }
5084
- __name(toJsonSchema, "toJsonSchema");
5533
+ __name(toJsonSchema2, "toJsonSchema");
5085
5534
  var unwrap = /* @__PURE__ */ __name((schema) => {
5086
5535
  let s = schema;
5087
5536
  let t = s?._zod?.def?.type;
@@ -5180,7 +5629,7 @@ var WriteRepository = class {
5180
5629
  return new import_common8.NotFoundException(`${this.config.name} with id ${id} not found`);
5181
5630
  }
5182
5631
  upsertWhere(data) {
5183
- const keys = upsertOnFor(resolveDefinition(this.config));
5632
+ const keys = upsertOnFor2(resolveDefinition2(this.config));
5184
5633
  if (!keys) throw new import_common8.BadRequestException(`${this.config.name} has no upsertOn configured`);
5185
5634
  if (typeof keys === "string") return {
5186
5635
  [keys]: data[keys]
@@ -5471,9 +5920,9 @@ function createCrudRepository(prisma, config, dataSources, configRegistry) {
5471
5920
  if (!model) {
5472
5921
  throw new Error(`Model "${config.model}" not found on the provided PrismaClient. Check the resource config for "${config.name}".`);
5473
5922
  }
5474
- const definition = resolveDefinition(config);
5475
- const listSchema = schemaFor(definition, "findAll");
5476
- const oneSchema = schemaFor(definition, "findOne");
5923
+ const definition = resolveDefinition2(config);
5924
+ const listSchema = schemaFor2(definition, "findAll");
5925
+ const oneSchema = schemaFor2(definition, "findOne");
5477
5926
  const listSelect = listSchema ? toSelectFields(listSchema) : void 0;
5478
5927
  const oneSelect = oneSchema ? toSelectFields(oneSchema) : listSelect;
5479
5928
  const adapter = new PrismaDataSourceAdapter(prisma);
@@ -5819,9 +6268,9 @@ var CroutonSecurityGuard = class {
5819
6268
  reflector;
5820
6269
  registry;
5821
6270
  moduleRef;
5822
- constructor(reflector, registry, moduleRef) {
6271
+ constructor(reflector, registry2, moduleRef) {
5823
6272
  this.reflector = reflector;
5824
- this.registry = registry;
6273
+ this.registry = registry2;
5825
6274
  this.moduleRef = moduleRef;
5826
6275
  }
5827
6276
  async canActivate(context) {
@@ -5922,7 +6371,7 @@ init_cjs_shims();
5922
6371
  var import_common13 = require("@nestjs/common");
5923
6372
  var import_swagger3 = require("@nestjs/swagger");
5924
6373
  var defaultCreate = /* @__PURE__ */ __name((ctx) => {
5925
- if (!isOperationEnabled(ctx.definition, "create")) return null;
6374
+ if (!isOperationEnabled2(ctx.definition, "create")) return null;
5926
6375
  const { cls, config, createSchema, bodyDecorator } = ctx;
5927
6376
  const methodName = "create";
5928
6377
  return {
@@ -5941,7 +6390,7 @@ var defaultCreate = /* @__PURE__ */ __name((ctx) => {
5941
6390
  };
5942
6391
  }, "defaultCreate");
5943
6392
  var childCreate = /* @__PURE__ */ __name((sub) => (ctx) => {
5944
- if (!isOperationEnabled(sub.operations, "create")) return null;
6393
+ if (!isOperationEnabled2(sub.operations, "create")) return null;
5945
6394
  const { cls } = ctx;
5946
6395
  const methodName = `createChild_${sub.childRoute}`;
5947
6396
  const createFn = /* @__PURE__ */ __name(async function(id, body, req) {
@@ -5985,7 +6434,7 @@ init_cjs_shims();
5985
6434
  var import_common14 = require("@nestjs/common");
5986
6435
  var import_swagger4 = require("@nestjs/swagger");
5987
6436
  var defaultDelete = /* @__PURE__ */ __name((ctx) => {
5988
- if (!isOperationEnabled(ctx.definition, "delete")) return null;
6437
+ if (!isOperationEnabled2(ctx.definition, "delete")) return null;
5989
6438
  const { config } = ctx;
5990
6439
  const methodName = "delete";
5991
6440
  const { name } = config;
@@ -6001,7 +6450,7 @@ var defaultDelete = /* @__PURE__ */ __name((ctx) => {
6001
6450
  };
6002
6451
  }, "defaultDelete");
6003
6452
  var deleteChild = /* @__PURE__ */ __name((sub) => (ctx) => {
6004
- if (!isOperationEnabled(sub.operations, "delete")) return null;
6453
+ if (!isOperationEnabled2(sub.operations, "delete")) return null;
6005
6454
  const { cls } = ctx;
6006
6455
  const methodName = `deleteChild_${sub.childRoute}`;
6007
6456
  const deleteFn = /* @__PURE__ */ __name(async function(childId, parentId, req) {
@@ -6049,14 +6498,14 @@ var import_swagger5 = require("@nestjs/swagger");
6049
6498
 
6050
6499
  // src/lib/crud/request.dto.ts
6051
6500
  init_cjs_shims();
6052
- var import_zod_nestjs = require("@anatine/zod-nestjs");
6501
+ var import_nestjs_zod = require("nestjs-zod");
6053
6502
  init_src();
6054
- var RequestDtoNoOffset = class extends (0, import_zod_nestjs.createZodDto)(RequestSchema) {
6503
+ var RequestDtoNoOffset = class extends (0, import_nestjs_zod.createZodDto)(RequestSchema) {
6055
6504
  static {
6056
6505
  __name(this, "RequestDtoNoOffset");
6057
6506
  }
6058
6507
  };
6059
- var RequestDto = class extends (0, import_zod_nestjs.createZodDto)(RequestSchemaWithOffset) {
6508
+ var RequestDto = class extends (0, import_nestjs_zod.createZodDto)(RequestSchemaWithOffset) {
6060
6509
  static {
6061
6510
  __name(this, "RequestDto");
6062
6511
  }
@@ -6179,7 +6628,7 @@ var findAllByParent = /* @__PURE__ */ __name(async (repo, id, childRoute, params
6179
6628
  };
6180
6629
  }, "findAllByParent");
6181
6630
  var defaultFindAll = /* @__PURE__ */ __name((ctx) => {
6182
- if (!isOperationEnabled(ctx.definition, "findAll")) return;
6631
+ if (!isOperationEnabled2(ctx.definition, "findAll")) return;
6183
6632
  const { config } = ctx;
6184
6633
  const lookupLabel = config.lookup?.label;
6185
6634
  const findAll = /* @__PURE__ */ __name(async function(params, q, req) {
@@ -6196,7 +6645,7 @@ var defaultFindAll = /* @__PURE__ */ __name((ctx) => {
6196
6645
  };
6197
6646
  }, "defaultFindAll");
6198
6647
  var childFindAll = /* @__PURE__ */ __name((sub) => (ctx) => {
6199
- if (!isOperationEnabled(sub.operations, "findAll")) return;
6648
+ if (!isOperationEnabled2(sub.operations, "findAll")) return;
6200
6649
  const { cls } = ctx;
6201
6650
  const methodName = `findAllBy_${sub.childRoute}`;
6202
6651
  const findAll = /* @__PURE__ */ __name(async function(params, q, id, req) {
@@ -6224,7 +6673,7 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
6224
6673
  def(cls, methodName, properties.findAll);
6225
6674
  const d = desc(cls, methodName);
6226
6675
  (0, import_common15.Get)(route)(cls.prototype, methodName, d);
6227
- (0, import_common15.Query)(new ZodValidationPipe(RequestDtoNoOffset.zodSchema))(cls.prototype, methodName, 0);
6676
+ (0, import_common15.Query)(new ZodValidationPipe(RequestDtoNoOffset.schema))(cls.prototype, methodName, 0);
6228
6677
  (0, import_common15.Query)("q")(cls.prototype, methodName, 1);
6229
6678
  if (!sub) (0, import_common15.Req)()(cls.prototype, methodName, 2);
6230
6679
  (0, import_swagger5.ApiOperation)({
@@ -6236,7 +6685,7 @@ var registerFindAll = /* @__PURE__ */ __name((ctx, sub) => {
6236
6685
  ...listSchema && {
6237
6686
  schema: {
6238
6687
  type: "array",
6239
- items: toJsonSchema(listSchema)
6688
+ items: toJsonSchema2(listSchema)
6240
6689
  }
6241
6690
  }
6242
6691
  })(cls.prototype, methodName, d);
@@ -6249,7 +6698,7 @@ init_cjs_shims();
6249
6698
  var import_common16 = require("@nestjs/common");
6250
6699
  var import_swagger6 = require("@nestjs/swagger");
6251
6700
  var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
6252
- if (!isOperationEnabled(ctx.definition, "findOne")) return null;
6701
+ if (!isOperationEnabled2(ctx.definition, "findOne")) return null;
6253
6702
  const { cls, config } = ctx;
6254
6703
  const methodName = "findOne";
6255
6704
  return {
@@ -6266,7 +6715,7 @@ var defaultFindOne = /* @__PURE__ */ __name((ctx) => {
6266
6715
  };
6267
6716
  }, "defaultFindOne");
6268
6717
  var childFindOne = /* @__PURE__ */ __name((sub) => (ctx) => {
6269
- if (!isOperationEnabled(sub.operations, "findOne")) return null;
6718
+ if (!isOperationEnabled2(sub.operations, "findOne")) return null;
6270
6719
  const { cls } = ctx;
6271
6720
  const methodName = `findOneChild_${sub.childRoute}`;
6272
6721
  const findOneFn = /* @__PURE__ */ __name(async function(parentId, childId, req) {
@@ -6302,7 +6751,7 @@ var registerFindOne = /* @__PURE__ */ __name((ctx, sub) => {
6302
6751
  status: 200,
6303
6752
  description: `The ${name}`,
6304
6753
  ...ctx.oneSchema && {
6305
- schema: toJsonSchema(ctx.oneSchema)
6754
+ schema: toJsonSchema2(ctx.oneSchema)
6306
6755
  }
6307
6756
  })(cls.prototype, methodName, d);
6308
6757
  (0, import_swagger6.ApiNotFoundResponse)({
@@ -6317,7 +6766,7 @@ init_cjs_shims();
6317
6766
  var import_common17 = require("@nestjs/common");
6318
6767
  var import_swagger7 = require("@nestjs/swagger");
6319
6768
  var defaultPatch = /* @__PURE__ */ __name((ctx) => {
6320
- if (!isOperationEnabled(ctx.definition, "patch")) return null;
6769
+ if (!isOperationEnabled2(ctx.definition, "patch")) return null;
6321
6770
  const { cls, config, patchSchema, bodyDecorator } = ctx;
6322
6771
  const methodName = "patch";
6323
6772
  return {
@@ -6335,7 +6784,7 @@ var defaultPatch = /* @__PURE__ */ __name((ctx) => {
6335
6784
  };
6336
6785
  }, "defaultPatch");
6337
6786
  var childPatch = /* @__PURE__ */ __name((sub) => (ctx) => {
6338
- if (!isOperationEnabled(sub.operations, "patch")) return null;
6787
+ if (!isOperationEnabled2(sub.operations, "patch")) return null;
6339
6788
  const { cls } = ctx;
6340
6789
  const methodName = `patchChild_${sub.childRoute}`;
6341
6790
  const patchFn = /* @__PURE__ */ __name(async function(_id, childId, body, req) {
@@ -6386,26 +6835,26 @@ init_dev_mode();
6386
6835
 
6387
6836
  // src/lib/crud/resource/PatchResourceJson.schema.ts
6388
6837
  init_cjs_shims();
6389
- var import_zod30 = require("zod");
6390
- var FieldVariantPatchSchema = import_zod30.z.object({
6391
- type: import_zod30.z.string().nullable().optional(),
6392
- format: import_zod30.z.string().nullable().optional(),
6393
- resource: import_zod30.z.string().nullable().optional(),
6394
- position: import_zod30.z.number().nullable().optional(),
6395
- options: import_zod30.z.record(import_zod30.z.string(), import_zod30.z.unknown().nullable()).optional()
6838
+ var import_zod40 = require("zod");
6839
+ var FieldVariantPatchSchema = import_zod40.z.object({
6840
+ type: import_zod40.z.string().nullable().optional(),
6841
+ format: import_zod40.z.string().nullable().optional(),
6842
+ resource: import_zod40.z.string().nullable().optional(),
6843
+ position: import_zod40.z.number().nullable().optional(),
6844
+ options: import_zod40.z.record(import_zod40.z.string(), import_zod40.z.unknown().nullable()).optional()
6396
6845
  }).partial();
6397
- var PatchColumnSchema = import_zod30.z.object({
6398
- label: import_zod30.z.string().optional(),
6399
- column: import_zod30.z.string().optional(),
6400
- hiddenInTable: import_zod30.z.boolean().optional(),
6401
- hiddenInForm: import_zod30.z.boolean().optional(),
6402
- hiddenInView: import_zod30.z.boolean().optional(),
6846
+ var PatchColumnSchema = import_zod40.z.object({
6847
+ label: import_zod40.z.string().optional(),
6848
+ column: import_zod40.z.string().optional(),
6849
+ hiddenInTable: import_zod40.z.boolean().optional(),
6850
+ hiddenInForm: import_zod40.z.boolean().optional(),
6851
+ hiddenInView: import_zod40.z.boolean().optional(),
6403
6852
  fieldInput: FieldVariantPatchSchema.optional(),
6404
6853
  fieldView: FieldVariantPatchSchema.optional(),
6405
6854
  fieldTable: FieldVariantPatchSchema.optional()
6406
6855
  }).partial();
6407
- var PatchResourceJsonSchema = import_zod30.z.object({
6408
- columns: import_zod30.z.record(import_zod30.z.string(), PatchColumnSchema)
6856
+ var PatchResourceJsonSchema = import_zod40.z.object({
6857
+ columns: import_zod40.z.record(import_zod40.z.string(), PatchColumnSchema)
6409
6858
  });
6410
6859
 
6411
6860
  // src/lib/crud/resource/WriteResourceJson.ts
@@ -6468,7 +6917,7 @@ var applyColumnPatch = /* @__PURE__ */ __name((raw, patch) => {
6468
6917
  }, "applyColumnPatch");
6469
6918
  var serializeResourceJson = /* @__PURE__ */ __name((config) => `${JSON.stringify(config, null, 2)}
6470
6919
  `, "serializeResourceJson");
6471
- var validateResourceJson = /* @__PURE__ */ __name((raw) => ResourceJsonSchema.safeParse(raw), "validateResourceJson");
6920
+ var validateResourceJson = /* @__PURE__ */ __name((raw) => buildResourceJsonSchema().safeParse(raw), "validateResourceJson");
6472
6921
  var writeRawResourceJson = /* @__PURE__ */ __name((jsonPath, raw) => {
6473
6922
  (0, import_node_fs6.writeFileSync)(jsonPath, serializeResourceJson(raw), "utf-8");
6474
6923
  }, "writeRawResourceJson");
@@ -6476,6 +6925,12 @@ var writeRawResourceJson = /* @__PURE__ */ __name((jsonPath, raw) => {
6476
6925
  // src/lib/crud/operations/payload-builders.ts
6477
6926
  init_cjs_shims();
6478
6927
  init_src();
6928
+ var pickExtensions = /* @__PURE__ */ __name((config) => Object.fromEntries([
6929
+ ...getResourceExtensions().keys()
6930
+ ].filter((k) => config[k] !== void 0).map((k) => [
6931
+ k,
6932
+ config[k]
6933
+ ])), "pickExtensions");
6479
6934
  var resolveEnvPlaceholders = /* @__PURE__ */ __name((value) => value.replace(/\{env\.([^}]+)\}/g, (match, varName) => process.env[varName] ?? match), "resolveEnvPlaceholders");
6480
6935
  var RESOURCE_OPS = [
6481
6936
  "findAll",
@@ -6501,22 +6956,22 @@ var OP_SUFFIX = {
6501
6956
  patch: "/{id}",
6502
6957
  delete: "/{id}"
6503
6958
  };
6504
- var buildResourceOperations = /* @__PURE__ */ __name((definition, baseUri) => Object.fromEntries(RESOURCE_OPS.filter((op) => isOperationEnabled(definition, op)).map((op) => [
6959
+ var buildResourceOperations = /* @__PURE__ */ __name((definition, baseUri) => Object.fromEntries(RESOURCE_OPS.filter((op) => isOperationEnabled2(definition, op)).map((op) => [
6505
6960
  op,
6506
6961
  {
6507
6962
  uri: `${baseUri}${OP_SUFFIX[op]}`,
6508
6963
  method: OP_METHOD[op]
6509
6964
  }
6510
6965
  ])), "buildResourceOperations");
6511
- var buildDefinitionPayload = /* @__PURE__ */ __name((config) => {
6966
+ var buildDefinitionPayload2 = /* @__PURE__ */ __name((config) => {
6512
6967
  const { route, name, tag, idType = "string" } = config;
6513
- const definition = resolveDefinition(config);
6514
- const listSchema = schemaFor(definition, "findAll");
6515
- const oneSchema = schemaFor(definition, "findOne") ?? listSchema;
6516
- const createSchema = schemaFor(definition, "create");
6517
- const updateSchema = schemaFor(definition, "update");
6518
- const patchSchema = schemaFor(definition, "patch");
6519
- const upsertSchema = schemaFor(definition, "upsert") ?? createSchema;
6968
+ const definition = resolveDefinition2(config);
6969
+ const listSchema = schemaFor2(definition, "findAll");
6970
+ const oneSchema = schemaFor2(definition, "findOne") ?? listSchema;
6971
+ const createSchema = schemaFor2(definition, "create");
6972
+ const updateSchema = schemaFor2(definition, "update");
6973
+ const patchSchema = schemaFor2(definition, "patch");
6974
+ const upsertSchema = schemaFor2(definition, "upsert") ?? createSchema;
6520
6975
  const operations = [
6521
6976
  "findAll",
6522
6977
  "findOne",
@@ -6525,44 +6980,45 @@ var buildDefinitionPayload = /* @__PURE__ */ __name((config) => {
6525
6980
  "patch",
6526
6981
  "upsert",
6527
6982
  "delete"
6528
- ].filter((op) => isOperationEnabled(definition, op));
6983
+ ].filter((op) => isOperationEnabled2(definition, op));
6529
6984
  return {
6530
6985
  name,
6531
6986
  route,
6532
6987
  idType,
6533
6988
  tag,
6534
6989
  operations,
6535
- upsertOn: upsertOnFor(definition),
6990
+ upsertOn: upsertOnFor2(definition),
6536
6991
  display: config.display,
6537
6992
  schemas: {
6538
6993
  ...listSchema && {
6539
- findAll: toJsonSchema(listSchema)
6994
+ findAll: toJsonSchema2(listSchema)
6540
6995
  },
6541
6996
  ...oneSchema && {
6542
- findOne: toJsonSchema(oneSchema)
6997
+ findOne: toJsonSchema2(oneSchema)
6543
6998
  },
6544
6999
  ...createSchema && {
6545
- create: toJsonSchema(createSchema)
7000
+ create: toJsonSchema2(createSchema)
6546
7001
  },
6547
7002
  ...updateSchema && {
6548
- update: toJsonSchema(updateSchema)
7003
+ update: toJsonSchema2(updateSchema)
6549
7004
  },
6550
7005
  ...patchSchema && {
6551
- patch: toJsonSchema(patchSchema)
7006
+ patch: toJsonSchema2(patchSchema)
6552
7007
  },
6553
- ...isOperationEnabled(definition, "upsert") && upsertSchema ? {
6554
- upsert: toJsonSchema(upsertSchema)
7008
+ ...isOperationEnabled2(definition, "upsert") && upsertSchema ? {
7009
+ upsert: toJsonSchema2(upsertSchema)
6555
7010
  } : {}
6556
- }
7011
+ },
7012
+ ...pickExtensions(config)
6557
7013
  };
6558
7014
  }, "buildDefinitionPayload");
6559
- var buildResourceJsonPayload = /* @__PURE__ */ __name((config, baseUrl) => {
7015
+ var buildResourceJsonPayload2 = /* @__PURE__ */ __name((config, baseUrl) => {
6560
7016
  const { name, route } = config;
6561
- const definition = resolveDefinition(config);
7017
+ const definition = resolveDefinition2(config);
6562
7018
  const uri = `${baseUrl}/${route}`;
6563
7019
  const operations = Object.fromEntries(RESOURCE_OPS.map((op) => [
6564
7020
  op,
6565
- isOperationEnabled(definition, op)
7021
+ isOperationEnabled2(definition, op)
6566
7022
  ]));
6567
7023
  operations.lookup = `${uri}?q={text}`;
6568
7024
  const form = config.views?.["form"];
@@ -6571,10 +7027,11 @@ var buildResourceJsonPayload = /* @__PURE__ */ __name((config, baseUrl) => {
6571
7027
  ui: form.ui_schema
6572
7028
  } : null;
6573
7029
  return {
6574
- id: name,
7030
+ id: config.id ?? route,
6575
7031
  uri,
6576
7032
  operations,
6577
- schema
7033
+ schema,
7034
+ ...pickExtensions(config)
6578
7035
  };
6579
7036
  }, "buildResourceJsonPayload");
6580
7037
  var _resolveActions = /* @__PURE__ */ __name((baseUrl, actions) => {
@@ -6597,12 +7054,12 @@ var resolveActions = /* @__PURE__ */ __name((baseUrl, actions) => {
6597
7054
  "{id}"
6598
7055
  ], actions);
6599
7056
  }, "resolveActions");
6600
- var buildViewsPayload = /* @__PURE__ */ __name((config, baseUrl) => {
7057
+ var buildViewsPayload2 = /* @__PURE__ */ __name((config, baseUrl) => {
6601
7058
  if (!config.views || !Object.keys(config.views).length) return void 0;
6602
- const definition = resolveDefinition(config);
7059
+ const definition = resolveDefinition2(config);
6603
7060
  const baseUri = config.parent ? `${baseUrl}/${config.parent.route}/{${config.parent.param}}/${config.route}` : `${baseUrl}/${config.route}`;
6604
7061
  const operations = buildResourceOperations(definition, baseUri);
6605
- if (isOperationEnabled(definition, "findAll")) {
7062
+ if (isOperationEnabled2(definition, "findAll")) {
6606
7063
  operations["lookup"] = `${baseUri}?q={text}`;
6607
7064
  }
6608
7065
  const schemas = Object.fromEntries(Object.entries(config.views).map(([key, v]) => [
@@ -6617,7 +7074,7 @@ var buildViewsPayload = /* @__PURE__ */ __name((config, baseUrl) => {
6617
7074
  ]));
6618
7075
  const baseAction = `${baseUri}${config.route}`;
6619
7076
  return {
6620
- id: config.name,
7077
+ id: config.id ?? config.route,
6621
7078
  name: config.name,
6622
7079
  route: config.route,
6623
7080
  uri: baseUri,
@@ -6631,7 +7088,8 @@ var buildViewsPayload = /* @__PURE__ */ __name((config, baseUrl) => {
6631
7088
  display: config.display,
6632
7089
  schemas,
6633
7090
  actions: resolveActions(baseAction, config.actions),
6634
- tableActions: resolveActions(baseAction, config.tableActions)
7091
+ tableActions: resolveActions(baseAction, config.tableActions),
7092
+ ...pickExtensions(config)
6635
7093
  };
6636
7094
  }, "buildViewsPayload");
6637
7095
  var buildSubResourceViewsPayload = /* @__PURE__ */ __name((config, sub, baseUrl) => {
@@ -6691,16 +7149,21 @@ var buildEditableColumnsPayload = /* @__PURE__ */ __name((config) => {
6691
7149
  // src/lib/crud/operations/register-schema-endpoints.ts
6692
7150
  var import_node_path9 = require("path");
6693
7151
  var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
6694
- const { cls, config } = ctx;
7152
+ const { cls, config, schemaEnricher } = ctx;
6695
7153
  const { route, name } = config;
6696
- const definitionPayload = buildDefinitionPayload(config);
7154
+ const definitionPayload = buildDefinitionPayload2(config);
6697
7155
  def(cls, "getDefinition", async function() {
6698
7156
  const language = getRequestLanguage();
7157
+ let payload = definitionPayload;
6699
7158
  if (IS_DEV || language) {
6700
7159
  const fresh = await this.configRegistry.getByRoute(route, language);
6701
- if (fresh) return buildDefinitionPayload(fresh);
7160
+ if (fresh) payload = buildDefinitionPayload2(fresh);
6702
7161
  }
6703
- return definitionPayload;
7162
+ if (!schemaEnricher) return payload;
7163
+ return {
7164
+ ...payload,
7165
+ ...schemaEnricher(payload)
7166
+ };
6704
7167
  });
6705
7168
  const d = desc(cls, "getDefinition");
6706
7169
  (0, import_common18.Get)("definition")(cls.prototype, "getDefinition", d);
@@ -6717,16 +7180,21 @@ var registerDefinitionEndpoint = /* @__PURE__ */ __name((ctx) => {
6717
7180
  }
6718
7181
  }, "registerDefinitionEndpoint");
6719
7182
  var registerResourceJsonEndpoint = /* @__PURE__ */ __name((ctx) => {
6720
- const { cls, config, baseUrl } = ctx;
7183
+ const { cls, config, baseUrl, schemaEnricher } = ctx;
6721
7184
  const { route, name } = config;
6722
- const resourceJsonPayload = buildResourceJsonPayload(config, baseUrl);
7185
+ const resourceJsonPayload = buildResourceJsonPayload2(config, baseUrl);
6723
7186
  def(cls, "getResourceJson", async function() {
6724
7187
  const language = getRequestLanguage();
7188
+ let payload = resourceJsonPayload;
6725
7189
  if (IS_DEV || language) {
6726
7190
  const fresh = await this.configRegistry.getByRoute(route, language);
6727
- if (fresh) return buildResourceJsonPayload(fresh, baseUrl);
7191
+ if (fresh) payload = buildResourceJsonPayload2(fresh, baseUrl);
6728
7192
  }
6729
- return resourceJsonPayload;
7193
+ if (!schemaEnricher) return payload;
7194
+ return {
7195
+ ...payload,
7196
+ ...schemaEnricher(payload)
7197
+ };
6730
7198
  });
6731
7199
  const d = desc(cls, "getResourceJson");
6732
7200
  (0, import_common18.Get)("resource.json")(cls.prototype, "getResourceJson", d);
@@ -6866,20 +7334,25 @@ var import_common19 = require("@nestjs/common");
6866
7334
  var import_swagger9 = require("@nestjs/swagger");
6867
7335
  init_dev_mode();
6868
7336
  var defaultSchemas = /* @__PURE__ */ __name((ctx) => {
6869
- const { config, baseUrl } = ctx;
7337
+ const { config, baseUrl, schemaEnricher } = ctx;
6870
7338
  const { route, name } = config;
6871
- const viewsPayload = buildViewsPayload(config, baseUrl);
7339
+ const viewsPayload = buildViewsPayload2(config, baseUrl);
6872
7340
  return {
6873
7341
  route: "schemas",
6874
7342
  methodName: "getSchemas",
6875
7343
  name,
6876
7344
  schemasFn: /* @__PURE__ */ __name(async function() {
6877
7345
  const language = getRequestLanguage();
7346
+ let payload = viewsPayload;
6878
7347
  if (IS_DEV || language) {
6879
7348
  const fresh = await this.configRegistry.getByRoute(route, language);
6880
- if (fresh) return buildViewsPayload(fresh, baseUrl) ?? viewsPayload;
7349
+ if (fresh) payload = buildViewsPayload2(fresh, baseUrl) ?? viewsPayload;
6881
7350
  }
6882
- return viewsPayload;
7351
+ if (!payload || !schemaEnricher) return payload;
7352
+ return {
7353
+ ...payload,
7354
+ ...schemaEnricher(payload)
7355
+ };
6883
7356
  }, "schemasFn"),
6884
7357
  decorators: /* @__PURE__ */ __name(() => {
6885
7358
  }, "decorators")
@@ -6928,7 +7401,7 @@ init_cjs_shims();
6928
7401
  var import_common20 = require("@nestjs/common");
6929
7402
  var import_swagger10 = require("@nestjs/swagger");
6930
7403
  var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
6931
- if (!isOperationEnabled(ctx.definition, "update")) return null;
7404
+ if (!isOperationEnabled2(ctx.definition, "update")) return null;
6932
7405
  const { cls, config, updateSchema, bodyDecorator } = ctx;
6933
7406
  const methodName = "update";
6934
7407
  return {
@@ -6946,7 +7419,7 @@ var defaultUpdate = /* @__PURE__ */ __name((ctx) => {
6946
7419
  };
6947
7420
  }, "defaultUpdate");
6948
7421
  var childUpdate = /* @__PURE__ */ __name((sub) => (ctx) => {
6949
- if (!isOperationEnabled(sub.operations, "update")) return null;
7422
+ if (!isOperationEnabled2(sub.operations, "update")) return null;
6950
7423
  const { cls } = ctx;
6951
7424
  const methodName = `updateChild_${sub.childRoute}`;
6952
7425
  const updateFn = /* @__PURE__ */ __name(async function(_id, childId, body, req) {
@@ -7019,17 +7492,17 @@ var registerEndpoint = /* @__PURE__ */ __name((ctx, sub) => {
7019
7492
  }, "registerEndpoint");
7020
7493
 
7021
7494
  // src/lib/crud/crud-controller.factory.ts
7022
- function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEnabled = false) {
7495
+ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEnabled = false, prefix, schemaEnricher) {
7023
7496
  const { route, name, tag, idType = "string" } = config;
7024
- const definition = resolveDefinition(config);
7025
- const listSchema = schemaFor(definition, "findAll");
7026
- const oneSchema = schemaFor(definition, "findOne") ?? listSchema;
7027
- const createSchema = schemaFor(definition, "create");
7028
- const updateSchema = schemaFor(definition, "update");
7029
- const explicitPatchSchema = schemaFor(definition, "patch");
7497
+ const definition = resolveDefinition2(config);
7498
+ const listSchema = schemaFor2(definition, "findAll");
7499
+ const oneSchema = schemaFor2(definition, "findOne") ?? listSchema;
7500
+ const createSchema = schemaFor2(definition, "create");
7501
+ const updateSchema = schemaFor2(definition, "update");
7502
+ const explicitPatchSchema = schemaFor2(definition, "patch");
7030
7503
  const patchSchema = explicitPatchSchema ?? (updateSchema && isZodSchema(updateSchema) ? updateSchema.partial() : void 0) ?? updateSchema;
7031
- const upsertSchema = schemaFor(definition, "upsert") ?? createSchema;
7032
- if (isOperationEnabled(definition, "upsert") && !upsertOnFor(definition)) {
7504
+ const upsertSchema = schemaFor2(definition, "upsert") ?? createSchema;
7505
+ if (isOperationEnabled2(definition, "upsert") && !upsertOnFor2(definition)) {
7033
7506
  throw new Error(`Resource "${name}" declares 'upsert' but no upsertOn`);
7034
7507
  }
7035
7508
  const bodyDecorator = /* @__PURE__ */ __name((schema, options) => {
@@ -7037,9 +7510,9 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7037
7510
  if (isZodSchema(schema)) return (0, import_common21.Body)(new ZodValidationPipe(schema, options));
7038
7511
  return (0, import_common21.Body)();
7039
7512
  }, "bodyDecorator");
7040
- const resolveClient = /* @__PURE__ */ __name((registry, resource) => {
7513
+ const resolveClient = /* @__PURE__ */ __name((registry2, resource) => {
7041
7514
  try {
7042
- return registry.resolve(resource.database);
7515
+ return registry2.resolve(resource.database);
7043
7516
  } catch (e) {
7044
7517
  if (resource.kind === "custom") return void 0;
7045
7518
  throw e;
@@ -7051,9 +7524,9 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7051
7524
  }
7052
7525
  repo;
7053
7526
  configRegistry;
7054
- constructor(registry, configRegistry) {
7055
- const prisma = resolveClient(registry, config);
7056
- this.repo = createCrudRepository(prisma, config, registry, configRegistry);
7527
+ constructor(registry2, configRegistry) {
7528
+ const prisma = resolveClient(registry2, config);
7529
+ this.repo = createCrudRepository(prisma, config, registry2, configRegistry);
7057
7530
  this.configRegistry = configRegistry;
7058
7531
  }
7059
7532
  };
@@ -7080,10 +7553,12 @@ function createCrudController(config, baseUrl, moduleDefaultSecurity, securityEn
7080
7553
  bodyDecorator,
7081
7554
  baseUrl,
7082
7555
  moduleDefaultSecurity,
7083
- secure
7556
+ secure,
7557
+ schemaEnricher
7084
7558
  };
7085
7559
  registerEndpoints(ctx);
7086
- (0, import_common21.Controller)(resourceControllerPath(route, config.parent))(CrudControllerBase);
7560
+ const controllerPath = resourceControllerPath(route, config.parent);
7561
+ (0, import_common21.Controller)(prefix ? `${prefix}/${controllerPath}` : controllerPath)(CrudControllerBase);
7087
7562
  if (securityEnabled) {
7088
7563
  (0, import_common21.UseGuards)(CroutonSecurityGuard)(CrudControllerBase);
7089
7564
  }
@@ -7832,13 +8307,13 @@ var resolveFromRoot = /* @__PURE__ */ __name((root, p) => (0, import_node_path11
7832
8307
 
7833
8308
  // ../crouton-codegen/src/scaffold.ts
7834
8309
  init_cjs_shims();
7835
- var import_zod31 = require("zod");
8310
+ var import_zod41 = require("zod");
7836
8311
  init_src();
7837
8312
  var import_promises5 = require("fs/promises");
7838
8313
  var import_node_path12 = require("path");
7839
8314
  var ScallfoldDatasourceSchema = DataSourceShape.extend({
7840
8315
  /** Folder name under `dataSourcesDir`. */
7841
- folder: import_zod31.z.string().default("default")
8316
+ folder: import_zod41.z.string().default("default")
7842
8317
  }).transform(transformDataSource);
7843
8318
 
7844
8319
  // ../crouton-codegen/src/datasource-scaffold.ts
@@ -8727,12 +9202,12 @@ init_cjs_shims();
8727
9202
 
8728
9203
  // src/lib/crud/enum-registry/enum-registry.types.ts
8729
9204
  init_cjs_shims();
8730
- var import_zod32 = require("zod");
8731
- var EnumEntrySchema = import_zod32.z.object({
8732
- value: import_zod32.z.unknown(),
8733
- label: import_zod32.z.string()
9205
+ var import_zod42 = require("zod");
9206
+ var EnumEntrySchema2 = import_zod42.z.object({
9207
+ value: import_zod42.z.unknown(),
9208
+ label: import_zod42.z.string()
8734
9209
  });
8735
- var EnumRegistrySchema = import_zod32.z.record(import_zod32.z.string(), import_zod32.z.array(EnumEntrySchema)).default({});
9210
+ var EnumRegistrySchema2 = import_zod42.z.record(import_zod42.z.string(), import_zod42.z.array(EnumEntrySchema2)).default({});
8736
9211
 
8737
9212
  // src/lib/crud/enum-registry/enum-registry.loader.ts
8738
9213
  init_cjs_shims();
@@ -8754,17 +9229,17 @@ var loadEnumRegistry = /* @__PURE__ */ __name((startDir, enumsFile) => {
8754
9229
  dir = parent;
8755
9230
  }
8756
9231
  }
8757
- if (!file || !(0, import_node_fs8.existsSync)(file)) return EnumRegistrySchema.parse(void 0);
9232
+ if (!file || !(0, import_node_fs8.existsSync)(file)) return EnumRegistrySchema2.parse(void 0);
8758
9233
  try {
8759
- return EnumRegistrySchema.parse(JSON.parse((0, import_node_fs8.readFileSync)(file, "utf-8")));
9234
+ return EnumRegistrySchema2.parse(JSON.parse((0, import_node_fs8.readFileSync)(file, "utf-8")));
8760
9235
  } catch {
8761
- return EnumRegistrySchema.parse(void 0);
9236
+ return EnumRegistrySchema2.parse(void 0);
8762
9237
  }
8763
9238
  }, "loadEnumRegistry");
8764
9239
 
8765
9240
  // src/lib/crud/enum-registry/enum-registry.injector.ts
8766
9241
  init_cjs_shims();
8767
- var injectEnumValues = /* @__PURE__ */ __name((columns, enums) => {
9242
+ var injectEnumValues2 = /* @__PURE__ */ __name((columns, enums) => {
8768
9243
  if (!columns) return;
8769
9244
  for (const col of columns) {
8770
9245
  if (!col.enum) continue;
@@ -8829,7 +9304,7 @@ var upsertOp = /* @__PURE__ */ __name((entry, schema) => {
8829
9304
  }
8830
9305
  return void 0;
8831
9306
  }, "upsertOp");
8832
- var buildResourceDefinitions = /* @__PURE__ */ __name((schema, operations, enrichedColumns) => {
9307
+ var buildResourceDefinitions2 = /* @__PURE__ */ __name((schema, operations, enrichedColumns) => {
8833
9308
  const picked = pickByColumns(schema, enrichedColumns);
8834
9309
  const createSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.createable !== false);
8835
9310
  const updateSchema = pickByColumns(schema, enrichedColumns, (c) => !c.idField && c.updateable !== false);
@@ -8864,9 +9339,9 @@ init_cjs_shims();
8864
9339
 
8865
9340
  // src/lib/crud/adapter/relation-type.ts
8866
9341
  init_cjs_shims();
8867
- var import_zod33 = require("zod");
9342
+ var import_zod43 = require("zod");
8868
9343
  var unwrapZodType = /* @__PURE__ */ __name((type) => {
8869
- if (type instanceof import_zod33.ZodOptional || type instanceof import_zod33.ZodNullable) {
9344
+ if (type instanceof import_zod43.ZodOptional || type instanceof import_zod43.ZodNullable) {
8870
9345
  return unwrapZodType(type.unwrap());
8871
9346
  }
8872
9347
  return type;
@@ -8876,7 +9351,7 @@ var deriveRelationType = /* @__PURE__ */ __name((schema, columnId) => {
8876
9351
  const field = schema.shape[columnId];
8877
9352
  if (!field) return void 0;
8878
9353
  const inner = unwrapZodType(field);
8879
- return inner instanceof import_zod33.ZodArray ? "oneToMany" : "manyToOne";
9354
+ return inner instanceof import_zod43.ZodArray ? "oneToMany" : "manyToOne";
8880
9355
  }, "deriveRelationType");
8881
9356
  var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
8882
9357
  const base = col.column ?? col.id;
@@ -8886,7 +9361,7 @@ var deriveRelationTypeFromColumns = /* @__PURE__ */ __name((col, cols) => {
8886
9361
  ]);
8887
9362
  return cols.some((c) => fkNames.has(c.id)) ? "manyToOne" : "oneToMany";
8888
9363
  }, "deriveRelationTypeFromColumns");
8889
- var enrichRelationTypes = /* @__PURE__ */ __name((columns, schema) => {
9364
+ var enrichRelationTypes2 = /* @__PURE__ */ __name((columns, schema) => {
8890
9365
  if (!schema) return columns;
8891
9366
  return columns.map((col) => {
8892
9367
  const fi = col.fieldInput;
@@ -8907,7 +9382,7 @@ var enrichRelationTypes = /* @__PURE__ */ __name((columns, schema) => {
8907
9382
  }, "enrichRelationTypes");
8908
9383
 
8909
9384
  // src/lib/crud/adapter/column-enrichment.ts
8910
- var enrichActionColumns = /* @__PURE__ */ __name((columns, parentRoute, subResources, baseUrl) => {
9385
+ var enrichActionColumns2 = /* @__PURE__ */ __name((columns, parentRoute, subResources, baseUrl) => {
8911
9386
  if (!columns) return columns;
8912
9387
  const base = baseUrl ?? "";
8913
9388
  return columns.map((col) => {
@@ -8971,7 +9446,7 @@ var enrichNestedRelationColumns = /* @__PURE__ */ __name((cols, dir, baseUrl) =>
8971
9446
  };
8972
9447
  });
8973
9448
  }, "enrichNestedRelationColumns");
8974
- var enrichIncludeWithSort = /* @__PURE__ */ __name((include, columns) => {
9449
+ var enrichIncludeWithSort2 = /* @__PURE__ */ __name((include, columns) => {
8975
9450
  if (!include?.length) return include;
8976
9451
  return include.map((entry) => {
8977
9452
  const relationName = typeof entry === "string" ? entry : entry.relation;
@@ -9023,8 +9498,8 @@ var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentMode
9023
9498
  const childRoute = childJson.route ?? resourcePath.replace(/^\.\.?\//, "").replace(/\/resource\.json$/, "").replace(/\.resource$/, "");
9024
9499
  const rawChildColumns = childJson?.columns;
9025
9500
  const expandedChildColumns = rawChildColumns ? expandExtendColumns(rawChildColumns, childDir) : void 0;
9026
- const childColumns = applyRelationFormatDefault(expandedChildColumns) ?? expandedChildColumns;
9027
- injectEnumValues(childColumns, enums);
9501
+ const childColumns = applyRelationFormatDefault2(expandedChildColumns) ?? expandedChildColumns;
9502
+ injectEnumValues2(childColumns, enums);
9028
9503
  const enrichedChildColumns = enrichNestedRelationColumns(childColumns, childDir, baseUrl);
9029
9504
  const autoIncludes = (enrichedChildColumns ?? []).filter((col) => col.fieldInput?.format === "relation" && (col.fieldInput.relationType ?? deriveRelationTypeFromColumns(col, enrichedChildColumns)) === "manyToOne").map((col) => col.fieldInput?.relation ?? col.id);
9030
9505
  const explicitIncludes = childJson?.include ?? [];
@@ -9104,8 +9579,8 @@ var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentMode
9104
9579
  return {};
9105
9580
  })()
9106
9581
  },
9107
- ...buildValueLabelColumns(childColumns).length && {
9108
- valueLabelColumns: buildValueLabelColumns(childColumns)
9582
+ ...buildValueLabelColumns2(childColumns).length && {
9583
+ valueLabelColumns: buildValueLabelColumns2(childColumns)
9109
9584
  },
9110
9585
  relationType: c.fieldInput?.relationType ?? deriveRelationTypeFromColumns(c, columns)
9111
9586
  };
@@ -9113,13 +9588,19 @@ var buildSubResources = /* @__PURE__ */ __name((columns, parentRoute, parentMode
9113
9588
  }, "buildSubResources");
9114
9589
 
9115
9590
  // src/lib/crud/adapter/json-adapter.ts
9591
+ var pickExtensions2 = /* @__PURE__ */ __name((obj) => Object.fromEntries([
9592
+ ...getResourceExtensions().keys()
9593
+ ].filter((k) => obj[k] !== void 0).map((k) => [
9594
+ k,
9595
+ obj[k]
9596
+ ])), "pickExtensions");
9116
9597
  var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, actions, tableActions, enums = {}, repository) => {
9117
9598
  const isCustom = json.kind === "custom";
9118
9599
  const rawColumns = expandExtendColumns(json.columns, dirPath);
9119
- const columns = enrichRelationTypes(applyRelationFormatDefault(rawColumns) ?? rawColumns, schema);
9120
- injectEnumValues(columns, enums);
9600
+ const columns = enrichRelationTypes2(applyRelationFormatDefault2(rawColumns) ?? rawColumns, schema);
9601
+ injectEnumValues2(columns, enums);
9121
9602
  const subResources = isCustom ? [] : buildSubResources(columns, json.route, json.model ?? "", dirPath, enums, baseUrl);
9122
- const enrichedColumns = resolveColumnFieldVariants(enrichResourceRefColumns(enrichActionColumns(columns, json.route, subResources, baseUrl), dirPath, baseUrl) ?? columns);
9603
+ const enrichedColumns = resolveColumnFieldVariants2(enrichResourceRefColumns(enrichActionColumns2(columns, json.route, subResources, baseUrl), dirPath, baseUrl) ?? columns);
9123
9604
  const calculatedColumns = json.calculatedColumns ?? [];
9124
9605
  let views = isCustom ? buildViewsFromColumnTypes(enrichedColumns) : buildViews(schema, enrichedColumns);
9125
9606
  if (views && calculatedColumns.length) {
@@ -9135,8 +9616,8 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
9135
9616
  }
9136
9617
  }
9137
9618
  const lookup = buildLookup(enrichedColumns);
9138
- const enrichedInclude = enrichIncludeWithSort(json.include, enrichedColumns);
9139
- const definition = buildResourceDefinitions(schema, json.operations, enrichedColumns);
9619
+ const enrichedInclude = enrichIncludeWithSort2(json.include, enrichedColumns);
9620
+ const definition = buildResourceDefinitions2(schema, json.operations, enrichedColumns);
9140
9621
  return {
9141
9622
  ...json,
9142
9623
  name: json.name,
@@ -9185,9 +9666,10 @@ var fromJson = /* @__PURE__ */ __name((json, schema, hooks, dirPath, baseUrl, ac
9185
9666
  ...json.modalSize && {
9186
9667
  modalSize: json.modalSize
9187
9668
  },
9188
- ...buildValueLabelColumns(enrichedColumns).length && {
9189
- valueLabelColumns: buildValueLabelColumns(enrichedColumns)
9190
- }
9669
+ ...buildValueLabelColumns2(enrichedColumns).length && {
9670
+ valueLabelColumns: buildValueLabelColumns2(enrichedColumns)
9671
+ },
9672
+ ...pickExtensions2(json)
9191
9673
  };
9192
9674
  }, "fromJson");
9193
9675
  var buildLookup = /* @__PURE__ */ __name((columns) => {
@@ -9270,6 +9752,45 @@ var migrateResourceJsonFile = /* @__PURE__ */ __name((jsonPath, opts) => {
9270
9752
  }
9271
9753
  }, "migrateResourceJsonFile");
9272
9754
 
9755
+ // src/lib/crud/resource/resource-config.validator.ts
9756
+ init_cjs_shims();
9757
+ var ALL_OPS = [
9758
+ "findAll",
9759
+ "findOne",
9760
+ "create",
9761
+ "update",
9762
+ "patch",
9763
+ "upsert",
9764
+ "delete"
9765
+ ];
9766
+ var validateResourceConfig = /* @__PURE__ */ __name((config, opts) => {
9767
+ const errors = [];
9768
+ const warnings = [];
9769
+ const definition = resolveDefinition2(config);
9770
+ const enabledOps = ALL_OPS.filter((op) => isOperationEnabled2(definition, op));
9771
+ if (enabledOps.length === 0) {
9772
+ warnings.push("All operations are disabled \u2014 this resource serves nothing.");
9773
+ }
9774
+ if (config.kind === "custom") {
9775
+ if (config.database) {
9776
+ warnings.push('"database" is set alongside kind: "custom" \u2014 it selects the client injected as ctx.prisma, but data access still comes from repository.ts.');
9777
+ }
9778
+ if (isOperationEnabled2(definition, "upsert")) {
9779
+ warnings.push('"upsert" is enabled but custom resources do not register a PUT handler \u2014 disable it in operations or implement it yourself.');
9780
+ }
9781
+ const repoError = validateCustomRepository(config, config.repository);
9782
+ if (repoError) errors.push(repoError);
9783
+ } else {
9784
+ if (opts?.repositoryFileExistsOnDisk) {
9785
+ warnings.push('repository.ts is present on a prisma resource and will be ignored \u2014 set kind: "custom" if you want to use it for data access.');
9786
+ }
9787
+ }
9788
+ return {
9789
+ errors,
9790
+ warnings
9791
+ };
9792
+ }, "validateResourceConfig");
9793
+
9273
9794
  // src/lib/crud/loader/index.ts
9274
9795
  var import_node_fs10 = require("fs");
9275
9796
  var import_node_path18 = require("path");
@@ -9332,10 +9853,35 @@ var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl,
9332
9853
  });
9333
9854
  continue;
9334
9855
  }
9856
+ const errorsBeforeRepo = resourceLoadErrorsRegistry.getAll().length;
9335
9857
  const repository = json.kind === "custom" ? await loadCustomRepository(basePath, json.name) : void 0;
9858
+ const repositoryImportFailed = resourceLoadErrorsRegistry.getAll().length > errorsBeforeRepo;
9336
9859
  const actions = await loadActions(json.actions ?? [], basePath, "row");
9337
9860
  const tableActions = await loadActions(json.tableActions ?? [], basePath, "table");
9338
9861
  const config = fromJson(json, schema, hooks, basePath, baseUrl, actions, tableActions, enums, repository);
9862
+ if (repositoryImportFailed) continue;
9863
+ const repositoryFileExistsOnDisk = json.kind !== "custom" && !!findModule(basePath, "repository");
9864
+ const { errors, warnings } = validateResourceConfig(config, {
9865
+ repositoryFileExistsOnDisk
9866
+ });
9867
+ if (errors.length > 0) {
9868
+ for (const error of errors) {
9869
+ resourceLoadErrorsRegistry.record({
9870
+ name: dir,
9871
+ path: jsonFile,
9872
+ error
9873
+ });
9874
+ }
9875
+ continue;
9876
+ }
9877
+ for (const warning of warnings) {
9878
+ resourceLoadReportRegistry.record({
9879
+ state: "warning",
9880
+ name: config.name,
9881
+ path: jsonFile,
9882
+ warning
9883
+ });
9884
+ }
9339
9885
  await loadSubResourceHooks(config.subResources ?? [], basePath);
9340
9886
  await loadSubResourceRepositories(config.subResources ?? [], config.name);
9341
9887
  onResourceDir?.(config.route, basePath);
@@ -9345,7 +9891,14 @@ var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl,
9345
9891
  const tsFile = findModule(basePath, "resource");
9346
9892
  if (tsFile) {
9347
9893
  const config = await importDefault(tsFile);
9348
- if (!config) continue;
9894
+ if (!config) {
9895
+ resourceLoadErrorsRegistry.record({
9896
+ name: dir,
9897
+ path: tsFile,
9898
+ error: "resource.ts has no default export \u2014 add `export default { name, route, ... }`."
9899
+ });
9900
+ continue;
9901
+ }
9349
9902
  if (config.draft) {
9350
9903
  resourceLoadReportRegistry.record({
9351
9904
  state: "draft",
@@ -9355,10 +9908,30 @@ var loadResourceConfigsFromDir = /* @__PURE__ */ __name(async (dirPath, baseUrl,
9355
9908
  });
9356
9909
  continue;
9357
9910
  }
9358
- configs.push(hooks ? {
9911
+ const merged = hooks ? {
9359
9912
  ...config,
9360
9913
  hooks
9361
- } : config);
9914
+ } : config;
9915
+ const { errors, warnings } = validateResourceConfig(merged);
9916
+ if (errors.length > 0) {
9917
+ for (const error of errors) {
9918
+ resourceLoadErrorsRegistry.record({
9919
+ name: dir,
9920
+ path: tsFile,
9921
+ error
9922
+ });
9923
+ }
9924
+ continue;
9925
+ }
9926
+ for (const warning of warnings) {
9927
+ resourceLoadReportRegistry.record({
9928
+ state: "warning",
9929
+ name: merged.name,
9930
+ path: tsFile,
9931
+ warning
9932
+ });
9933
+ }
9934
+ configs.push(merged);
9362
9935
  }
9363
9936
  }
9364
9937
  return configs;
@@ -9417,7 +9990,6 @@ init_src();
9417
9990
  var import_node_fs11 = require("fs");
9418
9991
  var import_node_path19 = require("path");
9419
9992
  var import_node_url = require("url");
9420
- var DB_CHECK_TIMEOUT_MS = 3e3;
9421
9993
  var CONNECTION_STRING_PATTERN = /(?:postgresql|postgres|mysql|mongodb|sqlserver|sqlite):\/\/[^\s"')]+/gi;
9422
9994
  var stripConnectionStrings = /* @__PURE__ */ __name((message) => message.replace(CONNECTION_STRING_PATTERN, "[REDACTED]"), "stripConnectionStrings");
9423
9995
  var getCroutonVersion = /* @__PURE__ */ __name(() => {
@@ -9438,16 +10010,11 @@ var getCroutonVersion = /* @__PURE__ */ __name(() => {
9438
10010
  }, "getCroutonVersion");
9439
10011
  var getVersion = /* @__PURE__ */ __name(() => process.env["APP_VERSION"] ?? "unknown", "getVersion");
9440
10012
  var getEnvironment = /* @__PURE__ */ __name(() => process.env["ENVIRONMENT"] ?? process.env["NODE_ENV"] ?? "unknown", "getEnvironment");
9441
- var checkDatabases = /* @__PURE__ */ __name(async (registry) => {
9442
- const entries = registry.entries();
10013
+ var checkDatabases = /* @__PURE__ */ __name(async (registry2) => {
9443
10014
  const results = [];
9444
- for (const { name, client } of entries) {
9445
- const prismaClient = client;
10015
+ for (const { name, adapter } of registry2.entries()) {
9446
10016
  try {
9447
- await Promise.race([
9448
- prismaClient.$queryRaw`SELECT 1`,
9449
- new Promise((_resolve, reject) => setTimeout(() => reject(new Error("Database health check timed out")), DB_CHECK_TIMEOUT_MS))
9450
- ]);
10017
+ await adapter.healthCheck?.();
9451
10018
  results.push({
9452
10019
  name,
9453
10020
  connected: true
@@ -9463,20 +10030,27 @@ var checkDatabases = /* @__PURE__ */ __name(async (registry) => {
9463
10030
  return results;
9464
10031
  }, "checkDatabases");
9465
10032
  var getResourceStatus = /* @__PURE__ */ __name((loadedConfigs) => {
10033
+ const warningsByName = /* @__PURE__ */ new Map();
10034
+ for (const w of resourceLoadReportRegistry.getByState("warning")) {
10035
+ const existing = warningsByName.get(w.name) ?? [];
10036
+ existing.push(w.warning);
10037
+ warningsByName.set(w.name, existing);
10038
+ }
9466
10039
  const valid = loadedConfigs.map((c) => ({
9467
10040
  name: c.name,
9468
10041
  path: c.route,
9469
10042
  valid: true,
9470
10043
  version: c.schemaVersion ?? CURRENT_RESOURCE_VERSION,
9471
10044
  kind: c.kind ?? "prisma",
9472
- // Which operations the user's repository.ts actually implements. A resource
9473
- // only reaches this list after validateCustomRepository passed, so this is
9474
- // informational rather than a warning.
10045
+ // Which operations the user's repository.ts actually implements.
9475
10046
  ...c.kind === "custom" && c.repository ? {
9476
10047
  customOperations: CUSTOM_OPS.filter((op) => typeof c.repository?.[op] === "function")
9477
10048
  } : {},
9478
10049
  ...c.sidebar?.hide ? {
9479
10050
  hidden: true
10051
+ } : {},
10052
+ ...warningsByName.has(c.name) ? {
10053
+ warnings: warningsByName.get(c.name)
9480
10054
  } : {}
9481
10055
  }));
9482
10056
  const failed = resourceLoadErrorsRegistry.getAll().map((e) => ({
@@ -9503,10 +10077,12 @@ var getResourceStatus = /* @__PURE__ */ __name((loadedConfigs) => {
9503
10077
  var buildSummary = /* @__PURE__ */ __name((databases, resources) => {
9504
10078
  const databaseErrors = databases.filter((d) => !d.connected).length;
9505
10079
  const resourceErrors = resources.filter((r) => !r.valid).length;
10080
+ const warningCount = resources.reduce((acc, r) => acc + (r.warnings?.length ?? 0), 0);
9506
10081
  return {
9507
10082
  ok: databaseErrors === 0 && resourceErrors === 0,
9508
10083
  databaseErrors,
9509
- resourceErrors
10084
+ resourceErrors,
10085
+ warningCount
9510
10086
  };
9511
10087
  }, "buildSummary");
9512
10088
  var getSystemEnums = /* @__PURE__ */ __name(() => {
@@ -9655,8 +10231,8 @@ var getI18nStatus = /* @__PURE__ */ __name((translationRegistry) => {
9655
10231
  bundles
9656
10232
  };
9657
10233
  }, "getI18nStatus");
9658
- var buildStatus = /* @__PURE__ */ __name(async (registry, loadedConfigs, enumRegistry, translationRegistry) => {
9659
- const databases = await checkDatabases(registry);
10234
+ var buildStatus = /* @__PURE__ */ __name(async (registry2, loadedConfigs, enumRegistry, translationRegistry) => {
10235
+ const databases = await checkDatabases(registry2);
9660
10236
  const resources = getResourceStatus(loadedConfigs);
9661
10237
  const summary = buildSummary(databases, resources);
9662
10238
  return {
@@ -9697,7 +10273,7 @@ function _ts_metadata9(metadataKey, metadataValue) {
9697
10273
  }
9698
10274
  }
9699
10275
  __name(_ts_metadata9, "_ts_metadata");
9700
- var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRegistry) => {
10276
+ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRegistry, prefix) => {
9701
10277
  let StatusController = class StatusController {
9702
10278
  static {
9703
10279
  __name(this, "StatusController");
@@ -9727,7 +10303,7 @@ var createStatusController = /* @__PURE__ */ __name((enumRegistry, translationRe
9727
10303
  _ts_metadata9("design:returntype", Promise)
9728
10304
  ], StatusController.prototype, "getStatus", null);
9729
10305
  StatusController = _ts_decorate9([
9730
- (0, import_common23.Controller)("crouton"),
10306
+ (0, import_common23.Controller)(prefix ? `${prefix}/crouton` : "crouton"),
9731
10307
  (0, import_swagger13.ApiTags)("Status"),
9732
10308
  _ts_metadata9("design:type", Function),
9733
10309
  _ts_metadata9("design:paramtypes", [
@@ -9771,7 +10347,7 @@ var CroutonApiModule = class _CroutonApiModule {
9771
10347
  }
9772
10348
  }
9773
10349
  static forResources(configs, dataSources, loader, appConfig, config) {
9774
- const { baseUrl, security } = appConfig;
10350
+ const { baseUrl, prefix, security } = appConfig;
9775
10351
  const dataSourceRegistry = new DataSourceRegistry(dataSources);
9776
10352
  const guardRegistry = new SecurityGuardRegistry(security?.guards ?? {});
9777
10353
  const moduleDefaultSecurity = security?.default;
@@ -9780,9 +10356,10 @@ var CroutonApiModule = class _CroutonApiModule {
9780
10356
  const validConfigs = [];
9781
10357
  for (const c of configs) {
9782
10358
  if (c.kind === "custom") {
10359
+ let adapterClient;
9783
10360
  if (c.database) {
9784
10361
  try {
9785
- dataSourceRegistry.resolveAdapter(c.database);
10362
+ adapterClient = dataSourceRegistry.resolveAdapter(c.database).client;
9786
10363
  } catch (e) {
9787
10364
  resourceLoadErrorsRegistry.record({
9788
10365
  name: c.name,
@@ -9792,7 +10369,7 @@ var CroutonApiModule = class _CroutonApiModule {
9792
10369
  continue;
9793
10370
  }
9794
10371
  }
9795
- const problem = validateCustomRepository(c, c.repository);
10372
+ const problem = validateCustomRepository(c, c.repository, adapterClient);
9796
10373
  if (problem) {
9797
10374
  resourceLoadErrorsRegistry.record({
9798
10375
  name: c.name,
@@ -9840,18 +10417,21 @@ var CroutonApiModule = class _CroutonApiModule {
9840
10417
  configRegistry.setTranslationRegistry(translationRegistry);
9841
10418
  }
9842
10419
  const controllers = [
9843
- ...validConfigs.map((c) => createCrudController(c, baseUrl, moduleDefaultSecurity, !!security)),
9844
- createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true, translationRegistry, config.i18n),
10420
+ ...validConfigs.map((c) => createCrudController(c, baseUrl, moduleDefaultSecurity, !!security, prefix, appConfig.schemaEnricher)),
10421
+ createAppLayoutController(configs, config.sidebarGroups, config.title, config.autoSave ?? true, translationRegistry, config.i18n, prefix),
9845
10422
  // Only registered (and thus only visible in Swagger/routing) when the
9846
10423
  // visual resource builder is enabled — see dev-resources.controller.ts.
9847
10424
  ...IS_DEV ? [
9848
10425
  DevResourcesController
9849
10426
  ] : [],
9850
- createStatusController(enumRegistry, translationRegistry)
10427
+ createStatusController(enumRegistry, translationRegistry, prefix)
9851
10428
  ];
9852
10429
  return {
9853
10430
  module: _CroutonApiModule,
9854
10431
  controllers,
10432
+ exports: [
10433
+ ResourceConfigRegistry
10434
+ ],
9855
10435
  providers: [
9856
10436
  {
9857
10437
  provide: import_core2.APP_FILTER,
@@ -9889,6 +10469,7 @@ var CroutonApiModule = class _CroutonApiModule {
9889
10469
  };
9890
10470
  }
9891
10471
  static async forResourceDir(dirPath, dataSourcesPath, appConfig) {
10472
+ if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);
9892
10473
  const config = await loadConfig();
9893
10474
  const loader = new FileSystemResourceConfigLoader(dirPath, appConfig.baseUrl, config.enumsFile);
9894
10475
  const configs = await loadResourceConfigsFromDir(dirPath, appConfig.baseUrl, config.enumsFile);
@@ -9908,6 +10489,36 @@ CroutonApiModule = _ts_decorate10([
9908
10489
  })
9909
10490
  ], CroutonApiModule);
9910
10491
 
10492
+ // src/lib/crud/parse-schema.ts
10493
+ init_cjs_shims();
10494
+ init_src();
10495
+ var parseSchema = /* @__PURE__ */ __name((input, appConfig, view = "schemas") => {
10496
+ if (appConfig.extensions) registerResourceExtensions(appConfig.extensions);
10497
+ const normalized = input !== null && typeof input === "object" && "json" in input ? input : {
10498
+ json: input
10499
+ };
10500
+ const parseResult = buildResourceJsonSchema().safeParse(normalized.json);
10501
+ if (!parseResult.success) {
10502
+ throw new Error(`Resource cannot be parsed: ${parseResult.error.message}`);
10503
+ }
10504
+ const resource = fromJson(parseResult.data, normalized.schema, normalized.hooks, normalized.dirPath, appConfig.baseUrl, normalized.actions, normalized.tableActions, normalized.enums ?? {}, void 0);
10505
+ let payload;
10506
+ if (view === "schemas") {
10507
+ payload = buildViewsPayload2(resource, appConfig.baseUrl);
10508
+ } else if (view === "definition") {
10509
+ payload = buildDefinitionPayload2(resource);
10510
+ } else {
10511
+ payload = buildResourceJsonPayload2(resource, appConfig.baseUrl);
10512
+ }
10513
+ if (payload && appConfig.schemaEnricher) {
10514
+ payload = {
10515
+ ...payload,
10516
+ ...appConfig.schemaEnricher(payload)
10517
+ };
10518
+ }
10519
+ return payload;
10520
+ }, "parseSchema");
10521
+
9911
10522
  // src/index.ts
9912
10523
  init_hooks();
9913
10524
  // Annotate the CommonJS export names for ESM import in node:
@@ -9937,6 +10548,7 @@ init_hooks();
9937
10548
  loadResourceHooks,
9938
10549
  loadSubResourceHooks,
9939
10550
  parseFilterString,
10551
+ parseSchema,
9940
10552
  postWrite,
9941
10553
  prepareWrite,
9942
10554
  resolveDefinition,