@kibibit/configit 1.0.0-beta.25 → 1.0.0-beta.27

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.
Files changed (98) hide show
  1. package/README.md +419 -0
  2. package/lib/scripts/test-vault-comprehensive.d.ts +2 -0
  3. package/lib/scripts/test-vault-comprehensive.d.ts.map +1 -0
  4. package/lib/scripts/test-vault-comprehensive.js +422 -0
  5. package/lib/scripts/test-vault-comprehensive.js.map +1 -0
  6. package/lib/scripts/test-vault-dynamic.d.ts +2 -0
  7. package/lib/scripts/test-vault-dynamic.d.ts.map +1 -0
  8. package/lib/scripts/test-vault-dynamic.js +193 -0
  9. package/lib/scripts/test-vault-dynamic.js.map +1 -0
  10. package/lib/scripts/test-vault-gcp-ttl.d.ts +3 -0
  11. package/lib/scripts/test-vault-gcp-ttl.d.ts.map +1 -0
  12. package/lib/scripts/test-vault-gcp-ttl.js +218 -0
  13. package/lib/scripts/test-vault-gcp-ttl.js.map +1 -0
  14. package/lib/scripts/test-vault.d.ts +2 -0
  15. package/lib/scripts/test-vault.d.ts.map +1 -0
  16. package/lib/scripts/test-vault.js +167 -0
  17. package/lib/scripts/test-vault.js.map +1 -0
  18. package/lib/src/config.errors.d.ts.map +1 -0
  19. package/lib/src/config.errors.js.map +1 -0
  20. package/lib/src/config.model.d.ts.map +1 -0
  21. package/lib/src/config.model.js.map +1 -0
  22. package/lib/{config.service.d.ts → src/config.service.d.ts} +10 -1
  23. package/lib/src/config.service.d.ts.map +1 -0
  24. package/lib/{config.service.js → src/config.service.js} +75 -9
  25. package/lib/src/config.service.js.map +1 -0
  26. package/lib/src/environment.service.d.ts.map +1 -0
  27. package/lib/src/environment.service.js.map +1 -0
  28. package/lib/{index.d.ts → src/index.d.ts} +1 -0
  29. package/lib/src/index.d.ts.map +1 -0
  30. package/lib/{index.js → src/index.js} +1 -0
  31. package/lib/src/index.js.map +1 -0
  32. package/lib/src/json-schema.validator.d.ts.map +1 -0
  33. package/lib/src/json-schema.validator.js.map +1 -0
  34. package/lib/src/vault/__tests__/vault-integration.test.d.ts +2 -0
  35. package/lib/src/vault/__tests__/vault-integration.test.d.ts.map +1 -0
  36. package/lib/src/vault/__tests__/vault-integration.test.js +190 -0
  37. package/lib/src/vault/__tests__/vault-integration.test.js.map +1 -0
  38. package/lib/src/vault/decorators.d.ts +17 -0
  39. package/lib/src/vault/decorators.d.ts.map +1 -0
  40. package/lib/src/vault/decorators.js +149 -0
  41. package/lib/src/vault/decorators.js.map +1 -0
  42. package/lib/src/vault/index.d.ts +7 -0
  43. package/lib/src/vault/index.d.ts.map +1 -0
  44. package/lib/src/vault/index.js +42 -0
  45. package/lib/src/vault/index.js.map +1 -0
  46. package/lib/src/vault/secret-refresh-manager.d.ts +23 -0
  47. package/lib/src/vault/secret-refresh-manager.d.ts.map +1 -0
  48. package/lib/src/vault/secret-refresh-manager.js +149 -0
  49. package/lib/src/vault/secret-refresh-manager.js.map +1 -0
  50. package/lib/src/vault/types.d.ts +149 -0
  51. package/lib/src/vault/types.d.ts.map +1 -0
  52. package/lib/src/vault/types.js +4 -0
  53. package/lib/src/vault/types.js.map +1 -0
  54. package/lib/src/vault/vault-cache.d.ts +20 -0
  55. package/lib/src/vault/vault-cache.d.ts.map +1 -0
  56. package/lib/src/vault/vault-cache.js +139 -0
  57. package/lib/src/vault/vault-cache.js.map +1 -0
  58. package/lib/src/vault/vault-integration.d.ts +27 -0
  59. package/lib/src/vault/vault-integration.d.ts.map +1 -0
  60. package/lib/src/vault/vault-integration.js +211 -0
  61. package/lib/src/vault/vault-integration.js.map +1 -0
  62. package/lib/src/vault/vault-provider.d.ts +37 -0
  63. package/lib/src/vault/vault-provider.d.ts.map +1 -0
  64. package/lib/src/vault/vault-provider.js +354 -0
  65. package/lib/src/vault/vault-provider.js.map +1 -0
  66. package/lib/tsconfig.tsbuildinfo +1 -1
  67. package/package.json +14 -74
  68. package/src/config.service.ts +155 -10
  69. package/src/config.service.vault.spec.ts +859 -0
  70. package/src/index.ts +1 -0
  71. package/src/vault/__tests__/vault-integration.test.ts +226 -0
  72. package/src/vault/decorators.ts +228 -0
  73. package/src/vault/index.ts +31 -0
  74. package/src/vault/secret-refresh-manager.ts +241 -0
  75. package/src/vault/types.ts +487 -0
  76. package/src/vault/vault-cache.ts +240 -0
  77. package/src/vault/vault-integration.ts +332 -0
  78. package/src/vault/vault-provider.ts +576 -0
  79. package/lib/config.errors.d.ts.map +0 -1
  80. package/lib/config.errors.js.map +0 -1
  81. package/lib/config.model.d.ts.map +0 -1
  82. package/lib/config.model.js.map +0 -1
  83. package/lib/config.service.d.ts.map +0 -1
  84. package/lib/config.service.js.map +0 -1
  85. package/lib/environment.service.d.ts.map +0 -1
  86. package/lib/environment.service.js.map +0 -1
  87. package/lib/index.d.ts.map +0 -1
  88. package/lib/index.js.map +0 -1
  89. package/lib/json-schema.validator.d.ts.map +0 -1
  90. package/lib/json-schema.validator.js.map +0 -1
  91. /package/lib/{config.errors.d.ts → src/config.errors.d.ts} +0 -0
  92. /package/lib/{config.errors.js → src/config.errors.js} +0 -0
  93. /package/lib/{config.model.d.ts → src/config.model.d.ts} +0 -0
  94. /package/lib/{config.model.js → src/config.model.js} +0 -0
  95. /package/lib/{environment.service.d.ts → src/environment.service.d.ts} +0 -0
  96. /package/lib/{environment.service.js → src/environment.service.js} +0 -0
  97. /package/lib/{json-schema.validator.d.ts → src/json-schema.validator.d.ts} +0 -0
  98. /package/lib/{json-schema.validator.js → src/json-schema.validator.js} +0 -0
