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.
Files changed (185) hide show
  1. package/AGENTS.md +101 -0
  2. package/agents/codex/AGENTS.md +95 -0
  3. package/agents/codex/CODING_STYLE.md +71 -0
  4. package/agents/codex/agents.md.zip +0 -0
  5. package/agents/codex/client/AGENTS.md +102 -0
  6. package/agents/codex/client/pages/AGENTS.md +35 -0
  7. package/agents/codex/server/routes/AGENTS.md +12 -0
  8. package/agents/codex/server/services/AGENTS.md +137 -0
  9. package/agents/codex/tests/AGENTS.md +8 -0
  10. package/cli/app/config.ts +13 -11
  11. package/cli/app/index.ts +74 -82
  12. package/cli/bin.js +1 -1
  13. package/cli/commands/build.ts +51 -14
  14. package/cli/commands/check.ts +19 -0
  15. package/cli/commands/deploy/app.ts +4 -8
  16. package/cli/commands/deploy/web.ts +16 -20
  17. package/cli/commands/dev.ts +189 -64
  18. package/cli/commands/devEvents.ts +106 -0
  19. package/cli/commands/init.ts +63 -57
  20. package/cli/commands/lint.ts +21 -0
  21. package/cli/commands/refresh.ts +18 -0
  22. package/cli/commands/typecheck.ts +18 -0
  23. package/cli/compiler/client/identite.ts +80 -53
  24. package/cli/compiler/client/index.ts +139 -213
  25. package/cli/compiler/common/bundleAnalysis.ts +94 -0
  26. package/cli/compiler/common/clientManifest.ts +67 -0
  27. package/cli/compiler/common/controllers.ts +288 -0
  28. package/cli/compiler/common/files/autres.ts +7 -18
  29. package/cli/compiler/common/files/images.ts +40 -37
  30. package/cli/compiler/common/files/style.ts +11 -22
  31. package/cli/compiler/common/generatedRouteModules.ts +368 -0
  32. package/cli/compiler/common/index.ts +31 -65
  33. package/cli/compiler/common/loaders/forbid-ssr-import.js +13 -0
  34. package/cli/compiler/common/rspackAliases.ts +13 -0
  35. package/cli/compiler/common/scripts.ts +37 -0
  36. package/cli/compiler/index.ts +781 -230
  37. package/cli/compiler/server/index.ts +59 -75
  38. package/cli/compiler/writeIfChanged.ts +21 -0
  39. package/cli/index.ts +71 -72
  40. package/cli/paths.ts +51 -57
  41. package/cli/print.ts +17 -11
  42. package/cli/tsconfig.json +5 -4
  43. package/cli/utils/agents.ts +100 -0
  44. package/cli/utils/check.ts +71 -0
  45. package/cli/utils/index.ts +1 -3
  46. package/cli/utils/keyboard.ts +8 -25
  47. package/cli/utils/runProcess.ts +30 -0
  48. package/client/app/component.tsx +29 -29
  49. package/client/app/index.ts +36 -57
  50. package/client/app/service.ts +7 -12
  51. package/client/app.tsconfig.json +2 -2
  52. package/client/components/Dialog/Manager.ssr.tsx +40 -0
  53. package/client/components/Dialog/Manager.tsx +119 -150
  54. package/client/components/Dialog/status.tsx +3 -3
  55. package/client/components/index.ts +1 -1
  56. package/client/components/types.d.ts +1 -3
  57. package/client/dev/hmr.ts +65 -0
  58. package/client/global.d.ts +2 -2
  59. package/client/hooks.ts +6 -9
  60. package/client/index.ts +2 -1
  61. package/client/islands/index.ts +7 -0
  62. package/client/islands/useDeferredModule.ts +199 -0
  63. package/client/pages/_layout/index.tsx +4 -12
  64. package/client/pages/useHeader.tsx +14 -21
  65. package/client/router.ts +27 -0
  66. package/client/services/router/components/Link.tsx +34 -27
  67. package/client/services/router/components/Page.tsx +6 -14
  68. package/client/services/router/components/router.ssr.tsx +36 -0
  69. package/client/services/router/components/router.tsx +63 -83
  70. package/client/services/router/index.tsx +185 -220
  71. package/client/services/router/request/api.ts +97 -119
  72. package/client/services/router/request/history.ts +2 -2
  73. package/client/services/router/request/index.ts +13 -12
  74. package/client/services/router/request/multipart.ts +72 -62
  75. package/client/services/router/response/index.tsx +68 -61
  76. package/client/services/router/response/page.ts +28 -32
  77. package/client/utils/dom.ts +17 -33
  78. package/common/app/index.ts +3 -3
  79. package/common/data/chaines/index.ts +22 -23
  80. package/common/data/dates.ts +35 -70
  81. package/common/data/markdown.ts +42 -39
  82. package/common/dev/serverHotReload.ts +26 -0
  83. package/common/errors/index.tsx +110 -142
  84. package/common/router/contracts.ts +29 -0
  85. package/common/router/index.ts +89 -108
  86. package/common/router/layouts.ts +34 -47
  87. package/common/router/pageSetup.ts +50 -0
  88. package/common/router/register.ts +53 -24
  89. package/common/router/request/api.ts +30 -36
  90. package/common/router/request/index.ts +2 -8
  91. package/common/router/response/index.ts +8 -15
  92. package/common/router/response/page.ts +70 -58
  93. package/common/utils.ts +1 -1
  94. package/doc/TODO.md +1 -1
  95. package/eslint.js +62 -0
  96. package/package.json +14 -49
  97. package/prettier.config.cjs +9 -0
  98. package/scripts/cleanup-generated-controllers.ts +62 -0
  99. package/scripts/fix-reference-app-typing.ts +490 -0
  100. package/scripts/refactor-client-app-imports.ts +244 -0
  101. package/scripts/refactor-client-pages.ts +587 -0
  102. package/scripts/refactor-server-controllers.ts +470 -0
  103. package/scripts/refactor-server-runtime-aliases.ts +360 -0
  104. package/scripts/restore-client-app-import-files.ts +41 -0
  105. package/scripts/restore-files-from-git-head.ts +20 -0
  106. package/scripts/update-codex-agents.ts +35 -0
  107. package/server/app/commands.ts +35 -64
  108. package/server/app/container/config.ts +48 -59
  109. package/server/app/container/console/index.ts +202 -248
  110. package/server/app/container/index.ts +33 -71
  111. package/server/app/controller/index.ts +61 -0
  112. package/server/app/index.ts +39 -105
  113. package/server/app/service/container.ts +41 -42
  114. package/server/app/service/index.ts +120 -147
  115. package/server/context.ts +1 -1
  116. package/server/index.ts +25 -1
  117. package/server/services/auth/index.ts +75 -115
  118. package/server/services/auth/router/index.ts +31 -32
  119. package/server/services/auth/router/request.ts +14 -16
  120. package/server/services/cron/CronTask.ts +13 -26
  121. package/server/services/cron/index.ts +14 -36
  122. package/server/services/disks/driver.ts +40 -58
  123. package/server/services/disks/drivers/local/index.ts +79 -90
  124. package/server/services/disks/drivers/s3/index.ts +116 -163
  125. package/server/services/disks/index.ts +23 -38
  126. package/server/services/email/index.ts +45 -104
  127. package/server/services/email/utils.ts +14 -27
  128. package/server/services/fetch/index.ts +53 -85
  129. package/server/services/prisma/Facet.ts +39 -91
  130. package/server/services/prisma/index.ts +74 -110
  131. package/server/services/router/generatedRuntime.ts +29 -0
  132. package/server/services/router/http/index.ts +78 -73
  133. package/server/services/router/http/multipart.ts +19 -42
  134. package/server/services/router/index.ts +378 -365
  135. package/server/services/router/request/api.ts +26 -25
  136. package/server/services/router/request/index.ts +44 -51
  137. package/server/services/router/request/service.ts +7 -11
  138. package/server/services/router/request/validation/zod.ts +111 -148
  139. package/server/services/router/response/index.ts +110 -125
  140. package/server/services/router/response/mask/Filter.ts +31 -72
  141. package/server/services/router/response/mask/index.ts +8 -15
  142. package/server/services/router/response/mask/selecteurs.ts +11 -25
  143. package/server/services/router/response/page/clientManifest.ts +25 -0
  144. package/server/services/router/response/page/document.tsx +199 -127
  145. package/server/services/router/response/page/index.tsx +89 -94
  146. package/server/services/router/service.ts +13 -15
  147. package/server/services/schema/index.ts +17 -26
  148. package/server/services/schema/request.ts +19 -33
  149. package/server/services/schema/router/index.ts +8 -11
  150. package/server/services/security/encrypt/aes/index.ts +15 -35
  151. package/server/utils/slug.ts +29 -35
  152. package/skills/clean-project-code/SKILL.md +63 -0
  153. package/skills/clean-project-code/agents/openai.yaml +4 -0
  154. package/tsconfig.common.json +4 -3
  155. package/tsconfig.json +4 -1
  156. package/types/aliases.d.ts +17 -21
  157. package/types/controller-input.test.ts +48 -0
  158. package/types/express-extra.d.ts +6 -0
  159. package/types/global/constants.d.ts +13 -0
  160. package/types/global/express-extra.d.ts +6 -0
  161. package/types/global/modules.d.ts +13 -16
  162. package/types/global/utils.d.ts +17 -49
  163. package/types/global/vendors.d.ts +62 -0
  164. package/types/icons.d.ts +65 -1
  165. package/types/uuid.d.ts +3 -0
  166. package/types/vendors.d.ts +62 -0
  167. package/cli/compiler/common/babel/index.ts +0 -170
  168. package/cli/compiler/common/babel/plugins/index.ts +0 -0
  169. package/cli/compiler/common/babel/plugins/services.ts +0 -586
  170. package/cli/compiler/common/babel/routes/imports.ts +0 -127
  171. package/cli/compiler/common/babel/routes/routes.ts +0 -1130
  172. package/client/services/captcha/index.ts +0 -67
  173. package/client/services/socket/index.ts +0 -147
  174. package/common/data/rte/nodes.ts +0 -83
  175. package/common/data/stats.ts +0 -90
  176. package/common/utils/rte.ts +0 -183
  177. package/server/services/auth/old.ts +0 -277
  178. package/server/services/cache/commands.ts +0 -41
  179. package/server/services/cache/index.ts +0 -297
  180. package/server/services/cache/service.json +0 -6
  181. package/server/services/socket/index.ts +0 -162
  182. package/server/services/socket/scope.ts +0 -226
  183. package/server/services/socket/service.json +0 -6
  184. package/server/services_old/SocketClient.ts +0 -92
  185. package/server/services_old/Token.old.ts +0 -97
