@djangocfg/centrifugo 2.1.54 → 2.1.55

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/README.md CHANGED
@@ -30,10 +30,18 @@ Professional Centrifugo WebSocket client with React integration, composable UI c
30
30
  src/
31
31
  ├── core/ # Platform-agnostic (no React dependencies)
32
32
  │ ├── client/ # CentrifugoRPCClient - WebSocket client
33
+ │ │ ├── CentrifugoRPCClient.ts # Main facade (~165 lines)
34
+ │ │ ├── connection.ts # Connection lifecycle
35
+ │ │ ├── subscriptions.ts # Channel subscriptions
36
+ │ │ ├── rpc.ts # RPC methods (namedRPC, namedRPCNoWait)
37
+ │ │ ├── version.ts # API version checking
38
+ │ │ ├── types.ts # Type definitions
39
+ │ │ └── index.ts # Exports
33
40
  │ ├── logger/ # Logging system with circular buffer
34
41
  │ │ ├── createLogger.ts # Logger factory (supports string prefix)
35
42
  │ │ └── LogsStore.ts # In-memory logs accumulation
36
43
  │ └── types/ # TypeScript type definitions
44
+ ├── events.ts # Unified event system (single 'centrifugo' event)
37
45
  ├── providers/ # React Context providers
38
46
  │ ├── CentrifugoProvider/ # Main connection provider (no auto-FAB)
39
47
  │ └── LogsProvider/ # Logs accumulation provider
@@ -486,6 +494,24 @@ async def terminal_input(conn, params: TerminalInputParams) -> SuccessResult:
486
494
  return SuccessResult(success=True, message="Input queued")
487
495
  ```
488
496
 
497
+ **Retry Logic with Exponential Backoff:**
498
+
499
+ `namedRPCNoWait` includes automatic retry with exponential backoff:
500
+
501
+ ```tsx
502
+ // Default: 3 retries, 100ms base delay, 2000ms max delay
503
+ client?.namedRPCNoWait('terminal.input', { session_id, data });
504
+
505
+ // Custom retry options
506
+ client?.namedRPCNoWait('terminal.input', { session_id, data }, {
507
+ maxRetries: 5, // Max retry attempts (default: 3)
508
+ baseDelayMs: 100, // Base delay for exponential backoff (default: 100)
509
+ maxDelayMs: 3000, // Max delay cap (default: 2000)
510
+ });
511
+ ```
512
+
513
+ **Retry sequence:** 100ms → 200ms → 400ms → 800ms → 1600ms (capped at maxDelayMs)
514
+
489
515
  **Performance comparison:**
490
516
 
491
517
  | Method | Latency | Use Case |
@@ -493,6 +519,44 @@ async def terminal_input(conn, params: TerminalInputParams) -> SuccessResult:
493
519
  | `namedRPC()` | ~800-1800ms | Commands that need response |
494
520
  | `namedRPCNoWait()` | ~10-30ms | Real-time input, fire-and-forget |
495
521
 
522
+ ### checkApiVersion() - API Contract Validation
523
+
524
+ Validates that the client API version matches the server. Useful for detecting when the frontend needs to refresh after a backend deployment.
525
+
526
+ ```tsx
527
+ import { API_VERSION } from '@/_ws'; // Generated client exports version hash
528
+
529
+ // Check version after connect
530
+ const result = await client.checkApiVersion(API_VERSION);
531
+
532
+ if (!result.compatible) {
533
+ // Versions don't match - show refresh prompt
534
+ toast.warning('New version available. Please refresh the page.');
535
+ }
536
+ ```
537
+
538
+ **Unified Event Handling:**
539
+
540
+ Version mismatch automatically dispatches a `'centrifugo'` event:
541
+
542
+ ```tsx
543
+ // Listen globally for version mismatch
544
+ window.addEventListener('centrifugo', (e: CustomEvent) => {
545
+ if (e.detail.type === 'version_mismatch') {
546
+ const { clientVersion, serverVersion, message } = e.detail.data;
547
+ toast.warning(message);
548
+ }
549
+ });
550
+ ```
551
+
552
+ **How Version Hash Works:**
553
+
554
+ The version hash is computed from:
555
+ - All `@websocket_rpc` method signatures (name, params, return type)
556
+ - All Pydantic model schemas used in handlers
557
+
558
+ When any handler or model changes, the hash changes, triggering a version mismatch.
559
+
496
560
  ## Auto-Generated Type-Safe Clients
497
561
 
498
562
  Django-CFG can auto-generate TypeScript clients from your `@websocket_rpc` handlers, providing full type safety and eliminating manual RPC calls.
@@ -857,16 +921,28 @@ function CustomLogsView() {
857
921
  import { CentrifugoRPCClient, createLogger } from '@djangocfg/centrifugo';
858
922
 
859
923
  const logger = createLogger('MyApp');
860
- const client = new CentrifugoRPCClient(
861
- 'ws://localhost:8000/ws',
862
- 'your-token',
863
- 'user-id',
864
- 30000, // timeout
865
- (entry) => logger.info(entry.message, entry.data)
866
- );
924
+
925
+ // Recommended: Options-based constructor
926
+ const client = new CentrifugoRPCClient({
927
+ url: 'ws://localhost:8000/ws',
928
+ token: 'your-token',
929
+ userId: 'user-id',
930
+ timeout: 30000,
931
+ logger,
932
+ // Auto-refresh token on expiration
933
+ getToken: async () => {
934
+ const response = await fetch('/api/auth/refresh-token');
935
+ const { token } = await response.json();
936
+ return token;
937
+ },
938
+ });
867
939
 
868
940
  await client.connect();
869
941
 
942
+ // Check API version after connect
943
+ import { API_VERSION } from '@/_ws';
944
+ await client.checkApiVersion(API_VERSION);
945
+
870
946
  // Subscribe to channel
871
947
  const unsubscribe = client.subscribe('channel-name', (data) => {
872
948
  console.log('Message:', data);
@@ -927,6 +1003,12 @@ The package is fully typed with comprehensive TypeScript definitions:
927
1003
 
928
1004
  ```typescript
