proteum 1.0.0-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.
- package/.dockerignore +10 -0
- package/Rte.zip +0 -0
- package/cli/app/config.ts +54 -0
- package/cli/app/index.ts +195 -0
- package/cli/bin.js +11 -0
- package/cli/commands/build.ts +34 -0
- package/cli/commands/deploy/app.ts +29 -0
- package/cli/commands/deploy/web.ts +60 -0
- package/cli/commands/dev.ts +109 -0
- package/cli/commands/init.ts +85 -0
- package/cli/compiler/client/identite.ts +72 -0
- package/cli/compiler/client/index.ts +334 -0
- package/cli/compiler/common/babel/index.ts +170 -0
- package/cli/compiler/common/babel/plugins/index.ts +0 -0
- package/cli/compiler/common/babel/plugins/services.ts +579 -0
- package/cli/compiler/common/babel/routes/imports.ts +127 -0
- package/cli/compiler/common/babel/routes/routes.ts +1130 -0
- package/cli/compiler/common/files/autres.ts +39 -0
- package/cli/compiler/common/files/images.ts +35 -0
- package/cli/compiler/common/files/style.ts +78 -0
- package/cli/compiler/common/index.ts +154 -0
- package/cli/compiler/index.ts +532 -0
- package/cli/compiler/server/index.ts +211 -0
- package/cli/index.ts +189 -0
- package/cli/paths.ts +165 -0
- package/cli/print.ts +12 -0
- package/cli/tsconfig.json +38 -0
- package/cli/utils/index.ts +22 -0
- package/cli/utils/keyboard.ts +78 -0
- package/client/app/component.tsx +54 -0
- package/client/app/index.ts +142 -0
- package/client/app/service.ts +34 -0
- package/client/app.tsconfig.json +28 -0
- package/client/components/Button.tsx +298 -0
- package/client/components/Dialog/Manager.tsx +309 -0
- package/client/components/Dialog/card.tsx +208 -0
- package/client/components/Dialog/index.less +151 -0
- package/client/components/Dialog/status.less +176 -0
- package/client/components/Dialog/status.tsx +48 -0
- package/client/components/index.ts +2 -0
- package/client/components/types.d.ts +3 -0
- package/client/data/input.ts +32 -0
- package/client/global.d.ts +5 -0
- package/client/hooks.ts +22 -0
- package/client/index.ts +6 -0
- package/client/pages/_layout/index.less +6 -0
- package/client/pages/_layout/index.tsx +43 -0
- package/client/pages/bug.tsx.old +60 -0
- package/client/pages/useHeader.tsx +50 -0
- package/client/services/captcha/index.ts +67 -0
- package/client/services/router/components/Link.tsx +46 -0
- package/client/services/router/components/Page.tsx +55 -0
- package/client/services/router/components/router.tsx +218 -0
- package/client/services/router/index.tsx +521 -0
- package/client/services/router/request/api.ts +267 -0
- package/client/services/router/request/history.ts +5 -0
- package/client/services/router/request/index.ts +53 -0
- package/client/services/router/request/multipart.ts +147 -0
- package/client/services/router/response/index.tsx +128 -0
- package/client/services/router/response/page.ts +86 -0
- package/client/services/socket/index.ts +147 -0
- package/client/utils/dom.ts +77 -0
- package/common/app/index.ts +9 -0
- package/common/data/chaines/index.ts +54 -0
- package/common/data/dates.ts +179 -0
- package/common/data/markdown.ts +73 -0
- package/common/data/rte/nodes.ts +83 -0
- package/common/data/stats.ts +90 -0
- package/common/errors/index.tsx +326 -0
- package/common/router/index.ts +213 -0
- package/common/router/layouts.ts +93 -0
- package/common/router/register.ts +55 -0
- package/common/router/request/api.ts +77 -0
- package/common/router/request/index.ts +35 -0
- package/common/router/response/index.ts +45 -0
- package/common/router/response/page.ts +128 -0
- package/common/utils/rte.ts +183 -0
- package/common/utils.ts +7 -0
- package/doc/TODO.md +71 -0
- package/doc/front/router.md +27 -0
- package/doc/workspace/workspace.png +0 -0
- package/doc/workspace/workspace2.png +0 -0
- package/doc/workspace/workspace_26.01.22.png +0 -0
- package/package.json +171 -0
- package/server/app/commands.ts +141 -0
- package/server/app/container/config.ts +203 -0
- package/server/app/container/console/index.ts +550 -0
- package/server/app/container/index.ts +137 -0
- package/server/app/index.ts +273 -0
- package/server/app/service/container.ts +88 -0
- package/server/app/service/index.ts +235 -0
- package/server/app.tsconfig.json +28 -0
- package/server/context.ts +4 -0
- package/server/index.ts +4 -0
- package/server/services/auth/index.ts +250 -0
- package/server/services/auth/old.ts +277 -0
- package/server/services/auth/router/index.ts +95 -0
- package/server/services/auth/router/request.ts +54 -0
- package/server/services/auth/router/service.json +6 -0
- package/server/services/auth/service.json +6 -0
- package/server/services/cache/commands.ts +41 -0
- package/server/services/cache/index.ts +297 -0
- package/server/services/cache/service.json +6 -0
- package/server/services/cron/CronTask.ts +86 -0
- package/server/services/cron/index.ts +112 -0
- package/server/services/cron/service.json +6 -0
- package/server/services/disks/driver.ts +103 -0
- package/server/services/disks/drivers/local/index.ts +188 -0
- package/server/services/disks/drivers/local/service.json +6 -0
- package/server/services/disks/drivers/s3/index.ts +301 -0
- package/server/services/disks/drivers/s3/service.json +6 -0
- package/server/services/disks/index.ts +90 -0
- package/server/services/disks/service.json +6 -0
- package/server/services/email/index.ts +188 -0
- package/server/services/email/utils.ts +53 -0
- package/server/services/fetch/index.ts +201 -0
- package/server/services/fetch/service.json +7 -0
- package/server/services/models.7z +0 -0
- package/server/services/prisma/Facet.ts +142 -0
- package/server/services/prisma/index.ts +201 -0
- package/server/services/prisma/service.json +6 -0
- package/server/services/router/http/index.ts +217 -0
- package/server/services/router/http/multipart.ts +102 -0
- package/server/services/router/http/session.ts.old +40 -0
- package/server/services/router/index.ts +801 -0
- package/server/services/router/request/api.ts +87 -0
- package/server/services/router/request/index.ts +184 -0
- package/server/services/router/request/service.ts +21 -0
- package/server/services/router/request/validation/zod.ts +180 -0
- package/server/services/router/response/index.ts +338 -0
- package/server/services/router/response/mask/Filter.ts +323 -0
- package/server/services/router/response/mask/index.ts +60 -0
- package/server/services/router/response/mask/selecteurs.ts +92 -0
- package/server/services/router/response/page/document.tsx +160 -0
- package/server/services/router/response/page/index.tsx +196 -0
- package/server/services/router/service.json +6 -0
- package/server/services/router/service.ts +36 -0
- package/server/services/schema/index.ts +44 -0
- package/server/services/schema/request.ts +49 -0
- package/server/services/schema/router/index.ts +28 -0
- package/server/services/schema/router/service.json +6 -0
- package/server/services/schema/service.json +6 -0
- package/server/services/security/encrypt/aes/index.ts +85 -0
- package/server/services/security/encrypt/aes/service.json +6 -0
- package/server/services/socket/index.ts +162 -0
- package/server/services/socket/scope.ts +226 -0
- package/server/services/socket/service.json +6 -0
- package/server/services_old/SocketClient.ts +92 -0
- package/server/services_old/Token.old.ts +97 -0
- package/server/utils/slug.ts +79 -0
- package/tsconfig.common.json +45 -0
- package/tsconfig.json +3 -0
- package/types/aliases.d.ts +54 -0
- package/types/global/modules.d.ts +49 -0
- package/types/global/utils.d.ts +103 -0
- package/types/icons.d.ts +1 -0
|
@@ -0,0 +1,273 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import type express from 'express';
|
|
7
|
+
|
|
8
|
+
// Core
|
|
9
|
+
import AppContainer from './container';
|
|
10
|
+
import ApplicationService, { AnyService, StartedServicesIndex } from './service';
|
|
11
|
+
import CommandsManager from './commands';
|
|
12
|
+
import ServicesContainer, {
|
|
13
|
+
ServicesContainer as ServicesContainerClass,
|
|
14
|
+
TServiceMetas
|
|
15
|
+
} from './service/container';
|
|
16
|
+
|
|
17
|
+
// Built-in
|
|
18
|
+
import type { default as Router, Request as ServerRequest, TRoute } from '@server/services/router';
|
|
19
|
+
import { Anomaly } from '@common/errors';
|
|
20
|
+
import { preprocessSchema } from '@server/services/router/request/validation/zod';
|
|
21
|
+
import { TBasicUser } from '@server/services/auth';
|
|
22
|
+
|
|
23
|
+
export { default as Services } from './service/container';
|
|
24
|
+
export type { TEnvConfig as Environment } from './container/config';
|
|
25
|
+
|
|
26
|
+
/*----------------------------------
|
|
27
|
+
- TYPES
|
|
28
|
+
----------------------------------*/
|
|
29
|
+
|
|
30
|
+
type Config = {
|
|
31
|
+
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
type Hooks = {
|
|
35
|
+
ready: {
|
|
36
|
+
args: [],
|
|
37
|
+
},
|
|
38
|
+
cleanup: {
|
|
39
|
+
args: [],
|
|
40
|
+
},
|
|
41
|
+
error: {
|
|
42
|
+
args: [error: Error, request?: ServerRequest<Router>],
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
export const Service = ServicesContainer;
|
|
47
|
+
|
|
48
|
+
// Without prettify, we don't get a clear list of the class properties
|
|
49
|
+
type Prettify<T> = {
|
|
50
|
+
[K in keyof T]: T[K];
|
|
51
|
+
} & {};
|
|
52
|
+
|
|
53
|
+
export type ApplicationProperties = Prettify<keyof Application>;
|
|
54
|
+
|
|
55
|
+
/*----------------------------------
|
|
56
|
+
- FUNCTIONS
|
|
57
|
+
----------------------------------*/
|
|
58
|
+
export abstract class Application<
|
|
59
|
+
TServicesContainer extends ServicesContainerClass = ServicesContainerClass,
|
|
60
|
+
TUser extends TBasicUser = TBasicUser,
|
|
61
|
+
> extends ApplicationService<Config, Hooks, Application, Application> {
|
|
62
|
+
|
|
63
|
+
public app!: this;
|
|
64
|
+
public servicesContainer!: TServicesContainer;
|
|
65
|
+
public userType!: TUser;
|
|
66
|
+
|
|
67
|
+
/*----------------------------------
|
|
68
|
+
- PROPERTIES
|
|
69
|
+
----------------------------------*/
|
|
70
|
+
|
|
71
|
+
public side = 'server' as 'server';
|
|
72
|
+
public metas: TServiceMetas = {
|
|
73
|
+
id: 'application',
|
|
74
|
+
name: 'Application',
|
|
75
|
+
parent: 'root',
|
|
76
|
+
dependences: [],
|
|
77
|
+
class: () => ({ 'default': Application })
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// Shortcuts to ApplicationContainer
|
|
81
|
+
public container = AppContainer;
|
|
82
|
+
public env = AppContainer.Environment;
|
|
83
|
+
public identity = AppContainer.Identity;
|
|
84
|
+
|
|
85
|
+
// Status
|
|
86
|
+
public debug: boolean = false;
|
|
87
|
+
public launched: boolean = false;
|
|
88
|
+
|
|
89
|
+
protected abstract registered: {
|
|
90
|
+
[serviceId: string]: {
|
|
91
|
+
name: string,
|
|
92
|
+
start: () => AnyService
|
|
93
|
+
}
|
|
94
|
+
};
|
|
95
|
+
|
|
96
|
+
/*----------------------------------
|
|
97
|
+
- INIT
|
|
98
|
+
----------------------------------*/
|
|
99
|
+
|
|
100
|
+
public constructor() {
|
|
101
|
+
|
|
102
|
+
const self = 'self' as unknown as Application;
|
|
103
|
+
|
|
104
|
+
// Application itself doesnt have configuration
|
|
105
|
+
// Configuration must be handled by application services
|
|
106
|
+
super(self, {}, self);
|
|
107
|
+
|
|
108
|
+
// Handle unhandled crash
|
|
109
|
+
this.on('error', (e, request) => this.container.handleBug(e, "An error occured in the application", request));
|
|
110
|
+
|
|
111
|
+
process.on('unhandledRejection', (error: any, promise: any) => {
|
|
112
|
+
|
|
113
|
+
// Log so we know it's coming from unhandledRejection
|
|
114
|
+
console.error("unhandledRejection", error);
|
|
115
|
+
|
|
116
|
+
// We don't log the error here because it's the role of the app to decidehiw to log errors
|
|
117
|
+
this.runHook('error', error);
|
|
118
|
+
});
|
|
119
|
+
|
|
120
|
+
// We can't pass this in super so we assign here
|
|
121
|
+
this.parent = this;
|
|
122
|
+
this.app = this;
|
|
123
|
+
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
public report(...anomalyArgs: ConstructorParameters<typeof Anomaly>) {
|
|
127
|
+
return this.container.Console.createBugReport(
|
|
128
|
+
new Anomaly(...anomalyArgs)
|
|
129
|
+
);
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
/*----------------------------------
|
|
133
|
+
- COMMANDS
|
|
134
|
+
----------------------------------*/
|
|
135
|
+
|
|
136
|
+
private commandsManager = new CommandsManager(this, { debug: true }, {}, this);
|
|
137
|
+
|
|
138
|
+
public command( ...args: Parameters<CommandsManager["command"]> ) {
|
|
139
|
+
return this.commandsManager.command(...args);
|
|
140
|
+
}
|
|
141
|
+
|
|
142
|
+
/*----------------------------------
|
|
143
|
+
- LAUNCH
|
|
144
|
+
----------------------------------*/
|
|
145
|
+
|
|
146
|
+
public async start() {
|
|
147
|
+
|
|
148
|
+
console.log("Build date", BUILD_DATE);
|
|
149
|
+
console.log("Core version", CORE_VERSION);
|
|
150
|
+
const startTime = Date.now();
|
|
151
|
+
|
|
152
|
+
this.startServices();
|
|
153
|
+
|
|
154
|
+
console.log('----------------------------------');
|
|
155
|
+
console.log('- SERVICES');
|
|
156
|
+
console.log('----------------------------------');
|
|
157
|
+
const startingServices = await this.ready();
|
|
158
|
+
await Promise.all(startingServices);
|
|
159
|
+
console.log('All services are ready');
|
|
160
|
+
await this.runHook('ready');
|
|
161
|
+
|
|
162
|
+
const startedTime = (Date.now() - startTime) / 1000;
|
|
163
|
+
console.info(`[boot] Application launched in ${startedTime}s`);
|
|
164
|
+
this.launched = true;
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
/*----------------------------------
|
|
168
|
+
- ERROR HANDLING
|
|
169
|
+
----------------------------------*/
|
|
170
|
+
|
|
171
|
+
private startServices() {
|
|
172
|
+
|
|
173
|
+
// Satrt services
|
|
174
|
+
for (const serviceId in this.registered) {
|
|
175
|
+
try {
|
|
176
|
+
const service = this.registered[serviceId];
|
|
177
|
+
const instance = service.start();
|
|
178
|
+
this[service.name] = instance.getServiceInstance();
|
|
179
|
+
} catch (error) {
|
|
180
|
+
console.error("Error while starting service", serviceId, error);
|
|
181
|
+
throw error;
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
public register( service: AnyService ) {
|
|
187
|
+
|
|
188
|
+
return service.ready();
|
|
189
|
+
|
|
190
|
+
}
|
|
191
|
+
|
|
192
|
+
protected async ready() {
|
|
193
|
+
|
|
194
|
+
const startingServices: Promise<any>[] = [];
|
|
195
|
+
|
|
196
|
+
// Print services
|
|
197
|
+
const processService = async (propKey: string, service: AnyService, level: number = 0) => {
|
|
198
|
+
|
|
199
|
+
if (service.status !== 'starting')
|
|
200
|
+
return;
|
|
201
|
+
|
|
202
|
+
// Services start shouldn't block app boot
|
|
203
|
+
// use await ServiceName.started to make services depends on each other
|
|
204
|
+
service.starting = service.ready();
|
|
205
|
+
startingServices.push(service.starting);
|
|
206
|
+
service.status = 'running';
|
|
207
|
+
console.log('-' + '-'.repeat(level * 1), propKey + ': ' + service.constructor.name);
|
|
208
|
+
|
|
209
|
+
// Routes
|
|
210
|
+
const routes = service.__routes as TRoute[];
|
|
211
|
+
if (routes) for (const route of routes) {
|
|
212
|
+
|
|
213
|
+
console.log('Attached service', service.constructor.name, 'to route', route.path);
|
|
214
|
+
|
|
215
|
+
const preprocessedSchema = route.schema ? preprocessSchema(route.schema) : undefined;
|
|
216
|
+
|
|
217
|
+
const origController = route.controller;
|
|
218
|
+
route.controller = (context: RouterContext) => {
|
|
219
|
+
|
|
220
|
+
// Filter data
|
|
221
|
+
const data = preprocessedSchema
|
|
222
|
+
? preprocessedSchema.parse( context.request.data )
|
|
223
|
+
: {};
|
|
224
|
+
|
|
225
|
+
// Run controller
|
|
226
|
+
return origController.bind( service )(
|
|
227
|
+
data,
|
|
228
|
+
context
|
|
229
|
+
);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
this.Router.controllers[ route.path ] = route;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
// Subservices
|
|
236
|
+
for (const propKey in service) {
|
|
237
|
+
|
|
238
|
+
if (propKey === 'app')
|
|
239
|
+
continue;
|
|
240
|
+
const propValue = service[propKey];
|
|
241
|
+
|
|
242
|
+
// Check if service
|
|
243
|
+
const isService =
|
|
244
|
+
typeof propValue === 'object' &&
|
|
245
|
+
!(propValue instanceof Application) &&
|
|
246
|
+
propValue !== null &&
|
|
247
|
+
propValue.status !== undefined;
|
|
248
|
+
if (!isService)
|
|
249
|
+
continue;
|
|
250
|
+
|
|
251
|
+
// Services start shouldn't block app boot
|
|
252
|
+
processService(propKey, propValue, level + 1);
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
for (const serviceId in this.registered) {
|
|
257
|
+
|
|
258
|
+
const registeredService = this.registered[serviceId];
|
|
259
|
+
const service = this[registeredService.name];
|
|
260
|
+
|
|
261
|
+
// TODO: move to router
|
|
262
|
+
// Application.on('service.ready')
|
|
263
|
+
|
|
264
|
+
// Services start shouldn't block app boot
|
|
265
|
+
processService(serviceId, service);
|
|
266
|
+
}
|
|
267
|
+
|
|
268
|
+
return startingServices;
|
|
269
|
+
}
|
|
270
|
+
|
|
271
|
+
}
|
|
272
|
+
|
|
273
|
+
export default Application
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Specific
|
|
6
|
+
import type {
|
|
7
|
+
AnyService, StartedServicesIndex,
|
|
8
|
+
// Hooks
|
|
9
|
+
THookCallback, THooksIndex
|
|
10
|
+
} from ".";
|
|
11
|
+
|
|
12
|
+
/*----------------------------------
|
|
13
|
+
- TYPES: REGISTRATION
|
|
14
|
+
----------------------------------*/
|
|
15
|
+
|
|
16
|
+
// From service/service.json
|
|
17
|
+
export type TServiceMetas<TServiceClass extends AnyService = AnyService> = {
|
|
18
|
+
id: string,
|
|
19
|
+
name: string,
|
|
20
|
+
parent: string,
|
|
21
|
+
dependences: string[],
|
|
22
|
+
class: () => { default: ClassType<TServiceClass> }
|
|
23
|
+
}
|
|
24
|
+
|
|
25
|
+
export type TRegisteredService<TServiceClass extends AnyService = AnyService> = {
|
|
26
|
+
type: 'service', // Used to recognize if an object is a registered service
|
|
27
|
+
config?: {},
|
|
28
|
+
metas: TServiceMetas<TServiceClass>,
|
|
29
|
+
hooks: THooksIndex<{}>,
|
|
30
|
+
on: (hookName: string, hookFunc: THookCallback<any>) => void,
|
|
31
|
+
subServices: TRegisteredServicesIndex
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
export type TRegisteredServicesIndex<TServiceClass extends AnyService = AnyService> = {
|
|
35
|
+
[serviceId: string]: TRegisteredService<TServiceClass>
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
/*----------------------------------
|
|
39
|
+
- CONFIG
|
|
40
|
+
----------------------------------*/
|
|
41
|
+
|
|
42
|
+
const LogPrefix = '[service]';
|
|
43
|
+
|
|
44
|
+
/*----------------------------------
|
|
45
|
+
- CLASS
|
|
46
|
+
----------------------------------*/
|
|
47
|
+
export class ServicesContainer<
|
|
48
|
+
TServicesIndex extends StartedServicesIndex = StartedServicesIndex
|
|
49
|
+
> {
|
|
50
|
+
|
|
51
|
+
public registered: TRegisteredServicesIndex = {}
|
|
52
|
+
|
|
53
|
+
// All service instances by service id
|
|
54
|
+
public allServices: TServicesIndex = {} as TServicesIndex
|
|
55
|
+
|
|
56
|
+
public callableInstance = <TInstance extends object, TCallableName extends keyof TInstance>(
|
|
57
|
+
instance: TInstance,
|
|
58
|
+
funcName: TCallableName
|
|
59
|
+
): TInstance[TCallableName] & TInstance => {
|
|
60
|
+
|
|
61
|
+
const callableFunc = instance[funcName];
|
|
62
|
+
if (typeof callableFunc !== 'function')
|
|
63
|
+
throw new Error(`instance[funcName] isn't callable.`);
|
|
64
|
+
|
|
65
|
+
const callable = callableFunc.bind(instance);
|
|
66
|
+
|
|
67
|
+
const methods = [
|
|
68
|
+
...Object.getOwnPropertyNames( Object.getPrototypeOf( instance )),
|
|
69
|
+
...Object.getOwnPropertyNames( instance ),
|
|
70
|
+
// service.launch() isn't included, maybe because parent abstract class
|
|
71
|
+
'launch',
|
|
72
|
+
'bindServices'
|
|
73
|
+
];
|
|
74
|
+
|
|
75
|
+
for (const method of methods)
|
|
76
|
+
if (method !== 'constructor')
|
|
77
|
+
callable[ method ] = typeof instance[ method ] === 'function'
|
|
78
|
+
? instance[ method ].bind( instance )
|
|
79
|
+
: instance[ method ];
|
|
80
|
+
|
|
81
|
+
// Allow us to recognize a callable as a service
|
|
82
|
+
callable.serviceInstance = instance;
|
|
83
|
+
|
|
84
|
+
return callable as TInstance[TCallableName] & TInstance;
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
export default new ServicesContainer
|
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
/*----------------------------------
|
|
2
|
+
- DEPENDANCES
|
|
3
|
+
----------------------------------*/
|
|
4
|
+
|
|
5
|
+
// Npm
|
|
6
|
+
import zod from 'zod';
|
|
7
|
+
|
|
8
|
+
// Specific
|
|
9
|
+
import type { Application } from "..";
|
|
10
|
+
import type { Command } from "../commands";
|
|
11
|
+
import type { TServiceMetas } from './container';
|
|
12
|
+
import type { TControllerDefinition, TRoute } from '../../services/router';
|
|
13
|
+
import { Anomaly } from "@common/errors";
|
|
14
|
+
|
|
15
|
+
export { schema } from '../../services/router/request/validation/zod';
|
|
16
|
+
export type { z } from '../../services/router/request/validation/zod';
|
|
17
|
+
|
|
18
|
+
/*----------------------------------
|
|
19
|
+
- TYPES: OPTIONS
|
|
20
|
+
----------------------------------*/
|
|
21
|
+
|
|
22
|
+
export type AnyService<TSubServices extends StartedServicesIndex = StartedServicesIndex> =
|
|
23
|
+
Service<{}, {}, Application>
|
|
24
|
+
|
|
25
|
+
export type { TRegisteredServicesIndex, TRegisteredService } from './container';
|
|
26
|
+
|
|
27
|
+
/*----------------------------------
|
|
28
|
+
- TYPES: HOOKS
|
|
29
|
+
----------------------------------*/
|
|
30
|
+
|
|
31
|
+
export type THookCallback<THookArgs extends THookOptions> = (...args: THookArgs["args"]) => Promise<void>;
|
|
32
|
+
|
|
33
|
+
type THooksList = {
|
|
34
|
+
[hookName: string]: THookOptions
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
type THookOptions = {
|
|
38
|
+
args: any[]
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export type THooksIndex<THooks extends THooksList> = {[name in keyof THooks]?: THookCallback< THooks[name] >[]}
|
|
42
|
+
|
|
43
|
+
export type StartedServicesIndex = {
|
|
44
|
+
[serviceId: string]: AnyService
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
export type TServiceArgs<TService extends AnyService> = [
|
|
48
|
+
parent: AnyService | 'self',
|
|
49
|
+
config: null | undefined | TService['config'],
|
|
50
|
+
app: TService['app'] | 'self'
|
|
51
|
+
]
|
|
52
|
+
|
|
53
|
+
/*----------------------------------
|
|
54
|
+
- CONFIG
|
|
55
|
+
----------------------------------*/
|
|
56
|
+
|
|
57
|
+
const LogPrefix = '[service]';
|
|
58
|
+
|
|
59
|
+
type TDecoratorArgs = (
|
|
60
|
+
[path: string] |
|
|
61
|
+
[path: string, schema: zod.ZodSchema] |
|
|
62
|
+
[path: string, schema: zod.ZodSchema, options?: Omit<TControllerDefinition, 'controller'|'schema'|'path'>] |
|
|
63
|
+
[options: Omit<TControllerDefinition, 'controller'>]
|
|
64
|
+
)
|
|
65
|
+
|
|
66
|
+
export function Route( ...args: TDecoratorArgs ) {
|
|
67
|
+
|
|
68
|
+
let path: string | undefined;
|
|
69
|
+
let schema: zod.ZodSchema | undefined;
|
|
70
|
+
let options: Omit<TControllerDefinition, 'controller'|'schema'|'path'> = {};
|
|
71
|
+
|
|
72
|
+
if (typeof args[0] === 'object') {
|
|
73
|
+
const { path: path_, schema: schema_, ...options_ } = args[0];
|
|
74
|
+
path = path_;
|
|
75
|
+
schema = schema_;
|
|
76
|
+
options = options_;
|
|
77
|
+
} else {
|
|
78
|
+
path = args[0];
|
|
79
|
+
schema = args[1];
|
|
80
|
+
options = args[2] || {};
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
return function (
|
|
84
|
+
target: any,
|
|
85
|
+
propertyKey: string,
|
|
86
|
+
descriptor: PropertyDescriptor
|
|
87
|
+
) {
|
|
88
|
+
// Store the original method
|
|
89
|
+
const originalMethod = descriptor.value;
|
|
90
|
+
|
|
91
|
+
if (path === undefined)
|
|
92
|
+
path = target.constructor.name + '/' + propertyKey;
|
|
93
|
+
|
|
94
|
+
// Ensure the class has a static property to collect routes
|
|
95
|
+
if (!target.__routes) {
|
|
96
|
+
target.__routes = [];
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
// Create route object
|
|
100
|
+
const route: TRoute = {
|
|
101
|
+
method: 'POST',
|
|
102
|
+
path: '/api/' + path,
|
|
103
|
+
controller: originalMethod,
|
|
104
|
+
schema: schema,
|
|
105
|
+
options: {
|
|
106
|
+
priority: options.priority || 0
|
|
107
|
+
}
|
|
108
|
+
};
|
|
109
|
+
|
|
110
|
+
// Add this route to the class's routes collection
|
|
111
|
+
target.__routes.push(route);
|
|
112
|
+
|
|
113
|
+
// Original method is unchanged, just registered with router
|
|
114
|
+
return descriptor;
|
|
115
|
+
};
|
|
116
|
+
}
|
|
117
|
+
|
|
118
|
+
/*----------------------------------
|
|
119
|
+
- CLASS
|
|
120
|
+
----------------------------------*/
|
|
121
|
+
export default abstract class Service<
|
|
122
|
+
TConfig extends {},
|
|
123
|
+
THooks extends THooksList,
|
|
124
|
+
TApplication extends Application,
|
|
125
|
+
TParent extends AnyService
|
|
126
|
+
> {
|
|
127
|
+
|
|
128
|
+
public started?: Promise<void>;
|
|
129
|
+
public status: 'stopped' | 'starting' | 'running' | 'paused' = 'starting';
|
|
130
|
+
|
|
131
|
+
public commands?: Command[];
|
|
132
|
+
public metas!: TServiceMetas;
|
|
133
|
+
public bindings: string[] = []
|
|
134
|
+
|
|
135
|
+
public parent: TParent;
|
|
136
|
+
public app: TApplication;
|
|
137
|
+
public config: TConfig = {} as TConfig;
|
|
138
|
+
|
|
139
|
+
public constructor(...[parent, config, app]: TServiceArgs<AnyService>) {
|
|
140
|
+
|
|
141
|
+
this.parent = parent;
|
|
142
|
+
if (this.parent === 'self')
|
|
143
|
+
this.parent = this as unknown as TParent;
|
|
144
|
+
|
|
145
|
+
this.app = app === 'self'
|
|
146
|
+
? this as unknown as TApplication
|
|
147
|
+
: app
|
|
148
|
+
|
|
149
|
+
this.config = config || {};
|
|
150
|
+
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
public getServiceInstance() {
|
|
154
|
+
return this;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
/*----------------------------------
|
|
158
|
+
- LIFECYCLE
|
|
159
|
+
----------------------------------*/
|
|
160
|
+
|
|
161
|
+
protected async ready(): Promise<void> {}
|
|
162
|
+
|
|
163
|
+
protected async shutdown(): Promise<void> {}
|
|
164
|
+
|
|
165
|
+
/*----------------------------------
|
|
166
|
+
- SUBSERVICES
|
|
167
|
+
----------------------------------*/
|
|
168
|
+
|
|
169
|
+
// TODO:; babel plugin: transform Service references to app.use('Service')
|
|
170
|
+
public use<TService extends AnyService = AnyService>(
|
|
171
|
+
serviceId: string,
|
|
172
|
+
useOptions: { optional?: boolean } = {}
|
|
173
|
+
): TService | undefined {
|
|
174
|
+
|
|
175
|
+
const registeredService = this.app.registered[serviceId];
|
|
176
|
+
if (registeredService !== undefined)
|
|
177
|
+
return this.app[ registeredService.name ];
|
|
178
|
+
|
|
179
|
+
if (useOptions.optional === false)
|
|
180
|
+
throw new Error(`Service ${registeredService} not registered.`);
|
|
181
|
+
|
|
182
|
+
return undefined;
|
|
183
|
+
}
|
|
184
|
+
|
|
185
|
+
/*----------------------------------
|
|
186
|
+
- HOOKS
|
|
187
|
+
----------------------------------*/
|
|
188
|
+
|
|
189
|
+
public hooks: THooksIndex<THooks> = {}
|
|
190
|
+
|
|
191
|
+
public on<THookName extends keyof THooksList>(
|
|
192
|
+
name: THookName,
|
|
193
|
+
callback: THookCallback<THooksList[THookName]>
|
|
194
|
+
) {
|
|
195
|
+
|
|
196
|
+
const callbacks = this.hooks[ name ];
|
|
197
|
+
if (callbacks)
|
|
198
|
+
callbacks.push( callback );
|
|
199
|
+
else
|
|
200
|
+
this.hooks[ name ] = [callback]
|
|
201
|
+
|
|
202
|
+
return this;
|
|
203
|
+
}
|
|
204
|
+
|
|
205
|
+
public runHook<THookName extends keyof THooksList>(
|
|
206
|
+
name: THookName,
|
|
207
|
+
...args: THooksList[THookName]["args"]
|
|
208
|
+
) {
|
|
209
|
+
|
|
210
|
+
const callbacks = this.hooks[name];
|
|
211
|
+
if (!callbacks)
|
|
212
|
+
return;// console.info(LogPrefix, `No ${name} hook defined in the current service instance.`);
|
|
213
|
+
|
|
214
|
+
//this.config.debug && console.info(`[hook] Run all ${name} hook (${callbacks.length}).`);
|
|
215
|
+
return Promise.all(
|
|
216
|
+
callbacks.map(
|
|
217
|
+
cb => cb(...args)
|
|
218
|
+
)
|
|
219
|
+
).then(() => {
|
|
220
|
+
//this.config.debug && console.info(`[hook] Hooks ${name} executed with success.`);
|
|
221
|
+
}).catch(e => {
|
|
222
|
+
if (name === 'error') {
|
|
223
|
+
|
|
224
|
+
// In error hook = avoid infinite loop
|
|
225
|
+
console.error("Error hook", e);
|
|
226
|
+
|
|
227
|
+
} else {
|
|
228
|
+
|
|
229
|
+
// Let the error hook handle it
|
|
230
|
+
throw e;
|
|
231
|
+
}
|
|
232
|
+
})
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
}
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
{
|
|
2
|
+
"extends": "../../node_modules/proteum/tsconfig.common.json",
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"rootDir": "..",
|
|
5
|
+
"baseUrl": "..",
|
|
6
|
+
"paths": {
|
|
7
|
+
|
|
8
|
+
"@/server/models": ["./server/.generated/models.ts"],
|
|
9
|
+
|
|
10
|
+
"@client/*": ["../node_modules/proteum/client/*"],
|
|
11
|
+
"@common/*": ["../node_modules/proteum/common/*"],
|
|
12
|
+
"@server/*": ["../node_modules/proteum/server/*"],
|
|
13
|
+
|
|
14
|
+
"@/*": ["./*"],
|
|
15
|
+
|
|
16
|
+
// ATTENTION: Les références à preact doivent toujours pointer vers la même instance
|
|
17
|
+
"react": ["preact/compat"],
|
|
18
|
+
"react-dom/test-utils": ["preact/test-utils"],
|
|
19
|
+
"react-dom": ["preact/compat"], // Must be below test-utils
|
|
20
|
+
"react/jsx-runtime": ["preact/jsx-runtime"]
|
|
21
|
+
}
|
|
22
|
+
},
|
|
23
|
+
|
|
24
|
+
"include": [
|
|
25
|
+
".",
|
|
26
|
+
"../../node_modules/proteum/types/global"
|
|
27
|
+
]
|
|
28
|
+
}
|
package/server/index.ts
ADDED