proteum 2.2.7 → 2.2.9

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 (43) hide show
  1. package/AGENTS.md +2 -1
  2. package/README.md +1 -1
  3. package/agents/project/AGENTS.md +4 -5
  4. package/agents/project/CODING_STYLE.md +5 -1
  5. package/agents/project/client/AGENTS.md +2 -0
  6. package/agents/project/diagnostics.md +2 -3
  7. package/agents/project/root/AGENTS.md +4 -5
  8. package/agents/project/tests/AGENTS.md +0 -1
  9. package/cli/commands/check.ts +21 -3
  10. package/cli/commands/configure.ts +1 -0
  11. package/cli/compiler/artifacts/controllers.ts +30 -4
  12. package/cli/compiler/artifacts/services.ts +67 -29
  13. package/cli/presentation/commands.ts +2 -2
  14. package/cli/scaffold/templates.ts +2 -3
  15. package/cli/utils/agents.ts +114 -4
  16. package/client/dev/profiler/ApexChart.tsx +4 -3
  17. package/common/dev/inspection.ts +16 -3
  18. package/common/dev/serverHotReload.ts +26 -25
  19. package/eslint.js +220 -0
  20. package/package.json +1 -1
  21. package/server/app/commands.ts +11 -16
  22. package/server/app/commandsManager.ts +5 -1
  23. package/server/app/controller/index.ts +68 -16
  24. package/server/app/devCommands.ts +3 -3
  25. package/server/app/devDiagnostics.ts +2 -2
  26. package/server/app/index.ts +19 -8
  27. package/server/app/service/container.ts +22 -19
  28. package/server/app/service/index.ts +33 -13
  29. package/server/app.tsconfig.json +0 -1
  30. package/server/services/auth/index.ts +12 -6
  31. package/server/services/auth/router/index.ts +12 -14
  32. package/server/services/auth/router/request.ts +34 -13
  33. package/server/services/disks/driver.ts +1 -1
  34. package/server/services/disks/index.ts +11 -8
  35. package/server/services/email/index.ts +1 -1
  36. package/server/services/prisma/Facet.ts +6 -5
  37. package/server/services/router/index.ts +8 -7
  38. package/server/services/router/request/validation/zod.ts +2 -0
  39. package/server/services/router/response/index.ts +9 -9
  40. package/server/services/router/service.ts +12 -8
  41. package/tests/agents-utils.test.cjs +55 -0
  42. package/tests/eslint-rules.test.cjs +110 -0
  43. package/types/global/vendors.d.ts +70 -0
@@ -3,29 +3,32 @@
3
3
  ----------------------------------*/
4
4
 
5
5
  // Specific
6
- import type { AnyService, AnyServiceClass, StartedServicesIndex } from '.';
6
+ import type { AnyServiceClass, StartedServicesIndex } from '.';
7
7
 
8
8
  /*----------------------------------
9
9
  - TYPES
10
10
  ----------------------------------*/
11
11
 
12
- export type ServiceConfig<TServiceClass extends AnyServiceClass> = NonNullable<ConstructorParameters<TServiceClass>[1]>;
12
+ type ConstructorConfig<TServiceClass extends AnyServiceClass> = ConstructorParameters<TServiceClass> extends [
13
+ _parent: object | 'self',
14
+ config: infer TConfig,
15
+ _app: object | 'self',
16
+ ..._rest: []
17
+ ]
18
+ ? NonNullable<TConfig>
19
+ : ConstructorParameters<TServiceClass> extends [config: infer TConfig, _app: object | 'self', ..._rest: []]
20
+ ? NonNullable<TConfig>
21
+ : {};
13
22
 
