5htp-core 0.6.2-98 → 0.6.2-99

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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "5htp-core",
3
3
  "description": "Convenient TypeScript framework designed for Performance and Productivity.",
4
- "version": "0.6.2-98",
4
+ "version": "0.6.2-99",
5
5
  "author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
6
6
  "repository": "git://github.com/gaetanlegac/5htp-core.git",
7
7
  "license": "MIT",
@@ -17,6 +17,7 @@ import ServicesContainer, {
17
17
  // Built-in
18
18
  import type { default as Router, Request as ServerRequest, TRoute } from '@server/services/router';
19
19
  import { Anomaly } from '@common/errors';
20
+ import { preprocessSchema } from '@server/services/router/request/validation/zod';
20
21
 
21
22
  export { default as Services } from './service/container';
22
23
  export type { TEnvConfig as Environment } from './container/config';
@@ -208,12 +209,14 @@ export abstract class Application<
208
209
 
209
210
  console.log('Attached service', service.constructor.name, 'to route', route.path);
210
211
 
212
+ const preprocessedSchema = route.schema ? preprocessSchema(route.schema) : undefined;
213
+
211
214
  const origController = route.controller;
212
215
  route.controller = (context: RouterContext) => {
213
216
 
214
217
  // Filter data
215
- const data = route.schema
216
- ? route.schema.parse( context.request.data )
218
+ const data = preprocessedSchema
219
+ ? preprocessedSchema.parse( context.request.data )
217
220
  : {};
218
221
 
219
222
  // Run controller
@@ -5,42 +5,61 @@ export type TRichTextValidatorOptions = {
5
5
  attachements?: boolean
6
6
  }
7
7
 
8
- // Recursive function to validate each node
9
- function validateLexicalNode(node: any, opts: TRichTextValidatorOptions ) {
8
+ export const preprocessSchema = (schema: zod.ZodObject): zod.ZodObject => {
10
9
 
11
- // Each node should be an object with a `type` property
12
- if (typeof node !== 'object' || !node.type || typeof node.type !== 'string')
13
- throw new InputError("Invalid rich text value (3).");
10
+ // Not working, data is {}
11
+ return schema;
14
12
 
15
- // Validate text nodes
16
- if (node.type === 'text') {
13
+ if (!(schema instanceof zod.ZodObject))
14
+ return schema;
17
15
 
18
- if (typeof node.text !== 'string')
19
- throw new InputError("Invalid rich text value (4).");
16
+ if (schema.withPreprocessing)
17
+ return schema;
20
18
 
21
- // Validate paragraph, heading, or other structural nodes that may contain children
22
- } else if (['paragraph', 'heading', 'list', 'listitem'].includes(node.type)) {
19
+ const shape = schema.def.shape;
20
+ const newShape: Record<string, zod.ZodTypeAny> = {};
23
21
 
24
- if (!Array.isArray(node.children) || !node.children.every(children => validateLexicalNode(children, opts))) {
25
- throw new InputError("Invalid rich text value (5).");
26
- }
22
+ for (const key in shape) {
27
23
 
28
- // Files upload
29
- } else if (node.type === 'image') {
24
+ if (!['newEntity', 'email'].includes(key))
25
+ continue;
30
26
 
31
- // Check if allowed
32
- /*if (opts.attachements === undefined)
33
- throw new InputError("Image attachments not allowed in this rich text field.");*/
27
+ let current: zod.ZodTypeAny = shape[key];
28
+ while (current) {
29
+
30
+ const origType = current.type;
31
+ const preprocessor = toPreprocess[origType];
34
32
 
35
- // TODO: check mime
33
+ if (origType === 'object') {
34
+ newShape[key] = preprocessSchema(current as zod.ZodObject);
35
+ break;
36
+ }
36
37
 
38
+ if (preprocessor) {
39
+ newShape[key] = preprocessor(current);
40
+ console.log('====newShape', key, newShape[key]);
41
+ break;
42
+ }
37
43
 
38
- // Upload file
44
+ current = current.def;
45
+ }
46
+ }
39
47
 
48
+ const newSchema = zod.object(newShape);
49
+ newSchema.withPreprocessing = true;
50
+ return newSchema;
51
+ }
40
52
 
41
- }
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),
42
62
 
43
- return true;
44
63
  }
45
64
 
46
65
  export const schema = {
@@ -56,15 +75,6 @@ export const schema = {
56
75
  return zod.file();
57
76
  },
58
77
 
59
- int: () => zod.preprocess( val => {
60
-
61
- if (typeof val === "string")
62
- return Number.parseInt(val);
63
-
64
- return val;
65
-
66
- }, zod.int()),
67
-
68
78
  choice: ( choices: string[] | { value: any, label: string }[] | _ZodType, options: { multiple?: boolean } = {} ) => {
69
79
 
70
80
  const normalizeValue = (value: any) => typeof value === 'object' ? value.value : value;
@@ -129,4 +139,42 @@ export const schema = {
129
139
  })
130
140
  }
131
141
 
132
- export type { default as z } from 'zod';
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';
@@ -313,11 +313,11 @@ export default class ServerResponse<
313
313
  return this.end();
314
314
  }
