@omnibase/core-js 0.6.0 → 0.7.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.
@@ -102,4 +102,197 @@ import { PostgrestClient } from '@supabase/postgrest-js';
102
102
  */
103
103
  declare const createClient: <T = any>(url: string, anonKey: string, getCookie: (cookie: string) => string) => PostgrestClient<T>;
104
104
 
105
- export { createClient };
105
+ /**
106
+ * Real-time database events client for WebSocket subscriptions
107
+ *
108
+ * This module provides a universal WebSocket client for subscribing to real-time
109
+ * database changes with Row-Level Security (RLS) authentication. Works in both
110
+ * browser and Node.js environments.
111
+ *
112
+ * @module Database Events
113
+ */
114
+ /**
115
+ * Subscription options for database events
116
+ */
117
+ interface SubscriptionOptions {
118
+ /** Specific row ID to subscribe to (optional) */
119
+ rowId?: number;
120
+ /** Specific columns to filter updates (optional) */
121
+ columns?: string[];
122
+ /** Callback function triggered on data updates */
123
+ onChange?: (data: any, message: UpdateMessage) => void;
124
+ }
125
+ /**
126
+ * Subscription request sent to the server
127
+ */
128
+ interface Subscription {
129
+ table: string;
130
+ row_id?: number;
131
+ columns?: string[];
132
+ jwt: string;
133
+ }
134
+ /**
135
+ * Message sent from client to server
136
+ */
137
+ interface SubscriptionMessage {
138
+ action: "subscribe" | "unsubscribe";
139
+ subscription: Subscription;
140
+ }
141
+ /**
142
+ * Update message received from server
143
+ */
144
+ interface UpdateMessage {
145
+ type: "update";
146
+ table: string;
147
+ row_id: number;
148
+ data: any;
149
+ }
150
+ /**
151
+ * Status message received from server
152
+ */
153
+ interface StatusMessage {
154
+ status: "subscribed" | "unsubscribed" | "error";
155
+ table?: string;
156
+ row_id?: number;
157
+ error?: string;
158
+ }
159
+ /**
160
+ * Universal WebSocket client for real-time database events
161
+ *
162
+ * Connects to the database events WebSocket endpoint and manages subscriptions
163
+ * to table changes with automatic RLS authentication and reconnection.
164
+ *
165
+ * @example
166
+ * Basic usage:
167
+ * ```typescript
168
+ * const client = new EventsClient(
169
+ * 'ws://localhost:8080/api/v1/events/ws',
170
+ * 'your-jwt-token'
171
+ * );
172
+ *
173
+ * client.subscribe('tasks', {
174
+ * onChange: (data) => {
175
+ * console.log('Task updated:', data);
176
+ * }
177
+ * });
178
+ * ```
179
+ *
180
+ * @example
181
+ * Subscribe to specific row:
182
+ * ```typescript
183
+ * client.subscribe('users', {
184
+ * rowId: 123,
185
+ * onChange: (user) => {
186
+ * console.log('User 123 updated:', user);
187
+ * }
188
+ * });
189
+ * ```
190
+ *
191
+ * @example
192
+ * Subscribe to specific columns:
193
+ * ```typescript
194
+ * client.subscribe('posts', {
195
+ * rowId: 456,
196
+ * columns: ['title', 'content', 'status'],
197
+ * onChange: (post) => {
198
+ * console.log('Post columns updated:', post);
199
+ * }
200
+ * });
201
+ * ```
202
+ */
203
+ declare class EventsClient {
204
+ private url;
205
+ private jwt;
206
+ private subscriptions;
207
+ private ws;
208
+ private reconnectDelay;
209
+ private listeners;
210
+ private shouldReconnect;
211
+ /**
212
+ * Creates a new EventsClient instance
213
+ *
214
+ * @param url - WebSocket endpoint URL (e.g., 'ws://localhost:8080/api/v1/events/ws')
215
+ * @param jwt - JWT authentication token for RLS checks
216
+ */
217
+ constructor(url: string, jwt: string);
218
+ /**
219
+ * Establishes WebSocket connection with automatic reconnection
220
+ * @private
221
+ */
222
+ private connect;
223
+ /**
224
+ * Subscribe to database changes for a table
225
+ *
226
+ * @param table - Table name to subscribe to
227
+ * @param options - Subscription options (rowId, columns, onChange callback)
228
+ *
229
+ * @example
230
+ * Subscribe to entire table:
231
+ * ```typescript
232
+ * client.subscribe('tasks', {
233
+ * onChange: (task) => console.log('Task changed:', task)
234
+ * });
235
+ * ```
236
+ *
237
+ * @example
238
+ * Subscribe to specific row:
239
+ * ```typescript
240
+ * client.subscribe('users', {
241
+ * rowId: 123,
242
+ * onChange: (user) => console.log('User 123 changed:', user)
243
+ * });
244
+ * ```
245
+ */
246
+ subscribe(table: string, options?: SubscriptionOptions): void;
247
+ /**
248
+ * Unsubscribe from database changes
249
+ *
250
+ * @param table - Table name to unsubscribe from
251
+ * @param rowId - Optional row ID (if subscribing to specific row)
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * client.unsubscribe('tasks');
256
+ * client.unsubscribe('users', 123);
257
+ * ```
258
+ */
259
+ unsubscribe(table: string, rowId?: number): void;
260
+ /**
261
+ * Send message to WebSocket server
262
+ * @private
263
+ */
264
+ private send;
265
+ /**
266
+ * Handle incoming WebSocket messages
267
+ * @private
268
+ */
269
+ private handleMessage;
270
+ /**
271
+ * Update JWT token for authentication
272
+ *
273
+ * @param jwt - New JWT token
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * client.updateJWT(newToken);
278
+ * ```
279
+ */
280
+ updateJWT(jwt: string): void;
281
+ /**
282
+ * Close WebSocket connection and prevent reconnection
283
+ *
284
+ * @example
285
+ * ```typescript
286
+ * client.close();
287
+ * ```
288
+ */
289
+ close(): void;
290
+ /**
291
+ * Check if WebSocket is currently connected
292
+ *
293
+ * @returns true if connected, false otherwise
294
+ */
295
+ isConnected(): boolean;
296
+ }
297
+
298
+ export { EventsClient, type StatusMessage, type Subscription, type SubscriptionMessage, type SubscriptionOptions, type UpdateMessage, createClient };
@@ -102,4 +102,197 @@ import { PostgrestClient } from '@supabase/postgrest-js';
102
102
  */
