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
package/common/router/index.ts
CHANGED
|
@@ -6,17 +6,10 @@
|
|
|
6
6
|
import type zod from 'zod';
|
|
7
7
|
|
|
8
8
|
// types
|
|
9
|
-
import type {
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
} from '@client/services/router';
|
|
14
|
-
|
|
15
|
-
import type {
|
|
16
|
-
TAnyRouter,
|
|
17
|
-
TRouterContext as ServerRouterContext,
|
|
18
|
-
TRouteHttpMethod
|
|
19
|
-
} from '@server/services/router';
|
|
9
|
+
import type { default as ClientRouter, TRouterContext as ClientRouterContext } from '@client/services/router';
|
|
10
|
+
import type { TRegisterPageArgs } from './contracts';
|
|
11
|
+
|
|
12
|
+
import type { TAnyRouter, TRouterContext as ServerRouterContext, TRouteHttpMethod } from '@server/services/router';
|
|
20
13
|
|
|
21
14
|
import type RouterRequest from './request';
|
|
22
15
|
|
|
@@ -25,7 +18,7 @@ import type { TUserRole } from '@server/services/auth';
|
|
|
25
18
|
import type { TAppArrowFunction } from '@common/app';
|
|
26
19
|
|
|
27
20
|
// Specfic
|
|
28
|
-
import type { default as Page, TFrontRenderer,
|
|
21
|
+
import type { default as Page, TFrontRenderer, TPageSetup } from './response/page';
|
|
29
22
|
|
|
30
23
|
/*----------------------------------
|
|
31
24
|
- TYPES: ROUTES
|
|
@@ -38,176 +31,164 @@ export type { default as Response } from './response';
|
|
|
38
31
|
|
|
39
32
|
export type ClientOrServerRouter = ClientRouter | TAnyRouter;
|
|
40
33
|
|
|
41
|
-
|
|
34
|
+
type TRouteMatch = { regex: RegExp; keys: (number | string)[] };
|
|
42
35
|
|
|
36
|
+
type TRouteBase<RouterContext = unknown, TResult = any> = {
|
|
43
37
|
// Match
|
|
44
|
-
method: TRouteHttpMethod
|
|
45
|
-
path: string
|
|
38
|
+
method: TRouteHttpMethod;
|
|
39
|
+
path: string;
|
|
46
40
|
|
|
47
41
|
// Execute
|
|
48
|
-
schema?: zod.ZodSchema
|
|
49
|
-
controller: TRouteController<RouterContext
|
|
50
|
-
options: TRouteOptions
|
|
51
|
-
}
|
|
52
|
-
// With regex
|
|
53
|
-
{
|
|
54
|
-
regex: RegExp,
|
|
55
|
-
keys: (number | string)[],
|
|
56
|
-
}
|
|
57
|
-
// Without regex (for ex: controllers)
|
|
58
|
-
|
|
|
59
|
-
{
|
|
60
|
-
regex?: undefined,
|
|
61
|
-
keys?: undefined,
|
|
62
|
-
}
|
|
63
|
-
)
|
|
42
|
+
schema?: zod.ZodSchema;
|
|
43
|
+
controller: TRouteController<RouterContext, TResult>;
|
|
44
|
+
options: TRouteOptions;
|
|
45
|
+
};
|
|
64
46
|
|
|
65
|
-
export type
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
47
|
+
export type TMatchedRoute<RouterContext = unknown, TResult = any> = TRouteBase<RouterContext, TResult> & TRouteMatch;
|
|
48
|
+
|
|
49
|
+
export type TRoute<RouterContext = unknown, TResult = any> =
|
|
50
|
+
| TMatchedRoute<RouterContext, TResult>
|
|
51
|
+
| TRouteBase<RouterContext, TResult>;
|
|
70
52
|
|
|
71
|
-
export type
|
|
72
|
-
|
|
53
|
+
export type TErrorRoute<RouterContext = unknown, TResult = any> = {
|
|
54
|
+
code: number;
|
|
55
|
+
controller: TRouteController<RouterContext, TResult>;
|
|
56
|
+
options: TRouteOptions;
|
|
57
|
+
};
|
|
58
|
+
|
|
59
|
+
export type TAnyRoute<RouterContext = unknown, TResult = any> =
|
|
60
|
+
| TRoute<RouterContext, TResult>
|
|
61
|
+
| TErrorRoute<RouterContext, TResult>;
|
|
73
62
|
|
|
74
63
|
// ClientRouterContext already includes server context
|
|
75
|
-
export type TClientOrServerContext = ClientRouterContext
|
|
64
|
+
export type TClientOrServerContext = ClientRouterContext; // | ServerRouterContext;
|
|
76
65
|
|
|
77
|
-
export type TClientOrServerContextForPage = With<TClientOrServerContext, 'page'
|
|
66
|
+
export type TClientOrServerContextForPage = With<TClientOrServerContext, 'page'>;
|
|
78
67
|
|
|
79
|
-
export type TRouteController<RouterContext
|
|
80
|
-
(context: RouterContext) => /* Page to render */Page | /* Any data (html, json) */Promise<any>
|
|
68
|
+
export type TRouteController<RouterContext = unknown, TResult = any> = (context: RouterContext) => TResult;
|
|
81
69
|
|
|
82
|
-
export type
|
|
70
|
+
export type TPageRoute = TRoute<TClientOrServerContextForPage, Page | Promise<any>>;
|
|
71
|
+
|
|
72
|
+
export type TPageErrorRoute = TErrorRoute<TClientOrServerContextForPage, Page | Promise<any>>;
|
|
83
73
|
|
|
74
|
+
export type TRouteOptions = {
|
|
84
75
|
// Injected by the page plugin
|
|
85
|
-
|
|
86
|
-
|
|
76
|
+
id?: string;
|
|
77
|
+
filepath?: string;
|
|
78
|
+
setup?: TPageSetup;
|
|
87
79
|
|
|
88
80
|
// Indexing
|
|
89
|
-
bodyId?: string
|
|
90
|
-
priority: number
|
|
91
|
-
preload?: boolean
|
|
81
|
+
bodyId?: string;
|
|
82
|
+
priority: number;
|
|
83
|
+
preload?: boolean;
|
|
92
84
|
|
|
93
85
|
// Resolving
|
|
94
|
-
domain?: string
|
|
95
|
-
accept?: string
|
|
96
|
-
raw?: boolean
|
|
97
|
-
auth?: TUserRole | boolean
|
|
98
|
-
redirectLogged?: string
|
|
86
|
+
domain?: string;
|
|
87
|
+
accept?: string;
|
|
88
|
+
raw?: boolean; // true to return raw data
|
|
89
|
+
auth?: TUserRole | boolean;
|
|
90
|
+
redirectLogged?: string; // Redirect to this route if auth: false and user is logged
|
|
99
91
|
|
|
100
92
|
// Rendering
|
|
101
|
-
static?: {
|
|
102
|
-
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
whenStatic?: boolean, // If true, the route is only executed even if the page is cached
|
|
106
|
-
canonicalParams?: string[], // For SEO + unique ID for static cache
|
|
107
|
-
layout?: false | string, // The nale of the layout
|
|
93
|
+
static?: { refresh?: string; urls: string[] };
|
|
94
|
+
whenStatic?: boolean; // If true, the route is only executed even if the page is cached
|
|
95
|
+
canonicalParams?: string[]; // For SEO + unique ID for static cache
|
|
96
|
+
layout?: false | string; // The nale of the layout
|
|
108
97
|
|
|
109
98
|
// To cleanup
|
|
110
|
-
TESTING?: boolean
|
|
111
|
-
logging?: boolean
|
|
112
|
-
}
|
|
99
|
+
TESTING?: boolean;
|
|
100
|
+
logging?: boolean;
|
|
101
|
+
};
|
|
113
102
|
|
|
114
|
-
export type TRouteModule<TRegisteredRoute = any> = {
|
|
103
|
+
export type TRouteModule<TRegisteredRoute = any> = {
|
|
115
104
|
// exporing __register is a way to know we axport a TAppArrowFunction
|
|
116
|
-
__register
|
|
117
|
-
}
|
|
105
|
+
__register: TAppArrowFunction<TRegisteredRoute>;
|
|
106
|
+
};
|
|
118
107
|
|
|
119
|
-
export type TDomainsList = {
|
|
120
|
-
[endpointId: string]: string
|
|
121
|
-
} & {
|
|
122
|
-
current: string
|
|
123
|
-
}
|
|
108
|
+
export type TDomainsList = { [endpointId: string]: string } & { current: string };
|
|
124
109
|
|
|
125
|
-
export const defaultOptions = {
|
|
126
|
-
priority: 0,
|
|
127
|
-
}
|
|
110
|
+
export const defaultOptions: Pick<TRouteOptions, 'priority'> = { priority: 0 };
|
|
128
111
|
|
|
129
112
|
/*----------------------------------
|
|
130
113
|
- FUNCTIONS
|
|
131
114
|
----------------------------------*/
|
|
132
115
|
export const buildUrl = (
|
|
133
116
|
path: string,
|
|
134
|
-
params: {[key: string]: any},
|
|
135
|
-
domains: {[alias: string]: string},
|
|
136
|
-
absolute: boolean
|
|
117
|
+
params: { [key: string]: any },
|
|
118
|
+
domains: { [alias: string]: string },
|
|
119
|
+
absolute: boolean,
|
|
137
120
|
) => {
|
|
138
|
-
|
|
139
121
|
let prefix: string = '';
|
|
140
122
|
|
|
141
123
|
// Relative to domain
|
|
142
|
-
if (path[0] === '/' && absolute)
|
|
143
|
-
prefix = domains.current;
|
|
124
|
+
if (path[0] === '/' && absolute) prefix = domains.current;
|
|
144
125
|
// Other domains of the project
|
|
145
126
|
else if (path[0] === '@') {
|
|
146
|
-
|
|
147
127
|
// Extract domain ID from path
|
|
148
128
|
let domainId: string;
|
|
149
129
|
let slackPos = path.indexOf('/');
|
|
150
|
-
if (slackPos === -1)
|
|
151
|
-
slackPos = path.length;
|
|
130
|
+
if (slackPos === -1) slackPos = path.length;
|
|
152
131
|
domainId = path.substring(1, slackPos);
|
|
153
132
|
path = path.substring(slackPos);
|
|
154
133
|
|
|
155
134
|
// Get domain
|
|
156
|
-
const domain = domains[
|
|
157
|
-
if (domain === undefined)
|
|
158
|
-
throw new Error("Unknown API endpoint ID: " + domainId);
|
|
135
|
+
const domain = domains[domainId];
|
|
136
|
+
if (domain === undefined) throw new Error('Unknown API endpoint ID: ' + domainId);
|
|
159
137
|
|
|
160
138
|
// Return full url
|
|
161
139
|
prefix = domain;
|
|
162
140
|
|
|
163
|
-
|
|
141
|
+
// Absolute URL
|
|
164
142
|
}
|
|
165
143
|
|
|
166
144
|
// Path parapeters
|
|
167
145
|
const searchParams = new URLSearchParams();
|
|
168
146
|
for (const key in params) {
|
|
169
|
-
|
|
170
147
|
// Exclude undefined of empty
|
|
171
|
-
if (!params[key])
|
|
172
|
-
continue;
|
|
148
|
+
if (!params[key]) continue;
|
|
173
149
|
// Path placeholder
|
|
174
|
-
else if (path.includes(':' + key))
|
|
175
|
-
path = path.replace(':' + key, params[key]);
|
|
150
|
+
else if (path.includes(':' + key)) path = path.replace(':' + key, params[key]);
|
|
176
151
|
// Query string
|
|
177
|
-
else
|
|
178
|
-
searchParams.set(key, params[key]);
|
|
152
|
+
else searchParams.set(key, params[key]);
|
|
179
153
|
}
|
|
180
154
|
|
|
181
155
|
// Return final url
|
|
182
156
|
return prefix + path + (searchParams.toString() ? '?' + searchParams.toString() : '');
|
|
183
|
-
}
|
|
157
|
+
};
|
|
184
158
|
|
|
185
|
-
export const
|
|
159
|
+
export const hasRouteMatcher = <TRouteLike extends { regex?: unknown; keys?: unknown }>(
|
|
160
|
+
route: TRouteLike,
|
|
161
|
+
): route is TRouteLike & TRouteMatch => 'regex' in route && route.regex instanceof RegExp;
|
|
186
162
|
|
|
163
|
+
export const matchRoute = (route: TRouteMatch, request: RouterRequest) => {
|
|
187
164
|
// Match Path
|
|
188
165
|
const match = route.regex.exec(request.path);
|
|
189
|
-
if (!match)
|
|
190
|
-
return false;
|
|
166
|
+
if (!match) return false;
|
|
191
167
|
|
|
192
168
|
// Extract URL params
|
|
193
169
|
for (let iKey = 0; iKey < route.keys.length; iKey++) {
|
|
194
170
|
const key = route.keys[iKey];
|
|
195
|
-
const value =
|
|
196
|
-
if (typeof key === 'string' && value)
|
|
197
|
-
|
|
171
|
+
const value = match[iKey + 1];
|
|
172
|
+
if (typeof key === 'string' && value)
|
|
173
|
+
// number = sans nom
|
|
174
|
+
request.data[key] = decodeURIComponent(value.replace(/\+/g, '%20'));
|
|
198
175
|
}
|
|
199
176
|
|
|
200
177
|
return true;
|
|
201
|
-
}
|
|
178
|
+
};
|
|
202
179
|
|
|
203
180
|
/*----------------------------------
|
|
204
181
|
- BASE ROUTER
|
|
205
182
|
----------------------------------*/
|
|
206
183
|
|
|
207
184
|
export default abstract class RouterInterface {
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
185
|
+
public abstract page<TControllerData extends TObjetDonnees = {}>(
|
|
186
|
+
...args: TRegisterPageArgs<TControllerData, TRouteOptions>
|
|
187
|
+
): unknown;
|
|
188
|
+
|
|
189
|
+
public abstract error(
|
|
190
|
+
code: number,
|
|
191
|
+
options: Partial<TRouteOptions>,
|
|
192
|
+
renderer: TFrontRenderer<{}, { message: string }>,
|
|
193
|
+
): unknown;
|
|
194
|
+
}
|
package/common/router/layouts.ts
CHANGED
|
@@ -6,88 +6,75 @@
|
|
|
6
6
|
import type { ComponentChild } from 'preact';
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
|
-
import type { ClientContext } from '@/client/context';
|
|
10
9
|
import type { TRouteOptions } from '.';
|
|
11
|
-
import type { TDataProvider } from './response/page';
|
|
10
|
+
import type { TDataProvider, TPageRenderContext } from './response/page';
|
|
12
11
|
|
|
13
12
|
// App
|
|
14
13
|
import internalLayout from '@client/pages/_layout';
|
|
15
|
-
|
|
16
|
-
import * as layouts from '@/client/pages/**/_layout/index.tsx';
|
|
14
|
+
import generatedLayouts, { layoutOrder } from '@/client/.generated/layouts';
|
|
17
15
|
|
|
18
16
|
/*----------------------------------
|
|
19
17
|
- CONST
|
|
20
18
|
----------------------------------*/
|
|
21
19
|
|
|
22
|
-
export const layoutsList =
|
|
20
|
+
export const layoutsList: ImportedLayouts = generatedLayouts;
|
|
23
21
|
|
|
24
22
|
/*----------------------------------
|
|
25
23
|
- TYPES
|
|
26
24
|
----------------------------------*/
|
|
27
|
-
type
|
|
25
|
+
export type LayoutProps = {
|
|
26
|
+
[key: string]: unknown;
|
|
27
|
+
context: TPageRenderContext;
|
|
28
|
+
menu: ComponentChild;
|
|
29
|
+
children: ComponentChild;
|
|
30
|
+
} & TPageRenderContext;
|
|
31
|
+
|
|
32
|
+
type LayoutComponent = (attributes: LayoutProps) => ComponentChild;
|
|
28
33
|
|
|
29
|
-
export type Layout = {
|
|
30
|
-
path: string,
|
|
31
|
-
Component: LayoutComponent,
|
|
32
|
-
data?: TDataProvider
|
|
33
|
-
}
|
|
34
|
+
export type Layout = { path: string; Component: LayoutComponent; data?: TDataProvider };
|
|
34
35
|
|
|
35
|
-
export type ImportedLayouts = {
|
|
36
|
-
[chunkId: string]: Layout["Component"]
|
|
37
|
-
}
|
|
36
|
+
export type ImportedLayouts = { [chunkId: string]: { default: Layout['Component']; data?: TDataProvider } };
|
|
38
37
|
|
|
39
38
|
/*----------------------------------
|
|
40
39
|
- UTILS
|
|
41
40
|
----------------------------------*/
|
|
42
41
|
// TODO: getLayot only on server side, and pass the layout chunk id
|
|
43
|
-
export const getLayout = (routePath: string, routeOptions?: TRouteOptions): Layout | undefined => {
|
|
44
|
-
|
|
45
|
-
if (routeOptions === undefined)
|
|
46
|
-
return undefined;
|
|
42
|
+
export const getLayout = (routePath: string, routeOptions?: Partial<TRouteOptions>): Layout | undefined => {
|
|
43
|
+
if (routeOptions === undefined) return undefined;
|
|
47
44
|
// W don't want a layout on this page
|
|
48
|
-
if (routeOptions.layout === false)
|
|
49
|
-
return undefined;
|
|
45
|
+
if (routeOptions.layout === false) return undefined;
|
|
50
46
|
|
|
51
47
|
// options.id has been injected via the babel plugon
|
|
52
|
-
const chunkId = routeOptions
|
|
48
|
+
const chunkId = routeOptions.id;
|
|
53
49
|
if (chunkId === undefined) {
|
|
54
|
-
console.error(
|
|
50
|
+
console.error('Route informations where ID cas not injected:', routeOptions);
|
|
55
51
|
throw new Error(`ID has not injected for the following page route: ${routePath}`);
|
|
56
52
|
}
|
|
57
|
-
|
|
53
|
+
|
|
58
54
|
// Layout via name
|
|
59
55
|
if (routeOptions.layout !== undefined) {
|
|
60
|
-
|
|
61
|
-
const { default: LayoutComponent, data } =
|
|
56
|
+
const layoutModule = layoutsList[routeOptions.layout];
|
|
57
|
+
const { default: LayoutComponent, data } = layoutModule || {};
|
|
62
58
|
if (LayoutComponent === undefined)
|
|
63
|
-
throw new Error(
|
|
59
|
+
throw new Error(
|
|
60
|
+
`No layout found with ID: ${routeOptions.layout}. registered layouts: ${Object.keys(layoutsList)}`,
|
|
61
|
+
);
|
|
62
|
+
|
|
63
|
+
return { path: routeOptions.layout, Component: layoutModule.default, data };
|
|
64
|
+
}
|
|
64
65
|
|
|
65
|
-
return {
|
|
66
|
-
path: routeOptions.layout,
|
|
67
|
-
Component: layouts[routeOptions.layout].default,
|
|
68
|
-
data
|
|
69
|
-
}
|
|
70
|
-
}
|
|
71
|
-
|
|
72
66
|
// Automatic layout via the nearest _layout folder
|
|
73
|
-
for (const layoutPath
|
|
67
|
+
for (const layoutPath of layoutOrder as string[])
|
|
74
68
|
if (
|
|
75
69
|
// The layout is nammed '' when it's at the root (@/client/pages/_layout)
|
|
76
|
-
layoutPath === '' // Root layout
|
|
70
|
+
layoutPath === '' || // Root layout
|
|
77
71
|
// Exact match
|
|
78
|
-
|
|
72
|
+
chunkId === layoutPath ||
|
|
79
73
|
// Parent
|
|
80
|
-
|
|
74
|
+
chunkId.startsWith(layoutPath + '_')
|
|
81
75
|
)
|
|
82
|
-
return {
|
|
83
|
-
path: layoutPath,
|
|
84
|
-
Component: layouts[layoutPath].default,
|
|
85
|
-
data: layouts[layoutPath].data,
|
|
86
|
-
};
|
|
76
|
+
return { path: layoutPath, Component: layoutsList[layoutPath].default, data: layoutsList[layoutPath].data };
|
|
87
77
|
|
|
88
78
|
// Internal layout
|
|
89
|
-
return {
|
|
90
|
-
|
|
91
|
-
Component: internalLayout
|
|
92
|
-
}
|
|
93
|
-
}
|
|
79
|
+
return { path: '/', Component: internalLayout };
|
|
80
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- TYPES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
import type { TRouteOptions } from '.';
|
|
6
|
+
|
|
7
|
+
export const routeSetupOptionKeys = [
|
|
8
|
+
'priority',
|
|
9
|
+
'preload',
|
|
10
|
+
'domain',
|
|
11
|
+
'accept',
|
|
12
|
+
'raw',
|
|
13
|
+
'auth',
|
|
14
|
+
'redirectLogged',
|
|
15
|
+
'static',
|
|
16
|
+
'whenStatic',
|
|
17
|
+
'canonicalParams',
|
|
18
|
+
'layout',
|
|
19
|
+
'TESTING',
|
|
20
|
+
'logging',
|
|
21
|
+
] as const satisfies (keyof TRouteOptions)[];
|
|
22
|
+
|
|
23
|
+
export const reservedRouteSetupKeys = ['id', 'filepath', 'bodyId', 'data', 'setup'] as const;
|
|
24
|
+
|
|
25
|
+
const routeSetupOptionKeysSet = new Set<string>(routeSetupOptionKeys);
|
|
26
|
+
const reservedRouteSetupKeysSet = new Set<string>(reservedRouteSetupKeys);
|
|
27
|
+
|
|
28
|
+
export const getRouteSetupOptionKey = (key: string) => {
|
|
29
|
+
const normalizedKey = key.startsWith('_') ? key.substring(1) : key;
|
|
30
|
+
|
|
31
|
+
if (reservedRouteSetupKeysSet.has(normalizedKey)) throw new Error(`"${key}" is a reserved Router.page setup key.`);
|
|
32
|
+
|
|
33
|
+
return routeSetupOptionKeysSet.has(normalizedKey) ? (normalizedKey as keyof TRouteOptions) : null;
|
|
34
|
+
};
|
|
35
|
+
|
|
36
|
+
export const splitRouteSetupResult = (result: TObjetDonnees | undefined) => {
|
|
37
|
+
const options: Partial<TRouteOptions> = {};
|
|
38
|
+
const data: TObjetDonnees = {};
|
|
39
|
+
|
|
40
|
+
if (!result) return { options, data };
|
|
41
|
+
|
|
42
|
+
for (const key in result) {
|
|
43
|
+
const optionKey = getRouteSetupOptionKey(key);
|
|
44
|
+
|
|
45
|
+
if (optionKey) options[optionKey] = result[key];
|
|
46
|
+
else data[key] = result[key];
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
return { options, data };
|
|
50
|
+
};
|
|
@@ -7,49 +7,78 @@ import { pathToRegexp, Key } from 'path-to-regexp';
|
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
9
|
import { getLayout } from './layouts';
|
|
10
|
+
import type { TRegisterPageArgs } from './contracts';
|
|
10
11
|
|
|
11
12
|
// types
|
|
12
13
|
import type { TRouteOptions } from '.';
|
|
13
|
-
import type { TFrontRenderer } from './response/page';
|
|
14
|
-
import type { TRegisterPageArgs } from '@client/services/router';
|
|
14
|
+
import type { TFrontRenderer, TPageSetup } from './response/page';
|
|
15
15
|
|
|
16
16
|
/*----------------------------------
|
|
17
17
|
- UTILS
|
|
18
18
|
----------------------------------*/
|
|
19
19
|
|
|
20
|
-
export const getRegisterPageArgs = (...args: TRegisterPageArgs) => {
|
|
21
|
-
|
|
20
|
+
export const getRegisterPageArgs = (...args: TRegisterPageArgs<any, TRouteOptions>) => {
|
|
22
21
|
let path: string;
|
|
23
22
|
let options: Partial<TRouteOptions> = {};
|
|
23
|
+
let setup: TPageSetup | undefined;
|
|
24
24
|
let renderer: TFrontRenderer;
|
|
25
25
|
|
|
26
|
-
if (args.length === 2)
|
|
27
|
-
|
|
28
|
-
else
|
|
29
|
-
|
|
26
|
+
if (args.length === 2) {
|
|
27
|
+
[path, renderer] = args;
|
|
28
|
+
} else if (args.length === 3) {
|
|
29
|
+
const [pathArg, optionsOrSetupArg, rendererArg] = args;
|
|
30
|
+
path = pathArg;
|
|
31
|
+
renderer = rendererArg;
|
|
32
|
+
|
|
33
|
+
if (typeof optionsOrSetupArg === 'function') setup = optionsOrSetupArg;
|
|
34
|
+
else options = optionsOrSetupArg;
|
|
35
|
+
} else {
|
|
36
|
+
const [pathArg, optionsArg, setupArg, rendererArg] = args;
|
|
37
|
+
path = pathArg;
|
|
38
|
+
options = optionsArg;
|
|
39
|
+
setup = setupArg;
|
|
40
|
+
renderer = rendererArg;
|
|
41
|
+
}
|
|
30
42
|
|
|
31
|
-
// Automatic layout form the nearest _layout folder
|
|
43
|
+
// Automatic layout form the nearest _layout folder using static options only.
|
|
32
44
|
const layout = getLayout(path, options);
|
|
33
45
|
|
|
34
|
-
return { path, options, renderer, layout }
|
|
46
|
+
return { path, options, setup, renderer, layout };
|
|
47
|
+
};
|
|
48
|
+
|
|
49
|
+
export const getRegisterPageOptions = (...args: TRegisterPageArgs<any, TRouteOptions>) => {
|
|
50
|
+
let path: string;
|
|
51
|
+
let options: Partial<TRouteOptions> = {};
|
|
52
|
+
let setup: TPageSetup | undefined;
|
|
53
|
+
let renderer: TFrontRenderer;
|
|
54
|
+
|
|
55
|
+
if (args.length === 2) {
|
|
56
|
+
[path, renderer] = args;
|
|
57
|
+
} else if (args.length === 3) {
|
|
58
|
+
const [pathArg, optionsOrSetupArg, rendererArg] = args;
|
|
59
|
+
path = pathArg;
|
|
60
|
+
renderer = rendererArg;
|
|
35
61
|
|
|
36
|
-
|
|
62
|
+
if (typeof optionsOrSetupArg === 'function') setup = optionsOrSetupArg;
|
|
63
|
+
else options = optionsOrSetupArg;
|
|
64
|
+
} else {
|
|
65
|
+
const [pathArg, optionsArg, setupArg, rendererArg] = args;
|
|
66
|
+
path = pathArg;
|
|
67
|
+
options = optionsArg;
|
|
68
|
+
setup = setupArg;
|
|
69
|
+
renderer = rendererArg;
|
|
70
|
+
}
|
|
37
71
|
|
|
38
|
-
|
|
72
|
+
return { path, options, setup, renderer };
|
|
73
|
+
};
|
|
39
74
|
|
|
75
|
+
export const buildRegex = (path: string) => {
|
|
40
76
|
// pathToRegexp ne supporte plus les wildcards depuis 4.0
|
|
41
|
-
if (path.endsWith('*'))
|
|
42
|
-
path = path.substring(0, path.length - 1) + '(.*)';
|
|
77
|
+
if (path.endsWith('*')) path = path.substring(0, path.length - 1) + '(.*)';
|
|
43
78
|
|
|
44
79
|
// path => regex
|
|
45
|
-
const keys: Key[] = []
|
|
46
|
-
const regex = pathToRegexp(path, keys, {
|
|
47
|
-
sensitive: true
|
|
48
|
-
});
|
|
49
|
-
|
|
50
|
-
return {
|
|
51
|
-
keys: keys.map(k => k.name),
|
|
52
|
-
regex
|
|
53
|
-
}
|
|
80
|
+
const keys: Key[] = [];
|
|
81
|
+
const regex = pathToRegexp(path, keys, { sensitive: true });
|
|
54
82
|
|
|
55
|
-
}
|
|
83
|
+
return { keys: keys.map((k) => k.name), regex };
|
|
84
|
+
};
|
|
@@ -10,62 +10,56 @@ import type { HttpMethod } from '@server/services/router';
|
|
|
10
10
|
|
|
11
11
|
// The fetcher can be undefined if we put a condition on it
|
|
12
12
|
// By example if we want to fetch an api endpoint only if the url contains a certain url parameter
|
|
13
|
-
export type TFetcherList = { [id: string]:
|
|
13
|
+
export type TFetcherList = { [id: string]: TFetcher<any> | Promise<any> | undefined };
|
|
14
14
|
|
|
15
15
|
export type TFetcher<TData extends any = unknown> = {
|
|
16
|
-
|
|
17
16
|
// For async calls: api.post(...).then((data) => ...)
|
|
18
|
-
then:
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
]
|
|
17
|
+
then: <TResult1 = TData, TResult2 = never>(
|
|
18
|
+
onfulfilled?: ((value: TData) => TResult1 | PromiseLike<TResult1>) | null,
|
|
19
|
+
onrejected?: ((reason: unknown) => TResult2 | PromiseLike<TResult2>) | null,
|
|
20
|
+
) => Promise<TResult1 | TResult2>;
|
|
21
|
+
catch: <TResult = never>(
|
|
22
|
+
onrejected?: ((reason: unknown) => TResult | PromiseLike<TResult>) | null,
|
|
23
|
+
) => Promise<TData | TResult>;
|
|
24
|
+
finally: (onfinally?: (() => void) | null) => Promise<TData>;
|
|
25
|
+
run: () => Promise<TData>;
|
|
26
|
+
|
|
27
|
+
method: HttpMethod;
|
|
28
|
+
path: string;
|
|
29
|
+
data?: TPostDataWithFile;
|
|
30
|
+
options?: TApiFetchOptions;
|
|
31
|
+
};
|
|
32
|
+
|
|
33
|
+
export type TFetcherArgs = [method: HttpMethod, path: string, data?: TPostDataWithFile, options?: TApiFetchOptions];
|
|
35
34
|
|
|
36
35
|
export type TApiFetchOptions = {
|
|
37
|
-
captcha?: string
|
|
38
|
-
onProgress?: (percent: number) => void
|
|
36
|
+
captcha?: string; // Action id (required by recaptcha)
|
|
37
|
+
onProgress?: (percent: number) => void;
|
|
39
38
|
// Default: json
|
|
40
|
-
encoding?: 'json' | 'multipart'
|
|
41
|
-
}
|
|
39
|
+
encoding?: 'json' | 'multipart';
|
|
40
|
+
};
|
|
42
41
|
|
|
43
|
-
export type TPostData = TPostDataWithFile
|
|
42
|
+
export type TPostData = TPostDataWithFile;
|
|
44
43
|
|
|
45
|
-
export type TPostDataWithFile = { [key: string]: PrimitiveValue }
|
|
44
|
+
export type TPostDataWithFile = { [key: string]: PrimitiveValue };
|
|
46
45
|
|
|
47
|
-
export type TPostDataWithoutFile = { [key: string]: PrimitiveValue }
|
|
48
|
-
|
|
49
|
-
// https://stackoverflow.com/questions/44851268/typescript-how-to-extract-the-generic-parameter-from-a-type
|
|
50
|
-
type TypeWithGeneric<T> = TFetcher<T>
|
|
51
|
-
type extractGeneric<Type> = Type extends TypeWithGeneric<infer X> ? X : never
|
|
46
|
+
export type TPostDataWithoutFile = { [key: string]: PrimitiveValue };
|
|
52
47
|
|
|
53
48
|
export type TDataReturnedByFetchers<TProvidedData extends TFetcherList = {}> = {
|
|
54
|
-
[Property in keyof TProvidedData]: ThenArg<
|
|
55
|
-
}
|
|
49
|
+
[Property in keyof TProvidedData]: ThenArg<TProvidedData[Property]>;
|
|
50
|
+
};
|
|
56
51
|
|
|
57
52
|
/*----------------------------------
|
|
58
53
|
- CLASS
|
|
59
54
|
----------------------------------*/
|
|
60
55
|
export default abstract class ApiClient {
|
|
61
|
-
|
|
62
56
|
/*----------------------------------
|
|
63
57
|
- TOP LEVEL
|
|
64
58
|
----------------------------------*/
|
|
65
59
|
|
|
66
|
-
public abstract set(
|
|
60
|
+
public abstract set(newData: TObjetDonnees): void;
|
|
67
61
|
|
|
68
|
-
public abstract reload(
|
|
62
|
+
public abstract reload(ids?: string | string[], params?: TObjetDonnees): void;
|
|
69
63
|
|
|
70
64
|
/*----------------------------------
|
|
71
65
|
- LOW LEVEL
|
|
@@ -74,4 +68,4 @@ export default abstract class ApiClient {
|
|
|
74
68
|
public abstract createFetcher<TData extends unknown = unknown>(...args: TFetcherArgs): TFetcher<TData>;
|
|
75
69
|
|
|
76
70
|
public abstract fetchSync(fetchers: TFetcherList, alreadyLoadedData: {}): Promise<TObjetDonnees>;
|
|
77
|
-
}
|
|
71
|
+
}
|