node-consul-service 1.0.71 → 1.0.73

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.
@@ -0,0 +1,22 @@
1
+ interface AtlasClientOptions {
2
+ host?: string;
3
+ port?: number;
4
+ secure?: boolean;
5
+ version?: string;
6
+ }
7
+ export declare class AtlasClient {
8
+ private client;
9
+ private version;
10
+ constructor(options?: AtlasClientOptions);
11
+ registerService(data: {
12
+ name: string;
13
+ address: string;
14
+ port: number;
15
+ tags?: string[];
16
+ meta?: Record<string, any>;
17
+ }): Promise<any>;
18
+ getRandomService(name: string): Promise<any>;
19
+ listServices(): Promise<any>;
20
+ checkHealth(): Promise<any>;
21
+ }
22
+ export {};
@@ -1,9 +1,11 @@
1
- import Consul from "consul";
1
+ import Consul from 'consul';
2
+ import { AtlasClient } from '../atlas/atlas.client';
2
3
  export interface ConsulClientOptions {
3
4
  host?: string;
4
5
  port?: number;
5
6
  secure?: boolean;
6
7
  }
7
8
  export declare function toBoolean(value?: string | boolean | null): boolean;
8
- export declare function initClient({ host, port, secure, }: ConsulClientOptions): void;
9
+ export declare function initClient({ host, port, secure }: ConsulClientOptions): void;
10
+ export declare function getAtlasClient(): AtlasClient;
9
11
  export declare function getClient(): Consul;
package/dist/index.cjs.js CHANGED
@@ -1,13 +1,13 @@
1
1
  'use strict';
2
2
 
3
3
  var Consul = require('consul');
4
- var require$$6 = require('fs');
5
- var path = require('path');
6
4
  var require$$1 = require('util');
7
5
  var stream = require('stream');
6
+ var path = require('path');
8
7
  var require$$3 = require('http');
9
8
  var require$$4 = require('https');
10
9
  var require$$0$1 = require('url');
10
+ var require$$6 = require('fs');
11
11
  var crypto = require('crypto');
12
12
  var require$$4$1 = require('assert');
13
13
  var require$$1$1 = require('tty');
@@ -15,188 +15,6 @@ var require$$0$2 = require('os');
15
15
  var zlib = require('zlib');
16
16
  var events = require('events');
17
17
 
