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.
- package/.dockerignore +10 -0
- package/Rte.zip +0 -0
- package/cli/app/config.ts +54 -0
- package/cli/app/index.ts +195 -0
- package/cli/bin.js +11 -0
- package/cli/commands/build.ts +34 -0
- package/cli/commands/deploy/app.ts +29 -0
- package/cli/commands/deploy/web.ts +60 -0
- package/cli/commands/dev.ts +109 -0
- package/cli/commands/init.ts +85 -0
- package/cli/compiler/client/identite.ts +72 -0
- package/cli/compiler/client/index.ts +334 -0
- package/cli/compiler/common/babel/index.ts +170 -0
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +579 -0
- package/cli/compiler/common/babel/routes/imports.ts +127 -0
- package/cli/compiler/common/babel/routes/routes.ts +1130 -0
- package/cli/compiler/common/files/autres.ts +39 -0
- package/cli/compiler/common/files/images.ts +35 -0
- package/cli/compiler/common/files/style.ts +78 -0
- package/cli/compiler/common/index.ts +154 -0
- package/cli/compiler/index.ts +532 -0
- package/cli/compiler/server/index.ts +211 -0
- package/cli/index.ts +189 -0
- package/cli/paths.ts +165 -0
- package/cli/print.ts +12 -0
- package/cli/tsconfig.json +38 -0
- package/cli/utils/index.ts +22 -0
- package/cli/utils/keyboard.ts +78 -0
- package/client/app/component.tsx +54 -0
- package/client/app/index.ts +142 -0
- package/client/app/service.ts +34 -0
- package/client/app.tsconfig.json +28 -0
- package/client/components/Button.tsx +298 -0
- package/client/components/Dialog/Manager.tsx +309 -0
- package/client/components/Dialog/card.tsx +208 -0
- package/client/components/Dialog/index.less +151 -0
- package/client/components/Dialog/status.less +176 -0
- package/client/components/Dialog/status.tsx +48 -0
- package/client/components/index.ts +2 -0
- package/client/components/types.d.ts +3 -0
- package/client/data/input.ts +32 -0
- package/client/global.d.ts +5 -0
- package/client/hooks.ts +22 -0
- package/client/index.ts +6 -0
- package/client/pages/_layout/index.less +6 -0
- package/client/pages/_layout/index.tsx +43 -0
- package/client/pages/bug.tsx.old +60 -0
- package/client/pages/useHeader.tsx +50 -0
- package/client/services/captcha/index.ts +67 -0
- package/client/services/router/components/Link.tsx +46 -0
- package/client/services/router/components/Page.tsx +55 -0
- package/client/services/router/components/router.tsx +218 -0
- package/client/services/router/index.tsx +521 -0
- package/client/services/router/request/api.ts +267 -0
- package/client/services/router/request/history.ts +5 -0
- package/client/services/router/request/index.ts +53 -0
- package/client/services/router/request/multipart.ts +147 -0
- package/client/services/router/response/index.tsx +128 -0
- package/client/services/router/response/page.ts +86 -0
- package/client/services/socket/index.ts +147 -0
- package/client/utils/dom.ts +77 -0
- package/common/app/index.ts +9 -0
- package/common/data/chaines/index.ts +54 -0
- package/common/data/dates.ts +179 -0
- package/common/data/markdown.ts +73 -0
- package/common/data/rte/nodes.ts +83 -0
- package/common/data/stats.ts +90 -0
- package/common/errors/index.tsx +326 -0
- package/common/router/index.ts +213 -0
- package/common/router/layouts.ts +93 -0
- package/common/router/register.ts +55 -0
- package/common/router/request/api.ts +77 -0
- package/common/router/request/index.ts +35 -0
- package/common/router/response/index.ts +45 -0
- package/common/router/response/page.ts +128 -0
- package/common/utils/rte.ts +183 -0
- package/common/utils.ts +7 -0
- package/doc/TODO.md +71 -0
- package/doc/front/router.md +27 -0
- package/doc/workspace/workspace.png +0 -0
- package/doc/workspace/workspace2.png +0 -0
- package/doc/workspace/workspace_26.01.22.png +0 -0
- package/package.json +171 -0
- package/server/app/commands.ts +141 -0
- package/server/app/container/config.ts +203 -0
- package/server/app/container/console/index.ts +550 -0
- package/server/app/container/index.ts +137 -0
- package/server/app/index.ts +273 -0
- package/server/app/service/container.ts +88 -0
- package/server/app/service/index.ts +235 -0
- package/server/app.tsconfig.json +28 -0
- package/server/context.ts +4 -0
- package/server/index.ts +4 -0
- package/server/services/auth/index.ts +250 -0
- package/server/services/auth/old.ts +277 -0
- package/server/services/auth/router/index.ts +95 -0
- package/server/services/auth/router/request.ts +54 -0
- package/server/services/auth/router/service.json +6 -0
- package/server/services/auth/service.json +6 -0
- package/server/services/cache/commands.ts +41 -0
- package/server/services/cache/index.ts +297 -0
- package/server/services/cache/service.json +6 -0
- package/server/services/cron/CronTask.ts +86 -0
- package/server/services/cron/index.ts +112 -0
- package/server/services/cron/service.json +6 -0
- package/server/services/disks/driver.ts +103 -0
- package/server/services/disks/drivers/local/index.ts +188 -0
- package/server/services/disks/drivers/local/service.json +6 -0
- package/server/services/disks/drivers/s3/index.ts +301 -0
- package/server/services/disks/drivers/s3/service.json +6 -0
- package/server/services/disks/index.ts +90 -0
- package/server/services/disks/service.json +6 -0
- package/server/services/email/index.ts +188 -0
- package/server/services/email/utils.ts +53 -0
- package/server/services/fetch/index.ts +201 -0
- package/server/services/fetch/service.json +7 -0
- package/server/services/models.7z +0 -0
- package/server/services/prisma/Facet.ts +142 -0
- package/server/services/prisma/index.ts +201 -0
- package/server/services/prisma/service.json +6 -0
- package/server/services/router/http/index.ts +217 -0
- package/server/services/router/http/multipart.ts +102 -0
- package/server/services/router/http/session.ts.old +40 -0
- package/server/services/router/index.ts +801 -0
- package/server/services/router/request/api.ts +87 -0
- package/server/services/router/request/index.ts +184 -0
- package/server/services/router/request/service.ts +21 -0
- package/server/services/router/request/validation/zod.ts +180 -0
- package/server/services/router/response/index.ts +338 -0
- package/server/services/router/response/mask/Filter.ts +323 -0
- package/server/services/router/response/mask/index.ts +60 -0
- package/server/services/router/response/mask/selecteurs.ts +92 -0
- package/server/services/router/response/page/document.tsx +160 -0
- package/server/services/router/response/page/index.tsx +196 -0
- package/server/services/router/service.json +6 -0
- package/server/services/router/service.ts +36 -0
- package/server/services/schema/index.ts +44 -0
- package/server/services/schema/request.ts +49 -0
- package/server/services/schema/router/index.ts +28 -0
- package/server/services/schema/router/service.json +6 -0
- package/server/services/schema/service.json +6 -0
- package/server/services/security/encrypt/aes/index.ts +85 -0
- package/server/services/security/encrypt/aes/service.json +6 -0
- package/server/services/socket/index.ts +162 -0
- package/server/services/socket/scope.ts +226 -0
- package/server/services/socket/service.json +6 -0
- package/server/services_old/SocketClient.ts +92 -0
- package/server/services_old/Token.old.ts +97 -0
- package/server/utils/slug.ts +79 -0
- package/tsconfig.common.json +45 -0
- package/tsconfig.json +3 -0
- package/types/aliases.d.ts +54 -0
- package/types/global/modules.d.ts +49 -0
- package/types/global/utils.d.ts +103 -0
- package/types/icons.d.ts +1 -0
|
@@ -0,0 +1,521 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import React from 'react';
|
|
7
|
+
import ReactDOM from 'react-dom';
|
|
8
|
+
|
|
9
|
+
// Core
|
|
10
|
+
import type {
|
|
11
|
+
default as ServerRouter,
|
|
12
|
+
Request as ServerRequest,
|
|
13
|
+
Response as ServerResponse
|
|
14
|
+
} from '@server/services/router';
|
|
15
|
+
import type { TBasicSSrData } from '@server/services/router/response';
|
|
16
|
+
|
|
17
|
+
import BaseRouter, {
|
|
18
|
+
defaultOptions, TRoute, TErrorRoute,
|
|
19
|
+
TClientOrServerContextForPage, TRouteModule,
|
|
20
|
+
matchRoute, buildUrl
|
|
21
|
+
} from '@common/router'
|
|
22
|
+
import { getLayout } from '@common/router/layouts';
|
|
23
|
+
import { getRegisterPageArgs, buildRegex } from '@common/router/register';
|
|
24
|
+
import { TFetcherList } from '@common/router/request/api';
|
|
25
|
+
import type { TFrontRenderer } from '@common/router/response/page';
|
|
26
|
+
import Button from '../../components/Button';
|
|
27
|
+
|
|
28
|
+
import App from '@client/app/component';
|
|
29
|
+
import type ClientApplication from '@client/app';
|
|
30
|
+
import Service from '@client/app/service';
|
|
31
|
+
|
|
32
|
+
// Specific
|
|
33
|
+
import type { ClientContext } from '@/client/context';
|
|
34
|
+
import ClientRequest from './request';
|
|
35
|
+
import { location, history } from './request/history';
|
|
36
|
+
import ClientResponse from './response';
|
|
37
|
+
import ClientPage from './response/page';
|
|
38
|
+
|
|
39
|
+
// Routes (import __register)
|
|
40
|
+
// We exclude files starting wiht uppercase, as they're considered as components
|
|
41
|
+
// WARN: The routes babel plugin must be updated with the glob path
|
|
42
|
+
//import * as coreRoutes from '@client/pages/**/([a-z0-9]*).tsx';
|
|
43
|
+
import * as appRoutes from '@/client/pages/**/([a-z0-9]*).tsx';
|
|
44
|
+
|
|
45
|
+
/*----------------------------------
|
|
46
|
+
- CONFIG
|
|
47
|
+
----------------------------------*/
|
|
48
|
+
|
|
49
|
+
const debug = false;
|
|
50
|
+
const LogPrefix = '[router]'
|
|
51
|
+
|
|
52
|
+
/*----------------------------------
|
|
53
|
+
- TYPES
|
|
54
|
+
----------------------------------*/
|
|
55
|
+
|
|
56
|
+
// Client router can handle Client requests AND Server requests (for pages only)
|
|
57
|
+
export type { default as ClientResponse, TRouterContext } from "./response";
|
|
58
|
+
|
|
59
|
+
export type Router = ClientRouter | ServerRouter;
|
|
60
|
+
|
|
61
|
+
export type Request = ClientRequest<ClientRouter> | ServerRequest<ServerRouter>;
|
|
62
|
+
|
|
63
|
+
export type Response = ClientResponse<ClientRouter> | ServerResponse<ServerRouter>;
|
|
64
|
+
|
|
65
|
+
/*----------------------------------
|
|
66
|
+
- TYPES: ROUTES LOADING
|
|
67
|
+
----------------------------------*/
|
|
68
|
+
|
|
69
|
+
// WARN: To be updated with the mplemenations list of Router.page AND the routes babel plugin
|
|
70
|
+
// (both server and client side)
|
|
71
|
+
export type TRegisterPageArgs<
|
|
72
|
+
TProvidedData extends TFetcherList = TFetcherList,
|
|
73
|
+
TRouter extends Router = Router
|
|
74
|
+
> = ([
|
|
75
|
+
path: string,
|
|
76
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
77
|
+
] | [
|
|
78
|
+
path: string,
|
|
79
|
+
options: Partial<TRoute["options"]>,
|
|
80
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
81
|
+
])
|
|
82
|
+
|
|
83
|
+
// Route definition passed by the server
|
|
84
|
+
export type TSsrUnresolvedRoute = {
|
|
85
|
+
chunk: string,
|
|
86
|
+
} & ({
|
|
87
|
+
// Normal route
|
|
88
|
+
regex: string,
|
|
89
|
+
keys: TRoute["keys"]
|
|
90
|
+
} | {
|
|
91
|
+
// Error
|
|
92
|
+
code: number
|
|
93
|
+
})
|
|
94
|
+
|
|
95
|
+
// Route definition without having loaded the controller
|
|
96
|
+
type TUnresolvedRoute = TUnresolvedErrorRoute | TUnresolvedNormalRoute;
|
|
97
|
+
|
|
98
|
+
export type TUnresolvedErrorRoute = {
|
|
99
|
+
index: number,
|
|
100
|
+
chunk: string,
|
|
101
|
+
code: number,
|
|
102
|
+
load: TRouteLoader<TErrorRoute>,
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
export type TUnresolvedNormalRoute = {
|
|
106
|
+
index: number,
|
|
107
|
+
chunk: string,
|
|
108
|
+
code: number,
|
|
109
|
+
load: TRouteLoader<TErrorRoute>,
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
type TRouteLoader<Route extends TRoute | TErrorRoute = TRoute | TErrorRoute> = () => Promise<TRouteModule<Route>>;
|
|
113
|
+
|
|
114
|
+
export type TFetchedRoute = Pick<TRoute, 'path' | 'options' | 'controller' | 'method'>
|
|
115
|
+
|
|
116
|
+
export type TRoutesLoaders = {
|
|
117
|
+
[chunkId: string]: () => Promise</* Preloaded via require() */TFetchedRoute | /* Loader via import() */TRouteLoader/* | undefined*/>
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
/*----------------------------------
|
|
121
|
+
- SERVICE TYPES
|
|
122
|
+
----------------------------------*/
|
|
123
|
+
|
|
124
|
+
export type THookCallback<TRouter extends ClientRouter> = (request: ClientRequest<TRouter>) => void;
|
|
125
|
+
|
|
126
|
+
type THookName = 'page.change' | 'page.changed' | 'page.rendered'
|
|
127
|
+
|
|
128
|
+
type Config<TAdditionnalContext extends {} = {}> = {
|
|
129
|
+
preload: string[], // List of globs
|
|
130
|
+
context: (context: {}, router: ClientRouter) => TAdditionnalContext,
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
/*----------------------------------
|
|
134
|
+
- ROUTER
|
|
135
|
+
----------------------------------*/
|
|
136
|
+
export default class ClientRouter<
|
|
137
|
+
TApplication extends ClientApplication = ClientApplication,
|
|
138
|
+
TAdditionnalContext extends {} = {}
|
|
139
|
+
> extends Service<Config<TAdditionnalContext>, ClientApplication> implements BaseRouter {
|
|
140
|
+
|
|
141
|
+
// Context data
|
|
142
|
+
public ssrRoutes = window["routes"] as TSsrUnresolvedRoute[];
|
|
143
|
+
public ssrContext = window["ssr"] as (TBasicSSrData | undefined);
|
|
144
|
+
public domains = window["ssr"].domains;
|
|
145
|
+
public context!: ClientContext;
|
|
146
|
+
|
|
147
|
+
public setLoading!: React.Dispatch< React.SetStateAction<boolean> >;
|
|
148
|
+
public navigate!: (page: ClientPage, data?: {}) => void;
|
|
149
|
+
|
|
150
|
+
public constructor(app: TApplication, config: Config<TAdditionnalContext>) {
|
|
151
|
+
|
|
152
|
+
super(app, config);
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
public async start() {
|
|
156
|
+
|
|
157
|
+
const currentRoute = await this.registerRoutes();
|
|
158
|
+
|
|
159
|
+
this.initialRender(currentRoute);
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
public url = (path: string, params: {} = {}, absolute: boolean = true) =>
|
|
163
|
+
buildUrl(path, params, this.domains, absolute);
|
|
164
|
+
|
|
165
|
+
public go( url: string | number, data: {} = {}, opt: {
|
|
166
|
+
newTab?: boolean
|
|
167
|
+
} = {}) {
|
|
168
|
+
|
|
169
|
+
// Error code
|
|
170
|
+
if (typeof url === 'number') {
|
|
171
|
+
this.createResponse( this.errors[url], this.context.request, data ).then(( page ) => {
|
|
172
|
+
this.navigate(page, data);
|
|
173
|
+
})
|
|
174
|
+
return;
|
|
175
|
+
}
|
|
176
|
+
|
|
177
|
+
url = this.url(url, data, false);
|
|
178
|
+
|
|
179
|
+
if (opt.newTab)
|
|
180
|
+
window.open(url)
|
|
181
|
+
// Same domain = history url replacement
|
|
182
|
+
else if (url[0] === '/')
|
|
183
|
+
history?.replace( url );
|
|
184
|
+
// Different domain = hard navigation
|
|
185
|
+
else
|
|
186
|
+
window.location.href = url;
|
|
187
|
+
}
|
|
188
|
+
|
|
189
|
+
/*----------------------------------
|
|
190
|
+
- REGISTRATION
|
|
191
|
+
----------------------------------*/
|
|
192
|
+
|
|
193
|
+
public routes: (TRoute | TUnresolvedNormalRoute)[] = [];
|
|
194
|
+
public errors: { [code: number]: TErrorRoute | TUnresolvedErrorRoute } = {};
|
|
195
|
+
|
|
196
|
+
public async registerRoutes() {
|
|
197
|
+
|
|
198
|
+
const loaders: TRoutesLoaders = { ...appRoutes }
|
|
199
|
+
let currentRoute: TUnresolvedRoute | undefined;
|
|
200
|
+
debug && console.log(LogPrefix, `Indexing routes and finding the current route from ssr data:`, this.context);
|
|
201
|
+
|
|
202
|
+
// Associe la liste des routes (obtenue via ssr) à leur loader
|
|
203
|
+
for (let routeIndex = 0; routeIndex < this.ssrRoutes.length; routeIndex++) {
|
|
204
|
+
|
|
205
|
+
const ssrRoute = this.ssrRoutes[routeIndex];
|
|
206
|
+
|
|
207
|
+
if (loaders[ssrRoute.chunk] === undefined) {
|
|
208
|
+
console.error("Chunk id not found for ssr route:", ssrRoute, "Searched in:", loaders);
|
|
209
|
+
continue;
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
// TODO: Fix types
|
|
213
|
+
const loader = loaders[ssrRoute.chunk];
|
|
214
|
+
|
|
215
|
+
// Register the route
|
|
216
|
+
let route: TUnresolvedRoute;
|
|
217
|
+
if ('code' in ssrRoute)
|
|
218
|
+
route = this.errors[ssrRoute.code] = {
|
|
219
|
+
code: ssrRoute.code,
|
|
220
|
+
chunk: ssrRoute.chunk,
|
|
221
|
+
load: loader,
|
|
222
|
+
}
|
|
223
|
+
else
|
|
224
|
+
route = this.routes[routeIndex] = {
|
|
225
|
+
index: routeIndex,
|
|
226
|
+
chunk: ssrRoute.chunk,
|
|
227
|
+
regex: new RegExp(ssrRoute.regex),
|
|
228
|
+
keys: ssrRoute.keys,
|
|
229
|
+
load: loader,
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
debug && console.log(LogPrefix, `${route.chunk}`, route);
|
|
233
|
+
|
|
234
|
+
// Detect if it's the current route
|
|
235
|
+
if (currentRoute === undefined) {
|
|
236
|
+
|
|
237
|
+
const isCurrentRoute = (
|
|
238
|
+
this.ssrContext !== undefined
|
|
239
|
+
&&
|
|
240
|
+
route.chunk === this.ssrContext.page.chunkId
|
|
241
|
+
);
|
|
242
|
+
|
|
243
|
+
if (isCurrentRoute) {
|
|
244
|
+
currentRoute = route;
|
|
245
|
+
continue;
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
return currentRoute;
|
|
251
|
+
}
|
|
252
|
+
|
|
253
|
+
public page<TProvidedData extends TFetcherList = TFetcherList>(
|
|
254
|
+
path: string,
|
|
255
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
256
|
+
): TRoute;
|
|
257
|
+
|
|
258
|
+
public page<TProvidedData extends TFetcherList = TFetcherList>(
|
|
259
|
+
path: string,
|
|
260
|
+
options: Partial<TRoute["options"]>,
|
|
261
|
+
renderer: TFrontRenderer<TProvidedData>
|
|
262
|
+
): TRoute;
|
|
263
|
+
|
|
264
|
+
public page(...args: TRegisterPageArgs): TRoute {
|
|
265
|
+
|
|
266
|
+
const { path, options, renderer, layout } = getRegisterPageArgs(...args);
|
|
267
|
+
|
|
268
|
+
// S'il s'agit d'une page, son id doit avoir été injecté via le plugin babel
|
|
269
|
+
const id = options["id"];
|
|
270
|
+
if (id === undefined)
|
|
271
|
+
throw new Error(`ID had not been injected into page options via the routes babel plugin for route ${path}.`);
|
|
272
|
+
|
|
273
|
+
const { regex, keys } = buildRegex(path);
|
|
274
|
+
|
|
275
|
+
const route: TRoute = {
|
|
276
|
+
method: 'GET',
|
|
277
|
+
path,
|
|
278
|
+
regex,
|
|
279
|
+
keys,
|
|
280
|
+
options: {
|
|
281
|
+
...defaultOptions,
|
|
282
|
+
...options
|
|
283
|
+
},
|
|
284
|
+
controller: (context: TClientOrServerContextForPage) => new ClientPage(route, renderer, context, layout)
|
|
285
|
+
};
|
|
286
|
+
|
|
287
|
+
this.routes.push(route);
|
|
288
|
+
|
|
289
|
+
return route;
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
public error(
|
|
293
|
+
code: number,
|
|
294
|
+
options: Partial<TRoute["options"]>,
|
|
295
|
+
renderer: TFrontRenderer<{}, { message: string }>
|
|
296
|
+
) {
|
|
297
|
+
|
|
298
|
+
// Automatic layout form the nearest _layout folder
|
|
299
|
+
const layout = getLayout('Error ' + code, options);
|
|
300
|
+
|
|
301
|
+
const route: TErrorRoute = {
|
|
302
|
+
code,
|
|
303
|
+
controller: (context: TClientOrServerContextForPage) => new ClientPage(route, renderer, context, layout),
|
|
304
|
+
options
|
|
305
|
+
};
|
|
306
|
+
|
|
307
|
+
this.errors[code] = route;
|
|
308
|
+
|
|
309
|
+
return route;
|
|
310
|
+
}
|
|
311
|
+
|
|
312
|
+
|
|
313
|
+
/*----------------------------------
|
|
314
|
+
- RESOLUTION
|
|
315
|
+
----------------------------------*/
|
|
316
|
+
public async resolve(request: ClientRequest<this>): Promise<ClientPage> {
|
|
317
|
+
|
|
318
|
+
debug && console.log(LogPrefix, 'Resolving request', request.path, Object.keys(request.data));
|
|
319
|
+
|
|
320
|
+
for (let iRoute = 0; iRoute < this.routes.length; iRoute++) {
|
|
321
|
+
|
|
322
|
+
let route = this.routes[iRoute];
|
|
323
|
+
if (!('regex' in route))
|
|
324
|
+
continue;
|
|
325
|
+
|
|
326
|
+
const isMatching = matchRoute(route, request);
|
|
327
|
+
if (!isMatching)
|
|
328
|
+
continue;
|
|
329
|
+
|
|
330
|
+
// Create response
|
|
331
|
+
debug && console.log(LogPrefix, 'Resolved request', request.path, '| Route:', route);
|
|
332
|
+
const page = await this.createResponse(route, request);
|
|
333
|
+
|
|
334
|
+
return page;
|
|
335
|
+
|
|
336
|
+
};
|
|
337
|
+
|
|
338
|
+
const notFoundRoute = this.errors[404];
|
|
339
|
+
return await this.createResponse(notFoundRoute, request, {
|
|
340
|
+
error: new Error("Page not found")
|
|
341
|
+
});
|
|
342
|
+
}
|
|
343
|
+
|
|
344
|
+
private async load(route: TUnresolvedNormalRoute): Promise<TRoute>;
|
|
345
|
+
private async load(route: TUnresolvedErrorRoute): Promise<TErrorRoute>;
|
|
346
|
+
private async load(route: TUnresolvedNormalRoute | TUnresolvedErrorRoute): Promise<TRoute | TErrorRoute> {
|
|
347
|
+
|
|
348
|
+
//throw new Error(`Failed to load route: ${route.chunk}`);
|
|
349
|
+
|
|
350
|
+
let fetched: TFetchedRoute;
|
|
351
|
+
if (typeof route.load === 'function') {
|
|
352
|
+
|
|
353
|
+
debug && console.log(`Fetching route ${route.chunk} ...`, route);
|
|
354
|
+
try {
|
|
355
|
+
|
|
356
|
+
const loaded = await route.load();
|
|
357
|
+
|
|
358
|
+
fetched = loaded.__register(this.app);
|
|
359
|
+
|
|
360
|
+
} catch (e) {
|
|
361
|
+
console.error(`Failed to fetch the route ${route.chunk}`, e);
|
|
362
|
+
try {
|
|
363
|
+
this.context.modal.show(() => (
|
|
364
|
+
<div class="card col bg white w-3">
|
|
365
|
+
<h2>New Update Available!</h2>
|
|
366
|
+
<p>
|
|
367
|
+
A new version of the website is available. Please refresh the page to continue.
|
|
368
|
+
</p>
|
|
369
|
+
<Button type="primary" onClick={() => window.location.reload()}>
|
|
370
|
+
Reload
|
|
371
|
+
</Button>
|
|
372
|
+
</div>
|
|
373
|
+
));
|
|
374
|
+
} catch (error) {}
|
|
375
|
+
throw new Error("A new version of the website is available. Please refresh the page.");
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
} else {
|
|
379
|
+
|
|
380
|
+
debug && console.log(`Route already fetched: ${route.chunk}`, route.load);
|
|
381
|
+
fetched = route.load;
|
|
382
|
+
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
debug && console.log(`Route fetched: ${route.chunk}`, fetched);
|
|
386
|
+
return {
|
|
387
|
+
...fetched,
|
|
388
|
+
regex: route.regex,
|
|
389
|
+
keys: route.keys
|
|
390
|
+
}
|
|
391
|
+
}
|
|
392
|
+
|
|
393
|
+
public set(data: TObjetDonnees) {
|
|
394
|
+
throw new Error(`router.set was not attached to the router component.`);
|
|
395
|
+
}
|
|
396
|
+
|
|
397
|
+
private async initialRender(route: TUnresolvedRoute | undefined) {
|
|
398
|
+
|
|
399
|
+
debug && console.log(LogPrefix, `Initial render route`, route);
|
|
400
|
+
|
|
401
|
+
if (!location)
|
|
402
|
+
throw new Error(`Unable to retrieve current location.`);
|
|
403
|
+
|
|
404
|
+
if (!route)
|
|
405
|
+
throw new Error(`Unable to resolve route.`);
|
|
406
|
+
|
|
407
|
+
const request = new ClientRequest(location, this);
|
|
408
|
+
|
|
409
|
+
// Restituate SSR response
|
|
410
|
+
let apiData: {} = {}
|
|
411
|
+
if (this.ssrContext) {
|
|
412
|
+
|
|
413
|
+
request.user = this.ssrContext.user || null;
|
|
414
|
+
|
|
415
|
+
request.data = this.ssrContext.request.data;
|
|
416
|
+
|
|
417
|
+
apiData = this.ssrContext.page.data || {};
|
|
418
|
+
}
|
|
419
|
+
|
|
420
|
+
// Replacer api data par ssr data
|
|
421
|
+
|
|
422
|
+
const response = await this.createResponse(route, request, apiData);
|
|
423
|
+
|
|
424
|
+
ReactDOM.hydrate((
|
|
425
|
+
<App context={response.context} />
|
|
426
|
+
), document.body, () => {
|
|
427
|
+
|
|
428
|
+
console.log(`Render complete`);
|
|
429
|
+
|
|
430
|
+
this.runHook('page.rendered', request);
|
|
431
|
+
});
|
|
432
|
+
}
|
|
433
|
+
|
|
434
|
+
private async createResponse(
|
|
435
|
+
route: TUnresolvedRoute | TErrorRoute | TRoute,
|
|
436
|
+
request: ClientRequest<this>,
|
|
437
|
+
pageData: {} = {}
|
|
438
|
+
): Promise<ClientPage> {
|
|
439
|
+
|
|
440
|
+
// Load the route if not done before
|
|
441
|
+
if ('load' in route)
|
|
442
|
+
route = this.routes[route.index] = await this.load(route);
|
|
443
|
+
|
|
444
|
+
// Run controller
|
|
445
|
+
// TODO: tell that ruController on the client side always returns pages
|
|
446
|
+
try {
|
|
447
|
+
|
|
448
|
+
const response = new ClientResponse<this, ClientPage>(request, route);
|
|
449
|
+
return await response.runController(pageData);
|
|
450
|
+
|
|
451
|
+
} catch (error) {
|
|
452
|
+
|
|
453
|
+
return await this.createErrorResponse(error, request);
|
|
454
|
+
}
|
|
455
|
+
}
|
|
456
|
+
|
|
457
|
+
private async createErrorResponse(
|
|
458
|
+
e: any,
|
|
459
|
+
request: ClientRequest<this>,
|
|
460
|
+
pageData: {} = {}
|
|
461
|
+
): Promise<ClientPage> {
|
|
462
|
+
|
|
463
|
+
const code = 'http' in e ? e.http : 500;
|
|
464
|
+
console.log(`Loading error page ` + code);
|
|
465
|
+
let route = this.errors[code];
|
|
466
|
+
|
|
467
|
+
// Nor page configurated for this error
|
|
468
|
+
if (route === undefined) {
|
|
469
|
+
console.error(`Error page for http error code ${code} not found.`, this.errors, this.routes);
|
|
470
|
+
e.http = 404;
|
|
471
|
+
this.app.handleError(e);
|
|
472
|
+
throw new Error(`Error page for http error code ${code} not found.`);
|
|
473
|
+
}
|
|
474
|
+
|
|
475
|
+
// Load if not done before
|
|
476
|
+
if ('load' in route)
|
|
477
|
+
route = this.errors[code] = await this.load(route);
|
|
478
|
+
|
|
479
|
+
const response = new ClientResponse<this, ClientPage>(request, route);
|
|
480
|
+
return await response.runController(pageData);
|
|
481
|
+
}
|
|
482
|
+
|
|
483
|
+
/*----------------------------------
|
|
484
|
+
- HOOKS
|
|
485
|
+
----------------------------------*/
|
|
486
|
+
private hooks: {
|
|
487
|
+
[hookname in THookName]?: (THookCallback<this> | null)[]
|
|
488
|
+
} = {}
|
|
489
|
+
|
|
490
|
+
public on(hookName: THookName, callback: THookCallback<this>) {
|
|
491
|
+
|
|
492
|
+
debug && console.info(LogPrefix, `Register hook ${hookName}`);
|
|
493
|
+
|
|
494
|
+
let cbIndex: number;
|
|
495
|
+
let callbacks = this.hooks[hookName];
|
|
496
|
+
if (!callbacks) {
|
|
497
|
+
cbIndex = 0;
|
|
498
|
+
callbacks = this.hooks[hookName] = [callback]
|
|
499
|
+
} else {
|
|
500
|
+
cbIndex = callbacks.length;
|
|
501
|
+
callbacks.push(callback);
|
|
502
|
+
}
|
|
503
|
+
|
|
504
|
+
// Listener remover
|
|
505
|
+
return () => {
|
|
506
|
+
debug && console.info(LogPrefix, `De-register hook ${hookName} (index ${cbIndex})`);
|
|
507
|
+
this.hooks[hookName] = this.hooks[hookName]?.filter(
|
|
508
|
+
(_, index) => index !== cbIndex
|
|
509
|
+
);
|
|
510
|
+
}
|
|
511
|
+
|
|
512
|
+
}
|
|
513
|
+
|
|
514
|
+
public runHook(hookName: THookName, request: ClientRequest<this>) {
|
|
515
|
+
const callbacks = this.hooks[hookName];
|
|
516
|
+
if (callbacks)
|
|
517
|
+
for (const callback of callbacks)
|
|
518
|
+
// callback can be null since we use delete to unregister
|
|
519
|
+
callback && callback(request);
|
|
520
|
+
}
|
|
521
|
+
}
|