adminforth 2.33.1 → 2.35.0

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.
Files changed (43) hide show
  1. package/commands/createApp/templates/api.ts.hbs +25 -16
  2. package/commands/createApp/templates/package.json.hbs +2 -1
  3. package/dist/basePlugin.js +1 -1
  4. package/dist/basePlugin.js.map +1 -1
  5. package/dist/index.d.ts +2 -0
  6. package/dist/index.d.ts.map +1 -1
  7. package/dist/index.js +4 -0
  8. package/dist/index.js.map +1 -1
  9. package/dist/modules/restApi.d.ts.map +1 -1
  10. package/dist/modules/restApi.js +495 -4
  11. package/dist/modules/restApi.js.map +1 -1
  12. package/dist/modules/utils.d.ts +1 -1
  13. package/dist/modules/utils.d.ts.map +1 -1
  14. package/dist/modules/utils.js +3 -5
  15. package/dist/modules/utils.js.map +1 -1
  16. package/dist/servers/express.d.ts +18 -7
  17. package/dist/servers/express.d.ts.map +1 -1
  18. package/dist/servers/express.js +137 -1
  19. package/dist/servers/express.js.map +1 -1
  20. package/dist/servers/openapi.d.ts +25 -0
  21. package/dist/servers/openapi.d.ts.map +1 -0
  22. package/dist/servers/openapi.js +92 -0
  23. package/dist/servers/openapi.js.map +1 -0
  24. package/dist/servers/openapiDocument.d.ts +12 -0
  25. package/dist/servers/openapiDocument.d.ts.map +1 -0
  26. package/dist/servers/openapiDocument.js +313 -0
  27. package/dist/servers/openapiDocument.js.map +1 -0
  28. package/dist/spa/package.json +1 -0
  29. package/dist/spa/pnpm-lock.yaml +346 -310
  30. package/dist/spa/pnpm-workspace.yaml +4 -0
  31. package/dist/spa/src/App.vue +1 -0
  32. package/dist/spa/src/afcl/Skeleton.vue +1 -1
  33. package/dist/spa/src/stores/core.ts +15 -1
  34. package/dist/spa/src/types/Back.ts +109 -23
  35. package/dist/spa/src/types/adapters/CompletionAdapter.ts +10 -0
  36. package/dist/spa/src/views/CreateEditSkeleton.vue +49 -34
  37. package/dist/spa/src/views/EditView.vue +1 -1
  38. package/dist/types/Back.d.ts +113 -18
  39. package/dist/types/Back.d.ts.map +1 -1
  40. package/dist/types/Back.js.map +1 -1
  41. package/dist/types/adapters/CompletionAdapter.d.ts +8 -1
  42. package/dist/types/adapters/CompletionAdapter.d.ts.map +1 -1
  43. package/package.json +5 -2
@@ -0,0 +1,4 @@
1
+
2
+ ignoredBuiltDependencies:
3
+ - esbuild
4
+
@@ -2,6 +2,7 @@
2
2
  <div>
3
3
  <nav
4
4
  v-if="loggedIn && routerIsReady && loginRedirectCheckIsReady && defaultLayout"
5
+ id="af-header-nav"
5
6
  class="fixed h-14 top-0 z-30 w-full border-b drop-shadow-sm bg-lightNavbar dark:bg-darkNavbar dark:border-darkSidebarDevider"
6
7
  >
7
8
  <div class="af-header px-3 lg:px-5 lg:pl-3 flex items-center justify-between h-full w-full" >
@@ -17,7 +17,7 @@
17
17
  <div
18
18
  v-else-if="type === 'input'"
19
19
  role="input"
20
- :class="['animate-pulse bg-gray-100 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded', $attrs.class]"
20
+ :class="['animate-pulse bg-gray-100 dark:bg-gray-700 border border-gray-200 dark:border-gray-600 rounded-default', $attrs.class]"
21
21
  ></div>
22
22
  <div v-else role="status" class="flex items-center justify-center animate-pulse bg-lightSkeletonIconColor rounded-full dark:bg-darkSkeletonBackgroundColor">
23
23
  <span class="sr-only">Loading...</span>