929
1005
  import type {
1006
+ // Client Options
1007
+ CentrifugoClientOptions,
1008
+ RPCOptions,
1009
+ RetryOptions,
1010
+ VersionCheckResult,
1011
+
930
1012
  // Connection
931
1013
  ConnectionState,
932
1014
  CentrifugoToken,
@@ -959,6 +1041,85 @@ import type {
959
1041
  } from '@djangocfg/centrifugo';
960
1042
  ```
961
1043
 
1044
+ ## Unified Event System
1045
+
1046
+ All Centrifugo events use a single `'centrifugo'` CustomEvent with a type discriminator. This simplifies event handling and reduces the number of event listeners needed.
1047
+
1048
+ **Event Types:**
1049
+
1050
+ | Type | Description | Data |
1051
+ |------|-------------|------|
1052
+ | `error` | RPC call failed | `{ method, error, code, data }` |
1053
+ | `version_mismatch` | API version mismatch | `{ clientVersion, serverVersion, message }` |
1054
+ | `connected` | Successfully connected | `{ userId }` |
1055
+ | `disconnected` | Connection lost | `{ userId, reason }` |
1056
+ | `reconnecting` | Attempting to reconnect | `{ userId, attempt, reason }` |
1057
+
1058
+ **Listening to Events:**
1059
+
1060
+ ```tsx
1061
+ // Listen to all Centrifugo events
1062
+ window.addEventListener('centrifugo', (e: CustomEvent) => {
1063
+ const { type, data, timestamp } = e.detail;
1064
+
1065
+ switch (type) {
1066
+ case 'error':
1067
+ console.error('RPC error:', data.method, data.error);
1068
+ break;
1069
+ case 'version_mismatch':
1070
+ toast.warning('Please refresh the page');
1071
+ break;
1072
+ case 'connected':
1073
+ console.log('Connected as', data.userId);
1074
+ break;
1075
+ case 'disconnected':
1076
+ console.log('Disconnected:', data.reason);
1077
+ break;
1078
+ case 'reconnecting':
1079
+ console.log('Reconnecting, attempt', data.attempt);
1080
+ break;
1081
+ }
1082
+ });
1083
+ ```
1084
+
1085
+ **Dispatching Events (for custom integrations):**
1086
+
1087
+ ```tsx
1088
+ import {
1089
+ dispatchCentrifugoError,
1090
+ dispatchVersionMismatch,
1091
+ dispatchConnected,
1092
+ dispatchDisconnected,
1093
+ dispatchReconnecting,
1094
+ } from '@djangocfg/centrifugo';
1095
+
1096
+ // Dispatch error
1097
+ dispatchCentrifugoError({
1098
+ method: 'terminal.input',
1099
+ error: 'Connection timeout',
1100
+ code: 408,
1101
+ });
1102
+
1103
+ // Dispatch version mismatch
1104
+ dispatchVersionMismatch({
1105
+ clientVersion: 'abc123',
1106
+ serverVersion: 'def456',
1107
+ message: 'API version mismatch',
1108
+ });
1109
+ ```
1110
+
1111
+ **Integration with ErrorsTracker:**
1112
+
1113
+ The `@djangocfg/layouts` package's `ErrorTrackingProvider` automatically listens to `'centrifugo'` events with `type: 'error'` and displays toast notifications.
1114
+
1115
+ ```tsx
1116
+ import { ErrorTrackingProvider } from '@djangocfg/layouts';
1117
+
1118
+ <ErrorTrackingProvider centrifugo={{ enabled: true, showToast: true }}>
1119
+ <App />
1120
+ </ErrorTrackingProvider>
1121
+ ```
1122
+
962
1123
  **Proper Centrifuge Types:**
963
1124
 
964
1125
  The package now uses proper types from the `centrifuge` library:
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@djangocfg/centrifugo",
3
- "version": "2.1.54",
3
+ "version": "2.1.55",
4
4
  "description": "Production-ready Centrifugo WebSocket client for React with real-time subscriptions, RPC patterns, and connection state management",
5
5
  "keywords": [
6
6
  "centrifugo",
@@ -51,9 +51,9 @@
51
51
  "centrifuge": "^5.2.2"
52
52
  },
53
53
  "peerDependencies": {
54
- "@djangocfg/api": "^2.1.54",
55
- "@djangocfg/ui-nextjs": "^2.1.54",
56
- "@djangocfg/layouts": "^2.1.54",
54
+ "@djangocfg/api": "^2.1.55",
55
+ "@djangocfg/ui-nextjs": "^2.1.55",
56
+ "@djangocfg/layouts": "^2.1.55",
57
57
  "consola": "^3.4.2",
58
58
  "lucide-react": "^0.545.0",
59
59
  "moment": "^2.30.1",
@@ -61,7 +61,7 @@
61
61
  "react-dom": "^19.1.0"
62
62
  },
63
63
  "devDependencies": {
64
- "@djangocfg/typescript-config": "^2.1.54",
64
+ "@djangocfg/typescript-config": "^2.1.55",
65
65
  "@types/react": "^19.1.0",
66
66
  "@types/react-dom": "^19.1.0",
67
67
  "moment": "^2.30.1",