proteum 2.1.9 → 2.2.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 (84) hide show
  1. package/.codex/environments/environment.toml +11 -0
  2. package/AGENTS.md +27 -11
  3. package/README.md +30 -11
  4. package/agents/project/AGENTS.md +172 -123
  5. package/agents/project/CODING_STYLE.md +1 -1
  6. package/agents/project/app-root/AGENTS.md +16 -0
  7. package/agents/project/client/AGENTS.md +5 -5
  8. package/agents/project/client/pages/AGENTS.md +13 -13
  9. package/agents/project/diagnostics.md +19 -10
  10. package/agents/project/optimizations.md +5 -6
  11. package/agents/project/root/AGENTS.md +297 -0
  12. package/agents/project/server/routes/AGENTS.md +2 -2
  13. package/agents/project/server/services/AGENTS.md +4 -2
  14. package/agents/project/tests/AGENTS.md +9 -2
  15. package/cli/app/index.ts +31 -7
  16. package/cli/commands/configure.ts +226 -0
  17. package/cli/commands/dev.ts +0 -2
  18. package/cli/commands/diagnose.ts +33 -1
  19. package/cli/commands/explain.ts +1 -1
  20. package/cli/commands/migrate.ts +51 -0
  21. package/cli/commands/orient.ts +169 -0
  22. package/cli/commands/perf.ts +8 -1
  23. package/cli/commands/verify.ts +1003 -49
  24. package/cli/compiler/artifacts/manifest.ts +4 -4
  25. package/cli/compiler/artifacts/routing.ts +2 -2
  26. package/cli/compiler/artifacts/services.ts +12 -3
  27. package/cli/compiler/client/index.ts +65 -19
  28. package/cli/compiler/common/files/style.ts +47 -2
  29. package/cli/compiler/common/generatedRouteModules.ts +31 -38
  30. package/cli/compiler/common/index.ts +10 -0
  31. package/cli/compiler/common/proteumManifest.ts +1 -0
  32. package/cli/compiler/server/index.ts +34 -9
  33. package/cli/context.ts +6 -1
  34. package/cli/index.ts +7 -8
  35. package/cli/migrate/pageContract.ts +516 -0
  36. package/cli/paths.ts +47 -6
  37. package/cli/presentation/commands.ts +100 -10
  38. package/cli/presentation/devSession.ts +4 -6
  39. package/cli/presentation/help.ts +2 -2
  40. package/cli/presentation/ink.ts +10 -5
  41. package/cli/presentation/welcome.ts +2 -4
  42. package/cli/runtime/commands.ts +94 -1
  43. package/cli/scaffold/index.ts +2 -2
  44. package/cli/scaffold/templates.ts +4 -2
  45. package/cli/utils/agents.ts +273 -58
  46. package/client/dev/profiler/index.tsx +3 -2
  47. package/client/router.ts +10 -2
  48. package/client/services/router/index.tsx +6 -22
  49. package/common/dev/connect.ts +20 -4
  50. package/common/dev/console.ts +7 -0
  51. package/common/dev/contractsDoctor.ts +354 -0
  52. package/common/dev/diagnostics.ts +10 -7
  53. package/common/dev/inspection.ts +830 -38
  54. package/common/dev/performance.ts +19 -5
  55. package/common/dev/profiler.ts +1 -0
  56. package/common/dev/proteumManifest.ts +5 -4
  57. package/common/dev/requestTrace.ts +78 -1
  58. package/common/env/proteumEnv.ts +10 -3
  59. package/common/router/contracts.ts +8 -11
  60. package/common/router/index.ts +2 -2
  61. package/common/router/pageData.ts +72 -0
  62. package/common/router/register.ts +10 -46
  63. package/common/router/response/page.ts +28 -16
  64. package/docs/assets/unique-domains-chip.png +0 -0
  65. package/docs/dev-sessions.md +8 -4
  66. package/docs/diagnostics.md +77 -11
  67. package/docs/migrate-from-2.1.3.md +388 -0
  68. package/docs/request-tracing.md +42 -9
  69. package/package.json +6 -1
  70. package/scripts/update-codex-agents.ts +2 -2
  71. package/server/app/container/console/index.ts +11 -1
  72. package/server/app/container/trace/index.ts +370 -72
  73. package/server/app/devDiagnostics.ts +1 -1
  74. package/server/app/index.ts +5 -1
  75. package/server/services/auth/index.ts +9 -0
  76. package/server/services/prisma/index.ts +15 -12
  77. package/server/services/router/http/index.ts +1 -1
  78. package/server/services/router/index.ts +105 -23
  79. package/server/services/router/request/api.ts +7 -1
  80. package/server/services/router/request/index.ts +2 -1
  81. package/server/services/router/response/index.ts +8 -28
  82. package/types/global/vendors.d.ts +12 -0
  83. package/types/vendors.d.ts +12 -0
  84. package/common/router/pageSetup.ts +0 -51
