@kadi.build/file-sharing 1.2.0 → 1.2.1
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/package.json +7 -3
- package/types/DownloadMonitor.d.ts +100 -0
- package/types/EventNotifier.d.ts +71 -0
- package/types/FileSharingServer.d.ts +229 -0
- package/types/HttpServerProvider.d.ts +152 -0
- package/types/MonitoringDashboard.d.ts +64 -0
- package/types/S3Server.d.ts +109 -0
- package/types/ShutdownManager.d.ts +51 -0
- package/types/index.d.ts +116 -0
package/package.json
CHANGED
|
@@ -1,18 +1,21 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@kadi.build/file-sharing",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.1",
|
|
4
4
|
"description": "File sharing service with tunneling and local S3-compatible interface",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "src/index.js",
|
|
7
|
+
"types": "types/index.d.ts",
|
|
7
8
|
"exports": {
|
|
8
9
|
".": {
|
|
9
|
-
"
|
|
10
|
-
"
|
|
10
|
+
"types": "./types/index.d.ts",
|
|
11
|
+
"import": "./src/index.js"
|
|
11
12
|
},
|
|
12
13
|
"./s3": {
|
|
14
|
+
"types": "./types/S3Server.d.ts",
|
|
13
15
|
"import": "./src/S3Server.js"
|
|
14
16
|
},
|
|
15
17
|
"./http": {
|
|
18
|
+
"types": "./types/HttpServerProvider.d.ts",
|
|
16
19
|
"import": "./src/HttpServerProvider.js"
|
|
17
20
|
}
|
|
18
21
|
},
|
|
@@ -52,6 +55,7 @@
|
|
|
52
55
|
},
|
|
53
56
|
"devDependencies": {
|
|
54
57
|
"@aws-sdk/client-s3": "^3.0.0",
|
|
58
|
+
"@types/node": "^20.19.33",
|
|
55
59
|
"supertest": "^6.0.0"
|
|
56
60
|
},
|
|
57
61
|
"engines": {
|
|
@@ -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;
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
import type { Server as HttpServer, IncomingMessage } from 'http';
|
|
4
|
+
|
|
5
|
+
export interface S3ServerConfig {
|
|
6
|
+
/** S3 server port (default: 9000) */
|
|
7
|
+
port?: number;
|
|
8
|
+
/** Bind host (default: '0.0.0.0') */
|
|
9
|
+
host?: string;
|
|
10
|
+
/** Root directory for object storage (default: process.cwd()) */
|
|
11
|
+
rootDir?: string;
|
|
12
|
+
/** S3 access key ID (default: 'minioadmin') */
|
|
13
|
+
accessKeyId?: string;
|
|
14
|
+
/** S3 secret access key (default: 'minioadmin') */
|
|
15
|
+
secretAccessKey?: string;
|
|
16
|
+
/** Default bucket name (default: 'local') */
|
|
17
|
+
bucketName?: string;
|
|
18
|
+
/** AWS region (default: 'us-east-1') */
|
|
19
|
+
region?: string;
|
|
20
|
+
/** Maximum file size in bytes (null = unlimited) */
|
|
21
|
+
maxFileSize?: number | null;
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
export interface S3StartResult {
|
|
25
|
+
port: number;
|
|
26
|
+
host: string;
|
|
27
|
+
endpoint: string;
|
|
28
|
+
serverId: string;
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
export interface S3BucketInfo {
|
|
32
|
+
name: string;
|
|
33
|
+
rootDir: string;
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
export interface S3ObjectEntry {
|
|
37
|
+
key: string;
|
|
38
|
+
size: number;
|
|
39
|
+
lastModified: string;
|
|
40
|
+
[key: string]: any;
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface S3AuthResult {
|
|
44
|
+
success: boolean;
|
|
45
|
+
user?: { accessKey: string };
|
|
46
|
+
error?: string;
|
|
47
|
+
}
|
|
48
|
+
|
|
49
|
+
export interface S3TemporaryCredentials {
|
|
50
|
+
accessKey: string;
|
|
51
|
+
secretKey: string;
|
|
52
|
+
expiresAt: string;
|
|
53
|
+
/** Backward-compat alias for expiresAt as Date */
|
|
54
|
+
expiry: Date;
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
export class S3Server extends EventEmitter {
|
|
58
|
+
constructor(config?: S3ServerConfig);
|
|
59
|
+
|
|
60
|
+
config: Required<S3ServerConfig>;
|
|
61
|
+
server: HttpServer | null;
|
|
62
|
+
isRunning: boolean;
|
|
63
|
+
multipartUploads: Map<string, any>;
|
|
64
|
+
requestCount: number;
|
|
65
|
+
|
|
66
|
+
/** Stable server identifier */
|
|
67
|
+
readonly serverId: string;
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Start the S3 server
|
|
71
|
+
*/
|
|
72
|
+
start(): Promise<S3StartResult>;
|
|
73
|
+
|
|
74
|
+
/**
|
|
75
|
+
* Stop the S3 server
|
|
76
|
+
*/
|
|
77
|
+
stop(): Promise<void>;
|
|
78
|
+
|
|
79
|
+
/**
|
|
80
|
+
* Get bucket configuration
|
|
81
|
+
*/
|
|
82
|
+
getBucket(): S3BucketInfo;
|
|
83
|
+
|
|
84
|
+
/**
|
|
85
|
+
* List objects in bucket (programmatic access)
|
|
86
|
+
* @param prefix - Optional prefix filter
|
|
87
|
+
*/
|
|
88
|
+
listObjects(prefix?: string): Promise<S3ObjectEntry[]>;
|
|
89
|
+
|
|
90
|
+
/**
|
|
91
|
+
* Validate an incoming request against the server's configured credentials.
|
|
92
|
+
* @param req - HTTP incoming request
|
|
93
|
+
*/
|
|
94
|
+
validateAuthentication(req: IncomingMessage): S3AuthResult;
|
|
95
|
+
|
|
96
|
+
/**
|
|
97
|
+
* Programmatically remove a bucket (force-deletes even non-empty directories).
|
|
98
|
+
* @param bucketName - The bucket/directory name to remove
|
|
99
|
+
*/
|
|
100
|
+
removeBucket(bucketName: string): Promise<void>;
|
|
101
|
+
|
|
102
|
+
/**
|
|
103
|
+
* Generate temporary S3 credentials with an expiry.
|
|
104
|
+
* @param opts - Options
|
|
105
|
+
*/
|
|
106
|
+
generateTemporaryCredentials(opts?: { ttl?: number }): S3TemporaryCredentials;
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
export default S3Server;
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
/// <reference types="node" />
|
|
2
|
+
import { EventEmitter } from 'events';
|
|
3
|
+
|
|
4
|
+
export interface ShutdownManagerConfig {
|
|
5
|
+
/** Timeout in ms for graceful shutdown (default: 30000) */
|
|
6
|
+
gracefulTimeout?: number;
|
|
7
|
+
/** Whether to wait for active downloads before shutting down (default: true) */
|
|
8
|
+
finishActiveDownloads?: boolean;
|
|
9
|
+
/** Timeout in ms before force kill (default: 60000) */
|
|
10
|
+
forceKillTimeout?: number;
|
|
11
|
+
}
|
|
12
|
+
|
|
13
|
+
export class ShutdownManager extends EventEmitter {
|
|
14
|
+
constructor(config?: ShutdownManagerConfig);
|
|
15
|
+
|
|
16
|
+
config: Required<ShutdownManagerConfig>;
|
|
17
|
+
isShuttingDown: boolean;
|
|
18
|
+
shutdownCallbacks: Array<{ callback: () => Promise<void>; priority: number }>;
|
|
19
|
+
|
|
20
|
+
/**
|
|
21
|
+
* Register a shutdown callback with priority.
|
|
22
|
+
* Lower priority numbers execute first.
|
|
23
|
+
* @param callback - Async callback to execute during shutdown
|
|
24
|
+
* @param priority - Execution priority (lower = earlier, default: 10)
|
|
25
|
+
*/
|
|
26
|
+
register(callback: () => Promise<void>, priority?: number): void;
|
|
27
|
+
|
|
28
|
+
/**
|
|
29
|
+
* Unregister a previously registered callback
|
|
30
|
+
* @param callback - The callback to remove
|
|
31
|
+
*/
|
|
32
|
+
unregister(callback: () => Promise<void>): void;
|
|
33
|
+
|
|
34
|
+
/**
|
|
35
|
+
* Install process signal handlers (SIGINT, SIGTERM)
|
|
36
|
+
*/
|
|
37
|
+
installSignalHandlers(): void;
|
|
38
|
+
|
|
39
|
+
/**
|
|
40
|
+
* Perform graceful shutdown.
|
|
41
|
+
* Executes all registered callbacks in priority order with timeout.
|
|
42
|
+
*/
|
|
43
|
+
shutdown(): Promise<void>;
|
|
44
|
+
|
|
45
|
+
/**
|
|
46
|
+
* Force shutdown - skip remaining callbacks
|
|
47
|
+
*/
|
|
48
|
+
forceShutdown(): Promise<void>;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export default ShutdownManager;
|
package/types/index.d.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @kadi.build/file-sharing - Type declarations
|
|
3
|
+
*
|
|
4
|
+
* File sharing service with tunneling and local S3-compatible interface.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import type { FileSharingServerConfig } from './FileSharingServer.js';
|
|
8
|
+
import type { FileSharingServer } from './FileSharingServer.js';
|
|
9
|
+
import type { HttpAuthConfig } from './HttpServerProvider.js';
|
|
10
|
+
|
|
11
|
+
// Core classes
|
|
12
|
+
export {
|
|
13
|
+
FileSharingServer,
|
|
14
|
+
FileSharingServerConfig,
|
|
15
|
+
TunnelConfig,
|
|
16
|
+
MonitoringConfig,
|
|
17
|
+
ShutdownConfig,
|
|
18
|
+
ServerInfo,
|
|
19
|
+
TunnelInfo,
|
|
20
|
+
FileEntry,
|
|
21
|
+
} from './FileSharingServer.js';
|
|
22
|
+
|
|
23
|
+
export {
|
|
24
|
+
HttpServerProvider,
|
|
25
|
+
HttpServerProviderConfig,
|
|
26
|
+
HttpAuthConfig,
|
|
27
|
+
SslConfig,
|
|
28
|
+
HttpStartResult,
|
|
29
|
+
MiddlewareInfo,
|
|
30
|
+
CustomRouteInfo,
|
|
31
|
+
} from './HttpServerProvider.js';
|
|
32
|
+
|
|
33
|
+
export {
|
|
34
|
+
S3Server,
|
|
35
|
+
S3ServerConfig,
|
|
36
|
+
S3StartResult,
|
|
37
|
+
S3BucketInfo,
|
|
38
|
+
S3ObjectEntry,
|
|
39
|
+
S3AuthResult,
|
|
40
|
+
S3TemporaryCredentials,
|
|
41
|
+
} from './S3Server.js';
|
|
42
|
+
|
|
43
|
+
export {
|
|
44
|
+
DownloadMonitor,
|
|
45
|
+
DownloadRecord,
|
|
46
|
+
DownloadMetadata,
|
|
47
|
+
DownloadStats,
|
|
48
|
+
} from './DownloadMonitor.js';
|
|
49
|
+
|
|
50
|
+
export {
|
|
51
|
+
ShutdownManager,
|
|
52
|
+
ShutdownManagerConfig,
|
|
53
|
+
} from './ShutdownManager.js';
|
|
54
|
+
|
|
55
|
+
export {
|
|
56
|
+
MonitoringDashboard,
|
|
57
|
+
MonitoringDashboardConfig,
|
|
58
|
+
DashboardStats,
|
|
59
|
+
DashboardServerInfo,
|
|
60
|
+
} from './MonitoringDashboard.js';
|
|
61
|
+
|
|
62
|
+
export {
|
|
63
|
+
EventNotifier,
|
|
64
|
+
EventNotifierConfig,
|
|
65
|
+
WebhookOptions,
|
|
66
|
+
WebhookInfo,
|
|
67
|
+
NotificationHistoryEntry,
|
|
68
|
+
} from './EventNotifier.js';
|
|
69
|
+
|
|
70
|
+
// Default export
|
|
71
|
+
export { FileSharingServer as default } from './FileSharingServer.js';
|
|
72
|
+
|
|
73
|
+
/**
|
|
74
|
+
* Create a FileSharingServer with default options
|
|
75
|
+
*/
|
|
76
|
+
export function createFileSharingServer(options?: FileSharingServerConfig): FileSharingServer;
|
|
77
|
+
|
|
78
|
+
export interface QuickShareOptions {
|
|
79
|
+
/** HTTP port (default: 3000) */
|
|
80
|
+
port?: number;
|
|
81
|
+
/** Enable tunnel (default: false) */
|
|
82
|
+
tunnel?: boolean;
|
|
83
|
+
/** Tunnel service name (default: 'kadi') */
|
|
84
|
+
tunnelService?: string;
|
|
85
|
+
/** KĀDI auth token */
|
|
86
|
+
kadiToken?: string;
|
|
87
|
+
/** Ngrok auth token */
|
|
88
|
+
ngrokAuthToken?: string;
|
|
89
|
+
/** HTTP auth config */
|
|
90
|
+
auth?: HttpAuthConfig | null;
|
|
91
|
+
/** Extra tunnel options */
|
|
92
|
+
tunnelOptions?: Record<string, any>;
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
export interface QuickShareResult {
|
|
96
|
+
server: FileSharingServer;
|
|
97
|
+
localUrl: string;
|
|
98
|
+
publicUrl?: string;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
/**
|
|
102
|
+
* Quick share - one-liner to share a directory
|
|
103
|
+
* @param directory - Directory to share
|
|
104
|
+
* @param options - Options
|
|
105
|
+
*/
|
|
106
|
+
export function createQuickShare(
|
|
107
|
+
directory: string,
|
|
108
|
+
options?: QuickShareOptions
|
|
109
|
+
): Promise<QuickShareResult>;
|
|
110
|
+
|
|
111
|
+
// Re-exports from dependencies (convenience)
|
|
112
|
+
// Note: These types come from the respective packages.
|
|
113
|
+
// If those packages don't have types, consumers should install them separately.
|
|
114
|
+
export declare const FileManager: any;
|
|
115
|
+
export declare const createFileManager: (...args: any[]) => any;
|
|
116
|
+
export declare const TunnelManager: any;
|