proteum 1.0.2 → 2.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/AGENTS.md +101 -0
- package/agents/codex/AGENTS.md +95 -0
- package/agents/codex/CODING_STYLE.md +71 -0
- package/agents/codex/agents.md.zip +0 -0
- package/agents/codex/client/AGENTS.md +102 -0
- package/agents/codex/client/pages/AGENTS.md +35 -0
- package/agents/codex/server/routes/AGENTS.md +12 -0
- package/agents/codex/server/services/AGENTS.md +137 -0
- package/agents/codex/tests/AGENTS.md +8 -0
- package/cli/app/config.ts +13 -11
- package/cli/app/index.ts +74 -82
- package/cli/bin.js +1 -1
- package/cli/commands/build.ts +51 -14
- package/cli/commands/check.ts +19 -0
- package/cli/commands/deploy/app.ts +4 -8
- package/cli/commands/deploy/web.ts +16 -20
- package/cli/commands/dev.ts +189 -64
- package/cli/commands/devEvents.ts +106 -0
- package/cli/commands/init.ts +63 -57
- package/cli/commands/lint.ts +21 -0
- package/cli/commands/refresh.ts +18 -0
- package/cli/commands/typecheck.ts +18 -0
- package/cli/compiler/client/identite.ts +80 -53
- package/cli/compiler/client/index.ts +139 -213
- package/cli/compiler/common/bundleAnalysis.ts +94 -0
- package/cli/compiler/common/clientManifest.ts +67 -0
- package/cli/compiler/common/controllers.ts +288 -0
- package/cli/compiler/common/files/autres.ts +7 -18
- package/cli/compiler/common/files/images.ts +40 -37
- package/cli/compiler/common/files/style.ts +11 -22
- package/cli/compiler/common/generatedRouteModules.ts +368 -0
- package/cli/compiler/common/index.ts +31 -65
- package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
- package/cli/compiler/common/rspackAliases.ts +13 -0
- package/cli/compiler/common/scripts.ts +37 -0
- package/cli/compiler/index.ts +781 -230
- package/cli/compiler/server/index.ts +59 -75
- package/cli/compiler/writeIfChanged.ts +21 -0
- package/cli/index.ts +71 -72
- package/cli/paths.ts +51 -57
- package/cli/print.ts +17 -11
- package/cli/tsconfig.json +5 -4
- package/cli/utils/agents.ts +100 -0
- package/cli/utils/check.ts +71 -0
- package/cli/utils/index.ts +1 -3
- package/cli/utils/keyboard.ts +8 -25
- package/cli/utils/runProcess.ts +30 -0
- package/client/app/component.tsx +29 -29
- package/client/app/index.ts +36 -57
- package/client/app/service.ts +7 -12
- package/client/app.tsconfig.json +2 -2
- package/client/components/Dialog/Manager.ssr.tsx +40 -0
- package/client/components/Dialog/Manager.tsx +119 -150
- package/client/components/Dialog/status.tsx +3 -3
- package/client/components/index.ts +1 -1
- package/client/components/types.d.ts +1 -3
- package/client/dev/hmr.ts +65 -0
- package/client/global.d.ts +2 -2
- package/client/hooks.ts +6 -9
- package/client/index.ts +2 -1
- package/client/islands/index.ts +7 -0
- package/client/islands/useDeferredModule.ts +199 -0
- package/client/pages/_layout/index.tsx +4 -12
- package/client/pages/useHeader.tsx +14 -21
- package/client/router.ts +27 -0
- package/client/services/router/components/Link.tsx +34 -27
- package/client/services/router/components/Page.tsx +6 -14
- package/client/services/router/components/router.ssr.tsx +36 -0
- package/client/services/router/components/router.tsx +63 -83
- package/client/services/router/index.tsx +185 -220
- package/client/services/router/request/api.ts +97 -119
- package/client/services/router/request/history.ts +2 -2
- package/client/services/router/request/index.ts +13 -12
- package/client/services/router/request/multipart.ts +72 -62
- package/client/services/router/response/index.tsx +68 -61
- package/client/services/router/response/page.ts +28 -32
- package/client/utils/dom.ts +17 -33
- package/common/app/index.ts +3 -3
- package/common/data/chaines/index.ts +22 -23
- package/common/data/dates.ts +35 -70
- package/common/data/markdown.ts +42 -39
- package/common/dev/serverHotReload.ts +26 -0
- package/common/errors/index.tsx +110 -142
- package/common/router/contracts.ts +29 -0
- package/common/router/index.ts +89 -108
- package/common/router/layouts.ts +34 -47
- package/common/router/pageSetup.ts +50 -0
- package/common/router/register.ts +53 -24
- package/common/router/request/api.ts +30 -36
- package/common/router/request/index.ts +2 -8
- package/common/router/response/index.ts +8 -15
- package/common/router/response/page.ts +70 -58
- package/common/utils.ts +1 -1
- package/doc/TODO.md +1 -1
- package/eslint.js +62 -0
- package/package.json +14 -49
- package/prettier.config.cjs +9 -0
- package/scripts/cleanup-generated-controllers.ts +62 -0
- package/scripts/fix-reference-app-typing.ts +490 -0
- package/scripts/refactor-client-app-imports.ts +244 -0
- package/scripts/refactor-client-pages.ts +587 -0
- package/scripts/refactor-server-controllers.ts +470 -0
- package/scripts/refactor-server-runtime-aliases.ts +360 -0
- package/scripts/restore-client-app-import-files.ts +41 -0
- package/scripts/restore-files-from-git-head.ts +20 -0
- package/scripts/update-codex-agents.ts +35 -0
- package/server/app/commands.ts +35 -64
- package/server/app/container/config.ts +48 -59
- package/server/app/container/console/index.ts +202 -248
- package/server/app/container/index.ts +33 -71
- package/server/app/controller/index.ts +61 -0
- package/server/app/index.ts +39 -105
- package/server/app/service/container.ts +41 -42
- package/server/app/service/index.ts +120 -147
- package/server/context.ts +1 -1
- package/server/index.ts +25 -1
- package/server/services/auth/index.ts +75 -115
- package/server/services/auth/router/index.ts +31 -32
- package/server/services/auth/router/request.ts +14 -16
- package/server/services/cron/CronTask.ts +13 -26
- package/server/services/cron/index.ts +14 -36
- package/server/services/disks/driver.ts +40 -58
- package/server/services/disks/drivers/local/index.ts +79 -90
- package/server/services/disks/drivers/s3/index.ts +116 -163
- package/server/services/disks/index.ts +23 -38
- package/server/services/email/index.ts +45 -104
- package/server/services/email/utils.ts +14 -27
- package/server/services/fetch/index.ts +53 -85
- package/server/services/prisma/Facet.ts +39 -91
- package/server/services/prisma/index.ts +74 -110
- package/server/services/router/generatedRuntime.ts +29 -0
- package/server/services/router/http/index.ts +78 -73
- package/server/services/router/http/multipart.ts +19 -42
- package/server/services/router/index.ts +378 -365
- package/server/services/router/request/api.ts +26 -25
- package/server/services/router/request/index.ts +44 -51
- package/server/services/router/request/service.ts +7 -11
- package/server/services/router/request/validation/zod.ts +111 -148
- package/server/services/router/response/index.ts +110 -125
- package/server/services/router/response/mask/Filter.ts +31 -72
- package/server/services/router/response/mask/index.ts +8 -15
- package/server/services/router/response/mask/selecteurs.ts +11 -25
- package/server/services/router/response/page/clientManifest.ts +25 -0
- package/server/services/router/response/page/document.tsx +199 -127
- package/server/services/router/response/page/index.tsx +89 -94
- package/server/services/router/service.ts +13 -15
- package/server/services/schema/index.ts +17 -26
- package/server/services/schema/request.ts +19 -33
- package/server/services/schema/router/index.ts +8 -11
- package/server/services/security/encrypt/aes/index.ts +15 -35
- package/server/utils/slug.ts +29 -35
- package/skills/clean-project-code/SKILL.md +63 -0
- package/skills/clean-project-code/agents/openai.yaml +4 -0
- package/tsconfig.common.json +4 -3
- package/tsconfig.json +4 -1
- package/types/aliases.d.ts +17 -21
- package/types/controller-input.test.ts +48 -0
- package/types/express-extra.d.ts +6 -0
- package/types/global/constants.d.ts +13 -0
- package/types/global/express-extra.d.ts +6 -0
- package/types/global/modules.d.ts +13 -16
- package/types/global/utils.d.ts +17 -49
- package/types/global/vendors.d.ts +62 -0
- package/types/icons.d.ts +65 -1
- package/types/uuid.d.ts +3 -0
- package/types/vendors.d.ts +62 -0
- package/cli/compiler/common/babel/index.ts +0 -170
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +0 -586
- package/cli/compiler/common/babel/routes/imports.ts +0 -127
- package/cli/compiler/common/babel/routes/routes.ts +0 -1130
- package/client/services/captcha/index.ts +0 -67
- package/client/services/socket/index.ts +0 -147
- package/common/data/rte/nodes.ts +0 -83
- package/common/data/stats.ts +0 -90
- package/common/utils/rte.ts +0 -183
- package/server/services/auth/old.ts +0 -277
- package/server/services/cache/commands.ts +0 -41
- package/server/services/cache/index.ts +0 -297
- package/server/services/cache/service.json +0 -6
- package/server/services/socket/index.ts +0 -162
- package/server/services/socket/scope.ts +0 -226
- package/server/services/socket/service.json +0 -6
- package/server/services_old/SocketClient.ts +0 -92
- package/server/services_old/Token.old.ts +0 -97
|
@@ -11,13 +11,16 @@
|
|
|
11
11
|
import express from 'express';
|
|
12
12
|
|
|
13
13
|
// Core
|
|
14
|
-
import
|
|
14
|
+
import context from '@server/context';
|
|
15
15
|
import type { AnyRouterService, default as ServerRouter, TServerRouter, TAnyRouter } from '@server/services/router';
|
|
16
16
|
import ServerRequest from '@server/services/router/request';
|
|
17
|
-
import { TRoute, TAnyRoute, TDomainsList } from '@common/router';
|
|
17
|
+
import { TMatchedRoute, TRoute, TAnyRoute, TDomainsList } from '@common/router';
|
|
18
18
|
import { NotFound, Forbidden, Anomaly } from '@common/errors';
|
|
19
19
|
import BaseResponse, { TResponseData } from '@common/router/response';
|
|
20
|
+
import { splitRouteSetupResult } from '@common/router/pageSetup';
|
|
20
21
|
import Page from './page';
|
|
22
|
+
import createControllers from '@/common/.generated/controllers';
|
|
23
|
+
import type { TControllers } from '@/common/.generated/controllers';
|
|
21
24
|
|
|
22
25
|
// To move into a new npm module: json-mask
|
|
23
26
|
import jsonMask from './mask';
|
|
@@ -32,72 +35,62 @@ import type { TBasicUser } from '@server/services/auth';
|
|
|
32
35
|
const debug = true;
|
|
33
36
|
|
|
34
37
|
export type TBasicSSrData = {
|
|
35
|
-
request: { data: TObjetDonnees
|
|
36
|
-
page: { chunkId: string
|
|
37
|
-
user: TBasicUser | null
|
|
38
|
-
domains: TDomainsList
|
|
39
|
-
}
|
|
38
|
+
request: { data: TObjetDonnees; id: string };
|
|
39
|
+
page: { chunkId: string; data?: TObjetDonnees };
|
|
40
|
+
user: TBasicUser | null;
|
|
41
|
+
domains: TDomainsList;
|
|
42
|
+
};
|
|
40
43
|
|
|
41
|
-
export type TRouterContext<TRouter extends TServerRouter> =
|
|
44
|
+
export type TRouterContext<TRouter extends TServerRouter> =
|
|
42
45
|
// Request context
|
|
43
46
|
{
|
|
44
|
-
app: TRouter[
|
|
45
|
-
context: TRouterContext<TRouter
|
|
46
|
-
request: ServerRequest<TRouter
|
|
47
|
-
api: ServerRequest<TRouter>[
|
|
48
|
-
response: ServerResponse<TRouter
|
|
49
|
-
route:
|
|
50
|
-
page?: Page
|
|
51
|
-
|
|
52
|
-
Router: TRouter
|
|
53
|
-
}
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
export type TRouterContextServices<
|
|
59
|
-
TRouter extends TServerRouter,
|
|
60
|
-
TPlugins = TRouter["config"]["plugins"]
|
|
61
|
-
> = (
|
|
47
|
+
app: TRouter['app'];
|
|
48
|
+
context: TRouterContext<TRouter>; // = this
|
|
49
|
+
request: ServerRequest<TRouter>;
|
|
50
|
+
api: ServerRequest<TRouter>['api'];
|
|
51
|
+
response: ServerResponse<TRouter>;
|
|
52
|
+
route: TAnyRoute<TRouterContext<TRouter>>;
|
|
53
|
+
page?: Page;
|
|
54
|
+
|
|
55
|
+
Router: TRouter;
|
|
56
|
+
} & TRouterContextServices<TRouter> &
|
|
57
|
+
TControllers &
|
|
58
|
+
TRouterRequestContext<TRouter>;
|
|
59
|
+
|
|
60
|
+
export type TRouterContextServices<TRouter extends TServerRouter, TPlugins = TRouter['config']['plugins']> =
|
|
62
61
|
// Custom context via servuces
|
|
63
62
|
// For each roiuter service, return the request service (returned by roiuterService.requestService() )
|
|
64
63
|
{
|
|
65
|
-
[serviceName in keyof TPlugins]: TPlugins[serviceName] extends AnyRouterService
|
|
66
|
-
? ReturnType<TPlugins[serviceName][
|
|
67
|
-
: TPlugins[serviceName]
|
|
68
|
-
}
|
|
69
|
-
)
|
|
70
|
-
|
|
71
|
-
export type TRouterRequestContext<
|
|
72
|
-
TRouter extends TServerRouter
|
|
73
|
-
> = ReturnType<TRouter["config"]["context"]>
|
|
64
|
+
[serviceName in keyof TPlugins]: TPlugins[serviceName] extends AnyRouterService
|
|
65
|
+
? Exclude<ReturnType<TPlugins[serviceName]['requestService']>, null | undefined>
|
|
66
|
+
: TPlugins[serviceName];
|
|
67
|
+
};
|
|
74
68
|
|
|
69
|
+
export type TRouterRequestContext<TRouter extends TServerRouter> = ReturnType<TRouter['config']['context']>;
|
|
75
70
|
|
|
76
71
|
/*----------------------------------
|
|
77
72
|
- CLASSE
|
|
78
73
|
----------------------------------*/
|
|
79
74
|
export default class ServerResponse<
|
|
80
75
|
TRouter extends TAnyRouter,
|
|
81
|
-
TRequestContext = TRouterContext<
|
|
82
|
-
TData extends TResponseData = TResponseData
|
|
76
|
+
TRequestContext extends TRouterContext<TRouter> = TRouterContext<TRouter>,
|
|
77
|
+
TData extends TResponseData = TResponseData,
|
|
83
78
|
> extends BaseResponse<TData, ServerRequest<TRouter>> {
|
|
84
|
-
|
|
85
79
|
// Services
|
|
86
|
-
public app:
|
|
80
|
+
public app: TRouter['app'];
|
|
87
81
|
public router: TRouter;
|
|
88
82
|
|
|
89
83
|
// Response metadata
|
|
90
84
|
public statusCode: number = 200;
|
|
91
|
-
public headers: {[cle: string]: string} = {}
|
|
92
|
-
public cookie: express.Response[
|
|
93
|
-
public clearCookie: express.Response[
|
|
85
|
+
public headers: { [cle: string]: string } = {};
|
|
86
|
+
public cookie: express.Response['cookie'];
|
|
87
|
+
public clearCookie: express.Response['clearCookie'];
|
|
94
88
|
public canonicalUrl: URL;
|
|
95
89
|
|
|
96
90
|
// If data was provided by at lead one controller
|
|
97
91
|
public wasProvided = false;
|
|
98
92
|
|
|
99
|
-
public constructor(
|
|
100
|
-
|
|
93
|
+
public constructor(request: ServerRequest<TRouter>) {
|
|
101
94
|
super(request);
|
|
102
95
|
|
|
103
96
|
this.cookie = this.request.res.cookie.bind(this.request.res);
|
|
@@ -110,44 +103,42 @@ export default class ServerResponse<
|
|
|
110
103
|
this.canonicalUrl.search = '';
|
|
111
104
|
}
|
|
112
105
|
|
|
113
|
-
public async runController(
|
|
114
|
-
|
|
106
|
+
public async runController(route: TAnyRoute<TRouterContext<TRouter>>, additionnalData: {} = {}) {
|
|
115
107
|
this.route = route;
|
|
116
108
|
|
|
117
109
|
// Update canonical url
|
|
118
110
|
this.updateCanonicalUrl(route);
|
|
119
111
|
|
|
120
112
|
// Create response context for controllers
|
|
121
|
-
const
|
|
113
|
+
const requestContext = await this.createContext(route);
|
|
114
|
+
const contextStore = context.getStore() as
|
|
115
|
+
| { requestContext?: TRouterContext<TAnyRouter>; inputSchemaUsed?: boolean }
|
|
116
|
+
| undefined;
|
|
117
|
+
if (contextStore) {
|
|
118
|
+
contextStore.requestContext = requestContext;
|
|
119
|
+
contextStore.inputSchemaUsed = false;
|
|
120
|
+
}
|
|
122
121
|
|
|
123
122
|
// Run controller
|
|
124
|
-
const content = await this.route.controller(
|
|
125
|
-
if (content === undefined)
|
|
126
|
-
return;
|
|
123
|
+
const content = await this.route.controller(requestContext);
|
|
124
|
+
if (content === undefined) return;
|
|
127
125
|
|
|
128
126
|
// No need to process the content
|
|
129
|
-
if (content instanceof ServerResponse)
|
|
130
|
-
return;
|
|
127
|
+
if (content instanceof ServerResponse) return;
|
|
131
128
|
// Render react page to html
|
|
132
|
-
else if (content instanceof Page)
|
|
133
|
-
await this.render(content, context, additionnalData);
|
|
129
|
+
else if (content instanceof Page) await this.render(content, requestContext, additionnalData);
|
|
134
130
|
// Return HTML
|
|
135
|
-
else if (typeof content === 'string' && this.route.options.accept === 'html')
|
|
136
|
-
await this.html(content);
|
|
131
|
+
else if (typeof content === 'string' && this.route.options.accept === 'html') await this.html(content);
|
|
137
132
|
// Return JSON
|
|
138
|
-
else
|
|
139
|
-
await this.json(content);
|
|
133
|
+
else await this.json(content);
|
|
140
134
|
}
|
|
141
135
|
|
|
142
|
-
private updateCanonicalUrl(
|
|
143
|
-
|
|
144
|
-
if (!route.options.canonicalParams)
|
|
145
|
-
return;
|
|
136
|
+
private updateCanonicalUrl(route: TAnyRoute<TRouterContext<TRouter>>) {
|
|
137
|
+
if (!route.options.canonicalParams) return;
|
|
146
138
|
|
|
147
139
|
for (const key of route.options.canonicalParams) {
|
|
148
|
-
const paramValue = this.request.data[
|
|
149
|
-
if (paramValue !== undefined)
|
|
150
|
-
this.canonicalUrl.searchParams.set(key, paramValue);
|
|
140
|
+
const paramValue = this.request.data[key];
|
|
141
|
+
if (paramValue !== undefined) this.canonicalUrl.searchParams.set(key, paramValue);
|
|
151
142
|
}
|
|
152
143
|
}
|
|
153
144
|
|
|
@@ -155,51 +146,58 @@ export default class ServerResponse<
|
|
|
155
146
|
- INTERNAL
|
|
156
147
|
----------------------------------*/
|
|
157
148
|
|
|
158
|
-
|
|
159
|
-
|
|
149
|
+
public async resolveRouteOptions(
|
|
150
|
+
route: TMatchedRoute<TRouterContext<TRouter>>,
|
|
151
|
+
): Promise<TMatchedRoute<TRouterContext<TRouter>>> {
|
|
152
|
+
const setup = route.options.setup;
|
|
153
|
+
if (!setup) return route;
|
|
154
|
+
|
|
155
|
+
const requestContext = await this.createContext(route);
|
|
156
|
+
const { options } = splitRouteSetupResult(((setup as any)({ ...requestContext, data: this.request.data }) as {}) || {});
|
|
157
|
+
|
|
158
|
+
return { ...route, options: { ...route.options, ...options } };
|
|
159
|
+
}
|
|
160
160
|
|
|
161
|
+
// Start controller services
|
|
162
|
+
private async createContext(route: TAnyRoute<TRouterContext<TRouter>>): Promise<TRequestContext> {
|
|
161
163
|
const contextServices = this.router.createContextServices(this.request);
|
|
162
164
|
|
|
163
|
-
const customSsrData = this.router.config.context(this.request, this.app)
|
|
165
|
+
const customSsrData = this.router.config.context(this.request, this.app) as TRouterRequestContext<TRouter>;
|
|
164
166
|
|
|
165
167
|
// TODO: transmiss safe data (especially for Router), as Router info could be printed on client side
|
|
166
|
-
const
|
|
168
|
+
const requestContext = {
|
|
167
169
|
// Router context
|
|
168
170
|
app: this.app,
|
|
169
|
-
context: undefined
|
|
171
|
+
context: undefined!,
|
|
170
172
|
request: this.request,
|
|
171
173
|
response: this,
|
|
172
174
|
route: route,
|
|
173
175
|
api: this.request.api,
|
|
174
176
|
|
|
175
177
|
Router: this.router,
|
|
178
|
+
...(this.app as {}),
|
|
179
|
+
...createControllers(this.request.api),
|
|
176
180
|
|
|
177
181
|
// Router services
|
|
178
182
|
...(contextServices as TRouterContextServices<TRouter>),
|
|
179
|
-
...customSsrData
|
|
180
|
-
}
|
|
183
|
+
...customSsrData,
|
|
184
|
+
} as TRequestContext;
|
|
181
185
|
|
|
182
|
-
|
|
186
|
+
requestContext.context = requestContext;
|
|
183
187
|
|
|
184
|
-
return
|
|
188
|
+
return requestContext;
|
|
185
189
|
}
|
|
186
190
|
|
|
187
|
-
public forSsr(
|
|
188
|
-
|
|
191
|
+
public forSsr(page: Page<TRouter>): TBasicSSrData {
|
|
189
192
|
const customSsrData = this.router.config.context(this.request, this.app);
|
|
190
193
|
|
|
191
194
|
return {
|
|
192
|
-
request: {
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
},
|
|
196
|
-
page: {
|
|
197
|
-
chunkId: page.chunkId,
|
|
198
|
-
data: page.data
|
|
199
|
-
},
|
|
195
|
+
request: { id: this.request.id, data: this.request.data },
|
|
196
|
+
page: { chunkId: page.chunkId || '', data: page.data },
|
|
197
|
+
user: this.request.user,
|
|
200
198
|
domains: this.router.config.domains,
|
|
201
|
-
...customSsrData
|
|
202
|
-
}
|
|
199
|
+
...customSsrData,
|
|
200
|
+
};
|
|
203
201
|
}
|
|
204
202
|
|
|
205
203
|
public status(code: number) {
|
|
@@ -207,29 +205,29 @@ export default class ServerResponse<
|
|
|
207
205
|
return this;
|
|
208
206
|
}
|
|
209
207
|
|
|
210
|
-
public setHeaders(
|
|
208
|
+
public setHeaders(headers: { [cle: string]: string }) {
|
|
211
209
|
this.headers = { ...this.headers, ...headers };
|
|
212
210
|
return this;
|
|
213
211
|
}
|
|
214
|
-
|
|
212
|
+
|
|
215
213
|
/*----------------------------------
|
|
216
214
|
- DATA RESPONSE
|
|
217
215
|
----------------------------------*/
|
|
218
216
|
|
|
219
|
-
public type(
|
|
217
|
+
public type(mimetype: string) {
|
|
220
218
|
this.headers['Content-Type'] = mimetype;
|
|
221
219
|
return this;
|
|
222
220
|
}
|
|
223
221
|
|
|
224
|
-
public async render(
|
|
225
|
-
|
|
222
|
+
public async render(page: Page, context: TRouterContext<TRouter>, additionnalData: {}) {
|
|
226
223
|
// Set page in context for the client side
|
|
227
224
|
context.page = page;
|
|
228
|
-
|
|
225
|
+
|
|
229
226
|
// Prepare page & fetch data
|
|
230
227
|
page.data = await page.fetchData();
|
|
231
|
-
if (additionnalData !== undefined)
|
|
232
|
-
|
|
228
|
+
if (additionnalData !== undefined)
|
|
229
|
+
// Example: error message for error pages
|
|
230
|
+
page.data = { ...page.data, ...additionnalData };
|
|
233
231
|
|
|
234
232
|
// Render page
|
|
235
233
|
await this.router.runHook('render', page);
|
|
@@ -238,51 +236,42 @@ export default class ServerResponse<
|
|
|
238
236
|
|
|
239
237
|
// Never put html in the cache
|
|
240
238
|
// Because assets urls need to be updated when their hash has been changed by a release
|
|
241
|
-
this.request.res.setHeader(
|
|
242
|
-
|
|
239
|
+
this.request.res.setHeader('Expires', '0');
|
|
243
240
|
}
|
|
244
241
|
|
|
245
242
|
public async json(data?: any, mask?: string) {
|
|
246
|
-
|
|
247
243
|
// RAPPEL: On jsonMask aussi les requetes internes, car leurs données seront imprimées au SSR pour le contexte client
|
|
248
244
|
// filtreApi vérifie systèmatiquement si la donnée a été filtrée
|
|
249
245
|
// NOTE: On évite le filtrage sans masque spécifié (performances + risques erreurs)
|
|
250
|
-
if (mask !== undefined)
|
|
251
|
-
data = await jsonMask(data, mask, this.request.user);
|
|
246
|
+
if (mask !== undefined) data = await jsonMask(data, mask);
|
|
252
247
|
|
|
253
248
|
this.headers['Content-Type'] = 'application/json';
|
|
254
|
-
this.data = this.request.isVirtual ? data : JSON.stringify(data);
|
|
249
|
+
this.data = (this.request.isVirtual ? data : JSON.stringify(data)) as TData;
|
|
255
250
|
return this.end();
|
|
256
251
|
}
|
|
257
252
|
|
|
258
253
|
public html(html: string) {
|
|
259
|
-
|
|
260
254
|
this.headers['Content-Type'] = 'text/html';
|
|
261
|
-
this.data = html;
|
|
255
|
+
this.data = html as TData;
|
|
262
256
|
return this.end();
|
|
263
|
-
|
|
264
257
|
}
|
|
265
258
|
|
|
266
259
|
public xml(xml: string) {
|
|
267
|
-
|
|
268
260
|
this.headers['Content-Type'] = 'text/xml';
|
|
269
|
-
this.data = xml;
|
|
261
|
+
this.data = xml as TData;
|
|
270
262
|
return this.end();
|
|
271
263
|
}
|
|
272
264
|
|
|
273
265
|
public text(text: string, mimetype: string = 'text/plain') {
|
|
274
|
-
|
|
275
266
|
this.headers['Content-Type'] = mimetype;
|
|
276
|
-
this.data = text;
|
|
267
|
+
this.data = text as TData;
|
|
277
268
|
return this.end();
|
|
278
269
|
}
|
|
279
270
|
|
|
280
271
|
// TODO: https://github.com/adonisjs/http-server/blob/develop/src/Response/index.ts#L430
|
|
281
|
-
public async file(
|
|
282
|
-
|
|
272
|
+
public async file(filename: string, mimetype?: string) {
|
|
283
273
|
// Securité
|
|
284
|
-
if (filename.includes('..'))
|
|
285
|
-
throw new Forbidden("Disallowed");
|
|
274
|
+
if (filename.includes('..')) throw new Forbidden('Disallowed');
|
|
286
275
|
|
|
287
276
|
// // Force absolute path
|
|
288
277
|
// if (!filename.startsWith( this.app.path.root ))
|
|
@@ -291,7 +280,9 @@ export default class ServerResponse<
|
|
|
291
280
|
// : this.app.path.data + '/' + filename;
|
|
292
281
|
// Disk not provided = file response disabled
|
|
293
282
|
if (this.router.disks === undefined)
|
|
294
|
-
throw new Anomaly(
|
|
283
|
+
throw new Anomaly(
|
|
284
|
+
'Router: Unable to return file response in router, because no disk has been given in the router config.',
|
|
285
|
+
);
|
|
295
286
|
|
|
296
287
|
// Retirve disk driver
|
|
297
288
|
const disk = this.router.disks.get('default');
|
|
@@ -299,29 +290,24 @@ export default class ServerResponse<
|
|
|
299
290
|
// Verif existance
|
|
300
291
|
const fileExists = await disk.exists('data', filename);
|
|
301
292
|
if (!fileExists) {
|
|
302
|
-
console.log(
|
|
293
|
+
console.log('File ' + filename + ' was not found.');
|
|
303
294
|
throw new NotFound();
|
|
304
295
|
}
|
|
305
296
|
|
|
306
297
|
// envoi filename
|
|
307
|
-
const file = await disk.readFile('data', filename, {
|
|
308
|
-
|
|
309
|
-
});
|
|
310
|
-
this.data = file;
|
|
311
|
-
|
|
298
|
+
const file = await disk.readFile('data', filename, { encoding: 'buffer' });
|
|
299
|
+
this.data = file as TData;
|
|
312
300
|
|
|
313
301
|
// Mimetype
|
|
314
|
-
if (mimetype !== undefined)
|
|
315
|
-
this.headers['Content-Type'] = mimetype;
|
|
302
|
+
if (mimetype !== undefined) this.headers['Content-Type'] = mimetype;
|
|
316
303
|
|
|
317
304
|
return this.end();
|
|
318
305
|
}
|
|
319
306
|
|
|
320
307
|
public redirect(url: string, code: number = 302, absolute: boolean = false) {
|
|
321
|
-
|
|
322
|
-
debug && console.log("[routeur][response] Redirect", url);
|
|
308
|
+
debug && console.log('[routeur][response] Redirect', url);
|
|
323
309
|
this.statusCode = code;
|
|
324
|
-
this.headers['Location'] = this.router.url(
|
|
310
|
+
this.headers['Location'] = this.router.url(url, {}, absolute);
|
|
325
311
|
return this.end();
|
|
326
312
|
}
|
|
327
313
|
|
|
@@ -334,5 +320,4 @@ export default class ServerResponse<
|
|
|
334
320
|
this.wasProvided = false;
|
|
335
321
|
return this;
|
|
336
322
|
}
|
|
337
|
-
|
|
338
|
-
}
|
|
323
|
+
}
|
|
@@ -23,28 +23,23 @@ const maxLevel = 10; // Prévention contre les références circulaires
|
|
|
23
23
|
- CLASS
|
|
24
24
|
----------------------------------*/
|
|
25
25
|
export default class Filtre {
|
|
26
|
-
|
|
27
|
-
public constructor() {
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
}
|
|
26
|
+
public constructor() {}
|
|
31
27
|
|
|
32
28
|
public filtrer(
|
|
33
29
|
donnee: TObjet | Array<unknown> | Date,
|
|
34
30
|
schema?: TSelecteur,
|
|
35
31
|
chemin: string[] = [],
|
|
36
|
-
schemaParent?: TObjet
|
|
32
|
+
schemaParent?: TObjet,
|
|
37
33
|
): any {
|
|
38
|
-
|
|
39
34
|
// Prévention contre les références circulaires
|
|
40
35
|
if (chemin.length > maxLevel)
|
|
41
|
-
throw new Error(
|
|
36
|
+
throw new Error(
|
|
37
|
+
`Erreur: Niveau max (${maxLevel}) atteint via la branche ${chemin.join('.')}. Vérifier s'il n'existe pas une référence circulaire dans l'objet à filtrer.`,
|
|
38
|
+
);
|
|
42
39
|
|
|
43
40
|
try {
|
|
44
|
-
|
|
45
41
|
// Tableau: on itère chaque élement de celui-ci
|
|
46
42
|
if (Array.isArray(donnee)) {
|
|
47
|
-
|
|
48
43
|
debug && console.log(`[requete][reponse][filtre]`, chemin.join('.'), ': Tableau');
|
|
49
44
|
|
|
50
45
|
return this.tableau(donnee, schema, chemin, schemaParent);
|
|
@@ -53,38 +48,25 @@ export default class Filtre {
|
|
|
53
48
|
// Si la donnée est une chaine, un nombre, etc ... On la traite comme s'il y avait un true
|
|
54
49
|
} else if (
|
|
55
50
|
// Extrémité de la branche
|
|
56
|
-
schema === true
|
|
57
|
-
||
|
|
51
|
+
schema === true ||
|
|
58
52
|
// Valeur non-itérable
|
|
59
|
-
!donnee
|
|
60
|
-
||
|
|
61
|
-
typeof donnee !== 'object'
|
|
62
|
-
||
|
|
53
|
+
!donnee ||
|
|
54
|
+
typeof donnee !== 'object' ||
|
|
63
55
|
donnee instanceof Date
|
|
64
56
|
) {
|
|
65
|
-
|
|
66
57
|
debug && console.log(`[requete][reponse][filtre]`, chemin.join('.'), ': Valeur');
|
|
67
58
|
|
|
68
|
-
return this.valeur(
|
|
69
|
-
donnee,
|
|
70
|
-
schema,
|
|
71
|
-
chemin
|
|
72
|
-
);
|
|
59
|
+
return this.valeur(donnee, schema, chemin);
|
|
73
60
|
|
|
74
61
|
// Objet
|
|
75
62
|
} else {
|
|
76
|
-
|
|
77
63
|
debug && console.log(`[requete][reponse][filtre]`, chemin.join('.'), ': Objet');
|
|
78
64
|
|
|
79
65
|
return this.objet(donnee, schema, chemin, schemaParent);
|
|
80
|
-
|
|
81
66
|
}
|
|
82
|
-
|
|
83
67
|
} catch (error) {
|
|
84
|
-
|
|
85
68
|
console.error('Erreur =', error, '|| données =', donnee, '|| chemin =', chemin, '|| schema =', schema);
|
|
86
69
|
throw new Error(`Erreur lors du filtrage. Infos ci-dessus.`);
|
|
87
|
-
|
|
88
70
|
}
|
|
89
71
|
}
|
|
90
72
|
|
|
@@ -93,9 +75,8 @@ export default class Filtre {
|
|
|
93
75
|
schema: TSelecteur | undefined,
|
|
94
76
|
|
|
95
77
|
chemin: string[],
|
|
96
|
-
schemaParent?: TObjet
|
|
78
|
+
schemaParent?: TObjet,
|
|
97
79
|
) {
|
|
98
|
-
|
|
99
80
|
let retour: any[] = [];
|
|
100
81
|
|
|
101
82
|
for (const iElem in donnee) {
|
|
@@ -105,9 +86,9 @@ export default class Filtre {
|
|
|
105
86
|
schema,
|
|
106
87
|
|
|
107
88
|
[...chemin, iElem],
|
|
108
|
-
schemaParent
|
|
109
|
-
)
|
|
110
|
-
)
|
|
89
|
+
schemaParent,
|
|
90
|
+
),
|
|
91
|
+
);
|
|
111
92
|
}
|
|
112
93
|
|
|
113
94
|
return retour;
|
|
@@ -118,39 +99,34 @@ export default class Filtre {
|
|
|
118
99
|
schema: TSelecteur | undefined,
|
|
119
100
|
|
|
120
101
|
chemin: string[],
|
|
121
|
-
schemaParent?: TObjet
|
|
102
|
+
schemaParent?: TObjet,
|
|
122
103
|
) {
|
|
123
|
-
|
|
124
104
|
if (typeof schema === 'object') {
|
|
125
|
-
|
|
126
105
|
// Exemple: article ( titre enfant( @ ) )
|
|
127
106
|
// Copie du schéma parent
|
|
128
107
|
if (schema['@'] === true) {
|
|
129
|
-
|
|
130
108
|
if (schemaParent === undefined)
|
|
131
|
-
throw new Error(
|
|
109
|
+
throw new Error(
|
|
110
|
+
`Référence au schéma parent trouvée, mais impossible d'accéder au schéma parent (schemaParent = undefined)`,
|
|
111
|
+
);
|
|
132
112
|
|
|
133
113
|
schema = schemaParent;
|
|
134
114
|
|
|
135
115
|
// Exemple: *
|
|
136
116
|
// Parcours et filtre toutes les entrées
|
|
137
117
|
} else if (schema['*'] === true) {
|
|
138
|
-
|
|
139
118
|
// L'itération se fera directement sur les données fournies
|
|
140
119
|
schema = undefined;
|
|
141
120
|
|
|
142
121
|
// Exemple: * ( nom symbole )
|
|
143
122
|
// Applique un selecteurs à toutes les entrées
|
|
144
123
|
} else if (schema['*'] !== undefined) {
|
|
145
|
-
|
|
146
124
|
const schemaBranches = schema['*'];
|
|
147
125
|
schema = {};
|
|
148
126
|
|
|
149
127
|
// Applique le schema du wildcard à toutes les entrées de l'objet
|
|
150
128
|
// TODO: alternative plus performante
|
|
151
|
-
for (const cle in donnee)
|
|
152
|
-
schema[cle] = schemaBranches;
|
|
153
|
-
|
|
129
|
+
for (const cle in donnee) schema[cle] = schemaBranches;
|
|
154
130
|
}
|
|
155
131
|
}
|
|
156
132
|
|
|
@@ -159,62 +135,46 @@ export default class Filtre {
|
|
|
159
135
|
// Liste des clés à itérer
|
|
160
136
|
let clesAiterer: string[];
|
|
161
137
|
if (schema !== undefined)
|
|
162
|
-
clesAiterer = Object.keys(schema as object);
|
|
163
|
-
else
|
|
164
|
-
clesAiterer = Object.keys(donnee);
|
|
138
|
+
clesAiterer = Object.keys(schema as object); // En dernier recours, on itère tout simplement les données de l'objet
|
|
139
|
+
else clesAiterer = Object.keys(donnee);
|
|
165
140
|
|
|
166
141
|
// Objet
|
|
167
142
|
for (const nomBranche of clesAiterer) {
|
|
168
|
-
|
|
169
143
|
const cheminA = [...chemin, nomBranche];
|
|
170
144
|
let donneeBranche = undefined;
|
|
171
145
|
|
|
172
146
|
// Extraction de la valeur de la propriété
|
|
173
|
-
if (donneeBranche === undefined)
|
|
174
|
-
donneeBranche = donnee[nomBranche];
|
|
147
|
+
if (donneeBranche === undefined) donneeBranche = donnee[nomBranche];
|
|
175
148
|
|
|
176
149
|
// Filtrage de la valeur de la propriété
|
|
177
|
-
|
|
178
|
-
donneeBranche,
|
|
179
|
-
schema !== undefined ? schema[nomBranche] : undefined,
|
|
150
|
+
const objectSchema = typeof schema === 'object' && schema !== null ? schema : undefined;
|
|
180
151
|
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
schema as TObjet
|
|
184
|
-
);
|
|
152
|
+
retour[nomBranche] = this.filtrer(donneeBranche, objectSchema?.[nomBranche], cheminA, schema as TObjet);
|
|
185
153
|
}
|
|
186
154
|
|
|
187
155
|
return retour;
|
|
188
156
|
}
|
|
189
157
|
|
|
190
158
|
// Traitement des données aux extrémités (auxquelles font référence les true)
|
|
191
|
-
private valeur(
|
|
192
|
-
donnee: any,
|
|
193
|
-
schema: TSelecteur,
|
|
194
|
-
chemin: string[]
|
|
195
|
-
) {
|
|
196
|
-
|
|
159
|
+
private valeur(donnee: any, schema: TSelecteur | undefined, chemin: string[]) {
|
|
197
160
|
// Si sélecteur wildcard
|
|
198
|
-
const wildcard = typeof schema === 'object' && schema['*'] === true
|
|
161
|
+
const wildcard = typeof schema === 'object' && schema['*'] === true;
|
|
199
162
|
|
|
200
163
|
// Traitement des objets
|
|
201
164
|
if (donnee && typeof donnee === 'object') {
|
|
202
|
-
|
|
203
165
|
// Promise
|
|
204
166
|
if (typeof donnee.then === 'function')
|
|
205
|
-
throw new Error(
|
|
206
|
-
|
|
167
|
+
throw new Error(
|
|
168
|
+
chemin.join('.') +
|
|
169
|
+
': Les promises ne sont pas autorisées en retour api, sauf via un getter de modèle.',
|
|
170
|
+
);
|
|
207
171
|
// Sinon, wildcard obliatoire si on souhaite conserver l'objet entier
|
|
208
172
|
else if (wildcard === false) {
|
|
209
|
-
|
|
210
|
-
if (donnee instanceof Date)
|
|
211
|
-
return donnee.toISOString();
|
|
173
|
+
if (donnee instanceof Date) return donnee.toISOString();
|
|
212
174
|
// Mauvaise idée: Les instances de modèle Sequelize possèdent une méthode toString()
|
|
213
175
|
/*else if (typeof donnee.toString === 'function')
|
|
214
176
|
return donnee.toString();*/
|
|
215
|
-
|
|
216
177
|
}
|
|
217
|
-
|
|
218
178
|
}
|
|
219
179
|
|
|
220
180
|
return donnee;
|
|
@@ -319,5 +279,4 @@ export default class Filtre {
|
|
|
319
279
|
return false;
|
|
320
280
|
}
|
|
321
281
|
}*/
|
|
322
|
-
|
|
323
|
-
}
|
|
282
|
+
}
|