@@ -202,7 +202,11 @@ export abstract class Application<
202
202
  const connectedProject = this.getConnectedProject(namespace);
203
203
  if (connectedProject) return connectedProject;
204
204
 
205
- throw new Error(`Connected project "${namespace}" is not configured on ${this.identity.identifier}.`);
205
+ throw new Error(
206
+ `Proteum connected boundary mismatch: "${namespace}" is not configured on ${this.identity.identifier}. ` +
207
+ `Likely fix: add connect.${namespace} in proteum.config.ts for this app or stop calling that connected namespace from this side. ` +
208
+ `Re-check both SSR and client navigation if the namespace is used from page render or setup code.`,
209
+ );
206
210
  }
207
211
 
208
212
  public register(service: AnyService) {
@@ -853,6 +853,9 @@ export default abstract class AuthService<
853
853
  return user as TUser;
854
854
  }
855
855
 
856
+ /**
857
+ * @deprecated Use `check(request, null, tracking)` to make the authenticated-user requirement explicit.
858
+ */
856
859
  public check(request: TRequest): TUser;
857
860
 
858
861
  public check(request: TRequest, conditions: null, tracking?: TAuthTrackingContext): TUser;
@@ -861,8 +864,14 @@ export default abstract class AuthService<
861
864
 
862
865
  public check(request: TRequest, conditions: false, tracking?: TAuthTrackingContext): null;
863
866
 
867
+ /**
868
+ * @deprecated Use `check(request, { role }, tracking)` or another explicit conditions object instead.
869
+ */
864
870
  public check(request: TRequest, role?: TUserRole | boolean): TUser | null;
865
871
 
872
+ /**
873
+ * @deprecated Use `check(request, { role, ...rules }, tracking)` with app-defined auth rules instead of legacy feature/action arguments.
874
+ */
866
875
  public check(request: TRequest, role: TUserRole | boolean, feature: FeatureKeys, action?: string): TUser | null;
867
876
 
868
877
  public check(
@@ -46,6 +46,12 @@ type TPrismaExtensionOperation = {
46
46
  query: (args: unknown) => Promise<unknown>;
47
47
  };
48
48
 
49
+ declare global {
50
+ interface BigInt {
51
+ toJSON: () => number | string;
52
+ }
53
+ }
54
+
49
55
  /*----------------------------------
50
56
  - HELPERS
51
57
  ----------------------------------*/
@@ -173,21 +179,18 @@ export default class ModelsManager extends Service<Config, Hooks, Application, A
173
179
  'DATABASE_URL is required before starting the Models service. Prisma 7 no longer auto-loads runtime env files.',
174
180
  );
175
181
 
