@xrystal/core 3.26.5 → 3.26.6

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.26.5",
4
+ "version": "3.26.6",
5
5
  "description": "Project core for xrystal",
6
6
  "publishConfig": {
7
7
  "access": "public",
@@ -38,20 +38,4 @@ export declare class BaseApiClient extends Client {
38
38
  request(path: string, options?: CustomRequestOptions): Promise<Response>;
39
39
  private _execute;
40
40
  }
41
- export declare abstract class AuthenticatedApiClient extends BaseApiClient {
42
- private _authPromise;
43
- constructor(config: any);
44
- request(path: string, options?: RequestInit & {
45
- version?: string;
46
- retries?: number;
47
- debug?: boolean;
48
- }): Promise<Response>;
49
- private _synchronizedAuthentication;
50
- private internalLogin;
51
- authentication(): Promise<any>;
52
- }
53
- export declare class SoapClient extends Client {
54
- constructor(config: any);
55
- call(methodName: string, args: any): Promise<any>;
56
- }
57
41
  export {};
@@ -1,5 +1,4 @@
1
1
  import { createHash, createHmac } from 'node:crypto';
2
- import soap from 'soap';
3
2
  import { Configs, Logger } from '../../../loader';
4
3
  import { LoggerLayerEnum, x } from '../../index';
5
4
  export class ClientStore {
@@ -16,7 +15,7 @@ export class Client {
16
15
  baseURL;
17
16
  version = null;
18
17
  timeout = 15000;
19
- debug = Number(this.configs.all.debug) >= LoggerLayerEnum.DEBUG;
18
+ debug;
20
19
  authConfigs;
21
20
  breaker = {
22
21
  failures: 0,
@@ -26,13 +25,13 @@ export class Client {
26
25
  cooldown: 30000
27
26
  };
28
27
  constructor({ clientName, baseURL, version, timeout, auth, debug }) {
29
- this.debug = debug ?? this.debug;
30
28
  this.clientName = clientName;
31
29
  this.baseURL = baseURL;
32
30
  this.version = version || null;
33
31
  this.authConfigs = auth;
34
- if (timeout)
35
- this.timeout = timeout;
32
+ this.timeout = timeout || 15000;
33
+ const configDebug = Number(this.configs.all.debug) >= LoggerLayerEnum.DEBUG;
34
+ this.debug = debug ?? configDebug;
36
35
  if (auth?.token)
37
36
  ClientStore.set(clientName, { accessToken: auth.token });
38
37
  }
@@ -51,14 +50,14 @@ export class BaseApiClient extends Client {
51
50
  this.breaker.state = 'HALF_OPEN';
52
51
  }
53
52
  else {
54
- throw new Error(`${this.clientName} circuit is OPEN. Request blocked.`);
53
+ throw new Error(`[CircuitBreaker] ${this.clientName} is OPEN`);
55
54
  }
56
55
  }
57
56
  const maxRetries = options.retries ?? 3;
58
57
  let attempt = 0;
59
58
  while (attempt < maxRetries) {
60
59
  try {
61
- const response = await this._execute(path, options);
60
+ const response = await this._execute(path, { ...options });
62
61
  if (response.ok || response.status === 401) {
63
62
  this.breaker.failures = 0;
64
63
  this.breaker.state = 'CLOSED';
@@ -81,7 +80,7 @@ export class BaseApiClient extends Client {
81
80
  await new Promise(res => setTimeout(res, backoff));
82
81
  }
83
82
  }
84
- throw new Error(`${this.clientName} request failed after ${maxRetries} attempts.`);
83
+ throw new Error(`${this.clientName} failed after ${maxRetries} attempts`);
85
84
  }
86
85
  async _execute(path, options) {
87
86
  const base = this.baseURL.replace(/\/$/, '');
@@ -91,7 +90,11 @@ export class BaseApiClient extends Client {
91
90
  const store = Logger.storage.getStore();
92
91
  const correlationId = store?.get('correlationId');
93
92
  const headers = new Headers(options.headers || {});
94
- headers.set('Content-Type', 'application/json');
93
+ const isUrlEncoded = options.body instanceof URLSearchParams;
94
+ const isFormData = options.body instanceof FormData;
95
+ if (!isUrlEncoded && !isFormData) {
96
+ headers.set('Content-Type', 'application/json');
97
+ }
95
98
  if (correlationId)
96
99
  headers.set('x-correlation-id', correlationId);
97
100
  const systemSecret = this.configs.all.internalSecret || process.env.INTERNAL_SECRET;
@@ -104,93 +107,36 @@ export class BaseApiClient extends Client {
104
107
  headers.set('x-internal-timestamp', timestamp);
105
108
  headers.set('x-internal-client', this.clientName);
106
109
  }
107
- const isDebugMode = options.debug !== undefined ? options.debug : this.debug;
110
+ const isDebugMode = options.debug ?? this.debug;
108
111
  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);
112
+ let processedBody = fetchOptions.body;
113
+ if (processedBody && typeof processedBody === 'object' && !isUrlEncoded && !isFormData) {
114
+ processedBody = JSON.stringify(processedBody);
111
115
  }
112
116
  if (isDebugMode) {
113
- const logPayload = {
114
- method: options.method || 'GET',
117
+ const logData = {
118
+ method: fetchOptions.method || 'GET',
115
119
  url,
116
- headers: Object.fromEntries(headers.entries()),
117
- body: options.body
120
+ body: processedBody && typeof processedBody === 'string' ? JSON.parse(processedBody) : processedBody
118
121
  };
119
- this.logger.winston.info(`${this.clientName} Request Details: ${JSON.stringify(logPayload, null, 2)}`);
122
+ console.log(`[DEBUG] ${this.clientName}`, logData);
123
+ this.logger.winston.info(`${this.clientName} Request`, logData);
120
124
  }
121
125
  const controller = new AbortController();
122
126
  const timeoutId = setTimeout(() => controller.abort(), this.timeout);
123
- const response = await fetch(url, { ...fetchOptions, headers, signal: controller.signal });
124
- clearTimeout(timeoutId);
125
- return response;
126
- }
127
- }
128
- export class AuthenticatedApiClient extends BaseApiClient {
129
- _authPromise = null;
130
- constructor(config) { super(config); }
131
- async request(path, options = {}) {
132
- const headerName = this.authConfigs?.header || 'Authorization';
133
- const prefix = this.authConfigs?.prefix ?? 'Bearer';
134
- const injectToken = (h, t) => h.set(headerName, prefix ? `${prefix} ${t}` : t);
135
- let store = ClientStore.get(this.clientName);
136
- const headers = new Headers(options.headers || {});
137
- if (store.accessToken)
138
- injectToken(headers, store.accessToken);
139
- options.headers = headers;
140
- let response = await super.request(path, options);
141
- if (response.status === 401) {
142
- await this._synchronizedAuthentication();
143
- const freshStore = ClientStore.get(this.clientName);
144
- if (freshStore.accessToken) {
145
- const retryHeaders = new Headers(options.headers);
146
- injectToken(retryHeaders, freshStore.accessToken);
147
- return super.request(path, { ...options, headers: retryHeaders });
148
- }
149
- }
150
- return response;
151
- }
152
- async _synchronizedAuthentication() {
153
- if (this._authPromise)
154
- return this._authPromise;
155
- this._authPromise = (async () => {
156
- await this.authentication();
157
- await this.internalLogin();
158
- })().finally(() => { this._authPromise = null; });
159
- return this._authPromise;
160
- }
161
- async internalLogin() {
162
- if (!this.authConfigs || !this.authConfigs.endpoint)
163
- return;
164
- const { endpoint, payload, method, tokenPath } = this.authConfigs;
165
127
  try {
166
- const response = await fetch(`${this.baseURL}${endpoint}`, {
167
- method: method || 'POST',
168
- headers: { 'Content-Type': 'application/json' },
169
- body: JSON.stringify(payload)
128
+ const response = await fetch(url, {
129
+ ...fetchOptions,
130
+ body: processedBody,
131
+ headers,
132
+ signal: controller.signal
170
133
  });
171
- const data = await response.json();
172
- const token = this.resolvePath(data, tokenPath || 'accessToken');
173
- if (token)
174
- ClientStore.set(this.clientName, { accessToken: token });
175
- return data;
134
+ clearTimeout(timeoutId);
135
+ return response;
176
136
  }
177
137
  catch (error) {
138
+ clearTimeout(timeoutId);
178
139
  throw error;
179
140
  }
180
141
  }
181
- async authentication() { return true; }
182
- }
183
- export class SoapClient extends Client {
184
- constructor(config) { super(config); }
185
- async call(methodName, args) {
186
- try {
187
- const client = await soap.createClientAsync(this.baseURL);
188
- const result = await client[`${methodName}Async`](args);
189
- return result[0];
190
- }
191
- catch (error) {
192
- this.logger.winston.error(`${this.clientName} SOAP Error: ${error.message}`);
193
- return null;
194
- }
195
- }
196
142
  }