@digilogiclabs/platform-core 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.
- package/README.md +545 -0
- package/dist/ConsoleEmail-XeUBAnwc.d.mts +2786 -0
- package/dist/ConsoleEmail-XeUBAnwc.d.ts +2786 -0
- package/dist/index-C_2W7Byw.d.mts +379 -0
- package/dist/index-C_2W7Byw.d.ts +379 -0
- package/dist/index.d.mts +2045 -0
- package/dist/index.d.ts +2045 -0
- package/dist/index.js +6690 -0
- package/dist/index.js.map +1 -0
- package/dist/index.mjs +6550 -0
- package/dist/index.mjs.map +1 -0
- package/dist/migrate.js +1101 -0
- package/dist/migrate.js.map +1 -0
- package/dist/migrations/index.d.mts +1 -0
- package/dist/migrations/index.d.ts +1 -0
- package/dist/migrations/index.js +508 -0
- package/dist/migrations/index.js.map +1 -0
- package/dist/migrations/index.mjs +468 -0
- package/dist/migrations/index.mjs.map +1 -0
- package/dist/testing.d.mts +97 -0
- package/dist/testing.d.ts +97 -0
- package/dist/testing.js +1789 -0
- package/dist/testing.js.map +1 -0
- package/dist/testing.mjs +1743 -0
- package/dist/testing.mjs.map +1 -0
- package/package.json +152 -0
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,2045 @@
|
|
|
1
|
+
import { p as ILogger, q as IMetrics, I as IPlatform, P as PlatformHealthStatus, u as MetricsSummary, e as IDatabase, k as IQueryBuilder, Q as QueryResult, l as ICache, m as IStorage, U as UploadOptions, S as StorageFile, n as IEmail, t as EmailMessage, v as EmailResult, o as IQueue, s as JobOptions, J as Job } from './ConsoleEmail-XeUBAnwc.js';
|
|
2
|
+
export { an as BulkheadConfigSchema, ax as CacheConfig, ag as CacheConfigSchema, a9 as CacheProviderSchema, al as CircuitBreakerConfigSchema, C as ConsoleEmail, h as ConsoleLogger, aw as DatabaseConfig, af as DatabaseConfigSchema, a8 as DatabaseProviderSchema, a4 as EmailAddress, a5 as EmailAttachment, az as EmailConfig, ai as EmailConfigSchema, ab as EmailProviderSchema, E as EnvSecrets, G as GetSecretOptions, H as HistogramStats, w as ICacheOptions, r as ISecrets, _ as ISpan, Z as ITracing, x as JobResult, z as LogEntry, L as LogLevel, ae as LogLevelSchema, y as LogMeta, A as LoggerConfig, ap as LoggingConfigSchema, a as MemoryCache, M as MemoryDatabase, c as MemoryEmail, i as MemoryMetrics, d as MemoryQueue, f as MemorySecrets, b as MemoryStorage, X as MemoryTracing, B as MetricTags, aq as MetricsConfigSchema, aD as MiddlewareConfig, at as MiddlewareConfigSchema, N as NoopLogger, j as NoopMetrics, Y as NoopTracing, aC as ObservabilityConfig, as as ObservabilityConfigSchema, av as PlatformConfig, au as PlatformConfigSchema, aA as QueueConfig, aj as QueueConfigSchema, ac as QueueProviderSchema, aB as ResilienceConfig, ao as ResilienceConfigSchema, ak as RetryConfigSchema, R as RotateSecretOptions, O as RotationResult, D as Secret, F as SecretMetadata, K as SetSecretOptions, $ as SpanContext, a7 as SpanEvent, a2 as SpanKind, a0 as SpanOptions, a1 as SpanStatus, a6 as SpanStatusCode, ay as StorageConfig, ah as StorageConfigSchema, aa as StorageProviderSchema, am as TimeoutConfigSchema, T as TimingStats, a3 as TracingConfig, ar as TracingConfigSchema, ad as TracingProviderSchema, g as createPlatform, V as createPlatformAsync, W as createScopedMetrics, aH as getDefaultConfig, aE as loadConfig, aG as safeValidateConfig, aF as validateConfig } from './ConsoleEmail-XeUBAnwc.js';
|
|
3
|
+
export { i as IMigrationDatabase, I as IMigrator, a as Migration, b as MigrationRecord, e as MigrationResult, f as MigrationStatus, M as Migrator, h as MigratorConfig, S as SQL, c as createMigration, d as defineMigration, g as generateVersion, s as sqlMigration } from './index-C_2W7Byw.js';
|
|
4
|
+
import { SupabaseClient } from '@supabase/supabase-js';
|
|
5
|
+
import { Pool } from 'pg';
|
|
6
|
+
import { Redis } from '@upstash/redis';
|
|
7
|
+
import { Redis as Redis$1 } from 'ioredis';
|
|
8
|
+
import { S3Client } from '@aws-sdk/client-s3';
|
|
9
|
+
import { getSignedUrl } from '@aws-sdk/s3-request-presigner';
|
|
10
|
+
import { Resend } from 'resend';
|
|
11
|
+
import 'zod';
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Health Check Interface
|
|
15
|
+
* Standardizes health check behavior across all adapters
|
|
16
|
+
*/
|
|
17
|
+
/**
|
|
18
|
+
* Result of a single health check
|
|
19
|
+
*/
|
|
20
|
+
interface HealthCheckResult {
|
|
21
|
+
/** Overall health status */
|
|
22
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
23
|
+
/** Time taken to perform the check in milliseconds */
|
|
24
|
+
latencyMs: number;
|
|
25
|
+
/** When the check was performed */
|
|
26
|
+
timestamp: Date;
|
|
27
|
+
/** Optional message with details */
|
|
28
|
+
message?: string;
|
|
29
|
+
/** Additional details about the health check */
|
|
30
|
+
details?: Record<string, unknown>;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Aggregated health result for the entire platform
|
|
34
|
+
*/
|
|
35
|
+
interface PlatformHealthResult {
|
|
36
|
+
/** Overall platform status */
|
|
37
|
+
status: 'healthy' | 'degraded' | 'unhealthy';
|
|
38
|
+
/** When the check was performed */
|
|
39
|
+
timestamp: Date;
|
|
40
|
+
/** Individual service health results */
|
|
41
|
+
services: {
|
|
42
|
+
database: HealthCheckResult;
|
|
43
|
+
cache: HealthCheckResult;
|
|
44
|
+
storage: HealthCheckResult;
|
|
45
|
+
email: HealthCheckResult;
|
|
46
|
+
queue: HealthCheckResult;
|
|
47
|
+
};
|
|
48
|
+
/** Summary counts */
|
|
49
|
+
summary: {
|
|
50
|
+
total: number;
|
|
51
|
+
healthy: number;
|
|
52
|
+
degraded: number;
|
|
53
|
+
unhealthy: number;
|
|
54
|
+
};
|
|
55
|
+
}
|
|
56
|
+
/**
|
|
57
|
+
* Interface for services that support health checks
|
|
58
|
+
*/
|
|
59
|
+
interface IHealth {
|
|
60
|
+
/**
|
|
61
|
+
* Perform a health check on the service
|
|
62
|
+
* @returns Promise resolving to health check result
|
|
63
|
+
*/
|
|
64
|
+
healthCheck(): Promise<HealthCheckResult>;
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* Interface for services that support simple boolean health checks
|
|
68
|
+
* (Legacy support - prefer IHealth for new implementations)
|
|
69
|
+
*/
|
|
70
|
+
interface IHealthCheckable {
|
|
71
|
+
/**
|
|
72
|
+
* Simple health check returning boolean
|
|
73
|
+
* @returns Promise resolving to true if healthy
|
|
74
|
+
*/
|
|
75
|
+
healthCheck(): Promise<boolean>;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Helper to convert boolean health check to HealthCheckResult
|
|
79
|
+
*/
|
|
80
|
+
declare function toHealthCheckResult(healthy: boolean, latencyMs: number, message?: string): HealthCheckResult;
|
|
81
|
+
/**
|
|
82
|
+
* Helper to perform a timed health check
|
|
83
|
+
*/
|
|
84
|
+
declare function timedHealthCheck<T>(fn: () => Promise<T>, successCheck?: (result: T) => boolean): Promise<HealthCheckResult>;
|
|
85
|
+
|
|
86
|
+
/**
|
|
87
|
+
* Middleware System for Platform Core
|
|
88
|
+
*
|
|
89
|
+
* Provides cross-cutting concerns like logging, metrics, caching, and error handling
|
|
90
|
+
* through a composable middleware pattern.
|
|
91
|
+
*/
|
|
92
|
+
|
|
93
|
+
/**
|
|
94
|
+
* Context passed to middleware functions
|
|
95
|
+
*/
|
|
96
|
+
interface MiddlewareContext<TArgs = unknown, TResult = unknown> {
|
|
97
|
+
/** The operation being performed (e.g., 'db.query', 'cache.get') */
|
|
98
|
+
operation: string;
|
|
99
|
+
/** The service type (e.g., 'database', 'cache', 'storage') */
|
|
100
|
+
service: 'database' | 'cache' | 'storage' | 'email' | 'queue';
|
|
101
|
+
/** Arguments passed to the operation */
|
|
102
|
+
args: TArgs;
|
|
103
|
+
/** Result of the operation (only available in after/onError) */
|
|
104
|
+
result?: TResult;
|
|
105
|
+
/** Error if operation failed (only available in onError) */
|
|
106
|
+
error?: Error;
|
|
107
|
+
/** Timestamp when operation started */
|
|
108
|
+
startTime: number;
|
|
109
|
+
/** Duration in milliseconds (only available in after/onError) */
|
|
110
|
+
duration?: number;
|
|
111
|
+
/** Metadata bag for middleware to share data */
|
|
112
|
+
metadata: Map<string, unknown>;
|
|
113
|
+
/** Logger instance */
|
|
114
|
+
logger: ILogger;
|
|
115
|
+
/** Correlation ID for distributed tracing */
|
|
116
|
+
correlationId: string;
|
|
117
|
+
/** Tenant ID for multi-tenant applications */
|
|
118
|
+
tenantId?: string;
|
|
119
|
+
/** Whether to skip remaining middleware */
|
|
120
|
+
skip: boolean;
|
|
121
|
+
/** Cached result to return (bypasses actual operation) */
|
|
122
|
+
cachedResult?: TResult;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Middleware function signatures
|
|
126
|
+
*/
|
|
127
|
+
interface Middleware<TArgs = unknown, TResult = unknown> {
|
|
128
|
+
/** Unique name for the middleware */
|
|
129
|
+
name: string;
|
|
130
|
+
/** Priority for ordering (lower runs first) */
|
|
131
|
+
priority?: number;
|
|
132
|
+
/**
|
|
133
|
+
* Called before the operation executes.
|
|
134
|
+
* Can modify args, set cached result, or skip operation.
|
|
135
|
+
*/
|
|
136
|
+
before?(ctx: MiddlewareContext<TArgs, TResult>): Promise<void> | void;
|
|
137
|
+
/**
|
|
138
|
+
* Called after successful operation.
|
|
139
|
+
* Can modify or transform the result.
|
|
140
|
+
*/
|
|
141
|
+
after?(ctx: MiddlewareContext<TArgs, TResult>): Promise<void> | void;
|
|
142
|
+
/**
|
|
143
|
+
* Called when operation throws an error.
|
|
144
|
+
* Can handle, transform, or re-throw the error.
|
|
145
|
+
*/
|
|
146
|
+
onError?(ctx: MiddlewareContext<TArgs, TResult>, error: Error): Promise<void> | void;
|
|
147
|
+
}
|
|
148
|
+
/**
|
|
149
|
+
* Middleware chain executor
|
|
150
|
+
*/
|
|
151
|
+
interface MiddlewareChain {
|
|
152
|
+
/** Add middleware to the chain */
|
|
153
|
+
use<TArgs = unknown, TResult = unknown>(middleware: Middleware<TArgs, TResult>): MiddlewareChain;
|
|
154
|
+
/** Remove middleware by name */
|
|
155
|
+
remove(name: string): MiddlewareChain;
|
|
156
|
+
/** Execute the middleware chain around an operation */
|
|
157
|
+
execute<TArgs, TResult>(ctx: Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'>, operation: () => Promise<TResult>): Promise<TResult>;
|
|
158
|
+
/** Get all registered middleware */
|
|
159
|
+
getMiddleware(): Middleware[];
|
|
160
|
+
}
|
|
161
|
+
/**
|
|
162
|
+
* Options for creating a middleware chain
|
|
163
|
+
*/
|
|
164
|
+
interface MiddlewareChainOptions {
|
|
165
|
+
/** Logger for middleware operations */
|
|
166
|
+
logger?: ILogger;
|
|
167
|
+
/** Default correlation ID generator */
|
|
168
|
+
generateCorrelationId?: () => string;
|
|
169
|
+
}
|
|
170
|
+
|
|
171
|
+
/**
|
|
172
|
+
* Middleware Chain Implementation
|
|
173
|
+
*/
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* Create a new middleware chain
|
|
177
|
+
*/
|
|
178
|
+
declare function createMiddlewareChain(options?: MiddlewareChainOptions): MiddlewareChain;
|
|
179
|
+
/**
|
|
180
|
+
* Create a context for middleware execution
|
|
181
|
+
*/
|
|
182
|
+
declare function createMiddlewareContext<TArgs = unknown, TResult = unknown>(service: MiddlewareContext['service'], operation: string, args: TArgs, logger: ILogger, options?: {
|
|
183
|
+
correlationId?: string;
|
|
184
|
+
tenantId?: string;
|
|
185
|
+
}): Omit<MiddlewareContext<TArgs, TResult>, 'metadata' | 'skip' | 'cachedResult'>;
|
|
186
|
+
|
|
187
|
+
/**
|
|
188
|
+
* Built-in Middleware Implementations
|
|
189
|
+
*/
|
|
190
|
+
|
|
191
|
+
/**
|
|
192
|
+
* Logging middleware - logs all operations with timing
|
|
193
|
+
*/
|
|
194
|
+
declare function createLoggingMiddleware(logger: ILogger): Middleware;
|
|
195
|
+
/**
|
|
196
|
+
* Metrics middleware - records timing and counters
|
|
197
|
+
*/
|
|
198
|
+
declare function createMetricsMiddleware(metrics: IMetrics): Middleware;
|
|
199
|
+
/**
|
|
200
|
+
* Slow query logging middleware
|
|
201
|
+
*/
|
|
202
|
+
declare function createSlowQueryMiddleware(logger: ILogger, thresholdMs?: number): Middleware;
|
|
203
|
+
/**
|
|
204
|
+
* Tenant isolation middleware - ensures tenant context is set
|
|
205
|
+
*/
|
|
206
|
+
declare function createTenantMiddleware(options?: {
|
|
207
|
+
required?: boolean;
|
|
208
|
+
headerName?: string;
|
|
209
|
+
}): Middleware;
|
|
210
|
+
/**
|
|
211
|
+
* Request ID middleware - ensures correlation ID exists
|
|
212
|
+
*/
|
|
213
|
+
declare function createRequestIdMiddleware(): Middleware;
|
|
214
|
+
/**
|
|
215
|
+
* Timeout middleware - enforces operation timeout
|
|
216
|
+
*/
|
|
217
|
+
declare function createTimeoutMiddleware(timeoutMs: number): Middleware;
|
|
218
|
+
/**
|
|
219
|
+
* Cache middleware - caches results of read operations
|
|
220
|
+
*/
|
|
221
|
+
declare function createCacheMiddleware(cache: {
|
|
222
|
+
get: (key: string) => Promise<unknown>;
|
|
223
|
+
set: (key: string, value: unknown, ttl?: number) => Promise<void>;
|
|
224
|
+
}, options?: {
|
|
225
|
+
ttl?: number;
|
|
226
|
+
keyPrefix?: string;
|
|
227
|
+
cacheableOperations?: string[];
|
|
228
|
+
}): Middleware;
|
|
229
|
+
/**
|
|
230
|
+
* Rate Limiting Error
|
|
231
|
+
*/
|
|
232
|
+
declare class RateLimitError extends Error {
|
|
233
|
+
readonly name = "RateLimitError";
|
|
234
|
+
readonly retryAfter: number;
|
|
235
|
+
readonly limit: number;
|
|
236
|
+
readonly remaining: number;
|
|
237
|
+
readonly resetAt: Date;
|
|
238
|
+
constructor(message: string, options: {
|
|
239
|
+
retryAfter: number;
|
|
240
|
+
limit: number;
|
|
241
|
+
remaining: number;
|
|
242
|
+
resetAt: Date;
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
/**
|
|
246
|
+
* Rate limit info for responses
|
|
247
|
+
*/
|
|
248
|
+
interface RateLimitInfo {
|
|
249
|
+
limit: number;
|
|
250
|
+
remaining: number;
|
|
251
|
+
resetAt: Date;
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Rate limiter storage interface
|
|
255
|
+
*/
|
|
256
|
+
interface RateLimiterStorage {
|
|
257
|
+
/**
|
|
258
|
+
* Get current count and increment
|
|
259
|
+
* Returns: [currentCount, resetAt timestamp]
|
|
260
|
+
*/
|
|
261
|
+
increment(key: string, windowMs: number): Promise<[number, number]>;
|
|
262
|
+
/**
|
|
263
|
+
* Get current state without incrementing
|
|
264
|
+
*/
|
|
265
|
+
get(key: string): Promise<{
|
|
266
|
+
count: number;
|
|
267
|
+
resetAt: number;
|
|
268
|
+
} | null>;
|
|
269
|
+
}
|
|
270
|
+
/**
|
|
271
|
+
* In-memory rate limiter storage
|
|
272
|
+
*/
|
|
273
|
+
declare class MemoryRateLimiterStorage implements RateLimiterStorage {
|
|
274
|
+
private windows;
|
|
275
|
+
private cleanupInterval;
|
|
276
|
+
constructor(options?: {
|
|
277
|
+
cleanupIntervalMs?: number;
|
|
278
|
+
});
|
|
279
|
+
increment(key: string, windowMs: number): Promise<[number, number]>;
|
|
280
|
+
get(key: string): Promise<{
|
|
281
|
+
count: number;
|
|
282
|
+
resetAt: number;
|
|
283
|
+
} | null>;
|
|
284
|
+
/**
|
|
285
|
+
* Clear all windows (for testing)
|
|
286
|
+
*/
|
|
287
|
+
clear(): void;
|
|
288
|
+
/**
|
|
289
|
+
* Stop cleanup interval
|
|
290
|
+
*/
|
|
291
|
+
stop(): void;
|
|
292
|
+
}
|
|
293
|
+
/**
|
|
294
|
+
* Rate limiting algorithm types
|
|
295
|
+
*/
|
|
296
|
+
type RateLimitAlgorithm = 'fixed-window' | 'sliding-window' | 'token-bucket';
|
|
297
|
+
/**
|
|
298
|
+
* Rate limiting options
|
|
299
|
+
*/
|
|
300
|
+
interface RateLimitOptions {
|
|
301
|
+
/** Maximum requests per window */
|
|
302
|
+
limit: number;
|
|
303
|
+
/** Time window in milliseconds */
|
|
304
|
+
windowMs: number;
|
|
305
|
+
/** Storage backend (defaults to memory) */
|
|
306
|
+
storage?: RateLimiterStorage;
|
|
307
|
+
/** Key generator function */
|
|
308
|
+
keyGenerator?: (ctx: MiddlewareContext) => string;
|
|
309
|
+
/** Skip rate limiting for certain requests */
|
|
310
|
+
skip?: (ctx: MiddlewareContext) => boolean;
|
|
311
|
+
/** Handler for rate limit exceeded */
|
|
312
|
+
onRateLimited?: (ctx: MiddlewareContext, info: RateLimitInfo) => void;
|
|
313
|
+
/** Whether to throw error or just log (defaults to throw) */
|
|
314
|
+
throwOnLimit?: boolean;
|
|
315
|
+
/** Custom message for rate limit error */
|
|
316
|
+
message?: string;
|
|
317
|
+
/** Headers to set with rate limit info */
|
|
318
|
+
setHeaders?: boolean;
|
|
319
|
+
}
|
|
320
|
+
/**
|
|
321
|
+
* Rate limiting middleware
|
|
322
|
+
* Prevents abuse by limiting request frequency
|
|
323
|
+
*/
|
|
324
|
+
declare function createRateLimitMiddleware(options: RateLimitOptions): Middleware;
|
|
325
|
+
/**
|
|
326
|
+
* Create an IP-based rate limiter key generator
|
|
327
|
+
*/
|
|
328
|
+
declare function createIpKeyGenerator(getIp: (ctx: MiddlewareContext) => string | undefined): (ctx: MiddlewareContext) => string;
|
|
329
|
+
/**
|
|
330
|
+
* Create a user-based rate limiter key generator
|
|
331
|
+
*/
|
|
332
|
+
declare function createUserKeyGenerator(getUserId: (ctx: MiddlewareContext) => string | undefined): (ctx: MiddlewareContext) => string;
|
|
333
|
+
/**
|
|
334
|
+
* Sliding window rate limiter options
|
|
335
|
+
*/
|
|
336
|
+
interface SlidingWindowRateLimitOptions extends Omit<RateLimitOptions, 'algorithm'> {
|
|
337
|
+
/** Number of sub-windows (more = more accurate, more memory) */
|
|
338
|
+
precision?: number;
|
|
339
|
+
}
|
|
340
|
+
/**
|
|
341
|
+
* Token bucket rate limiter options
|
|
342
|
+
*/
|
|
343
|
+
interface TokenBucketOptions {
|
|
344
|
+
/** Bucket capacity (max tokens) */
|
|
345
|
+
capacity: number;
|
|
346
|
+
/** Token refill rate per second */
|
|
347
|
+
refillRate: number;
|
|
348
|
+
/** Storage backend */
|
|
349
|
+
storage?: RateLimiterStorage;
|
|
350
|
+
/** Key generator function */
|
|
351
|
+
keyGenerator?: (ctx: MiddlewareContext) => string;
|
|
352
|
+
/** Skip rate limiting for certain requests */
|
|
353
|
+
skip?: (ctx: MiddlewareContext) => boolean;
|
|
354
|
+
/** Whether to throw error or just log */
|
|
355
|
+
throwOnLimit?: boolean;
|
|
356
|
+
/** Custom message for rate limit error */
|
|
357
|
+
message?: string;
|
|
358
|
+
}
|
|
359
|
+
/**
|
|
360
|
+
* Pre-configured rate limit presets
|
|
361
|
+
*/
|
|
362
|
+
declare const RateLimitPresets: {
|
|
363
|
+
/** Standard API rate limit: 100 req/min */
|
|
364
|
+
readonly standard: {
|
|
365
|
+
readonly limit: 100;
|
|
366
|
+
readonly windowMs: number;
|
|
367
|
+
};
|
|
368
|
+
/** Strict rate limit: 10 req/min */
|
|
369
|
+
readonly strict: {
|
|
370
|
+
readonly limit: 10;
|
|
371
|
+
readonly windowMs: number;
|
|
372
|
+
};
|
|
373
|
+
/** Relaxed rate limit: 1000 req/min */
|
|
374
|
+
readonly relaxed: {
|
|
375
|
+
readonly limit: 1000;
|
|
376
|
+
readonly windowMs: number;
|
|
377
|
+
};
|
|
378
|
+
/** Burst protection: 50 req/sec */
|
|
379
|
+
readonly burst: {
|
|
380
|
+
readonly limit: 50;
|
|
381
|
+
readonly windowMs: 1000;
|
|
382
|
+
};
|
|
383
|
+
/** Auth rate limit: 5 attempts/15 min */
|
|
384
|
+
readonly auth: {
|
|
385
|
+
readonly limit: 5;
|
|
386
|
+
readonly windowMs: number;
|
|
387
|
+
};
|
|
388
|
+
/** Expensive operations: 10 req/hour */
|
|
389
|
+
readonly expensive: {
|
|
390
|
+
readonly limit: 10;
|
|
391
|
+
readonly windowMs: number;
|
|
392
|
+
};
|
|
393
|
+
};
|
|
394
|
+
|
|
395
|
+
/**
|
|
396
|
+
* Hooks System for Platform Core
|
|
397
|
+
*
|
|
398
|
+
* Provides lifecycle events and extensibility points for platform operations.
|
|
399
|
+
*/
|
|
400
|
+
|
|
401
|
+
/**
|
|
402
|
+
* All available platform hooks
|
|
403
|
+
*/
|
|
404
|
+
interface PlatformHooks {
|
|
405
|
+
/**
|
|
406
|
+
* Called when platform is fully initialized
|
|
407
|
+
*/
|
|
408
|
+
onReady?: () => Promise<void> | void;
|
|
409
|
+
/**
|
|
410
|
+
* Called when platform is shutting down
|
|
411
|
+
*/
|
|
412
|
+
onShutdown?: () => Promise<void> | void;
|
|
413
|
+
/**
|
|
414
|
+
* Called after health check completes
|
|
415
|
+
*/
|
|
416
|
+
onHealthCheck?: (result: PlatformHealthResult) => Promise<void> | void;
|
|
417
|
+
/**
|
|
418
|
+
* Called before any database query
|
|
419
|
+
*/
|
|
420
|
+
beforeQuery?: (context: QueryHookContext) => Promise<void> | void;
|
|
421
|
+
/**
|
|
422
|
+
* Called after successful database query
|
|
423
|
+
*/
|
|
424
|
+
afterQuery?: (context: QueryHookContext & {
|
|
425
|
+
result: unknown;
|
|
426
|
+
duration: number;
|
|
427
|
+
}) => Promise<void> | void;
|
|
428
|
+
/**
|
|
429
|
+
* Called before insert operation
|
|
430
|
+
*/
|
|
431
|
+
beforeInsert?: (context: InsertHookContext) => Promise<void> | void;
|
|
432
|
+
/**
|
|
433
|
+
* Called after successful insert
|
|
434
|
+
*/
|
|
435
|
+
afterInsert?: (context: InsertHookContext & {
|
|
436
|
+
result: unknown;
|
|
437
|
+
}) => Promise<void> | void;
|
|
438
|
+
/**
|
|
439
|
+
* Called before update operation
|
|
440
|
+
*/
|
|
441
|
+
beforeUpdate?: (context: UpdateHookContext) => Promise<void> | void;
|
|
442
|
+
/**
|
|
443
|
+
* Called after successful update
|
|
444
|
+
*/
|
|
445
|
+
afterUpdate?: (context: UpdateHookContext & {
|
|
446
|
+
result: unknown;
|
|
447
|
+
}) => Promise<void> | void;
|
|
448
|
+
/**
|
|
449
|
+
* Called before delete operation
|
|
450
|
+
*/
|
|
451
|
+
beforeDelete?: (context: DeleteHookContext) => Promise<void> | void;
|
|
452
|
+
/**
|
|
453
|
+
* Called after successful delete
|
|
454
|
+
*/
|
|
455
|
+
afterDelete?: (context: DeleteHookContext & {
|
|
456
|
+
count: number;
|
|
457
|
+
}) => Promise<void> | void;
|
|
458
|
+
/**
|
|
459
|
+
* Called when cache hit occurs
|
|
460
|
+
*/
|
|
461
|
+
onCacheHit?: (key: string, value: unknown) => Promise<void> | void;
|
|
462
|
+
/**
|
|
463
|
+
* Called when cache miss occurs
|
|
464
|
+
*/
|
|
465
|
+
onCacheMiss?: (key: string) => Promise<void> | void;
|
|
466
|
+
/**
|
|
467
|
+
* Called when cache entry is set
|
|
468
|
+
*/
|
|
469
|
+
onCacheSet?: (key: string, ttl?: number) => Promise<void> | void;
|
|
470
|
+
/**
|
|
471
|
+
* Called when cache entry is deleted
|
|
472
|
+
*/
|
|
473
|
+
onCacheDelete?: (key: string) => Promise<void> | void;
|
|
474
|
+
/**
|
|
475
|
+
* Called before file upload
|
|
476
|
+
*/
|
|
477
|
+
beforeUpload?: (context: UploadHookContext) => Promise<void> | void;
|
|
478
|
+
/**
|
|
479
|
+
* Called after successful upload
|
|
480
|
+
*/
|
|
481
|
+
afterUpload?: (context: UploadHookContext & {
|
|
482
|
+
url: string;
|
|
483
|
+
}) => Promise<void> | void;
|
|
484
|
+
/**
|
|
485
|
+
* Called before file download
|
|
486
|
+
*/
|
|
487
|
+
beforeDownload?: (key: string) => Promise<void> | void;
|
|
488
|
+
/**
|
|
489
|
+
* Called after successful download
|
|
490
|
+
*/
|
|
491
|
+
afterDownload?: (key: string, size: number) => Promise<void> | void;
|
|
492
|
+
/**
|
|
493
|
+
* Called before file deletion
|
|
494
|
+
*/
|
|
495
|
+
beforeStorageDelete?: (key: string) => Promise<void> | void;
|
|
496
|
+
/**
|
|
497
|
+
* Called after successful storage deletion
|
|
498
|
+
*/
|
|
499
|
+
afterStorageDelete?: (key: string) => Promise<void> | void;
|
|
500
|
+
/**
|
|
501
|
+
* Called before email is sent
|
|
502
|
+
*/
|
|
503
|
+
beforeEmailSend?: (context: EmailHookContext) => Promise<void> | void;
|
|
504
|
+
/**
|
|
505
|
+
* Called after email is sent successfully
|
|
506
|
+
*/
|
|
507
|
+
afterEmailSend?: (context: EmailHookContext & {
|
|
508
|
+
messageId: string;
|
|
509
|
+
}) => Promise<void> | void;
|
|
510
|
+
/**
|
|
511
|
+
* Called when email send fails
|
|
512
|
+
*/
|
|
513
|
+
onEmailFailed?: (context: EmailHookContext, error: Error) => Promise<void> | void;
|
|
514
|
+
/**
|
|
515
|
+
* Called when job is added to queue
|
|
516
|
+
*/
|
|
517
|
+
onJobAdd?: (context: JobHookContext) => Promise<void> | void;
|
|
518
|
+
/**
|
|
519
|
+
* Called when job starts processing
|
|
520
|
+
*/
|
|
521
|
+
onJobStart?: (context: JobHookContext) => Promise<void> | void;
|
|
522
|
+
/**
|
|
523
|
+
* Called when job completes successfully
|
|
524
|
+
*/
|
|
525
|
+
onJobComplete?: (context: JobHookContext & {
|
|
526
|
+
result: unknown;
|
|
527
|
+
}) => Promise<void> | void;
|
|
528
|
+
/**
|
|
529
|
+
* Called when job fails
|
|
530
|
+
*/
|
|
531
|
+
onJobFailed?: (context: JobHookContext, error: Error) => Promise<void> | void;
|
|
532
|
+
/**
|
|
533
|
+
* Called when job is retried
|
|
534
|
+
*/
|
|
535
|
+
onJobRetry?: (context: JobHookContext & {
|
|
536
|
+
attempt: number;
|
|
537
|
+
}) => Promise<void> | void;
|
|
538
|
+
/**
|
|
539
|
+
* Global error handler for any platform operation
|
|
540
|
+
*/
|
|
541
|
+
onError?: (context: ErrorHookContext) => Promise<void> | void;
|
|
542
|
+
}
|
|
543
|
+
/**
|
|
544
|
+
* Context for database query hooks
|
|
545
|
+
*/
|
|
546
|
+
interface QueryHookContext {
|
|
547
|
+
table: string;
|
|
548
|
+
operation: 'select' | 'insert' | 'update' | 'delete' | 'raw';
|
|
549
|
+
conditions?: Record<string, unknown>;
|
|
550
|
+
correlationId?: string;
|
|
551
|
+
tenantId?: string;
|
|
552
|
+
}
|
|
553
|
+
/**
|
|
554
|
+
* Context for insert hooks
|
|
555
|
+
*/
|
|
556
|
+
interface InsertHookContext {
|
|
557
|
+
table: string;
|
|
558
|
+
data: Record<string, unknown> | Record<string, unknown>[];
|
|
559
|
+
correlationId?: string;
|
|
560
|
+
tenantId?: string;
|
|
561
|
+
}
|
|
562
|
+
/**
|
|
563
|
+
* Context for update hooks
|
|
564
|
+
*/
|
|
565
|
+
interface UpdateHookContext {
|
|
566
|
+
table: string;
|
|
567
|
+
data: Record<string, unknown>;
|
|
568
|
+
conditions: Record<string, unknown>;
|
|
569
|
+
correlationId?: string;
|
|
570
|
+
tenantId?: string;
|
|
571
|
+
}
|
|
572
|
+
/**
|
|
573
|
+
* Context for delete hooks
|
|
574
|
+
*/
|
|
575
|
+
interface DeleteHookContext {
|
|
576
|
+
table: string;
|
|
577
|
+
conditions: Record<string, unknown>;
|
|
578
|
+
correlationId?: string;
|
|
579
|
+
tenantId?: string;
|
|
580
|
+
}
|
|
581
|
+
/**
|
|
582
|
+
* Context for upload hooks
|
|
583
|
+
*/
|
|
584
|
+
interface UploadHookContext {
|
|
585
|
+
key: string;
|
|
586
|
+
contentType?: string;
|
|
587
|
+
size?: number;
|
|
588
|
+
correlationId?: string;
|
|
589
|
+
tenantId?: string;
|
|
590
|
+
}
|
|
591
|
+
/**
|
|
592
|
+
* Context for email hooks
|
|
593
|
+
*/
|
|
594
|
+
interface EmailHookContext {
|
|
595
|
+
to: string | string[];
|
|
596
|
+
subject: string;
|
|
597
|
+
correlationId?: string;
|
|
598
|
+
tenantId?: string;
|
|
599
|
+
}
|
|
600
|
+
/**
|
|
601
|
+
* Context for job hooks
|
|
602
|
+
*/
|
|
603
|
+
interface JobHookContext {
|
|
604
|
+
jobId: string;
|
|
605
|
+
name: string;
|
|
606
|
+
data: unknown;
|
|
607
|
+
correlationId?: string;
|
|
608
|
+
tenantId?: string;
|
|
609
|
+
}
|
|
610
|
+
/**
|
|
611
|
+
* Context for error hooks
|
|
612
|
+
*/
|
|
613
|
+
interface ErrorHookContext {
|
|
614
|
+
service: 'database' | 'cache' | 'storage' | 'email' | 'queue';
|
|
615
|
+
operation: string;
|
|
616
|
+
error: Error;
|
|
617
|
+
correlationId?: string;
|
|
618
|
+
tenantId?: string;
|
|
619
|
+
}
|
|
620
|
+
/**
|
|
621
|
+
* Hook registry for managing platform hooks
|
|
622
|
+
*/
|
|
623
|
+
interface HookRegistry {
|
|
624
|
+
/**
|
|
625
|
+
* Register hooks
|
|
626
|
+
*/
|
|
627
|
+
register(hooks: Partial<PlatformHooks>): void;
|
|
628
|
+
/**
|
|
629
|
+
* Unregister all hooks
|
|
630
|
+
*/
|
|
631
|
+
clear(): void;
|
|
632
|
+
/**
|
|
633
|
+
* Execute a hook by name
|
|
634
|
+
*/
|
|
635
|
+
execute<K extends keyof PlatformHooks>(hookName: K, ...args: Parameters<NonNullable<PlatformHooks[K]>>): Promise<void>;
|
|
636
|
+
/**
|
|
637
|
+
* Get registered hooks
|
|
638
|
+
*/
|
|
639
|
+
getHooks(): PlatformHooks;
|
|
640
|
+
}
|
|
641
|
+
|
|
642
|
+
/**
|
|
643
|
+
* Hook Registry Implementation
|
|
644
|
+
*/
|
|
645
|
+
|
|
646
|
+
/**
|
|
647
|
+
* Create a hook registry
|
|
648
|
+
*/
|
|
649
|
+
declare function createHookRegistry(logger?: ILogger): HookRegistry;
|
|
650
|
+
/**
|
|
651
|
+
* Compose multiple hook registries
|
|
652
|
+
*/
|
|
653
|
+
declare function composeHookRegistries(...registries: HookRegistry[]): HookRegistry;
|
|
654
|
+
|
|
655
|
+
/**
|
|
656
|
+
* Retry Pattern Implementation
|
|
657
|
+
*
|
|
658
|
+
* Provides configurable retry logic with exponential backoff and jitter.
|
|
659
|
+
*/
|
|
660
|
+
|
|
661
|
+
/**
|
|
662
|
+
* Options for retry behavior
|
|
663
|
+
*/
|
|
664
|
+
interface RetryOptions {
|
|
665
|
+
/**
|
|
666
|
+
* Maximum number of retry attempts
|
|
667
|
+
* @default 3
|
|
668
|
+
*/
|
|
669
|
+
maxAttempts: number;
|
|
670
|
+
/**
|
|
671
|
+
* Initial delay between retries in milliseconds
|
|
672
|
+
* @default 100
|
|
673
|
+
*/
|
|
674
|
+
baseDelay: number;
|
|
675
|
+
/**
|
|
676
|
+
* Maximum delay between retries in milliseconds
|
|
677
|
+
* @default 10000
|
|
678
|
+
*/
|
|
679
|
+
maxDelay: number;
|
|
680
|
+
/**
|
|
681
|
+
* Multiplier for exponential backoff
|
|
682
|
+
* @default 2
|
|
683
|
+
*/
|
|
684
|
+
backoffMultiplier: number;
|
|
685
|
+
/**
|
|
686
|
+
* Whether to add random jitter to delays
|
|
687
|
+
* @default true
|
|
688
|
+
*/
|
|
689
|
+
jitter: boolean;
|
|
690
|
+
/**
|
|
691
|
+
* Maximum jitter in milliseconds
|
|
692
|
+
* @default 100
|
|
693
|
+
*/
|
|
694
|
+
maxJitter: number;
|
|
695
|
+
/**
|
|
696
|
+
* Function to determine if error is retryable
|
|
697
|
+
* @default All errors are retryable
|
|
698
|
+
*/
|
|
699
|
+
retryIf?: (error: Error) => boolean;
|
|
700
|
+
/**
|
|
701
|
+
* Function to determine if error is non-retryable
|
|
702
|
+
* Takes precedence over retryIf
|
|
703
|
+
*/
|
|
704
|
+
abortIf?: (error: Error) => boolean;
|
|
705
|
+
/**
|
|
706
|
+
* Callback on each retry attempt
|
|
707
|
+
*/
|
|
708
|
+
onRetry?: (error: Error, attempt: number, delay: number) => void;
|
|
709
|
+
/**
|
|
710
|
+
* Logger for retry operations
|
|
711
|
+
*/
|
|
712
|
+
logger?: ILogger;
|
|
713
|
+
}
|
|
714
|
+
/**
|
|
715
|
+
* Default retry options
|
|
716
|
+
*/
|
|
717
|
+
declare const DEFAULT_RETRY_OPTIONS: RetryOptions;
|
|
718
|
+
/**
|
|
719
|
+
* Result of a retry operation
|
|
720
|
+
*/
|
|
721
|
+
interface RetryResult<T> {
|
|
722
|
+
/** Whether the operation succeeded */
|
|
723
|
+
success: boolean;
|
|
724
|
+
/** The result if successful */
|
|
725
|
+
result?: T;
|
|
726
|
+
/** The final error if all attempts failed */
|
|
727
|
+
error?: Error;
|
|
728
|
+
/** Number of attempts made */
|
|
729
|
+
attempts: number;
|
|
730
|
+
/** Total time spent in milliseconds */
|
|
731
|
+
totalTime: number;
|
|
732
|
+
}
|
|
733
|
+
/**
|
|
734
|
+
* Execute a function with retry logic
|
|
735
|
+
*/
|
|
736
|
+
declare function withRetry<T>(fn: () => Promise<T>, options?: Partial<RetryOptions>): Promise<T>;
|
|
737
|
+
/**
|
|
738
|
+
* Execute with retry and return detailed result
|
|
739
|
+
*/
|
|
740
|
+
declare function withRetryResult<T>(fn: () => Promise<T>, options?: Partial<RetryOptions>): Promise<RetryResult<T>>;
|
|
741
|
+
/**
|
|
742
|
+
* Create a retryable version of a function
|
|
743
|
+
*/
|
|
744
|
+
declare function retryable<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, options?: Partial<RetryOptions>): (...args: TArgs) => Promise<TResult>;
|
|
745
|
+
/**
|
|
746
|
+
* Common retry predicates
|
|
747
|
+
*/
|
|
748
|
+
declare const RetryPredicates: {
|
|
749
|
+
/**
|
|
750
|
+
* Retry on network errors
|
|
751
|
+
*/
|
|
752
|
+
networkErrors: (error: Error) => boolean;
|
|
753
|
+
/**
|
|
754
|
+
* Retry on HTTP 5xx errors
|
|
755
|
+
*/
|
|
756
|
+
serverErrors: (error: Error) => boolean;
|
|
757
|
+
/**
|
|
758
|
+
* Retry on HTTP 429 (rate limit) errors
|
|
759
|
+
*/
|
|
760
|
+
rateLimitErrors: (error: Error) => boolean;
|
|
761
|
+
/**
|
|
762
|
+
* Retry on database deadlock errors
|
|
763
|
+
*/
|
|
764
|
+
deadlockErrors: (error: Error) => boolean;
|
|
765
|
+
/**
|
|
766
|
+
* Never retry on authentication errors
|
|
767
|
+
*/
|
|
768
|
+
authenticationErrors: (error: Error) => boolean;
|
|
769
|
+
/**
|
|
770
|
+
* Never retry on validation errors
|
|
771
|
+
*/
|
|
772
|
+
validationErrors: (error: Error) => boolean;
|
|
773
|
+
};
|
|
774
|
+
/**
|
|
775
|
+
* Common retry configurations
|
|
776
|
+
*/
|
|
777
|
+
declare const RetryConfigs: {
|
|
778
|
+
/**
|
|
779
|
+
* Fast retry for quick failures
|
|
780
|
+
*/
|
|
781
|
+
fast: Partial<RetryOptions>;
|
|
782
|
+
/**
|
|
783
|
+
* Standard retry configuration
|
|
784
|
+
*/
|
|
785
|
+
standard: Partial<RetryOptions>;
|
|
786
|
+
/**
|
|
787
|
+
* Aggressive retry for critical operations
|
|
788
|
+
*/
|
|
789
|
+
aggressive: Partial<RetryOptions>;
|
|
790
|
+
/**
|
|
791
|
+
* Conservative retry for rate-limited APIs
|
|
792
|
+
*/
|
|
793
|
+
rateLimited: Partial<RetryOptions>;
|
|
794
|
+
/**
|
|
795
|
+
* Database retry configuration
|
|
796
|
+
*/
|
|
797
|
+
database: Partial<RetryOptions>;
|
|
798
|
+
};
|
|
799
|
+
|
|
800
|
+
/**
|
|
801
|
+
* Circuit Breaker Pattern Implementation
|
|
802
|
+
*
|
|
803
|
+
* Prevents cascading failures by temporarily blocking calls to a failing service.
|
|
804
|
+
*/
|
|
805
|
+
|
|
806
|
+
/**
|
|
807
|
+
* Circuit breaker states
|
|
808
|
+
*/
|
|
809
|
+
type CircuitState = 'closed' | 'open' | 'half-open';
|
|
810
|
+
/**
|
|
811
|
+
* Options for circuit breaker behavior
|
|
812
|
+
*/
|
|
813
|
+
interface CircuitBreakerOptions {
|
|
814
|
+
/**
|
|
815
|
+
* Name of the circuit (for logging)
|
|
816
|
+
*/
|
|
817
|
+
name: string;
|
|
818
|
+
/**
|
|
819
|
+
* Number of failures before opening the circuit
|
|
820
|
+
* @default 5
|
|
821
|
+
*/
|
|
822
|
+
failureThreshold: number;
|
|
823
|
+
/**
|
|
824
|
+
* Time in milliseconds before attempting to close the circuit
|
|
825
|
+
* @default 30000
|
|
826
|
+
*/
|
|
827
|
+
resetTimeout: number;
|
|
828
|
+
/**
|
|
829
|
+
* Number of successful requests needed in half-open state to close the circuit
|
|
830
|
+
* @default 3
|
|
831
|
+
*/
|
|
832
|
+
successThreshold: number;
|
|
833
|
+
/**
|
|
834
|
+
* Time window in milliseconds for counting failures
|
|
835
|
+
* @default 60000
|
|
836
|
+
*/
|
|
837
|
+
failureWindow: number;
|
|
838
|
+
/**
|
|
839
|
+
* Function to determine if error should trip the circuit
|
|
840
|
+
* @default All errors trip the circuit
|
|
841
|
+
*/
|
|
842
|
+
shouldTrip?: (error: Error) => boolean;
|
|
843
|
+
/**
|
|
844
|
+
* Callback when circuit state changes
|
|
845
|
+
*/
|
|
846
|
+
onStateChange?: (from: CircuitState, to: CircuitState) => void;
|
|
847
|
+
/**
|
|
848
|
+
* Callback when circuit opens
|
|
849
|
+
*/
|
|
850
|
+
onOpen?: (failures: number, lastError: Error) => void;
|
|
851
|
+
/**
|
|
852
|
+
* Callback when circuit closes
|
|
853
|
+
*/
|
|
854
|
+
onClose?: () => void;
|
|
855
|
+
/**
|
|
856
|
+
* Callback when request is rejected due to open circuit
|
|
857
|
+
*/
|
|
858
|
+
onReject?: (state: CircuitState) => void;
|
|
859
|
+
/**
|
|
860
|
+
* Logger for circuit breaker events
|
|
861
|
+
*/
|
|
862
|
+
logger?: ILogger;
|
|
863
|
+
}
|
|
864
|
+
/**
|
|
865
|
+
* Default circuit breaker options
|
|
866
|
+
*/
|
|
867
|
+
declare const DEFAULT_CIRCUIT_BREAKER_OPTIONS: Omit<CircuitBreakerOptions, 'name'>;
|
|
868
|
+
/**
|
|
869
|
+
* Error thrown when circuit is open
|
|
870
|
+
*/
|
|
871
|
+
declare class CircuitOpenError extends Error {
|
|
872
|
+
readonly name = "CircuitOpenError";
|
|
873
|
+
readonly circuitName: string;
|
|
874
|
+
readonly state: CircuitState;
|
|
875
|
+
readonly nextAttemptAt: Date;
|
|
876
|
+
constructor(circuitName: string, state: CircuitState, resetTimeout: number);
|
|
877
|
+
}
|
|
878
|
+
/**
|
|
879
|
+
* Circuit breaker statistics
|
|
880
|
+
*/
|
|
881
|
+
interface CircuitBreakerStats {
|
|
882
|
+
state: CircuitState;
|
|
883
|
+
failures: number;
|
|
884
|
+
successes: number;
|
|
885
|
+
lastFailure?: Date;
|
|
886
|
+
lastSuccess?: Date;
|
|
887
|
+
lastStateChange?: Date;
|
|
888
|
+
totalRequests: number;
|
|
889
|
+
rejectedRequests: number;
|
|
890
|
+
}
|
|
891
|
+
/**
|
|
892
|
+
* Circuit breaker implementation
|
|
893
|
+
*/
|
|
894
|
+
declare class CircuitBreaker {
|
|
895
|
+
private state;
|
|
896
|
+
private failures;
|
|
897
|
+
private successes;
|
|
898
|
+
private failureTimestamps;
|
|
899
|
+
private lastFailure?;
|
|
900
|
+
private lastSuccess?;
|
|
901
|
+
private lastStateChange?;
|
|
902
|
+
private lastOpenedAt?;
|
|
903
|
+
private totalRequests;
|
|
904
|
+
private rejectedRequests;
|
|
905
|
+
private lastError?;
|
|
906
|
+
private readonly options;
|
|
907
|
+
private readonly logger;
|
|
908
|
+
constructor(options: CircuitBreakerOptions);
|
|
909
|
+
/**
|
|
910
|
+
* Execute a function with circuit breaker protection
|
|
911
|
+
*/
|
|
912
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
913
|
+
/**
|
|
914
|
+
* Check if circuit allows execution
|
|
915
|
+
*/
|
|
916
|
+
canExecute(): boolean;
|
|
917
|
+
/**
|
|
918
|
+
* Record a successful execution
|
|
919
|
+
*/
|
|
920
|
+
private onSuccess;
|
|
921
|
+
/**
|
|
922
|
+
* Record a failed execution
|
|
923
|
+
*/
|
|
924
|
+
private onFailure;
|
|
925
|
+
/**
|
|
926
|
+
* Transition to a new state
|
|
927
|
+
*/
|
|
928
|
+
private transitionTo;
|
|
929
|
+
/**
|
|
930
|
+
* Check if reset timeout has passed
|
|
931
|
+
*/
|
|
932
|
+
private shouldAttemptReset;
|
|
933
|
+
/**
|
|
934
|
+
* Get remaining time until reset attempt
|
|
935
|
+
*/
|
|
936
|
+
private getRemainingTimeout;
|
|
937
|
+
/**
|
|
938
|
+
* Get current circuit state
|
|
939
|
+
*/
|
|
940
|
+
getState(): CircuitState;
|
|
941
|
+
/**
|
|
942
|
+
* Get circuit breaker statistics
|
|
943
|
+
*/
|
|
944
|
+
getStats(): CircuitBreakerStats;
|
|
945
|
+
/**
|
|
946
|
+
* Manually reset the circuit to closed state
|
|
947
|
+
*/
|
|
948
|
+
reset(): void;
|
|
949
|
+
/**
|
|
950
|
+
* Manually trip the circuit to open state
|
|
951
|
+
*/
|
|
952
|
+
trip(): void;
|
|
953
|
+
/**
|
|
954
|
+
* Check if circuit is open
|
|
955
|
+
*/
|
|
956
|
+
isOpen(): boolean;
|
|
957
|
+
/**
|
|
958
|
+
* Check if circuit is closed
|
|
959
|
+
*/
|
|
960
|
+
isClosed(): boolean;
|
|
961
|
+
/**
|
|
962
|
+
* Check if circuit is half-open
|
|
963
|
+
*/
|
|
964
|
+
isHalfOpen(): boolean;
|
|
965
|
+
}
|
|
966
|
+
/**
|
|
967
|
+
* Create a circuit breaker
|
|
968
|
+
*/
|
|
969
|
+
declare function createCircuitBreaker(options: CircuitBreakerOptions): CircuitBreaker;
|
|
970
|
+
/**
|
|
971
|
+
* Circuit breaker registry for managing multiple circuits
|
|
972
|
+
*/
|
|
973
|
+
declare class CircuitBreakerRegistry {
|
|
974
|
+
private circuits;
|
|
975
|
+
private readonly logger;
|
|
976
|
+
private readonly defaultOptions;
|
|
977
|
+
constructor(options?: {
|
|
978
|
+
logger?: ILogger;
|
|
979
|
+
defaults?: Partial<CircuitBreakerOptions>;
|
|
980
|
+
});
|
|
981
|
+
/**
|
|
982
|
+
* Get or create a circuit breaker
|
|
983
|
+
*/
|
|
984
|
+
get(name: string, options?: Partial<CircuitBreakerOptions>): CircuitBreaker;
|
|
985
|
+
/**
|
|
986
|
+
* Execute with a named circuit breaker
|
|
987
|
+
*/
|
|
988
|
+
execute<T>(name: string, fn: () => Promise<T>, options?: Partial<CircuitBreakerOptions>): Promise<T>;
|
|
989
|
+
/**
|
|
990
|
+
* Get all circuit statistics
|
|
991
|
+
*/
|
|
992
|
+
getAllStats(): Record<string, CircuitBreakerStats>;
|
|
993
|
+
/**
|
|
994
|
+
* Reset all circuits
|
|
995
|
+
*/
|
|
996
|
+
resetAll(): void;
|
|
997
|
+
/**
|
|
998
|
+
* Clear all circuits
|
|
999
|
+
*/
|
|
1000
|
+
clear(): void;
|
|
1001
|
+
}
|
|
1002
|
+
|
|
1003
|
+
/**
|
|
1004
|
+
* Timeout Pattern Implementation
|
|
1005
|
+
*
|
|
1006
|
+
* Enforces time limits on operations to prevent hanging.
|
|
1007
|
+
*/
|
|
1008
|
+
/**
|
|
1009
|
+
* Error thrown when operation times out
|
|
1010
|
+
*/
|
|
1011
|
+
declare class TimeoutError extends Error {
|
|
1012
|
+
readonly name = "TimeoutError";
|
|
1013
|
+
readonly operation: string;
|
|
1014
|
+
readonly timeout: number;
|
|
1015
|
+
constructor(operation: string, timeout: number);
|
|
1016
|
+
}
|
|
1017
|
+
/**
|
|
1018
|
+
* Options for timeout behavior
|
|
1019
|
+
*/
|
|
1020
|
+
interface TimeoutOptions {
|
|
1021
|
+
/**
|
|
1022
|
+
* Timeout in milliseconds
|
|
1023
|
+
*/
|
|
1024
|
+
timeout: number;
|
|
1025
|
+
/**
|
|
1026
|
+
* Operation name (for error messages)
|
|
1027
|
+
*/
|
|
1028
|
+
operation?: string;
|
|
1029
|
+
/**
|
|
1030
|
+
* Whether to abort the operation on timeout (if supported)
|
|
1031
|
+
*/
|
|
1032
|
+
abortOnTimeout?: boolean;
|
|
1033
|
+
}
|
|
1034
|
+
/**
|
|
1035
|
+
* Execute a function with a timeout
|
|
1036
|
+
*/
|
|
1037
|
+
declare function withTimeout<T>(fn: () => Promise<T>, options: TimeoutOptions | number): Promise<T>;
|
|
1038
|
+
/**
|
|
1039
|
+
* Create a timeout-wrapped version of a function
|
|
1040
|
+
*/
|
|
1041
|
+
declare function withTimeoutWrapper<TArgs extends unknown[], TResult>(fn: (...args: TArgs) => Promise<TResult>, options: TimeoutOptions | number): (...args: TArgs) => Promise<TResult>;
|
|
1042
|
+
/**
|
|
1043
|
+
* Race a promise against a timeout
|
|
1044
|
+
*/
|
|
1045
|
+
declare function raceTimeout<T>(promise: Promise<T>, timeout: number, operation?: string): Promise<T>;
|
|
1046
|
+
/**
|
|
1047
|
+
* Default timeouts for different operations
|
|
1048
|
+
*/
|
|
1049
|
+
declare const DefaultTimeouts: {
|
|
1050
|
+
/** Quick operations like cache lookups */
|
|
1051
|
+
fast: number;
|
|
1052
|
+
/** Standard database queries */
|
|
1053
|
+
database: number;
|
|
1054
|
+
/** API calls to external services */
|
|
1055
|
+
api: number;
|
|
1056
|
+
/** File uploads/downloads */
|
|
1057
|
+
storage: number;
|
|
1058
|
+
/** Email sending */
|
|
1059
|
+
email: number;
|
|
1060
|
+
/** Long-running background jobs */
|
|
1061
|
+
job: number;
|
|
1062
|
+
};
|
|
1063
|
+
|
|
1064
|
+
/**
|
|
1065
|
+
* Bulkhead Pattern Implementation
|
|
1066
|
+
*
|
|
1067
|
+
* Isolates failures by limiting concurrent operations.
|
|
1068
|
+
*/
|
|
1069
|
+
|
|
1070
|
+
/**
|
|
1071
|
+
* Options for bulkhead behavior
|
|
1072
|
+
*/
|
|
1073
|
+
interface BulkheadOptions {
|
|
1074
|
+
/**
|
|
1075
|
+
* Name of the bulkhead (for logging)
|
|
1076
|
+
*/
|
|
1077
|
+
name: string;
|
|
1078
|
+
/**
|
|
1079
|
+
* Maximum concurrent executions allowed
|
|
1080
|
+
* @default 10
|
|
1081
|
+
*/
|
|
1082
|
+
maxConcurrent: number;
|
|
1083
|
+
/**
|
|
1084
|
+
* Maximum queue size for waiting requests
|
|
1085
|
+
* @default 100
|
|
1086
|
+
*/
|
|
1087
|
+
maxQueue: number;
|
|
1088
|
+
/**
|
|
1089
|
+
* Timeout for queued requests in milliseconds
|
|
1090
|
+
* @default 30000
|
|
1091
|
+
*/
|
|
1092
|
+
queueTimeout: number;
|
|
1093
|
+
/**
|
|
1094
|
+
* Callback when execution is rejected
|
|
1095
|
+
*/
|
|
1096
|
+
onReject?: (reason: 'concurrent' | 'queue' | 'timeout') => void;
|
|
1097
|
+
/**
|
|
1098
|
+
* Logger for bulkhead events
|
|
1099
|
+
*/
|
|
1100
|
+
logger?: ILogger;
|
|
1101
|
+
}
|
|
1102
|
+
/**
|
|
1103
|
+
* Default bulkhead options
|
|
1104
|
+
*/
|
|
1105
|
+
declare const DEFAULT_BULKHEAD_OPTIONS: Omit<BulkheadOptions, 'name'>;
|
|
1106
|
+
/**
|
|
1107
|
+
* Error thrown when bulkhead rejects a request
|
|
1108
|
+
*/
|
|
1109
|
+
declare class BulkheadRejectedError extends Error {
|
|
1110
|
+
readonly name = "BulkheadRejectedError";
|
|
1111
|
+
readonly bulkheadName: string;
|
|
1112
|
+
readonly reason: 'concurrent' | 'queue' | 'timeout';
|
|
1113
|
+
constructor(bulkheadName: string, reason: 'concurrent' | 'queue' | 'timeout');
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Bulkhead statistics
|
|
1117
|
+
*/
|
|
1118
|
+
interface BulkheadStats {
|
|
1119
|
+
activeCalls: number;
|
|
1120
|
+
queuedCalls: number;
|
|
1121
|
+
maxConcurrent: number;
|
|
1122
|
+
maxQueue: number;
|
|
1123
|
+
totalExecutions: number;
|
|
1124
|
+
rejectedCalls: number;
|
|
1125
|
+
availableSlots: number;
|
|
1126
|
+
availableQueueSlots: number;
|
|
1127
|
+
}
|
|
1128
|
+
/**
|
|
1129
|
+
* Bulkhead implementation
|
|
1130
|
+
*/
|
|
1131
|
+
declare class Bulkhead {
|
|
1132
|
+
private activeCalls;
|
|
1133
|
+
private queue;
|
|
1134
|
+
private totalExecutions;
|
|
1135
|
+
private rejectedCalls;
|
|
1136
|
+
private readonly options;
|
|
1137
|
+
private readonly logger;
|
|
1138
|
+
constructor(options: BulkheadOptions);
|
|
1139
|
+
/**
|
|
1140
|
+
* Execute a function with bulkhead protection
|
|
1141
|
+
*/
|
|
1142
|
+
execute<T>(fn: () => Promise<T>): Promise<T>;
|
|
1143
|
+
/**
|
|
1144
|
+
* Run an execution immediately
|
|
1145
|
+
*/
|
|
1146
|
+
private runExecution;
|
|
1147
|
+
/**
|
|
1148
|
+
* Queue a request for later execution
|
|
1149
|
+
*/
|
|
1150
|
+
private queueExecution;
|
|
1151
|
+
/**
|
|
1152
|
+
* Process queued requests
|
|
1153
|
+
*/
|
|
1154
|
+
private processQueue;
|
|
1155
|
+
/**
|
|
1156
|
+
* Get bulkhead statistics
|
|
1157
|
+
*/
|
|
1158
|
+
getStats(): BulkheadStats;
|
|
1159
|
+
/**
|
|
1160
|
+
* Check if bulkhead is at capacity
|
|
1161
|
+
*/
|
|
1162
|
+
isAtCapacity(): boolean;
|
|
1163
|
+
/**
|
|
1164
|
+
* Check if queue is full
|
|
1165
|
+
*/
|
|
1166
|
+
isQueueFull(): boolean;
|
|
1167
|
+
/**
|
|
1168
|
+
* Drain the queue (reject all pending)
|
|
1169
|
+
*/
|
|
1170
|
+
drain(): void;
|
|
1171
|
+
}
|
|
1172
|
+
/**
|
|
1173
|
+
* Create a bulkhead
|
|
1174
|
+
*/
|
|
1175
|
+
declare function createBulkhead(options: BulkheadOptions): Bulkhead;
|
|
1176
|
+
/**
|
|
1177
|
+
* Bulkhead registry for managing multiple bulkheads
|
|
1178
|
+
*/
|
|
1179
|
+
declare class BulkheadRegistry {
|
|
1180
|
+
private bulkheads;
|
|
1181
|
+
private readonly logger;
|
|
1182
|
+
private readonly defaultOptions;
|
|
1183
|
+
constructor(options?: {
|
|
1184
|
+
logger?: ILogger;
|
|
1185
|
+
defaults?: Partial<BulkheadOptions>;
|
|
1186
|
+
});
|
|
1187
|
+
/**
|
|
1188
|
+
* Get or create a bulkhead
|
|
1189
|
+
*/
|
|
1190
|
+
get(name: string, options?: Partial<BulkheadOptions>): Bulkhead;
|
|
1191
|
+
/**
|
|
1192
|
+
* Execute with a named bulkhead
|
|
1193
|
+
*/
|
|
1194
|
+
execute<T>(name: string, fn: () => Promise<T>, options?: Partial<BulkheadOptions>): Promise<T>;
|
|
1195
|
+
/**
|
|
1196
|
+
* Get all bulkhead statistics
|
|
1197
|
+
*/
|
|
1198
|
+
getAllStats(): Record<string, BulkheadStats>;
|
|
1199
|
+
/**
|
|
1200
|
+
* Drain all bulkheads
|
|
1201
|
+
*/
|
|
1202
|
+
drainAll(): void;
|
|
1203
|
+
/**
|
|
1204
|
+
* Clear all bulkheads
|
|
1205
|
+
*/
|
|
1206
|
+
clear(): void;
|
|
1207
|
+
}
|
|
1208
|
+
|
|
1209
|
+
/**
|
|
1210
|
+
* Fallback Pattern Implementation
|
|
1211
|
+
*
|
|
1212
|
+
* Provides fallback strategies when primary operations fail.
|
|
1213
|
+
*/
|
|
1214
|
+
|
|
1215
|
+
/**
|
|
1216
|
+
* Fallback options
|
|
1217
|
+
*/
|
|
1218
|
+
interface FallbackOptions<T> {
|
|
1219
|
+
/**
|
|
1220
|
+
* Static fallback value
|
|
1221
|
+
*/
|
|
1222
|
+
value?: T;
|
|
1223
|
+
/**
|
|
1224
|
+
* Fallback function (called with the error)
|
|
1225
|
+
*/
|
|
1226
|
+
fallbackFn?: (error: Error) => T | Promise<T>;
|
|
1227
|
+
/**
|
|
1228
|
+
* Cache the fallback result
|
|
1229
|
+
*/
|
|
1230
|
+
cache?: boolean;
|
|
1231
|
+
/**
|
|
1232
|
+
* Cache TTL in milliseconds
|
|
1233
|
+
*/
|
|
1234
|
+
cacheTTL?: number;
|
|
1235
|
+
/**
|
|
1236
|
+
* Callback when fallback is used
|
|
1237
|
+
*/
|
|
1238
|
+
onFallback?: (error: Error, fallbackValue: T) => void;
|
|
1239
|
+
/**
|
|
1240
|
+
* Errors to ignore (not trigger fallback)
|
|
1241
|
+
*/
|
|
1242
|
+
ignoreErrors?: (error: Error) => boolean;
|
|
1243
|
+
/**
|
|
1244
|
+
* Logger for fallback events
|
|
1245
|
+
*/
|
|
1246
|
+
logger?: ILogger;
|
|
1247
|
+
}
|
|
1248
|
+
/**
|
|
1249
|
+
* Result of a fallback operation
|
|
1250
|
+
*/
|
|
1251
|
+
interface FallbackResult<T> {
|
|
1252
|
+
/** The result value */
|
|
1253
|
+
value: T;
|
|
1254
|
+
/** Whether fallback was used */
|
|
1255
|
+
usedFallback: boolean;
|
|
1256
|
+
/** The original error (if fallback was used) */
|
|
1257
|
+
error?: Error;
|
|
1258
|
+
/** Whether the value came from cache */
|
|
1259
|
+
cached?: boolean;
|
|
1260
|
+
}
|
|
1261
|
+
/**
|
|
1262
|
+
* Execute with fallback
|
|
1263
|
+
*/
|
|
1264
|
+
declare function withFallback<T>(fn: () => Promise<T>, options: FallbackOptions<T>): Promise<T>;
|
|
1265
|
+
/**
|
|
1266
|
+
* Execute with fallback and return detailed result
|
|
1267
|
+
*/
|
|
1268
|
+
declare function withFallbackResult<T>(fn: () => Promise<T>, options: FallbackOptions<T>): Promise<FallbackResult<T>>;
|
|
1269
|
+
/**
|
|
1270
|
+
* Create a cached fallback
|
|
1271
|
+
*/
|
|
1272
|
+
declare function createCachedFallback<T>(options: {
|
|
1273
|
+
getValue: () => Promise<T>;
|
|
1274
|
+
cacheTTL?: number;
|
|
1275
|
+
logger?: ILogger;
|
|
1276
|
+
}): () => Promise<T>;
|
|
1277
|
+
/**
|
|
1278
|
+
* Fallback chain - try multiple fallbacks in order
|
|
1279
|
+
*/
|
|
1280
|
+
declare function withFallbackChain<T>(primary: () => Promise<T>, fallbacks: Array<() => Promise<T>>, options?: {
|
|
1281
|
+
logger?: ILogger;
|
|
1282
|
+
onFallback?: (index: number, error: Error) => void;
|
|
1283
|
+
}): Promise<T>;
|
|
1284
|
+
/**
|
|
1285
|
+
* Common fallback strategies
|
|
1286
|
+
*/
|
|
1287
|
+
declare const FallbackStrategies: {
|
|
1288
|
+
/**
|
|
1289
|
+
* Return empty array
|
|
1290
|
+
*/
|
|
1291
|
+
emptyArray: <T>() => FallbackOptions<T[]>;
|
|
1292
|
+
/**
|
|
1293
|
+
* Return null
|
|
1294
|
+
*/
|
|
1295
|
+
nullable: <T>() => FallbackOptions<T | null>;
|
|
1296
|
+
/**
|
|
1297
|
+
* Return default value
|
|
1298
|
+
*/
|
|
1299
|
+
defaultValue: <T>(value: T) => FallbackOptions<T>;
|
|
1300
|
+
/**
|
|
1301
|
+
* Return cached value from a cache function
|
|
1302
|
+
*/
|
|
1303
|
+
fromCache: <T>(getCached: () => Promise<T | null>, defaultValue: T) => FallbackOptions<T>;
|
|
1304
|
+
/**
|
|
1305
|
+
* Degrade gracefully with partial data
|
|
1306
|
+
*/
|
|
1307
|
+
degrade: <T>(getDegraded: (error: Error) => T) => FallbackOptions<T>;
|
|
1308
|
+
};
|
|
1309
|
+
|
|
1310
|
+
/**
|
|
1311
|
+
* Health Check HTTP Endpoints
|
|
1312
|
+
*
|
|
1313
|
+
* Provides standardized health check endpoints for Kubernetes probes
|
|
1314
|
+
* and monitoring systems.
|
|
1315
|
+
*
|
|
1316
|
+
* Endpoints:
|
|
1317
|
+
* - /health/live - Liveness probe (is the process alive?)
|
|
1318
|
+
* - /health/ready - Readiness probe (can it serve traffic?)
|
|
1319
|
+
* - /health/startup - Startup probe (has it finished initializing?)
|
|
1320
|
+
* - /health - Detailed health status for dashboards
|
|
1321
|
+
*/
|
|
1322
|
+
|
|
1323
|
+
type HealthStatus = 'healthy' | 'degraded' | 'unhealthy';
|
|
1324
|
+
interface LivenessResponse {
|
|
1325
|
+
status: 'ok' | 'error';
|
|
1326
|
+
}
|
|
1327
|
+
interface ReadinessResponse {
|
|
1328
|
+
status: 'ok' | 'error';
|
|
1329
|
+
checks: {
|
|
1330
|
+
database: boolean;
|
|
1331
|
+
cache: boolean;
|
|
1332
|
+
storage: boolean;
|
|
1333
|
+
email: boolean;
|
|
1334
|
+
queue: boolean;
|
|
1335
|
+
};
|
|
1336
|
+
}
|
|
1337
|
+
interface StartupResponse {
|
|
1338
|
+
status: 'ok' | 'error';
|
|
1339
|
+
ready: boolean;
|
|
1340
|
+
}
|
|
1341
|
+
interface ServiceHealth {
|
|
1342
|
+
status: HealthStatus;
|
|
1343
|
+
latencyMs?: number;
|
|
1344
|
+
message?: string;
|
|
1345
|
+
lastChecked?: string;
|
|
1346
|
+
}
|
|
1347
|
+
interface DetailedHealthResponse {
|
|
1348
|
+
status: HealthStatus;
|
|
1349
|
+
version: string;
|
|
1350
|
+
environment: string;
|
|
1351
|
+
uptime: number;
|
|
1352
|
+
uptimeFormatted: string;
|
|
1353
|
+
timestamp: string;
|
|
1354
|
+
services: {
|
|
1355
|
+
database: ServiceHealth;
|
|
1356
|
+
cache: ServiceHealth;
|
|
1357
|
+
storage: ServiceHealth;
|
|
1358
|
+
email: ServiceHealth;
|
|
1359
|
+
queue: ServiceHealth;
|
|
1360
|
+
};
|
|
1361
|
+
system?: {
|
|
1362
|
+
memoryUsage: {
|
|
1363
|
+
heapUsed: number;
|
|
1364
|
+
heapTotal: number;
|
|
1365
|
+
external: number;
|
|
1366
|
+
rss: number;
|
|
1367
|
+
};
|
|
1368
|
+
cpuUsage?: {
|
|
1369
|
+
user: number;
|
|
1370
|
+
system: number;
|
|
1371
|
+
};
|
|
1372
|
+
};
|
|
1373
|
+
}
|
|
1374
|
+
interface HealthEndpoints {
|
|
1375
|
+
/**
|
|
1376
|
+
* Liveness probe - is the process alive?
|
|
1377
|
+
* Returns 200 if alive, 503 if dead.
|
|
1378
|
+
* K8s will restart the pod if this fails.
|
|
1379
|
+
*/
|
|
1380
|
+
live(): Promise<LivenessResponse>;
|
|
1381
|
+
/**
|
|
1382
|
+
* Readiness probe - can it serve traffic?
|
|
1383
|
+
* Returns 200 if ready, 503 if not ready.
|
|
1384
|
+
* K8s will remove from load balancer if this fails.
|
|
1385
|
+
*/
|
|
1386
|
+
ready(): Promise<ReadinessResponse>;
|
|
1387
|
+
/**
|
|
1388
|
+
* Startup probe - has it finished initializing?
|
|
1389
|
+
* Returns 200 when startup is complete.
|
|
1390
|
+
* K8s waits for this before starting liveness/readiness probes.
|
|
1391
|
+
*/
|
|
1392
|
+
startup(): Promise<StartupResponse>;
|
|
1393
|
+
/**
|
|
1394
|
+
* Detailed health status for monitoring dashboards.
|
|
1395
|
+
* Includes service-level health, latencies, and system metrics.
|
|
1396
|
+
*/
|
|
1397
|
+
detailed(): Promise<DetailedHealthResponse>;
|
|
1398
|
+
/**
|
|
1399
|
+
* Mark startup as complete (call after initialization)
|
|
1400
|
+
*/
|
|
1401
|
+
markStartupComplete(): void;
|
|
1402
|
+
/**
|
|
1403
|
+
* Get raw health status for custom integrations
|
|
1404
|
+
*/
|
|
1405
|
+
getRawStatus(): Promise<PlatformHealthStatus>;
|
|
1406
|
+
}
|
|
1407
|
+
interface HealthEndpointsOptions {
|
|
1408
|
+
/** Application version */
|
|
1409
|
+
version?: string;
|
|
1410
|
+
/** Environment name */
|
|
1411
|
+
environment?: string;
|
|
1412
|
+
/** Include system metrics in detailed response */
|
|
1413
|
+
includeSystemMetrics?: boolean;
|
|
1414
|
+
/** Custom health checks to include */
|
|
1415
|
+
customChecks?: Record<string, () => Promise<boolean>>;
|
|
1416
|
+
/** Timeout for individual health checks (ms) */
|
|
1417
|
+
checkTimeout?: number;
|
|
1418
|
+
}
|
|
1419
|
+
declare function createHealthEndpoints(platform: IPlatform, options?: HealthEndpointsOptions): HealthEndpoints;
|
|
1420
|
+
/**
|
|
1421
|
+
* Create Express-compatible health route handlers
|
|
1422
|
+
*/
|
|
1423
|
+
declare function createExpressHealthHandlers(endpoints: HealthEndpoints): {
|
|
1424
|
+
live: (_req: unknown, res: {
|
|
1425
|
+
status: (code: number) => {
|
|
1426
|
+
json: (data: unknown) => void;
|
|
1427
|
+
};
|
|
1428
|
+
}) => Promise<void>;
|
|
1429
|
+
ready: (_req: unknown, res: {
|
|
1430
|
+
status: (code: number) => {
|
|
1431
|
+
json: (data: unknown) => void;
|
|
1432
|
+
};
|
|
1433
|
+
}) => Promise<void>;
|
|
1434
|
+
startup: (_req: unknown, res: {
|
|
1435
|
+
status: (code: number) => {
|
|
1436
|
+
json: (data: unknown) => void;
|
|
1437
|
+
};
|
|
1438
|
+
}) => Promise<void>;
|
|
1439
|
+
detailed: (_req: unknown, res: {
|
|
1440
|
+
status: (code: number) => {
|
|
1441
|
+
json: (data: unknown) => void;
|
|
1442
|
+
};
|
|
1443
|
+
}) => Promise<void>;
|
|
1444
|
+
};
|
|
1445
|
+
/**
|
|
1446
|
+
* Create a simple HTTP server for health checks (standalone, no framework)
|
|
1447
|
+
*/
|
|
1448
|
+
declare function createHealthServer(endpoints: HealthEndpoints, port?: number): Promise<{
|
|
1449
|
+
close: () => Promise<void>;
|
|
1450
|
+
}>;
|
|
1451
|
+
|
|
1452
|
+
/**
|
|
1453
|
+
* Prometheus Metrics HTTP Endpoint
|
|
1454
|
+
*
|
|
1455
|
+
* Provides a /metrics endpoint that exports metrics in Prometheus text format.
|
|
1456
|
+
* This enables scraping by Prometheus, Grafana Agent, or other compatible systems.
|
|
1457
|
+
*
|
|
1458
|
+
* @example
|
|
1459
|
+
* ```typescript
|
|
1460
|
+
* import { createMetricsEndpoint } from '@digilogiclabs/platform-core';
|
|
1461
|
+
*
|
|
1462
|
+
* const metricsEndpoint = createMetricsEndpoint(platform.metrics, {
|
|
1463
|
+
* prefix: 'myapp',
|
|
1464
|
+
* defaultLabels: { service: 'api', environment: 'production' },
|
|
1465
|
+
* });
|
|
1466
|
+
*
|
|
1467
|
+
* // Get Prometheus format output
|
|
1468
|
+
* const prometheusText = metricsEndpoint.getPrometheusMetrics();
|
|
1469
|
+
*
|
|
1470
|
+
* // Or use the built-in server
|
|
1471
|
+
* const server = await createMetricsServer(metricsEndpoint, 9090);
|
|
1472
|
+
* ```
|
|
1473
|
+
*/
|
|
1474
|
+
|
|
1475
|
+
interface MetricsEndpointOptions {
|
|
1476
|
+
/** Prefix for all metric names */
|
|
1477
|
+
prefix?: string;
|
|
1478
|
+
/** Default labels to add to all metrics */
|
|
1479
|
+
defaultLabels?: Record<string, string>;
|
|
1480
|
+
/** Include process metrics (memory, cpu, etc.) */
|
|
1481
|
+
includeProcessMetrics?: boolean;
|
|
1482
|
+
/** Include Node.js event loop metrics */
|
|
1483
|
+
includeEventLoopMetrics?: boolean;
|
|
1484
|
+
/** Histogram buckets for timing metrics */
|
|
1485
|
+
histogramBuckets?: number[];
|
|
1486
|
+
}
|
|
1487
|
+
interface MetricsEndpoint {
|
|
1488
|
+
/**
|
|
1489
|
+
* Get metrics in Prometheus text exposition format
|
|
1490
|
+
*/
|
|
1491
|
+
getPrometheusMetrics(): string;
|
|
1492
|
+
/**
|
|
1493
|
+
* Get metrics as JSON (for debugging)
|
|
1494
|
+
*/
|
|
1495
|
+
getJsonMetrics(): MetricsSummary;
|
|
1496
|
+
/**
|
|
1497
|
+
* Record a custom metric
|
|
1498
|
+
*/
|
|
1499
|
+
recordMetric(type: 'counter' | 'gauge' | 'histogram', name: string, value: number, labels?: Record<string, string>): void;
|
|
1500
|
+
}
|
|
1501
|
+
declare function createMetricsEndpoint(metrics: IMetrics, options?: MetricsEndpointOptions): MetricsEndpoint;
|
|
1502
|
+
/**
|
|
1503
|
+
* Create Express-compatible metrics handler
|
|
1504
|
+
*/
|
|
1505
|
+
declare function createExpressMetricsHandler(endpoint: MetricsEndpoint): (_req: unknown, res: {
|
|
1506
|
+
setHeader: (name: string, value: string) => void;
|
|
1507
|
+
status: (code: number) => {
|
|
1508
|
+
send: (data: string) => void;
|
|
1509
|
+
};
|
|
1510
|
+
}) => void;
|
|
1511
|
+
/**
|
|
1512
|
+
* Create a standalone HTTP server for metrics (no framework required)
|
|
1513
|
+
*/
|
|
1514
|
+
declare function createMetricsServer(endpoint: MetricsEndpoint, port?: number): Promise<{
|
|
1515
|
+
close: () => Promise<void>;
|
|
1516
|
+
port: number;
|
|
1517
|
+
}>;
|
|
1518
|
+
|
|
1519
|
+
/**
|
|
1520
|
+
* Create a combined server that serves both health and metrics endpoints
|
|
1521
|
+
*
|
|
1522
|
+
* Endpoints:
|
|
1523
|
+
* - /health/live, /healthz - Liveness probe
|
|
1524
|
+
* - /health/ready, /readyz - Readiness probe
|
|
1525
|
+
* - /health/startup, /startupz - Startup probe
|
|
1526
|
+
* - /health - Detailed health
|
|
1527
|
+
* - /metrics - Prometheus metrics
|
|
1528
|
+
* - /metrics.json - JSON metrics (debugging)
|
|
1529
|
+
*/
|
|
1530
|
+
declare function createObservabilityServer(healthEndpoints: HealthEndpoints, metricsEndpoint: MetricsEndpoint, port?: number): Promise<{
|
|
1531
|
+
close: () => Promise<void>;
|
|
1532
|
+
port: number;
|
|
1533
|
+
}>;
|
|
1534
|
+
|
|
1535
|
+
/**
|
|
1536
|
+
* Supabase Database Adapter
|
|
1537
|
+
* Production implementation using Supabase as the database provider
|
|
1538
|
+
*/
|
|
1539
|
+
|
|
1540
|
+
declare class SupabaseDatabase implements IDatabase {
|
|
1541
|
+
private client;
|
|
1542
|
+
constructor(client: SupabaseClient);
|
|
1543
|
+
from<T = unknown>(table: string): IQueryBuilder<T>;
|
|
1544
|
+
raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
1545
|
+
transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T>;
|
|
1546
|
+
healthCheck(): Promise<boolean>;
|
|
1547
|
+
close(): Promise<void>;
|
|
1548
|
+
}
|
|
1549
|
+
|
|
1550
|
+
/**
|
|
1551
|
+
* PostgreSQL Direct Database Adapter
|
|
1552
|
+
*
|
|
1553
|
+
* Production implementation using pg (node-postgres) for direct PostgreSQL connections.
|
|
1554
|
+
* Provides true ACID transaction support, connection pooling, and prepared statements.
|
|
1555
|
+
*
|
|
1556
|
+
* This adapter is vendor-agnostic - works with any PostgreSQL-compatible database:
|
|
1557
|
+
* - PostgreSQL (self-hosted or managed)
|
|
1558
|
+
* - Amazon RDS PostgreSQL
|
|
1559
|
+
* - Azure Database for PostgreSQL
|
|
1560
|
+
* - Google Cloud SQL for PostgreSQL
|
|
1561
|
+
* - CockroachDB (PostgreSQL wire protocol)
|
|
1562
|
+
* - YugabyteDB
|
|
1563
|
+
* - Neon, Supabase (direct connection, not REST)
|
|
1564
|
+
*/
|
|
1565
|
+
|
|
1566
|
+
interface PostgresConfig {
|
|
1567
|
+
/** Connection string (postgresql://user:pass@host:port/database) */
|
|
1568
|
+
connectionString?: string;
|
|
1569
|
+
/** Host name */
|
|
1570
|
+
host?: string;
|
|
1571
|
+
/** Port number */
|
|
1572
|
+
port?: number;
|
|
1573
|
+
/** Database name */
|
|
1574
|
+
database?: string;
|
|
1575
|
+
/** Username */
|
|
1576
|
+
user?: string;
|
|
1577
|
+
/** Password */
|
|
1578
|
+
password?: string;
|
|
1579
|
+
/** SSL configuration */
|
|
1580
|
+
ssl?: boolean | {
|
|
1581
|
+
rejectUnauthorized?: boolean;
|
|
1582
|
+
ca?: string;
|
|
1583
|
+
};
|
|
1584
|
+
/** Maximum number of connections in pool */
|
|
1585
|
+
max?: number;
|
|
1586
|
+
/** Idle timeout in milliseconds */
|
|
1587
|
+
idleTimeoutMillis?: number;
|
|
1588
|
+
/** Connection timeout in milliseconds */
|
|
1589
|
+
connectionTimeoutMillis?: number;
|
|
1590
|
+
/** Statement timeout in milliseconds (0 = no limit) */
|
|
1591
|
+
statementTimeout?: number;
|
|
1592
|
+
/** Query timeout in milliseconds (0 = no limit) */
|
|
1593
|
+
queryTimeout?: number;
|
|
1594
|
+
/** Application name for connection identification */
|
|
1595
|
+
applicationName?: string;
|
|
1596
|
+
}
|
|
1597
|
+
declare class PostgresDatabase implements IDatabase {
|
|
1598
|
+
private pool;
|
|
1599
|
+
private config;
|
|
1600
|
+
constructor(pool: Pool, config?: PostgresConfig);
|
|
1601
|
+
/**
|
|
1602
|
+
* Create a PostgresDatabase from configuration
|
|
1603
|
+
*/
|
|
1604
|
+
static create(config: PostgresConfig): Promise<PostgresDatabase>;
|
|
1605
|
+
/**
|
|
1606
|
+
* Create from environment variables
|
|
1607
|
+
*/
|
|
1608
|
+
static fromEnv(): Promise<PostgresDatabase>;
|
|
1609
|
+
from<T = unknown>(table: string): IQueryBuilder<T>;
|
|
1610
|
+
raw<T = unknown>(sql: string, params?: unknown[]): Promise<QueryResult<T>>;
|
|
1611
|
+
/**
|
|
1612
|
+
* Execute a function within a database transaction.
|
|
1613
|
+
* Provides true ACID guarantees - either all operations succeed or all are rolled back.
|
|
1614
|
+
*/
|
|
1615
|
+
transaction<T>(fn: (tx: IDatabase) => Promise<T>): Promise<T>;
|
|
1616
|
+
healthCheck(): Promise<boolean>;
|
|
1617
|
+
close(): Promise<void>;
|
|
1618
|
+
/**
|
|
1619
|
+
* Get pool statistics for monitoring
|
|
1620
|
+
*/
|
|
1621
|
+
getPoolStats(): {
|
|
1622
|
+
totalCount: number;
|
|
1623
|
+
idleCount: number;
|
|
1624
|
+
waitingCount: number;
|
|
1625
|
+
};
|
|
1626
|
+
}
|
|
1627
|
+
|
|
1628
|
+
/**
|
|
1629
|
+
* Upstash Redis Cache Adapter
|
|
1630
|
+
* Production implementation using Upstash Redis REST API
|
|
1631
|
+
*/
|
|
1632
|
+
|
|
1633
|
+
declare class UpstashCache implements ICache {
|
|
1634
|
+
private client;
|
|
1635
|
+
constructor(client: Redis);
|
|
1636
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
1637
|
+
set<T = unknown>(key: string, value: T, ttl?: number): Promise<void>;
|
|
1638
|
+
delete(key: string): Promise<void>;
|
|
1639
|
+
exists(key: string): Promise<boolean>;
|
|
1640
|
+
deletePattern(pattern: string): Promise<number>;
|
|
1641
|
+
mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
|
|
1642
|
+
mset<T = unknown>(entries: Array<{
|
|
1643
|
+
key: string;
|
|
1644
|
+
value: T;
|
|
1645
|
+
ttl?: number;
|
|
1646
|
+
}>): Promise<void>;
|
|
1647
|
+
incr(key: string, by?: number): Promise<number>;
|
|
1648
|
+
publish(channel: string, message: string): Promise<void>;
|
|
1649
|
+
subscribe(channel: string, callback: (message: string) => void): Promise<() => void>;
|
|
1650
|
+
healthCheck(): Promise<boolean>;
|
|
1651
|
+
close(): Promise<void>;
|
|
1652
|
+
}
|
|
1653
|
+
|
|
1654
|
+
/**
|
|
1655
|
+
* Redis Direct Cache Adapter
|
|
1656
|
+
*
|
|
1657
|
+
* Production implementation using ioredis for direct Redis connections.
|
|
1658
|
+
* Provides lower latency than REST-based solutions, true pub/sub support,
|
|
1659
|
+
* and full Redis command set.
|
|
1660
|
+
*
|
|
1661
|
+
* This adapter is vendor-agnostic - works with any Redis-compatible server:
|
|
1662
|
+
* - Redis (self-hosted or managed)
|
|
1663
|
+
* - Amazon ElastiCache for Redis
|
|
1664
|
+
* - Azure Cache for Redis
|
|
1665
|
+
* - Google Cloud Memorystore for Redis
|
|
1666
|
+
* - Redis Enterprise
|
|
1667
|
+
* - KeyDB
|
|
1668
|
+
* - DragonflyDB
|
|
1669
|
+
*/
|
|
1670
|
+
|
|
1671
|
+
interface RedisConfig {
|
|
1672
|
+
/** Connection URL (redis://user:pass@host:port/db) */
|
|
1673
|
+
url?: string;
|
|
1674
|
+
/** Host name */
|
|
1675
|
+
host?: string;
|
|
1676
|
+
/** Port number */
|
|
1677
|
+
port?: number;
|
|
1678
|
+
/** Password */
|
|
1679
|
+
password?: string;
|
|
1680
|
+
/** Database number (0-15) */
|
|
1681
|
+
db?: number;
|
|
1682
|
+
/** Username (Redis 6+) */
|
|
1683
|
+
username?: string;
|
|
1684
|
+
/** Connection name for identification */
|
|
1685
|
+
name?: string;
|
|
1686
|
+
/** Key prefix for namespacing */
|
|
1687
|
+
keyPrefix?: string;
|
|
1688
|
+
/** Enable TLS */
|
|
1689
|
+
tls?: boolean | {
|
|
1690
|
+
rejectUnauthorized?: boolean;
|
|
1691
|
+
ca?: string;
|
|
1692
|
+
};
|
|
1693
|
+
/** Connection timeout in milliseconds */
|
|
1694
|
+
connectTimeout?: number;
|
|
1695
|
+
/** Command timeout in milliseconds */
|
|
1696
|
+
commandTimeout?: number;
|
|
1697
|
+
/** Keep alive timeout */
|
|
1698
|
+
keepAlive?: number;
|
|
1699
|
+
/** Max retries per request */
|
|
1700
|
+
maxRetriesPerRequest?: number;
|
|
1701
|
+
/** Enable auto-reconnect */
|
|
1702
|
+
autoReconnect?: boolean;
|
|
1703
|
+
/** Lazy connect (don't connect until first command) */
|
|
1704
|
+
lazyConnect?: boolean;
|
|
1705
|
+
/** Enable offline queue */
|
|
1706
|
+
enableOfflineQueue?: boolean;
|
|
1707
|
+
/** Sentinel configuration for HA */
|
|
1708
|
+
sentinel?: {
|
|
1709
|
+
sentinels: Array<{
|
|
1710
|
+
host: string;
|
|
1711
|
+
port: number;
|
|
1712
|
+
}>;
|
|
1713
|
+
name: string;
|
|
1714
|
+
password?: string;
|
|
1715
|
+
};
|
|
1716
|
+
/** Cluster configuration */
|
|
1717
|
+
cluster?: {
|
|
1718
|
+
nodes: Array<{
|
|
1719
|
+
host: string;
|
|
1720
|
+
port: number;
|
|
1721
|
+
}>;
|
|
1722
|
+
options?: {
|
|
1723
|
+
scaleReads?: 'master' | 'slave' | 'all';
|
|
1724
|
+
maxRedirections?: number;
|
|
1725
|
+
};
|
|
1726
|
+
};
|
|
1727
|
+
}
|
|
1728
|
+
declare class RedisCache implements ICache {
|
|
1729
|
+
private client;
|
|
1730
|
+
private subscriberClient;
|
|
1731
|
+
private config;
|
|
1732
|
+
private subscriptions;
|
|
1733
|
+
constructor(client: Redis$1, config?: RedisConfig);
|
|
1734
|
+
/**
|
|
1735
|
+
* Create a RedisCache from configuration
|
|
1736
|
+
*/
|
|
1737
|
+
static create(config: RedisConfig): Promise<RedisCache>;
|
|
1738
|
+
/**
|
|
1739
|
+
* Create from environment variables
|
|
1740
|
+
*/
|
|
1741
|
+
static fromEnv(): Promise<RedisCache>;
|
|
1742
|
+
get<T = unknown>(key: string): Promise<T | null>;
|
|
1743
|
+
set<T = unknown>(key: string, value: T, ttl?: number): Promise<void>;
|
|
1744
|
+
delete(key: string): Promise<void>;
|
|
1745
|
+
exists(key: string): Promise<boolean>;
|
|
1746
|
+
deletePattern(pattern: string): Promise<number>;
|
|
1747
|
+
mget<T = unknown>(keys: string[]): Promise<(T | null)[]>;
|
|
1748
|
+
mset<T = unknown>(entries: Array<{
|
|
1749
|
+
key: string;
|
|
1750
|
+
value: T;
|
|
1751
|
+
ttl?: number;
|
|
1752
|
+
}>): Promise<void>;
|
|
1753
|
+
incr(key: string, by?: number): Promise<number>;
|
|
1754
|
+
publish(channel: string, message: string): Promise<void>;
|
|
1755
|
+
subscribe(channel: string, callback: (message: string) => void): Promise<() => void>;
|
|
1756
|
+
healthCheck(): Promise<boolean>;
|
|
1757
|
+
close(): Promise<void>;
|
|
1758
|
+
/**
|
|
1759
|
+
* Get connection info for monitoring
|
|
1760
|
+
*/
|
|
1761
|
+
getConnectionInfo(): {
|
|
1762
|
+
status: string;
|
|
1763
|
+
host?: string;
|
|
1764
|
+
port?: number;
|
|
1765
|
+
};
|
|
1766
|
+
/**
|
|
1767
|
+
* Execute arbitrary Redis command
|
|
1768
|
+
*/
|
|
1769
|
+
command<T = unknown>(command: string, ...args: unknown[]): Promise<T>;
|
|
1770
|
+
/**
|
|
1771
|
+
* Get TTL of a key
|
|
1772
|
+
*/
|
|
1773
|
+
ttl(key: string): Promise<number>;
|
|
1774
|
+
/**
|
|
1775
|
+
* Set expiry on an existing key
|
|
1776
|
+
*/
|
|
1777
|
+
expire(key: string, seconds: number): Promise<boolean>;
|
|
1778
|
+
/**
|
|
1779
|
+
* Get all keys matching a pattern (use with caution in production)
|
|
1780
|
+
*/
|
|
1781
|
+
keys(pattern: string): Promise<string[]>;
|
|
1782
|
+
}
|
|
1783
|
+
|
|
1784
|
+
/**
|
|
1785
|
+
* S3 Storage Adapter
|
|
1786
|
+
* Production implementation using AWS S3 (compatible with MinIO, R2, etc.)
|
|
1787
|
+
*/
|
|
1788
|
+
|
|
1789
|
+
declare class S3Storage implements IStorage {
|
|
1790
|
+
private client;
|
|
1791
|
+
private bucket;
|
|
1792
|
+
private publicUrl?;
|
|
1793
|
+
private signedUrlFn;
|
|
1794
|
+
constructor(client: S3Client, bucket: string, getSignedUrlFn: typeof getSignedUrl, publicUrl?: string);
|
|
1795
|
+
upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions): Promise<{
|
|
1796
|
+
url: string;
|
|
1797
|
+
}>;
|
|
1798
|
+
download(key: string): Promise<Buffer>;
|
|
1799
|
+
getSignedUrl(key: string, expiresIn?: number): Promise<string>;
|
|
1800
|
+
private createSignedUrl;
|
|
1801
|
+
delete(key: string): Promise<void>;
|
|
1802
|
+
deleteMany(keys: string[]): Promise<void>;
|
|
1803
|
+
list(prefix?: string): Promise<StorageFile[]>;
|
|
1804
|
+
exists(key: string): Promise<boolean>;
|
|
1805
|
+
getMetadata(key: string): Promise<StorageFile | null>;
|
|
1806
|
+
healthCheck(): Promise<boolean>;
|
|
1807
|
+
}
|
|
1808
|
+
|
|
1809
|
+
/**
|
|
1810
|
+
* Supabase Storage Adapter
|
|
1811
|
+
*
|
|
1812
|
+
* Production implementation using Supabase Storage for file management.
|
|
1813
|
+
* Provides vendor-agnostic file storage via Supabase's storage buckets.
|
|
1814
|
+
*
|
|
1815
|
+
* Features:
|
|
1816
|
+
* - Simple bucket-based file storage
|
|
1817
|
+
* - Automatic public URL generation
|
|
1818
|
+
* - Signed URL support for private files
|
|
1819
|
+
* - Built-in CDN caching
|
|
1820
|
+
*/
|
|
1821
|
+
|
|
1822
|
+
interface SupabaseStorageConfig {
|
|
1823
|
+
/** Supabase project URL */
|
|
1824
|
+
url: string;
|
|
1825
|
+
/** Supabase API key (anon or service role) */
|
|
1826
|
+
apiKey: string;
|
|
1827
|
+
/** Default bucket name */
|
|
1828
|
+
bucket: string;
|
|
1829
|
+
/** Whether the bucket is public */
|
|
1830
|
+
publicBucket?: boolean;
|
|
1831
|
+
/** Default signed URL expiry in seconds */
|
|
1832
|
+
signedUrlExpiry?: number;
|
|
1833
|
+
}
|
|
1834
|
+
declare class SupabaseStorage implements IStorage {
|
|
1835
|
+
private client;
|
|
1836
|
+
private bucket;
|
|
1837
|
+
private publicBucket;
|
|
1838
|
+
private signedUrlExpiry;
|
|
1839
|
+
constructor(client: SupabaseClient, config: {
|
|
1840
|
+
bucket: string;
|
|
1841
|
+
publicBucket?: boolean;
|
|
1842
|
+
signedUrlExpiry?: number;
|
|
1843
|
+
});
|
|
1844
|
+
/**
|
|
1845
|
+
* Create a SupabaseStorage adapter from configuration
|
|
1846
|
+
*/
|
|
1847
|
+
static create(config: SupabaseStorageConfig): Promise<SupabaseStorage>;
|
|
1848
|
+
/**
|
|
1849
|
+
* Create from environment variables
|
|
1850
|
+
*/
|
|
1851
|
+
static fromEnv(): Promise<SupabaseStorage>;
|
|
1852
|
+
upload(key: string, data: Buffer | Blob | ReadableStream, options?: UploadOptions): Promise<{
|
|
1853
|
+
url: string;
|
|
1854
|
+
}>;
|
|
1855
|
+
download(path: string): Promise<Buffer>;
|
|
1856
|
+
delete(path: string): Promise<void>;
|
|
1857
|
+
deleteMany(paths: string[]): Promise<void>;
|
|
1858
|
+
getMetadata(path: string): Promise<StorageFile | null>;
|
|
1859
|
+
exists(path: string): Promise<boolean>;
|
|
1860
|
+
list(prefix?: string): Promise<StorageFile[]>;
|
|
1861
|
+
getSignedUrl(path: string, expiresIn?: number): Promise<string>;
|
|
1862
|
+
healthCheck(): Promise<boolean>;
|
|
1863
|
+
/**
|
|
1864
|
+
* Get URL for a file (public URL or signed URL based on bucket config)
|
|
1865
|
+
*/
|
|
1866
|
+
private getUrl;
|
|
1867
|
+
/**
|
|
1868
|
+
* Get directory from path
|
|
1869
|
+
*/
|
|
1870
|
+
private getDirectory;
|
|
1871
|
+
/**
|
|
1872
|
+
* Get filename from path
|
|
1873
|
+
*/
|
|
1874
|
+
private getFilename;
|
|
1875
|
+
/**
|
|
1876
|
+
* Get storage bucket info
|
|
1877
|
+
*/
|
|
1878
|
+
getBucketInfo(): {
|
|
1879
|
+
bucket: string;
|
|
1880
|
+
publicBucket: boolean;
|
|
1881
|
+
};
|
|
1882
|
+
/**
|
|
1883
|
+
* Copy file to new location
|
|
1884
|
+
*/
|
|
1885
|
+
copy(sourcePath: string, destPath: string): Promise<{
|
|
1886
|
+
key: string;
|
|
1887
|
+
url: string;
|
|
1888
|
+
}>;
|
|
1889
|
+
/**
|
|
1890
|
+
* Move file to new location
|
|
1891
|
+
*/
|
|
1892
|
+
move(sourcePath: string, destPath: string): Promise<{
|
|
1893
|
+
key: string;
|
|
1894
|
+
url: string;
|
|
1895
|
+
}>;
|
|
1896
|
+
}
|
|
1897
|
+
|
|
1898
|
+
/**
|
|
1899
|
+
* Resend Email Adapter
|
|
1900
|
+
* Production implementation using Resend for transactional emails
|
|
1901
|
+
*/
|
|
1902
|
+
|
|
1903
|
+
declare class ResendEmail implements IEmail {
|
|
1904
|
+
private client;
|
|
1905
|
+
private defaultFrom;
|
|
1906
|
+
constructor(client: Resend, defaultFrom?: string);
|
|
1907
|
+
send(message: EmailMessage): Promise<EmailResult>;
|
|
1908
|
+
sendBatch(messages: EmailMessage[]): Promise<EmailResult[]>;
|
|
1909
|
+
healthCheck(): Promise<boolean>;
|
|
1910
|
+
private formatAddress;
|
|
1911
|
+
private formatAddresses;
|
|
1912
|
+
}
|
|
1913
|
+
|
|
1914
|
+
/**
|
|
1915
|
+
* SMTP Email Adapter
|
|
1916
|
+
*
|
|
1917
|
+
* Production implementation using nodemailer for direct SMTP connections.
|
|
1918
|
+
* Provides vendor-agnostic email sending via standard SMTP protocol.
|
|
1919
|
+
*
|
|
1920
|
+
* Compatible with any SMTP server:
|
|
1921
|
+
* - Self-hosted mail servers (Postfix, Sendmail)
|
|
1922
|
+
* - Gmail SMTP
|
|
1923
|
+
* - Amazon SES (SMTP interface)
|
|
1924
|
+
* - SendGrid SMTP
|
|
1925
|
+
* - Mailgun SMTP
|
|
1926
|
+
* - Microsoft 365 SMTP
|
|
1927
|
+
* - Any standard SMTP relay
|
|
1928
|
+
*/
|
|
1929
|
+
|
|
1930
|
+
interface SmtpConfig {
|
|
1931
|
+
/** SMTP host */
|
|
1932
|
+
host: string;
|
|
1933
|
+
/** SMTP port (typically 25, 465, or 587) */
|
|
1934
|
+
port: number;
|
|
1935
|
+
/** Use TLS/SSL */
|
|
1936
|
+
secure?: boolean;
|
|
1937
|
+
/** SMTP username */
|
|
1938
|
+
username?: string;
|
|
1939
|
+
/** SMTP password */
|
|
1940
|
+
password?: string;
|
|
1941
|
+
/** Default from address */
|
|
1942
|
+
from?: string;
|
|
1943
|
+
/** Connection timeout in milliseconds */
|
|
1944
|
+
connectionTimeout?: number;
|
|
1945
|
+
/** Socket timeout in milliseconds */
|
|
1946
|
+
socketTimeout?: number;
|
|
1947
|
+
/** Enable debug logging */
|
|
1948
|
+
debug?: boolean;
|
|
1949
|
+
/** Reject unauthorized certificates */
|
|
1950
|
+
rejectUnauthorized?: boolean;
|
|
1951
|
+
}
|
|
1952
|
+
declare class SmtpEmail implements IEmail {
|
|
1953
|
+
private transporter;
|
|
1954
|
+
private config;
|
|
1955
|
+
constructor(config: SmtpConfig);
|
|
1956
|
+
/**
|
|
1957
|
+
* Create an SmtpEmail adapter from configuration
|
|
1958
|
+
*/
|
|
1959
|
+
static create(config: SmtpConfig): Promise<SmtpEmail>;
|
|
1960
|
+
/**
|
|
1961
|
+
* Create from environment variables
|
|
1962
|
+
*/
|
|
1963
|
+
static fromEnv(): Promise<SmtpEmail>;
|
|
1964
|
+
/**
|
|
1965
|
+
* Initialize the SMTP transporter
|
|
1966
|
+
*/
|
|
1967
|
+
private initialize;
|
|
1968
|
+
send(message: EmailMessage): Promise<EmailResult>;
|
|
1969
|
+
sendBatch(messages: EmailMessage[]): Promise<EmailResult[]>;
|
|
1970
|
+
healthCheck(): Promise<boolean>;
|
|
1971
|
+
/**
|
|
1972
|
+
* Close the transporter and release connections
|
|
1973
|
+
*/
|
|
1974
|
+
close(): Promise<void>;
|
|
1975
|
+
/**
|
|
1976
|
+
* Get transporter info for debugging
|
|
1977
|
+
*/
|
|
1978
|
+
getTransporterInfo(): {
|
|
1979
|
+
host: string;
|
|
1980
|
+
port: number;
|
|
1981
|
+
secure: boolean;
|
|
1982
|
+
};
|
|
1983
|
+
}
|
|
1984
|
+
|
|
1985
|
+
/**
|
|
1986
|
+
* BullMQ Queue Adapter
|
|
1987
|
+
* Production queue implementation using BullMQ (Redis-backed)
|
|
1988
|
+
*/
|
|
1989
|
+
|
|
1990
|
+
interface BullMQConfig {
|
|
1991
|
+
/** Redis connection URL */
|
|
1992
|
+
redisUrl?: string;
|
|
1993
|
+
/** Redis host */
|
|
1994
|
+
host?: string;
|
|
1995
|
+
/** Redis port */
|
|
1996
|
+
port?: number;
|
|
1997
|
+
/** Redis password */
|
|
1998
|
+
password?: string;
|
|
1999
|
+
/** Redis database number */
|
|
2000
|
+
db?: number;
|
|
2001
|
+
/** Queue name */
|
|
2002
|
+
queueName: string;
|
|
2003
|
+
/** Default job options */
|
|
2004
|
+
defaultJobOptions?: JobOptions;
|
|
2005
|
+
}
|
|
2006
|
+
/**
|
|
2007
|
+
* BullMQ Queue Adapter
|
|
2008
|
+
* Requires: pnpm add bullmq ioredis
|
|
2009
|
+
*/
|
|
2010
|
+
declare class BullMQQueue<T = unknown> implements IQueue<T> {
|
|
2011
|
+
private queue;
|
|
2012
|
+
private worker;
|
|
2013
|
+
private config;
|
|
2014
|
+
private initialized;
|
|
2015
|
+
constructor(config: BullMQConfig);
|
|
2016
|
+
/**
|
|
2017
|
+
* Initialize the queue (called lazily on first use)
|
|
2018
|
+
*/
|
|
2019
|
+
private ensureInitialized;
|
|
2020
|
+
private getConnectionConfig;
|
|
2021
|
+
add(name: string, data: T, options?: JobOptions): Promise<Job<T>>;
|
|
2022
|
+
addBulk(jobs: Array<{
|
|
2023
|
+
name: string;
|
|
2024
|
+
data: T;
|
|
2025
|
+
options?: JobOptions;
|
|
2026
|
+
}>): Promise<Job<T>[]>;
|
|
2027
|
+
process(handler: (job: Job<T>) => Promise<unknown>): void;
|
|
2028
|
+
private startWorker;
|
|
2029
|
+
getJob(id: string): Promise<Job<T> | null>;
|
|
2030
|
+
removeJob(id: string): Promise<void>;
|
|
2031
|
+
pause(): Promise<void>;
|
|
2032
|
+
resume(): Promise<void>;
|
|
2033
|
+
getStats(): Promise<{
|
|
2034
|
+
waiting: number;
|
|
2035
|
+
active: number;
|
|
2036
|
+
completed: number;
|
|
2037
|
+
failed: number;
|
|
2038
|
+
delayed: number;
|
|
2039
|
+
}>;
|
|
2040
|
+
healthCheck(): Promise<boolean>;
|
|
2041
|
+
close(): Promise<void>;
|
|
2042
|
+
private mapJob;
|
|
2043
|
+
}
|
|
2044
|
+
|
|
2045
|
+
export { Bulkhead, type BulkheadOptions, BulkheadRegistry, BulkheadRejectedError, type BulkheadStats, type BullMQConfig, BullMQQueue, CircuitBreaker, type CircuitBreakerOptions, CircuitBreakerRegistry, type CircuitBreakerStats, CircuitOpenError, type CircuitState, DEFAULT_BULKHEAD_OPTIONS, DEFAULT_CIRCUIT_BREAKER_OPTIONS, DEFAULT_RETRY_OPTIONS, DefaultTimeouts, type DeleteHookContext, type DetailedHealthResponse, type EmailHookContext, EmailMessage, EmailResult, type ErrorHookContext, type FallbackOptions, type FallbackResult, FallbackStrategies, type HealthCheckResult, type HealthEndpoints, type HealthEndpointsOptions, type HealthStatus, type HookRegistry, ICache, IDatabase, IEmail, type IHealth, type IHealthCheckable, ILogger, IMetrics, IPlatform, IQueryBuilder, IQueue, IStorage, type InsertHookContext, Job, type JobHookContext, JobOptions, type LivenessResponse, MemoryRateLimiterStorage, type MetricsEndpoint, type MetricsEndpointOptions, MetricsSummary, type Middleware, type MiddlewareChain, type MiddlewareChainOptions, type MiddlewareContext, type PlatformHealthResult, PlatformHealthStatus, type PlatformHooks, type PostgresConfig, PostgresDatabase, type QueryHookContext, QueryResult, type RateLimitAlgorithm, RateLimitError, type RateLimitInfo, type RateLimitOptions, RateLimitPresets, type RateLimiterStorage, type ReadinessResponse, RedisCache, type RedisConfig, ResendEmail, RetryConfigs, type RetryOptions, RetryPredicates, type RetryResult, S3Storage, type ServiceHealth, type SlidingWindowRateLimitOptions, type SmtpConfig, SmtpEmail, type StartupResponse, StorageFile, SupabaseDatabase, SupabaseStorage, type SupabaseStorageConfig, TimeoutError, type TimeoutOptions, type TokenBucketOptions, type UpdateHookContext, type UploadHookContext, UploadOptions, UpstashCache, composeHookRegistries, createBulkhead, createCacheMiddleware, createCachedFallback, createCircuitBreaker, createExpressHealthHandlers, createExpressMetricsHandler, createHealthEndpoints, createHealthServer, createHookRegistry, createIpKeyGenerator, createLoggingMiddleware, createMetricsEndpoint, createMetricsMiddleware, createMetricsServer, createMiddlewareChain, createMiddlewareContext, createObservabilityServer, createRateLimitMiddleware, createRequestIdMiddleware, createSlowQueryMiddleware, createTenantMiddleware, createTimeoutMiddleware, createUserKeyGenerator, raceTimeout, retryable, timedHealthCheck, toHealthCheckResult, withFallback, withFallbackChain, withFallbackResult, withRetry, withRetryResult, withTimeout, withTimeoutWrapper };
|