proteum 1.0.0-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.
Files changed (156) hide show
  1. package/.dockerignore +10 -0
  2. package/Rte.zip +0 -0
  3. package/cli/app/config.ts +54 -0
  4. package/cli/app/index.ts +195 -0
  5. package/cli/bin.js +11 -0
  6. package/cli/commands/build.ts +34 -0
  7. package/cli/commands/deploy/app.ts +29 -0
  8. package/cli/commands/deploy/web.ts +60 -0
  9. package/cli/commands/dev.ts +109 -0
  10. package/cli/commands/init.ts +85 -0
  11. package/cli/compiler/client/identite.ts +72 -0
  12. package/cli/compiler/client/index.ts +334 -0
  13. package/cli/compiler/common/babel/index.ts +170 -0
  14. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  15. package/cli/compiler/common/babel/plugins/services.ts +579 -0
  16. package/cli/compiler/common/babel/routes/imports.ts +127 -0
  17. package/cli/compiler/common/babel/routes/routes.ts +1130 -0
  18. package/cli/compiler/common/files/autres.ts +39 -0
  19. package/cli/compiler/common/files/images.ts +35 -0
  20. package/cli/compiler/common/files/style.ts +78 -0
  21. package/cli/compiler/common/index.ts +154 -0
  22. package/cli/compiler/index.ts +532 -0
  23. package/cli/compiler/server/index.ts +211 -0
  24. package/cli/index.ts +189 -0
  25. package/cli/paths.ts +165 -0
  26. package/cli/print.ts +12 -0
  27. package/cli/tsconfig.json +38 -0
  28. package/cli/utils/index.ts +22 -0
  29. package/cli/utils/keyboard.ts +78 -0
  30. package/client/app/component.tsx +54 -0
  31. package/client/app/index.ts +142 -0
  32. package/client/app/service.ts +34 -0
  33. package/client/app.tsconfig.json +28 -0
  34. package/client/components/Button.tsx +298 -0
  35. package/client/components/Dialog/Manager.tsx +309 -0
  36. package/client/components/Dialog/card.tsx +208 -0
  37. package/client/components/Dialog/index.less +151 -0
  38. package/client/components/Dialog/status.less +176 -0
  39. package/client/components/Dialog/status.tsx +48 -0
  40. package/client/components/index.ts +2 -0
  41. package/client/components/types.d.ts +3 -0
  42. package/client/data/input.ts +32 -0
  43. package/client/global.d.ts +5 -0
  44. package/client/hooks.ts +22 -0
  45. package/client/index.ts +6 -0
  46. package/client/pages/_layout/index.less +6 -0
  47. package/client/pages/_layout/index.tsx +43 -0
  48. package/client/pages/bug.tsx.old +60 -0
  49. package/client/pages/useHeader.tsx +50 -0
  50. package/client/services/captcha/index.ts +67 -0
  51. package/client/services/router/components/Link.tsx +46 -0
  52. package/client/services/router/components/Page.tsx +55 -0
  53. package/client/services/router/components/router.tsx +218 -0
  54. package/client/services/router/index.tsx +521 -0
  55. package/client/services/router/request/api.ts +267 -0
  56. package/client/services/router/request/history.ts +5 -0
  57. package/client/services/router/request/index.ts +53 -0
  58. package/client/services/router/request/multipart.ts +147 -0
  59. package/client/services/router/response/index.tsx +128 -0
  60. package/client/services/router/response/page.ts +86 -0
  61. package/client/services/socket/index.ts +147 -0
  62. package/client/utils/dom.ts +77 -0
  63. package/common/app/index.ts +9 -0
  64. package/common/data/chaines/index.ts +54 -0
  65. package/common/data/dates.ts +179 -0
  66. package/common/data/markdown.ts +73 -0
  67. package/common/data/rte/nodes.ts +83 -0
  68. package/common/data/stats.ts +90 -0
  69. package/common/errors/index.tsx +326 -0
  70. package/common/router/index.ts +213 -0
  71. package/common/router/layouts.ts +93 -0
  72. package/common/router/register.ts +55 -0
  73. package/common/router/request/api.ts +77 -0
  74. package/common/router/request/index.ts +35 -0
  75. package/common/router/response/index.ts +45 -0
  76. package/common/router/response/page.ts +128 -0
  77. package/common/utils/rte.ts +183 -0
  78. package/common/utils.ts +7 -0
  79. package/doc/TODO.md +71 -0
  80. package/doc/front/router.md +27 -0
  81. package/doc/workspace/workspace.png +0 -0
  82. package/doc/workspace/workspace2.png +0 -0
  83. package/doc/workspace/workspace_26.01.22.png +0 -0
  84. package/package.json +171 -0
  85. package/server/app/commands.ts +141 -0
  86. package/server/app/container/config.ts +203 -0
  87. package/server/app/container/console/index.ts +550 -0
  88. package/server/app/container/index.ts +137 -0
  89. package/server/app/index.ts +273 -0
  90. package/server/app/service/container.ts +88 -0
  91. package/server/app/service/index.ts +235 -0
  92. package/server/app.tsconfig.json +28 -0
  93. package/server/context.ts +4 -0
  94. package/server/index.ts +4 -0
  95. package/server/services/auth/index.ts +250 -0
  96. package/server/services/auth/old.ts +277 -0
  97. package/server/services/auth/router/index.ts +95 -0
  98. package/server/services/auth/router/request.ts +54 -0
  99. package/server/services/auth/router/service.json +6 -0
  100. package/server/services/auth/service.json +6 -0
  101. package/server/services/cache/commands.ts +41 -0
  102. package/server/services/cache/index.ts +297 -0
  103. package/server/services/cache/service.json +6 -0
  104. package/server/services/cron/CronTask.ts +86 -0
  105. package/server/services/cron/index.ts +112 -0
  106. package/server/services/cron/service.json +6 -0
  107. package/server/services/disks/driver.ts +103 -0
  108. package/server/services/disks/drivers/local/index.ts +188 -0
  109. package/server/services/disks/drivers/local/service.json +6 -0
  110. package/server/services/disks/drivers/s3/index.ts +301 -0
  111. package/server/services/disks/drivers/s3/service.json +6 -0
  112. package/server/services/disks/index.ts +90 -0
  113. package/server/services/disks/service.json +6 -0
  114. package/server/services/email/index.ts +188 -0
  115. package/server/services/email/utils.ts +53 -0
  116. package/server/services/fetch/index.ts +201 -0
  117. package/server/services/fetch/service.json +7 -0
  118. package/server/services/models.7z +0 -0
  119. package/server/services/prisma/Facet.ts +142 -0
  120. package/server/services/prisma/index.ts +201 -0
  121. package/server/services/prisma/service.json +6 -0
  122. package/server/services/router/http/index.ts +217 -0
  123. package/server/services/router/http/multipart.ts +102 -0
  124. package/server/services/router/http/session.ts.old +40 -0
  125. package/server/services/router/index.ts +801 -0
  126. package/server/services/router/request/api.ts +87 -0
  127. package/server/services/router/request/index.ts +184 -0
  128. package/server/services/router/request/service.ts +21 -0
  129. package/server/services/router/request/validation/zod.ts +180 -0
  130. package/server/services/router/response/index.ts +338 -0
  131. package/server/services/router/response/mask/Filter.ts +323 -0
  132. package/server/services/router/response/mask/index.ts +60 -0
  133. package/server/services/router/response/mask/selecteurs.ts +92 -0
  134. package/server/services/router/response/page/document.tsx +160 -0
  135. package/server/services/router/response/page/index.tsx +196 -0
  136. package/server/services/router/service.json +6 -0
  137. package/server/services/router/service.ts +36 -0
  138. package/server/services/schema/index.ts +44 -0
  139. package/server/services/schema/request.ts +49 -0
  140. package/server/services/schema/router/index.ts +28 -0
  141. package/server/services/schema/router/service.json +6 -0
  142. package/server/services/schema/service.json +6 -0
  143. package/server/services/security/encrypt/aes/index.ts +85 -0
  144. package/server/services/security/encrypt/aes/service.json +6 -0
  145. package/server/services/socket/index.ts +162 -0
  146. package/server/services/socket/scope.ts +226 -0
  147. package/server/services/socket/service.json +6 -0
  148. package/server/services_old/SocketClient.ts +92 -0
  149. package/server/services_old/Token.old.ts +97 -0
  150. package/server/utils/slug.ts +79 -0
  151. package/tsconfig.common.json +45 -0
  152. package/tsconfig.json +3 -0
  153. package/types/aliases.d.ts +54 -0
  154. package/types/global/modules.d.ts +49 -0
  155. package/types/global/utils.d.ts +103 -0
  156. package/types/icons.d.ts +1 -0
