@topgunbuild/client 0.11.0 → 0.12.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/index.d.mts CHANGED
@@ -1,4 +1,4 @@
1
- import { LWWRecord, ORMapRecord, PredicateNode, ConflictResolverDef, MergeRejection, Timestamp, LWWMap, ORMap, HLC, EntryProcessorDef, EntryProcessorResult, SearchOptions, HybridQueryRespPayload, HybridQueryDeltaPayload, PNCounter, PNCounterState, JournalEvent, JournalEventType, NodeHealth, ConnectionPoolConfig, PartitionRouterConfig, PartitionMap, ClusterClientConfig } from '@topgunbuild/core';
1
+ import { LWWRecord, ORMapRecord, PredicateNode, ConflictResolverDef, MergeRejection, Timestamp, LWWMap, ORMap, HLC, EntryProcessorDef, EntryProcessorResult, SearchOptions, PNCounter, PNCounterState, JournalEvent, JournalEventType, NodeHealth, ConnectionPoolConfig, PartitionRouterConfig, PartitionMap, ClusterClientConfig } from '@topgunbuild/core';
2
2
  export { LWWMap, LWWRecord, PredicateNode, Predicates } from '@topgunbuild/core';
3
3
  import pino from 'pino';
4
4
 
@@ -606,9 +606,18 @@ interface OperationDroppedEvent {
606
606
  /**
607
607
  * Connection Provider Types
608
608
  *
609
- * IConnectionProvider abstracts WebSocket connection handling to support
610
- * both single-server and cluster modes.
609
+ * IConnectionProvider abstracts connection handling to support
610
+ * both single-server and cluster modes across WebSocket and HTTP transports.
611
611
  */
612
+ /**
613
+ * Minimal connection interface capturing the actual usage pattern.
614
+ * Allows transport-agnostic code without depending on the WebSocket global.
615
+ */
616
+ interface IConnection {
617
+ send(data: ArrayBuffer | Uint8Array | string): void;
618
+ close(): void;
619
+ readonly readyState: number;
620
+ }
612
621
  /**
613
622
  * Events emitted by IConnectionProvider.
614
623
  */
@@ -618,11 +627,13 @@ type ConnectionProviderEvent = 'connected' | 'disconnected' | 'reconnected' | 'm
618
627
  */
619
628
  type ConnectionEventHandler = (...args: any[]) => void;
620
629
  /**
621
- * Abstract interface for WebSocket connection providers.
630
+ * Abstract interface for connection providers.
622
631
  *
623
632
  * Implementations:
624
633
  * - SingleServerProvider: Direct connection to a single server
625
634
  * - ClusterClient: Multi-node connection pool with partition routing
635
+ * - HttpSyncProvider: HTTP polling for serverless environments
636
+ * - AutoConnectionProvider: WebSocket-to-HTTP fallback
626
637
  */
627
638
  interface IConnectionProvider {
628
639
  /**
@@ -638,14 +649,14 @@ interface IConnectionProvider {
638
649
  * @param key - The key to route (used for partition-aware routing)
639
650
  * @throws Error if not connected
640
651
  */
641
- getConnection(key: string): WebSocket;
652
+ getConnection(key: string): IConnection;
642
653
  /**
643
654
  * Get any available connection.
644
655
  * Used for subscriptions, metadata requests, and non-key-specific operations.
645
656
  *
646
657
  * @throws Error if not connected
647
658
  */
648
- getAnyConnection(): WebSocket;
659
+ getAnyConnection(): IConnection;
649
660
  /**
650
661
  * Check if at least one connection is active and ready.
651
662
  */
@@ -680,6 +691,25 @@ interface IConnectionProvider {
680
691
  * @param key - Optional key for routing (cluster mode)
681
692
  */
682
693
  send(data: ArrayBuffer | Uint8Array, key?: string): void;
694
+ /**
695
+ * Send a batch of keyed operations with per-key routing.
696
+ * Optional -- when implemented (e.g. by ClusterClient), SyncEngine delegates
697
+ * batch sending here so each operation is routed to the correct partition owner.
698
+ * When absent, SyncEngine falls back to sending all ops in a single OP_BATCH.
699
+ *
700
+ * @param operations - Array of { key, message } pairs where key is the routing key
701
+ * @returns Map of key -> success boolean
702
+ */
703
+ sendBatch?(operations: Array<{
704
+ key: string;
705
+ message: any;
706
+ }>): Map<string, boolean>;
707
+ /**
708
+ * Force-close the current connection to trigger reconnection.
709
+ * Unlike close(), this preserves reconnect behavior so the provider
710
+ * will automatically attempt to re-establish the connection.
711
+ */
712
+ forceReconnect(): void;
683
713
  /**
684
714
  * Close all connections gracefully.
685
715
  */
@@ -691,7 +721,7 @@ interface IConnectionProvider {
691
721
  interface SingleServerProviderConfig {
692
722
  /** WebSocket URL to connect to */
693
723
  url: string;
694
- /** Maximum reconnection attempts (default: 10) */
724
+ /** Maximum reconnection attempts (default: 10). Use Infinity for unlimited. */
695
725
  maxReconnectAttempts?: number;
696
726
  /** Initial reconnect delay in ms (default: 1000) */
697
727
  reconnectDelayMs?: number;
@@ -699,6 +729,8 @@ interface SingleServerProviderConfig {
699
729
  backoffMultiplier?: number;
700
730
  /** Maximum reconnect delay in ms (default: 30000) */
701
731
  maxReconnectDelayMs?: number;
732
+ /** Listen for browser online/offline events to trigger instant reconnect (default: true) */
733
+ listenNetworkEvents?: boolean;
702
734
  }
703
735
 
704
736
  /**
@@ -1241,13 +1273,13 @@ declare class SyncEngine {
1241
1273
  matchedTerms?: string[];
1242
1274
  }>>;
1243
1275
  /**
1244
- * Handle hybrid query response from server.
1276
+ * Handle operation rejected by server (permission denied, validation failure, etc.).
1245
1277
  */
1246
- handleHybridQueryResponse(payload: HybridQueryRespPayload): void;
1278
+ private handleOpRejected;
1247
1279
  /**
1248
- * Handle hybrid query delta update from server.
1280
+ * Handle generic error message from server.
1249
1281
  */
1250
- handleHybridQueryDelta(payload: HybridQueryDeltaPayload): void;
1282
+ private handleError;
1251
1283
  }
1252
1284
 
1253
1285
  interface ILock {
@@ -2150,6 +2182,7 @@ interface ConnectionPoolEvents {
2150
2182
  'node:disconnected': (nodeId: string, reason: string) => void;
2151
2183
  'node:healthy': (nodeId: string) => void;
2152
2184
  'node:unhealthy': (nodeId: string, reason: string) => void;
2185
+ 'node:remapped': (oldId: string, newId: string) => void;
2153
2186
  'message': (nodeId: string, message: any) => void;
2154
2187
  'error': (nodeId: string, error: Error) => void;
2155
2188
  }
@@ -2177,20 +2210,25 @@ declare class ConnectionPool {
2177
2210
  * Remove a node from the connection pool
2178
2211
  */
2179
2212
  removeNode(nodeId: string): Promise<void>;
2213
+ /**
2214
+ * Remap a node from one ID to another, preserving the existing connection.
2215
+ * Used when the server-assigned node ID differs from the temporary seed ID.
2216
+ */
2217
+ remapNodeId(oldId: string, newId: string): void;
2180
2218
  /**
2181
2219
  * Get connection for a specific node
2182
2220
  */
2183
- getConnection(nodeId: string): WebSocket | null;
2221
+ getConnection(nodeId: string): IConnection | null;
2184
2222
  /**
2185
2223
  * Get primary connection (first/seed node)
2186
2224
  */
2187
- getPrimaryConnection(): WebSocket | null;
2225
+ getPrimaryConnection(): IConnection | null;
2188
2226
  /**
2189
2227
  * Get any healthy connection
2190
2228
  */
2191
2229
  getAnyHealthyConnection(): {
2192
2230
  nodeId: string;
2193
- socket: WebSocket;
2231
+ connection: IConnection;
2194
2232
  } | null;
2195
2233
  /**
2196
2234
  * Send message to a specific node
@@ -2213,7 +2251,7 @@ declare class ConnectionPool {
2213
2251
  */
2214
2252
  getAllNodes(): string[];
2215
2253
  /**
2216
- * Check if node is connected and authenticated
2254
+ * Check if node has an open WebSocket connection
2217
2255
  */
2218
2256
  isNodeConnected(nodeId: string): boolean;
2219
2257
  /**
@@ -2290,7 +2328,7 @@ declare class PartitionRouter {
2290
2328
  */
2291
2329
  routeToConnection(key: string): {
2292
2330
  nodeId: string;
2293
- socket: WebSocket;
2331
+ connection: IConnection;
2294
2332
  } | null;
2295
2333
  /**
2296
2334
  * Get routing info for multiple keys (batch routing)
@@ -2431,6 +2469,8 @@ declare class ClusterClient implements IConnectionProvider {
2431
2469
  private readonly routingMetrics;
2432
2470
  private readonly circuits;
2433
2471
  private readonly circuitBreakerConfig;
2472
+ private partitionMapRequestTimer;
2473
+ private static readonly PARTITION_MAP_REQUEST_DEBOUNCE_MS;
2434
2474
  constructor(config: ClusterClientConfig);
2435
2475
  on(event: string, listener: (...args: any[]) => void): this;
2436
2476
  off(event: string, listener: (...args: any[]) => void): this;
@@ -2446,7 +2486,7 @@ declare class ClusterClient implements IConnectionProvider {
2446
2486
  * Routes to partition owner based on key hash when smart routing is enabled.
2447
2487
  * @throws Error if not connected
2448
2488
  */
2449
- getConnection(key: string): WebSocket;
2489
+ getConnection(key: string): IConnection;
2450
2490
  /**
2451
2491
  * Get fallback connection when owner is unavailable.
2452
2492
  * @throws Error if no connection available
@@ -2457,9 +2497,15 @@ declare class ClusterClient implements IConnectionProvider {
2457
2497
  * Called when routing to an unknown/disconnected owner.
2458
2498
  */
2459
2499
  private requestPartitionMapRefresh;
2500
+ /**
2501
+ * Debounce partition map requests to prevent flooding when multiple nodes
2502
+ * reconnect simultaneously. Coalesces rapid requests into a single request
2503
+ * sent to the most recently connected node.
2504
+ */
2505
+ private debouncedPartitionMapRequest;
2460
2506
  /**
2461
2507
  * Request partition map from a specific node.
2462
- * Called on first node connection.
2508
+ * Called on node connection via debounced handler.
2463
2509
  */
2464
2510
  private requestPartitionMapFromNode;
2465
2511
  /**
@@ -2555,6 +2601,10 @@ declare class ClusterClient implements IConnectionProvider {
2555
2601
  * Force refresh of partition map
2556
2602
  */
2557
2603
  refreshPartitionMap(): Promise<void>;
2604
+ /**
2605
+ * Force reconnect all connections in the pool.
2606
+ */
2607
+ forceReconnect(): void;
2558
2608
  /**
2559
2609
  * Shutdown cluster client (IConnectionProvider interface).
2560
2610
  */
@@ -2568,15 +2618,15 @@ declare class ClusterClient implements IConnectionProvider {
2568
2618
  */
2569
2619
  getPartitionRouter(): PartitionRouter;
2570
2620
  /**
2571
- * Get any healthy WebSocket connection (IConnectionProvider interface).
2621
+ * Get any healthy connection (IConnectionProvider interface).
2572
2622
  * @throws Error if not connected
2573
2623
  */
2574
- getAnyConnection(): WebSocket;
2624
+ getAnyConnection(): IConnection;
2575
2625
  /**
2576
- * Get any healthy WebSocket connection, or null if none available.
2626
+ * Get any healthy connection, or null if none available.
2577
2627
  * Use this for optional connection checks.
2578
2628
  */
2579
- getAnyConnectionOrNull(): WebSocket | null;
2629
+ getAnyConnectionOrNull(): IConnection | null;
2580
2630
  /**
2581
2631
  * Get circuit breaker state for a node.
2582
2632
  */
@@ -2625,6 +2675,8 @@ declare class SingleServerProvider implements IConnectionProvider {
2625
2675
  private reconnectTimer;
2626
2676
  private isClosing;
2627
2677
  private listeners;
2678
+ private onlineHandler;
2679
+ private offlineHandler;
2628
2680
  constructor(config: SingleServerProviderConfig);
2629
2681
  /**
2630
2682
  * Connect to the WebSocket server.
@@ -2634,11 +2686,11 @@ declare class SingleServerProvider implements IConnectionProvider {
2634
2686
  * Get connection for a specific key.
2635
2687
  * In single-server mode, key is ignored.
2636
2688
  */
2637
- getConnection(_key: string): WebSocket;
2689
+ getConnection(_key: string): IConnection;
2638
2690
  /**
2639
2691
  * Get any available connection.
2640
2692
  */
2641
- getAnyConnection(): WebSocket;
2693
+ getAnyConnection(): IConnection;
2642
2694
  /**
2643
2695
  * Check if connected.
2644
2696
  */
@@ -2677,6 +2729,17 @@ declare class SingleServerProvider implements IConnectionProvider {
2677
2729
  * Calculate backoff delay with exponential increase.
2678
2730
  */
2679
2731
  private calculateBackoffDelay;
2732
+ /**
2733
+ * Force-close the current WebSocket and immediately schedule reconnection.
2734
+ * Unlike close(), this does NOT set isClosing and preserves reconnect behavior.
2735
+ * Resets the reconnect counter so the full backoff budget is available.
2736
+ *
2737
+ * Critically, this does NOT wait for the TCP close handshake (which can
2738
+ * hang 20+ seconds on a dead network). Instead it strips all handlers from
2739
+ * the old WebSocket, fires a best-effort close(), nulls the reference, and
2740
+ * schedules reconnect right away.
2741
+ */
2742
+ forceReconnect(): void;
2680
2743
  /**
2681
2744
  * Get the WebSocket URL this provider connects to.
2682
2745
  */
@@ -2690,6 +2753,15 @@ declare class SingleServerProvider implements IConnectionProvider {
2690
2753
  * Called externally after successful authentication.
2691
2754
  */
2692
2755
  resetReconnectAttempts(): void;
2756
+ /**
2757
+ * Listen for browser 'online' event to trigger instant reconnect
2758
+ * when network comes back. Only active in browser environments.
2759
+ */
2760
+ private setupNetworkListeners;
2761
+ /**
2762
+ * Remove browser network event listeners.
2763
+ */
2764
+ private teardownNetworkListeners;
2693
2765
  }
2694
2766
 
2695
2767
  /**
@@ -2753,14 +2825,14 @@ declare class HttpSyncProvider implements IConnectionProvider {
2753
2825
  connect(): Promise<void>;
2754
2826
  /**
2755
2827
  * Get connection for a specific key.
2756
- * HTTP mode does not expose raw WebSocket connections.
2828
+ * Returns an HttpConnection that queues operations for the next poll cycle.
2757
2829
  */
2758
- getConnection(_key: string): WebSocket;
2830
+ getConnection(_key: string): IConnection;
2759
2831
  /**
2760
2832
  * Get any available connection.
2761
- * HTTP mode does not expose raw WebSocket connections.
2833
+ * Returns an HttpConnection that queues operations for the next poll cycle.
2762
2834
  */
2763
- getAnyConnection(): WebSocket;
2835
+ getAnyConnection(): IConnection;
2764
2836
  /**
2765
2837
  * Check if connected (last HTTP request succeeded).
2766
2838
  */
@@ -2789,6 +2861,10 @@ declare class HttpSyncProvider implements IConnectionProvider {
2789
2861
  * - All other types: silently dropped with debug log
2790
2862
  */
2791
2863
  send(data: ArrayBuffer | Uint8Array, _key?: string): void;
2864
+ /**
2865
+ * Force reconnect by restarting the polling loop.
2866
+ */
2867
+ forceReconnect(): void;
2792
2868
  /**
2793
2869
  * Close the HTTP sync provider.
2794
2870
  * Stops the polling loop, clears queued operations, and sets disconnected state.
@@ -2864,13 +2940,17 @@ declare class AutoConnectionProvider implements IConnectionProvider {
2864
2940
  * Connect using HTTP sync provider.
2865
2941
  */
2866
2942
  private connectHttp;
2867
- getConnection(key: string): WebSocket;
2868
- getAnyConnection(): WebSocket;
2943
+ getConnection(key: string): IConnection;
2944
+ getAnyConnection(): IConnection;
2869
2945
  isConnected(): boolean;
2870
2946
  getConnectedNodes(): string[];
2871
2947
  on(event: ConnectionProviderEvent, handler: ConnectionEventHandler): void;
2872
2948
  off(event: ConnectionProviderEvent, handler: ConnectionEventHandler): void;
2873
2949
  send(data: ArrayBuffer | Uint8Array, key?: string): void;
2950
+ /**
2951
+ * Force reconnect by delegating to the active provider.
2952
+ */
2953
+ forceReconnect(): void;
2874
2954
  /**
2875
2955
  * Close the active underlying provider.
2876
2956
  */
@@ -2893,6 +2973,29 @@ declare class AutoConnectionProvider implements IConnectionProvider {
2893
2973
  private toHttpUrl;
2894
2974
  }
2895
2975
 
2976
+ /**
2977
+ * Ready-state constants matching the WebSocket spec values.
2978
+ * Allows callers to compare readyState without depending on the WebSocket global.
2979
+ */
2980
+ declare const ConnectionReadyState: {
2981
+ readonly CONNECTING: 0;
2982
+ readonly OPEN: 1;
2983
+ readonly CLOSING: 2;
2984
+ readonly CLOSED: 3;
2985
+ };
2986
+ /**
2987
+ * Thin adapter that wraps a raw WebSocket and exposes only the IConnection
2988
+ * surface. This keeps the concrete WebSocket type out of public return types
2989
+ * while adding zero overhead.
2990
+ */
2991
+ declare class WebSocketConnection implements IConnection {
2992
+ private readonly ws;
2993
+ constructor(ws: WebSocket);
2994
+ send(data: ArrayBuffer | Uint8Array | string): void;
2995
+ close(): void;
2996
+ get readyState(): number;
2997
+ }
2998
+
2896
2999
  declare const logger: pino.Logger<never, boolean>;
2897
3000
 
2898
- export { AutoConnectionProvider, type AutoConnectionProviderConfig, type BackoffConfig, type BackpressureConfig, BackpressureError, type BackpressureStatus, type BackpressureStrategy, type BackpressureThresholdEvent, type ChangeEvent, ChangeTracker, type CircuitState, ClusterClient, type ClusterClientEvents, type ClusterRoutingMode, ConflictResolverClient, type ConnectionEventHandler, ConnectionPool, type ConnectionPoolEvents, type ConnectionProviderEvent, type CursorStatus, DEFAULT_BACKPRESSURE_CONFIG, DEFAULT_CLUSTER_CONFIG, EncryptedStorageAdapter, EventJournalReader, type HeartbeatConfig, HttpSyncProvider, type HttpSyncProviderConfig, type HybridQueryFilter, HybridQueryHandle, type HybridResultItem, type HybridResultSource, type IConnectionProvider, IDBAdapter, type IStorageAdapter, type JournalEventData, type JournalSubscribeOptions, type OpLogEntry, type OperationDroppedEvent, PNCounterHandle, type PaginationInfo, PartitionRouter, type PartitionRouterEvents, type QueryFilter, QueryHandle, type QueryResultItem, type QueryResultSource, type RegisterResult, type ResolverInfo, type RoutingMetrics, type RoutingResult, SearchHandle, type SearchResult, type SearchResultsCallback, SingleServerProvider, type SingleServerProviderConfig, type StateChangeEvent, type StateChangeListener, SyncEngine, type SyncEngineConfig, SyncState, SyncStateMachine, type SyncStateMachineConfig, TopGun, TopGunClient, type TopGunClientConfig, type TopGunClusterConfig, type TopicCallback, TopicHandle, VALID_TRANSITIONS, isValidTransition, logger };
3001
+ export { AutoConnectionProvider, type AutoConnectionProviderConfig, type BackoffConfig, type BackpressureConfig, BackpressureError, type BackpressureStatus, type BackpressureStrategy, type BackpressureThresholdEvent, type ChangeEvent, ChangeTracker, type CircuitState, ClusterClient, type ClusterClientEvents, type ClusterRoutingMode, ConflictResolverClient, type ConnectionEventHandler, ConnectionPool, type ConnectionPoolEvents, type ConnectionProviderEvent, ConnectionReadyState, type CursorStatus, DEFAULT_BACKPRESSURE_CONFIG, DEFAULT_CLUSTER_CONFIG, EncryptedStorageAdapter, EventJournalReader, type HeartbeatConfig, HttpSyncProvider, type HttpSyncProviderConfig, type HybridQueryFilter, HybridQueryHandle, type HybridResultItem, type HybridResultSource, type IConnection, type IConnectionProvider, IDBAdapter, type IStorageAdapter, type JournalEventData, type JournalSubscribeOptions, type OpLogEntry, type OperationDroppedEvent, PNCounterHandle, type PaginationInfo, PartitionRouter, type PartitionRouterEvents, type QueryFilter, QueryHandle, type QueryResultItem, type QueryResultSource, type RegisterResult, type ResolverInfo, type RoutingMetrics, type RoutingResult, SearchHandle, type SearchResult, type SearchResultsCallback, SingleServerProvider, type SingleServerProviderConfig, type StateChangeEvent, type StateChangeListener, SyncEngine, type SyncEngineConfig, SyncState, SyncStateMachine, type SyncStateMachineConfig, TopGun, TopGunClient, type TopGunClientConfig, type TopGunClusterConfig, type TopicCallback, TopicHandle, VALID_TRANSITIONS, WebSocketConnection, isValidTransition, logger };