@frp-bridge/core 0.0.2 → 0.0.3

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.ts CHANGED
@@ -1,4 +1,4 @@
1
- import { NodeRegisterPayload, NodeHeartbeatPayload, NodeInfo as NodeInfo$1, NodeListQuery, NodeListResponse, NodeStatistics, TunnelSyncPayload, ProxyConfig, ClientConfig, ServerConfig, RpcRequest } from '@frp-bridge/types';
1
+ import { NodeRegisterPayload, NodeHeartbeatPayload, NodeInfo as NodeInfo$1, NodeListQuery, NodeListResponse, NodeStatistics, TunnelSyncPayload, ProxyConfig, ClientConfig, ServerConfig, RpcRequest as RpcRequest$1 } from '@frp-bridge/types';
2
2
  import { EventEmitter } from 'node:events';
3
3
 
4
4
  type Awaitable<T> = T | Promise<T>;
@@ -165,7 +165,7 @@ declare class ClientNodeCollector {
165
165
 
166
166
  interface NodeManagerOptions {
167
167
  heartbeatTimeout?: number;
168
- logger?: any;
168
+ logger?: Partial<RuntimeLogger>;
169
169
  }
170
170
  interface NodeStorage {
171
171
  save: (node: NodeInfo$1) => Promise<void> | void;
@@ -185,7 +185,7 @@ declare class NodeManager extends EventEmitter {
185
185
  private tunnelRegistry;
186
186
  private storage?;
187
187
  private heartbeatTimeout;
188
- private logger?;
188
+ private readonly log;
189
189
  constructor(context: RuntimeContext, options?: NodeManagerOptions, storage?: NodeStorage);
190
190
  initialize(): Promise<void>;
191
191
  /** Register a new node (called when client connects) */
@@ -261,8 +261,69 @@ declare class FileNodeStorage implements NodeStorage {
261
261
  private updateIndex;
262
262
  }
263
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
+
264
318
  /**
265
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
266
327
  */
267
328
 
268
329
  interface FrpProcessManagerOptions {
@@ -293,16 +354,27 @@ interface NodeInfo {
293
354
  }
294
355
  /**
295
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
296
364
  */
297
365
  declare class FrpProcessManager extends EventEmitter {
298
366
  private readonly workDir;
299
- private version;
300
367
  private readonly mode;
301
368
  private readonly specifiedVersion?;
302
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;
303
377
  private process;
304
- private configPath;
305
- private binaryPath;
306
378
  private uptime;
307
379
  private isManualStop;
308
380
  constructor(options: FrpProcessManagerOptions);
@@ -315,9 +387,9 @@ declare class FrpProcessManager extends EventEmitter {
315
387
  /** Check if binary exists */
316
388
  hasBinary(): boolean;
317
389
  /** Get current configuration */
318
- getConfig(): ClientConfig | ServerConfig | null;
390
+ getConfig(): Promise<ClientConfig | ServerConfig | null>;
319
391
  /** Update configuration */
320
- updateConfig(config: Partial<ClientConfig | ServerConfig>): void;
392
+ updateConfig(config: Partial<ClientConfig | ServerConfig>): Promise<void>;
321
393
  /** Backup configuration */
322
394
  backupConfig(): Promise<string>;
323
395
  /** Return the absolute config file path */
@@ -333,25 +405,36 @@ declare class FrpProcessManager extends EventEmitter {
333
405
  /** Check if process is running */
334
406
  isRunning(): boolean;
335
407
  /** Add node (for client mode) */
336
- addNode(node: NodeInfo): void;
408
+ addNode(node: NodeInfo): Promise<void>;
337
409
  /** Get node info */
338
- getNode(): NodeInfo | null;
410
+ getNode(): Promise<NodeInfo | null>;
339
411
  /** Update node info */
340
- updateNode(node: Partial<NodeInfo>): void;
412
+ updateNode(node: Partial<NodeInfo>): Promise<void>;
341
413
  /** Remove node */
342
- removeNode(): void;
414
+ removeNode(): Promise<void>;
343
415
  /** Add tunnel (proxy) */
344
- addTunnel(proxy: ProxyConfig): void;
345
- /** Check if proxy type uses remotePort */
346
- private typeUsesRemotePort;
416
+ addTunnel(proxy: ProxyConfig): Promise<void>;
347
417
  /** Get tunnel by name */
348
- getTunnel(name: string): ProxyConfig | null;
418
+ getTunnel(name: string): Promise<ProxyConfig | null>;
349
419
  /** Update tunnel */
350
- updateTunnel(name: string, proxy: Partial<ProxyConfig>): void;
420
+ updateTunnel(name: string, proxy: Partial<ProxyConfig>): Promise<void>;
351
421
  /** Remove tunnel */
352
- removeTunnel(name: string): void;
422
+ removeTunnel(name: string): Promise<void>;
353
423
  /** List all tunnels */
354
- 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;
355
438
  /**
356
439
  * Query current process status
357
440
  */
@@ -359,60 +442,452 @@ declare class FrpProcessManager extends EventEmitter {
359
442
  pid: number | undefined;
360
443
  uptime: number;
361
444
  };
362
- private setupProcessListeners;
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;
363
772
  }
364
773
 
365
774
  interface RpcClientOptions {
366
775
  url: string;
367
776
  nodeId: string;
368
777
  getRegisterPayload: () => Promise<NodeInfo$1> | NodeInfo$1;
369
- handleRequest: (req: RpcRequest) => Promise<unknown>;
370
- reconnectInterval?: number;
371
- logger?: {
372
- info?: (msg: string, data?: unknown) => void;
373
- warn?: (msg: string, data?: unknown) => void;
374
- error?: (msg: string, data?: unknown) => void;
375
- };
778
+ handleRequest: (req: RpcRequest$1) => Promise<unknown>;
779
+ handleCommand?: (command: CommandRpcMessage) => Promise<unknown>;
780
+ reconnectStrategy?: ReconnectStrategy;
781
+ logger?: Partial<RuntimeLogger>;
376
782
  }
377
783
  declare class RpcClient {
378
784
  private readonly options;
379
785
  private ws;
380
786
  private reconnectTimer?;
381
- private readonly reconnectInterval;
787
+ private reconnectAttempt;
788
+ private readonly reconnectStrategy;
789
+ private connectionState;
790
+ private readonly log;
382
791
  constructor(options: RpcClientOptions);
383
792
  connect(): Promise<void>;
384
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;
385
806
  private createConnection;
386
807
  private handleMessage;
808
+ /**
809
+ * Handle event-based command messages from server (matching document spec)
810
+ */
811
+ private handleCommandEvent;
387
812
  private handleRpcRequest;
388
813
  private send;
389
814
  private scheduleReconnect;
390
815
  }
391
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
+ }
392
829
  interface RpcServerOptions {
393
830
  port: number;
394
831
  heartbeatInterval?: number;
395
- logger?: {
396
- info?: (msg: string, data?: unknown) => void;
397
- warn?: (msg: string, data?: unknown) => void;
398
- error?: (msg: string, data?: unknown) => void;
399
- };
400
832
  validateToken?: (token: string | undefined, nodeId: string | undefined) => boolean | Promise<boolean>;
401
833
  authorize?: (nodeId: string, method: string) => boolean | Promise<boolean>;
402
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>;
403
838
  }
404
839
  declare class RpcServer {
405
840
  private readonly options;
406
841
  private readonly clients;
407
842
  private readonly pendingRequests;
843
+ private readonly commandStatuses;
408
844
  private readonly wsToNode;
409
845
  private heartbeatTimer?;
410
846
  private server?;
847
+ private readonly defaultCommandTimeout;
848
+ private readonly log;
411
849
  constructor(options: RpcServerOptions);
412
850
  start(): void;
413
851
  stop(): void;
414
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;
415
885
  private handleMessage;
886
+ /**
887
+ * Handle event-based messages from clients
888
+ */
889
+ private handleEventMessage;
890
+ private handleRegister;
416
891
  private handleRpcResponse;
417
892
  private handleClose;
418
893
  private startHeartbeat;
@@ -434,12 +909,15 @@ interface FrpBridgeRpcOptions {
434
909
  serverHeartbeatInterval?: number;
435
910
  serverValidateToken?: (token: string | undefined, nodeId: string | undefined) => boolean | Promise<boolean>;
436
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;
437
915
  clientUrl?: string;
438
916
  clientNodeId?: string;
439
917
  clientToken?: string;
440
918
  clientReconnectInterval?: number;
441
919
  getRegisterPayload?: () => Promise<NodeInfo$1> | NodeInfo$1;
442
- handleRequest?: (req: RpcRequest) => Promise<unknown>;
920
+ handleRequest?: (req: RpcRequest$1) => Promise<unknown>;
443
921
  }
444
922
 
445
923
  interface FrpBridgeOptions {
@@ -531,26 +1009,122 @@ declare const ARCH_MAP: Record<string, string>;
531
1009
  /** Platform OS mapping */
532
1010
  declare const OS_MAP: Record<string, string>;
533
1011
 
534
- /** Custom error for FRP Bridge operations */
535
- declare class FrpBridgeError extends Error {
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 {
536
1044
  readonly code: string;
537
- readonly details?: unknown | undefined;
538
- constructor(message: string, code: string, details?: unknown | undefined);
539
- }
540
- /** Error codes */
541
- declare enum ErrorCode {
542
- BINARY_NOT_FOUND = "BINARY_NOT_FOUND",
543
- DOWNLOAD_FAILED = "DOWNLOAD_FAILED",
544
- EXTRACTION_FAILED = "EXTRACTION_FAILED",
545
- CONFIG_NOT_FOUND = "CONFIG_NOT_FOUND",
546
- CONFIG_INVALID = "CONFIG_INVALID",
547
- PROCESS_ALREADY_RUNNING = "PROCESS_ALREADY_RUNNING",
548
- PROCESS_NOT_RUNNING = "PROCESS_NOT_RUNNING",
549
- PROCESS_START_FAILED = "PROCESS_START_FAILED",
550
- UNSUPPORTED_PLATFORM = "UNSUPPORTED_PLATFORM",
551
- VERSION_FETCH_FAILED = "VERSION_FETCH_FAILED",
552
- MODE_ERROR = "MODE_ERROR",
553
- NOT_FOUND = "NOT_FOUND"
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;
554
1128
  }
555
1129
 
556
1130
  declare class FileSnapshotStorage implements SnapshotStorage {
@@ -562,6 +1136,51 @@ declare class FileSnapshotStorage implements SnapshotStorage {
562
1136
  private buildPath;
563
1137
  }
564
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
+
565
1184
  /**
566
1185
  * Utility functions
567
1186
  */
@@ -582,10 +1201,16 @@ declare function executeCommand(command: string): Promise<{
582
1201
  declare function commandExists(command: string): Promise<boolean>;
583
1202
  /** Ensure directory exists */
584
1203
  declare function ensureDir(dirPath: string): void;
585
- /** Parse TOML-like config to JSON */
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
+ */
586
1209
  declare function parseToml(content: string): Record<string, any>;
587
- /** Convert JSON to TOML-like config */
1210
+ /**
1211
+ * Convert JSON to TOML-like config
1212
+ */
588
1213
  declare function toToml(obj: Record<string, any>): string;
589
1214
 
590
- export { ARCH_MAP, BINARY_NAMES, ClientNodeCollector, ErrorCode, FileNodeStorage, FileSnapshotStorage, FrpBridge, FrpBridgeError, FrpProcessManager, FrpRuntime, GITHUB_OWNER, GITHUB_REPO, NodeManager, OS_MAP, RpcClient, RpcServer, commandExists, downloadFile, ensureDir, executeCommand, getDownloadUrl, getLatestVersion, getPlatform, parseToml, toToml };
591
- export type { Awaitable, ClientCollectorOptions, CommandHandler, CommandHandlerContext, CommandMetadata, CommandResult, CommandStatus, ConfigSnapshot, FrpBridgeOptions, FrpProcessManagerOptions, NodeEvent, NodeInfo, NodeManagerOptions, NodeStorage, QueryHandler, QueryResult, RpcClientOptions, RpcServerOptions, 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 };