@@ -0,0 +1,60 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Libs
6
+ import compilerSelecteurs, { TObjetSelecteurs } from './selecteurs';
7
+ import Filter from './Filter';
8
+
9
+ // Filtres spécifiques métier
10
+ //import filtresProps from '@/general/serveur/filtresApi';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+ /*----------------------------------
17
+ - CONFIG
18
+ ----------------------------------*/
19
+
20
+ const debug = false;
21
+
22
+ /*----------------------------------
23
+ - MODULE
24
+ ----------------------------------*/
25
+
26
+ // proprieteModele = Si l'objet actuellement traité fait partie des valeurs d'un modèle
27
+ export default (
28
+ donnee: any,
29
+ selecteurs?: string | TObjetSelecteurs
30
+ ) => {
31
+
32
+ // Pas besoin de filtrer
33
+ if (donnee === null || typeof donnee !== 'object'/* || donnee._filtered === true */) {
34
+ return donnee;
35
+ }
36
+
37
+ // Correction sélecteurs
38
+ let selecteursCompiles: TObjetSelecteurs | undefined;
39
+ if (selecteurs === undefined)
40
+ selecteursCompiles = undefined;
41
+ else if (typeof selecteurs === 'string')
42
+ selecteursCompiles = compilerSelecteurs(selecteurs);
43
+ else // Déjà un objet, pas besoin de compiler
44
+ selecteursCompiles = selecteurs;
45
+
46
+ debug && console.log('Avant filtrage', donnee);
47
+
48
+ const filtre = new Filter();
49
+ const retour = filtre.filtrer(donnee, selecteursCompiles);
50
+
51
+ // Empêche un nouveau filtrage
52
+ // OBSOLETE: éviter d emodifier le retour des api, car cela peut poser probleme lors du traitement de ces données (ex: itération clés objet)
53
+ /*if (typeof retour === 'object' && retour !== null)
54
+ retour._filtered = true;*/
55
+
56
+ debug && console.log('Apres filtrage', retour);
57
+
58
+ return retour;
59
+
60
+ }
@@ -0,0 +1,92 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ /*----------------------------------
6
+ - TYPES
7
+ ----------------------------------*/
8
+ export type TSelecteur = true | "*" | TObjetSelecteurs
9
+ // Wildcard en clé = selectionner toutes les clés
10
+ // Wildcard en valeur = sélectionner absolument toutes les valeur descendantes
11
+ export type TObjetSelecteurs = {[cle: string]: TSelecteur}
12
+
13
+ /*----------------------------------
14
+ - CONSTANTES
15
+ ----------------------------------*/
16
+ const reSelecteurs = /((([a-z0-9\*\@\.\_\#]+)|(\{[^\}]+\}))\s*(\(?))|\)/gi; // <branche>( <elem1> <elem2> )
17
+
18
+ const cache: TObjetSelecteurs = {};
19
+
20
+ /*----------------------------------
21
+ - FONCTION
22
+ ----------------------------------*/
23
+ export default (selecteurs: string) => {
24
+
25
+ if (cache[selecteurs] === undefined)
26
+ cache[selecteurs] = compiler(selecteurs);
27
+
28
+ return cache[selecteurs];
29
+
30
+ }
31
+
32
+ const compiler = (selecteurs: string): TObjetSelecteurs => {
33
+
34
+ let chemins: TObjetSelecteurs = {};
35
+ let cheminA: string[] = []; // Chemin en construction
36
+
37
+ let branche;
38
+ while (branche = reSelecteurs.exec(selecteurs)) {
39
+
40
+ if (branche[0] === ')') { // fermeture
41
+
42
+ // Niveau précédent: docs.titre => docs
43
+ cheminA.pop();
44
+
45
+ } else {
46
+
47
+ const nomBranche = branche[2];
48
+ const ouverture = branche[5] === '(';
49
+
50
+ // Ligne débutant par un # = commentaire
51
+ if (nomBranche.startsWith("#"))
52
+ continue;
53
+
54
+ if (ouverture)
55
+ // Ouverture de la branche: docs => docs.titre
56
+ cheminA.push(nomBranche);
57
+ else {
58
+
59
+ const chemin = [...cheminA, nomBranche];
60
+
61
+ // Construction du chemin
62
+ let brancheA = chemins;
63
+ const nbBranches = chemin.length;
64
+ for (let iBranche = 0; iBranche < nbBranches; iBranche++) {
65
+
66
+ const nomBranche = chemin[iBranche];
67
+
68
+ const extremite = iBranche === nbBranches - 1
69
+ if (extremite) {
70
+
71
+ // Dernière branche = extremité = true
72
+ brancheA[nomBranche] = true;
73
+
74
+ } else {
75
+
76
+ // Pas encore définie
77
+ if (brancheA[nomBranche] === undefined)
78
+ // Sinon, initialisation
79
+ brancheA[nomBranche] = {};
80
+
81
+ // Rférnce pour la prochaine itération
82
+ brancheA = brancheA[nomBranche];
83
+
84
+ }
85
+ }
86
+ }
87
+ }
88
+ }
89
+
90
+ return chemins;
91
+
92
+ }
@@ -0,0 +1,160 @@
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<TRouter extends Router> {
23
+
24
+ public constructor(
25
+ public router: TRouter,
26
+ public app = router.app
27
+ ) {
28
+
29
+ }
30
+
31
+ public staticDocument() {
32
+ const routesForClient = JSON.stringify( this.router.ssrRoutes );
33
+ return '<!doctype html>' + 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="preload" href="/public/client.css" as="style" />
42
+ <link rel="preload" as="font" href={"/public/icons.woff2?v=" + BUILD_ID} type="font/woff2" />
43
+ <link rel="stylesheet" type="text/css" href="/public/icons.css" />
44
+ <link rel="stylesheet" type="text/css" href="/public/client.css" />
45
+
46
+ {/* JS */}
47
+ <script type="text/javascript" dangerouslySetInnerHTML={{
48
+ __html: `window.routes=${routesForClient};` + (this.app.env.profile === 'dev' ? 'window.dev = true;' : '')
49
+ }} />
50
+ <link rel="preload" href="/public/client.js" as="script" />
51
+ <script defer type="text/javascript" src="/public/client.js" />
52
+
53
+ </head>
54
+ <body></body>
55
+ </html>
56
+ );
57
+ }
58
+
59
+ public async page( html: string, page: Page, response: ServerResponse<TRouter> ) {
60
+
61
+ let attrsBody = {
62
+ className: [...page.bodyClass].join(' '),
63
+ };
64
+
65
+ return '<!doctype html>' + renderToString(
66
+ <html lang="en">
67
+ <head>
68
+ {/* Format */}
69
+ <meta charSet="utf-8" />
70
+ <meta content="IE=edge" httpEquiv="X-UA-Compatible" />
71
+ <meta name="viewport" content="width=device-width,minimum-scale=1,initial-scale=1" />
72
+
73
+ {/* Mobile */}
74
+ <meta name="application-name" content={this.app.identity.web.title} />
75
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
76
+ <meta name="apple-mobile-web-app-title" content={this.app.identity.web.title} />
77
+ <meta content={this.app.identity.author.name} name="author" />
78
+ <meta name="theme-color" content={this.app.identity.maincolor} />
79
+ <meta name="msapplication-TileColor" content={this.app.identity.maincolor} />
80
+ <meta name="apple-mobile-web-app-capable" content="yes" />
81
+ <meta name="mobile-web-app-capable" content="yes" />
82
+ <meta name="viewport" content="width=device-width, initial-scale=1.0, maximum-scale=1.0, user-scalable=0" />
83
+
84
+ {/* https://stackoverflow.com/questions/48956465/favicon-standard-2019-svg-ico-png-and-dimensions */}
85
+ {/*<link rel="manifest" href={RES['manifest.json']} />*/}
86
+ <link rel="shortcut icon" href="/public/app/favicon.ico" />
87
+ <link rel="icon" type="image/png" sizes="16x16" href="/public/app/favicon-16x16.png" />
88
+ <link rel="icon" type="image/png" sizes="32x32" href="/public/app/favicon-32x32.png" />
89
+ <link rel="apple-touch-icon" sizes="180x180" href="/public/app/apple-touch-icon-180x180.png" />
90
+ <meta name="msapplication-config" content="/public/app/browserconfig.xml" />
91
+
92
+ {/* Page */}
93
+ <title>{page.title}</title>
94
+ <meta content={page.description} name="description" />
95
+ <link rel="canonical" href={response.canonicalUrl} />
96
+
97
+ {/* SEO, social medias, OG tags, ... */}
98
+ {page.head.map(({ $, ...attrs }) => (
99
+ React.createElement($, attrs)
100
+ ))}
101
+
102
+ {this.styles( page )}
103
+
104
+ {await this.scripts( response, page )}
105
+
106
+ {/* Rich Snippets: https://schema.org/docs/full.html + https://jsonld.com/ */}
107
+ <script type="application/ld+json" dangerouslySetInnerHTML={{
108
+ __html: JSON.stringify({
109
+ '@context': 'http://schema.org',
110
+ '@graph': page.jsonld
111
+ })
112
+ }}/>
113
+
114
+ </head>
115
+ <body {...attrsBody} dangerouslySetInnerHTML={{ __html: html }}></body>
116
+ </html>
117
+ )
118
+ }
119
+
120
+ private styles( page: Page ) {
121
+ return <>
122
+ <link rel="preload" href="/public/client.css" as="style" />
123
+ <link rel="stylesheet" type="text/css" href="/public/client.css" />
124
+
125
+ {page.style.map( style => 'url' in style ? <>
126
+ <link rel="preload" href={style.url} as="style" />
127
+ <link rel="stylesheet" type="text/css" href={style.url} />
128
+ </> : <>
129
+ <style id={style.id} dangerouslySetInnerHTML={{ __html: style.inline }} />
130
+ </>)}
131
+ </>
132
+ }
133
+
134
+ private async scripts( response: ServerResponse<TRouter>, page: Page ) {
135
+
136
+ const ssrData = response.forSsr(page);
137
+ const context = safeStringify( ssrData );
138
+ const routesForClient = JSON.stringify( this.router.ssrRoutes );
139
+
140
+ return <>
141
+ {/* JS */}
142
+ <script type="text/javascript" dangerouslySetInnerHTML={{
143
+ __html: `window.ssr=${context}; window.routes=${routesForClient};` + (
144
+ this.app.env.profile === 'dev' ? 'window.dev = true;' : ''
145
+ )
146
+ }} />
147
+
148
+ <link rel="preload" href={"/public/client.js?v=" + BUILD_ID} as="script" />
149
+ <script defer type="text/javascript" src={"/public/client.js?v=" + BUILD_ID} />
150
+
151
+ {page.scripts.map( script => 'url' in script ? <>
152
+ <link rel="preload" href={script.url} as="script" />
153
+ <script type="text/javascript" src={script.url} {...script.attrs || {}} />
154
+ </> : <>
155
+ <script type="text/javascript" {...script.attrs || {}} id={script.id}
156
+ dangerouslySetInnerHTML={{ __html: script.inline }} />
157
+ </>)}
158
+ </>
159
+ }
160
+ }
@@ -0,0 +1,196 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import React from 'react';
7
+ import renderToString from "preact-render-to-string";
8
+
9
+ // Core
10
+ import { default as Router, TRouterContext } from "@server/services/router";
11
+ import type { Layout, TRoute, TErrorRoute, TClientOrServerContext } from '@common/router';
12
+ import PageResponse, { TFrontRenderer } from "@common/router/response/page";
13
+
14
+ // Composants UI
15
+ import App from '@client/app/component';
16
+
17
+ // Caches
18
+ const chunks = require('./chunk-manifest.json');
19
+
20
+ /*----------------------------------
21
+ - TYPES
22
+ ----------------------------------*/
23
+
24
+ const seoLimits = {
25
+ title: 70,
26
+ description: 255
27
+ }
28
+
29
+ /*----------------------------------
30
+ - FONCTION
31
+ ----------------------------------*/
32
+
33
+ export default class ServerPage<TRouter extends Router = Router> extends PageResponse<TRouter> {
34
+
35
+ public constructor(
36
+ public route: TRoute | TErrorRoute,
37
+ public renderer: TFrontRenderer,
38
+ public context: TRouterContext,
39
+ public layout?: Layout,
40
+
41
+ public app = context.app,
42
+ public router = context.request.router,
43
+
44
+ ) {
45
+
46
+ super(route, renderer, context)
47
+
48
+ }
49
+
50
+ public render(): Promise<string> {
51
+
52
+ // Complete SEO metadatas
53
+ const titleSuffix = ' | ' + this.app.identity.web.titleSuffix
54
+ if (this.title === undefined)
55
+ this.title = this.app.identity.web.fullTitle;
56
+ else if (this.title.length < seoLimits.title - titleSuffix.length)
57
+ this.title += titleSuffix;
58
+
59
+ if (this.description === undefined)
60
+ this.description = this.app.identity.web.description;
61
+
62
+ // We render page & document separatly,
63
+ // because document needs to access to runtime assigned values
64
+ // Ex: runtime added scripts, title, metas, ....
65
+
66
+ const html = renderToString(
67
+ <App {...this.context} />
68
+ );
69
+
70
+ if (html === undefined)
71
+ throw new Error(`Page HTML is empty (undefined)`);
72
+
73
+ // Metas
74
+ this.buildMetas();
75
+ this.buildJsonLd();
76
+
77
+ // Un chunk peut regrouper plusieurs fihciers css / js
78
+ // L'id du chunk est injecté depuis le plugin babel
79
+ this.addChunks();
80
+
81
+ /*if (page.classeBody)
82
+ attrsBody.className += ' ' + page.classeBody.join(' ');
83
+
84
+ if (page.theme)
85
+ attrsBody.className += ' ' + page.theme;*/
86
+
87
+ return this.router.render.page(html, this, this.context.response);
88
+ }
89
+
90
+ // Define which chunks (script / style) to load
91
+ private addChunks() {
92
+ const pageChunks = [this.route.options["id"]];
93
+ for (const chunk of pageChunks) {
94
+
95
+ if (!chunk) continue;
96
+
97
+ const assets = chunks[chunk];
98
+ if (!assets) {
99
+ console.warn(`Chunk ${chunk} was not found. Indexed chunks: ${Object.keys(chunks).join(', ')}`);
100
+ continue;
101
+ }
102
+
103
+ for (let i = 0; i < assets.length; i++) {
104
+ const asset = assets[i];
105
+
106
+ if (asset.endsWith('.css'))
107
+ this.style.push({
108
+ id: chunk,
109
+ url: '/public/' + asset
110
+ })
111
+ else
112
+ this.scripts.push({
113
+ id: chunk,
114
+ url: '/public/' + asset
115
+ });
116
+ }
117
+
118
+ }
119
+ }
120
+
121
+ private buildMetas() {
122
+
123
+ const shouldIndex = this.context.response.statusCode < 300;
124
+
125
+ const metas = {
126
+
127
+ robots: shouldIndex ? 'index' : 'noindex',
128
+
129
+ 'og:type': 'website',
130
+ 'og:locale': this.app.identity.locale,
131
+ 'og:site_name': this.app.identity.web.title,
132
+ 'og:url': this.url,
133
+
134
+ 'og:title': this.title,
135
+ 'og:description': this.description,
136
+
137
+ 'twitter:url': this.url,
138
+ 'twitter:card': 'summary_large_image',
139
+ 'twitter:title': this.title,
140
+ 'twitter:description': this.description,
141
+
142
+ ...(this.app.identity.web.metas || {}),
143
+
144
+ ...this.metas
145
+ };
146
+
147
+ for (const key in metas) {
148
+ const value = metas[key];
149
+ if (value === "") continue;
150
+ this.head.push({ $: 'meta', property: key, content: value });
151
+ }
152
+ }
153
+
154
+ private buildJsonLd() {
155
+ this.jsonld.push({
156
+ '@type': 'Organization',
157
+ '@id': this.router.url('/#organization'),
158
+ name: this.app.identity.author.name,
159
+ url: this.app.identity.author.url,
160
+ logo: {
161
+ '@type': 'ImageObject',
162
+ '@id': this.router.url('/#logo'),
163
+ url: this.router.url('/public/brand/1024.png'),
164
+ width: "1024px",
165
+ height: "1024px",
166
+ caption: this.app.identity.name
167
+ },
168
+ sameAs: []
169
+ }, {
170
+ '@type': 'WebSite',
171
+ '@id': this.router.url('/#website'),
172
+ url: this.router.url('/'),
173
+ name: this.app.identity.name,
174
+ description: this.app.identity.description,
175
+ "publisher": {
176
+ "@id": this.router.url('/#organization'),
177
+ },
178
+ inLanguage: this.app.identity.locale,
179
+ potentialAction: [],
180
+
181
+ ...(this.app.identity.web.jsonld || {}),
182
+ }, {
183
+ '@type': "WebPage",
184
+ '@id': this.url,
185
+ url: this.url,
186
+
187
+ "isPartOf": {
188
+ "@id": this.router.url('/#website'),
189
+ },
190
+
191
+ name: this.title,
192
+ description: this.description,
193
+ inLanguage: this.app.identity.locale,
194
+ });
195
+ }
196
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "Core/Router",
3
+ "name": "Router",
4
+ "parent": "app",
5
+ "dependences": []
6
+ }
@@ -0,0 +1,36 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import type { Application } from '@server/app';
7
+ import Service, { TRegisteredServicesIndex, TServiceArgs } from '@server/app/service';
8
+
9
+ // Specific
10
+ import type { default as Router } from '.';
11
+ import type ServerRequest from './request';
12
+ import type RequestService from './request/service';
13
+ import type { TAnyRouter } from '.';
14
+
15
+ export type AnyRouterService = RouterService<any, TAnyRouter>;
16
+
17
+ export type TRouterServiceArgs = [
18
+ getConfig: TServiceArgs<AnyRouterService>[1],
19
+ app: Application,
20
+ ];
21
+
22
+ /*----------------------------------
23
+ - SERVICE
24
+ ----------------------------------*/
25
+ export default abstract class RouterService<
26
+ TConfig extends {},
27
+ TRouter extends TAnyRouter
28
+ > extends Service<TConfig, {}, Application, TRouter> {
29
+
30
+ public constructor( ...[config, app]: TRouterServiceArgs) {
31
+ super(app, config, app);
32
+ }
33
+
34
+ public abstract requestService( request: ServerRequest<TRouter> ): RequestService | {} | null;
35
+
36
+ }
@@ -0,0 +1,44 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import type { Application } from '@server/app';
7
+
8
+ // Specific
9
+ import { SchemaValidators, TFileValidator } from '@server/services/router/request/validation/validators';
10
+ import Validator, { TValidatorOptions } from '@server/services/router/request/validation/validator';
11
+
12
+ /*----------------------------------
13
+ - TYPES
14
+ ----------------------------------*/
15
+
16
+
17
+ /*----------------------------------
18
+ - SERVICE
19
+ ----------------------------------*/
20
+ export default class ServerSchemaValidator extends SchemaValidators {
21
+
22
+ public constructor( public app: Application ) {
23
+ super();
24
+ }
25
+
26
+ public richText = (opts: TValidatorOptions<string> & {
27
+ attachements?: TFileValidator
28
+ } = {}) => new Validator<string>('richText', (val, options, path) => {
29
+
30
+ // Default validation
31
+ val = super.richText(opts).validate(val, options, path);
32
+
33
+ // Uploads are done in the business code since the process is specific to every case:
34
+ // - ID in the destination directory
35
+ // - Cleanup before upload
36
+
37
+ return val;
38
+
39
+ }, {
40
+ //defaut: new Date,
41
+ ...opts,
42
+ })
43
+
44
+ }
@@ -0,0 +1,49 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Npm
6
+ import zod from 'zod';
7
+ import { SomeType } from 'zod/v4/core';
8
+
9
+ // Core
10
+ import {
11
+ default as Router, TServerRouter, Request as ServerRequest
12
+ } from '@server/services/router';
13
+
14
+ // Ap
15
+ import { preprocessSchema, schema } from '@server/services/router/request/validation/zod';
16
+
17
+ /*----------------------------------
18
+ - SERVICE CONFIG
19
+ ----------------------------------*/
20
+
21
+ const LogPrefix = `[router][validation]`;
22
+
23
+ export type TConfig = {
24
+ debug?: boolean
25
+ }
26
+
27
+ /*----------------------------------
28
+ - SERVICE
29
+ ----------------------------------*/
30
+ export default(
31
+ request: ServerRequest< TServerRouter >,
32
+ config: TConfig,
33
+ router = request.router,
34
+ app = router.app
35
+ ) => ({
36
+
37
+ ...schema,
38
+
39
+ validate( fields: zod.ZodSchema | { [key: string]: zod.ZodSchema } ) {
40
+
41
+ config.debug && console.log(LogPrefix, "Validate request data:", request.data);
42
+
43
+ const schema = typeof fields === 'object' ? zod.object(fields) : fields;
44
+
45
+ const preprocessedSchema = preprocessSchema(schema);
46
+
47
+ return preprocessedSchema.parse(request.data);
48
+ },
49
+ })
@@ -0,0 +1,28 @@
1
+ /*----------------------------------
2
+ - DEPENDANCES
3
+ ----------------------------------*/
4
+
5
+ // Core
6
+ import {
7
+ default as Router, Request as ServerRequest, Config as RouterConfig,
8
+ RouterService, TAnyRouter
9
+ } from '@server/services/router';
10
+
11
+ import makeRequestValidators from '../request';
12
+
13
+ /*----------------------------------
14
+ - TYPES
15
+ ----------------------------------*/
16
+
17
+
18
+ /*----------------------------------
19
+ - SERVICE
20
+ ----------------------------------*/
21
+ export default class SchemaRouterService<
22
+ TUser extends {} = {}
23
+ > extends RouterService<{}, TAnyRouter> {
24
+
25
+ public requestService( request: ServerRequest ) {
26
+ return makeRequestValidators( request, this.config );
27
+ }
28
+ }
@@ -0,0 +1,6 @@
1
+ {
2
+ "id": "Core/Schema/Router",
3
+ "name": "RouteSchema",
4
+ "parent": "router",
5
+ "dependences": []
6
+ }