@xrystal/core 3.20.0 → 3.20.2

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.20.0",
4
+ "version": "3.20.2",
5
5
  "description": "Project core for xrystal",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -1,7 +1,8 @@
1
1
  import SystemService from '../system/index';
2
- import { IService } from '../../utils';
2
+ import { IService, ModeEnum } from '../../utils';
3
3
  export interface IConfig {
4
4
  worker: boolean;
5
+ mode: ModeEnum;
5
6
  nodeEnv: string;
6
7
  debug: string;
7
8
  https: string;
@@ -16,7 +17,9 @@ export interface IConfig {
16
17
  projectNameSuffixEnv: string;
17
18
  systemStaticFolderPath: string;
18
19
  systemLoggerLayer: string;
20
+ isKafkaPassive: boolean;
19
21
  kafkaBrokers: string;
22
+ kafkaTopics: string;
20
23
  kafkaLogsTopic: string;
21
24
  baseApiUri: string;
22
25
  port: number;
@@ -1,7 +1,7 @@
1
1
  import path from 'node:path';
2
2
  import { merge } from 'lodash';
3
- import { Constants } from '../../utils';
4
3
  import { pathToFileURL } from 'node:url';
4
+ import { Constants } from '../../utils';
5
5
  export default class ConfigsService {
6
6
  publicFolderName = Constants.publicFolderName;
7
7
  kafkaLogsTopic = Constants.kafkaLogsTopic;
@@ -27,6 +27,7 @@ export default class ConfigsService {
27
27
  const modulePromise = import(fileUrl);
28
28
  this.#config = {
29
29
  worker: process.env.WORKER === 'true' ? true : false || false,
30
+ mode: process.env.MODE,
30
31
  nodeEnv: process.env.NODE_ENV,
31
32
  debug: process.env.SYSTEM_LOGGER_LAYER,
32
33
  https: process.env.HTTPS,
@@ -41,7 +42,9 @@ export default class ConfigsService {
41
42
  projectNameSuffixEnv: process.env.PROJECT_NAME_SUFFIX || '',
42
43
  systemStaticFolderPath: path.resolve(tmp.configs.rootFolderPath, this.publicFolderName),
43
44
  systemLoggerLayer: process.env.SYSTEM_LOGGER_LAYER,
45
+ isKafkaPassive: process.env.IS_KAFKA_PASSIVE === 'true' ? true : false,
44
46
  kafkaBrokers: process.env?.KAFKA_BROKERS,
47
+ kafkaTopics: process.env?.KAFKA_TOPICS,
45
48
  kafkaLogsTopic: this.kafkaLogsTopic,
46
49
  baseApiUri: process.env.HTTPS === 'true' ? process.env.SYSTEM_HTTPS_BASE_API_URI : process.env.SYSTEM_BASE_API_URI,
47
50
  port: Number(process.env.PORT),
@@ -1,6 +1,7 @@
1
1
  import { AsyncLocalStorage } from 'node:async_hooks';
2
2
  import { ProtocolEnum } from '../../utils/index';
3
3
  import LoggerService from '../logger';
4
+ import SystemService from '../system';
4
5
  export declare const controllerContextStorage: AsyncLocalStorage<{
5
6
  protocol?: ProtocolEnum;
6
7
  ctx?: any;
@@ -63,9 +64,11 @@ declare abstract class Controller {
63
64
  protected get res(): CustomResponse;
64
65
  }
65
66
  export declare abstract class ControllerService extends Controller {
66
- load(props?: {
67
- type?: ProtocolEnum | ProtocolEnum[];
68
- }): Promise<void>;
67
+ protected systemService: SystemService;
68
+ constructor({ systemService }: {
69
+ systemService: SystemService;
70
+ });
71
+ load(): Promise<void>;
69
72
  schema({ checks, logic, response }: {
70
73
  checks?: (args: any) => Promise<any>;
71
74
  logic?: (args: any) => Promise<any>;
@@ -79,9 +79,14 @@ class Controller {
79
79
  }
80
80
  }
81
81
  export class ControllerService extends Controller {
82
- async load(props = {}) {
83
- if (props.type)
84
- this.supportedProtocols = Array.isArray(props.type) ? props.type : [props.type];
82
+ systemService;
83
+ constructor({ systemService }) {
84
+ super();
85
+ this.systemService = systemService;
86
+ }
87
+ async load() {
88
+ const protocols = this.systemService.tmp.configs.loaders.controller.protocols;
89
+ this.supportedProtocols = Array.isArray(protocols) ? protocols : [protocols];
85
90
  }
86
91
  async schema({ checks, logic, response }) {
87
92
  try {
@@ -1,11 +1,14 @@
1
+ import ConfigsService from "../configs";
1
2
  import { IService } from "../../utils";
3
+ import SystemService from "../system";
2
4
  export default class LocalizationsService implements IService {
5
+ #private;
3
6
  _instance: any;
4
- load: ({ loadPath, fallbackLang, preloadLang, }: {
5
- loadPath: string;
6
- fallbackLang: string;
7
- preloadLang: string;
8
- }) => any;
7
+ constructor({ systemService, configsService, }: {
8
+ systemService: SystemService;
9
+ configsService: ConfigsService;
10
+ });
11
+ load: ({}: {}) => any;
9
12
  i18next: ({ loadPath, fallbackLang, preloadLang, }: {
10
13
  loadPath?: string;
11
14
  fallbackLang?: string;
@@ -3,11 +3,18 @@ import Backend from 'i18next-fs-backend';
3
3
  import * as middleware from 'i18next-http-middleware';
4
4
  export default class LocalizationsService {
5
5
  _instance = null;
6
- load = ({ loadPath, fallbackLang, preloadLang, }) => {
6
+ #systemService;
7
+ #configsService;
8
+ constructor({ systemService, configsService, }) {
9
+ this.#systemService = systemService;
10
+ this.#configsService = configsService;
11
+ }
12
+ load = ({}) => {
13
+ const localization = this.#systemService.tmp.configs.loaders.localization;
7
14
  this.i18next({
8
- loadPath,
9
- fallbackLang,
10
- preloadLang,
15
+ loadPath: localization.loadPath,
16
+ fallbackLang: localization.fallbackLang,
17
+ preloadLang: localization.preloadLang,
11
18
  });
12
19
  };
13
20
  i18next = ({ loadPath, fallbackLang, preloadLang, }) => {
@@ -1,7 +1,9 @@
1
1
  import winston from "winston";
2
2
  import "winston-daily-rotate-file";
3
3
  import { AsyncLocalStorage } from "node:async_hooks";
4
+ import ConfigsService from "../configs";
4
5
  import { LoggerLayerEnum, IService } from "../../utils";
6
+ import SystemService from "../system";
5
7
  export interface ICustomLogger extends winston.Logger {
6
8
  critical: winston.LeveledLogMethod;
7
9
  http: winston.LeveledLogMethod;
@@ -20,10 +22,11 @@ export default class LoggerService implements IService {
20
22
  private kafkaLogsTopic;
21
23
  private isKafkaReady;
22
24
  winston: ICustomLogger;
23
- constructor({ configsService }: {
24
- configsService: any;
25
+ constructor({ systemService, configsService }: {
26
+ systemService: SystemService;
27
+ configsService: ConfigsService;
25
28
  });
26
- load: (config: Record<string, any>) => Promise<void>;
29
+ load: ({}: {}) => Promise<void>;
27
30
  winstonLoader: ({ loadPath, loggerLevel }: {
28
31
  loadPath: string;
29
32
  loggerLevel: string;
@@ -38,23 +38,27 @@ export default class LoggerService {
38
38
  kafkaLogsTopic = "";
39
39
  isKafkaReady = false;
40
40
  winston;
41
+ #systemService;
41
42
  #configsService;
42
- constructor({ configsService }) {
43
+ constructor({ systemService, configsService }) {
44
+ this.#systemService = systemService;
43
45
  this.#configsService = configsService;
44
46
  this.kafkaLogsTopic = this.#configsService?.all.kafkaLogsTopic;
45
47
  winston.addColors(customColors);
46
48
  this.winston = winston.createLogger({
47
- level: this.#configsService.all.systemLoggerLayer,
49
+ level: this.#configsService.all.systemLoggerLayer || 'info',
48
50
  levels: customLevels,
49
51
  format: this.getConsoleFormat(),
50
52
  transports: [new winston.transports.Console()]
51
53
  });
52
54
  }
53
- load = async (config) => {
54
- this.serviceName = config?.serviceName;
55
- const rawBrokers = this.#configsService.all.kafkaBrokers;
56
- const brokers = rawBrokers ? String(rawBrokers).split(",").map((b) => b.trim()) : [];
57
- if (brokers.length > 0) {
55
+ load = async ({}) => {
56
+ const loggersConfigs = this.#systemService.tmp.configs.loaders.loggers;
57
+ this.serviceName = this.#systemService.tmp.configs?.serviceName;
58
+ const { kafkaBrokers, isKafkaPassive } = this.#configsService.all;
59
+ const brokers = kafkaBrokers ? String(kafkaBrokers).split(",").map((b) => b.trim()) : [];
60
+ const isKafkaEnabled = isKafkaPassive === false && brokers.length > 0;
61
+ if (isKafkaEnabled) {
58
62
  const kafka = new Kafka({
59
63
  clientId: this.serviceName,
60
64
  brokers: brokers,
@@ -73,8 +77,8 @@ export default class LoggerService {
73
77
  }
74
78
  }
75
79
  this.winstonLoader({
76
- loadPath: config?.loadPath,
77
- loggerLevel: config?.loggerLevel
80
+ loadPath: path.join(this.#configsService.all.rootFolderPath, loggersConfigs?.loadPath),
81
+ loggerLevel: loggersConfigs?.loggerLevel
78
82
  });
79
83
  };
80
84
  winstonLoader = ({ loadPath, loggerLevel }) => {
@@ -100,7 +104,7 @@ export default class LoggerService {
100
104
  maxFiles: "14d"
101
105
  })
102
106
  ];
103
- if (this.kafkaProducer) {
107
+ if (this.isKafkaReady && this.kafkaProducer) {
104
108
  transports.push(new KafkaTransport({ level: loggerLevel }, this));
105
109
  }
106
110
  this.winston = winston.createLogger({
@@ -123,11 +127,6 @@ export default class LoggerService {
123
127
  if (store && store.has("correlationId")) {
124
128
  info.id = store.get("correlationId");
125
129
  }
126
- Object.keys(info).forEach(key => {
127
- if (info[key] instanceof Headers) {
128
- info[key] = Object.fromEntries(info[key].entries());
129
- }
130
- });
131
130
  return info;
132
131
  });
133
132
  getConsoleFormat() {
@@ -1,10 +1,13 @@
1
1
  import { IService } from "../../utils";
2
2
  export default class SystemService implements IService {
3
- _tmp: Record<string, any>;
3
+ protected _core: Record<string, any>;
4
+ protected _tmp: Record<string, any>;
4
5
  cwd: string;
5
- load: ({ tmp, }: {
6
- tmp: any;
6
+ load: ({ core }: {
7
+ core: any;
7
8
  }) => Promise<void>;
9
+ private initializeKafkaInfrastructure;
8
10
  private _systemLoader;
11
+ get core(): Record<string, any>;
9
12
  get tmp(): Record<string, any>;
10
13
  }
@@ -1,14 +1,69 @@
1
+ import { Kafka, logLevel } from "kafkajs";
2
+ import { Constants } from "../../utils";
1
3
  export default class SystemService {
4
+ _core = {};
2
5
  _tmp = {};
3
6
  cwd = process.cwd();
4
- load = async ({ tmp, }) => {
5
- this._tmp = tmp;
7
+ load = async ({ core }) => {
8
+ this._core = core;
9
+ this._tmp = this._core._;
10
+ await this.initializeKafkaInfrastructure();
6
11
  await this._systemLoader({});
7
12
  };
13
+ initializeKafkaInfrastructure = async () => {
14
+ const { kafkaBrokers, kafkaTopics, isKafkaPassive, serviceName } = {
15
+ isKafkaPassive: process.env.IS_KAFKA_PASSIVE === 'true' ? true : false,
16
+ kafkaBrokers: process.env?.KAFKA_BROKERS,
17
+ kafkaTopics: [
18
+ ...new Set([
19
+ Constants.kafkaLogsTopic,
20
+ ...(process.env.KAFKA_TOPICS?.split(',').map(t => t.trim()).filter(Boolean) || [])
21
+ ])
22
+ ],
23
+ serviceName: this._tmp.configs.service
24
+ };
25
+ if (isKafkaPassive === true || !kafkaBrokers)
26
+ return;
27
+ const brokers = String(kafkaBrokers).split(",").map(b => b.trim());
28
+ const topicsToCreate = Array.isArray(kafkaTopics) ? kafkaTopics : [];
29
+ if (topicsToCreate.length === 0)
30
+ return;
31
+ const kafka = new Kafka({
32
+ clientId: `${serviceName}`,
33
+ brokers,
34
+ logLevel: logLevel.NOTHING
35
+ });
36
+ const admin = kafka.admin();
37
+ try {
38
+ await admin.connect();
39
+ const existingTopics = await admin.listTopics();
40
+ const newTopics = topicsToCreate
41
+ .filter(topic => !existingTopics.includes(topic))
42
+ .map(topic => ({
43
+ topic,
44
+ numPartitions: 1,
45
+ replicationFactor: 1
46
+ }));
47
+ if (newTopics.length > 0) {
48
+ await admin.createTopics({
49
+ waitForLeaders: true,
50
+ topics: newTopics
51
+ });
52
+ }
53
+ }
54
+ catch (error) {
55
+ // => Error
56
+ }
57
+ finally {
58
+ await admin.disconnect();
59
+ }
60
+ };
8
61
  _systemLoader = async ({}) => {
9
- //console.log(this._tmp)
62
+ return;
10
63
  };
11
- // => getters
64
+ get core() {
65
+ return this._core;
66
+ }
12
67
  get tmp() {
13
68
  return this._tmp;
14
69
  }
@@ -1,20 +1,18 @@
1
1
  import path from 'path';
2
2
  import { SystemService, ConfigsService, LoggerService, EventsService, LocalizationsService, ClientsService, ControllerService } from '../loader';
3
- import { Constants, x, getTmp, } from '../utils';
3
+ import { Constants, getCore, x, } from '../utils';
4
4
  //
5
- let coreHasRun = false;
6
- export const core = getTmp();
5
+ export const core = getCore();
7
6
  export const coreInit = async (params) => {
8
7
  const { locales } = params;
9
8
  if (locales)
10
9
  globalThis.__LOCAL_MESSAGES__ = locales;
11
10
  };
11
+ let coreHasRun = false;
12
12
  const coreLoader = async ({}) => {
13
13
  if (coreHasRun)
14
14
  return {};
15
15
  try {
16
- const { configs } = core._;
17
- const rootFolderPath = configs.rootFolderPath;
18
16
  await (await x.load([
19
17
  path.join(__dirname, '..', 'loader', '**/*.{ts,js}'),
20
18
  ], {
@@ -24,22 +22,16 @@ const coreLoader = async ({}) => {
24
22
  {
25
23
  service: SystemService,
26
24
  props: {
27
- tmp: core._
25
+ core
28
26
  }
29
27
  },
30
28
  {
31
29
  service: ConfigsService,
32
- props: {
33
- ...(configs.loaders.configs.globalEnvFileName && { globalEnvFileName: configs.loaders.configs.globalEnvFileName })
34
- }
30
+ props: {}
35
31
  },
36
32
  {
37
33
  service: LoggerService,
38
- props: {
39
- loadPath: path.join(rootFolderPath, configs.loaders.loggers.loadPath),
40
- loggerLevel: configs.loaders.loggers.logLevel,
41
- serviceName: configs.service,
42
- }
34
+ props: {}
43
35
  },
44
36
  {
45
37
  service: EventsService,
@@ -47,17 +39,11 @@ const coreLoader = async ({}) => {
47
39
  },
48
40
  {
49
41
  service: LocalizationsService,
50
- props: {
51
- loadPath: path.join(rootFolderPath, configs.loaders.localization.loadPath),
52
- fallbackLang: configs.loaders.localization.fallbackLang,
53
- preloadLang: configs.loaders.localization.preloadLangs
54
- }
42
+ props: {}
55
43
  },
56
44
  {
57
45
  service: ControllerService,
58
- props: {
59
- type: configs.loaders.controller.protocols,
60
- }
46
+ props: {}
61
47
  },
62
48
  {
63
49
  service: ClientsService,
@@ -1,4 +1,4 @@
1
- export declare const getTmp: () => {
1
+ export declare const getCore: () => {
2
2
  _: any;
3
3
  };
4
4
  export declare const getTmpConfig: ({ root, tmpFileName, ext }: {
@@ -2,7 +2,7 @@ import path from "path";
2
2
  import fs from 'fs';
3
3
  import Handlebars from 'handlebars';
4
4
  import { Constants, TmpFileLoader } from "../../index.js";
5
- export const getTmp = () => {
5
+ export const getCore = () => {
6
6
  const ownerTmpFilePath = findFileRecursively(".", Constants.defaultTmpFileName, Constants.defaultTmpFileExt);
7
7
  if (!ownerTmpFilePath) {
8
8
  throw new Error(`${Constants.defaultTmpFileName} file not found`);
@@ -1,5 +1,5 @@
1
1
  export { default as pic } from "picocolors";
2
- export * from './tmp/index';
2
+ export * from './core/index';
3
3
  export * from './path/index';
4
4
  export * from './is/index';
5
5
  export * from './id/index';
@@ -1,5 +1,5 @@
1
1
  export { default as pic } from "picocolors";
2
- export * from './tmp/index';
2
+ export * from './core/index';
3
3
  export * from './path/index';
4
4
  export * from './is/index';
5
5
  export * from './id/index';
@@ -76,15 +76,9 @@ export declare enum TimezoneEnum {
76
76
  EtcUTC = "Etc/UTC",
77
77
  EtcGMT = "Etc/GMT"
78
78
  }
79
- export declare enum WsActionsEnum {
80
- REGISTER = "register",
81
- JOIN = "join",
82
- MESSAGE = "message"
83
- }
84
- export declare enum WsKeyEnum {
85
- BUS = "WS_BUS",
86
- USER = "ws:user",
87
- ROOM = "ws:room"
79
+ export declare enum ModeEnum {
80
+ MONOLITIC = "monolitic",
81
+ MICRO_SERVICE = "micro_service"
88
82
  }
89
83
  export declare enum TokensEnum {
90
84
  INTERNAL_API_TOKEN = "internal_api_key",
@@ -90,18 +90,11 @@ export var TimezoneEnum;
90
90
  TimezoneEnum["EtcUTC"] = "Etc/UTC";
91
91
  TimezoneEnum["EtcGMT"] = "Etc/GMT";
92
92
  })(TimezoneEnum || (TimezoneEnum = {}));
93
- export var WsActionsEnum;
94
- (function (WsActionsEnum) {
95
- WsActionsEnum["REGISTER"] = "register";
96
- WsActionsEnum["JOIN"] = "join";
97
- WsActionsEnum["MESSAGE"] = "message";
98
- })(WsActionsEnum || (WsActionsEnum = {}));
99
- export var WsKeyEnum;
100
- (function (WsKeyEnum) {
101
- WsKeyEnum["BUS"] = "WS_BUS";
102
- WsKeyEnum["USER"] = "ws:user";
103
- WsKeyEnum["ROOM"] = "ws:room";
104
- })(WsKeyEnum || (WsKeyEnum = {}));
93
+ export var ModeEnum;
94
+ (function (ModeEnum) {
95
+ ModeEnum["MONOLITIC"] = "monolitic";
96
+ ModeEnum["MICRO_SERVICE"] = "micro_service";
97
+ })(ModeEnum || (ModeEnum = {}));
105
98
  export var TokensEnum;
106
99
  (function (TokensEnum) {
107
100
  TokensEnum["INTERNAL_API_TOKEN"] = "internal_api_key";
package/x/tmp.yml CHANGED
@@ -21,7 +21,7 @@ configs:
21
21
  - tr
22
22
 
23
23
  controller:
24
- protocol: http
24
+ protocols: http
25
25
 
26
26
  end:
27
27
  version: 1