framework-do-dede 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/README.md +15 -0
- package/dist/Controller.d.ts +13 -0
- package/dist/FrameworkError.d.ts +5 -0
- package/dist/HttpMiddleware.d.ts +3 -0
- package/dist/HttpServer.d.ts +87 -0
- package/dist/ServerError.d.ts +42 -0
- package/dist/UseCase.d.ts +3 -0
- package/dist/Validation.d.ts +3 -0
- package/dist/controller.d.ts +11 -0
- package/dist/controller.handler.d.ts +86 -0
- package/dist/di.d.ts +1 -0
- package/dist/index.d.ts +24 -0
- package/dist/registry.d.ts +4 -0
- package/dist/usecase.d.ts +1 -0
- package/dist/usecase.handler.d.ts +23 -0
- package/package.json +42 -0
package/README.md
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
# Framework do Dedé
|
|
2
|
+
|
|
3
|
+
To install dependencies:
|
|
4
|
+
|
|
5
|
+
```bash
|
|
6
|
+
bun install
|
|
7
|
+
```
|
|
8
|
+
|
|
9
|
+
To run:
|
|
10
|
+
|
|
11
|
+
```bash
|
|
12
|
+
bun run index.ts
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
This project was created using `bun init` in bun v1.1.42. [Bun](https://bun.sh) is a fast all-in-one JavaScript runtime.
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { AllowedMethods, HttpStatusCode } from '@/http/HttpServer';
|
|
2
|
+
|
|
3
|
+
export declare type Controller = {
|
|
4
|
+
instance: any
|
|
5
|
+
instanceMethod: string
|
|
6
|
+
route: string
|
|
7
|
+
method: AllowedMethods
|
|
8
|
+
middlewares?: HttpMiddleware[]
|
|
9
|
+
statusCode?: HttpStatusCode
|
|
10
|
+
validation?: Validation
|
|
11
|
+
params?: any
|
|
12
|
+
query?: any
|
|
13
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
export declare type HttpStatusCode = 200 | 201 | 204 | 401 | 403 | 404 | 409 | 422 | 500
|
|
2
|
+
|
|
3
|
+
export type AllowedMethods = 'get' | 'post' | 'put' | 'delete' | 'patch'
|
|
4
|
+
|
|
5
|
+
export type HttpServerParams = {
|
|
6
|
+
method: AllowedMethods,
|
|
7
|
+
route: string,
|
|
8
|
+
statusCode?: number,
|
|
9
|
+
params?: string[],
|
|
10
|
+
query?: string[]
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
type FrameworkWeb = {
|
|
14
|
+
listen(port: number): void;
|
|
15
|
+
use(middleware: CallableFunction): void
|
|
16
|
+
get(route: string, handler: CallableFunction): void
|
|
17
|
+
post(route: string, handler: CallableFunction): void
|
|
18
|
+
put(route: string, handler: CallableFunction): void
|
|
19
|
+
delete(route: string, handler: CallableFunction): void
|
|
20
|
+
patch(route: string, handler: CallableFunction): void
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
export default abstract class HttpServer {
|
|
24
|
+
protected framework: FrameworkWeb
|
|
25
|
+
protected frameworkName: string;
|
|
26
|
+
protected defaultMessageError = 'Ops, An unexpected error occurred';
|
|
27
|
+
|
|
28
|
+
constructor(framework: FrameworkWeb, frameworkName: 'elysia' | 'express') {
|
|
29
|
+
if (frameworkName !== 'elysia' && frameworkName !== 'express') throw new FrameworkError('Framework not supported')
|
|
30
|
+
this.framework = framework
|
|
31
|
+
this.frameworkName = frameworkName
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
use(middleware: CallableFunction): HttpServer {
|
|
35
|
+
this.framework.use(middleware)
|
|
36
|
+
return this;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
register(httpServerParams: HttpServerParams, handler: CallableFunction) {
|
|
40
|
+
const route = this.mountRoute(httpServerParams)
|
|
41
|
+
if (this.frameworkName === 'elysia') return this.elysia(httpServerParams, route, handler)
|
|
42
|
+
}
|
|
43
|
+
|
|
44
|
+
listen(port: number): void {
|
|
45
|
+
this.framework.listen(port)
|
|
46
|
+
}
|
|
47
|
+
|
|
48
|
+
private mountRoute(httpServerParams: HttpServerParams) {
|
|
49
|
+
const params = httpServerParams.params?.map((param) => param.split('|')[0])
|
|
50
|
+
if (params && params.length > 0) {
|
|
51
|
+
const paramsMounted = params.map((v) => {
|
|
52
|
+
return v.includes('_') ? `${v.replace('_', '/')}` : `/:${v}`
|
|
53
|
+
}).join('')
|
|
54
|
+
return `${httpServerParams.route}${paramsMounted}`
|
|
55
|
+
}
|
|
56
|
+
return httpServerParams.route
|
|
57
|
+
}
|
|
58
|
+
|
|
59
|
+
private elysia (httpServerParams: HttpServerParams, route: string, handler: CallableFunction) {
|
|
60
|
+
const method = httpServerParams.method as AllowedMethods
|
|
61
|
+
(this.framework[method])(route, async ({ headers, set, query, params, body, request, path }: any) => {
|
|
62
|
+
try {
|
|
63
|
+
set.status = httpServerParams.statusCode ?? 200
|
|
64
|
+
const output = await handler({
|
|
65
|
+
headers,
|
|
66
|
+
query,
|
|
67
|
+
params,
|
|
68
|
+
body
|
|
69
|
+
})
|
|
70
|
+
return output
|
|
71
|
+
} catch (error: any) {
|
|
72
|
+
if (error instanceof ServerError) {
|
|
73
|
+
set.status = error.getStatusCode()
|
|
74
|
+
return {
|
|
75
|
+
error: error.message,
|
|
76
|
+
statusCode: error.getStatusCode()
|
|
77
|
+
}
|
|
78
|
+
}
|
|
79
|
+
set.status = 500
|
|
80
|
+
return {
|
|
81
|
+
error: this.defaultMessageError,
|
|
82
|
+
statusCode: 500
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
})
|
|
86
|
+
}
|
|
87
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
export declare abstract class ServerError extends Error {
|
|
2
|
+
private statusCode: number
|
|
3
|
+
constructor(message: string, statusCode: number) {
|
|
4
|
+
super(message)
|
|
5
|
+
this.name = this.constructor.name
|
|
6
|
+
this.statusCode = statusCode
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
getStatusCode() {
|
|
10
|
+
return this.statusCode
|
|
11
|
+
}
|
|
12
|
+
}
|
|
13
|
+
export declare class NotFound extends ServerError {
|
|
14
|
+
constructor(message: string) {
|
|
15
|
+
super(message, 404)
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
export declare class Forbidden extends ServerError {
|
|
19
|
+
constructor(message: string) {
|
|
20
|
+
super(message, 403)
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
export declare class UnprocessableEntity extends ServerError {
|
|
24
|
+
constructor(message: string) {
|
|
25
|
+
super(message, 422)
|
|
26
|
+
}
|
|
27
|
+
}
|
|
28
|
+
export declare class Conflict extends ServerError {
|
|
29
|
+
constructor(message: string) {
|
|
30
|
+
super(message, 409)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export declare class Unauthorized extends ServerError {
|
|
34
|
+
constructor(message: string) {
|
|
35
|
+
super(message, 401)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
export declare class BadRequest extends ServerError {
|
|
39
|
+
constructor(message: string) {
|
|
40
|
+
super(message, 400)
|
|
41
|
+
}
|
|
42
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { HttpMiddleware } from '@/protocols';
|
|
2
|
+
|
|
3
|
+
declare const middlewares: Map<string, HttpMiddleware>;
|
|
4
|
+
export declare function Controller(basePath: string): void;
|
|
5
|
+
export declare function Middleware(middlewareClass: new ()): void;
|
|
6
|
+
export declare function Post(config: { path?: string,, statusCode?: number,, params?: string[],, query?: string[] }): void;
|
|
7
|
+
export declare function Get(config: { path?: string,, statusCode?: number,, params?: string[],, query?: string[] }): void;
|
|
8
|
+
export declare function Put(config: { path?: string,, statusCode?: number,, params?: string[],, query?: string[] }): void;
|
|
9
|
+
export declare function Patch(config: { path?: string,, statusCode?: number,, params?: string[],, query?: string[] }): void;
|
|
10
|
+
export declare function Delete(config: { path?: string,, statusCode?: number,, params?: string[],, query?: string[] }): void;
|
|
11
|
+
export declare function Validator(validationClass: new ()): void;
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
import type { Controller } from '@/protocols/Controller';
|
|
2
|
+
|
|
3
|
+
declare type Input = {
|
|
4
|
+
headers: any
|
|
5
|
+
body: any
|
|
6
|
+
params: any
|
|
7
|
+
query: any
|
|
8
|
+
}
|
|
9
|
+
|
|
10
|
+
export default class ControllerHandler {
|
|
11
|
+
constructor(httpServer: HttpServer, port: number) {
|
|
12
|
+
for (const { instance, instanceMethod, middlewares, method, route, statusCode, params, query, validation } of this.registryControllers()) {
|
|
13
|
+
httpServer.register(
|
|
14
|
+
{
|
|
15
|
+
method,
|
|
16
|
+
route,
|
|
17
|
+
statusCode,
|
|
18
|
+
params,
|
|
19
|
+
query
|
|
20
|
+
},
|
|
21
|
+
async (input: Input) => {
|
|
22
|
+
const filterParams = this.filter(input.params, params)
|
|
23
|
+
const queryParams = this.filter(input.query, query)
|
|
24
|
+
let mergedParams = { ...filterParams, ...queryParams, ...(input.body || {}) }
|
|
25
|
+
if (validation) mergedParams = validation.validate({ ...filterParams, ...queryParams, ...(input.body || {}) });
|
|
26
|
+
let middlewareData = {}
|
|
27
|
+
if (middlewares) {
|
|
28
|
+
for (const middleware of middlewares) {
|
|
29
|
+
const middlewareResult = await middleware.execute({ headers: input.headers, ...mergedParams })
|
|
30
|
+
middlewareData = { ...middlewareResult, ...middlewareData }
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
const request = { headers: input.headers, data: mergedParams, middlewareData }
|
|
34
|
+
return await instance[instanceMethod](mergedParams, request)
|
|
35
|
+
}
|
|
36
|
+
)
|
|
37
|
+
}
|
|
38
|
+
httpServer.listen(port)
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
private registryControllers() {
|
|
42
|
+
const registryControllers = Registry.resolve<any[]>('controllers');
|
|
43
|
+
const controllers: Controller[] = []
|
|
44
|
+
for (const controller of registryControllers) {
|
|
45
|
+
const basePath = Reflect.getMetadata('basePath', controller);
|
|
46
|
+
const injections = Reflect.getMetadata('injections', controller) || [];
|
|
47
|
+
const args = injections.map((token: string) => Registry.resolve(token))
|
|
48
|
+
const instance = new controller(...args)
|
|
49
|
+
const methodNames = Object.getOwnPropertyNames(controller.prototype).filter(method => method !== 'constructor')
|
|
50
|
+
for (const methodName of methodNames) {
|
|
51
|
+
const validation = Reflect.getMetadata('validation', controller.prototype, methodName);
|
|
52
|
+
const routeConfig = Reflect.getMetadata('route', controller.prototype, methodName);
|
|
53
|
+
const middlewares = Reflect.getMetadata('middlewares', controller.prototype, methodName);
|
|
54
|
+
controllers.push({
|
|
55
|
+
method: routeConfig.method,
|
|
56
|
+
route: basePath + routeConfig.path,
|
|
57
|
+
params: routeConfig.params,
|
|
58
|
+
query: routeConfig.query,
|
|
59
|
+
statusCode: routeConfig.statusCode,
|
|
60
|
+
instance,
|
|
61
|
+
instanceMethod: methodName,
|
|
62
|
+
middlewares,
|
|
63
|
+
validation
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
return controllers
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
private filter(params: any, filterParams?: string[]): any {
|
|
71
|
+
const filter: any = {}
|
|
72
|
+
for (const paramName of filterParams || []) {
|
|
73
|
+
const [paramNameFiltered, type] = paramName.split('|')
|
|
74
|
+
let value = params[paramName] || params[paramNameFiltered]
|
|
75
|
+
if (!value) return
|
|
76
|
+
if (type === 'boolean') value = value === 'true'
|
|
77
|
+
if (type === 'integer') {
|
|
78
|
+
value = value.replace(/[^0-9]/g, '')
|
|
79
|
+
value = value ? parseInt(value) : 0
|
|
80
|
+
}
|
|
81
|
+
if (type === 'string') value = value.toString()
|
|
82
|
+
filter[paramNameFiltered] = value
|
|
83
|
+
}
|
|
84
|
+
return filter
|
|
85
|
+
}
|
|
86
|
+
}
|
package/dist/di.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Inject(token: string): void;
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { Auth, Controller, Delete, Get, Post, Put, Validator } from '@/decorators';
|
|
2
|
+
import { ControllerHandler, UseCaseHandler } from '@/handlers';
|
|
3
|
+
import { HttpMiddleware, UseCase, Validation } from '@/protocols';
|
|
4
|
+
import { HttpServer, ServerError } from '@/http';
|
|
5
|
+
import { Registry } from './di/registry';
|
|
6
|
+
|
|
7
|
+
|
|
8
|
+
export {
|
|
9
|
+
Registry,
|
|
10
|
+
Auth,
|
|
11
|
+
Controller,
|
|
12
|
+
Delete,
|
|
13
|
+
Get,
|
|
14
|
+
Post,
|
|
15
|
+
Put,
|
|
16
|
+
Validator,
|
|
17
|
+
HttpMiddleware,
|
|
18
|
+
UseCase,
|
|
19
|
+
Validation,
|
|
20
|
+
HttpServer,
|
|
21
|
+
ServerError,
|
|
22
|
+
UseCaseHandler,
|
|
23
|
+
ControllerHandler
|
|
24
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export declare function Auth(propertyName: string): void;
|
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import type { UseCase } from '@/protocols';
|
|
2
|
+
|
|
3
|
+
declare type RequestData = {
|
|
4
|
+
headers: any,
|
|
5
|
+
data?: any,
|
|
6
|
+
middlewareData?: any
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
export class UseCaseHandler {
|
|
11
|
+
static load<T extends UseCase<any, any>>(
|
|
12
|
+
useCaseClass: new (...args: any[]) => T,
|
|
13
|
+
request?: RequestData
|
|
14
|
+
): T {
|
|
15
|
+
const instance = Registry.classLoader(useCaseClass);
|
|
16
|
+
const auth = Reflect.getMetadata("auth", useCaseClass);
|
|
17
|
+
const context = request
|
|
18
|
+
if (auth && context?.middlewareData) {
|
|
19
|
+
(instance as any)[auth] = context.middlewareData[auth]
|
|
20
|
+
}
|
|
21
|
+
return instance
|
|
22
|
+
}
|
|
23
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "framework-do-dede",
|
|
3
|
+
"version": "0.0.1",
|
|
4
|
+
"main": "./dist/index.cjs",
|
|
5
|
+
"module": "./dist/index.js",
|
|
6
|
+
"types": "./dist/index.d.ts",
|
|
7
|
+
"description": "",
|
|
8
|
+
"exports": {
|
|
9
|
+
"types": "./dist/index.d.ts",
|
|
10
|
+
"import": "./dist/index.js",
|
|
11
|
+
"require": "./dist/index.cjs"
|
|
12
|
+
},
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "bun run build.ts",
|
|
15
|
+
"prepare": "bun run build"
|
|
16
|
+
},
|
|
17
|
+
"files": [
|
|
18
|
+
"dist"
|
|
19
|
+
],
|
|
20
|
+
"keywords": [
|
|
21
|
+
"bun"
|
|
22
|
+
],
|
|
23
|
+
"license": "MIT",
|
|
24
|
+
"homepage": "https://github.com/marcossaore/framework-do-dede#readme",
|
|
25
|
+
"repository": {
|
|
26
|
+
"type": "git",
|
|
27
|
+
"url": "git+https://github.com/marcossaore/framework-do-dede.git"
|
|
28
|
+
},
|
|
29
|
+
"bugs": "https://github.com/marcossaore/framework-do-dede/issues",
|
|
30
|
+
"author": "Marcos Soares",
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/reflect-metadata": "^0.1.0",
|
|
33
|
+
"bun-plugin-dtsx": "^0.21.9"
|
|
34
|
+
},
|
|
35
|
+
"peerDependencies": {
|
|
36
|
+
"typescript": "^5.8.2"
|
|
37
|
+
},
|
|
38
|
+
"dependencies": {
|
|
39
|
+
"@types/bun": "^1.2.5",
|
|
40
|
+
"reflect-metadata": "^0.2.2"
|
|
41
|
+
}
|
|
42
|
+
}
|