@xrystal/core 3.8.9 → 3.9.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/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "author": "Yusuf Yasir KAYGUSUZ",
3
3
  "name": "@xrystal/core",
4
- "version": "3.8.9",
4
+ "version": "3.9.1",
5
5
  "description": "Project core for xrystal",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -49,8 +49,6 @@
49
49
  "i18next-http-middleware": "^3.8.2",
50
50
  "kafkajs": "^2.2.4",
51
51
  "moment-timezone": "^0.6.0",
52
- "nodemailer": "^7.0.11",
53
- "nodemailer-express-handlebars": "^7.0.0",
54
52
  "ora": "^9.0.0",
55
53
  "picocolors": "^1.1.1",
56
54
  "qs": "^6.14.1",
@@ -64,8 +62,6 @@
64
62
  "@types/bun": "^1.3.5",
65
63
  "@types/minimist": "^1.2.5",
66
64
  "@types/node": "^25.0.6",
67
- "@types/nodemailer": "^7.0.4",
68
- "@types/nodemailer-express-handlebars": "^4.0.6",
69
65
  "typescript": "^5.5.3"
70
66
  }
71
67
  }
@@ -1,7 +1,8 @@
1
1
  import ConfigsService from '../configs';
2
2
  export default class ClientsService {
3
- static services: Record<string, any>;
4
- baseApiClientName: string;
3
+ #private;
4
+ static get instances(): Record<string, any>;
5
+ static set instances(value: Record<string, any>);
5
6
  load({ configs }: {
6
7
  configs: ConfigsService;
7
8
  }): Promise<void>;
@@ -1,12 +1,17 @@
1
- import { BaseApiClient } from '../../utils/index';
1
+ import { BaseApiClient, CoreServiceEnum } from '../../utils/index';
2
2
  export default class ClientsService {
3
- static services = {};
4
- baseApiClientName = 'base-api-client';
3
+ static #services = {};
4
+ static get instances() {
5
+ return this.#services;
6
+ }
7
+ static set instances(value) {
8
+ this.#services = { ...this.#services, ...value };
9
+ }
5
10
  async load({ configs }) {
6
- const baseApiClient = new BaseApiClient({
7
- clientName: this.baseApiClientName,
11
+ const baseClient = new BaseApiClient({
12
+ clientName: CoreServiceEnum.BASE_API_CLIENT,
8
13
  baseURL: configs.all.baseApiUri || ''
9
14
  });
10
- ClientsService.services[this.baseApiClientName] = baseApiClient;
15
+ ClientsService.instances[CoreServiceEnum.BASE_API_CLIENT] = baseClient;
11
16
  }
12
17
  }
@@ -2,6 +2,7 @@ import { LoggerLayerEnum } from '../../utils/index';
2
2
  export default class EventsService {
3
3
  logger;
4
4
  load = ({ logger, }) => {
5
+ this.logger = logger;
5
6
  this._globalLoader();
6
7
  };
7
8
  _globalLoader = () => {
@@ -1,66 +1,42 @@
1
- import nodemailer from 'nodemailer';
2
1
  import { ConfigsService, LoggerService } from '../../../loader';
3
- export declare abstract class Service {
2
+ export declare class ClientStore {
3
+ private static _store;
4
+ static get(clientName: string): any;
5
+ static set(clientName: string, data: Record<string, any>): void;
6
+ }
7
+ export declare abstract class Client {
4
8
  protected configService: ConfigsService;
5
9
  protected logger: LoggerService;
6
10
  clientName: string;
7
11
  protected baseURL: string;
8
12
  protected version: string | null;
9
13
  protected timeout: number;
10
- constructor({ clientName, baseURL, version, timeout }: {
11
- clientName: string;
12
- baseURL: string;
13
- version?: string;
14
- timeout?: number;
15
- });
14
+ protected authConfigs: any;
15
+ constructor({ clientName, baseURL, version, timeout, auth }: any);
16
+ protected resolvePath(obj: any, path: string): any;
16
17
  static cryptoHashGenerate: ({ algorithm, input, digest }: {
17
18
  algorithm: string;
18
19
  input: string;
19
20
  digest?: string;
20
21
  }) => string;
21
- static generateRandomNumber: ({ length }: {
22
- length?: number;
23
- }) => string;
24
22
  }
25
- export declare class BaseApiClient extends Service {
26
- constructor(config: {
27
- clientName: string;
28
- baseURL: string;
29
- version?: string;
30
- timeout?: number;
31
- });
23
+ export declare class BaseApiClient extends Client {
24
+ constructor(config: any);
32
25
  request(path: string, options?: RequestInit & {
33
26
  version?: string;
34
27
  }): Promise<Response>;
35
28
  }
36
29
  export declare abstract class AuthenticatedApiClient extends BaseApiClient {
37
- accessToken?: string;
38
- constructor(config: {
39
- clientName: string;
40
- baseURL: string;
41
- version?: string;
42
- timeout?: number;
43
- });
30
+ private _authPromise;
31
+ constructor(config: any);
44
32
  request(path: string, options?: RequestInit & {
45
33
  version?: string;
46
34
  }): Promise<Response>;
47
- abstract authentication(): Promise<any>;
48
- }
49
- export declare class EmailClient extends Service {
50
- constructor(config: {
51
- clientName: string;
52
- baseURL: string;
53
- version?: string;
54
- timeout?: number;
55
- });
56
- nodemailerLoader(config: any): nodemailer.Transporter<import("nodemailer/lib/smtp-transport").SentMessageInfo, import("nodemailer/lib/smtp-transport").Options>;
35
+ private _synchronizedAuthentication;
36
+ private internalLogin;
37
+ authentication(): Promise<any>;
57
38
  }
58
- export declare class SoapClient extends Service {
59
- constructor(config: {
60
- clientName: string;
61
- baseURL: string;
62
- version?: string;
63
- timeout?: number;
64
- });
39
+ export declare class SoapClient extends Client {
40
+ constructor(config: any);
65
41
  call(methodName: string, args: any): Promise<any>;
66
42
  }
@@ -1,59 +1,66 @@
1
- import { createHash } from 'node:crypto';
2
- import path from 'node:path';
3
- import nodemailer from 'nodemailer';
4
- import hbs from 'nodemailer-express-handlebars';
1
+ import { createHash, createHmac } from 'node:crypto';
5
2
  import soap from 'soap';
6
3
  import { ConfigsService, LoggerService } from '../../../loader';
7
- import { TokensEnum, x } from '../../index';
8
- export class Service {
4
+ import { x } from '../../index';
5
+ export class ClientStore {
6
+ static _store = {};
7
+ static get(clientName) { return this._store[clientName] || {}; }
8
+ static set(clientName, data) {
9
+ this._store[clientName] = { ...this._store[clientName], ...data };
10
+ }
11
+ }
12
+ export class Client {
9
13
  configService = x.get(ConfigsService);
10
14
  logger = x.get(LoggerService);
11
15
  clientName;
12
16
  baseURL;
13
17
  version = null;
14
18
  timeout = 15000;
15
- constructor({ clientName, baseURL, version, timeout }) {
19
+ authConfigs;
20
+ constructor({ clientName, baseURL, version, timeout, auth }) {
16
21
  this.clientName = clientName;
17
22
  this.baseURL = baseURL;
18
23
  this.version = version || null;
24
+ this.authConfigs = auth;
19
25
  if (timeout)
20
26
  this.timeout = timeout;
27
+ if (auth?.token) {
28
+ ClientStore.set(clientName, { accessToken: auth.token });
29
+ }
30
+ }
31
+ resolvePath(obj, path) {
32
+ return path.split('.').reduce((prev, curr) => prev ? prev[curr] : undefined, obj);
21
33
  }
22
34
  static cryptoHashGenerate = ({ algorithm, input, digest = 'hex' }) => {
23
35
  return createHash(algorithm).update(input).digest(digest);
24
36
  };
25
- static generateRandomNumber = ({ length = 10 }) => {
26
- let result = '';
27
- for (let i = 0; i < length; i++) {
28
- result += Math.floor(Math.random() * 10).toString();
29
- }
30
- return result;
31
- };
32
37
  }
33
- export class BaseApiClient extends Service {
34
- constructor(config) {
35
- super(config);
36
- }
37
- // version opsiyonel yapıldı, default constructor'dan gelir ama istek anında ezilebilir
38
+ export class BaseApiClient extends Client {
39
+ constructor(config) { super(config); }
38
40
  async request(path, options = {}) {
39
41
  const base = this.baseURL.replace(/\/$/, '');
40
- // İstekte versiyon varsa onu, yoksa sınıftaki default versiyonu kullan
41
42
  const activeVersion = options.version !== undefined ? options.version : this.version;
42
43
  const ver = activeVersion ? `/${activeVersion.replace(/^\//, '')}` : '';
43
44
  const url = `${base}${ver}${path}`;
44
45
  const store = LoggerService.storage.getStore();
45
46
  const correlationId = store?.get('correlationId');
46
47
  const headers = new Headers(options.headers || {});
47
- if (!headers.has('Content-Type'))
48
- headers.set('Content-Type', 'application/json');
48
+ headers.set('Content-Type', 'application/json');
49
49
  if (correlationId)
50
50
  headers.set('x-correlation-id', correlationId);
51
- if (process.env.INTERNAL_SECRET)
52
- headers.set('X-Internal-Secret', process.env.INTERNAL_SECRET);
51
+ const systemSecret = this.configService.all.internalSecret || process.env.INTERNAL_SECRET;
52
+ if (systemSecret) {
53
+ const timestamp = Date.now().toString();
54
+ const signature = createHmac('sha256', systemSecret)
55
+ .update(timestamp + this.clientName)
56
+ .digest('hex');
57
+ headers.set('x-internal-signature', signature);
58
+ headers.set('x-internal-timestamp', timestamp);
59
+ headers.set('x-internal-client', this.clientName);
60
+ }
53
61
  const controller = new AbortController();
54
62
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
55
63
  try {
56
- // version alanını fetch options'dan ayıklıyoruz
57
64
  const { version, ...fetchOptions } = options;
58
65
  const response = await fetch(url, { ...fetchOptions, headers, signal: controller.signal });
59
66
  clearTimeout(timeoutId);
@@ -66,56 +73,67 @@ export class BaseApiClient extends Service {
66
73
  }
67
74
  }
68
75
  export class AuthenticatedApiClient extends BaseApiClient {
69
- accessToken;
70
- constructor(config) {
71
- super(config);
72
- }
76
+ _authPromise = null;
77
+ constructor(config) { super(config); }
73
78
  async request(path, options = {}) {
74
- const injectToken = (h, t) => h.set('Cookie', `${TokensEnum.ACCESS_TOKEN}:${t}`);
79
+ const headerName = this.authConfigs?.header || 'Authorization';
80
+ const prefix = this.authConfigs?.prefix ?? 'Bearer';
81
+ const injectToken = (h, t) => {
82
+ const value = prefix ? `${prefix} ${t}` : t;
83
+ h.set(headerName, value);
84
+ };
85
+ let store = ClientStore.get(this.clientName);
75
86
  const headers = new Headers(options.headers || {});
76
- if (this.accessToken)
77
- injectToken(headers, this.accessToken);
87
+ if (store.accessToken)
88
+ injectToken(headers, store.accessToken);
78
89
  options.headers = headers;
79
90
  let response = await super.request(path, options);
80
91
  if (response.status === 401) {
81
- await this.authentication();
82
- if (this.accessToken) {
92
+ await this._synchronizedAuthentication();
93
+ store = ClientStore.get(this.clientName);
94
+ if (store.accessToken) {
83
95
  const retryHeaders = new Headers(options.headers);
84
- injectToken(retryHeaders, this.accessToken);
96
+ injectToken(retryHeaders, store.accessToken);
85
97
  return super.request(path, { ...options, headers: retryHeaders });
86
98
  }
87
99
  }
88
100
  return response;
89
101
  }
90
- }
91
- export class EmailClient extends Service {
92
- constructor(config) {
93
- super(config);
102
+ async _synchronizedAuthentication() {
103
+ if (this._authPromise)
104
+ return this._authPromise;
105
+ this._authPromise = (async () => {
106
+ await this.authentication();
107
+ await this.internalLogin();
108
+ })().finally(() => { this._authPromise = null; });
109
+ return this._authPromise;
94
110
  }
95
- nodemailerLoader(config) {
96
- const transporter = nodemailer.createTransport({
97
- host: config.host || this.baseURL,
98
- port: config.port,
99
- secure: config.secure ?? true,
100
- auth: { user: config.username, pass: config.password }
101
- });
102
- const staticPath = this.configService.all.systemStaticFolderPath || 'source/statics';
103
- transporter.use('compile', hbs({
104
- viewEngine: {
105
- extname: '.hbs',
106
- layoutsDir: path.resolve(staticPath, 'email'),
107
- defaultLayout: 'index'
108
- },
109
- viewPath: path.resolve(staticPath, 'email', 'templates'),
110
- extName: '.hbs'
111
- }));
112
- return transporter;
111
+ async internalLogin() {
112
+ if (!this.authConfigs || !this.authConfigs.endpoint)
113
+ return;
114
+ const { endpoint, payload, method, tokenPath } = this.authConfigs;
115
+ try {
116
+ const response = await fetch(`${this.baseURL}${endpoint}`, {
117
+ method: method || 'POST',
118
+ headers: { 'Content-Type': 'application/json' },
119
+ body: JSON.stringify(payload)
120
+ });
121
+ const data = await response.json();
122
+ const token = this.resolvePath(data, tokenPath || 'accessToken');
123
+ if (token)
124
+ ClientStore.set(this.clientName, { accessToken: token });
125
+ return data;
126
+ }
127
+ catch (error) {
128
+ throw error;
129
+ }
113
130
  }
114
- }
115
- export class SoapClient extends Service {
116
- constructor(config) {
117
- super(config);
131
+ async authentication() {
132
+ return true;
118
133
  }
134
+ }
135
+ export class SoapClient extends Client {
136
+ constructor(config) { super(config); }
119
137
  async call(methodName, args) {
120
138
  try {
121
139
  const client = await soap.createClientAsync(this.baseURL);
@@ -86,12 +86,17 @@ export declare enum WsKeyEnum {
86
86
  ROOM = "ws:room"
87
87
  }
88
88
  export declare enum TokensEnum {
89
+ INTERNAL_API_TOKEN = "internal_api_key",
89
90
  CSRF_TOKEN = "csrf_token",
90
91
  ACCESS_TOKEN = "access_token",
91
92
  REFRESH_TOKEN = "refresh_token",
92
93
  REFERENCE_TOKEN = "reference_token",
93
94
  PERSONAL_ACCESS_TOKEN = "personal_access_token"
94
95
  }
96
+ export declare enum CoreServiceEnum {
97
+ BASE_API_CLIENT = "base_client_name",
98
+ SOAP_API_CLIENT = "soap_api_client"
99
+ }
95
100
  export declare enum EndpointResourceEnum {
96
101
  EXAMPLE = "example",
97
102
  FULL = "full",
@@ -103,12 +103,18 @@ export var WsKeyEnum;
103
103
  })(WsKeyEnum || (WsKeyEnum = {}));
104
104
  export var TokensEnum;
105
105
  (function (TokensEnum) {
106
+ TokensEnum["INTERNAL_API_TOKEN"] = "internal_api_key";
106
107
  TokensEnum["CSRF_TOKEN"] = "csrf_token";
107
108
  TokensEnum["ACCESS_TOKEN"] = "access_token";
108
109
  TokensEnum["REFRESH_TOKEN"] = "refresh_token";
109
110
  TokensEnum["REFERENCE_TOKEN"] = "reference_token";
110
111
  TokensEnum["PERSONAL_ACCESS_TOKEN"] = "personal_access_token";
111
112
  })(TokensEnum || (TokensEnum = {}));
113
+ export var CoreServiceEnum;
114
+ (function (CoreServiceEnum) {
115
+ CoreServiceEnum["BASE_API_CLIENT"] = "base_client_name";
116
+ CoreServiceEnum["SOAP_API_CLIENT"] = "soap_api_client";
117
+ })(CoreServiceEnum || (CoreServiceEnum = {}));
112
118
  export var EndpointResourceEnum;
113
119
  (function (EndpointResourceEnum) {
114
120
  EndpointResourceEnum["EXAMPLE"] = "example";