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
@@ -0,0 +1,194 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import renderToString from "preact-render-to-string";
8
+ const safeStringify = require('fast-safe-stringify'); // remplace les références circulairs par un [Circular]
9
+
10
+ // Core
11
+ import type { default as Router, Response as ServerResponse } from "@server/services/router";
12
+ import type Page from '.';
13
+
14
+ /*----------------------------------
15
+ - TYPES
16
+ ----------------------------------*/
17
+
18
+
19
+ /*----------------------------------
20
+ - SERVICE
21
+ ----------------------------------*/
22
+ export default class DocumentRenderer {
23
+
24
+ public constructor(
25
+ public router: Router,
26
+ public app = router.app
27
+ ) {
28
+
29
+ }
30
+
31
+ public staticDocument() {
32
+ const routesForClient = JSON.stringify( this.router.ssrRoutes );
33
+ return renderToString(
34
+ <html lang="en">
35
+ <head>
36
+ {/* Format */}
37
+ <meta charSet="utf-8" />
38
+ <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
39
+
40
+ {/* CSS */}
41
+ <link rel="stylesheet" type="text/css" href="/public/icons.css" />
42
+ <link rel="preload" href="/public/client.css" as="style" />
43
+ <link rel="stylesheet" type="text/css" href="/public/client.css" />
44
+
45
+ {/* JS */}
46
+ <script type="text/javascript" dangerouslySetInnerHTML={{
47
+ __html: `window.routes=${routesForClient};` + (this.app.env.profile === 'dev' ? 'window.dev = true;' : '')
48
+ }} />
49
+ <link rel="preload" href="/public/client.js" as="script" />
50
+ <script defer type="text/javascript" src="/public/client.js" />
51
+
52
+ </head>
53
+ <body></body>
54
+ </html>
55
+ );
56
+ }
57
+
58
+ public async page( html: string, page: Page, response: ServerResponse<Router> ) {
59
+
60
+ const fullUrl = this.router.http.publicUrl + response.request.path;
61
+
62
+ let attrsBody = {
63
+ className: [...page.bodyClass].join(' '),
64
+ };
65
+
66
+ return renderToString(
67
+ <html lang="en" {...(page.amp ? { amp: "true" } : {})}>
68
+ <head>
69
+ {/* Format */}
70
+ <meta charSet="utf-8" />
71
+ {page.amp && ( // As a best practice, you should include the script as early as possible in the <head>.
72
+ <script async={true} src="https://cdn.ampproject.org/v0.js"></script>
73
+ )}
74
+ <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
75
+ <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
76
+ {!page.amp && page.amp && (
77
+ <link rel="amphtml" href={fullUrl + '/amp'} />
78
+ )}
79
+
80
+ {/* Basique*/}
81
+ <meta content={this.app.identity.web.title} name="apple-mobile-web-app-title" />
82
+ <title>{page.title}</title>
83
+ <meta content={page.description} name="description" />
84
+ <link rel="canonical" href={fullUrl} />
85
+
86
+ {this.metas()}
87
+
88
+ {this.styles( page )}
89
+
90
+ {await this.scripts( response, page )}
91
+
92
+ {/* Rich Snippets: https://schema.org/docs/full.html + https://jsonld.com/ */}
93
+ {/* <script type="application/ld+json" dangerouslySetInnerHTML={{
94
+ __html: JSON.stringify( schemaGenerator(page, route) )
95
+ }}/> */}
96
+
97
+ </head>
98
+ <body {...attrsBody} dangerouslySetInnerHTML={{ __html: html }}></body>
99
+ </html>
100
+ )
101
+ }
102
+
103
+ private metas() {
104
+ return <>
105
+ {/* Réseaux sociaux */}
106
+ {/*page.metas.metasAdditionnelles && Object.entries(page.metas.metasAdditionnelles).map(
107
+ ([ cle, val ]: [ string, string ]) => (
108
+ <meta name={cle} content={val} />
109
+ )
110
+ )*/}
111
+
112
+ {/* Mobile */}
113
+ <meta name="theme-color" content={this.app.identity.maincolor} />
114
+ <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
115
+ <meta name="apple-mobile-web-app-capable" content="yes" />
116
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
117
+
118
+ {/* Identité */}
119
+ <meta name="mobile-web-app-capable" content="yes" />
120
+ <meta name="application-name" content={this.app.identity.web.title} />
121
+ <meta name="type" content="website" />
122
+ {/*app.identity.social?.facebook?.appId && (
123
+ <meta content={app.identity.social?.facebook?.appId} property="fb:appid" />
124
+ )*/}
125
+
126
+ {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
127
+ {/*<link rel="manifest" href={RES['manifest.json']} />*/}
128
+ <link rel="shortcut icon" href="/public/app/favicon.ico" />
129
+ <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
130
+ <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
131
+ <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
132
+ <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
133
+ </>
134
+ }
135
+
136
+ private styles( page ) {
137
+ return <>
138
+ <link rel="stylesheet" type="text/css" href="/public/icons.css" />
139
+ <link rel="preload" href="/public/client.css" as="style" />
140
+ <link rel="stylesheet" type="text/css" href="/public/client.css" />
141
+
142
+ {page.style.map( style => 'url' in style ? <>
143
+ <link rel="preload" href={style.url} as="style" />
144
+ <link rel="stylesheet" type="text/css" href={style.url} />
145
+ </> : <>
146
+ <style id={style.id} dangerouslySetInnerHTML={{ __html: style.inline }} />
147
+ </>)}
148
+
149
+ {/* Sera remplacé par la chaine exacte après renderToStaticMarkup */}
150
+ {page.amp && (<style amp-boilerplate=""></style>)}
151
+ </>
152
+ }
153
+
154
+ private async scripts( response, page ) {
155
+
156
+ const ssrData = safeStringify( await response.forSsr(page) );
157
+
158
+ const routesForClient = JSON.stringify( this.router.ssrRoutes );
159
+
160
+ return <>
161
+ {/* JS */}
162
+ {!page.amp && (
163
+ <script type="text/javascript" dangerouslySetInnerHTML={{
164
+ __html: `window.ssr=${ssrData}; window.routes=${routesForClient};` + (
165
+ this.app.env.profile === 'dev' ? 'window.dev = true;' : ''
166
+ )
167
+ }} />
168
+ )}
169
+
170
+ <link rel="preload" href="/public/client.js" as="script" />
171
+ <script defer type="text/javascript" src="/public/client.js" />
172
+
173
+ {page.scripts.map( script => 'url' in script ? <>
174
+ <link rel="preload" href={script.url} as="script" />
175
+ <script type="text/javascript" src={script.url} {...script.attrs || {}} />
176
+ </> : <>
177
+ <script type="text/javascript" {...script.attrs || {}} id={script.id} dangerouslySetInnerHTML={{ __html: script.inline }} />
178
+ </>)}
179
+
180
+ {/* Initialize GTM & GA for pagechange events */}
181
+ {/* TODO: append via the metrics module */}
182
+ {/*<script async src={"https://www.googletagmanager.com/gtag/js?id=" + this.app.config.tracking.ga.pub}></script>
183
+ <script dangerouslySetInnerHTML={{ __html: `
184
+ window.dataLayer = window.dataLayer || [];
185
+ function gtag(){dataLayer.push(arguments);}
186
+ gtag('js', new Date());
187
+
188
+ gtag('config', '${this.app.config.tracking.ga.pub}', {
189
+ send_page_view: false
190
+ });
191
+ `}} />*/}
192
+ </>
193
+ }
194
+ }
@@ -0,0 +1,157 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import renderToString from "preact-render-to-string";
8
+ const safeStringify = require('fast-safe-stringify'); // remplace les références circulairs par un [Circular]
9
+
10
+ // Core
11
+ import { default as Router, TRouterContext } from "@server/services/router";
12
+ import type ServerResponse from "@server/services/router/response";
13
+ import type { TRoute } from '@common/router';
14
+ import PageResponse, { TDataProvider, TFrontRenderer } from "@common/router/response/page";
15
+
16
+ // Composants UI
17
+ import App from '@client/app/component';
18
+
19
+ // Caches
20
+ const chunks = require('./chunk-manifest.json');
21
+
22
+ /*----------------------------------
23
+ - TYPES
24
+ ----------------------------------*/
25
+
26
+ /*----------------------------------
27
+ - FONCTION
28
+ ----------------------------------*/
29
+
30
+ export default class Page<TRouter extends Router = Router> extends PageResponse<TRouter> {
31
+
32
+ public constructor(
33
+ public dataProvider: TDataProvider | null,
34
+ public renderer: TFrontRenderer,
35
+ public context: TRouterContext,
36
+
37
+ public route = context.route,
38
+ public router = context.request.router
39
+
40
+ ) {
41
+
42
+ super(dataProvider, renderer, context)
43
+
44
+ }
45
+
46
+ public render(): Promise<string> {
47
+
48
+ // We render page & document separatly,
49
+ // because document needs to access to runtime assigned values
50
+ // Ex: runtime added scripts, title, metas, ....
51
+
52
+ const html = renderToString(
53
+ <App {...this.context} />
54
+ );
55
+
56
+ if (html === undefined)
57
+ throw new Error(`Page HTML is empty (undefined)`);
58
+
59
+ // Un chunk peut regrouper plusieurs fihciers css / js
60
+ // L'id du chunk est injecté depuis le plugin babel
61
+ this.addChunks();
62
+
63
+ /*if (page.classeBody)
64
+ attrsBody.className += ' ' + page.classeBody.join(' ');
65
+
66
+ if (page.theme)
67
+ attrsBody.className += ' ' + page.theme;
68
+
69
+ // L'url canonique doit pointer vers la version html
70
+ if (page.amp && fullUrl.endsWith('/amp'))
71
+ fullUrl = fullUrl.substring(0, fullUrl.length - 4);*/
72
+
73
+ return this.router.render.page(html, this, this.context.response);
74
+ }
75
+
76
+ // Define which chunks (script / style) to load
77
+ private addChunks() {
78
+ const pageChunks = [this.route.options["id"]];
79
+ for (const chunk of pageChunks) {
80
+
81
+ if (!chunk) continue;
82
+
83
+ const assets = chunks[chunk];
84
+ if (!assets) {
85
+ console.warn(`Chunk ${chunk} was not found. Indexed chunks: ${Object.keys(chunks).join(', ')}`);
86
+ continue;
87
+ }
88
+
89
+ for (let i = 0; i < assets.length; i++) {
90
+ const asset = assets[i];
91
+
92
+ if (asset.endsWith('.css'))
93
+ this.style.push({
94
+ id: chunk,
95
+ url: '/public/' + asset
96
+ })
97
+ // Si mode amp, on ne charge pas le JS react (rendu serveur uniquement)
98
+ // Sauf si mode dev, car le hot reload est quand même bien pratique ...
99
+ else if (!this.amp)
100
+ this.scripts.push({
101
+ id: chunk,
102
+ url: '/public/' + asset
103
+ });
104
+ }
105
+
106
+ }
107
+ }
108
+
109
+ private getSocialMetas() {
110
+ /*if (page.metas.imageUrl)
111
+ page.metas.imageUrl = app.web.url + page.metas.imageUrl;
112
+
113
+ if (!page.metas.metasAdditionnelles)
114
+ page.metas.metasAdditionnelles = {};
115
+
116
+ page.metas.metasAdditionnelles = {
117
+ 'og:locale': 'fr_FR',
118
+ 'og:site_name': app.identity.web.title,
119
+ 'og:title': page.title,
120
+ 'og:description': page.description,
121
+ 'og:url': fullUrl,
122
+
123
+ ...(page.metas.imageUrl ? {
124
+ 'og:image': page.metas.imageUrl,
125
+ ...(page.metas.imageX ? {
126
+ 'og:image:width': page.metas.imageX.toString()
127
+ } : {}),
128
+ ...(page.metas.imageY ? {
129
+ 'og:image:height': page.metas.imageY.toString()
130
+ } : {})
131
+ } : {}),
132
+
133
+ 'twitter:card': 'summary_large_image',
134
+ 'twitter:title': page.title,
135
+ 'twitter:description': page.description,
136
+ 'twitter:url': fullUrl,
137
+ 'twitter:text:title': page.title,
138
+
139
+ ...(app.identity.social?.twitter? ? {
140
+ 'twitter:site': `@${app.identity.social?.twitter?}`,
141
+ 'twitter:creator': `@${app.identity.social?.twitter?}`
142
+ } : {}),
143
+
144
+ ...(page.metas.imageUrl ? {
145
+ 'twitter:image': page.metas.imageUrl,
146
+ ...(page.metas.imageX ? {
147
+ 'twitter:image:width': page.metas.imageX.toString()
148
+ } : {}),
149
+ ...(page.metas.imageY ? {
150
+ 'twitter:image:height': page.metas.imageY.toString()
151
+ } : {})
152
+ } : {}),
153
+
154
+ ...page.metas.metasAdditionnelles
155
+ };*/
156
+ }
157
+ }
@@ -0,0 +1,48 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Specific
6
+ import type Application from '@server/app';
7
+ import type { default as Router } from '.';
8
+ import type ServerRequest from './request';
9
+ import type RequestService from './request/service';
10
+
11
+ /*----------------------------------
12
+ - SERVICE
13
+ ----------------------------------*/
14
+ export default abstract class RouterService<TRouter extends Router = Router> {
15
+
16
+ protected router!: TRouter;
17
+ protected app!: Application;
18
+
19
+ public constructor(
20
+
21
+ ) {
22
+
23
+ }
24
+
25
+ /*
26
+ We can't pass the router instance in the routerservice constructor
27
+ Because we instanciate the routerservice in the router instanciation itself
28
+ So if we do:
29
+ public router = new Router(this, {
30
+ ...,
31
+ services: () => ({
32
+
33
+ auth: new AuthService(this.router, this.users),
34
+
35
+ }),
36
+ )
37
+ We would have a cicular reference in typings, which will make router typed as any
38
+ */
39
+ public attach( router: TRouter ) {
40
+ this.router = router;
41
+ this.app = router.app;
42
+ }
43
+
44
+ public abstract register(): Promise<void>;
45
+
46
+ public abstract requestService( request: ServerRequest<TRouter> ): RequestService;
47
+
48
+ }
@@ -0,0 +1,47 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+
7
+ // Specific
8
+ import SchemaValidator, { TFileValidator } from '@common/validation/validators';
9
+
10
+ import Validator, { EXCLUDE_VALUE,} from '@common/validation/validator';
11
+
12
+ import NormalizedFile from '@common/data/file';
13
+
14
+ /*----------------------------------
15
+ - TYPES
16
+ ----------------------------------*/
17
+
18
+
19
+ /*----------------------------------
20
+ - SERVICE
21
+ ----------------------------------*/
22
+ export default class ServerSchemaValidator extends SchemaValidator {
23
+
24
+ public file = ({ ...opts }: TFileValidator & { sharp: any }) =>
25
+ new Validator<NormalizedFile>('file', (val, input, output) => {
26
+
27
+ // Chaine = url ancien fichier = exclusion de la valeur pour conserver l'ancien fichier
28
+ // NOTE: Si la valeur est présente mais undefined, alors on supprimera le fichier
29
+ if (typeof val === 'string')
30
+ return EXCLUDE_VALUE;
31
+
32
+ // Validation universelle
33
+ const file = this.validateFile(opts, val, input, output);
34
+
35
+ if (file === undefined)
36
+ return file;
37
+
38
+ // Process Image
39
+ if (opts.sharp !== undefined) {
40
+
41
+
42
+
43
+ }
44
+
45
+ return file;
46
+ }, opts)
47
+ }
@@ -0,0 +1,55 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import {
7
+ default as Router, RequestService, Request as ServerRequest
8
+ } from '@server/services/router';
9
+
10
+ import ServerSchemaValidator from '.';
11
+
12
+ import Schema, { TSchemaFields, TValidatedData } from '@common/validation/schema';
13
+
14
+ /*----------------------------------
15
+ - TYPES
16
+ ----------------------------------*/
17
+
18
+ /*----------------------------------
19
+ - SERVICE
20
+ ----------------------------------*/
21
+ export default class RequestValidator extends ServerSchemaValidator implements RequestService {
22
+
23
+ public constructor(
24
+ public request: ServerRequest<Router>,
25
+ public router = request.router,
26
+ public app = router.app
27
+ ) {
28
+
29
+ super();
30
+
31
+ }
32
+
33
+ public validate<TSchemaFieldsA extends TSchemaFields>( fields: TSchemaFieldsA ): TValidatedData<TSchemaFieldsA> {
34
+
35
+ console.log("Validate request data:", this.request.data);
36
+
37
+ const schema = new Schema(fields);
38
+
39
+ // Les InputError seront propagées vers le middleware dédié à la gestion des erreurs
40
+ const { values } = schema.validate(
41
+ this.request.data,
42
+ this.request.data,
43
+ {},
44
+ {
45
+ critique: true,
46
+ validationComplete: true,
47
+ avecDependances: false
48
+ },
49
+ []
50
+ );
51
+
52
+ return values;
53
+ }
54
+
55
+ }
@@ -0,0 +1,33 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import {
7
+ default as Router, Request as ServerRequest, Config as RouterConfig,
8
+ RouterService
9
+ } from '@server/services/router';
10
+
11
+ import RequestValidator from './request';
12
+
13
+ /*----------------------------------
14
+ - TYPES
15
+ ----------------------------------*/
16
+
17
+ type TRouterWithSchema<TAuthService extends AuthenticationRouterService> = Router<RouterConfig<{ auth: TAuthService }>>
18
+
19
+ /*----------------------------------
20
+ - SERVICE
21
+ ----------------------------------*/
22
+ export default class AuthenticationRouterService<
23
+ TUser extends {} = {}
24
+ > extends RouterService {
25
+
26
+ public async register() {
27
+
28
+ }
29
+
30
+ public requestService( request: ServerRequest< TRouterWithSchema<this>> ): RequestValidator {
31
+ return new RequestValidator( request );
32
+ }
33
+ }
@@ -3,68 +3,75 @@
3
3
  ----------------------------------*/
4
4
 
5
5
  // Npm
6
- import { Server as WebSocketServer } from 'ws';
6
+ import { Server as WebSocketServer, ServerOptions } from 'ws';
7
7
  import { v4 as uuidv4 } from 'uuid';
8
8
  import { IncomingMessage } from 'http';
9
9
  import cookie from 'cookie';
10
10
 
11
11
  // Core
12
- import SocketScope from './scope';
13
- import app from '@server/app';
14
-
15
- // Services
16
- import '@server/services/http';
12
+ import Application, { Service } from '@server/app';
13
+ import SocketScope, { WebSocket } from './scope';
14
+ export type { WebSocket, default as SocketScope } from './scope';
15
+ import type UsersManagementService from '../users';
17
16
 
18
17
  /*----------------------------------
19
- - SERVICE CONFIG
18
+ - TYPES
20
19
  ----------------------------------*/
21
20
 
22
- export type SocketServiceConfig = {
23
- port: number
24
- }
25
21
 
26
- declare global {
27
- namespace Core {
28
- namespace Config {
29
- interface Services {
30
- socket: SocketServiceConfig
31
- }
32
- }
33
- }
22
+ export type Config<TUser extends {}> = {
23
+ server: ServerOptions["server"],
24
+ users: UsersManagementService<TUser>,
25
+ port: number,
34
26
  }
35
27
 
36
- /*----------------------------------
37
- - TYPES
38
- ----------------------------------*/
28
+ export type Hooks = {
39
29
 
40
- export type { WebSocket, default as SocketScope } from './scope';
30
+ }
41
31
 
42
32
  /*----------------------------------
43
33
  - MANAGER
44
34
  ----------------------------------*/
45
- export class WebSocketCommander {
35
+ export default class WebSocketCommander<
36
+ TUser extends {},
37
+ TConfig extends Config<TUser>= Config<TUser>
38
+ > extends Service<TConfig, Hooks, Application> {
46
39
 
40
+ // Services
47
41
  public ws!: WebSocketServer;
42
+ public users: UsersManagementService<TUser>;
43
+
44
+ // Context
45
+ public scopes: {[path: string]: SocketScope<TUser>} = {}
48
46
 
49
- public scopes: {[path: string]: SocketScope} = {}
47
+ public constructor( app: Application, config: TConfig ) {
48
+ super(app, config);
50
49
 
51
- public constructor() {
52
- app.on('cleanup', async () => {
50
+ this.users = config.users;
51
+ }
52
+
53
+ public async register() {
54
+
55
+ this.app.on('cleanup', async () => {
53
56
  this.closeAll();
54
57
  });
55
- }
56
58
 
57
59
 
60
+ this.users.on('disconnect', async (userId: string) => {
61
+ this.disconnect(userId, 'Logout');
62
+ });
63
+ }
64
+
58
65
  public loading: Promise<void> | undefined = undefined;
59
- public async load() {
66
+ public async start() {
60
67
 
61
68
  console.info(`Loading socket commander`);
62
- this.ws = new WebSocketServer({ server: app.services.http.http })
69
+ this.ws = new WebSocketServer({ server: this.config.server })
63
70
  .on('connection', (socket: WebSocket, req: IncomingMessage) => {
64
71
 
65
72
  // Resolve scope
66
73
  const path = req.url;
67
- let scope: SocketScope | undefined;
74
+ let scope: SocketScope<TUser> | undefined;
68
75
  for (const scopePath in this.scopes)
69
76
  if (path === scopePath) {
70
77
  scope = this.scopes[path];
@@ -105,7 +112,7 @@ export class WebSocketCommander {
105
112
  if (!(path in this.scopes)) {
106
113
 
107
114
  console.info("Registering socket scope:", path);
108
- this.scopes[path] = new SocketScope(path);
115
+ this.scopes[path] = new SocketScope(path, this);
109
116
 
110
117
  }
111
118
 
@@ -135,16 +142,4 @@ export class WebSocketCommander {
135
142
  for (const path in this.scopes)
136
143
  this.scopes[path].close();
137
144
  }
138
- }
139
-
140
- /*----------------------------------
141
- - REGISTER SERVICE
142
- ----------------------------------*/
143
- app.register('socket', WebSocketCommander);
144
- declare global {
145
- namespace Core {
146
- interface Services {
147
- socket: WebSocketCommander;
148
- }
149
- }
150
145
  }