proteum 2.1.0 → 2.1.2

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 (95) hide show
  1. package/AGENTS.md +44 -98
  2. package/README.md +143 -10
  3. package/agents/framework/AGENTS.md +146 -886
  4. package/agents/project/AGENTS.md +73 -127
  5. package/agents/project/client/AGENTS.md +22 -93
  6. package/agents/project/client/pages/AGENTS.md +24 -26
  7. package/agents/project/server/routes/AGENTS.md +10 -8
  8. package/agents/project/server/services/AGENTS.md +22 -159
  9. package/agents/project/tests/AGENTS.md +11 -8
  10. package/cli/app/config.ts +7 -20
  11. package/cli/bin.js +8 -0
  12. package/cli/commands/command.ts +243 -0
  13. package/cli/commands/commandLocalRunner.js +198 -0
  14. package/cli/commands/create.ts +5 -0
  15. package/cli/commands/deploy/web.ts +1 -2
  16. package/cli/commands/dev.ts +98 -2
  17. package/cli/commands/doctor.ts +8 -74
  18. package/cli/commands/explain.ts +8 -186
  19. package/cli/commands/init.ts +2 -94
  20. package/cli/commands/trace.ts +228 -0
  21. package/cli/compiler/artifacts/commands.ts +217 -0
  22. package/cli/compiler/artifacts/manifest.ts +35 -21
  23. package/cli/compiler/artifacts/services.ts +300 -1
  24. package/cli/compiler/client/index.ts +43 -8
  25. package/cli/compiler/common/commands.ts +175 -0
  26. package/cli/compiler/common/index.ts +1 -1
  27. package/cli/compiler/common/proteumManifest.ts +15 -114
  28. package/cli/compiler/index.ts +25 -2
  29. package/cli/compiler/server/index.ts +31 -6
  30. package/cli/index.ts +1 -4
  31. package/cli/paths.ts +16 -1
  32. package/cli/presentation/commands.ts +104 -14
  33. package/cli/presentation/devSession.ts +22 -3
  34. package/cli/presentation/proteum_logo_400x400_square_icon.txt +400 -0
  35. package/cli/runtime/commands.ts +121 -4
  36. package/cli/scaffold/index.ts +720 -0
  37. package/cli/scaffold/templates.ts +344 -0
  38. package/cli/scaffold/types.ts +26 -0
  39. package/cli/tsconfig.json +4 -1
  40. package/cli/utils/check.ts +1 -1
  41. package/client/app/component.tsx +13 -9
  42. package/client/dev/profiler/index.tsx +2511 -0
  43. package/client/dev/profiler/noop.tsx +5 -0
  44. package/client/dev/profiler/runtime.noop.ts +116 -0
  45. package/client/dev/profiler/runtime.ts +840 -0
  46. package/client/services/router/components/router.tsx +30 -2
  47. package/client/services/router/index.tsx +27 -3
  48. package/client/services/router/request/api.ts +133 -17
  49. package/commands/proteum/diagnostics.ts +11 -0
  50. package/common/dev/commands.ts +50 -0
  51. package/common/dev/diagnostics.ts +298 -0
  52. package/common/dev/profiler.ts +92 -0
  53. package/common/dev/proteumManifest.ts +135 -0
  54. package/common/dev/requestTrace.ts +115 -0
  55. package/common/env/proteumEnv.ts +284 -0
  56. package/common/router/index.ts +4 -22
  57. package/docs/dev-commands.md +93 -0
  58. package/docs/diagnostics.md +88 -0
  59. package/docs/request-tracing.md +132 -0
  60. package/eslint.js +11 -6
  61. package/package.json +3 -3
  62. package/server/app/commands.ts +35 -370
  63. package/server/app/commandsManager.ts +393 -0
  64. package/server/app/container/config.ts +11 -49
  65. package/server/app/container/console/index.ts +2 -3
  66. package/server/app/container/index.ts +5 -2
  67. package/server/app/container/trace/index.ts +364 -0
  68. package/server/app/devCommands.ts +192 -0
  69. package/server/app/devDiagnostics.ts +53 -0
  70. package/server/app/index.ts +29 -6
  71. package/server/index.ts +0 -1
  72. package/server/services/auth/index.ts +525 -61
  73. package/server/services/auth/router/index.ts +106 -7
  74. package/server/services/cron/CronTask.ts +73 -5
  75. package/server/services/cron/index.ts +34 -11
  76. package/server/services/fetch/index.ts +3 -10
  77. package/server/services/prisma/index.ts +66 -4
  78. package/server/services/router/http/index.ts +173 -6
  79. package/server/services/router/index.ts +200 -12
  80. package/server/services/router/request/api.ts +30 -1
  81. package/server/services/router/response/index.ts +83 -10
  82. package/server/services/router/response/page/document.tsx +16 -0
  83. package/server/services/router/response/page/index.tsx +27 -1
  84. package/skills/clean-project-code/SKILL.md +7 -2
  85. package/test-results/.last-run.json +4 -0
  86. package/types/aliases.d.ts +6 -0
  87. package/types/global/utils.d.ts +7 -14
  88. package/Rte.zip +0 -0
  89. package/agents/project/agents.md.zip +0 -0
  90. package/doc/TODO.md +0 -71
  91. package/doc/front/router.md +0 -27
  92. package/doc/workspace/workspace.png +0 -0
  93. package/doc/workspace/workspace2.png +0 -0
  94. package/doc/workspace/workspace_26.01.22.png +0 -0
  95. package/server/services/router/http/session.ts.old +0 -40