@@ -1,4 +1,4 @@
1
- import { ref, computed } from 'vue'
1
+ import { ref, computed, onMounted, onUnmounted } from 'vue'
2
2
  import { defineStore } from 'pinia'
3
3
  import { callAdminForthApi } from '@/utils';
4
4
  import websocket from '@/websocket';
@@ -21,6 +21,19 @@ export const useCoreStore = defineStore('core', () => {
21
21
  const userData: Ref<UserData | null> = ref(null);
22
22
  const isResourceFetching = ref(false);
23
23
  const isInternetError = ref(false);
24
+ const screenWidth = ref(window.innerWidth);
25
+
26
+ onMounted(() => {
27
+ window.addEventListener('resize', updateWidth);
28
+ });
29
+ onUnmounted(() => {
30
+ window.removeEventListener('resize', updateWidth);
31
+ });
32
+
33
+ const isMobile = computed(() => screenWidth.value <= 768);
34
+ const updateWidth = () => {
35
+ screenWidth.value = window.innerWidth
36
+ }
24
37
 
25
38
  const resourceColumnsWithFilters = computed(() => {
26
39
  if (!resource.value) {
@@ -261,5 +274,6 @@ export const useCoreStore = defineStore('core', () => {
261
274
  isResourceFetching,
262
275
  isIos,
263
276
  isInternetError,
277
+ isMobile,
264
278
  }
265
279
  })
@@ -1,5 +1,7 @@
1
1
  import type { Express, Request, Response } from 'express';
2
+ import type { AnySchemaObject } from 'ajv';
2
3
  import type { Writable } from 'stream';
4
+ import type { ZodType } from 'zod';
3
5
 
4
6
  import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum, AdminForthResourcePages,
5
7
  type AdminForthComponentDeclaration,
@@ -38,6 +40,81 @@ export interface IAdminForthHttpResponse {
38
40
  blobStream: () => Writable,
39
41
  };
40
42
 
43
+ export interface IAdminForthEndpointHandlerInput {
44
+ body: any;
45
+ adminUser: AdminUser | undefined;
46
+ query: {[key: string]: any};
47
+ headers: {[key: string]: any};
48
+ cookies: Array<{ key: string, value: string }>;
49
+ response: IAdminForthHttpResponse;
50
+ requestUrl: string;
51
+ abortSignal: AbortSignal;
52
+ _raw_express_req: Request;
53
+ _raw_express_res: Response;
54
+ tr: ITranslateFunction;
55
+ }
56
+
57
+ export interface IAdminForthEndpointOptions {
58
+ method: string,
59
+ noAuth?: boolean,
60
+ path: string,
61
+ description?: string,
62
+ request_schema?: AnySchemaObject,
63
+ response_schema?: AnySchemaObject,
64
+ responce_schema?: AnySchemaObject,
65
+ handler: (input: IAdminForthEndpointHandlerInput) => void | Promise<any>,
66
+ }
67
+
68
+ export type AdminForthExpressSchemaInput = AnySchemaObject | ZodType;
69
+
70
+ export interface IAdminForthExpressRouteSchema {
71
+ /**
72
+ * Detailed OpenAPI operation description for a custom Express route.
73
+ */
74
+ description?: string;
75
+
76
+ /**
77
+ * JSON schema or Zod schema describing the request body for a custom Express route.
78
+ */
79
+ request?: AdminForthExpressSchemaInput;
80
+
81
+ /**
82
+ * JSON schema or Zod schema describing the JSON response body for a custom Express route.
83
+ */
84
+ response?: AdminForthExpressSchemaInput;
85
+ }
86
+
87
+ export interface IRegisteredApiSchema {
88
+ method: string;
89
+ path: string;
90
+ description?: string;
91
+ request_schema?: AnySchemaObject;
92
+ response_schema?: AnySchemaObject;
93
+ }
94
+
95
+ export interface IAdminForthApiValidationError {
96
+ instancePath: string;
97
+ schemaPath: string;
98
+ keyword: string;
99
+ message?: string;
100
+ params: {[key: string]: any};
101
+ }
102
+
103
+ export interface IAdminForthApiValidationResult {
104
+ valid: boolean;
105
+ errors?: IAdminForthApiValidationError[];
106
+ }
107
+
108
+ export interface IOpenApiRegistry {
109
+ registeredSchemas: IRegisteredApiSchema[];
110
+
111
+ registerApiSchema(options: IAdminForthEndpointOptions): IRegisteredApiSchema;
112
+ register_api_schema(options: IAdminForthEndpointOptions): IRegisteredApiSchema;
113
+ validateRequestSchema(route: IRegisteredApiSchema | null, payload: any): IAdminForthApiValidationResult;
114
+ validateResponseSchema(route: IRegisteredApiSchema | null, payload: any): IAdminForthApiValidationResult;
115
+ renderOpenApiDocument(): {[key: string]: any};
116
+ }
117
+
41
118
  /**
42
119
  * Implement this interface to create custom HTTP server adapter for AdminForth.
43
120
  */
@@ -57,23 +134,7 @@ export interface IHttpServer {
57
134
  *
58
135
  * @param options : Object with method, path and handler properties.
59
136
  */
60
- endpoint(options: {
61
- method: string,
62
- noAuth?: boolean,
63
- path: string,
64
- handler: (
65
- body: any,
66
- adminUser: any,
67
- query: {[key: string]: string},
68
- headers: {[key: string]: string},
69
- cookies: {[key: string]: string},
70
- response: IAdminForthHttpResponse,
71
- requestUrl: string,
72
- abortSignal: AbortSignal,
73
- _raw_express_req: Request,
74
- _raw_express_res: Response,
75
- ) => void,
76
- }): void;
137
+ endpoint(options: IAdminForthEndpointOptions): void;
77
138
 
78
139
  }
79
140
 
@@ -107,14 +168,38 @@ export interface IExpressHttpServer extends IHttpServer {
107
168
  * ```
108
169
  *
109
170
  */
110
- authorize(callable: Function): void;
171
+ authorize(callable: (...args: any[]) => any): (...args: any[]) => any;
172
+
173
+ /**
174
+ * Method (middleware) to inject translation helper into Express request object.
175
+ */
176
+ translatable(callable: (...args: any[]) => any): (...args: any[]) => any;
177
+
178
+ /**
179
+ * Registers OpenAPI schemas for a custom Express route.
180
+ *
181
+ * Wrap this around the handler passed to `app.get/post/...`.
182
+ * If you also need authorization, make `withSchema` the outer wrapper:
183
+ *
184
+ * ```ts
185
+ * import * as z from 'zod';
186
+ *
187
+ * app.get('/myApi', admin.express.withSchema({
188
+ * description: 'Returns current user profile',
189
+ * response: z.object({ user: z.unknown() }),
190
+ * }, admin.express.authorize((req, res) => {
191
+ * res.json({ user: req.adminUser });
192
+ * })));
193
+ * ```
194
+ */
195
+ withSchema(schema: IAdminForthExpressRouteSchema, callable: (...args: any[]) => any): (...args: any[]) => any;
111
196
  }
112
197
 
113
198
  export interface ITranslateFunction {
114
199
  (
115
200
  msg: string,
116
201
  category: string,
117
- params: any,
202
+ params?: any,
118
203
  pluralizationNumber?: number
119
204
  ): Promise<string>;
120
205
  }
@@ -359,7 +444,8 @@ export interface IAdminForthRestAPI {
359
444
  export interface IAdminForth {
360
445
  config: AdminForthConfig;
361
446
  codeInjector: ICodeInjector;
362
- express: IHttpServer;
447
+ express: IExpressHttpServer;
448
+ openApi: IOpenApiRegistry;
363
449
 
364
450
  restApi: IAdminForthRestAPI;
365
451
  activatedPlugins: Array<IAdminForthPlugin>;
@@ -535,7 +621,7 @@ export type BeforeDataSourceRequestFunction = (params: {
535
621
  body: any,
536
622
  query: Record<string, string>,
537
623
  headers: Record<string, string>,
538
- cookies: Record<string, string>,
624
+ cookies: { key: string, value: string }[],
539
625
  requestUrl: string,
540
626
  },
541
627
  filtersTools: any,
@@ -573,7 +659,7 @@ export interface HttpExtra {
573
659
  body: any,
574
660
  query: Record<string, string>,
575
661
  headers: Record<string, string>,
576
- cookies: Record<string, string>,
662
+ cookies: { key: string, value: string }[],
577
663
  requestUrl: string,
578
664
  meta?: any,
579
665
  response: IAdminForthHttpResponse
@@ -2021,7 +2107,7 @@ export interface AdminForthBulkAction extends AdminForthBulkActionCommon {
2021
2107
  * It should return Promise which will be resolved when action is done.
2022
2108
  */
2023
2109
  action: ({ resource, selectedIds, adminUser, response, tr }: {
2024
- resource: AdminForthResource, selectedIds: Array<any>, adminUser: AdminUser, response: IAdminForthHttpResponse, tr: (key: string, category?: string, params?: any) => string
2110
+ resource: AdminForthResource, selectedIds: Array<any>, adminUser: AdminUser, response: IAdminForthHttpResponse, tr: ITranslateFunction
2025
2111
  }) => Promise<{ ok: boolean, error?: string, successMessage?: string }>,
2026
2112
 
2027
2113
  /**
@@ -1,9 +1,18 @@
1
+ import type { JSONSchemaType } from "ajv";
2
+
1
3
  export type CompletionStreamEvent = {
2
4
  type: "output" | "reasoning";
3
5
  delta: string;
4
6
  text: string;
5
7
  source?: "summary" | "text";
6
8
  };
9
+
10
+ export type CompletionTool<Input = Record<string, any>, Output = any> = {
11
+ name: string;
12
+ input_schema: JSONSchemaType<Input>;
13
+ description?: string;
14
+ handler: (input: Input) => Promise<Output> | Output;
15
+ };
7
16
  export interface CompletionAdapter {
8
17
 
9
18
  /**
@@ -26,6 +35,7 @@ export interface CompletionAdapter {
26
35
  maxTokens: number,
27
36
  outputSchema?: any,
28
37
  reasoningEffort?: 'none' | 'minimal' | 'low' | 'medium' | 'high' | 'xhigh',
38
+ tools?: CompletionTool[],
29
39
  onChunk?: (
30
40
  chunk: string,
31
41
  event?: CompletionStreamEvent,
@@ -11,50 +11,32 @@
11
11
  </div>
12
12
  </div>
13
13
 
14
- <div v-for="i in 5" :key="i"
15
- class="flex items-center bg-lightForm dark:bg-darkForm border-b border-gray-100 dark:border-darkFormBorder"
16
- :style="{ height: i === 2 ? '95px' : '75px' }"
17
- >
18
- <div class="w-[208px] flex-shrink-0 px-6 flex items-center gap-1">
14
+ <template v-for="column in visibleColumns" :key="column.name">
15
+ <div
16
+ class="flex items-center bg-lightForm dark:bg-darkForm border-b border-gray-100 dark:border-darkFormBorder"
17
+ :style="{ height: getFieldHeight(column) }"
18
+ >
19
+ <div class="w-[208px] flex-shrink-0 px-6 flex items-center">
19
20
  <Skeleton class="w-24 h-[10px]" />
20
21
  </div>
21
-
22
- <div class="flex-1 px-6">
23
- <div v-if="i === 2">
24
- <Skeleton type="input" class="h-[42px] w-[160px]" />
25
- <Skeleton class="mt-1 h-[12px] w-20" />
26
- </div>
27
- <Skeleton type="input" v-else-if="i === 4 || i === 5" class="h-[42px] w-[160px]" />
28
- <Skeleton v-else type="input" class="h-[42px] w-full" />
29
- </div>
30
- </div>
31
22
 
32
- <div class="flex items-start bg-lightForm dark:bg-darkForm" style="height: 759px;">
33
- <div class="w-[208px] flex-shrink-0 px-6 pt-7">
34
- <Skeleton class="w-24 h-[10px]" />
35
- </div>
36
-
37
- <div class="flex-1 px-6 pt-4 h-full flex flex-col">
38
- <div class="flex flex-wrap items-center gap-3 p-1.5 border border-gray-300 dark:border-gray-600 rounded-t-lg bg-gray-50 dark:bg-gray-800 w-full box-border h-[44px]">
39
- <template v-for="btn in skeletonButtons" :key="btn.id">
40
- <div class=" animate-pulse flex items-center justify-center h-8 px-1 text-gray-300 dark:text-gray-600">
41
- <component :is="btn.icon" class="w-5 h-5" />
42
- </div>
43
- <div v-if="btn.sep" class="w-px h-4 bg-gray-300 dark:bg-gray-600 mx-1"></div>
44
- </template>
23
+ <div class="flex-1 px-6">
24
+ <Skeleton type="input" :class="getSkeletonInputClass(column)" />
25
+
26
+ <div v-if="hasEditingNote(column)" class="mt-1">
27
+ <Skeleton class="h-[12px] w-20" />
28
+ </div>
45
29
  </div>
46
- <div class="flex-1 animate-pulse bg-white dark:bg-gray-950 border-x border-b border-gray-200 dark:border-gray-700 rounded-b-lg w-full shadow-inner"></div>
47
- <div class="h-10"></div>
48
30
  </div>
49
- </div>
31
+
32
+ </template>
50
33
  </div>
51
34
  </div>
52
35
  </template>
53
36
 
54
37
  <script setup lang="ts">
55
- import { markRaw } from 'vue';
56
- import { IconExclamationCircleSolid } from '@iconify-prerendered/vue-flowbite';
57
- import {
38
+ import { computed, markRaw } from 'vue';
39
+ import {
58
40
  IconLinkOutline, IconCodeOutline, IconRectangleListOutline,
59
41
  IconOrderedListOutline, IconLetterBoldOutline, IconLetterUnderlineOutline,
60
42
  IconLetterItalicOutline, IconTextSlashOutline
@@ -62,6 +44,39 @@ import {
62
44
  import { IconH116Solid, IconH216Solid, IconH316Solid } from '@iconify-prerendered/vue-heroicons';
63
45
  import { Skeleton } from '@/afcl';
64
46
 
47
+ interface Props {
48
+ resource?: any;
49
+ page?: string;}
50
+
51
+ const props = withDefaults(defineProps<Props>(), {
52
+ page: 'edit'
53
+ });
54
+
55
+ const visibleColumns = computed(() => {
56
+ if (!props.resource?.columns) return [];
57
+
58
+ return props.resource.columns.filter((col: any) => {
59
+ if (col.virtual) return false;
60
+ if (col.primaryKey) return false;
61
+ if (col.backendOnly) return false;
62
+ if (col.showIn?.[props.page] === false) return false;
63
+ return true;
64
+ });
65
+ });
66
+
67
+
68
+ const hasEditingNote = (column: any) => !!column.editingNote;
69
+
70
+ const getFieldHeight = (column: any) =>
71
+ hasEditingNote(column) ? '95px' : '75px';
72
+
73
+ const getSkeletonInputClass = (column: any) => {
74
+ if (['integer', 'decimal', 'float'].includes(column.type)) {
75
+ return 'h-[42px] w-[160px]';
76
+ }
77
+ return 'h-[42px] w-full';
78
+ };
79
+
65
80
  const skeletonButtons = [
66
81
  { id: 'bold', icon: markRaw(IconLetterBoldOutline), sep: false },
67
82
  { id: 'italic', icon: markRaw(IconLetterItalicOutline), sep: false },
@@ -41,7 +41,7 @@
41
41
  :adminUser="coreStore.adminUser"
42
42
  />
43
43
 
44
- <CreateEditSkeleton v-if="loading"></CreateEditSkeleton>
44
+ <CreateEditSkeleton :resource="coreStore.resource" v-if="loading"></CreateEditSkeleton>
45
45
 
46
46
  <ResourceForm
47
47
  v-else-if="coreStore.resource"
@@ -1,5 +1,7 @@
1
1
  import type { Express, Request, Response } from 'express';
2
+ import type { AnySchemaObject } from 'ajv';
2
3
  import type { Writable } from 'stream';
4
+ import type { ZodType } from 'zod';
3
5
  import { ActionCheckSource, AdminForthFilterOperators, AdminForthSortDirections, AllowedActionsEnum, AdminForthResourcePages, type AdminForthComponentDeclaration, type AdminUser, type AllowedActionsResolved, type AdminForthBulkActionCommon, type AdminForthForeignResourceCommon, type AdminForthResourceColumnCommon, type AdminForthResourceInputCommon, type AdminForthComponentDeclarationFull, type AdminForthConfigMenuItem, type AnnouncementBadgeResponse, type AdminForthResourceColumnInputCommon, type ColumnMinMaxValue } from './Common.js';
4
6
  export interface ICodeInjector {
5
7
  srcFoldersToSync: Object;
@@ -19,6 +21,81 @@ export interface IAdminForthHttpResponse {
19
21
  setStatus: (code: number, message: string) => void;
20
22
  blobStream: () => Writable;
21
23
  }
24
+ export interface IAdminForthEndpointHandlerInput {
25
+ body: any;
26
+ adminUser: AdminUser | undefined;
27
+ query: {
28
+ [key: string]: any;
29
+ };
30
+ headers: {
31
+ [key: string]: any;
32
+ };
33
+ cookies: Array<{
34
+ key: string;
35
+ value: string;
36
+ }>;
37
+ response: IAdminForthHttpResponse;
38
+ requestUrl: string;
39
+ abortSignal: AbortSignal;
40
+ _raw_express_req: Request;
41
+ _raw_express_res: Response;
42
+ tr: ITranslateFunction;
43
+ }
44
+ export interface IAdminForthEndpointOptions {
45
+ method: string;
46
+ noAuth?: boolean;
47
+ path: string;
48
+ description?: string;
49
+ request_schema?: AnySchemaObject;
50
+ response_schema?: AnySchemaObject;
51
+ responce_schema?: AnySchemaObject;
52
+ handler: (input: IAdminForthEndpointHandlerInput) => void | Promise<any>;
53
+ }
54
+ export type AdminForthExpressSchemaInput = AnySchemaObject | ZodType;
55
+ export interface IAdminForthExpressRouteSchema {
56
+ /**
57
+ * Detailed OpenAPI operation description for a custom Express route.
58
+ */
59
+ description?: string;
60
+ /**
61
+ * JSON schema or Zod schema describing the request body for a custom Express route.
62
+ */
63
+ request?: AdminForthExpressSchemaInput;
64
+ /**
65
+ * JSON schema or Zod schema describing the JSON response body for a custom Express route.
66
+ */
67
+ response?: AdminForthExpressSchemaInput;
68
+ }
69
+ export interface IRegisteredApiSchema {
70
+ method: string;
71
+ path: string;
72
+ description?: string;
73
+ request_schema?: AnySchemaObject;
74
+ response_schema?: AnySchemaObject;
75
+ }
76
+ export interface IAdminForthApiValidationError {
77
+ instancePath: string;
78
+ schemaPath: string;
79
+ keyword: string;
80
+ message?: string;
81
+ params: {
82
+ [key: string]: any;
83
+ };
84
+ }
85
+ export interface IAdminForthApiValidationResult {
86
+ valid: boolean;
87
+ errors?: IAdminForthApiValidationError[];
88
+ }
89
+ export interface IOpenApiRegistry {
90
+ registeredSchemas: IRegisteredApiSchema[];
91
+ registerApiSchema(options: IAdminForthEndpointOptions): IRegisteredApiSchema;
92
+ register_api_schema(options: IAdminForthEndpointOptions): IRegisteredApiSchema;
93
+ validateRequestSchema(route: IRegisteredApiSchema | null, payload: any): IAdminForthApiValidationResult;
94
+ validateResponseSchema(route: IRegisteredApiSchema | null, payload: any): IAdminForthApiValidationResult;
95
+ renderOpenApiDocument(): {
96
+ [key: string]: any;
97
+ };
98
+ }
22
99
  /**
23
100
  * Implement this interface to create custom HTTP server adapter for AdminForth.
24
101
  */
@@ -34,18 +111,7 @@ export interface IHttpServer {
34
111
  *
35
112
  * @param options : Object with method, path and handler properties.
36
113
  */
37
- endpoint(options: {
38
- method: string;
39
- noAuth?: boolean;
40
- path: string;
41
- handler: (body: any, adminUser: any, query: {
42
- [key: string]: string;
43
- }, headers: {
44
- [key: string]: string;
45
- }, cookies: {
46
- [key: string]: string;
47
- }, response: IAdminForthHttpResponse, requestUrl: string, abortSignal: AbortSignal, _raw_express_req: Request, _raw_express_res: Response) => void;
48
- }): void;
114
+ endpoint(options: IAdminForthEndpointOptions): void;
49
115
  }
50
116
  export interface IExpressHttpServer extends IHttpServer {
51
117
  /**
@@ -73,10 +139,32 @@ export interface IExpressHttpServer extends IHttpServer {
73
139
  * ```
74
140
  *
75
141
  */
76
- authorize(callable: Function): void;
142
+ authorize(callable: (...args: any[]) => any): (...args: any[]) => any;
143
+ /**
144
+ * Method (middleware) to inject translation helper into Express request object.
145
+ */
146
+ translatable(callable: (...args: any[]) => any): (...args: any[]) => any;
147
+ /**
148
+ * Registers OpenAPI schemas for a custom Express route.
149
+ *
150
+ * Wrap this around the handler passed to `app.get/post/...`.
151
+ * If you also need authorization, make `withSchema` the outer wrapper:
152
+ *
153
+ * ```ts
154
+ * import * as z from 'zod';
155
+ *
156
+ * app.get('/myApi', admin.express.withSchema({
157
+ * description: 'Returns current user profile',
158
+ * response: z.object({ user: z.unknown() }),
159
+ * }, admin.express.authorize((req, res) => {
160
+ * res.json({ user: req.adminUser });
161
+ * })));
162
+ * ```
163
+ */
164
+ withSchema(schema: IAdminForthExpressRouteSchema, callable: (...args: any[]) => any): (...args: any[]) => any;
77
165
  }
78
166
  export interface ITranslateFunction {
79
- (msg: string, category: string, params: any, pluralizationNumber?: number): Promise<string>;
167
+ (msg: string, category: string, params?: any, pluralizationNumber?: number): Promise<string>;
80
168
  }
81
169
  export interface IAdminUserExpressRequest extends Omit<Request, 'protocol' | 'param' | 'unshift'> {
82
170
  adminUser: AdminUser;
@@ -333,7 +421,8 @@ export interface IAdminForthRestAPI {
333
421
  export interface IAdminForth {
334
422
  config: AdminForthConfig;
335
423
  codeInjector: ICodeInjector;
336
- express: IHttpServer;
424
+ express: IExpressHttpServer;
425
+ openApi: IOpenApiRegistry;
337
426
  restApi: IAdminForthRestAPI;
338
427
  activatedPlugins: Array<IAdminForthPlugin>;
339
428
  websocket: IWebSocketBroker;
@@ -477,7 +566,10 @@ export type BeforeDataSourceRequestFunction = (params: {
477
566
  body: any;
478
567
  query: Record<string, string>;
479
568
  headers: Record<string, string>;
480
- cookies: Record<string, string>;
569
+ cookies: {
570
+ key: string;
571
+ value: string;
572
+ }[];
481
573
  requestUrl: string;
482
574
  };
483
575
  filtersTools: any;
@@ -519,7 +611,10 @@ export interface HttpExtra {
519
611
  body: any;
520
612
  query: Record<string, string>;
521
613
  headers: Record<string, string>;
522
- cookies: Record<string, string>;
614
+ cookies: {
615
+ key: string;
616
+ value: string;
617
+ }[];
523
618
  requestUrl: string;
524
619
  meta?: any;
525
620
  response: IAdminForthHttpResponse;
@@ -1756,7 +1851,7 @@ export interface AdminForthBulkAction extends AdminForthBulkActionCommon {
1756
1851
  selectedIds: Array<any>;
1757
1852
  adminUser: AdminUser;
1758
1853
  response: IAdminForthHttpResponse;
1759
- tr: (key: string, category?: string, params?: any) => string;
1854
+ tr: ITranslateFunction;
1760
1855
  }) => Promise<{
1761
1856
  ok: boolean;
1762
1857
  error?: string;