5htp-core 0.6.2 → 0.6.3

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 (33) hide show
  1. package/client/app/index.ts +2 -1
  2. package/client/assets/css/components/table.less +1 -0
  3. package/client/components/Input.tsx +0 -2
  4. package/client/components/Rte/Editor.tsx +2 -0
  5. package/client/components/Rte/index.tsx +0 -1
  6. package/client/services/router/request/api.ts +0 -9
  7. package/common/router/request/api.ts +0 -8
  8. package/package.json +1 -1
  9. package/server/app/container/console/index.ts +65 -48
  10. package/server/app/index.ts +19 -8
  11. package/server/app/service/index.ts +55 -15
  12. package/server/services/auth/router/index.ts +3 -1
  13. package/server/services/disks/driver.ts +5 -1
  14. package/server/services/disks/drivers/s3/index.ts +2 -2
  15. package/server/services/disks/index.ts +10 -5
  16. package/server/services/email/index.ts +1 -1
  17. package/server/services/prisma/Facet.ts +39 -15
  18. package/server/services/prisma/index.ts +5 -7
  19. package/server/services/router/http/multipart.ts +5 -0
  20. package/server/services/router/index.ts +50 -35
  21. package/server/services/router/request/api.ts +0 -12
  22. package/server/services/router/request/validation/zod.ts +180 -0
  23. package/server/services/router/response/index.ts +14 -9
  24. package/server/services/router/response/page/document.tsx +5 -3
  25. package/server/services/router/service.ts +7 -4
  26. package/server/services/schema/request.ts +21 -34
  27. package/server/services/schema/router/index.ts +3 -3
  28. package/types/icons.d.ts +1 -1
  29. package/common/data/input/validate.ts +0 -54
  30. package/server/services/router/request/validation/index.ts +0 -23
  31. package/server/services/router/request/validation/schema.ts +0 -211
  32. package/server/services/router/request/validation/validator.ts +0 -117
  33. package/server/services/router/request/validation/validators.ts +0 -485
@@ -10,7 +10,7 @@ import type { Application } from '@server/app';
10
10
  import Service from '@server/app/service';
11
11
 
12
12
  // Specific
13
- import Facet, { TSubset } from './Facet';
13
+ import Facet, { TDelegate, TSubset, Transform } from './Facet';
14
14
 
