5htp-core 0.1.2 → 0.2.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 (127) hide show
  1. package/changelog.md +5 -0
  2. package/doc/TODO.md +71 -0
  3. package/package.json +5 -4
  4. package/src/client/{App.tsx → app/component.tsx} +15 -8
  5. package/src/client/app/index.ts +128 -0
  6. package/src/client/app/service.ts +34 -0
  7. package/src/client/app.tsconfig.json +0 -4
  8. package/src/client/assets/css/medias.less +14 -0
  9. package/src/client/components/Card/index.tsx +2 -2
  10. package/src/client/components/Dialog/Manager.tsx +39 -12
  11. package/src/client/components/Form/index.tsx +1 -1
  12. package/src/client/components/button.tsx +2 -2
  13. package/src/client/components/containers/Popover/index.tsx +1 -1
  14. package/src/client/components/data/spintext/index.tsx +1 -1
  15. package/src/client/components/dropdown/index.tsx +1 -1
  16. package/src/client/components/index.ts +8 -0
  17. package/src/client/components/input/BaseV2/index.tsx +1 -1
  18. package/src/client/components/input/UploadImage/index.tsx +1 -1
  19. package/src/client/hooks/index.ts +5 -0
  20. package/src/client/hooks/useState/index.tsx +2 -2
  21. package/src/client/hooks.ts +22 -0
  22. package/src/client/index.ts +5 -0
  23. package/src/client/pages/_layout/landing/index.tsx +0 -2
  24. package/src/client/pages/_messages/400.tsx +2 -2
  25. package/src/client/pages/_messages/401.tsx +2 -2
  26. package/src/client/pages/_messages/403.tsx +2 -2
  27. package/src/client/pages/_messages/404.tsx +2 -2
  28. package/src/client/pages/_messages/500.tsx +2 -2
  29. package/src/client/pages/bug.tsx +1 -1
  30. package/src/client/pages/useHeader.tsx +1 -1
  31. package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
  32. package/src/client/services/metrics/index.ts +37 -0
  33. package/src/client/{router → services/router/components}/Link.tsx +1 -1
  34. package/src/client/services/router/components/Page.tsx +59 -0
  35. package/src/client/{router/component.tsx → services/router/components/router.tsx} +43 -74
  36. package/src/client/services/router/index.tsx +448 -0
  37. package/src/client/services/router/request/api.ts +229 -0
  38. package/src/client/{router → services/router}/request/history.ts +0 -0
  39. package/src/client/services/router/request/index.ts +52 -0
  40. package/src/client/services/router/response/index.tsx +107 -0
  41. package/src/client/services/router/response/page.ts +95 -0
  42. package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
  43. package/src/client/utils/dom.ts +1 -1
  44. package/src/common/app/index.ts +9 -0
  45. package/src/common/data/chaines/index.ts +9 -6
  46. package/src/common/data/input/validate.ts +3 -166
  47. package/src/common/data/objets.ts +25 -0
  48. package/src/common/data/tableaux.ts +8 -0
  49. package/src/common/errors/index.ts +3 -1
  50. package/src/common/router/index.ts +67 -88
  51. package/src/common/router/layouts.ts +50 -0
  52. package/src/common/router/register.ts +62 -0
  53. package/src/common/router/request/api.ts +72 -0
  54. package/src/common/router/request/index.ts +31 -0
  55. package/src/common/router/{response.ts → response/index.ts} +9 -13
  56. package/src/common/router/response/page.ts +40 -56
  57. package/src/common/validation/index.ts +3 -0
  58. package/src/common/validation/schema.ts +184 -0
  59. package/src/common/validation/validator.ts +88 -0
  60. package/src/common/validation/validators.ts +313 -0
  61. package/src/server/app/config.ts +9 -27
  62. package/src/server/app/index.ts +81 -124
  63. package/src/server/app/service.ts +98 -0
  64. package/src/server/app.tsconfig.json +0 -8
  65. package/src/server/error/index.ts +13 -0
  66. package/src/server/index.ts +5 -0
  67. package/src/server/patch.ts +0 -6
  68. package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
  69. package/src/server/services/console/bugReporter.ts +26 -16
  70. package/src/server/services/console/index.ts +59 -51
  71. package/src/server/services/cron/index.ts +12 -26
  72. package/src/server/services/database/bucket.ts +40 -0
  73. package/src/server/services/database/connection.ts +206 -75
  74. package/src/server/services/database/datatypes.ts +63 -40
  75. package/src/server/services/database/index.ts +295 -272
  76. package/src/server/services/database/metas.ts +246 -135
  77. package/src/server/services/database/stats.ts +151 -126
  78. package/src/server/services/email/index.ts +28 -52
  79. package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
  80. package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
  81. package/src/server/services/{http → router/http}/index.ts +28 -70
  82. package/src/server/services/{http → router/http}/multipart.ts +0 -0
  83. package/src/server/services/{http → router/http}/session.ts.old +0 -0
  84. package/src/server/services/router/index.ts +273 -203
  85. package/src/server/services/router/request/api.ts +73 -0
  86. package/src/server/services/router/request/index.ts +16 -97
  87. package/src/server/services/router/request/service.ts +21 -0
  88. package/src/server/services/router/response/index.ts +125 -64
  89. package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
  90. package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
  91. package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
  92. package/src/server/services/router/response/page/document.tsx +194 -0
  93. package/src/server/services/router/response/page/index.tsx +157 -0
  94. package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
  95. package/src/server/services/router/service.ts +48 -0
  96. package/src/server/services/schema/index.ts +47 -0
  97. package/src/server/services/schema/request.ts +55 -0
  98. package/src/server/services/schema/router.ts +33 -0
  99. package/src/server/services/socket/index.ts +38 -43
  100. package/src/server/services/socket/scope.ts +6 -4
  101. package/src/server/services/users/index.ts +203 -0
  102. package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
  103. package/src/server/services/users/router/index.ts +72 -0
  104. package/src/server/services/users/router/request.ts +49 -0
  105. package/src/types/aliases.d.ts +43 -2
  106. package/templates/composant.tsx +1 -1
  107. package/templates/modal.tsx +1 -1
  108. package/templates/page.tsx +1 -1
  109. package/tsconfig.common.json +0 -4
  110. package/src/client/context/api.ts +0 -92
  111. package/src/client/context/index.ts +0 -246
  112. package/src/client/index.tsx +0 -129
  113. package/src/client/router/index.ts +0 -286
  114. package/src/client/router/request/index.ts +0 -106
  115. package/src/client/router/response/index.ts +0 -38
  116. package/src/client/router/route.ts +0 -75
  117. package/src/common/data/input/validators/basic.ts +0 -299
  118. package/src/common/data/input/validators/build.ts +0 -63
  119. package/src/common/router/request.ts +0 -83
  120. package/src/server/data/ApiClient.ts +0 -119
  121. package/src/server/data/input.ts +0 -41
  122. package/src/server/libs/pages/document.static.tsx +0 -41
  123. package/src/server/libs/pages/document.tsx +0 -203
  124. package/src/server/libs/pages/render.tsx +0 -90
  125. package/src/server/routes/auth.ts +0 -151
  126. package/src/server/services/redis/index.ts +0 -71
  127. package/src/server/services/router/request/services/auth.ts +0 -177
