@topgunbuild/client 0.11.0 → 0.13.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.ts 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
 
@@ -101,6 +101,8 @@ interface QueryFilter {
101
101
  limit?: number;
102
102
  /** Cursor for pagination */
103
103
  cursor?: string;
104
+ /** Optional field projection — only these fields will be returned by the server */
105
+ fields?: string[];
104
106
  }
105
107
  /** Cursor status for debugging */
106
108
  type CursorStatus = 'valid' | 'expired' | 'invalid' | 'none';
@@ -131,6 +133,10 @@ declare class QueryHandle<T> {
131
133
  private changeListeners;
132
134
  private _paginationInfo;
133
135
  private paginationListeners;
136
+ /** Field projection list — only these fields are returned by the server when set */
137
+ readonly fields: string[] | undefined;
138
+ /** Merkle root hash from last server QUERY_RESP — used for delta reconnect */
139
+ merkleRootHash: number;
134
140
  constructor(syncEngine: SyncEngine, mapName: string, filter?: QueryFilter);
135
141
  subscribe(callback: (results: QueryResultItem<T>[]) => void): () => void;
136
142
  private loadInitialLocalData;
@@ -150,7 +156,7 @@ declare class QueryHandle<T> {
150
156
  onResult(items: {
151
157
  key: string;
152
158
  value: T;
153
- }[], source?: QueryResultSource): void;
159
+ }[], source?: QueryResultSource, merkleRootHash?: number): void;
154
160
  /**
155
161
  * Called by SyncEngine when server sends a live update
156
162
  */
