@xrystal/core 3.14.1 → 3.14.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "author": "Yusuf Yasir KAYGUSUZ",
3
3
  "name": "@xrystal/core",
4
- "version": "3.14.1",
4
+ "version": "3.14.3",
5
5
  "description": "Project core for xrystal",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -1,4 +1,15 @@
1
- import { ProtocolEnum } from '../../index';
1
+ import { AsyncLocalStorage } from 'node:async_hooks';
2
+ import { ProtocolEnum } from '../../utils/index';
3
+ export declare const controllerContextStorage: AsyncLocalStorage<{
4
+ ctx?: any;
5
+ req?: any;
6
+ res?: any;
7
+ }>;
8
+ export declare const getControllerCtx: () => {
9
+ ctx?: any;
10
+ req?: any;
11
+ res?: any;
12
+ };
2
13
  export interface CustomRequest {
3
14
  accounts?: any;
4
15
  url: string;
@@ -17,23 +28,26 @@ export interface CustomResponse {
17
28
  }
18
29
  declare abstract class Controller {
19
30
  protected loggerService: any;
20
- protected protocol: ProtocolEnum | null;
21
- protected req: CustomRequest | null;
22
- protected res: CustomResponse | null;
23
- constructor({ protocol, req, res, ctx, }: {
24
- protocol: ProtocolEnum;
31
+ constructor({ loggerService }: any);
32
+ protected get currentStore(): {
33
+ ctx?: any;
25
34
  req?: any;
26
35
  res?: any;
27
- ctx?: any;
28
- });
36
+ };
37
+ protected get req(): CustomRequest;
38
+ protected get res(): CustomResponse;
29
39
  protected responseProtocolSwitch: ({ res, resStatus, context, req }: any) => Promise<any>;
30
40
  protected parsedQuerys: (url: string) => Record<string, any>;
31
41
  }
32
- export declare class ControllerSchema extends Controller {
33
- schema({ checks, logic, response, }: {
42
+ export declare abstract class ControllerService extends Controller {
43
+ protected controllerType: ProtocolEnum;
44
+ load(props?: {
45
+ type?: ProtocolEnum;
46
+ }): Promise<void>;
47
+ schema({ checks, logic, response }: {
34
48
  checks?: (args: any) => Promise<any>;
35
49
  logic: (args: any) => Promise<any>;
36
50
  response?: (args: any) => Promise<any>;
37
51
  }): Promise<any>;
38
52
  }
39
- export { Controller };
53
+ export {};
@@ -0,0 +1,146 @@
1
+ import qs from 'qs';
2
+ import { AsyncLocalStorage } from 'node:async_hooks';
3
+ import { ProtocolEnum, responseMessageHelper, ResponseSchema } from '../../utils/index';
4
+ export const controllerContextStorage = new AsyncLocalStorage();
5
+ export const getControllerCtx = () => controllerContextStorage.getStore();
6
+ class Controller {
7
+ loggerService;
8
+ constructor({ loggerService }) {
9
+ this.loggerService = loggerService;
10
+ }
11
+ get currentStore() {
12
+ return getControllerCtx();
13
+ }
14
+ get req() {
15
+ const store = this.currentStore;
16
+ if (!store)
17
+ return {};
18
+ if (store.ctx) {
19
+ const { ctx } = store;
20
+ return {
21
+ url: ctx.request?.url || '',
22
+ method: ctx.request?.method || '',
23
+ headers: ctx.headers || {},
24
+ body: ctx.body,
25
+ params: ctx.params || {},
26
+ query: ctx.query || {},
27
+ accounts: ctx.user || ctx.accounts,
28
+ t: ctx.t
29
+ };
30
+ }
31
+ return {
32
+ url: store.req?.originalUrl || store.req?.url || '',
33
+ method: store.req?.method || 'GET',
34
+ headers: store.req?.headers || {},
35
+ body: store.req?.body,
36
+ params: store.req?.params || {},
37
+ query: store.req?.query || {},
38
+ accounts: store.req?.accounts,
39
+ t: store.req?.t
40
+ };
41
+ }
42
+ get res() {
43
+ const store = this.currentStore;
44
+ if (!store)
45
+ return {};
46
+ if (store.ctx) {
47
+ const protocol = this.controllerType || ProtocolEnum.HTTP;
48
+ return {
49
+ locals: {},
50
+ status(code) {
51
+ this.locals._code = code;
52
+ return this;
53
+ },
54
+ send(data) {
55
+ if (protocol === ProtocolEnum.WEBSOCKET)
56
+ return data;
57
+ return new Response(JSON.stringify(data), {
58
+ status: this.locals._code || 200,
59
+ headers: { 'content-type': 'application/json' }
60
+ });
61
+ },
62
+ json(data) { return this.send(data); }
63
+ };
64
+ }
65
+ return {
66
+ locals: store.res?.locals || {},
67
+ status(code) {
68
+ if (store.res?.status)
69
+ store.res.status(code);
70
+ return this;
71
+ },
72
+ send(data) {
73
+ if (store.res?.send)
74
+ return store.res.send(data);
75
+ return data;
76
+ },
77
+ json(data) {
78
+ if (store.res?.json)
79
+ return store.res.json(data);
80
+ return data;
81
+ }
82
+ };
83
+ }
84
+ responseProtocolSwitch = async ({ res, resStatus = 200, context, req }) => {
85
+ const responseData = context({ localeLanguageConverter: req.t });
86
+ return res.status(resStatus).send(responseData);
87
+ };
88
+ parsedQuerys = (url) => {
89
+ const queryString = url.includes('?') ? url.split('?')[1] : '';
90
+ return queryString ? qs.parse(queryString, { decoder: decodeURIComponent }) : {};
91
+ };
92
+ }
93
+ export class ControllerService extends Controller {
94
+ controllerType = ProtocolEnum.HTTP;
95
+ async load(props = {}) {
96
+ if (props.type)
97
+ this.controllerType = props.type;
98
+ }
99
+ async schema({ checks, logic, response }) {
100
+ const currentReq = this.req;
101
+ const currentRes = this.res;
102
+ if (!currentReq || !currentRes)
103
+ return;
104
+ const payload = { req: currentReq, res: currentRes };
105
+ const convertedPayload = { ...payload, parsedQuerys: this.parsedQuerys(currentReq.url) };
106
+ try {
107
+ if (checks) {
108
+ const checkResult = await checks({ payload, convertedPayload });
109
+ if (checkResult?.message) {
110
+ return await this.responseProtocolSwitch({
111
+ req: currentReq,
112
+ res: currentRes,
113
+ context: () => new ResponseSchema(checkResult).getResponse
114
+ });
115
+ }
116
+ }
117
+ const logicResult = await logic({ payload, convertedPayload });
118
+ if (logicResult.response instanceof Function)
119
+ return logicResult.response(logicResult.payload);
120
+ if (logicResult.message) {
121
+ return await this.responseProtocolSwitch({
122
+ req: currentReq,
123
+ res: currentRes,
124
+ resStatus: 400,
125
+ context: () => new ResponseSchema(logicResult).getResponse
126
+ });
127
+ }
128
+ if (response) {
129
+ const resResult = await response({ payload, convertedPayload });
130
+ return await this.responseProtocolSwitch({
131
+ req: currentReq,
132
+ res: currentRes,
133
+ resStatus: 200,
134
+ context: ({ localeLanguageConverter }) => new ResponseSchema({
135
+ status: true,
136
+ message: responseMessageHelper.successFully(resResult.message[0], resResult.message[1], localeLanguageConverter),
137
+ payload: logicResult.payload
138
+ }).getResponse
139
+ });
140
+ }
141
+ }
142
+ catch (error) {
143
+ return currentRes.status(500).send({ status: false, message: error.message });
144
+ }
145
+ }
146
+ }
@@ -3,5 +3,6 @@ import ConfigsService from "./configs";
3
3
  import LoggerService from "./logger";
4
4
  import EventsService from "./events";
5
5
  import LocalizationsService from "./localizations";
6
+ import { ControllerService } from "./controller";
6
7
  import ClientsService from "./clients";
7
- export { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ClientsService };
8
+ export { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ControllerService, ClientsService };
@@ -3,5 +3,6 @@ import ConfigsService from "./configs";
3
3
  import LoggerService from "./logger";
4
4
  import EventsService from "./events";
5
5
  import LocalizationsService from "./localizations";
6
+ import { ControllerService } from "./controller";
6
7
  import ClientsService from "./clients";
7
- export { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ClientsService };
8
+ export { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ControllerService, ClientsService };
@@ -1,7 +1,7 @@
1
1
  // => import dependencies
2
2
  import path from 'path';
3
- import { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ClientsService } from '../loader/index';
4
- import { packageName, x, kafkaBrokers, systemLoggerLayer, getTmp, } from '../utils/index';
3
+ import { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ClientsService, ControllerService } from '../loader/index';
4
+ import { packageName, x, kafkaBrokers, systemLoggerLayer, getTmp, ProtocolEnum, } from '../utils/index';
5
5
  //
6
6
  let coreHasRun = false;
7
7
  export const core = getTmp();
@@ -59,6 +59,12 @@ const coreLoader = async ({}) => {
59
59
  preloadLang: configs.loaders.localization.preloadLangs
60
60
  }
61
61
  },
62
+ {
63
+ service: ControllerService,
64
+ props: {
65
+ type: ProtocolEnum.HTTP
66
+ }
67
+ },
62
68
  {
63
69
  service: ClientsService,
64
70
  props: {}
@@ -1,3 +1,4 @@
1
+ import { AwilixContainer, LifetimeType } from 'awilix';
1
2
  export declare class X {
2
3
  private container;
3
4
  private initializedNames;
@@ -6,9 +7,10 @@ export declare class X {
6
7
  load(patterns: string | string[], options?: {
7
8
  verbose?: boolean;
8
9
  exclude?: string | Function | (string | Function)[];
10
+ lifetime?: LifetimeType;
9
11
  }): this;
10
- register(Dependency: any): this;
11
- registerAll(dependencies: any[]): this;
12
+ register(Dependency: any, lifetime?: LifetimeType): this;
13
+ registerAll(dependencies: any[], lifetime?: LifetimeType): this;
12
14
  registerInstance(name: string, instance: any): this;
13
15
  initialize(input?: {
14
16
  service: any;
@@ -18,8 +20,10 @@ export declare class X {
18
20
  props?: any;
19
21
  }[], verbose?: boolean): Promise<this>;
20
22
  get<T>(target: string | any): T;
23
+ createScope(): AwilixContainer<any>;
21
24
  get cradle(): any;
22
25
  private isRegistered;
26
+ private getSourceByInstance;
23
27
  }
24
28
  declare const _default: X;
25
29
  export default _default;
@@ -1,4 +1,4 @@
1
- import { createContainer, asClass, asValue, InjectionMode, listModules } from 'awilix';
1
+ import { createContainer, asClass, asValue, InjectionMode, listModules, Lifetime } from 'awilix';
2
2
  import path from 'node:path';
3
3
  export class X {
4
4
  container;
@@ -15,7 +15,7 @@ export class X {
15
15
  return normalizedPath.includes('node_modules') || !normalizedPath.startsWith(projectRoot) ? 'LIB' : 'APP';
16
16
  }
17
17
  load(patterns, options = {}) {
18
- const { verbose = false, exclude = [] } = options;
18
+ const { verbose = false, exclude = [], lifetime = Lifetime.SINGLETON } = options;
19
19
  const cwd = process.cwd();
20
20
  const excludeList = Array.isArray(exclude) ? exclude : [exclude];
21
21
  const resolvedPatterns = (Array.isArray(patterns) ? patterns : [patterns]).map(p => {
@@ -41,12 +41,10 @@ export class X {
41
41
  dependency = Object.values(loaded).find(val => typeof val === 'function' && !!val.prototype && !!val.name);
42
42
  }
43
43
  const isExcluded = excludeList.some(ex => {
44
- if (typeof ex === 'string') {
44
+ if (typeof ex === 'string')
45
45
  return m.path.includes(ex) || m.name === ex;
46
- }
47
- if (typeof ex === 'function') {
46
+ if (typeof ex === 'function')
48
47
  return dependency === ex;
49
- }
50
48
  return false;
51
49
  });
52
50
  if (isExcluded) {
@@ -59,9 +57,11 @@ export class X {
59
57
  const className = dependency.name;
60
58
  const name = className.charAt(0).toLowerCase() + className.slice(1);
61
59
  if (!this.isRegistered(name)) {
62
- this.container.register({ [name]: asClass(dependency).singleton() });
60
+ this.container.register({
61
+ [name]: asClass(dependency).setLifetime(lifetime)
62
+ });
63
63
  if (verbose)
64
- console.log(`[DI][${source}] Registered: ${name}`);
64
+ console.log(`[DI][${source}] Registered (${lifetime}): ${name}`);
65
65
  }
66
66
  }
67
67
  }
@@ -71,18 +71,20 @@ export class X {
71
71
  }
72
72
  return this;
73
73
  }
74
- register(Dependency) {
74
+ register(Dependency, lifetime = Lifetime.SINGLETON) {
75
75
  if (!Dependency?.name)
76
76
  return this;
77
77
  const name = Dependency.name.charAt(0).toLowerCase() + Dependency.name.slice(1);
78
78
  if (this.isRegistered(name))
79
79
  return this;
80
- this.container.register({ [name]: asClass(Dependency).singleton() });
80
+ this.container.register({
81
+ [name]: asClass(Dependency).setLifetime(lifetime)
82
+ });
81
83
  return this;
82
84
  }
83
- registerAll(dependencies) {
85
+ registerAll(dependencies, lifetime = Lifetime.SINGLETON) {
84
86
  if (Array.isArray(dependencies))
85
- dependencies.forEach(dep => this.register(dep));
87
+ dependencies.forEach(dep => this.register(dep, lifetime));
86
88
  return this;
87
89
  }
88
90
  registerInstance(name, instance) {
@@ -105,14 +107,17 @@ export class X {
105
107
  if (name)
106
108
  propsMap.set(name, item.props);
107
109
  }
108
- const registrationKeys = Object.keys(this.container.registrations);
109
- const allKeys = new Set([...propsMap.keys(), ...registrationKeys]);
110
+ const registrations = this.container.registrations;
111
+ const allKeys = new Set([...propsMap.keys(), ...Object.keys(registrations)]);
110
112
  for (const key of allKeys) {
111
113
  if (this.initializedNames.has(key))
112
114
  continue;
115
+ const reg = registrations[key];
116
+ if (!reg || reg.lifetime !== Lifetime.SINGLETON)
117
+ continue;
113
118
  const instance = cradle[key];
114
119
  if (instance && typeof instance.load === 'function') {
115
- const source = instance.constructor && instance.constructor.name ? 'APP' : 'LIB';
120
+ const source = this.getSourceByInstance(instance);
116
121
  try {
117
122
  const props = propsMap.get(key) || {};
118
123
  await instance.load(props);
@@ -136,15 +141,21 @@ export class X {
136
141
  }
137
142
  catch (err) {
138
143
  if (err.message.includes('Cyclic dependencies')) {
139
- console.error('\n❌ [DI] addiction detected!');
140
- console.error(`🔍 Hata Yolu: ${err.resolutionStack}`);
144
+ console.error('\n❌ [DI][CRITICAL] Cyclic dependency detected!');
145
+ console.error(`🔍 Resolution Path: ${err.resolutionStack}`);
141
146
  }
142
147
  throw err;
143
148
  }
144
149
  }
150
+ createScope() {
151
+ return this.container.createScope();
152
+ }
145
153
  get cradle() { return this.container.cradle; }
146
154
  isRegistered(name) {
147
155
  return !!this.container.registrations[name] && this.container.registrations[name].resolve !== undefined;
148
156
  }
157
+ getSourceByInstance(instance) {
158
+ return instance.constructor?.name?.includes('Service') || instance.constructor?.name?.includes('Controller') ? 'APP' : 'LIB';
159
+ }
149
160
  }
150
161
  export default new X();
@@ -1,7 +1,6 @@
1
1
  import x, { X } from './classes/class.x';
2
2
  import locator, { Locator } from './classes/class.service-locator';
3
3
  export * from './classes/class.tmp-file-loader';
4
- export * from './classes/class.controller';
5
4
  export * from './classes/class.response';
6
5
  export * from './classes/class.services';
7
6
  export * from './classes/class.interfaces';
@@ -1,7 +1,6 @@
1
1
  import x, { X } from './classes/class.x';
2
2
  import locator, { Locator } from './classes/class.service-locator';
3
3
  export * from './classes/class.tmp-file-loader';
4
- export * from './classes/class.controller';
5
4
  export * from './classes/class.response';
6
5
  export * from './classes/class.services';
7
6
  export * from './classes/class.interfaces';
@@ -1,160 +0,0 @@
1
- import qs from 'qs';
2
- import { LoggerService } from '../../../loader';
3
- import { ProtocolEnum, responseMessageHelper, ResponseSchema, x } from '../../index';
4
- class Controller {
5
- loggerService = x.get(LoggerService);
6
- protocol = null;
7
- req = null;
8
- res = null;
9
- constructor({ protocol, req, res, ctx, }) {
10
- this.protocol = protocol;
11
- if (ctx) {
12
- this.req = {
13
- url: ctx.request?.url || '',
14
- method: ctx.request?.method || '',
15
- headers: ctx.headers || {},
16
- body: ctx.body,
17
- params: ctx.params || {},
18
- query: ctx.query || {},
19
- accounts: ctx.user || ctx.accounts,
20
- t: ctx.t
21
- };
22
- this.res = {
23
- locals: {},
24
- status(code) {
25
- this.locals._code = code;
26
- return this;
27
- },
28
- send(data) {
29
- if (protocol === ProtocolEnum.WEBSOCKET)
30
- return data;
31
- return new Response(JSON.stringify(data), {
32
- status: this.locals._code || 200,
33
- headers: { 'content-type': 'application/json' }
34
- });
35
- },
36
- json(data) {
37
- return this.send(data);
38
- }
39
- };
40
- }
41
- else {
42
- this.req = {
43
- url: req?.originalUrl || req?.url || '',
44
- method: req?.method || 'GET',
45
- headers: req?.headers || {},
46
- body: req?.body,
47
- params: req?.params || {},
48
- query: req?.query || {},
49
- accounts: req?.accounts,
50
- t: req?.t
51
- };
52
- this.res = {
53
- locals: res?.locals || {},
54
- status(code) {
55
- if (res?.status)
56
- res.status(code);
57
- return this;
58
- },
59
- send(data) {
60
- if (res?.send)
61
- return res.send(data);
62
- return data;
63
- },
64
- json(data) {
65
- if (res?.json)
66
- return res.json(data);
67
- return data;
68
- }
69
- };
70
- }
71
- }
72
- responseProtocolSwitch = async ({ res, resStatus = 200, context, req }) => {
73
- const responseData = context({ localeLanguageConverter: req.t });
74
- return res.status(resStatus).send(responseData);
75
- };
76
- parsedQuerys = (url) => {
77
- const queryString = url.includes('?') ? url.split('?')[1] : '';
78
- return queryString ? qs.parse(queryString, { decoder: decodeURIComponent }) : {};
79
- };
80
- }
81
- export class ControllerSchema extends Controller {
82
- async schema({ checks, logic, response, }) {
83
- if (!this.req || !this.res)
84
- return;
85
- const payload = { req: this.req, res: this.res };
86
- const convertedPayload = {
87
- ...payload,
88
- parsedQuerys: this.parsedQuerys(this.req.url)
89
- };
90
- try {
91
- if (checks) {
92
- const checkResult = await checks({ payload, convertedPayload });
93
- let isInvalid = false;
94
- if (Array.isArray(checkResult)) {
95
- isInvalid = !checkResult.every(c => c !== undefined && c !== null && c !== "");
96
- }
97
- else if (typeof checkResult === 'object' && checkResult.message) {
98
- return await this.responseProtocolSwitch({
99
- req: this.req,
100
- res: this.res,
101
- context: () => new ResponseSchema({
102
- status: checkResult.status || false,
103
- message: checkResult.message,
104
- payload: checkResult.payload,
105
- code: checkResult.code
106
- }).getResponse
107
- });
108
- }
109
- if (isInvalid) {
110
- return await this.responseProtocolSwitch({
111
- req: this.req,
112
- res: this.res,
113
- resStatus: 400,
114
- context: ({ localeLanguageConverter }) => new ResponseSchema({
115
- status: false,
116
- message: responseMessageHelper.schemaMissingDataChecks(localeLanguageConverter)
117
- }).getResponse
118
- });
119
- }
120
- }
121
- const logicResult = await logic({ payload, convertedPayload });
122
- if (logicResult.response instanceof Function) {
123
- return logicResult.response(logicResult.payload);
124
- }
125
- if (logicResult.message) {
126
- return await this.responseProtocolSwitch({
127
- req: this.req,
128
- res: this.res,
129
- resStatus: 400,
130
- context: () => new ResponseSchema({
131
- status: logicResult.status || false,
132
- message: logicResult.message,
133
- payload: logicResult.payload,
134
- code: logicResult.code
135
- }).getResponse
136
- });
137
- }
138
- if (response) {
139
- const resResult = await response({ payload, convertedPayload });
140
- if (resResult.response instanceof Function) {
141
- return resResult.response(resResult);
142
- }
143
- return await this.responseProtocolSwitch({
144
- req: this.req,
145
- res: this.res,
146
- resStatus: 200,
147
- context: ({ localeLanguageConverter }) => new ResponseSchema({
148
- status: true,
149
- message: responseMessageHelper.successFully(resResult.message[0], resResult.message[1], localeLanguageConverter),
150
- payload: logicResult.payload
151
- }).getResponse
152
- });
153
- }
154
- }
155
- catch (error) {
156
- return this.res.status(500).send({ status: false, message: error.message });
157
- }
158
- }
159
- }
160
- export { Controller };