315
315
 
316
- public redirect(url: string, code: number = 302) {
316
+ public redirect(url: string, code: number = 302, absolute: boolean = false) {
317
317
 
318
318
  debug && console.log("[routeur][response] Redirect", url);
319
319
  this.statusCode = code;
320
- this.headers['Location'] = this.router.url( url );
320
+ this.headers['Location'] = this.router.url( url, {}, absolute );
321
321
  return this.end();
322
322
  }
323
323
 
@@ -12,7 +12,7 @@ import {
12
12
  } from '@server/services/router';
13
13
 
14
14
  // Ap
15
- import { schema } from '@server/services/router/request/validation/zod';
15
+ import { preprocessSchema, schema } from '@server/services/router/request/validation/zod';
16
16
 
17
17
  /*----------------------------------
18
18
  - SERVICE CONFIG
@@ -42,6 +42,8 @@ export default(
42
42
 
43
43
  const schema = typeof fields === 'object' ? zod.object(fields) : fields;
44
44
 
45
- return schema.parse(request.data);
45
+ const preprocessedSchema = preprocessSchema(schema);
46
+
47
+ return preprocessedSchema.parse(request.data);
46
48
  },
47
49
  })
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"|"mouse-pointer"|"thumbs-up"|"dollar-sign"|"angle-down"|"info-circle"|"check-circle"|"exclamation-circle"|"heart"|"lock"|"eye"|"credit-card"|"at"|"brands/linkedin"|"key"|"bars"|"font"|"tag"|"compress"|"bolt"|"puzzle-piece"|"planet-ringed"|"chart-bar"|"power-off"|"exclamation"|"solid/download"|"database"|"solid/fire"|"usd-circle"|"lightbulb"|"download"|"solid/dollar-sign"|"bell"|"code"|"solid/clock"|"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"|"plus-circle"|"user-circle"|"brands/twitter"|"brands/facebook"|"comment-alt"|"list"|"file"|"plug"|"paper-plane"|"check"|"long-arrow-left"|"angle-left"|"angle-right"|"meh-rolling-eyes"|"trash"|"arrow-left"|"arrow-right"|"link"|"bold"|"italic"|"underline"|"strikethrough"|"subscript"|"superscript"|"unlink"|"pen"|"empty-set"|"horizontal-rule"|"page-break"|"image"|"table"|"poll"|"columns"|"sticky-note"|"caret-right"|"plus"|"align-left"|"align-center"|"align-right"|"align-justify"|"indent"|"outdent"|"list-ul"|"check-square"|"h1"|"h2"|"h3"|"h4"|"list-ol"|"paragraph"|"quote-left"
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"