proteum 2.2.6 → 2.2.8
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/AGENTS.md +1 -1
- package/README.md +4 -4
- package/agents/project/AGENTS.md +2 -1
- package/agents/project/app-root/AGENTS.md +1 -1
- package/agents/project/diagnostics.md +1 -1
- package/agents/project/root/AGENTS.md +2 -1
- package/cli/commands/configure.ts +14 -35
- package/cli/commands/dev.ts +105 -52
- package/cli/compiler/artifacts/controllers.ts +30 -4
- package/cli/compiler/artifacts/manifest.ts +1 -5
- package/cli/compiler/artifacts/services.ts +67 -29
- package/cli/presentation/commands.ts +9 -9
- package/cli/presentation/help.ts +1 -1
- package/cli/scaffold/index.ts +2 -5
- package/cli/scaffold/templates.ts +3 -10
- package/cli/utils/agents.ts +281 -199
- package/client/dev/profiler/ApexChart.tsx +4 -3
- package/common/dev/serverHotReload.ts +26 -25
- package/package.json +1 -1
- package/server/app/commands.ts +11 -16
- package/server/app/commandsManager.ts +5 -1
- package/server/app/controller/index.ts +68 -16
- package/server/app/devCommands.ts +3 -3
- package/server/app/devDiagnostics.ts +2 -2
- package/server/app/index.ts +19 -8
- package/server/app/service/container.ts +22 -19
- package/server/app/service/index.ts +33 -13
- package/server/app.tsconfig.json +0 -1
- package/server/services/auth/index.ts +12 -6
- package/server/services/auth/router/index.ts +12 -14
- package/server/services/auth/router/request.ts +34 -13
- package/server/services/disks/driver.ts +1 -1
- package/server/services/disks/index.ts +11 -8
- package/server/services/email/index.ts +1 -1
- package/server/services/prisma/Facet.ts +6 -5
- package/server/services/router/index.ts +8 -7
- package/server/services/router/request/validation/zod.ts +2 -0
- package/server/services/router/response/index.ts +9 -9
- package/server/services/router/service.ts +12 -8
- package/tests/agents-utils.test.cjs +207 -0
- package/tests/dev-transpile-watch.test.cjs +513 -0
- package/types/global/vendors.d.ts +70 -0
|
@@ -18,7 +18,7 @@ export default function ApexChart({
|
|
|
18
18
|
if (!target || !options) return;
|
|
19
19
|
|
|
20
20
|
let disposed = false;
|
|
21
|
-
let chart: { destroy: () => void } | undefined;
|
|
21
|
+
let chart: { destroy: () => void; render: () => Promise<unknown> | void } | undefined;
|
|
22
22
|
|
|
23
23
|
target.innerHTML = '';
|
|
24
24
|
setErrorMessage(undefined);
|
|
@@ -29,8 +29,9 @@ export default function ApexChart({
|
|
|
29
29
|
if (disposed || !mountRef.current) return;
|
|
30
30
|
|
|
31
31
|
const ApexCharts = module.default;
|
|
32
|
-
|
|
33
|
-
|
|
32
|
+
const nextChart = new ApexCharts(mountRef.current, options);
|
|
33
|
+
chart = nextChart;
|
|
34
|
+
await nextChart.render();
|
|
34
35
|
} catch (error) {
|
|
35
36
|
if (!disposed) setErrorMessage(readErrorMessage(error));
|
|
36
37
|
}
|
|
@@ -27,33 +27,34 @@ export type TServerReadyMessage = {
|
|
|
27
27
|
connectedProjects?: TServerReadyConnectedProject[];
|
|
28
28
|
};
|
|
29
29
|
|
|
30
|
+
const isRecord = (value: unknown): value is Record<string, unknown> => typeof value === 'object' && value !== null;
|
|
31
|
+
|
|
30
32
|
export const isServerHotReloadRequest = (value: unknown): value is TServerHotReloadRequest =>
|
|
31
|
-
|
|
32
|
-
value
|
|
33
|
-
(value
|
|
34
|
-
Array.isArray((value as TServerHotReloadRequest).changedFiles);
|
|
33
|
+
isRecord(value) &&
|
|
34
|
+
value.type === serverHotReloadMessageType.request &&
|
|
35
|
+
Array.isArray(value.changedFiles);
|
|
35
36
|
|
|
36
37
|
export const isServerHotReloadResult = (value: unknown): value is TServerHotReloadResult =>
|
|
37
|
-
|
|
38
|
-
value
|
|
39
|
-
(
|
|
40
|
-
(value as TServerHotReloadResult).type === serverHotReloadMessageType.failed) &&
|
|
41
|
-
Array.isArray((value as TServerHotReloadResult).changedFiles);
|
|
38
|
+
isRecord(value) &&
|
|
39
|
+
(value.type === serverHotReloadMessageType.succeeded || value.type === serverHotReloadMessageType.failed) &&
|
|
40
|
+
Array.isArray(value.changedFiles);
|
|
42
41
|
|
|
43
42
|
const isServerReadyConnectedProject = (value: unknown): value is TServerReadyConnectedProject =>
|
|
44
|
-
|
|
45
|
-
value
|
|
46
|
-
typeof
|
|
47
|
-
typeof
|
|
48
|
-
typeof
|
|
49
|
-
typeof
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
(
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
(
|
|
59
|
-
(
|
|
43
|
+
isRecord(value) &&
|
|
44
|
+
typeof value.namespace === 'string' &&
|
|
45
|
+
typeof value.identifier === 'string' &&
|
|
46
|
+
typeof value.name === 'string' &&
|
|
47
|
+
typeof value.urlInternal === 'string' &&
|
|
48
|
+
typeof value.healthUrl === 'string';
|
|
49
|
+
|
|
50
|
+
export const isServerReadyMessage = (value: unknown): value is TServerReadyMessage => {
|
|
51
|
+
if (!isRecord(value)) return false;
|
|
52
|
+
|
|
53
|
+
const connectedProjects = value.connectedProjects;
|
|
54
|
+
return (
|
|
55
|
+
value.type === serverHotReloadMessageType.ready &&
|
|
56
|
+
typeof value.publicUrl === 'string' &&
|
|
57
|
+
(connectedProjects === undefined ||
|
|
58
|
+
(Array.isArray(connectedProjects) && connectedProjects.every(isServerReadyConnectedProject)))
|
|
59
|
+
);
|
|
60
|
+
};
|
package/package.json
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "proteum",
|
|
3
3
|
"description": "LLM-first Opinionated Typescript Framework for web applications.",
|
|
4
|
-
"version": "2.2.
|
|
4
|
+
"version": "2.2.8",
|
|
5
5
|
"author": "Gaetan Le Gac (https://github.com/gaetanlegac)",
|
|
6
6
|
"repository": "git://github.com/gaetanlegac/proteum.git",
|
|
7
7
|
"license": "MIT",
|
package/server/app/commands.ts
CHANGED
|
@@ -3,26 +3,25 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
import { Command as ClipanionCommand, Option, UsageError } from 'clipanion';
|
|
6
|
-
import type CurrentCommandApplication from '@/server/index';
|
|
7
6
|
|
|
8
7
|
/*----------------------------------
|
|
9
8
|
- TYPES
|
|
10
9
|
----------------------------------*/
|
|
11
10
|
|
|
12
11
|
export type TCommandApplication = {
|
|
13
|
-
env
|
|
12
|
+
env?: {
|
|
14
13
|
profile?: string;
|
|
15
14
|
name?: string;
|
|
16
15
|
[key: string]: unknown;
|
|
17
16
|
};
|
|
18
|
-
identity
|
|
17
|
+
identity?: {
|
|
19
18
|
identifier?: string;
|
|
20
19
|
[key: string]: unknown;
|
|
21
20
|
};
|
|
22
|
-
getRootServices
|
|
21
|
+
getRootServices?: () => Record<string, unknown>;
|
|
23
22
|
findService?: (serviceId: string) => unknown;
|
|
24
|
-
models?: { client?:
|
|
25
|
-
Models?: { client?:
|
|
23
|
+
models?: { client?: object };
|
|
24
|
+
Models?: { client?: object };
|
|
26
25
|
};
|
|
27
26
|
|
|
28
27
|
export type TCommandService = {
|
|
@@ -33,23 +32,19 @@ export type TCommandService = {
|
|
|
33
32
|
- COMMAND CLASSES
|
|
34
33
|
----------------------------------*/
|
|
35
34
|
|
|
36
|
-
export abstract class Commands<TApplication extends TCommandApplication =
|
|
37
|
-
public app:
|
|
35
|
+
export abstract class Commands<TApplication extends TCommandApplication = TCommandApplication> {
|
|
36
|
+
public app: TApplication;
|
|
38
37
|
|
|
39
|
-
public constructor(app:
|
|
38
|
+
public constructor(app: TApplication) {
|
|
40
39
|
this.app = app;
|
|
41
40
|
}
|
|
42
41
|
|
|
43
|
-
public get services():
|
|
42
|
+
public get services(): TApplication {
|
|
44
43
|
return this.app;
|
|
45
44
|
}
|
|
46
45
|
|
|
47
|
-
public get models():
|
|
48
|
-
const
|
|
49
|
-
models?: { client?: any };
|
|
50
|
-
Models?: { client?: any };
|
|
51
|
-
};
|
|
52
|
-
const models = app.models?.client ?? app.Models?.client;
|
|
46
|
+
public get models(): object {
|
|
47
|
+
const models = this.app.models?.client ?? this.app.Models?.client;
|
|
53
48
|
|
|
54
49
|
if (!models)
|
|
55
50
|
throw new Error(`${this.constructor.name} tried to access models but no Models service is registered.`);
|
|
@@ -197,13 +197,17 @@ const parseCommandOptionTokens = (tokens: string[]) => {
|
|
|
197
197
|
- SERVICE
|
|
198
198
|
----------------------------------*/
|
|
199
199
|
|
|
200
|
-
export default class CommandsManager extends Service<Config, Hooks, Application> {
|
|
200
|
+
export default class CommandsManager extends Service<Config, Hooks, Application, object> {
|
|
201
201
|
public priority = 2 as 2;
|
|
202
202
|
|
|
203
203
|
public commandsIndex: CommandsList = {};
|
|
204
204
|
|
|
205
205
|
private runtimeCli?: Cli;
|
|
206
206
|
|
|
207
|
+
public constructor(parent: object | 'self', config: Config | null | undefined, app: Application | 'self') {
|
|
208
|
+
super(parent, config, app);
|
|
209
|
+
}
|
|
210
|
+
|
|
207
211
|
public command<TArgs extends any[]>(
|
|
208
212
|
...args:
|
|
209
213
|
| [name: string, description: string, childrens: RuntimeCommand[]]
|
|
@@ -7,39 +7,88 @@ import zod from 'zod';
|
|
|
7
7
|
|
|
8
8
|
// Core
|
|
9
9
|
import context from '@server/context';
|
|
10
|
-
import type { Application } from '../index';
|
|
11
|
-
import type { TServiceModelsClient } from '../service';
|
|
12
|
-
import type { TRouterContext, TAnyRouter } from '@server/services/router';
|
|
13
10
|
import {
|
|
14
11
|
toValidationSchema,
|
|
15
12
|
type TValidationSchema,
|
|
16
13
|
type TValidationShape,
|
|
17
14
|
} from '@server/services/router/request/validation/zod';
|
|
15
|
+
import type {
|
|
16
|
+
Request as ServerRequest,
|
|
17
|
+
Response as ServerResponse,
|
|
18
|
+
TAnyRouter,
|
|
19
|
+
TRouterContextServices,
|
|
20
|
+
} from '@server/services/router';
|
|
18
21
|
|
|
19
22
|
export { schema } from '@server/services/router/request/validation/zod';
|
|
20
|
-
export type {
|
|
23
|
+
export type {
|
|
24
|
+
z,
|
|
25
|
+
TInferValidationSchema,
|
|
26
|
+
TTypedValidationSchema,
|
|
27
|
+
TValidationSchema,
|
|
28
|
+
TValidationShape,
|
|
29
|
+
} from '@server/services/router/request/validation/zod';
|
|
21
30
|
|
|
22
31
|
/*----------------------------------
|
|
23
32
|
- TYPES
|
|
24
33
|
----------------------------------*/
|
|
25
34
|
|
|
26
|
-
type
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
35
|
+
type TControllerModelsClient<TApplication extends object = object> = TApplication extends {
|
|
36
|
+
Models: { client: infer TModels };
|
|
37
|
+
}
|
|
38
|
+
? TModels
|
|
39
|
+
: TApplication extends {
|
|
40
|
+
models: { client: infer TModels };
|
|
41
|
+
}
|
|
42
|
+
? TModels
|
|
43
|
+
: object;
|
|
44
|
+
|
|
45
|
+
type TControllerRouter<TRouter> = TRouter extends TAnyRouter ? TRouter : TAnyRouter;
|
|
46
|
+
type TControllerApplicationRouter<TApplication extends object> = TApplication extends { Router: infer TRouter }
|
|
47
|
+
? TControllerRouter<TRouter>
|
|
30
48
|
: TAnyRouter;
|
|
31
49
|
|
|
32
|
-
export type TControllerRequestContext<
|
|
33
|
-
|
|
34
|
-
|
|
50
|
+
export type TControllerRequestContext<
|
|
51
|
+
TApplication extends object = object,
|
|
52
|
+
TRouter extends object = object,
|
|
53
|
+
TRequestServices extends object = {},
|
|
54
|
+
> = {
|
|
55
|
+
app: TApplication;
|
|
56
|
+
context: object;
|
|
57
|
+
request: ServerRequest<TControllerRouter<TRouter>>;
|
|
58
|
+
api: ServerRequest<TControllerRouter<TRouter>>['api'];
|
|
59
|
+
response: ServerResponse<TControllerRouter<TRouter>>;
|
|
60
|
+
route: object;
|
|
61
|
+
page?: object;
|
|
62
|
+
Router: TControllerRouter<TRouter>;
|
|
63
|
+
} & (TRouter extends TAnyRouter ? TRouterContextServices<TControllerRouter<TRouter>> : {}) &
|
|
64
|
+
TRequestServices;
|
|
65
|
+
|
|
66
|
+
type TControllerBaseContext<TApplication extends object> = {
|
|
67
|
+
app: TApplication;
|
|
68
|
+
request: { data: TObjetDonnees };
|
|
69
|
+
};
|
|
70
|
+
|
|
71
|
+
type TControllerDefaultContext<TApplication extends object, TRequestServices extends object> = {
|
|
72
|
+
app: TApplication;
|
|
73
|
+
context: object;
|
|
74
|
+
request: ServerRequest<TControllerApplicationRouter<TApplication>>;
|
|
75
|
+
api: ServerRequest<TControllerApplicationRouter<TApplication>>['api'];
|
|
76
|
+
response: ServerResponse<TControllerApplicationRouter<TApplication>>;
|
|
77
|
+
route: object;
|
|
78
|
+
page?: object;
|
|
79
|
+
Router: TControllerApplicationRouter<TApplication>;
|
|
80
|
+
} & TRouterContextServices<TControllerApplicationRouter<TApplication>> &
|
|
81
|
+
TRequestServices;
|
|
35
82
|
|
|
36
83
|
/*----------------------------------
|
|
37
84
|
- CLASS
|
|
38
85
|
----------------------------------*/
|
|
39
86
|
|
|
40
87
|
export default abstract class Controller<
|
|
41
|
-
TApplication extends
|
|
42
|
-
|
|
88
|
+
TApplication extends object = object,
|
|
89
|
+
TRouter extends object = object,
|
|
90
|
+
TRequestServices extends object = {},
|
|
91
|
+
TContext extends TControllerBaseContext<TApplication> = TControllerDefaultContext<TApplication, TRequestServices>,
|
|
43
92
|
> {
|
|
44
93
|
public constructor(public request: TContext) {}
|
|
45
94
|
|
|
@@ -51,9 +100,12 @@ export default abstract class Controller<
|
|
|
51
100
|
return this.app;
|
|
52
101
|
}
|
|
53
102
|
|
|
54
|
-
public get models():
|
|
55
|
-
const app = this.app as {
|
|
56
|
-
|
|
103
|
+
public get models(): TControllerModelsClient<TApplication> {
|
|
104
|
+
const app = this.app as {
|
|
105
|
+
models?: { client?: TControllerModelsClient<TApplication> };
|
|
106
|
+
Models?: { client?: TControllerModelsClient<TApplication> };
|
|
107
|
+
};
|
|
108
|
+
return (app.models?.client ?? app.Models?.client) as TControllerModelsClient<TApplication>;
|
|
57
109
|
}
|
|
58
110
|
|
|
59
111
|
public input<TSchema extends TValidationSchema>(schema: TSchema): zod.output<TSchema>;
|
|
@@ -112,10 +112,10 @@ const loadGeneratedCommandDefinitions = () =>
|
|
|
112
112
|
(a, b) => a.path.localeCompare(b.path),
|
|
113
113
|
);
|
|
114
114
|
|
|
115
|
-
export default class DevCommandsRegistry
|
|
115
|
+
export default class DevCommandsRegistry {
|
|
116
116
|
private definitions = loadGeneratedCommandDefinitions();
|
|
117
117
|
|
|
118
|
-
public constructor(private app:
|
|
118
|
+
public constructor(private app: Application) {}
|
|
119
119
|
|
|
120
120
|
public list() {
|
|
121
121
|
return this.definitions.map((definition) => ({
|
|
@@ -150,7 +150,7 @@ export default class DevCommandsRegistry<TApplication extends Application = Appl
|
|
|
150
150
|
|
|
151
151
|
try {
|
|
152
152
|
const instance = new definition.Command(this.app);
|
|
153
|
-
const method = (instance
|
|
153
|
+
const method = Reflect.get(instance, definition.methodName);
|
|
154
154
|
|
|
155
155
|
if (typeof method !== 'function') {
|
|
156
156
|
throw new Error(
|
|
@@ -36,8 +36,8 @@ const isExplainSectionName = (value: string): value is TExplainSectionName =>
|
|
|
36
36
|
const isConsoleLogLevel = (value: string): value is TDevConsoleLogLevel =>
|
|
37
37
|
['silly', 'log', 'info', 'warn', 'error'].includes(value);
|
|
38
38
|
|
|
39
|
-
export default class DevDiagnosticsRegistry
|
|
40
|
-
public constructor(private app:
|
|
39
|
+
export default class DevDiagnosticsRegistry {
|
|
40
|
+
public constructor(private app: Application) {}
|
|
41
41
|
|
|
42
42
|
private getManifestFilepath() {
|
|
43
43
|
return path.join(this.app.container.path.root, '.proteum', 'manifest.json');
|
package/server/app/index.ts
CHANGED
|
@@ -44,8 +44,13 @@ export const Service = ServicesContainer;
|
|
|
44
44
|
type Prettify<T> = { [K in keyof T]: T[K] } & {};
|
|
45
45
|
|
|
46
46
|
export type ApplicationProperties = Prettify<keyof Application>;
|
|
47
|
-
|
|
48
|
-
|
|
47
|
+
type RootServiceCandidate = {
|
|
48
|
+
runHook: object;
|
|
49
|
+
getServiceInstance: object;
|
|
50
|
+
status: string | undefined;
|
|
51
|
+
};
|
|
52
|
+
export type RootServicesOf<TApplication extends object = object> = Prettify<{
|
|
53
|
+
[TKey in Exclude<keyof TApplication, ApplicationProperties> as TApplication[TKey] extends RootServiceCandidate ? TKey : never]: TApplication[TKey];
|
|
49
54
|
}>;
|
|
50
55
|
|
|
51
56
|
const isServiceInstance = (value: unknown): value is AnyService => {
|
|
@@ -56,19 +61,24 @@ const isServiceInstance = (value: unknown): value is AnyService => {
|
|
|
56
61
|
return typeof service.runHook === 'function' && typeof service.getServiceInstance === 'function' && service.status !== undefined;
|
|
57
62
|
};
|
|
58
63
|
|
|
64
|
+
const createCommandsManager = (app: Application) => new CommandsManager(app, { debug: true }, app);
|
|
65
|
+
const createDevCommandsRegistry = (app: Application) => new DevCommandsRegistry(app);
|
|
66
|
+
const createDevDiagnosticsRegistry = (app: Application) => new DevDiagnosticsRegistry(app);
|
|
67
|
+
|
|
59
68
|
/*----------------------------------
|
|
60
69
|
- FUNCTIONS
|
|
61
70
|
----------------------------------*/
|
|
62
71
|
export abstract class Application<
|
|
63
72
|
TServicesContainer extends ServicesContainerClass = ServicesContainerClass,
|
|
64
73
|
TUser extends TBasicUser = TBasicUser,
|
|
65
|
-
> extends ApplicationService<Config, Hooks,
|
|
74
|
+
> extends ApplicationService<Config, Hooks, object, object> {
|
|
66
75
|
public static identity = ConfigApplication.identity;
|
|
67
76
|
public static setup = ConfigApplication.setup;
|
|
68
77
|
|
|
69
78
|
public app!: this;
|
|
70
79
|
public servicesContainer!: TServicesContainer;
|
|
71
80
|
public userType!: TUser;
|
|
81
|
+
public declare Router: object;
|
|
72
82
|
|
|
73
83
|
/*----------------------------------
|
|
74
84
|
- PROPERTIES
|
|
@@ -122,21 +132,22 @@ export abstract class Application<
|
|
|
122
132
|
- COMMANDS
|
|
123
133
|
----------------------------------*/
|
|
124
134
|
|
|
125
|
-
private commandsManager
|
|
126
|
-
private devCommandsRegistry?: DevCommandsRegistry
|
|
127
|
-
private devDiagnosticsRegistry?: DevDiagnosticsRegistry
|
|
135
|
+
private commandsManager?: CommandsManager;
|
|
136
|
+
private devCommandsRegistry?: DevCommandsRegistry;
|
|
137
|
+
private devDiagnosticsRegistry?: DevDiagnosticsRegistry;
|
|
128
138
|
|
|
129
139
|
public command(...args: Parameters<CommandsManager['command']>) {
|
|
140
|
+
this.commandsManager ??= createCommandsManager(this as Application);
|
|
130
141
|
return this.commandsManager.command(...args);
|
|
131
142
|
}
|
|
132
143
|
|
|
133
144
|
public getDevCommands() {
|
|
134
|
-
this.devCommandsRegistry ??=
|
|
145
|
+
this.devCommandsRegistry ??= createDevCommandsRegistry(this as Application);
|
|
135
146
|
return this.devCommandsRegistry;
|
|
136
147
|
}
|
|
137
148
|
|
|
138
149
|
public getDevDiagnostics() {
|
|
139
|
-
this.devDiagnosticsRegistry ??=
|
|
150
|
+
this.devDiagnosticsRegistry ??= createDevDiagnosticsRegistry(this as Application);
|
|
140
151
|
return this.devDiagnosticsRegistry;
|
|
141
152
|
}
|
|
142
153
|
|
|
@@ -3,29 +3,32 @@
|
|
|
3
3
|
----------------------------------*/
|
|
4
4
|
|
|
5
5
|
// Specific
|
|
6
|
-
import type {
|
|
6
|
+
import type { AnyServiceClass, StartedServicesIndex } from '.';
|
|
7
7
|
|
|
8
8
|
/*----------------------------------
|
|
9
9
|
- TYPES
|
|
10
10
|
----------------------------------*/
|
|
11
11
|
|
|
12
|
-
|
|
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
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
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 {
|
|
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 {
|
|
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<{},
|
|
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
|
|
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
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
|
|
48
|
-
|
|
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
|
-
:
|
|
74
|
+
: object;
|
|
57
75
|
|
|
58
|
-
export type TSetupConfig<TConfig> = TConfig extends (...args:
|
|
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
|
|
90
|
-
TParent extends object =
|
|
109
|
+
TApplication extends object = object,
|
|
110
|
+
TParent extends object = object,
|
|
91
111
|
> {
|
|
92
112
|
public started?: Promise<void>;
|
|
93
113
|
public starting?: Promise<void>;
|
package/server/app.tsconfig.json
CHANGED
|
@@ -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
|
|
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
|
|
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
|
|
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:
|
|
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
|
|
611
|
+
conditions
|
|
606
612
|
? (Object.keys(conditions) as Array<Extract<keyof TAuthConfiguredRules, string>>)
|
|
607
613
|
: [];
|
|
608
614
|
|