11import { {{ spec .title | caseUcfirst }}Exception, Client } from '../client';
22
3- type RealtimeCallback = {
3+ export type RealtimeSubscription = {
4+ close: () => Promise<void >;
5+ }
6+
7+ export type RealtimeCallback<T = any > = {
48 channels: Set<string >;
5- callback: (event: RealtimeResponseEvent) => void;
9+ callback: (event: RealtimeResponseEvent< T > ) => void;
610}
711
8- type RealtimeResponseEvent = {
12+ export type RealtimeResponse = {
13+ type: string;
14+ data?: any;
15+ }
16+
17+ export type RealtimeResponseEvent<T = any > = {
918 events: string[];
1019 channels: string[];
1120 timestamp: string;
12- payload: Record< string , any > ;
21+ payload: T ;
1322}
1423
15- export type RealtimeSubscription = {
16- close: () => Promise<void >;
24+ export enum RealtimeCode {
25+ POLICY_VIOLATION = 1008,
26+ UNKNOWN_ERROR = -1
1727}
1828
1929export class Realtime {
@@ -26,7 +36,7 @@ export class Realtime {
2636 private client: Client;
2737 private socket?: WebSocket;
2838 private activeChannels = new Set<string >();
29- private activeSubscriptions = new Map<number , RealtimeCallback >();
39+ private activeSubscriptions = new Map<number , RealtimeCallback < any > >();
3040 private heartbeatTimer?: number;
3141
3242 private subCallDepth = 0;
@@ -132,18 +142,18 @@ export class Realtime {
132142
133143 this.socket.addEventListener('message', (event: MessageEvent) => {
134144 try {
135- const message = JSON.parse(event.data);
145+ const message = JSON.parse(event.data) as RealtimeResponse ;
136146 this.handleMessage(message);
137147 } catch (error) {
138148 console.error('Failed to parse message:', error);
139149 }
140150 });
141151
142- this.socket.addEventListener('close', async () => {
152+ this.socket.addEventListener('close', async (event: CloseEvent ) => {
143153 this.stopHeartbeat();
144154 this.onCloseCallbacks.forEach(callback => callback());
145155
146- if (!this.reconnect) {
156+ if (!this.reconnect || event.code === RealtimeCode.POLICY_VIOLATION ) {
147157 this.reconnect = true;
148158 return;
149159 }
@@ -189,7 +199,7 @@ export class Realtime {
189199 this.socket.addEventListener('close', () => {
190200 resolve();
191201 }, { once: true });
192- this.socket.close();
202+ this.socket.close(RealtimeCode.POLICY_VIOLATION );
193203 } else {
194204 resolve();
195205 }
@@ -222,7 +232,7 @@ export class Realtime {
222232 */
223233 public async subscribe(
224234 channel: string,
225- callback: (event: RealtimeResponseEvent) => void
235+ callback: (event: RealtimeResponseEvent< any > ) => void
226236 ): Promise<RealtimeSubscription >;
227237
228238 /**
@@ -234,12 +244,36 @@ export class Realtime {
234244 */
235245 public async subscribe(
236246 channels: string[],
237- callback: (event: RealtimeResponseEvent) => void
247+ callback: (event: RealtimeResponseEvent< any > ) => void
238248 ): Promise<RealtimeSubscription >;
239249
240- public async subscribe(
250+ /**
251+ * Subscribe to a single channel with typed payload
252+ *
253+ * @param {string} channel - Channel name to subscribe to
254+ * @param {Function} callback - Callback function to handle events with typed payload
255+ * @returns {Promise<RealtimeSubscription >} Subscription object with close method
256+ */
257+ public async subscribe<T >(
258+ channel: string,
259+ callback: (event: RealtimeResponseEvent<T >) => void
260+ ): Promise<RealtimeSubscription >;
261+
262+ /**
263+ * Subscribe to multiple channels with typed payload
264+ *
265+ * @param {string[]} channels - Array of channel names to subscribe to
266+ * @param {Function} callback - Callback function to handle events with typed payload
267+ * @returns {Promise<RealtimeSubscription >} Subscription object with close method
268+ */
269+ public async subscribe<T >(
270+ channels: string[],
271+ callback: (event: RealtimeResponseEvent<T >) => void
272+ ): Promise<RealtimeSubscription >;
273+
274+ public async subscribe<T = any >(
241275 channelsOrChannel: string | string[],
242- callback: (event: RealtimeResponseEvent) => void
276+ callback: (event: RealtimeResponseEvent< T > ) => void
243277 ): Promise<RealtimeSubscription > {
244278 const channels = Array.isArray(channelsOrChannel)
245279 ? new Set(channelsOrChannel)
@@ -291,7 +325,7 @@ export class Realtime {
291325 );
292326 }
293327
294- private handleMessage(message: any ): void {
328+ private handleMessage(message: RealtimeResponse ): void {
295329 if (!message.type) {
296330 return;
297331 }
@@ -309,23 +343,23 @@ export class Realtime {
309343 }
310344 }
311345
312- private handleResponseError(message: any ): void {
346+ private handleResponseError(message: RealtimeResponse ): void {
313347 const error = new {{spec .title | caseUcfirst }}Exception(
314- message.message || message. data?.message || 'Unknown error'
348+ message.data?.message || 'Unknown error'
315349 );
316- const statusCode = message.code || message. data?.code;
350+ const statusCode = message.data?.code;
317351 this.onErrorCallbacks.forEach(callback => callback(error, statusCode));
318352 }
319353
320- private handleResponseEvent(message: any ): void {
354+ private handleResponseEvent(message: RealtimeResponse ): void {
321355 const data = message.data;
322356 if (!data) {
323357 return;
324358 }
325359
326360 const channels = data.channels as string[];
327361 const events = data.events as string[];
328- const payload = data.payload as Record< string , any > ;
362+ const payload = data.payload;
329363 const timestamp = data.timestamp as string;
330364
331365 if (!channels || !events || !payload) {
@@ -346,7 +380,7 @@ export class Realtime {
346380 );
347381
348382 if (hasSubscribedChannel) {
349- const response: RealtimeResponseEvent = {
383+ const response: RealtimeResponseEvent< any > = {
350384 events,
351385 channels,
352386 timestamp,
0 commit comments