fix(core): Resolve TypeScript strict mode and ES client API compatibility issues for v3.0.0
- Fix ES client v8+ API: use document/doc instead of body for index/update operations - Add type assertions (as any) for ES client ILM, template, and search APIs - Fix strict null checks with proper undefined handling (nullish coalescing) - Fix MetricsCollector interface to match required method signatures - Fix Logger.error signature compatibility in plugins - Resolve TermsQuery type index signature conflict - Remove sourceMap from tsconfig (handled by tsbuild with inlineSourceMap)
This commit is contained in:
@@ -1,6 +1,7 @@
|
||||
import { Client as ElasticClient } from '@elastic/elasticsearch';
|
||||
import { ElasticsearchConfig } from '../config/types.js';
|
||||
import { HealthChecker, HealthCheckResult, HealthStatus } from './health-check.js';
|
||||
import type { ElasticsearchConfig } from '../config/types.js';
|
||||
import { HealthChecker, HealthStatus } from './health-check.js';
|
||||
import type { HealthCheckResult } from './health-check.js';
|
||||
import { CircuitBreaker } from './circuit-breaker.js';
|
||||
import { Logger, defaultLogger } from '../observability/logger.js';
|
||||
import { MetricsCollector, defaultMetricsCollector } from '../observability/metrics.js';
|
||||
|
||||
@@ -1,4 +1,5 @@
|
||||
import { ErrorCode, ErrorContext } from './types.js';
|
||||
import { ErrorCode } from './types.js';
|
||||
import type { ErrorContext } from './types.js';
|
||||
|
||||
/**
|
||||
* Base error class for all Elasticsearch client errors
|
||||
|
||||
@@ -1,4 +1,4 @@
|
||||
import { RetryConfig, RetryStrategy } from './types.js';
|
||||
import type { RetryConfig } from './types.js';
|
||||
import { ElasticsearchError } from './elasticsearch-error.js';
|
||||
|
||||
/**
|
||||
|
||||
@@ -199,9 +199,26 @@ export class Logger {
|
||||
|
||||
/**
|
||||
* Log at ERROR level
|
||||
*
|
||||
* Accepts either:
|
||||
* - error(message, Error, meta) - explicit error with optional metadata
|
||||
* - error(message, meta) - error context as metadata (error property extracted)
|
||||
*/
|
||||
error(message: string, error?: Error, meta?: Record<string, unknown>): void {
|
||||
this.log(LogLevel.ERROR, message, meta, error);
|
||||
error(message: string, errorOrMeta?: Error | Record<string, unknown>, meta?: Record<string, unknown>): void {
|
||||
if (errorOrMeta instanceof Error) {
|
||||
this.log(LogLevel.ERROR, message, meta, errorOrMeta);
|
||||
} else if (errorOrMeta && typeof errorOrMeta === 'object') {
|
||||
// Extract error from meta if present
|
||||
const errorValue = (errorOrMeta as Record<string, unknown>).error;
|
||||
const extractedError = errorValue instanceof Error
|
||||
? errorValue
|
||||
: typeof errorValue === 'string'
|
||||
? new Error(errorValue)
|
||||
: undefined;
|
||||
this.log(LogLevel.ERROR, message, errorOrMeta, extractedError);
|
||||
} else {
|
||||
this.log(LogLevel.ERROR, message);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
|
||||
@@ -529,6 +529,42 @@ export class MetricsCollector {
|
||||
return histogram;
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a counter increment (convenience method for plugins)
|
||||
*/
|
||||
recordCounter(name: string, value: number = 1, labels: Labels = {}): void {
|
||||
let counter = this.registry.get(name) as Counter | undefined;
|
||||
if (!counter) {
|
||||
counter = new Counter(name, `Counter: ${name}`, Object.keys(labels));
|
||||
this.registry.register(counter);
|
||||
}
|
||||
counter.inc(labels, value);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a histogram observation (convenience method for plugins)
|
||||
*/
|
||||
recordHistogram(name: string, value: number, labels: Labels = {}): void {
|
||||
let histogram = this.registry.get(name) as Histogram | undefined;
|
||||
if (!histogram) {
|
||||
histogram = new Histogram(name, `Histogram: ${name}`, Object.keys(labels));
|
||||
this.registry.register(histogram);
|
||||
}
|
||||
histogram.observe(value, labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Record a gauge value (convenience method for plugins)
|
||||
*/
|
||||
recordGauge(name: string, value: number, labels: Labels = {}): void {
|
||||
let gauge = this.registry.get(name) as Gauge | undefined;
|
||||
if (!gauge) {
|
||||
gauge = new Gauge(name, `Gauge: ${name}`, Object.keys(labels));
|
||||
this.registry.register(gauge);
|
||||
}
|
||||
gauge.set(value, labels);
|
||||
}
|
||||
|
||||
/**
|
||||
* Export all metrics in Prometheus format
|
||||
*/
|
||||
|
||||
@@ -311,10 +311,16 @@ export class InMemoryTracer implements Tracer {
|
||||
const parts = traceparent.split('-');
|
||||
if (parts.length !== 4) return null;
|
||||
|
||||
const traceId = parts[1];
|
||||
const spanId = parts[2];
|
||||
const flagsStr = parts[3];
|
||||
|
||||
if (!traceId || !spanId || !flagsStr) return null;
|
||||
|
||||
return {
|
||||
traceId: parts[1],
|
||||
spanId: parts[2],
|
||||
traceFlags: parseInt(parts[3], 16),
|
||||
traceId,
|
||||
spanId,
|
||||
traceFlags: parseInt(flagsStr, 16),
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
@@ -107,17 +107,12 @@ export function createLoggingPlugin(config: LoggingPluginConfig = {}): Plugin {
|
||||
|
||||
const duration = Date.now() - context.request.startTime;
|
||||
|
||||
logger.error('Elasticsearch error', {
|
||||
logger.error('Elasticsearch error', context.error, {
|
||||
requestId: context.request.requestId,
|
||||
method: context.request.method,
|
||||
path: context.request.path,
|
||||
duration,
|
||||
attempts: context.attempts,
|
||||
error: {
|
||||
name: context.error.name,
|
||||
message: context.error.message,
|
||||
stack: context.error.stack,
|
||||
},
|
||||
statusCode: context.response?.statusCode,
|
||||
});
|
||||
|
||||
|
||||
@@ -128,14 +128,19 @@ function extractIndexFromPath(path: string): string {
|
||||
|
||||
// Split by slash and get first segment
|
||||
const segments = cleanPath.split('/');
|
||||
const firstSegment = segments[0];
|
||||
|
||||
// Common patterns:
|
||||
// /{index}/_search
|
||||
// /{index}/_doc/{id}
|
||||
// /_cat/indices
|
||||
if (segments[0].startsWith('_')) {
|
||||
return segments[0]; // API endpoint like _cat, _search
|
||||
if (!firstSegment) {
|
||||
return 'unknown';
|
||||
}
|
||||
|
||||
return segments[0] || 'unknown';
|
||||
if (firstSegment.startsWith('_')) {
|
||||
return firstSegment; // API endpoint like _cat, _search
|
||||
}
|
||||
|
||||
return firstSegment;
|
||||
}
|
||||
|
||||
@@ -63,7 +63,7 @@ export class PluginManager {
|
||||
try {
|
||||
await plugin.initialize(this.client, plugin.config || {});
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to initialize plugin '${plugin.name}'`, { error });
|
||||
this.logger.error(`Failed to initialize plugin '${plugin.name}'`, error instanceof Error ? error : new Error(String(error)));
|
||||
throw error;
|
||||
}
|
||||
}
|
||||
@@ -109,7 +109,7 @@ export class PluginManager {
|
||||
try {
|
||||
await plugin.destroy();
|
||||
} catch (error) {
|
||||
this.logger.error(`Failed to destroy plugin '${name}'`, { error });
|
||||
this.logger.error(`Failed to destroy plugin '${name}'`, error instanceof Error ? error : new Error(String(error)));
|
||||
}
|
||||
}
|
||||
|
||||
@@ -186,16 +186,15 @@ export class PluginManager {
|
||||
}
|
||||
|
||||
currentContext = result;
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in beforeRequest hook for plugin '${plugin.name}'`, {
|
||||
error,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error in beforeRequest hook for plugin '${plugin.name}'`, err);
|
||||
|
||||
if (this.config.collectStats) {
|
||||
const stats = this.pluginStats.get(plugin.name);
|
||||
if (stats) {
|
||||
stats.errors++;
|
||||
stats.lastError = error.message;
|
||||
stats.lastError = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -245,16 +244,15 @@ export class PluginManager {
|
||||
});
|
||||
|
||||
currentResponse = result;
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in afterResponse hook for plugin '${plugin.name}'`, {
|
||||
error,
|
||||
});
|
||||
} catch (error: unknown) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error in afterResponse hook for plugin '${plugin.name}'`, err);
|
||||
|
||||
if (this.config.collectStats) {
|
||||
const stats = this.pluginStats.get(plugin.name);
|
||||
if (stats) {
|
||||
stats.errors++;
|
||||
stats.lastError = error.message;
|
||||
stats.lastError = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -303,14 +301,15 @@ export class PluginManager {
|
||||
this.logger.debug(`Error handled by plugin '${plugin.name}'`);
|
||||
return result;
|
||||
}
|
||||
} catch (error: any) {
|
||||
this.logger.error(`Error in onError hook for plugin '${plugin.name}'`, { error });
|
||||
} catch (error: unknown) {
|
||||
const err = error instanceof Error ? error : new Error(String(error));
|
||||
this.logger.error(`Error in onError hook for plugin '${plugin.name}'`, err);
|
||||
|
||||
if (this.config.collectStats) {
|
||||
const stats = this.pluginStats.get(plugin.name);
|
||||
if (stats) {
|
||||
stats.errors++;
|
||||
stats.lastError = error.message;
|
||||
stats.lastError = err.message;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user