@aerostack/sdk-web 0.6.5 → 0.6.7

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.
@@ -8,19 +8,37 @@ export interface RealtimeSubscriptionOptions {
8
8
  event?: RealtimeEvent;
9
9
  filter?: Record<string, any>;
10
10
  }
11
- export type RealtimeCallback = (payload: any) => void;
12
- export declare class RealtimeSubscription {
11
+ export type RealtimeCallback<T = any> = (payload: RealtimePayload<T>) => void;
12
+ export interface RealtimePayload<T = any> {
13
+ type: 'db_change' | 'chat_message';
14
+ topic: string;
15
+ operation: RealtimeEvent;
16
+ data: T;
17
+ old?: T;
18
+ timestamp?: string;
19
+ [key: string]: any;
20
+ }
21
+ export declare class RealtimeSubscription<T = any> {
13
22
  private client;
14
23
  private topic;
15
24
  private options;
16
25
  private callbacks;
17
26
  private isSubscribed;
18
27
  constructor(client: RealtimeClient, topic: string, options?: RealtimeSubscriptionOptions);
19
- on(event: RealtimeEvent, callback: RealtimeCallback): this;
28
+ on(event: RealtimeEvent, callback: RealtimeCallback<T>): this;
20
29
  subscribe(): this;
21
30
  unsubscribe(): void;
22
31
  /** @internal */
23
- _emit(payload: any): void;
32
+ _emit(payload: RealtimePayload<T>): void;
33
+ }
34
+ export type RealtimeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
35
+ export interface RealtimeClientOptions {
36
+ baseUrl: string;
37
+ projectId: string;
38
+ token?: string;
39
+ userId?: string;
40
+ apiKey?: string;
41
+ maxReconnectAttempts?: number;
24
42
  }
25
43
  export declare class RealtimeClient {
26
44
  private baseUrl;
@@ -33,23 +51,35 @@ export declare class RealtimeClient {
33
51
  private reconnectTimer;
34
52
  private heartbeatTimer;
35
53
  private reconnectAttempts;
36
- constructor(options: {
37
- baseUrl: string;
38
- projectId: string;
39
- token?: string;
40
- userId?: string;
41
- apiKey?: string;
42
- });
54
+ private _sendQueue;
55
+ private _connectingPromise;
56
+ private _status;
57
+ private _statusListeners;
58
+ private _lastPong;
59
+ private _maxReconnectAttempts;
60
+ private _maxRetriesListeners;
61
+ constructor(options: RealtimeClientOptions);
62
+ get status(): RealtimeStatus;
63
+ onStatusChange(cb: (status: RealtimeStatus) => void): () => void;
64
+ onMaxRetriesExceeded(cb: () => void): () => void;
65
+ private _setStatus;
66
+ setToken(newToken: string): void;
43
67
  connect(): Promise<void>;
68
+ private _doConnect;
44
69
  disconnect(): void;
45
- channel(topic: string, options?: RealtimeSubscriptionOptions): RealtimeSubscription;
70
+ channel<T = any>(topic: string, options?: RealtimeSubscriptionOptions): RealtimeSubscription<T>;
71
+ sendChat(roomId: string, text: string): void;
72
+ chatRoom(roomId: string): RealtimeSubscription;
46
73
  /** @internal */
47
74
  _send(data: any): void;
48
75
  private handleMessage;
49
76
  private startHeartbeat;
50
77
  private stopHeartbeat;
51
- /** Exponential backoff with jitter: 1s → 2s → 4s → ... → 30s */
52
78
  private scheduleReconnect;
53
79
  private stopReconnect;
80
+ private _handleOnline;
81
+ private _handleOffline;
82
+ private _setupOfflineDetection;
83
+ private _teardownOfflineDetection;
54
84
  }
55
85
  //# sourceMappingURL=realtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IACxC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;AAEtD,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,SAAS,CAAwD;IACzE,OAAO,CAAC,YAAY,CAAkB;gBAE1B,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC;IAM5F,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAQ1D,SAAS,IAAI,IAAI;IAWjB,WAAW,IAAI,IAAI;IAUnB,gBAAgB;IAChB,KAAK,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;CAW5B;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,iBAAiB,CAAa;gBAE1B,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAQ7G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDxB,UAAU;IAOV,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC,GAAG,oBAAoB;IAWvF,gBAAgB;IAChB,KAAK,CAAC,IAAI,EAAE,GAAG;IAMf,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,aAAa;IAIrB,gEAAgE;IAChE,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;CAGxB"}
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"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"}
@@ -40,13 +40,8 @@ class RealtimeSubscription {
40
40
  /** @internal */
41
41
  _emit(payload) {
42
42
  const event = payload.operation;
43
- const requestedEvent = this.options.event || '*';
44
- if (requestedEvent === '*' || requestedEvent === event) {
45
- // Emit to specific event listeners
46
- this.callbacks.get(event)?.forEach(cb => cb(payload));
47
- // Emit to catch-all listeners
48
- this.callbacks.get('*')?.forEach(cb => cb(payload));
49
- }
43
+ this.callbacks.get(event)?.forEach(cb => cb(payload));
44
+ this.callbacks.get('*')?.forEach(cb => cb(payload));
50
45
  }
51
46
  }
52
47
  exports.RealtimeSubscription = RealtimeSubscription;
@@ -57,7 +52,24 @@ class RealtimeClient {
57
52
  this.reconnectTimer = null;
58
53
  this.heartbeatTimer = null;
59
54
  this.reconnectAttempts = 0;
60
- this.baseUrl = options.baseUrl.replace(/^http/, 'ws') + '/realtime';
55
+ this._sendQueue = [];
56
+ this._connectingPromise = null;
57
+ this._status = 'idle';
58
+ this._statusListeners = new Set();
59
+ this._lastPong = 0;
60
+ this._maxRetriesListeners = new Set();
61
+ this._handleOnline = () => {
62
+ if (this._status !== 'connected') {
63
+ this.reconnectAttempts = 0;
64
+ this.connect().catch(() => { });
65
+ }
66
+ };
67
+ this._handleOffline = () => {
68
+ this.stopReconnect();
69
+ this._setStatus('disconnected');
70
+ };
71
+ const wsBase = options.baseUrl.replace(/\/v1\/?$/, '').replace(/^http/, 'ws');
72
+ this.baseUrl = `${wsBase}/api/realtime`;
61
73
  this.projectId = options.projectId || '';
62
74
  if (options.token)
63
75
  this.token = options.token;
@@ -65,10 +77,37 @@ class RealtimeClient {
65
77
  this.userId = options.userId;
66
78
  if (options.apiKey)
67
79
  this.apiKey = options.apiKey;
80
+ this._maxReconnectAttempts = options.maxReconnectAttempts ?? Infinity;
81
+ }
82
+ get status() { return this._status; }
83
+ onStatusChange(cb) {
84
+ this._statusListeners.add(cb);
85
+ return () => this._statusListeners.delete(cb);
86
+ }
87
+ onMaxRetriesExceeded(cb) {
88
+ this._maxRetriesListeners.add(cb);
89
+ return () => this._maxRetriesListeners.delete(cb);
90
+ }
91
+ _setStatus(s) {
92
+ this._status = s;
93
+ this._statusListeners.forEach(cb => cb(s));
94
+ }
95
+ setToken(newToken) {
96
+ this.token = newToken;
97
+ this._send({ type: 'auth', token: newToken });
68
98
  }
69
99
  connect() {
70
- if (this.ws)
100
+ if (this.ws && this.ws.readyState === WebSocket.OPEN)
71
101
  return Promise.resolve();
102
+ if (this._connectingPromise)
103
+ return this._connectingPromise;
104
+ this._connectingPromise = this._doConnect().finally(() => {
105
+ this._connectingPromise = null;
106
+ });
107
+ return this._connectingPromise;
108
+ }
109
+ _doConnect() {
110
+ this._setStatus('connecting');
72
111
  return new Promise((resolve, reject) => {
73
112
  const url = new URL(this.baseUrl);
74
113
  if (this.apiKey) {
@@ -83,10 +122,14 @@ class RealtimeClient {
83
122
  url.searchParams.set('token', this.token);
84
123
  this.ws = new WebSocket(url.toString());
85
124
  this.ws.onopen = () => {
86
- console.log('Aerostack Realtime Connected');
125
+ this._setStatus('connected');
87
126
  this.reconnectAttempts = 0;
127
+ this._lastPong = Date.now();
88
128
  this.startHeartbeat();
89
- // Re-subscribe
129
+ this._setupOfflineDetection();
130
+ while (this._sendQueue.length > 0) {
131
+ this.ws.send(JSON.stringify(this._sendQueue.shift()));
132
+ }
90
133
  for (const sub of this.subscriptions.values()) {
91
134
  sub.subscribe();
92
135
  }
@@ -102,22 +145,28 @@ class RealtimeClient {
102
145
  }
103
146
  };
104
147
  this.ws.onclose = () => {
105
- console.log('Aerostack Realtime Disconnected');
148
+ this._setStatus('reconnecting');
106
149
  this.stopHeartbeat();
107
150
  this.ws = null;
108
151
  this.scheduleReconnect();
109
152
  };
110
153
  this.ws.onerror = (err) => {
111
154
  console.error('Realtime connection error:', err);
155
+ this._setStatus('disconnected');
112
156
  reject(err);
113
157
  };
114
158
  });
115
159
  }
116
160
  disconnect() {
161
+ this._setStatus('disconnected');
162
+ this.stopReconnect();
163
+ this.stopHeartbeat();
164
+ this._teardownOfflineDetection();
117
165
  if (this.ws) {
118
166
  this.ws.close();
167
+ this.ws = null;
119
168
  }
120
- this.stopReconnect();
169
+ this._sendQueue = [];
121
170
  }
122
171
  channel(topic, options = {}) {
123
172
  const fullTopic = topic.includes('/') ? topic : `table/${topic}/${this.projectId}`;
@@ -128,32 +177,54 @@ class RealtimeClient {
128
177
  }
129
178
  return sub;
130
179
  }
180
+ sendChat(roomId, text) {
181
+ this._send({ type: 'chat', roomId, text });
182
+ }
183
+ chatRoom(roomId) {
184
+ return this.channel(`chat/${roomId}/${this.projectId}`);
185
+ }
131
186
  /** @internal */
132
187
  _send(data) {
133
188
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
134
189
  this.ws.send(JSON.stringify(data));
135
190
  }
191
+ else {
192
+ this._sendQueue.push(data);
193
+ }
136
194
  }
137
195
  handleMessage(data) {
196
+ if (data.type === 'pong') {
197
+ this._lastPong = Date.now();
198
+ return;
199
+ }
138
200
  if (data.type === 'db_change' || data.type === 'chat_message') {
139
201
  const sub = this.subscriptions.get(data.topic);
140
- if (sub) {
202
+ if (sub)
141
203
  sub._emit(data);
142
- }
143
204
  }
144
205
  }
145
206
  startHeartbeat() {
146
207
  this.heartbeatTimer = setInterval(() => {
147
208
  this._send({ type: 'ping' });
209
+ if (this._lastPong > 0 && Date.now() - this._lastPong > 70000) {
210
+ console.warn('Realtime: no pong received, forcing reconnect');
211
+ this.ws?.close();
212
+ }
148
213
  }, 30000);
149
214
  }
150
215
  stopHeartbeat() {
151
- if (this.heartbeatTimer)
216
+ if (this.heartbeatTimer) {
152
217
  clearInterval(this.heartbeatTimer);
218
+ this.heartbeatTimer = null;
219
+ }
153
220
  }
154
- /** Exponential backoff with jitter: 1s → 2s → 4s → ... → 30s */
155
221
  scheduleReconnect() {
156
222
  this.stopReconnect();
223
+ if (this.reconnectAttempts >= this._maxReconnectAttempts) {
224
+ this._setStatus('disconnected');
225
+ this._maxRetriesListeners.forEach(cb => cb());
226
+ return;
227
+ }
157
228
  const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
158
229
  const jitter = delay * 0.3 * Math.random();
159
230
  this.reconnectAttempts++;
@@ -162,8 +233,22 @@ class RealtimeClient {
162
233
  }, delay + jitter);
163
234
  }
164
235
  stopReconnect() {
165
- if (this.reconnectTimer)
236
+ if (this.reconnectTimer) {
166
237
  clearTimeout(this.reconnectTimer);
238
+ this.reconnectTimer = null;
239
+ }
240
+ }
241
+ _setupOfflineDetection() {
242
+ if (typeof window !== 'undefined') {
243
+ window.addEventListener('online', this._handleOnline);
244
+ window.addEventListener('offline', this._handleOffline);
245
+ }
246
+ }
247
+ _teardownOfflineDetection() {
248
+ if (typeof window !== 'undefined') {
249
+ window.removeEventListener('online', this._handleOnline);
250
+ window.removeEventListener('offline', this._handleOffline);
251
+ }
167
252
  }
168
253
  }
169
254
  exports.RealtimeClient = RealtimeClient;
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":";;;AAeA,MAAa,oBAAoB;IAO7B,YAAY,MAAsB,EAAE,KAAa,EAAE,UAAuC,EAAE;QAHpF,cAAS,GAA8C,IAAI,GAAG,EAAE,CAAC;QACjE,iBAAY,GAAY,KAAK,CAAC;QAGlC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,EAAE,CAAC,KAAoB,EAAE,QAA0B;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,SAAS;QACL,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACd,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,WAAW;QACP,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACd,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;SACpB,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,gBAAgB;IAChB,KAAK,CAAC,OAAY;QACd,MAAM,KAAK,GAAG,OAAO,CAAC,SAA0B,CAAC;QACjD,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;QAEjD,IAAI,cAAc,KAAK,GAAG,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;YACrD,mCAAmC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACtD,8BAA8B;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,CAAC;IACL,CAAC;CACJ;AAtDD,oDAsDC;AAED,MAAa,cAAc;IAYvB,YAAY,OAAiG;QANrG,OAAE,GAAqB,IAAI,CAAC;QAC5B,kBAAa,GAAsC,IAAI,GAAG,EAAE,CAAC;QAC7D,mBAAc,GAAQ,IAAI,CAAC;QAC3B,mBAAc,GAAQ,IAAI,CAAC;QAC3B,sBAAiB,GAAW,CAAC,CAAC;QAGlC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,WAAW,CAAC;QACpE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACrD,CAAC;IAED,OAAO;QACH,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAEtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACJ,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,IAAI,CAAC,MAAM;gBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7D,IAAI,IAAI,CAAC,KAAK;gBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAE1D,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAExC,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;gBAClB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;gBAC5C,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;gBAC3B,IAAI,CAAC,cAAc,EAAE,CAAC;gBACtB,eAAe;gBACf,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC5C,GAAG,CAAC,SAAS,EAAE,CAAC;gBACpB,CAAC;gBACD,OAAO,EAAE,CAAC;YACd,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;gBAC1B,IAAI,CAAC;oBACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAC7B,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACT,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,CAAC,CAAC,CAAC;gBACtD,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;gBAC/C,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC7B,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE,EAAE;gBACtB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;gBACjD,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC;IAED,UAAU;QACN,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACV,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,UAAuC,EAAE;QAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAEnF,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,GAAG,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED,gBAAgB;IAChB,KAAK,CAAC,IAAS;QACX,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,IAAqB;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,GAAG,EAAE,CAAC;gBACN,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACL,CAAC;IACL,CAAC;IAEO,cAAc;QAClB,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACjC,CAAC,EAAE,KAAK,CAAC,CAAC;IACd,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,cAAc;YAAE,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChE,CAAC;IAED,gEAAgE;IACxD,iBAAiB;QACrB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC;IACvB,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,cAAc;YAAE,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/D,CAAC;CACJ;AA/HD,wCA+HC"}
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"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"}
@@ -8,19 +8,37 @@ export interface RealtimeSubscriptionOptions {
8
8
  event?: RealtimeEvent;
9
9
  filter?: Record<string, any>;
10
10
  }
