@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,310 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.createAuthenticateDeviceOrOfficer = void 0;
16
+ const jsonwebtoken_1 = __importDefault(require("jsonwebtoken"));
17
+ const apiKeyService_1 = require("../services/apiKeyService");
18
+ const auditService_1 = require("../services/auditService");
19
+ const deviceService_1 = require("../services/deviceService");
20
+ const officerService_1 = require("../services/officerService");
21
+ const logMode_1 = require("../utils/logMode");
22
+ /**
23
+ * Middleware to authenticate either a device, an officer, or a microservice (via API key)
24
+ * Checks JWT token and validates against Device or Officer table
25
+ * Also checks for API keys for microservice authentication
26
+ *
27
+ * Supports multiple authentication methods:
28
+ * - X-API-Key: <api_key> (for microservice authentication)
29
+ * - Device-Token: <device_jwt_token> (for device authentication)
30
+ * - Authorization: Bearer <user_jwt_token> (for officer/user authentication)
31
+ *
32
+ * Priority: API Key > Device Token > Authorization Token
33
+ */
34
+ const createAuthenticateDeviceOrOfficer = (deps) => {
35
+ const apiKeyService = new apiKeyService_1.ApiKeyService(deps);
36
+ const logger = deps.logger;
37
+ const enableDebugLogs = deps.enableDebugLogs || false;
38
+ // Debug log helper for middleware
39
+ const debugLog = (message, data) => {
40
+ if (enableDebugLogs) {
41
+ if (data) {
42
+ console.log(`[AUDIT MIDDLEWARE] ${message}`, data);
43
+ }
44
+ else {
45
+ console.log(`[AUDIT MIDDLEWARE] ${message}`);
46
+ }
47
+ }
48
+ };
49
+ const debugError = (message, data) => {
50
+ if (enableDebugLogs) {
51
+ if (data) {
52
+ console.error(`[AUDIT MIDDLEWARE] ${message}`, data);
53
+ }
54
+ else {
55
+ console.error(`[AUDIT MIDDLEWARE] ${message}`);
56
+ }
57
+ }
58
+ };
59
+ // Use internal services instead of external functions
60
+ const deviceService = new deviceService_1.DeviceService(deps);
61
+ const officerService = new officerService_1.OfficerService(deps);
62
+ const jwtConfig = deps.jwtConfig || {
63
+ secret: process.env.JWT_SECRET || 'your-super-secret-key-change-this-in-production',
64
+ expiresIn: 24 * 60 * 60,
65
+ issuer: deps.serverName || 'citizen-app',
66
+ audience: deps.serverName || 'citizen-users',
67
+ };
68
+ // Initialize audit service (it will handle Kafka unavailability gracefully)
69
+ // Always initialize so we can log to console/logger even if Kafka is not available
70
+ const auditService = new auditService_1.AuditService(deps);
71
+ return (req, res, next) => __awaiter(void 0, void 0, void 0, function* () {
72
+ try {
73
+ // First, check for API key (for microservice authentication)
74
+ const apiKeyHeader = req.headers['x-api-key'];
75
+ if (apiKeyHeader) {
76
+ const apiKey = yield apiKeyService.validateApiKey(apiKeyHeader);
77
+ if (apiKey) {
78
+ // Attach API key info to request
79
+ req.apiKey = apiKey;
80
+ req.microservice = apiKey.microservice;
81
+ req.authType = 'api_key';
82
+ // Log audit event
83
+ if (auditService) {
84
+ auditService.logAuditEvent(req, {
85
+ // Event type will be determined automatically
86
+ }).catch((err) => {
87
+ logger.error('Failed to log audit event', { error: err.message });
88
+ });
89
+ }
90
+ return next();
91
+ }
92
+ else {
93
+ return res.status(401).json({
94
+ message: 'Invalid, expired, or inactive API key'
95
+ });
96
+ }
97
+ }
98
+ // Check for device-token header (case-insensitive)
99
+ // Express normalizes headers to lowercase, but check multiple variations
100
+ // Also check rawHeaders in case Express hasn't normalized it
101
+ let deviceTokenHeader;
102
+ // Check normalized headers first
103
+ deviceTokenHeader =
104
+ req.headers['device-token'] ||
105
+ req.headers['device_token']; // Also check underscore variant
106
+ // If not found, check rawHeaders
107
+ if (!deviceTokenHeader && req.rawHeaders) {
108
+ const index = req.rawHeaders.findIndex((h) => h.toLowerCase() === 'device-token' || h.toLowerCase() === 'device_token');
109
+ if (index >= 0 && index < req.rawHeaders.length - 1) {
110
+ deviceTokenHeader = req.rawHeaders[index + 1];
111
+ }
112
+ }
113
+ const authHeader = req.headers.authorization;
114
+ let deviceAuthenticated = false;
115
+ let officerAuthenticated = false;
116
+ // Authenticate device if Device-Token header is present
117
+ if (deviceTokenHeader) {
118
+ try {
119
+ const decoded = jsonwebtoken_1.default.verify(deviceTokenHeader, jwtConfig.secret, {
120
+ issuer: jwtConfig.issuer,
121
+ audience: jwtConfig.audience,
122
+ });
123
+ // Get device from service (uses Redis cache with auth service fallback)
124
+ const device = yield deviceService.getDeviceById(decoded.sub);
125
+ if (!device) {
126
+ // Log audit event for device not found
127
+ if (auditService) {
128
+ req.authType = 'device';
129
+ auditService.logAuditEvent(req, {
130
+ event_type: undefined, // Will be determined automatically
131
+ response_status: 401,
132
+ error_message: 'Device not found',
133
+ error_code: 'DEVICE_NOT_FOUND',
134
+ }).catch((err) => {
135
+ logger.debug('Failed to log audit event', { error: err.message });
136
+ });
137
+ }
138
+ return res.status(401).json({ message: 'Device not found' });
139
+ }
140
+ if (!device.is_active) {
141
+ // Log audit event for inactive device
142
+ if (auditService) {
143
+ req.authType = 'device';
144
+ req.device = device;
145
+ auditService.logAuditEvent(req, {
146
+ event_type: undefined, // Will be determined automatically
147
+ response_status: 403,
148
+ error_message: 'Device is not active',
149
+ error_code: 'DEVICE_INACTIVE',
150
+ }).catch((err) => {
151
+ logger.debug('Failed to log audit event', { error: err.message });
152
+ });
153
+ }
154
+ return res.status(403).json({ message: 'Device is not active' });
155
+ }
156
+ // Attach device to request
157
+ req.device = device;
158
+ deviceAuthenticated = true;
159
+ }
160
+ catch (error) {
161
+ // Log audit event for invalid device token
162
+ if (auditService) {
163
+ req.authType = 'device';
164
+ auditService.logAuditEvent(req, {
165
+ event_type: undefined, // Will be determined automatically
166
+ response_status: 401,
167
+ error_message: error instanceof Error ? error.message : 'Invalid or expired device token',
168
+ error_code: 'INVALID_DEVICE_TOKEN',
169
+ }).catch((err) => {
170
+ logger.debug('Failed to log audit event', { error: err.message });
171
+ });
172
+ }
173
+ return res.status(401).json({ message: 'Invalid or expired device token' });
174
+ }
175
+ }
176
+ // Authenticate officer if Authorization header is present
177
+ if (authHeader && authHeader.startsWith('Bearer ')) {
178
+ const token = authHeader.substring(7); // Remove 'Bearer ' prefix
179
+ try {
180
+ const decoded = jsonwebtoken_1.default.verify(token, jwtConfig.secret, {
181
+ issuer: jwtConfig.issuer,
182
+ audience: jwtConfig.audience,
183
+ });
184
+ // Skip if this is a device token (should use Device-Token header instead)
185
+ if (decoded.type === 'device') {
186
+ if (!deviceAuthenticated) {
187
+ return res.status(401).json({ message: 'Device tokens should use Device-Token header' });
188
+ }
189
+ // If device already authenticated via Device-Token, continue
190
+ }
191
+ else {
192
+ // Authenticate as officer
193
+ const officerId = decoded.id || decoded.sub;
194
+ if (!officerId) {
195
+ return res.status(401).json({ message: 'Invalid token payload' });
196
+ }
197
+ // Get officer from service (uses Redis cache with auth service fallback)
198
+ const officer = yield officerService.getOfficerById(officerId);
199
+ if (!officer) {
200
+ // Log audit event for officer not found
201
+ if (auditService) {
202
+ req.authType = 'officer';
203
+ auditService.logAuditEvent(req, {
204
+ event_type: undefined, // Will be determined automatically
205
+ response_status: 401,
206
+ error_message: 'Officer not found',
207
+ error_code: 'OFFICER_NOT_FOUND',
208
+ }).catch((err) => {
209
+ logger.debug('Failed to log audit event', { error: err.message });
210
+ });
211
+ }
212
+ return res.status(401).json({ message: 'Officer not found' });
213
+ }
214
+ // Attach officer to request
215
+ req.officer = officer;
216
+ req.user = officer;
217
+ officerAuthenticated = true;
218
+ }
219
+ }
220
+ catch (error) {
221
+ // Log audit event for invalid authorization token
222
+ if (auditService) {
223
+ req.authType = 'officer';
224
+ auditService.logAuditEvent(req, {
225
+ event_type: undefined, // Will be determined automatically
226
+ response_status: 401,
227
+ error_message: error instanceof Error ? error.message : 'Invalid or expired authorization token',
228
+ error_code: 'INVALID_AUTH_TOKEN',
229
+ }).catch((err) => {
230
+ logger.debug('Failed to log audit event', { error: err.message });
231
+ });
232
+ }
233
+ return res.status(401).json({ message: 'Invalid or expired authorization token' });
234
+ }
235
+ }
236
+ // At least one authentication method must succeed
237
+ if (!deviceAuthenticated && !officerAuthenticated) {
238
+ // Log audit event for missing authentication
239
+ if (auditService) {
240
+ auditService.logAuditEvent(req, {
241
+ event_type: undefined, // Will be determined automatically
242
+ response_status: 401,
243
+ error_message: 'No valid token provided. Provide either Device-Token or Authorization header',
244
+ error_code: 'NO_AUTH_TOKEN',
245
+ }).catch((err) => {
246
+ logger.debug('Failed to log audit event', { error: err.message });
247
+ });
248
+ }
249
+ return res.status(401).json({ message: 'No valid token provided. Provide either Device-Token or Authorization header' });
250
+ }
251
+ // Set auth type
252
+ if (deviceAuthenticated && officerAuthenticated) {
253
+ req.authType = 'both';
254
+ }
255
+ else if (deviceAuthenticated) {
256
+ req.authType = 'device';
257
+ req.user = null;
258
+ }
259
+ else {
260
+ req.authType = 'officer';
261
+ req.device = null;
262
+ }
263
+ (0, logMode_1.devLog)('Authentication successful', {
264
+ authType: req.authType,
265
+ device: req.device,
266
+ officer: req.officer,
267
+ apiKey: req.apiKey,
268
+ microservice: req.microservice,
269
+ });
270
+ // Log audit event for endpoint access (non-blocking)
271
+ if (auditService) {
272
+ (0, logMode_1.devLog)('Calling audit service for endpoint access', {
273
+ path: req.path,
274
+ originalUrl: req.originalUrl,
275
+ baseUrl: req.baseUrl,
276
+ method: req.method,
277
+ authType: req.authType,
278
+ });
279
+ auditService.logAuditEvent(req, {
280
+ event_type: undefined, // Will be determined automatically
281
+ // Custom keys can be added here
282
+ }).catch((err) => {
283
+ logger.error('Failed to log audit event', {
284
+ error: err.message,
285
+ stack: err.stack,
286
+ path: req.path,
287
+ originalUrl: req.originalUrl,
288
+ });
289
+ (0, logMode_1.devError)('Audit logging failed', err);
290
+ });
291
+ }
292
+ else {
293
+ debugError('Audit service not available', {
294
+ hasKafkaProducer: !!deps.kafkaProducer,
295
+ hasIsProducerConnected: !!deps.isProducerConnected,
296
+ });
297
+ (0, logMode_1.devLog)('Audit service not available', {
298
+ hasKafkaProducer: !!deps.kafkaProducer,
299
+ hasIsProducerConnected: !!deps.isProducerConnected,
300
+ });
301
+ }
302
+ return next();
303
+ }
304
+ catch (error) {
305
+ (0, logMode_1.devError)('Authentication error:', error);
306
+ return res.status(500).json({ message: 'Authentication error' });
307
+ }
308
+ });
309
+ };
310
+ exports.createAuthenticateDeviceOrOfficer = createAuthenticateDeviceOrOfficer;
@@ -0,0 +1,53 @@
1
+ import { SharedServicesDependencies } from '../types/dependencies';
2
+ export interface ApiKeyData {
3
+ id: number;
4
+ key: string;
5
+ microservice: string;
6
+ description?: string;
7
+ is_active: boolean;
8
+ last_used_at?: Date;
9
+ expires_at?: Date;
10
+ created_at: Date;
11
+ updated_at: Date;
12
+ created_by?: number;
13
+ }
14
+ export declare class ApiKeyService {
15
+ private logger;
16
+ private safeRedisGet?;
17
+ private safeRedisSet?;
18
+ constructor(deps: SharedServicesDependencies);
19
+ /**
20
+ * Generate a new API key
21
+ */
22
+ generateApiKey(): string;
23
+ /**
24
+ * Create a new API key for a microservice
25
+ * Creates via auth service API
26
+ */
27
+ createApiKey(microservice: string, description?: string, expiresInDays?: number, createdBy?: number): Promise<ApiKeyData>;
28
+ /**
29
+ * Validate an API key
30
+ * Uses Redis cache with auth service fallback (similar to officer service pattern)
31
+ */
32
+ validateApiKey(apiKey: string): Promise<ApiKeyData | null>;
33
+ /**
34
+ * Get all API keys from auth service
35
+ */
36
+ getAllApiKeys(microservice?: string): Promise<ApiKeyData[]>;
37
+ /**
38
+ * Get API key by ID from auth service
39
+ */
40
+ getApiKeyById(id: number): Promise<ApiKeyData | null>;
41
+ /**
42
+ * Revoke/deactivate an API key via auth service
43
+ */
44
+ revokeApiKey(id: number): Promise<ApiKeyData>;
45
+ /**
46
+ * Reactivate an API key via auth service
47
+ */
48
+ reactivateApiKey(id: number): Promise<ApiKeyData>;
49
+ /**
50
+ * Delete an API key via auth service
51
+ */
52
+ deleteApiKey(id: number): Promise<void>;
53
+ }
@@ -0,0 +1,293 @@
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
+ var __importDefault = (this && this.__importDefault) || function (mod) {
12
+ return (mod && mod.__esModule) ? mod : { "default": mod };
13
+ };
14
+ Object.defineProperty(exports, "__esModule", { value: true });
15
+ exports.ApiKeyService = void 0;
16
+ const crypto_1 = __importDefault(require("crypto"));
17
+ class ApiKeyService {
18
+ constructor(deps) {
19
+ this.logger = deps.logger;
20
+ this.safeRedisGet = deps.safeRedisGet;
21
+ this.safeRedisSet = deps.safeRedisSet;
22
+ }
23
+ /**
24
+ * Generate a new API key
25
+ */
26
+ generateApiKey() {
27
+ // Generate a secure random API key
28
+ const randomBytes = crypto_1.default.randomBytes(32);
29
+ const apiKey = `ak_${randomBytes.toString('base64url')}`;
30
+ return apiKey;
31
+ }
32
+ /**
33
+ * Create a new API key for a microservice
34
+ * Creates via auth service API
35
+ */
36
+ createApiKey(microservice, description, expiresInDays, createdBy) {
37
+ return __awaiter(this, void 0, void 0, function* () {
38
+ try {
39
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
40
+ if (!authHost.includes(':')) {
41
+ authHost = `${authHost}:3000`;
42
+ }
43
+ // Create API key via auth service
44
+ const response = yield fetch(`http://${authHost}/api/v1/api-key`, {
45
+ method: 'POST',
46
+ headers: { 'Content-Type': 'application/json' },
47
+ body: JSON.stringify({
48
+ microservice,
49
+ description,
50
+ expiresInDays,
51
+ createdBy
52
+ })
53
+ });
54
+ if (!response.ok) {
55
+ const errorData = yield response.json().catch(() => ({}));
56
+ throw new Error(errorData.message || `Failed to create API key: ${response.status}`);
57
+ }
58
+ const apiKey = yield response.json();
59
+ const keyData = apiKey.data || apiKey;
60
+ this.logger.info('API key created successfully', {
61
+ apiKeyId: keyData.id,
62
+ microservice
63
+ });
64
+ return keyData;
65
+ }
66
+ catch (error) {
67
+ this.logger.error('Error creating API key', {
68
+ error: error instanceof Error ? error.message : 'Unknown error',
69
+ microservice
70
+ });
71
+ throw error;
72
+ }
73
+ });
74
+ }
75
+ /**
76
+ * Validate an API key
77
+ * Uses Redis cache with auth service fallback (similar to officer service pattern)
78
+ */
79
+ validateApiKey(apiKey) {
80
+ return __awaiter(this, void 0, void 0, function* () {
81
+ try {
82
+ // Try to get from Redis cache first
83
+ const cacheKey = `api_key:${apiKey}`;
84
+ const cachedData = this.safeRedisGet ? yield this.safeRedisGet(cacheKey) : null;
85
+ let key = null;
86
+ if (cachedData) {
87
+ try {
88
+ key = JSON.parse(cachedData);
89
+ this.logger.debug('API key found in cache', { apiKeyId: key.id });
90
+ }
91
+ catch (parseError) {
92
+ this.logger.warn('Failed to parse cached API key', {
93
+ error: parseError instanceof Error ? parseError.message : 'Unknown error'
94
+ });
95
+ }
96
+ }
97
+ // If not in cache, fetch from auth service
98
+ if (!key) {
99
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
100
+ if (!authHost.includes(':')) {
101
+ authHost = `${authHost}:3000`;
102
+ }
103
+ const response = yield fetch(`http://${authHost}/api/v1/api-key/validate`, {
104
+ method: 'POST',
105
+ headers: { 'Content-Type': 'application/json' },
106
+ body: JSON.stringify({ apiKey })
107
+ });
108
+ if (!response.ok) {
109
+ if (response.status === 404 || response.status === 401) {
110
+ return null;
111
+ }
112
+ this.logger.warn('Failed to validate API key from auth service', {
113
+ status: response.status
114
+ });
115
+ return null;
116
+ }
117
+ const result = yield response.json();
118
+ key = result.data || result;
119
+ // Cache the result if found (15 minutes TTL for API keys)
120
+ if (key && this.safeRedisSet) {
121
+ yield this.safeRedisSet(cacheKey, JSON.stringify(key));
122
+ this.logger.debug('API key cached', { apiKeyId: key.id });
123
+ }
124
+ }
125
+ if (!key) {
126
+ return null;
127
+ }
128
+ // Check if key is active
129
+ if (!key.is_active) {
130
+ this.logger.warn('Inactive API key used', { apiKeyId: key.id });
131
+ return null;
132
+ }
133
+ // Check if key has expired
134
+ if (key.expires_at && new Date(key.expires_at) < new Date()) {
135
+ this.logger.warn('Expired API key used', { apiKeyId: key.id });
136
+ return null;
137
+ }
138
+ return key;
139
+ }
140
+ catch (error) {
141
+ this.logger.error('Error validating API key', {
142
+ error: error instanceof Error ? error.message : 'Unknown error'
143
+ });
144
+ return null;
145
+ }
146
+ });
147
+ }
148
+ /**
149
+ * Get all API keys from auth service
150
+ */
151
+ getAllApiKeys(microservice) {
152
+ return __awaiter(this, void 0, void 0, function* () {
153
+ try {
154
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
155
+ if (!authHost.includes(':')) {
156
+ authHost = `${authHost}:3000`;
157
+ }
158
+ const url = microservice
159
+ ? `http://${authHost}/api/v1/api-key?microservice=${microservice}`
160
+ : `http://${authHost}/api/v1/api-key`;
161
+ const response = yield fetch(url);
162
+ if (!response.ok) {
163
+ throw new Error(`Failed to fetch API keys: ${response.status}`);
164
+ }
165
+ const result = yield response.json();
166
+ return result.data || result;
167
+ }
168
+ catch (error) {
169
+ this.logger.error('Error fetching API keys', {
170
+ error: error instanceof Error ? error.message : 'Unknown error'
171
+ });
172
+ throw error;
173
+ }
174
+ });
175
+ }
176
+ /**
177
+ * Get API key by ID from auth service
178
+ */
179
+ getApiKeyById(id) {
180
+ return __awaiter(this, void 0, void 0, function* () {
181
+ try {
182
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
183
+ if (!authHost.includes(':')) {
184
+ authHost = `${authHost}:3000`;
185
+ }
186
+ const response = yield fetch(`http://${authHost}/api/v1/api-key/${id}`);
187
+ if (!response.ok) {
188
+ if (response.status === 404) {
189
+ return null;
190
+ }
191
+ throw new Error(`Failed to fetch API key: ${response.status}`);
192
+ }
193
+ const result = yield response.json();
194
+ return result.data || result;
195
+ }
196
+ catch (error) {
197
+ this.logger.error('Error fetching API key by ID', {
198
+ error: error instanceof Error ? error.message : 'Unknown error',
199
+ id
200
+ });
201
+ throw error;
202
+ }
203
+ });
204
+ }
205
+ /**
206
+ * Revoke/deactivate an API key via auth service
207
+ */
208
+ revokeApiKey(id) {
209
+ return __awaiter(this, void 0, void 0, function* () {
210
+ try {
211
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
212
+ if (!authHost.includes(':')) {
213
+ authHost = `${authHost}:3000`;
214
+ }
215
+ const response = yield fetch(`http://${authHost}/api/v1/api-key/${id}/revoke`, {
216
+ method: 'PUT'
217
+ });
218
+ if (!response.ok) {
219
+ throw new Error(`Failed to revoke API key: ${response.status}`);
220
+ }
221
+ const result = yield response.json();
222
+ const apiKey = result.data || result;
223
+ this.logger.info('API key revoked', { apiKeyId: id });
224
+ return apiKey;
225
+ }
226
+ catch (error) {
227
+ this.logger.error('Error revoking API key', {
228
+ error: error instanceof Error ? error.message : 'Unknown error',
229
+ id
230
+ });
231
+ throw error;
232
+ }
233
+ });
234
+ }
235
+ /**
236
+ * Reactivate an API key via auth service
237
+ */
238
+ reactivateApiKey(id) {
239
+ return __awaiter(this, void 0, void 0, function* () {
240
+ try {
241
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
242
+ if (!authHost.includes(':')) {
243
+ authHost = `${authHost}:3000`;
244
+ }
245
+ const response = yield fetch(`http://${authHost}/api/v1/api-key/${id}/reactivate`, {
246
+ method: 'PUT'
247
+ });
248
+ if (!response.ok) {
249
+ throw new Error(`Failed to reactivate API key: ${response.status}`);
250
+ }
251
+ const result = yield response.json();
252
+ const apiKey = result.data || result;
253
+ this.logger.info('API key reactivated', { apiKeyId: id });
254
+ return apiKey;
255
+ }
256
+ catch (error) {
257
+ this.logger.error('Error reactivating API key', {
258
+ error: error instanceof Error ? error.message : 'Unknown error',
259
+ id
260
+ });
261
+ throw error;
262
+ }
263
+ });
264
+ }
265
+ /**
266
+ * Delete an API key via auth service
267
+ */
268
+ deleteApiKey(id) {
269
+ return __awaiter(this, void 0, void 0, function* () {
270
+ try {
271
+ let authHost = process.env.AUTH_HOST || 'localhost:3000';
272
+ if (!authHost.includes(':')) {
273
+ authHost = `${authHost}:3000`;
274
+ }
275
+ const response = yield fetch(`http://${authHost}/api/v1/api-key/${id}`, {
276
+ method: 'DELETE'
277
+ });
278
+ if (!response.ok) {
279
+ throw new Error(`Failed to delete API key: ${response.status}`);
280
+ }
281
+ this.logger.info('API key deleted', { apiKeyId: id });
282
+ }
283
+ catch (error) {
284
+ this.logger.error('Error deleting API key', {
285
+ error: error instanceof Error ? error.message : 'Unknown error',
286
+ id
287
+ });
288
+ throw error;
289
+ }
290
+ });
291
+ }
292
+ }
293
+ exports.ApiKeyService = ApiKeyService;