@thewhateverapp/platform 0.7.25 → 0.9.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/client/index.d.ts +2 -0
- package/dist/client/index.d.ts.map +1 -1
- package/dist/client/index.js +2 -0
- package/dist/client/index.js.map +1 -1
- package/dist/client/realtime/index.d.ts +138 -0
- package/dist/client/realtime/index.d.ts.map +1 -0
- package/dist/client/realtime/index.js +438 -0
- package/dist/client/realtime/index.js.map +1 -0
- package/dist/client/realtime/types.d.ts +143 -0
- package/dist/client/realtime/types.d.ts.map +1 -0
- package/dist/client/realtime/types.js +7 -0
- package/dist/client/realtime/types.js.map +1 -0
- package/dist/env.d.ts +1 -0
- package/dist/env.d.ts.map +1 -1
- package/dist/env.js.map +1 -1
- package/dist/index.d.ts +4 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +4 -0
- package/dist/index.js.map +1 -1
- package/dist/keyspace/index.d.ts +86 -0
- package/dist/keyspace/index.d.ts.map +1 -0
- package/dist/keyspace/index.js +929 -0
- package/dist/keyspace/index.js.map +1 -0
- package/dist/keyspace/types.d.ts +377 -0
- package/dist/keyspace/types.d.ts.map +1 -0
- package/dist/keyspace/types.js +8 -0
- package/dist/keyspace/types.js.map +1 -0
- package/dist/realtime/index.d.ts +97 -0
- package/dist/realtime/index.d.ts.map +1 -0
- package/dist/realtime/index.js +247 -0
- package/dist/realtime/index.js.map +1 -0
- package/dist/realtime/types.d.ts +198 -0
- package/dist/realtime/types.d.ts.map +1 -0
- package/dist/realtime/types.js +8 -0
- package/dist/realtime/types.js.map +1 -0
- package/package.json +7 -2
package/dist/client/index.d.ts
CHANGED
|
@@ -8,4 +8,6 @@ export { TileStateClient } from './tile-state';
|
|
|
8
8
|
export type * from './tile-state/types';
|
|
9
9
|
export { MobileAuthClient, AuthError } from './auth';
|
|
10
10
|
export type * from './auth/types';
|
|
11
|
+
export { RealtimeClient, useRealtime } from './realtime';
|
|
12
|
+
export type * from './realtime/types';
|
|
11
13
|
//# sourceMappingURL=index.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,mBAAmB,oBAAoB,CAAC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrD,mBAAmB,cAAc,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAC/C,mBAAmB,oBAAoB,CAAC;AAGxC,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrD,mBAAmB,cAAc,CAAC;AAGlC,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AACzD,mBAAmB,kBAAkB,CAAC"}
|
package/dist/client/index.js
CHANGED
|
@@ -8,4 +8,6 @@
|
|
|
8
8
|
export { TileStateClient } from './tile-state';
|
|
9
9
|
// Mobile Authentication client
|
|
10
10
|
export { MobileAuthClient, AuthError } from './auth';
|
|
11
|
+
// Realtime WebSocket client and React hook
|
|
12
|
+
export { RealtimeClient, useRealtime } from './realtime';
|
|
11
13
|
//# sourceMappingURL=index.js.map
|
package/dist/client/index.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,+BAA+B;AAC/B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC"}
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/client/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,sCAAsC;AACtC,OAAO,EAAE,eAAe,EAAE,MAAM,cAAc,CAAC;AAG/C,+BAA+B;AAC/B,OAAO,EAAE,gBAAgB,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AAGrD,2CAA2C;AAC3C,OAAO,EAAE,cAAc,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side Realtime Module
|
|
3
|
+
*
|
|
4
|
+
* Provides WebSocket-based real-time pub/sub for tile apps.
|
|
5
|
+
* Includes both a vanilla JavaScript client and a React hook.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useRealtime } from '@thewhateverapp/platform/client';
|
|
10
|
+
*
|
|
11
|
+
* function Counter() {
|
|
12
|
+
* const { lastMessage, isConnected } = useRealtime<{ count: number }>('my-app', {
|
|
13
|
+
* channels: ['counter'],
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* return (
|
|
17
|
+
* <div>
|
|
18
|
+
* <p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
|
|
19
|
+
* <p>Count: {lastMessage?.data.count ?? 0}</p>
|
|
20
|
+
* </div>
|
|
21
|
+
* );
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import type { RealtimeClientConfig, UseRealtimeOptions, UseRealtimeReturn, MessageHandler, StateChangeHandler, RealtimeConnectionState } from './types';
|
|
26
|
+
export type * from './types';
|
|
27
|
+
/**
|
|
28
|
+
* RealtimeClient - Vanilla JavaScript WebSocket client
|
|
29
|
+
*
|
|
30
|
+
* Handles WebSocket connection, reconnection, and message handling.
|
|
31
|
+
* Can be used without React for vanilla JS applications.
|
|
32
|
+
*
|
|
33
|
+
* @example
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const client = new RealtimeClient({
|
|
36
|
+
* appId: 'my-app',
|
|
37
|
+
* channels: ['counter'],
|
|
38
|
+
* });
|
|
39
|
+
*
|
|
40
|
+
* client.on('counter', (data) => {
|
|
41
|
+
* console.log('Counter updated:', data);
|
|
42
|
+
* });
|
|
43
|
+
*
|
|
44
|
+
* client.connect();
|
|
45
|
+
* ```
|
|
46
|
+
*/
|
|
47
|
+
export declare class RealtimeClient {
|
|
48
|
+
private config;
|
|
49
|
+
private ws;
|
|
50
|
+
private state;
|
|
51
|
+
private subscribedChannels;
|
|
52
|
+
private messageHandlers;
|
|
53
|
+
private anyMessageHandlers;
|
|
54
|
+
private stateChangeHandlers;
|
|
55
|
+
private reconnectAttempts;
|
|
56
|
+
private reconnectTimeout;
|
|
57
|
+
private pingInterval;
|
|
58
|
+
constructor(config: RealtimeClientConfig);
|
|
59
|
+
/**
|
|
60
|
+
* Get current connection state
|
|
61
|
+
*/
|
|
62
|
+
get connectionState(): RealtimeConnectionState;
|
|
63
|
+
/**
|
|
64
|
+
* Get subscribed channels
|
|
65
|
+
*/
|
|
66
|
+
get channels(): string[];
|
|
67
|
+
/**
|
|
68
|
+
* Connect to the realtime server
|
|
69
|
+
*/
|
|
70
|
+
connect(): void;
|
|
71
|
+
/**
|
|
72
|
+
* Disconnect from the realtime server
|
|
73
|
+
*/
|
|
74
|
+
disconnect(): void;
|
|
75
|
+
/**
|
|
76
|
+
* Subscribe to a channel
|
|
77
|
+
*/
|
|
78
|
+
subscribe(channel: string): void;
|
|
79
|
+
/**
|
|
80
|
+
* Unsubscribe from a channel
|
|
81
|
+
*/
|
|
82
|
+
unsubscribe(channel: string): void;
|
|
83
|
+
/**
|
|
84
|
+
* Publish data to a channel (client-to-server-to-all)
|
|
85
|
+
*/
|
|
86
|
+
publish(channel: string, data: unknown): void;
|
|
87
|
+
/**
|
|
88
|
+
* Add a message handler for a specific channel
|
|
89
|
+
*/
|
|
90
|
+
on<T = unknown>(channel: string, handler: MessageHandler<T>): () => void;
|
|
91
|
+
/**
|
|
92
|
+
* Add a handler for all messages
|
|
93
|
+
*/
|
|
94
|
+
onAny(handler: (channel: string, data: unknown) => void): () => void;
|
|
95
|
+
/**
|
|
96
|
+
* Add a connection state change handler
|
|
97
|
+
*/
|
|
98
|
+
onStateChange(handler: StateChangeHandler): () => void;
|
|
99
|
+
private setupWebSocketHandlers;
|
|
100
|
+
private handleMessage;
|
|
101
|
+
private handleDisconnect;
|
|
102
|
+
private setState;
|
|
103
|
+
private send;
|
|
104
|
+
private startPingInterval;
|
|
105
|
+
private clearPingInterval;
|
|
106
|
+
private clearReconnectTimeout;
|
|
107
|
+
}
|
|
108
|
+
/**
|
|
109
|
+
* useRealtime - React hook for real-time pub/sub
|
|
110
|
+
*
|
|
111
|
+
* Provides a simple interface for subscribing to channels and receiving
|
|
112
|
+
* real-time updates in React components.
|
|
113
|
+
*
|
|
114
|
+
* @param appId - App ID for channel isolation
|
|
115
|
+
* @param options - Hook options
|
|
116
|
+
* @returns Realtime state and controls
|
|
117
|
+
*
|
|
118
|
+
* @example
|
|
119
|
+
* ```tsx
|
|
120
|
+
* function Counter() {
|
|
121
|
+
* const { lastMessage, isConnected, publish } = useRealtime<{ count: number }>('my-app', {
|
|
122
|
+
* channels: ['counter'],
|
|
123
|
+
* });
|
|
124
|
+
*
|
|
125
|
+
* return (
|
|
126
|
+
* <div>
|
|
127
|
+
* <p>Connected: {isConnected ? 'Yes' : 'No'}</p>
|
|
128
|
+
* <p>Count: {lastMessage?.data.count ?? 0}</p>
|
|
129
|
+
* <button onClick={() => publish('counter', { count: 42 })}>
|
|
130
|
+
* Update
|
|
131
|
+
* </button>
|
|
132
|
+
* </div>
|
|
133
|
+
* );
|
|
134
|
+
* }
|
|
135
|
+
* ```
|
|
136
|
+
*/
|
|
137
|
+
export declare function useRealtime<T = unknown>(appId: string, options?: UseRealtimeOptions): UseRealtimeReturn<T>;
|
|
138
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/client/realtime/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AAGH,OAAO,KAAK,EACV,oBAAoB,EACpB,kBAAkB,EAClB,iBAAiB,EACjB,cAAc,EACd,kBAAkB,EAClB,uBAAuB,EAExB,MAAM,SAAS,CAAC;AAGjB,mBAAmB,SAAS,CAAC;AAE7B;;;;;;;;;;;;;;;;;;;GAmBG;AACH,qBAAa,cAAc;IACzB,OAAO,CAAC,MAAM,CAAiC;IAC/C,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,KAAK,CAA2C;IACxD,OAAO,CAAC,kBAAkB,CAA0B;IACpD,OAAO,CAAC,eAAe,CAA+C;IACtE,OAAO,CAAC,kBAAkB,CAA4D;IACtF,OAAO,CAAC,mBAAmB,CAAsC;IACjE,OAAO,CAAC,iBAAiB,CAAK;IAC9B,OAAO,CAAC,gBAAgB,CAA8C;IACtE,OAAO,CAAC,YAAY,CAA+C;gBAEvD,MAAM,EAAE,oBAAoB;IAiBxC;;OAEG;IACH,IAAI,eAAe,IAAI,uBAAuB,CAE7C;IAED;;OAEG;IACH,IAAI,QAAQ,IAAI,MAAM,EAAE,CAEvB;IAED;;OAEG;IACH,OAAO,IAAI,IAAI;IAwBf;;OAEG;IACH,UAAU,IAAI,IAAI;IAalB;;OAEG;IACH,SAAS,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYhC;;OAEG;IACH,WAAW,CAAC,OAAO,EAAE,MAAM,GAAG,IAAI;IAYlC;;OAEG;IACH,OAAO,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,GAAG,IAAI;IAS7C;;OAEG;IACH,EAAE,CAAC,CAAC,GAAG,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,OAAO,EAAE,cAAc,CAAC,CAAC,CAAC,GAAG,MAAM,IAAI;IAaxE;;OAEG;IACH,KAAK,CAAC,OAAO,EAAE,CAAC,OAAO,EAAE,MAAM,EAAE,IAAI,EAAE,OAAO,KAAK,IAAI,GAAG,MAAM,IAAI;IAQpE;;OAEG;IACH,aAAa,CAAC,OAAO,EAAE,kBAAkB,GAAG,MAAM,IAAI;IAUtD,OAAO,CAAC,sBAAsB;IA4B9B,OAAO,CAAC,aAAa;IAiDrB,OAAO,CAAC,gBAAgB;IA2BxB,OAAO,CAAC,QAAQ;IAchB,OAAO,CAAC,IAAI;IAMZ,OAAO,CAAC,iBAAiB;IAQzB,OAAO,CAAC,iBAAiB;IAOzB,OAAO,CAAC,qBAAqB;CAM9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA4BG;AACH,wBAAgB,WAAW,CAAC,CAAC,GAAG,OAAO,EACrC,KAAK,EAAE,MAAM,EACb,OAAO,GAAE,kBAAuB,GAC/B,iBAAiB,CAAC,CAAC,CAAC,CA4GtB"}
|
|
@@ -0,0 +1,438 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Client-side Realtime Module
|
|
3
|
+
*
|
|
4
|
+
* Provides WebSocket-based real-time pub/sub for tile apps.
|
|
5
|
+
* Includes both a vanilla JavaScript client and a React hook.
|
|
6
|
+
*
|
|
7
|
+
* @example
|
|
8
|
+
* ```tsx
|
|
9
|
+
* import { useRealtime } from '@thewhateverapp/platform/client';
|
|
10
|
+
*
|
|
11
|
+
* function Counter() {
|
|
12
|
+
* const { lastMessage, isConnected } = useRealtime<{ count: number }>('my-app', {
|
|
13
|
+
* channels: ['counter'],
|
|
14
|
+
* });
|
|
15
|
+
*
|
|
16
|
+
* return (
|
|
17
|
+
* <div>
|
|
18
|
+
* <p>Status: {isConnected ? 'Connected' : 'Disconnected'}</p>
|
|
19
|
+
* <p>Count: {lastMessage?.data.count ?? 0}</p>
|
|
20
|
+
* </div>
|
|
21
|
+
* );
|
|
22
|
+
* }
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
import { useState, useEffect, useCallback, useRef } from 'react';
|
|
26
|
+
/**
|
|
27
|
+
* RealtimeClient - Vanilla JavaScript WebSocket client
|
|
28
|
+
*
|
|
29
|
+
* Handles WebSocket connection, reconnection, and message handling.
|
|
30
|
+
* Can be used without React for vanilla JS applications.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* const client = new RealtimeClient({
|
|
35
|
+
* appId: 'my-app',
|
|
36
|
+
* channels: ['counter'],
|
|
37
|
+
* });
|
|
38
|
+
*
|
|
39
|
+
* client.on('counter', (data) => {
|
|
40
|
+
* console.log('Counter updated:', data);
|
|
41
|
+
* });
|
|
42
|
+
*
|
|
43
|
+
* client.connect();
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export class RealtimeClient {
|
|
47
|
+
config;
|
|
48
|
+
ws = null;
|
|
49
|
+
state = 'disconnected';
|
|
50
|
+
subscribedChannels = new Set();
|
|
51
|
+
messageHandlers = new Map();
|
|
52
|
+
anyMessageHandlers = new Set();
|
|
53
|
+
stateChangeHandlers = new Set();
|
|
54
|
+
reconnectAttempts = 0;
|
|
55
|
+
reconnectTimeout = null;
|
|
56
|
+
pingInterval = null;
|
|
57
|
+
constructor(config) {
|
|
58
|
+
this.config = {
|
|
59
|
+
baseUrl: config.baseUrl || 'wss://realtime.thewhatever.app',
|
|
60
|
+
appId: config.appId,
|
|
61
|
+
channels: config.channels || [],
|
|
62
|
+
autoReconnect: config.autoReconnect ?? true,
|
|
63
|
+
reconnectDelay: config.reconnectDelay || 1000,
|
|
64
|
+
maxReconnectAttempts: config.maxReconnectAttempts || 10,
|
|
65
|
+
pingInterval: config.pingInterval || 30000,
|
|
66
|
+
};
|
|
67
|
+
// Add initial channels
|
|
68
|
+
for (const channel of this.config.channels) {
|
|
69
|
+
this.subscribedChannels.add(channel);
|
|
70
|
+
}
|
|
71
|
+
}
|
|
72
|
+
/**
|
|
73
|
+
* Get current connection state
|
|
74
|
+
*/
|
|
75
|
+
get connectionState() {
|
|
76
|
+
return this.state;
|
|
77
|
+
}
|
|
78
|
+
/**
|
|
79
|
+
* Get subscribed channels
|
|
80
|
+
*/
|
|
81
|
+
get channels() {
|
|
82
|
+
return Array.from(this.subscribedChannels);
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Connect to the realtime server
|
|
86
|
+
*/
|
|
87
|
+
connect() {
|
|
88
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
89
|
+
return; // Already connected
|
|
90
|
+
}
|
|
91
|
+
this.setState('connecting');
|
|
92
|
+
// Build WebSocket URL
|
|
93
|
+
const url = new URL('/ws', this.config.baseUrl);
|
|
94
|
+
url.searchParams.set('appId', this.config.appId);
|
|
95
|
+
if (this.subscribedChannels.size > 0) {
|
|
96
|
+
url.searchParams.set('channels', Array.from(this.subscribedChannels).join(','));
|
|
97
|
+
}
|
|
98
|
+
try {
|
|
99
|
+
this.ws = new WebSocket(url.toString());
|
|
100
|
+
this.setupWebSocketHandlers();
|
|
101
|
+
}
|
|
102
|
+
catch (error) {
|
|
103
|
+
console.error('[Realtime] Failed to create WebSocket:', error);
|
|
104
|
+
this.handleDisconnect();
|
|
105
|
+
}
|
|
106
|
+
}
|
|
107
|
+
/**
|
|
108
|
+
* Disconnect from the realtime server
|
|
109
|
+
*/
|
|
110
|
+
disconnect() {
|
|
111
|
+
this.clearReconnectTimeout();
|
|
112
|
+
this.clearPingInterval();
|
|
113
|
+
if (this.ws) {
|
|
114
|
+
this.ws.close(1000, 'Client disconnect');
|
|
115
|
+
this.ws = null;
|
|
116
|
+
}
|
|
117
|
+
this.setState('disconnected');
|
|
118
|
+
this.reconnectAttempts = 0;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Subscribe to a channel
|
|
122
|
+
*/
|
|
123
|
+
subscribe(channel) {
|
|
124
|
+
if (this.subscribedChannels.has(channel)) {
|
|
125
|
+
return; // Already subscribed
|
|
126
|
+
}
|
|
127
|
+
this.subscribedChannels.add(channel);
|
|
128
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
129
|
+
this.send({ type: 'subscribe', channel });
|
|
130
|
+
}
|
|
131
|
+
}
|
|
132
|
+
/**
|
|
133
|
+
* Unsubscribe from a channel
|
|
134
|
+
*/
|
|
135
|
+
unsubscribe(channel) {
|
|
136
|
+
if (!this.subscribedChannels.has(channel)) {
|
|
137
|
+
return; // Not subscribed
|
|
138
|
+
}
|
|
139
|
+
this.subscribedChannels.delete(channel);
|
|
140
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
141
|
+
this.send({ type: 'unsubscribe', channel });
|
|
142
|
+
}
|
|
143
|
+
}
|
|
144
|
+
/**
|
|
145
|
+
* Publish data to a channel (client-to-server-to-all)
|
|
146
|
+
*/
|
|
147
|
+
publish(channel, data) {
|
|
148
|
+
if (this.ws?.readyState !== WebSocket.OPEN) {
|
|
149
|
+
console.warn('[Realtime] Cannot publish: not connected');
|
|
150
|
+
return;
|
|
151
|
+
}
|
|
152
|
+
this.send({ type: 'publish', channel, data });
|
|
153
|
+
}
|
|
154
|
+
/**
|
|
155
|
+
* Add a message handler for a specific channel
|
|
156
|
+
*/
|
|
157
|
+
on(channel, handler) {
|
|
158
|
+
if (!this.messageHandlers.has(channel)) {
|
|
159
|
+
this.messageHandlers.set(channel, new Set());
|
|
160
|
+
}
|
|
161
|
+
this.messageHandlers.get(channel).add(handler);
|
|
162
|
+
// Return unsubscribe function
|
|
163
|
+
return () => {
|
|
164
|
+
this.messageHandlers.get(channel)?.delete(handler);
|
|
165
|
+
};
|
|
166
|
+
}
|
|
167
|
+
/**
|
|
168
|
+
* Add a handler for all messages
|
|
169
|
+
*/
|
|
170
|
+
onAny(handler) {
|
|
171
|
+
this.anyMessageHandlers.add(handler);
|
|
172
|
+
return () => {
|
|
173
|
+
this.anyMessageHandlers.delete(handler);
|
|
174
|
+
};
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Add a connection state change handler
|
|
178
|
+
*/
|
|
179
|
+
onStateChange(handler) {
|
|
180
|
+
this.stateChangeHandlers.add(handler);
|
|
181
|
+
return () => {
|
|
182
|
+
this.stateChangeHandlers.delete(handler);
|
|
183
|
+
};
|
|
184
|
+
}
|
|
185
|
+
// ==================== Private Methods ====================
|
|
186
|
+
setupWebSocketHandlers() {
|
|
187
|
+
if (!this.ws)
|
|
188
|
+
return;
|
|
189
|
+
this.ws.addEventListener('open', () => {
|
|
190
|
+
this.setState('connected');
|
|
191
|
+
this.reconnectAttempts = 0;
|
|
192
|
+
this.startPingInterval();
|
|
193
|
+
});
|
|
194
|
+
this.ws.addEventListener('message', (event) => {
|
|
195
|
+
try {
|
|
196
|
+
const message = JSON.parse(event.data);
|
|
197
|
+
this.handleMessage(message);
|
|
198
|
+
}
|
|
199
|
+
catch (error) {
|
|
200
|
+
console.error('[Realtime] Failed to parse message:', error);
|
|
201
|
+
}
|
|
202
|
+
});
|
|
203
|
+
this.ws.addEventListener('close', (event) => {
|
|
204
|
+
console.log(`[Realtime] Connection closed: code=${event.code}, reason=${event.reason}`);
|
|
205
|
+
this.handleDisconnect();
|
|
206
|
+
});
|
|
207
|
+
this.ws.addEventListener('error', (event) => {
|
|
208
|
+
console.error('[Realtime] WebSocket error:', event);
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
handleMessage(message) {
|
|
212
|
+
switch (message.type) {
|
|
213
|
+
case 'data':
|
|
214
|
+
if (message.channel) {
|
|
215
|
+
// Notify channel-specific handlers
|
|
216
|
+
const handlers = this.messageHandlers.get(message.channel);
|
|
217
|
+
if (handlers) {
|
|
218
|
+
for (const handler of handlers) {
|
|
219
|
+
try {
|
|
220
|
+
handler(message.data, message.channel);
|
|
221
|
+
}
|
|
222
|
+
catch (error) {
|
|
223
|
+
console.error('[Realtime] Handler error:', error);
|
|
224
|
+
}
|
|
225
|
+
}
|
|
226
|
+
}
|
|
227
|
+
// Notify any-message handlers
|
|
228
|
+
for (const handler of this.anyMessageHandlers) {
|
|
229
|
+
try {
|
|
230
|
+
handler(message.channel, message.data);
|
|
231
|
+
}
|
|
232
|
+
catch (error) {
|
|
233
|
+
console.error('[Realtime] Any handler error:', error);
|
|
234
|
+
}
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
break;
|
|
238
|
+
case 'connected':
|
|
239
|
+
console.log('[Realtime] Connected, channels:', message.channels);
|
|
240
|
+
break;
|
|
241
|
+
case 'subscribed':
|
|
242
|
+
console.log('[Realtime] Subscribed to:', message.channel || message.channels);
|
|
243
|
+
break;
|
|
244
|
+
case 'unsubscribed':
|
|
245
|
+
console.log('[Realtime] Unsubscribed from:', message.channel);
|
|
246
|
+
break;
|
|
247
|
+
case 'pong':
|
|
248
|
+
// Heartbeat response received
|
|
249
|
+
break;
|
|
250
|
+
case 'error':
|
|
251
|
+
console.error('[Realtime] Server error:', message.message);
|
|
252
|
+
break;
|
|
253
|
+
}
|
|
254
|
+
}
|
|
255
|
+
handleDisconnect() {
|
|
256
|
+
this.clearPingInterval();
|
|
257
|
+
this.ws = null;
|
|
258
|
+
if (this.config.autoReconnect && this.state !== 'disconnected') {
|
|
259
|
+
if (this.config.maxReconnectAttempts === 0 ||
|
|
260
|
+
this.reconnectAttempts < this.config.maxReconnectAttempts) {
|
|
261
|
+
this.reconnectAttempts++;
|
|
262
|
+
this.setState('reconnecting');
|
|
263
|
+
const delay = this.config.reconnectDelay * Math.min(this.reconnectAttempts, 5);
|
|
264
|
+
console.log(`[Realtime] Reconnecting in ${delay}ms (attempt ${this.reconnectAttempts})`);
|
|
265
|
+
this.reconnectTimeout = setTimeout(() => {
|
|
266
|
+
this.connect();
|
|
267
|
+
}, delay);
|
|
268
|
+
}
|
|
269
|
+
else {
|
|
270
|
+
console.error('[Realtime] Max reconnect attempts reached');
|
|
271
|
+
this.setState('disconnected');
|
|
272
|
+
}
|
|
273
|
+
}
|
|
274
|
+
else {
|
|
275
|
+
this.setState('disconnected');
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
setState(newState) {
|
|
279
|
+
if (this.state === newState)
|
|
280
|
+
return;
|
|
281
|
+
this.state = newState;
|
|
282
|
+
for (const handler of this.stateChangeHandlers) {
|
|
283
|
+
try {
|
|
284
|
+
handler(newState);
|
|
285
|
+
}
|
|
286
|
+
catch (error) {
|
|
287
|
+
console.error('[Realtime] State change handler error:', error);
|
|
288
|
+
}
|
|
289
|
+
}
|
|
290
|
+
}
|
|
291
|
+
send(message) {
|
|
292
|
+
if (this.ws?.readyState === WebSocket.OPEN) {
|
|
293
|
+
this.ws.send(JSON.stringify(message));
|
|
294
|
+
}
|
|
295
|
+
}
|
|
296
|
+
startPingInterval() {
|
|
297
|
+
if (this.config.pingInterval <= 0)
|
|
298
|
+
return;
|
|
299
|
+
this.pingInterval = setInterval(() => {
|
|
300
|
+
this.send({ type: 'ping' });
|
|
301
|
+
}, this.config.pingInterval);
|
|
302
|
+
}
|
|
303
|
+
clearPingInterval() {
|
|
304
|
+
if (this.pingInterval) {
|
|
305
|
+
clearInterval(this.pingInterval);
|
|
306
|
+
this.pingInterval = null;
|
|
307
|
+
}
|
|
308
|
+
}
|
|
309
|
+
clearReconnectTimeout() {
|
|
310
|
+
if (this.reconnectTimeout) {
|
|
311
|
+
clearTimeout(this.reconnectTimeout);
|
|
312
|
+
this.reconnectTimeout = null;
|
|
313
|
+
}
|
|
314
|
+
}
|
|
315
|
+
}
|
|
316
|
+
/**
|
|
317
|
+
* useRealtime - React hook for real-time pub/sub
|
|
318
|
+
*
|
|
319
|
+
* Provides a simple interface for subscribing to channels and receiving
|
|
320
|
+
* real-time updates in React components.
|
|
321
|
+
*
|
|
322
|
+
* @param appId - App ID for channel isolation
|
|
323
|
+
* @param options - Hook options
|
|
324
|
+
* @returns Realtime state and controls
|
|
325
|
+
*
|
|
326
|
+
* @example
|
|
327
|
+
* ```tsx
|
|
328
|
+
* function Counter() {
|
|
329
|
+
* const { lastMessage, isConnected, publish } = useRealtime<{ count: number }>('my-app', {
|
|
330
|
+
* channels: ['counter'],
|
|
331
|
+
* });
|
|
332
|
+
*
|
|
333
|
+
* return (
|
|
334
|
+
* <div>
|
|
335
|
+
* <p>Connected: {isConnected ? 'Yes' : 'No'}</p>
|
|
336
|
+
* <p>Count: {lastMessage?.data.count ?? 0}</p>
|
|
337
|
+
* <button onClick={() => publish('counter', { count: 42 })}>
|
|
338
|
+
* Update
|
|
339
|
+
* </button>
|
|
340
|
+
* </div>
|
|
341
|
+
* );
|
|
342
|
+
* }
|
|
343
|
+
* ```
|
|
344
|
+
*/
|
|
345
|
+
export function useRealtime(appId, options = {}) {
|
|
346
|
+
const [state, setState] = useState('disconnected');
|
|
347
|
+
const [channels, setChannels] = useState(options.channels || []);
|
|
348
|
+
const [lastMessage, setLastMessage] = useState(null);
|
|
349
|
+
const clientRef = useRef(null);
|
|
350
|
+
// Initialize client
|
|
351
|
+
useEffect(() => {
|
|
352
|
+
const client = new RealtimeClient({
|
|
353
|
+
appId,
|
|
354
|
+
baseUrl: options.baseUrl,
|
|
355
|
+
channels: options.channels,
|
|
356
|
+
autoReconnect: options.autoReconnect,
|
|
357
|
+
reconnectDelay: options.reconnectDelay,
|
|
358
|
+
maxReconnectAttempts: options.maxReconnectAttempts,
|
|
359
|
+
});
|
|
360
|
+
clientRef.current = client;
|
|
361
|
+
// Set up state change handler
|
|
362
|
+
const unsubState = client.onStateChange((newState) => {
|
|
363
|
+
setState(newState);
|
|
364
|
+
if (newState === 'connected') {
|
|
365
|
+
options.onConnect?.();
|
|
366
|
+
}
|
|
367
|
+
else if (newState === 'disconnected') {
|
|
368
|
+
options.onDisconnect?.();
|
|
369
|
+
}
|
|
370
|
+
else if (newState === 'reconnecting') {
|
|
371
|
+
options.onReconnecting?.(client['reconnectAttempts']);
|
|
372
|
+
}
|
|
373
|
+
});
|
|
374
|
+
// Set up message handler
|
|
375
|
+
const unsubAny = client.onAny((channel, data) => {
|
|
376
|
+
setLastMessage({ channel, data: data });
|
|
377
|
+
});
|
|
378
|
+
// Connect
|
|
379
|
+
client.connect();
|
|
380
|
+
return () => {
|
|
381
|
+
unsubState();
|
|
382
|
+
unsubAny();
|
|
383
|
+
client.disconnect();
|
|
384
|
+
clientRef.current = null;
|
|
385
|
+
};
|
|
386
|
+
}, [appId, options.baseUrl]); // Only re-create on appId or baseUrl change
|
|
387
|
+
// Handle channel changes
|
|
388
|
+
useEffect(() => {
|
|
389
|
+
const client = clientRef.current;
|
|
390
|
+
if (!client)
|
|
391
|
+
return;
|
|
392
|
+
const currentChannels = new Set(client.channels);
|
|
393
|
+
const newChannels = new Set(options.channels || []);
|
|
394
|
+
// Subscribe to new channels
|
|
395
|
+
for (const channel of newChannels) {
|
|
396
|
+
if (!currentChannels.has(channel)) {
|
|
397
|
+
client.subscribe(channel);
|
|
398
|
+
}
|
|
399
|
+
}
|
|
400
|
+
// Unsubscribe from removed channels
|
|
401
|
+
for (const channel of currentChannels) {
|
|
402
|
+
if (!newChannels.has(channel)) {
|
|
403
|
+
client.unsubscribe(channel);
|
|
404
|
+
}
|
|
405
|
+
}
|
|
406
|
+
setChannels(client.channels);
|
|
407
|
+
}, [options.channels?.join(',')]);
|
|
408
|
+
const subscribe = useCallback((channel) => {
|
|
409
|
+
clientRef.current?.subscribe(channel);
|
|
410
|
+
setChannels(clientRef.current?.channels || []);
|
|
411
|
+
}, []);
|
|
412
|
+
const unsubscribe = useCallback((channel) => {
|
|
413
|
+
clientRef.current?.unsubscribe(channel);
|
|
414
|
+
setChannels(clientRef.current?.channels || []);
|
|
415
|
+
}, []);
|
|
416
|
+
const publish = useCallback((channel, data) => {
|
|
417
|
+
clientRef.current?.publish(channel, data);
|
|
418
|
+
}, []);
|
|
419
|
+
const reconnect = useCallback(() => {
|
|
420
|
+
clientRef.current?.disconnect();
|
|
421
|
+
clientRef.current?.connect();
|
|
422
|
+
}, []);
|
|
423
|
+
const disconnect = useCallback(() => {
|
|
424
|
+
clientRef.current?.disconnect();
|
|
425
|
+
}, []);
|
|
426
|
+
return {
|
|
427
|
+
state,
|
|
428
|
+
isConnected: state === 'connected',
|
|
429
|
+
channels,
|
|
430
|
+
lastMessage,
|
|
431
|
+
subscribe,
|
|
432
|
+
unsubscribe,
|
|
433
|
+
publish,
|
|
434
|
+
reconnect,
|
|
435
|
+
disconnect,
|
|
436
|
+
};
|
|
437
|
+
}
|
|
438
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/client/realtime/index.ts"],"names":[],"mappings":"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"}
|