14
- type ExactConfig<TValue, TShape> = TValue extends TShape
15
- ? TShape extends (...args: never[]) => infer _TReturn
16
- ? TValue
17
- : TValue extends readonly (infer TValueItem)[]
18
- ? TShape extends readonly (infer TShapeItem)[]
19
- ? readonly ExactConfig<TValueItem, TShapeItem>[]
20
- : never
21
- : TValue extends object
22
- ? TShape extends object
23
- ? Exclude<keyof TValue, keyof TShape> extends never
24
- ? { [K in keyof TValue]: K extends keyof TShape ? ExactConfig<TValue[K], TShape[K]> : never }
25
- : never
26
- : TValue
27
- : TValue
28
- : never;
23
+ export type ServiceConfig<TServiceClass extends AnyServiceClass> = ConstructorConfig<TServiceClass>;
24
+
25
+ type ExactConfig<TConfig, TExpected> = TExpected extends object
26
+ ? TConfig extends object
27
+ ? { [TKey in Exclude<keyof TConfig, keyof TExpected>]: never } & {
28
+ [TKey in keyof TConfig & keyof TExpected]?: ExactConfig<TConfig[TKey], NonNullable<TExpected[TKey]>>;
29
+ }
30
+ : {}
31
+ : {};
29
32
 
30
33
  /*----------------------------------
31
34
  - CLASS
@@ -41,7 +44,7 @@ export class ServicesContainer<TServicesIndex extends StartedServicesIndex = Sta
41
44
  public callableInstance = <TInstance extends object, TCallableName extends keyof TInstance>(
42
45
  instance: TInstance,
43
46
  funcName: TCallableName,
44
- ): TInstance[TCallableName] & TInstance => {
47
+ ): TInstance[TCallableName] & { serviceInstance: TInstance } => {
45
48
  const instanceRecord = instance as Record<string, unknown>;
46
49
  const callableFunc = instance[funcName];
47
50
  if (typeof callableFunc !== 'function') throw new Error(`instance[funcName] isn't callable.`);
@@ -66,7 +69,7 @@ export class ServicesContainer<TServicesIndex extends StartedServicesIndex = Sta
66
69
  // Allow us to recognize a callable as a service
67
70
  callable.serviceInstance = instance;
68
71
 
69
- return callable as TInstance[TCallableName] & TInstance;
72
+ return callable as TInstance[TCallableName] & { serviceInstance: TInstance };
70
73
  };
71
74
  }
72
75
 
@@ -5,16 +5,27 @@
5
5
  // Specific
6
6
  import type { Application } from '../index';
7
7
  import type { Command } from '../commands';
8
- import type { TRouterContext, TAnyRouter } from '../../services/router';
8
+ import type {
9
+ Request as ServerRequest,
10
+ Response as ServerResponse,
11
+ TRouterContextServices,
12
+ TAnyRouter,
13
+ } from '../../services/router';
9
14
 
10
15
  export { schema } from '../../services/router/request/validation/zod';
11
- export type { z } from '../../services/router/request/validation/zod';
16
+ export type {
17
+ z,
18
+ TInferValidationSchema,
19
+ TTypedValidationSchema,
20
+ TValidationSchema,
21
+ TValidationShape,
22
+ } from '../../services/router/request/validation/zod';
12
23
 
13
24
  /*----------------------------------
14
25
  - TYPES: OPTIONS
15
26
  ----------------------------------*/
16
27
 
17
- export type AnyService = Service<{}, {}, Application, any>;
28
+ export type AnyService = Service<{}, any, any, any>;
18
29
  export type AnyServiceClass = ClassType<AnyService>;
19
30
 
20
31
  /*----------------------------------
@@ -31,7 +42,7 @@ export type THooksIndex<THooks extends THooksList> = { [name in keyof THooks]?:
31
42
 
32
43
  export type StartedServicesIndex = { [serviceId: string]: AnyService };
33
44
 
34
- type TServiceRouter<TApplication extends Application> = TApplication extends { Router: infer TRouter }
45
+ type TServiceRouter<TApplication extends object> = TApplication extends { Router: infer TRouter }
35
46
  ? TRouter extends TAnyRouter
36
47
  ? TRouter
37
48
  : TAnyRouter
@@ -41,11 +52,18 @@ type TServiceRouter<TApplication extends Application> = TApplication extends { R
41
52
  * @deprecated Services should not depend on request context.
42
53
  * Resolve auth/input/request data in controllers and pass explicit typed values into services instead.
43
54
  */