@@ -606,9 +612,18 @@ interface OperationDroppedEvent {
606
612
  /**
607
613
  * Connection Provider Types
608
614
  *
609
- * IConnectionProvider abstracts WebSocket connection handling to support
610
- * both single-server and cluster modes.
615
+ * IConnectionProvider abstracts connection handling to support
616
+ * both single-server and cluster modes across WebSocket and HTTP transports.
611
617
  */
618
+ /**
619
+ * Minimal connection interface capturing the actual usage pattern.
620
+ * Allows transport-agnostic code without depending on the WebSocket global.
621
+ */
622
+ interface IConnection {
623
+ send(data: ArrayBuffer | Uint8Array | string): void;
624
+ close(): void;
625
+ readonly readyState: number;
626
+ }
612
627
  /**
613
628
  * Events emitted by IConnectionProvider.
614
629
  */
@@ -618,11 +633,13 @@ type ConnectionProviderEvent = 'connected' | 'disconnected' | 'reconnected' | 'm
618
633
  */
619
634
  type ConnectionEventHandler = (...args: any[]) => void;
620
635
  /**
621
- * Abstract interface for WebSocket connection providers.
636
+ * Abstract interface for connection providers.
622
637
  *
623
638
  * Implementations:
624
639
  * - SingleServerProvider: Direct connection to a single server
625
640
  * - ClusterClient: Multi-node connection pool with partition routing
641
+ * - HttpSyncProvider: HTTP polling for serverless environments
642
+ * - AutoConnectionProvider: WebSocket-to-HTTP fallback
626
643
  */
627
644
  interface IConnectionProvider {
628
645
  /**
@@ -638,14 +655,14 @@ interface IConnectionProvider {
638
655
  * @param key - The key to route (used for partition-aware routing)
639
656
  * @throws Error if not connected
640
657
  */
641
- getConnection(key: string): WebSocket;
658
+ getConnection(key: string): IConnection;
642
659
  /**
643
660
  * Get any available connection.
644
661
  * Used for subscriptions, metadata requests, and non-key-specific operations.
645
662
  *
646
663
  * @throws Error if not connected
647
664
  */
648
- getAnyConnection(): WebSocket;
665
+ getAnyConnection(): IConnection;
649
666
  /**
650
667
  * Check if at least one connection is active and ready.
651
668
  */
@@ -680,6 +697,25 @@ interface IConnectionProvider {
680
697
  * @param key - Optional key for routing (cluster mode)
681
698
  */
682
699
  send(data: ArrayBuffer | Uint8Array, key?: string): void;
700
+ /**
701
+ * Send a batch of keyed operations with per-key routing.
702
+ * Optional -- when implemented (e.g. by ClusterClient), SyncEngine delegates
703
+ * batch sending here so each operation is routed to the correct partition owner.
704
+ * When absent, SyncEngine falls back to sending all ops in a single OP_BATCH.
705
+ *
706
+ * @param operations - Array of { key, message } pairs where key is the routing key
707
+ * @returns Map of key -> success boolean
708
+ */
709
+ sendBatch?(operations: Array<{
710
+ key: string;
711
+ message: any;
712
+ }>): Map<string, boolean>;
713
+ /**
714
+ * Force-close the current connection to trigger reconnection.
715
+ * Unlike close(), this preserves reconnect behavior so the provider
716
+ * will automatically attempt to re-establish the connection.
717
+ */
718
+ forceReconnect(): void;
683
719
  /**
684
720
  * Close all connections gracefully.
685
721
  */
@@ -691,7 +727,7 @@ interface IConnectionProvider {
691
727
  interface SingleServerProviderConfig {
692
728
  /** WebSocket URL to connect to */
693
729
  url: string;
694
- /** Maximum reconnection attempts (default: 10) */
730
+ /** Maximum reconnection attempts (default: 10). Use Infinity for unlimited. */
695
731
  maxReconnectAttempts?: number;
696
732
  /** Initial reconnect delay in ms (default: 1000) */
697
733
  reconnectDelayMs?: number;
@@ -699,6 +735,8 @@ interface SingleServerProviderConfig {
699
735
  backoffMultiplier?: number;
700
736
  /** Maximum reconnect delay in ms (default: 30000) */
701
737
  maxReconnectDelayMs?: number;
738
+ /** Listen for browser online/offline events to trigger instant reconnect (default: true) */
739
+ listenNetworkEvents?: boolean;
702
740
  }
703
741
 
704
742
  /**
@@ -1241,13 +1279,13 @@ declare class SyncEngine {
1241
1279
  matchedTerms?: string[];
1242
1280
  }>>;
1243
1281
  /**
1244
- * Handle hybrid query response from server.
1282
+ * Handle operation rejected by server (permission denied, validation failure, etc.).
1245
1283
  */
1246
- handleHybridQueryResponse(payload: HybridQueryRespPayload): void;
1284
+ private handleOpRejected;
1247
1285
  /**
1248
- * Handle hybrid query delta update from server.
1286
+ * Handle generic error message from server.
1249
1287
  */
1250
- handleHybridQueryDelta(payload: HybridQueryDeltaPayload): void;
1288
+ private handleError;
1251
1289
  }
1252
1290
 
1253
1291
  interface ILock {
@@ -2150,6 +2188,7 @@ interface ConnectionPoolEvents {
2150
2188
  'node:disconnected': (nodeId: string, reason: string) => void;
2151
2189
  'node:healthy': (nodeId: string) => void;
2152
2190
  'node:unhealthy': (nodeId: string, reason: string) => void;
2191
+ 'node:remapped': (oldId: string, newId: string) => void;
2153
2192
  'message': (nodeId: string, message: any) => void;
2154
2193
  'error': (nodeId: string, error: Error) => void;
2155
2194
  }
@@ -2177,20 +2216,25 @@ declare class ConnectionPool {
2177
2216
  * Remove a node from the connection pool
2178
2217
  */
2179
2218
  removeNode(nodeId: string): Promise<void>;
2219
+ /**
2220
+ * Remap a node from one ID to another, preserving the existing connection.
2221
+ * Used when the server-assigned node ID differs from the temporary seed ID.
2222
+ */
2223
+ remapNodeId(oldId: string, newId: string): void;
2180
2224
  /**
2181
2225
  * Get connection for a specific node
2182
2226
  */
2183
- getConnection(nodeId: string): WebSocket | null;
2227
+ getConnection(nodeId: string): IConnection | null;
2184
2228
  /**
2185
2229
  * Get primary connection (first/seed node)
2186
2230
  */
2187
- getPrimaryConnection(): WebSocket | null;
2231
+ getPrimaryConnection(): IConnection | null;
2188
2232
  /**
2189
2233
  * Get any healthy connection
2190
2234
  */
2191
2235
  getAnyHealthyConnection(): {
2192
2236
  nodeId: string;
2193
- socket: WebSocket;
2237
+ connection: IConnection;
2194
2238
  } | null;
2195
2239
  /**
2196
2240
  * Send message to a specific node
@@ -2213,7 +2257,7 @@ declare class ConnectionPool {
2213
2257
  */
2214
2258
  getAllNodes(): string[];
2215
2259
  /**
2216
- * Check if node is connected and authenticated
2260
+ * Check if node has an open WebSocket connection
2217
2261
  */
2218
2262
  isNodeConnected(nodeId: string): boolean;
2219
2263
  /**
@@ -2290,7 +2334,7 @@ declare class PartitionRouter {
2290
2334
  */
2291
2335
  routeToConnection(key: string): {
2292
2336
  nodeId: string;
2293
- socket: WebSocket;
2337
+ connection: IConnection;
2294
2338
  } | null;
2295
2339
  /**
2296
2340
  * Get routing info for multiple keys (batch routing)
@@ -2431,6 +2475,8 @@ declare class ClusterClient implements IConnectionProvider {
2431
2475
  private readonly routingMetrics;
2432
2476
  private readonly circuits;
2433
2477
  private readonly circuitBreakerConfig;
2478
+ private partitionMapRequestTimer;
2479
+ private static readonly PARTITION_MAP_REQUEST_DEBOUNCE_MS;
2434
2480
  constructor(config: ClusterClientConfig);
2435
2481
  on(event: string, listener: (...args: any[]) => void): this;
2436
2482
  off(event: string, listener: (...args: any[]) => void): this;
@@ -2446,7 +2492,7 @@ declare class ClusterClient implements IConnectionProvider {
2446
2492
  * Routes to partition owner based on key hash when smart routing is enabled.
2447
2493
  * @throws Error if not connected
2448
2494
  */
2449
- getConnection(key: string): WebSocket;
2495
+ getConnection(key: string): IConnection;
2450
2496
  /**
2451
2497
  * Get fallback connection when owner is unavailable.
2452
2498
  * @throws Error if no connection available
@@ -2457,9 +2503,15 @@ declare class ClusterClient implements IConnectionProvider {
2457
2503
  * Called when routing to an unknown/disconnected owner.
2458
2504
  */
2459
2505
  private requestPartitionMapRefresh;
2506
+ /**
2507
+ * Debounce partition map requests to prevent flooding when multiple nodes
2508
+ * reconnect simultaneously. Coalesces rapid requests into a single request
2509
+ * sent to the most recently connected node.
2510
+ */
2511
+ private debouncedPartitionMapRequest;
2460
2512
  /**
2461
2513
  * Request partition map from a specific node.
2462
- * Called on first node connection.
2514
+ * Called on node connection via debounced handler.
2463
2515
  */
2464
2516
  private requestPartitionMapFromNode;
2465
2517
  /**
@@ -2555,6 +2607,10 @@ declare class ClusterClient implements IConnectionProvider {
2555
2607
  * Force refresh of partition map
2556
2608
  */
2557
2609
  refreshPartitionMap(): Promise<void>;
2610
+ /**
2611
+ * Force reconnect all connections in the pool.
2612
+ */
2613
+ forceReconnect(): void;
2558
2614
  /**
2559
2615
  * Shutdown cluster client (IConnectionProvider interface).
2560
2616
  */
@@ -2568,15 +2624,15 @@ declare class ClusterClient implements IConnectionProvider {
2568
2624
  */
2569
2625
  getPartitionRouter(): PartitionRouter;
2570
2626
  /**
2571
- * Get any healthy WebSocket connection (IConnectionProvider interface).
2627
+ * Get any healthy connection (IConnectionProvider interface).
2572
2628
  * @throws Error if not connected
2573
2629
  */
2574
- getAnyConnection(): WebSocket;
2630
+ getAnyConnection(): IConnection;
2575
2631
  /**
2576
- * Get any healthy WebSocket connection, or null if none available.
2632
+ * Get any healthy connection, or null if none available.
2577
2633
  * Use this for optional connection checks.
2578
2634
  */
2579
- getAnyConnectionOrNull(): WebSocket | null;
2635
+ getAnyConnectionOrNull(): IConnection | null;
2580
2636
  /**
2581
2637
  * Get circuit breaker state for a node.
2582
2638
  */
@@ -2625,6 +2681,8 @@ declare class SingleServerProvider implements IConnectionProvider {
2625
2681
  private reconnectTimer;
2626
2682
  private isClosing;
2627
2683
  private listeners;
2684
+ private onlineHandler;
2685
+ private offlineHandler;
2628
2686
  constructor(config: SingleServerProviderConfig);
2629
2687
  /**
2630
2688
  * Connect to the WebSocket server.
@@ -2634,11 +2692,11 @@ declare class SingleServerProvider implements IConnectionProvider {
2634
2692
  * Get connection for a specific key.
2635
2693
  * In single-server mode, key is ignored.
2636
2694
  */
2637
- getConnection(_key: string): WebSocket;
2695
+ getConnection(_key: string): IConnection;
2638
2696
  /**
2639
2697
  * Get any available connection.
2640
2698
  */
2641
- getAnyConnection(): WebSocket;
2699
+ getAnyConnection(): IConnection;
2642
2700
  /**
2643
2701
  * Check if connected.
2644
2702
  */
@@ -2677,6 +2735,17 @@ declare class SingleServerProvider implements IConnectionProvider {
2677
2735
  * Calculate backoff delay with exponential increase.
2678
2736
  */
2679
2737
  private calculateBackoffDelay;
2738
+ /**
2739
+ * Force-close the current WebSocket and immediately schedule reconnection.
2740
+ * Unlike close(), this does NOT set isClosing and preserves reconnect behavior.
2741
+ * Resets the reconnect counter so the full backoff budget is available.
2742
+ *
2743
+ * Critically, this does NOT wait for the TCP close handshake (which can
2744
+ * hang 20+ seconds on a dead network). Instead it strips all handlers from
2745
+ * the old WebSocket, fires a best-effort close(), nulls the reference, and
2746
+ * schedules reconnect right away.
2747
+ */
2748
+ forceReconnect(): void;
2680
2749
  /**
2681
2750
  * Get the WebSocket URL this provider connects to.
2682
2751
  */
@@ -2690,6 +2759,15 @@ declare class SingleServerProvider implements IConnectionProvider {
2690
2759
  * Called externally after successful authentication.
2691
2760
  */
2692
2761
  resetReconnectAttempts(): void;
2762
+ /**
2763
+ * Listen for browser 'online' event to trigger instant reconnect
2764
+ * when network comes back. Only active in browser environments.
2765
+ */
2766
+ private setupNetworkListeners;
2767
+ /**
2768
+ * Remove browser network event listeners.
2769
+ */
2770
+ private teardownNetworkListeners;
2693
2771
  }
2694
2772
 
2695
2773
  /**
@@ -2753,14 +2831,14 @@ declare class HttpSyncProvider implements IConnectionProvider {
2753
2831
  connect(): Promise<void>;
2754
2832
  /**
2755
2833
  * Get connection for a specific key.
2756
- * HTTP mode does not expose raw WebSocket connections.
2834
+ * Returns an HttpConnection that queues operations for the next poll cycle.
2757
2835
  */
2758
- getConnection(_key: string): WebSocket;
2836
+ getConnection(_key: string): IConnection;
2759
2837
  /**
2760
2838
  * Get any available connection.
2761
- * HTTP mode does not expose raw WebSocket connections.
2839
+ * Returns an HttpConnection that queues operations for the next poll cycle.
2762
2840
  */
2763
- getAnyConnection(): WebSocket;
2841
+ getAnyConnection(): IConnection;
2764
2842
  /**
2765
2843
  * Check if connected (last HTTP request succeeded).
2766
2844
  */
@@ -2789,6 +2867,10 @@ declare class HttpSyncProvider implements IConnectionProvider {
2789
2867
  * - All other types: silently dropped with debug log
2790
2868
  */
2791
2869
  send(data: ArrayBuffer | Uint8Array, _key?: string): void;
2870
+ /**
2871
+ * Force reconnect by restarting the polling loop.
2872
+ */
2873
+ forceReconnect(): void;
2792
2874
  /**
2793
2875
  * Close the HTTP sync provider.
2794
2876
  * Stops the polling loop, clears queued operations, and sets disconnected state.
@@ -2864,13 +2946,17 @@ declare class AutoConnectionProvider implements IConnectionProvider {
2864
2946
  * Connect using HTTP sync provider.
2865
2947
  */
2866
2948
  private connectHttp;
2867
- getConnection(key: string): WebSocket;
2868
- getAnyConnection(): WebSocket;
2949
+ getConnection(key: string): IConnection;
2950
+ getAnyConnection(): IConnection;
2869
2951
  isConnected(): boolean;
2870
2952
  getConnectedNodes(): string[];
2871
2953
  on(event: ConnectionProviderEvent, handler: ConnectionEventHandler): void;
2872
2954
  off(event: ConnectionProviderEvent, handler: ConnectionEventHandler): void;
2873
2955
  send(data: ArrayBuffer | Uint8Array, key?: string): void;
2956
+ /**
2957
+ * Force reconnect by delegating to the active provider.
2958
+ */
2959
+ forceReconnect(): void;
2874
2960
  /**
2875
2961
  * Close the active underlying provider.
2876
2962
  */
@@ -2893,6 +2979,29 @@ declare class AutoConnectionProvider implements IConnectionProvider {
2893
2979
  private toHttpUrl;
2894
2980
  }
2895
2981
 
2982
+ /**
2983
+ * Ready-state constants matching the WebSocket spec values.
2984
+ * Allows callers to compare readyState without depending on the WebSocket global.
2985
+ */
2986
+ declare const ConnectionReadyState: {
2987
+ readonly CONNECTING: 0;
2988
+ readonly OPEN: 1;
2989
+ readonly CLOSING: 2;
2990
+ readonly CLOSED: 3;
2991
+ };
2992
+ /**
2993
+ * Thin adapter that wraps a raw WebSocket and exposes only the IConnection
2994
+ * surface. This keeps the concrete WebSocket type out of public return types
2995
+ * while adding zero overhead.
2996
+ */
2997
+ declare class WebSocketConnection implements IConnection {
2998
+ private readonly ws;
2999
+ constructor(ws: WebSocket);
3000
+ send(data: ArrayBuffer | Uint8Array | string): void;
3001
+ close(): void;
3002
+ get readyState(): number;
3003
+ }
3004
+
2896
3005
  declare const logger: pino.Logger<never, boolean>;
2897
3006
 
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 };
3007
+ 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 };