5htp-core 0.1.2 → 0.2.1
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/changelog.md +5 -0
- package/doc/TODO.md +71 -0
- package/package.json +5 -4
- package/src/client/{App.tsx → app/component.tsx} +15 -11
- package/src/client/app/index.ts +128 -0
- package/src/client/app/service.ts +34 -0
- package/src/client/app.tsconfig.json +0 -4
- package/src/client/assets/css/components.less +52 -0
- package/src/client/assets/css/core.less +7 -28
- package/src/client/assets/css/theme.less +1 -1
- package/src/client/assets/css/{borders.less → utils/borders.less} +0 -0
- package/src/client/assets/css/{layouts.less → utils/layouts.less} +0 -0
- package/src/client/assets/css/{medias.less → utils/medias.less} +14 -1
- package/src/client/assets/css/{sizing.less → utils/sizing.less} +0 -0
- package/src/client/assets/css/{spacing.less → utils/spacing.less} +0 -0
- package/src/client/components/Card/index.tsx +13 -7
- package/src/client/components/Dialog/Manager.tsx +41 -14
- package/src/client/components/Dialog/index.less +2 -4
- package/src/client/components/Form/index.tsx +1 -1
- package/src/client/components/Row/index.less +0 -2
- package/src/client/components/Table/index.tsx +3 -2
- package/src/client/components/button.tsx +2 -2
- package/src/client/components/containers/Popover/index.tsx +1 -1
- package/src/client/components/containers/champs.less +0 -2
- package/src/client/components/data/spintext/index.tsx +1 -1
- package/src/client/components/dropdown/index.tsx +1 -1
- package/src/client/components/index.ts +23 -0
- package/src/client/components/input/BaseV2/index.less +0 -2
- package/src/client/components/input/BaseV2/index.tsx +1 -1
- package/src/client/components/input/Date/index.less +0 -2
- package/src/client/components/input/Periode/index.less +0 -2
- package/src/client/components/input/Radio/index.less +0 -2
- package/src/client/components/input/UploadImage/index.less +0 -2
- package/src/client/components/input/UploadImage/index.tsx +1 -1
- package/src/client/hooks/index.ts +5 -0
- package/src/client/hooks/useState/index.tsx +2 -2
- package/src/client/hooks.ts +22 -0
- package/src/client/index.ts +5 -0
- package/src/client/pages/_layout/landing/index.tsx +0 -2
- package/src/client/pages/_messages/400.tsx +2 -2
- package/src/client/pages/_messages/401.tsx +2 -2
- package/src/client/pages/_messages/403.tsx +2 -2
- package/src/client/pages/_messages/404.tsx +2 -2
- package/src/client/pages/_messages/500.tsx +2 -2
- package/src/client/pages/bug.tsx +1 -1
- package/src/client/pages/useHeader.tsx +1 -1
- package/src/client/{context/captcha.ts → services/captcha/index.ts} +0 -0
- package/src/client/services/metrics/index.ts +37 -0
- package/src/client/{router → services/router/components}/Link.tsx +1 -1
- package/src/client/services/router/components/Page.tsx +59 -0
- package/src/client/{router/component.tsx → services/router/components/router.tsx} +52 -74
- package/src/client/services/router/index.tsx +453 -0
- package/src/client/services/router/request/api.ts +227 -0
- package/src/client/{router → services/router}/request/history.ts +0 -0
- package/src/client/services/router/request/index.ts +52 -0
- package/src/client/services/router/response/index.tsx +107 -0
- package/src/client/services/router/response/page.ts +90 -0
- package/src/client/{context/socket.ts → services/socket/index.ts} +2 -2
- package/src/client/utils/dom.ts +1 -1
- package/src/common/app/index.ts +9 -0
- package/src/common/data/chaines/index.ts +9 -6
- package/src/common/data/input/validate.ts +3 -166
- package/src/common/data/objets.ts +25 -0
- package/src/common/data/tableaux.ts +8 -0
- package/src/common/errors/index.ts +3 -1
- package/src/common/router/index.ts +67 -88
- package/src/common/router/layouts.ts +50 -0
- package/src/common/router/register.ts +62 -0
- package/src/common/router/request/api.ts +72 -0
- package/src/common/router/request/index.ts +31 -0
- package/src/common/router/{response.ts → response/index.ts} +9 -13
- package/src/common/router/response/page.ts +46 -54
- package/src/common/validation/index.ts +3 -0
- package/src/common/validation/schema.ts +185 -0
- package/src/common/validation/validator.ts +95 -0
- package/src/common/validation/validators.ts +313 -0
- package/src/server/app/config.ts +9 -27
- package/src/server/app/index.ts +81 -124
- package/src/server/app/service.ts +98 -0
- package/src/server/app.tsconfig.json +0 -8
- package/src/server/index.ts +5 -0
- package/src/server/patch.ts +0 -6
- package/src/server/{data/Cache.ts → services/cache/index.ts} +79 -47
- package/src/server/services/console/bugReporter.ts +26 -16
- package/src/server/services/console/index.ts +59 -51
- package/src/server/services/cron/index.ts +12 -26
- package/src/server/services/database/bucket.ts +40 -0
- package/src/server/services/database/connection.ts +213 -80
- package/src/server/services/database/datatypes.ts +63 -40
- package/src/server/services/database/debug.ts +20 -0
- package/src/server/services/database/index.ts +295 -272
- package/src/server/services/database/metas.ts +246 -135
- package/src/server/services/database/stats.ts +151 -126
- package/src/server/services/email/index.ts +30 -62
- package/src/server/services/email/transporter.ts +38 -0
- package/src/server/services/{router/request/services → metrics}/detect.ts +8 -10
- package/src/server/services/{router/request/services/tracking.ts → metrics/index.ts} +68 -45
- package/src/server/services/{http → router/http}/index.ts +28 -70
- package/src/server/services/{http → router/http}/multipart.ts +0 -0
- package/src/server/services/{http → router/http}/session.ts.old +0 -0
- package/src/server/services/router/index.ts +273 -202
- package/src/server/services/router/request/api.ts +76 -0
- package/src/server/services/router/request/index.ts +16 -97
- package/src/server/services/router/request/service.ts +21 -0
- package/src/server/services/router/response/index.ts +131 -65
- package/src/server/services/router/response/{filter → mask}/Filter.ts +0 -0
- package/src/server/services/router/response/{filter → mask}/index.ts +0 -2
- package/src/server/services/router/response/{filter → mask}/selecteurs.ts +0 -0
- package/src/server/services/router/response/page/document.tsx +194 -0
- package/src/server/services/router/response/page/index.tsx +157 -0
- package/src/server/{libs/pages → services/router/response/page}/schemaGenerator.ts +0 -0
- package/src/server/services/router/service.ts +48 -0
- package/src/server/services/schema/index.ts +47 -0
- package/src/server/services/schema/request.ts +55 -0
- package/src/server/services/schema/router.ts +33 -0
- package/src/server/services/socket/index.ts +38 -43
- package/src/server/services/socket/scope.ts +6 -4
- package/src/server/services/users/index.ts +203 -0
- package/src/server/services/{auth/base.ts → users/old.ts} +28 -112
- package/src/server/services/users/router/index.ts +72 -0
- package/src/server/services/users/router/request.ts +49 -0
- package/src/server/{data → services_old}/SocketClient.ts +0 -0
- package/src/server/{data/Token.olg.ts → services_old/Token.old.ts} +0 -0
- package/src/server/{data → services_old}/aes.ts +0 -0
- package/src/types/aliases.d.ts +43 -2
- package/templates/composant.tsx +1 -1
- package/templates/modal.tsx +1 -1
- package/templates/page.tsx +1 -1
- package/tsconfig.common.json +0 -4
- package/src/client/assets/css/components/components.less +0 -31
- package/src/client/context/api.ts +0 -92
- package/src/client/context/index.ts +0 -246
- package/src/client/index.tsx +0 -129
- package/src/client/router/index.ts +0 -286
- package/src/client/router/request/index.ts +0 -106
- package/src/client/router/response/index.ts +0 -38
- package/src/client/router/route.ts +0 -75
- package/src/common/data/input/validators/basic.ts +0 -299
- package/src/common/data/input/validators/build.ts +0 -63
- package/src/common/router/request.ts +0 -83
- package/src/server/data/ApiClient.ts +0 -119
- package/src/server/data/input.ts +0 -41
- package/src/server/libs/pages/document.static.tsx +0 -41
- package/src/server/libs/pages/document.tsx +0 -203
- package/src/server/libs/pages/render.tsx +0 -90
- package/src/server/routes/auth.ts +0 -151
- package/src/server/services/redis/index.ts +0 -71
- package/src/server/services/router/request/services/auth.ts +0 -177
|
@@ -0,0 +1,76 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Core
|
|
6
|
+
|
|
7
|
+
import RequestService from './service';
|
|
8
|
+
|
|
9
|
+
import ApiClientService, {
|
|
10
|
+
TApiFetchOptions, TFetcherList, TFetcherArgs, TFetcher
|
|
11
|
+
} from '@common/router/request/api';
|
|
12
|
+
|
|
13
|
+
/*----------------------------------
|
|
14
|
+
- TYPES
|
|
15
|
+
----------------------------------*/
|
|
16
|
+
|
|
17
|
+
|
|
18
|
+
/*----------------------------------
|
|
19
|
+
- SERVICE
|
|
20
|
+
----------------------------------*/
|
|
21
|
+
export default class ApiClientRequest extends RequestService implements ApiClientService {
|
|
22
|
+
|
|
23
|
+
public async start() {
|
|
24
|
+
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
/*----------------------------------
|
|
28
|
+
- HIGH LEVEL
|
|
29
|
+
----------------------------------*/
|
|
30
|
+
|
|
31
|
+
public get = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
32
|
+
this.createFetcher<TData>('GET', path, data, opts);
|
|
33
|
+
|
|
34
|
+
public post = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
35
|
+
this.createFetcher<TData>('POST', path, data, opts);
|
|
36
|
+
|
|
37
|
+
public put = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
38
|
+
this.createFetcher<TData>('PUT', path, data, opts);
|
|
39
|
+
|
|
40
|
+
public delete = <TData extends unknown = unknown>(path: string, data?: TObjetDonnees, opts?: TApiFetchOptions) =>
|
|
41
|
+
this.createFetcher<TData>('DELETE', path, data, opts);
|
|
42
|
+
|
|
43
|
+
/*----------------------------------
|
|
44
|
+
- API CALLS FROM SERVER
|
|
45
|
+
----------------------------------*/
|
|
46
|
+
|
|
47
|
+
public createFetcher<TData extends unknown = unknown>(...[method, path, data, options]: TFetcherArgs): TFetcher<TData> {
|
|
48
|
+
return {
|
|
49
|
+
method, path, data, options,
|
|
50
|
+
then: () => { throw new Error("Async resolvers should not be run from server side."); },
|
|
51
|
+
run: () => { throw new Error("Async resolvers should not be run from server side."); },
|
|
52
|
+
};
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
public async fetchSync(fetchers: TFetcherList, alreadyLoadedData: {}): Promise<TObjetDonnees> {
|
|
56
|
+
|
|
57
|
+
const fetchedData: TObjetDonnees = { ...alreadyLoadedData };
|
|
58
|
+
|
|
59
|
+
for (const id in fetchers) {
|
|
60
|
+
|
|
61
|
+
const { method, path, data, options } = fetchers[id];
|
|
62
|
+
//this.router.config.debug && console.log(`[api] Resolving from internal api`, method, path, data);
|
|
63
|
+
|
|
64
|
+
// We don't fetch the already given data
|
|
65
|
+
if (id in fetchedData)
|
|
66
|
+
continue;
|
|
67
|
+
|
|
68
|
+
// Create a children request to resolve the api data
|
|
69
|
+
const internalHeaders = { accept: 'application/json' }
|
|
70
|
+
const request = this.request.children(method, path, data, { ...internalHeaders/*, ...headers*/ });
|
|
71
|
+
fetchedData[id] = await request.router.resolve(request).then(res => res.data);
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
return fetchedData;
|
|
75
|
+
}
|
|
76
|
+
}
|
|
@@ -8,34 +8,30 @@ import ISO6391 from 'iso-639-1';
|
|
|
8
8
|
import accepts from 'accepts';
|
|
9
9
|
import Bowser from "bowser";
|
|
10
10
|
|
|
11
|
-
// Core
|
|
12
|
-
import
|
|
13
|
-
import { TSchema, validate as validerSchema, TDonneesValidees } from '@common/data/input/validate';
|
|
14
|
-
import app from '@server/app';
|
|
11
|
+
// Core
|
|
12
|
+
import BaseRequest from '@common/router/request';
|
|
15
13
|
|
|
16
|
-
//
|
|
14
|
+
// Specific
|
|
17
15
|
import ServerResponse from '../response';
|
|
18
|
-
import
|
|
19
|
-
|
|
20
|
-
// Extensions
|
|
21
|
-
import AuthService from './services/auth';
|
|
22
|
-
import SecurityService from './services/detect';
|
|
23
|
-
import TrackingService from './services/tracking';
|
|
24
|
-
|
|
25
|
-
const debug = true;
|
|
16
|
+
import ApiClient from './api';
|
|
26
17
|
|
|
27
18
|
/*----------------------------------
|
|
28
19
|
- TYPES
|
|
29
20
|
----------------------------------*/
|
|
30
21
|
|
|
31
|
-
import type {
|
|
22
|
+
import type {
|
|
23
|
+
default as Router, Config as RouterConfig,
|
|
24
|
+
HttpMethod, HttpHeaders
|
|
25
|
+
} from '@server/services/router';
|
|
32
26
|
|
|
33
27
|
const localeFilter = (input: any) => typeof input === 'string' && ISO6391.validate(input) ? input : undefined;
|
|
34
28
|
|
|
35
29
|
/*----------------------------------
|
|
36
30
|
- CONTEXTE
|
|
37
31
|
----------------------------------*/
|
|
38
|
-
export default class ServerRequest
|
|
32
|
+
export default class ServerRequest<
|
|
33
|
+
TRouter extends Router = Router
|
|
34
|
+
> extends BaseRequest {
|
|
39
35
|
|
|
40
36
|
/*----------------------------------
|
|
41
37
|
- PROPRIÉTÉS
|
|
@@ -53,15 +49,15 @@ export default class ServerRequest extends BaseRequest {
|
|
|
53
49
|
public cookies: TObjetDonnees = {};
|
|
54
50
|
|
|
55
51
|
// reponse
|
|
56
|
-
public response?: ServerResponse
|
|
57
|
-
public router:
|
|
52
|
+
public response?: ServerResponse<TRouter>;
|
|
53
|
+
public router: TRouter;
|
|
58
54
|
|
|
59
55
|
// Origin
|
|
60
56
|
public req: express.Request;
|
|
61
57
|
public res: express.Response;
|
|
62
58
|
|
|
63
59
|
// Services
|
|
64
|
-
|
|
60
|
+
public api: ApiClient;
|
|
65
61
|
|
|
66
62
|
/*----------------------------------
|
|
67
63
|
- INITIALISATION
|
|
@@ -75,7 +71,7 @@ export default class ServerRequest extends BaseRequest {
|
|
|
75
71
|
headers: HttpHeaders | undefined,
|
|
76
72
|
|
|
77
73
|
res: express.Response,
|
|
78
|
-
router:
|
|
74
|
+
router: TRouter,
|
|
79
75
|
isVirtual: boolean = false
|
|
80
76
|
) {
|
|
81
77
|
|
|
@@ -87,6 +83,7 @@ export default class ServerRequest extends BaseRequest {
|
|
|
87
83
|
this.req = res.req;
|
|
88
84
|
this.res = res
|
|
89
85
|
this.router = router;
|
|
86
|
+
this.api = new ApiClient(this);
|
|
90
87
|
|
|
91
88
|
this.host = this.req.get('host') as string;
|
|
92
89
|
this.method = method;
|
|
@@ -96,16 +93,8 @@ export default class ServerRequest extends BaseRequest {
|
|
|
96
93
|
this.cookies = res.req.cookies;
|
|
97
94
|
|
|
98
95
|
this.ip = res.req.ip;
|
|
99
|
-
if (this.ip === '::1' && app.env.localIP)
|
|
100
|
-
this.ip = app.env.localIP;
|
|
101
96
|
|
|
102
97
|
this.data = data || {};
|
|
103
|
-
|
|
104
|
-
// FIX: L'utilisation du sprad sur la classe Servercontext fait perdre le contexte this à ses méthodes
|
|
105
|
-
this.schema.validate = this.schema.validate.bind(this);
|
|
106
|
-
|
|
107
|
-
//this.url = this.url.bind(this);
|
|
108
|
-
|
|
109
98
|
}
|
|
110
99
|
|
|
111
100
|
public children(method: HttpMethod, path: string, data: TObjetDonnees | undefined, headers?: HttpHeaders) {
|
|
@@ -163,74 +152,4 @@ export default class ServerRequest extends BaseRequest {
|
|
|
163
152
|
const { os, browser } = info;
|
|
164
153
|
return (os.name || 'Unknown OS') + ' ' + (os.versionName || os.version || '') + ' / ' + (browser.name || 'Unknown browser') + ' ' + (browser.version || '');
|
|
165
154
|
}
|
|
166
|
-
|
|
167
|
-
/*----------------------------------
|
|
168
|
-
- SERVICES
|
|
169
|
-
----------------------------------*/
|
|
170
|
-
public schema = {
|
|
171
|
-
...validateurs,
|
|
172
|
-
// shortcut pour validation données requete
|
|
173
|
-
validate: async <TSchemaA extends TSchema>(schema: TSchemaA): Promise<TDonneesValidees<TSchemaA>> => {
|
|
174
|
-
|
|
175
|
-
console.log("Validate request data:", this.data);
|
|
176
|
-
|
|
177
|
-
// Les InputError seront propagées vers le middleware dédié à la gestion des erreurs
|
|
178
|
-
const { valeurs } = await validerSchema(
|
|
179
|
-
schema,
|
|
180
|
-
this.data,
|
|
181
|
-
this.data,
|
|
182
|
-
{},
|
|
183
|
-
{
|
|
184
|
-
critique: true,
|
|
185
|
-
validationComplete: true,
|
|
186
|
-
avecDependances: false
|
|
187
|
-
},
|
|
188
|
-
[]
|
|
189
|
-
);
|
|
190
|
-
|
|
191
|
-
return valeurs;
|
|
192
|
-
}
|
|
193
|
-
};
|
|
194
|
-
|
|
195
|
-
/*public url = (route: string, params: any = {}, absolu: boolean = true) =>
|
|
196
|
-
url(route, params, absolu);*/
|
|
197
|
-
|
|
198
|
-
public auth = new AuthService(this);
|
|
199
|
-
|
|
200
|
-
public tracking = new TrackingService(this);
|
|
201
|
-
|
|
202
|
-
public detect = new SecurityService(this);
|
|
203
|
-
|
|
204
|
-
public createFetcher(...[method, path, data, options]: TFetcherArgs) {
|
|
205
|
-
return {
|
|
206
|
-
method, path, data, options,
|
|
207
|
-
then: () => { throw new Error("Async resolvers should not be run from server side."); },
|
|
208
|
-
run: () => { throw new Error("Async resolvers should not be run from server side."); },
|
|
209
|
-
} as TFetcher;
|
|
210
|
-
}
|
|
211
|
-
|
|
212
|
-
public async fetchSync(fetchers: TFetcherList): Promise<TObjetDonnees> {
|
|
213
|
-
|
|
214
|
-
const resolved: TObjetDonnees = {};
|
|
215
|
-
|
|
216
|
-
for (const id in fetchers) {
|
|
217
|
-
|
|
218
|
-
const { method, path, data, options } = fetchers[id];
|
|
219
|
-
|
|
220
|
-
debug && console.log(`[api] Resolving from internal api`, method, path, data);
|
|
221
|
-
|
|
222
|
-
const internalHeaders = { accept: 'application/json' }
|
|
223
|
-
const request = this.request.children(method, path, data, { ...internalHeaders/*, ...headers*/ });
|
|
224
|
-
resolved[id] = await request.router.resolve(request).then(res => res.data);
|
|
225
|
-
|
|
226
|
-
}
|
|
227
|
-
|
|
228
|
-
return resolved;
|
|
229
|
-
|
|
230
|
-
}
|
|
231
|
-
|
|
232
|
-
public fetchAsync(...args: TFetcherArgs): Promise<any> {
|
|
233
|
-
throw new Error("Async resolvers should not be run from server side.");
|
|
234
|
-
}
|
|
235
|
-
|
|
236
155
|
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
import type Router from '..';
|
|
6
|
+
import type ServerRequest from '.';
|
|
7
|
+
|
|
8
|
+
/*----------------------------------
|
|
9
|
+
- SERVICE
|
|
10
|
+
----------------------------------*/
|
|
11
|
+
export default abstract class RequestService {
|
|
12
|
+
|
|
13
|
+
public constructor(
|
|
14
|
+
public request: ServerRequest<Router>,
|
|
15
|
+
public router = request.router,
|
|
16
|
+
public app = router.app
|
|
17
|
+
) {
|
|
18
|
+
|
|
19
|
+
}
|
|
20
|
+
|
|
21
|
+
}
|
|
@@ -12,16 +12,16 @@ import fs from 'fs-extra';
|
|
|
12
12
|
import express from 'express';
|
|
13
13
|
|
|
14
14
|
// Core
|
|
15
|
-
import
|
|
16
|
-
import
|
|
17
|
-
|
|
18
|
-
// Libs métier
|
|
19
|
-
import * as render from '../../../libs/pages/render';
|
|
20
|
-
import filter from './filter';
|
|
15
|
+
import Application from '@server/app';
|
|
16
|
+
import type ServerRouter from '@server/services/router';
|
|
21
17
|
import ServerRequest from '@server/services/router/request';
|
|
22
18
|
import { TRoute } from '@common/router';
|
|
23
|
-
import
|
|
24
|
-
import {
|
|
19
|
+
import { NotFound, Forbidden } from '@common/errors';
|
|
20
|
+
import BaseResponse, { TResponseData } from '@common/router/response';
|
|
21
|
+
import Page from './page';
|
|
22
|
+
|
|
23
|
+
// To move into a new npm module: json-mask
|
|
24
|
+
import jsonMask from './mask';
|
|
25
25
|
|
|
26
26
|
/*----------------------------------
|
|
27
27
|
- TYPES
|
|
@@ -29,98 +29,145 @@ import { ClientContext } from '@client/context';
|
|
|
29
29
|
|
|
30
30
|
const debug = true;
|
|
31
31
|
|
|
32
|
-
export type
|
|
32
|
+
export type TBasicSSrData = {
|
|
33
33
|
request: { data: TObjetDonnees, id: string },
|
|
34
|
-
page: {
|
|
35
|
-
user: User | null
|
|
34
|
+
page: { chunkId: string, data?: TObjetDonnees },
|
|
35
|
+
//user: User | null
|
|
36
36
|
}
|
|
37
37
|
|
|
38
|
+
export type TRouterContext<TRouter extends ServerRouter = ServerRouter> = (
|
|
39
|
+
// Request context
|
|
40
|
+
{
|
|
41
|
+
app: Application,
|
|
42
|
+
context: TRouterContext<TRouter>, // = this
|
|
43
|
+
request: ServerRequest<TRouter>,
|
|
44
|
+
api: ServerRequest<TRouter>["api"],
|
|
45
|
+
response: ServerResponse<TRouter>,
|
|
46
|
+
route: TRoute,
|
|
47
|
+
page?: Page,
|
|
48
|
+
user: User
|
|
49
|
+
}
|
|
50
|
+
&
|
|
51
|
+
TRouterContextServices<TRouter>
|
|
52
|
+
)
|
|
53
|
+
|
|
54
|
+
type TRouterContextWithPage = With<TRouterContext, 'page'>
|
|
55
|
+
|
|
56
|
+
export type TRouterContextServices<TRouter extends ServerRouter> = (
|
|
57
|
+
// Custom context via servuces
|
|
58
|
+
// For each roiuter service, return the request service (returned by roiuterService.requestService() )
|
|
59
|
+
{
|
|
60
|
+
[serviceName in keyof TRouter["services"]]: ReturnType< TRouter["services"][serviceName]["requestService"] >
|
|
61
|
+
}
|
|
62
|
+
)
|
|
63
|
+
|
|
64
|
+
|
|
38
65
|
/*----------------------------------
|
|
39
66
|
- CLASSE
|
|
40
67
|
----------------------------------*/
|
|
41
|
-
export default class ServerResponse<
|
|
68
|
+
export default class ServerResponse<
|
|
69
|
+
TRouter extends ServerRouter,
|
|
70
|
+
TRequestContext = TRouterContext<ServerRouter>,
|
|
71
|
+
TData extends TResponseData = TResponseData
|
|
72
|
+
> extends BaseResponse<TData, ServerRequest<TRouter>> {
|
|
42
73
|
|
|
74
|
+
// Services
|
|
75
|
+
public app: Application;
|
|
76
|
+
public router: ServerRouter;
|
|
77
|
+
|
|
78
|
+
// Response metadata
|
|
43
79
|
public statusCode: number = 200;
|
|
44
80
|
public headers: {[cle: string]: string} = {}
|
|
45
|
-
private triggers: {[cle: string]: any[]} = {}
|
|
46
81
|
public cookie: express.Response["cookie"];
|
|
47
82
|
|
|
83
|
+
// If data was provided by at lead one controller
|
|
48
84
|
public wasProvided = false;
|
|
49
85
|
|
|
50
|
-
public constructor( request: ServerRequest ) {
|
|
86
|
+
public constructor( request: ServerRequest<TRouter> ) {
|
|
51
87
|
|
|
52
88
|
super(request);
|
|
53
89
|
|
|
54
90
|
this.cookie = this.request.res.cookie.bind(this.request.res);
|
|
91
|
+
|
|
92
|
+
this.router = request.router;
|
|
93
|
+
this.app = this.router.app;
|
|
55
94
|
}
|
|
56
95
|
|
|
57
|
-
public async runController( route: TRoute, additionnalData
|
|
96
|
+
public async runController( route: TRoute, additionnalData: {} = {} ) {
|
|
58
97
|
|
|
59
98
|
this.route = route;
|
|
60
99
|
|
|
61
|
-
|
|
100
|
+
// Create response context for controllers
|
|
101
|
+
const context = this.createContext(route);
|
|
102
|
+
|
|
103
|
+
// Run controller
|
|
104
|
+
const response = await this.route.controller( context );
|
|
105
|
+
|
|
106
|
+
// Handle response type
|
|
107
|
+
if (response === undefined)
|
|
108
|
+
return;
|
|
109
|
+
|
|
110
|
+
// No need to process the response
|
|
111
|
+
if (response instanceof ServerResponse)
|
|
112
|
+
return;
|
|
113
|
+
// Render react page to html
|
|
114
|
+
else if (response instanceof Page)
|
|
115
|
+
await this.render(response, context, additionnalData);
|
|
116
|
+
// Return HTML
|
|
117
|
+
else if (typeof response === 'string' && this.route.options.accept === 'html')
|
|
118
|
+
await this.html(response);
|
|
119
|
+
// Return JSON
|
|
120
|
+
else
|
|
121
|
+
await this.json(response);
|
|
122
|
+
}
|
|
62
123
|
|
|
63
|
-
|
|
124
|
+
/*----------------------------------
|
|
125
|
+
- INTERNAL
|
|
126
|
+
----------------------------------*/
|
|
64
127
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
await page.fetchData();
|
|
68
|
-
if (additionnalData !== undefined) // Example: error message for error pages
|
|
69
|
-
page.data = { ...page.data, ...additionnalData }
|
|
128
|
+
// Start controller services
|
|
129
|
+
private createContext( route: TRoute ): TRequestContext {
|
|
70
130
|
|
|
71
|
-
// Render page
|
|
72
|
-
const document = await render.page(page, this, context);
|
|
73
|
-
this.html(document);
|
|
74
131
|
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
this.request.res.setHeader("Expires", "0");
|
|
132
|
+
const contextServices: Partial<TRouterContextServices<TRouter>> = {}
|
|
133
|
+
for (const serviceName in this.router.services) {
|
|
78
134
|
|
|
79
|
-
|
|
135
|
+
const routerService = this.router.services[serviceName];
|
|
136
|
+
contextServices[ serviceName ] = routerService.requestService( this.request );
|
|
80
137
|
|
|
81
|
-
|
|
82
|
-
if (this.route.options.form !== undefined) {
|
|
83
|
-
const formData = await this.request.schema.validate( this.route.options.form );
|
|
84
|
-
console.log("FORM DATA VIA RESPONSE", formData);
|
|
85
|
-
this.request.data = { ...this.request.data, ...formData }
|
|
86
|
-
}
|
|
138
|
+
}
|
|
87
139
|
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
140
|
+
const context: TRequestContext = {
|
|
141
|
+
// Router context
|
|
142
|
+
app: this.app,
|
|
143
|
+
context: undefined as TRequestContext,
|
|
144
|
+
request: this.request,
|
|
145
|
+
response: this,
|
|
146
|
+
route: route,
|
|
147
|
+
api: this.request.api,
|
|
148
|
+
// Router services
|
|
149
|
+
...(contextServices as TRouterContextServices<TRouter>),
|
|
150
|
+
}
|
|
92
151
|
|
|
93
|
-
|
|
94
|
-
const returnedData = await this.route.controller(this.request, controllerData);
|
|
152
|
+
context.context = context;
|
|
95
153
|
|
|
96
|
-
|
|
97
|
-
if (returnedData !== undefined && !(returnedData instanceof ServerResponse)) {
|
|
98
|
-
if (typeof returnedData === 'string' && this.route.options.accept === 'html')
|
|
99
|
-
await this.html(returnedData);
|
|
100
|
-
else
|
|
101
|
-
await this.json(returnedData);
|
|
102
|
-
}
|
|
103
|
-
}
|
|
154
|
+
return context;
|
|
104
155
|
}
|
|
105
156
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
157
|
+
public async forSsr( page: Page<TRouter> ): Promise<TBasicSSrData> {
|
|
158
|
+
|
|
159
|
+
const customSsrData = await this.router.config.ssrData(this.request);
|
|
109
160
|
|
|
110
|
-
public async forSsr(page: PageResponse): Promise<TSsrData> {
|
|
111
161
|
return {
|
|
112
162
|
request: {
|
|
113
163
|
id: this.request.id,
|
|
114
164
|
data: this.request.data,
|
|
115
165
|
},
|
|
116
166
|
page: {
|
|
117
|
-
|
|
167
|
+
chunkId: page.chunkId,
|
|
118
168
|
data: page.data
|
|
119
169
|
},
|
|
120
|
-
|
|
121
|
-
user: this.request.user
|
|
122
|
-
? await filter(this.request.user, $.auth.SsrMask, this.request.user)
|
|
123
|
-
: null
|
|
170
|
+
...customSsrData
|
|
124
171
|
}
|
|
125
172
|
}
|
|
126
173
|
|
|
@@ -138,13 +185,34 @@ export default class ServerResponse<TData extends TResponseData = TResponseData>
|
|
|
138
185
|
- DATA RESPONSE
|
|
139
186
|
----------------------------------*/
|
|
140
187
|
|
|
188
|
+
public async render( page: Page, context: TRouterContext, additionnalData: {} ) {
|
|
189
|
+
|
|
190
|
+
// Set page in context for the client side
|
|
191
|
+
context.page = page;
|
|
192
|
+
|
|
193
|
+
// Prepare page & fetch data
|
|
194
|
+
page.data = await page.fetchData();
|
|
195
|
+
if (additionnalData !== undefined) // Example: error message for error pages
|
|
196
|
+
page.data = { ...page.data, ...additionnalData }
|
|
197
|
+
|
|
198
|
+
// Render page
|
|
199
|
+
await this.router.runHook('render', page);
|
|
200
|
+
const document = await page.render();
|
|
201
|
+
this.html(document);
|
|
202
|
+
|
|
203
|
+
// Never put html in the cache
|
|
204
|
+
// Because assets urls need to be updated when their hash has been changed by a release
|
|
205
|
+
this.request.res.setHeader("Expires", "0");
|
|
206
|
+
|
|
207
|
+
}
|
|
208
|
+
|
|
141
209
|
public async json(data?: any, mask?: string) {
|
|
142
210
|
|
|
143
|
-
// RAPPEL: On
|
|
211
|
+
// RAPPEL: On jsonMask aussi les requetes internes, car leurs données seront imprimées au SSR pour le contexte client
|
|
144
212
|
// filtreApi vérifie systèmatiquement si la donnée a été filtrée
|
|
145
213
|
// NOTE: On évite le filtrage sans masque spécifié (performances + risques erreurs)
|
|
146
214
|
if (mask !== undefined)
|
|
147
|
-
data = await
|
|
215
|
+
data = await jsonMask(data, mask, this.request.user);
|
|
148
216
|
|
|
149
217
|
this.headers['Content-Type'] = 'application/json';
|
|
150
218
|
this.data = this.request.isVirtual ? data : JSON.stringify(data);
|
|
@@ -170,17 +238,15 @@ export default class ServerResponse<TData extends TResponseData = TResponseData>
|
|
|
170
238
|
// TODO: https://github.com/adonisjs/http-server/blob/develop/src/Response/index.ts#L430
|
|
171
239
|
public file( fichier: string ) {
|
|
172
240
|
|
|
173
|
-
const app = this.request.router.app;
|
|
174
|
-
|
|
175
241
|
// Securité
|
|
176
242
|
if (fichier.includes('..'))
|
|
177
243
|
throw new Forbidden("Disallowed");
|
|
178
244
|
|
|
179
245
|
// Force absolute path
|
|
180
|
-
if (!fichier.startsWith( app.path.root ))
|
|
246
|
+
if (!fichier.startsWith( this.app.path.root ))
|
|
181
247
|
fichier = fichier[0] === '/'
|
|
182
|
-
? app.path.root + '/bin' + fichier
|
|
183
|
-
: app.path.data + '/' + fichier;
|
|
248
|
+
? this.app.path.root + '/bin' + fichier
|
|
249
|
+
: this.app.path.data + '/' + fichier;
|
|
184
250
|
|
|
185
251
|
console.log(`[response] Serving file "${fichier}"`);
|
|
186
252
|
|
|
File without changes
|
|
File without changes
|