15
15
  /*----------------------------------
16
16
  - TYPES
@@ -52,13 +52,11 @@ export default class ModelsManager extends Service<Config, Hooks, Application> {
52
52
  }
53
53
 
54
54
  public Facet<
55
- D extends {
56
- findMany(args?: any): Promise<any>
57
- findFirst(args?: any): Promise<any>
58
- },
55
+ D extends TDelegate<R>,
59
56
  S extends TSubset,
60
- R
61
- >(...args: [D, S, R]) {
57
+ R,
58
+ RT
59
+ >(...args: [D, S, Transform<S, R, RT>]) {
62
60
 
63
61
  return new Facet(
64
62
  this.client,
@@ -81,11 +81,16 @@ export const traiterMultipart = (...canaux: any[]) => {
81
81
  &&
82
82
  donnee.data instanceof Buffer
83
83
  ){
84
+ const md5 = donnee.md5;
85
+ const data = donnee.data;
84
86
  donnee = new File(donnee.data, donnee.name, {
85
87
  type: donnee.mimetype,
86
88
  lastModified: Date.now(),
87
89
  //size: donnee.size,
88
90
  });
91
+
92
+ donnee.md5 = md5;
93
+ donnee.data = data;
89
94
  }
90
95
 
91
96
  brancheA[ cle ] = donnee;
@@ -55,7 +55,7 @@ export type { default as Request, UploadedFile } from "./request";
55
55
  export type { default as Response, TRouterContext } from "./response";
56
56
  export type { TRoute, TAnyRoute } from '@common/router';
57
57
 
58
- export type TApiRegisterArgs<TRouter extends ServerRouter> = ([
58
+ export type TApiRegisterArgs<TRouter extends TServerRouter> = ([
59
59
  path: string,
60
60
  controller: TServerController<TRouter>
61
61
  ] | [
@@ -64,7 +64,7 @@ export type TApiRegisterArgs<TRouter extends ServerRouter> = ([
64
64
  controller: TServerController<TRouter>
65
65
  ])
66
66
 
67
- export type TServerController<TRouter extends ServerRouter> = (context: TRouterContext<TRouter>) => any;
67
+ export type TServerController<TRouter extends TServerRouter> = (context: TRouterContext<TRouter>) => any;
68
68
 
69
69
  export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE' | 'OPTIONS'
70
70
  export type TRouteHttpMethod = HttpMethod | '*';
@@ -83,8 +83,7 @@ export type HttpHeaders = { [cle: string]: string }
83
83
  const LogPrefix = '[router]';
84
84
 
85
85
  export type Config<
86
- TServiceList extends TRouterServicesList = TRouterServicesList,
87
- TAdditionnalSsrData extends {} = {}
86
+ TServices extends TRouterServicesList
88
87
  > = {
89
88
 
90
89
  debug: boolean,
@@ -96,18 +95,16 @@ export type Config<
96
95
  http: HttpServiceConfig,
97
96
 
98
97
  context: (
99
- request: ServerRequest<ServerRouter>,
98
+ request: ServerRequest<TServerRouter>,
100
99
  app: Application
101
- ) => TAdditionnalSsrData,
100
+ ) => {},
102
101
 
103
- plugins: {
104
- [routerServiceId: string]: RouterService
105
- }
102
+ plugins: TServices
106
103
  }
107
104
 
108
105
  // Set it as a function, so when we instanciate the services, we can callthis.router to pass the router instance in roiuter services
109
106
  type TRouterServicesList = {
110
- [serviceName: string]: RouterService<ServerRouter>
107
+ [serviceName: string]: RouterService
111
108
  }
112
109
 
113
110
  export type Hooks = {
@@ -117,14 +114,20 @@ export type Hooks = {
117
114
  export type TControllerDefinition = {
118
115
  path?: string,
119
116
  schema?: zod.ZodSchema,
120
- controller: TServerController<ServerRouter>,
117
+ controller: TServerController<TServerRouter>,
121
118
  }
122
119
 
120
+ export type TServerRouter = ServerRouter<Application, TRouterServicesList, Config<TRouterServicesList>>;
121
+
123
122
  /*----------------------------------
124
123
  - CLASSE
125
124
  ----------------------------------*/
