@govish/shared-services 1.0.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.
@@ -0,0 +1,109 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.PenalCodeCacheService = void 0;
13
+ class PenalCodeCacheService {
14
+ constructor(deps) {
15
+ this.redisClient = deps.redisClient;
16
+ this.logger = deps.logger;
17
+ }
18
+ /**
19
+ * Get penal codes from Redis cache
20
+ * @returns Array of penal codes or null if not found/error
21
+ */
22
+ getPenalCodes() {
23
+ return __awaiter(this, void 0, void 0, function* () {
24
+ try {
25
+ // Check if Redis is connected
26
+ if (!this.redisClient.isOpen) {
27
+ this.logger.warn('Redis client not connected, attempting to connect...');
28
+ yield this.redisClient.connect();
29
+ }
30
+ const penalCodesData = yield this.redisClient.get('penalCodes');
31
+ if (!penalCodesData) {
32
+ this.logger.info('Penal codes not found in cache');
33
+ return null;
34
+ }
35
+ // Parse JSON if the data is a string
36
+ if (typeof penalCodesData === 'string') {
37
+ try {
38
+ return JSON.parse(penalCodesData);
39
+ }
40
+ catch (parseError) {
41
+ this.logger.error('Error parsing penal codes from cache', {
42
+ error: parseError instanceof Error ? parseError.message : String(parseError)
43
+ });
44
+ return null;
45
+ }
46
+ }
47
+ // If it's already an object/array, return as-is
48
+ return penalCodesData;
49
+ }
50
+ catch (error) {
51
+ this.logger.error('Error getting penal codes from cache', {
52
+ error: error instanceof Error ? error.message : String(error),
53
+ stack: error instanceof Error ? error.stack : undefined
54
+ });
55
+ return null;
56
+ }
57
+ });
58
+ }
59
+ /**
60
+ * Store penal codes in Redis cache
61
+ * @param penalCodes - Array of penal codes to store
62
+ */
63
+ storePenalCodes(penalCodes) {
64
+ return __awaiter(this, void 0, void 0, function* () {
65
+ try {
66
+ // Check if Redis is connected
67
+ if (!this.redisClient.isOpen) {
68
+ this.logger.warn('Redis client not connected, attempting to connect...');
69
+ yield this.redisClient.connect();
70
+ }
71
+ const penalCodesJson = JSON.stringify(penalCodes);
72
+ yield this.redisClient.set('penalCodes', penalCodesJson);
73
+ this.logger.info('Penal codes stored in cache successfully', {
74
+ count: penalCodes.length
75
+ });
76
+ }
77
+ catch (error) {
78
+ this.logger.error('Error storing penal codes in cache', {
79
+ error: error instanceof Error ? error.message : String(error),
80
+ stack: error instanceof Error ? error.stack : undefined
81
+ });
82
+ throw error;
83
+ }
84
+ });
85
+ }
86
+ /**
87
+ * Clear penal codes from cache
88
+ */
89
+ clearCache() {
90
+ return __awaiter(this, void 0, void 0, function* () {
91
+ try {
92
+ // Check if Redis is connected
93
+ if (!this.redisClient.isOpen) {
94
+ this.logger.warn('Redis client not connected, attempting to connect...');
95
+ yield this.redisClient.connect();
96
+ }
97
+ yield this.redisClient.del('penalCodes');
98
+ this.logger.info('Penal codes cache cleared successfully');
99
+ }
100
+ catch (error) {
101
+ this.logger.error('Error clearing penal codes cache', {
102
+ error: error instanceof Error ? error.message : String(error),
103
+ stack: error instanceof Error ? error.stack : undefined
104
+ });
105
+ }
106
+ });
107
+ }
108
+ }
109
+ exports.PenalCodeCacheService = PenalCodeCacheService;
@@ -0,0 +1,23 @@
1
+ import { Logger } from 'winston';
2
+ import { Producer } from 'kafkajs';
3
+ export interface SharedServicesDependencies {
4
+ redisClient: any;
5
+ logger: Logger;
6
+ authHost?: string;
7
+ authPort?: string;
8
+ serverName?: string;
9
+ auditTopic?: string;
10
+ jwtConfig?: {
11
+ secret: string;
12
+ expiresIn?: number;
13
+ issuer?: string;
14
+ audience?: string;
15
+ };
16
+ kafkaProducer?: Producer;
17
+ isProducerConnected?: () => boolean;
18
+ kafkaBrokers?: string | string[];
19
+ kafkaClientId?: string;
20
+ enableDebugLogs?: boolean;
21
+ safeRedisGet?: (key: string) => Promise<string | null>;
22
+ safeRedisSet?: (key: string, value: string) => Promise<boolean>;
23
+ }
@@ -0,0 +1,2 @@
1
+ "use strict";
2
+ Object.defineProperty(exports, "__esModule", { value: true });
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Environment mode utilities
3
+ * Controls whether logs and debug information should be shown
4
+ */
5
+ export type EnvironmentMode = 'development' | 'production' | 'test';
6
+ /**
7
+ * Get the current environment mode
8
+ */
9
+ export declare const getEnvironmentMode: () => EnvironmentMode;
10
+ /**
11
+ * Check if we're in development mode
12
+ */
13
+ export declare const isDevelopmentMode: () => boolean;
14
+ /**
15
+ * Check if we're in production mode
16
+ */
17
+ export declare const isProductionMode: () => boolean;
18
+ /**
19
+ * Conditional console.log - only logs in development mode
20
+ */
21
+ export declare const devLog: (...args: any[]) => void;
22
+ /**
23
+ * Conditional console.error - always logs errors, but with less detail in production
24
+ */
25
+ export declare const devError: (...args: any[]) => void;
26
+ /**
27
+ * Conditional console.warn - always logs warnings (even in production)
28
+ */
29
+ export declare const devWarn: (...args: any[]) => void;
30
+ /**
31
+ * Conditional console.debug - only logs in development mode
32
+ */
33
+ export declare const devDebug: (...args: any[]) => void;
@@ -0,0 +1,90 @@
1
+ "use strict";
2
+ /**
3
+ * Environment mode utilities
4
+ * Controls whether logs and debug information should be shown
5
+ */
6
+ Object.defineProperty(exports, "__esModule", { value: true });
7
+ exports.devDebug = exports.devWarn = exports.devError = exports.devLog = exports.isProductionMode = exports.isDevelopmentMode = exports.getEnvironmentMode = void 0;
8
+ /**
9
+ * Get the current environment mode
10
+ */
11
+ const getEnvironmentMode = () => {
12
+ const env = process.env.NODE_ENV || 'development';
13
+ if (env === 'production' || env === 'prod') {
14
+ return 'production';
15
+ }
16
+ if (env === 'test') {
17
+ return 'test';
18
+ }
19
+ return 'development';
20
+ };
21
+ exports.getEnvironmentMode = getEnvironmentMode;
22
+ /**
23
+ * Check if we're in development mode
24
+ */
25
+ const isDevelopmentMode = () => {
26
+ return (0, exports.getEnvironmentMode)() === 'development';
27
+ };
28
+ exports.isDevelopmentMode = isDevelopmentMode;
29
+ /**
30
+ * Check if we're in production mode
31
+ */
32
+ const isProductionMode = () => {
33
+ return (0, exports.getEnvironmentMode)() === 'production';
34
+ };
35
+ exports.isProductionMode = isProductionMode;
36
+ /**
37
+ * Conditional console.log - only logs in development mode
38
+ */
39
+ const devLog = (...args) => {
40
+ if ((0, exports.isDevelopmentMode)()) {
41
+ console.log(...args);
42
+ }
43
+ };
44
+ exports.devLog = devLog;
45
+ /**
46
+ * Conditional console.error - always logs errors, but with less detail in production
47
+ */
48
+ const devError = (...args) => {
49
+ if ((0, exports.isDevelopmentMode)()) {
50
+ console.error(...args);
51
+ }
52
+ else {
53
+ // In production, only log minimal error info
54
+ const errorInfo = args.map(arg => {
55
+ if (arg instanceof Error) {
56
+ return arg.message;
57
+ }
58
+ if (typeof arg === 'object') {
59
+ // Only include essential error info in production
60
+ return JSON.stringify(Object.assign({ error: arg.error || arg.message || 'Unknown error' }, ((0, exports.isDevelopmentMode)() ? arg : {})));
61
+ }
62
+ return arg;
63
+ });
64
+ console.error(...errorInfo);
65
+ }
66
+ };
67
+ exports.devError = devError;
68
+ /**
69
+ * Conditional console.warn - always logs warnings (even in production)
70
+ */
71
+ const devWarn = (...args) => {
72
+ // Always log warnings
73
+ if ((0, exports.isDevelopmentMode)()) {
74
+ console.warn(...args);
75
+ }
76
+ else {
77
+ // In production, still show warnings
78
+ console.warn('[WARN]', ...args);
79
+ }
80
+ };
81
+ exports.devWarn = devWarn;
82
+ /**
83
+ * Conditional console.debug - only logs in development mode
84
+ */
85
+ const devDebug = (...args) => {
86
+ if ((0, exports.isDevelopmentMode)()) {
87
+ console.debug(...args);
88
+ }
89
+ };
90
+ exports.devDebug = devDebug;
@@ -0,0 +1,24 @@
1
+ /**
2
+ * Helper function to safely get from Redis with reconnection handling
3
+ * @param redisClient - Redis client instance
4
+ * @param key - Redis key to get
5
+ * @returns The value from Redis or null if not found/error
6
+ */
7
+ export declare const createSafeRedisGet: (redisClient: any) => (key: string) => Promise<string | null>;
8
+ /**
9
+ * Helper function to safely set in Redis with reconnection handling
10
+ * @param redisClient - Redis client instance
11
+ * @param key - Redis key to set
12
+ * @param value - Value to set
13
+ * @returns true if successful, false otherwise
14
+ */
15
+ export declare const createSafeRedisSet: (redisClient: any) => (key: string, value: string) => Promise<boolean>;
16
+ /**
17
+ * Factory function to create both safe Redis utility functions
18
+ * @param redisClient - Redis client instance
19
+ * @returns Object containing safeRedisGet and safeRedisSet functions
20
+ */
21
+ export declare const createSafeRedisUtils: (redisClient: any) => {
22
+ safeRedisGet: (key: string) => Promise<string | null>;
23
+ safeRedisSet: (key: string, value: string) => Promise<boolean>;
24
+ };
@@ -0,0 +1,122 @@
1
+ "use strict";
2
+ var __awaiter = (this && this.__awaiter) || function (thisArg, _arguments, P, generator) {
3
+ function adopt(value) { return value instanceof P ? value : new P(function (resolve) { resolve(value); }); }
4
+ return new (P || (P = Promise))(function (resolve, reject) {
5
+ function fulfilled(value) { try { step(generator.next(value)); } catch (e) { reject(e); } }
6
+ function rejected(value) { try { step(generator["throw"](value)); } catch (e) { reject(e); } }
7
+ function step(result) { result.done ? resolve(result.value) : adopt(result.value).then(fulfilled, rejected); }
8
+ step((generator = generator.apply(thisArg, _arguments || [])).next());
9
+ });
10
+ };
11
+ Object.defineProperty(exports, "__esModule", { value: true });
12
+ exports.createSafeRedisUtils = exports.createSafeRedisSet = exports.createSafeRedisGet = void 0;
13
+ const logMode_1 = require("./logMode");
14
+ /**
15
+ * Helper function to ensure Redis client is connected
16
+ */
17
+ const ensureRedisConnected = (redisClient) => __awaiter(void 0, void 0, void 0, function* () {
18
+ var _a, _b;
19
+ try {
20
+ if (!redisClient.isOpen) {
21
+ (0, logMode_1.devLog)(`[REDIS] Client closed, attempting to reconnect...`);
22
+ yield redisClient.connect();
23
+ (0, logMode_1.devLog)(`[REDIS] Successfully reconnected`);
24
+ }
25
+ return true;
26
+ }
27
+ catch (error) {
28
+ // If already connected, that's fine
29
+ if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('already connected')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('Connected'))) {
30
+ return true;
31
+ }
32
+ (0, logMode_1.devError)(`[REDIS] Error connecting:`, error);
33
+ return false;
34
+ }
35
+ });
36
+ /**
37
+ * Helper function to safely get from Redis with reconnection handling
38
+ * @param redisClient - Redis client instance
39
+ * @param key - Redis key to get
40
+ * @returns The value from Redis or null if not found/error
41
+ */
42
+ const createSafeRedisGet = (redisClient) => {
43
+ return (key) => __awaiter(void 0, void 0, void 0, function* () {
44
+ var _a, _b;
45
+ try {
46
+ // Ensure client is connected
47
+ const connected = yield ensureRedisConnected(redisClient);
48
+ if (!connected) {
49
+ return null;
50
+ }
51
+ return yield redisClient.get(key);
52
+ }
53
+ catch (error) {
54
+ // If error is due to closed client, try to reconnect once
55
+ if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('closed')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('ClientClosedError'))) {
56
+ try {
57
+ (0, logMode_1.devLog)(`[REDIS] Reconnecting after closed client error for key: ${key}`);
58
+ yield ensureRedisConnected(redisClient);
59
+ return yield redisClient.get(key);
60
+ }
61
+ catch (retryError) {
62
+ (0, logMode_1.devError)(`[REDIS] Failed to reconnect for key ${key}:`, retryError);
63
+ return null;
64
+ }
65
+ }
66
+ (0, logMode_1.devError)(`[REDIS] Error getting key ${key}:`, error);
67
+ return null;
68
+ }
69
+ });
70
+ };
71
+ exports.createSafeRedisGet = createSafeRedisGet;
72
+ /**
73
+ * Helper function to safely set in Redis with reconnection handling
74
+ * @param redisClient - Redis client instance
75
+ * @param key - Redis key to set
76
+ * @param value - Value to set
77
+ * @returns true if successful, false otherwise
78
+ */
79
+ const createSafeRedisSet = (redisClient) => {
80
+ return (key, value) => __awaiter(void 0, void 0, void 0, function* () {
81
+ var _a, _b;
82
+ try {
83
+ // Ensure client is connected
84
+ const connected = yield ensureRedisConnected(redisClient);
85
+ if (!connected) {
86
+ return false;
87
+ }
88
+ yield redisClient.set(key, value);
89
+ return true;
90
+ }
91
+ catch (error) {
92
+ // If error is due to closed client, try to reconnect once
93
+ if (((_a = error === null || error === void 0 ? void 0 : error.message) === null || _a === void 0 ? void 0 : _a.includes('closed')) || ((_b = error === null || error === void 0 ? void 0 : error.message) === null || _b === void 0 ? void 0 : _b.includes('ClientClosedError'))) {
94
+ try {
95
+ (0, logMode_1.devLog)(`[REDIS] Reconnecting after closed client error for key: ${key}`);
96
+ yield ensureRedisConnected(redisClient);
97
+ yield redisClient.set(key, value);
98
+ return true;
99
+ }
100
+ catch (retryError) {
101
+ (0, logMode_1.devError)(`[REDIS] Failed to reconnect for key ${key}:`, retryError);
102
+ return false;
103
+ }
104
+ }
105
+ (0, logMode_1.devError)(`[REDIS] Error setting key ${key}:`, error);
106
+ return false;
107
+ }
108
+ });
109
+ };
110
+ exports.createSafeRedisSet = createSafeRedisSet;
111
+ /**
112
+ * Factory function to create both safe Redis utility functions
113
+ * @param redisClient - Redis client instance
114
+ * @returns Object containing safeRedisGet and safeRedisSet functions
115
+ */
116
+ const createSafeRedisUtils = (redisClient) => {
117
+ return {
118
+ safeRedisGet: (0, exports.createSafeRedisGet)(redisClient),
119
+ safeRedisSet: (0, exports.createSafeRedisSet)(redisClient),
120
+ };
121
+ };
122
+ exports.createSafeRedisUtils = createSafeRedisUtils;
package/package.json ADDED
@@ -0,0 +1,52 @@
1
+ {
2
+ "name": "@govish/shared-services",
3
+ "version": "1.0.0",
4
+ "description": "Govish shared services package - includes cache services, API key service, audit logging, and authentication middleware",
5
+ "main": "dist/index.js",
6
+ "types": "dist/index.d.ts",
7
+ "files": [
8
+ "dist/**/*",
9
+ "README.md",
10
+ "CHANGELOG.md"
11
+ ],
12
+ "scripts": {
13
+ "build": "tsc",
14
+ "watch": "tsc --watch",
15
+ "prepublishOnly": "npm run build"
16
+ },
17
+ "keywords": [
18
+ "govish",
19
+ "shared-services",
20
+ "redis",
21
+ "cache",
22
+ "kafka",
23
+ "audit",
24
+ "authentication",
25
+ "middleware",
26
+ "typescript"
27
+ ],
28
+ "author": "",
29
+ "license": "ISC",
30
+ "repository": {
31
+ "type": "git",
32
+ "url": ""
33
+ },
34
+ "dependencies": {
35
+ "jsonwebtoken": "^9.0.1",
36
+ "kafkajs": "^2.2.4",
37
+ "redis": "^4.7.0",
38
+ "winston": "^3.19.0"
39
+ },
40
+ "devDependencies": {
41
+ "@types/express": "^4.17.21",
42
+ "@types/jsonwebtoken": "^9.0.1",
43
+ "@types/node": "^20.11.26",
44
+ "typescript": "^5.6.3"
45
+ },
46
+ "engines": {
47
+ "node": ">=18.0.0"
48
+ },
49
+ "publishConfig": {
50
+ "access": "public"
51
+ }
52
+ }