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