@@ -6,17 +6,10 @@
6
6
  import type zod from 'zod';
7
7
 
8
8
  // types
9
- import type {
10
- default as ClientRouter,
11
- TRouterContext as ClientRouterContext,
12
- TRegisterPageArgs
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, TDataProvider } from './response/page';
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
- export type TRoute<RouterContext extends TClientOrServerContextForPage = TClientOrServerContextForPage> = {
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 TErrorRoute<RouterContext extends TClientOrServerContextForPage = TClientOrServerContextForPage> = {
66
- code,
67
- controller: TRouteController<RouterContext>,
68
- options: TRouteOptions
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 TAnyRoute<RouterContext extends TClientOrServerContextForPage = TClientOrServerContextForPage> =
72
- TRoute<RouterContext> | TErrorRoute<RouterContext>
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;// | ServerRouterContext;
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 extends TClientOrServerContextForPage = TClientOrServerContextForPage> =
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 TRouteOptions = {
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
- filepath?: string,
86
- data?: TDataProvider
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, // true to return raw data
97
- auth?: TUserRole | boolean,
98
- redirectLogged?: string, // Redirect to this route if auth: false and user is logged
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
- refresh?: string,
103
- urls: string[]
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?: TAppArrowFunction<TRegisteredRoute>
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[ domainId ];
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
- // Absolute URL
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 matchRoute = (route: TRoute, request: RouterRequest) => {
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 = match[iKey + 1];
196
- if (typeof key === 'string' && value) // number = sans nom
197
- request.data[key] = decodeURIComponent( value.replaceAll('+', '%20') );
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
- public abstract page<TControllerData extends TObjetDonnees = {}>(...args: TRegisterPageArgs<TControllerData>);
210
-
211
- public abstract error(code: number, options, renderer: TFrontRenderer<{}, { message: string }>);
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
+ }
@@ -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 = layouts as ImportedLayouts;
20
+ export const layoutsList: ImportedLayouts = generatedLayouts;
23
21
 
24
22
  /*----------------------------------
25
23
  - TYPES
26
24
  ----------------------------------*/
27
- type LayoutComponent = (attributes: { context: ClientContext }) => ComponentChild;
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["id"];
48
+ const chunkId = routeOptions.id;
53
49
  if (chunkId === undefined) {
54
- console.error("Route informations where ID cas not injected:", routeOptions);
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 } = layouts[routeOptions.layout];
56
+ const layoutModule = layoutsList[routeOptions.layout];
57
+ const { default: LayoutComponent, data } = layoutModule || {};
62
58
  if (LayoutComponent === undefined)
63
- throw new Error(`No layout found with ID: ${routeOptions.layout}. registered layouts: ${Object.keys(layouts)}`);
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 in layouts)
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
- || chunkId === layoutPath
72
+ chunkId === layoutPath ||
79
73
  // Parent
80
- || chunkId.startsWith( layoutPath + '_' )
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
- path: '/',
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
- ([path, renderer] = args)
28
- else
29
- ([path, options, renderer] = args)
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
- export const buildRegex = ( path: string ) => {
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]: /*TFetcher | */Promise<any> | undefined }
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: (callback: (data: TData) => void) => Promise<TData>,
19
- catch: (callback: (data: any) => false | void) => Promise<TData>,
20
- finally: (callback: () => void) => Promise<TData>,
21
- run: () => Promise<TData>,
22
-
23
- method: HttpMethod,
24
- path: string,
25
- data?: TPostDataWithFile,
26
- options?: TApiFetchOptions
27
- }
28
-
29
- export type TFetcherArgs = [
30
- method: HttpMethod,
31
- path: string,
32
- data?: TPostDataWithFile,
33
- options?: TApiFetchOptions
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, // Action id (required by recaptcha)
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< TProvidedData[Property] >
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( newData: TObjetDonnees );
60
+ public abstract set(newData: TObjetDonnees): void;
67
61
 
68
- public abstract reload( ids?: string | string[], params?: TObjetDonnees );
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
+ }