@@ -14,7 +14,7 @@ import express from 'express';
14
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 { TMatchedRoute, TRoute, TAnyRoute, TDomainsList } from '@common/router';
17
+ import { TMatchedRoute, TRoute, TAnyRoute } from '@common/router';
18
18
  import { NotFound, Forbidden, Anomaly } from '@common/errors';
19
19
  import BaseResponse, { TResponseData } from '@common/router/response';
20
20
  import { splitRouteSetupResult } from '@common/router/pageSetup';
@@ -38,7 +38,7 @@ export type TBasicSSrData = {
38
38
  request: { data: TObjetDonnees; id: string };
39
39
  page: { chunkId: string; data?: TObjetDonnees };
40
40
  user: TBasicUser | null;
41
- domains: TDomainsList;
41
+ currentDomain: string;
42
42
  };
43
43
 
44
44
  type TServerRouterApplication<TRouter extends TServerRouter> =
@@ -88,6 +88,11 @@ export type TRouterContextServices<
88
88
 
89
89
  export type TRouterRequestContext<TRouter extends TServerRouter> = TServerRouterCustomContext<TRouter>;
90
90
 
91
+ const getRouteTraceTarget = (route: TAnyRoute<TRouterContext<TServerRouter>>) => {
92
+ if ('code' in route) return String(route.code);
93
+ return route.path || '';
94
+ };
95
+
91
96
  /*----------------------------------
92
97
  - CLASSE
93
98
  ----------------------------------*/
@@ -129,6 +134,18 @@ export default class ServerResponse<
129
134
  // Update canonical url
130
135
  this.updateCanonicalUrl(route);
131
136
 
137
+ this.app.container.Trace.record(
138
+ this.request.id,
139
+ 'controller.start',
140
+ {
141
+ target: getRouteTraceTarget(route as TAnyRoute<TRouterContext<TServerRouter>>),
142
+ routeId: route.options.id || '',
143
+ filepath: route.options.filepath || '',
144
+ accept: route.options.accept || '',
145
+ },
146
+ 'summary',
147
+ );
148
+
132
149
  // Create response context for controllers
133
150
  const requestContext = await this.createContext(route);
134
151
  const contextStore = context.getStore() as
@@ -141,16 +158,41 @@ export default class ServerResponse<
141
158
 
142
159
  // Run controller