@@ -6,46 +6,97 @@
6
6
  import mysql from 'mysql2/promise';
7
7
 
8
8
  // Core: general
9
- import app from '@server/app';
10
- import loadMetadata, { TDatabasesList } from './metas';
11
- import { seconds } from '@common/utils';
9
+ import Application from '@server/app';
10
+ import { SqlError } from '@server/error';
11
+ import Service from '@server/app/service';
12
+
13
+ // Core: specific
14
+ import type Console from '../console';
15
+ import MetadataParser, { TDatabasesList, TMetasTable, TColumnTypes } from './metas';
16
+ import { TMySQLTypeName, mysqlToJs, js as jsTypes } from './datatypes';
17
+ import Bucket from './bucket';
12
18
 
13
19
  /*----------------------------------
14
- - DEFINITIONS TYPESSQL
20
+ - CONFIG
15
21
  ----------------------------------*/
16
22
 
23
+ const LogPrefix = '[database][connection]';
24
+
25
+ /*----------------------------------
26
+ - SERVICE CONFIG
27
+ ----------------------------------*/
28
+
29
+ export type DatabaseServiceConfig = {
30
+ list: string[],
31
+ dev: {
32
+ host: string,
33
+ port: number,
34
+ login: string,
35
+ password: string,
36
+ },
37
+ prod: {
38
+ host: string,
39
+ port: number,
40
+ login: string,
41
+ password: string,
42
+ }
43
+ }
44
+
45
+ export type THooks = {
46
+
47
+ }
48
+
49
+ /*----------------------------------
50
+ - TYPES
51
+ ----------------------------------*/
52
+
53
+ type TBasicQueryOptions = {
54
+ bucket?: Bucket,
55
+ simulate?: boolean,
56
+ log?: boolean,
57
+ returnQuery?: boolean,
58
+ }
59
+
60
+ export type TQueryOptions<TOmitValues extends keyof TBasicQueryOptions = never, TRequireValues extends keyof TBasicQueryOptions = never> = (
61
+ Omit<TBasicQueryOptions, TOmitValues>
62
+ &
63
+ Required<Pick<TBasicQueryOptions, TRequireValues>>
64
+ )
65
+
66
+ export type TQueryResult = TSelectQueryResult;
67
+
68
+ // TODO: specifiy return type of every mysql query type
69
+ type TSelectQueryResult = any;
17
70
 