11
- export type RealtimeCallback = (payload: any) => void;
12
- export declare class RealtimeSubscription {
11
+ export type RealtimeCallback<T = any> = (payload: RealtimePayload<T>) => void;
12
+ export interface RealtimePayload<T = any> {
13
+ type: 'db_change' | 'chat_message';
14
+ topic: string;
15
+ operation: RealtimeEvent;
16
+ data: T;
17
+ old?: T;
18
+ timestamp?: string;
19
+ [key: string]: any;
20
+ }
21
+ export declare class RealtimeSubscription<T = any> {
13
22
  private client;
14
23
  private topic;
15
24
  private options;
16
25
  private callbacks;
17
26
  private isSubscribed;
18
27
  constructor(client: RealtimeClient, topic: string, options?: RealtimeSubscriptionOptions);
19
- on(event: RealtimeEvent, callback: RealtimeCallback): this;
28
+ on(event: RealtimeEvent, callback: RealtimeCallback<T>): this;
20
29
  subscribe(): this;
21
30
  unsubscribe(): void;
22
31
  /** @internal */
23
- _emit(payload: any): void;
32
+ _emit(payload: RealtimePayload<T>): void;
33
+ }
34
+ export type RealtimeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
35
+ export interface RealtimeClientOptions {
36
+ baseUrl: string;
37
+ projectId: string;
38
+ token?: string;
39
+ userId?: string;
40
+ apiKey?: string;
41
+ maxReconnectAttempts?: number;
24
42
  }
25
43
  export declare class RealtimeClient {
26
44
  private baseUrl;
@@ -33,23 +51,35 @@ export declare class RealtimeClient {
33
51
  private reconnectTimer;
34
52
  private heartbeatTimer;
35
53
  private reconnectAttempts;
36
- constructor(options: {
37
- baseUrl: string;
38
- projectId: string;
39
- token?: string;
40
- userId?: string;
41
- apiKey?: string;
42
- });
54
+ private _sendQueue;
55
+ private _connectingPromise;
56
+ private _status;
57
+ private _statusListeners;
58
+ private _lastPong;
59
+ private _maxReconnectAttempts;
60
+ private _maxRetriesListeners;
61
+ constructor(options: RealtimeClientOptions);
62
+ get status(): RealtimeStatus;
63
+ onStatusChange(cb: (status: RealtimeStatus) => void): () => void;
64
+ onMaxRetriesExceeded(cb: () => void): () => void;
65
+ private _setStatus;
66
+ setToken(newToken: string): void;
43
67
  connect(): Promise<void>;
68
+ private _doConnect;
44
69
  disconnect(): void;
45
- channel(topic: string, options?: RealtimeSubscriptionOptions): RealtimeSubscription;
70
+ channel<T = any>(topic: string, options?: RealtimeSubscriptionOptions): RealtimeSubscription<T>;
71
+ sendChat(roomId: string, text: string): void;
72
+ chatRoom(roomId: string): RealtimeSubscription;
46
73
  /** @internal */
47
74
  _send(data: any): void;
48
75
  private handleMessage;
49
76
  private startHeartbeat;
50
77
  private stopHeartbeat;
51
- /** Exponential backoff with jitter: 1s → 2s → 4s → ... → 30s */
52
78
  private scheduleReconnect;
53
79
  private stopReconnect;
80
+ private _handleOnline;
81
+ private _handleOffline;
82
+ private _setupOfflineDetection;
83
+ private _teardownOfflineDetection;
54
84
  }
55
85
  //# sourceMappingURL=realtime.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"AAAA,MAAM,MAAM,aAAa,GAAG,QAAQ,GAAG,QAAQ,GAAG,QAAQ,GAAG,GAAG,CAAC;AAEjE,MAAM,WAAW,eAAe;IAC5B,IAAI,EAAE,MAAM,CAAC;IACb,KAAK,EAAE,MAAM,CAAC;IACd,CAAC,GAAG,EAAE,MAAM,GAAG,GAAG,CAAC;CACtB;AAED,MAAM,WAAW,2BAA2B;IACxC,KAAK,CAAC,EAAE,aAAa,CAAC;IACtB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,CAAC;CAChC;AAED,MAAM,MAAM,gBAAgB,GAAG,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;AAEtD,qBAAa,oBAAoB;IAC7B,OAAO,CAAC,MAAM,CAAiB;IAC/B,OAAO,CAAC,KAAK,CAAS;IACtB,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,SAAS,CAAwD;IACzE,OAAO,CAAC,YAAY,CAAkB;gBAE1B,MAAM,EAAE,cAAc,EAAE,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC;IAM5F,EAAE,CAAC,KAAK,EAAE,aAAa,EAAE,QAAQ,EAAE,gBAAgB,GAAG,IAAI;IAQ1D,SAAS,IAAI,IAAI;IAWjB,WAAW,IAAI,IAAI;IAUnB,gBAAgB;IAChB,KAAK,CAAC,OAAO,EAAE,GAAG,GAAG,IAAI;CAW5B;AAED,qBAAa,cAAc;IACvB,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAC,CAAS;IACvB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,MAAM,CAAC,CAAS;IACxB,OAAO,CAAC,EAAE,CAA0B;IACpC,OAAO,CAAC,aAAa,CAAgD;IACrE,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,cAAc,CAAa;IACnC,OAAO,CAAC,iBAAiB,CAAa;gBAE1B,OAAO,EAAE;QAAE,OAAO,EAAE,MAAM,CAAC;QAAC,SAAS,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAC;QAAC,MAAM,CAAC,EAAE,MAAM,CAAA;KAAE;IAQ7G,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAiDxB,UAAU;IAOV,OAAO,CAAC,KAAK,EAAE,MAAM,EAAE,OAAO,GAAE,2BAAgC,GAAG,oBAAoB;IAWvF,gBAAgB;IAChB,KAAK,CAAC,IAAI,EAAE,GAAG;IAMf,OAAO,CAAC,aAAa;IASrB,OAAO,CAAC,cAAc;IAMtB,OAAO,CAAC,aAAa;IAIrB,gEAAgE;IAChE,OAAO,CAAC,iBAAiB;IAUzB,OAAO,CAAC,aAAa;CAGxB"}
1
+ {"version":3,"file":"realtime.d.ts","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"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"}
@@ -37,13 +37,8 @@ export class RealtimeSubscription {
37
37
  /** @internal */
38
38
  _emit(payload) {
39
39
  const event = payload.operation;
40
- const requestedEvent = this.options.event || '*';
41
- if (requestedEvent === '*' || requestedEvent === event) {
42
- // Emit to specific event listeners
43
- this.callbacks.get(event)?.forEach(cb => cb(payload));
44
- // Emit to catch-all listeners
45
- this.callbacks.get('*')?.forEach(cb => cb(payload));
46
- }
40
+ this.callbacks.get(event)?.forEach(cb => cb(payload));
41
+ this.callbacks.get('*')?.forEach(cb => cb(payload));
47
42
  }
48
43
  }
49
44
  export class RealtimeClient {
@@ -53,7 +48,24 @@ export class RealtimeClient {
53
48
  this.reconnectTimer = null;
54
49
  this.heartbeatTimer = null;
55
50
  this.reconnectAttempts = 0;
56
- this.baseUrl = options.baseUrl.replace(/^http/, 'ws') + '/realtime';
51
+ this._sendQueue = [];
52
+ this._connectingPromise = null;
53
+ this._status = 'idle';
54
+ this._statusListeners = new Set();
55
+ this._lastPong = 0;
56
+ this._maxRetriesListeners = new Set();
57
+ this._handleOnline = () => {
58
+ if (this._status !== 'connected') {
59
+ this.reconnectAttempts = 0;
60
+ this.connect().catch(() => { });
61
+ }
62
+ };
63
+ this._handleOffline = () => {
64
+ this.stopReconnect();
65
+ this._setStatus('disconnected');
66
+ };
67
+ const wsBase = options.baseUrl.replace(/\/v1\/?$/, '').replace(/^http/, 'ws');
68
+ this.baseUrl = `${wsBase}/api/realtime`;
57
69
  this.projectId = options.projectId || '';
58
70
  if (options.token)
59
71
  this.token = options.token;
@@ -61,10 +73,37 @@ export class RealtimeClient {
61
73
  this.userId = options.userId;
62
74
  if (options.apiKey)
63
75
  this.apiKey = options.apiKey;
76
+ this._maxReconnectAttempts = options.maxReconnectAttempts ?? Infinity;
77
+ }
78
+ get status() { return this._status; }
79
+ onStatusChange(cb) {
80
+ this._statusListeners.add(cb);
81
+ return () => this._statusListeners.delete(cb);
82
+ }
83
+ onMaxRetriesExceeded(cb) {
84
+ this._maxRetriesListeners.add(cb);
85
+ return () => this._maxRetriesListeners.delete(cb);
86
+ }
87
+ _setStatus(s) {
88
+ this._status = s;
89
+ this._statusListeners.forEach(cb => cb(s));
90
+ }
91
+ setToken(newToken) {
92
+ this.token = newToken;
93
+ this._send({ type: 'auth', token: newToken });
64
94
  }
65
95
  connect() {
66
- if (this.ws)
96
+ if (this.ws && this.ws.readyState === WebSocket.OPEN)
67
97
  return Promise.resolve();
98
+ if (this._connectingPromise)
99
+ return this._connectingPromise;
100
+ this._connectingPromise = this._doConnect().finally(() => {
101
+ this._connectingPromise = null;
102
+ });
103
+ return this._connectingPromise;
104
+ }
105
+ _doConnect() {
106
+ this._setStatus('connecting');
68
107
  return new Promise((resolve, reject) => {
69
108
  const url = new URL(this.baseUrl);
70
109
  if (this.apiKey) {
@@ -79,10 +118,14 @@ export class RealtimeClient {
79
118
  url.searchParams.set('token', this.token);
80
119
  this.ws = new WebSocket(url.toString());
81
120
  this.ws.onopen = () => {
82
- console.log('Aerostack Realtime Connected');
121
+ this._setStatus('connected');
83
122
  this.reconnectAttempts = 0;
123
+ this._lastPong = Date.now();
84
124
  this.startHeartbeat();
85
- // Re-subscribe
125
+ this._setupOfflineDetection();
126
+ while (this._sendQueue.length > 0) {
127
+ this.ws.send(JSON.stringify(this._sendQueue.shift()));
128
+ }
86
129
  for (const sub of this.subscriptions.values()) {
87
130
  sub.subscribe();
88
131
  }
@@ -98,22 +141,28 @@ export class RealtimeClient {
98
141
  }
99
142
  };
100
143
  this.ws.onclose = () => {
101
- console.log('Aerostack Realtime Disconnected');
144
+ this._setStatus('reconnecting');
102
145
  this.stopHeartbeat();
103
146
  this.ws = null;
104
147
  this.scheduleReconnect();
105
148
  };
106
149
  this.ws.onerror = (err) => {
107
150
  console.error('Realtime connection error:', err);
151
+ this._setStatus('disconnected');
108
152
  reject(err);
109
153
  };
110
154
  });
111
155
  }
112
156
  disconnect() {
157
+ this._setStatus('disconnected');
158
+ this.stopReconnect();
159
+ this.stopHeartbeat();
160
+ this._teardownOfflineDetection();
113
161
  if (this.ws) {
114
162
  this.ws.close();
163
+ this.ws = null;
115
164
  }
116
- this.stopReconnect();
165
+ this._sendQueue = [];
117
166
  }
118
167
  channel(topic, options = {}) {
119
168
  const fullTopic = topic.includes('/') ? topic : `table/${topic}/${this.projectId}`;
@@ -124,32 +173,54 @@ export class RealtimeClient {
124
173
  }
125
174
  return sub;
126
175
  }
176
+ sendChat(roomId, text) {
177
+ this._send({ type: 'chat', roomId, text });
178
+ }
179
+ chatRoom(roomId) {
180
+ return this.channel(`chat/${roomId}/${this.projectId}`);
181
+ }
127
182
  /** @internal */
128
183
  _send(data) {
129
184
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
130
185
  this.ws.send(JSON.stringify(data));
131
186
  }
187
+ else {
188
+ this._sendQueue.push(data);
189
+ }
132
190
  }
133
191
  handleMessage(data) {
192
+ if (data.type === 'pong') {
193
+ this._lastPong = Date.now();
194
+ return;
195
+ }
134
196
  if (data.type === 'db_change' || data.type === 'chat_message') {
135
197
  const sub = this.subscriptions.get(data.topic);
136
- if (sub) {
198
+ if (sub)
137
199
  sub._emit(data);
138
- }
139
200
  }
140
201
  }
141
202
  startHeartbeat() {
142
203
  this.heartbeatTimer = setInterval(() => {
143
204
  this._send({ type: 'ping' });
205
+ if (this._lastPong > 0 && Date.now() - this._lastPong > 70000) {
206
+ console.warn('Realtime: no pong received, forcing reconnect');
207
+ this.ws?.close();
208
+ }
144
209
  }, 30000);
145
210
  }
146
211
  stopHeartbeat() {
147
- if (this.heartbeatTimer)
212
+ if (this.heartbeatTimer) {
148
213
  clearInterval(this.heartbeatTimer);
214
+ this.heartbeatTimer = null;
215
+ }
149
216
  }
150
- /** Exponential backoff with jitter: 1s → 2s → 4s → ... → 30s */
151
217
  scheduleReconnect() {
152
218
  this.stopReconnect();
219
+ if (this.reconnectAttempts >= this._maxReconnectAttempts) {
220
+ this._setStatus('disconnected');
221
+ this._maxRetriesListeners.forEach(cb => cb());
222
+ return;
223
+ }
153
224
  const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
154
225
  const jitter = delay * 0.3 * Math.random();
155
226
  this.reconnectAttempts++;
@@ -158,8 +229,22 @@ export class RealtimeClient {
158
229
  }, delay + jitter);
159
230
  }
160
231
  stopReconnect() {
161
- if (this.reconnectTimer)
232
+ if (this.reconnectTimer) {
162
233
  clearTimeout(this.reconnectTimer);
234
+ this.reconnectTimer = null;
235
+ }
236
+ }
237
+ _setupOfflineDetection() {
238
+ if (typeof window !== 'undefined') {
239
+ window.addEventListener('online', this._handleOnline);
240
+ window.addEventListener('offline', this._handleOffline);
241
+ }
242
+ }
243
+ _teardownOfflineDetection() {
244
+ if (typeof window !== 'undefined') {
245
+ window.removeEventListener('online', this._handleOnline);
246
+ window.removeEventListener('offline', this._handleOffline);
247
+ }
163
248
  }
164
249
  }
165
250
  //# sourceMappingURL=realtime.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"AAeA,MAAM,OAAO,oBAAoB;IAO7B,YAAY,MAAsB,EAAE,KAAa,EAAE,UAAuC,EAAE;QAHpF,cAAS,GAA8C,IAAI,GAAG,EAAE,CAAC;QACjE,iBAAY,GAAY,KAAK,CAAC;QAGlC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;QACrB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;QACnB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;IAC3B,CAAC;IAED,EAAE,CAAC,KAAoB,EAAE,QAA0B;QAC/C,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,CAAC;YAC7B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,EAAE,IAAI,GAAG,EAAE,CAAC,CAAC;QACzC,CAAC;QACD,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAE,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAC;QACzC,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,SAAS;QACL,IAAI,IAAI,CAAC,YAAY;YAAE,OAAO,IAAI,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACd,IAAI,EAAE,WAAW;YACjB,KAAK,EAAE,IAAI,CAAC,KAAK;YACjB,MAAM,EAAE,IAAI,CAAC,OAAO,CAAC,MAAM;SAC9B,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,IAAI,CAAC;QACzB,OAAO,IAAI,CAAC;IAChB,CAAC;IAED,WAAW;QACP,IAAI,CAAC,IAAI,CAAC,YAAY;YAAE,OAAO;QAC/B,IAAI,CAAC,MAAM,CAAC,KAAK,CAAC;YACd,IAAI,EAAE,aAAa;YACnB,KAAK,EAAE,IAAI,CAAC,KAAK;SACpB,CAAC,CAAC;QACH,IAAI,CAAC,YAAY,GAAG,KAAK,CAAC;QAC1B,IAAI,CAAC,SAAS,CAAC,KAAK,EAAE,CAAC;IAC3B,CAAC;IAED,gBAAgB;IAChB,KAAK,CAAC,OAAY;QACd,MAAM,KAAK,GAAG,OAAO,CAAC,SAA0B,CAAC;QACjD,MAAM,cAAc,GAAG,IAAI,CAAC,OAAO,CAAC,KAAK,IAAI,GAAG,CAAC;QAEjD,IAAI,cAAc,KAAK,GAAG,IAAI,cAAc,KAAK,KAAK,EAAE,CAAC;YACrD,mCAAmC;YACnC,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,KAAK,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;YACtD,8BAA8B;YAC9B,IAAI,CAAC,SAAS,CAAC,GAAG,CAAC,GAAG,CAAC,EAAE,OAAO,CAAC,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,OAAO,CAAC,CAAC,CAAC;QACxD,CAAC;IACL,CAAC;CACJ;AAED,MAAM,OAAO,cAAc;IAYvB,YAAY,OAAiG;QANrG,OAAE,GAAqB,IAAI,CAAC;QAC5B,kBAAa,GAAsC,IAAI,GAAG,EAAE,CAAC;QAC7D,mBAAc,GAAQ,IAAI,CAAC;QAC3B,mBAAc,GAAQ,IAAI,CAAC;QAC3B,sBAAiB,GAAW,CAAC,CAAC;QAGlC,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,OAAO,CAAC,OAAO,EAAE,IAAI,CAAC,GAAG,WAAW,CAAC;QACpE,IAAI,CAAC,SAAS,GAAG,OAAO,CAAC,SAAS,IAAI,EAAE,CAAC;QACzC,IAAI,OAAO,CAAC,KAAK;YAAE,IAAI,CAAC,KAAK,GAAG,OAAO,CAAC,KAAK,CAAC;QAC9C,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;QACjD,IAAI,OAAO,CAAC,MAAM;YAAE,IAAI,CAAC,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC;IACrD,CAAC;IAED,OAAO;QACH,IAAI,IAAI,CAAC,EAAE;YAAE,OAAO,OAAO,CAAC,OAAO,EAAE,CAAC;QAEtC,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;YACnC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC;YAClC,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBACd,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAChD,CAAC;iBAAM,CAAC;gBACJ,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,IAAI,CAAC,SAAS,CAAC,CAAC;YACtD,CAAC;YACD,IAAI,IAAI,CAAC,MAAM;gBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,QAAQ,EAAE,IAAI,CAAC,MAAM,CAAC,CAAC;YAC7D,IAAI,IAAI,CAAC,KAAK;gBAAE,GAAG,CAAC,YAAY,CAAC,GAAG,CAAC,OAAO,EAAE,IAAI,CAAC,KAAK,CAAC,CAAC;YAE1D,IAAI,CAAC,EAAE,GAAG,IAAI,SAAS,CAAC,GAAG,CAAC,QAAQ,EAAE,CAAC,CAAC;YAExC,IAAI,CAAC,EAAE,CAAC,MAAM,GAAG,GAAG,EAAE;gBAClB,OAAO,CAAC,GAAG,CAAC,8BAA8B,CAAC,CAAC;gBAC5C,IAAI,CAAC,iBAAiB,GAAG,CAAC,CAAC;gBAC3B,IAAI,CAAC,cAAc,EAAE,CAAC;gBACtB,eAAe;gBACf,KAAK,MAAM,GAAG,IAAI,IAAI,CAAC,aAAa,CAAC,MAAM,EAAE,EAAE,CAAC;oBAC5C,GAAG,CAAC,SAAS,EAAE,CAAC;gBACpB,CAAC;gBACD,OAAO,EAAE,CAAC;YACd,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,SAAS,GAAG,CAAC,KAAK,EAAE,EAAE;gBAC1B,IAAI,CAAC;oBACD,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;oBACpC,IAAI,CAAC,aAAa,CAAC,IAAI,CAAC,CAAC;gBAC7B,CAAC;gBAAC,OAAO,CAAC,EAAE,CAAC;oBACT,OAAO,CAAC,KAAK,CAAC,+BAA+B,EAAE,CAAC,CAAC,CAAC;gBACtD,CAAC;YACL,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,GAAG,EAAE;gBACnB,OAAO,CAAC,GAAG,CAAC,iCAAiC,CAAC,CAAC;gBAC/C,IAAI,CAAC,aAAa,EAAE,CAAC;gBACrB,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC;gBACf,IAAI,CAAC,iBAAiB,EAAE,CAAC;YAC7B,CAAC,CAAC;YAEF,IAAI,CAAC,EAAE,CAAC,OAAO,GAAG,CAAC,GAAG,EAAE,EAAE;gBACtB,OAAO,CAAC,KAAK,CAAC,4BAA4B,EAAE,GAAG,CAAC,CAAC;gBACjD,MAAM,CAAC,GAAG,CAAC,CAAC;YAChB,CAAC,CAAC;QACN,CAAC,CAAC,CAAC;IACP,CAAC;IAED,UAAU;QACN,IAAI,IAAI,CAAC,EAAE,EAAE,CAAC;YACV,IAAI,CAAC,EAAE,CAAC,KAAK,EAAE,CAAC;QACpB,CAAC;QACD,IAAI,CAAC,aAAa,EAAE,CAAC;IACzB,CAAC;IAED,OAAO,CAAC,KAAa,EAAE,UAAuC,EAAE;QAC5D,MAAM,SAAS,GAAG,KAAK,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,SAAS,KAAK,IAAI,IAAI,CAAC,SAAS,EAAE,CAAC;QAEnF,IAAI,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;QAC5C,IAAI,CAAC,GAAG,EAAE,CAAC;YACP,GAAG,GAAG,IAAI,oBAAoB,CAAC,IAAI,EAAE,SAAS,EAAE,OAAO,CAAC,CAAC;YACzD,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,SAAS,EAAE,GAAG,CAAC,CAAC;QAC3C,CAAC;QACD,OAAO,GAAG,CAAC;IACf,CAAC;IAED,gBAAgB;IAChB,KAAK,CAAC,IAAS;QACX,IAAI,IAAI,CAAC,EAAE,IAAI,IAAI,CAAC,EAAE,CAAC,UAAU,KAAK,SAAS,CAAC,IAAI,EAAE,CAAC;YACnD,IAAI,CAAC,EAAE,CAAC,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC,CAAC;QACvC,CAAC;IACL,CAAC;IAEO,aAAa,CAAC,IAAqB;QACvC,IAAI,IAAI,CAAC,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,IAAI,KAAK,cAAc,EAAE,CAAC;YAC5D,MAAM,GAAG,GAAG,IAAI,CAAC,aAAa,CAAC,GAAG,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;YAC/C,IAAI,GAAG,EAAE,CAAC;gBACN,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC;YACpB,CAAC;QACL,CAAC;IACL,CAAC;IAEO,cAAc;QAClB,IAAI,CAAC,cAAc,GAAG,WAAW,CAAC,GAAG,EAAE;YACnC,IAAI,CAAC,KAAK,CAAC,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACjC,CAAC,EAAE,KAAK,CAAC,CAAC;IACd,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,cAAc;YAAE,aAAa,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAChE,CAAC;IAED,gEAAgE;IACxD,iBAAiB;QACrB,IAAI,CAAC,aAAa,EAAE,CAAC;QACrB,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,CAAC,iBAAiB,CAAC,EAAE,KAAK,CAAC,CAAC;QAC1E,MAAM,MAAM,GAAG,KAAK,GAAG,GAAG,GAAG,IAAI,CAAC,MAAM,EAAE,CAAC;QAC3C,IAAI,CAAC,iBAAiB,EAAE,CAAC;QACzB,IAAI,CAAC,cAAc,GAAG,UAAU,CAAC,GAAG,EAAE;YAClC,IAAI,CAAC,OAAO,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,GAAG,CAAC,CAAC,CAAC;QACpC,CAAC,EAAE,KAAK,GAAG,MAAM,CAAC,CAAC;IACvB,CAAC;IAEO,aAAa;QACjB,IAAI,IAAI,CAAC,cAAc;YAAE,YAAY,CAAC,IAAI,CAAC,cAAc,CAAC,CAAC;IAC/D,CAAC;CACJ"}
1
+ {"version":3,"file":"realtime.js","sourceRoot":"","sources":["../../../src/sdk/realtime.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aerostack/sdk-web",
3
- "version": "0.6.5",
3
+ "version": "0.6.7",
4
4
  "author": "Aerostack",
5
5
  "type": "module",
6
6
  "tshy": {
@@ -36,7 +36,7 @@
36
36
  "ws": "^8.19.0"
37
37
  },
38
38
  "dependencies": {
39
- "@aerostack/core": "^0.6.0",
39
+ "@aerostack/core": "^0.6.7",
40
40
  "zod": "^3.25.0 || ^4.0.0"
41
41
  },
42
42
  "exports": {
@@ -11,13 +11,23 @@ export interface RealtimeSubscriptionOptions {
11
11
  filter?: Record<string, any>;
12
12
  }
13
13
 
14
- export type RealtimeCallback = (payload: any) => void;
14
+ export type RealtimeCallback<T = any> = (payload: RealtimePayload<T>) => void;
15
15
 
16
- export class RealtimeSubscription {
16
+ export interface RealtimePayload<T = any> {
17
+ type: 'db_change' | 'chat_message';
18
+ topic: string;
19
+ operation: RealtimeEvent;
20
+ data: T;
21
+ old?: T;
22
+ timestamp?: string;
23
+ [key: string]: any;
24
+ }
25
+
26
+ export class RealtimeSubscription<T = any> {
17
27
  private client: RealtimeClient;
18
28
  private topic: string;
19
29
  private options: RealtimeSubscriptionOptions;
20
- private callbacks: Map<RealtimeEvent, Set<RealtimeCallback>> = new Map();
30
+ private callbacks: Map<RealtimeEvent, Set<RealtimeCallback<T>>> = new Map();
21
31
  private isSubscribed: boolean = false;
22
32
 
23
33
  constructor(client: RealtimeClient, topic: string, options: RealtimeSubscriptionOptions = {}) {
@@ -26,7 +36,7 @@ export class RealtimeSubscription {
26
36
  this.options = options;
27
37
  }
28
38
 
29
- on(event: RealtimeEvent, callback: RealtimeCallback): this {
39
+ on(event: RealtimeEvent, callback: RealtimeCallback<T>): this {
30
40
  if (!this.callbacks.has(event)) {
31
41
  this.callbacks.set(event, new Set());
32
42
  }
@@ -56,19 +66,24 @@ export class RealtimeSubscription {
56
66
  }
57
67
 
58
68
  /** @internal */
59
- _emit(payload: any): void {
69
+ _emit(payload: RealtimePayload<T>): void {
60
70
  const event = payload.operation as RealtimeEvent;
61
- const requestedEvent = this.options.event || '*';
62
-
63
- if (requestedEvent === '*' || requestedEvent === event) {
64
- // Emit to specific event listeners
65
- this.callbacks.get(event)?.forEach(cb => cb(payload));
66
- // Emit to catch-all listeners
67
- this.callbacks.get('*')?.forEach(cb => cb(payload));
68
- }
71
+ this.callbacks.get(event)?.forEach(cb => cb(payload));
72
+ this.callbacks.get('*')?.forEach(cb => cb(payload));
69
73
  }
70
74
  }
71
75
 
76
+ export type RealtimeStatus = 'idle' | 'connecting' | 'connected' | 'reconnecting' | 'disconnected';
77
+
78
+ export interface RealtimeClientOptions {
79
+ baseUrl: string;
80
+ projectId: string;
81
+ token?: string;
82
+ userId?: string;
83
+ apiKey?: string;
84
+ maxReconnectAttempts?: number;
85
+ }
86
+
72
87
  export class RealtimeClient {
73
88
  private baseUrl: string;
74
89
  private projectId: string;
@@ -80,18 +95,57 @@ export class RealtimeClient {
80
95
  private reconnectTimer: any = null;
81
96
  private heartbeatTimer: any = null;
82
97
  private reconnectAttempts: number = 0;
98
+ private _sendQueue: any[] = [];
99
+ private _connectingPromise: Promise<void> | null = null;
100
+ private _status: RealtimeStatus = 'idle';
101
+ private _statusListeners: Set<(s: RealtimeStatus) => void> = new Set();
102
+ private _lastPong: number = 0;
103
+ private _maxReconnectAttempts: number;
104
+ private _maxRetriesListeners: Set<() => void> = new Set();
83
105
 
84
- constructor(options: { baseUrl: string; projectId: string; token?: string; userId?: string; apiKey?: string }) {
85
- this.baseUrl = options.baseUrl.replace(/^http/, 'ws') + '/realtime';
106
+ constructor(options: RealtimeClientOptions) {
107
+ const wsBase = options.baseUrl.replace(/\/v1\/?$/, '').replace(/^http/, 'ws');
108
+ this.baseUrl = `${wsBase}/api/realtime`;
86
109
  this.projectId = options.projectId || '';
87
110
  if (options.token) this.token = options.token;
88
111
  if (options.userId) this.userId = options.userId;
89
112
  if (options.apiKey) this.apiKey = options.apiKey;
113
+ this._maxReconnectAttempts = options.maxReconnectAttempts ?? Infinity;
114
+ }
115
+
116
+ get status(): RealtimeStatus { return this._status; }
117
+
118
+ onStatusChange(cb: (status: RealtimeStatus) => void): () => void {
119
+ this._statusListeners.add(cb);
120
+ return () => this._statusListeners.delete(cb);
121
+ }
122
+
123
+ onMaxRetriesExceeded(cb: () => void): () => void {
124
+ this._maxRetriesListeners.add(cb);
125
+ return () => this._maxRetriesListeners.delete(cb);
126
+ }
127
+
128
+ private _setStatus(s: RealtimeStatus) {
129
+ this._status = s;
130
+ this._statusListeners.forEach(cb => cb(s));
131
+ }
132
+
133
+ setToken(newToken: string): void {
134
+ this.token = newToken;
135
+ this._send({ type: 'auth', token: newToken });
90
136
  }
91
137
 
92
138
  connect(): Promise<void> {
93
- if (this.ws) return Promise.resolve();
139
+ if (this.ws && this.ws.readyState === WebSocket.OPEN) return Promise.resolve();
140
+ if (this._connectingPromise) return this._connectingPromise;
141
+ this._connectingPromise = this._doConnect().finally(() => {
142
+ this._connectingPromise = null;
143
+ });
144
+ return this._connectingPromise;
145
+ }
94
146
 
147
+ private _doConnect(): Promise<void> {
148
+ this._setStatus('connecting');
95
149
  return new Promise((resolve, reject) => {
96
150
  const url = new URL(this.baseUrl);
97
151
  if (this.apiKey) {
@@ -105,10 +159,14 @@ export class RealtimeClient {
105
159
  this.ws = new WebSocket(url.toString());
106
160
 
107
161
  this.ws.onopen = () => {
108
- console.log('Aerostack Realtime Connected');
162
+ this._setStatus('connected');
109
163
  this.reconnectAttempts = 0;
164
+ this._lastPong = Date.now();
110
165
  this.startHeartbeat();
111
- // Re-subscribe
166
+ this._setupOfflineDetection();
167
+ while (this._sendQueue.length > 0) {
168
+ this.ws!.send(JSON.stringify(this._sendQueue.shift()));
169
+ }
112
170
  for (const sub of this.subscriptions.values()) {
113
171
  sub.subscribe();
114
172
  }
@@ -125,7 +183,7 @@ export class RealtimeClient {
125
183
  };
126
184
 
127
185
  this.ws.onclose = () => {
128
- console.log('Aerostack Realtime Disconnected');
186
+ this._setStatus('reconnecting');
129
187
  this.stopHeartbeat();
130
188
  this.ws = null;
131
189
  this.scheduleReconnect();
@@ -133,58 +191,86 @@ export class RealtimeClient {
133
191
 
134
192
  this.ws.onerror = (err) => {
135
193
  console.error('Realtime connection error:', err);
194
+ this._setStatus('disconnected');
136
195
  reject(err);
137
196
  };
138
197
  });
139
198
  }
140
199
 
141
200
  disconnect() {
201
+ this._setStatus('disconnected');
202
+ this.stopReconnect();
203
+ this.stopHeartbeat();
204
+ this._teardownOfflineDetection();
142
205
  if (this.ws) {
143
206
  this.ws.close();
207
+ this.ws = null;
144
208
  }
145
- this.stopReconnect();
209
+ this._sendQueue = [];
146
210
  }
147
211
 
148
- channel(topic: string, options: RealtimeSubscriptionOptions = {}): RealtimeSubscription {
212
+ channel<T = any>(topic: string, options: RealtimeSubscriptionOptions = {}): RealtimeSubscription<T> {
149
213
  const fullTopic = topic.includes('/') ? topic : `table/${topic}/${this.projectId}`;
150
-
151
214
  let sub = this.subscriptions.get(fullTopic);
152
215
  if (!sub) {
153
- sub = new RealtimeSubscription(this, fullTopic, options);
216
+ sub = new RealtimeSubscription<T>(this, fullTopic, options);
154
217
  this.subscriptions.set(fullTopic, sub);
155
218
  }
156
- return sub;
219
+ return sub as RealtimeSubscription<T>;
220
+ }
221
+
222
+ sendChat(roomId: string, text: string): void {
223
+ this._send({ type: 'chat', roomId, text });
224
+ }
225
+
226
+ chatRoom(roomId: string): RealtimeSubscription {
227
+ return this.channel(`chat/${roomId}/${this.projectId}`);
157
228
  }
158
229
 
159
230
  /** @internal */
160
231
  _send(data: any) {
161
232
  if (this.ws && this.ws.readyState === WebSocket.OPEN) {
162
233
  this.ws.send(JSON.stringify(data));
234
+ } else {
235
+ this._sendQueue.push(data);
163
236
  }
164
237
  }
165
238
 
166
239
  private handleMessage(data: RealtimeMessage) {
240
+ if (data.type === 'pong') {
241
+ this._lastPong = Date.now();
242
+ return;
243
+ }
167
244
  if (data.type === 'db_change' || data.type === 'chat_message') {
168
245
  const sub = this.subscriptions.get(data.topic);
169
- if (sub) {
170
- sub._emit(data);
171
- }
246
+ if (sub) sub._emit(data as any);
172
247
  }
173
248
  }
174
249
 
175
250
  private startHeartbeat() {
176
251
  this.heartbeatTimer = setInterval(() => {
177
252
  this._send({ type: 'ping' });
253
+ if (this._lastPong > 0 && Date.now() - this._lastPong > 70000) {
254
+ console.warn('Realtime: no pong received, forcing reconnect');
255
+ this.ws?.close();
256
+ }
178
257
  }, 30000);
179
258
  }
180
259
 
181
260
  private stopHeartbeat() {
182
- if (this.heartbeatTimer) clearInterval(this.heartbeatTimer);
261
+ if (this.heartbeatTimer) {
262
+ clearInterval(this.heartbeatTimer);
263
+ this.heartbeatTimer = null;
264
+ }
183
265
  }
184
266
 
185
- /** Exponential backoff with jitter: 1s → 2s → 4s → ... → 30s */
186
267
  private scheduleReconnect() {
187
268
  this.stopReconnect();
269
+ if (this.reconnectAttempts >= this._maxReconnectAttempts) {
270
+ this._setStatus('disconnected');
271
+ this._maxRetriesListeners.forEach(cb => cb());
272
+ return;
273
+ }
188
274
  const delay = Math.min(1000 * Math.pow(2, this.reconnectAttempts), 30000);
189
275
  const jitter = delay * 0.3 * Math.random();
190
276
  this.reconnectAttempts++;
@@ -194,6 +280,35 @@ export class RealtimeClient {
194
280
  }
195
281
 
196
282
  private stopReconnect() {
197
- if (this.reconnectTimer) clearTimeout(this.reconnectTimer);
283
+ if (this.reconnectTimer) {
284
+ clearTimeout(this.reconnectTimer);
285
+ this.reconnectTimer = null;
286
+ }
287
+ }
288
+
289
+ private _handleOnline = () => {
290
+ if (this._status !== 'connected') {
291
+ this.reconnectAttempts = 0;
292
+ this.connect().catch(() => { });
293
+ }
294
+ };
295
+
296
+ private _handleOffline = () => {
297
+ this.stopReconnect();
298
+ this._setStatus('disconnected');
299
+ };
300
+
301
+ private _setupOfflineDetection() {
302
+ if (typeof window !== 'undefined') {
303
+ window.addEventListener('online', this._handleOnline);
304
+ window.addEventListener('offline', this._handleOffline);
305
+ }
306
+ }
307
+
308
+ private _teardownOfflineDetection() {
309
+ if (typeof window !== 'undefined') {
310
+ window.removeEventListener('online', this._handleOnline);
311
+ window.removeEventListener('offline', this._handleOffline);
312
+ }
198
313
  }
199
314
  }