@frp-bridge/core 0.0.1 → 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/index.d.mts +946 -47
- package/dist/index.d.ts +946 -47
- package/dist/index.mjs +8 -5
- package/package.json +7 -6
package/dist/index.d.mts
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { ClientConfig, ServerConfig,
|
|
1
|
+
import { NodeRegisterPayload, NodeHeartbeatPayload, NodeInfo as NodeInfo$1, NodeListQuery, NodeListResponse, NodeStatistics, TunnelSyncPayload, ProxyConfig, ClientConfig, ServerConfig, RpcRequest as RpcRequest$1 } from '@frp-bridge/types';
|
|
2
|
+
import { EventEmitter } from 'node:events';
|
|
2
3
|
|
|
3
4
|
type Awaitable<T> = T | Promise<T>;
|
|
4
5
|
type RuntimeMode = 'client' | 'server';
|
|
@@ -62,7 +63,7 @@ interface RuntimeError {
|
|
|
62
63
|
message: string;
|
|
63
64
|
details?: Record<string, unknown>;
|
|
64
65
|
}
|
|
65
|
-
type RuntimeErrorCode = 'VALIDATION_ERROR' | 'RUNTIME_ERROR' | 'SYSTEM_ERROR';
|
|
66
|
+
type RuntimeErrorCode = 'VALIDATION_ERROR' | 'RUNTIME_ERROR' | 'SYSTEM_ERROR' | 'PORT_CONFLICT' | 'RPC_NOT_AVAILABLE' | 'RPC_ERROR';
|
|
66
67
|
interface ConfigSnapshot {
|
|
67
68
|
version: number;
|
|
68
69
|
checksum: string;
|
|
@@ -113,13 +114,223 @@ declare class FrpRuntime {
|
|
|
113
114
|
private now;
|
|
114
115
|
}
|
|
115
116
|
|
|
117
|
+
/**
|
|
118
|
+
* Client-side node information collector
|
|
119
|
+
* Gathers system information and reports to server via heartbeat
|
|
120
|
+
*/
|
|
121
|
+
|
|
122
|
+
interface ClientCollectorOptions {
|
|
123
|
+
/** Node ID (set by server after registration) */
|
|
124
|
+
nodeId?: string;
|
|
125
|
+
/** Heartbeat interval in milliseconds (default: 30000) */
|
|
126
|
+
heartbeatInterval?: number;
|
|
127
|
+
/** Logger instance */
|
|
128
|
+
logger?: {
|
|
129
|
+
debug?: (msg: string, data?: unknown) => void;
|
|
130
|
+
info?: (msg: string, data?: unknown) => void;
|
|
131
|
+
error?: (msg: string, error?: unknown) => void;
|
|
132
|
+
};
|
|
133
|
+
}
|
|
134
|
+
/**
|
|
135
|
+
* Collects node information on client side
|
|
136
|
+
* Used in client mode to send system info and heartbeat to server
|
|
137
|
+
*/
|
|
138
|
+
declare class ClientNodeCollector {
|
|
139
|
+
private nodeId?;
|
|
140
|
+
private heartbeatInterval;
|
|
141
|
+
private logger;
|
|
142
|
+
private heartbeatTimer?;
|
|
143
|
+
constructor(options?: ClientCollectorOptions);
|
|
144
|
+
/** Set node ID after server registration */
|
|
145
|
+
setNodeId(nodeId: string): void;
|
|
146
|
+
/** Collect current node information */
|
|
147
|
+
collectNodeInfo(): Partial<NodeRegisterPayload>;
|
|
148
|
+
/** Collect heartbeat payload */
|
|
149
|
+
collectHeartbeat(): Partial<NodeHeartbeatPayload>;
|
|
150
|
+
/**
|
|
151
|
+
* Start periodic heartbeat collection
|
|
152
|
+
* Callback will be called at each interval with heartbeat payload
|
|
153
|
+
*/
|
|
154
|
+
startHeartbeat(callback: (payload: Partial<NodeHeartbeatPayload>) => void, interval?: number): void;
|
|
155
|
+
/** Stop periodic heartbeat collection */
|
|
156
|
+
stopHeartbeat(): void;
|
|
157
|
+
/** Check if heartbeat is running */
|
|
158
|
+
isHeartbeatRunning(): boolean;
|
|
159
|
+
}
|
|
160
|
+
|
|
161
|
+
/**
|
|
162
|
+
* Node Manager for server-side node management
|
|
163
|
+
* Handles node registration, heartbeat, tunnel registry, and queries
|
|
164
|
+
*/
|
|
165
|
+
|
|
166
|
+
interface NodeManagerOptions {
|
|
167
|
+
heartbeatTimeout?: number;
|
|
168
|
+
logger?: Partial<RuntimeLogger>;
|
|
169
|
+
}
|
|
170
|
+
interface NodeStorage {
|
|
171
|
+
save: (node: NodeInfo$1) => Promise<void> | void;
|
|
172
|
+
delete: (id: string) => Promise<void> | void;
|
|
173
|
+
load: (id: string) => Promise<NodeInfo$1 | undefined> | NodeInfo$1 | undefined;
|
|
174
|
+
list: () => Promise<NodeInfo$1[]> | NodeInfo$1[];
|
|
175
|
+
}
|
|
176
|
+
type NodeEvent = 'node:registered' | 'node:heartbeat' | 'node:unregistered' | 'node:statusChanged' | 'tunnel:synced';
|
|
177
|
+
/**
|
|
178
|
+
* Manages nodes in server mode
|
|
179
|
+
* Stores node info, handles heartbeat, manages global tunnel registry, emits events
|
|
180
|
+
*/
|
|
181
|
+
declare class NodeManager extends EventEmitter {
|
|
182
|
+
private context;
|
|
183
|
+
private nodes;
|
|
184
|
+
private heartbeatTimers;
|
|
185
|
+
private tunnelRegistry;
|
|
186
|
+
private storage?;
|
|
187
|
+
private heartbeatTimeout;
|
|
188
|
+
private readonly log;
|
|
189
|
+
constructor(context: RuntimeContext, options?: NodeManagerOptions, storage?: NodeStorage);
|
|
190
|
+
initialize(): Promise<void>;
|
|
191
|
+
/** Register a new node (called when client connects) */
|
|
192
|
+
registerNode(payload: NodeRegisterPayload): Promise<NodeInfo$1>;
|
|
193
|
+
/** Update node heartbeat and status */
|
|
194
|
+
updateHeartbeat(payload: NodeHeartbeatPayload): Promise<void>;
|
|
195
|
+
/** Unregister a node (called when client disconnects) */
|
|
196
|
+
unregisterNode(nodeId: string): Promise<void>;
|
|
197
|
+
/** Get node by id */
|
|
198
|
+
getNode(id: string): Promise<NodeInfo$1 | undefined>;
|
|
199
|
+
/** List nodes with pagination and filtering */
|
|
200
|
+
listNodes(query?: NodeListQuery): Promise<NodeListResponse>;
|
|
201
|
+
/** Get node statistics */
|
|
202
|
+
getStatistics(): Promise<NodeStatistics>;
|
|
203
|
+
/** Check if node exists */
|
|
204
|
+
hasNode(id: string): boolean;
|
|
205
|
+
/** Get all online nodes */
|
|
206
|
+
getOnlineNodes(): NodeInfo$1[];
|
|
207
|
+
/** Get all offline nodes */
|
|
208
|
+
getOfflineNodes(): NodeInfo$1[];
|
|
209
|
+
/** Get nodes by status */
|
|
210
|
+
getNodesByStatus(status: NodeInfo$1['status']): NodeInfo$1[];
|
|
211
|
+
/** Setup heartbeat timer for a node */
|
|
212
|
+
private setupHeartbeatTimer;
|
|
213
|
+
/** Clear heartbeat timer for a node */
|
|
214
|
+
private clearHeartbeatTimer;
|
|
215
|
+
/** Handle heartbeat timeout */
|
|
216
|
+
private handleHeartbeatTimeout;
|
|
217
|
+
/** Sync tunnels for a node (called when node connects or updates tunnels) */
|
|
218
|
+
syncTunnels(payload: TunnelSyncPayload): Promise<void>;
|
|
219
|
+
/** Get tunnels for a specific node */
|
|
220
|
+
getNodeTunnels(nodeId: string): ProxyConfig[];
|
|
221
|
+
/** Get all tunnels across all nodes */
|
|
222
|
+
getAllTunnels(): Map<string, ProxyConfig[]>;
|
|
223
|
+
/** Check if a remotePort is in use across all nodes (for conflict detection) */
|
|
224
|
+
isRemotePortInUse(remotePort: number, excludeNodeId?: string): {
|
|
225
|
+
inUse: boolean;
|
|
226
|
+
nodeId?: string;
|
|
227
|
+
tunnelName?: string;
|
|
228
|
+
};
|
|
229
|
+
/** Clear tunnels for a node (called when node disconnects) */
|
|
230
|
+
private clearNodeTunnels;
|
|
231
|
+
/** Update dispose method to clear tunnels */
|
|
232
|
+
dispose(): Promise<void>;
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* File-based node storage implementation
|
|
237
|
+
* Persists node information to disk
|
|
238
|
+
*/
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* Stores nodes in JSON files
|
|
242
|
+
* Directory structure:
|
|
243
|
+
* ~/.frp-bridge/runtime/nodes/
|
|
244
|
+
* ├── nodes.json (index of all nodes)
|
|
245
|
+
* └── node-{id}.json (individual node data)
|
|
246
|
+
*/
|
|
247
|
+
declare class FileNodeStorage implements NodeStorage {
|
|
248
|
+
private storagePath;
|
|
249
|
+
private indexPath;
|
|
250
|
+
private nodeDir;
|
|
251
|
+
constructor(storagePath: string);
|
|
252
|
+
/** Save or update a node */
|
|
253
|
+
save(node: NodeInfo$1): Promise<void>;
|
|
254
|
+
/** Delete a node */
|
|
255
|
+
delete(id: string): Promise<void>;
|
|
256
|
+
/** Load a single node */
|
|
257
|
+
load(id: string): Promise<NodeInfo$1 | undefined>;
|
|
258
|
+
/** Load all nodes */
|
|
259
|
+
list(): Promise<NodeInfo$1[]>;
|
|
260
|
+
/** Update the index of node IDs */
|
|
261
|
+
private updateIndex;
|
|
262
|
+
}
|
|
263
|
+
|
|
264
|
+
/**
|
|
265
|
+
* 配置合并方法 - core 包内部使用
|
|
266
|
+
* 将预设配置和用户配置合并成最终的 frp 配置
|
|
267
|
+
*/
|
|
268
|
+
|
|
269
|
+
/**
|
|
270
|
+
* 预设配置接口
|
|
271
|
+
*/
|
|
272
|
+
interface PresetConfig {
|
|
273
|
+
frps?: FrpsPresetConfig;
|
|
274
|
+
frpc?: FrpcPresetConfig;
|
|
275
|
+
}
|
|
276
|
+
interface FrpsPresetConfig {
|
|
277
|
+
bindPort?: number;
|
|
278
|
+
vhostHTTPPort?: number;
|
|
279
|
+
vhostHTTPSPort?: number;
|
|
280
|
+
domain?: string;
|
|
281
|
+
dashboardPort?: number;
|
|
282
|
+
dashboardUser?: string;
|
|
283
|
+
dashboardPassword?: string;
|
|
284
|
+
authToken?: string;
|
|
285
|
+
subdomainHost?: string;
|
|
286
|
+
}
|
|
287
|
+
interface FrpcPresetConfig {
|
|
288
|
+
serverAddr?: string;
|
|
289
|
+
serverPort?: number;
|
|
290
|
+
authToken?: string;
|
|
291
|
+
user?: string;
|
|
292
|
+
heartbeatInterval?: number;
|
|
293
|
+
}
|
|
294
|
+
/**
|
|
295
|
+
* 默认预设配置
|
|
296
|
+
*/
|
|
297
|
+
declare const DEFAULT_PRESET_CONFIG: PresetConfig;
|
|
298
|
+
/**
|
|
299
|
+
* 合并预设配置和用户配置,生成最终的 TOML 配置
|
|
300
|
+
*/
|
|
301
|
+
declare function mergeConfigs(presetConfig: PresetConfig, userConfig: string, type: 'frps' | 'frpc'): string;
|
|
302
|
+
/**
|
|
303
|
+
* 从 tunnels 数组生成并保存 FRP 配置文件
|
|
304
|
+
*/
|
|
305
|
+
declare function saveFrpConfigFile(configPath: string, tunnels: ProxyConfig[], presetConfig: PresetConfig, type: 'frps' | 'frpc'): void;
|
|
306
|
+
/**
|
|
307
|
+
* 将配置对象转换为 TOML 格式
|
|
308
|
+
*/
|
|
309
|
+
declare function configToToml(config: Record<string, any>): string;
|
|
310
|
+
/**
|
|
311
|
+
* 验证预设配置
|
|
312
|
+
*/
|
|
313
|
+
declare function validatePresetConfig(config: PresetConfig, type: 'frps' | 'frpc'): {
|
|
314
|
+
valid: boolean;
|
|
315
|
+
errors: string[];
|
|
316
|
+
};
|
|
317
|
+
|
|
116
318
|
/**
|
|
117
319
|
* FRP process management utilities
|
|
320
|
+
*
|
|
321
|
+
* This class serves as a facade that delegates to specialized components:
|
|
322
|
+
* - ProcessController: Process lifecycle management
|
|
323
|
+
* - ConfigurationStore: Configuration file operations
|
|
324
|
+
* - TunnelManager: Tunnel/proxy management
|
|
325
|
+
* - NodeManager: Node information management
|
|
326
|
+
* - BinaryManager: Binary file management
|
|
118
327
|
*/
|
|
119
328
|
|
|
120
329
|
interface FrpProcessManagerOptions {
|
|
121
330
|
/** Working directory for FRP files */
|
|
122
331
|
workDir?: string;
|
|
332
|
+
/** Path to config file (overrides default) */
|
|
333
|
+
configPath?: string;
|
|
123
334
|
/** FRP version (defaults to latest) */
|
|
124
335
|
version?: string;
|
|
125
336
|
/** Mode: client or server */
|
|
@@ -143,16 +354,29 @@ interface NodeInfo {
|
|
|
143
354
|
}
|
|
144
355
|
/**
|
|
145
356
|
* Manages FRP client/server lifecycle, config, and tunnels
|
|
357
|
+
*
|
|
358
|
+
* This class now serves as a facade that delegates to specialized components:
|
|
359
|
+
* - ProcessController: Process lifecycle management
|
|
360
|
+
* - ConfigurationStore: Configuration file operations
|
|
361
|
+
* - TunnelManager: Tunnel/proxy management
|
|
362
|
+
* - NodeManager: Node information management
|
|
363
|
+
* - BinaryManager: Binary file management
|
|
146
364
|
*/
|
|
147
|
-
declare class FrpProcessManager {
|
|
365
|
+
declare class FrpProcessManager extends EventEmitter {
|
|
148
366
|
private readonly workDir;
|
|
149
|
-
private version;
|
|
150
367
|
private readonly mode;
|
|
151
368
|
private readonly specifiedVersion?;
|
|
152
369
|
private readonly logger;
|
|
370
|
+
private readonly configPath;
|
|
371
|
+
private readonly processController;
|
|
372
|
+
private readonly configStore;
|
|
373
|
+
private readonly binaryManager;
|
|
374
|
+
private readonly presetConfigManager;
|
|
375
|
+
private tunnelManager;
|
|
376
|
+
private nodeManager;
|
|
153
377
|
private process;
|
|
154
|
-
private
|
|
155
|
-
private
|
|
378
|
+
private uptime;
|
|
379
|
+
private isManualStop;
|
|
156
380
|
constructor(options: FrpProcessManagerOptions);
|
|
157
381
|
/** Ensure version is fetched and binary path is set */
|
|
158
382
|
private ensureVersion;
|
|
@@ -163,17 +387,17 @@ declare class FrpProcessManager {
|
|
|
163
387
|
/** Check if binary exists */
|
|
164
388
|
hasBinary(): boolean;
|
|
165
389
|
/** Get current configuration */
|
|
166
|
-
getConfig(): ClientConfig | ServerConfig | null
|
|
390
|
+
getConfig(): Promise<ClientConfig | ServerConfig | null>;
|
|
167
391
|
/** Update configuration */
|
|
168
|
-
updateConfig(config: Partial<ClientConfig | ServerConfig>): void
|
|
392
|
+
updateConfig(config: Partial<ClientConfig | ServerConfig>): Promise<void>;
|
|
169
393
|
/** Backup configuration */
|
|
170
394
|
backupConfig(): Promise<string>;
|
|
171
395
|
/** Return the absolute config file path */
|
|
172
396
|
getConfigPath(): string;
|
|
173
397
|
/** Read raw config file contents */
|
|
174
|
-
|
|
398
|
+
getConfigRaw(): string | null;
|
|
175
399
|
/** Overwrite config file with provided content */
|
|
176
|
-
|
|
400
|
+
updateConfigRaw(content: string): void;
|
|
177
401
|
/** Start FRP process */
|
|
178
402
|
start(): Promise<void>;
|
|
179
403
|
/** Stop FRP process */
|
|
@@ -181,23 +405,492 @@ declare class FrpProcessManager {
|
|
|
181
405
|
/** Check if process is running */
|
|
182
406
|
isRunning(): boolean;
|
|
183
407
|
/** Add node (for client mode) */
|
|
184
|
-
addNode(node: NodeInfo): void
|
|
408
|
+
addNode(node: NodeInfo): Promise<void>;
|
|
185
409
|
/** Get node info */
|
|
186
|
-
getNode(): NodeInfo | null
|
|
410
|
+
getNode(): Promise<NodeInfo | null>;
|
|
187
411
|
/** Update node info */
|
|
188
|
-
updateNode(node: Partial<NodeInfo>): void
|
|
412
|
+
updateNode(node: Partial<NodeInfo>): Promise<void>;
|
|
189
413
|
/** Remove node */
|
|
190
|
-
removeNode(): void
|
|
414
|
+
removeNode(): Promise<void>;
|
|
191
415
|
/** Add tunnel (proxy) */
|
|
192
|
-
addTunnel(proxy: ProxyConfig): void
|
|
416
|
+
addTunnel(proxy: ProxyConfig): Promise<void>;
|
|
193
417
|
/** Get tunnel by name */
|
|
194
|
-
getTunnel(name: string): ProxyConfig | null
|
|
418
|
+
getTunnel(name: string): Promise<ProxyConfig | null>;
|
|
195
419
|
/** Update tunnel */
|
|
196
|
-
updateTunnel(name: string, proxy: Partial<ProxyConfig>): void
|
|
420
|
+
updateTunnel(name: string, proxy: Partial<ProxyConfig>): Promise<void>;
|
|
197
421
|
/** Remove tunnel */
|
|
198
|
-
removeTunnel(name: string): void
|
|
422
|
+
removeTunnel(name: string): Promise<void>;
|
|
199
423
|
/** List all tunnels */
|
|
200
|
-
listTunnels(): ProxyConfig[]
|
|
424
|
+
listTunnels(): Promise<ProxyConfig[]>;
|
|
425
|
+
/**
|
|
426
|
+
* 生成 FRP 配置文件(合并预设配置和用户 tunnels)
|
|
427
|
+
* @param force 是否强制重新生成
|
|
428
|
+
*/
|
|
429
|
+
generateConfig(force?: boolean): Promise<void>;
|
|
430
|
+
/**
|
|
431
|
+
* 获取预设配置
|
|
432
|
+
*/
|
|
433
|
+
getPresetConfig(): PresetConfig;
|
|
434
|
+
/**
|
|
435
|
+
* 保存预设配置
|
|
436
|
+
*/
|
|
437
|
+
savePresetConfig(config: Record<string, any>): void;
|
|
438
|
+
/**
|
|
439
|
+
* Query current process status
|
|
440
|
+
*/
|
|
441
|
+
queryProcess(): {
|
|
442
|
+
pid: number | undefined;
|
|
443
|
+
uptime: number;
|
|
444
|
+
};
|
|
445
|
+
}
|
|
446
|
+
|
|
447
|
+
/**
|
|
448
|
+
* RPC 消息类型定义
|
|
449
|
+
* 提供类型安全的消息结构和类型守卫
|
|
450
|
+
*/
|
|
451
|
+
/**
|
|
452
|
+
* RPC 消息类型枚举
|
|
453
|
+
*/
|
|
454
|
+
declare enum RpcMessageType {
|
|
455
|
+
REGISTER = "register",
|
|
456
|
+
COMMAND = "command",
|
|
457
|
+
RESPONSE = "response",
|
|
458
|
+
PING = "ping",
|
|
459
|
+
PONG = "pong"
|
|
460
|
+
}
|
|
461
|
+
/**
|
|
462
|
+
* 节点注册消息
|
|
463
|
+
*/
|
|
464
|
+
interface RegisterMessage {
|
|
465
|
+
type: RpcMessageType.REGISTER;
|
|
466
|
+
nodeId: string;
|
|
467
|
+
payload: Record<string, unknown>;
|
|
468
|
+
}
|
|
469
|
+
/**
|
|
470
|
+
* RPC 请求
|
|
471
|
+
*/
|
|
472
|
+
interface RpcRequest {
|
|
473
|
+
id: string;
|
|
474
|
+
method: string;
|
|
475
|
+
params: Record<string, unknown>;
|
|
476
|
+
timeout?: number;
|
|
477
|
+
}
|
|
478
|
+
/**
|
|
479
|
+
* RPC 响应状态
|
|
480
|
+
*/
|
|
481
|
+
type RpcResponseStatus = 'success' | 'error';
|
|
482
|
+
/**
|
|
483
|
+
* RPC 响应
|
|
484
|
+
*/
|
|
485
|
+
interface RpcResponse {
|
|
486
|
+
id: string;
|
|
487
|
+
status: RpcResponseStatus;
|
|
488
|
+
result?: unknown;
|
|
489
|
+
error?: {
|
|
490
|
+
code: string;
|
|
491
|
+
message: string;
|
|
492
|
+
};
|
|
493
|
+
}
|
|
494
|
+
/**
|
|
495
|
+
* Ping 消息
|
|
496
|
+
*/
|
|
497
|
+
interface PingMessage {
|
|
498
|
+
type: RpcMessageType.PING;
|
|
499
|
+
timestamp: number;
|
|
500
|
+
}
|
|
501
|
+
/**
|
|
502
|
+
* Pong 消息
|
|
503
|
+
*/
|
|
504
|
+
interface PongMessage {
|
|
505
|
+
type: RpcMessageType.PONG;
|
|
506
|
+
timestamp: number;
|
|
507
|
+
}
|
|
508
|
+
/**
|
|
509
|
+
* 所有 RPC 消息类型
|
|
510
|
+
*/
|
|
511
|
+
type RpcMessage = RegisterMessage | RpcRequest | RpcResponse | PingMessage | PongMessage;
|
|
512
|
+
/**
|
|
513
|
+
* Event-based RPC message type (matching document spec)
|
|
514
|
+
*/
|
|
515
|
+
interface EventRpcMessage {
|
|
516
|
+
type: 'command' | 'event';
|
|
517
|
+
action: string;
|
|
518
|
+
payload: unknown;
|
|
519
|
+
id?: string;
|
|
520
|
+
targetNodeId?: string;
|
|
521
|
+
}
|
|
522
|
+
/**
|
|
523
|
+
* Command message (frps -> frpc)
|
|
524
|
+
*/
|
|
525
|
+
interface CommandRpcMessage extends EventRpcMessage {
|
|
526
|
+
type: 'command';
|
|
527
|
+
id: string;
|
|
528
|
+
}
|
|
529
|
+
/**
|
|
530
|
+
* Event message (frpc -> frps)
|
|
531
|
+
*/
|
|
532
|
+
interface EventRpcMessageEvent extends EventRpcMessage {
|
|
533
|
+
type: 'event';
|
|
534
|
+
id?: string;
|
|
535
|
+
}
|
|
536
|
+
/**
|
|
537
|
+
* Tunnel add payload
|
|
538
|
+
*/
|
|
539
|
+
interface TunnelAddPayload {
|
|
540
|
+
name: string;
|
|
541
|
+
type: 'tcp' | 'http' | 'https' | 'stcp' | 'sudp' | 'xtcp';
|
|
542
|
+
localPort: number;
|
|
543
|
+
remotePort?: number;
|
|
544
|
+
customDomains?: string[];
|
|
545
|
+
subdomain?: string;
|
|
546
|
+
nodeId?: string;
|
|
547
|
+
[key: string]: unknown;
|
|
548
|
+
}
|
|
549
|
+
/**
|
|
550
|
+
* Tunnel delete payload
|
|
551
|
+
*/
|
|
552
|
+
interface TunnelDeletePayload {
|
|
553
|
+
name: string;
|
|
554
|
+
nodeId?: string;
|
|
555
|
+
}
|
|
556
|
+
/**
|
|
557
|
+
* Tunnel response payload
|
|
558
|
+
*/
|
|
559
|
+
interface TunnelResponsePayload {
|
|
560
|
+
success: boolean;
|
|
561
|
+
error?: string;
|
|
562
|
+
tunnel?: TunnelAddPayload;
|
|
563
|
+
}
|
|
564
|
+
/**
|
|
565
|
+
* Node delete payload
|
|
566
|
+
*/
|
|
567
|
+
interface NodeDeletePayload {
|
|
568
|
+
name: string;
|
|
569
|
+
}
|
|
570
|
+
/**
|
|
571
|
+
* Node response payload
|
|
572
|
+
*/
|
|
573
|
+
interface NodeResponsePayload {
|
|
574
|
+
success: boolean;
|
|
575
|
+
error?: string;
|
|
576
|
+
deletedNode?: string;
|
|
577
|
+
}
|
|
578
|
+
/**
|
|
579
|
+
* All message types including event-based
|
|
580
|
+
*/
|
|
581
|
+
type AllRpcMessage = RpcMessage | EventRpcMessage;
|
|
582
|
+
/**
|
|
583
|
+
* 类型守卫:检查是否为注册消息
|
|
584
|
+
*/
|
|
585
|
+
declare function isRegisterMessage(msg: unknown): msg is RegisterMessage;
|
|
586
|
+
/**
|
|
587
|
+
* 类型守卫:检查是否为 RPC 请求
|
|
588
|
+
*/
|
|
589
|
+
declare function isRpcRequest(msg: unknown): msg is RpcRequest;
|
|
590
|
+
/**
|
|
591
|
+
* 类型守卫:检查是否为 RPC 响应
|
|
592
|
+
*/
|
|
593
|
+
declare function isRpcResponse(msg: unknown): msg is RpcResponse;
|
|
594
|
+
/**
|
|
595
|
+
* 类型守卫:检查是否为 Ping 消息
|
|
596
|
+
*/
|
|
597
|
+
declare function isPingMessage(msg: unknown): msg is PingMessage;
|
|
598
|
+
/**
|
|
599
|
+
* 类型守卫:检查是否为 Pong 消息
|
|
600
|
+
*/
|
|
601
|
+
declare function isPongMessage(msg: unknown): msg is PongMessage;
|
|
602
|
+
/**
|
|
603
|
+
* 类型守卫:检查是否为 Event-based RPC 消息
|
|
604
|
+
*/
|
|
605
|
+
declare function isEventRpcMessage(msg: unknown): msg is EventRpcMessage;
|
|
606
|
+
/**
|
|
607
|
+
* 类型守卫:检查是否为 Command 消息
|
|
608
|
+
*/
|
|
609
|
+
declare function isCommandMessage(msg: unknown): msg is CommandRpcMessage;
|
|
610
|
+
/**
|
|
611
|
+
* 类型守卫:检查是否为 Event 消息
|
|
612
|
+
*/
|
|
613
|
+
declare function isEventMessage(msg: unknown): msg is EventRpcMessageEvent;
|
|
614
|
+
/**
|
|
615
|
+
* 类型守卫:检查是否为 TunnelAddPayload
|
|
616
|
+
*/
|
|
617
|
+
declare function isTunnelAddPayload(data: unknown): data is TunnelAddPayload;
|
|
618
|
+
/**
|
|
619
|
+
* 类型守卫:检查是否为 TunnelDeletePayload
|
|
620
|
+
*/
|
|
621
|
+
declare function isTunnelDeletePayload(data: unknown): data is TunnelDeletePayload;
|
|
622
|
+
/**
|
|
623
|
+
* 类型守卫:检查是否为 NodeDeletePayload
|
|
624
|
+
*/
|
|
625
|
+
declare function isNodeDeletePayload(data: unknown): data is NodeDeletePayload;
|
|
626
|
+
|
|
627
|
+
/**
|
|
628
|
+
* RPC 中间件系统
|
|
629
|
+
* 提供可扩展的请求处理管道
|
|
630
|
+
*/
|
|
631
|
+
|
|
632
|
+
/**
|
|
633
|
+
* 中间件上下文
|
|
634
|
+
*/
|
|
635
|
+
interface MiddlewareContext {
|
|
636
|
+
request: RpcRequest;
|
|
637
|
+
response: Partial<RpcResponse>;
|
|
638
|
+
startTime: number;
|
|
639
|
+
}
|
|
640
|
+
/**
|
|
641
|
+
* 中间件函数类型
|
|
642
|
+
*/
|
|
643
|
+
type MiddlewareFn = (context: MiddlewareContext, next: () => Promise<void>) => Promise<void>;
|
|
644
|
+
/**
|
|
645
|
+
* 中间件选项
|
|
646
|
+
*/
|
|
647
|
+
interface MiddlewareOptions {
|
|
648
|
+
preHooks?: MiddlewareFn[];
|
|
649
|
+
postHooks?: MiddlewareFn[];
|
|
650
|
+
}
|
|
651
|
+
/**
|
|
652
|
+
* 日志中间件
|
|
653
|
+
*/
|
|
654
|
+
declare function loggingMiddleware(logger?: {
|
|
655
|
+
info?: (msg: string, data?: unknown) => void;
|
|
656
|
+
warn?: (msg: string, data?: unknown) => void;
|
|
657
|
+
error?: (msg: string, data?: unknown) => void;
|
|
658
|
+
}): MiddlewareFn;
|
|
659
|
+
/**
|
|
660
|
+
* 认证中间件
|
|
661
|
+
*/
|
|
662
|
+
declare function authMiddleware(validateToken: (token: string | undefined) => boolean | Promise<boolean>): MiddlewareFn;
|
|
663
|
+
/**
|
|
664
|
+
* 超时中间件
|
|
665
|
+
*/
|
|
666
|
+
declare function timeoutMiddleware(timeoutMs: number): MiddlewareFn;
|
|
667
|
+
/**
|
|
668
|
+
* 错误处理中间件
|
|
669
|
+
*/
|
|
670
|
+
declare function errorHandlerMiddleware(logger?: {
|
|
671
|
+
error?: (msg: string, data?: unknown) => void;
|
|
672
|
+
}): MiddlewareFn;
|
|
673
|
+
/**
|
|
674
|
+
* 中间件管道
|
|
675
|
+
*/
|
|
676
|
+
declare class MiddlewarePipeline {
|
|
677
|
+
private middlewares;
|
|
678
|
+
/**
|
|
679
|
+
* 添加中间件
|
|
680
|
+
*/
|
|
681
|
+
use(middleware: MiddlewareFn): this;
|
|
682
|
+
/**
|
|
683
|
+
* 执行中间件管道
|
|
684
|
+
*/
|
|
685
|
+
execute(request: RpcRequest, handler: () => Promise<unknown>): Promise<Partial<RpcResponse>>;
|
|
686
|
+
/**
|
|
687
|
+
* 执行处理器
|
|
688
|
+
*/
|
|
689
|
+
private executeHandler;
|
|
690
|
+
/**
|
|
691
|
+
* 清空中间件
|
|
692
|
+
*/
|
|
693
|
+
clear(): void;
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
/**
|
|
697
|
+
* RPC 重连策略
|
|
698
|
+
* 提供可配置的重连机制,包括指数退避
|
|
699
|
+
*/
|
|
700
|
+
/**
|
|
701
|
+
* 重连策略接口
|
|
702
|
+
*/
|
|
703
|
+
interface ReconnectStrategy {
|
|
704
|
+
/**
|
|
705
|
+
* 判断是否应该重连
|
|
706
|
+
*/
|
|
707
|
+
shouldReconnect: (attempt: number) => boolean;
|
|
708
|
+
/**
|
|
709
|
+
* 获取重连延迟时间(毫秒)
|
|
710
|
+
*/
|
|
711
|
+
getDelay: (attempt: number) => number;
|
|
712
|
+
/**
|
|
713
|
+
* 达到最大重连次数时的回调
|
|
714
|
+
*/
|
|
715
|
+
onMaxAttemptsReached: () => void;
|
|
716
|
+
}
|
|
717
|
+
/**
|
|
718
|
+
* 指数退避重连策略
|
|
719
|
+
*/
|
|
720
|
+
declare class ExponentialBackoffStrategy implements ReconnectStrategy {
|
|
721
|
+
private maxAttempts;
|
|
722
|
+
private baseDelay;
|
|
723
|
+
private maxDelay;
|
|
724
|
+
private logger?;
|
|
725
|
+
constructor(maxAttempts?: number, baseDelay?: number, maxDelay?: number, logger?: {
|
|
726
|
+
error?: (msg: string, data?: unknown) => void;
|
|
727
|
+
} | undefined);
|
|
728
|
+
shouldReconnect(attempt: number): boolean;
|
|
729
|
+
getDelay(attempt: number): number;
|
|
730
|
+
onMaxAttemptsReached(): void;
|
|
731
|
+
}
|
|
732
|
+
/**
|
|
733
|
+
* 固定间隔重连策略
|
|
734
|
+
*/
|
|
735
|
+
declare class FixedIntervalStrategy implements ReconnectStrategy {
|
|
736
|
+
private maxAttempts;
|
|
737
|
+
private interval;
|
|
738
|
+
private logger?;
|
|
739
|
+
constructor(maxAttempts?: number, interval?: number, logger?: {
|
|
740
|
+
error?: (msg: string, data?: unknown) => void;
|
|
741
|
+
} | undefined);
|
|
742
|
+
shouldReconnect(attempt: number): boolean;
|
|
743
|
+
getDelay(): number;
|
|
744
|
+
onMaxAttemptsReached(): void;
|
|
745
|
+
}
|
|
746
|
+
/**
|
|
747
|
+
* 线性增长重连策略
|
|
748
|
+
*/
|
|
749
|
+
declare class LinearBackoffStrategy implements ReconnectStrategy {
|
|
750
|
+
private maxAttempts;
|
|
751
|
+
private baseDelay;
|
|
752
|
+
private increment;
|
|
753
|
+
private maxDelay;
|
|
754
|
+
private logger?;
|
|
755
|
+
constructor(maxAttempts?: number, baseDelay?: number, increment?: number, maxDelay?: number, logger?: {
|
|
756
|
+
error?: (msg: string, data?: unknown) => void;
|
|
757
|
+
} | undefined);
|
|
758
|
+
shouldReconnect(attempt: number): boolean;
|
|
759
|
+
getDelay(attempt: number): number;
|
|
760
|
+
onMaxAttemptsReached(): void;
|
|
761
|
+
}
|
|
762
|
+
/**
|
|
763
|
+
* 无限重连策略(永不停止)
|
|
764
|
+
*/
|
|
765
|
+
declare class InfiniteReconnectStrategy implements ReconnectStrategy {
|
|
766
|
+
private baseDelay;
|
|
767
|
+
private maxDelay;
|
|
768
|
+
constructor(baseDelay?: number, maxDelay?: number);
|
|
769
|
+
shouldReconnect(): boolean;
|
|
770
|
+
getDelay(attempt: number): number;
|
|
771
|
+
onMaxAttemptsReached(): void;
|
|
772
|
+
}
|
|
773
|
+
|
|
774
|
+
interface RpcClientOptions {
|
|
775
|
+
url: string;
|
|
776
|
+
nodeId: string;
|
|
777
|
+
getRegisterPayload: () => Promise<NodeInfo$1> | NodeInfo$1;
|
|
778
|
+
handleRequest: (req: RpcRequest$1) => Promise<unknown>;
|
|
779
|
+
handleCommand?: (command: CommandRpcMessage) => Promise<unknown>;
|
|
780
|
+
reconnectStrategy?: ReconnectStrategy;
|
|
781
|
+
logger?: Partial<RuntimeLogger>;
|
|
782
|
+
}
|
|
783
|
+
declare class RpcClient {
|
|
784
|
+
private readonly options;
|
|
785
|
+
private ws;
|
|
786
|
+
private reconnectTimer?;
|
|
787
|
+
private reconnectAttempt;
|
|
788
|
+
private readonly reconnectStrategy;
|
|
789
|
+
private connectionState;
|
|
790
|
+
private readonly log;
|
|
791
|
+
constructor(options: RpcClientOptions);
|
|
792
|
+
connect(): Promise<void>;
|
|
793
|
+
disconnect(): void;
|
|
794
|
+
/**
|
|
795
|
+
* Get current connection state
|
|
796
|
+
*/
|
|
797
|
+
getConnectionState(): 'connecting' | 'connected' | 'disconnected';
|
|
798
|
+
/**
|
|
799
|
+
* Check if connected
|
|
800
|
+
*/
|
|
801
|
+
isConnected(): boolean;
|
|
802
|
+
/**
|
|
803
|
+
* Send an event message to server (matching document spec)
|
|
804
|
+
*/
|
|
805
|
+
sendEvent(event: EventRpcMessageEvent): boolean;
|
|
806
|
+
private createConnection;
|
|
807
|
+
private handleMessage;
|
|
808
|
+
/**
|
|
809
|
+
* Handle event-based command messages from server (matching document spec)
|
|
810
|
+
*/
|
|
811
|
+
private handleCommandEvent;
|
|
812
|
+
private handleRpcRequest;
|
|
813
|
+
private send;
|
|
814
|
+
private scheduleReconnect;
|
|
815
|
+
}
|
|
816
|
+
|
|
817
|
+
/**
|
|
818
|
+
* Command status for tracking
|
|
819
|
+
*/
|
|
820
|
+
interface RpcCommandStatus {
|
|
821
|
+
commandId: string;
|
|
822
|
+
nodeId: string;
|
|
823
|
+
action: string;
|
|
824
|
+
status: 'pending' | 'completed' | 'failed';
|
|
825
|
+
result?: unknown;
|
|
826
|
+
error?: string;
|
|
827
|
+
timestamp: number;
|
|
828
|
+
}
|
|
829
|
+
interface RpcServerOptions {
|
|
830
|
+
port: number;
|
|
831
|
+
heartbeatInterval?: number;
|
|
832
|
+
validateToken?: (token: string | undefined, nodeId: string | undefined) => boolean | Promise<boolean>;
|
|
833
|
+
authorize?: (nodeId: string, method: string) => boolean | Promise<boolean>;
|
|
834
|
+
onRegister?: (nodeId: string, payload: NodeInfo$1) => void | Promise<void>;
|
|
835
|
+
onEvent?: (nodeId: string, event: EventRpcMessage) => void | Promise<void>;
|
|
836
|
+
commandTimeout?: number;
|
|
837
|
+
logger?: Partial<RuntimeLogger>;
|
|
838
|
+
}
|
|
839
|
+
declare class RpcServer {
|
|
840
|
+
private readonly options;
|
|
841
|
+
private readonly clients;
|
|
842
|
+
private readonly pendingRequests;
|
|
843
|
+
private readonly commandStatuses;
|
|
844
|
+
private readonly wsToNode;
|
|
845
|
+
private heartbeatTimer?;
|
|
846
|
+
private server?;
|
|
847
|
+
private readonly defaultCommandTimeout;
|
|
848
|
+
private readonly log;
|
|
849
|
+
constructor(options: RpcServerOptions);
|
|
850
|
+
start(): void;
|
|
851
|
+
stop(): void;
|
|
852
|
+
rpcCall(nodeId: string, method: string, params: Record<string, unknown>, timeout?: number): Promise<unknown>;
|
|
853
|
+
/**
|
|
854
|
+
* Send event-based message to a specific node (matching document spec)
|
|
855
|
+
*/
|
|
856
|
+
sendToNode(nodeId: string, message: EventRpcMessage): boolean;
|
|
857
|
+
/**
|
|
858
|
+
* Broadcast event-based message to all connected nodes
|
|
859
|
+
*/
|
|
860
|
+
broadcast(message: EventRpcMessage): void;
|
|
861
|
+
/**
|
|
862
|
+
* Get list of all online node IDs
|
|
863
|
+
*/
|
|
864
|
+
getOnlineNodes(): string[];
|
|
865
|
+
/**
|
|
866
|
+
* Check if a specific node is online
|
|
867
|
+
*/
|
|
868
|
+
isNodeOnline(nodeId: string): boolean;
|
|
869
|
+
/**
|
|
870
|
+
* Get the count of online nodes
|
|
871
|
+
*/
|
|
872
|
+
getOnlineNodeCount(): number;
|
|
873
|
+
/**
|
|
874
|
+
* Get command status by ID
|
|
875
|
+
*/
|
|
876
|
+
getRpcCommandStatus(commandId: string): RpcCommandStatus | undefined;
|
|
877
|
+
/**
|
|
878
|
+
* Get all command statuses
|
|
879
|
+
*/
|
|
880
|
+
getAllRpcCommandStatuses(): RpcCommandStatus[];
|
|
881
|
+
/**
|
|
882
|
+
* Clear completed/failed command statuses older than specified milliseconds
|
|
883
|
+
*/
|
|
884
|
+
clearOldStatuses(maxAge?: number): void;
|
|
885
|
+
private handleMessage;
|
|
886
|
+
/**
|
|
887
|
+
* Handle event-based messages from clients
|
|
888
|
+
*/
|
|
889
|
+
private handleEventMessage;
|
|
890
|
+
private handleRegister;
|
|
891
|
+
private handleRpcResponse;
|
|
892
|
+
private handleClose;
|
|
893
|
+
private startHeartbeat;
|
|
201
894
|
}
|
|
202
895
|
|
|
203
896
|
interface FrpBridgeRuntimeOptions {
|
|
@@ -210,34 +903,93 @@ interface FrpBridgeRuntimeOptions {
|
|
|
210
903
|
}
|
|
211
904
|
interface FrpBridgeProcessOptions extends Partial<Omit<FrpProcessManagerOptions, 'mode'>> {
|
|
212
905
|
mode?: 'client' | 'server';
|
|
213
|
-
workDir?: string;
|
|
214
906
|
}
|
|
907
|
+
interface FrpBridgeRpcOptions {
|
|
908
|
+
serverPort?: number;
|
|
909
|
+
serverHeartbeatInterval?: number;
|
|
910
|
+
serverValidateToken?: (token: string | undefined, nodeId: string | undefined) => boolean | Promise<boolean>;
|
|
911
|
+
serverAuthorize?: (nodeId: string, method: string) => boolean | Promise<boolean>;
|
|
912
|
+
serverOnRegister?: (nodeId: string, payload: NodeInfo$1) => void | Promise<void>;
|
|
913
|
+
serverOnEvent?: (nodeId: string, event: EventRpcMessage) => void | Promise<void>;
|
|
914
|
+
serverCommandTimeout?: number;
|
|
915
|
+
clientUrl?: string;
|
|
916
|
+
clientNodeId?: string;
|
|
917
|
+
clientToken?: string;
|
|
918
|
+
clientReconnectInterval?: number;
|
|
919
|
+
getRegisterPayload?: () => Promise<NodeInfo$1> | NodeInfo$1;
|
|
920
|
+
handleRequest?: (req: RpcRequest$1) => Promise<unknown>;
|
|
921
|
+
}
|
|
922
|
+
|
|
215
923
|
interface FrpBridgeOptions {
|
|
216
924
|
mode: 'client' | 'server';
|
|
217
925
|
workDir?: string;
|
|
926
|
+
configPath?: string;
|
|
218
927
|
runtime?: FrpBridgeRuntimeOptions;
|
|
219
928
|
process?: FrpBridgeProcessOptions;
|
|
929
|
+
rpc?: FrpBridgeRpcOptions;
|
|
220
930
|
storage?: SnapshotStorage;
|
|
221
931
|
commands?: Record<string, CommandHandler>;
|
|
222
932
|
queries?: Record<string, QueryHandler>;
|
|
223
933
|
eventSink?: (event: RuntimeEvent) => void;
|
|
224
934
|
}
|
|
935
|
+
/**
|
|
936
|
+
* FrpBridge - Main facade class for managing FRP bridge operations.
|
|
937
|
+
*
|
|
938
|
+
* This class serves as a facade that coordinates multiple components:
|
|
939
|
+
* - Runtime management (command/query execution)
|
|
940
|
+
* - Process management (FRP process lifecycle)
|
|
941
|
+
* - Node management (server mode only)
|
|
942
|
+
* - RPC communication
|
|
943
|
+
*
|
|
944
|
+
* Design patterns used:
|
|
945
|
+
* - Facade Pattern: Simplifies interface to complex subsystems
|
|
946
|
+
* - Dependency Injection: All dependencies injected via constructor
|
|
947
|
+
* - Factory Pattern: Handlers created via factory functions
|
|
948
|
+
*/
|
|
225
949
|
declare class FrpBridge {
|
|
226
|
-
private readonly options;
|
|
227
950
|
private readonly runtime;
|
|
228
951
|
private readonly process;
|
|
952
|
+
private readonly mode;
|
|
229
953
|
private readonly eventSink?;
|
|
954
|
+
private readonly nodeManager?;
|
|
955
|
+
private readonly clientCollector?;
|
|
956
|
+
private readonly rpcServer?;
|
|
957
|
+
private readonly rpcClient?;
|
|
230
958
|
constructor(options: FrpBridgeOptions);
|
|
959
|
+
/**
|
|
960
|
+
* Execute a command
|
|
961
|
+
*/
|
|
231
962
|
execute<TPayload, TResult = unknown>(command: RuntimeCommand<TPayload>): Promise<CommandResult<TResult>>;
|
|
963
|
+
/**
|
|
964
|
+
* Execute a query
|
|
965
|
+
*/
|
|
232
966
|
query<TPayload, TResult = unknown>(query: RuntimeQuery<TPayload>): Promise<QueryResult<TResult>>;
|
|
967
|
+
/**
|
|
968
|
+
* Get current runtime state snapshot
|
|
969
|
+
*/
|
|
233
970
|
snapshot(): RuntimeState;
|
|
971
|
+
/**
|
|
972
|
+
* Drain and return all pending events
|
|
973
|
+
*/
|
|
234
974
|
drainEvents(): RuntimeEvent[];
|
|
235
975
|
getProcessManager(): FrpProcessManager;
|
|
236
976
|
getRuntime(): FrpRuntime;
|
|
237
|
-
|
|
238
|
-
|
|
977
|
+
getNodeManager(): NodeManager | undefined;
|
|
978
|
+
getClientCollector(): ClientNodeCollector | undefined;
|
|
979
|
+
getRpcServer(): RpcServer | undefined;
|
|
980
|
+
getRpcClient(): RpcClient | undefined;
|
|
981
|
+
/**
|
|
982
|
+
* Initialize all async components
|
|
983
|
+
*/
|
|
984
|
+
initialize(): Promise<void>;
|
|
985
|
+
/**
|
|
986
|
+
* Cleanup and dispose all resources
|
|
987
|
+
*/
|
|
988
|
+
dispose(): Promise<void>;
|
|
989
|
+
/**
|
|
990
|
+
* Forward runtime events to external event sink
|
|
991
|
+
*/
|
|
239
992
|
private forwardEvents;
|
|
240
|
-
private runConfigMutation;
|
|
241
993
|
}
|
|
242
994
|
|
|
243
995
|
/**
|
|
@@ -257,26 +1009,122 @@ declare const ARCH_MAP: Record<string, string>;
|
|
|
257
1009
|
/** Platform OS mapping */
|
|
258
1010
|
declare const OS_MAP: Record<string, string>;
|
|
259
1011
|
|
|
260
|
-
/**
|
|
261
|
-
|
|
1012
|
+
/**
|
|
1013
|
+
* Base error class for all FRP Bridge errors
|
|
1014
|
+
* Provides consistent error structure and handling
|
|
1015
|
+
*/
|
|
1016
|
+
declare abstract class FrpBridgeErrorBase extends Error {
|
|
1017
|
+
/**
|
|
1018
|
+
* Error code for programmatic error handling
|
|
1019
|
+
*/
|
|
1020
|
+
abstract readonly code: string;
|
|
1021
|
+
/**
|
|
1022
|
+
* HTTP status code (optional, for API responses)
|
|
1023
|
+
*/
|
|
1024
|
+
readonly statusCode?: number;
|
|
1025
|
+
/**
|
|
1026
|
+
* Additional error details
|
|
1027
|
+
*/
|
|
1028
|
+
readonly details?: unknown;
|
|
1029
|
+
constructor(message: string, details?: unknown);
|
|
1030
|
+
/**
|
|
1031
|
+
* Convert error to plain object for serialization
|
|
1032
|
+
*/
|
|
1033
|
+
toJSON(): {
|
|
1034
|
+
code: string;
|
|
1035
|
+
message: string;
|
|
1036
|
+
statusCode?: number;
|
|
1037
|
+
details?: unknown;
|
|
1038
|
+
};
|
|
1039
|
+
}
|
|
1040
|
+
/**
|
|
1041
|
+
* Generic error for uncategorized errors
|
|
1042
|
+
*/
|
|
1043
|
+
declare class GenericError extends FrpBridgeErrorBase {
|
|
262
1044
|
readonly code: string;
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
/**
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
270
|
-
|
|
271
|
-
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
|
|
279
|
-
|
|
1045
|
+
constructor(message: string, code: string, details?: unknown);
|
|
1046
|
+
}
|
|
1047
|
+
|
|
1048
|
+
/**
|
|
1049
|
+
* Categorized error classes for FRP Bridge
|
|
1050
|
+
* Each error extends FrpBridgeErrorBase directly
|
|
1051
|
+
*/
|
|
1052
|
+
|
|
1053
|
+
/**
|
|
1054
|
+
* Configuration errors (400 Bad Request)
|
|
1055
|
+
*/
|
|
1056
|
+
declare class ConfigNotFoundError extends FrpBridgeErrorBase {
|
|
1057
|
+
readonly code = "CONFIG_NOT_FOUND";
|
|
1058
|
+
readonly statusCode = 400;
|
|
1059
|
+
}
|
|
1060
|
+
declare class ConfigInvalidError extends FrpBridgeErrorBase {
|
|
1061
|
+
readonly code = "CONFIG_INVALID";
|
|
1062
|
+
readonly statusCode = 400;
|
|
1063
|
+
}
|
|
1064
|
+
/**
|
|
1065
|
+
* Process errors
|
|
1066
|
+
*/
|
|
1067
|
+
declare class ProcessNotRunningError extends FrpBridgeErrorBase {
|
|
1068
|
+
readonly code = "PROCESS_NOT_RUNNING";
|
|
1069
|
+
readonly statusCode = 409;
|
|
1070
|
+
}
|
|
1071
|
+
declare class ProcessAlreadyRunningError extends FrpBridgeErrorBase {
|
|
1072
|
+
readonly code = "PROCESS_ALREADY_RUNNING";
|
|
1073
|
+
readonly statusCode = 409;
|
|
1074
|
+
}
|
|
1075
|
+
declare class ProcessStartFailedError extends FrpBridgeErrorBase {
|
|
1076
|
+
readonly code = "PROCESS_START_FAILED";
|
|
1077
|
+
readonly statusCode = 500;
|
|
1078
|
+
}
|
|
1079
|
+
/**
|
|
1080
|
+
* Binary errors (500 Internal Server Error)
|
|
1081
|
+
*/
|
|
1082
|
+
declare class BinaryNotFoundError extends FrpBridgeErrorBase {
|
|
1083
|
+
readonly code = "BINARY_NOT_FOUND";
|
|
1084
|
+
readonly statusCode = 500;
|
|
1085
|
+
}
|
|
1086
|
+
declare class DownloadFailedError extends FrpBridgeErrorBase {
|
|
1087
|
+
readonly code = "DOWNLOAD_FAILED";
|
|
1088
|
+
readonly statusCode = 500;
|
|
1089
|
+
}
|
|
1090
|
+
declare class ExtractionFailedError extends FrpBridgeErrorBase {
|
|
1091
|
+
readonly code = "EXTRACTION_FAILED";
|
|
1092
|
+
readonly statusCode = 500;
|
|
1093
|
+
}
|
|
1094
|
+
/**
|
|
1095
|
+
* Network/Version errors (503 Service Unavailable)
|
|
1096
|
+
*/
|
|
1097
|
+
declare class VersionFetchError extends FrpBridgeErrorBase {
|
|
1098
|
+
readonly code = "VERSION_FETCH_FAILED";
|
|
1099
|
+
readonly statusCode = 503;
|
|
1100
|
+
}
|
|
1101
|
+
/**
|
|
1102
|
+
* Validation errors (400 Bad Request)
|
|
1103
|
+
*/
|
|
1104
|
+
declare class ValidationError extends FrpBridgeErrorBase {
|
|
1105
|
+
readonly code = "VALIDATION_ERROR";
|
|
1106
|
+
readonly statusCode = 400;
|
|
1107
|
+
}
|
|
1108
|
+
/**
|
|
1109
|
+
* Mode/State errors (409 Conflict)
|
|
1110
|
+
*/
|
|
1111
|
+
declare class ModeError extends FrpBridgeErrorBase {
|
|
1112
|
+
readonly code = "MODE_ERROR";
|
|
1113
|
+
readonly statusCode = 409;
|
|
1114
|
+
}
|
|
1115
|
+
/**
|
|
1116
|
+
* Resource not found (404 Not Found)
|
|
1117
|
+
*/
|
|
1118
|
+
declare class NotFoundError extends FrpBridgeErrorBase {
|
|
1119
|
+
readonly code = "NOT_FOUND";
|
|
1120
|
+
readonly statusCode = 404;
|
|
1121
|
+
}
|
|
1122
|
+
/**
|
|
1123
|
+
* Platform errors (500 Internal Server Error)
|
|
1124
|
+
*/
|
|
1125
|
+
declare class PlatformError extends FrpBridgeErrorBase {
|
|
1126
|
+
readonly code = "UNSUPPORTED_PLATFORM";
|
|
1127
|
+
readonly statusCode = 500;
|
|
280
1128
|
}
|
|
281
1129
|
|
|
282
1130
|
declare class FileSnapshotStorage implements SnapshotStorage {
|
|
@@ -288,6 +1136,51 @@ declare class FileSnapshotStorage implements SnapshotStorage {
|
|
|
288
1136
|
private buildPath;
|
|
289
1137
|
}
|
|
290
1138
|
|
|
1139
|
+
/**
|
|
1140
|
+
* Unified TOML parsing and serialization module
|
|
1141
|
+
* Wraps smol-toml with consistent error handling
|
|
1142
|
+
*/
|
|
1143
|
+
interface ParseOptions {
|
|
1144
|
+
/**
|
|
1145
|
+
* Parse integers as BigInt
|
|
1146
|
+
*/
|
|
1147
|
+
integersAsBigInt?: boolean | 'asNeeded';
|
|
1148
|
+
}
|
|
1149
|
+
interface StringifyOptions {
|
|
1150
|
+
/**
|
|
1151
|
+
* Serialize numbers as floats
|
|
1152
|
+
*/
|
|
1153
|
+
numbersAsFloat?: boolean;
|
|
1154
|
+
}
|
|
1155
|
+
/**
|
|
1156
|
+
* Parse TOML string to JavaScript object
|
|
1157
|
+
* @param content - TOML string content
|
|
1158
|
+
* @param options - Parse options
|
|
1159
|
+
* @returns Parsed JavaScript object
|
|
1160
|
+
* @throws {Error} If TOML is invalid
|
|
1161
|
+
*/
|
|
1162
|
+
declare function parse<T = Record<string, any>>(content: string, options?: ParseOptions): T;
|
|
1163
|
+
/**
|
|
1164
|
+
* Serialize JavaScript object to TOML string
|
|
1165
|
+
* @param obj - JavaScript object to serialize
|
|
1166
|
+
* @param options - Stringify options
|
|
1167
|
+
* @returns TOML string
|
|
1168
|
+
* @throws {Error} If object contains unserializable values
|
|
1169
|
+
*/
|
|
1170
|
+
declare function stringify(obj: Record<string, any>, options?: StringifyOptions): string;
|
|
1171
|
+
/**
|
|
1172
|
+
* Check if a string is valid TOML
|
|
1173
|
+
* @param content - String content to check
|
|
1174
|
+
* @returns true if valid TOML, false otherwise
|
|
1175
|
+
*/
|
|
1176
|
+
declare function isValidToml(content: string): boolean;
|
|
1177
|
+
/**
|
|
1178
|
+
* Parse TOML file content safely (returns null on error)
|
|
1179
|
+
* @param content - TOML string content
|
|
1180
|
+
* @returns Parsed object or null if parsing fails
|
|
1181
|
+
*/
|
|
1182
|
+
declare function safeParse<T = Record<string, any>>(content: string): T | null;
|
|
1183
|
+
|
|
291
1184
|
/**
|
|
292
1185
|
* Utility functions
|
|
293
1186
|
*/
|
|
@@ -308,10 +1201,16 @@ declare function executeCommand(command: string): Promise<{
|
|
|
308
1201
|
declare function commandExists(command: string): Promise<boolean>;
|
|
309
1202
|
/** Ensure directory exists */
|
|
310
1203
|
declare function ensureDir(dirPath: string): void;
|
|
311
|
-
/**
|
|
1204
|
+
/** Find existing FRP version in work directory */
|
|
1205
|
+
declare function findExistingVersion(workDir: string): string | null;
|
|
1206
|
+
/**
|
|
1207
|
+
* Parse TOML-like config to JSON
|
|
1208
|
+
*/
|
|
312
1209
|
declare function parseToml(content: string): Record<string, any>;
|
|
313
|
-
/**
|
|
1210
|
+
/**
|
|
1211
|
+
* Convert JSON to TOML-like config
|
|
1212
|
+
*/
|
|
314
1213
|
declare function toToml(obj: Record<string, any>): string;
|
|
315
1214
|
|
|
316
|
-
export { ARCH_MAP, BINARY_NAMES,
|
|
317
|
-
export type { Awaitable, CommandHandler, CommandHandlerContext, CommandMetadata, CommandResult, CommandStatus, ConfigSnapshot, FrpBridgeOptions, FrpProcessManagerOptions, NodeInfo, QueryHandler, QueryResult, RuntimeAdapters, RuntimeCommand, RuntimeContext, RuntimeError, RuntimeErrorCode, RuntimeEvent, RuntimeLogger, RuntimeMode, RuntimeQuery, RuntimeState, RuntimeStatus, SnapshotStorage };
|
|
1215
|
+
export { ARCH_MAP, BINARY_NAMES, BinaryNotFoundError, ClientNodeCollector, ConfigInvalidError, ConfigNotFoundError, DEFAULT_PRESET_CONFIG, DownloadFailedError, FrpBridgeErrorBase as Error, ExponentialBackoffStrategy, ExtractionFailedError, FileNodeStorage, FileSnapshotStorage, FixedIntervalStrategy, FrpBridge, FrpBridgeErrorBase, FrpProcessManager, FrpRuntime, GITHUB_OWNER, GITHUB_REPO, GenericError, InfiniteReconnectStrategy, LinearBackoffStrategy, MiddlewarePipeline, ModeError, NodeManager, NotFoundError, OS_MAP, PlatformError, ProcessAlreadyRunningError, ProcessNotRunningError, ProcessStartFailedError, RpcClient, RpcMessageType, RpcServer, ValidationError, VersionFetchError, authMiddleware, commandExists, configToToml, downloadFile, ensureDir, errorHandlerMiddleware, executeCommand, findExistingVersion, getDownloadUrl, getLatestVersion, getPlatform, isCommandMessage, isEventMessage, isEventRpcMessage, isNodeDeletePayload, isPingMessage, isPongMessage, isRegisterMessage, isRpcRequest, isRpcResponse, isTunnelAddPayload, isTunnelDeletePayload, isValidToml, loggingMiddleware, mergeConfigs, parse, parseToml, safeParse, saveFrpConfigFile, stringify, timeoutMiddleware, toToml, validatePresetConfig };
|
|
1216
|
+
export type { AllRpcMessage, Awaitable, ClientCollectorOptions, CommandHandler, CommandHandlerContext, CommandMetadata, CommandResult, CommandRpcMessage, CommandStatus, ConfigSnapshot, EventRpcMessage, EventRpcMessageEvent, FrpBridgeOptions, FrpProcessManagerOptions, FrpcPresetConfig, FrpsPresetConfig, MiddlewareContext, MiddlewareFn, MiddlewareOptions, NodeDeletePayload, NodeEvent, NodeInfo, NodeManagerOptions, NodeResponsePayload, NodeStorage, ParseOptions, PingMessage, PongMessage, PresetConfig, QueryHandler, QueryResult, ReconnectStrategy, RegisterMessage, RpcClientOptions, RpcCommandStatus, RpcMessage, RpcRequest, RpcResponse, RpcResponseStatus, RpcServerOptions, RuntimeAdapters, RuntimeCommand, RuntimeContext, RuntimeError, RuntimeErrorCode, RuntimeEvent, RuntimeLogger, RuntimeMode, RuntimeQuery, RuntimeState, RuntimeStatus, SnapshotStorage, StringifyOptions, TunnelAddPayload, TunnelDeletePayload, TunnelResponsePayload };
|