44
- export type TServiceRequestContext<TApplication extends Application = Application> = TRouterContext<
45
- TServiceRouter<TApplication>
46
- >;
47
-
48
- export type TServiceModelsClient<TApplication extends Application = Application> = TApplication extends {
55
+ export type TServiceRequestContext<TApplication extends object = object> = {
56
+ app: TApplication;
57
+ context: object;
58
+ request: ServerRequest<TServiceRouter<TApplication>>;
59
+ api: ServerRequest<TServiceRouter<TApplication>>['api'];
60
+ response: ServerResponse<TServiceRouter<TApplication>>;
61
+ route: object;
62
+ page?: object;
63
+ Router: TServiceRouter<TApplication>;
64
+ } & TRouterContextServices<TServiceRouter<TApplication>>;
65
+
66
+ export type TServiceModelsClient<TApplication extends object = object> = TApplication extends {
49
67
  Models: { client: infer TModels };
50
68
  }
51
69
  ? TModels
@@ -53,10 +71,12 @@ export type TServiceModelsClient<TApplication extends Application = Application>
53
71
  models: { client: infer TModels };
54
72
  }
55
73
  ? TModels
56
- : never;
74
+ : object;
57
75
 
58
- export type TSetupConfig<TConfig> = TConfig extends (...args: any[]) => any
76
+ export type TSetupConfig<TConfig> = TConfig extends (...args: infer TFunctionArgs) => infer TFunctionResult
59
77
  ? TConfig
78
+ : TConfig extends { getServiceInstance: (...args: infer TServiceArgs) => infer TServiceInstance }
79
+ ? TConfig
60
80
  : TConfig extends Array<infer TItem>
61
81
  ? Array<TSetupConfig<TItem>>
62
82
  : TConfig extends object