103
103
  declare const createClient: <T = any>(url: string, anonKey: string, getCookie: (cookie: string) => string) => PostgrestClient<T>;
104
104
 
105
- export { createClient };
105
+ /**
106
+ * Real-time database events client for WebSocket subscriptions
107
+ *
108
+ * This module provides a universal WebSocket client for subscribing to real-time
109
+ * database changes with Row-Level Security (RLS) authentication. Works in both
110
+ * browser and Node.js environments.
111
+ *
112
+ * @module Database Events
113
+ */
114
+ /**
115
+ * Subscription options for database events
116
+ */
117
+ interface SubscriptionOptions {
118
+ /** Specific row ID to subscribe to (optional) */
119
+ rowId?: number;
120
+ /** Specific columns to filter updates (optional) */
121
+ columns?: string[];
122
+ /** Callback function triggered on data updates */
123
+ onChange?: (data: any, message: UpdateMessage) => void;
124
+ }
125
+ /**
126
+ * Subscription request sent to the server
127
+ */
128
+ interface Subscription {
129
+ table: string;
130
+ row_id?: number;
131
+ columns?: string[];
132
+ jwt: string;
133
+ }
134
+ /**
135
+ * Message sent from client to server
136
+ */
137
+ interface SubscriptionMessage {
138
+ action: "subscribe" | "unsubscribe";
139
+ subscription: Subscription;
140
+ }
141
+ /**
142
+ * Update message received from server
143
+ */
144
+ interface UpdateMessage {
145
+ type: "update";
146
+ table: string;
147
+ row_id: number;
148
+ data: any;
149
+ }
150
+ /**
151
+ * Status message received from server
152
+ */
153
+ interface StatusMessage {
154
+ status: "subscribed" | "unsubscribed" | "error";
155
+ table?: string;
156
+ row_id?: number;
157
+ error?: string;
158
+ }
159
+ /**
160
+ * Universal WebSocket client for real-time database events
161
+ *
162
+ * Connects to the database events WebSocket endpoint and manages subscriptions
163
+ * to table changes with automatic RLS authentication and reconnection.
164
+ *
165
+ * @example
166
+ * Basic usage:
167
+ * ```typescript
168
+ * const client = new EventsClient(
169
+ * 'ws://localhost:8080/api/v1/events/ws',
170
+ * 'your-jwt-token'
171
+ * );
172
+ *
173
+ * client.subscribe('tasks', {
174
+ * onChange: (data) => {
175
+ * console.log('Task updated:', data);
176
+ * }
177
+ * });
178
+ * ```
179
+ *
180
+ * @example
181
+ * Subscribe to specific row:
182
+ * ```typescript
183
+ * client.subscribe('users', {
184
+ * rowId: 123,
185
+ * onChange: (user) => {
186
+ * console.log('User 123 updated:', user);
187
+ * }
188
+ * });
189
+ * ```
190
+ *
191
+ * @example
192
+ * Subscribe to specific columns:
193
+ * ```typescript
194
+ * client.subscribe('posts', {
195
+ * rowId: 456,
196
+ * columns: ['title', 'content', 'status'],
197
+ * onChange: (post) => {
198
+ * console.log('Post columns updated:', post);
199
+ * }
200
+ * });
201
+ * ```
202
+ */
203
+ declare class EventsClient {
204
+ private url;
205
+ private jwt;
206
+ private subscriptions;
207
+ private ws;
208
+ private reconnectDelay;
209
+ private listeners;
210
+ private shouldReconnect;
211
+ /**
212
+ * Creates a new EventsClient instance
213
+ *
214
+ * @param url - WebSocket endpoint URL (e.g., 'ws://localhost:8080/api/v1/events/ws')
215
+ * @param jwt - JWT authentication token for RLS checks
216
+ */
217
+ constructor(url: string, jwt: string);
218
+ /**
219
+ * Establishes WebSocket connection with automatic reconnection
220
+ * @private
221
+ */
222
+ private connect;
223
+ /**
224
+ * Subscribe to database changes for a table
225
+ *
226
+ * @param table - Table name to subscribe to
227
+ * @param options - Subscription options (rowId, columns, onChange callback)
228
+ *
229
+ * @example
230
+ * Subscribe to entire table:
231
+ * ```typescript
232
+ * client.subscribe('tasks', {
233
+ * onChange: (task) => console.log('Task changed:', task)
234
+ * });
235
+ * ```
236
+ *
237
+ * @example
238
+ * Subscribe to specific row:
239
+ * ```typescript
240
+ * client.subscribe('users', {
241
+ * rowId: 123,
242
+ * onChange: (user) => console.log('User 123 changed:', user)
243
+ * });
244
+ * ```
245
+ */
246
+ subscribe(table: string, options?: SubscriptionOptions): void;
247
+ /**
248
+ * Unsubscribe from database changes
249
+ *
250
+ * @param table - Table name to unsubscribe from
251
+ * @param rowId - Optional row ID (if subscribing to specific row)
252
+ *
253
+ * @example
254
+ * ```typescript
255
+ * client.unsubscribe('tasks');
256
+ * client.unsubscribe('users', 123);
257
+ * ```
258
+ */
259
+ unsubscribe(table: string, rowId?: number): void;
260
+ /**
261
+ * Send message to WebSocket server
262
+ * @private
263
+ */
264
+ private send;
265
+ /**
266
+ * Handle incoming WebSocket messages
267
+ * @private
268
+ */
269
+ private handleMessage;
270
+ /**
271
+ * Update JWT token for authentication
272
+ *
273
+ * @param jwt - New JWT token
274
+ *
275
+ * @example
276
+ * ```typescript
277
+ * client.updateJWT(newToken);
278
+ * ```
279
+ */
280
+ updateJWT(jwt: string): void;
281
+ /**
282
+ * Close WebSocket connection and prevent reconnection
283
+ *
284
+ * @example
285
+ * ```typescript
286
+ * client.close();
287
+ * ```
288
+ */
289
+ close(): void;
290
+ /**
291
+ * Check if WebSocket is currently connected
292
+ *
293
+ * @returns true if connected, false otherwise
294
+ */
295
+ isConnected(): boolean;
296
+ }
297
+
298
+ export { EventsClient, type StatusMessage, type Subscription, type SubscriptionMessage, type SubscriptionOptions, type UpdateMessage, createClient };
@@ -8,6 +8,219 @@ var createClient = (url, anonKey, getCookie) => {
8
8
  }