143
160
  const content = await this.route.controller(requestContext);
144
- if (content === undefined) return;
161
+ if (content === undefined) {
162
+ this.app.container.Trace.record(this.request.id, 'controller.result', { kind: 'undefined' }, 'summary');
163
+ return;
164
+ }
145
165
 
146
166
  // No need to process the content
147
- if (content instanceof ServerResponse) return;
167
+ if (content instanceof ServerResponse) {
168
+ this.app.container.Trace.record(this.request.id, 'controller.result', { kind: 'response' }, 'summary');
169
+ return;
170
+ }
148
171
  // Render react page to html
149
- else if (content instanceof Page) await this.render(content, requestContext, additionnalData);
172
+ else if (content instanceof Page) {
173
+ this.app.container.Trace.record(
174
+ this.request.id,
175
+ 'controller.result',
176
+ { kind: 'page', chunkId: content.chunkId || '' },
177
+ 'summary',
178
+ );
179
+ await this.render(content, requestContext, additionnalData);
180
+ }
150
181
  // Return HTML
151
- else if (typeof content === 'string' && this.route.options.accept === 'html') await this.html(content);
182
+ else if (typeof content === 'string' && this.route.options.accept === 'html') {
183
+ this.app.container.Trace.record(
184
+ this.request.id,
185
+ 'controller.result',
186
+ { kind: 'html', length: content.length },
187
+ 'summary',
188
+ );
189
+ await this.html(content);
190
+ }
152
191
  // Return JSON
153
- else await this.json(content);
192
+ else {
193
+ this.app.container.Trace.record(this.request.id, 'controller.result', { kind: 'json', data: content }, 'resolve');
194
+ await this.json(content);
195
+ }
154
196
  }
155
197
 
156
198
  private updateCanonicalUrl(route: TAnyRoute<TRouterContext<TRouter>>) {
@@ -175,13 +217,20 @@ export default class ServerResponse<
175
217
  const requestContext = await this.createContext(route);
176
218
  const { options } = splitRouteSetupResult(((setup as any)({ ...requestContext, data: this.request.data }) as {}) || {});
177
219
 
220
+ this.app.container.Trace.record(
221
+ this.request.id,
222
+ 'setup.options',
223
+ { optionKeys: Object.keys(options) },
224
+ 'resolve',
225
+ );
226
+
178
227
  return { ...route, options: { ...route.options, ...options } };
179
228
  }
180
229
 
181
230
  // Start controller services
182
231
  private async createContext(route: TAnyRoute<TRouterContext<TRouter>>): Promise<TRequestContext> {
183
232
  const contextServices = this.router.createContextServices(this.request);
184
-
233
+ const controllers = createControllers(this.request.api);
185
234
  const customSsrData = this.router.config.context(this.request, this.app) as TRouterRequestContext<TRouter>;
186
235
 
187
236
  // TODO: transmiss safe data (especially for Router), as Router info could be printed on client side
@@ -196,7 +245,7 @@ export default class ServerResponse<
196
245
 
197
246
  Router: this.router,
198
247
  ...(this.app as {}),
199
- ...createControllers(this.request.api),
248
+ ...controllers,
200
249
 
201
250
  // Router services
202
251
  ...(contextServices as TRouterContextServices<TRouter>),
@@ -205,6 +254,19 @@ export default class ServerResponse<
205
254
 
206
255
  requestContext.context = requestContext;
207
256
 
257
+ this.app.container.Trace.record(
258
+ this.request.id,
259
+ 'context.create',
260
+ {
261
+ target: getRouteTraceTarget(route as TAnyRoute<TRouterContext<TServerRouter>>),
262
+ routeId: route.options.id || '',
263
+ routerServiceKeys: Object.keys(contextServices),
264
+ controllerKeys: Object.keys(controllers),
265
+ customContextKeys: Object.keys(customSsrData as object),
266
+ },
267
+ 'resolve',
268
+ );
269
+
208
270
  return requestContext;
209
271
  }
