@xitkov/core 2.4.9
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 +256 -0
- package/lib/app.d.ts +75 -0
- package/lib/app.js +143 -0
- package/lib/app.js.map +1 -0
- package/lib/errors/index.d.ts +25 -0
- package/lib/errors/index.js +41 -0
- package/lib/errors/index.js.map +1 -0
- package/lib/hooks/business.d.ts +1 -0
- package/lib/hooks/business.js +26 -0
- package/lib/hooks/business.js.map +1 -0
- package/lib/hooks/hooks.d.ts +4 -0
- package/lib/hooks/hooks.js +66 -0
- package/lib/hooks/hooks.js.map +1 -0
- package/lib/hooks/index.d.ts +3 -0
- package/lib/hooks/index.js +20 -0
- package/lib/hooks/index.js.map +1 -0
- package/lib/hooks/types.d.ts +9 -0
- package/lib/hooks/types.js +3 -0
- package/lib/hooks/types.js.map +1 -0
- package/lib/index.d.ts +17 -0
- package/lib/index.js +23 -0
- package/lib/index.js.map +1 -0
- package/lib/libs/cache.d.ts +7 -0
- package/lib/libs/cache.js +22 -0
- package/lib/libs/cache.js.map +1 -0
- package/lib/libs/index.d.ts +5 -0
- package/lib/libs/index.js +22 -0
- package/lib/libs/index.js.map +1 -0
- package/lib/libs/logs.d.ts +5 -0
- package/lib/libs/logs.js +26 -0
- package/lib/libs/logs.js.map +1 -0
- package/lib/libs/queue.d.ts +21 -0
- package/lib/libs/queue.js +49 -0
- package/lib/libs/queue.js.map +1 -0
- package/lib/libs/socket.d.ts +8 -0
- package/lib/libs/socket.js +26 -0
- package/lib/libs/socket.js.map +1 -0
- package/lib/libs/utils.d.ts +8 -0
- package/lib/libs/utils.js +28 -0
- package/lib/libs/utils.js.map +1 -0
- package/lib/logger/index.d.ts +11 -0
- package/lib/logger/index.js +50 -0
- package/lib/logger/index.js.map +1 -0
- package/lib/services/auth.d.ts +19 -0
- package/lib/services/auth.js +41 -0
- package/lib/services/auth.js.map +1 -0
- package/lib/services/databases/index.d.ts +3 -0
- package/lib/services/databases/index.js +20 -0
- package/lib/services/databases/index.js.map +1 -0
- package/lib/services/databases/mongo-service.d.ts +26 -0
- package/lib/services/databases/mongo-service.js +55 -0
- package/lib/services/databases/mongo-service.js.map +1 -0
- package/lib/services/databases/postgres-service.d.ts +28 -0
- package/lib/services/databases/postgres-service.js +126 -0
- package/lib/services/databases/postgres-service.js.map +1 -0
- package/lib/services/databases/types.d.ts +26 -0
- package/lib/services/databases/types.js +3 -0
- package/lib/services/databases/types.js.map +1 -0
- package/lib/services/index.d.ts +6 -0
- package/lib/services/index.js +23 -0
- package/lib/services/index.js.map +1 -0
- package/lib/services/micro-service.d.ts +60 -0
- package/lib/services/micro-service.js +146 -0
- package/lib/services/micro-service.js.map +1 -0
- package/lib/services/register-micro-services.d.ts +1 -0
- package/lib/services/register-micro-services.js +41 -0
- package/lib/services/register-micro-services.js.map +1 -0
- package/lib/services/register-services.d.ts +5 -0
- package/lib/services/register-services.js +272 -0
- package/lib/services/register-services.js.map +1 -0
- package/lib/services/service.d.ts +46 -0
- package/lib/services/service.js +63 -0
- package/lib/services/service.js.map +1 -0
- package/package.json +49 -0
- package/src/app.ts +182 -0
- package/src/errors/index.ts +37 -0
- package/src/hooks/business.ts +23 -0
- package/src/hooks/hooks.ts +60 -0
- package/src/hooks/index.ts +3 -0
- package/src/hooks/types.ts +9 -0
- package/src/index.ts +18 -0
- package/src/libs/cache.ts +25 -0
- package/src/libs/index.ts +5 -0
- package/src/libs/logs.ts +21 -0
- package/src/libs/queue.ts +48 -0
- package/src/libs/socket.ts +28 -0
- package/src/libs/utils.ts +28 -0
- package/src/logger/index.ts +49 -0
- package/src/services/auth.ts +48 -0
- package/src/services/databases/index.ts +3 -0
- package/src/services/databases/mongo-service.ts +75 -0
- package/src/services/databases/postgres-service.ts +149 -0
- package/src/services/databases/types.ts +29 -0
- package/src/services/index.ts +6 -0
- package/src/services/micro-service.ts +188 -0
- package/src/services/register-micro-services.ts +37 -0
- package/src/services/register-services.ts +268 -0
- package/src/services/service.ts +118 -0
|
@@ -0,0 +1,188 @@
|
|
|
1
|
+
import axios, { AxiosInstance, AxiosRequestConfig } from 'axios';
|
|
2
|
+
import { BadRequest, InternalServer, NoContent, Unauthorized } from '../errors';
|
|
3
|
+
import { Logger } from '../logger';
|
|
4
|
+
|
|
5
|
+
export type MicroServiceQuery = {[key: string]: any};
|
|
6
|
+
|
|
7
|
+
export interface InternalMicroServiceMethods {
|
|
8
|
+
find<T = any>(query: MicroServiceQuery, config?: IConfig<T>): Promise<T[]>;
|
|
9
|
+
get<T = any>(id: string | null, query?: MicroServiceQuery, config?: IConfig<T>): Promise<T | null>;
|
|
10
|
+
create<T = any, U = any>(data: Partial<U>, query?: MicroServiceQuery, config?: IConfig<T>): Promise<T | null>;
|
|
11
|
+
update<T = any, U = any>(id: string, data: U, query?: MicroServiceQuery, config?: IConfig<T>): Promise<T | null>;
|
|
12
|
+
patch<T = any, U = any>(id: string, data: Partial<U>, query?: MicroServiceQuery, config?: IConfig<T>): Promise<T | null>;
|
|
13
|
+
remove<T = any>(id: string, query?: MicroServiceQuery, config?: IConfig<T>): Promise<T | T[] | null>;
|
|
14
|
+
readonly request: AxiosInstance;
|
|
15
|
+
readonly call: AxiosInstance
|
|
16
|
+
readonly name: string;
|
|
17
|
+
readonly baseURL: string;
|
|
18
|
+
readonly service: string
|
|
19
|
+
readonly url: string
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
export interface InternalMicroServiceOptions {
|
|
23
|
+
axiosConfig?: AxiosRequestConfig;
|
|
24
|
+
name: string;
|
|
25
|
+
baseURL: string;
|
|
26
|
+
service: string
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
interface IExceptionConfig<T = any> {
|
|
30
|
+
handle?: boolean;
|
|
31
|
+
defaultValue?: Partial<T> | null;
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface IConfig<T = any> {
|
|
35
|
+
axiosConfig?: AxiosRequestConfig;
|
|
36
|
+
exception?: IExceptionConfig<T>;
|
|
37
|
+
/** @deprecated typo alias, use `exception` */
|
|
38
|
+
execption?: IExceptionConfig<T>;
|
|
39
|
+
}
|
|
40
|
+
|
|
41
|
+
export class MicroService implements InternalMicroServiceMethods {
|
|
42
|
+
readonly request: AxiosInstance
|
|
43
|
+
readonly name: string
|
|
44
|
+
readonly baseURL: string
|
|
45
|
+
readonly service: string
|
|
46
|
+
readonly url: string
|
|
47
|
+
|
|
48
|
+
constructor({ axiosConfig, name, service, baseURL }: InternalMicroServiceOptions) {
|
|
49
|
+
const providedAxiosConfig = (axiosConfig ?? {})
|
|
50
|
+
this.request = axios.create({
|
|
51
|
+
baseURL,
|
|
52
|
+
headers: {
|
|
53
|
+
InternalToken: process.env.INTERNAL_TOKEN ?? 'internal_token',
|
|
54
|
+
...providedAxiosConfig.headers,
|
|
55
|
+
},
|
|
56
|
+
...providedAxiosConfig,
|
|
57
|
+
})
|
|
58
|
+
this.name = name
|
|
59
|
+
this.baseURL = baseURL;
|
|
60
|
+
this.service = service
|
|
61
|
+
this.url = `/${service}`
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
throwError(err: any): Error {
|
|
65
|
+
const message = err?.response?.data?.message
|
|
66
|
+
const status = err?.response?.status
|
|
67
|
+
if (message) {
|
|
68
|
+
switch(status) {
|
|
69
|
+
case 401: return new Unauthorized(message)
|
|
70
|
+
case 400: return new BadRequest(message)
|
|
71
|
+
case 500: return new InternalServer(message)
|
|
72
|
+
case 204: return new NoContent(message)
|
|
73
|
+
default: return new InternalServer(message)
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
return new InternalServer(err?.message ?? String(err))
|
|
77
|
+
}
|
|
78
|
+
|
|
79
|
+
async find<T = any>(query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T[]> {
|
|
80
|
+
const defaultValue: T[] = [];
|
|
81
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
82
|
+
try {
|
|
83
|
+
const { data } = await this.request.get(`${this.url}`, { ...axiosConfig, params: query });
|
|
84
|
+
return data?.data ?? data
|
|
85
|
+
}
|
|
86
|
+
catch (err) {
|
|
87
|
+
return this.handleException(exception, defaultValue, err);
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
async get<T = any>(id: string | null, query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T | null> {
|
|
92
|
+
const defaultValue = {};
|
|
93
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
94
|
+
try {
|
|
95
|
+
const { data } = await this.request.get(`${this.url}/${id}`, { ...axiosConfig, params: query });
|
|
96
|
+
return data?.data ?? data
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return this.handleException(exception, defaultValue, err);
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
async create<T = any, U = any>(payload: Partial<U>, query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T | null> {
|
|
104
|
+
const defaultValue = {};
|
|
105
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
106
|
+
try {
|
|
107
|
+
const { data } = await this.request.post(`${this.url}`, payload, { ...axiosConfig, params: query });
|
|
108
|
+
return data?.data ?? data
|
|
109
|
+
}
|
|
110
|
+
catch (err) {
|
|
111
|
+
return this.handleException(exception, defaultValue, err);
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async update<T = any, U = any>(id: string, payload: U, query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T | null> {
|
|
116
|
+
const defaultValue = {};
|
|
117
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
118
|
+
try {
|
|
119
|
+
const { data } = await this.request.put(`${this.url}/${id}`, payload, { ...axiosConfig, params: query });
|
|
120
|
+
return data?.data ?? data
|
|
121
|
+
}
|
|
122
|
+
catch (err) {
|
|
123
|
+
return this.handleException(exception, defaultValue, err);
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
|
|
127
|
+
async patch<T = any, U = any>(id: string, payload: Partial<U>, query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T | null> {
|
|
128
|
+
const defaultValue = {};
|
|
129
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
130
|
+
try {
|
|
131
|
+
const { data } = await this.request.patch(`${this.url}/${id}`, payload, { ...axiosConfig, params: query });
|
|
132
|
+
return data?.data ?? data
|
|
133
|
+
}
|
|
134
|
+
catch (err) {
|
|
135
|
+
return this.handleException(exception, defaultValue, err);
|
|
136
|
+
}
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
async remove<T = any>(id: string, query?: MicroServiceQuery, config: IConfig<T> = {}): Promise<T | T[] | null> {
|
|
140
|
+
const defaultValue = {};
|
|
141
|
+
const { axiosConfig, exception } = this.getConfig(config, defaultValue);
|
|
142
|
+
try {
|
|
143
|
+
const { data } = await this.request.delete(`${this.url}/${id}`, { ...axiosConfig, params: query });
|
|
144
|
+
return data?.data ?? data
|
|
145
|
+
}
|
|
146
|
+
catch (err) {
|
|
147
|
+
return this.handleException(exception, defaultValue, err);
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
get call() {
|
|
152
|
+
return this.request
|
|
153
|
+
}
|
|
154
|
+
|
|
155
|
+
private getLog(err: any) {
|
|
156
|
+
const message = err?.response?.data?.message
|
|
157
|
+
const status = err?.response?.status
|
|
158
|
+
Logger.error(`Error ${this.name}`, {
|
|
159
|
+
message,
|
|
160
|
+
status,
|
|
161
|
+
url: this.url,
|
|
162
|
+
errorMessage: message ?? err?.message ?? err,
|
|
163
|
+
error: err?.response?.data ?? err?.response ?? err,
|
|
164
|
+
});
|
|
165
|
+
}
|
|
166
|
+
|
|
167
|
+
private getConfig(config: IConfig<any>, defaultValue: any) {
|
|
168
|
+
const src = config ?? {};
|
|
169
|
+
const axiosConfig = src.axiosConfig ?? {};
|
|
170
|
+
const exception = src.exception ?? src.execption ?? { defaultValue, handle: false };
|
|
171
|
+
return { axiosConfig, exception };
|
|
172
|
+
}
|
|
173
|
+
private handleException(exception: IExceptionConfig | undefined, defaultInitialValue: any, err: any) {
|
|
174
|
+
const { defaultValue = defaultInitialValue, handle = false } = exception ?? {};
|
|
175
|
+
if (handle) {
|
|
176
|
+
this.getLog(err);
|
|
177
|
+
return defaultValue;
|
|
178
|
+
}
|
|
179
|
+
throw this.throwError(err);
|
|
180
|
+
}
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
export interface IMicroService {
|
|
184
|
+
name: string;
|
|
185
|
+
baseURL: string;
|
|
186
|
+
config?: AxiosRequestConfig;
|
|
187
|
+
services: string[]
|
|
188
|
+
}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
import {promises} from 'fs';
|
|
2
|
+
import path from 'path';
|
|
3
|
+
import { Logger } from '../logger';
|
|
4
|
+
import { MicroService } from './micro-service';
|
|
5
|
+
|
|
6
|
+
export async function registerMicroServices() {
|
|
7
|
+
if (require.main?.filename == undefined) {
|
|
8
|
+
throw new Error("Please provide service path")
|
|
9
|
+
}
|
|
10
|
+
const appDir = path.dirname(require.main?.filename as string);
|
|
11
|
+
const serviceDirPath = appDir + '/micro-services';
|
|
12
|
+
|
|
13
|
+
const servicesNames = (await promises.readdir(serviceDirPath)).filter(
|
|
14
|
+
file => !/^(index|types)\.(ts|js|d\.ts)$/.test(file) && !/\.map$/.test(file)
|
|
15
|
+
);
|
|
16
|
+
|
|
17
|
+
const services: any = {}
|
|
18
|
+
|
|
19
|
+
for (const serviceName of servicesNames) {
|
|
20
|
+
const servicePath = `${serviceDirPath}/${serviceName}`;
|
|
21
|
+
try {
|
|
22
|
+
const instance = new (require(servicePath).default)
|
|
23
|
+
if (instance) {
|
|
24
|
+
const { baseURL, name, services: subServicesNames, config } = instance
|
|
25
|
+
services[name] = services[name] ?? {}
|
|
26
|
+
subServicesNames?.forEach((subService: string) => {
|
|
27
|
+
services[name][subService] = new MicroService({ axiosConfig: config, name, service: subService, baseURL })
|
|
28
|
+
})
|
|
29
|
+
}
|
|
30
|
+
} catch(error) {
|
|
31
|
+
Logger.warn("No micro services", {
|
|
32
|
+
error
|
|
33
|
+
})
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return services;
|
|
37
|
+
}
|
|
@@ -0,0 +1,268 @@
|
|
|
1
|
+
import type {Application, Request, Response} from 'express';
|
|
2
|
+
// eslint-disable-next-line node/no-unsupported-features/node-builtins
|
|
3
|
+
import {promises} from 'fs';
|
|
4
|
+
import path from 'path';
|
|
5
|
+
import {Router} from 'express';
|
|
6
|
+
import {Config, Dialect, IAuth, Logger, addQuerySupport} from '..';
|
|
7
|
+
import {PostgresInternalServiceOptions, MongoInternalServiceOptions} from '.';
|
|
8
|
+
import { BadRequest, Unauthorized } from '../errors';
|
|
9
|
+
import { AuthService } from './auth';
|
|
10
|
+
|
|
11
|
+
type Method = 'get' | 'post' | 'patch' | 'put' | 'delete';
|
|
12
|
+
|
|
13
|
+
type Functions = 'find' | 'get' | 'create' | 'update' | 'patch' | 'remove';
|
|
14
|
+
|
|
15
|
+
type InternalServiceOptions = (PostgresInternalServiceOptions | MongoInternalServiceOptions) & { dialect : Dialect };
|
|
16
|
+
|
|
17
|
+
interface Methods {
|
|
18
|
+
method: Method;
|
|
19
|
+
url: string;
|
|
20
|
+
func: Functions;
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
async function validate(Validator: any, func: string, value: any) {
|
|
24
|
+
const schema = await Validator[func]
|
|
25
|
+
if (schema) {
|
|
26
|
+
try {
|
|
27
|
+
const schemaValue = await schema().validateAsync(value);
|
|
28
|
+
return schemaValue;
|
|
29
|
+
} catch (err: any) {
|
|
30
|
+
throw new BadRequest(err.message)
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
return value
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
async function hooks(Hooks: any, func: string, parameters: any[], methodName: string) {
|
|
37
|
+
const allHooks = Hooks[func]
|
|
38
|
+
|
|
39
|
+
allHooks?.forEach?.((hook: any) => {
|
|
40
|
+
hook?.(...parameters, methodName)
|
|
41
|
+
});
|
|
42
|
+
return allHooks
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
function getJWTDecoded(accessToken: string) {
|
|
46
|
+
try {
|
|
47
|
+
const base64Url = accessToken.split('.')[1];
|
|
48
|
+
const decoded = Buffer.from(base64Url, 'base64').toString()
|
|
49
|
+
return JSON.parse(decoded)
|
|
50
|
+
} catch(error) {
|
|
51
|
+
Logger.error("getJWTDecoded", error)
|
|
52
|
+
return {}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
export async function registerServices(app: Application, auth?: IAuth, database?: Config['database']) {
|
|
57
|
+
if (require.main?.filename == undefined) {
|
|
58
|
+
throw new Error("Please provide service path")
|
|
59
|
+
}
|
|
60
|
+
const appDir = path.dirname(require.main?.filename as string);
|
|
61
|
+
const serviceDirPath = appDir + '/services';
|
|
62
|
+
|
|
63
|
+
const servicesNames = (await promises.readdir(serviceDirPath)).filter(
|
|
64
|
+
file => !/^index\.(ts|js|d\.ts)$/.test(file) && !/\.map$/.test(file)
|
|
65
|
+
);
|
|
66
|
+
|
|
67
|
+
const methods: Methods[] = [
|
|
68
|
+
{
|
|
69
|
+
method: 'get',
|
|
70
|
+
url: '/',
|
|
71
|
+
func: 'find',
|
|
72
|
+
},
|
|
73
|
+
{
|
|
74
|
+
method: 'get',
|
|
75
|
+
url: '/:id',
|
|
76
|
+
func: 'get',
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
method: 'post',
|
|
80
|
+
url: '/',
|
|
81
|
+
func: 'create',
|
|
82
|
+
},
|
|
83
|
+
{
|
|
84
|
+
method: 'patch',
|
|
85
|
+
url: '/:id',
|
|
86
|
+
func: 'patch',
|
|
87
|
+
},
|
|
88
|
+
{
|
|
89
|
+
method: 'put',
|
|
90
|
+
url: '/:id',
|
|
91
|
+
func: 'update',
|
|
92
|
+
},
|
|
93
|
+
{
|
|
94
|
+
method: 'delete',
|
|
95
|
+
url: '/:id',
|
|
96
|
+
func: 'remove',
|
|
97
|
+
},
|
|
98
|
+
];
|
|
99
|
+
|
|
100
|
+
const services: {[serviceName: string]: any} = {}
|
|
101
|
+
|
|
102
|
+
for (const serviceName of servicesNames) {
|
|
103
|
+
const servicePath = `${serviceDirPath}/${serviceName}/service`;
|
|
104
|
+
const modelPath = `${serviceDirPath}/${serviceName}/model`;
|
|
105
|
+
const validatorPath = `${serviceDirPath}/${serviceName}/validator`;
|
|
106
|
+
const hooksPath = `${serviceDirPath}/${serviceName}/hooks`;
|
|
107
|
+
let Model = null
|
|
108
|
+
let Validator: any = null
|
|
109
|
+
let Hooks: any = null
|
|
110
|
+
try {
|
|
111
|
+
if(database?.instance) {
|
|
112
|
+
Model = (await import(modelPath)).default(database.instance);
|
|
113
|
+
} else {
|
|
114
|
+
Model = (await import(modelPath)).default;
|
|
115
|
+
}
|
|
116
|
+
} catch(err) {
|
|
117
|
+
//
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
try {
|
|
121
|
+
Validator = new (await import(validatorPath)).default;
|
|
122
|
+
} catch(err) {
|
|
123
|
+
//
|
|
124
|
+
}
|
|
125
|
+
|
|
126
|
+
try {
|
|
127
|
+
Hooks = new (await import(hooksPath)).default;
|
|
128
|
+
} catch(err) {
|
|
129
|
+
//
|
|
130
|
+
}
|
|
131
|
+
const serviceConfig: Partial<InternalServiceOptions> = {}
|
|
132
|
+
|
|
133
|
+
if (Model) {
|
|
134
|
+
serviceConfig.Model = Model
|
|
135
|
+
}
|
|
136
|
+
serviceConfig.dialect = database?.dialect ?? 'mongodb'
|
|
137
|
+
|
|
138
|
+
const service = new (await import(servicePath)).default(serviceConfig);
|
|
139
|
+
services[serviceName] = service
|
|
140
|
+
const router = Router();
|
|
141
|
+
for (const {method, url, func} of methods) {
|
|
142
|
+
const callback = async (req: Request, res: Response) => {
|
|
143
|
+
const { required, baseURL } = auth ?? {}
|
|
144
|
+
const {params, query, body, baseUrl, ...rest} = req;
|
|
145
|
+
|
|
146
|
+
try {
|
|
147
|
+
if (service.auth !== false) {
|
|
148
|
+
// TODO: Temp will find the better solution later
|
|
149
|
+
if (req.headers['internaltoken'] !== (process.env.INTERNAL_TOKEN ?? 'internal_token')) {
|
|
150
|
+
if (required && baseURL) {
|
|
151
|
+
const authorization = req.headers['authorization']
|
|
152
|
+
if (!authorization) {
|
|
153
|
+
throw new Unauthorized("You don't have permission")
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
const authService = new AuthService({
|
|
157
|
+
baseURL: baseURL,
|
|
158
|
+
axiosConfig: {
|
|
159
|
+
headers: {
|
|
160
|
+
Authorization: authorization
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
})
|
|
164
|
+
|
|
165
|
+
const authData = await authService.verify()
|
|
166
|
+
const {businessId} = authData ?? {}
|
|
167
|
+
const decodedAccessToken = getJWTDecoded(authorization);
|
|
168
|
+
const { business } = decodedAccessToken;
|
|
169
|
+
const userBusinessId = businessId ?? business
|
|
170
|
+
if (!userBusinessId) {
|
|
171
|
+
throw new Unauthorized("You don't have permission")
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
const userData = ((req as any).user ?? {});
|
|
175
|
+
(req as any).user = { ...userData, userBusinessId }
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
const user = (req as any).user
|
|
181
|
+
const {id} = params;
|
|
182
|
+
let parameters: any[] = [];
|
|
183
|
+
let validatorValue
|
|
184
|
+
switch (func) {
|
|
185
|
+
case 'find':
|
|
186
|
+
parameters = [query, user, req];
|
|
187
|
+
validatorValue = query
|
|
188
|
+
break;
|
|
189
|
+
case 'get':
|
|
190
|
+
parameters = [id, query, user, req];
|
|
191
|
+
validatorValue = query
|
|
192
|
+
break;
|
|
193
|
+
case 'create':
|
|
194
|
+
parameters = [body, query, user, req];
|
|
195
|
+
validatorValue = body
|
|
196
|
+
break;
|
|
197
|
+
case 'patch':
|
|
198
|
+
parameters = [id, body, query, user, req];
|
|
199
|
+
validatorValue = body
|
|
200
|
+
break;
|
|
201
|
+
case 'update':
|
|
202
|
+
parameters = [id, body, query, user, req];
|
|
203
|
+
validatorValue = body
|
|
204
|
+
break;
|
|
205
|
+
case 'remove':
|
|
206
|
+
parameters = [id, query, user, req];
|
|
207
|
+
validatorValue = query
|
|
208
|
+
break;
|
|
209
|
+
}
|
|
210
|
+
if (Hooks) {
|
|
211
|
+
await hooks(Hooks, 'all', parameters, func)
|
|
212
|
+
await hooks(Hooks, func, parameters, func)
|
|
213
|
+
}
|
|
214
|
+
if (service.filtering !== false && func === 'find') {
|
|
215
|
+
parameters[0] = addQuerySupport(...parameters, func)
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
if(service[func] == undefined) {
|
|
219
|
+
return res.status(404).send({
|
|
220
|
+
message: "Not found"
|
|
221
|
+
});
|
|
222
|
+
}
|
|
223
|
+
if (Validator) {
|
|
224
|
+
await validate(Validator, func, validatorValue)
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
const response = await service[func](...parameters)
|
|
228
|
+
let data: any = response
|
|
229
|
+
let count: number | undefined = undefined
|
|
230
|
+
|
|
231
|
+
if (func === 'find' && data && !Array.isArray(data) && data.rows) {
|
|
232
|
+
count = data.count
|
|
233
|
+
data = data.rows
|
|
234
|
+
} else if (response == null) {
|
|
235
|
+
if (id) {
|
|
236
|
+
return res.status(400).send({message: `No record found for ${id}`});
|
|
237
|
+
}
|
|
238
|
+
return res.status(400).send({message: 'Bad Request'});
|
|
239
|
+
}
|
|
240
|
+
|
|
241
|
+
return res.send({
|
|
242
|
+
message: "ok",
|
|
243
|
+
data,
|
|
244
|
+
count
|
|
245
|
+
});
|
|
246
|
+
} catch (error: any) {
|
|
247
|
+
Logger.error('Error', {
|
|
248
|
+
baseUrl,
|
|
249
|
+
url,
|
|
250
|
+
error,
|
|
251
|
+
message: error?.message
|
|
252
|
+
});
|
|
253
|
+
const status = error?.status
|
|
254
|
+
const message = error?.message
|
|
255
|
+
if (typeof status === 'number' && message) {
|
|
256
|
+
return res.status(status).send({ message });
|
|
257
|
+
}
|
|
258
|
+
return res.status(500).send({ message: 'Something went wrong' });
|
|
259
|
+
}
|
|
260
|
+
};
|
|
261
|
+
router[method](url, callback);
|
|
262
|
+
}
|
|
263
|
+
app.set('services', services)
|
|
264
|
+
|
|
265
|
+
app.use(`/${serviceName}`, router);
|
|
266
|
+
}
|
|
267
|
+
return services;
|
|
268
|
+
}
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { Request, Response } from "express";
|
|
2
|
+
import { Model as MongoModel } from "mongoose";
|
|
3
|
+
import { ModelStatic as SequelizeModel} from 'sequelize'
|
|
4
|
+
import { Dialect } from "..";
|
|
5
|
+
import { FindResponse, InternalServiceMethods, MongoDBService, PostgreSQLService, Query, User } from './databases'
|
|
6
|
+
|
|
7
|
+
/**
|
|
8
|
+
* Augment via:
|
|
9
|
+
* declare module 'xitkov' {
|
|
10
|
+
* interface XitkovConfig { dialect: 'postgres' }
|
|
11
|
+
* }
|
|
12
|
+
*/
|
|
13
|
+
export interface XitkovConfig {}
|
|
14
|
+
|
|
15
|
+
export type DefaultDialect = XitkovConfig extends { dialect: infer D }
|
|
16
|
+
? D extends Dialect ? D : 'mongodb'
|
|
17
|
+
: 'mongodb';
|
|
18
|
+
|
|
19
|
+
type ServiceType<T, U> =
|
|
20
|
+
U extends 'postgres'
|
|
21
|
+
? PostgreSQLService<T>
|
|
22
|
+
: U extends 'mongodb'
|
|
23
|
+
? MongoDBService<T>
|
|
24
|
+
: any;
|
|
25
|
+
|
|
26
|
+
type ModelType<T, U> =
|
|
27
|
+
U extends 'postgres'
|
|
28
|
+
? SequelizeModel<any>
|
|
29
|
+
: U extends "mongodb"
|
|
30
|
+
? MongoModel<T>
|
|
31
|
+
: any
|
|
32
|
+
|
|
33
|
+
export interface IXitovServiceProps {
|
|
34
|
+
Model: any;
|
|
35
|
+
dialect?: Dialect;
|
|
36
|
+
pagination?: boolean
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
export class XitkovService<T, U extends Dialect = DefaultDialect> implements InternalServiceMethods<T> {
|
|
40
|
+
private service: ServiceType<T, U>;
|
|
41
|
+
private Model: ModelType<T, U>
|
|
42
|
+
pagination?: boolean;
|
|
43
|
+
|
|
44
|
+
static defaultDialect: Dialect = 'mongodb';
|
|
45
|
+
|
|
46
|
+
static setDefaultDialect(dialect: Dialect) {
|
|
47
|
+
XitkovService.defaultDialect = dialect;
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
constructor({Model, dialect, pagination}: IXitovServiceProps) {
|
|
51
|
+
this.Model = Model;
|
|
52
|
+
const resolved = dialect ?? XitkovService.defaultDialect;
|
|
53
|
+
switch(resolved) {
|
|
54
|
+
case 'postgres':
|
|
55
|
+
this.service = new PostgreSQLService({ Model, pagination }) as any;
|
|
56
|
+
break;
|
|
57
|
+
case 'mongodb':
|
|
58
|
+
default:
|
|
59
|
+
this.service = new MongoDBService({ Model }) as any;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
|
|
63
|
+
async find(query: Query, user?: any, req?: Request, res?: Response): Promise<FindResponse<T>> {
|
|
64
|
+
return await this.service.find(query, user, req, res);
|
|
65
|
+
}
|
|
66
|
+
|
|
67
|
+
async get(id: string | null, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | null> {
|
|
68
|
+
return await this.service.get(id, query, user, req, res);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
async create(data: Partial<T>, query?: Query, user?: User, req?: Request, res?: Response): Promise<T>;
|
|
72
|
+
async create(data: Partial<T>[], query?: Query, user?: User, req?: Request, res?: Response): Promise<T[]>;
|
|
73
|
+
async create(data: Partial<T> | Partial<T>[], query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[]> {
|
|
74
|
+
return this.service.create(data, query, user, req, res);
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
async update(id: string, data: T, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | null> {
|
|
78
|
+
return await this.service.update(id, data, query, user, req, res);
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
async patch(id: string, data: Partial<T>, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[] | null> {
|
|
82
|
+
return await this.service.patch(id, data, query, user, req, res);
|
|
83
|
+
}
|
|
84
|
+
|
|
85
|
+
async remove(id: string, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[] | null> {
|
|
86
|
+
return await this.service.remove(id, query, user, req, res);
|
|
87
|
+
}
|
|
88
|
+
|
|
89
|
+
get model(): ModelType<T, U> {
|
|
90
|
+
return this.Model
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
async _find(query: Query, user?: any, req?: Request, res?: Response): Promise<FindResponse<T>> {
|
|
94
|
+
return await this.service.find(query, user, req, res);
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
async _get(id: string | null, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | null> {
|
|
98
|
+
return await this.service.get(id, query, user, req, res);
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
async _create(data: Partial<T>, query?: Query, user?: User, req?: Request, res?: Response): Promise<T>;
|
|
102
|
+
async _create(data: Partial<T>[], query?: Query, user?: User, req?: Request, res?: Response): Promise<T[]>;
|
|
103
|
+
async _create(data: Partial<T> | Partial<T>[], query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[]> {
|
|
104
|
+
return this.service.create(data, query, user, req, res);
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
async _update(id: string, data: T, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | null> {
|
|
108
|
+
return await this.service.update(id, data, query, user, req, res);
|
|
109
|
+
}
|
|
110
|
+
|
|
111
|
+
async _patch(id: string, data: Partial<T>, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[] | null> {
|
|
112
|
+
return await this.service.patch(id, data, query, user, req, res);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
async _remove(id: string, query?: Query, user?: User, req?: Request, res?: Response): Promise<T | T[] | null> {
|
|
116
|
+
return await this.service.remove(id, query, user, req, res);
|
|
117
|
+
}
|
|
118
|
+
}
|