@xrystal/core 3.10.2 → 3.10.4

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/bin/main-cli.js CHANGED
@@ -22,6 +22,12 @@ import { findFileRecursively, resolveObjWithHandlebars } from "./helpers/index.m
22
22
  const setupCLI = async () => {
23
23
  const cli = new Command()
24
24
 
25
+ const isBun = !!process.versions.bun
26
+ const runtimeName = isBun ? "Bun" : "Node.js"
27
+ const packageManager = isBun ? "bun" : "npm"
28
+ const installCommand = isBun ? "bun install" : "npm install"
29
+ const devCommand = isBun ? "bun run dev:local" : "npm run dev:local"
30
+
25
31
  try {
26
32
  let ownerTmpFilePath = findFileRecursively(".", tmpFileDefaultName, tmpFileDefaultExt)
27
33
 
@@ -54,7 +60,7 @@ const setupCLI = async () => {
54
60
 
55
61
  cli
56
62
  .command("create <project-name> [target-path]")
57
- .description("Project initializer with git setup")
63
+ .description(`Project initializer using ${runtimeName}`)
58
64
  .action(async (projectName, targetDir) => {
59
65
  let targetPath = ""
60
66
  const isCurrentDir = projectName === "."
@@ -75,7 +81,7 @@ const setupCLI = async () => {
75
81
  fs.mkdirSync(targetPath, { recursive: true })
76
82
  }
77
83
 
78
- const spinner = ora("Cloning and initializing git...").start()
84
+ const spinner = ora(`${runtimeName} environment detected. Cloning template...`).start()
79
85
 
80
86
  try {
81
87
  execSync(`git clone --depth 1 ${templateRepoUri} "${targetPath}"`, { stdio: "ignore" })
@@ -91,9 +97,9 @@ const setupCLI = async () => {
91
97
  }
92
98
 
93
99
  spinner.succeed(chalk.green("Template cloned and git initialized!"))
94
- console.log(chalk.blue(`\nšŸ“¦ Installing dependencies with bun...`))
100
+ console.log(chalk.blue(`\nšŸ“¦ Installing dependencies with ${packageManager}...`))
95
101
 
96
- execSync("bun install", { cwd: targetPath, stdio: "inherit" })
102
+ execSync(installCommand, { cwd: targetPath, stdio: "inherit" })
97
103
 
98
104
  console.log(chalk.green("\nāœ… Done!"))
99
105
 
@@ -102,7 +108,7 @@ const setupCLI = async () => {
102
108
  console.log(chalk.cyan(`\n cd ${relativePath}`))
103
109
  }
104
110
 
105
- console.log(chalk.cyan(` bun run dev:local`))
111
+ console.log(chalk.cyan(` ${devCommand}`))
106
112
 
107
113
  } catch (err) {
108
114
  spinner.fail(chalk.red("Failed!"))
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "author": "Yusuf Yasir KAYGUSUZ",
3
3
  "name": "@xrystal/core",
4
- "version": "3.10.2",
4
+ "version": "3.10.4",
5
5
  "description": "Project core for xrystal",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -37,8 +37,8 @@
37
37
  "start": "bun --env-file=../infrastructer/x/environments/.global.env --env-file=../infrastructer/x/environments/.dev.env source/index.js"
38
38
  },
39
39
  "dependencies": {
40
- "@types/bcrypt": "^5.0.2",
41
40
  "@types/yaml": "^1.9.7",
41
+ "awilix": "^12.0.5",
42
42
  "chalk": "^5.6.2",
43
43
  "commander": "^13.0.0",
44
44
  "ejs": "^3.1.9",
@@ -1,9 +1,10 @@
1
1
  import ConfigsService from '../configs';
2
2
  export default class ClientsService {
3
3
  #private;
4
+ constructor({ configsService }: {
5
+ configsService: ConfigsService;
6
+ });
4
7
  static get instances(): Record<string, any>;
5
8
  static set instances(value: Record<string, any>);
6
- load({ configs }: {
7
- configs: ConfigsService;
8
- }): Promise<void>;
9
+ load({}: {}): Promise<void>;
9
10
  }
@@ -1,16 +1,20 @@
1
1
  import { BaseApiClient, CoreServiceEnum } from '../../utils/index';
2
2
  export default class ClientsService {
3
3
  static #services = {};
4
+ #configs;
5
+ constructor({ configsService }) {
6
+ this.#configs = configsService;
7
+ }
4
8
  static get instances() {
5
9
  return this.#services;
6
10
  }
7
11
  static set instances(value) {
8
12
  this.#services = { ...this.#services, ...value };
9
13
  }
10
- async load({ configs }) {
14
+ async load({}) {
11
15
  const baseClient = new BaseApiClient({
12
16
  clientName: CoreServiceEnum.BASE_API_CLIENT,
13
- baseURL: configs.all.baseApiUri || ''
17
+ baseURL: this.#configs.all.baseApiUri || ''
14
18
  });
15
19
  ClientsService.instances[CoreServiceEnum.BASE_API_CLIENT] = baseClient;
16
20
  }
@@ -1,11 +1,11 @@
1
1
  import SystemService from '../system/index';
2
2
  export default class ConfigsService {
3
+ #private;
3
4
  private config;
4
- protected _systemService: SystemService;
5
5
  publicFolderName: string;
6
- load: ({ tmp, systemService }: {
7
- tmp: any;
6
+ constructor({ systemService }: {
8
7
  systemService: SystemService;
9
- }) => void;
8
+ });
9
+ load: ({}: {}) => void;
10
10
  get all(): Record<string, any>;
11
11
  }
@@ -1,10 +1,14 @@
1
1
  import path from 'node:path';
2
+ import { publicFolderName } from 'source/utils';
2
3
  export default class ConfigsService {
3
4
  config = {};
4
- _systemService;
5
- publicFolderName = 'public';
6
- load = ({ tmp, systemService }) => {
7
- this._systemService = systemService;
5
+ publicFolderName = publicFolderName;
6
+ #systemService;
7
+ constructor({ systemService }) {
8
+ this.#systemService = systemService;
9
+ }
10
+ load = ({}) => {
11
+ const tmp = this.#systemService.tmp;
8
12
  const rawConfigs = tmp?.configs || tmp?.configs || {};
9
13
  this.config = {
10
14
  debug: process.env.SYSTEM_LOGGER_LAYER,
@@ -1,7 +1,10 @@
1
1
  import LoggerService from '../logger/index';
2
2
  export default class EventsService {
3
- private logger;
4
- load: ({ logger, }: {
3
+ #private;
4
+ constructor({ loggerService }: {
5
+ loggerService: LoggerService;
6
+ });
7
+ load: ({}: {
5
8
  logger: LoggerService;
6
9
  }) => any;
7
10
  private _globalLoader;
@@ -1,19 +1,21 @@
1
1
  import { LoggerLayerEnum } from '../../utils/index';
2
2
  export default class EventsService {
3
- logger;
4
- load = ({ logger, }) => {
5
- this.logger = logger;
3
+ #loggerService;
4
+ constructor({ loggerService }) {
5
+ this.#loggerService = loggerService;
6
+ }
7
+ load = ({}) => {
6
8
  this._globalLoader();
7
9
  };
8
10
  _globalLoader = () => {
9
11
  process.on("uncaughtException", (exception) => {
10
- this.logger.winston.log({
12
+ this.#loggerService.winston.log({
11
13
  level: LoggerLayerEnum[LoggerLayerEnum.CRITICAL].toLowerCase(),
12
14
  message: `UncaughtException: ${exception}`,
13
15
  });
14
16
  });
15
17
  process.on("unhandledRejection", (exception) => {
16
- this.logger.winston.log({
18
+ this.#loggerService.winston.log({
17
19
  level: LoggerLayerEnum[LoggerLayerEnum.CRITICAL].toLowerCase(),
18
20
  message: `UnhandledRejection: ${exception}`,
19
21
  });
@@ -1,22 +1,25 @@
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
  interface CustomLogger extends winston.Logger {
5
6
  critical: winston.LeveledLogMethod;
6
7
  http: winston.LeveledLogMethod;
7
8
  }
8
9
  export default class LoggerService {
10
+ #private;
9
11
  static readonly storage: AsyncLocalStorage<Map<string, string>>;
10
12
  private serviceName;
11
- private environment;
12
13
  private kafkaProducer;
13
14
  private kafkaTopic;
14
15
  private isKafkaReady;
16
+ constructor({ configsService }: {
17
+ configsService: ConfigsService;
18
+ });
15
19
  private safeReplacer;
16
20
  private getTracingFormat;
17
21
  private getConsoleFormat;
18
22
  winston: CustomLogger;
19
- constructor();
20
23
  runWithId: <T>(id: string, callback: () => T) => T;
21
24
  load: (config: Record<string, any>) => Promise<void>;
22
25
  winstonLoader: ({ loadPath, loggerLevel }: {
@@ -34,10 +34,14 @@ const customColors = {
34
34
  export default class LoggerService {
35
35
  static storage = new AsyncLocalStorage();
36
36
  serviceName = "";
37
- environment = "";
38
37
  kafkaProducer = null;
39
38
  kafkaTopic = "";
40
39
  isKafkaReady = false;
40
+ #configsService;
41
+ constructor({ configsService }) {
42
+ this.#configsService = configsService;
43
+ winston.addColors(customColors);
44
+ }
41
45
  safeReplacer = (key, value) => {
42
46
  if (value instanceof Headers)
43
47
  return Object.fromEntries(value.entries());
@@ -72,9 +76,6 @@ export default class LoggerService {
72
76
  format: this.getConsoleFormat(),
73
77
  transports: [new winston.transports.Console()]
74
78
  });
75
- constructor() {
76
- winston.addColors(customColors);
77
- }
78
79
  runWithId = (id, callback) => {
79
80
  const store = new Map();
80
81
  store.set("correlationId", id);
@@ -82,7 +83,6 @@ export default class LoggerService {
82
83
  };
83
84
  load = async (config) => {
84
85
  this.serviceName = config?.serviceName || "service";
85
- this.environment = config?.env || "dev";
86
86
  this.kafkaTopic = config?.kafkaTopic || "logs";
87
87
  const rawBrokers = config?.kafkaBrokers;
88
88
  const brokers = rawBrokers ? String(rawBrokers).split(",").map((b) => b.trim()) : [];
@@ -100,7 +100,6 @@ export default class LoggerService {
100
100
  try {
101
101
  await this.kafkaProducer?.connect();
102
102
  this.isKafkaReady = true;
103
- this.winston.info("Kafka connected successfully");
104
103
  }
105
104
  catch (err) {
106
105
  this.isKafkaReady = false;
@@ -163,7 +162,7 @@ export default class LoggerService {
163
162
  ...rest,
164
163
  timestamp: new Date().toISOString(),
165
164
  id: id || null,
166
- env: this.environment
165
+ env: this.#configsService.all.env
167
166
  }, this.safeReplacer)
168
167
  }]
169
168
  });
@@ -1,8 +1,8 @@
1
1
  export default class SystemService {
2
- private static _tmp;
2
+ _tmp: Record<string, any>;
3
3
  load: ({ tmp, }: {
4
4
  tmp: any;
5
5
  }) => Promise<void>;
6
6
  private _systemLoader;
7
- static get tmp(): any;
7
+ get tmp(): Record<string, any>;
8
8
  }
@@ -1,14 +1,14 @@
1
1
  export default class SystemService {
2
- static _tmp;
2
+ _tmp = {};
3
3
  load = async ({ tmp, }) => {
4
- SystemService._tmp = tmp;
4
+ this._tmp = tmp;
5
5
  await this._systemLoader({});
6
6
  };
7
7
  _systemLoader = async ({}) => {
8
8
  //console.log(this._tmp)
9
9
  };
10
10
  // => getters
11
- static get tmp() {
12
- return SystemService._tmp;
11
+ get tmp() {
12
+ return this._tmp;
13
13
  }
14
14
  }
@@ -24,42 +24,48 @@ const coreLoader = async ({}) => {
24
24
  LocalizationsService,
25
25
  ClientsService
26
26
  ];
27
- services.forEach(service => x.set({ service, reference: service }));
28
- const system = x.get(SystemService);
29
- const configService = x.get(ConfigsService);
30
- const logger = x.get(LoggerService);
31
- const events = x.get(EventsService);
32
- const i18n = x.get(LocalizationsService);
33
- const clientsService = x.get(ClientsService);
34
- await system.load({
35
- tmp: core._
36
- });
37
- configService.load({
38
- tmp: core._,
39
- systemService: system,
40
- ...(configs.loaders.configs.globalEnvFileName && { globalEnvFileName: configs.loaders.configs.globalEnvFileName })
41
- });
42
- await logger.load({
43
- loadPath: path.join(rootFolderPath, configs.loaders.loggers.loadPath),
44
- loggerLevel: systemLoggerLayer ?? configs.loaders.loggers.logLevel,
45
- serviceName: configs.service,
46
- env: process.env.NODE_ENV,
47
- kafkaBrokers: kafkaBrokers ?? "",
48
- kafkaTopic: configs.loaders.loggers.topic
49
- });
50
- await events.load({
51
- logger
52
- });
53
- await i18n.load({
54
- loadPath: path.resolve(rootFolderPath, configs.loaders.localization.loadPath),
55
- fallbackLang: configs.loaders.localization.fallbackLang,
56
- preloadLang: configs.loaders.localization.preloadLangs
57
- });
58
- await clientsService.load({
59
- configs: configService,
60
- });
27
+ x.registerServices(services);
28
+ x.initialize([
29
+ {
30
+ service: SystemService,
31
+ props: {
32
+ tmp: core._
33
+ }
34
+ },
35
+ {
36
+ service: ConfigsService,
37
+ props: {
38
+ ...(configs.loaders.configs.globalEnvFileName && { globalEnvFileName: configs.loaders.configs.globalEnvFileName })
39
+ }
40
+ },
41
+ {
42
+ service: LoggerService,
43
+ props: {
44
+ loadPath: path.join(rootFolderPath, configs.loaders.loggers.loadPath),
45
+ loggerLevel: systemLoggerLayer ?? configs.loaders.loggers.logLevel,
46
+ serviceName: configs.service,
47
+ kafkaBrokers: kafkaBrokers ?? "",
48
+ kafkaTopic: configs.loaders.loggers.topic
49
+ }
50
+ },
51
+ {
52
+ service: EventsService,
53
+ props: {}
54
+ },
55
+ {
56
+ service: LocalizationsService,
57
+ props: {
58
+ loadPath: path.resolve(rootFolderPath, configs.loaders.localization.loadPath),
59
+ fallbackLang: configs.loaders.localization.fallbackLang,
60
+ preloadLang: configs.loaders.localization.preloadLangs
61
+ }
62
+ },
63
+ {
64
+ service: ClientsService,
65
+ props: {}
66
+ },
67
+ ]);
61
68
  coreHasRun = true;
62
- return {};
63
69
  }
64
70
  catch (error) {
65
71
  const errorMessage = error instanceof Error ? error.message : String(error);
@@ -6,3 +6,4 @@ export declare const defaultTmpFilePath: string;
6
6
  export declare const defaultOwnerTmpFilePath: string;
7
7
  export declare const systemLoggerLayer: string;
8
8
  export declare const kafkaBrokers: string;
9
+ export declare const publicFolderName = "public";
@@ -8,3 +8,4 @@ export const defaultTmpFilePath = path.resolve(__dirname(import.meta.url), `../.
8
8
  export const defaultOwnerTmpFilePath = path.resolve(`./${tmpFileDefaultMainFolderName}/${tmpFileDefaultName}.yml`);
9
9
  export const systemLoggerLayer = process.env.SYSTEM_LOGGER_LAYER;
10
10
  export const kafkaBrokers = process.env?.KAFKA_BROKERS;
11
+ export const publicFolderName = 'public';
@@ -0,0 +1,12 @@
1
+ export declare class Locator {
2
+ private _context;
3
+ constructor({}: {});
4
+ set: <T extends new (...args: any[]) => any>({ service, reference, args }: {
5
+ service: T;
6
+ reference: T;
7
+ args?: ConstructorParameters<T>;
8
+ }) => void;
9
+ get: <T>(service: new (...args: any) => T) => T;
10
+ }
11
+ declare const _default: Locator;
12
+ export default _default;
@@ -0,0 +1,16 @@
1
+ // => // X Service Locator
2
+ export class Locator {
3
+ _context = new Map();
4
+ constructor({}) {
5
+ }
6
+ set = ({ service, reference, args }) => {
7
+ this._context.set(service, new reference(...(args || [])));
8
+ };
9
+ get = (service) => {
10
+ if (!this._context.has(service)) {
11
+ throw new Error(`${service} not found in context.`);
12
+ }
13
+ return this._context.get(service);
14
+ };
15
+ }
16
+ export default new Locator({});
@@ -1,4 +1,10 @@
1
1
  import { ConfigsService, LoggerService } from '../../../loader';
2
+ type CustomRequestOptions = Omit<RequestInit, 'body'> & {
3
+ body?: any;
4
+ version?: string;
5
+ retries?: number;
6
+ debug?: boolean;
7
+ };
2
8
  export declare class ClientStore {
3
9
  private static _store;
4
10
  static get(clientName: string): any;
@@ -30,11 +36,7 @@ export declare abstract class Client {
30
36
  }
31
37
  export declare class BaseApiClient extends Client {
32
38
  constructor(config: any);
33
- request(path: string, options?: RequestInit & {
34
- version?: string;
35
- retries?: number;
36
- debug?: boolean;
37
- }): Promise<Response>;
39
+ request(path: string, options?: CustomRequestOptions): Promise<Response>;
38
40
  private _execute;
39
41
  }
40
42
  export declare abstract class AuthenticatedApiClient extends BaseApiClient {
@@ -53,3 +55,4 @@ export declare class SoapClient extends Client {
53
55
  constructor(config: any);
54
56
  call(methodName: string, args: any): Promise<any>;
55
57
  }
58
+ export {};
@@ -105,21 +105,21 @@ export class BaseApiClient extends Client {
105
105
  headers.set('x-internal-client', this.clientName);
106
106
  }
107
107
  const isDebugMode = options.debug !== undefined ? options.debug : this.debug;
108
+ const { version, retries, debug, ...fetchOptions } = options;
109
+ if (fetchOptions.body && typeof fetchOptions.body === 'object' && !(fetchOptions.body instanceof FormData)) {
110
+ fetchOptions.body = JSON.stringify(fetchOptions.body);
111
+ }
108
112
  if (isDebugMode) {
109
113
  const logPayload = {
110
114
  method: options.method || 'GET',
111
115
  url,
112
116
  headers: Object.fromEntries(headers.entries()),
113
- body: options.body ? (typeof options.body === 'string' ? JSON.parse(options.body) : options.body) : null
117
+ body: options.body
114
118
  };
115
119
  this.logger.winston.info(`${this.clientName} Request Details: ${JSON.stringify(logPayload, null, 2)}`);
116
120
  }
117
121
  const controller = new AbortController();
118
122
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
119
- const { version, retries, debug, ...fetchOptions } = options;
120
- if (fetchOptions.body && typeof fetchOptions.body === 'object') {
121
- fetchOptions.body = JSON.stringify(fetchOptions.body);
122
- }
123
123
  const response = await fetch(url, { ...fetchOptions, headers, signal: controller.signal });
124
124
  clearTimeout(timeoutId);
125
125
  return response;
@@ -1,12 +1,18 @@
1
1
  export declare class X {
2
- private _context;
3
- constructor({}: {});
4
- set: <T extends new (...args: any[]) => any>({ service, reference, args }: {
5
- service: T;
6
- reference: T;
7
- args?: ConstructorParameters<T>;
8
- }) => void;
9
- get: <T>(service: new (...args: any) => T) => T;
2
+ private container;
3
+ constructor();
4
+ registerService(ServiceClass: any): void;
5
+ registerServices(services: any[]): void;
6
+ registerInstance(name: string, instance: any): void;
7
+ initialize(input: {
8
+ service: any;
9
+ props?: any;
10
+ } | {
11
+ service: any;
12
+ props?: any;
13
+ }[]): Promise<void>;
14
+ get<T>(name: string | any): T;
15
+ get cradle(): any;
10
16
  }
11
17
  declare const _default: X;
12
18
  export default _default;
@@ -1,16 +1,45 @@
1
- // => // X Service Locator
1
+ import { createContainer, asClass, asValue, InjectionMode } from 'awilix';
2
2
  export class X {
3
- _context = new Map();
4
- constructor({}) {
3
+ container;
4
+ constructor() {
5
+ this.container = createContainer({
6
+ injectionMode: InjectionMode.PROXY,
7
+ strict: true
8
+ });
5
9
  }
6
- set = ({ service, reference, args }) => {
7
- this._context.set(service, new reference(...(args || [])));
8
- };
9
- get = (service) => {
10
- if (!this._context.has(service)) {
11
- throw new Error(`${service} not found in context.`);
10
+ registerService(ServiceClass) {
11
+ const name = ServiceClass.name.charAt(0).toLowerCase() + ServiceClass.name.slice(1);
12
+ this.container.register({
13
+ [name]: asClass(ServiceClass).singleton()
14
+ });
15
+ }
16
+ registerServices(services) {
17
+ services.forEach(ServiceClass => {
18
+ this.registerService(ServiceClass);
19
+ });
20
+ }
21
+ registerInstance(name, instance) {
22
+ this.container.register({
23
+ [name]: asValue(instance)
24
+ });
25
+ }
26
+ async initialize(input) {
27
+ const items = Array.isArray(input) ? input : [input];
28
+ for (const item of items) {
29
+ const instance = this.get(item.service);
30
+ if (instance && typeof instance.load === 'function') {
31
+ await instance.load(item.props);
32
+ }
12
33
  }
13
- return this._context.get(service);
14
- };
34
+ }
35
+ get(name) {
36
+ const resolveName = typeof name === 'function'
37
+ ? name.name.charAt(0).toLowerCase() + name.name.slice(1)
38
+ : name;
39
+ return this.container.resolve(resolveName);
40
+ }
41
+ get cradle() {
42
+ return this.container.cradle;
43
+ }
15
44
  }
16
- export default new X({});
45
+ export default new X();
@@ -1,8 +1,9 @@
1
1
  import x, { X } from './classes/class.x';
2
+ import locator, { Locator } from './classes/class.service-locator';
2
3
  export * from './classes/class.tmp-file-loader';
3
4
  export * from './classes/class.controller';
4
5
  export * from './classes/class.response';
5
6
  export * from './classes/class.services';
6
7
  export * from './types';
7
8
  export * from './enums';
8
- export { x, X };
9
+ export { x, X, locator, Locator };
@@ -1,8 +1,9 @@
1
1
  import x, { X } from './classes/class.x';
2
+ import locator, { Locator } from './classes/class.service-locator';
2
3
  export * from './classes/class.tmp-file-loader';
3
4
  export * from './classes/class.controller';
4
5
  export * from './classes/class.response';
5
6
  export * from './classes/class.services';
6
7
  export * from './types';
7
8
  export * from './enums';
8
- export { x, X };
9
+ export { x, X, locator, Locator };