proteum 2.2.7 → 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/cli/compiler/artifacts/controllers.ts +30 -4
- package/cli/compiler/artifacts/services.ts +67 -29
- package/cli/scaffold/templates.ts +2 -3
- 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/types/global/vendors.d.ts +70 -0
|
@@ -120,12 +120,14 @@ export const generateControllerArtifacts = async () => {
|
|
|
120
120
|
const connectedManifestControllers: TProteumManifestController[] = [];
|
|
121
121
|
|
|
122
122
|
connectedProjectContracts.forEach(({ namespace, cachedContractFilepath, contract, sourceKind, sourceValue, typeImportModuleSpecifier, typingMode }) => {
|
|
123
|
+
let connectedTypeName: string | null = null;
|
|
124
|
+
|
|
123
125
|
if (typingMode === 'local-typed' && typeImportModuleSpecifier) {
|
|
124
|
-
|
|
126
|
+
connectedTypeName = `ConnectedControllers_${namespace.replace(/[^A-Za-z0-9_$]+/g, '_')}`;
|
|
125
127
|
connectedControllerTypeImports.push(
|
|
126
|
-
`import type { TConnectedControllers as ${
|
|
128
|
+
`import type { TConnectedControllers as ${connectedTypeName} } from ${JSON.stringify(typeImportModuleSpecifier)};`,
|
|
127
129
|
);
|
|
128
|
-
typeTree[namespace] = JSON.stringify({ rawType:
|
|
130
|
+
typeTree[namespace] = JSON.stringify({ rawType: connectedTypeName });
|
|
129
131
|
} else {
|
|
130
132
|
typeTree[namespace] = JSON.stringify({ runtimeOnly: true });
|
|
131
133
|
}
|
|
@@ -164,7 +166,9 @@ export const generateControllerArtifacts = async () => {
|
|
|
164
166
|
hasInput: controller.hasInput,
|
|
165
167
|
httpPath: controller.httpPath,
|
|
166
168
|
methodName: controller.methodName,
|
|
167
|
-
resultType:
|
|
169
|
+
resultType: connectedTypeName
|
|
170
|
+
? `TConnectedControllerResult<${connectedTypeName}, ${JSON.stringify(controller.clientAccessor)}>`
|
|
171
|
+
: 'unknown',
|
|
168
172
|
}),
|
|
169
173
|
);
|
|
170
174
|
});
|
|
@@ -228,6 +232,28 @@ type TControllerResult<TController, TMethod extends keyof TController> =
|
|
|
228
232
|
|
|
229
233
|
type TControllerFetcher<TController, TMethod extends keyof TController> = TFetcher<TControllerResult<TController, TMethod>>;
|
|
230
234
|
|
|
235
|
+
type TConnectedFallbackValue =
|
|
236
|
+
| string
|
|
237
|
+
| number
|
|
238
|
+
| boolean
|
|
239
|
+
| null
|
|
240
|
+
| TConnectedFallbackValue[]
|
|
241
|
+
| { [key: string]: TConnectedFallbackValue | undefined };
|
|
242
|
+
|
|
243
|
+
type TConnectedControllerLeaf<TControllerTree, TAccessor extends string> =
|
|
244
|
+
TAccessor extends \`${'${infer THead}.${infer TTail}'}\`
|
|
245
|
+
? THead extends keyof TControllerTree
|
|
246
|
+
? TConnectedControllerLeaf<TControllerTree[THead], TTail>
|
|
247
|
+
: undefined
|
|
248
|
+
: TAccessor extends keyof TControllerTree
|
|
249
|
+
? TControllerTree[TAccessor]
|
|
250
|
+
: undefined;
|
|
251
|
+
|
|
252
|
+
type TConnectedControllerResult<TControllerTree, TAccessor extends string> =
|
|
253
|
+
TConnectedControllerLeaf<TControllerTree, TAccessor> extends (...args: infer TArgs) => TFetcher<infer TResult>
|
|
254
|
+
? Awaited<TResult>
|
|
255
|
+
: TConnectedFallbackValue;
|
|
256
|
+
|
|
231
257
|
export type TControllers = ${printControllerTree(typeTree, typeLeaf)};
|
|
232
258
|
|
|
233
259
|
export const createControllers = (
|
|
@@ -711,6 +711,68 @@ ${classMembers.join('\n')}
|
|
|
711
711
|
};
|
|
712
712
|
};
|
|
713
713
|
|
|
714
|
+
const isNamespaceImportDeclaration = (statement: ts.ImportDeclaration) =>
|
|
715
|
+
statement.importClause?.namedBindings !== undefined && ts.isNamespaceImport(statement.importClause.namedBindings);
|
|
716
|
+
|
|
717
|
+
const isClientServerStubSupportStatement = (statement: ts.Statement, appClassIdentifier: string) => {
|
|
718
|
+
if (ts.isTypeAliasDeclaration(statement)) {
|
|
719
|
+
return !new Set([
|
|
720
|
+
`${appClassIdentifier}Disks`,
|
|
721
|
+
`${appClassIdentifier}Router`,
|
|
722
|
+
`${appClassIdentifier}RouterPlugins`,
|
|
723
|
+
]).has(statement.name.text);
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
return ts.isInterfaceDeclaration(statement) || ts.isModuleDeclaration(statement);
|
|
727
|
+
};
|
|
728
|
+
|
|
729
|
+
const createClientServerIndexDeclaration = (rootServices: TParsedService[]) => {
|
|
730
|
+
const sourceFile = createSourceFile(getAppServerEntryFilepath());
|
|
731
|
+
const appClass = getDefaultExportClassDeclaration(sourceFile);
|
|
732
|
+
const serviceTypesByRegisteredName = new Map(
|
|
733
|
+
rootServices.map((service) => [service.registeredName, `import("${service.importPath}").default`] as const),
|
|
734
|
+
);
|
|
735
|
+
|
|
736
|
+
const imports = sourceFile.statements
|
|
737
|
+
.filter((statement): statement is ts.ImportDeclaration => ts.isImportDeclaration(statement))
|
|
738
|
+
.filter((statement) => !isNamespaceImportDeclaration(statement))
|
|
739
|
+
.map((statement) => statement.getText(sourceFile));
|
|
740
|
+
const supportStatements = sourceFile.statements
|
|
741
|
+
.slice(0, sourceFile.statements.indexOf(appClass))
|
|
742
|
+
.filter((statement) => isClientServerStubSupportStatement(statement, app.identity.identifier))
|
|
743
|
+
.map((statement) => statement.getText(sourceFile));
|
|
744
|
+
const heritageClauses = appClass.heritageClauses?.map((clause) => clause.getText(sourceFile)).join(' ');
|
|
745
|
+
const properties = appClass.members
|
|
746
|
+
.filter((member): member is ts.PropertyDeclaration => ts.isPropertyDeclaration(member))
|
|
747
|
+
.filter((member) => !isPrivateOrProtectedInstanceMember(member))
|
|
748
|
+
.map((property) => {
|
|
749
|
+
const propertyName = getPropertyNameText(property.name);
|
|
750
|
+
if (!propertyName) return undefined;
|
|
751
|
+
|
|
752
|
+
const propertyType =
|
|
753
|
+
propertyName === 'Disks'
|
|
754
|
+
? 'object'
|
|
755
|
+
: propertyName === 'Router'
|
|
756
|
+
? `${app.identity.identifier}Router`
|
|
757
|
+
: property.type?.getText(sourceFile) || serviceTypesByRegisteredName.get(propertyName);
|
|
758
|
+
if (!propertyType) return undefined;
|
|
759
|
+
|
|
760
|
+
return ` public ${propertyName}: ${propertyType};`;
|
|
761
|
+
})
|
|
762
|
+
.filter((property): property is string => property !== undefined);
|
|
763
|
+
|
|
764
|
+
return `${imports.join('\n')}
|
|
765
|
+
|
|
766
|
+
${supportStatements.join('\n\n')}
|
|
767
|
+
|
|
768
|
+
type ${app.identity.identifier}Router = Router<${app.identity.identifier}>;
|
|
769
|
+
|
|
770
|
+
export default class ${app.identity.identifier}${heritageClauses ? ` ${heritageClauses}` : ''} {
|
|
771
|
+
${properties.join('\n')}
|
|
772
|
+
}
|
|
773
|
+
`;
|
|
774
|
+
};
|
|
775
|
+
|
|
714
776
|
const resolveManifestService = (service: TParsedService, parent: string): TProteumManifestService => ({
|
|
715
777
|
kind: 'service',
|
|
716
778
|
registeredName: service.registeredName,
|
|
@@ -730,6 +792,11 @@ export const generateServiceArtifacts = () => {
|
|
|
730
792
|
const routerPluginServices = routerPlugins.map((service) => resolveManifestService(service, 'Router.plugins'));
|
|
731
793
|
const commandServiceStubs = createCommandServiceStubDeclarations(rootServices);
|
|
732
794
|
|
|
795
|
+
writeIfChanged(
|
|
796
|
+
path.join(app.paths.client.generated, 'server-index.d.ts'),
|
|
797
|
+
createClientServerIndexDeclaration(rootServices),
|
|
798
|
+
);
|
|
799
|
+
|
|
733
800
|
writeIfChanged(
|
|
734
801
|
path.join(app.paths.client.generated, 'services.d.ts'),
|
|
735
802
|
`declare type ${appClassIdentifier} = import("@/server/index").default;
|
|
@@ -737,18 +804,9 @@ export const generateServiceArtifacts = () => {
|
|
|
737
804
|
declare module "@app" {
|
|
738
805
|
|
|
739
806
|
import { ${appClassIdentifier} as ${appClassIdentifier}Client } from "@/client";
|
|
740
|
-
import ${appClassIdentifier}Server from "@/server/index";
|
|
741
807
|
|
|
742
808
|
export const Router: ${appClassIdentifier}Client['Router'];
|
|
743
809
|
|
|
744
|
-
${rootServices
|
|
745
|
-
.map((service) =>
|
|
746
|
-
service.registeredName !== 'Router'
|
|
747
|
-
? `export const ${service.registeredName}: ${appClassIdentifier}Server["${service.registeredName}"];`
|
|
748
|
-
: '',
|
|
749
|
-
)
|
|
750
|
-
.join('\n')}
|
|
751
|
-
|
|
752
810
|
}
|
|
753
811
|
|
|
754
812
|
declare module '@models/types' {
|
|
@@ -894,26 +952,6 @@ declare module "@app" {
|
|
|
894
952
|
export = ServerServices
|
|
895
953
|
}
|
|
896
954
|
|
|
897
|
-
declare module '@server/app' {
|
|
898
|
-
|
|
899
|
-
import { Application } from "@server/app";
|
|
900
|
-
import { Environment } from "@server/app";
|
|
901
|
-
import { ServicesContainer } from "@server/app/service/container";
|
|
902
|
-
|
|
903
|
-
abstract class ApplicationWithServices extends Application<
|
|
904
|
-
ServicesContainer<InstalledServices>
|
|
905
|
-
> {}
|
|
906
|
-
|
|
907
|
-
export interface Exported {
|
|
908
|
-
Application: typeof ApplicationWithServices,
|
|
909
|
-
Environment: Environment,
|
|
910
|
-
}
|
|
911
|
-
|
|
912
|
-
const foo: Exported;
|
|
913
|
-
|
|
914
|
-
export = foo;
|
|
915
|
-
}
|
|
916
|
-
|
|
917
955
|
declare module '@common/errors' {
|
|
918
956
|
|
|
919
957
|
export * from '@common/errors/index';
|
|
@@ -191,6 +191,7 @@ export const createClientTsconfigTemplate = (paths: TTsconfigTemplatePaths) => `
|
|
|
191
191
|
"@server/*": [${JSON.stringify(paths.frameworkServer)}],
|
|
192
192
|
|
|
193
193
|
"@/client/context": ["./.proteum/client/context.ts"],
|
|
194
|
+
"@/server/index": ["./.proteum/client/server-index.d.ts"],
|
|
194
195
|
"@generated/client/*": ["./.proteum/client/*"],
|
|
195
196
|
"@generated/common/*": ["./.proteum/common/*"],
|
|
196
197
|
"@generated/server/*": ["./.proteum/server/*"],
|
|
@@ -207,8 +208,7 @@ export const createClientTsconfigTemplate = (paths: TTsconfigTemplatePaths) => `
|
|
|
207
208
|
".",
|
|
208
209
|
"../var/typings",
|
|
209
210
|
${JSON.stringify(paths.frameworkTypesGlobal)},
|
|
210
|
-
"../.proteum/client/services.d.ts"
|
|
211
|
-
"../server/index.ts"
|
|
211
|
+
"../.proteum/client/services.d.ts"
|
|
212
212
|
]
|
|
213
213
|
}
|
|
214
214
|
`;
|
|
@@ -228,7 +228,6 @@ export const createServerTsconfigTemplate = (paths: TTsconfigTemplatePaths) => `
|
|
|
228
228
|
"@common/*": [${JSON.stringify(paths.frameworkCommon)}],
|
|
229
229
|
"@server/*": [${JSON.stringify(paths.frameworkServer)}],
|
|
230
230
|
|
|
231
|
-
"@/client/context": ["./.proteum/client/context.ts"],
|
|
232
231
|
"@generated/client/*": ["./.proteum/client/*"],
|
|
233
232
|
"@generated/common/*": ["./.proteum/common/*"],
|
|
234
233
|
"@generated/server/*": ["./.proteum/server/*"],
|
|
@@ -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
|
|