raiton 1.0.0-alpha.2 → 1.0.0-alpha.3
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/CHANGELOG.md +19 -0
- package/README.md +1 -2
- package/build/bin/index.mjs +3798 -3644
- package/build/raiton-1.0.0-alpha.3.tgz +0 -0
- package/deno.json +9 -0
- package/package.json +2 -1
- package/source/bin/cli-tools.ts +1 -6
- package/source/bin/constants.ts +5 -0
- package/source/bin/index.ts +1 -1
- package/source/commands/develop.command.ts +3 -3
- package/source/commands/start.command.ts +1 -1
- package/source/core/application.ts +66 -18
- package/source/core/builder.ts +27 -21
- package/source/core/controller/builder.ts +8 -5
- package/source/core/controller/metadata.ts +1 -1
- package/source/core/directories.ts +1 -1
- package/source/core/index.ts +0 -1
- package/source/core/injection/injection.ts +67 -5
- package/source/core/middleware/compose.ts +1 -1
- package/source/core/raiton.ts +2 -3
- package/source/core/router/handler.ts +100 -44
- package/source/core/thread.ts +18 -8
- package/source/sdk/artifacts.ts +65 -41
- package/source/sdk/constants/decorators.constant.ts +1 -0
- package/source/sdk/data-transfer-object.ts +11 -3
- package/source/sdk/decorators/parametrable.ts +19 -15
- package/source/sdk/decorators/routable.decorator.ts +0 -3
- package/source/sdk/encryption.ts +5 -6
- package/source/sdk/enums/encrypted.enum.ts +10 -0
- package/source/sdk/enums/http-status.enum.ts +73 -0
- package/source/sdk/enums/index.ts +2 -1
- package/source/sdk/exceptions/http-exception.ts +28 -0
- package/source/sdk/exceptions/index.ts +2 -0
- package/source/sdk/index.ts +7 -0
- package/source/sdk/parameter-bag.ts +55 -0
- package/source/sdk/repositories.ts +1 -1
- package/source/sdk/responses/error.ts +52 -0
- package/source/sdk/responses/helpers.ts +28 -0
- package/source/sdk/responses/http-throwable.ts +28 -0
- package/source/sdk/responses/http.ts +48 -0
- package/source/sdk/responses/index.ts +4 -0
- package/source/sdk/runtime/bun/server.ts +2 -1
- package/source/sdk/runtime/deno/server.ts +2 -2
- package/source/sdk/runtime/node/server.ts +2 -2
- package/source/sdk/utilities/artifact.util.ts +18 -0
- package/source/sdk/utilities/index.ts +1 -3
- package/source/types/application.ts +3 -3
- package/source/types/artifact.ts +36 -32
- package/source/types/builder.ts +0 -4
- package/source/types/config.ts +2 -2
- package/source/types/controller.ts +1 -2
- package/source/types/index.ts +2 -3
- package/source/types/lifecycle.ts +11 -0
- package/source/types/responses.ts +17 -7
- package/source/types/runtime.ts +1 -1
- package/build/raiton-1.0.0-alpha.2.tgz +0 -0
- package/source/core/artifacts/artifact.ts +0 -109
- package/source/core/artifacts/artifacts.ts +0 -10
- package/source/core/artifacts/index.ts +0 -1
- package/source/core/artifacts/runner.ts +0 -3
- package/source/core/hmr.ts +0 -106
- package/source/sdk/decorators/payload.decorator.ts +0 -77
- package/source/sdk/json.ts +0 -55
- package/source/sdk/request.ts +0 -3
- package/source/sdk/responses.ts +0 -45
- package/source/sdk/schemes.ts +0 -178
- package/source/sdk/utilities/artifacts.util.ts +0 -62
- package/source/sdk/utilities/controller.util.ts +0 -8
- package/source/types/data-transfer-object.ts +0 -4
- package/source/types/hmr.ts +0 -39
- /package/source/sdk/enums/{http.enum.ts → http-method.enum.ts} +0 -0
- /package/source/sdk/{throwable.ts → exceptions/throwable.ts} +0 -0
|
Binary file
|
package/deno.json
ADDED
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "raiton",
|
|
3
|
-
"version": "1.0.0-alpha.
|
|
3
|
+
"version": "1.0.0-alpha.3",
|
|
4
4
|
"private": false,
|
|
5
5
|
"type": "module",
|
|
6
6
|
"description": "Protorians Raiton Development Kit",
|
|
@@ -54,6 +54,7 @@
|
|
|
54
54
|
"@types/node": "^25.0.3",
|
|
55
55
|
"argon2": "^0.44.0",
|
|
56
56
|
"bcrypt": "^6.0.0",
|
|
57
|
+
"class-validator": "^0.14.3",
|
|
57
58
|
"commander": "^14.0.2",
|
|
58
59
|
"dotenv": "^17.2.3",
|
|
59
60
|
"reflect-metadata": "^0.2.2"
|
package/source/bin/cli-tools.ts
CHANGED
|
@@ -1,10 +1,6 @@
|
|
|
1
1
|
import {spawn} from 'node:child_process';
|
|
2
|
+
import {isBunUsed, isDenoUsed} from "@/bin/constants";
|
|
2
3
|
|
|
3
|
-
const isBunUsed = typeof (globalThis as any).Bun !== "undefined";
|
|
4
|
-
const isDenoUsed = typeof (globalThis as any).Deno !== "undefined";
|
|
5
|
-
|
|
6
|
-
declare const Bun: any;
|
|
7
|
-
declare const Deno: any;
|
|
8
4
|
|
|
9
5
|
export class CliTools {
|
|
10
6
|
static get cwd() {
|
|
@@ -54,7 +50,6 @@ export class CliTools {
|
|
|
54
50
|
}).spawn();
|
|
55
51
|
}
|
|
56
52
|
|
|
57
|
-
|
|
58
53
|
return new Deno.Command(cmd, {
|
|
59
54
|
args: cmdArgs,
|
|
60
55
|
...options
|
package/source/bin/index.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import {Raiton, RaitonCommand} from "@/core";
|
|
2
|
-
import {ChildProcess} from 'node:child_process';
|
|
2
|
+
import {ChildProcess, ChildProcessWithoutNullStreams} from 'node:child_process';
|
|
3
3
|
import {Logger} from "@protorians/logger";
|
|
4
4
|
import {EventMessageEnum} from "@/sdk";
|
|
5
5
|
import {CliTools} from "@/bin/cli-tools";
|
|
@@ -9,7 +9,7 @@ export default class DevelopCommand extends RaitonCommand {
|
|
|
9
9
|
public readonly name: string = 'develop';
|
|
10
10
|
public readonly description: string = 'Run the application in development mode';
|
|
11
11
|
|
|
12
|
-
private child: Bun.Subprocess<"ignore", "pipe", "inherit"> | ChildProcess | null = null;
|
|
12
|
+
private child: Bun.Subprocess<"ignore", "pipe", "inherit"> | ChildProcess | Deno.ChildProcess | ChildProcessWithoutNullStreams | null = null;
|
|
13
13
|
|
|
14
14
|
public register(): void {
|
|
15
15
|
this.cli
|
|
@@ -42,6 +42,6 @@ export default class DevelopCommand extends RaitonCommand {
|
|
|
42
42
|
if (msg === EventMessageEnum.RESTART) this.restart()
|
|
43
43
|
});
|
|
44
44
|
|
|
45
|
-
Logger.log('PID', this.child
|
|
45
|
+
Logger.log('PID', this.child?.pid)
|
|
46
46
|
}
|
|
47
47
|
}
|
|
@@ -8,7 +8,7 @@ export default class StartCommand extends RaitonCommand {
|
|
|
8
8
|
public readonly name: string = 'start';
|
|
9
9
|
public readonly description: string = 'Run the application in production mode';
|
|
10
10
|
|
|
11
|
-
private child: Bun.Subprocess<"ignore", "pipe", "inherit"> | ChildProcess | null = null;
|
|
11
|
+
private child: Bun.Subprocess<"ignore", "pipe", "inherit"> | ChildProcess | Deno.ChildProcess | null = null;
|
|
12
12
|
|
|
13
13
|
public register(): void {
|
|
14
14
|
this.cli
|
|
@@ -4,6 +4,8 @@ import {ApplicationConfig, ApplicationInterface} from "@/types/application";
|
|
|
4
4
|
import {HttpMethod} from "@/sdk";
|
|
5
5
|
import {RouteHandler} from "@/types";
|
|
6
6
|
import {Logger} from "@protorians/logger";
|
|
7
|
+
import {RaitonConfig} from "@/core/config";
|
|
8
|
+
import {Artifacts} from "@/sdk/artifacts";
|
|
7
9
|
|
|
8
10
|
export class Application implements ApplicationInterface {
|
|
9
11
|
private root: PluginScope
|
|
@@ -12,6 +14,18 @@ export class Application implements ApplicationInterface {
|
|
|
12
14
|
readonly config: ApplicationConfig
|
|
13
15
|
) {
|
|
14
16
|
this.root = new PluginScope()
|
|
17
|
+
if (this.config.workdir) {
|
|
18
|
+
process.chdir(this.config.workdir)
|
|
19
|
+
}
|
|
20
|
+
this.initialize()
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
protected initialize(): this {
|
|
24
|
+
const artifacts = RaitonConfig.get('artifacts')
|
|
25
|
+
const artifactTypes = [...artifacts?.types || [], ...Artifacts.defaultTypes]
|
|
26
|
+
|
|
27
|
+
Artifacts.registerMany(...artifactTypes)
|
|
28
|
+
return this;
|
|
15
29
|
}
|
|
16
30
|
|
|
17
31
|
public get hostname(): string {
|
|
@@ -26,15 +40,15 @@ export class Application implements ApplicationInterface {
|
|
|
26
40
|
}`
|
|
27
41
|
}
|
|
28
42
|
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
43
|
+
public setOption<K extends keyof ApplicationConfig>(key: K, value: ApplicationConfig[K]): this {
|
|
44
|
+
this.config[key] = value;
|
|
45
|
+
return this;
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
public setOptions(options: ApplicationConfig): this {
|
|
49
|
+
Object.assign(this.config, options);
|
|
50
|
+
return this;
|
|
51
|
+
}
|
|
38
52
|
|
|
39
53
|
register(plugin: any): this {
|
|
40
54
|
this.root.register(plugin)
|
|
@@ -47,7 +61,9 @@ export class Application implements ApplicationInterface {
|
|
|
47
61
|
}
|
|
48
62
|
|
|
49
63
|
route(method: HttpMethod, path: string, handler: RouteHandler, version?: string): this {
|
|
50
|
-
this.
|
|
64
|
+
const prefix = this.config.prefix ?? ''
|
|
65
|
+
const fullPath = `${prefix}${path}`.replace(/\/+/g, '/') || '/'
|
|
66
|
+
this.root.route(method, fullPath, handler, version)
|
|
51
67
|
return this
|
|
52
68
|
}
|
|
53
69
|
|
|
@@ -86,27 +102,59 @@ export class Application implements ApplicationInterface {
|
|
|
86
102
|
async handle(req: any, reply: any): Promise<any> {
|
|
87
103
|
const ctx = new RequestContext(req, reply)
|
|
88
104
|
|
|
105
|
+
if (this.config.verbose) {
|
|
106
|
+
Logger.info(
|
|
107
|
+
`Incoming request: ${req.method} ${req.url}`
|
|
108
|
+
)
|
|
109
|
+
}
|
|
110
|
+
|
|
89
111
|
await this.root.hooks.run('onRequest', ctx)
|
|
90
112
|
|
|
113
|
+
const url = new URL(req.url, this.hostname)
|
|
114
|
+
let pathname = url.pathname
|
|
115
|
+
|
|
116
|
+
if (this.config.pathname && this.config.pathname !== '/') {
|
|
117
|
+
const appPathname = this.config.pathname.endsWith('/') ? this.config.pathname : `${this.config.pathname}/`
|
|
118
|
+
if (pathname.startsWith(appPathname)) {
|
|
119
|
+
pathname = pathname.substring(appPathname.length - 1) || '/'
|
|
120
|
+
} else if (pathname === this.config.pathname) {
|
|
121
|
+
pathname = '/'
|
|
122
|
+
} else {
|
|
123
|
+
// Requête hors du pathname de l'application
|
|
124
|
+
if (this.config.verbose) {
|
|
125
|
+
Logger.warn(`Request out of application pathname: ${pathname} (expected prefix: ${this.config.pathname})`)
|
|
126
|
+
}
|
|
127
|
+
reply.status(404)
|
|
128
|
+
return reply.send({error: false, statusCode: 404})
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
91
132
|
const route = this.root.router.match(
|
|
92
133
|
req.method,
|
|
93
|
-
|
|
134
|
+
pathname
|
|
94
135
|
)
|
|
95
136
|
|
|
96
137
|
if (!route) {
|
|
138
|
+
if (this.config.verbose) {
|
|
139
|
+
Logger.warn(`Route not found: ${req.method} ${pathname}`)
|
|
140
|
+
}
|
|
97
141
|
reply.status(404)
|
|
98
142
|
return reply.send({error: false, statusCode: 404})
|
|
99
143
|
}
|
|
100
144
|
|
|
101
145
|
const pipeline = this.root.middleware.clone()
|
|
102
146
|
pipeline.use(async ({context}) => {
|
|
103
|
-
|
|
104
|
-
|
|
105
|
-
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
|
|
109
|
-
|
|
147
|
+
try {
|
|
148
|
+
(context as any).params = route.parameters;
|
|
149
|
+
let responses = await route.handler(context)
|
|
150
|
+
|
|
151
|
+
context.reply.send(responses)
|
|
152
|
+
} catch (e: any) {
|
|
153
|
+
Logger.error('Failed to handle request', e.message ?? e)
|
|
154
|
+
if (this.config.develop) {
|
|
155
|
+
console.error(e)
|
|
156
|
+
}
|
|
157
|
+
}
|
|
110
158
|
})
|
|
111
159
|
|
|
112
160
|
await pipeline.run(ctx)
|
package/source/core/builder.ts
CHANGED
|
@@ -2,18 +2,16 @@ import {RaitonConfig} from "./config";
|
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import {RaitonDirectories} from "./directories";
|
|
4
4
|
import fs, {WatchEventType} from "node:fs";
|
|
5
|
-
import type {
|
|
6
|
-
BuilderConfig,
|
|
7
|
-
BuilderInterface,
|
|
8
|
-
HmrInterface,
|
|
9
|
-
} from "@/types";
|
|
5
|
+
import type {BuilderConfig, BuilderInterface,} from "@/types";
|
|
10
6
|
import {RaitonThread} from "./thread";
|
|
11
7
|
import {Raiton} from "@/core/raiton";
|
|
12
|
-
import {
|
|
13
|
-
import {Hmr} from "@/core/hmr";
|
|
14
|
-
import {Throwable} from "@/sdk/throwable";
|
|
8
|
+
import {isControllerArtifact, isServiceArtifact} from "@/sdk";
|
|
15
9
|
import {ControllerBuilder} from "@/core/controller";
|
|
16
10
|
import {watch} from "fs";
|
|
11
|
+
import {LBadge, Logger} from "@protorians/logger";
|
|
12
|
+
import {Throwable} from "@/sdk/exceptions";
|
|
13
|
+
import {Injection} from "@/core/injection";
|
|
14
|
+
import {Artifacts} from "@/sdk/artifacts";
|
|
17
15
|
|
|
18
16
|
export class RaitonBuilder implements BuilderInterface {
|
|
19
17
|
protected _source: string | null = null;
|
|
@@ -21,8 +19,6 @@ export class RaitonBuilder implements BuilderInterface {
|
|
|
21
19
|
protected _bootstrapper: string | null = null;
|
|
22
20
|
protected _bootstrapperFile: string | null = null;
|
|
23
21
|
protected _compiledVersionNumber: number = 1;
|
|
24
|
-
|
|
25
|
-
public readonly hmr: HmrInterface = new Hmr()
|
|
26
22
|
protected _watcher?: fs.FSWatcher;
|
|
27
23
|
|
|
28
24
|
|
|
@@ -53,7 +49,7 @@ export class RaitonBuilder implements BuilderInterface {
|
|
|
53
49
|
return this._watcher;
|
|
54
50
|
}
|
|
55
51
|
|
|
56
|
-
protected parse(filename: string, type?: WatchEventType) {
|
|
52
|
+
protected async parse(filename: string, type?: WatchEventType) {
|
|
57
53
|
if (!fs.existsSync(filename)) return;
|
|
58
54
|
|
|
59
55
|
const payload = {
|
|
@@ -63,20 +59,28 @@ export class RaitonBuilder implements BuilderInterface {
|
|
|
63
59
|
type
|
|
64
60
|
}
|
|
65
61
|
|
|
66
|
-
|
|
62
|
+
Logger.log(LBadge.info('HMR'), 'activated');
|
|
63
|
+
|
|
64
|
+
if (isControllerArtifact(filename)) {
|
|
67
65
|
Raiton.signals.dispatch('hmr:controller', payload)
|
|
68
66
|
}
|
|
69
67
|
|
|
68
|
+
if (Artifacts.is(filename))
|
|
69
|
+
Artifacts.reload(
|
|
70
|
+
await import(`${filename}?v=${payload.version || 1}&t=${payload.timestamp || Date.now()}`),
|
|
71
|
+
filename
|
|
72
|
+
)
|
|
73
|
+
|
|
70
74
|
return payload;
|
|
71
75
|
}
|
|
72
76
|
|
|
73
|
-
protected parsing() {
|
|
77
|
+
protected async parsing(): Promise<this> {
|
|
74
78
|
if (typeof this._source != 'string') throw new Throwable('Application source not found');
|
|
75
79
|
|
|
76
|
-
for (const filename of [...fs.readdirSync(this._source, {recursive: true})])
|
|
77
|
-
this.parse(path.join(this._source, String(filename)));
|
|
78
|
-
}
|
|
80
|
+
for (const filename of [...fs.readdirSync(this._source, {recursive: true})])
|
|
81
|
+
await this.parse(path.join(this._source, String(filename)));
|
|
79
82
|
|
|
83
|
+
return this;
|
|
80
84
|
}
|
|
81
85
|
|
|
82
86
|
protected watching(): this {
|
|
@@ -114,11 +118,12 @@ export class RaitonBuilder implements BuilderInterface {
|
|
|
114
118
|
await this.initialize()
|
|
115
119
|
Raiton.signals.listen(
|
|
116
120
|
'hmr:controller',
|
|
117
|
-
async ({filename, version, timestamp}) =>
|
|
121
|
+
async ({filename, version, timestamp}) => {
|
|
118
122
|
await ControllerBuilder.build({filename, version, timestamp})
|
|
123
|
+
}
|
|
119
124
|
)
|
|
120
|
-
this.parsing()
|
|
121
|
-
this.watching()
|
|
125
|
+
// this.parsing();
|
|
126
|
+
this.watching();
|
|
122
127
|
return this;
|
|
123
128
|
}
|
|
124
129
|
|
|
@@ -131,8 +136,9 @@ export class RaitonBuilder implements BuilderInterface {
|
|
|
131
136
|
if (!('default' in bootstrapper))
|
|
132
137
|
throw new Error('Bootstrapper not supported! Please export to "default"')
|
|
133
138
|
|
|
134
|
-
|
|
135
|
-
|
|
139
|
+
const thread = new RaitonThread(this, {})
|
|
140
|
+
Raiton.thread = thread;
|
|
141
|
+
return await bootstrapper.default(thread);
|
|
136
142
|
}
|
|
137
143
|
|
|
138
144
|
}
|
|
@@ -3,7 +3,8 @@ import {BuilderHMRDeclaration} from "@/types";
|
|
|
3
3
|
import {LBadge, Logger} from "@protorians/logger";
|
|
4
4
|
import {compileController} from "@/core/controller/compiler";
|
|
5
5
|
import {RaitonThread} from "@/core/thread";
|
|
6
|
-
import {
|
|
6
|
+
import {Injection} from "@/core/injection";
|
|
7
|
+
import {isControllerArtifact} from "@/sdk";
|
|
7
8
|
import path from "node:path";
|
|
8
9
|
|
|
9
10
|
export class ControllerBuilder {
|
|
@@ -13,24 +14,26 @@ export class ControllerBuilder {
|
|
|
13
14
|
.map(file => file.toString());
|
|
14
15
|
const output: any[] = []
|
|
15
16
|
|
|
16
|
-
for (const file of files)
|
|
17
|
+
for (const file of files) {
|
|
17
18
|
output.push(await this.build<any>({filename: path.join(workdir, file), version: 1, timestamp: Date.now()}))
|
|
19
|
+
}
|
|
18
20
|
|
|
19
21
|
return output.filter(f => typeof f !== 'undefined');
|
|
20
22
|
}
|
|
21
23
|
|
|
22
24
|
static async build<T>({filename, version, timestamp}: BuilderHMRDeclaration): Promise<T | undefined> {
|
|
23
|
-
if (!
|
|
25
|
+
if (!isControllerArtifact(filename))
|
|
24
26
|
return undefined;
|
|
25
27
|
|
|
26
28
|
const imported = await import(`${filename}?v=${version || 1}&t=${timestamp || Date.now()}`)
|
|
27
29
|
const controller = imported.default || imported || undefined;
|
|
28
30
|
|
|
29
31
|
if (!controller) return undefined;
|
|
30
|
-
if(!RaitonThread.current
|
|
32
|
+
if (!RaitonThread.current?.application) return undefined;
|
|
31
33
|
|
|
32
34
|
const compilated = compileController(controller, RaitonThread.current.application);
|
|
33
|
-
|
|
35
|
+
const name = controller.name || (typeof controller === 'function' ? controller.name : undefined);
|
|
36
|
+
if (name) Injection.registerArtifactPath(name, filename);
|
|
34
37
|
|
|
35
38
|
return compilated;
|
|
36
39
|
}
|
|
@@ -5,7 +5,7 @@ import "reflect-metadata";
|
|
|
5
5
|
export function getControllerMetadata(target: any): ControllerMetaInterface {
|
|
6
6
|
let metadata = Reflect.getMetadata(METADATA_KEYS.CONTROLLERS, target);
|
|
7
7
|
if (!metadata) {
|
|
8
|
-
metadata = {routes: [],
|
|
8
|
+
metadata = {routes: [], middlewares: {}};
|
|
9
9
|
Reflect.defineMetadata(METADATA_KEYS.CONTROLLERS, metadata, target);
|
|
10
10
|
}
|
|
11
11
|
|
|
@@ -25,6 +25,6 @@ export class RaitonDirectories {
|
|
|
25
25
|
}
|
|
26
26
|
|
|
27
27
|
public static app(): string {
|
|
28
|
-
return path.join(Raiton.thread
|
|
28
|
+
return path.join(Raiton.thread?.builder.workdir || '', RaitonConfig.get('rootDir') || './');
|
|
29
29
|
}
|
|
30
30
|
}
|
package/source/core/index.ts
CHANGED
|
@@ -1,16 +1,19 @@
|
|
|
1
1
|
import "reflect-metadata";
|
|
2
2
|
import type {IConstructor, ContainerDefinitionInterface} from "@/types";
|
|
3
|
-
import {Throwable} from "@/sdk/throwable";
|
|
4
3
|
import {LifetimeEnum, TextUtility} from "@protorians/core";
|
|
5
4
|
import {Logger} from "@protorians/logger";
|
|
6
5
|
import {METADATA_KEYS} from "@/sdk/constants";
|
|
7
|
-
import
|
|
6
|
+
import {Throwable} from "@/sdk/exceptions";
|
|
7
|
+
|
|
8
|
+
const camelCase = TextUtility.camelCase;
|
|
8
9
|
|
|
9
10
|
export class Injection {
|
|
10
11
|
|
|
11
12
|
protected static _classes: Map<string, ContainerDefinitionInterface> = new Map();
|
|
12
13
|
protected static _instances: Map<string, Map<any, any>> = new Map();
|
|
13
14
|
protected static _resolutionStack: string[] = [];
|
|
15
|
+
protected static _dependents: Map<string, Set<string>> = new Map();
|
|
16
|
+
protected static _artifactPaths: Map<string, string> = new Map();
|
|
14
17
|
|
|
15
18
|
static get classes(): Map<string, ContainerDefinitionInterface> {
|
|
16
19
|
return this._classes;
|
|
@@ -29,6 +32,8 @@ export class Injection {
|
|
|
29
32
|
static clear(): void {
|
|
30
33
|
this._classes.clear();
|
|
31
34
|
this._instances.clear();
|
|
35
|
+
this._dependents.clear();
|
|
36
|
+
this._artifactPaths.clear();
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
static normalizeName(name: string): string {
|
|
@@ -49,6 +54,25 @@ export class Injection {
|
|
|
49
54
|
return this;
|
|
50
55
|
}
|
|
51
56
|
|
|
57
|
+
static updateConstruct(name: string, construct: IConstructor): typeof this {
|
|
58
|
+
const name_ = this.normalizeName(name);
|
|
59
|
+
this._classes.set(name_, {...this._classes.get(this.normalizeName(name))!, construct});
|
|
60
|
+
return this;
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
static getDependents(name: string): string[] {
|
|
64
|
+
return Array.from(this._dependents.get(this.normalizeName(name)) || []);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
static registerArtifactPath(name: string, path: string): typeof this {
|
|
68
|
+
this._artifactPaths.set(this.normalizeName(name), path);
|
|
69
|
+
return this;
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
static getArtifactPath(name: string): string | undefined {
|
|
73
|
+
return this._artifactPaths.get(this.normalizeName(name));
|
|
74
|
+
}
|
|
75
|
+
|
|
52
76
|
static resolveArguments(definition: ContainerDefinitionInterface, scope?: any): any[] {
|
|
53
77
|
try {
|
|
54
78
|
const parameters = Reflect.getMetadata(METADATA_KEYS.INJECT_PARAMETERS, definition.construct) || [];
|
|
@@ -65,19 +89,24 @@ export class Injection {
|
|
|
65
89
|
if (param && param !== true) {
|
|
66
90
|
const token = typeof param === 'function' ? (param.name || param) : param;
|
|
67
91
|
if (typeof token === 'string') {
|
|
92
|
+
this.addDependent(token, definition.name);
|
|
68
93
|
args.push(this.get(token, effectiveScope));
|
|
69
94
|
continue;
|
|
70
95
|
}
|
|
71
96
|
if (typeof param === 'function') {
|
|
72
97
|
const metadata: ContainerDefinitionInterface = Reflect.getMetadata(METADATA_KEYS.CONTAINER, param);
|
|
73
|
-
|
|
98
|
+
const token = metadata?.name || param.name;
|
|
99
|
+
this.addDependent(token, definition.name);
|
|
100
|
+
args.push(this.get(token, effectiveScope));
|
|
74
101
|
continue;
|
|
75
102
|
}
|
|
76
103
|
}
|
|
77
104
|
|
|
78
105
|
if (designParam && typeof designParam === 'function' && designParam.name) {
|
|
79
106
|
const metadata: ContainerDefinitionInterface = Reflect.getMetadata(METADATA_KEYS.CONTAINER, designParam);
|
|
80
|
-
|
|
107
|
+
const token = metadata?.name || designParam.name;
|
|
108
|
+
this.addDependent(token, definition.name);
|
|
109
|
+
args.push(this.get(token, effectiveScope));
|
|
81
110
|
continue;
|
|
82
111
|
}
|
|
83
112
|
|
|
@@ -90,6 +119,14 @@ export class Injection {
|
|
|
90
119
|
}
|
|
91
120
|
}
|
|
92
121
|
|
|
122
|
+
protected static addDependent(dependencyName: string, dependentName: string) {
|
|
123
|
+
const dep = this.normalizeName(dependencyName);
|
|
124
|
+
if (!this._dependents.has(dep)) {
|
|
125
|
+
this._dependents.set(dep, new Set());
|
|
126
|
+
}
|
|
127
|
+
this._dependents.get(dep)!.add(this.normalizeName(dependentName));
|
|
128
|
+
}
|
|
129
|
+
|
|
93
130
|
static get<T>(name: string, scope?: Symbol): T | undefined {
|
|
94
131
|
const name_ = this.normalizeName(name);
|
|
95
132
|
const cls = this._classes.get(name_);
|
|
@@ -114,6 +151,7 @@ export class Injection {
|
|
|
114
151
|
instance = new cls.construct(...this.resolveArguments(cls, effectiveScope));
|
|
115
152
|
scopeInstances.set(effectiveScope, instance);
|
|
116
153
|
this.injectProperties(instance, cls, effectiveScope);
|
|
154
|
+
this.triggerLifecycle(instance);
|
|
117
155
|
}
|
|
118
156
|
return scopeInstances.get(effectiveScope);
|
|
119
157
|
}
|
|
@@ -121,6 +159,7 @@ export class Injection {
|
|
|
121
159
|
if (cls.lifetime === LifetimeEnum.TRANSIENT) {
|
|
122
160
|
instance = new cls.construct(...this.resolveArguments(cls, effectiveScope));
|
|
123
161
|
this.injectProperties(instance, cls, effectiveScope);
|
|
162
|
+
this.triggerLifecycle(instance);
|
|
124
163
|
return instance as any;
|
|
125
164
|
}
|
|
126
165
|
} finally {
|
|
@@ -137,13 +176,36 @@ export class Injection {
|
|
|
137
176
|
for (const [propertyKey, type] of properties) {
|
|
138
177
|
const token = typeof type === 'function' ? (type.name || type) : type;
|
|
139
178
|
if (typeof token === 'string') {
|
|
179
|
+
this.addDependent(token, definition.name);
|
|
140
180
|
instance[propertyKey] = this.get(token, scope);
|
|
141
181
|
} else if (typeof type === 'function') {
|
|
142
182
|
const metadata: ContainerDefinitionInterface = Reflect.getMetadata(METADATA_KEYS.CONTAINER, type);
|
|
143
|
-
|
|
183
|
+
const token_ = metadata?.name || type.name;
|
|
184
|
+
this.addDependent(token_, definition.name);
|
|
185
|
+
instance[propertyKey] = this.get(token_, scope);
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
protected static triggerLifecycle(instance: any): void {
|
|
192
|
+
if (typeof instance.onInit === 'function') {
|
|
193
|
+
instance.onInit();
|
|
194
|
+
}
|
|
195
|
+
if (typeof instance.onMount === 'function') {
|
|
196
|
+
instance.onMount();
|
|
197
|
+
}
|
|
198
|
+
}
|
|
199
|
+
|
|
200
|
+
static async shutdown(): Promise<void> {
|
|
201
|
+
for (const scopeInstances of this._instances.values()) {
|
|
202
|
+
for (const instance of scopeInstances.values()) {
|
|
203
|
+
if (typeof instance.onUnmount === 'function') {
|
|
204
|
+
await instance.onUnmount();
|
|
144
205
|
}
|
|
145
206
|
}
|
|
146
207
|
}
|
|
208
|
+
this.clear();
|
|
147
209
|
}
|
|
148
210
|
|
|
149
211
|
static resolve<T>(construct: IConstructor<T>): T {
|
package/source/core/raiton.ts
CHANGED
|
@@ -9,9 +9,8 @@ export class Raiton {
|
|
|
9
9
|
static title: string = 'Protorians Raiton';
|
|
10
10
|
static identifier: string = 'raiton';
|
|
11
11
|
|
|
12
|
-
static get thread(): ThreadInterface {
|
|
13
|
-
if (!this._thread)
|
|
14
|
-
throw new Error(`${Raiton.title} Thread instance not initialized`);
|
|
12
|
+
static get thread(): ThreadInterface| undefined {
|
|
13
|
+
// if (!this._thread) throw new Error(`${Raiton.title} Thread instance not initialized`);
|
|
15
14
|
return this._thread;
|
|
16
15
|
}
|
|
17
16
|
|