vona-module-a-openapi 5.0.72 → 5.1.2

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 (94) hide show
  1. package/LICENSE +0 -0
  2. package/dist/.metadata/index.d.ts +1 -0
  3. package/dist/.metadata/index.d.ts.map +1 -0
  4. package/dist/.metadata/this.d.ts +1 -0
  5. package/dist/.metadata/this.d.ts.map +1 -0
  6. package/dist/bean/bean.openapi.d.ts +1 -0
  7. package/dist/bean/bean.openapi.d.ts.map +1 -0
  8. package/dist/bean/summerCache.json.d.ts +1 -0
  9. package/dist/bean/summerCache.json.d.ts.map +1 -0
  10. package/dist/config/config.d.ts +1 -0
  11. package/dist/config/config.d.ts.map +1 -0
  12. package/dist/index.d.ts +1 -0
  13. package/dist/index.d.ts.map +1 -0
  14. package/dist/index.js +1 -0
  15. package/dist/index.js.map +1 -0
  16. package/dist/lib/index.d.ts +1 -0
  17. package/dist/lib/index.d.ts.map +1 -0
  18. package/dist/lib/zod/index.d.ts +1 -0
  19. package/dist/lib/zod/index.d.ts.map +1 -0
  20. package/dist/lib/zod/schemaRefCustomAdapter.d.ts +1 -0
  21. package/dist/lib/zod/schemaRefCustomAdapter.d.ts.map +1 -0
  22. package/dist/main.d.ts +1 -0
  23. package/dist/main.d.ts.map +1 -0
  24. package/dist/service/openapi.d.ts +1 -0
  25. package/dist/service/openapi.d.ts.map +1 -0
  26. package/dist/types/actions.d.ts +1 -0
  27. package/dist/types/actions.d.ts.map +1 -0
  28. package/dist/types/behavior.d.ts +1 -0
  29. package/dist/types/behavior.d.ts.map +1 -0
  30. package/dist/types/captcha.d.ts +3 -2
  31. package/dist/types/captcha.d.ts.map +1 -0
  32. package/dist/types/component.d.ts +1 -0
  33. package/dist/types/component.d.ts.map +1 -0
  34. package/dist/types/date.d.ts +1 -0
  35. package/dist/types/date.d.ts.map +1 -0
  36. package/dist/types/decorator.d.ts +1 -0
  37. package/dist/types/decorator.d.ts.map +1 -0
  38. package/dist/types/formProvider.d.ts +1 -0
  39. package/dist/types/formProvider.d.ts.map +1 -0
  40. package/dist/types/index.d.ts +6 -0
  41. package/dist/types/index.d.ts.map +1 -0
  42. package/dist/types/openapi.d.ts +1 -0
  43. package/dist/types/openapi.d.ts.map +1 -0
  44. package/dist/types/permissions.d.ts +1 -0
  45. package/dist/types/permissions.d.ts.map +1 -0
  46. package/dist/types/resource.d.ts +1 -0
  47. package/dist/types/resource.d.ts.map +1 -0
  48. package/dist/types/resourceMeta.d.ts +1 -0
  49. package/dist/types/resourceMeta.d.ts.map +1 -0
  50. package/dist/types/resourcePicker.d.ts +11 -0
  51. package/dist/types/resourcePicker.d.ts.map +1 -0
  52. package/dist/types/rest.d.ts +18 -7
  53. package/dist/types/rest.d.ts.map +1 -0
  54. package/dist/types/select.d.ts +16 -0
  55. package/dist/types/select.d.ts.map +1 -0
  56. package/dist/types/table.d.ts +23 -0
  57. package/dist/types/table.d.ts.map +1 -0
  58. package/dist/types/tableProvider.d.ts +1 -0
  59. package/dist/types/tableProvider.d.ts.map +1 -0
  60. package/dist/types/textarea.d.ts +11 -0
  61. package/dist/types/textarea.d.ts.map +1 -0
  62. package/dist/types/toggle.d.ts +4 -0
  63. package/dist/types/toggle.d.ts.map +1 -0
  64. package/package.json +33 -29
  65. package/src/.metadata/index.ts +139 -0
  66. package/src/.metadata/this.ts +2 -0
  67. package/src/bean/bean.openapi.ts +84 -0
  68. package/src/bean/summerCache.json.ts +17 -0
  69. package/src/config/config.ts +35 -0
  70. package/src/index.ts +3 -0
  71. package/src/lib/index.ts +1 -0
  72. package/src/lib/zod/index.ts +1 -0
  73. package/src/lib/zod/schemaRefCustomAdapter.ts +29 -0
  74. package/src/main.ts +14 -0
  75. package/src/service/openapi.ts +400 -0
  76. package/src/types/actions.ts +18 -0
  77. package/src/types/behavior.ts +11 -0
  78. package/src/types/captcha.ts +5 -0
  79. package/src/types/component.ts +14 -0
  80. package/src/types/date.ts +25 -0
  81. package/src/types/decorator.ts +45 -0
  82. package/src/types/formProvider.ts +21 -0
  83. package/src/types/index.ts +20 -0
  84. package/src/types/openapi.ts +7 -0
  85. package/src/types/permissions.ts +18 -0
  86. package/src/types/resource.ts +1 -0
  87. package/src/types/resourceMeta.ts +38 -0
  88. package/src/types/resourcePicker.ts +11 -0
  89. package/src/types/rest.ts +133 -0
  90. package/src/types/select.ts +16 -0
  91. package/src/types/table.ts +27 -0
  92. package/src/types/tableProvider.ts +10 -0
  93. package/src/types/textarea.ts +10 -0
  94. package/src/types/toggle.ts +3 -0
