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
@@ -2,7 +2,7 @@
2
2
  // INSPIRATION:
3
3
  // https://adonisjs.com/docs/4.1/routing
4
4
  // https://laravel.com/docs/8.x/routing
5
- // https://github.com/adonisjs/http-server/blob/develop/src/Router/indexApi.ts
5
+ // https://github.com/adonisjs/http-server/blob/develop/src/ServerRouter/indexApi.ts
6
6
  // https://github.com/expressjs/express/blob/06d11755c99fe4c1cddf8b889a687448b568472d/lib/response.js#L1016
7
7
 
8
8
  /*----------------------------------
@@ -12,179 +12,258 @@
12
12
  // Npm
13
13
  import type express from 'express';
14
14
  import { v4 as uuid } from 'uuid';
15
+ import type { GlobImportedWithMetas } from 'babel-plugin-glob-import';
15
16
 
16
- // Core: Router
17
+ // Core
18
+ import Application, { Service } from '@server/app';
17
19
  import context from '@server/context';
18
- import ServerRequest from "./request";
19
- import ServerResponse from './response';
20
- import AuthService from './request/services/auth';
21
- import TrackingService from './request/services/tracking';
22
-
23
- // Core: libs
24
- import app, { $ } from '@server/app';
25
- import { NotFound } from '@common/errors';
26
-
27
- // Core: types
28
- import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@client/router';
29
- import BaseRouter, {
30
- TBaseRoute, TRoute, TErrorRoute,
20
+ import { Erreur, NotFound } from '@common/errors';
21
+ import BaseRouter, {
22
+ TRoute, TErrorRoute, TRouteModule,
31
23
  TRouteOptions, defaultOptions
32
24
  } from '@common/router';
33
- import { TFetcherArgs } from '@common/router/request';
25
+ import { buildRegex, getRegisterPageArgs } from '@common/router/register';
26
+ import { layoutsList } from '@common/router/layouts';
27
+ import { TFetcherArgs } from '@common/router/request/api';
28
+ import type { TFrontRenderer } from '@common/router/response/page';
29
+ import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@client/services/router';
30
+
31
+ // Specific
32
+ import RouterService from './service';
33
+ import ServerRequest from "./request";
34
+ import ServerResponse, { TRouterContext } from './response';
35
+ import Page from './response/page';
36
+ import HTTP, { Config as HttpServiceConfig } from './http';
37
+ import DocumentRenderer from './response/page/document';
34
38
 
35
39
  /*----------------------------------
36
- - SERVICE CONFIG
40
+ - TYPES
37
41
  ----------------------------------*/
38
42
 
39
- export type RouterServiceConfig = {
40
- // Routes to systematically preload
41
-
42
- }
43
+ export { default as RouterService } from './service';
44
+ export { default as RequestService } from './request/service';
45
+ export type { default as Request } from "./request";
46
+ export type { default as Response, TRouterContext } from "./response";
47
+ export type { TRoute } from '@common/router';
48
+
49
+ export type TApiRegisterArgs<TRouter extends ServerRouter> = ([
50
+ path: string,
51
+ controller: TServerController<TRouter>
52
+ ] | [
53
+ path: string,
54
+ options: Partial<TRouteOptions>,
55
+ controller: TServerController<TRouter>
56
+ ])
43
57
 
