service-call-library-dev 0.1.0

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/dist/index.cjs ADDED
@@ -0,0 +1,1122 @@
1
+ "use strict";
2
+ var __create = Object.create;
3
+ var __defProp = Object.defineProperty;
4
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __getProtoOf = Object.getPrototypeOf;
7
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
8
+ var __esm = (fn, res) => function __init() {
9
+ return fn && (res = (0, fn[__getOwnPropNames(fn)[0]])(fn = 0)), res;
10
+ };
11
+ var __export = (target, all) => {
12
+ for (var name in all)
13
+ __defProp(target, name, { get: all[name], enumerable: true });
14
+ };
15
+ var __copyProps = (to, from, except, desc) => {
16
+ if (from && typeof from === "object" || typeof from === "function") {
17
+ for (let key of __getOwnPropNames(from))
18
+ if (!__hasOwnProp.call(to, key) && key !== except)
19
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
20
+ }
21
+ return to;
22
+ };
23
+ var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
24
+ // If the importer is in node compatibility mode or this is not an ESM
25
+ // file that has been converted to a CommonJS file using a Babel-
26
+ // compatible transform (i.e. "__esModule" has not been set), then set
27
+ // "default" to the CommonJS "module.exports" for node compatibility.
28
+ isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
29
+ mod
30
+ ));
31
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
32
+ var __decorateClass = (decorators, target, key, kind) => {
33
+ var result = kind > 1 ? void 0 : kind ? __getOwnPropDesc(target, key) : target;
34
+ for (var i = decorators.length - 1, decorator; i >= 0; i--)
35
+ if (decorator = decorators[i])
36
+ result = (kind ? decorator(target, key, result) : decorator(result)) || result;
37
+ if (kind && result) __defProp(target, key, result);
38
+ return result;
39
+ };
40
+ var __decorateParam = (index, decorator) => (target, key) => decorator(target, key, index);
41
+
42
+ // src/logging/logger.service.ts
43
+ var import_winston, LoggerService;
44
+ var init_logger_service = __esm({
45
+ "src/logging/logger.service.ts"() {
46
+ "use strict";
47
+ import_winston = __toESM(require("winston"), 1);
48
+ LoggerService = class {
49
+ static {
50
+ this.logger = import_winston.default.createLogger({
51
+ level: process.env.LOG_LEVEL ?? "info",
52
+ format: import_winston.default.format.combine(
53
+ import_winston.default.format.timestamp(),
54
+ import_winston.default.format.errors({ stack: true }),
55
+ import_winston.default.format.json()
56
+ ),
57
+ transports: [new import_winston.default.transports.Console()]
58
+ });
59
+ }
60
+ static info(message, meta) {
61
+ this.logger.info(message, meta);
62
+ }
63
+ static error(message, meta) {
64
+ this.logger.error(message, meta);
65
+ }
66
+ static warn(message, meta) {
67
+ this.logger.warn(message, meta);
68
+ }
69
+ static debug(message, meta) {
70
+ this.logger.debug(message, meta);
71
+ }
72
+ };
73
+ }
74
+ });
75
+
76
+ // src/utils/zookeeperConfig.ts
77
+ var getZooKeeperConfig;
78
+ var init_zookeeperConfig = __esm({
79
+ "src/utils/zookeeperConfig.ts"() {
80
+ "use strict";
81
+ getZooKeeperConfig = () => {
82
+ const config = {
83
+ connectionString: process.env.ZOOKEEPER_CONNECTION_STRING,
84
+ infraPath: process.env.ZOOKEEPER_INFRA_PATH,
85
+ servicePath: process.env.ZOOKEEPER_SERVICE_PATH,
86
+ user: process.env.ZOOKEEPER_USER,
87
+ password: process.env.ZOOKEEPER_PASSWORD
88
+ };
89
+ if (!config.connectionString) {
90
+ throw new Error("ZOOKEEPER_CONNECTION_STRING is required");
91
+ }
92
+ return config;
93
+ };
94
+ }
95
+ });
96
+
97
+ // src/utils/zookeeperCrypto.ts
98
+ var import_crypto, fs, path, LOG_PREFIX, INFRA_VALUE_REGEX, parseInfraValue, getPrivateKeyPath, decryptWithAlias, getServicePrivateKeyPath, decryptWithPrivateKey;
99
+ var init_zookeeperCrypto = __esm({
100
+ "src/utils/zookeeperCrypto.ts"() {
101
+ "use strict";
102
+ import_crypto = __toESM(require("crypto"), 1);
103
+ fs = __toESM(require("fs"), 1);
104
+ path = __toESM(require("path"), 1);
105
+ init_logger_service();
106
+ LOG_PREFIX = "[ZK] ";
107
+ INFRA_VALUE_REGEX = /^devEnc:([A-Za-z0-9+/=_-]+):([A-Za-z0-9-_]+)$/;
108
+ parseInfraValue = (value) => {
109
+ const match = value.match(INFRA_VALUE_REGEX);
110
+ if (!match) return null;
111
+ return {
112
+ prefix: "devEnc",
113
+ encryptedData: match[1],
114
+ alias: match[2]
115
+ };
116
+ };
117
+ getPrivateKeyPath = (alias) => {
118
+ const baseDir = process.env.PRIVATE_KEY_DIR || path.join(process.cwd(), "keys");
119
+ return path.join(baseDir, `private_key_${alias}.pem`);
120
+ };
121
+ decryptWithAlias = (encryptedData, alias) => {
122
+ try {
123
+ const privateKeyPath = getPrivateKeyPath(alias);
124
+ if (!fs.existsSync(privateKeyPath)) {
125
+ throw new Error(`Private key file not found for alias '${alias}': ${privateKeyPath}`);
126
+ }
127
+ const privateKey = fs.readFileSync(privateKeyPath, "utf8");
128
+ const buffer = Buffer.from(encryptedData, "base64");
129
+ const attempts = [
130
+ {
131
+ key: privateKey,
132
+ padding: import_crypto.default.constants.RSA_PKCS1_OAEP_PADDING,
133
+ oaepHash: "sha256"
134
+ },
135
+ {
136
+ key: privateKey,
137
+ padding: import_crypto.default.constants.RSA_PKCS1_OAEP_PADDING,
138
+ oaepHash: "sha1"
139
+ },
140
+ {
141
+ key: privateKey,
142
+ padding: import_crypto.default.constants.RSA_PKCS1_PADDING
143
+ }
144
+ ];
145
+ let lastError = null;
146
+ for (const options of attempts) {
147
+ try {
148
+ const out = import_crypto.default.privateDecrypt(options, buffer);
149
+ return out.toString("utf-8");
150
+ } catch (error) {
151
+ lastError = error;
152
+ }
153
+ }
154
+ LoggerService.error(`${LOG_PREFIX}RSA decryption failed with alias '${alias}'`, {
155
+ error: lastError
156
+ });
157
+ throw new Error(`Decryption failed for alias '${alias}'`);
158
+ } catch (error) {
159
+ LoggerService.error(`${LOG_PREFIX}failed to decrypt with alias '${alias}'`, {
160
+ error: error?.message || error
161
+ });
162
+ throw new Error(`Decryption failed for alias '${alias}': ${error.message}`);
163
+ }
164
+ };
165
+ getServicePrivateKeyPath = () => {
166
+ const baseDir = process.env.PRIVATE_KEY_DIR || path.join(process.cwd(), "keys");
167
+ return path.join(baseDir, "private.pem");
168
+ };
169
+ decryptWithPrivateKey = (encryptedData) => {
170
+ try {
171
+ const privateKeyPath = getServicePrivateKeyPath();
172
+ if (!fs.existsSync(privateKeyPath)) {
173
+ throw new Error(`Private key file not found: ${privateKeyPath}`);
174
+ }
175
+ const privateKey = fs.readFileSync(privateKeyPath, "utf8");
176
+ const buffer = Buffer.from(encryptedData, "base64");
177
+ const attempts = [
178
+ {
179
+ key: privateKey,
180
+ padding: import_crypto.default.constants.RSA_PKCS1_OAEP_PADDING,
181
+ oaepHash: "sha256"
182
+ },
183
+ {
184
+ key: privateKey,
185
+ padding: import_crypto.default.constants.RSA_PKCS1_OAEP_PADDING,
186
+ oaepHash: "sha1"
187
+ },
188
+ {
189
+ key: privateKey,
190
+ padding: import_crypto.default.constants.RSA_PKCS1_PADDING
191
+ }
192
+ ];
193
+ let lastError = null;
194
+ for (const options of attempts) {
195
+ try {
196
+ const out = import_crypto.default.privateDecrypt(options, buffer);
197
+ return out.toString("utf-8");
198
+ } catch (error) {
199
+ lastError = error;
200
+ }
201
+ }
202
+ LoggerService.error(`${LOG_PREFIX}RSA decryption failed with private.pem`, {
203
+ error: lastError
204
+ });
205
+ throw new Error("All decryption attempts failed");
206
+ } catch (error) {
207
+ LoggerService.error(`${LOG_PREFIX}failed to decrypt with private.pem`, {
208
+ error: error?.message || error
209
+ });
210
+ throw new Error(`Decryption failed: ${error.message}`);
211
+ }
212
+ };
213
+ }
214
+ });
215
+
216
+ // src/utils/zookeeper.ts
217
+ var zookeeper_exports = {};
218
+ __export(zookeeper_exports, {
219
+ default: () => zookeeper_default,
220
+ registerRestartCallback: () => registerRestartCallback
221
+ });
222
+ var import_node_zookeeper_client, process2, SESSION_TIMEOUT, CONNECT_TIMEOUT, LOG_PREFIX2, isInfraDataBeingProcessed, isServiceDataBeingProcessed, hasLoadedInfraOnce, hasLoadedServiceOnce, currentClient, connectWatchdog, hasInfraPath, hasServicePath, restartCallback, registerRestartCallback, processEnvironmentData, decryptInfraValue, decryptServiceValue, handleZooKeeperData, connectToPath, cleanupClient, startZooKeeperClient, zookeeper_default;
223
+ var init_zookeeper = __esm({
224
+ "src/utils/zookeeper.ts"() {
225
+ "use strict";
226
+ import_node_zookeeper_client = __toESM(require("node-zookeeper-client"), 1);
227
+ process2 = __toESM(require("process"), 1);
228
+ init_zookeeperConfig();
229
+ init_zookeeperCrypto();
230
+ SESSION_TIMEOUT = 3e7;
231
+ CONNECT_TIMEOUT = 1e7;
232
+ LOG_PREFIX2 = "[ZK] ";
233
+ isInfraDataBeingProcessed = false;
234
+ isServiceDataBeingProcessed = false;
235
+ hasLoadedInfraOnce = false;
236
+ hasLoadedServiceOnce = false;
237
+ currentClient = null;
238
+ connectWatchdog = null;
239
+ hasInfraPath = false;
240
+ hasServicePath = false;
241
+ restartCallback = null;
242
+ registerRestartCallback = (callback) => {
243
+ restartCallback = callback;
244
+ };
245
+ processEnvironmentData = (data, isInfraPath) => {
246
+ const pathType = isInfraPath ? "infra" : "service";
247
+ const lines = data.split("\n");
248
+ let processedCount = 0;
249
+ let encryptedCount = 0;
250
+ let errorCount = 0;
251
+ const errors = [];
252
+ for (const line of lines) {
253
+ if (!line.trim()) continue;
254
+ const firstEqualIndex = line.indexOf("=");
255
+ if (firstEqualIndex === -1) continue;
256
+ const key = line.slice(0, firstEqualIndex).trim();
257
+ const value = line.slice(firstEqualIndex + 1).trim();
258
+ if (!key || value.length === 0) continue;
259
+ try {
260
+ if (value.startsWith("devEnc:") && isInfraPath) {
261
+ encryptedCount++;
262
+ let decryptedValue = decryptInfraValue(value);
263
+ decryptedValue = decryptedValue.replace(/(\r?\n)$/, "");
264
+ process2.env[key] = decryptedValue;
265
+ } else if (value.startsWith("devEnc:")) {
266
+ encryptedCount++;
267
+ let decryptedValue = decryptServiceValue(value);
268
+ decryptedValue = decryptedValue.replace(/(\r?\n)$/, "");
269
+ process2.env[key] = decryptedValue;
270
+ } else {
271
+ process2.env[key] = value;
272
+ }
273
+ processedCount++;
274
+ } catch (error) {
275
+ errorCount++;
276
+ errors.push({
277
+ key,
278
+ error: error?.message || "Unknown decryption error"
279
+ });
280
+ }
281
+ }
282
+ if (errorCount > 0) {
283
+ console.log(
284
+ JSON.stringify({
285
+ type: "ZK",
286
+ message: `${LOG_PREFIX2}errors processing environment variables`,
287
+ pathType,
288
+ processedCount,
289
+ encryptedCount,
290
+ errorCount,
291
+ errors: errors.slice(0, 10),
292
+ totalErrors: errors.length,
293
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
294
+ })
295
+ );
296
+ }
297
+ };
298
+ decryptInfraValue = (value) => {
299
+ const encryptedValue = parseInfraValue(value);
300
+ if (!encryptedValue) {
301
+ throw new Error("Invalid encrypted value format");
302
+ }
303
+ const decryptedValue = decryptWithAlias(
304
+ encryptedValue.encryptedData,
305
+ encryptedValue.alias
306
+ );
307
+ return decryptedValue;
308
+ };
309
+ decryptServiceValue = (value) => {
310
+ const cleanValue = value.replace("devEnc:", "");
311
+ const encryptedValue = decryptWithPrivateKey(cleanValue);
312
+ return encryptedValue;
313
+ };
314
+ handleZooKeeperData = (client, zkPath, isInfraPath, resolve, reject) => {
315
+ const pathType = isInfraPath ? "infra" : "service";
316
+ const isBeingProcessed = isInfraPath ? isInfraDataBeingProcessed : isServiceDataBeingProcessed;
317
+ if (isBeingProcessed) return;
318
+ if (isInfraPath) {
319
+ isInfraDataBeingProcessed = true;
320
+ } else {
321
+ isServiceDataBeingProcessed = true;
322
+ }
323
+ client.getData(
324
+ zkPath,
325
+ (event) => {
326
+ if (event.type === import_node_zookeeper_client.default.Event.NODE_DATA_CHANGED) {
327
+ console.log(
328
+ JSON.stringify({
329
+ type: "ZK",
330
+ message: `${LOG_PREFIX2}Config changed detected, restarting application`,
331
+ pathType: isInfraPath ? "infra" : "service",
332
+ path: zkPath,
333
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
334
+ })
335
+ );
336
+ if (restartCallback) {
337
+ restartCallback().catch((error) => {
338
+ console.log(
339
+ JSON.stringify({
340
+ type: "ZK",
341
+ message: `${LOG_PREFIX2}Error during restart`,
342
+ error: {
343
+ message: error?.message || "Unknown error",
344
+ stack: error?.stack
345
+ },
346
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
347
+ })
348
+ );
349
+ process2.exit(0);
350
+ });
351
+ } else {
352
+ console.log(
353
+ JSON.stringify({
354
+ type: "ZK",
355
+ message: `${LOG_PREFIX2}No restart callback registered, exiting process`,
356
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
357
+ })
358
+ );
359
+ process2.exit(0);
360
+ }
361
+ }
362
+ },
363
+ (error, data) => {
364
+ if (isInfraPath) {
365
+ isInfraDataBeingProcessed = false;
366
+ } else {
367
+ isServiceDataBeingProcessed = false;
368
+ }
369
+ if (error) {
370
+ const errorMsg = `${LOG_PREFIX2}getData failed for ${pathType} path: ${zkPath}`;
371
+ console.log(
372
+ JSON.stringify({
373
+ type: "ZK",
374
+ message: errorMsg,
375
+ pathType,
376
+ path: zkPath,
377
+ error: {
378
+ message: error?.message || "Unknown error",
379
+ code: error?.code,
380
+ name: error?.name,
381
+ stack: error?.stack,
382
+ errno: error?.errno
383
+ },
384
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
385
+ })
386
+ );
387
+ reject(new Error(errorMsg));
388
+ return;
389
+ }
390
+ if (!data) {
391
+ reject(
392
+ new Error(
393
+ `${LOG_PREFIX2}No data received for ${pathType} path: ${zkPath}`
394
+ )
395
+ );
396
+ return;
397
+ }
398
+ try {
399
+ const rawData = data.toString("utf8");
400
+ processEnvironmentData(rawData, isInfraPath);
401
+ if (isInfraPath) {
402
+ hasInfraPath = true;
403
+ } else {
404
+ hasServicePath = true;
405
+ }
406
+ if (isInfraPath) {
407
+ if (!hasLoadedInfraOnce) {
408
+ hasLoadedInfraOnce = true;
409
+ console.log(
410
+ JSON.stringify({
411
+ type: "ZK",
412
+ message: `${LOG_PREFIX2}loaded infra environment variables`,
413
+ path: zkPath
414
+ })
415
+ );
416
+ }
417
+ } else {
418
+ if (!hasLoadedServiceOnce) {
419
+ hasLoadedServiceOnce = true;
420
+ console.log(
421
+ JSON.stringify({
422
+ type: "ZK",
423
+ message: `${LOG_PREFIX2}loaded service environment variables`,
424
+ path: zkPath
425
+ })
426
+ );
427
+ }
428
+ }
429
+ if (hasInfraPath && hasServicePath) {
430
+ resolve();
431
+ }
432
+ } catch (error2) {
433
+ const errorMsg = `${LOG_PREFIX2}error processing data for ${pathType} path: ${zkPath}`;
434
+ console.log(
435
+ JSON.stringify({
436
+ type: "ZK",
437
+ message: errorMsg,
438
+ pathType,
439
+ path: zkPath,
440
+ error: {
441
+ message: error2?.message || "Unknown error",
442
+ code: error2?.code,
443
+ name: error2?.name,
444
+ stack: error2?.stack
445
+ },
446
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
447
+ })
448
+ );
449
+ reject(new Error(errorMsg));
450
+ }
451
+ }
452
+ );
453
+ };
454
+ connectToPath = (client, zkPath, isInfraPath, resolve, reject) => {
455
+ const pathType = isInfraPath ? "infra" : "service";
456
+ client.exists(
457
+ zkPath,
458
+ () => {
459
+ },
460
+ (error, stat) => {
461
+ if (error) {
462
+ const errorMsg = `${LOG_PREFIX2}exists check failed for ${pathType} path: ${zkPath}`;
463
+ console.log(
464
+ JSON.stringify({
465
+ type: "ZK",
466
+ message: errorMsg,
467
+ pathType,
468
+ path: zkPath,
469
+ error: {
470
+ message: error?.message || "Unknown error",
471
+ code: error?.code,
472
+ name: error?.name,
473
+ stack: error?.stack,
474
+ errno: error?.errno
475
+ },
476
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
477
+ })
478
+ );
479
+ reject(new Error(errorMsg));
480
+ return;
481
+ }
482
+ if (stat) {
483
+ handleZooKeeperData(client, zkPath, isInfraPath, resolve, reject);
484
+ } else {
485
+ const errorMsg = `${LOG_PREFIX2}path does not exist: ${zkPath}`;
486
+ console.log(
487
+ JSON.stringify({
488
+ type: "ZK",
489
+ message: errorMsg,
490
+ pathType,
491
+ path: zkPath,
492
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
493
+ })
494
+ );
495
+ reject(new Error(errorMsg));
496
+ }
497
+ }
498
+ );
499
+ };
500
+ cleanupClient = () => {
501
+ try {
502
+ if (currentClient?.close) currentClient.close();
503
+ } catch (e) {
504
+ if (e?.message) {
505
+ console.log(
506
+ JSON.stringify({
507
+ type: "ZK",
508
+ message: `${LOG_PREFIX2}error closing client`,
509
+ error: {
510
+ message: e?.message,
511
+ stack: e?.stack
512
+ },
513
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
514
+ })
515
+ );
516
+ }
517
+ }
518
+ currentClient = null;
519
+ if (connectWatchdog) {
520
+ clearTimeout(connectWatchdog);
521
+ connectWatchdog = null;
522
+ }
523
+ };
524
+ startZooKeeperClient = () => {
525
+ return new Promise((resolve, reject) => {
526
+ let resolved = false;
527
+ const safeResolve = () => {
528
+ if (!resolved) {
529
+ resolved = true;
530
+ resolve();
531
+ }
532
+ };
533
+ try {
534
+ const config = getZooKeeperConfig();
535
+ console.log(
536
+ JSON.stringify({
537
+ type: "ZK",
538
+ message: `${LOG_PREFIX2}initializing`,
539
+ config: {
540
+ connectionString: config.connectionString,
541
+ infraPath: config.infraPath,
542
+ servicePath: config.servicePath,
543
+ hasAuth: !!(config.user && config.password),
544
+ user: config.user || null,
545
+ sessionTimeout: SESSION_TIMEOUT
546
+ }
547
+ })
548
+ );
549
+ cleanupClient();
550
+ hasInfraPath = false;
551
+ hasServicePath = false;
552
+ hasLoadedInfraOnce = false;
553
+ hasLoadedServiceOnce = false;
554
+ isInfraDataBeingProcessed = false;
555
+ isServiceDataBeingProcessed = false;
556
+ const client = import_node_zookeeper_client.default.createClient(config.connectionString, {
557
+ sessionTimeout: SESSION_TIMEOUT,
558
+ retries: 0
559
+ // No retries - fail fast
560
+ });
561
+ currentClient = client;
562
+ if (config.user && config.password) {
563
+ client.addAuthInfo(
564
+ "digest",
565
+ Buffer.from(`${config.user}:${config.password}`)
566
+ );
567
+ }
568
+ connectWatchdog = setTimeout(() => {
569
+ if (currentClient === client) {
570
+ cleanupClient();
571
+ const errorMsg = `${LOG_PREFIX2}Connection timeout after ${CONNECT_TIMEOUT}ms`;
572
+ console.log(
573
+ JSON.stringify({
574
+ type: "ZK",
575
+ message: errorMsg,
576
+ config: {
577
+ connectionString: config.connectionString
578
+ },
579
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
580
+ })
581
+ );
582
+ reject(new Error(errorMsg));
583
+ }
584
+ }, CONNECT_TIMEOUT);
585
+ client.on("connected", () => {
586
+ console.log(
587
+ JSON.stringify({
588
+ type: "ZK",
589
+ message: `${LOG_PREFIX2}connected`,
590
+ config: {
591
+ connectionString: config.connectionString,
592
+ infraPath: config.infraPath,
593
+ servicePath: config.servicePath,
594
+ user: config.user,
595
+ password: config.password
596
+ }
597
+ })
598
+ );
599
+ if (connectWatchdog) {
600
+ clearTimeout(connectWatchdog);
601
+ connectWatchdog = null;
602
+ }
603
+ connectToPath(client, config.infraPath, true, safeResolve, reject);
604
+ connectToPath(client, config.servicePath, false, safeResolve, reject);
605
+ });
606
+ client.on("disconnected", () => {
607
+ console.log(
608
+ JSON.stringify({
609
+ type: "ZK",
610
+ message: `${LOG_PREFIX2}disconnected`,
611
+ config: {
612
+ connectionString: config.connectionString
613
+ }
614
+ })
615
+ );
616
+ cleanupClient();
617
+ reject(new Error(`${LOG_PREFIX2}Disconnected from ZooKeeper`));
618
+ });
619
+ client.on("expired", () => {
620
+ console.log(
621
+ JSON.stringify({
622
+ type: "ZK",
623
+ message: `${LOG_PREFIX2}session expired`,
624
+ config: {
625
+ connectionString: config.connectionString
626
+ }
627
+ })
628
+ );
629
+ cleanupClient();
630
+ reject(new Error(`${LOG_PREFIX2}ZooKeeper session expired`));
631
+ });
632
+ client.on("error", (error) => {
633
+ console.log(
634
+ JSON.stringify({
635
+ type: "ZK",
636
+ message: `${LOG_PREFIX2}error`,
637
+ error: {
638
+ message: error?.message || "Unknown error",
639
+ code: error?.code,
640
+ name: error?.name,
641
+ stack: error?.stack,
642
+ errno: error?.errno,
643
+ syscall: error?.syscall,
644
+ address: error?.address,
645
+ port: error?.port
646
+ },
647
+ config: {
648
+ connectionString: config.connectionString
649
+ },
650
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
651
+ })
652
+ );
653
+ cleanupClient();
654
+ reject(
655
+ new Error(
656
+ `${LOG_PREFIX2}ZooKeeper error: ${error?.message || "Unknown error"}`
657
+ )
658
+ );
659
+ });
660
+ client.connect();
661
+ } catch (error) {
662
+ const config = getZooKeeperConfig();
663
+ console.log(
664
+ JSON.stringify({
665
+ type: "ZK",
666
+ message: `${LOG_PREFIX2}initialization failed`,
667
+ error: {
668
+ message: error?.message || "Unknown error",
669
+ code: error?.code,
670
+ name: error?.name,
671
+ stack: error?.stack,
672
+ errno: error?.errno,
673
+ syscall: error?.syscall
674
+ },
675
+ config: {
676
+ connectionString: config.connectionString,
677
+ infraPath: config.infraPath,
678
+ servicePath: config.servicePath,
679
+ hasAuth: !!(config.user && config.password)
680
+ },
681
+ timestamp: (/* @__PURE__ */ new Date()).toISOString()
682
+ })
683
+ );
684
+ cleanupClient();
685
+ reject(
686
+ new Error(
687
+ `${LOG_PREFIX2}Initialization exception: ${error?.message || "Unknown error"}`
688
+ )
689
+ );
690
+ }
691
+ });
692
+ };
693
+ zookeeper_default = startZooKeeperClient;
694
+ }
695
+ });
696
+
697
+ // src/index.ts
698
+ var index_exports = {};
699
+ __export(index_exports, {
700
+ ServiceCallLibrary: () => ServiceCallLibrary,
701
+ TYPES: () => TYPES
702
+ });
703
+ module.exports = __toCommonJS(index_exports);
704
+ var import_reflect_metadata = require("reflect-metadata");
705
+
706
+ // src/inversify.container.ts
707
+ var import_inversify7 = require("inversify");
708
+
709
+ // src/configs/redis-client.ts
710
+ var import_redis = require("redis");
711
+ init_logger_service();
712
+ var RedisClient = class _RedisClient {
713
+ constructor() {
714
+ this.reconnectAttempts = 0;
715
+ this.maxReconnectAttempts = 2;
716
+ this.connectPromise = null;
717
+ this.client = (0, import_redis.createClient)({
718
+ socket: {
719
+ host: process.env.REDIS_HOST ?? "127.0.0.1",
720
+ port: Number(process.env.REDIS_PORT) || 6379,
721
+ reconnectStrategy: (retries) => {
722
+ this.reconnectAttempts = retries;
723
+ if (retries > this.maxReconnectAttempts) {
724
+ LoggerService.error("Redis reconnect attempts exceeded", {
725
+ retries,
726
+ host: process.env.REDIS_HOST ?? "127.0.0.1",
727
+ port: Number(process.env.REDIS_PORT) || 6379
728
+ });
729
+ return new Error("Redis reconnect attempts exceeded");
730
+ }
731
+ return 1e3;
732
+ }
733
+ },
734
+ password: process.env.REDIS_PASSWORD || void 0
735
+ });
736
+ this.client.on("error", (err) => {
737
+ LoggerService.error("Redis error", {
738
+ error: err?.message || err,
739
+ reconnectAttempts: this.reconnectAttempts
740
+ });
741
+ });
742
+ this.client.on("connect", () => {
743
+ LoggerService.info("Redis connected", {
744
+ host: process.env.REDIS_HOST ?? "127.0.0.1",
745
+ port: Number(process.env.REDIS_PORT) || 6379
746
+ });
747
+ });
748
+ }
749
+ static getInstance() {
750
+ if (!_RedisClient.instance) {
751
+ _RedisClient.instance = new _RedisClient();
752
+ }
753
+ return _RedisClient.instance;
754
+ }
755
+ async connect() {
756
+ if (this.client.isOpen) {
757
+ return this.client;
758
+ }
759
+ if (!this.connectPromise) {
760
+ this.connectPromise = this.client.connect().catch((err) => {
761
+ LoggerService.error("Redis initial connect error", {
762
+ error: err?.message || err
763
+ });
764
+ this.connectPromise = null;
765
+ throw err;
766
+ });
767
+ }
768
+ return await this.connectPromise;
769
+ }
770
+ getClient() {
771
+ return this.client;
772
+ }
773
+ async disconnect() {
774
+ if (this.client.isOpen) {
775
+ await this.client.quit();
776
+ LoggerService.info("Redis disconnected");
777
+ }
778
+ }
779
+ isConnected() {
780
+ return this.client.isOpen;
781
+ }
782
+ };
783
+ var redis_client_default = RedisClient.getInstance();
784
+
785
+ // src/modules/cache/cacheService.ts
786
+ var import_inversify = require("inversify");
787
+ var CacheService = class {
788
+ constructor() {
789
+ this.client = redis_client_default.getClient();
790
+ }
791
+ async setValue(key, value, ttlInSeconds) {
792
+ const payload = JSON.stringify(value);
793
+ if (ttlInSeconds && ttlInSeconds > 0) {
794
+ await this.client.setEx(key, ttlInSeconds, payload);
795
+ return;
796
+ }
797
+ const result = await this.client.set(key, payload);
798
+ return result === null ? void 0 : result;
799
+ }
800
+ async getValue(key) {
801
+ const result = await this.client.get(key);
802
+ return result ? JSON.parse(result) : null;
803
+ }
804
+ async deleteValue(key) {
805
+ await this.client.del(key);
806
+ }
807
+ async hSet(key, hash) {
808
+ return this.client.hSet(key, hash);
809
+ }
810
+ async hmGet(key, ...fields) {
811
+ return this.client.hmGet(key, fields);
812
+ }
813
+ async hGetAll(key) {
814
+ return this.client.hGetAll(key);
815
+ }
816
+ async expire(key, ttlSeconds) {
817
+ return this.client.expire(key, ttlSeconds);
818
+ }
819
+ async sAdd(key, ...members) {
820
+ return this.client.sAdd(key, members);
821
+ }
822
+ async sMembers(key) {
823
+ return this.client.sMembers(key);
824
+ }
825
+ async sRem(key, ...members) {
826
+ return this.client.sRem(key, members);
827
+ }
828
+ async sCard(key) {
829
+ return this.client.sCard(key);
830
+ }
831
+ async del(...keys) {
832
+ return this.client.del(keys);
833
+ }
834
+ multi() {
835
+ return this.client.multi();
836
+ }
837
+ };
838
+ CacheService = __decorateClass([
839
+ (0, import_inversify.injectable)()
840
+ ], CacheService);
841
+
842
+ // src/modules/cache/cacheController.ts
843
+ var import_inversify2 = require("inversify");
844
+
845
+ // src/inversify.types.ts
846
+ var TYPES = {
847
+ CacheService: /* @__PURE__ */ Symbol.for("CacheService"),
848
+ CacheController: /* @__PURE__ */ Symbol.for("CacheController"),
849
+ SsoController: /* @__PURE__ */ Symbol.for("SsoController"),
850
+ SsoService: /* @__PURE__ */ Symbol.for("SsoService")
851
+ };
852
+
853
+ // src/types/cache.types.ts
854
+ var REQUIRED_BIN_NAMES = ["bin1", "bin2", "bin3", "bin4", "bin5"];
855
+
856
+ // src/modules/cache/cacheController.ts
857
+ var SET_NAME_PREFIX = process.env.SCRIPT_SET_NAME_PREFIX ?? "scriptSet";
858
+ var DEFAULT_EXPIRE_TIME_MS = Number(
859
+ process.env.SCRIPT_PUT_CACHE_EXPIRE_TIME_MS ?? 6e5
860
+ );
861
+ var CacheController = class {
862
+ constructor(cacheService) {
863
+ this.cacheService = cacheService;
864
+ }
865
+ async putScriptRecord(setName, key, record, ttlSeconds) {
866
+ for (const bin of REQUIRED_BIN_NAMES) {
867
+ if (typeof record[bin] === "undefined") {
868
+ throw new Error(`Field ${bin} is required`);
869
+ }
870
+ }
871
+ const safeRecord = {};
872
+ for (const bin of REQUIRED_BIN_NAMES) {
873
+ const value = record[bin];
874
+ if (typeof value !== "string") {
875
+ throw new Error(`Invalid value for ${bin}`);
876
+ }
877
+ safeRecord[bin] = value;
878
+ }
879
+ const redisKey = `${setName}:${key}`;
880
+ const ttl = typeof ttlSeconds === "number" ? ttlSeconds : Math.floor(DEFAULT_EXPIRE_TIME_MS / 1e3);
881
+ const multi = this.cacheService.multi();
882
+ const entries = Object.entries(safeRecord);
883
+ if (!entries.length) {
884
+ throw new Error("No record found to store in Redis");
885
+ }
886
+ for (const [field, value] of entries) {
887
+ multi.hSet(redisKey, field, value);
888
+ }
889
+ if (ttl > 0) {
890
+ multi.expire(redisKey, ttl);
891
+ }
892
+ for (const bin of REQUIRED_BIN_NAMES) {
893
+ const value = safeRecord[bin];
894
+ if (value) {
895
+ multi.sAdd(`index:${setName}:${bin}:${value}`, redisKey);
896
+ }
897
+ }
898
+ multi.sAdd(`set:${setName}:keys`, redisKey);
899
+ await multi.exec();
900
+ return { redisKey, ttl };
901
+ }
902
+ async getScriptRecord(setName, key) {
903
+ const redisKey = `${setName}:${key}`;
904
+ const values = await this.cacheService.hmGet(redisKey, ...REQUIRED_BIN_NAMES);
905
+ if (!values || values.every((v) => v === null)) {
906
+ return null;
907
+ }
908
+ const record = {};
909
+ REQUIRED_BIN_NAMES.forEach((bin, i) => {
910
+ record[bin] = values[i];
911
+ });
912
+ return record;
913
+ }
914
+ async equalScriptRecordsWithIndex(setName, binName, value) {
915
+ const indexKey = this.buildIndexKey(setName, binName, value);
916
+ const redisKeys = await this.cacheService.sMembers(indexKey);
917
+ if (!redisKeys.length) {
918
+ return [];
919
+ }
920
+ const multi = this.cacheService.multi();
921
+ for (const key of redisKeys) {
922
+ multi.hGetAll(key);
923
+ }
924
+ const responses = await multi.exec();
925
+ if (!responses) {
926
+ throw new Error("Pipeline execution failed");
927
+ }
928
+ return responses.map((record, idx) => {
929
+ const formattedRecord = {};
930
+ REQUIRED_BIN_NAMES.forEach((bin) => {
931
+ formattedRecord[bin] = record[bin] ?? null;
932
+ });
933
+ return {
934
+ redisKey: redisKeys[idx],
935
+ record: formattedRecord
936
+ };
937
+ });
938
+ }
939
+ async countScriptRecordsWithIndex(setName, binName, value) {
940
+ return this.cacheService.sCard(this.buildIndexKey(setName, binName, value));
941
+ }
942
+ async deleteScriptRecord(setName, key) {
943
+ const redisKey = `${setName}:${key}`;
944
+ const hash = await this.cacheService.hGetAll(redisKey);
945
+ if (!hash || !Object.keys(hash).length) {
946
+ return false;
947
+ }
948
+ const multi = this.cacheService.multi();
949
+ multi.del(redisKey);
950
+ for (const bin of REQUIRED_BIN_NAMES) {
951
+ const value = hash[bin];
952
+ if (value) {
953
+ multi.sRem(this.buildIndexKey(setName, bin, value), redisKey);
954
+ }
955
+ }
956
+ multi.sRem(`set:${setName}:keys`, redisKey);
957
+ await multi.exec();
958
+ return true;
959
+ }
960
+ async createBaseStructureForScript(totalSets = 5) {
961
+ const multi = this.cacheService.multi();
962
+ for (let s = 1; s <= totalSets; s++) {
963
+ const setName = `${SET_NAME_PREFIX}${s}`;
964
+ const keyStr = `${setName}_key`;
965
+ const redisKey = `${setName}:${keyStr}`;
966
+ const hashMap = {};
967
+ for (const bin of REQUIRED_BIN_NAMES) {
968
+ hashMap[bin] = "DUMMY";
969
+ }
970
+ for (const [field, val] of Object.entries(hashMap)) {
971
+ multi.hSet(redisKey, field, val);
972
+ }
973
+ multi.sAdd(`set:${setName}:keys`, redisKey);
974
+ for (const bin of REQUIRED_BIN_NAMES) {
975
+ multi.sAdd(this.buildIndexKey(setName, bin, hashMap[bin]), redisKey);
976
+ }
977
+ }
978
+ await multi.exec();
979
+ }
980
+ async setValue(key, value, ttlInSeconds) {
981
+ return this.cacheService.setValue(key, value, ttlInSeconds);
982
+ }
983
+ async getValue(key) {
984
+ return this.cacheService.getValue(key);
985
+ }
986
+ async deleteValue(key) {
987
+ await this.cacheService.deleteValue(key);
988
+ }
989
+ buildIndexKey(setName, binName, value) {
990
+ return `index:${setName}:${binName}:${value}`;
991
+ }
992
+ };
993
+ CacheController = __decorateClass([
994
+ (0, import_inversify2.injectable)(),
995
+ __decorateParam(0, (0, import_inversify2.inject)(TYPES.CacheService))
996
+ ], CacheController);
997
+
998
+ // src/modules/sso/sso.controller.ts
999
+ var import_inversify4 = require("inversify");
1000
+ var SsoController = class {
1001
+ constructor(ssoService) {
1002
+ this.ssoService = ssoService;
1003
+ }
1004
+ async getUserByAccesstoken(AccessToken) {
1005
+ const getData = await this.ssoService.getUserByAccesstoken(AccessToken);
1006
+ return getData;
1007
+ }
1008
+ async getUserByIdentity(identity, identityType) {
1009
+ return await this.ssoService.getUserByIdentity(identity, identityType);
1010
+ }
1011
+ };
1012
+ SsoController = __decorateClass([
1013
+ (0, import_inversify4.injectable)(),
1014
+ __decorateParam(0, (0, import_inversify4.inject)(TYPES.SsoService))
1015
+ ], SsoController);
1016
+
1017
+ // src/modules/sso/sso.service.ts
1018
+ var import_inversify6 = require("inversify");
1019
+ var SsoService = class {
1020
+ async getUserByAccesstoken(AccessToken) {
1021
+ let data = null;
1022
+ try {
1023
+ const response = await fetch(`${process.env.SsoUrl}/users`, {
1024
+ method: "GET",
1025
+ headers: {
1026
+ "accept": "application/json",
1027
+ "Accept-Language": "en",
1028
+ "Authorization": `Bearer ${AccessToken}`
1029
+ }
1030
+ });
1031
+ data = await response.json();
1032
+ if (!response.ok) {
1033
+ throw new Error(`HTTP error! status: ${response.status}`);
1034
+ }
1035
+ return {
1036
+ data,
1037
+ error: false,
1038
+ errorMessage: ""
1039
+ };
1040
+ } catch (error) {
1041
+ return {
1042
+ data,
1043
+ error: true,
1044
+ errorMessage: error.message
1045
+ };
1046
+ }
1047
+ }
1048
+ async getUserByIdentity(identity, identityType) {
1049
+ const url = `http://sso-sandbox.sandpod.ir/social/POD/users/${identity}?identityType=${identityType}`;
1050
+ try {
1051
+ const response = await fetch(url, {
1052
+ method: "GET",
1053
+ headers: {
1054
+ "accept": "application/json",
1055
+ "Accept-Language": "en",
1056
+ "Authorization": `Bearer ${process.env.AuthToken}`
1057
+ }
1058
+ });
1059
+ const data = JSON.parse(await response.text());
1060
+ if (!response.ok) {
1061
+ throw new Error(`HTTP error! status: ${response.status} and error is ${data}`);
1062
+ }
1063
+ return {
1064
+ data,
1065
+ error: false,
1066
+ errorMessage: ""
1067
+ };
1068
+ } catch (error) {
1069
+ return {
1070
+ data: null,
1071
+ error: true,
1072
+ errorMessage: error
1073
+ };
1074
+ }
1075
+ }
1076
+ };
1077
+ SsoService = __decorateClass([
1078
+ (0, import_inversify6.injectable)()
1079
+ ], SsoService);
1080
+
1081
+ // src/inversify.container.ts
1082
+ function createContainer(_options = {}) {
1083
+ const container = new import_inversify7.Container();
1084
+ container.bind(TYPES.CacheService).to(CacheService).inSingletonScope();
1085
+ container.bind(TYPES.SsoService).to(SsoService).inSingletonScope();
1086
+ container.bind(TYPES.CacheController).to(CacheController).inSingletonScope();
1087
+ container.bind(TYPES.SsoController).to(SsoController).inSingletonScope();
1088
+ return container;
1089
+ }
1090
+
1091
+ // src/service-call-library.ts
1092
+ var ServiceCallLibrary = class {
1093
+ constructor(options = {}) {
1094
+ this.ready = null;
1095
+ this.container = createContainer(options);
1096
+ this.ssoController = this.container.get(TYPES.SsoController);
1097
+ this.cacheController = this.container.get(TYPES.CacheController);
1098
+ }
1099
+ async init() {
1100
+ if (!this.ready) {
1101
+ this.ready = this.bootstrap();
1102
+ }
1103
+ await this.ready;
1104
+ }
1105
+ async bootstrap() {
1106
+ await redis_client_default.connect();
1107
+ const { default: initZookeeper } = await Promise.resolve().then(() => (init_zookeeper(), zookeeper_exports));
1108
+ await initZookeeper();
1109
+ }
1110
+ get sso() {
1111
+ return this.ssoController;
1112
+ }
1113
+ get cache() {
1114
+ return this.cacheController;
1115
+ }
1116
+ };
1117
+ // Annotate the CommonJS export names for ESM import in node:
1118
+ 0 && (module.exports = {
1119
+ ServiceCallLibrary,
1120
+ TYPES
1121
+ });
1122
+ //# sourceMappingURL=index.cjs.map