@@ -0,0 +1,400 @@
1
+ import type { OpenAPIObject as OpenAPIObject30, SchemaObject as SchemaObject30, SecurityRequirementObject } from 'openapi3-ts/oas30';
2
+ import type { OpenAPIObject as OpenAPIObject31, SchemaObject as SchemaObject31 } from 'openapi3-ts/oas31';
3
+ import type { Constructable, IDecoratorBeanOptionsBase } from 'vona';
4
+ import type { IOpenapiHeader, IOpenapiOptions, TypeGenerateJsonScene } from 'vona-module-a-openapiutils';
5
+ import type { IDecoratorControllerOptions, RequestMappingMetadata, TypeRequestMethod } from 'vona-module-a-web';
6
+
7
+ import * as ModuleInfo from '@cabloy/module-info';
8
+ import { isEmptyObject, isNil } from '@cabloy/utils';
9
+ import { toUpperCaseFirstChar } from '@cabloy/word-utils';
10
+ import { translateError } from '@cabloy/zod-errors-custom';
11
+ import { getInnerTypeName } from '@cabloy/zod-query';
12
+ import { OpenAPIRegistry } from '@cabloy/zod-to-openapi';
13
+ import { appMetadata, appResource, BeanBase, cast } from 'vona';
14
+ import { Service } from 'vona-module-a-bean';
15
+ import { $schema, bodySchemaWrapperDefault, SymbolOpenApiOptions, SymbolRouteHandlersArgumentsMeta } from 'vona-module-a-openapiutils';
16
+ import { SymbolRequestMappingHandler } from 'vona-module-a-web';
17
+ import { z } from 'zod';
18
+
19
+ import type { RouteHandlerArgumentMetaDecorator } from '../types/decorator.ts';
20
+
21
+ const __ArgumentTypes = ['param', 'query', 'body', 'headers', 'fields', 'field', 'files', 'file'];
22
+
23
+ @Service()
24
+ export class ServiceOpenapi extends BeanBase {
25
+ public translate(apiObj: OpenAPIObject30 | OpenAPIObject31, generateJsonScene: TypeGenerateJsonScene) {
26
+ // paths
27
+ if (apiObj.paths) {
28
+ for (const key in apiObj.paths) {
29
+ const pathObj = apiObj.paths[key];
30
+ for (const method in pathObj) {
31
+ const methodObj = pathObj[method];
32
+ // parameters
33
+ for (const parameterObj of methodObj.parameters || []) {
34
+ if (parameterObj.schema) {
35
+ parameterObj.schema = this._translateSchema(parameterObj.schema, generateJsonScene);
36
+ }
37
+ }
38
+ // requestBody
39
+ if (methodObj.requestBody?.content?.['application/json']?.schema) {
40
+ methodObj.requestBody.content['application/json'].schema = this._translateSchema(
41
+ methodObj.requestBody.content['application/json'].schema,
42
+ generateJsonScene,
43
+ );
44
+ }
45
+ }
46
+ }
47
+ }
48
+ // components
49
+ if (apiObj.components?.schemas) {
50
+ for (const key in apiObj.components.schemas) {
51
+ const schema = apiObj.components.schemas[key];
52
+ if (schema) {
53
+ apiObj.components.schemas[key] = this._translateSchema(schema, generateJsonScene);
54
+ }
55
+ }
56
+ }
57
+ }
58
+
59
+ private _translateSchema(schema: any, generateJsonScene: TypeGenerateJsonScene) {
60
+ if (schema.type === 'object' && schema.required === undefined) schema.required = [];
61
+ // serializerTransforms
62
+ delete schema.serializerTransforms;
63
+ // filter
64
+ if (schema.filter) {
65
+ const filterCapabilities = schema.filter.capabilities;
66
+ if (filterCapabilities) {
67
+ schema.filter = { capabilities: filterCapabilities };
68
+ } else {
69
+ delete schema.filter;
70
+ }
71
+ }
72
+ // schema
73
+ if (generateJsonScene === 'api' && !schema.description && schema.title) {
74
+ schema.description = schema.title;
75
+ delete schema.title;
76
+ }
77
+ // errorMessage
78
+ this._translateErrorMessages(schema);
79
+ // properties
80
+ const properties = cast<SchemaObject30 | SchemaObject31>(schema).properties;
81
+ if (properties && typeof properties === 'object') {
82
+ for (const prop in properties) {
83
+ const propObj = properties[prop];
84
+ if (propObj) {
85
+ properties[prop] = this._translateSchema(propObj, generateJsonScene);
86
+ }
87
+ }
88
+ }
89
+ // items
90
+ const items = cast<SchemaObject30 | SchemaObject31>(schema).items;
91
+ if (items && typeof items === 'object') {
92
+ cast<SchemaObject30 | SchemaObject31>(schema).items = this._translateSchema(items, generateJsonScene);
93
+ }
94
+ // ok
95
+ return schema;
96
+ }
97
+
98
+ private _translateErrorMessages(obj: any) {
99
+ if (!obj.errorMessage) return;
100
+ for (const key in obj.errorMessage) {
101
+ let error = obj.errorMessage[key];
102
+ if (typeof error === 'function') {
103
+ error = error();
104
+ }
105
+ const scope = Object.assign({}, obj);
106
+ if (!isNil(obj.minLength)) scope.minimum = obj.minLength;
107
+ if (!isNil(obj.exclusiveMinimum)) scope.minimum = obj.exclusiveMinimum;
108
+ if (!isNil(obj.maxLength)) scope.maximum = obj.maxLength;
109
+ if (!isNil(obj.exclusiveMaximum)) scope.maximum = obj.exclusiveMaximum;
110
+ obj.errorMessage[key] = translateError(
111
+ (text: string, ...args: any[]) => {
112
+ return this.app.meta.text(text, ...args);
113
+ },
114
+ error,
115
+ scope,
116
+ );
117
+ }
118
+ }
119
+
120
+ public collectRegistry() {
121
+ const registry = new OpenAPIRegistry();
122
+ // securitySchemes
123
+ const configSecuritySchemes = this.scope.config.securitySchemes;
124
+ for (const key in configSecuritySchemes) {
125
+ let securityScheme = configSecuritySchemes[key];
126
+ if (typeof securityScheme === 'function') {
127
+ securityScheme = (securityScheme as any).call(this.app);
128
+ }
129
+ registry.registerComponent('securitySchemes', key, securityScheme as any);
130
+ }
131
+ // schema: independent
132
+ for (const sceneName of ['dto', 'entity']) {
133
+ const onionSlices = this.bean.onion[sceneName].getOnionsEnabledCached();
134
+ for (const onionSlice of onionSlices) {
135
+ if (onionSlice.beanOptions.options?.independent) {
136
+ const schema = $schema(onionSlice.beanOptions.beanClass);
137
+ registry.register(onionSlice.beanOptions.beanFullName, schema);
138
+ }
139
+ }
140
+ }
141
+ // controller
142
+ for (const controller of this.bean.onion.controller.getOnionsEnabledCached()) {
143
+ this.collectController(registry, controller.beanOptions.module, controller.beanOptions.beanClass);
144
+ }
145
+ return registry;
146
+ }
147
+
148
+ public collectController(registry: OpenAPIRegistry, moduleName: string, controller: Constructable, actionKey?: string) {
149
+ // info
150
+ const info = ModuleInfo.parseInfo(moduleName)!;
151
+ // controller options
152
+ const beanOptions = appResource.getBean(controller);
153
+ if (!beanOptions) return;
154
+ const controllerBeanFullName = beanOptions.beanFullName;
155
+ const controllerOptions = beanOptions.options as IDecoratorControllerOptions;
156
+ const controllerPath = controllerOptions.path;
157
+ const controllerOpenApiOptions = appMetadata.getMetadata<IOpenapiOptions>(SymbolOpenApiOptions, controller);
158
+ if (controllerOpenApiOptions?.exclude) return;
159
+ // descs
160
+ const descs = Object.getOwnPropertyDescriptors(controller.prototype);
161
+ const actionKeys = actionKey ? [actionKey] : Object.keys(descs);
162
+ for (const actionKey of actionKeys) {
163
+ const desc = descs[actionKey];
164
+ if (['constructor'].includes(actionKey)) continue;
165
+ if (!desc.value || typeof desc.value !== 'function') continue;
166
+ this._registerControllerAction(
167
+ registry,
168
+ info,
169
+ controller,
170
+ beanOptions,
171
+ controllerBeanFullName,
172
+ controllerPath,
173
+ controllerOpenApiOptions,
174
+ actionKey,
175
+ desc,
176
+ );
177
+ }
178
+ }
179
+
180
+ private _registerControllerAction(
181
+ registry: OpenAPIRegistry,
182
+ info: ModuleInfo.IModuleInfo,
183
+ controller: Constructable,
184
+ beanOptions: IDecoratorBeanOptionsBase,
185
+ _controllerBeanFullName: string,
186
+ controllerPath: string | undefined,
187
+ controllerOpenApiOptions: IOpenapiOptions | undefined,
188
+ actionKey: string,
189
+ _desc: PropertyDescriptor,
190
+ ) {
191
+ // app
192
+ const app = this.app;
193
+
194
+ // action options: should not extend controllerOpenApiOptions
195
+ const actionOpenApiOptions = appMetadata.getMetadata<IOpenapiOptions>(SymbolOpenApiOptions, controller.prototype, actionKey);
196
+ if (actionOpenApiOptions?.exclude) return;
197
+
198
+ // actionPath/actionMethod
199
+ if (!appMetadata.hasMetadata(SymbolRequestMappingHandler, controller.prototype, actionKey)) return;
200
+ const handlerMetadata = appMetadata.getMetadata<RequestMappingMetadata>(SymbolRequestMappingHandler, controller.prototype, actionKey)!;
201
+ const actionPath: string = handlerMetadata.path || '';
202
+ const actionMethod: TypeRequestMethod = handlerMetadata.method || 'get';
203
+
204
+ // routePath
205
+ const routePath = app.util.combineApiPathControllerAndAction(info.relativeName, controllerPath, actionPath, true, true);
206
+ // :id -> {id}
207
+ const routePath2 = routePath.replace(/:([^/]+)/g, '{$1}');
208
+
209
+ // tags
210
+ let tags: string[] | undefined = actionOpenApiOptions?.tags ?? controllerOpenApiOptions?.tags;
211
+ if (!tags || tags.length === 0) {
212
+ tags = [toUpperCaseFirstChar(this.app.util.combineResourceName(beanOptions.name, info.relativeName, true, true))];
213
+ }
214
+ // operationId
215
+ let operationId = actionOpenApiOptions?.operationId ?? actionKey;
216
+ operationId = `${tags[0]}_${operationId}`;
217
+ // security
218
+ const _public: boolean | undefined = actionOpenApiOptions?.public ?? controllerOpenApiOptions?.public;
219
+ let security: SecurityRequirementObject[] | undefined;
220
+ if (!_public) {
221
+ security = [
222
+ {
223
+ bearerAuth: [],
224
+ },
225
+ ];
226
+ }
227
+ // registerPath
228
+ registry.registerPath({
229
+ tags,
230
+ method: actionMethod,
231
+ path: routePath2,
232
+ operationId,
233
+ security,
234
+ description: actionOpenApiOptions?.description as string,
235
+ summary: actionOpenApiOptions?.summary as string,
236
+ request: this._collectRequest(info, controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions),
237
+ responses: this._collectResponses(controller, actionKey, actionOpenApiOptions),
238
+ });
239
+ }
240
+
241
+ private _collectRequest(
242
+ info: ModuleInfo.IModuleInfo,
243
+ controller: Constructable,
244
+ actionKey: string,
245
+ actionOpenApiOptions: IOpenapiOptions | undefined,
246
+ controllerOpenApiOptions: IOpenapiOptions | undefined,
247
+ ) {
248
+ // meta
249
+ const argsMeta = this._prepareArgsMeta(controller, actionKey, actionOpenApiOptions, controllerOpenApiOptions);
250
+ if (!argsMeta) return;
251
+ // args
252
+ const argsMapWithField: any = {};
253
+ const argsMapIsolate: any = {};
254
+ let isUpload;
255
+ for (const argMeta of argsMeta) {
256
+ if (!argMeta) continue;
257
+ if (!__ArgumentTypes.includes(argMeta.type)) continue;
258
+ if (['fields', 'field', 'files', 'file'].includes(argMeta.type)) {
259
+ isUpload = true;
260
+ }
261
+ if (argMeta.field) {
262
+ if (!argsMapWithField[argMeta.type]) {
263
+ argsMapWithField[argMeta.type] = {};
264
+ }
265
+ argsMapWithField[argMeta.type][argMeta.field] = argMeta.schema;
266
+ } else {
267
+ if (!argsMapIsolate[argMeta.type]) {
268
+ argsMapIsolate[argMeta.type] = argMeta.schema;
269
+ }
270
+ }
271
+ }
272
+ // request
273
+ const request: any = {};
274
+ if (isUpload) {
275
+ const schemaObj: any = {};
276
+ // not check argsMapIsolate.fields
277
+ if (argsMapWithField.fields) Object.assign(schemaObj, argsMapWithField.fields);
278
+ if (argsMapWithField.field) Object.assign(schemaObj, argsMapWithField.field);
279
+ if (argsMapWithField.files) Object.assign(schemaObj, argsMapWithField.files);
280
+ if (argsMapWithField.file) Object.assign(schemaObj, argsMapWithField.file);
281
+ if (argsMapIsolate.files) schemaObj.blobs = argsMapIsolate.files;
282
+ const schema = z.object(schemaObj);
283
+ // body
284
+ request.body = {
285
+ required: true,
286
+ content: {
287
+ 'multipart/form-data': {
288
+ schema,
289
+ },
290
+ },
291
+ };
292
+ } else {
293
+ for (const argumentType of __ArgumentTypes) {
294
+ let schema: z.ZodType | undefined = argsMapIsolate[argumentType];
295
+ if (argsMapWithField[argumentType]) {
296
+ if (!schema) {
297
+ schema = z.object(argsMapWithField[argumentType]);
298
+ } else {
299
+ schema = (schema as any).extend(argsMapWithField[argumentType]);
300
+ }
301
+ }
302
+ if (!schema) continue;
303
+ // check schema
304
+ if (getInnerTypeName(schema) === 'any') {
305
+ throw new Error(`Invalid Openapi argument type: ${info.relativeName}:${controller.name}.${actionKey}#${argumentType}`);
306
+ }
307
+ // record
308
+ if (argumentType === 'body') {
309
+ // body
310
+ request.body = {
311
+ required: !schema.safeParse(undefined).success,
312
+ content: {
313
+ 'application/json': {
314
+ schema,
315
+ },
316
+ },
317
+ };
318
+ } else {
319
+ // others
320
+ const name = argumentType === 'param' ? 'params' : argumentType;
321
+ request[name] = schema;
322
+ }
323
+ }
324
+ }
325
+
326
+ return request;
327
+ }
328
+
329
+ private _collectResponses(controller: Constructable, actionKey: string, actionOpenApiOptions: IOpenapiOptions | undefined) {
330
+ // contentType
331
+ const contentType = actionOpenApiOptions?.contentType || 'application/json';
332
+ // body schema
333
+ const bodySchema = this._parseBodySchema(controller, actionKey, actionOpenApiOptions, contentType);
334
+ // response
335
+ const response = {
336
+ description: '',
337
+ content: {
338
+ [contentType]: {
339
+ schema: bodySchema,
340
+ },
341
+ },
342
+ };
343
+ // responses
344
+ const responses = { 200: response };
345
+ return responses;
346
+ }
347
+
348
+ private _parseBodySchema(controller: Constructable, actionKey: string, actionOpenApiOptions: IOpenapiOptions | undefined, contentType: string) {
349
+ // bodySchema
350
+ let bodySchema: z.ZodType;
351
+ if (actionOpenApiOptions?.bodySchema) {
352
+ bodySchema = actionOpenApiOptions.bodySchema;
353
+ } else {
354
+ const metaType = appMetadata.getDesignReturntype(controller.prototype, actionKey);
355
+ bodySchema = $schema(metaType as any);
356
+ }
357
+ // wrapper
358
+ if (contentType !== 'application/json') return bodySchema;
359
+ if (actionOpenApiOptions?.bodySchemaWrapper === false) return bodySchema;
360
+ const wrapper = actionOpenApiOptions?.bodySchemaWrapper ?? bodySchemaWrapperDefault;
361
+ return wrapper(bodySchema);
362
+ }
363
+
364
+ private _prepareArgsMeta(
365
+ controller: Constructable,
366
+ actionKey: string,
367
+ actionOpenApiOptions: IOpenapiOptions | undefined,
368
+ controllerOpenApiOptions: IOpenapiOptions | undefined,
369
+ ) {
370
+ // meta
371
+ let argsMeta = appMetadata.getMetadata<RouteHandlerArgumentMetaDecorator[]>(SymbolRouteHandlersArgumentsMeta, controller.prototype, actionKey);
372
+ // headers
373
+ const objHeaders = Object.assign(
374
+ {} as any,
375
+ this._combineArgHeaders(controllerOpenApiOptions?.headers),
376
+ this._combineArgHeaders(actionOpenApiOptions?.headers),
377
+ );
378
+ if (isEmptyObject(objHeaders)) return argsMeta;
379
+ // merge
380
+ if (!argsMeta) argsMeta = [];
381
+ let argHeaders = argsMeta.find(item => item.type === 'headers' && !item.field);
382
+ if (!argHeaders) {
383
+ argHeaders = { type: 'headers', field: undefined, schema: z.object(objHeaders) } as any;
384
+ argsMeta.push(argHeaders!);
385
+ } else {
386
+ if (!(argHeaders.schema as any).extend) throw new Error(`headers schema is not valid: ${actionKey}`);
387
+ argHeaders.schema = (argHeaders.schema as any).extend(objHeaders);
388
+ }
389
+ return argsMeta;
390
+ }
391
+
392
+ private _combineArgHeaders(headers?: IOpenapiHeader[] | undefined) {
393
+ if (!headers) return;
394
+ const objHeaders = {};
395
+ for (const header of headers) {
396
+ objHeaders[header.name] = z.string().openapi({ description: header.description });
397
+ }
398
+ return objHeaders;
399
+ }
400
+ }
@@ -0,0 +1,18 @@
1
+ export interface IResourceActionTableOptions {}
2
+ export interface IResourceActionRowOptions {}
3
+
4
+ export interface TypeResourceActionTableRecord {
5
+ create: IResourceActionTableOptions;
6
+ operationsTable: IResourceActionTableOptions;
7
+ }
8
+
9
+ export interface TypeResourceActionRowRecord {
10
+ view: IResourceActionRowOptions;
11
+ update: IResourceActionRowOptions;
12
+ delete: IResourceActionRowOptions;
13
+ operationsRow: IResourceActionRowOptions;
14
+ }
15
+
16
+ export type TypeResourceActionRowRecordRender = {
17
+ [key in keyof TypeResourceActionRowRecord as `action${Capitalize<key>}`]: TypeResourceActionRowRecord[key];
18
+ };
@@ -0,0 +1,11 @@
1
+ export interface IBehaviorRecord {}
2
+
3
+ export type TypeBehaviorRecordSelector<PREFIX extends string> = {
4
+ [K in keyof IBehaviorRecord as K extends `${string}:${PREFIX}${string}` ? K : never]: IBehaviorRecord[K];
5
+ };
6
+ export type TypeBehaviorRecordSelectorKeys<PREFIX extends string> = keyof TypeBehaviorRecordSelector<PREFIX>;
7
+
8
+ export type TypeBehaviorRecordSelectorStrict<PREFIX extends string> = {
9
+ [K in keyof IBehaviorRecord as K extends `${string}:${PREFIX}` ? K : never]: IBehaviorRecord[K];
10
+ };
11
+ export type TypeBehaviorRecordSelectorKeysStrict<PREFIX extends string> = keyof TypeBehaviorRecordSelectorStrict<PREFIX>;
@@ -0,0 +1,5 @@
1
+ import type { ICaptchaSceneRecord } from 'vona-module-a-captcha';
2
+
3
+ export interface ICaptchaOptions {
4
+ scene?: keyof ICaptchaSceneRecord;
5
+ }
@@ -0,0 +1,14 @@
1
+ export interface IComponentRecord {}
2
+ export interface ITableCellComponentRecord {}
3
+
4
+ export type TypeComponentRecordSelector<PREFIX extends string> = {
5
+ [K in keyof IComponentRecord as K extends `${string}:${PREFIX}${string}` ? K : never]: IComponentRecord[K];
6
+ };
7
+ export type TypeComponentRecordSelectorKeys<PREFIX extends string> = keyof TypeComponentRecordSelector<PREFIX>;
8
+
9
+ export type TypeComponentRecordSelectorStrict<PREFIX extends string> = {
10
+ [K in keyof IComponentRecord as K extends `${string}:${PREFIX}` ? K : never]: IComponentRecord[K];
11
+ };
12
+ export type TypeComponentRecordSelectorKeysStrict<PREFIX extends string> = keyof TypeComponentRecordSelectorStrict<PREFIX>;
13
+
14
+ export type TypeComponentLayoutRecord = TypeComponentRecordSelector<'layout'>;
@@ -0,0 +1,25 @@
1
+ export type TypeDateFormatPreset =
2
+ | 'DATE_SHORT'
3
+ | 'DATE_MED'
4
+ | 'DATE_MED_WITH_WEEKDAY'
5
+ | 'DATE_FULL'
6
+ | 'DATE_HUGE'
7
+ | 'TIME_SIMPLE'
8
+ | 'TIME_WITH_SECONDS'
9
+ | 'TIME_WITH_SHORT_OFFSET'
10
+ | 'TIME_WITH_LONG_OFFSET'
11
+ | 'TIME_24_SIMPLE'
12
+ | 'TIME_24_WITH_SECONDS'
13
+ | 'TIME_24_WITH_SHORT_OFFSET'
14
+ | 'TIME_24_WITH_LONG_OFFSET'
15
+ | 'DATETIME_SHORT'
16
+ | 'DATETIME_MED'
17
+ | 'DATETIME_MED_WITH_WEEKDAY'
18
+ | 'DATETIME_FULL'
19
+ | 'DATETIME_HUGE'
20
+ | 'DATETIME_SHORT_WITH_SECONDS'
21
+ | 'DATETIME_MED_WITH_SECONDS'
22
+ | 'DATETIME_FULL_WITH_SECONDS'
23
+ | 'DATETIME_HUGE_WITH_SECONDS';
24
+
25
+ export type TypeDateFormat = { preset: TypeDateFormatPreset } | string;
@@ -0,0 +1,45 @@
1
+ import type { Constructable, Type, VonaContext } from 'vona';
2
+ import type { z } from 'zod';
3
+
4
+ export interface ISchemaObjectOptions {
5
+ loose?: boolean;
6
+ strict?: boolean;
7
+ }
8
+
9
+ export interface RouteHandlerArgumentMetaDecorator {
10
+ index: number;
11
+ type: RouteHandlerArgumentType;
12
+ field?: string;
13
+ pipes: Function[];
14
+ schema: z.ZodType;
15
+ extractValue?: TypeExtractValue;
16
+ }
17
+
18
+ export interface RouteHandlerArgumentMeta {
19
+ type: RouteHandlerArgumentType;
20
+ field?: string;
21
+ metaType?: Type<any>;
22
+ controller: Constructable;
23
+ method: string;
24
+ index: number;
25
+ }
26
+
27
+ export type RouteHandlerArgumentType =
28
+ | 'request'
29
+ | 'response'
30
+ | 'body'
31
+ | 'query'
32
+ | 'param'
33
+ | 'headers'
34
+ | 'session'
35
+ | 'fields'
36
+ | 'field'
37
+ | 'files'
38
+ | 'file'
39
+ | 'host'
40
+ | 'ip'
41
+ | 'rawBody'
42
+ | 'string'
43
+ | 'user';
44
+
45
+ export type TypeExtractValue = (ctx: VonaContext, argMeta: RouteHandlerArgumentMetaDecorator) => Promise<any>;
@@ -0,0 +1,21 @@
1
+ import type { TypeBehaviorRecordSelectorKeys, TypeBehaviorRecordSelectorKeysStrict } from './behavior.ts';
2
+ import type { TypeComponentRecordSelectorKeysStrict } from './component.ts';
3
+ import type { TypeFormFieldRenderComponentProvider } from './rest.ts';
4
+
5
+ export interface IFormProviderBehaviors {
6
+ formField?: TypeBehaviorRecordSelectorKeysStrict<'formField'>;
7
+ formFieldModel?: TypeBehaviorRecordSelectorKeys<'formFieldModel'>;
8
+ formFieldLayout?: TypeBehaviorRecordSelectorKeys<'formFieldLayout'>;
9
+ }
10
+
11
+ export interface IFormProviderComponents {
12
+ formField?: TypeComponentRecordSelectorKeysStrict<'formField'>;
13
+ text?: TypeFormFieldRenderComponentProvider;
14
+ password?: TypeFormFieldRenderComponentProvider;
15
+ currency?: TypeFormFieldRenderComponentProvider;
16
+ }
17
+
18
+ export interface IFormProvider {
19
+ components?: IFormProviderComponents;
20
+ behaviors?: IFormProviderBehaviors;
21
+ }
@@ -0,0 +1,20 @@
1
+ import '@cabloy/zod-query';
2
+
3
+ export * from './actions.ts';
4
+ export * from './behavior.ts';
5
+ export * from './captcha.ts';
6
+ export * from './component.ts';
7
+ export * from './date.ts';
8
+ export * from './decorator.ts';
9
+ export * from './formProvider.ts';
10
+ export * from './openapi.ts';
11
+ export * from './permissions.ts';
12
+ export * from './resource.ts';
13
+ export * from './resourceMeta.ts';
14
+ export * from './resourcePicker.ts';
15
+ export * from './rest.ts';
16
+ export * from './select.ts';
17
+ export * from './table.ts';
18
+ export * from './tableProvider.ts';
19
+ export * from './textarea.ts';
20
+ export * from './toggle.ts';
@@ -0,0 +1,7 @@
1
+ import type { IOpenapiOptionsResourceMeta } from './resourceMeta.ts';
2
+
3
+ declare module 'vona-module-a-openapiutils' {
4
+ export interface IOpenapiOptions {
5
+ resourceMeta?: IOpenapiOptionsResourceMeta;
6
+ }
7
+ }
@@ -0,0 +1,18 @@
1
+ import type { IRoleIdRecord, IRoleNameRecord } from 'vona-module-a-user';
2
+
3
+ export interface IOpenapiActionRecord {
4
+ create: boolean;
5
+ view: boolean;
6
+ update: boolean;
7
+ delete: boolean;
8
+ }
9
+
10
+ export type IOpenapiPermissionModeActionActions = {
11
+ [K in keyof IOpenapiActionRecord]?: IOpenapiActionRecord[K];
12
+ };
13
+
14
+ export interface IOpenapiPermissions {
15
+ roleIds?: (keyof IRoleIdRecord)[];
16
+ roleNames?: (keyof IRoleNameRecord)[];
17
+ actions?: IOpenapiPermissionModeActionActions;
18
+ }
@@ -0,0 +1 @@
1
+ export interface IResourceRecord {}
@@ -0,0 +1,38 @@
1
+ import type { IOpenapiPermissions, TypeComponentRecordSelectorKeysStrict, TypeRenderComponentJsx } from 'vona-module-a-openapi';
2
+
3
+ import type { IFormProvider } from './formProvider.ts';
4
+ import type { ITableProvider } from './tableProvider.ts';
5
+
6
+ export type TypeOpenapiPermissions = IOpenapiPermissions | boolean;
7
+
8
+ export interface IOpenapiOptionsResourceMeta {
9
+ /**
10
+ * false: disallow
11
+ * true: public
12
+ * undefined: by api
13
+ * IOpenapiPermissions: specific
14
+ */
15
+ permissions?: TypeOpenapiPermissions;
16
+ provider?: IOpenapiOptionsResourceMetaProvider;
17
+ form?: IOpenapiOptionsResourceMetaForm;
18
+ table?: IOpenapiOptionsResourceMetaTable;
19
+ }
20
+
21
+ export interface IOpenapiOptionsResourceMetaForm {
22
+ provider?: IFormProvider;
23
+ }
24
+
25
+ export interface IOpenapiOptionsResourceMetaTable {
26
+ provider?: ITableProvider;
27
+ }
28
+
29
+ export interface IOpenapiOptionsResourceMetaProvider {
30
+ components?: IOpenapiOptionsResourceMetaProviderComponents;
31
+ }
32
+
33
+ export interface IOpenapiOptionsResourceMetaProviderComponents {
34
+ restPage?: TypeComponentRecordSelectorKeysStrict<'restPage'> | TypeRenderComponentJsx;
35
+ restPageEntry?: TypeComponentRecordSelectorKeysStrict<'restPageEntry'> | TypeRenderComponentJsx;
36
+ table?: TypeComponentRecordSelectorKeysStrict<'table'>;
37
+ form?: TypeComponentRecordSelectorKeysStrict<'form'>;
38
+ }
@@ -0,0 +1,11 @@
1
+ import type { IResourceRecord } from './resource.ts';
2
+ import type { ISelectOptions } from './select.ts';
3
+ import type { ITableQuery } from './table.ts';
4
+
5
+ export interface IResourcePickerOptions {
6
+ resource?: keyof IResourceRecord;
7
+ actionPath?: string;
8
+ query?: ITableQuery;
9
+ selectOptions?: ISelectOptions;
10
+ relation?: string;
11
+ }