@djangocfg/centrifugo 2.1.27 → 2.1.29
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 +135 -1
- package/package.json +5 -5
- package/src/components/ConnectionStatus/ConnectionStatus.tsx +2 -2
- package/src/components/SubscriptionsList/SubscriptionsList.tsx +2 -2
- package/src/core/client/CentrifugoRPCClient.ts +6 -3
- package/src/core/logger/consolaLogger.ts +37 -0
- package/src/core/utils/devTips.ts +74 -0
- package/src/hooks/useCodegenTip.ts +39 -0
- package/src/hooks/useNamedRPC.ts +2 -2
- package/src/hooks/useRPC.ts +3 -3
- package/src/hooks/useSubscription.ts +2 -2
- package/src/index.ts +3 -0
- package/src/providers/CentrifugoProvider/CentrifugoProvider.tsx +7 -3
package/README.md
CHANGED
|
@@ -441,7 +441,141 @@ interface UseNamedRPCResult {
|
|
|
441
441
|
}
|
|
442
442
|
```
|
|
443
443
|
|
|
444
|
-
> **Note:** `useNamedRPC` uses native Centrifugo RPC which requires RPC proxy to be configured in Centrifugo server. See the [Setup Guide](https://djangocfg.com/features/integrations/centrifugo/
|
|
444
|
+
> **Note:** `useNamedRPC` uses native Centrifugo RPC which requires RPC proxy to be configured in Centrifugo server. See the [Setup Guide](https://djangocfg.com/docs/features/integrations/centrifugo/client-generation/) for configuration details.
|
|
445
|
+
|
|
446
|
+
## Auto-Generated Type-Safe Clients
|
|
447
|
+
|
|
448
|
+
Django-CFG can auto-generate TypeScript clients from your `@websocket_rpc` handlers, providing full type safety and eliminating manual RPC calls.
|
|
449
|
+
|
|
450
|
+
### Generate Clients
|
|
451
|
+
|
|
452
|
+
```bash
|
|
453
|
+
# Generate TypeScript client from @websocket_rpc handlers
|
|
454
|
+
python manage.py generate_centrifugo_clients --typescript --output ./clients
|
|
455
|
+
|
|
456
|
+
# Generate and auto-copy to Next.js app (recommended)
|
|
457
|
+
python manage.py generate_centrifugo_clients --typescript
|
|
458
|
+
# Outputs to: openapi/centrifuge/typescript/
|
|
459
|
+
```
|
|
460
|
+
|
|
461
|
+
This generates type-safe clients with:
|
|
462
|
+
|
|
463
|
+
```
|
|
464
|
+
typescript/
|
|
465
|
+
├── client.ts # Type-safe API methods
|
|
466
|
+
├── types.ts # Pydantic models → TypeScript interfaces
|
|
467
|
+
├── index.ts # Exports
|
|
468
|
+
└── rpc-client.ts # Low-level RPC client (optional)
|
|
469
|
+
```
|
|
470
|
+
|
|
471
|
+
**Copy to your app:**
|
|
472
|
+
|
|
473
|
+
```bash
|
|
474
|
+
# Manual copy
|
|
475
|
+
cp -r openapi/centrifuge/typescript/* apps/web/app/_ws/
|
|
476
|
+
|
|
477
|
+
# Or create a custom command for your project
|
|
478
|
+
# See: core/management/commands/generate_centrifuge_web.py
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Using Generated Clients
|
|
482
|
+
|
|
483
|
+
**Before (manual RPC):**
|
|
484
|
+
```tsx
|
|
485
|
+
// ❌ No type safety, easy to make mistakes
|
|
486
|
+
const result = await client.namedRPC('ai_chat.get_messages', {
|
|
487
|
+
session_id: sessionId,
|
|
488
|
+
limit: 50,
|
|
489
|
+
before_id: beforeId, // Could typo: beforeID
|
|
490
|
+
});
|
|
491
|
+
```
|
|
492
|
+
|
|
493
|
+
**After (generated client):**
|
|
494
|
+
```tsx
|
|
495
|
+
import { APIClient, type MessageListResult } from '@/_ws';
|
|
496
|
+
|
|
497
|
+
const apiClient = useMemo(() =>
|
|
498
|
+
client ? new APIClient(client) : null,
|
|
499
|
+
[client]
|
|
500
|
+
);
|
|
501
|
+
|
|
502
|
+
// ✅ Full type safety with autocomplete
|
|
503
|
+
const result: MessageListResult = await apiClient.aiChatGetMessages({
|
|
504
|
+
session_id: sessionId, // ✓ Autocomplete
|
|
505
|
+
limit: 50, // ✓ Type checking
|
|
506
|
+
before_id: beforeId, // ✓ Typo protection
|
|
507
|
+
});
|
|
508
|
+
```
|
|
509
|
+
|
|
510
|
+
### How It Works
|
|
511
|
+
|
|
512
|
+
1. **Backend** - Define RPC handlers with Pydantic models:
|
|
513
|
+
|
|
514
|
+
```python
|
|
515
|
+
from pydantic import BaseModel
|
|
516
|
+
from django_cfg.apps.integrations.centrifugo.decorators import websocket_rpc
|
|
517
|
+
|
|
518
|
+
class GetMessagesParams(BaseModel):
|
|
519
|
+
session_id: str
|
|
520
|
+
limit: int = 50
|
|
521
|
+
before_id: str | None = None
|
|
522
|
+
|
|
523
|
+
class MessageListResult(BaseModel):
|
|
524
|
+
messages: list[MessageData]
|
|
525
|
+
total: int
|
|
526
|
+
has_more: bool
|
|
527
|
+
|
|
528
|
+
@websocket_rpc("ai_chat.get_messages")
|
|
529
|
+
async def ai_chat_get_messages(conn, params: GetMessagesParams) -> MessageListResult:
|
|
530
|
+
# Implementation
|
|
531
|
+
return MessageListResult(...)
|
|
532
|
+
```
|
|
533
|
+
|
|
534
|
+
2. **Generate** - Run generation command:
|
|
535
|
+
|
|
536
|
+
```bash
|
|
537
|
+
python manage.py generate_centrifuge_web
|
|
538
|
+
# Discovers all @websocket_rpc handlers
|
|
539
|
+
# Converts Pydantic models to TypeScript
|
|
540
|
+
# Generates type-safe APIClient
|
|
541
|
+
```
|
|
542
|
+
|
|
543
|
+
3. **Frontend** - Use generated client:
|
|
544
|
+
|
|
545
|
+
```tsx
|
|
546
|
+
const apiClient = new APIClient(client);
|
|
547
|
+
const result = await apiClient.aiChatGetMessages({
|
|
548
|
+
session_id: "uuid",
|
|
549
|
+
limit: 50,
|
|
550
|
+
});
|
|
551
|
+
// TypeScript knows result is MessageListResult!
|
|
552
|
+
```
|
|
553
|
+
|
|
554
|
+
### Benefits
|
|
555
|
+
|
|
556
|
+
- ✅ **Type Safety** - Compile-time errors for invalid parameters
|
|
557
|
+
- ✅ **Autocomplete** - IDE suggests available methods and parameters
|
|
558
|
+
- ✅ **Sync with Backend** - Regenerate when backend changes
|
|
559
|
+
- ✅ **No Manual Updates** - Types automatically match Pydantic models
|
|
560
|
+
- ✅ **Documentation** - Docstrings from backend appear in IDE
|
|
561
|
+
|
|
562
|
+
### Available Methods
|
|
563
|
+
|
|
564
|
+
All `@websocket_rpc` handlers are auto-generated:
|
|
565
|
+
|
|
566
|
+
```tsx
|
|
567
|
+
// Terminal RPC
|
|
568
|
+
await apiClient.terminalInput({ session_id, data });
|
|
569
|
+
await apiClient.terminalResize({ session_id, cols, rows });
|
|
570
|
+
await apiClient.terminalClose({ session_id });
|
|
571
|
+
|
|
572
|
+
// AI Chat RPC
|
|
573
|
+
await apiClient.aiChatCreateSession({ workspace_id, title });
|
|
574
|
+
await apiClient.aiChatSendMessage({ session_id, message, stream });
|
|
575
|
+
await apiClient.aiChatGetMessages({ session_id, limit, before_id });
|
|
576
|
+
```
|
|
577
|
+
|
|
578
|
+
> **Tip:** Run `python manage.py generate_centrifugo_clients --typescript` after adding new RPC handlers to update types.
|
|
445
579
|
|
|
446
580
|
## UI Components
|
|
447
581
|
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@djangocfg/centrifugo",
|
|
3
|
-
"version": "2.1.
|
|
3
|
+
"version": "2.1.29",
|
|
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.
|
|
55
|
-
"@djangocfg/ui-nextjs": "^2.1.
|
|
56
|
-
"@djangocfg/layouts": "^2.1.
|
|
54
|
+
"@djangocfg/api": "^2.1.29",
|
|
55
|
+
"@djangocfg/ui-nextjs": "^2.1.29",
|
|
56
|
+
"@djangocfg/layouts": "^2.1.29",
|
|
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.
|
|
64
|
+
"@djangocfg/typescript-config": "^2.1.29",
|
|
65
65
|
"@types/react": "^19.1.0",
|
|
66
66
|
"@types/react-dom": "^19.1.0",
|
|
67
67
|
"moment": "^2.30.1",
|
|
@@ -12,9 +12,9 @@ import { Badge } from '@djangocfg/ui-nextjs';
|
|
|
12
12
|
import { Wifi, WifiOff, Radio, Clock } from 'lucide-react';
|
|
13
13
|
import moment from 'moment';
|
|
14
14
|
import { useCentrifugo } from '../../providers/CentrifugoProvider';
|
|
15
|
-
import {
|
|
15
|
+
import { getConsolaLogger } from '../../core/logger/consolaLogger';
|
|
16
16
|
|
|
17
|
-
const logger =
|
|
17
|
+
const logger = getConsolaLogger('ConnectionStatus');
|
|
18
18
|
|
|
19
19
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20
20
|
// Types
|
|
@@ -19,9 +19,9 @@ import {
|
|
|
19
19
|
import { Radio, RefreshCw, Trash2 } from 'lucide-react';
|
|
20
20
|
import { Subscription, SubscriptionState } from 'centrifuge';
|
|
21
21
|
import { useCentrifugo } from '../../providers/CentrifugoProvider';
|
|
22
|
-
import {
|
|
22
|
+
import { getConsolaLogger } from '../../core/logger/consolaLogger';
|
|
23
23
|
|
|
24
|
-
const logger =
|
|
24
|
+
const logger = getConsolaLogger('SubscriptionsList');
|
|
25
25
|
|
|
26
26
|
// ─────────────────────────────────────────────────────────────────────────
|
|
27
27
|
// Types
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
|
|
8
8
|
import { Centrifuge } from 'centrifuge';
|
|
9
9
|
import type { Logger } from '../logger';
|
|
10
|
-
import {
|
|
10
|
+
import { getConsolaLogger } from '../logger/consolaLogger';
|
|
11
11
|
|
|
12
12
|
export interface CentrifugoClientOptions {
|
|
13
13
|
url: string;
|
|
@@ -76,7 +76,7 @@ export class CentrifugoRPCClient {
|
|
|
76
76
|
this.userId = actualUserId;
|
|
77
77
|
this.replyChannel = `user#${actualUserId}`;
|
|
78
78
|
this.timeout = actualTimeout;
|
|
79
|
-
this.logger = actualLogger ||
|
|
79
|
+
this.logger = actualLogger || getConsolaLogger('client');
|
|
80
80
|
|
|
81
81
|
// Build Centrifuge options
|
|
82
82
|
const centrifugeOptions: any = {
|
|
@@ -571,11 +571,14 @@ export class CentrifugoRPCClient {
|
|
|
571
571
|
*/
|
|
572
572
|
async namedRPC<TRequest = any, TResponse = any>(
|
|
573
573
|
method: string,
|
|
574
|
-
data: TRequest
|
|
574
|
+
data: TRequest,
|
|
575
|
+
options?: { timeout?: number }
|
|
575
576
|
): Promise<TResponse> {
|
|
576
577
|
this.logger.info(`Native RPC: ${method}`, { data });
|
|
577
578
|
|
|
578
579
|
try {
|
|
580
|
+
// Note: centrifuge.rpc does not support timeout parameter directly
|
|
581
|
+
// Timeout should be handled at higher level or via AbortController
|
|
579
582
|
const result = await this.centrifuge.rpc(method, data);
|
|
580
583
|
|
|
581
584
|
this.logger.success(`Native RPC success: ${method}`, {
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shared Consola Logger
|
|
3
|
+
*
|
|
4
|
+
* Single consola instance used across the package for development logging.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { createConsola } from 'consola';
|
|
8
|
+
import type { Logger } from './createLogger';
|
|
9
|
+
|
|
10
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
11
|
+
|
|
12
|
+
/**
|
|
13
|
+
* Shared consola logger for Centrifugo package
|
|
14
|
+
*/
|
|
15
|
+
export const consolaLogger = createConsola({
|
|
16
|
+
level: isDevelopment ? 4 : 3,
|
|
17
|
+
formatOptions: {
|
|
18
|
+
colors: true,
|
|
19
|
+
date: false,
|
|
20
|
+
compact: !isDevelopment,
|
|
21
|
+
},
|
|
22
|
+
}).withTag('[Centrifugo]');
|
|
23
|
+
|
|
24
|
+
/**
|
|
25
|
+
* Get a consola logger with custom tag wrapped to match Logger interface
|
|
26
|
+
*/
|
|
27
|
+
export function getConsolaLogger(tag: string): Logger {
|
|
28
|
+
const consola = consolaLogger.withTag(`[${tag}]`);
|
|
29
|
+
|
|
30
|
+
return {
|
|
31
|
+
debug: (message: string, data?: unknown) => consola.debug(message, data || ''),
|
|
32
|
+
info: (message: string, data?: unknown) => consola.info(message, data || ''),
|
|
33
|
+
success: (message: string, data?: unknown) => consola.success(message, data || ''),
|
|
34
|
+
warning: (message: string, data?: unknown) => consola.warn(message, data || ''),
|
|
35
|
+
error: (message: string, error?: Error | unknown) => consola.error(message, error || ''),
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Development Tips
|
|
3
|
+
*
|
|
4
|
+
* Shows helpful development tips once per session.
|
|
5
|
+
* Used across the package to educate developers about features.
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { getConsolaLogger } from '../logger/consolaLogger';
|
|
9
|
+
|
|
10
|
+
const logger = getConsolaLogger('DevTips');
|
|
11
|
+
const shownTips = new Set<string>();
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Show a development tip once per session
|
|
15
|
+
*
|
|
16
|
+
* @param id - Unique identifier for the tip
|
|
17
|
+
* @param message - Tip message
|
|
18
|
+
* @param details - Optional details (shown as second parameter)
|
|
19
|
+
*
|
|
20
|
+
* @example
|
|
21
|
+
* showDevTip('codegen', 'Generate type-safe clients:', 'python manage.py ...');
|
|
22
|
+
*/
|
|
23
|
+
export function showDevTip(id: string, message: string, details?: string): void {
|
|
24
|
+
if (process.env.NODE_ENV !== 'development') return;
|
|
25
|
+
if (shownTips.has(id)) return;
|
|
26
|
+
|
|
27
|
+
shownTips.add(id);
|
|
28
|
+
logger.info(message, details);
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* Predefined tips
|
|
33
|
+
*/
|
|
34
|
+
export const DevTips = {
|
|
35
|
+
/**
|
|
36
|
+
* Show tip about generating type-safe clients
|
|
37
|
+
*/
|
|
38
|
+
codegenClients: () => {
|
|
39
|
+
showDevTip(
|
|
40
|
+
'codegen-clients',
|
|
41
|
+
'💡 Generate type-safe clients from @websocket_rpc handlers:',
|
|
42
|
+
'\n\npython manage.py generate_centrifugo_clients --typescript\n\nLearn more: https://djangocfg.com/centrifugo/codegen'
|
|
43
|
+
);
|
|
44
|
+
},
|
|
45
|
+
|
|
46
|
+
/**
|
|
47
|
+
* Show tip about using generated client instead of manual RPC
|
|
48
|
+
*/
|
|
49
|
+
useGeneratedClient: () => {
|
|
50
|
+
showDevTip(
|
|
51
|
+
'use-generated-client',
|
|
52
|
+
'💡 Consider using auto-generated APIClient for type safety:',
|
|
53
|
+
'\n\nimport { APIClient } from \'@/_ws\';\nconst apiClient = new APIClient(client);\nawait apiClient.aiChatGetMessages({ ... });\n\nGenerate: python manage.py generate_centrifugo_clients --typescript'
|
|
54
|
+
);
|
|
55
|
+
},
|
|
56
|
+
|
|
57
|
+
/**
|
|
58
|
+
* Show tip about RPC proxy configuration
|
|
59
|
+
*/
|
|
60
|
+
rpcProxyConfig: () => {
|
|
61
|
+
showDevTip(
|
|
62
|
+
'rpc-proxy-config',
|
|
63
|
+
'💡 Using namedRPC requires Centrifugo RPC proxy configuration:',
|
|
64
|
+
'\n\nSee: https://djangocfg.com/features/integrations/centrifugo/setup'
|
|
65
|
+
);
|
|
66
|
+
},
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
/**
|
|
70
|
+
* Reset shown tips (useful for testing)
|
|
71
|
+
*/
|
|
72
|
+
export function resetDevTips(): void {
|
|
73
|
+
shownTips.clear();
|
|
74
|
+
}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* useCodegenTip Hook
|
|
3
|
+
*
|
|
4
|
+
* Shows development tip about client generation once per session.
|
|
5
|
+
*/
|
|
6
|
+
|
|
7
|
+
import { useEffect, useRef } from 'react';
|
|
8
|
+
import { consolaLogger } from '../core/logger/consolaLogger';
|
|
9
|
+
|
|
10
|
+
const isDevelopment = process.env.NODE_ENV === 'development';
|
|
11
|
+
let tipShown = false; // Global flag to show tip once across all components
|
|
12
|
+
|
|
13
|
+
/**
|
|
14
|
+
* Show dev tip about generating type-safe clients from @websocket_rpc handlers
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* function MyComponent() {
|
|
18
|
+
* useCodegenTip();
|
|
19
|
+
* // ... rest of component
|
|
20
|
+
* }
|
|
21
|
+
*/
|
|
22
|
+
export function useCodegenTip() {
|
|
23
|
+
const mountedRef = useRef(false);
|
|
24
|
+
|
|
25
|
+
useEffect(() => {
|
|
26
|
+
if (!isDevelopment) return;
|
|
27
|
+
if (tipShown) return;
|
|
28
|
+
if (mountedRef.current) return;
|
|
29
|
+
|
|
30
|
+
mountedRef.current = true;
|
|
31
|
+
tipShown = true;
|
|
32
|
+
|
|
33
|
+
consolaLogger.info(
|
|
34
|
+
'💡 Generate type-safe clients from @websocket_rpc handlers:\n\n' +
|
|
35
|
+
'python manage.py generate_centrifugo_clients --typescript\n\n' +
|
|
36
|
+
'Learn more: https://djangocfg.com/docs/features/integrations/centrifugo/client-generation/'
|
|
37
|
+
);
|
|
38
|
+
}, []);
|
|
39
|
+
}
|
package/src/hooks/useNamedRPC.ts
CHANGED
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
|
|
28
28
|
import { useState, useCallback, useRef } from 'react';
|
|
29
29
|
import { useCentrifugo } from '../providers/CentrifugoProvider';
|
|
30
|
-
import {
|
|
30
|
+
import { getConsolaLogger } from '../core/logger/consolaLogger';
|
|
31
31
|
|
|
32
32
|
export interface UseNamedRPCOptions {
|
|
33
33
|
onError?: (error: Error) => void;
|
|
@@ -50,7 +50,7 @@ export function useNamedRPC(
|
|
|
50
50
|
const [isLoading, setIsLoading] = useState(false);
|
|
51
51
|
const [error, setError] = useState<Error | null>(null);
|
|
52
52
|
|
|
53
|
-
const logger = useRef(
|
|
53
|
+
const logger = useRef(getConsolaLogger('useNamedRPC')).current;
|
|
54
54
|
|
|
55
55
|
const reset = useCallback(() => {
|
|
56
56
|
setIsLoading(false);
|
package/src/hooks/useRPC.ts
CHANGED
|
@@ -22,7 +22,7 @@
|
|
|
22
22
|
|
|
23
23
|
import { useState, useCallback, useRef } from 'react';
|
|
24
24
|
import { useCentrifugo } from '../providers/CentrifugoProvider';
|
|
25
|
-
import {
|
|
25
|
+
import { getConsolaLogger } from '../core/logger/consolaLogger';
|
|
26
26
|
|
|
27
27
|
export interface UseRPCOptions {
|
|
28
28
|
timeout?: number;
|
|
@@ -45,8 +45,8 @@ export function useRPC(defaultOptions: UseRPCOptions = {}): UseRPCResult {
|
|
|
45
45
|
const { client, isConnected } = useCentrifugo();
|
|
46
46
|
const [isLoading, setIsLoading] = useState(false);
|
|
47
47
|
const [error, setError] = useState<Error | null>(null);
|
|
48
|
-
|
|
49
|
-
const logger = useRef(
|
|
48
|
+
|
|
49
|
+
const logger = useRef(getConsolaLogger('useRPC')).current;
|
|
50
50
|
const abortControllerRef = useRef<AbortController | null>(null);
|
|
51
51
|
|
|
52
52
|
const reset = useCallback(() => {
|
|
@@ -14,7 +14,7 @@
|
|
|
14
14
|
|
|
15
15
|
import { useEffect, useCallback, useRef, useState } from 'react';
|
|
16
16
|
import { useCentrifugo } from '../providers/CentrifugoProvider';
|
|
17
|
-
import {
|
|
17
|
+
import { getConsolaLogger } from '../core/logger/consolaLogger';
|
|
18
18
|
import { logChannelWarnings } from '../core/utils/channelValidator';
|
|
19
19
|
|
|
20
20
|
export interface UseSubscriptionOptions<T = any> {
|
|
@@ -42,7 +42,7 @@ export function useSubscription<T = any>(
|
|
|
42
42
|
const [isSubscribed, setIsSubscribed] = useState(false);
|
|
43
43
|
|
|
44
44
|
const unsubscribeRef = useRef<(() => void) | null>(null);
|
|
45
|
-
const logger = useRef(
|
|
45
|
+
const logger = useRef(getConsolaLogger('useSubscription')).current;
|
|
46
46
|
|
|
47
47
|
// Store callbacks in refs to avoid re-subscriptions when they change
|
|
48
48
|
const onPublicationRef = useRef(onPublication);
|
package/src/index.ts
CHANGED
|
@@ -53,6 +53,7 @@ export type { Subscription } from 'centrifuge';
|
|
|
53
53
|
|
|
54
54
|
export { CentrifugoRPCClient } from './core/client/CentrifugoRPCClient';
|
|
55
55
|
export { createLogger, getGlobalLogsStore } from './core/logger';
|
|
56
|
+
export { consolaLogger, getConsolaLogger } from './core/logger/consolaLogger';
|
|
56
57
|
export type {
|
|
57
58
|
// Connection
|
|
58
59
|
ConnectionState,
|
|
@@ -92,6 +93,8 @@ export type {
|
|
|
92
93
|
UseSubscriptionResult,
|
|
93
94
|
} from './hooks/useSubscription';
|
|
94
95
|
|
|
96
|
+
export { useCodegenTip } from './hooks/useCodegenTip';
|
|
97
|
+
|
|
95
98
|
// ─────────────────────────────────────────────────────────────────────────
|
|
96
99
|
// Configuration
|
|
97
100
|
// ─────────────────────────────────────────────────────────────────────────
|
|
@@ -10,11 +10,12 @@
|
|
|
10
10
|
import { createContext, useContext, useState, useEffect, useCallback, useRef, useMemo, type ReactNode } from 'react';
|
|
11
11
|
import { useAuth } from '@djangocfg/api/auth';
|
|
12
12
|
import { CentrifugoRPCClient } from '../../core/client';
|
|
13
|
-
import {
|
|
13
|
+
import { getConsolaLogger } from '../../core/logger/consolaLogger';
|
|
14
14
|
import type { ConnectionState, CentrifugoToken, ActiveSubscription } from '../../core/types';
|
|
15
15
|
import { LogsProvider } from '../LogsProvider';
|
|
16
16
|
import { isStaticBuild, isDevelopment, reconnectConfig } from '../../config';
|
|
17
17
|
import { CentrifugoMonitorDialog } from '../../components/CentrifugoMonitor/CentrifugoMonitorDialog';
|
|
18
|
+
import { useCodegenTip } from '../../hooks/useCodegenTip';
|
|
18
19
|
|
|
19
20
|
// ─────────────────────────────────────────────────────────────────────────
|
|
20
21
|
// Context
|
|
@@ -92,15 +93,18 @@ function CentrifugoProviderInner({
|
|
|
92
93
|
const [subscriptions, setSubscriptions] = useState<string[]>([]);
|
|
93
94
|
const [activeSubscriptions, setActiveSubscriptions] = useState<ActiveSubscription[]>([]);
|
|
94
95
|
|
|
95
|
-
const logger = useMemo(() =>
|
|
96
|
+
const logger = useMemo(() => getConsolaLogger('provider'), []);
|
|
97
|
+
|
|
98
|
+
// Show dev tip about client generation
|
|
99
|
+
useCodegenTip();
|
|
96
100
|
|
|
97
101
|
const reconnectTimeoutRef = useRef<NodeJS.Timeout | null>(null);
|
|
98
102
|
const hasConnectedRef = useRef(false);
|
|
99
103
|
const isConnectingRef = useRef(false);
|
|
100
104
|
const isMountedRef = useRef(true);
|
|
101
105
|
const reconnectAttemptRef = useRef(0);
|
|
102
|
-
const devWarningShownRef = useRef(false);
|
|
103
106
|
const reconnectStoppedRef = useRef(false); // Track if we should stop reconnecting
|
|
107
|
+
const devWarningShownRef = useRef(false); // Track if server unavailable warning was shown
|
|
104
108
|
const connectRef = useRef<(() => Promise<void>) | null>(null);
|
|
105
109
|
const disconnectRef = useRef<(() => void) | null>(null);
|
|
106
110
|
|