@ceschiatti/redistail 0.0.2 → 0.0.3
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/dist/cli/redistail.exe +0 -0
- package/dist/cli/redistail.js +1 -1
- package/package.json +3 -2
- 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
package/src/cli/types.ts
ADDED
|
@@ -0,0 +1,302 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Core data types and error definitions for the redistail CLI utility.
|
|
3
|
+
*
|
|
4
|
+
* This module defines immutable data structures using Effect Data types
|
|
5
|
+
* and error types using Data.TaggedError for type-safe error handling.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { Data } from 'effect';
|
|
9
|
+
|
|
10
|
+
// ============================================================================
|
|
11
|
+
// CLI Configuration Types
|
|
12
|
+
// ============================================================================
|
|
13
|
+
|
|
14
|
+
/**
|
|
15
|
+
* CLI configuration parsed from command line arguments
|
|
16
|
+
*/
|
|
17
|
+
export interface CLIConfig {
|
|
18
|
+
readonly connectionType: 'pubsub' | 'stream';
|
|
19
|
+
readonly topicName: string;
|
|
20
|
+
readonly help?: boolean;
|
|
21
|
+
readonly version?: boolean;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Complete redistail configuration including Redis connection and display settings
|
|
26
|
+
*/
|
|
27
|
+
export interface RedistailConfig {
|
|
28
|
+
readonly redis: {
|
|
29
|
+
readonly host: string;
|
|
30
|
+
readonly port: number;
|
|
31
|
+
readonly url?: string;
|
|
32
|
+
readonly timeout: number;
|
|
33
|
+
readonly retryAttempts: number;
|
|
34
|
+
readonly retryDelay: number;
|
|
35
|
+
};
|
|
36
|
+
readonly display: {
|
|
37
|
+
readonly colors: boolean;
|
|
38
|
+
readonly timestamps: boolean;
|
|
39
|
+
readonly prettyJson: boolean;
|
|
40
|
+
};
|
|
41
|
+
readonly monitoring: {
|
|
42
|
+
readonly blockTimeout: number;
|
|
43
|
+
readonly maxReconnectAttempts: number;
|
|
44
|
+
};
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// Data constructors for immutable data structures
|
|
48
|
+
export const CLIConfig = Data.struct<CLIConfig>;
|
|
49
|
+
export const RedistailConfig = Data.struct<RedistailConfig>;
|
|
50
|
+
|
|
51
|
+
// ============================================================================
|
|
52
|
+
// Message Types
|
|
53
|
+
// ============================================================================
|
|
54
|
+
|
|
55
|
+
/**
|
|
56
|
+
* Pub/Sub message data structure
|
|
57
|
+
*/
|
|
58
|
+
export interface PubSubMessage {
|
|
59
|
+
readonly timestamp: Date;
|
|
60
|
+
readonly channel: string;
|
|
61
|
+
readonly content: string;
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
/**
|
|
65
|
+
* Redis Stream message data structure
|
|
66
|
+
*/
|
|
67
|
+
export interface StreamMessage {
|
|
68
|
+
readonly timestamp: Date;
|
|
69
|
+
readonly streamKey: string;
|
|
70
|
+
readonly entryId: string;
|
|
71
|
+
readonly fields: Record<string, string>;
|
|
72
|
+
}
|
|
73
|
+
|
|
74
|
+
// Data constructors for message types
|
|
75
|
+
export const PubSubMessage = Data.struct<PubSubMessage>;
|
|
76
|
+
export const StreamMessage = Data.struct<StreamMessage>;
|
|
77
|
+
|
|
78
|
+
// ============================================================================
|
|
79
|
+
// Error Types using Data.TaggedError
|
|
80
|
+
// ============================================================================
|
|
81
|
+
|
|
82
|
+
/**
|
|
83
|
+
* CLI-specific errors for argument parsing and validation
|
|
84
|
+
*/
|
|
85
|
+
export class CLIError extends Data.TaggedError('CLIError')<{
|
|
86
|
+
readonly reason: 'InvalidArguments' | 'MissingArguments' | 'UnknownCommand';
|
|
87
|
+
readonly message: string;
|
|
88
|
+
readonly context?: string;
|
|
89
|
+
}> {}
|
|
90
|
+
|
|
91
|
+
/**
|
|
92
|
+
* Configuration errors for environment variables and Redis connection
|
|
93
|
+
*/
|
|
94
|
+
export class ConfigError extends Data.TaggedError('ConfigError')<{
|
|
95
|
+
readonly reason:
|
|
96
|
+
| 'InvalidEnvironment'
|
|
97
|
+
| 'ConnectionFailed'
|
|
98
|
+
| 'ValidationFailed';
|
|
99
|
+
readonly message: string;
|
|
100
|
+
readonly cause?: unknown;
|
|
101
|
+
readonly context?: string;
|
|
102
|
+
}> {}
|
|
103
|
+
|
|
104
|
+
/**
|
|
105
|
+
* Runtime monitoring errors for subscription and connection issues
|
|
106
|
+
*/
|
|
107
|
+
export class MonitoringError extends Data.TaggedError('MonitoringError')<{
|
|
108
|
+
readonly reason: 'ConnectionLost' | 'SubscriptionFailed' | 'StreamReadFailed';
|
|
109
|
+
readonly message: string;
|
|
110
|
+
readonly retryable: boolean;
|
|
111
|
+
readonly cause?: unknown;
|
|
112
|
+
}> {}
|
|
113
|
+
|
|
114
|
+
/**
|
|
115
|
+
* Union type for all redistail-specific errors
|
|
116
|
+
*/
|
|
117
|
+
export type RedistailError = CLIError | ConfigError | MonitoringError;
|
|
118
|
+
|
|
119
|
+
// ============================================================================
|
|
120
|
+
// Stream Monitor Options
|
|
121
|
+
// ============================================================================
|
|
122
|
+
|
|
123
|
+
/**
|
|
124
|
+
* Options for Redis Stream monitoring
|
|
125
|
+
*/
|
|
126
|
+
export interface StreamMonitorOptions {
|
|
127
|
+
readonly startId?: string;
|
|
128
|
+
readonly blockTimeout?: number;
|
|
129
|
+
readonly count?: number;
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
export const StreamMonitorOptions = Data.struct<StreamMonitorOptions>;
|
|
133
|
+
|
|
134
|
+
// ============================================================================
|
|
135
|
+
// Type Guards and Utilities
|
|
136
|
+
// ============================================================================
|
|
137
|
+
|
|
138
|
+
/**
|
|
139
|
+
* Type guard to check if a connection type is valid
|
|
140
|
+
*/
|
|
141
|
+
export const isValidConnectionType = (
|
|
142
|
+
type: string,
|
|
143
|
+
): type is 'pubsub' | 'stream' => type === 'pubsub' || type === 'stream';
|
|
144
|
+
|
|
145
|
+
/**
|
|
146
|
+
* Type guard to check if a topic name is valid (non-empty after trimming)
|
|
147
|
+
*/
|
|
148
|
+
export const isValidTopicName = (name: string): boolean =>
|
|
149
|
+
typeof name === 'string' && name.trim().length > 0;
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Helper to create CLIError for invalid arguments
|
|
153
|
+
*/
|
|
154
|
+
export const createInvalidArgumentError = (
|
|
155
|
+
message: string,
|
|
156
|
+
context?: string,
|
|
157
|
+
): CLIError =>
|
|
158
|
+
new CLIError({
|
|
159
|
+
reason: 'InvalidArguments',
|
|
160
|
+
message,
|
|
161
|
+
context,
|
|
162
|
+
});
|
|
163
|
+
|
|
164
|
+
/**
|
|
165
|
+
* Helper to create CLIError for missing arguments
|
|
166
|
+
*/
|
|
167
|
+
export const createMissingArgumentError = (
|
|
168
|
+
message: string,
|
|
169
|
+
context?: string,
|
|
170
|
+
): CLIError =>
|
|
171
|
+
new CLIError({
|
|
172
|
+
reason: 'MissingArguments',
|
|
173
|
+
message,
|
|
174
|
+
context,
|
|
175
|
+
});
|
|
176
|
+
|
|
177
|
+
/**
|
|
178
|
+
* Helper to create ConfigError for environment issues
|
|
179
|
+
*/
|
|
180
|
+
export const createEnvironmentError = (
|
|
181
|
+
message: string,
|
|
182
|
+
cause?: unknown,
|
|
183
|
+
context?: string,
|
|
184
|
+
): ConfigError =>
|
|
185
|
+
new ConfigError({
|
|
186
|
+
reason: 'InvalidEnvironment',
|
|
187
|
+
message,
|
|
188
|
+
cause,
|
|
189
|
+
context,
|
|
190
|
+
});
|
|
191
|
+
|
|
192
|
+
/**
|
|
193
|
+
* Helper to create ConfigError for connection failures
|
|
194
|
+
*/
|
|
195
|
+
export const createConnectionError = (
|
|
196
|
+
message: string,
|
|
197
|
+
cause?: unknown,
|
|
198
|
+
context?: string,
|
|
199
|
+
): ConfigError =>
|
|
200
|
+
new ConfigError({
|
|
201
|
+
reason: 'ConnectionFailed',
|
|
202
|
+
message,
|
|
203
|
+
cause,
|
|
204
|
+
context,
|
|
205
|
+
});
|
|
206
|
+
|
|
207
|
+
/**
|
|
208
|
+
* Helper to create MonitoringError for connection loss
|
|
209
|
+
*/
|
|
210
|
+
export const createConnectionLostError = (
|
|
211
|
+
message: string,
|
|
212
|
+
cause?: unknown,
|
|
213
|
+
): MonitoringError =>
|
|
214
|
+
new MonitoringError({
|
|
215
|
+
reason: 'ConnectionLost',
|
|
216
|
+
message,
|
|
217
|
+
retryable: true,
|
|
218
|
+
cause,
|
|
219
|
+
});
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Helper to create MonitoringError for subscription failures
|
|
223
|
+
*/
|
|
224
|
+
export const createSubscriptionFailedError = (
|
|
225
|
+
message: string,
|
|
226
|
+
retryable = true,
|
|
227
|
+
cause?: unknown,
|
|
228
|
+
): MonitoringError =>
|
|
229
|
+
new MonitoringError({
|
|
230
|
+
reason: 'SubscriptionFailed',
|
|
231
|
+
message,
|
|
232
|
+
retryable,
|
|
233
|
+
cause,
|
|
234
|
+
});
|
|
235
|
+
|
|
236
|
+
/**
|
|
237
|
+
* Helper to create MonitoringError for stream read failures
|
|
238
|
+
*/
|
|
239
|
+
export const createStreamReadFailedError = (
|
|
240
|
+
message: string,
|
|
241
|
+
retryable = true,
|
|
242
|
+
cause?: unknown,
|
|
243
|
+
): MonitoringError =>
|
|
244
|
+
new MonitoringError({
|
|
245
|
+
reason: 'StreamReadFailed',
|
|
246
|
+
message,
|
|
247
|
+
retryable,
|
|
248
|
+
cause,
|
|
249
|
+
});
|
|
250
|
+
|
|
251
|
+
// ============================================================================
|
|
252
|
+
// Default Configuration Values
|
|
253
|
+
// ============================================================================
|
|
254
|
+
|
|
255
|
+
/**
|
|
256
|
+
* Default Redis configuration values for CLI
|
|
257
|
+
*/
|
|
258
|
+
export const DEFAULT_CLI_REDIS_CONFIG = {
|
|
259
|
+
host: '127.0.0.1',
|
|
260
|
+
port: 6379,
|
|
261
|
+
timeout: 5000,
|
|
262
|
+
retryAttempts: 3,
|
|
263
|
+
retryDelay: 1000,
|
|
264
|
+
} as const;
|
|
265
|
+
|
|
266
|
+
/**
|
|
267
|
+
* Default display configuration values
|
|
268
|
+
*/
|
|
269
|
+
export const DEFAULT_DISPLAY_CONFIG = {
|
|
270
|
+
colors: true,
|
|
271
|
+
timestamps: true,
|
|
272
|
+
prettyJson: true,
|
|
273
|
+
} as const;
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Default monitoring configuration values
|
|
277
|
+
*/
|
|
278
|
+
export const DEFAULT_MONITORING_CONFIG = {
|
|
279
|
+
blockTimeout: 5000,
|
|
280
|
+
maxReconnectAttempts: 5,
|
|
281
|
+
} as const;
|
|
282
|
+
|
|
283
|
+
/**
|
|
284
|
+
* Helper to create a default RedistailConfig with overrides
|
|
285
|
+
*/
|
|
286
|
+
export const createDefaultRedistailConfig = (
|
|
287
|
+
overrides?: Partial<RedistailConfig>,
|
|
288
|
+
): RedistailConfig =>
|
|
289
|
+
RedistailConfig({
|
|
290
|
+
redis: {
|
|
291
|
+
...DEFAULT_CLI_REDIS_CONFIG,
|
|
292
|
+
...overrides?.redis,
|
|
293
|
+
},
|
|
294
|
+
display: {
|
|
295
|
+
...DEFAULT_DISPLAY_CONFIG,
|
|
296
|
+
...overrides?.display,
|
|
297
|
+
},
|
|
298
|
+
monitoring: {
|
|
299
|
+
...DEFAULT_MONITORING_CONFIG,
|
|
300
|
+
...overrides?.monitoring,
|
|
301
|
+
},
|
|
302
|
+
});
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build version information
|
|
3
|
+
*
|
|
4
|
+
* This file is a template that gets replaced during the build process
|
|
5
|
+
* DO NOT EDIT MANUALLY
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// These values are replaced at build time by build-cli.js
|
|
9
|
+
export const BUILD_COMMIT: string = '72aad04';
|
|
10
|
+
export const BUILD_VERSION: string = '0.0.3';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get formatted version information for display
|
|
14
|
+
*/
|
|
15
|
+
export const getVersionInfo = () => ({
|
|
16
|
+
version: BUILD_VERSION,
|
|
17
|
+
commit: BUILD_COMMIT,
|
|
18
|
+
isDev: BUILD_VERSION === '__BUILD_VERSION__',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format version information as a string
|
|
23
|
+
*/
|
|
24
|
+
export const formatVersion = () => {
|
|
25
|
+
const info = getVersionInfo();
|
|
26
|
+
return `${info.version}${info.isDev ? ' (dev)' : ` (${info.commit})`}`;
|
|
27
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Build version information
|
|
3
|
+
*
|
|
4
|
+
* This file is a template that gets replaced during the build process
|
|
5
|
+
* DO NOT EDIT MANUALLY
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
// These values are replaced at build time by build-cli.js
|
|
9
|
+
export const BUILD_COMMIT: string = '__BUILD_COMMIT__';
|
|
10
|
+
export const BUILD_VERSION: string = '__BUILD_VERSION__';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Get formatted version information for display
|
|
14
|
+
*/
|
|
15
|
+
export const getVersionInfo = () => ({
|
|
16
|
+
version: BUILD_VERSION,
|
|
17
|
+
commit: BUILD_COMMIT,
|
|
18
|
+
isDev: BUILD_VERSION === '__BUILD_VERSION__',
|
|
19
|
+
});
|
|
20
|
+
|
|
21
|
+
/**
|
|
22
|
+
* Format version information as a string
|
|
23
|
+
*/
|
|
24
|
+
export const formatVersion = () => {
|
|
25
|
+
const info = getVersionInfo();
|
|
26
|
+
return `${info.version}${info.isDev ? ' (dev)' : ` (${info.commit})`}`;
|
|
27
|
+
};
|