210
272
 
@@ -215,7 +277,7 @@ export default class ServerResponse<
215
277
  request: { id: this.request.id, data: this.request.data },
216
278
  page: { chunkId: page.chunkId || '', data: page.data },
217
279
  user: this.request.user,
218
- domains: this.router.config.domains,
280
+ currentDomain: this.router.config.currentDomain,
219
281
  ...customSsrData,
220
282
  };
221
283
  }
@@ -249,6 +311,17 @@ export default class ServerResponse<
249
311
  // Example: error message for error pages
250
312
  page.data = { ...page.data, ...additionnalData };
251
313
 
314
+ this.app.container.Trace.record(
315
+ this.request.id,
316
+ 'page.data',
317
+ {
318
+ chunkId: page.chunkId || '',
319
+ dataKeys: Object.keys(page.data || {}),
320
+ data: page.data || {},
321
+ },
322
+ 'resolve',
323
+ );
324
+
252
325
  // Render page
253
326
  await this.router.runHook('render', page);
254
327
  const document = await page.render();
@@ -182,6 +182,22 @@ export default class DocumentRenderer<TRouter extends TServerRouter> {
182
182
  const ssrData = response.forSsr(page);
183
183
  const context = safeStringify(ssrData);
184
184
  const routesForClient = JSON.stringify(this.router.ssrRoutes);
185
+ const customContextKeys = Object.keys(ssrData).filter((key) => !['request', 'page', 'user', 'domains'].includes(key));
186
+
187
+ this.app.container.Trace.record(
188
+ response.request.id,
189
+ 'ssr.payload',
190
+ {
191
+ chunkId: page.chunkId || '',
192
+ topLevelKeys: Object.keys(ssrData),
193
+ requestDataKeys: Object.keys(ssrData.request.data || {}),
194
+ pageDataKeys: Object.keys(ssrData.page.data || {}),
195
+ customContextKeys,
196
+ serializedBytes: Buffer.byteLength(context, 'utf8'),
197
+ routeCount: this.router.ssrRoutes.length,
198
+ },
199
+ 'resolve',
200
+ );
185
201
 
186
202
  return (
187
203
  <>
@@ -62,6 +62,17 @@ export default class ServerPage<TRouter extends TServerRouter = TServerRouter> e
62
62
  // Ex: runtime added scripts, title, metas, ....
63
63
 
64
64
  const context = this.context as TPageRenderContext & TRouterContext<TRouter>;
65
+ const requestId = context.response.request.id;
66
+ this.app.container.Trace.record(
67
+ requestId,
68
+ 'render.start',
69
+ {
70
+ chunkId: this.chunkId || '',
71
+ title: this.title || '',
72
+ routeId: this.route.options['id'] || '',
73
+ },
74
+ 'summary',
75
+ );
65
76
  const html = renderToString(
66
77
  <App context={context as Parameters<typeof App>[0]['context'] & TRouterContext<TRouter>} />,
67
78
  );
@@ -82,7 +93,22 @@ export default class ServerPage<TRouter extends TServerRouter = TServerRouter> e
82
93
  if (page.theme)
83
94
  attrsBody.className += ' ' + page.theme;*/
84
95
 
85
- return this.router.render.page(html, this, context.response);
96
+ return this.router.render.page(html, this, context.response).then((document) => {
97
+ this.app.container.Trace.record(
98
+ requestId,
99
+ 'render.end',
100
+ {
101
+ chunkId: this.chunkId || '',
102
+ htmlLength: html.length,
103
+ documentLength: document.length,
104
+ styleCount: this.style.length,
105
+ scriptCount: this.scripts.length,
106
+ },
107
+ 'summary',
108
+ );
109
+
110
+ return document;
111
+ });
86
112
  }
87
113
 
88
114
  /*----------------------------------
@@ -32,10 +32,13 @@ Use fast search tools such as `rg` to verify references. Check exports, dynamic
32
32
  5. Keep uncertain cases.
33
33
  If code looks unused but safety is not clear, keep it and report it separately. Favor false negatives over unsafe deletions.
34
34
 
35
- 6. Apply style only on touched files.
35
+ 6. Audit redundancy candidates across the project.
36
+ List catalogs, constants, and functions that look redundant and could be centralized, unified, or merged. Treat this as a reporting task by default unless the user explicitly asked for structural refactoring. Give each candidate an impact score from 1 to 5, where 5 is the highest expected payoff for maintainability, consistency, or simplification.
37
+
38
+ 7. Apply style only on touched files.
36
39
  Follow the repository coding style for files you change. Run Prettier with the repo config, preferably on touched files only unless the user explicitly asks for repo-wide formatting.
37
40
 
38
- 7. Verify.
41
+ 8. Verify.
39
42
  Run the smallest relevant verification available after edits. Prefer project-native checks. If no suitable automated verification exists, say so explicitly.
40
43
 
41
44
  ## Deletion Rules
@@ -50,6 +53,7 @@ Run the smallest relevant verification available after edits. Prefer project-nat
50
53
  Always report:
51
54
  - what was removed
52
55
  - what was intentionally left unchanged because it was uncertain
56
+ - which catalogs, constants, and functions appear redundant across the project, with a proposed centralization or merge direction and an impact score from 1 to 5
53
57
  - what verification was run
54
58
  - what could not be verified automatically
55
59
 
@@ -59,5 +63,6 @@ When the user provides a cleanup brief, turn it into an execution checklist befo
59
63
  - instructions read
60
64
  - safe deletion targets identified
61
65
  - risky candidates deferred
66
+ - redundancy candidates and impact scoring captured
62
67
  - formatting scope confirmed
63
68
  - verification plan chosen
@@ -0,0 +1,4 @@
1
+ {
2
+ "status": "failed",
3
+ "failedTests": []
4
+ }
@@ -18,6 +18,12 @@ declare module '@/server' {
18
18
  export = InstanceType<ServerApplicationClass>;
19
19
  }
20
20
 
21
+ declare module '@/server/index' {
22
+ import ServerApplicationBase from '../server/app';
23
+
24
+ export default class ServerApplication extends ServerApplicationBase {}
25
+ }
26
+
21
27
  declare module '@/client' {
22
28
  const ClientApplicationClass: import('../client/app').default;
23
29
  export = InstanceType<ClientApplicationClass>;
@@ -43,24 +43,17 @@ declare type PrimitiveValue = string | number | boolean;
43
43
  /*type TEnvConfig = {
44
44
  name: 'local' | 'server',
45
45
  profile: 'dev' | 'testing' | 'prod',
46
-
46
+
47
47
  router: {
48
48
  port: number,
49
- domains: TDomainsList
50
- },
51
- database: {
52
- name: string,
53
- databases: string[],
54
- host: string,
55
- port: number,
56
- login: string,
57
- password: string,
49
+ currentDomain: string
58
50
  },
59
- console: {
51
+ trace: {
60
52
  enable: boolean,
61
- debug: boolean,
62
- bufferLimit: number,
63
- level: TLogProfile,
53
+ requestsLimit: number,
54
+ eventsLimit: number,
55
+ capture: 'summary' | 'resolve' | 'deep',
56
+ persistOnError: boolean,
64
57
  },
65
58
  }*/
66
59
 
package/Rte.zip DELETED
Binary file
Binary file
package/doc/TODO.md DELETED
@@ -1,71 +0,0 @@
1
- * Fix erreurs type Client / Server context
2
- * Server side: ServerContext
3
- * Client side: ClientContext | ServerContext
4
- * PageResponse extends Response
5
- * Toast service
6
- * ClientApplication hooks
7
- app.on('bug')
8
- app.on('error')
9
-
10
-
11
- # Dependancies injection
12
-
13
- # Full stack Pages
14
-
15
- ```typescript
16
- import Router from '@server/services/router';
17
- import { TRouterContext as ServerServices } from '@server/services/router/response';
18
- import { TRouterContext as ClientServices } from '@client/services/router/response';
19
-
20
- abstract class Controller<
21
- TRouter extends Router,
22
- TData extends any = any,
23
- TUserAccess extends string = string
24
- > {
25
-
26
- abstract auth: TUserAccess;
27
-
28
- abstract get( services: ServerServices<TRouter> ): Promise<TData>;
29
-
30
- abstract render( context: TData, services: ClientServices<TRouter> ): ComponentChild;
31
-
32
- }
33
- ```
34
-
35
- ```typescript
36
- //? /headhunter/missions/suggested'
37
- class Missions extends Controller<CrossPath["router"]> {
38
-
39
- auth = 'USER';
40
-
41
- async get({ headhunting, response, auth }) {
42
-
43
- const user = await auth.check('USER');
44
-
45
- const suggested = await headhunting.missions.Suggest( user );
46
-
47
- return { suggested }
48
- }
49
-
50
- render({ page, api, suggested }) {
51
- return (
52
- <Page title="App title here" subtitle="SEO description here">{page.loading || <>
53
-
54
- <section class="col">
55
-
56
- <header class="row">
57
- <h2 class="col-1">Suggested Missions</h2>
58
- </header>
59
-
60
- <div class="grid xa3">
61
- {suggested.map( mission => (
62
- <MissionCard mission={mission} />
63
- ))}
64
- </div>
65
- </section>
66
-
67
- </>}</Page>
68
- )
69
- }
70
- }
71
- ```
@@ -1,27 +0,0 @@
1
- # Disallowed
2
-
3
- - To destructure page data objects
4
-
5
- ```
6
- route.page('/withdraw', { bodyId: 'withdraw' }, ({}, { api }) => ({
7
-
8
- withdraw: api.get('/withdraw')
9
-
10
- }), ({ withdraw: { history, balance, minimum, fees } }, { api, modal, page, user }) => {
11
-
12
- ...
13
- ```
14
-
15
- Do instead:
16
-
17
- ```
18
- route.page('/withdraw', { bodyId: 'withdraw' }, ({}, { api }) => ({
19
-
20
- withdraw: api.get('/withdraw')
21
-
22
- }), ({ withdraw }, { api, modal, page, user }) => {
23
-
24
- const { history, balance, minimum, fees } = withdraw;
25
-
26
- ...
27
- ```
Binary file
Binary file
@@ -1,40 +0,0 @@
1
- // Npm
2
- import session from 'express-session';
3
- import { v4 as uuidv4 } from 'uuid';
4
- import redisConnector from 'connect-redis';
5
- const RedisStore = redisConnector(session);
6
-
7
- // Services
8
- import type { THttpConfig } from '@server/services/http';
9
- import Redis from '@server/services/redis';
10
-
11
- // Middleware
12
- export const createSessionMiddleware = (httpConfig: THttpConfig) => {
13
- return session({
14
-
15
- genid: (req) => {
16
- return /*req.id;*/uuidv4(); // ID session via UUID
17
- },
18
-
19
- name: httpConfig.session.name,
20
- store: new RedisStore({
21
- client: Redis.instance,
22
- ttl: httpConfig.session.duration // secondes
23
- }),
24
- secret: httpConfig.session.secret,
25
-
26
- // Ces deux valeurs sont recommandes avec session filestore
27
- // https://github.com/valery-barysok/session-file-store/blob/master/examples/express-example/app.js
28
- resave: true, // Quand false, /admin/console réinitialise la session
29
- saveUninitialized: true,
30
-
31
- cookie: {
32
- maxAge: httpConfig.session.duration * 1000, // millisecondes
33
- //sameSite: true,
34
- httpOnly: true,
35
- // Les variables d'environnement sont des chaines
36
- secure: httpConfig.ssl,
37
- path: '/',
38
- }
39
- })
40
- }