@@ -0,0 +1,241 @@
1
+ /**
2
+ * SecretRefreshManager
3
+ * Manages background refresh of Vault secrets based on TTL
4
+ */
5
+
6
+ import { IRefreshStatus, VaultPropertyMetadata } from './types';
7
+ import { VaultCache } from './vault-cache';
8
+ import { VaultProvider } from './vault-provider';
9
+
10
+ interface IRefreshContext {
11
+ metadata: VaultPropertyMetadata;
12
+ targetInstance?: object;
13
+ fullPath: string;
14
+ }
15
+
16
+ /**
17
+ * SecretRefreshManager - Handles TTL-based secret refresh scheduling
18
+ */
19
+ export class SecretRefreshManager {
20
+ private refreshTimers: Map<string, NodeJS.Timeout> = new Map();
21
+ private refreshLocks: Map<string, Promise<void>> = new Map();
22
+ private refreshCounts: Map<string, number> = new Map();
23
+ private lastRefreshTimes: Map<string, number> = new Map();
24
+ private refreshContexts: Map<string, IRefreshContext> = new Map();
25
+ private vaultProvider: VaultProvider;
26
+ private cache: VaultCache;
27
+ private refreshBuffer: number; // Default refresh buffer in seconds
28
+
29
+ constructor(provider: VaultProvider, cache: VaultCache, refreshBuffer?: number) {
30
+ this.vaultProvider = provider;
31
+ this.cache = cache;
32
+ // Default: min(10% of TTL, 300s) - but we'll use a fixed buffer per secret
33
+ this.refreshBuffer = refreshBuffer || 300; // 5 minutes default
34
+ }
35
+
36
+ /**
37
+ * Schedule refresh for a secret based on TTL
38
+ */
39
+ scheduleRefresh(propertyName: string, metadata: VaultPropertyMetadata, targetInstance?: object): void {
40
+ const entry = this.cache.getEntry(propertyName);
41
+ if (!entry) {
42
+ return; // No cache entry to refresh
43
+ }
44
+
45
+ // Store context for refresh
46
+ this.refreshContexts.set(propertyName, {
47
+ metadata,
48
+ targetInstance,
49
+ fullPath: entry.vaultPath
50
+ });
51
+
52
+ // Cancel existing refresh if any
53
+ this.cancelRefresh(propertyName);
54
+
55
+ // Calculate refresh time
56
+ const now = Date.now();
57
+ const timeUntilRefresh = Math.max(0, entry.refreshAt - now);
58
+
59
+ if (timeUntilRefresh <= 0) {
60
+ // Already past refresh time, refresh immediately
61
+ this.executeRefresh(propertyName);
62
+ return;
63
+ }
64
+
65
+ // Schedule refresh
66
+ const timer = setTimeout(() => {
67
+ this.executeRefresh(propertyName);
68
+ }, timeUntilRefresh);
69
+
70
+ this.refreshTimers.set(propertyName, timer);
71
+ }
72
+
73
+ /**
74
+ * Cancel scheduled refresh for a property
75
+ */
76
+ cancelRefresh(propertyName: string): void {
77
+ const timer = this.refreshTimers.get(propertyName);
78
+ if (timer) {
79
+ clearTimeout(timer);
80
+ this.refreshTimers.delete(propertyName);
81
+ }
82
+ }
83
+
84
+ /**
85
+ * Execute refresh for a secret (with locking to prevent concurrent refreshes)
86
+ */
87
+ private async executeRefresh(propertyName: string): Promise<void> {
88
+ // Check if refresh is already in progress
89
+ const existingLock = this.refreshLocks.get(propertyName);
90
+ if (existingLock) {
91
+ await existingLock;
92
+ return; // Refresh already completed
93
+ }
94
+
95
+ // Create refresh lock
96
+ const refreshPromise = this.performRefresh(propertyName)
97
+ .finally(() => {
98
+ this.refreshLocks.delete(propertyName);
99
+ this.refreshTimers.delete(propertyName);
100
+ });
101
+
102
+ this.refreshLocks.set(propertyName, refreshPromise);
103
+ await refreshPromise;
104
+ }
105
+
106
+ /**
107
+ * Perform the actual refresh operation
108
+ */
109
+ private async performRefresh(propertyName: string): Promise<void> {
110
+ const context = this.refreshContexts.get(propertyName);
111
+ if (!context) {
112
+ console.error(`No refresh context for ${ propertyName }`);
113
+ return;
114
+ }
115
+
116
+ const { metadata, targetInstance, fullPath } = context;
117
+ const refreshCount = (this.refreshCounts.get(propertyName) || 0) + 1;
118
+ this.refreshCounts.set(propertyName, refreshCount);
119
+
120
+ try {
121
+ // Read fresh secret from Vault (using full path)
122
+ const secret = await this.vaultProvider.read(fullPath);
123
+
124
+ // Update cache
125
+ this.cache.set(propertyName, fullPath, secret, metadata);
126
+
127
+ // Update target instance if provided
128
+ if (targetInstance) {
129
+ const key = metadata.key || metadata.propertyName;
130
+ const value = secret.data[key];
131
+ (targetInstance as any)[propertyName] = value;
132
+ }
133
+
134
+ // Record refresh time
135
+ this.lastRefreshTimes.set(propertyName, Date.now());
136
+
137
+ // Reschedule next refresh
138
+ this.scheduleRefresh(propertyName, metadata, targetInstance);
139
+ } catch (error: any) {
140
+ // Log error (sanitized)
141
+ const errorMessage = error?.message || 'Unknown error';
142
+ console.error(`Failed to refresh secret for ${ propertyName }: ${ this.sanitizeError(errorMessage) }`);
143
+
144
+ // Retry with exponential backoff
145
+ const retryDelay = Math.min(1000 * Math.pow(2, refreshCount - 1), 30000); // Max 30s
146
+ setTimeout(() => {
147
+ this.scheduleRefresh(propertyName, metadata, targetInstance);
148
+ }, retryDelay);
149
+ }
150
+ }
151
+
152
+ /**
153
+ * Get refresh status for all secrets
154
+ */
155
+ getRefreshStatus(): IRefreshStatus[] {
156
+ const statuses: IRefreshStatus[] = [];
157
+ const cachedProperties = this.cache.getCachedProperties();
158
+
159
+ for (const propertyName of cachedProperties) {
160
+ const entry = this.cache.getEntry(propertyName);
161
+ if (!entry) {
162
+ continue;
163
+ }
164
+
165
+ const timer = this.refreshTimers.get(propertyName);
166
+ const now = Date.now();
167
+ const refreshAt = entry.refreshAt;
168
+ const timeUntilRefresh = Math.max(0, refreshAt - now);
169
+
170
+ statuses.push({
171
+ propertyName,
172
+ vaultPath: entry.vaultPath,
173
+ scheduled: timer !== undefined,
174
+ refreshAt,
175
+ timeUntilRefresh,
176
+ lastRefresh: this.lastRefreshTimes.get(propertyName) || entry.cachedAt,
177
+ refreshCount: this.refreshCounts.get(propertyName) || 0
178
+ });
179
+ }
180
+
181
+ return statuses;
182
+ }
183
+
184
+ /**
185
+ * Get refresh status for a specific property
186
+ */
187
+ getRefreshStatusForProperty(propertyName: string): IRefreshStatus | null {
188
+ const entry = this.cache.getEntry(propertyName);
189
+ if (!entry) {
190
+ return null;
191
+ }
192
+
193
+ const timer = this.refreshTimers.get(propertyName);
194
+ const now = Date.now();
195
+ const refreshAt = entry.refreshAt;
196
+ const timeUntilRefresh = Math.max(0, refreshAt - now);
197
+
198
+ return {
199
+ propertyName,
200
+ vaultPath: entry.vaultPath,
201
+ scheduled: timer !== undefined,
202
+ refreshAt,
203
+ timeUntilRefresh,
204
+ lastRefresh: this.lastRefreshTimes.get(propertyName) || entry.cachedAt,
205
+ refreshCount: this.refreshCounts.get(propertyName) || 0
206
+ };
207
+ }
208
+
209
+ /**
210
+ * Stop all refresh workers
211
+ */
212
+ shutdown(): void {
213
+ // Cancel all timers
214
+ for (const [ propertyName, timer ] of this.refreshTimers.entries()) {
215
+ clearTimeout(timer);
216
+ }
217
+
218
+ this.refreshTimers.clear();
219
+ this.refreshLocks.clear();
220
+ this.refreshCounts.clear();
221
+ this.lastRefreshTimes.clear();
222
+ }
223
+
224
+ /**
225
+ * Sanitize error message (remove potential secret values)
226
+ */
227
+ private sanitizeError(message: string): string {
228
+ // Remove potential secret values from error messages
229
+ const sensitivePatterns = [ /password/i, /secret/i, /key/i, /token/i, /credential/i ];
230
+ let sanitized = message;
231
+
232
+ sensitivePatterns.forEach((pattern) => {
233
+ sanitized = sanitized.replace(
234
+ new RegExp(`${ pattern.source }[:=]\\s*[^\\s,}]+`, 'gi'),
235
+ `${ pattern.source }: ***`
236
+ );
237
+ });
238
+
239
+ return sanitized;
240
+ }
241
+ }
@@ -0,0 +1,487 @@
1
+ /**
2
+ * Vault Integration Types
3
+ * TypeScript interfaces and types for HashiCorp Vault integration
4
+ */
5
+
6
+ import 'reflect-metadata';
7
+
8
+ /**
9
+ * Vault secrets engine types
10
+ * - kv1/kv-v1: Key-Value v1 (simple)
11
+ * - kv2/kv-v2: Key-Value v2 (versioned, default)
12
+ * - database: Database secrets engine (dynamic credentials)
13
+ * - aws: AWS secrets engine
14
+ * - azure: Azure secrets engine
15
+ * - gcp: GCP secrets engine
16
+ * - transit: Transit secrets engine (encryption)
17
+ * - pki: PKI secrets engine
18
+ * - custom: Custom engine (requires custom extraction logic)
19
+ */
20
+ export type VaultEngineType =
21
+ | 'kv1'
22
+ | 'kv-v1'
23
+ | 'kv2'
24
+ | 'kv-v2'
25
+ | 'database'
26
+ | 'aws'
27
+ | 'azure'
28
+ | 'gcp'
29
+ | 'transit'
30
+ | 'pki'
31
+ | 'custom';
32
+
33
+ /**
34
+ * Vault configuration options for ConfigService
35
+ */
36
+ export interface IVaultConfigOptions {
37
+ /**
38
+ * Vault server endpoint (must be HTTPS in production)
39
+ */
40
+ endpoint: string;
41
+
42
+ /**
43
+ * Authentication configuration
44
+ */
45
+ auth: IVaultAuthConfig;
46
+
47
+ /**
48
+ * TLS configuration
49
+ */
50
+ tls?: IVaultTLSConfig;
51
+
52
+ /**
53
+ * Refresh buffer (seconds) - default: min(10% of TTL, 300s)
54
+ */
55
+ refreshBuffer?: number;
56
+
57
+ /**
58
+ * Fallback configuration
59
+ */
60
+ fallback?: IVaultFallbackConfig;
61
+
62
+ /**
63
+ * Retry configuration
64
+ */
65
+ retry?: IRetryPolicy;
66
+
67
+ /**
68
+ * Circuit breaker configuration
69
+ */
70
+ circuitBreaker?: ICircuitBreakerConfig;
71
+ }
72
+
73
+ /**
74
+ * Authentication configuration with priority
75
+ * Supports both simple single-method and array-based multi-method configs
76
+ */
77
+ export type IVaultAuthConfig = IVaultAuthConfigSimple | IVaultAuthConfigMethods;
78
+
79
+ /**
80
+ * Simple single-method auth config (for convenience)
81
+ */
82
+ export type IVaultAuthConfigSimple =
83
+ | ({ method: 'gcp' } & IGCPAuthConfig)
84
+ | ({ method: 'aws' } & IAWSAuthConfig)
85
+ | ({ method: 'approle' } & IAppRoleAuthConfig)
86
+ | ({ method: 'token' } & ITokenAuthConfig);
87
+
88
+ /**
89
+ * Multi-method auth config (for fallback chains)
90
+ */
91
+ export interface IVaultAuthConfigMethods {
92
+ /**
93
+ * Authentication methods in priority order
94
+ * Tried sequentially until one succeeds
95
+ */
96
+ methods: IVaultAuthMethod[];
97
+ }
98
+
99
+ /**
100
+ * Individual authentication method
101
+ */
102
+ export interface IVaultAuthMethod {
103
+ type: 'gcp' | 'aws' | 'approle' | 'token';
104
+ config: IGCPAuthConfig | IAWSAuthConfig | IAppRoleAuthConfig | ITokenAuthConfig;
105
+ }
106
+
107
+ /**
108
+ * GCP IAM authentication
109
+ */
110
+ export interface IGCPAuthConfig {
111
+ type?: 'gcp';
112
+ /** Vault role name configured for GCP auth */
113
+ role: string;
114
+ /** Path to service account key file (JSON). If not provided, uses ADC */
115
+ serviceAccountKeyFile?: string;
116
+ /** Service account email. If not provided, derived from key file or metadata */
117
+ serviceAccountEmail?: string;
118
+ /** JWT expiration in seconds (default: 900 = 15 minutes) */
119
+ jwtExpiration?: number;
120
+ }
121
+
122
+ /**
123
+ * AWS IAM authentication
124
+ */
125
+ export interface IAWSAuthConfig {
126
+ type?: 'aws';
127
+ role: string;
128
+ // Uses instance profile or environment credentials
129
+ }
130
+
131
+ /**
132
+ * AppRole authentication
133
+ */
134
+ export interface IAppRoleAuthConfig {
135
+ type?: 'approle';
136
+ /** Can be in config */
137
+ roleId: string;
138
+ /** MUST come from secure source */
139
+ secretId: string;
140
+ /** Default: 'approle' */
141
+ mountPath?: string;
142
+ }
143
+
144
+ /**
145
+ * Token authentication (dev only)
146
+ */
147
+ export interface ITokenAuthConfig {
148
+ type?: 'token';
149
+ /** MUST come from secure source */
150
+ token: string;
151
+ }
152
+
153
+ /**
154
+ * TLS configuration
155
+ */
156
+ export interface IVaultTLSConfig {
157
+ /**
158
+ * Require TLS (default: true, cannot be disabled)
159
+ */
160
+ enabled: boolean;
161
+
162
+ /**
163
+ * Verify server certificate (default: true)
164
+ */
165
+ verifyCertificate: boolean;
166
+
167
+ /**
168
+ * Certificate fingerprint for pinning (optional)
169
+ */
170
+ certificateFingerprint?: string;
171
+
172
+ /**
173
+ * Custom CA certificate (optional)
174
+ */
175
+ caCert?: string | Buffer;
176
+
177
+ /**
178
+ * Minimum TLS version (default: 'TLSv1.2')
179
+ */
180
+ minVersion?: 'TLSv1.2' | 'TLSv1.3';
181
+ }
182
+
183
+ /**
184
+ * Fallback configuration
185
+ */
186
+ export interface IVaultFallbackConfig {
187
+ /**
188
+ * Whether Vault is required (default: true)
189
+ * If false, falls back to env/file on initialization failure
190
+ */
191
+ required: boolean;
192
+
193
+ /**
194
+ * Use cached secrets on failure (default: true)
195
+ */
196
+ useCacheOnFailure: boolean;
197
+
198
+ /**
199
+ * Maximum cache age for fallback (ms) - default: TTL or 1 hour
200
+ */
201
+ maxCacheAge: number;
202
+
203
+ /**
204
+ * Fail fast on refresh failure (default: true for required secrets)
205
+ */
206
+ failFast: boolean;
207
+ }
208
+
209
+ /**
210
+ * Retry policy
211
+ */
212
+ export interface IRetryPolicy {
213
+ /** Default: 3 */
214
+ maxAttempts: number;
215
+ backoff: {
216
+ strategy: 'exponential' | 'linear' | 'fixed';
217
+ /** Default: 1000ms */
218
+ initial: number;
219
+ /** Default: 10000ms */
220
+ max: number;
221
+ /** Default: 2 */
222
+ multiplier: number;
223
+ };
224
+ /** Default: ['ECONNREFUSED', 'ETIMEDOUT', '5xx'] */
225
+ retryableErrors: string[];
226
+ }
227
+
228
+ /**
229
+ * Circuit breaker configuration
230
+ */
231
+ export interface ICircuitBreakerConfig {
232
+ /** Default: true */
233
+ enabled: boolean;
234
+ /** Default: 5 */
235
+ failureThreshold: number;
236
+ /** Default: 60000ms */
237
+ resetTimeout: number;
238
+ /** Default: 1 */
239
+ halfOpenMaxRequests: number;
240
+ }
241
+
242
+ /**
243
+ * Vault secret response structure
244
+ */
245
+ export interface IVaultSecretResponse {
246
+ /**
247
+ * Secret data (structure varies by engine)
248
+ */
249
+ data: Record<string, any>;
250
+
251
+ /**
252
+ * Lease ID (for dynamic secrets)
253
+ */
254
+ lease_id?: string;
255
+
256
+ /**
257
+ * Lease duration in seconds (for dynamic secrets)
258
+ */
259
+ lease_duration?: number;
260
+
261
+ /**
262
+ * Whether the lease can be renewed
263
+ */
264
+ renewable?: boolean;
265
+
266
+ /**
267
+ * Request ID for tracing
268
+ */
269
+ request_id?: string;
270
+ }
271
+
272
+ /**
273
+ * Normalized Vault secret (internal representation)
274
+ */
275
+ export interface IVaultSecret {
276
+ /**
277
+ * Secret data (engine-specific structure)
278
+ */
279
+ data: Record<string, any>;
280
+
281
+ /**
282
+ * Lease ID (for dynamic secrets)
283
+ */
284
+ leaseId?: string;
285
+
286
+ /**
287
+ * Lease duration in seconds
288
+ */
289
+ leaseDuration: number;
290
+
291
+ /**
292
+ * Whether lease is renewable
293
+ */
294
+ renewable: boolean;
295
+
296
+ /**
297
+ * Metadata (for KV v2)
298
+ */
299
+ metadata?: {
300
+ createdTime: string;
301
+ deletionTime: string;
302
+ destroyed: boolean;
303
+ version: number;
304
+ };
305
+ }
306
+
307
+ /**
308
+ * Vault property metadata (from decorators)
309
+ */
310
+ export interface VaultPropertyMetadata {
311
+ /**
312
+ * Vault path (from @VaultPath decorator)
313
+ */
314
+ path: string;
315
+
316
+ /**
317
+ * Engine type (from @VaultEngine decorator, or auto-detected)
318
+ */
319
+ engine: VaultEngineType;
320
+
321
+ /**
322
+ * Key name (from @VaultKey decorator, or defaults to property name)
323
+ */
324
+ key?: string;
325
+
326
+ /**
327
+ * Refresh buffer override (from @VaultRefreshBuffer decorator)
328
+ */
329
+ refreshBuffer?: number;
330
+
331
+ /**
332
+ * Whether required (from @VaultOptional decorator - false if present, true otherwise)
333
+ */
334
+ required: boolean;
335
+
336
+ /**
337
+ * Property name
338
+ */
339
+ propertyName: string;
340
+
341
+ /**
342
+ * Property type (for validation)
343
+ */
344
+ propertyType: string;
345
+ }
346
+
347
+ /**
348
+ * Vault cache entry
349
+ */
350
+ export interface VaultCacheEntry {
351
+ /**
352
+ * The secret value (extracted from Vault response)
353
+ */
354
+ value: any;
355
+
356
+ /**
357
+ * Original Vault secret
358
+ */
359
+ secret: IVaultSecret;
360
+
361
+ /**
362
+ * When this secret was cached
363
+ */
364
+ cachedAt: number;
365
+
366
+ /**
367
+ * When this secret expires (timestamp)
368
+ */
369
+ expiresAt: number;
370
+
371
+ /**
372
+ * When to refresh this secret (timestamp)
373
+ */
374
+ refreshAt: number;
375
+
376
+ /**
377
+ * Property name this secret is mapped to
378
+ */
379
+ propertyName: string;
380
+
381
+ /**
382
+ * Vault path
383
+ */
384
+ vaultPath: string;
385
+ }
386
+
387
+ /**
388
+ * Vault health status
389
+ */
390
+ export interface VaultHealth {
391
+ connected: boolean;
392
+ authenticated: boolean;
393
+ cacheSize: number;
394
+ refreshQueueSize: number;
395
+ lastRefreshTime: number;
396
+ errors: VaultError[];
397
+ }
398
+
399
+ /**
400
+ * Vault error (sanitized)
401
+ */
402
+ export interface VaultError {
403
+ timestamp: number;
404
+ path: string;
405
+ error: string; // Sanitized
406
+ retryable: boolean;
407
+ }
408
+
409
+ /**
410
+ * Refresh status for a secret
411
+ */
412
+ export interface IRefreshStatus {
413
+ /**
414
+ * Property name
415
+ */
416
+ propertyName: string;
417
+
418
+ /**
419
+ * Vault path
420
+ */
421
+ vaultPath: string;
422
+
423
+ /**
424
+ * Whether refresh is scheduled
425
+ */
426
+ scheduled: boolean;
427
+
428
+ /**
429
+ * When refresh is scheduled (timestamp)
430
+ */
431
+ refreshAt: number;
432
+
433
+ /**
434
+ * Time until refresh (ms)
435
+ */
436
+ timeUntilRefresh: number;
437
+
438
+ /**
439
+ * Last refresh time (timestamp)
440
+ */
441
+ lastRefresh: number;
442
+
443
+ /**
444
+ * Number of refresh attempts
445
+ */
446
+ refreshCount: number;
447
+ }
448
+
449
+ /**
450
+ * Detailed Vault health information
451
+ */
452
+ export interface IVaultHealthDetails {
453
+ /**
454
+ * Whether connected to Vault
455
+ */
456
+ connected: boolean;
457
+
458
+ /**
459
+ * Whether authenticated
460
+ */
461
+ authenticated: boolean;
462
+
463
+ /**
464
+ * Cache size (number of cached secrets)
465
+ */
466
+ cacheSize: number;
467
+
468
+ /**
469
+ * Refresh queue size (number of scheduled refreshes)
470
+ */
471
+ refreshQueueSize: number;
472
+
473
+ /**
474
+ * Last refresh time (timestamp)
475
+ */
476
+ lastRefreshTime: number;
477
+
478
+ /**
479
+ * Recent errors
480
+ */
481
+ errors: VaultError[];
482
+
483
+ /**
484
+ * Refresh status for all secrets
485
+ */
486
+ refreshStatus: IRefreshStatus[];
487
+ }