126
- export default class ServerRouter
127
- extends Service<Config, Hooks, Application> implements BaseRouter {
125
+ export default class ServerRouter<
126
+ TApplication extends Application,
127
+ TServices extends TRouterServicesList,
128
+ TConfig extends Config<TServices>,
129
+ >
130
+ extends Service<TConfig, Hooks, TApplication, TApplication> implements BaseRouter {
128
131
 
129
132
  public disks = this.use<DisksManager>('Core/Disks', { optional: true });
130
133
 
@@ -151,7 +154,7 @@ export default class ServerRouter
151
154
  - SERVICE
152
155
  ----------------------------------*/
153
156
 
154
- public constructor( ...args: TServiceArgs<ServerRouter>) {
157
+ public constructor( ...args: TServiceArgs< ServerRouter<TApplication, TServices, TConfig> >) {
155
158
 
156
159
  super(...args);
157
160
 
@@ -165,14 +168,11 @@ export default class ServerRouter
165
168
 
166
169
  public async ready() {
167
170
 
168
- // Every hours
169
- setInterval(() => {
170
- this.refreshStaticPages();
171
- }, 1000 * 60 * 60);
172
-
173
171
  // Detect router services
174
172
  for (const serviceName in this.config.plugins) {
175
- this.app.register( this.config.plugins[serviceName] )
173
+ const service = this.config.plugins[serviceName];
174
+ service.parent = this;
175
+ this.app.register( service )
176
176
  }
177
177
 
178
178
  // Use require to avoid circular references
@@ -211,6 +211,12 @@ export default class ServerRouter
211
211
  );
212
212
  };
213
213
 
214
+
215
+ // When all the services are ready, initialize static routes
216
+ this.app.on('ready', () => {
217
+ this.initStaticRoutes();
218
+ });
219
+
214
220
  }
215
221
 
216
222
  public async shutdown() {
@@ -233,6 +239,8 @@ export default class ServerRouter
233
239
 
234
240
  if (!rendered) {
235
241
 
242
+ console.log('[router] renderStatic: url', url);
243
+
236
244
  const fullUrl = this.url(url, {}, true);
237
245
  const response = await got( fullUrl, {
238
246
  method: 'GET',
@@ -261,6 +269,26 @@ export default class ServerRouter
261
269
 
262
270
  }
263
271
 
272
+ private initStaticRoutes() {
273
+
274
+ for (const route of this.routes) {
275
+
276
+ if (!route.options.static)
277
+ continue;
278
+
279
+ // Add to static pages
280
+ // Should be a GET oage that don't take any parameter
281
+ for (const url of route.options.static.urls) {
282
+ this.renderStatic(url, route.options.static);
283
+ }
284
+ }
285
+
286
+ // Every hours, refresh static pages
287
+ setInterval(() => {
288
+ this.refreshStaticPages();
289
+ }, 1000 * 60 * 60);
290
+ }
291
+
264
292
  private refreshStaticPages() {
265
293
 
266
294
  console.log('[router] refreshStaticPages');
@@ -270,15 +298,10 @@ export default class ServerRouter
270
298
  if (page.expire && page.expire < Date.now()) {
271
299
 
272
300
  this.renderStatic(pageUrl, page.options);
273
-
274
301
  }
275
302
  }
276
303
  }
277
304
 
278
-
279
-
280
-
281
-
282
305
  private registerRoutes(defModules: GlobImportedWithMetas<TRouteModule>) {
283
306
  for (const routeModule of defModules) {
284
307
 
@@ -327,14 +350,6 @@ export default class ServerRouter
327
350
 
328
351
  this.routes.push(route);
329
352
 
330
- // Add to static pages
331
- // Should be a GET oage that don't take any parameter
332
- if (options.static) {
333
- for (const url of options.static.urls) {
334
- this.renderStatic(url, options.static);
335
- }
336
- }
337
-
338
353
  return this;
339
354
 
340
355
  }
@@ -370,10 +385,10 @@ export default class ServerRouter
370
385
  req: Request,
371
386
  res: Response,
372
387
  next: NextFunction,
373
- requestContext: TRouterContext
388
+ requestContext: TRouterContext<this>
374
389
  ) => void
375
390
  ) {
376
- return (context: TRouterContext) => new Promise((resolve) => {
391
+ return (context: TRouterContext<this>) => new Promise((resolve) => {
377
392
 
378
393
  context.request.res.on('finish', function() {
379
394
  //console.log('the response has been sent', request.res.statusCode);
@@ -31,18 +31,6 @@ export default class ApiClientRequest extends RequestService implements ApiClien
31
31
  throw new Error("api.fetch shouldn't be called here.");
32
32
  }
33
33
 
34
- public get = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
35
- this.createFetcher<TData>('GET', path, data, opts);
36
-
37
- public post = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
38
- this.createFetcher<TData>('POST', path, data, opts);
39
-
40
- public put = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
41
- this.createFetcher<TData>('PUT', path, data, opts);
42
-
43
- public delete = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
44
- this.createFetcher<TData>('DELETE', path, data, opts);
45
-
46
34
  /*----------------------------------
47
35
  - PLACEHOLDERS
48
36
  ----------------------------------*/
@@ -0,0 +1,180 @@
1
+ import { InputError } from '@common/errors';
2
+ import zod, { _ZodType } from 'zod';
3
+
4
+ export type TRichTextValidatorOptions = {
5
+ attachements?: boolean
6
+ }
7
+
8
+ export const preprocessSchema = (schema: zod.ZodObject): zod.ZodObject => {
9
+
10
+ // Not working, data is {}
11
+ return schema;
12
+
13
+ if (!(schema instanceof zod.ZodObject))
14
+ return schema;
15
+
16
+ if (schema.withPreprocessing)
17
+ return schema;
18
+
19
+ const shape = schema.def.shape;
20
+ const newShape: Record<string, zod.ZodTypeAny> = {};
21
+
22
+ for (const key in shape) {
23
+
24
+ if (!['newEntity', 'email'].includes(key))
25
+ continue;
26
+
27
+ let current: zod.ZodTypeAny = shape[key];
28
+ while (current) {
29
+
30
+ const origType = current.type;
31
+ const preprocessor = toPreprocess[origType];
32
+
33
+ if (origType === 'object') {
34
+ newShape[key] = preprocessSchema(current as zod.ZodObject);
35
+ break;
36
+ }
37
+
38
+ if (preprocessor) {
39
+ newShape[key] = preprocessor(current);
40
+ console.log('====newShape', key, newShape[key]);
41
+ break;
42
+ }
43
+
44
+ current = current.def;
45
+ }
46
+ }
47
+
48
+ const newSchema = zod.object(newShape);
49
+ newSchema.withPreprocessing = true;
50
+ return newSchema;
51
+ }
52
+
53
+ const toPreprocess = {
54
+
55
+ string: (zString: zod.ZodString) => zod.preprocess( val => {
56
+ return val === '' ? undefined : val;
57
+ }, zString),
58
+
59
+ int: (zInt: zod.ZodInt) => zod.preprocess( val => {
60
+ return typeof val === 'string' ? Number.parseInt(val) : val;
61
+ }, zInt),
62
+
63
+ }
64
+
65
+ export const schema = {
66
+ ...zod,
67
+
68
+ file: () => {
69
+
70
+ // Chaine = url ancien fichier = exclusion de la valeur pour conserver l'ancien fichier
71
+ // NOTE: Si la valeur est présente mais undefined, alors on supprimera le fichier
72
+ /*if (typeof val === 'string')
73
+ return true;*/
74
+
75
+ return zod.file();
76
+ },
77
+
78
+ choice: ( choices: string[] | { value: any, label: string }[] | _ZodType, options: { multiple?: boolean } = {} ) => {
79
+
80
+ const normalizeValue = (value: any) => typeof value === 'object' ? value.value : value;
81
+
82
+ const valueType: _ZodType = Array.isArray(choices)
83
+ ? zod.enum( choices.map(normalizeValue) )
84
+ : zod.string();
85
+
86
+ const itemType = zod.union([
87
+
88
+ zod.object({ value: valueType, label: zod.string() }),
89
+
90
+ valueType
91
+
92
+ ]);
93
+
94
+ const type = options.multiple ? zod.array( itemType ) : itemType;
95
+
96
+ return type.transform(v => {
97
+ if (options.multiple) {
98
+ return v.map(normalizeValue);
99
+ } else {
100
+ return normalizeValue(v);
101
+ }
102
+ });
103
+ },
104
+
105
+ richText: (opts: TRichTextValidatorOptions = {}) => schema.custom(val => {
106
+
107
+ if (typeof val !== 'string') {
108
+ console.error("Invalid rich text format.", val);
109
+ return false;
110
+ }
111
+
112
+ // We get a stringified json as input since the editor workds with JSON string
113
+ try {
114
+ val = JSON.parse(val);
115
+ } catch (error) {
116
+ console.error("Failed to parse rich text json:", error, val);
117
+ return false;//throw new InputError("Invalid rich text format.");
118
+ }
119
+
120
+ // Check that the root exists and has a valid type
121
+ if (!val || typeof val !== 'object' || typeof val.root !== 'object' || val.root.type !== 'root') {
122
+ console.error("Invalid rich text value (1).", val);
123
+ return false;//throw new InputError("Invalid rich text value (1).");
124
+ }
125
+
126
+ // Check if root has children array
127
+ if (!Array.isArray(val.root.children)) {
128
+ console.error("Invalid rich text value (2).", val);
129
+ return false;
130
+ }
131
+
132
+ // Validate each child node in root
133
+ for (const child of val.root.children) {
134
+ if (!validateLexicalNode(child, opts))
135
+ return false;
136
+ }
137
+
138
+ return true;
139
+ })
140
+ }
141
+
142
+ // Recursive function to validate each node
143
+ function validateLexicalNode(node: any, opts: TRichTextValidatorOptions ) {
144
+
145
+ // Each node should be an object with a `type` property
146
+ if (typeof node !== 'object' || !node.type || typeof node.type !== 'string')
147
+ throw new InputError("Invalid rich text value (3).");
148
+
149
+ // Validate text nodes
150
+ if (node.type === 'text') {
151
+
152
+ if (typeof node.text !== 'string')
153
+ throw new InputError("Invalid rich text value (4).");
154
+
155
+ // Validate paragraph, heading, or other structural nodes that may contain children
156
+ } else if (['paragraph', 'heading', 'list', 'listitem'].includes(node.type)) {
157
+
158
+ if (!Array.isArray(node.children) || !node.children.every(children => validateLexicalNode(children, opts))) {
159
+ throw new InputError("Invalid rich text value (5).");
160
+ }
161
+
162
+ // Files upload
163
+ } else if (node.type === 'image') {
164
+
165
+ // Check if allowed
166
+ /*if (opts.attachements === undefined)
167
+ throw new InputError("Image attachments not allowed in this rich text field.");*/
168
+
169
+ // TODO: check mime
170
+
171
+
172
+ // Upload file
173
+
174
+
175
+ }
176
+
177
+ return true;
178
+ }
179
+
180
+ export type { default as z } from 'zod';
@@ -12,7 +12,7 @@ import express from 'express';
12
12
 
13
13
  // Core
14
14
  import { Application } from '@server/app';
15
- import type ServerRouter from '@server/services/router';
15
+ import type { RouterService, default as ServerRouter, TServerRouter } from '@server/services/router';
16
16
  import ServerRequest from '@server/services/router/request';
17
17
  import { TRoute, TAnyRoute, TDomainsList } from '@common/router';
18
18
  import { NotFound, Forbidden, Anomaly } from '@common/errors';
@@ -38,10 +38,10 @@ export type TBasicSSrData = {
38
38
  domains: TDomainsList
39
39
  }
40
40
 
41
- export type TRouterContext<TRouter extends ServerRouter = ServerRouter> = (
41
+ export type TRouterContext<TRouter extends TServerRouter> = (
42
42
  // Request context
43
43
  {
44
- app: Application,
44
+ app: TRouter["app"],
45
45
  context: TRouterContext<TRouter>, // = this
46
46
  request: ServerRequest<TRouter>,
47
47
  api: ServerRequest<TRouter>["api"],
@@ -52,14 +52,19 @@ export type TRouterContext<TRouter extends ServerRouter = ServerRouter> = (
52
52
 
53
53
  Router: TRouter,
54
54
  }
55
- //& TRouterContextServices<TRouter>
55
+ & TRouterContextServices<TRouter>
56
56
  )
57
57
 
58
- export type TRouterContextServices<TRouter extends ServerRouter> = (
58
+ export type TRouterContextServices<
59
+ TRouter extends TServerRouter,
60
+ TPlugins = TRouter["config"]["plugins"]
61
+ > = (
59
62
  // Custom context via servuces
60
63
  // For each roiuter service, return the request service (returned by roiuterService.requestService() )
61
64
  {
62
- [serviceName in keyof TRouter["services"]]: ReturnType< TRouter["services"][serviceName]["requestService"] >
65
+ [serviceName in keyof TPlugins]: TPlugins[serviceName] extends RouterService
66
+ ? ReturnType<TPlugins[serviceName]["requestService"]>
67
+ : TPlugins[serviceName]
63
68
  }
64
69
  )
65
70
 
@@ -212,7 +217,7 @@ export default class ServerResponse<
212
217
  return this;
213
218
  }
214
219
 
215
- public async render( page: Page, context: TRouterContext, additionnalData: {} ) {
220
+ public async render( page: Page, context: TRouterContext<TRouter>, additionnalData: {} ) {
216
221
 
217
222
  // Set page in context for the client side
218
223
  context.page = page;
@@ -308,11 +313,11 @@ export default class ServerResponse<
308
313
  return this.end();
309
314
  }
310
315
 
311
- public redirect(url: string, code: number = 302) {
316
+ public redirect(url: string, code: number = 302, absolute: boolean = false) {
312
317
 
313
318
  debug && console.log("[routeur][response] Redirect", url);
314
319
  this.statusCode = code;
315
- this.headers['Location'] = this.router.url( url );
320
+ this.headers['Location'] = this.router.url( url, {}, absolute );
316
321
  return this.end();
317
322
  }
318
323
 
@@ -39,8 +39,9 @@ export default class DocumentRenderer<TRouter extends Router> {
39
39
  <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
40
40
 
41
41
  {/* CSS */}
42
- <link rel="stylesheet" type="text/css" href="/public/icons.css" />
43
42
  <link rel="preload" href="/public/client.css" as="style" />
43
+ <link rel="preload" as="font" href={"/public/icons.woff2?v=" + BUILD_ID} type="font/woff2" />
44
+ <link rel="stylesheet" type="text/css" href="/public/icons.css" />
44
45
  <link rel="stylesheet" type="text/css" href="/public/client.css" />
45
46
  <ColorSchemeScript />
46
47
 
@@ -120,6 +121,7 @@ export default class DocumentRenderer<TRouter extends Router> {
120
121
 
121
122
  private styles( page: Page ) {
122
123
  return <>
124
+ <link rel="preload" as="font" href={"/public/icons.woff2?v=" + BUILD_ID} type="font/woff2" />
123
125
  <link rel="stylesheet" type="text/css" href={"/public/icons.css?" + BUILD_ID} />
124
126
  <link rel="preload" href="/public/client.css" as="style" />
125
127
  <link rel="stylesheet" type="text/css" href="/public/client.css" />
@@ -135,8 +137,8 @@ export default class DocumentRenderer<TRouter extends Router> {
135
137
 
136
138
  private async scripts( response: ServerResponse<TRouter>, page: Page ) {
137
139
 
138
- const context = safeStringify( response.forSsr(page) );
139
-
140
+ const ssrData = response.forSsr(page);
141
+ const context = safeStringify( ssrData );
140
142
  const routesForClient = JSON.stringify( this.router.ssrRoutes );
141
143
 
142
144
  return <>
@@ -11,7 +11,10 @@ import type { default as Router } from '.';
11
11
  import type ServerRequest from './request';
12
12
  import type RequestService from './request/service';
13
13
 
14
- export type TRouterServiceArgs = TServiceArgs<RouterService>;
14
+ export type TRouterServiceArgs = [
15
+ getConfig: TServiceArgs<RouterService>[1],
16
+ app: Application,
17
+ ];
15
18
 
16
19
  /*----------------------------------
17
20
  - SERVICE
@@ -20,10 +23,10 @@ export default abstract class RouterService<
20
23
  TConfig extends {} = {}
21
24
  > extends Service<TConfig, {}, Application> {
22
25
 
23
- public constructor( ...args: TRouterServiceArgs) {
24
- super(...args);
26
+ public constructor( ...[config, app]: TRouterServiceArgs) {
27
+ super(app, config, app);
25
28
  }
26
29
 
27
- public abstract requestService( request: ServerRequest<Router> ): RequestService | null;
30
+ public abstract requestService( request: ServerRequest<RouterService> ): RequestService | {} | null;
28
31
 
29
32
  }
@@ -2,15 +2,17 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
+ // Npm
6
+ import zod from 'zod';
7
+ import { SomeType } from 'zod/v4/core';
8
+
5
9
  // Core
6
10
  import {
7
- default as Router, RequestService, Request as ServerRequest
11
+ default as Router, TServerRouter, Request as ServerRequest
8
12
  } from '@server/services/router';
9
13
 
10
- import Schema, { TSchemaFields, TValidatedData } from '@server/services/router/request/validation/schema';
11
-
12
- // Specific
13
- import ServerSchemaValidator from '.';
14
+ // Ap
15
+ import { preprocessSchema, schema } from '@server/services/router/request/validation/zod';
14
16
 
15
17
  /*----------------------------------
16
18
  - SERVICE CONFIG
@@ -25,38 +27,23 @@ export type TConfig = {
25
27
  /*----------------------------------
26
28
  - SERVICE
27
29
  ----------------------------------*/
28
- export default class RequestValidator extends ServerSchemaValidator implements RequestService {
29
-
30
- public constructor(
31
- public request: ServerRequest<Router>,
32
- public config: TConfig,
33
- public router = request.router,
34
- public app = router.app
35
- ) {
36
-
37
- super(app);
38
-
39
- }
40
-
41
- public validate<TSchemaFieldsA extends TSchemaFields>(
42
- fields: TSchemaFieldsA | Schema<TSchemaFieldsA>
43
- ): TValidatedData<TSchemaFieldsA> {
30
+ export default(
31
+ request: ServerRequest< TServerRouter >,
32
+ config: TConfig,
33
+ router = request.router,
34
+ app = router.app
35
+ ) => ({
44
36
 
45
- this.config.debug && console.log(LogPrefix, "Validate request data:", this.request.data);
37
+ ...schema,
46
38
 
47
- const schema = fields instanceof Schema ? fields : new Schema(fields);
39
+ validate( fields: zod.ZodSchema | { [key: string]: zod.ZodSchema } ) {
48
40
 
49
- // Les InputError seront propagées vers le middleware dédié à la gestion des erreurs
50
- const values = schema.validate( this.request.data, {
51
- debug: this.config.debug,
52
- validateDeps: false,
53
- validators: this
54
- }, []);
41
+ config.debug && console.log(LogPrefix, "Validate request data:", request.data);
55
42
 
56
- // For logging
57
- this.request.validatedData = values;
43
+ const schema = typeof fields === 'object' ? zod.object(fields) : fields;
58
44
 
59
- return values;
60
- }
45
+ const preprocessedSchema = preprocessSchema(schema);
61
46
 
62
- }
47
+ return preprocessedSchema.parse(request.data);
48
+ },
49
+ })
@@ -8,7 +8,7 @@ import {
8
8
  RouterService
9
9
  } from '@server/services/router';
10
10
 
11
- import RequestValidator, { TConfig } from '../request';
11
+ import makeRequestValidators from '../request';
12
12
 
13
13
  /*----------------------------------
14
14
  - TYPES
@@ -22,7 +22,7 @@ export default class SchemaRouterService<
22
22
  TUser extends {} = {}
23
23
  > extends RouterService {
24
24
 
25
- public requestService( request: ServerRequest ): RequestValidator {
26
- return new RequestValidator( request, this.config );
25
+ public requestService( request: ServerRequest ) {
26
+ return makeRequestValidators( request, this.config );
27
27
  }
28
28
  }
package/types/icons.d.ts CHANGED
@@ -1 +1 @@
1
- export type TIcones = "solid/spinner-third"|"long-arrow-right"|"times-circle"|"brands/whatsapp"|"times"|"search"|"user"|"rocket"|"globe"|"bullhorn"|"briefcase"|"chart-line"|"handshake"|"ellipsis-h"|"brands/google"|"brands/reddit-alien"|"brands/linkedin-in"|"brands/github"|"robot"|"comments"|"user-friends"|"angle-down"|"mouse-pointer"|"thumbs-up"|"dollar-sign"|"info-circle"|"check-circle"|"exclamation-circle"|"bars"|"font"|"tag"|"compress"|"bolt"|"puzzle-piece"|"planet-ringed"|"chart-bar"|"power-off"|"heart"|"lock"|"eye"|"credit-card"|"at"|"brands/linkedin"|"key"|"database"|"solid/fire"|"usd-circle"|"lightbulb"|"solid/dollar-sign"|"download"|"code"|"solid/clock"|"exclamation"|"solid/download"|"seedling"|"palette"|"car"|"plane"|"university"|"hard-hat"|"graduation-cap"|"cogs"|"film"|"leaf"|"tshirt"|"utensils"|"map-marked-alt"|"dumbbell"|"stethoscope"|"concierge-bell"|"book"|"shield-alt"|"gavel"|"industry"|"square-root-alt"|"newspaper"|"pills"|"medal"|"capsules"|"balance-scale"|"home"|"praying-hands"|"shopping-cart"|"flask"|"futbol"|"microchip"|"satellite-dish"|"shipping-fast"|"passport"|"tools"|"user-circle"|"plus-circle"|"brands/twitter"|"brands/facebook"|"comment-alt"|"check"|"angle-left"|"angle-right"|"paper-plane"|"long-arrow-left"|"meh-rolling-eyes"|"arrow-left"|"arrow-right"|"trash"|"bold"|"italic"|"underline"|"strikethrough"|"subscript"|"superscript"|"link"|"unlink"|"pen"|"file"|"plus"|"empty-set"|"horizontal-rule"|"page-break"|"image"|"table"|"poll"|"columns"|"sticky-note"|"caret-right"|"list-ul"|"check-square"|"h1"|"h2"|"h3"|"h4"|"list-ol"|"paragraph"|"quote-left"|"align-left"|"align-center"|"align-right"|"align-justify"|"indent"|"outdent"
1
+ export type TIcones = "solid/spinner-third"|"rocket"|"user-circle"|"brands/linkedin"|"play"|"stop"|"trash"|"times"|"at"|"star"|"plus"|"minus"|"magnet"|"paper-plane"|"search"|"check"|"plus-circle"|"regular/shield-check"|"angle-down"|"clock"|"cog"|"ellipsis-h"|"long-arrow-right"|"lightbulb"|"long-arrow-left"|"phone"|"arrow-right"|"plane-departure"|"comments-alt"|"user-shield"|"shield-alt"|"chart-line"|"money-bill-wave"|"link"|"file-alt"|"solid/crown"|"eye"|"pen"|"file"|"envelope"|"angle-up"|"user-plus"|"sack-dollar"|"info-circle"|"mouse-pointer"|"thumbs-up"|"dollar-sign"|"download"|"brands/google"|"brands/whatsapp"|"crown"|"check-circle"|"exclamation-circle"|"times-circle"|"arrow-left"|"key"|"building"|"briefcase"|"map-marker-alt"|"graduation-cap"|"solid/check-circle"|"solid/exclamation-triangle"|"solid/times-circle"|"hourglass"|"angle-left"|"angle-right"|"broom"|"question-circle"|"coin"|"coins"|"plug"|"arrow-to-bottom"|"external-link"|"magic"|"minus-circle"|"user"|"meh-rolling-eyes"|"bold"|"italic"|"underline"|"strikethrough"|"subscript"|"superscript"|"code"|"unlink"|"font"|"empty-set"|"horizontal-rule"|"page-break"|"image"|"table"|"poll"|"columns"|"sticky-note"|"caret-right"|"align-left"|"align-center"|"align-right"|"align-justify"|"indent"|"outdent"|"list-ul"|"check-square"|"h1"|"h2"|"h3"|"h4"|"list-ol"|"paragraph"|"quote-left"