UNPKG

@hpkv/zustand-multiplayer

Version:

A multiplayer middleware for Zustand using HPKV

168 lines (160 loc) 5.32 kB
import { StoreMutatorIdentifier, StateCreator } from 'zustand/vanilla'; import { ConnectionStats, ConnectionState } from '@hpkv/websocket-client'; import { StoreApi } from 'zustand'; declare enum LogLevel { DEBUG = 0, INFO = 1, WARN = 2, ERROR = 3, NONE = 4 } interface LogContext { clientId?: string; operation?: string; timestamp: number; [key: string]: unknown; } declare class Logger { private level; constructor(level?: LogLevel); private shouldLog; private formatMessage; debug(message: string, context?: Partial<LogContext>): void; info(message: string, context?: Partial<LogContext>): void; warn(message: string, context?: Partial<LogContext>): void; error(message: string, error?: Error, context?: Partial<LogContext>): void; setLevel(level: LogLevel): void; getLevel(): LogLevel; } /** * Creates a new logger instance with the specified log level * @param level The log level for the logger * @returns A new Logger instance */ declare function createLogger(level?: LogLevel): Logger; interface PerformanceMetrics { averageSyncTime: number; } interface MultiplayerOptions<TState> { namespace: string; apiBaseUrl: string; apiKey?: string; tokenGenerationUrl?: string; sync?: Array<keyof TState>; logLevel?: LogLevel; rateLimit?: number; zFactor?: number; } interface MultiplayerState { connectionState: ConnectionState; hasHydrated: boolean; performanceMetrics: PerformanceMetrics; } type MultiplayerStoreApi<S> = StoreApi<S> & { multiplayer: { reHydrate: () => Promise<void>; clearStorage: () => Promise<void>; disconnect: () => Promise<void>; connect: () => Promise<void>; destroy: () => Promise<void>; getConnectionStatus: () => ConnectionStats | null; getMetrics: () => PerformanceMetrics; }; }; type WithMultiplayer<S> = S & { multiplayer: MultiplayerState; }; type MultiplayerStore<S, _U> = S extends { getState: () => infer T; } ? MultiplayerStoreApi<T> : never; declare module 'zustand/vanilla' { interface StoreMutators<S, A> { 'zustand/multiplayer': MultiplayerStore<S, A>; } } /** * Main multiplayer middleware type */ type Multiplayer = <T, Mps extends [StoreMutatorIdentifier, unknown][] = [], Mcs extends [StoreMutatorIdentifier, unknown][] = []>(initializer: StateCreator<T, [ ...Mps, ['zustand/multiplayer', never] ], Mcs, Omit<T, 'multiplayer'>>, options: MultiplayerOptions<Omit<T, 'multiplayer'>>) => StateCreator<T, Mps, [['zustand/multiplayer', never], ...Mcs], WithMultiplayer<T>>; declare const multiplayer: Multiplayer; /** * Generates a cryptographically secure unique client identifier * @returns A unique client identifier string */ declare function generateClientId(): string; /** * Normalizes an error to ensure it's an Error instance * @param error The error to normalize * @returns A normalized Error instance */ declare function normalizeError(error: unknown): Error; /** * Creates a delay promise * @param ms Milliseconds to delay * @returns Promise that resolves after the delay */ declare function createDelay(ms: number): Promise<void>; /** * Safely clears a timeout * @param timeoutId The timeout ID to clear */ declare function clearTimeoutSafely(timeoutId: ReturnType<typeof setTimeout> | null): void; /** * Escapes special characters in a string for use in a regular expression * @param string The string to escape * @returns The escaped string */ declare function escapeRegExp(string: string): string; /** * Type guard to check if a value is a plain object * @param value The value to check * @returns True if the value is a plain object */ declare function isPlainObject(value: unknown): value is Record<string, unknown>; /** * Request format for token generation endpoint */ interface TokenRequest { /** Store name to generate token for */ namespace: string; /** Keys and patterns to subscribe to */ subscribedKeysAndPatterns: string[]; } /** * Response format from token generation endpoint */ interface TokenResponse { /** The namespace the token is for */ namespace: string; /** The generated WebSocket token */ token: string; } /** * Utility to help generate WebSocket tokens for HPKV */ declare class TokenHelper { private readonly tokenManager; /** * Creates a new TokenHelper instance * * @param apiKey HPKV API key * @param baseUrl HPKV base URL */ constructor(apiKey: string, baseUrl: string); /** * Generate a token for a store with the given namespace and keys */ generateTokenForStore(namespace: string, subscribedKeysAnPatterns: string[]): Promise<string>; /** * Process a token request and return a token response * * @param requestData The request data object or string * @returns TokenResponse object with the generated token */ processTokenRequest(requestData: unknown): Promise<TokenResponse>; } export { LogLevel, Logger, TokenHelper, clearTimeoutSafely, createDelay, createLogger, escapeRegExp, generateClientId, isPlainObject, multiplayer, normalizeError }; export type { LogContext, MultiplayerOptions, MultiplayerState, TokenRequest, TokenResponse, WithMultiplayer };