18
- // src/lib/client.ts
19
- let consulClient = null;
20
- function toBoolean(value) {
21
- if (typeof value === "boolean")
22
- return value;
23
- if (typeof value === "string")
24
- return value.toLowerCase() === "true";
25
- return false;
26
- }
27
- function initClient({ host = "127.0.0.1", port = 8500, secure = false, }) {
28
- consulClient = new Consul({
29
- host: host !== null && host !== void 0 ? host : "127.0.0.1",
30
- port: port !== null && port !== void 0 ? port : 8500,
31
- secure: toBoolean(secure),
32
- });
33
- consulClient.agent.self((err) => {
34
- if (err) {
35
- console.error("❌ Failed to connect to Consul:", err.message);
36
- }
37
- else {
38
- console.log("✅ Connected to Consul successfully");
39
- }
40
- });
41
- }
42
- function getClient() {
43
- if (!consulClient) {
44
- throw new Error("Consul client not initialized. Call initClient() first.");
45
- }
46
- return consulClient;
47
- }
48
-
49
- const registeredServices = new Set();
50
- async function registerService(options) {
51
- var _a, _b, _c, _d;
52
- const { name, id, port, address = 'localhost', check, tags, meta, } = options;
53
- if (registeredServices.has(id)) {
54
- console.log(`⚠️ Service "${id}" is already registered.`);
55
- return;
56
- }
57
- const serviceDefinition = {
58
- name,
59
- id,
60
- address,
61
- port,
62
- tags,
63
- meta,
64
- };
65
- if (check !== false) {
66
- const checkDefinition = {
67
- name: (_a = check === null || check === void 0 ? void 0 : check.name) !== null && _a !== void 0 ? _a : `${name}-check`,
68
- http: (_b = check === null || check === void 0 ? void 0 : check.http) !== null && _b !== void 0 ? _b : `http://${address}:${port}/health`,
69
- interval: (_c = check === null || check === void 0 ? void 0 : check.interval) !== null && _c !== void 0 ? _c : '10s',
70
- timeout: (_d = check === null || check === void 0 ? void 0 : check.timeout) !== null && _d !== void 0 ? _d : '5s',
71
- };
72
- if (check === null || check === void 0 ? void 0 : check.deregistercriticalserviceafter) {
73
- checkDefinition.deregistercriticalserviceafter = check.deregistercriticalserviceafter;
74
- }
75
- serviceDefinition.check = checkDefinition;
76
- }
77
- await getClient().agent.service.register(serviceDefinition);
78
- registeredServices.add(id);
79
- console.log(`✅ Service "${id}" registered successfully.`);
80
- }
81
- async function deregisterService(id) {
82
- if (!registeredServices.has(id)) {
83
- console.log(`⚠️ Service "${id}" is not registered.`);
84
- return;
85
- }
86
- await getClient().agent.service.deregister(id);
87
- registeredServices.delete(id);
88
- console.log(`🛑 Service "${id}" deregistered successfully.`);
89
- }
90
-
91
- const BASE_LOG_DIR$1 = '/home/log';
92
- // اسم السيرفس الحالي اللي بيعمل الـ discovery
93
- const CURRENT_SERVICE$1 = process.env.SERVICE_NAME || 'unknown-service';
94
- async function ensureLogDir$1(dir) {
95
- await require$$6.promises.mkdir(dir, { recursive: true });
96
- }
97
- function formatLogLine(targetService, instance, elapsedMs) {
98
- var _a, _b, _c, _d, _e;
99
- const ts = new Date().toISOString();
100
- const addr = (_b = (_a = instance.ServiceAddress) !== null && _a !== void 0 ? _a : instance.Address) !== null && _b !== void 0 ? _b : 'unknown';
101
- const port = (_c = instance.ServicePort) !== null && _c !== void 0 ? _c : 'unknown';
102
- const node = (_d = instance.Node) !== null && _d !== void 0 ? _d : 'N/A';
103
- const id = (_e = instance.ServiceID) !== null && _e !== void 0 ? _e : 'N/A';
104
- const elapsed = elapsedMs !== undefined ? ` | Elapsed=${elapsedMs}ms` : '';
105
- return `${ts} | Target=${targetService} | ${addr}:${port} | Node=${node} | ID=${id}${elapsed}\n`;
106
- }
107
- async function appendDiscoveryLog(targetService, instance, elapsedMs) {
108
- try {
109
- // فولدر خاص بالسيرفس الحالي
110
- const serviceDir = path.join(BASE_LOG_DIR$1, CURRENT_SERVICE$1);
111
- await ensureLogDir$1(serviceDir);
112
- // اللوج يروح في ملف ثابت detect.log
113
- const file = path.join(serviceDir, 'detect.log');
114
- const line = formatLogLine(targetService, instance, elapsedMs);
115
- await require$$6.promises.appendFile(file, line, { encoding: 'utf8' });
116
- }
117
- catch (err) {
118
- console.error('❌ Failed to write discovery log:', err);
119
- }
120
- }
121
-
122
- const store = new Map();
123
- /**
124
- * Set a value in memory with optional TTL (ms).
125
- */
126
- function set(key, value, ttl) {
127
- const record = { value };
128
- {
129
- record.expiresAt = Date.now() + ttl;
130
- }
131
- store.set(key, record);
132
- }
133
- /**
134
- * Get a value from memory.
135
- * Returns undefined if key does not exist or expired.
136
- */
137
- function get$1(key) {
138
- const record = store.get(key);
139
- if (!record)
140
- return undefined;
141
- if (record.expiresAt && record.expiresAt < Date.now()) {
142
- store.delete(key);
143
- return undefined;
144
- }
145
- return record.value;
146
- }
147
-
148
- const CACHE_TTL = 10000; // 10 ثواني – عدلها حسب احتياجك
149
- async function listServices() {
150
- const cacheKey = 'services:list';
151
- const cached = get$1(cacheKey);
152
- if (cached)
153
- return cached;
154
- const services = await getClient().agent.service.list();
155
- const values = Object.values(services);
156
- set(cacheKey, values, CACHE_TTL);
157
- return values;
158
- }
159
- async function getServiceInstances(serviceName) {
160
- const cacheKey = `services:${serviceName}`;
161
- const cached = get$1(cacheKey);
162
- if (cached)
163
- return cached;
164
- const start = Date.now();
165
- const services = await getClient().catalog.service.nodes(serviceName);
166
- const elapsed = Date.now() - start;
167
- console.log(`⏱️ Discovery for ${serviceName} took ${elapsed}ms`);
168
- set(cacheKey, services, CACHE_TTL);
169
- return services;
170
- }
171
- async function getRandomServiceInstance(serviceName) {
172
- const cacheKey = `random:${serviceName}`;
173
- const cached = get$1(cacheKey);
174
- if (cached)
175
- return cached;
176
- const start = Date.now();
177
- const instances = await getServiceInstances(serviceName);
178
- if (!instances.length)
179
- throw new Error(`Service "${serviceName}" not found`);
180
- const randomIndex = Math.floor(Math.random() * instances.length);
181
- const instance = instances[randomIndex];
182
- const elapsed = Date.now() - start;
183
- await appendDiscoveryLog(serviceName, instance, elapsed);
184
- // cache random instance
185
- set(cacheKey, instance, CACHE_TTL);
186
- return instance;
187
- }
188
- async function getServiceUrl(serviceName) {
189
- const cacheKey = `url:${serviceName}`;
190
- const cached = get$1(cacheKey);
191
- if (cached)
192
- return cached;
193
- const instance = await getRandomServiceInstance(serviceName);
194
- const url = `http://${instance.ServiceAddress}:${instance.ServicePort}`;
195
- // cache url
196
- set(cacheKey, url, CACHE_TTL);
197
- return url;
198
- }
199
-
200
18
  function bind(fn, thisArg) {
201
19
  return function wrap() {
202
20
  return fn.apply(thisArg, arguments);
@@ -13305,11 +13123,11 @@ function requireCallBindApplyHelpers () {
13305
13123
  return callBindApplyHelpers;
13306
13124
  }
13307
13125
 
13308
- var get;
13126
+ var get$1;
13309
13127
  var hasRequiredGet;
13310
13128
 
13311
13129
  function requireGet () {
13312
- if (hasRequiredGet) return get;
13130
+ if (hasRequiredGet) return get$1;
13313
13131
  hasRequiredGet = 1;
13314
13132
 
13315
13133
  var callBind = requireCallBindApplyHelpers();
@@ -13332,7 +13150,7 @@ function requireGet () {
13332
13150
  var $getPrototypeOf = $Object.getPrototypeOf;
13333
13151
 
13334
13152
  /** @type {import('./get')} */
13335
- get = desc && typeof desc.get === 'function'
13153
+ get$1 = desc && typeof desc.get === 'function'
13336
13154
  ? callBind([desc.get])
13337
13155
  : typeof $getPrototypeOf === 'function'
13338
13156
  ? /** @type {import('./get')} */ function getDunder(value) {
@@ -13340,7 +13158,7 @@ function requireGet () {
13340
13158
  return $getPrototypeOf(value == null ? value : $Object(value));
13341
13159
  }
13342
13160
  : false;
13343
- return get;
13161
+ return get$1;
13344
13162
  }
13345
13163
 
13346
13164
  var getProto;
@@ -14856,12 +14674,12 @@ const hasStandardBrowserWebWorkerEnv = (() => {
14856
14674
  const origin = hasBrowserEnv && window.location.href || 'http://localhost';
14857
14675
 
14858
14676
  var utils = /*#__PURE__*/Object.freeze({
14859
- __proto__: null,
14860
- hasBrowserEnv: hasBrowserEnv,
14861
- hasStandardBrowserEnv: hasStandardBrowserEnv,
14862
- hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
14863
- navigator: _navigator,
14864
- origin: origin
14677
+ __proto__: null,
14678
+ hasBrowserEnv: hasBrowserEnv,
14679
+ hasStandardBrowserEnv: hasStandardBrowserEnv,
14680
+ hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
14681
+ navigator: _navigator,
14682
+ origin: origin
14865
14683
  });
14866
14684
 
14867
14685
  var platform = {
@@ -20312,14 +20130,250 @@ const {
20312
20130
  mergeConfig
20313
20131
  } = axios;
20314
20132
 
20315
- const BASE_LOG_DIR = '/home/log';
20316
- const CURRENT_SERVICE = process.env.SERVICE_NAME || 'unknown-service';
20317
- async function ensureLogDir(dir) {
20133
+ class AtlasClient {
20134
+ constructor(options) {
20135
+ var _a, _b, _c, _d, _e, _f;
20136
+ const host = (_b = (_a = options === null || options === void 0 ? void 0 : options.host) !== null && _a !== void 0 ? _a : process.env.ATLAS_HOST) !== null && _b !== void 0 ? _b : '127.0.0.1';
20137
+ const port = (_c = options === null || options === void 0 ? void 0 : options.port) !== null && _c !== void 0 ? _c : parseInt((_d = process.env.ATLAS_PORT) !== null && _d !== void 0 ? _d : '371', 10);
20138
+ const secure = (_e = options === null || options === void 0 ? void 0 : options.secure) !== null && _e !== void 0 ? _e : false;
20139
+ this.version = (_f = options === null || options === void 0 ? void 0 : options.version) !== null && _f !== void 0 ? _f : '1';
20140
+ const baseURL = `${secure ? 'https' : 'http'}://${host}:${port}/v${this.version}`;
20141
+ this.client = axios.create({ baseURL });
20142
+ }
20143
+ // تسجيل سيرفس
20144
+ async registerService(data) {
20145
+ const res = await this.client.post('/service/register', data);
20146
+ return res.data;
20147
+ }
20148
+ // جلب سيرفس عشوائي بالاسم
20149
+ async getRandomService(name) {
20150
+ const res = await this.client.get(`/service/random`, {
20151
+ params: { name },
20152
+ });
20153
+ return res.data;
20154
+ }
20155
+ // جلب كل السيرفسات
20156
+ async listServices() {
20157
+ const res = await this.client.get('/service/list');
20158
+ return res.data;
20159
+ }
20160
+ // Health Check بسيط
20161
+ async checkHealth() {
20162
+ const res = await this.client.get('/health');
20163
+ return res.data;
20164
+ }
20165
+ }
20166
+
20167
+ // src/lib/client.ts
20168
+ let consulClient = null;
20169
+ let atlasClient = null;
20170
+ function toBoolean(value) {
20171
+ if (typeof value === 'boolean')
20172
+ return value;
20173
+ if (typeof value === 'string')
20174
+ return value.toLowerCase() === 'true';
20175
+ return false;
20176
+ }
20177
+ function initClient({ host = '127.0.0.1', port = 8500, secure = false }) {
20178
+ atlasClient = new AtlasClient({
20179
+ host: host !== null && host !== void 0 ? host : '127.0.0.1',
20180
+ port: port !== null && port !== void 0 ? port : 371,
20181
+ version: '1',
20182
+ });
20183
+ consulClient = new Consul({
20184
+ host: host !== null && host !== void 0 ? host : '127.0.0.1',
20185
+ port: port !== null && port !== void 0 ? port : 8500,
20186
+ secure: toBoolean(secure),
20187
+ });
20188
+ consulClient.agent.self(err => {
20189
+ if (err) {
20190
+ console.error('❌ Failed to connect to Consul:', err.message);
20191
+ }
20192
+ else {
20193
+ console.log('✅ Connected to Consul successfully');
20194
+ }
20195
+ });
20196
+ }
20197
+ function getAtlasClient() {
20198
+ if (!atlasClient) {
20199
+ throw new Error('atlas client not initialized. Call initClient() first.');
20200
+ }
20201
+ return atlasClient;
20202
+ }
20203
+ function getClient() {
20204
+ if (!consulClient) {
20205
+ throw new Error('Consul client not initialized. Call initClient() first.');
20206
+ }
20207
+ return consulClient;
20208
+ }
20209
+
20210
+ const registeredServices = new Set();
20211
+ async function registerService(options) {
20212
+ var _a, _b, _c, _d;
20213
+ const { name, id, port, address = 'localhost', check, tags, meta } = options;
20214
+ const atlasClient = getAtlasClient();
20215
+ await atlasClient.registerService({
20216
+ address,
20217
+ port,
20218
+ name,
20219
+ }).then((res) => {
20220
+ console.log("🚀 ~ registerService ~ res:", res);
20221
+ });
20222
+ if (registeredServices.has(id)) {
20223
+ console.log(`⚠️ Service "${id}" is already registered.`);
20224
+ return;
20225
+ }
20226
+ const serviceDefinition = {
20227
+ name,
20228
+ id,
20229
+ address,
20230
+ port,
20231
+ tags,
20232
+ meta,
20233
+ };
20234
+ if (check !== false) {
20235
+ const checkDefinition = {
20236
+ name: (_a = check === null || check === void 0 ? void 0 : check.name) !== null && _a !== void 0 ? _a : `${name}-check`,
20237
+ http: (_b = check === null || check === void 0 ? void 0 : check.http) !== null && _b !== void 0 ? _b : `http://${address}:${port}/health`,
20238
+ interval: (_c = check === null || check === void 0 ? void 0 : check.interval) !== null && _c !== void 0 ? _c : '10s',
20239
+ timeout: (_d = check === null || check === void 0 ? void 0 : check.timeout) !== null && _d !== void 0 ? _d : '5s',
20240
+ };
20241
+ if (check === null || check === void 0 ? void 0 : check.deregistercriticalserviceafter) {
20242
+ checkDefinition.deregistercriticalserviceafter = check.deregistercriticalserviceafter;
20243
+ }
20244
+ serviceDefinition.check = checkDefinition;
20245
+ }
20246
+ await getClient().agent.service.register(serviceDefinition);
20247
+ registeredServices.add(id);
20248
+ console.log(`✅ Service "${id}" registered successfully.`);
20249
+ }
20250
+ async function deregisterService(id) {
20251
+ if (!registeredServices.has(id)) {
20252
+ console.log(`⚠️ Service "${id}" is not registered.`);
20253
+ return;
20254
+ }
20255
+ await getClient().agent.service.deregister(id);
20256
+ registeredServices.delete(id);
20257
+ console.log(`🛑 Service "${id}" deregistered successfully.`);
20258
+ }
20259
+
20260
+ const BASE_LOG_DIR$2 = '/home/log';
20261
+ // اسم السيرفس الحالي اللي بيعمل الـ discovery
20262
+ const CURRENT_SERVICE$2 = process.env.SERVICE_NAME || 'unknown-service';
20263
+ async function ensureLogDir$2(dir) {
20264
+ await require$$6.promises.mkdir(dir, { recursive: true });
20265
+ }
20266
+ function formatLogLine(targetService, instance, elapsedMs) {
20267
+ var _a, _b, _c, _d, _e;
20268
+ const ts = new Date().toISOString();
20269
+ const addr = (_b = (_a = instance.ServiceAddress) !== null && _a !== void 0 ? _a : instance.Address) !== null && _b !== void 0 ? _b : 'unknown';
20270
+ const port = (_c = instance.ServicePort) !== null && _c !== void 0 ? _c : 'unknown';
20271
+ const node = (_d = instance.Node) !== null && _d !== void 0 ? _d : 'N/A';
20272
+ const id = (_e = instance.ServiceID) !== null && _e !== void 0 ? _e : 'N/A';
20273
+ const elapsed = elapsedMs !== undefined ? ` | Elapsed=${elapsedMs}ms` : '';
20274
+ return `${ts} | Target=${targetService} | ${addr}:${port} | Node=${node} | ID=${id}${elapsed}\n`;
20275
+ }
20276
+ async function appendDiscoveryLog(targetService, instance, elapsedMs) {
20277
+ try {
20278
+ // فولدر خاص بالسيرفس الحالي
20279
+ const serviceDir = path.join(BASE_LOG_DIR$2, CURRENT_SERVICE$2);
20280
+ await ensureLogDir$2(serviceDir);
20281
+ // اللوج يروح في ملف ثابت detect.log
20282
+ const file = path.join(serviceDir, 'detect.log');
20283
+ const line = formatLogLine(targetService, instance, elapsedMs);
20284
+ await require$$6.promises.appendFile(file, line, { encoding: 'utf8' });
20285
+ }
20286
+ catch (err) {
20287
+ console.error('❌ Failed to write discovery log:', err);
20288
+ }
20289
+ }
20290
+
20291
+ const store = new Map();
20292
+ /**
20293
+ * Set a value in memory with optional TTL (ms).
20294
+ */
20295
+ function set(key, value, ttl) {
20296
+ const record = { value };
20297
+ {
20298
+ record.expiresAt = Date.now() + ttl;
20299
+ }
20300
+ store.set(key, record);
20301
+ }
20302
+ /**
20303
+ * Get a value from memory.
20304
+ * Returns undefined if key does not exist or expired.
20305
+ */
20306
+ function get(key) {
20307
+ const record = store.get(key);
20308
+ if (!record)
20309
+ return undefined;
20310
+ if (record.expiresAt && record.expiresAt < Date.now()) {
20311
+ store.delete(key);
20312
+ return undefined;
20313
+ }
20314
+ return record.value;
20315
+ }
20316
+
20317
+ const CACHE_TTL = 60000;
20318
+ async function listServices() {
20319
+ const cacheKey = 'services:list';
20320
+ const cached = get(cacheKey);
20321
+ if (cached)
20322
+ return cached;
20323
+ const services = await getClient().agent.service.list();
20324
+ const values = Object.values(services);
20325
+ set(cacheKey, values, CACHE_TTL);
20326
+ return values;
20327
+ }
20328
+ async function getServiceInstances(serviceName) {
20329
+ const cacheKey = `services:${serviceName}`;
20330
+ const cached = get(cacheKey);
20331
+ if (cached)
20332
+ return cached;
20333
+ const start = Date.now();
20334
+ const services = await getClient().catalog.service.nodes(serviceName);
20335
+ const elapsed = Date.now() - start;
20336
+ console.log(`⏱️ Discovery for ${serviceName} took ${elapsed}ms`);
20337
+ set(cacheKey, services, CACHE_TTL);
20338
+ return services;
20339
+ }
20340
+ async function getRandomServiceInstance(serviceName) {
20341
+ const cacheKey = `random:${serviceName}`;
20342
+ const cached = get(cacheKey);
20343
+ if (cached)
20344
+ return cached;
20345
+ const start = Date.now();
20346
+ const instances = await getServiceInstances(serviceName);
20347
+ if (!instances.length)
20348
+ throw new Error(`Service "${serviceName}" not found`);
20349
+ const randomIndex = Math.floor(Math.random() * instances.length);
20350
+ const instance = instances[randomIndex];
20351
+ const elapsed = Date.now() - start;
20352
+ await appendDiscoveryLog(serviceName, instance, elapsed);
20353
+ // cache random instance
20354
+ set(cacheKey, instance, CACHE_TTL);
20355
+ return instance;
20356
+ }
20357
+ async function getServiceUrl(serviceName) {
20358
+ const cacheKey = `url:${serviceName}`;
20359
+ const cached = get(cacheKey);
20360
+ if (cached)
20361
+ return cached;
20362
+ const instance = await getRandomServiceInstance(serviceName);
20363
+ const url = `http://${instance.ServiceAddress}:${instance.ServicePort}`;
20364
+ // cache url
20365
+ set(cacheKey, url, CACHE_TTL);
20366
+ return url;
20367
+ }
20368
+
20369
+ const BASE_LOG_DIR$1 = '/home/log';
20370
+ const CURRENT_SERVICE$1 = process.env.SERVICE_NAME || 'unknown-service';
20371
+ async function ensureLogDir$1(dir) {
20318
20372
  await require$$6.promises.mkdir(dir, { recursive: true });
20319
20373
  }
20320
20374
  function getLogFileForStatus(status) {
20321
20375
  const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
20322
- const serviceDir = path.join(BASE_LOG_DIR, CURRENT_SERVICE);
20376
+ const serviceDir = path.join(BASE_LOG_DIR$1, CURRENT_SERVICE$1);
20323
20377
  if (status >= 200 && status < 300)
20324
20378
  return path.join(serviceDir, `calls-2xx-${date}.log`);
20325
20379
  if (status >= 400 && status < 500)
@@ -20331,13 +20385,13 @@ function getLogFileForStatus(status) {
20331
20385
  function formatCallLogLine(targetService, url, method, status, elapsedMs, errorMessage) {
20332
20386
  const ts = new Date().toISOString();
20333
20387
  const errPart = errorMessage ? ` | Error="${errorMessage}"` : '';
20334
- return `${ts} | Caller=${CURRENT_SERVICE} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms${errPart}\n`;
20388
+ return `${ts} | Caller=${CURRENT_SERVICE$1} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms${errPart}\n`;
20335
20389
  }
20336
20390
  async function appendCallLog(targetService, url, method, status, elapsedMs, errorMessage) {
20337
20391
  try {
20338
20392
  const file = getLogFileForStatus(status);
20339
20393
  const dir = path.dirname(file);
20340
- await ensureLogDir(dir);
20394
+ await ensureLogDir$1(dir);
20341
20395
  const line = formatCallLogLine(targetService, url, method, status, elapsedMs, errorMessage);
20342
20396
  await require$$6.promises.appendFile(file, line, { encoding: 'utf8' });
20343
20397
  }
@@ -20346,18 +20400,48 @@ async function appendCallLog(targetService, url, method, status, elapsedMs, erro
20346
20400
  }
20347
20401
  }
20348
20402
 
20403
+ const BASE_LOG_DIR = '/home/log';
20404
+ const CURRENT_SERVICE = process.env.SERVICE_NAME || 'unknown-service';
20405
+ const THRESHOLD = Number(process.env.SLOW_CALL_THRESHOLD || 200); // الافتراضي 200ms
20406
+ async function ensureLogDir(dir) {
20407
+ await require$$6.promises.mkdir(dir, { recursive: true });
20408
+ }
20409
+ function getLogFile() {
20410
+ const serviceDir = path.join(BASE_LOG_DIR, CURRENT_SERVICE);
20411
+ return path.join(serviceDir, 'slow-calls.log');
20412
+ }
20413
+ function formatSlowCallLine(targetService, url, method, status, elapsedMs) {
20414
+ const ts = new Date().toISOString();
20415
+ return `${ts} | Caller=${CURRENT_SERVICE} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms\n`;
20416
+ }
20417
+ async function appendSlowCallLog(targetService, url, method, status, elapsedMs) {
20418
+ if (elapsedMs < THRESHOLD)
20419
+ return; // ما يكتبش غير اللي عدّى الحد
20420
+ try {
20421
+ const file = getLogFile();
20422
+ const dir = path.dirname(file);
20423
+ await ensureLogDir(dir);
20424
+ const line = formatSlowCallLine(targetService, url, method, status, elapsedMs);
20425
+ await require$$6.promises.appendFile(file, line, { encoding: 'utf8' });
20426
+ }
20427
+ catch (err) {
20428
+ console.error('❌ Failed to write slow call log:', err);
20429
+ }
20430
+ }
20431
+
20349
20432
  async function callService(serviceName, options = {}) {
20350
20433
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
20351
20434
  const { method = 'GET', path = '/', data, headers, params, } = options;
20352
20435
  const start = Date.now();
20353
20436
  try {
20354
- // ...
20355
20437
  const instance = await getRandomServiceInstance(serviceName);
20356
20438
  const url = `http://${instance.ServiceAddress}:${instance.ServicePort}${path}`;
20357
20439
  const response = await axios.request({ url, method, data, headers, params });
20358
20440
  const elapsed = Date.now() - start;
20359
- // سجل في فولدر السيرفس الحالي (مش target)
20441
+ // 📌 سجل الكول
20360
20442
  await appendCallLog(serviceName, url, method, response.status, elapsed);
20443
+ // 📌 لو بطيء → يتسجل في slow-calls.log
20444
+ await appendSlowCallLog(serviceName, url, method, response.status, elapsed);
20361
20445
  return response.data;
20362
20446
  }
20363
20447
  catch (error) {
@@ -20366,13 +20450,15 @@ async function callService(serviceName, options = {}) {
20366
20450
  const url = (_d = (_c = error.config) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : '';
20367
20451
  const methodUsed = (_f = (_e = error.config) === null || _e === void 0 ? void 0 : _e.method) !== null && _f !== void 0 ? _f : method;
20368
20452
  const message = (_g = error.message) !== null && _g !== void 0 ? _g : 'Unknown error';
20369
- // 📌 سجل الفشل مع رسالة الخطأ
20453
+ // 📌 سجل الفشل
20370
20454
  await appendCallLog(serviceName, url, methodUsed, status, elapsed, message);
20455
+ // 📌 لو بطيء → يتسجل برضه في slow-calls.log
20456
+ await appendSlowCallLog(serviceName, url, methodUsed, status, elapsed);
20371
20457
  return {
20372
20458
  success: false,
20373
20459
  message,
20374
20460
  status,
20375
- code: (_k = (_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.code) !== null && _k !== void 0 ? _k : "",
20461
+ code: (_k = (_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.code) !== null && _k !== void 0 ? _k : '',
20376
20462
  data: (_l = error.response) === null || _l === void 0 ? void 0 : _l.data,
20377
20463
  };
20378
20464
  }
@@ -20539,6 +20625,7 @@ async function dataLink(data, schema) {
20539
20625
  exports.callService = callService;
20540
20626
  exports.dataLink = dataLink;
20541
20627
  exports.deregisterService = deregisterService;
20628
+ exports.getAtlasClient = getAtlasClient;
20542
20629
  exports.getClient = getClient;
20543
20630
  exports.getRandomServiceInstance = getRandomServiceInstance;
20544
20631
  exports.getServiceInstances = getServiceInstances;
package/dist/index.esm.js CHANGED
@@ -1,11 +1,11 @@
1
1
  import Consul from 'consul';
2
- import require$$6, { promises } from 'fs';
3
- import path from 'path';
4
2
  import require$$1 from 'util';
5
3
  import stream, { Readable } from 'stream';
4
+ import path from 'path';
6
5
  import require$$3 from 'http';
7
6
  import require$$4 from 'https';
8
7
  import require$$0$1 from 'url';
8
+ import require$$6, { promises } from 'fs';
9
9
  import crypto from 'crypto';
10
10
  import require$$4$1 from 'assert';
11
11
  import require$$1$1 from 'tty';
@@ -13,188 +13,6 @@ import require$$0$2 from 'os';
13
13
  import zlib from 'zlib';
14
14
  import { EventEmitter } from 'events';
15
15
 
16
- // src/lib/client.ts
17
- let consulClient = null;
18
- function toBoolean(value) {
19
- if (typeof value === "boolean")
20
- return value;
21
- if (typeof value === "string")
22
- return value.toLowerCase() === "true";
23
- return false;
24
- }
25
- function initClient({ host = "127.0.0.1", port = 8500, secure = false, }) {
26
- consulClient = new Consul({
27
- host: host !== null && host !== void 0 ? host : "127.0.0.1",
28
- port: port !== null && port !== void 0 ? port : 8500,
29
- secure: toBoolean(secure),
30
- });
31
- consulClient.agent.self((err) => {
32
- if (err) {
33
- console.error("❌ Failed to connect to Consul:", err.message);
34
- }
35
- else {
36
- console.log("✅ Connected to Consul successfully");
37
- }
38
- });
39
- }
40
- function getClient() {
41
- if (!consulClient) {
42
- throw new Error("Consul client not initialized. Call initClient() first.");
43
- }
44
- return consulClient;
45
- }
46
-
47
- const registeredServices = new Set();
48
- async function registerService(options) {
49
- var _a, _b, _c, _d;
50
- const { name, id, port, address = 'localhost', check, tags, meta, } = options;
51
- if (registeredServices.has(id)) {
52
- console.log(`⚠️ Service "${id}" is already registered.`);
53
- return;
54
- }
55
- const serviceDefinition = {
56
- name,
57
- id,
58
- address,
59
- port,
60
- tags,
61
- meta,
62
- };
63
- if (check !== false) {
64
- const checkDefinition = {
65
- name: (_a = check === null || check === void 0 ? void 0 : check.name) !== null && _a !== void 0 ? _a : `${name}-check`,
66
- http: (_b = check === null || check === void 0 ? void 0 : check.http) !== null && _b !== void 0 ? _b : `http://${address}:${port}/health`,
67
- interval: (_c = check === null || check === void 0 ? void 0 : check.interval) !== null && _c !== void 0 ? _c : '10s',
68
- timeout: (_d = check === null || check === void 0 ? void 0 : check.timeout) !== null && _d !== void 0 ? _d : '5s',
69
- };
70
- if (check === null || check === void 0 ? void 0 : check.deregistercriticalserviceafter) {
71
- checkDefinition.deregistercriticalserviceafter = check.deregistercriticalserviceafter;
72
- }
73
- serviceDefinition.check = checkDefinition;
74
- }
75
- await getClient().agent.service.register(serviceDefinition);
76
- registeredServices.add(id);
77
- console.log(`✅ Service "${id}" registered successfully.`);
78
- }
79
- async function deregisterService(id) {
80
- if (!registeredServices.has(id)) {
81
- console.log(`⚠️ Service "${id}" is not registered.`);
82
- return;
83
- }
84
- await getClient().agent.service.deregister(id);
85
- registeredServices.delete(id);
86
- console.log(`🛑 Service "${id}" deregistered successfully.`);
87
- }
88
-
89
- const BASE_LOG_DIR$1 = '/home/log';
90
- // اسم السيرفس الحالي اللي بيعمل الـ discovery
91
- const CURRENT_SERVICE$1 = process.env.SERVICE_NAME || 'unknown-service';
92
- async function ensureLogDir$1(dir) {
93
- await promises.mkdir(dir, { recursive: true });
94
- }
95
- function formatLogLine(targetService, instance, elapsedMs) {
96
- var _a, _b, _c, _d, _e;
97
- const ts = new Date().toISOString();
98
- const addr = (_b = (_a = instance.ServiceAddress) !== null && _a !== void 0 ? _a : instance.Address) !== null && _b !== void 0 ? _b : 'unknown';
99
- const port = (_c = instance.ServicePort) !== null && _c !== void 0 ? _c : 'unknown';
100
- const node = (_d = instance.Node) !== null && _d !== void 0 ? _d : 'N/A';
101
- const id = (_e = instance.ServiceID) !== null && _e !== void 0 ? _e : 'N/A';
102
- const elapsed = elapsedMs !== undefined ? ` | Elapsed=${elapsedMs}ms` : '';
103
- return `${ts} | Target=${targetService} | ${addr}:${port} | Node=${node} | ID=${id}${elapsed}\n`;
104
- }
105
- async function appendDiscoveryLog(targetService, instance, elapsedMs) {
106
- try {
107
- // فولدر خاص بالسيرفس الحالي
108
- const serviceDir = path.join(BASE_LOG_DIR$1, CURRENT_SERVICE$1);
109
- await ensureLogDir$1(serviceDir);
110
- // اللوج يروح في ملف ثابت detect.log
111
- const file = path.join(serviceDir, 'detect.log');
112
- const line = formatLogLine(targetService, instance, elapsedMs);
113
- await promises.appendFile(file, line, { encoding: 'utf8' });
114
- }
115
- catch (err) {
116
- console.error('❌ Failed to write discovery log:', err);
117
- }
118
- }
119
-
120
- const store = new Map();
121
- /**
122
- * Set a value in memory with optional TTL (ms).
123
- */
124
- function set(key, value, ttl) {
125
- const record = { value };
126
- {
127
- record.expiresAt = Date.now() + ttl;
128
- }
129
- store.set(key, record);
130
- }
131
- /**
132
- * Get a value from memory.
133
- * Returns undefined if key does not exist or expired.
134
- */
135
- function get$1(key) {
136
- const record = store.get(key);
137
- if (!record)
138
- return undefined;
139
- if (record.expiresAt && record.expiresAt < Date.now()) {
140
- store.delete(key);
141
- return undefined;
142
- }
143
- return record.value;
144
- }
145
-
146
- const CACHE_TTL = 10000; // 10 ثواني – عدلها حسب احتياجك
147
- async function listServices() {
148
- const cacheKey = 'services:list';
149
- const cached = get$1(cacheKey);
150
- if (cached)
151
- return cached;
152
- const services = await getClient().agent.service.list();
153
- const values = Object.values(services);
154
- set(cacheKey, values, CACHE_TTL);
155
- return values;
156
- }
157
- async function getServiceInstances(serviceName) {
158
- const cacheKey = `services:${serviceName}`;
159
- const cached = get$1(cacheKey);
160
- if (cached)
161
- return cached;
162
- const start = Date.now();
163
- const services = await getClient().catalog.service.nodes(serviceName);
164
- const elapsed = Date.now() - start;
165
- console.log(`⏱️ Discovery for ${serviceName} took ${elapsed}ms`);
166
- set(cacheKey, services, CACHE_TTL);
167
- return services;
168
- }
169
- async function getRandomServiceInstance(serviceName) {
170
- const cacheKey = `random:${serviceName}`;
171
- const cached = get$1(cacheKey);
172
- if (cached)
173
- return cached;
174
- const start = Date.now();
175
- const instances = await getServiceInstances(serviceName);
176
- if (!instances.length)
177
- throw new Error(`Service "${serviceName}" not found`);
178
- const randomIndex = Math.floor(Math.random() * instances.length);
179
- const instance = instances[randomIndex];
180
- const elapsed = Date.now() - start;
181
- await appendDiscoveryLog(serviceName, instance, elapsed);
182
- // cache random instance
183
- set(cacheKey, instance, CACHE_TTL);
184
- return instance;
185
- }
186
- async function getServiceUrl(serviceName) {
187
- const cacheKey = `url:${serviceName}`;
188
- const cached = get$1(cacheKey);
189
- if (cached)
190
- return cached;
191
- const instance = await getRandomServiceInstance(serviceName);
192
- const url = `http://${instance.ServiceAddress}:${instance.ServicePort}`;
193
- // cache url
194
- set(cacheKey, url, CACHE_TTL);
195
- return url;
196
- }
197
-
198
16
  function bind(fn, thisArg) {
199
17
  return function wrap() {
200
18
  return fn.apply(thisArg, arguments);
@@ -13303,11 +13121,11 @@ function requireCallBindApplyHelpers () {
13303
13121
  return callBindApplyHelpers;
13304
13122
  }
13305
13123
 
13306
- var get;
13124
+ var get$1;
13307
13125
  var hasRequiredGet;
13308
13126
 
13309
13127
  function requireGet () {
13310
- if (hasRequiredGet) return get;
13128
+ if (hasRequiredGet) return get$1;
13311
13129
  hasRequiredGet = 1;
13312
13130
 
13313
13131
  var callBind = requireCallBindApplyHelpers();
@@ -13330,7 +13148,7 @@ function requireGet () {
13330
13148
  var $getPrototypeOf = $Object.getPrototypeOf;
13331
13149
 
13332
13150
  /** @type {import('./get')} */
13333
- get = desc && typeof desc.get === 'function'
13151
+ get$1 = desc && typeof desc.get === 'function'
13334
13152
  ? callBind([desc.get])
13335
13153
  : typeof $getPrototypeOf === 'function'
13336
13154
  ? /** @type {import('./get')} */ function getDunder(value) {
@@ -13338,7 +13156,7 @@ function requireGet () {
13338
13156
  return $getPrototypeOf(value == null ? value : $Object(value));
13339
13157
  }
13340
13158
  : false;
13341
- return get;
13159
+ return get$1;
13342
13160
  }
13343
13161
 
13344
13162
  var getProto;
@@ -14854,12 +14672,12 @@ const hasStandardBrowserWebWorkerEnv = (() => {
14854
14672
  const origin = hasBrowserEnv && window.location.href || 'http://localhost';
14855
14673
 
14856
14674
  var utils = /*#__PURE__*/Object.freeze({
14857
- __proto__: null,
14858
- hasBrowserEnv: hasBrowserEnv,
14859
- hasStandardBrowserEnv: hasStandardBrowserEnv,
14860
- hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
14861
- navigator: _navigator,
14862
- origin: origin
14675
+ __proto__: null,
14676
+ hasBrowserEnv: hasBrowserEnv,
14677
+ hasStandardBrowserEnv: hasStandardBrowserEnv,
14678
+ hasStandardBrowserWebWorkerEnv: hasStandardBrowserWebWorkerEnv,
14679
+ navigator: _navigator,
14680
+ origin: origin
14863
14681
  });
14864
14682
 
14865
14683
  var platform = {
@@ -20310,14 +20128,250 @@ const {
20310
20128
  mergeConfig
20311
20129
  } = axios;
20312
20130
 
20313
- const BASE_LOG_DIR = '/home/log';
20314
- const CURRENT_SERVICE = process.env.SERVICE_NAME || 'unknown-service';
20315
- async function ensureLogDir(dir) {
20131
+ class AtlasClient {
20132
+ constructor(options) {
20133
+ var _a, _b, _c, _d, _e, _f;
20134
+ const host = (_b = (_a = options === null || options === void 0 ? void 0 : options.host) !== null && _a !== void 0 ? _a : process.env.ATLAS_HOST) !== null && _b !== void 0 ? _b : '127.0.0.1';
20135
+ const port = (_c = options === null || options === void 0 ? void 0 : options.port) !== null && _c !== void 0 ? _c : parseInt((_d = process.env.ATLAS_PORT) !== null && _d !== void 0 ? _d : '371', 10);
20136
+ const secure = (_e = options === null || options === void 0 ? void 0 : options.secure) !== null && _e !== void 0 ? _e : false;
20137
+ this.version = (_f = options === null || options === void 0 ? void 0 : options.version) !== null && _f !== void 0 ? _f : '1';
20138
+ const baseURL = `${secure ? 'https' : 'http'}://${host}:${port}/v${this.version}`;
20139
+ this.client = axios.create({ baseURL });
20140
+ }
20141
+ // تسجيل سيرفس
20142
+ async registerService(data) {
20143
+ const res = await this.client.post('/service/register', data);
20144
+ return res.data;
20145
+ }
20146
+ // جلب سيرفس عشوائي بالاسم
20147
+ async getRandomService(name) {
20148
+ const res = await this.client.get(`/service/random`, {
20149
+ params: { name },
20150
+ });
20151
+ return res.data;
20152
+ }
20153
+ // جلب كل السيرفسات
20154
+ async listServices() {
20155
+ const res = await this.client.get('/service/list');
20156
+ return res.data;
20157
+ }
20158
+ // Health Check بسيط
20159
+ async checkHealth() {
20160
+ const res = await this.client.get('/health');
20161
+ return res.data;
20162
+ }
20163
+ }
20164
+
20165
+ // src/lib/client.ts
20166
+ let consulClient = null;
20167
+ let atlasClient = null;
20168
+ function toBoolean(value) {
20169
+ if (typeof value === 'boolean')
20170
+ return value;
20171
+ if (typeof value === 'string')
20172
+ return value.toLowerCase() === 'true';
20173
+ return false;
20174
+ }
20175
+ function initClient({ host = '127.0.0.1', port = 8500, secure = false }) {
20176
+ atlasClient = new AtlasClient({
20177
+ host: host !== null && host !== void 0 ? host : '127.0.0.1',
20178
+ port: port !== null && port !== void 0 ? port : 371,
20179
+ version: '1',
20180
+ });
20181
+ consulClient = new Consul({
20182
+ host: host !== null && host !== void 0 ? host : '127.0.0.1',
20183
+ port: port !== null && port !== void 0 ? port : 8500,
20184
+ secure: toBoolean(secure),
20185
+ });
20186
+ consulClient.agent.self(err => {
20187
+ if (err) {
20188
+ console.error('❌ Failed to connect to Consul:', err.message);
20189
+ }
20190
+ else {
20191
+ console.log('✅ Connected to Consul successfully');
20192
+ }
20193
+ });
20194
+ }
20195
+ function getAtlasClient() {
20196
+ if (!atlasClient) {
20197
+ throw new Error('atlas client not initialized. Call initClient() first.');
20198
+ }
20199
+ return atlasClient;
20200
+ }
20201
+ function getClient() {
20202
+ if (!consulClient) {
20203
+ throw new Error('Consul client not initialized. Call initClient() first.');
20204
+ }
20205
+ return consulClient;
20206
+ }
20207
+
20208
+ const registeredServices = new Set();
20209
+ async function registerService(options) {
20210
+ var _a, _b, _c, _d;
20211
+ const { name, id, port, address = 'localhost', check, tags, meta } = options;
20212
+ const atlasClient = getAtlasClient();
20213
+ await atlasClient.registerService({
20214
+ address,
20215
+ port,
20216
+ name,
20217
+ }).then((res) => {
20218
+ console.log("🚀 ~ registerService ~ res:", res);
20219
+ });
20220
+ if (registeredServices.has(id)) {
20221
+ console.log(`⚠️ Service "${id}" is already registered.`);
20222
+ return;
20223
+ }
20224
+ const serviceDefinition = {
20225
+ name,
20226
+ id,
20227
+ address,
20228
+ port,
20229
+ tags,
20230
+ meta,
20231
+ };
20232
+ if (check !== false) {
20233
+ const checkDefinition = {
20234
+ name: (_a = check === null || check === void 0 ? void 0 : check.name) !== null && _a !== void 0 ? _a : `${name}-check`,
20235
+ http: (_b = check === null || check === void 0 ? void 0 : check.http) !== null && _b !== void 0 ? _b : `http://${address}:${port}/health`,
20236
+ interval: (_c = check === null || check === void 0 ? void 0 : check.interval) !== null && _c !== void 0 ? _c : '10s',
20237
+ timeout: (_d = check === null || check === void 0 ? void 0 : check.timeout) !== null && _d !== void 0 ? _d : '5s',
20238
+ };
20239
+ if (check === null || check === void 0 ? void 0 : check.deregistercriticalserviceafter) {
20240
+ checkDefinition.deregistercriticalserviceafter = check.deregistercriticalserviceafter;
20241
+ }
20242
+ serviceDefinition.check = checkDefinition;
20243
+ }
20244
+ await getClient().agent.service.register(serviceDefinition);
20245
+ registeredServices.add(id);
20246
+ console.log(`✅ Service "${id}" registered successfully.`);
20247
+ }
20248
+ async function deregisterService(id) {
20249
+ if (!registeredServices.has(id)) {
20250
+ console.log(`⚠️ Service "${id}" is not registered.`);
20251
+ return;
20252
+ }
20253
+ await getClient().agent.service.deregister(id);
20254
+ registeredServices.delete(id);
20255
+ console.log(`🛑 Service "${id}" deregistered successfully.`);
20256
+ }
20257
+
20258
+ const BASE_LOG_DIR$2 = '/home/log';
20259
+ // اسم السيرفس الحالي اللي بيعمل الـ discovery
20260
+ const CURRENT_SERVICE$2 = process.env.SERVICE_NAME || 'unknown-service';
20261
+ async function ensureLogDir$2(dir) {
20262
+ await promises.mkdir(dir, { recursive: true });
20263
+ }
20264
+ function formatLogLine(targetService, instance, elapsedMs) {
20265
+ var _a, _b, _c, _d, _e;
20266
+ const ts = new Date().toISOString();
20267
+ const addr = (_b = (_a = instance.ServiceAddress) !== null && _a !== void 0 ? _a : instance.Address) !== null && _b !== void 0 ? _b : 'unknown';
20268
+ const port = (_c = instance.ServicePort) !== null && _c !== void 0 ? _c : 'unknown';
20269
+ const node = (_d = instance.Node) !== null && _d !== void 0 ? _d : 'N/A';
20270
+ const id = (_e = instance.ServiceID) !== null && _e !== void 0 ? _e : 'N/A';
20271
+ const elapsed = elapsedMs !== undefined ? ` | Elapsed=${elapsedMs}ms` : '';
20272
+ return `${ts} | Target=${targetService} | ${addr}:${port} | Node=${node} | ID=${id}${elapsed}\n`;
20273
+ }
20274
+ async function appendDiscoveryLog(targetService, instance, elapsedMs) {
20275
+ try {
20276
+ // فولدر خاص بالسيرفس الحالي
20277
+ const serviceDir = path.join(BASE_LOG_DIR$2, CURRENT_SERVICE$2);
20278
+ await ensureLogDir$2(serviceDir);
20279
+ // اللوج يروح في ملف ثابت detect.log
20280
+ const file = path.join(serviceDir, 'detect.log');
20281
+ const line = formatLogLine(targetService, instance, elapsedMs);
20282
+ await promises.appendFile(file, line, { encoding: 'utf8' });
20283
+ }
20284
+ catch (err) {
20285
+ console.error('❌ Failed to write discovery log:', err);
20286
+ }
20287
+ }
20288
+
20289
+ const store = new Map();
20290
+ /**
20291
+ * Set a value in memory with optional TTL (ms).
20292
+ */
20293
+ function set(key, value, ttl) {
20294
+ const record = { value };
20295
+ {
20296
+ record.expiresAt = Date.now() + ttl;
20297
+ }
20298
+ store.set(key, record);
20299
+ }
20300
+ /**
20301
+ * Get a value from memory.
20302
+ * Returns undefined if key does not exist or expired.
20303
+ */
20304
+ function get(key) {
20305
+ const record = store.get(key);
20306
+ if (!record)
20307
+ return undefined;
20308
+ if (record.expiresAt && record.expiresAt < Date.now()) {
20309
+ store.delete(key);
20310
+ return undefined;
20311
+ }
20312
+ return record.value;
20313
+ }
20314
+
20315
+ const CACHE_TTL = 60000;
20316
+ async function listServices() {
20317
+ const cacheKey = 'services:list';
20318
+ const cached = get(cacheKey);
20319
+ if (cached)
20320
+ return cached;
20321
+ const services = await getClient().agent.service.list();
20322
+ const values = Object.values(services);
20323
+ set(cacheKey, values, CACHE_TTL);
20324
+ return values;
20325
+ }
20326
+ async function getServiceInstances(serviceName) {
20327
+ const cacheKey = `services:${serviceName}`;
20328
+ const cached = get(cacheKey);
20329
+ if (cached)
20330
+ return cached;
20331
+ const start = Date.now();
20332
+ const services = await getClient().catalog.service.nodes(serviceName);
20333
+ const elapsed = Date.now() - start;
20334
+ console.log(`⏱️ Discovery for ${serviceName} took ${elapsed}ms`);
20335
+ set(cacheKey, services, CACHE_TTL);
20336
+ return services;
20337
+ }
20338
+ async function getRandomServiceInstance(serviceName) {
20339
+ const cacheKey = `random:${serviceName}`;
20340
+ const cached = get(cacheKey);
20341
+ if (cached)
20342
+ return cached;
20343
+ const start = Date.now();
20344
+ const instances = await getServiceInstances(serviceName);
20345
+ if (!instances.length)
20346
+ throw new Error(`Service "${serviceName}" not found`);
20347
+ const randomIndex = Math.floor(Math.random() * instances.length);
20348
+ const instance = instances[randomIndex];
20349
+ const elapsed = Date.now() - start;
20350
+ await appendDiscoveryLog(serviceName, instance, elapsed);
20351
+ // cache random instance
20352
+ set(cacheKey, instance, CACHE_TTL);
20353
+ return instance;
20354
+ }
20355
+ async function getServiceUrl(serviceName) {
20356
+ const cacheKey = `url:${serviceName}`;
20357
+ const cached = get(cacheKey);
20358
+ if (cached)
20359
+ return cached;
20360
+ const instance = await getRandomServiceInstance(serviceName);
20361
+ const url = `http://${instance.ServiceAddress}:${instance.ServicePort}`;
20362
+ // cache url
20363
+ set(cacheKey, url, CACHE_TTL);
20364
+ return url;
20365
+ }
20366
+
20367
+ const BASE_LOG_DIR$1 = '/home/log';
20368
+ const CURRENT_SERVICE$1 = process.env.SERVICE_NAME || 'unknown-service';
20369
+ async function ensureLogDir$1(dir) {
20316
20370
  await promises.mkdir(dir, { recursive: true });
20317
20371
  }
20318
20372
  function getLogFileForStatus(status) {
20319
20373
  const date = new Date().toISOString().split('T')[0]; // YYYY-MM-DD
20320
- const serviceDir = path.join(BASE_LOG_DIR, CURRENT_SERVICE);
20374
+ const serviceDir = path.join(BASE_LOG_DIR$1, CURRENT_SERVICE$1);
20321
20375
  if (status >= 200 && status < 300)
20322
20376
  return path.join(serviceDir, `calls-2xx-${date}.log`);
20323
20377
  if (status >= 400 && status < 500)
@@ -20329,13 +20383,13 @@ function getLogFileForStatus(status) {
20329
20383
  function formatCallLogLine(targetService, url, method, status, elapsedMs, errorMessage) {
20330
20384
  const ts = new Date().toISOString();
20331
20385
  const errPart = errorMessage ? ` | Error="${errorMessage}"` : '';
20332
- return `${ts} | Caller=${CURRENT_SERVICE} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms${errPart}\n`;
20386
+ return `${ts} | Caller=${CURRENT_SERVICE$1} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms${errPart}\n`;
20333
20387
  }
20334
20388
  async function appendCallLog(targetService, url, method, status, elapsedMs, errorMessage) {
20335
20389
  try {
20336
20390
  const file = getLogFileForStatus(status);
20337
20391
  const dir = path.dirname(file);
20338
- await ensureLogDir(dir);
20392
+ await ensureLogDir$1(dir);
20339
20393
  const line = formatCallLogLine(targetService, url, method, status, elapsedMs, errorMessage);
20340
20394
  await promises.appendFile(file, line, { encoding: 'utf8' });
20341
20395
  }
@@ -20344,18 +20398,48 @@ async function appendCallLog(targetService, url, method, status, elapsedMs, erro
20344
20398
  }
20345
20399
  }
20346
20400
 
20401
+ const BASE_LOG_DIR = '/home/log';
20402
+ const CURRENT_SERVICE = process.env.SERVICE_NAME || 'unknown-service';
20403
+ const THRESHOLD = Number(process.env.SLOW_CALL_THRESHOLD || 200); // الافتراضي 200ms
20404
+ async function ensureLogDir(dir) {
20405
+ await promises.mkdir(dir, { recursive: true });
20406
+ }
20407
+ function getLogFile() {
20408
+ const serviceDir = path.join(BASE_LOG_DIR, CURRENT_SERVICE);
20409
+ return path.join(serviceDir, 'slow-calls.log');
20410
+ }
20411
+ function formatSlowCallLine(targetService, url, method, status, elapsedMs) {
20412
+ const ts = new Date().toISOString();
20413
+ return `${ts} | Caller=${CURRENT_SERVICE} | Target=${targetService} | ${method.toUpperCase()} ${url} | Status=${status} | Elapsed=${elapsedMs}ms\n`;
20414
+ }
20415
+ async function appendSlowCallLog(targetService, url, method, status, elapsedMs) {
20416
+ if (elapsedMs < THRESHOLD)
20417
+ return; // ما يكتبش غير اللي عدّى الحد
20418
+ try {
20419
+ const file = getLogFile();
20420
+ const dir = path.dirname(file);
20421
+ await ensureLogDir(dir);
20422
+ const line = formatSlowCallLine(targetService, url, method, status, elapsedMs);
20423
+ await promises.appendFile(file, line, { encoding: 'utf8' });
20424
+ }
20425
+ catch (err) {
20426
+ console.error('❌ Failed to write slow call log:', err);
20427
+ }
20428
+ }
20429
+
20347
20430
  async function callService(serviceName, options = {}) {
20348
20431
  var _a, _b, _c, _d, _e, _f, _g, _h, _j, _k, _l;
20349
20432
  const { method = 'GET', path = '/', data, headers, params, } = options;
20350
20433
  const start = Date.now();
20351
20434
  try {
20352
- // ...
20353
20435
  const instance = await getRandomServiceInstance(serviceName);
20354
20436
  const url = `http://${instance.ServiceAddress}:${instance.ServicePort}${path}`;
20355
20437
  const response = await axios.request({ url, method, data, headers, params });
20356
20438
  const elapsed = Date.now() - start;
20357
- // سجل في فولدر السيرفس الحالي (مش target)
20439
+ // 📌 سجل الكول
20358
20440
  await appendCallLog(serviceName, url, method, response.status, elapsed);
20441
+ // 📌 لو بطيء → يتسجل في slow-calls.log
20442
+ await appendSlowCallLog(serviceName, url, method, response.status, elapsed);
20359
20443
  return response.data;
20360
20444
  }
20361
20445
  catch (error) {
@@ -20364,13 +20448,15 @@ async function callService(serviceName, options = {}) {
20364
20448
  const url = (_d = (_c = error.config) === null || _c === void 0 ? void 0 : _c.url) !== null && _d !== void 0 ? _d : '';
20365
20449
  const methodUsed = (_f = (_e = error.config) === null || _e === void 0 ? void 0 : _e.method) !== null && _f !== void 0 ? _f : method;
20366
20450
  const message = (_g = error.message) !== null && _g !== void 0 ? _g : 'Unknown error';
20367
- // 📌 سجل الفشل مع رسالة الخطأ
20451
+ // 📌 سجل الفشل
20368
20452
  await appendCallLog(serviceName, url, methodUsed, status, elapsed, message);
20453
+ // 📌 لو بطيء → يتسجل برضه في slow-calls.log
20454
+ await appendSlowCallLog(serviceName, url, methodUsed, status, elapsed);
20369
20455
  return {
20370
20456
  success: false,
20371
20457
  message,
20372
20458
  status,
20373
- code: (_k = (_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.code) !== null && _k !== void 0 ? _k : "",
20459
+ code: (_k = (_j = (_h = error.response) === null || _h === void 0 ? void 0 : _h.data) === null || _j === void 0 ? void 0 : _j.code) !== null && _k !== void 0 ? _k : '',
20374
20460
  data: (_l = error.response) === null || _l === void 0 ? void 0 : _l.data,
20375
20461
  };
20376
20462
  }
@@ -20534,5 +20620,5 @@ async function dataLink(data, schema) {
20534
20620
  return isArray ? result : result[0];
20535
20621
  }
20536
20622
 
20537
- export { callService, dataLink, deregisterService, getClient, getRandomServiceInstance, getServiceInstances, getServiceUrl, initClient, listServices, registerService, toBoolean };
20623
+ export { callService, dataLink, deregisterService, getAtlasClient, getClient, getRandomServiceInstance, getServiceInstances, getServiceUrl, initClient, listServices, registerService, toBoolean };
20538
20624
  //# sourceMappingURL=index.esm.js.map
@@ -0,0 +1 @@
1
+ export declare function appendSlowCallLog(targetService: string, url: string, method: string, status: number, elapsedMs: number): Promise<void>;
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "node-consul-service",
3
- "version": "1.0.71",
3
+ "version": "1.0.73",
4
4
  "main": "dist/index.cjs.js",
5
5
  "module": "dist/index.esm.js",
6
6
  "types": "dist/index.d.ts",