@kadi.build/file-sharing 1.2.0 → 1.3.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.
@@ -0,0 +1,100 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+
4
+ export interface DownloadRecord {
5
+ id: string;
6
+ file: string;
7
+ totalSize: number;
8
+ clientIp: string;
9
+ bytesTransferred: number;
10
+ progress: number;
11
+ speed: number;
12
+ startTime: number;
13
+ endTime?: number;
14
+ duration?: number;
15
+ status: 'active' | 'completed' | 'failed' | 'cancelled';
16
+ error?: string;
17
+ [key: string]: any;
18
+ }
19
+
20
+ export interface DownloadMetadata {
21
+ file?: string;
22
+ totalSize?: number;
23
+ size?: number;
24
+ clientIp?: string;
25
+ [key: string]: any;
26
+ }
27
+
28
+ export interface DownloadStats {
29
+ totalBytes: number;
30
+ totalDownloads: number;
31
+ activeCount: number;
32
+ failedCount: number;
33
+ averageSpeed: number;
34
+ peakConcurrent: number;
35
+ activeDownloads: DownloadRecord[];
36
+ }
37
+
38
+ export class DownloadMonitor extends EventEmitter {
39
+ constructor();
40
+
41
+ activeDownloads: Map<string, DownloadRecord>;
42
+ completedDownloads: DownloadRecord[];
43
+ stats: Omit<DownloadStats, 'activeDownloads'>;
44
+
45
+ /**
46
+ * Register a new download being tracked
47
+ * @param id - Unique download identifier
48
+ * @param metadata - Download metadata
49
+ */
50
+ startDownload(id: string, metadata?: DownloadMetadata): DownloadRecord;
51
+
52
+ /**
53
+ * Update download progress
54
+ * @param id - Download identifier
55
+ * @param bytesTransferred - Bytes transferred so far
56
+ */
57
+ updateProgress(id: string, bytesTransferred: number): void;
58
+
59
+ /**
60
+ * Mark a download as completed
61
+ * @param id - Download identifier
62
+ */
63
+ completeDownload(id: string): void;
64
+
65
+ /**
66
+ * Mark a download as failed
67
+ * @param id - Download identifier
68
+ * @param error - The error that caused the failure
69
+ */
70
+ failDownload(id: string, error: Error): void;
71
+
72
+ /**
73
+ * Cancel an active download
74
+ * @param id - Download identifier
75
+ */
76
+ cancelDownload(id: string): void;
77
+
78
+ /**
79
+ * Get current download statistics
80
+ */
81
+ getStats(): DownloadStats;
82
+
83
+ /**
84
+ * Get all active downloads
85
+ */
86
+ getActiveDownloads(): DownloadRecord[];
87
+
88
+ /**
89
+ * Get completed downloads
90
+ * @param limit - Max number of records to return (default: 100)
91
+ */
92
+ getCompletedDownloads(limit?: number): DownloadRecord[];
93
+
94
+ /**
95
+ * Clear completed download history
96
+ */
97
+ clearHistory(): void;
98
+ }
99
+
100
+ export default DownloadMonitor;
@@ -0,0 +1,71 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+
4
+ export interface EventNotifierConfig {
5
+ /** Maximum number of retry attempts for failed notifications (default: 3) */
6
+ maxRetries?: number;
7
+ /** Delay in ms between retries (default: 1000) */
8
+ retryDelay?: number;
9
+ /** Request timeout in ms (default: 5000) */
10
+ timeout?: number;
11
+ }
12
+
13
+ export interface WebhookOptions {
14
+ /** Custom HTTP headers to send with notifications */
15
+ headers?: Record<string, string>;
16
+ }
17
+
18
+ export interface WebhookInfo {
19
+ url: string;
20
+ events: string[];
21
+ active: boolean;
22
+ failCount: number;
23
+ lastNotified: string | null;
24
+ }
25
+
26
+ export interface NotificationHistoryEntry {
27
+ event: string;
28
+ timestamp: string;
29
+ recipientCount: number;
30
+ }
31
+
32
+ export class EventNotifier extends EventEmitter {
33
+ constructor(config?: EventNotifierConfig);
34
+
35
+ config: Required<EventNotifierConfig>;
36
+ webhooks: Map<string, any>;
37
+
38
+ /**
39
+ * Register a webhook for event notifications
40
+ * @param url - Webhook URL to send notifications to
41
+ * @param events - Array of event names to subscribe to (empty = all events)
42
+ * @param options - Additional options (headers, etc.)
43
+ */
44
+ addWebhook(url: string, events?: string[], options?: WebhookOptions): void;
45
+
46
+ /**
47
+ * Remove a registered webhook
48
+ * @param url - Webhook URL to remove
49
+ */
50
+ removeWebhook(url: string): void;
51
+
52
+ /**
53
+ * Send a notification for an event
54
+ * @param event - Event name
55
+ * @param data - Event data payload
56
+ */
57
+ notify(event: string, data?: Record<string, any>): Promise<void>;
58
+
59
+ /**
60
+ * Get list of registered webhooks
61
+ */
62
+ getWebhooks(): WebhookInfo[];
63
+
64
+ /**
65
+ * Get notification history
66
+ * @param limit - Max records to return (default: 50)
67
+ */
68
+ getHistory(limit?: number): NotificationHistoryEntry[];
69
+ }
70
+
71
+ export default EventNotifier;
@@ -0,0 +1,229 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import type { HttpServerProvider, HttpAuthConfig } from './HttpServerProvider.js';
4
+ import type { S3Server } from './S3Server.js';
5
+ import type { DownloadMonitor, DownloadStats } from './DownloadMonitor.js';
6
+ import type { ShutdownManager } from './ShutdownManager.js';
7
+ import type { MonitoringDashboard } from './MonitoringDashboard.js';
8
+ import type { EventNotifier } from './EventNotifier.js';
9
+
10
+ export interface TunnelConfig {
11
+ /** Enable tunneling (default: false) */
12
+ enabled?: boolean;
13
+ /** Tunnel service to use (default: 'kadi') */
14
+ service?: string;
15
+ /** Extra service-specific options */
16
+ options?: Record<string, any>;
17
+ /** Auto-reconnect on failure (default: true) */
18
+ autoReconnect?: boolean;
19
+ /** Reconnect delay in ms (default: 5000) */
20
+ reconnectDelay?: number;
21
+ /** Auto-fallback to other services */
22
+ autoFallback?: boolean;
23
+ /** KĀDI tunnel auth token */
24
+ kadiToken?: string;
25
+ /** KĀDI broker server address */
26
+ kadiServer?: string;
27
+ /** KĀDI tunnel domain */
28
+ kadiDomain?: string;
29
+ /** KĀDI frpc port */
30
+ kadiPort?: number;
31
+ /** KĀDI SSH gateway port */
32
+ kadiSshPort?: number;
33
+ /** KĀDI tunnel mode ('ssh' | 'frpc' | 'auto') */
34
+ kadiMode?: string;
35
+ /** KĀDI agent identifier */
36
+ kadiAgentId?: string;
37
+ /** KĀDI transport ('wss' | 'tcp') */
38
+ kadiTransport?: string;
39
+ /** KĀDI WSS gateway hostname */
40
+ kadiWssControlHost?: string;
41
+ /** Ngrok auth token */
42
+ ngrokAuthToken?: string;
43
+ /** Override for TunnelManager options */
44
+ managerOptions?: Record<string, any>;
45
+ /** Port to tunnel (defaults to s3Port if running, else httpPort) */
46
+ port?: number;
47
+ }
48
+
49
+ export interface MonitoringConfig {
50
+ /** Enable monitoring (default: true) */
51
+ enabled?: boolean;
52
+ /** Enable console dashboard (default: false) */
53
+ dashboard?: boolean;
54
+ /** Webhook configurations */
55
+ webhooks?: Array<{
56
+ url: string;
57
+ events?: string[];
58
+ options?: Record<string, any>;
59
+ }>;
60
+ }
61
+
62
+ export interface ShutdownConfig {
63
+ /** Timeout in ms for graceful shutdown (default: 30000) */
64
+ gracefulTimeout?: number;
65
+ /** Whether to finish active downloads (default: true) */
66
+ finishActiveDownloads?: boolean;
67
+ /** Timeout in ms before force kill (default: 60000) */
68
+ forceKillTimeout?: number;
69
+ }
70
+
71
+ export interface FileSharingServerConfig {
72
+ /** Directory to serve files from (default: process.cwd()) */
73
+ staticDir?: string;
74
+ /** HTTP port (default: 3000) */
75
+ port?: number;
76
+ /** Bind host (default: '0.0.0.0') */
77
+ host?: string;
78
+ /** Enable local S3-compatible API (default: false) */
79
+ enableS3?: boolean;
80
+ /** S3 server port (default: 9000) */
81
+ s3Port?: number;
82
+ /** S3 server config overrides */
83
+ s3Config?: Record<string, any>;
84
+ /** Enable directory listing (default: true) */
85
+ enableDirectoryListing?: boolean;
86
+ /** Enable CORS (default: true) */
87
+ cors?: boolean;
88
+ /** HTTP authentication config */
89
+ auth?: HttpAuthConfig | null;
90
+ /** Tunnel configuration */
91
+ tunnel?: TunnelConfig;
92
+ /** Monitoring configuration */
93
+ monitoring?: MonitoringConfig;
94
+ /** Shutdown configuration */
95
+ shutdown?: ShutdownConfig;
96
+ /** Additional HTTP server config overrides */
97
+ httpConfig?: Record<string, any>;
98
+ }
99
+
100
+ export interface ServerInfo {
101
+ isRunning: boolean;
102
+ localUrl: string;
103
+ publicUrl: string | null;
104
+ s3Endpoint: string | null;
105
+ staticDir: string;
106
+ stats: DownloadStats;
107
+ uptime: number;
108
+ tunnelStatus: TunnelInfo | null;
109
+ }
110
+
111
+ export interface TunnelInfo {
112
+ id: string;
113
+ publicUrl: string;
114
+ [key: string]: any;
115
+ }
116
+
117
+ export interface FileEntry {
118
+ name: string;
119
+ type: 'file' | 'directory';
120
+ size: number;
121
+ modified: string;
122
+ }
123
+
124
+ export class FileSharingServer extends EventEmitter {
125
+ constructor(config?: FileSharingServerConfig);
126
+
127
+ config: FileSharingServerConfig & {
128
+ staticDir: string;
129
+ port: number;
130
+ host: string;
131
+ enableS3: boolean;
132
+ s3Port: number;
133
+ tunnel: Required<Pick<TunnelConfig, 'enabled' | 'service' | 'options' | 'autoReconnect' | 'reconnectDelay'>> & TunnelConfig;
134
+ };
135
+
136
+ /** The file manager instance */
137
+ fileManager: any;
138
+ /** The HTTP server provider instance */
139
+ httpServer: HttpServerProvider;
140
+ /** The S3 server instance (null if S3 disabled) */
141
+ s3Server: S3Server | null;
142
+ /** The tunnel manager instance */
143
+ tunnelManager: any;
144
+ /** The download monitor instance */
145
+ downloadMonitor: DownloadMonitor;
146
+ /** The shutdown manager instance */
147
+ shutdownManager: ShutdownManager;
148
+ /** The monitoring dashboard instance */
149
+ monitoringDashboard: MonitoringDashboard;
150
+ /** The event notifier instance */
151
+ eventNotifier: EventNotifier;
152
+ /** Whether the server is running */
153
+ isRunning: boolean;
154
+ /** Active tunnel info (null if no tunnel active) */
155
+ tunnel: TunnelInfo | null;
156
+
157
+ /** HTTP port */
158
+ readonly port: number;
159
+ /** Public tunnel URL (null if no tunnel) */
160
+ readonly tunnelUrl: string | null;
161
+ /** S3 endpoint URL (null if S3 not running) */
162
+ readonly s3Endpoint: string | null;
163
+ /** Served directory */
164
+ readonly staticDir: string;
165
+
166
+ /**
167
+ * Start the file sharing server
168
+ */
169
+ start(): Promise<ServerInfo>;
170
+
171
+ /**
172
+ * Stop the file sharing server.
173
+ * Gracefully shuts down all components.
174
+ */
175
+ stop(): Promise<void>;
176
+
177
+ /**
178
+ * Enable tunnel to expose server publicly
179
+ * @param options - Tunnel options
180
+ */
181
+ enableTunnel(options?: TunnelConfig): Promise<TunnelInfo>;
182
+
183
+ /**
184
+ * Disable active tunnel
185
+ */
186
+ disableTunnel(): Promise<void>;
187
+
188
+ /**
189
+ * Enable S3-compatible API dynamically
190
+ * @param options - S3 server options
191
+ */
192
+ enableS3(options?: Record<string, any>): Promise<{ port: number; endpoint: string }>;
193
+
194
+ /**
195
+ * Disable S3 API
196
+ */
197
+ disableS3(): Promise<void>;
198
+
199
+ /**
200
+ * Get current server information and statistics
201
+ */
202
+ getInfo(): ServerInfo;
203
+
204
+ /**
205
+ * Get download statistics
206
+ */
207
+ getStats(): DownloadStats;
208
+
209
+ /**
210
+ * List files in the served directory
211
+ * @param subPath - Optional subdirectory path
212
+ */
213
+ listFiles(subPath?: string): Promise<FileEntry[]>;
214
+
215
+ /**
216
+ * Add a webhook for event notifications
217
+ * @param url - Webhook URL
218
+ * @param events - Events to subscribe to
219
+ */
220
+ addWebhook(url: string, events?: string[]): void;
221
+
222
+ /**
223
+ * Remove a webhook
224
+ * @param url - Webhook URL to remove
225
+ */
226
+ removeWebhook(url: string): void;
227
+ }
228
+
229
+ export default FileSharingServer;
@@ -0,0 +1,152 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+ import type { Server as HttpServer, IncomingMessage, ServerResponse } from 'http';
4
+
5
+ export interface HttpAuthConfig {
6
+ /** API key for Bearer / X-API-Key authentication */
7
+ apiKey?: string;
8
+ /** Bearer token for Authorization header */
9
+ bearerToken?: string;
10
+ /** Username for HTTP Basic auth */
11
+ username?: string;
12
+ /** Password for HTTP Basic auth */
13
+ password?: string;
14
+ }
15
+
16
+ export interface SslConfig {
17
+ key: string | Buffer;
18
+ cert: string | Buffer;
19
+ ca?: string | Buffer;
20
+ }
21
+
22
+ export interface HttpServerProviderConfig {
23
+ /** HTTP port (default: 3000) */
24
+ port?: number;
25
+ /** Bind host (default: '0.0.0.0') */
26
+ host?: string;
27
+ /** Directory to serve files from (default: process.cwd()) */
28
+ staticDir?: string;
29
+ /** Whether to show directory listing (default: true) */
30
+ enableDirectoryListing?: boolean;
31
+ /** Enable CORS (default: true) */
32
+ cors?: boolean;
33
+ /** Authentication configuration */
34
+ auth?: HttpAuthConfig | null;
35
+ /** SSL/TLS configuration */
36
+ ssl?: SslConfig | null;
37
+ /** Maximum file size in bytes (null = unlimited) */
38
+ maxFileSize?: number | null;
39
+ /** Directory for uploads (null = same as staticDir) */
40
+ uploadDir?: string | null;
41
+ }
42
+
43
+ export interface HttpStartResult {
44
+ port: number;
45
+ host: string;
46
+ url: string;
47
+ already?: boolean;
48
+ }
49
+
50
+ export interface MiddlewareInfo {
51
+ name: string;
52
+ priority: number;
53
+ }
54
+
55
+ export interface CustomRouteInfo {
56
+ method: string;
57
+ path: string;
58
+ priority: number;
59
+ }
60
+
61
+ type MiddlewareHandler = (
62
+ req: IncomingMessage,
63
+ res: ServerResponse,
64
+ next: (err?: Error) => void
65
+ ) => void | Promise<void>;
66
+
67
+ type RouteHandler = (req: IncomingMessage & { params?: Record<string, string> }, res: ServerResponse) => void | Promise<void>;
68
+
69
+ export class HttpServerProvider extends EventEmitter {
70
+ constructor(config?: HttpServerProviderConfig);
71
+
72
+ config: Required<HttpServerProviderConfig>;
73
+ server: HttpServer | null;
74
+ isRunning: boolean;
75
+ activeConnections: Map<string, any>;
76
+ startTime: Date | null;
77
+ requestCount: number;
78
+ errorCount: number;
79
+
80
+ /**
81
+ * Start the HTTP server
82
+ */
83
+ start(): Promise<HttpStartResult>;
84
+
85
+ /**
86
+ * Stop the HTTP server
87
+ */
88
+ stop(): Promise<void>;
89
+
90
+ /**
91
+ * Get active connection count
92
+ */
93
+ getActiveConnections(): number;
94
+
95
+ /**
96
+ * Force close all active connections
97
+ */
98
+ closeAllConnections(): void;
99
+
100
+ /**
101
+ * Register a named middleware function into the request pipeline.
102
+ * Middleware runs BEFORE built-in auth and static-file handling.
103
+ * @param name - Unique middleware identifier
104
+ * @param handler - Middleware handler function
105
+ * @param opts - Options
106
+ */
107
+ addMiddleware(
108
+ name: string,
109
+ handler: MiddlewareHandler,
110
+ opts?: { priority?: number }
111
+ ): void;
112
+
113
+ /**
114
+ * Remove a named middleware.
115
+ * @param name - Middleware identifier to remove
116
+ */
117
+ removeMiddleware(name: string): boolean;
118
+
119
+ /**
120
+ * Get the list of registered middleware names (in execution order).
121
+ */
122
+ getMiddleware(): MiddlewareInfo[];
123
+
124
+ /**
125
+ * Register a custom route handler.
126
+ * Custom routes are matched BEFORE built-in static-file/upload handling.
127
+ * @param method - HTTP method ('GET', 'POST', etc.)
128
+ * @param urlPath - URL path or Express-style pattern
129
+ * @param handler - Route handler
130
+ * @param opts - Options
131
+ */
132
+ addCustomRoute(
133
+ method: string,
134
+ urlPath: string,
135
+ handler: RouteHandler,
136
+ opts?: { priority?: number }
137
+ ): void;
138
+
139
+ /**
140
+ * Remove a custom route.
141
+ * @param method - HTTP method
142
+ * @param urlPath - URL path pattern
143
+ */
144
+ removeCustomRoute(method: string, urlPath: string): boolean;
145
+
146
+ /**
147
+ * Get the list of registered custom routes.
148
+ */
149
+ getCustomRoutes(): CustomRouteInfo[];
150
+ }
151
+
152
+ export default HttpServerProvider;
@@ -0,0 +1,64 @@
1
+ /// <reference types="node" />
2
+ import { EventEmitter } from 'events';
3
+
4
+ export interface MonitoringDashboardConfig {
5
+ /** Refresh interval in ms (default: 1000) */
6
+ refreshInterval?: number;
7
+ /** Whether to show progress bars in output (default: true) */
8
+ showProgressBars?: boolean;
9
+ /** Max number of active downloads to display (default: 10) */
10
+ maxDisplayItems?: number;
11
+ }
12
+
13
+ export interface DashboardStats {
14
+ totalBytes: number;
15
+ totalDownloads: number;
16
+ activeCount: number;
17
+ activeDownloads: Array<{
18
+ id?: string;
19
+ file?: string;
20
+ progress?: number;
21
+ [key: string]: any;
22
+ }>;
23
+ averageSpeed: number;
24
+ peakConcurrent: number;
25
+ uptime: number;
26
+ }
27
+
28
+ export interface DashboardServerInfo {
29
+ localUrl?: string;
30
+ publicUrl?: string;
31
+ s3Endpoint?: string;
32
+ [key: string]: any;
33
+ }
34
+
35
+ export class MonitoringDashboard extends EventEmitter {
36
+ constructor(config?: MonitoringDashboardConfig);
37
+
38
+ config: Required<MonitoringDashboardConfig>;
39
+ isRunning: boolean;
40
+
41
+ /**
42
+ * Start the monitoring dashboard
43
+ */
44
+ start(): Promise<{ running: boolean }>;
45
+
46
+ /**
47
+ * Stop the monitoring dashboard
48
+ */
49
+ stop(): Promise<void>;
50
+
51
+ /**
52
+ * Update dashboard statistics
53
+ * @param stats - New stats to display
54
+ */
55
+ updateStats(stats: Partial<DashboardStats>): void;
56
+
57
+ /**
58
+ * Set server information
59
+ * @param info - Server info (localUrl, publicUrl, etc.)
60
+ */
61
+ setServerInfo(info: DashboardServerInfo): void;
62
+ }
63
+
64
+ export default MonitoringDashboard;