44
- declare global {
45
- namespace Core {
46
- namespace Config {
47
- interface Services {
48
- router: RouterServiceConfig
49
- }
50
- }
51
- }
58
+ export type TServerController<TRouter extends ServerRouter> = (context: TRouterContext<TRouter>) => any;
59
+
60
+ export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS'
61
+ export type TRouteHttpMethod = HttpMethod | '*';
62
+
63
+ export type TApiResponseData = {
64
+ data: any,
65
+ triggers?: { [cle: string]: any }
52
66
  }
53
67
 
68
+ export type HttpHeaders = { [cle: string]: string }
69
+
54
70
  /*----------------------------------
55
- - TYPES: REGISTER
71
+ - SERVICE CONFIG
56
72
  ----------------------------------*/
57
73
 
58
- export type { default as Request } from "./request";
59
- export type { default as Response } from "./response";
60
-
61
- export type TApiRegisterArgs = ([
62
- path: string,
63
- controller: TServerController
64
- ] | [
65
- path: string,
66
- options: Partial<TRouteOptions>,
67
- controller: TServerController
68
- ])
74
+ const LogPrefix = '[router]';
69
75
 
70
- /*----------------------------------
71
- - TYPES: ROUTE
72
- ----------------------------------*/
76
+ export type TRouterServicesList = {
77
+ [serviceName: string]: RouterService<ServerRouter>
78
+ }
73
79
 
74
- export type TServerController = (request: With<ServerRequest, 'response'>, data: TObjetDonnees) => any;
80
+ export type Config<
81
+ TServiceList extends TRouterServicesList = TRouterServicesList,
82
+ TAdditionnalSsrData extends {} = {}
83
+ > = {
75
84
 
76
- export type HttpHeaders = {[cle: string]: string}
85
+ debug: boolean,
77
86
 
78
- export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'OPTIONS'
79
- export type TRouteHttpMethod = HttpMethod | '*';
87
+ http: HttpServiceConfig
80
88
 
81
- export type TApiServerRoute = TBaseRoute & {
82
- controller: TServerController,
83
- type: 'API',
84
- method: TRouteHttpMethod
89
+ // Set it as a function, so when we instanciate the services, we can callthis.router to pass the router instance in roiuter services
90
+ services: TServiceList,
91
+
92
+ ssrData: (request: ServerRequest<ServerRouter>) => Promise<TAdditionnalSsrData>,
93
+
94
+ // Protections against bots
95
+ // TODO: move to Protection service
96
+ /*security: {
97
+ recaptcha: {
98
+ prv: string,
99
+ pub: string
100
+ },
101
+ iphub: string
102
+ },*/
85
103
  }
86
104
 
87
- export type TApiResponseData = {
88
- data: any,
89
- triggers?: {[cle: string]: any}
105
+ export type Hooks = {
106
+
90
107
  }
91
108
 
92
109
  /*----------------------------------
93
110
  - CLASSE
94
111
  ----------------------------------*/
95
- export class Router extends BaseRouter {
112
+ export default class ServerRouter<
113
+ TConfig extends Config = Config,
114
+ TApplication extends Application = Application
115
+ > extends Service<TConfig, Hooks, TApplication> implements BaseRouter {
96
116
 
97
- public app = app;
117
+ // Services
118
+ public http: HTTP;
119
+ public services: TConfig["services"];
120
+ public render: DocumentRenderer;
98
121
 
122
+ // Indexed
99
123
  public routes: TRoute[] = []; // API + pages front front
100
-
124
+ public errors: { [code: number]: TErrorRoute } = {};
101
125
  public ssrRoutes: TSsrUnresolvedRoute[] = [];
102
126
 
103
127
  /*----------------------------------
104
128
  - SERVICE
105
129
  ----------------------------------*/
106
130
 
107
- public constructor() {
108
- super();
109
- app.on('ready', () => this.afterRegister());
131
+ public constructor(app: TApplication, config: TConfig) {
132
+
133
+ super(app, config);
134
+
135
+ this.http = new HTTP(config.http, this);
136
+ this.render = new DocumentRenderer(this);
137
+ this.services = config.services;
138
+
110
139
  }
111
140
 
112
- public async load() {
141
+ public async register() {
142
+
143
+ // Since route registering requires all services to be ready,
144
+ // We load routes only when all services are ready
145
+ this.app.on('ready', async () => {
113
146
 
147
+ // Use require to avoid circular references
148
+ this.registerRoutes([
149
+ ...require("metas:@/server/routes/**/*.ts"),
150
+ ...require("metas:@/client/pages/**/*.tsx"),
151
+ ...require("metas:@client/pages/**/*.tsx")
152
+ ]);
153
+ })
114
154
  }
115
155
 
116
- /*----------------------------------
117
- - INDEXING
118
- ----------------------------------*/
156
+ public async start() {
157
+ this.startServices();
158
+ }
119
159
 
120
- public all = (...args: TApiRegisterArgs) => this.registerApi('*', ...args);
121
- public options = (...args: TApiRegisterArgs) => this.registerApi('OPTIONS', ...args);
122
- public get = (...args: TApiRegisterArgs) => this.registerApi('GET', ...args);
123
- public post = (...args: TApiRegisterArgs) => this.registerApi('POST', ...args);
124
- public put = (...args: TApiRegisterArgs) => this.registerApi('PUT', ...args);
125
- public delete = (...args: TApiRegisterArgs) => this.registerApi('DELETE', ...args)
160
+ private async startServices() {
161
+ console.log(LogPrefix, `Starting router services`);
126
162
 
127
- protected registerApi(method: TRouteHttpMethod, ...args: TApiRegisterArgs): TRoute {
163
+ for (const serviceId in this.services) {
164
+ const service = this.services[serviceId];
165
+ service.attach(this);
166
+ await service.register();
167
+ }
168
+ }
128
169
 
129
- let path: string;
130
- let options: Partial<TRouteOptions> = {};
131
- let controller: TServerController;
170
+ private registerRoutes(defModules: GlobImportedWithMetas<TRouteModule>) {
171
+ for (const routeModule of defModules) {
132
172
 
133
- if (args.length === 2)
134
- ([path, controller] = args)
135
- else
136
- ([path, options, controller] = args)
173
+ const register = routeModule.exports.__register;
174
+ if (!register)
175
+ continue;
137
176
 
138
- const { regex, keys } = this.buildRegex(path);
177
+ console.log(LogPrefix, `Register file:`, routeModule.matches.join('/'));
178
+ register(this.app);
179
+ }
180
+
181
+ this.afterRegister();
182
+ }
183
+
184
+ /*----------------------------------
185
+ - REGISTER
186
+ ----------------------------------*/
187
+
188
+ public page(...args: TRegisterPageArgs) {
189
+
190
+ const { path, options, controller, renderer } = getRegisterPageArgs(...args);
191
+
192
+ const { regex, keys } = buildRegex(path);
139
193
 
140
194
  const route: TRoute = {
141
- type: 'API',
142
- method: method,
143
- path: path,
195
+ method: 'GET',
196
+ path,
144
197
  regex,
145
- keys: keys.map(k => k.name),
198
+ keys,
199
+ controller: (context: TRouterContext<this>) => new Page(controller, renderer, context),
146
200
  options: {
147
201
  ...defaultOptions,
202
+ accept: 'html', // Les pages retournent forcémment du html
148
203
  ...options
149
204
  },
150
- controller
151
205
  }
152
206
 
153
207
  this.routes.push(route);
154
208
 
155
- return route;
209
+ return this;
210
+
156
211
  }
157
212
 
158
- protected registerPage( ...args: TRegisterPageArgs ) {
213
+ public error(
214
+ code: number,
215
+ options: TRoute["options"],
216
+ renderer: TFrontRenderer<{}, { message: string }>
217
+ ) {
218
+ this.errors[code] = {
219
+ code,
220
+ controller: (context: TRouterContext<this>) => new Page(null, renderer, context),
221
+ options
222
+ };
223
+ }
159
224
 
160
- const { path, options, controller, renderer } = this.getRegisterPageArgs(...args);
225
+ public all = (...args: TApiRegisterArgs<this>) => this.registerApi('*', ...args);
226
+ public options = (...args: TApiRegisterArgs<this>) => this.registerApi('OPTIONS', ...args);
227
+ public get = (...args: TApiRegisterArgs<this>) => this.registerApi('GET', ...args);
228
+ public post = (...args: TApiRegisterArgs<this>) => this.registerApi('POST', ...args);
229
+ public put = (...args: TApiRegisterArgs<this>) => this.registerApi('PUT', ...args);
230
+ public delete = (...args: TApiRegisterArgs<this>) => this.registerApi('DELETE', ...args)
161
231
 
162
- const { regex, keys } = this.buildRegex(path);
232
+ protected registerApi(method: TRouteHttpMethod, ...args: TApiRegisterArgs<this>): this {
163
233
 
164
- this.routes.push({
165
- type: 'PAGE',
166
- method: 'GET',
167
- path,
234
+ let path: string;
235
+ let options: Partial<TRouteOptions> = {};
236
+ let controller: TServerController<this>;
237
+
238
+ if (args.length === 2)
239
+ ([path, controller] = args)
240
+ else
241
+ ([path, options, controller] = args)
242
+
243
+ const { regex, keys } = buildRegex(path);
244
+
245
+ const route: TRoute = {
246
+
247
+ method: method,
248
+ path: path,
168
249
  regex,
169
- keys: keys.map(k => k.name),
250
+ keys: keys,
170
251
  options: {
171
252
  ...defaultOptions,
172
- accept: 'html', // Les pages retournent forcémment du html
173
253
  ...options
174
254
  },
175
- controller,
255
+ controller
256
+ }
176
257
 
177
- renderer
178
- });
258
+ this.routes.push(route);
179
259
 
180
260
  return this;
181
-
182
261
  }
183
262
 
184
263
  private async afterRegister() {
185
264
 
186
265
  console.info("Pre-Loading request services");
187
- await TrackingService.LoadCache();
266
+ //await TrackingService.LoadCache();
188
267
 
189
268
  console.info("Loading routes ...");
190
269
 
@@ -206,19 +285,19 @@ export class Router extends BaseRouter {
206
285
  console.info(`Registered routes:`);
207
286
  for (const route of this.routes) {
208
287
 
288
+ const chunkId = route.options["id"];
289
+
209
290
  console.info('-',
210
- route.type,
211
291
  route.method,
212
292
  route.path,
213
293
  ' :: ', JSON.stringify(route.options)
214
294
  );
215
295
 
216
- if ('renderer' in route)
296
+ if (route.options["id"])
217
297
  this.ssrRoutes.push({
218
- type: route.type,
219
298
  regex: route.regex.source,
220
299
  keys: route.keys,
221
- chunk: route.options["id"]
300
+ chunk: chunkId
222
301
  });
223
302
 
224
303
  }
@@ -227,15 +306,26 @@ export class Router extends BaseRouter {
227
306
  for (const code in this.errors) {
228
307
 
229
308
  const route = this.errors[code];
230
- console.info('-', code);
309
+ const chunkId = route.options["id"];
310
+
311
+ console.info('-', code,
312
+ ' :: ', JSON.stringify(route.options)
313
+ );
231
314
 
232
315
  this.ssrRoutes.push({
233
- type: route.type,
234
- chunk: route.options["id"],
235
- code
316
+ code: parseInt(code),
317
+ chunk: chunkId,
236
318
  });
237
319
  }
238
320
 
321
+ console.info(`Registered layouts:`);
322
+ for (const layoutId in layoutsList) {
323
+
324
+ const layout = layoutsList[layoutId];
325
+
326
+ console.info('-', layoutId, layout);
327
+ }
328
+
239
329
  console.info(this.routes.length + " routes where registered.");
240
330
  }
241
331
 
@@ -257,6 +347,7 @@ export class Router extends BaseRouter {
257
347
  let requestId = uuid();
258
348
  const request = new ServerRequest(
259
349
  requestId,
350
+
260
351
  req.method as HttpMethod,
261
352
  req.path, // url sans params
262
353
  // Exclusion de req.files, car le middleware multipart les a normalisé dans req.body
@@ -267,7 +358,11 @@ export class Router extends BaseRouter {
267
358
  this
268
359
  );
269
360
 
270
- const now = new Date;
361
+ // Hook
362
+ await this.runHook('request', request);
363
+
364
+ // TODO: move to tracking
365
+ /*const now = new Date;
271
366
 
272
367
  // Identify Guest & create log entry
273
368
  const username = request.user?.name;
@@ -280,41 +375,18 @@ export class Router extends BaseRouter {
280
375
 
281
376
  const keepLogs = request.ip !== '86.76.176.80';
282
377
  if (!keepLogs)
283
- requestId = 'admin';
378
+ requestId = 'admin';*/
284
379
 
285
380
  // Create request context so we can access request context across all the request-triggered libs
286
381
  context.run({ channelType: 'request', channelId: requestId }, async () => {
287
382
 
288
- let response: ServerResponse;
383
+ let response: ServerResponse<this>;
289
384
  try {
290
-
291
- // Auth
292
- request.user = await AuthService.decode(req, true);
293
385
 
294
386
  // Bulk API Requests
295
387
  if (request.path === '/api' && typeof request.data.fetchers === "object") {
296
388
 
297
- const responseData: TObjetDonnees = {};
298
- for (const id in request.data.fetchers) {
299
-
300
- const [method, path, data] = request.data.fetchers[id] as TFetcherArgs;
301
-
302
- const response = await this.resolve(
303
- request.children(method, path, data)
304
- );
305
-
306
- responseData[id] = response.data;
307
-
308
- // TODO: merge response.headers ?
309
-
310
- }
311
-
312
- // Status
313
- res.status(200);
314
- // Data
315
- res.json(responseData);
316
-
317
- return;
389
+ return await this.resolveApiBatch(request);
318
390
 
319
391
  } else {
320
392
  response = await this.resolve(request);
@@ -330,8 +402,9 @@ export class Router extends BaseRouter {
330
402
  // Data
331
403
  res.send(response.data);
332
404
 
333
- if (newClient)
334
- $.console.client({
405
+ // TODO: move to tracking
406
+ /*if (newClient)
407
+ console.client({
335
408
  id: clientId,
336
409
  ip: request.ip,
337
410
  user: username,
@@ -340,7 +413,7 @@ export class Router extends BaseRouter {
340
413
  activity: now,
341
414
  });
342
415
 
343
- $.console.request({
416
+ console.request({
344
417
 
345
418
  id: requestId,
346
419
  date: now,
@@ -355,85 +428,46 @@ export class Router extends BaseRouter {
355
428
 
356
429
  statusCode: response.statusCode,
357
430
  time: Date.now() - now.valueOf()
358
- });
431
+ });*/
359
432
  });
360
-
361
- }
362
-
363
- private async handleError(e: Error, request: ServerRequest) {
364
-
365
- const code = 'http' in e ? e.http : 500;
366
- const route = this.errors[code];
367
- if (route === undefined)
368
- throw new Error(`No route for error code ${code}`);
369
-
370
- const response = new ServerResponse(request).status(code).setRoute(route);
371
-
372
- // Rapport / debug
373
- if (code === 500) {
374
-
375
- for (const callback of app.hooks.error)
376
- callback(e);
377
-
378
- $.console.bugReport.server(e, request);
379
-
380
- // Pour déboguer les erreurs HTTP
381
- } else if (app.env.profile === "dev")
382
- console.warn(e);
383
-
384
- if (request.accepts("html"))
385
- await response.runController( route, { message: e.message });
386
- else if (request.accepts("json"))
387
- await response.json(e.message);
388
- else
389
- await response.text(e.message);
390
-
391
- return response;
392
-
393
433
  }
394
434
 
395
- public async resolve( request: ServerRequest ): Promise<ServerResponse> {
435
+ public async resolve(request: ServerRequest<this>): Promise<ServerResponse<this>> {
396
436
 
397
- console.info(request.ip, request.method, request.domain, request.path);
437
+ console.info(request.ip, request.method, request.domain, request.path, 'user =', request.user);
398
438
 
399
- const response = new ServerResponse(request);
439
+ const response = new ServerResponse<this>(request);
400
440
 
401
- request.tracking.event('pageview');
441
+ await this.runHook('resolve', request);
402
442
 
403
443
  for (const route of this.routes) {
404
444
 
405
- // Method
445
+ // Match Method
406
446
  if (request.method !== route.method && route.method !== '*')
407
447
  continue;
408
448
 
409
- // Response format
449
+ // Match Response format
410
450
  if (!request.accepts(route.options.accept))
411
451
  continue;
412
452
 
413
- // URL
453
+ // Match Path
414
454
  const match = route.regex.exec(request.path);
415
455
  if (!match)
416
456
  continue;
417
457
 
418
- // Testing = must be admin
419
- if (route.options.TESTING === true && !(request.user && request.user.email === "Decentraliseur"))
420
- break;
421
-
422
- // Auth
423
- if (route.options.auth !== undefined)
424
- request.auth.check(route.options.auth);
425
-
426
- //console.log('Resolved route:', route.regex.source);
427
-
458
+ // Extract URL params
428
459
  for (let iKey = 0; iKey < route.keys.length; iKey++) {
429
460
  const nomParam = route.keys[iKey];
430
461
  if (typeof nomParam === 'string') // number = sans nom
431
462
  request.data[nomParam] = match[iKey + 1]
432
463
  }
433
464
 
465
+ // Run on resolution hooks. Ex: authentication check
466
+ await this.runHook('resolved', route);
467
+
434
468
  // Create response
435
469
  await response.runController(route);
436
- if (response.wasProvided)
470
+ if (response.wasProvided)
437
471
  // On continue l'itération des routes, sauf si des données ont été fournie dans la réponse (.json(), .html(), ...)
438
472
  return response;
439
473
  }
@@ -441,20 +475,56 @@ export class Router extends BaseRouter {
441
475
  throw new NotFound(`The requested endpoint was not found.`);
442
476
  }
443
477
 
444
- }
478
+ private async resolveApiBatch( request: ServerRequest<this> ) {
479
+
480
+ const responseData: TObjetDonnees = {};
481
+ for (const id in request.data.fetchers) {
482
+
483
+ const [method, path, data] = request.data.fetchers[id] as TFetcherArgs;
484
+
485
+ const response = await this.resolve(
486
+ request.children(method, path, data)
487
+ );
488
+
489
+ responseData[id] = response.data;
490
+
491
+ // TODO: merge response.headers ?
445
492
 
446
- /*----------------------------------
447
- - REGISTER SERVICE
448
- ----------------------------------*/
449
- app.register('router', Router);
450
- declare global {
451
- namespace Core {
452
- interface Services {
453
- router: Router;
454
493
  }
494
+
495
+ // Status
496
+ request.res.status(200);
497
+ // Data
498
+ request.res.json(responseData);
499
+ }
500
+
501
+ private async handleError(e: Erreur, request: ServerRequest<ServerRouter>) {
502
+
503
+ const code = 'http' in e ? e.http : 500;
504
+ const route = this.errors[code];
505
+ if (route === undefined)
506
+ throw new Error(`No route for error code ${code}`);
507
+
508
+ const response = new ServerResponse(request).status(code).setRoute(route);
509
+
510
+ // Rapport / debug
511
+ if (code === 500) {
512
+
513
+ await this.app.runHook('error', e, request);
514
+
515
+ // Pour déboguer les erreurs HTTP
516
+ } else if (this.app.env.profile === "dev")
517
+ console.warn(e);
518
+
519
+ if (request.accepts("html"))
520
+ await response.runController(route, { message: e.message });
521
+ else if (request.accepts("json"))
522
+ await response.json(e.message);
523
+ else
524
+ await response.text(e.message);
525
+
526
+ return response;
527
+
455
528
  }
456
- }
457
529
 
458
- // Exceptionnally, we export the @router module
459
- // Bacause import router from '@router'; need to be available both on client and sevrer side.
460
- export default app.services.router;
530
+ }