176
- const shouldTraceQueries = this.app.container.Trace.isEnabled();
177
- const prismaClient = shouldTraceQueries
178
- ? new PrismaClient({
179
- adapter: createMariaDbAdapter(databaseUrl),
180
- log: [{ emit: 'event', level: 'query' }],
181
- })
182
- : new PrismaClient({
183
- adapter: createMariaDbAdapter(databaseUrl),
184
- });
185
-
186
- if (!shouldTraceQueries) {
187
- this.client = prismaClient;
182
+ if (!this.app.container.Trace.shouldInstrumentRequests()) {
183
+ this.client = new PrismaClient({
184
+ adapter: createMariaDbAdapter(databaseUrl),
185
+ });
188
186
  return;
189
187
  }
190
188
 
189
+ const prismaClient = new PrismaClient({
190
+ adapter: createMariaDbAdapter(databaseUrl),
191
+ log: [{ emit: 'event', level: 'query' }],
192
+ });
193
+
191
194
  prismaClient.$on('query', (event: TPrismaQueryEvent) => this.traceQuery(event));
192
195
 
193
196
  this.client = prismaClient.$extends(
@@ -510,7 +510,7 @@ export default class HttpServer<TRouter extends TServerRouter = TServerRouter> {
510
510
  private registerDevTraceRoutes(routes: express.Express) {
511
511
  if (!__DEV__ || this.app.env.profile !== 'dev') return;
512
512
 
513
- if (this.app.container.Trace.isEnabled()) {
513
+ if (this.app.container.Trace.isDevTraceEnabled()) {
514
514
  routes.get('/__proteum/trace/requests', (req, res) => {
515
515
  const rawLimit = Array.isArray(req.query.limit) ? req.query.limit[0] : req.query.limit;
516
516
  const parsedLimit = typeof rawLimit === 'string' ? Number.parseInt(rawLimit, 10) : NaN;
@@ -37,6 +37,7 @@ import type { TSsrUnresolvedRoute, TRegisterPageArgs } from '@common/router/cont
37
37
  import { buildRegex, getRegisterPageArgs } from '@common/router/register';
38
38
  import { layoutsList, getLayout } from '@common/router/layouts';
39
39
  import {
40
+ profilerConnectedNamespaceHeader,
40
41
  profilerOriginHeader,
41
42
  profilerParentRequestIdHeader,
42
43
  profilerSessionIdHeader,
@@ -131,7 +132,13 @@ export type Config<
131
132
  // Set it as a function, so when we instanciate the services, we can callthis.router to pass the router instance in roiuter services
132
133
  type TRouterServicesList = { [serviceName: string]: AnyRouterService };
133
134
 
134
- export type Hooks = {};
135
+ export type Hooks = {
136
+ request: { args: [request: ServerRequest<TServerRouter>] };
137
+ 'request.finished': { args: [request: ServerRequest<TServerRouter>] };
138
+ resolve: { args: [request: ServerRequest<TServerRouter>] };
139
+ resolved: { args: [route: TMatchedRoute, request: ServerRequest<TServerRouter>, response: ServerResponse<TServerRouter>] };
140
+ render: { args: [page: Page<TServerRouter>] };
141
+ };
135
142
 
136
143
  export type TControllerDefinition = {
137
144
  path?: string;
@@ -221,6 +228,7 @@ export default class ServerRouter<
221
228
  const methodName = match ? match[2] : '<anonymous>';*/
222
229
 
223
230
  const contextData = context.getStore() || { channelType: 'master' };
231
+ if (contextData.silentLogs) return;
224
232
 
225
233
  const requestPrefix =
226
234
  contextData.channelType === 'request'
@@ -272,21 +280,18 @@ export default class ServerRouter<
272
280
 
273
281
  public async renderStatic(url: string, options: TRouteOptions['static'], rendered?: any) {
274
282
  // Wildcard: tell that the newly rendered pages should be cached
275
- if (url === '*' || !url) return;
276
-
277
- if (!rendered) {
278
- console.log('[router] renderStatic: url', url);
283
+ if (url === '*' || !url) throw new Error(`Unable to cache a dynamic or empty URL.`);
279
284
 
285
+ if (rendered === undefined) {
280
286
  const fullUrl = this.url(url, {}, true);
281
287
  const response = await got(fullUrl, {
282
288
  method: 'GET',
283
- headers: { Accept: 'text/html', bypasscache: '1' },
289
+ headers: { Accept: 'text/html', bypasscache: '1', 'x-proteum-static-warmup': '1' },
284
290
  throwHttpErrors: false,
285
291
  });
286
292
 
287
293
  if (response.statusCode !== 200) {
288
- console.error('[router] renderStatic: page returned code', response.statusCode, fullUrl);
289
- return;
294
+ throw new Error(`Static render returned ${response.statusCode} for ${fullUrl}`);
290
295
  }
291
296
 
292
297
  rendered = response.body;
@@ -301,17 +306,50 @@ export default class ServerRouter<
301
306
 
302
307
  private initStaticRoutes() {
303
308
  this.clearStaticRoutesRefreshInterval();
309
+ const staticEntries: Array<{ routePath: string; url: string; options: TRouteOptions['static'] }> = [];
310
+ const seenStaticUrls = new Set<string>();
304
311
 
305
312
  for (const route of this.routes) {
313
+ if (route.method !== 'GET' || route.options.accept !== 'html') continue;
314
+
306
315
  if (!route.options.static) continue;
307
316
 
308
317
  // Add to static pages
309
318
  // Should be a GET oage that don't take any parameter
310
319
  for (const url of route.options.static.urls) {
311
- this.renderStatic(url, route.options.static);
320
+ if (!url || url === '*' || seenStaticUrls.has(url)) continue;
321
+
322
+ staticEntries.push({
323
+ routePath: route.path || '(unknown route)',
324
+ url,
325
+ options: route.options.static,
326
+ });
327
+ seenStaticUrls.add(url);
312
328
  }
313
329
  }
314
330
 
331
+ void (async () => {
332
+ const warmedUrls: string[] = [];
333
+ let failedCount = 0;
334
+
335
+ for (const entry of staticEntries) {
336
+ try {
337
+ await this.renderStatic(entry.url, entry.options);
338
+ warmedUrls.push(entry.url);
339
+ } catch (error) {
340
+ failedCount += 1;
341
+ console.error('[router] Static warmup failed', entry.url, `route=${entry.routePath}`, error);
342
+ }
343
+ }
344
+
345
+ console.log(
346
+ '[router] Static warmup finished',
347
+ `warmed=${warmedUrls.length}`,
348
+ `failed=${failedCount}`,
349
+ `urls=${warmedUrls.length > 0 ? warmedUrls.join(', ') : 'none'}`,
350
+ );
351
+ })();
352
+
315
353
  // Every hours, refresh static pages
316
354
  this.staticRoutesRefreshInterval = setInterval(
317
355
  () => {
@@ -327,7 +365,9 @@ export default class ServerRouter<
327
365
  for (const pageUrl in this.cache) {
328
366
  const page = this.cache[pageUrl];
329
367
  if (page.expire && page.expire < Date.now()) {
330
- this.renderStatic(pageUrl, page.options);
368
+ void this.renderStatic(pageUrl, page.options).catch((error) => {
369
+ console.error('[router] Static refresh failed', pageUrl, error);
370
+ });
331
371
  }
332
372
  }
333
373
  }
@@ -382,7 +422,7 @@ export default class ServerRouter<
382
422
  ----------------------------------*/
383
423
 
384
424
  public page(...args: TRegisterPageArgs<any, TRouteOptions>) {
385
- const { path, options, setup, renderer, layout } = getRegisterPageArgs(...args);
425
+ const { path, options, data, renderer, layout } = getRegisterPageArgs(...args);
386
426
 
387
427
  const { regex, keys } = buildRegex(path);
388
428
 
@@ -391,10 +431,10 @@ export default class ServerRouter<
391
431
  path,
392
432
  regex,
393
433
  keys,
434
+ data,
394
435
  controller: (context: TRouterContext<this>) => new Page(route, renderer, context, layout),
395
436
  options: this.buildRouteOptions({
396
437
  accept: 'html', // Les pages retournent forcémment du html
397
- setup,
398
438
  ...options,
399
439
  }),
400
440
  };
@@ -573,6 +613,32 @@ export default class ServerRouter<
573
613
  /*----------------------------------
574
614
  - RESOLUTION
575
615
  ----------------------------------*/
616
+ private async finalizeRequest(
617
+ request: ServerRequest<this>,
618
+ output: {
619
+ statusCode: number;
620
+ user?: string;
621
+ errorMessage?: string;
622
+ },
623
+ ) {
624
+ this.app.container.Trace.finishRequest(request.id, output);
625
+
626
+ try {
627
+ await this.runHook('request.finished', request);
628
+ } catch (error) {
629
+ const typedError =
630
+ error instanceof Error ? error : new Error(typeof error === 'string' ? error : 'Unknown request.finished hook error');
631
+
632
+ try {
633
+ await this.app.runHook('error', typedError, request);
634
+ } catch (hookError) {
635
+ console.error('request.finished hook error', typedError, 'Error hook failure', hookError);
636
+ }
637
+ } finally {
638
+ this.app.container.Trace.releaseRequest(request.id);
639
+ }
640
+ }
641
+
576
642
  public async middleware(req: express.Request, res: express.Response) {
577
643
  // Create request
578
644
  let requestId = uuid();
@@ -595,7 +661,7 @@ export default class ServerRouter<
595
661
  this,
596
662
  );
597
663
 
598
- this.app.container.Trace.startRequest({
664
+ request.profiling = this.app.container.Trace.startRequest({
599
665
  id: request.id,
600
666
  method: request.method,
601
667
  path: request.path,
@@ -606,7 +672,15 @@ export default class ServerRouter<
606
672
  profilerOrigin: request.headers[profilerOriginHeader] || undefined,
607
673
  profilerParentRequestId: request.headers[profilerParentRequestIdHeader] || undefined,
608
674
  });
609
- if (this.app.container.Trace.isEnabled()) res.setHeader(profilerTraceRequestIdHeader, request.id);
675
+ if (this.app.container.Trace.isDevTraceEnabled()) res.setHeader(profilerTraceRequestIdHeader, request.id);
676
+ if (cachedPage) {
677
+ this.app.container.Trace.record(
678
+ request.id,
679
+ 'cache.hit',
680
+ { cacheKey: req.path, cachePhase: 'hit' },
681
+ 'summary',
682
+ );
683
+ }
610
684
 
611
685
  let response: ServerResponse<this>;
612
686
  try {
@@ -617,7 +691,7 @@ export default class ServerRouter<
617
691
  // Bulk API Requests
618
692
  if (request.path === '/api' && typeof request.data.fetchers === 'object') {
619
693
  await this.resolveApiBatch(request.data.fetchers, request);
620
- this.app.container.Trace.finishRequest(request.id, {
694
+ await this.finalizeRequest(request, {
621
695
  statusCode: request.res.statusCode || 200,
622
696
  user: request.user?.email,
623
697
  });
@@ -654,7 +728,7 @@ export default class ServerRouter<
654
728
  },
655
729
  'summary',
656
730
  );
657
- this.app.container.Trace.finishRequest(request.id, {
731
+ await this.finalizeRequest(request, {
658
732
  statusCode: response.statusCode,
659
733
  user: request.user?.email,
660
734
  });
@@ -673,7 +747,7 @@ export default class ServerRouter<
673
747
  'summary',
674
748
  );
675
749
  res.send(cachedPage.rendered);
676
- this.app.container.Trace.finishRequest(request.id, {
750
+ await this.finalizeRequest(request, {
677
751
  statusCode: response.statusCode,
678
752
  user: request.user?.email,
679
753
  });
@@ -697,19 +771,19 @@ export default class ServerRouter<
697
771
  'summary',
698
772
  );
699
773
  res.send(response.data);
700
- this.app.container.Trace.finishRequest(request.id, {
774
+ await this.finalizeRequest(request, {
701
775
  statusCode: response.statusCode,
702
776
  user: request.user?.email,
703
777
  });
704
778
  } else if (response.data !== 'true') {
705
- this.app.container.Trace.finishRequest(request.id, {
779
+ await this.finalizeRequest(request, {
706
780
  statusCode: res.statusCode || response.statusCode,
707
781
  user: request.user?.email,
708
782
  errorMessage: "Can't return data from the controller since response has already been sent via express.",
709
783
  });
710
784
  throw new Error("Can't return data from the controller since response has already been sent via express.");
711
785
  } else {
712
- this.app.container.Trace.finishRequest(request.id, {
786
+ await this.finalizeRequest(request, {
713
787
  statusCode: res.statusCode || response.statusCode,
714
788
  user: request.user?.email,
715
789
  });
@@ -747,8 +821,10 @@ export default class ServerRouter<
747
821
  // This is for debugging
748
822
  channelType: 'request',
749
823
  channelId: request.id,
824
+ silentLogs: request.headers['x-proteum-static-warmup'] === '1',
750
825
  method: request.method,
751
826
  path: request.path,
827
+ connectedNamespace: request.headers[profilerConnectedNamespaceHeader] || undefined,
752
828
  ...(request.traceCall
753
829
  ? {
754
830
  traceCallFetcherId: request.traceCall.fetcherId,
@@ -930,8 +1006,6 @@ export default class ServerRouter<
930
1006
  });
931
1007
 
932
1008
  private async resolvedRoute(route: TMatchedRoute, response: ServerResponse<this>, timeStart: number) {
933
- route = await response.resolveRouteOptions(route);
934
-
935
1009
  this.app.container.Trace.record(
936
1010
  response.request.id,
937
1011
  'resolve.route-match',
@@ -964,11 +1038,19 @@ export default class ServerRouter<
964
1038
  if (!staticUrl) continue;
965
1039
 
966
1040
  console.log('[router] Set in cache', staticUrl);
1041
+ this.app.container.Trace.record(
1042
+ response.request.id,
1043
+ 'cache.write',
1044
+ { cacheKey: staticUrl, cachePhase: 'write' },
1045
+ 'summary',
1046
+ );
967
1047
  void this.renderStatic(
968
1048
  staticUrl,
969
1049
  route.options.static,
970
1050
  staticUrl === response.request.path ? response.data : undefined,
971
- );
1051
+ ).catch((error) => {
1052
+ console.error('[router] Static cache write failed', staticUrl, error);
1053
+ });
972
1054
  }
973
1055
  }
974
1056
 
@@ -6,6 +6,7 @@
6
6
 
7
7
  import { fromJson as errorFromJson } from '@common/errors';
8
8
  import {
9
+ profilerConnectedNamespaceHeader,
9
10
  profilerOriginHeader,
10
11
  profilerParentRequestIdHeader,
11
12
  profilerSessionIdHeader,
@@ -87,6 +88,7 @@ export default class ApiClientRequest extends RequestService implements ApiClien
87
88
 
88
89
  if (fetcher.options?.connected) {
89
90
  headers.set(profilerOriginHeader, this.getTraceCallOrigin());
91
+ headers.set(profilerConnectedNamespaceHeader, fetcher.options.connected.namespace);
90
92
 
91
93
  const profilerSessionId = this.request.headers[profilerSessionIdHeader];
92
94
  if (profilerSessionId) headers.set(profilerSessionIdHeader, profilerSessionId);
@@ -102,7 +104,11 @@ export default class ApiClientRequest extends RequestService implements ApiClien
102
104
 
103
105
  const connectedProject = this.request.router.app.connectedProjects?.[connected.namespace];
104
106
  if (!connectedProject) {
105
- throw new Error(`Connected project "${connected.namespace}" is not registered on ${this.request.router.app.identity.identifier}.`);
107
+ throw new Error(
108
+ `Proteum connected boundary mismatch: "${connected.namespace}" is not registered on ${this.request.router.app.identity.identifier}. ` +
109
+ `Likely fix: declare connect.${connected.namespace} in proteum.config.ts for the consumer app or stop using that connected controller accessor here. ` +
110
+ `Re-check both SSR and client navigation if this fetcher is used from a page data or render path.`,
111
+ );
106
112
  }
107
113
 
108
114
  const headers = this.buildConnectedRequestHeaders(fetcher);
@@ -10,7 +10,7 @@ import Bowser from 'bowser';
10
10
 
11
11
  // Core
12
12
  import BaseRequest from '@common/router/request';
13
- import type { TTraceCallOrigin } from '@common/dev/requestTrace';
13
+ import type { TRequestProfiling, TTraceCallOrigin } from '@common/dev/requestTrace';
14
14
 
15
15
  // Specific
16
16
  import type { HttpMethod, HttpHeaders } from '..';
@@ -74,6 +74,7 @@ export default class ServerRequest<TRouter extends TAnyRouter = TAnyRouter> exte
74
74
  // Services
75
75
  public api: ApiClient;
76
76
  public traceCall?: TRequestTraceCallContext;
77
+ public profiling!: TRequestProfiling;
77
78
 
78
79
  /*----------------------------------
79
80
  - INITIALISATION
@@ -17,7 +17,6 @@ import ServerRequest from '@server/services/router/request';
17
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
- import { splitRouteSetupResult } from '@common/router/pageSetup';
21
20
  import Page from './page';
22
21
  import createControllers from '@generated/common/controllers';
23
22
  import type { TControllers } from '@generated/common/controllers';
@@ -154,11 +153,18 @@ export default class ServerResponse<
154
153
  // Create response context for controllers
155
154
  const requestContext = await this.createContext(route);
156
155
  const contextStore = context.getStore() as
157
- | { requestContext?: TRouterContext<TAnyRouter>; inputSchemaUsed?: boolean }
156
+ | {
157
+ requestContext?: TRouterContext<TAnyRouter>;
158
+ inputSchemaUsed?: boolean;
159
+ ownerLabel?: string;
160
+ ownerFilepath?: string;
161
+ }
158
162
  | undefined;
159
163
  if (contextStore) {
160
164
  contextStore.requestContext = requestContext;
161
165
  contextStore.inputSchemaUsed = false;
166
+ contextStore.ownerLabel = getRouteTraceTarget(route as TAnyRoute<TRouterContext<TServerRouter>>);
167
+ contextStore.ownerFilepath = route.options.filepath || undefined;
162
168
  }
163
169
 
164
170
  // Run controller
@@ -213,32 +219,6 @@ export default class ServerResponse<
213
219
  - INTERNAL
214
220
  ----------------------------------*/
215
221
 
216
- public async resolveRouteOptions(
217
- route: TMatchedRoute<TRouterContext<TRouter>>,
218
- ): Promise<TMatchedRoute<TRouterContext<TRouter>>> {
219
- const setup = route.options.setup;
220
- if (!setup) return route;
221
-
222
- const requestContext = await this.createContext(route);
223
- const { options } = splitRouteSetupResult(((setup as any)({ ...requestContext, data: this.request.data }) as {}) || {});
224
-
225
- this.app.container.Trace.record(
226
- this.request.id,
227
- 'setup.options',
228
- {
229
- optionKeys: Object.keys(options),
230
- source: {
231
- filepath: route.options.filepath || '',
232
- line: route.options.sourceLocation?.line || 0,
233
- column: route.options.sourceLocation?.column || 0,
234
- },
235
- },
236
- 'resolve',
237
- );
238
-
239
- return { ...route, options: { ...route.options, ...options } };
240
- }
241
-
242
222
  // Start controller services
243
223
  private async createContext(route: TAnyRoute<TRouterContext<TRouter>>): Promise<TRequestContext> {
244
224
  const contextServices = this.router.createContextServices(this.request);
@@ -3,6 +3,18 @@ declare module 'accepts' {
3
3
  export default accepts;
4
4
  }
5
5
 
6
+ declare module '@babel/generator' {
7
+ const generate: any;
8
+ export default generate;
9
+ }
10
+
11
+ declare module '@babel/traverse' {
12
+ export type Binding = any;
13
+ export type NodePath<T = any> = any;
14
+ const traverse: any;
15
+ export default traverse;
16
+ }
17
+
6
18
  declare module 'bytes' {
7
19
  const bytes: (value: string | number) => number;
8
20
  export default bytes;
@@ -3,6 +3,18 @@ declare module 'accepts' {
3
3
  export default accepts;
4
4
  }
5
5
 
6
+ declare module '@babel/generator' {
7
+ const generate: any;
8
+ export default generate;
9
+ }
10
+
11
+ declare module '@babel/traverse' {
12
+ export type Binding = any;
13
+ export type NodePath<T = any> = any;
14
+ const traverse: any;
15
+ export default traverse;
16
+ }
17
+
6
18
  declare module 'bytes' {
7
19
  const bytes: (value: string | number) => number;
8
20
  export default bytes;
@@ -1,51 +0,0 @@
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
- 'authTracking',
15
- 'redirectLogged',
16
- 'static',
17
- 'whenStatic',
18
- 'canonicalParams',
19
- 'layout',
20
- 'TESTING',
21
- 'logging',
22
- ] as const satisfies (keyof TRouteOptions)[];
23
-
24
- export const reservedRouteSetupKeys = ['id', 'filepath', 'bodyId', 'data', 'setup'] as const;
25
-
26
- const routeSetupOptionKeysSet = new Set<string>(routeSetupOptionKeys);
27
- const reservedRouteSetupKeysSet = new Set<string>(reservedRouteSetupKeys);
28
-
29
- export const getRouteSetupOptionKey = (key: string) => {
30
- const normalizedKey = key.startsWith('_') ? key.substring(1) : key;
31
-
32
- if (reservedRouteSetupKeysSet.has(normalizedKey)) throw new Error(`"${key}" is a reserved Router.page setup key.`);
33
-
34
- return routeSetupOptionKeysSet.has(normalizedKey) ? (normalizedKey as keyof TRouteOptions) : null;
35
- };
36
-
37
- export const splitRouteSetupResult = (result: TObjetDonnees | undefined) => {
38
- const options: Partial<TRouteOptions> = {};
39
- const data: TObjetDonnees = {};
40
-
41
- if (!result) return { options, data };
42
-
43
- for (const key in result) {
44
- const optionKey = getRouteSetupOptionKey(key);
45
-
46
- if (optionKey) options[optionKey] = result[key];
47
- else data[key] = result[key];
48
- }
49
-
50
- return { options, data };
51
- };