18
71
  /*----------------------------------
19
72
  - SERVICES
20
73
  ----------------------------------*/
21
- export default class FastDatabase {
74
+ export default class DatabaseConnection extends Service<DatabaseServiceConfig, THooks, Application> {
22
75
 
23
76
  private initialized = false;
24
77
  public connection!: mysql.Pool;
25
- public tables: TDatabasesList = {};
26
78
 
27
- public config = app.config.database;
79
+ public tables: TDatabasesList = {};
80
+ public metas = new MetadataParser(this);
28
81
 
29
82
  /*----------------------------------
30
83
  - HOOKS
31
84
  ----------------------------------*/
32
- public constructor() {
33
85
 
34
- app.on('cleanup', () => this.cleanup());
86
+ public async register() {
35
87
 
36
88
  }
37
-
89
+
38
90
  public loading: Promise<void> | undefined = undefined;
39
- public async load() {
40
-
41
- // Wait for database service to be ready
42
- //await seconds(5);
91
+ public async start() {
43
92
 
44
93
  this.initialized = false;
45
94
 
95
+ this.app.on('cleanup', () => this.cleanup());
96
+
46
97
  this.connection = await this.connect();
47
98
 
48
- this.tables = await loadMetadata( app.config.database.list, this.connection);
99
+ this.tables = await this.metas.load( this.config.list );
49
100
 
50
101
  this.initialized = true;
51
102
 
@@ -60,9 +111,9 @@ export default class FastDatabase {
60
111
  ----------------------------------*/
61
112
  public async connect() {
62
113
 
63
- console.info(`Connecting to databases ...`);
114
+ console.info(LogPrefix, `Connecting to databases ...`);
64
115
 
65
- const creds = this.config[ app.env.profile ];
116
+ const creds = this.config[ this.app.env.profile ];
66
117
 
67
118
  return await mysql.createPool({
68
119
 
@@ -93,102 +144,182 @@ export default class FastDatabase {
93
144
  multipleStatements: true,
94
145
 
95
146
  queryFormat: function (query, values) {
96
- //console.info('queryFormat', query);
147
+ //console.info(LogPrefix, 'queryFormat', query);
97
148
  return query;
98
149
  }
99
150
  });
100
151
  }
101
152
 
102
- private typeCast(field, next) {
153
+ private typeCast( field: mysql.Field, next: Function ) {
103
154
 
104
- // Metadata must be loaded
155
+ // Wait for the connection to be initialized
105
156
  if (!this.initialized)
106
157
  return next();
107
158
 
108
- let type = field.type;
109
- if (field.db) {
110
-
111
- // TODO: A revoir, car les infos passées peuvent être des alias
159
+ // Normal column
160
+ let type: TColumnTypes;
161
+ if (field.db && field.table && field.name) {
112
162
 
113
163
  const db = this.tables[ field.db ];
114
164
  if (db === undefined) {
115
- return next();
116
165
  console.error("Field infos:", field);
117
166
  throw new Error(`Database metadatas for ${field.db} were not loaded.`);
118
167
  }
119
168
 
120
169
  const table = db[field.table];
121
170
  if (table === undefined) {
122
- return next();
123
171
  console.error("Field infos:", field);
124
172
  throw new Error(`Table metadatas for ${field.db}.${field.table} were not loaded.`);
125
173
  }
126
174
 
127
175
  const column = table.colonnes[field.name];
128
176
  if (column === undefined) {
129
- return next();
130
177
  console.error("Field infos:", field);
131
178
  throw new Error(`Column metadatas for ${field.db}.${field.table}.${field.name} were not loaded.`);
132
179
  }
133
180
 
134
181
  type = column.type;
135
182
 
136
- }
183
+ // Custom column (computed or aliased)
184
+ } else {
185
+
186
+ const mysqlType = {
187
+ name: field.type as TMySQLTypeName,
188
+ params: []
189
+ }
190
+
191
+ let jsTypeName = mysqlToJs[ mysqlType.name ];
192
+ if (jsTypeName === undefined) {
193
+ console.warn(`The mySQL data type « ${mysqlType.name} » has not been associated with a JS equivalent in mysqlToJs. Using any instead.`);
194
+ jsTypeName = mysqlToJs['UNKNOWN'];
195
+ }
196
+
197
+ type = {
198
+ sql: mysqlType,
199
+ js: {
200
+ name: jsTypeName,
201
+ params: []
202
+ }
203
+ }
204
+ }
137
205
 
138
- const val = field.string();
206
+ // Retrieve value
207
+ let val = field.string();
139
208
  if (val === null)
140
209
  return undefined;
141
210
 
142
- // https://www.w3schools.com/sql/sql_datatypes.asp
143
- switch (type) {
144
-
145
- case 'SET':
146
- return val.split(',');
147
-
148
- case 'DECIMAL':
149
- case 'FLOAT':
150
- case 'NEWDECIMAL':
151
- case 'DOUBLE':
152
- return parseFloat(val);
153
-
154
- case 'INT':
155
- case 'LONG':
156
- case 'LONGLONG':
157
- case 'TINYINT':
158
- case 'SMALLINT':
159
- case 'MEDIUMINT':
160
- return parseInt(val);
161
-
162
- case 'DATE':
163
- case 'DATETIME':
164
- return new Date(val);
165
-
166
- case 'VARCHAR':
167
- case 'CHAR':
168
- case 'VAR_STRING':
169
- case 'LONGTEXT':
170
- case 'TEXT':
171
- case 'ENUM':
172
- return val;
173
-
174
- case 'JSON':
175
- return JSON.parse(val);
176
-
211
+ // Cast value
212
+ const jsTypeParser = jsTypes[ type.js.name ];
213
+ const castedVal = jsTypeParser.parse(val);
214
+ //console.log(LogPrefix, `type cast`, val, `(${type.sql.name}) =>`, castedVal, `(${type.js.name})`);
215
+
216
+ return castedVal;
217
+ }
218
+
219
+ /*----------------------------------
220
+ - METADATA
221
+ ----------------------------------*/
222
+
223
+ public getTable( path: string ): TMetasTable {
224
+
225
+ // Parse path
226
+ let db: string, table: string;
227
+ if (path.includes('.'))
228
+ ([db, table] = path.split('.'));
229
+ else {
230
+ // Only the table = use the main database (first of the list in the config)
231
+ db = this.config.list[0];
232
+ table = path;
177
233
  }
234
+
235
+ // Retrieve table info
236
+ if (this.tables[db] === undefined)
237
+ throw new Error(`Database "${db}" not loaded. Did you add it in the database config ?`);
238
+ if (this.tables[db][table] === undefined)
239
+ throw new Error(`Table "${db}.${table}" not loaded.`);
240
+
241
+ return this.tables[db][table];
178
242
 
179
- console.warn("/!\\ UNHANDLED TYPE " + type + " for field " + field.name);
180
- return val;
181
243
  }
182
- }
183
244
 
184
- /*----------------------------------
185
- - REGISTER SERVICE
186
- ----------------------------------*/
187
- app.register('database', FastDatabase);
188
- declare global {
189
- namespace Core {
190
- interface Services {
191
- database: FastDatabase;
245
+ /*----------------------------------
246
+ - QUERY
247
+ ----------------------------------*/
248
+ public bucket(
249
+ queryOptions: TQueryOptions<'bucket'> = {},
250
+ queriesList: string[] = [],
251
+ ) {
252
+ return new Bucket(queryOptions, queriesList);
253
+ }
254
+
255
+ public async query<TResult extends TQueryResult>(
256
+ query: string,
257
+ opts: TQueryOptions<'bucket', 'bucket'>
258
+ ): Promise<Bucket>;
259
+
260
+ public async query<TResult extends TQueryResult>(
261
+ query: string,
262
+ opts: TQueryOptions<'returnQuery', 'returnQuery'>
263
+ ): Promise<string>;
264
+
265
+ public async query<TResult extends TQueryResult>(
266
+ query: string,
267
+ opts: TQueryOptions<'simulate', 'simulate'>
268
+ ): Promise<void>;
269
+
270
+ public async query<TResult extends TQueryResult>(
271
+ query: string,
272
+ opts?: TQueryOptions
273
+ ): Promise<TResult>;
274
+
275
+ public async query<TResult extends TQueryResult>(
276
+ query: string,
277
+ opts: TQueryOptions = {}
278
+ ): Promise<TResult | Bucket | string | void> {
279
+
280
+ if (opts.bucket)
281
+ return opts.bucket.add(query);
282
+
283
+ if (opts.returnQuery === true)
284
+ return query;
285
+
286
+ if (opts.log === true)
287
+ console.log(`[database][query]`, query);
288
+
289
+ if (opts.simulate === true)
290
+ return;
291
+
292
+ try {
293
+
294
+ const startTime = Date.now();
295
+
296
+ // Lancement de la requête
297
+ const [rows, fields] = await this.connection.query(query);
298
+
299
+ if (opts.log !== false)
300
+ this.log(query, startTime);
301
+
302
+ return rows as unknown as TResult;
303
+
304
+ } catch (error) {
305
+
306
+ throw new SqlError(error, query);
192
307
  }
193
308
  }
309
+
310
+ private log( query: string, startTime: number ) {
311
+
312
+ const console = this.app.use<Console>('console');
313
+ if (!console) return;
314
+
315
+ const { channelType, channelId } = console.getChannel();
316
+ if (channelId !== 'admin')
317
+ console.sqlQueries.push({
318
+ channelType,
319
+ channelId,
320
+ date: new Date(),
321
+ query: query.trim(),
322
+ time: Date.now() - startTime,
323
+ });
324
+ }
194
325
  }
@@ -1,74 +1,97 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+ import type { TMetasColonne } from './metas';
5
+
6
+ /*----------------------------------
7
+ - TYPES
8
+ ----------------------------------*/
9
+
1
10
  type JsType = {
2
11
  parse: (value: string) => any,
3
- typescript: string
12
+ print: (col: TMetasColonne) => string
4
13
  }
5
14
 
6
- const js: {
7
- [type: string]: JsType
8
- } = {
15
+ export type TJsTypeName = keyof typeof js;
16
+ export type TMySQLTypeName = keyof typeof mysqlToJs;
17
+
18
+ /*----------------------------------
19
+ - LISTS
20
+ ----------------------------------*/
21
+ export const js = {
9
22
  array: {
10
23
  parse: (val: string) => val.split(','),
11
- typescript: 'string[]'
24
+ print: (col) => (col.type.sql.params.length
25
+ ? '(' + col.type.sql.params.map( param => "'" + param + "'").join(' | ') + ')'
26
+ : 'string'
27
+ ) + '[]'
28
+ },
29
+ enum: {
30
+ parse: (val: string) => val,
31
+ print: (col) => col.type.sql.params.map( param => "'" + param + "'").join(' | ')
12
32
  },
13
33
  float: {
14
34
  parse: (val: string) => parseFloat(val),
15
- typescript: 'number'
35
+ print: (col) => 'number'
16
36
  },
17
37
  int: {
18
38
  parse: (val: string) => parseFloat(val),
19
- typescript: 'number'
39
+ print: (col) => 'number'
20
40
  },
21
41
  date: {
22
42
  parse: (val: string) => new Date(val),
23
- typescript: 'Date'
43
+ print: (col) => 'Date'
24
44
  },
25
45
  string: {
26
46
  parse: (val: string) => val,
27
- typescript: 'string'
47
+ print: (col) => 'string'
28
48
  },
29
49
  object: {
30
50
  parse: (val: string) => JSON.parse(val),
31
- typescript: 'object'
51
+ print: (col) => 'object'
32
52
  },
33
53
 
34
54
  // When we were not able to find an equivalent
35
55
  unknown: {
36
56
  parse: (val: any) => val,
37
- typescript: 'any'
57
+ print: (col) => 'any'
38
58
  },
39
- }
40
-
41
- export const mysqlToJs: {
42
- [type: string]: JsType
43
- } = {
44
-
45
- 'SET': js.array,
59
+ } as const
46
60
 
47
- 'DECIMAL': js.float,
48
- 'FLOAT': js.float,
49
- 'NEWDECIMAL': js.float,
50
- 'DOUBLE': js.float,
61
+ // https://www.w3schools.com/sql/sql_datatypes.asp
62
+ export const mysqlToJs = {
63
+ // Float
64
+ 'DECIMAL': 'float',
65
+ 'FLOAT': 'float',
66
+ 'NEWDECIMAL': 'float',
67
+ 'DOUBLE': 'float',
68
+ 'POINT': 'float',
51
69
 
52
- 'INT': js.int,
53
- 'BIGINT': js.int,
54
- 'LONG': js.int,
55
- 'LONGLONG': js.int,
56
- 'TINYINT': js.int,
57
- 'SMALLINT': js.int,
58
- 'MEDIUMINT': js.int,
70
+ // Integres
71
+ 'INT': 'int',
72
+ 'BIGINT': 'int',
73
+ 'LONG': 'int',
74
+ 'LONGLONG': 'int',
75
+ 'TINYINT': 'int',
76
+ 'SMALLINT': 'int',
77
+ 'MEDIUMINT': 'int',
59
78
 
60
- 'DATE': js.date,
61
- 'DATETIME': js.date,
79
+ // Dates
80
+ 'DATE': 'date',
81
+ 'DATETIME': 'date',
62
82
 
63
- 'VARCHAR': js.string,
64
- 'CHAR': js.string,
65
- 'VAR_STRING': js.string,
66
- 'LONGTEXT': js.string,
67
- 'TEXT': js.string,
68
- 'ENUM': js.string,
83
+ // Strings
84
+ 'VARCHAR': 'string',
85
+ 'CHAR': 'string',
86
+ 'VAR_STRING': 'string',
87
+ 'LONGTEXT': 'string',
88
+ 'TEXT': 'string',
89
+ 'ENUM': 'enum',
69
90
 
70
- 'JSON': js.object,
91
+ // Objects
92
+ 'SET': 'array',
93
+ 'JSON': 'object',
71
94
 
72
95
  // When we were not able to find an equivalent
73
- 'UNKNOWN': js.unknown,
74
- }
96
+ 'UNKNOWN': 'unknown',
97
+ } as const