9
9
  });
10
10
  };
11
+
12
+ // src/database/events.ts
13
+ var WS = typeof globalThis !== "undefined" && globalThis.WebSocket ? globalThis.WebSocket : null;
14
+ var EventsClient = class {
15
+ url;
16
+ jwt;
17
+ subscriptions = [];
18
+ ws = null;
19
+ reconnectDelay = 1e3;
20
+ listeners = /* @__PURE__ */ new Map();
21
+ shouldReconnect = true;
22
+ /**
23
+ * Creates a new EventsClient instance
24
+ *
25
+ * @param url - WebSocket endpoint URL (e.g., 'ws://localhost:8080/api/v1/events/ws')
26
+ * @param jwt - JWT authentication token for RLS checks
27
+ */
28
+ constructor(url, jwt) {
29
+ if (!WS) {
30
+ throw new Error(
31
+ 'WebSocket is not available in this environment. Install "ws" package for Node.js.'
32
+ );
33
+ }
34
+ this.url = url;
35
+ this.jwt = jwt;
36
+ this.connect();
37
+ }
38
+ /**
39
+ * Establishes WebSocket connection with automatic reconnection
40
+ * @private
41
+ */
42
+ connect() {
43
+ if (!WS) return;
44
+ this.ws = new WS(this.url);
45
+ this.ws.onopen = () => {
46
+ console.log("\u2705 Connected to database events");
47
+ this.reconnectDelay = 1e3;
48
+ this.subscriptions.forEach((sub) => this.send(sub));
49
+ };
50
+ this.ws.onmessage = (event) => {
51
+ const data = typeof event.data === "string" ? event.data : event.data.toString();
52
+ const msg = JSON.parse(data);
53
+ this.handleMessage(msg);
54
+ };
55
+ this.ws.onerror = (error) => {
56
+ console.error("\u274C WebSocket error:", error);
57
+ };
58
+ this.ws.onclose = () => {
59
+ if (this.shouldReconnect) {
60
+ console.log(
61
+ `\u26A0\uFE0F Disconnected, reconnecting in ${this.reconnectDelay}ms`
62
+ );
63
+ setTimeout(() => this.connect(), this.reconnectDelay);
64
+ this.reconnectDelay = Math.min(this.reconnectDelay * 2, 3e4);
65
+ } else {
66
+ console.log("Disconnected from database events");
67
+ }
68
+ };
69
+ }
70
+ /**
71
+ * Subscribe to database changes for a table
72
+ *
73
+ * @param table - Table name to subscribe to
74
+ * @param options - Subscription options (rowId, columns, onChange callback)
75
+ *
76
+ * @example
77
+ * Subscribe to entire table:
78
+ * ```typescript
79
+ * client.subscribe('tasks', {
80
+ * onChange: (task) => console.log('Task changed:', task)
81
+ * });
82
+ * ```
83
+ *
84
+ * @example
85
+ * Subscribe to specific row:
86
+ * ```typescript
87
+ * client.subscribe('users', {
88
+ * rowId: 123,
89
+ * onChange: (user) => console.log('User 123 changed:', user)
90
+ * });
91
+ * ```
92
+ */
93
+ subscribe(table, options = {}) {
94
+ const { rowId, columns, onChange } = options;
95
+ const sub = {
96
+ action: "subscribe",
97
+ subscription: {
98
+ table,
99
+ ...rowId !== void 0 && { row_id: rowId },
100
+ ...columns && { columns },
101
+ jwt: this.jwt
102
+ }
103
+ };
104
+ this.subscriptions.push(sub);
105
+ if (onChange) {
106
+ const key = `${table}:${rowId ?? "*"}`;
107
+ this.listeners.set(key, onChange);
108
+ }
109
+ this.send(sub);
110
+ }
111
+ /**
112
+ * Unsubscribe from database changes
113
+ *
114
+ * @param table - Table name to unsubscribe from
115
+ * @param rowId - Optional row ID (if subscribing to specific row)
116
+ *
117
+ * @example
118
+ * ```typescript
119
+ * client.unsubscribe('tasks');
120
+ * client.unsubscribe('users', 123);
121
+ * ```
122
+ */
123
+ unsubscribe(table, rowId) {
124
+ const sub = {
125
+ action: "unsubscribe",
126
+ subscription: {
127
+ table,
128
+ ...rowId !== void 0 && { row_id: rowId },
129
+ jwt: this.jwt
130
+ }
131
+ };
132
+ this.subscriptions = this.subscriptions.filter(
133
+ (s) => !(s.subscription.table === table && s.subscription.row_id === rowId)
134
+ );
135
+ const key = `${table}:${rowId ?? "*"}`;
136
+ this.listeners.delete(key);
137
+ this.send(sub);
138
+ }
139
+ /**
140
+ * Send message to WebSocket server
141
+ * @private
142
+ */
143
+ send(data) {
144
+ if (!WS) return;
145
+ if (this.ws?.readyState === WS.OPEN || this.ws?.readyState === 1) {
146
+ this.ws.send(JSON.stringify(data));
147
+ }
148
+ }
149
+ /**
150
+ * Handle incoming WebSocket messages
151
+ * @private
152
+ */
153
+ handleMessage(msg) {
154
+ if ("type" in msg && msg.type === "update") {
155
+ const key = `${msg.table}:${msg.row_id}`;
156
+ const wildcardKey = `${msg.table}:*`;
157
+ const listener = this.listeners.get(key) || this.listeners.get(wildcardKey);
158
+ if (listener) {
159
+ listener(msg.data, msg);
160
+ }
161
+ } else if ("status" in msg) {
162
+ if (msg.status === "subscribed") {
163
+ console.log(
164
+ "\u2705 Subscribed to",
165
+ msg.table,
166
+ msg.row_id ? `(row ${msg.row_id})` : "(all rows)"
167
+ );
168
+ } else if (msg.status === "unsubscribed") {
169
+ console.log(
170
+ "Unsubscribed from",
171
+ msg.table,
172
+ msg.row_id ? `(row ${msg.row_id})` : "(all rows)"
173
+ );
174
+ } else if (msg.status === "error") {
175
+ console.error(
176
+ "\u274C Subscription error:",
177
+ msg.error,
178
+ "for table:",
179
+ msg.table
180
+ );
181
+ }
182
+ }
183
+ }
184
+ /**
185
+ * Update JWT token for authentication
186
+ *
187
+ * @param jwt - New JWT token
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * client.updateJWT(newToken);
192
+ * ```
193
+ */
194
+ updateJWT(jwt) {
195
+ this.jwt = jwt;
196
+ this.subscriptions = this.subscriptions.map((sub) => ({
197
+ ...sub,
198
+ subscription: { ...sub.subscription, jwt }
199
+ }));
200
+ }
201
+ /**
202
+ * Close WebSocket connection and prevent reconnection
203
+ *
204
+ * @example
205
+ * ```typescript
206
+ * client.close();
207
+ * ```
208
+ */
209
+ close() {
210
+ this.shouldReconnect = false;
211
+ this.ws?.close();
212
+ }
213
+ /**
214
+ * Check if WebSocket is currently connected
215
+ *
216
+ * @returns true if connected, false otherwise
217
+ */
218
+ isConnected() {
219
+ if (!WS) return false;
220
+ return this.ws?.readyState === WS.OPEN || this.ws?.readyState === 1;
221
+ }
222
+ };
11
223
  export {
224
+ EventsClient,
12
225
  createClient
13
226
  };