@@ -86,8 +106,8 @@ const resolveSelfReference = <TSelf extends object, TValue extends object>(
86
106
  export default abstract class Service<
87
107
  TConfig extends {},
88
108
  THooks extends THooksList,
89
- TApplication extends Application = Application,
90
- TParent extends object = AnyService,
109
+ TApplication extends object = object,
110
+ TParent extends object = object,
91
111
  > {
92
112
  public started?: Promise<void>;
93
113
  public starting?: Promise<void>;
@@ -6,7 +6,6 @@
6
6
  "paths": {
7
7
 
8
8
  "@/server/models": ["./.proteum/server/models.ts"],
9
- "@/client/context": ["./.proteum/client/context.ts"],
10
9
  "@generated/client/*": ["./.proteum/client/*"],
11
10
  "@generated/common/*": ["./.proteum/common/*"],
12
11
  "@generated/server/*": ["./.proteum/server/*"],
@@ -10,7 +10,6 @@ import type http from 'http';
10
10
  // Core
11
11
  import type { Application } from '@server/app/index';
12
12
  import Service from '@server/app/service';
13
- import { type TAnyRouter, Request as ServerRequest } from '@server/services/router';
14
13
  import * as AuthErrors from '@common/errors';
15
14
  import type { TTraceCaptureMode, TTraceEventType } from '@common/dev/requestTrace';
16
15
 
@@ -103,7 +102,13 @@ export type TAuthConfiguredRules = {
103
102
 
104
103
  export type TAuthTrackingContext = ProteumAuthTrackingContext | null;
105
104
 
106
- export type TAuthRulesFactory<TUser extends TBasicUser, TRequest extends ServerRequest<TAnyRouter>> = (
105
+ export type TAuthRequest = {
106
+ id: string;
107
+ res: Pick<express.Response, 'clearCookie' | 'cookie'>;
108
+ user: TBasicUser | null;
109
+ };
110
+
111
+ export type TAuthRulesFactory<TUser extends TBasicUser, TRequest extends TAuthRequest> = (
107
112
  user: TUser,
108
113
  tracking: TAuthTrackingContext,
109
114
  request: TRequest,
@@ -121,7 +126,7 @@ export const UserRoles = ['USER', 'ADMIN', 'TEST', 'DEV'] as const;
121
126
 
122
127
  export type TConfig<
123
128
  TUser extends TBasicUser = TBasicUser,
124
- TRequest extends ServerRequest<TAnyRouter> = ServerRequest<TAnyRouter>,
129
+ TRequest extends TAuthRequest = TAuthRequest,
125
130
  > = {
126
131
  debug: boolean;
127
132
  logoutUrl: string;
@@ -155,7 +160,7 @@ export default abstract class AuthService<
155
160
  TUser extends TBasicUser,
156
161
  TApplication extends Application,
157
162
  TJwtSession extends TBasicJwtSession = TBasicJwtSession,
158
- TRequest extends ServerRequest<TAnyRouter> = ServerRequest<TAnyRouter>,
163
+ TRequest extends TAuthRequest = TAuthRequest,
159
164
  > extends Service<TConfig<TUser, TRequest>, THooks, TApplication, TApplication> {
160
165
  public login?(request: TRequest, email: string): Promise<unknown>;
161
166
  public abstract decodeSession(jwt: TJwtSession, req: THttpRequest): Promise<TUser | null>;
@@ -200,7 +205,8 @@ export default abstract class AuthService<
200
205
  if ('apiKey' in session) {
201
206
  return {
202
207
  payloadKind: 'api-key',
203
- payloadAccountType: session.accountType ?? null,
208
+ payloadAccountType:
209
+ 'accountType' in session && typeof session.accountType === 'string' ? session.accountType : null,
204
210
  };
205
211
  }
206
212
 
@@ -602,7 +608,7 @@ export default abstract class AuthService<
602
608
  ): TUser | null {
603
609
  const user = this.getDecodedUser(request);
604
610
  const conditionRuleNames =
605
- conditions && conditions !== false
611
+ conditions
606
612
  ? (Object.keys(conditions) as Array<Extract<keyof TAuthConfiguredRules, string>>)
607
613
  : [];
608
614
 
@@ -11,32 +11,30 @@ import {
11
11
  TAnyRoute,
12
12
  RouterService,
13
13
  TAnyRouter,
14
+ TServerRouter,
14
15
  } from '@server/services/router';
15
16
 
16
17
  import type { Application } from '@server/app/index';
18
+ import AppContainer from '@server/app/container';
17
19
 
18
20
  import type { TRouterServiceArgs } from '@server/services/router/service';
19
21
 
20
22
  // Specific
21
23
  import type { default as UsersService, TAuthCheckConditions, TBasicUser } from '..';
22
- import UsersRequestService from './request';
23
-
24
- /*----------------------------------
25
- - TYPES
26
- ----------------------------------*/
24
+ import { createUsersRequestService, type TUsersRequestContext } from './request';
27
25
 
28
26
  /*----------------------------------
29
27
  - SERVICE
30
28
  ----------------------------------*/
31
29
  export default class AuthenticationRouterService<
32
- TApplication extends Application = Application,
33
- TUser extends TBasicUser = TApplication['app']['userType'],
34
- TRouter extends TAnyRouter = TAnyRouter,
30
+ TApplication extends Application,
31
+ TUser extends TBasicUser,
32
+ TRouter extends TAnyRouter = TServerRouter,
35
33
  TRequest extends ServerRequest<TRouter> = ServerRequest<TRouter>,
36
34
  > extends RouterService<
37
35
  { users: UsersService<TUser, TApplication> },
38
36
  TRouter,
39
- UsersRequestService<TRouter, TUser, TRequest>
37
+ TUsersRequestContext<TUser>
40
38
  > {
41
39
  /*----------------------------------
42
40
  - LIFECYCLE
@@ -45,7 +43,7 @@ export default class AuthenticationRouterService<
45
43
  public users: UsersService<TUser, TApplication>;
46
44
 
47
45
  public constructor(
48
- getConfig: TRouterServiceArgs<{ users: UsersService<TUser, TApplication> }, TRouter>[0],
46
+ getConfig: TRouterServiceArgs<{ users: UsersService<TUser, TApplication> }>[0],
49
47
  app: TApplication,
50
48
  ) {
51
49
  super(getConfig, app);
@@ -59,11 +57,11 @@ export default class AuthenticationRouterService<
59
57
  details: Record<string, any>,
60
58
  minimumCapture: 'summary' | 'resolve' | 'deep' = 'resolve',
61
59
  ) {
62
- this.app.container.Trace.record(
60
+ AppContainer.Trace.record(
63
61
  request.id,
64
62
  'auth.route',
65
63
  {
66
- routePath: route.path || '',
64
+ routePath: 'path' in route ? route.path || '' : '',
67
65
  routeId: route.options.id || '',
68
66
  authInput: route.options.auth ?? null,
69
67
  tracking: route.options.authTracking ?? null,
@@ -219,7 +217,7 @@ export default class AuthenticationRouterService<
219
217
  - ROUTER SERVICE LIFECYCLE
220
218
  ----------------------------------*/
221
219
 
222
- public requestService(request: TRequest): UsersRequestService<TRouter, TUser, TRequest> {
223
- return new UsersRequestService(request, this);
220
+ public requestService(request: TRequest): TUsersRequestContext<TUser> {
221
+ return createUsersRequestService(request, this.users);
224
222
  }
225
223
  }
@@ -2,13 +2,11 @@
2
2
  - DEPENDANCES
3
3
  ----------------------------------*/
4
4
 
5
- // Core
6
- import type { Request as ServerRequest, TAnyRouter } from '@server/services/router';
7
- import RequestService from '@server/services/router/request/service';
5
+ import type { Application } from '@server/app/index';
8
6
 
9
7
  // Specific
10
- import type AuthenticationRouterService from '.';
11
- import type { TAuthCheckConditions, TAuthTrackingContext, TUserRole } from '..';
8
+ import type UsersService from '..';
9
+ import type { TAuthCheckConditions, TAuthRequest, TAuthTrackingContext, TUserRole } from '..';
12
10
 
13
11
  // Types
14
12
  import type { TBasicUser } from '@server/services/auth';
@@ -17,21 +15,36 @@ import type { TBasicUser } from '@server/services/auth';
17
15
  - TYPES
18
16
  ----------------------------------*/
19
17
 
18
+ type TUsersRouterService<TUser extends TBasicUser> = {
19
+ users: UsersService<TUser, Application>;
20
+ };
21
+
22
+ export interface TUsersRequestContext<TUser extends TBasicUser> {
23
+ login(email: string): Promise<unknown>;
24
+ logout(): void;
25
+
26
+ check(): TUser;
27
+ check(conditions: null, tracking?: TAuthTrackingContext): TUser;
28
+ check(conditions: TAuthCheckConditions, tracking?: TAuthTrackingContext): TUser;
29
+ check(conditions: false, tracking?: TAuthTrackingContext): null;
30
+ check(role: TUserRole, feature: null): TUser;
31
+ check(role: false): null;
32
+ check(role: TUserRole | true, feature: FeatureKeys, action?: string): TUser;
33
+ check(role: false, feature: FeatureKeys, action?: string): null;
34
+ }
35
+
20
36
  /*----------------------------------
21
37
  - MODULE
22
38
  ----------------------------------*/
23
39
  export default class UsersRequestService<
24
- TRouter extends TAnyRouter,
25
40
  TUser extends TBasicUser,
26
- TRequest extends ServerRequest<TRouter> = ServerRequest<TRouter>,
27
- > extends RequestService<TRequest> {
41
+ TRequest extends TAuthRequest,
42
+ > implements TUsersRequestContext<TUser> {
28
43
  public constructor(
29
- request: TRequest,
30
- public auth: AuthenticationRouterService<TRouter['app'], TUser, TRouter, TRequest>,
44
+ public request: TRequest,
45
+ public auth: TUsersRouterService<TUser>,
31
46
  public users = auth.users,
32
- ) {
33
- super(request);
34
- }
47
+ ) {}
35
48
 
36
49
  public login(email: string) {
37
50
  if (!this.users.login) throw new Error('The current auth service does not implement login().');
@@ -93,3 +106,11 @@ export default class UsersRequestService<
93
106
  return this.users.check(this.request, roleOrConditions, featureOrTracking, action);
94
107
  }
95
108
  }
109
+
110
+ export const createUsersRequestService = <
111
+ TUser extends TBasicUser,
112
+ TRequest extends TAuthRequest,
113
+ >(
114
+ request: TRequest,
115
+ users: UsersService<TUser, Application>,
116
+ ): TUsersRequestContext<TUser> => new UsersRequestService<TUser, TRequest>(request, { users });
@@ -27,7 +27,7 @@ export type TDrivercnfig = {
27
27
 
28
28
  export type SourceFile = { name: string; path: string; modified: number; parentFolder: string; source: string };
29
29
 
30
- export type TOutputFileOptions = { encoding: string };
30
+ export type TOutputFileOptions = { encoding: BufferEncoding };
31
31
 
32
32
  export type TReadFileOptions = { encoding?: 'string' | 'buffer'; withMetas?: boolean };
33
33
 
@@ -32,8 +32,6 @@ export default class DisksManager<
32
32
  TConfig extends Config & { default: keyof MountpointList & string; drivers: MountpointList },
33
33
  TApplication extends Application,
34
34
  > extends Service<TConfig, Hooks, TApplication, TApplication> {
35
- public default!: MountpointList[keyof MountpointList & string];
36
-
37
35
  /*----------------------------------
38
36
  - LIFECYCLE
39
37
  ----------------------------------*/
@@ -50,10 +48,14 @@ export default class DisksManager<
50
48
  drivers[driverId].parent = this;
51
49
  }*/
52
50
 
53
- const defaultDisk = drivers[this.config.default];
54
- if (defaultDisk === undefined) console.log(`Default disk "${this.config.default as string}" not mounted.`);
51
+ this.default;
52
+ }
55
53
 
56
- this.default = defaultDisk;
54
+ public get default(): Driver {
55
+ const drivers: Services = this.config.drivers;
56
+ const defaultDisk = drivers[this.config.default];
57
+ if (defaultDisk === undefined) throw new Error(`Default disk "${String(this.config.default)}" not mounted.`);
58
+ return defaultDisk;
57
59
  }
58
60
 
59
61
  public async shutdown() {}
@@ -62,13 +64,14 @@ export default class DisksManager<
62
64
  - LIFECYCLE
63
65
  ----------------------------------*/
64
66
 
65
- public get(diskName?: 'default' | keyof MountpointList) {
67
+ public get(diskName?: 'default' | keyof MountpointList): Driver {
68
+ const drivers: Services = this.config.drivers;
66
69
  const disk =
67
70
  diskName === 'default' || diskName === undefined
68
71
  ? this.default
69
- : this.config.drivers[diskName as keyof MountpointList];
72
+ : drivers[String(diskName)];
70
73
 
71
- if (disk === undefined) throw new Error(`Disk "${diskName as string}" not found.`);
74
+ if (disk === undefined) throw new Error(`Disk "${String(diskName)}" not found.`);
72
75
 
73
76
  return disk;
74
77
  }
@@ -57,7 +57,7 @@ type TOptions = { transporter?: string };
57
57
  /*----------------------------------
58
58
  - FONCTIONS
59
59
  ----------------------------------*/
60
- export default abstract class Email<TConfig extends Config, TApplication extends Application = Application> extends Service<
60
+ export default abstract class Email<TConfig extends Config, TApplication extends Application> extends Service<
61
61
  TConfig,
62
62
  Hooks,
63
63
  TApplication,
@@ -1,9 +1,10 @@
1
- import type { PrismaClient } from '@models/types';
2
-
3
1
  export type TDelegate<R = unknown> = {
4
2
  findMany(args?: Record<string, unknown>): Promise<R[]>;
5
3
  findFirst(args?: Record<string, unknown>): Promise<R | null>;
6
4
  };
5
+ type TPrismaRawClient = {
6
+ $queryRawUnsafe(query: string): Promise<Record<string, unknown>[]>;
7
+ };
7
8
 
8
9
  export type TWithStats = { $table: string; $key: string } & Record<string, string>;
9
10
 
@@ -18,7 +19,7 @@ export default class Facet<
18
19
  RT = R,
19
20
  > {
20
21
  constructor(
21
- private readonly prisma: PrismaClient,
22
+ private readonly prisma: TPrismaRawClient,
22
23
  private readonly delegate: D,
23
24
  private readonly subset: S,
24
25
  private readonly transform?: Transform<R, RT>,
@@ -57,13 +58,13 @@ export default class Facet<
57
58
  ), 0)) as ${key}`,
58
59
  );
59
60
 
60
- const statRows = (await this.prisma.$queryRawUnsafe(`
61
+ const statRows = await this.prisma.$queryRawUnsafe(`
61
62
  SELECT ${$key}, ${select.join(', ')}
62
63
  FROM ${$table}
63
64
  WHERE ${$key} IN (
64
65
  ${(results as Array<Record<string, unknown>>).map((row) => "'" + row[$key] + "'").join(',')}
65
66
  )
66
- `)) as Record<string, unknown>[];
67
+ `);
67
68
 
68
69
  for (const stat of statRows) {
69
70
  for (const key in stat) {
@@ -19,7 +19,8 @@ import zod, { ZodError } from 'zod';
19
19
  export { default as schema } from 'zod';
20
20
 
21
21
  // Core
22
- import Service, { AnyService, TServiceArgs } from '@server/app/service';
22
+ import type { Application } from '@server/app/index';
23
+ import Service, { TServiceArgs } from '@server/app/service';
23
24
  import context from '@server/context';
24
25
  import type DisksManager from '@server/services/disks';
25
26
  import { CoreError, InputError, NotFound, toJson as errorToJson } from '@common/errors';
@@ -104,16 +105,16 @@ const staticHtmlCacheControl = 'public, max-age=0, must-revalidate';
104
105
  ----------------------------------*/
105
106
 
106
107
  export type TAnyRouter = ServerRouter<
107
- AnyService['app'],
108
+ Application,
108
109
  TRouterServicesList,
109
- Config<TRouterServicesList, AnyService['app']>
110
+ Config<TRouterServicesList, Application>
110
111
  >;
111
112
 
112
113
  const LogPrefix = '[router]';
113
114
 
114
115
  export type Config<
115
116
  TServices extends TRouterServicesList,
116
- TApplication extends AnyService['app'] = AnyService['app'],
117
+ TApplication extends Application = Application,
117
118
  > = {
118
119
  debug: boolean;
119
120
 
@@ -147,16 +148,16 @@ export type TControllerDefinition = {
147
148
  };
148
149
 
149
150
  export type TServerRouter = ServerRouter<
150
- AnyService['app'],
151
+ Application,
151
152
  TRouterServicesList,
152
- Config<TRouterServicesList, AnyService['app']>
153
+ Config<TRouterServicesList, Application>
153
154
  >;
154
155
 
155
156
  /*----------------------------------
156
157
  - CLASSE
157
158
  ----------------------------------*/
158
159
  export default class ServerRouter<
159
- TApplication extends AnyService['app'] = AnyService['app'],
160
+ TApplication extends Application = Application,
160
161
  TServices extends TRouterServicesList = TRouterServicesList,
161
162
  TConfig extends Config<TServices, TApplication> = Config<TServices, TApplication>,
162
163
  >
@@ -4,6 +4,8 @@ import zod from 'zod';
4
4
  export type TRichTextValidatorOptions = { attachements?: boolean };
5
5
  export type TValidationSchema = zod.ZodTypeAny;
6
6
  export type TValidationShape = zod.ZodRawShape;
7
+ export type TInferValidationSchema<TSchema extends TValidationSchema> = zod.infer<TSchema>;
8
+ export type TTypedValidationSchema<TOutput> = zod.ZodType<TOutput>;
7
9
 
8
10
  type TChoiceOption = { value: PrimitiveValue; label: string };
9
11
 
@@ -12,7 +12,7 @@ import express from 'express';
12
12
 
13
13
  // Core
14
14
  import context from '@server/context';
15
- import type { AnyRouterService, default as ServerRouter, TServerRouter, TAnyRouter } from '@server/services/router';
15
+ import type { default as ServerRouter, TServerRouter, TAnyRouter } from '@server/services/router';
16
16
  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';
@@ -40,8 +40,7 @@ export type TBasicSSrData = {
40
40
  currentDomain: string;
41
41
  };
42
42
 
43
- type TServerRouterApplication<TRouter extends TServerRouter> =
44
- TRouter extends ServerRouter<infer TApplication, any, any> ? TApplication : never;
43
+ type TServerRouterApplication<TRouter extends TServerRouter> = TRouter['app'];
45
44
 
46
45
  type TServerRouterPlugins<TRouter extends TServerRouter> =
47
46
  TRouter extends ServerRouter<any, any, infer TConfig>
@@ -80,8 +79,10 @@ export type TRouterContextServices<
80
79
  // Custom context via servuces
81
80
  // For each roiuter service, return the request service (returned by roiuterService.requestService() )
82
81
  {
83
- [serviceName in keyof TPlugins]: TPlugins[serviceName] extends AnyRouterService
84
- ? Exclude<ReturnType<TPlugins[serviceName]['requestService']>, null | undefined>
82
+ [serviceName in keyof TPlugins]: TPlugins[serviceName] extends { requestService: infer TRequestServiceMethod }
83
+ ? TRequestServiceMethod extends (...args: infer TRequestServiceArgs) => infer TRequestService
84
+ ? Exclude<TRequestService, null | undefined>
85
+ : TPlugins[serviceName]
85
86
  : TPlugins[serviceName];
86
87
  };
87
88
 
@@ -97,7 +98,6 @@ const getRouteTraceTarget = (route: TAnyRoute<TRouterContext<TServerRouter>>) =>
97
98
  ----------------------------------*/
98
99
  export default class ServerResponse<
99
100
  TRouter extends TAnyRouter,
100
- TRequestContext extends TRouterContext<TRouter> = TRouterContext<TRouter>,
101
101
  TData extends TResponseData = TResponseData,
102
102
  > extends BaseResponse<TData, ServerRequest<TRouter>> {
103
103
  // Services
@@ -220,13 +220,13 @@ export default class ServerResponse<
220
220
  ----------------------------------*/
221
221
 
222
222
  // Start controller services
223
- private async createContext(route: TAnyRoute<TRouterContext<TRouter>>): Promise<TRequestContext> {
223
+ private async createContext(route: TAnyRoute<TRouterContext<TRouter>>): Promise<TRouterContext<TRouter>> {
224
224
  const contextServices = this.router.createContextServices(this.request);
225
225
  const controllers = createControllers(this.request.api);
226
226
  const customSsrData = this.router.config.context(this.request, this.app) as TRouterRequestContext<TRouter>;
227
227
 
228
228
  // TODO: transmiss safe data (especially for Router), as Router info could be printed on client side
229
- const requestContext = {
229
+ const requestContext: TRouterContext<TRouter> = {
230
230
  // Router context
231
231
  app: this.app,
232
232
  context: undefined!,
@@ -242,7 +242,7 @@ export default class ServerResponse<
242
242
  // Router services
243
243
  ...(contextServices as TRouterContextServices<TRouter>),
244
244
  ...customSsrData,
245
- } as TRequestContext;
245
+ };
246
246
 
247
247
  requestContext.context = requestContext;
248
248
 
@@ -7,15 +7,16 @@ import type { Application } from '@server/app/index';
7
7
  import Service, { TSetupConfig } from '@server/app/service';
8
8
 
9
9
  // Specific
10
- import type { default as Router } from '.';
11
10
  import type ServerRequest from './request';
12
11
  import type { TAnyRouter } from '.';
13
12
 
14
- export type AnyRouterService = RouterService<any, TAnyRouter, object | null>;
13
+ export type AnyRouterService = Service<{}, {}, Application, object> & {
14
+ requestService(request: object): object | null;
15
+ };
15
16
 
16
- export type TRouterServiceArgs<TConfig extends {} = {}, TRouter extends TAnyRouter = TAnyRouter> = [
17
+ export type TRouterServiceArgs<TConfig extends {} = {}> = [
17
18
  getConfig: TSetupConfig<TConfig> | null | undefined,
18
- app: TRouter['app'],
19
+ app: Application,
19
20
  ];
20
21
 
21
22
  /*----------------------------------
@@ -23,11 +24,14 @@ export type TRouterServiceArgs<TConfig extends {} = {}, TRouter extends TAnyRout
23
24
  ----------------------------------*/
24
25
  export default abstract class RouterService<
25
26
  TConfig extends {},
26
- TRouter extends TAnyRouter = TAnyRouter,
27
+ TRouter extends TAnyRouter,
27
28
  TRequestService extends object | null = object | null,
28
- > extends Service<TConfig, {}, TRouter['app'], TRouter> {
29
- public constructor(...[config, app]: TRouterServiceArgs<TConfig, TRouter>) {
30
- super(app as TRouter['app'] & TRouter, config, app);
29
+ > extends Service<TConfig, {}, Application, object> {
30
+ public declare parent: TRouter;
31
+ public declare app: TRouter extends { app: infer TApplication extends Application } ? TApplication : Application;
32
+
33
+ public constructor(...[config, app]: TRouterServiceArgs<TConfig>) {
34
+ super(app, config, app);
31
35
  }
32
36
 
33
37
  public abstract requestService(request: ServerRequest<TRouter>): TRequestService;