@hpkv/websocket-client
Version:
HPKV WebSocket client for Node.js
449 lines (345 loc) • 15 kB
Markdown
# HPKV WebSocket Client for Node.js
[](https://www.npmjs.com/package/@hpkv/websocket-client)
[](https://www.npmjs.com/package/@hpkv/websocket-client)
[](./License)
This is the official Node.js client for the HPKV WebSocket API, providing high-performance access to HPKV's real-time key-value store capabilities.
For more details, refer to the [SDK Documentation Page](https://hpkv.io/docs/sdk-guides)
## Table of Contents
- [Features](#features)
- [Installation](#installation)
- [Quick Start](#quick-start)
- [Subscription Client](#subscription-client)
- [Error Handling](#error-handling)
- [Request Throttling](#request-throttling)
- [Key Throttling Features](#key-throttling-features)
- [Configuring Throttling](#configuring-throttling)
- [Monitoring Throttling Metrics](#monitoring-throttling-metrics)
- [Connection Management](#connection-management)
- [Connection Features](#connection-features)
- [Connection Lifecycle Events](#connection-lifecycle-events)
- [Connection Configuration](#connection-configuration)
- [Monitoring Connection State](#monitoring-connection-state)
- [Reference](#reference)
- [Core Classes](#core-classes)
- [Key Types and Interfaces](#key-types-and-interfaces)
- [Response Types](#response-types)
- [License](#license)
## Features
- WebSocket-based communication for low-latency operations
- Automatic reconnection with exponential backoff
- Support for key monitoring (pub-sub) for real-time updates
- Request throttling
- Support for atomic operations
- Range queries for efficient data retrieval
- Robust error handling and type safety
## Installation
```bash
npm install @hpkv/websocket-client
```
## Quick Start
```javascript
import { HPKVClientFactory } from '@hpkv/websocket-client';
// Create an API client for server-side operations
const apiClient = HPKVClientFactory.createApiClient(
'your-api-key',
'your-api-base-url',
);
// Connect to the HPKV service
await apiClient.connect();
// Store a value
await apiClient.set('user:123', { name: 'John', age: 30 });
// Retrieve a value
const response = await apiClient.get('user:123');
console.log(response.value); // '{"name":"John","age":30}'
// Update a value (JSON patch)
await apiClient.set('user:123', { city: 'New York' }, true);
// Delete a value
await apiClient.delete('user:123');
// Range query
const users = await apiClient.range('user:', 'user:~');
console.log(users.records); // Array of user records
// Atomic increment
const counter = await apiClient.atomicIncrement('visits:page1', 1);
console.log(counter.newValue); // Current counter value
// Close connection when done
await apiClient.disconnect();
```
## Subscription Client
For real-time updates on key changes:
```javascript
import { HPKVClientFactory } from '@hpkv/websocket-client';
// First generate a token to be used for connection to websocket with subscription to provided changes.
const tokenManager = new WebsocketTokenManager(HPKV_API_KEY, HPKV_API_BASE_URL);
// Subscribe to keys matching patterns (prefixes, suffixes, or regex)
const token = await tokenManager.generateToken({
subscribePatterns: ['product:headphone:*', 'user:session:*'], // subscribe to changes matching these patterns
accessPattern: `^(product|user):*$`, // to allow CRUD operations on product and user keys
});
// Create a subscription client for real-time updates
const subscriptionClient = HPKVClientFactory.createSubscriptionClient(
token,
HPKV_API_BASE_URL,
);
// Connect to the service
await subscriptionClient.connect();
// Subscribe to changes in the subscribed keys/patterns
const subscriptionId = subscriptionClient.subscribe((notification) => {
console.log(`Key ${notification.key} changed to ${notification.value}`);
// Value is null if the key was deleted
if (notification.value === null) {
console.log(`Key ${notification.key} was deleted`);
}
});
// This get operation will succeed as the key starts with 'product:'
await subscriptionClient.get('product:phone:modelA')
// This get operation will fail as the key does not start with 'product:'
await subscriptionClient.get('order:1')
// Later, unsubscribe when no longer needed
subscriptionClient.unsubscribe(subscriptionId);
// Disconnect when done
await subscriptionClient.disconnect();
```
## Error Handling
All operations can throw exceptions for network issues, timeouts, or server errors:
```javascript
try {
const result = await apiClient.get('nonexistent-key');
console.log(result.value);
} catch (error) {
if (error.code === 404) {
console.error('Key not found');
} else {
console.error('Operation failed:', error.message);
}
}
```
## Request Throttling
The HPKV WebSocket client includes a request throttling system to help manage request rates and prevent overwhelming the server.
### Key Throttling Features
- **Rate Limiting**: Enforces a maximum number of requests per second.
- **Exponential Backoff**: Handles 429 (Too Many Requests) responses with intelligent retry logic, reducing the request rate when signaled by the server.
- **Queue Management**: Queues requests when the rate limit is exceeded, processing them as slots become available according to the limit.
- **Configurable Limits**: Customize throttling behavior to match your application needs.
### Configuring Throttling
```javascript
const apiClient = HPKVClientFactory.createApiClient('your-api-key', 'your-api-base-url', {
throttling: {
enabled: true, // Enable/disable throttling (default: true)
rateLimit: 10 // Default rate limit in requests per second
}
});
// Later, update throttling configuration
apiClient.updateThrottlingConfig({
enabled: true,
rateLimit: 20 // Increase rate limit to 20 requests per second
});
```
### Monitoring Throttling Metrics
```javascript
// Get detailed throttling metrics
const status = apiClient.getThrottlingStatus();
console.log(`Current allowed rate: ${status.metrics.currentRate} req/sec`);
console.log(`Queue length: ${status.metrics.queueLength}`);
```
The throttling system queues requests if they exceed the `currentRate`. When the server returns a 429 response, the client significantly reduces the `currentRate` and applies exponential backoff, gradually increasing the rate back towards the configured `rateLimit` once the backoff period expires.
## Connection Management
The HPKV WebSocket client implements robust connection management with automatic reconnection capabilities:
### Connection Features
- **Automatic Reconnection**: Handles network disruptions with exponential backoff
- **Connection Events**: Subscribe to connection lifecycle events
- **Connection Statistics**: Monitor connection health and performance
- **Configurable Retry Logic**: Customize reconnection behavior
### Connection Lifecycle Events
```javascript
// Subscribe to connection events
apiClient.on('connected', () => {
console.log('Connected to HPKV service');
});
apiClient.on('disconnected', (details) => {
console.log(`Disconnected: ${details.reason}`);
});
apiClient.on('reconnecting', (attempt) => {
console.log(`Reconnection attempt ${attempt.attempt}/${attempt.maxAttempts}`);
});
apiClient.on('reconnectFailed', (error) => {
console.error('Failed to reconnect after multiple attempts:', error.message);
});
apiClient.on('error', (error) => {
console.error('Connection error:', error.message);
});
```
### Connection Configuration
```javascript
const apiClient = HPKVClientFactory.createApiClient('your-api-key', 'your-api-base-url', {
// Reconnection settings
maxReconnectAttempts: 5, // Maximum reconnection attempts
initialDelayBetweenReconnects: 1000, // Initial delay in ms
maxDelayBetweenReconnects: 30000, // Maximum delay in ms
});
```
### Monitoring Connection State
```javascript
// Get current connection statistics
const stats = apiClient.getConnectionStats();
console.log(`Connected: ${stats.isConnected}`);
console.log(`State: ${stats.connectionState}`);
console.log(`Reconnect attempts: ${stats.reconnectAttempts}`);
console.log(`Pending messages: ${stats.messagesPending}`);
// Log throttling info if enabled
if (stats.throttling) {
console.log(`Throttling Rate: ${stats.throttling.currentRate} req/sec`);
console.log(`Throttling Queue: ${stats.throttling.queueLength}`);
}
```
## Reference
### Core Classes
#### `HPKVClientFactory`
Factory class for creating API and subscription clients.
| Method | Description |
| ------ | ----------- |
| `createApiClient(apiKey, baseUrl, config?)` | Creates a client for server-side operations using an API key |
| `createSubscriptionClient(token, baseUrl, config?)` | Creates a client for subscription-based operations using a token |
#### `BaseWebSocketClient`
Abstract base class for WebSocket communication with the HPKV service.
| Method | Description |
| ------ | ----------- |
| `connect()` | Establishes a WebSocket connection |
| `disconnect(cancelPendingRequests?)` | Closes the WebSocket connection |
| `get(key, timeoutMs?)` | Retrieves a value from the store |
| `set(key, value, partialUpdate?, timeoutMs?)` | Stores or updates a value |
| `delete(key, timeoutMs?)` | Deletes a value |
| `range(key, endKey, options?, timeoutMs?)` | Performs a range query |
| `atomicIncrement(key, value, timeoutMs?)` | Performs an atomic increment operation |
| `on(event, listener)` | Registers an event listener |
| `off(event, listener)` | Removes an event listener |
| `getConnectionState()` | Returns the current connection state |
| `getConnectionStats()` | Returns statistics about the connection |
| `getThrottlingStatus()` | Returns throttling configuration and metrics (current rate, queue length) |
| `updateThrottlingConfig(config)` | Updates the throttling configuration |
#### `HPKVApiClient`
Client for performing CRUD operations with API key authentication.
- Extends `BaseWebSocketClient` with API key authentication
- Used for server-side operations with full read/write access
#### `HPKVSubscriptionClient`
Client for subscribing to real-time updates using token authentication.
| Method | Description |
| ------ | ----------- |
| `subscribe(callback)` | Subscribes to changes with the provided callback |
| `unsubscribe(callbackId)` | Unsubscribes a callback |
#### `WebsocketTokenManager`
Utility for generating authentication tokens for WebSocket connections.
| Method | Description |
| ------ | ----------- |
| `generateToken(config)` | Generates an authentication token for subscription access |
### Key Types and Interfaces
This section details key exported types and interfaces you'll work with when using the SDK.
#### `ConnectionConfig`
Configuration options for the WebSocket connection.
| Property | Type | Description |
| -------- | ---- | ----------- |
| `maxReconnectAttempts` | `number` | Maximum number of reconnection attempts |
| `initialDelayBetweenReconnects` | `number` | Initial delay between reconnection attempts (ms) |
| `maxDelayBetweenReconnects` | `number` | Maximum delay between reconnection attempts (ms) |
| `connectionTimeout` | `number` | Timeout for connection attempts (ms) |
| `throttling` | `ThrottlingConfig` | Configuration for request throttling |
#### `ThrottlingConfig`
Configuration for the throttling mechanism.
| Property | Type | Description |
| -------- | ---- | ----------- |
| `enabled` | `boolean` | Whether throttling is enabled |
| `rateLimit` | `number` | Maximum requests per second |
#### `HPKVTokenConfig`
Configuration for generating authentication tokens.
| Property | Type | Description |
| -------- | ---- | ----------- |
| `subscribePatterns` | `string[]` | Key patterns the token can subscribe to (supports wildcards, prefixes, suffixes, or regex) |
| `accessPattern` | `string` | Optional regex pattern for key access control |
#### `ConnectionState`
Enum representing the connection state.
| Value | Description |
| ----- | ----------- |
| `DISCONNECTED` | Not connected |
| `CONNECTING` | Connection in progress |
| `CONNECTED` | Successfully connected |
| `DISCONNECTING` | Disconnection in progress |
#### `ConnectionStats`
Interface representing connection statistics.
| Property | Type | Description |
| -------- | ---- | ----------- |
| `isConnected` | `boolean` | Whether the client is currently connected |
| `reconnectAttempts` | `number` | Number of reconnect attempts since the last successful connection |
| `messagesPending` | `number` | Number of messages awaiting a response |
| `connectionState` | `string` (`ConnectionState` enum) | Current state of the connection |
| `throttling` | `object \| null` | Throttling metrics if enabled (contains `currentRate`, `queueLength`) |
#### `HPKVResponse`
Union type for all possible response types from the HPKV service. Most responses may include an optional `messageId` (number, linking back to the request) and `code` (number, often an HTTP-like status code).
- **`HPKVGetResponse`**: Response for GET operations.
```typescript
interface HPKVGetResponse {
key: string;
value: string | number;
code?: number;
messageId?: number;
}
```
- **`HPKVSetResponse`**: Response for SET operations.
```typescript
interface HPKVSetResponse {
success: boolean;
message?: string;
code?: number;
messageId?: number;
}
```
- **`HPKVPatchResponse`**: Response for PATCH operations (partial updates). Typically similar to `HPKVSetResponse`.
```typescript
interface HPKVPatchResponse {
success: boolean;
message?: string;
code?: number;
messageId?: number;
}
```
- **`HPKVDeleteResponse`**: Response for DELETE operations.
```typescript
interface HPKVDeleteResponse {
success: boolean;
message?: string;
code?: number;
messageId?: number;
}
```
- **`HPKVRangeResponse`**: Response for RANGE operations.
```typescript
interface HPKVRangeRecord {
key: string;
value: string | number;
}
interface HPKVRangeResponse {
records: HPKVRangeRecord[];
code?: number;
messageId?: number;
}
```
- **`HPKVAtomicResponse`**: Response for ATOMIC operations (e.g., increment).
```typescript
interface HPKVAtomicResponse {
newValue: number;
success: boolean;
code?: number;
messageId?: number;
}
```
- **`HPKVNotificationResponse`**: Data structure for key notifications in pub-sub subscriptions.
```typescript
interface HPKVNotificationResponse {
key: string;
value: string | number | null; // Value is null if the key was deleted
}
```
- **`HPKVErrorResponse`**: Structure of the error payload from the server, often wrapped by client-side exceptions.
```typescript
interface HPKVErrorResponse {
error: string;
}
```