@ceschiatti/redistail 0.0.2 → 0.0.4
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 +680 -0
- package/dist/cli/redistail.exe +0 -0
- package/dist/cli/redistail.js +5 -5
- package/package.json +38 -37
- package/src/cli/config-service.ts +455 -0
- package/src/cli/display-service.ts +321 -0
- package/src/cli/layers.ts +492 -0
- package/src/cli/pubsub-monitor-service.ts +296 -0
- package/src/cli/redistail-launcher.js +65 -0
- package/src/cli/redistail.ts +417 -0
- package/src/cli/signal-handler-service.ts +210 -0
- package/src/cli/stream-monitor-service.ts +427 -0
- package/src/cli/types.ts +302 -0
- package/src/cli/version-generated.ts +27 -0
- package/src/cli/version.ts +27 -0
|
@@ -0,0 +1,492 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Layer composition and dependency injection for the redistail CLI utility.
|
|
3
|
+
*
|
|
4
|
+
* This module provides all service layers and their composition for the redistail
|
|
5
|
+
* application. It follows Effect-TS patterns for dependency injection, resource
|
|
6
|
+
* management, and proper error handling. The layers are composed to create a
|
|
7
|
+
* complete application environment with all necessary services.
|
|
8
|
+
*
|
|
9
|
+
* Requirements addressed:
|
|
10
|
+
* - 7.1: Integration with effect-redis package services
|
|
11
|
+
* - 7.2: Effect-TS patterns for error handling and resource management
|
|
12
|
+
* - 7.3: Service composition through Effect Layers
|
|
13
|
+
* - 7.4: Proper error handling and resource management
|
|
14
|
+
*/
|
|
15
|
+
|
|
16
|
+
import { Context, Effect, Layer } from 'effect';
|
|
17
|
+
import {
|
|
18
|
+
Redis,
|
|
19
|
+
RedisPubSub,
|
|
20
|
+
RedisStream,
|
|
21
|
+
RedisConnectionOptions,
|
|
22
|
+
RedisConnectionOptionsLive,
|
|
23
|
+
RedisLive,
|
|
24
|
+
RedisPubSubLive,
|
|
25
|
+
RedisStreamLive,
|
|
26
|
+
} from 'effect-redis';
|
|
27
|
+
import { CLIConfigService, CLIConfigServiceLive } from './config-service.js';
|
|
28
|
+
import {
|
|
29
|
+
DisplayServiceTag,
|
|
30
|
+
createTestDisplayService,
|
|
31
|
+
type DisplayService,
|
|
32
|
+
} from './display-service.js';
|
|
33
|
+
import {
|
|
34
|
+
PubSubMonitorService,
|
|
35
|
+
PubSubMonitorServiceLive,
|
|
36
|
+
} from './pubsub-monitor-service.js';
|
|
37
|
+
import {
|
|
38
|
+
StreamMonitorService,
|
|
39
|
+
StreamMonitorServiceLive,
|
|
40
|
+
} from './stream-monitor-service.js';
|
|
41
|
+
import {
|
|
42
|
+
SignalHandlerService,
|
|
43
|
+
SignalHandlerServiceLive,
|
|
44
|
+
} from './signal-handler-service.js';
|
|
45
|
+
import type { RedistailConfig, ConfigError, RedistailError } from './types.js';
|
|
46
|
+
import { RedistailConfig as RedistailConfigConstructor } from './types.js';
|
|
47
|
+
|
|
48
|
+
// ============================================================================
|
|
49
|
+
// Configuration Layer
|
|
50
|
+
// ============================================================================
|
|
51
|
+
|
|
52
|
+
/**
|
|
53
|
+
* Context tag for RedistailConfig dependency injection
|
|
54
|
+
*/
|
|
55
|
+
const RedistailConfigTag = Context.GenericTag<RedistailConfig>(
|
|
56
|
+
'@redistail/RedistailConfig',
|
|
57
|
+
);
|
|
58
|
+
|
|
59
|
+
/**
|
|
60
|
+
* Live layer that provides RedistailConfig by loading from environment
|
|
61
|
+
* This layer depends on CLIConfigService to load the configuration
|
|
62
|
+
*/
|
|
63
|
+
export const RedistailConfigLive: Layer.Layer<
|
|
64
|
+
RedistailConfig,
|
|
65
|
+
ConfigError,
|
|
66
|
+
CLIConfigService
|
|
67
|
+
> = Layer.effect(
|
|
68
|
+
RedistailConfigTag,
|
|
69
|
+
Effect.gen(function* () {
|
|
70
|
+
const configService = yield* CLIConfigService;
|
|
71
|
+
return yield* configService.loadConfig();
|
|
72
|
+
}),
|
|
73
|
+
);
|
|
74
|
+
|
|
75
|
+
// ============================================================================
|
|
76
|
+
// Redis Connection Layer
|
|
77
|
+
// ============================================================================
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Live layer that provides Redis connection configuration based on RedistailConfig
|
|
81
|
+
* This layer creates the appropriate Redis connection options from the loaded configuration
|
|
82
|
+
*
|
|
83
|
+
* Requirement 7.1: Integrates with effect-redis RedisConnectionOptions
|
|
84
|
+
*/
|
|
85
|
+
export const RedisConnectionLive: Layer.Layer<
|
|
86
|
+
RedisConnectionOptions,
|
|
87
|
+
never,
|
|
88
|
+
RedistailConfig
|
|
89
|
+
> = Layer.effect(
|
|
90
|
+
RedisConnectionOptions,
|
|
91
|
+
Effect.gen(function* () {
|
|
92
|
+
const config = yield* RedistailConfigTag;
|
|
93
|
+
|
|
94
|
+
// Determine the Redis URL - prefer explicit URL over host/port
|
|
95
|
+
const redisUrl =
|
|
96
|
+
config.redis.url ?? `redis://${config.redis.host}:${config.redis.port}`;
|
|
97
|
+
|
|
98
|
+
// Create Redis connection options with timeout and retry configuration
|
|
99
|
+
const connectionOptions = {
|
|
100
|
+
url: redisUrl,
|
|
101
|
+
socket: {
|
|
102
|
+
connectTimeout: config.redis.timeout,
|
|
103
|
+
reconnectStrategy: (retries: number) => {
|
|
104
|
+
// Use exponential backoff with max attempts from config
|
|
105
|
+
if (retries >= config.redis.retryAttempts) {
|
|
106
|
+
return false; // Stop retrying after max attempts
|
|
107
|
+
}
|
|
108
|
+
return Math.min(config.redis.retryDelay * 2 ** retries, 30000);
|
|
109
|
+
},
|
|
110
|
+
},
|
|
111
|
+
// Set command timeout
|
|
112
|
+
commandsQueueMaxLength: 1000,
|
|
113
|
+
};
|
|
114
|
+
|
|
115
|
+
// Return the connection options shape
|
|
116
|
+
return {
|
|
117
|
+
options: connectionOptions,
|
|
118
|
+
createClient: undefined,
|
|
119
|
+
};
|
|
120
|
+
}),
|
|
121
|
+
);
|
|
122
|
+
|
|
123
|
+
// ============================================================================
|
|
124
|
+
// Display Service Layer
|
|
125
|
+
// ============================================================================
|
|
126
|
+
|
|
127
|
+
/**
|
|
128
|
+
* Live layer that provides DisplayService with configuration
|
|
129
|
+
* This layer depends on RedistailConfig to configure display options
|
|
130
|
+
*/
|
|
131
|
+
export const DisplayServiceLive: Layer.Layer<
|
|
132
|
+
DisplayService,
|
|
133
|
+
never,
|
|
134
|
+
RedistailConfig
|
|
135
|
+
> = Layer.effect(
|
|
136
|
+
DisplayServiceTag,
|
|
137
|
+
Effect.gen(function* () {
|
|
138
|
+
const config = yield* RedistailConfigTag;
|
|
139
|
+
return createTestDisplayService(config);
|
|
140
|
+
}),
|
|
141
|
+
);
|
|
142
|
+
|
|
143
|
+
// ============================================================================
|
|
144
|
+
// Helper Functions for Layer Creation
|
|
145
|
+
// ============================================================================
|
|
146
|
+
|
|
147
|
+
/**
|
|
148
|
+
* Create a Redis connection layer with custom options
|
|
149
|
+
*
|
|
150
|
+
* Requirement 7.1: Provides integration with effect-redis connection system
|
|
151
|
+
*/
|
|
152
|
+
export const createRedisConnectionLayer = (
|
|
153
|
+
host: string,
|
|
154
|
+
port: number,
|
|
155
|
+
options?: {
|
|
156
|
+
url?: string;
|
|
157
|
+
timeout?: number;
|
|
158
|
+
retryAttempts?: number;
|
|
159
|
+
retryDelay?: number;
|
|
160
|
+
},
|
|
161
|
+
): Layer.Layer<RedisConnectionOptions> => {
|
|
162
|
+
const redisUrl = options?.url ?? `redis://${host}:${port}`;
|
|
163
|
+
const timeout = options?.timeout ?? 5000;
|
|
164
|
+
const retryAttempts = options?.retryAttempts ?? 3;
|
|
165
|
+
const retryDelay = options?.retryDelay ?? 1000;
|
|
166
|
+
|
|
167
|
+
return RedisConnectionOptionsLive({
|
|
168
|
+
url: redisUrl,
|
|
169
|
+
socket: {
|
|
170
|
+
connectTimeout: timeout,
|
|
171
|
+
reconnectStrategy: (retries: number) => {
|
|
172
|
+
if (retries >= retryAttempts) {
|
|
173
|
+
return false;
|
|
174
|
+
}
|
|
175
|
+
return Math.min(retryDelay * 2 ** retries, 30000);
|
|
176
|
+
},
|
|
177
|
+
},
|
|
178
|
+
commandsQueueMaxLength: 1000,
|
|
179
|
+
});
|
|
180
|
+
};
|
|
181
|
+
|
|
182
|
+
/**
|
|
183
|
+
* Create a layer with custom Redis connection options
|
|
184
|
+
*/
|
|
185
|
+
export const createRedisOptionsLayer = (
|
|
186
|
+
options: Parameters<typeof RedisConnectionOptionsLive>[0],
|
|
187
|
+
): Layer.Layer<RedisConnectionOptions> => RedisConnectionOptionsLive(options);
|
|
188
|
+
|
|
189
|
+
/**
|
|
190
|
+
* Create a test configuration layer
|
|
191
|
+
*/
|
|
192
|
+
export const createTestConfigLayer = (
|
|
193
|
+
config: RedistailConfig,
|
|
194
|
+
): Layer.Layer<RedistailConfig> => Layer.succeed(RedistailConfigTag, config);
|
|
195
|
+
|
|
196
|
+
// ============================================================================
|
|
197
|
+
// Application Layer Composition
|
|
198
|
+
// ============================================================================
|
|
199
|
+
|
|
200
|
+
/**
|
|
201
|
+
* Complete application layer that provides all services needed for redistail
|
|
202
|
+
* This is the main layer that applications should use to get all dependencies
|
|
203
|
+
*
|
|
204
|
+
* OPTIMIZATION: Only includes Redis services that are actually used by the CLI:
|
|
205
|
+
* - RedisPubSub: For PubSub channel monitoring
|
|
206
|
+
* - RedisStream: For Stream monitoring
|
|
207
|
+
* - Core Redis service (RedisLive) is excluded as it's not used by redistail
|
|
208
|
+
*
|
|
209
|
+
* This reduces Redis connections from 5 to 4 (2 for PubSub + 2 for Stream)
|
|
210
|
+
*
|
|
211
|
+
* Requirements 7.1, 7.2, 7.3, 7.4: This layer integrates with effect-redis,
|
|
212
|
+
* uses Effect-TS patterns, provides service composition and proper error handling
|
|
213
|
+
*/
|
|
214
|
+
|
|
215
|
+
// Build the base configuration layer first
|
|
216
|
+
// CLIConfigServiceLive has no dependencies
|
|
217
|
+
// RedistailConfigLive depends on CLIConfigService
|
|
218
|
+
const ConfigLayer = Layer.provide(RedistailConfigLive, CLIConfigServiceLive);
|
|
219
|
+
|
|
220
|
+
// RedisConnectionLive depends on RedistailConfig
|
|
221
|
+
// We need to provide RedistailConfig to it, which comes from ConfigLayer
|
|
222
|
+
const ConnectionLayer = Layer.provide(RedisConnectionLive, ConfigLayer);
|
|
223
|
+
|
|
224
|
+
// Only create the Redis services that are actually used by the CLI
|
|
225
|
+
// RedisLive (core Redis service) is not used by redistail CLI
|
|
226
|
+
const RedisPubSubServiceLayer = Layer.provide(RedisPubSubLive, ConnectionLayer);
|
|
227
|
+
const RedisStreamServiceLayer = Layer.provide(RedisStreamLive, ConnectionLayer);
|
|
228
|
+
|
|
229
|
+
// Merge only the Redis services that are actually needed
|
|
230
|
+
const RequiredRedisServicesLayer = Layer.mergeAll(
|
|
231
|
+
RedisPubSubServiceLayer,
|
|
232
|
+
RedisStreamServiceLayer,
|
|
233
|
+
);
|
|
234
|
+
|
|
235
|
+
// DisplayServiceLive depends on RedistailConfig
|
|
236
|
+
const DisplayLayer = Layer.provide(DisplayServiceLive, ConfigLayer);
|
|
237
|
+
|
|
238
|
+
// PubSubMonitorServiceLive depends on RedisPubSub and CLIConfigService
|
|
239
|
+
const PubSubMonitorLayer = Layer.provide(
|
|
240
|
+
PubSubMonitorServiceLive,
|
|
241
|
+
Layer.merge(RedisPubSubServiceLayer, CLIConfigServiceLive),
|
|
242
|
+
);
|
|
243
|
+
|
|
244
|
+
// StreamMonitorServiceLive depends on RedisStream and CLIConfigService
|
|
245
|
+
const StreamMonitorLayer = Layer.provide(
|
|
246
|
+
StreamMonitorServiceLive,
|
|
247
|
+
Layer.merge(RedisStreamServiceLayer, CLIConfigServiceLive),
|
|
248
|
+
);
|
|
249
|
+
|
|
250
|
+
// Compose the final application layer
|
|
251
|
+
export const AppLive = Layer.mergeAll(
|
|
252
|
+
CLIConfigServiceLive,
|
|
253
|
+
SignalHandlerServiceLive,
|
|
254
|
+
ConfigLayer,
|
|
255
|
+
DisplayLayer,
|
|
256
|
+
RequiredRedisServicesLayer,
|
|
257
|
+
PubSubMonitorLayer,
|
|
258
|
+
StreamMonitorLayer,
|
|
259
|
+
);
|
|
260
|
+
|
|
261
|
+
/**
|
|
262
|
+
* Layer for PubSub-only applications
|
|
263
|
+
* Provides only the services needed for PubSub monitoring
|
|
264
|
+
*
|
|
265
|
+
* Requirement 7.3: Service composition through Effect Layers
|
|
266
|
+
*/
|
|
267
|
+
export const PubSubAppLive = (() => {
|
|
268
|
+
// Build the dependency chain step by step
|
|
269
|
+
const configLayer = Layer.provide(RedistailConfigLive, CLIConfigServiceLive);
|
|
270
|
+
const connectionLayer = Layer.provide(RedisConnectionLive, configLayer);
|
|
271
|
+
const displayLayer = Layer.provide(DisplayServiceLive, configLayer);
|
|
272
|
+
const pubsubLayer = Layer.provide(RedisPubSubLive, connectionLayer);
|
|
273
|
+
const monitorLayer = Layer.provide(
|
|
274
|
+
PubSubMonitorServiceLive,
|
|
275
|
+
Layer.merge(pubsubLayer, CLIConfigServiceLive),
|
|
276
|
+
);
|
|
277
|
+
|
|
278
|
+
// Merge all the layers together - only what's needed for PubSub
|
|
279
|
+
return Layer.mergeAll(
|
|
280
|
+
CLIConfigServiceLive,
|
|
281
|
+
SignalHandlerServiceLive,
|
|
282
|
+
configLayer,
|
|
283
|
+
displayLayer,
|
|
284
|
+
pubsubLayer,
|
|
285
|
+
monitorLayer,
|
|
286
|
+
);
|
|
287
|
+
})();
|
|
288
|
+
|
|
289
|
+
/**
|
|
290
|
+
* Layer for Stream-only applications
|
|
291
|
+
* Provides only the services needed for Stream monitoring
|
|
292
|
+
*
|
|
293
|
+
* Requirement 7.3: Service composition through Effect Layers
|
|
294
|
+
*/
|
|
295
|
+
export const StreamAppLive = (() => {
|
|
296
|
+
// Build the dependency chain step by step
|
|
297
|
+
const configLayer = Layer.provide(RedistailConfigLive, CLIConfigServiceLive);
|
|
298
|
+
const connectionLayer = Layer.provide(RedisConnectionLive, configLayer);
|
|
299
|
+
const displayLayer = Layer.provide(DisplayServiceLive, configLayer);
|
|
300
|
+
const streamLayer = Layer.provide(RedisStreamLive, connectionLayer);
|
|
301
|
+
const monitorLayer = Layer.provide(
|
|
302
|
+
StreamMonitorServiceLive,
|
|
303
|
+
Layer.merge(streamLayer, CLIConfigServiceLive),
|
|
304
|
+
);
|
|
305
|
+
|
|
306
|
+
// Merge all the layers together - only what's needed for Streams
|
|
307
|
+
return Layer.mergeAll(
|
|
308
|
+
CLIConfigServiceLive,
|
|
309
|
+
SignalHandlerServiceLive,
|
|
310
|
+
configLayer,
|
|
311
|
+
displayLayer,
|
|
312
|
+
streamLayer,
|
|
313
|
+
monitorLayer,
|
|
314
|
+
);
|
|
315
|
+
})();
|
|
316
|
+
|
|
317
|
+
// ============================================================================
|
|
318
|
+
// Testing Layers
|
|
319
|
+
// ============================================================================
|
|
320
|
+
|
|
321
|
+
/**
|
|
322
|
+
* Create a test layer with custom configuration
|
|
323
|
+
* Useful for testing with specific Redis configurations
|
|
324
|
+
*
|
|
325
|
+
* Requirement 7.4: Proper resource management for testing
|
|
326
|
+
*/
|
|
327
|
+
export const createTestAppLayer = (config: RedistailConfig) =>
|
|
328
|
+
Layer.mergeAll(CLIConfigServiceLive, SignalHandlerServiceLive).pipe(
|
|
329
|
+
Layer.provideMerge(createTestConfigLayer(config)),
|
|
330
|
+
Layer.provideMerge(RedisConnectionLive),
|
|
331
|
+
Layer.provideMerge(
|
|
332
|
+
Layer.mergeAll(RedisLive, RedisPubSubLive, RedisStreamLive),
|
|
333
|
+
),
|
|
334
|
+
Layer.provideMerge(DisplayServiceLive),
|
|
335
|
+
Layer.provideMerge(
|
|
336
|
+
Layer.mergeAll(PubSubMonitorServiceLive, StreamMonitorServiceLive),
|
|
337
|
+
),
|
|
338
|
+
);
|
|
339
|
+
|
|
340
|
+
/**
|
|
341
|
+
* Create a minimal test layer with mock Redis connection
|
|
342
|
+
* Useful for unit testing without actual Redis connection
|
|
343
|
+
*
|
|
344
|
+
* Requirement 7.4: Resource management for testing scenarios
|
|
345
|
+
*/
|
|
346
|
+
export const createMockAppLayer = (config: RedistailConfig) =>
|
|
347
|
+
Layer.mergeAll(CLIConfigServiceLive, SignalHandlerServiceLive).pipe(
|
|
348
|
+
Layer.provideMerge(createTestConfigLayer(config)),
|
|
349
|
+
Layer.provideMerge(DisplayServiceLive),
|
|
350
|
+
);
|
|
351
|
+
|
|
352
|
+
// ============================================================================
|
|
353
|
+
// Error Handling Utilities
|
|
354
|
+
// ============================================================================
|
|
355
|
+
|
|
356
|
+
/**
|
|
357
|
+
* Helper to handle layer initialization errors gracefully
|
|
358
|
+
* Provides proper error handling and resource management (Requirement 7.4)
|
|
359
|
+
*/
|
|
360
|
+
export const handleLayerError = <E>(error: E): Effect.Effect<never, never> =>
|
|
361
|
+
Effect.gen(function* () {
|
|
362
|
+
// Log the error details
|
|
363
|
+
yield* Effect.logError(`Layer initialization failed: ${String(error)}`);
|
|
364
|
+
|
|
365
|
+
// Provide specific error messages based on error type
|
|
366
|
+
if (typeof error === 'object' && error !== null && '_tag' in error) {
|
|
367
|
+
const taggedError = error as { _tag: string; message?: string };
|
|
368
|
+
if (taggedError._tag === 'ConfigError') {
|
|
369
|
+
yield* Effect.logError(
|
|
370
|
+
'Configuration error - check environment variables and Redis connection settings',
|
|
371
|
+
);
|
|
372
|
+
} else if (taggedError._tag === 'RedisConnectionError') {
|
|
373
|
+
yield* Effect.logError(
|
|
374
|
+
'Redis connection error - check Redis server availability',
|
|
375
|
+
);
|
|
376
|
+
} else if (taggedError._tag === 'MonitoringError') {
|
|
377
|
+
yield* Effect.logError(
|
|
378
|
+
'Monitoring error - check Redis connection and topic names',
|
|
379
|
+
);
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
// Exit with error code
|
|
384
|
+
return yield* Effect.sync(() => process.exit(1));
|
|
385
|
+
});
|
|
386
|
+
|
|
387
|
+
/**
|
|
388
|
+
* Create a default RedistailConfig for testing and development
|
|
389
|
+
*
|
|
390
|
+
* Requirement 7.4: Proper configuration management
|
|
391
|
+
*/
|
|
392
|
+
export const createDefaultConfig = (
|
|
393
|
+
overrides?: Partial<RedistailConfig>,
|
|
394
|
+
): RedistailConfig =>
|
|
395
|
+
RedistailConfigConstructor({
|
|
396
|
+
redis: {
|
|
397
|
+
host: '127.0.0.1',
|
|
398
|
+
port: 6379,
|
|
399
|
+
timeout: 5000,
|
|
400
|
+
retryAttempts: 3,
|
|
401
|
+
retryDelay: 1000,
|
|
402
|
+
...overrides?.redis,
|
|
403
|
+
},
|
|
404
|
+
display: {
|
|
405
|
+
colors: true,
|
|
406
|
+
timestamps: true,
|
|
407
|
+
prettyJson: true,
|
|
408
|
+
...overrides?.display,
|
|
409
|
+
},
|
|
410
|
+
monitoring: {
|
|
411
|
+
blockTimeout: 5000,
|
|
412
|
+
maxReconnectAttempts: 5,
|
|
413
|
+
...overrides?.monitoring,
|
|
414
|
+
},
|
|
415
|
+
});
|
|
416
|
+
|
|
417
|
+
// ============================================================================
|
|
418
|
+
// Layer Validation and Utilities
|
|
419
|
+
// ============================================================================
|
|
420
|
+
|
|
421
|
+
/**
|
|
422
|
+
* Validate that all required services are available in a layer
|
|
423
|
+
* This is a compile-time check to ensure layer completeness
|
|
424
|
+
*
|
|
425
|
+
* Requirement 7.3: Service composition validation
|
|
426
|
+
*/
|
|
427
|
+
export const validateAppLayer = (): void => {
|
|
428
|
+
// This function serves as a compile-time check for layer dependencies
|
|
429
|
+
// If there are missing dependencies, TypeScript will show errors here
|
|
430
|
+
|
|
431
|
+
// The AppLive layer should provide all these services
|
|
432
|
+
const _appLayerCheck = AppLive;
|
|
433
|
+
|
|
434
|
+
// Suppress unused variable warning
|
|
435
|
+
void _appLayerCheck;
|
|
436
|
+
};
|
|
437
|
+
|
|
438
|
+
// ============================================================================
|
|
439
|
+
// Re-exports for Convenience
|
|
440
|
+
// ============================================================================
|
|
441
|
+
|
|
442
|
+
// Re-export commonly used services and types for convenience
|
|
443
|
+
export {
|
|
444
|
+
CLIConfigService,
|
|
445
|
+
DisplayServiceTag,
|
|
446
|
+
PubSubMonitorService,
|
|
447
|
+
StreamMonitorService,
|
|
448
|
+
SignalHandlerService,
|
|
449
|
+
Redis,
|
|
450
|
+
RedisPubSub,
|
|
451
|
+
RedisStream,
|
|
452
|
+
};
|
|
453
|
+
|
|
454
|
+
export type { RedistailConfig, RedistailError, ConfigError };
|
|
455
|
+
|
|
456
|
+
// Export the RedistailConfigTag for use in other modules
|
|
457
|
+
export { RedistailConfigTag };
|
|
458
|
+
|
|
459
|
+
// ============================================================================
|
|
460
|
+
// Documentation and Examples
|
|
461
|
+
// ============================================================================
|
|
462
|
+
|
|
463
|
+
/**
|
|
464
|
+
* Example usage of the layers:
|
|
465
|
+
*
|
|
466
|
+
* ```typescript
|
|
467
|
+
* import { AppLive, runWithAppLayer } from './layers.js';
|
|
468
|
+
* import { Effect } from 'effect';
|
|
469
|
+
*
|
|
470
|
+
* const myProgram = Effect.gen(function* () {
|
|
471
|
+
* const cliService = yield* CLIConfigService;
|
|
472
|
+
* const config = yield* cliService.loadConfig();
|
|
473
|
+
* // ... use other services
|
|
474
|
+
* });
|
|
475
|
+
*
|
|
476
|
+
* // Run with complete application layer
|
|
477
|
+
* Effect.runPromise(Effect.provide(myProgram, AppLive));
|
|
478
|
+
* ```
|
|
479
|
+
*
|
|
480
|
+
* For testing:
|
|
481
|
+
*
|
|
482
|
+
* ```typescript
|
|
483
|
+
* import { createTestAppLayer, createDefaultConfig } from './layers.js';
|
|
484
|
+
*
|
|
485
|
+
* const testConfig = createDefaultConfig({
|
|
486
|
+
* redis: { host: 'localhost', port: 6380 }
|
|
487
|
+
* });
|
|
488
|
+
*
|
|
489
|
+
* const testLayer = createTestAppLayer(testConfig);
|
|
490
|
+
* Effect.runPromise(Effect.provide(myProgram, testLayer));
|
|
491
|
+
* ```
|
|
492
|
+
*/
|