5htp-core 0.5.0 → 0.5.1-2
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 +1 -1
- package/src/client/assets/css/components/button.less +0 -1
- package/src/client/assets/css/core.less +5 -3
- package/src/client/assets/css/text/icons.less +4 -1
- package/src/client/assets/css/text/text.less +1 -1
- package/src/client/assets/css/text/titres.less +4 -3
- package/src/client/assets/css/theme.less +2 -1
- package/src/client/assets/css/utils/layouts.less +1 -0
- package/src/client/assets/css/utils/sizing.less +15 -15
- package/src/client/components/Dialog/Manager.tsx +1 -3
- package/src/client/components/Dialog/index.less +6 -9
- package/src/client/components/Form.ts +62 -31
- package/src/client/components/Select/index.tsx +1 -1
- package/src/client/components/Table/index.tsx +40 -6
- package/src/client/components/button.tsx +40 -31
- package/src/client/components/containers/Popover/getPosition.ts +48 -28
- package/src/client/components/containers/Popover/index.tsx +9 -3
- package/src/client/components/inputv3/Rte/Editor.tsx +64 -5
- package/src/client/components/inputv3/Rte/ToolbarPlugin/BlockFormat.tsx +1 -1
- package/src/client/components/inputv3/Rte/index.tsx +11 -76
- package/src/client/components/inputv3/Rte/plugins/DraggableBlockPlugin/index.css +1 -1
- package/src/client/components/inputv3/Rte/style.less +1 -25
- package/src/client/components/inputv3/base.tsx +1 -1
- package/src/client/components/inputv3/index.tsx +7 -1
- package/src/client/services/router/components/Link.tsx +9 -5
- package/src/client/services/router/components/router.tsx +4 -3
- package/src/client/services/router/index.tsx +2 -1
- package/src/client/utils/dom.ts +1 -1
- package/src/common/errors/index.tsx +19 -7
- package/src/common/router/index.ts +2 -0
- package/src/common/validation/validators.ts +1 -0
- package/src/server/services/auth/index.ts +0 -9
- package/src/server/services/database/index.ts +2 -2
- package/src/server/services/router/http/index.ts +8 -11
- package/src/server/services/router/index.ts +62 -56
- package/src/server/services/router/request/index.ts +11 -0
- package/src/server/services/router/response/index.ts +21 -0
- package/src/server/services/router/response/page/document.tsx +1 -4
- package/src/server/services/router/response/page/index.tsx +4 -0
|
@@ -143,7 +143,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
143
143
|
query.then = (cb: (data: any) => void) => query().then(cb);
|
|
144
144
|
|
|
145
145
|
query.first = <TRowData extends TObjetDonnees = {}>(opts: TSelectQueryOptions = {}) => this.first<TRowData>(string, opts);
|
|
146
|
-
query.firstOrFail = (message
|
|
146
|
+
query.firstOrFail = (message: string, opts: TQueryOptions = {}) => this.firstOrFail<TRowData>(string, message, opts);
|
|
147
147
|
|
|
148
148
|
query.value = <TValue extends any = number>(opts: TQueryOptions = {}) => this.selectVal<TValue>(string, opts);
|
|
149
149
|
|
|
@@ -283,7 +283,7 @@ export default class SQL extends Service<Config, Hooks, Application, Services> {
|
|
|
283
283
|
return resultatRequetes[0] || null;
|
|
284
284
|
});
|
|
285
285
|
|
|
286
|
-
public firstOrFail = <TRowData extends TObjetDonnees = {}>(query: string, message
|
|
286
|
+
public firstOrFail = <TRowData extends TObjetDonnees = {}>(query: string, message: string, opts: TSelectQueryOptions = {}): Promise<TRowData> =>
|
|
287
287
|
this.select(query, opts).then((resultatRequetes: any) => {
|
|
288
288
|
|
|
289
289
|
if (resultatRequetes.length === 0)
|
|
@@ -49,7 +49,8 @@ export type Config = {
|
|
|
49
49
|
images?: string[],
|
|
50
50
|
scripts: string[],
|
|
51
51
|
},
|
|
52
|
-
cors?: CorsOptions
|
|
52
|
+
cors?: CorsOptions,
|
|
53
|
+
helmet?: Parameters<typeof helmet>[0]
|
|
53
54
|
}
|
|
54
55
|
|
|
55
56
|
export type Hooks = {
|
|
@@ -100,7 +101,7 @@ export default class HttpServer {
|
|
|
100
101
|
// Config
|
|
101
102
|
routes.set('trust proxy', 1); // Indique qu'on est sous le proxy apache
|
|
102
103
|
// Diverses protections (dont le disable x-powered-by)
|
|
103
|
-
routes.use(helmet());
|
|
104
|
+
routes.use( helmet(this.config.helmet) );
|
|
104
105
|
|
|
105
106
|
/*----------------------------------
|
|
106
107
|
- FICHIERS STATIQUES
|
|
@@ -162,16 +163,12 @@ export default class HttpServer {
|
|
|
162
163
|
|
|
163
164
|
// Décodage des données post
|
|
164
165
|
express.json({
|
|
165
|
-
|
|
166
|
-
// NOTE: Encore nécessaire ? Les webhooks stripe & bitgo n'étant plus utilisés
|
|
167
|
-
// Because Stripe needs the raw body, we compute it but only when hitting the Stripe callback URL.
|
|
168
|
-
/*verify: function (req: Request, res: Response, buf: Buffer) {
|
|
169
|
-
if (req.originalUrl.startsWith('/api/paiement/impact/stripe'))
|
|
170
|
-
//req.rawBody = buf.toString();
|
|
171
|
-
},*/
|
|
172
|
-
|
|
173
166
|
// TODO: prendre en considération les upload de fichiers
|
|
174
|
-
limit: '2mb'
|
|
167
|
+
limit: '2mb',
|
|
168
|
+
verify: (req, res, buf, encoding) => {
|
|
169
|
+
// Store the raw request body so we can access it later
|
|
170
|
+
req.rawBody = buf;
|
|
171
|
+
}
|
|
175
172
|
}),
|
|
176
173
|
|
|
177
174
|
// Permet de receptionner les données multipart (req.body + req.files)
|
|
@@ -12,6 +12,7 @@
|
|
|
12
12
|
// Node
|
|
13
13
|
// Npm
|
|
14
14
|
import type express from 'express';
|
|
15
|
+
import type { Request, Response, NextFunction } from 'express';
|
|
15
16
|
import { v4 as uuid } from 'uuid';
|
|
16
17
|
import type { GlobImportedWithMetas } from 'babel-plugin-glob-import';
|
|
17
18
|
|
|
@@ -265,7 +266,31 @@ export default class ServerRouter<
|
|
|
265
266
|
public post = (...args: TApiRegisterArgs<this>) => this.registerApi('POST', ...args);
|
|
266
267
|
public put = (...args: TApiRegisterArgs<this>) => this.registerApi('PUT', ...args);
|
|
267
268
|
public patch = (...args: TApiRegisterArgs<this>) => this.registerApi('PATCH', ...args);
|
|
268
|
-
public delete = (...args: TApiRegisterArgs<this>) => this.registerApi('DELETE', ...args)
|
|
269
|
+
public delete = (...args: TApiRegisterArgs<this>) => this.registerApi('DELETE', ...args);
|
|
270
|
+
|
|
271
|
+
public express(
|
|
272
|
+
middleware: (
|
|
273
|
+
req: Request,
|
|
274
|
+
res: Response,
|
|
275
|
+
next: NextFunction,
|
|
276
|
+
requestContext: TRouterContext
|
|
277
|
+
) => void
|
|
278
|
+
) {
|
|
279
|
+
return (context: TRouterContext) => new Promise((resolve) => {
|
|
280
|
+
|
|
281
|
+
context.request.res.on('finish', function() {
|
|
282
|
+
//console.log('the response has been sent', request.res.statusCode);
|
|
283
|
+
resolve(true);
|
|
284
|
+
});
|
|
285
|
+
|
|
286
|
+
middleware(
|
|
287
|
+
context.request.req,
|
|
288
|
+
context.request.res,
|
|
289
|
+
() => { resolve(true); },
|
|
290
|
+
context
|
|
291
|
+
)
|
|
292
|
+
})
|
|
293
|
+
}
|
|
269
294
|
|
|
270
295
|
protected registerApi(method: TRouteHttpMethod, ...args: TApiRegisterArgs<this>): this {
|
|
271
296
|
|
|
@@ -414,22 +439,6 @@ declare type Routes = {
|
|
|
414
439
|
// Hook
|
|
415
440
|
await this.runHook('request', request);
|
|
416
441
|
|
|
417
|
-
// TODO: move to tracking
|
|
418
|
-
/*const now = new Date;
|
|
419
|
-
|
|
420
|
-
// Identify Guest & create log entry
|
|
421
|
-
const username = request.user?.name;
|
|
422
|
-
let clientId: string = request.cookies.clientId;
|
|
423
|
-
const newClient = !(typeof clientId === 'string' && clientId.length <= 39)
|
|
424
|
-
if (newClient) {
|
|
425
|
-
clientId = uuid();
|
|
426
|
-
res.cookie('clientId', clientId, { expires: new Date(253402300000000) }); // Never expires
|
|
427
|
-
}
|
|
428
|
-
|
|
429
|
-
const keepLogs = request.ip !== '86.76.176.80';
|
|
430
|
-
if (!keepLogs)
|
|
431
|
-
requestId = 'admin';*/
|
|
432
|
-
|
|
433
442
|
// Create request context so we can access request context across all the request-triggered libs
|
|
434
443
|
context.run({ channelType: 'request', channelId: requestId }, async () => {
|
|
435
444
|
|
|
@@ -448,40 +457,17 @@ declare type Routes = {
|
|
|
448
457
|
response = await this.handleError(e, request);
|
|
449
458
|
}
|
|
450
459
|
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
id: clientId,
|
|
462
|
-
ip: request.ip,
|
|
463
|
-
user: username,
|
|
464
|
-
device: request.deviceString(),
|
|
465
|
-
meet: now,
|
|
466
|
-
activity: now,
|
|
467
|
-
});
|
|
468
|
-
|
|
469
|
-
console.request({
|
|
470
|
-
|
|
471
|
-
id: requestId,
|
|
472
|
-
date: now,
|
|
473
|
-
|
|
474
|
-
method: request.method,
|
|
475
|
-
url: request.path,
|
|
476
|
-
data: request.data,
|
|
477
|
-
|
|
478
|
-
ip: request.ip,
|
|
479
|
-
user: request.user?.name,
|
|
480
|
-
clientId,
|
|
460
|
+
if (!res.headersSent) {
|
|
461
|
+
// Status
|
|
462
|
+
res.status(response.statusCode);
|
|
463
|
+
// Headers
|
|
464
|
+
res.header(response.headers);
|
|
465
|
+
// Data
|
|
466
|
+
res.send(response.data);
|
|
467
|
+
} else if (response.data !== 'true') {
|
|
468
|
+
throw new Error("Can't return data from the controller since response has already been sent via express.");
|
|
469
|
+
}
|
|
481
470
|
|
|
482
|
-
statusCode: response.statusCode,
|
|
483
|
-
time: Date.now() - now.valueOf()
|
|
484
|
-
});*/
|
|
485
471
|
});
|
|
486
472
|
}
|
|
487
473
|
|
|
@@ -502,12 +488,15 @@ declare type Routes = {
|
|
|
502
488
|
|
|
503
489
|
public async resolve(request: ServerRequest<this>): Promise<ServerResponse<this>> {
|
|
504
490
|
|
|
505
|
-
|
|
491
|
+
const logId = LogPrefix + ' ' + (request.isVirtual ? ' ---- ' : '') + request.ip + ' ' + request.method + ' ' + request.domain + ' ' + request.path;
|
|
492
|
+
console.info(logId);
|
|
493
|
+
const timeStart = Date.now();
|
|
506
494
|
|
|
507
495
|
if (this.status === 'starting') {
|
|
508
496
|
console.log(LogPrefix, `Waiting for servert to be resdy before resolving request`);
|
|
509
497
|
await this.started;
|
|
510
498
|
}
|
|
499
|
+
|
|
511
500
|
try {
|
|
512
501
|
|
|
513
502
|
const response = new ServerResponse<this>(request);
|
|
@@ -530,12 +519,14 @@ declare type Routes = {
|
|
|
530
519
|
|
|
531
520
|
// Run on resolution hooks. Ex: authentication check
|
|
532
521
|
await this.runHook('resolved', route);
|
|
522
|
+
const timeEndResolving = Date.now();
|
|
533
523
|
|
|
534
524
|
// Create response
|
|
535
525
|
await response.runController(route);
|
|
536
|
-
if (response.wasProvided)
|
|
537
|
-
|
|
526
|
+
if (response.wasProvided) {
|
|
527
|
+
this.printTakenTime(logId, timeStart, timeEndResolving);
|
|
538
528
|
return response;
|
|
529
|
+
}
|
|
539
530
|
}
|
|
540
531
|
|
|
541
532
|
throw new NotFound();
|
|
@@ -551,10 +542,20 @@ declare type Routes = {
|
|
|
551
542
|
error.details.origin = errOrigin;
|
|
552
543
|
}
|
|
553
544
|
|
|
545
|
+
this.printTakenTime(logId, timeStart);
|
|
554
546
|
throw error;
|
|
555
547
|
}
|
|
556
548
|
}
|
|
557
549
|
|
|
550
|
+
private printTakenTime = (logId: string, timeStart: number, timeEndResolving?: number) => {
|
|
551
|
+
|
|
552
|
+
if (this.app.env.name === 'server') return;
|
|
553
|
+
|
|
554
|
+
console.log(logId + ' ' + Math.round(Date.now() - timeStart) + 'ms' +
|
|
555
|
+
(timeEndResolving === undefined ? '' : ' | Routing: ' + Math.round(timeEndResolving - timeStart))
|
|
556
|
+
);
|
|
557
|
+
}
|
|
558
|
+
|
|
558
559
|
private async resolveApiBatch( fetchers: TFetcherList, request: ServerRequest<this> ) {
|
|
559
560
|
|
|
560
561
|
// TODO: use api.fetchSync instead
|
|
@@ -601,9 +602,14 @@ declare type Routes = {
|
|
|
601
602
|
if (this.app.env.profile === 'prod')
|
|
602
603
|
e.message = "We encountered an internal error, and our team has just been notified. Sorry for the inconvenience.";
|
|
603
604
|
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
605
|
+
} else {
|
|
606
|
+
|
|
607
|
+
// For debugging HTTP errors
|
|
608
|
+
if (this.app.env.profile === "dev")
|
|
609
|
+
console.warn(e);
|
|
610
|
+
|
|
611
|
+
await this.app.runHook('error.' + code, e, request);
|
|
612
|
+
}
|
|
607
613
|
|
|
608
614
|
// Return error based on the request format
|
|
609
615
|
if (request.accepts("html")) {
|
|
@@ -135,6 +135,17 @@ export default class ServerRequest<
|
|
|
135
135
|
return locale ? locale.toUpperCase() : 'EN'
|
|
136
136
|
}
|
|
137
137
|
|
|
138
|
+
public cookie( key: string, consume: boolean = false ) {
|
|
139
|
+
|
|
140
|
+
const value = this.req.cookies[ key ];
|
|
141
|
+
|
|
142
|
+
if (consume)
|
|
143
|
+
this.res.clearCookie(key);
|
|
144
|
+
|
|
145
|
+
return value;
|
|
146
|
+
|
|
147
|
+
}
|
|
148
|
+
|
|
138
149
|
/*----------------------------------
|
|
139
150
|
- TESTS
|
|
140
151
|
----------------------------------*/
|
|
@@ -81,6 +81,8 @@ export default class ServerResponse<
|
|
|
81
81
|
public statusCode: number = 200;
|
|
82
82
|
public headers: {[cle: string]: string} = {}
|
|
83
83
|
public cookie: express.Response["cookie"];
|
|
84
|
+
public clearCookie: express.Response["clearCookie"];
|
|
85
|
+
public canonicalUrl: URL;
|
|
84
86
|
|
|
85
87
|
// If data was provided by at lead one controller
|
|
86
88
|
public wasProvided = false;
|
|
@@ -90,15 +92,22 @@ export default class ServerResponse<
|
|
|
90
92
|
super(request);
|
|
91
93
|
|
|
92
94
|
this.cookie = this.request.res.cookie.bind(this.request.res);
|
|
95
|
+
this.clearCookie = this.request.res.clearCookie.bind(this.request.res);
|
|
93
96
|
|
|
94
97
|
this.router = request.router;
|
|
95
98
|
this.app = this.router.app;
|
|
99
|
+
|
|
100
|
+
this.canonicalUrl = new URL(request.url);
|
|
101
|
+
this.canonicalUrl.search = '';
|
|
96
102
|
}
|
|
97
103
|
|
|
98
104
|
public async runController( route: TAnyRoute, additionnalData: {} = {} ) {
|
|
99
105
|
|
|
100
106
|
this.route = route;
|
|
101
107
|
|
|
108
|
+
// Update canonical url
|
|
109
|
+
this.updateCanonicalUrl(route);
|
|
110
|
+
|
|
102
111
|
// Create response context for controllers
|
|
103
112
|
const context = await this.createContext(route);
|
|
104
113
|
|
|
@@ -138,6 +147,18 @@ export default class ServerResponse<
|
|
|
138
147
|
this.router.cache[ chunkId ] = this.data;
|
|
139
148
|
}
|
|
140
149
|
|
|
150
|
+
private updateCanonicalUrl( route: TAnyRoute ) {
|
|
151
|
+
|
|
152
|
+
if (!route.options.canonicalParams)
|
|
153
|
+
return;
|
|
154
|
+
|
|
155
|
+
for (const key of route.options.canonicalParams) {
|
|
156
|
+
const paramValue = this.request.data[ key ];
|
|
157
|
+
if (paramValue !== undefined)
|
|
158
|
+
this.canonicalUrl.searchParams.set(key, paramValue);
|
|
159
|
+
}
|
|
160
|
+
}
|
|
161
|
+
|
|
141
162
|
/*----------------------------------
|
|
142
163
|
- INTERNAL
|
|
143
164
|
----------------------------------*/
|
|
@@ -57,9 +57,6 @@ export default class DocumentRenderer<TRouter extends Router> {
|
|
|
57
57
|
|
|
58
58
|
public async page( html: string, page: Page, response: ServerResponse<TRouter> ) {
|
|
59
59
|
|
|
60
|
-
// TODO: can be customized via page / route config
|
|
61
|
-
const canonicalUrl = response.request.req.url;
|
|
62
|
-
|
|
63
60
|
let attrsBody = {
|
|
64
61
|
className: [...page.bodyClass].join(' '),
|
|
65
62
|
};
|
|
@@ -94,7 +91,7 @@ export default class DocumentRenderer<TRouter extends Router> {
|
|
|
94
91
|
{/* Page */}
|
|
95
92
|
<title>{page.title}</title>
|
|
96
93
|
<meta content={page.description} name="description" />
|
|
97
|
-
<link rel="canonical" href={canonicalUrl} />
|
|
94
|
+
<link rel="canonical" href={response.canonicalUrl} />
|
|
98
95
|
|
|
99
96
|
{/* SEO, social medias, OG tags, ... */}
|
|
100
97
|
{page.head.map(({ $, ...attrs }) => (
|
|
@@ -120,8 +120,12 @@ export default class ServerPage<TRouter extends Router = Router> extends PageRes
|
|
|
120
120
|
|
|
121
121
|
private buildMetas() {
|
|
122
122
|
|
|
123
|
+
const shouldIndex = this.context.response.statusCode < 300;
|
|
124
|
+
|
|
123
125
|
const metas = {
|
|
124
126
|
|
|
127
|
+
robots: shouldIndex ? 'index' : 'noindex',
|
|
128
|
+
|
|
125
129
|
'og:type': 'website',
|
|
126
130
|
'og:locale': this.app.identity.locale,
|
|
127
131
|
'og:site_name': this.app.identity.web.title,
|