@fluxbase/sdk 0.0.2-rc.2 → 0.1.0-rc.1

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/index.js CHANGED
@@ -120,6 +120,7 @@ var FluxbaseAuth = class {
120
120
  constructor(fetch2, autoRefresh = true, persist = true) {
121
121
  this.session = null;
122
122
  this.refreshTimer = null;
123
+ this.stateChangeListeners = /* @__PURE__ */ new Set();
123
124
  this.fetch = fetch2;
124
125
  this.persist = persist;
125
126
  this.autoRefresh = autoRefresh;
@@ -156,6 +157,29 @@ var FluxbaseAuth = class {
156
157
  getAccessToken() {
157
158
  return this.session?.access_token ?? null;
158
159
  }
160
+ /**
161
+ * Listen to auth state changes
162
+ * @param callback - Function called when auth state changes
163
+ * @returns Subscription object with unsubscribe method
164
+ *
165
+ * @example
166
+ * ```typescript
167
+ * const { data: { subscription } } = client.auth.onAuthStateChange((event, session) => {
168
+ * console.log('Auth event:', event, session)
169
+ * })
170
+ *
171
+ * // Later, to unsubscribe:
172
+ * subscription.unsubscribe()
173
+ * ```
174
+ */
175
+ onAuthStateChange(callback) {
176
+ this.stateChangeListeners.add(callback);
177
+ return {
178
+ unsubscribe: () => {
179
+ this.stateChangeListeners.delete(callback);
180
+ }
181
+ };
182
+ }
159
183
  /**
160
184
  * Sign in with email and password
161
185
  * Returns AuthSession if successful, or SignInWith2FAResponse if 2FA is required
@@ -212,7 +236,7 @@ var FluxbaseAuth = class {
212
236
  ...response,
213
237
  expires_at: Date.now() + response.expires_in * 1e3
214
238
  };
215
- this.setSession(session);
239
+ this.setSession(session, "TOKEN_REFRESHED");
216
240
  return session;
217
241
  }
218
242
  /**
@@ -235,6 +259,7 @@ var FluxbaseAuth = class {
235
259
  if (this.session) {
236
260
  this.session.user = user;
237
261
  this.saveSession();
262
+ this.emitAuthChange("USER_UPDATED", this.session);
238
263
  }
239
264
  return user;
240
265
  }
@@ -296,7 +321,7 @@ var FluxbaseAuth = class {
296
321
  ...response,
297
322
  expires_at: Date.now() + response.expires_in * 1e3
298
323
  };
299
- this.setSession(session);
324
+ this.setSession(session, "MFA_CHALLENGE_VERIFIED");
300
325
  return session;
301
326
  }
302
327
  /**
@@ -423,11 +448,12 @@ var FluxbaseAuth = class {
423
448
  /**
424
449
  * Internal: Set the session and persist it
425
450
  */
426
- setSession(session) {
451
+ setSession(session, event = "SIGNED_IN") {
427
452
  this.session = session;
428
453
  this.fetch.setAuthToken(session.access_token);
429
454
  this.saveSession();
430
455
  this.scheduleTokenRefresh();
456
+ this.emitAuthChange(event, session);
431
457
  }
432
458
  /**
433
459
  * Internal: Clear the session
@@ -442,6 +468,7 @@ var FluxbaseAuth = class {
442
468
  clearTimeout(this.refreshTimer);
443
469
  this.refreshTimer = null;
444
470
  }
471
+ this.emitAuthChange("SIGNED_OUT", null);
445
472
  }
446
473
  /**
447
474
  * Internal: Save session to storage
@@ -472,6 +499,18 @@ var FluxbaseAuth = class {
472
499
  }, delay);
473
500
  }
474
501
  }
502
+ /**
503
+ * Internal: Emit auth state change event to all listeners
504
+ */
505
+ emitAuthChange(event, session) {
506
+ this.stateChangeListeners.forEach((callback) => {
507
+ try {
508
+ callback(event, session);
509
+ } catch (error) {
510
+ console.error("Error in auth state change listener:", error);
511
+ }
512
+ });
513
+ }
475
514
  };
476
515
 
477
516
  // src/realtime.ts
@@ -479,6 +518,7 @@ var RealtimeChannel = class {
479
518
  constructor(url, channelName, token = null) {
480
519
  this.ws = null;
481
520
  this.callbacks = /* @__PURE__ */ new Map();
521
+ this.subscriptionConfig = null;
482
522
  this.reconnectAttempts = 0;
483
523
  this.maxReconnectAttempts = 10;
484
524
  this.reconnectDelay = 1e3;
@@ -487,16 +527,25 @@ var RealtimeChannel = class {
487
527
  this.channelName = channelName;
488
528
  this.token = token;
489
529
  }
490
- /**
491
- * Listen to a specific event type
492
- * @param event - The event type (INSERT, UPDATE, DELETE, or '*' for all)
493
- * @param callback - The callback function
494
- */
495
- on(event, callback) {
496
- if (!this.callbacks.has(event)) {
497
- this.callbacks.set(event, /* @__PURE__ */ new Set());
530
+ // Implementation
531
+ on(event, configOrCallback, callback) {
532
+ if (event === "postgres_changes" && typeof configOrCallback !== "function") {
533
+ const config = configOrCallback;
534
+ this.subscriptionConfig = config;
535
+ const actualCallback = callback;
536
+ const eventType = config.event;
537
+ if (!this.callbacks.has(eventType)) {
538
+ this.callbacks.set(eventType, /* @__PURE__ */ new Set());
539
+ }
540
+ this.callbacks.get(eventType).add(actualCallback);
541
+ } else {
542
+ const actualEvent = event;
543
+ const actualCallback = configOrCallback;
544
+ if (!this.callbacks.has(actualEvent)) {
545
+ this.callbacks.set(actualEvent, /* @__PURE__ */ new Set());
546
+ }
547
+ this.callbacks.get(actualEvent).add(actualCallback);
498
548
  }
499
- this.callbacks.get(event).add(callback);
500
549
  return this;
501
550
  }
502
551
  /**
@@ -545,10 +594,14 @@ var RealtimeChannel = class {
545
594
  this.ws.onopen = () => {
546
595
  console.log("[Fluxbase Realtime] Connected");
547
596
  this.reconnectAttempts = 0;
548
- this.send({
597
+ const subscribeMessage = {
549
598
  type: "subscribe",
550
599
  channel: this.channelName
551
- });
600
+ };
601
+ if (this.subscriptionConfig) {
602
+ subscribeMessage.config = this.subscriptionConfig;
603
+ }
604
+ this.send(subscribeMessage);
552
605
  this.startHeartbeat();
553
606
  };
554
607
  this.ws.onmessage = (event) => {
@@ -2223,7 +2276,9 @@ var FluxbaseAdmin = class {
2223
2276
  * ```
2224
2277
  */
2225
2278
  async getSetupStatus() {
2226
- return await this.fetch.get("/api/v1/admin/setup/status");
2279
+ return await this.fetch.get(
2280
+ "/api/v1/admin/setup/status"
2281
+ );
2227
2282
  }
2228
2283
  /**
2229
2284
  * Perform initial admin setup
@@ -2249,7 +2304,10 @@ var FluxbaseAdmin = class {
2249
2304
  * ```
2250
2305
  */
2251
2306
  async setup(request) {
2252
- const response = await this.fetch.post("/api/v1/admin/setup", request);
2307
+ const response = await this.fetch.post(
2308
+ "/api/v1/admin/setup",
2309
+ request
2310
+ );
2253
2311
  this.setToken(response.access_token);
2254
2312
  return response;
2255
2313
  }
@@ -2274,7 +2332,10 @@ var FluxbaseAdmin = class {
2274
2332
  * ```
2275
2333
  */
2276
2334
  async login(request) {
2277
- const response = await this.fetch.post("/api/v1/admin/login", request);
2335
+ const response = await this.fetch.post(
2336
+ "/api/v1/admin/login",
2337
+ request
2338
+ );
2278
2339
  this.setToken(response.access_token);
2279
2340
  return response;
2280
2341
  }
@@ -2295,7 +2356,10 @@ var FluxbaseAdmin = class {
2295
2356
  * ```
2296
2357
  */
2297
2358
  async refreshToken(request) {
2298
- const response = await this.fetch.post("/api/v1/admin/refresh", request);
2359
+ const response = await this.fetch.post(
2360
+ "/api/v1/admin/refresh",
2361
+ request
2362
+ );
2299
2363
  this.setToken(response.access_token);
2300
2364
  return response;
2301
2365
  }
@@ -2370,6 +2434,30 @@ var FluxbaseAdmin = class {
2370
2434
  const url = queryString ? `/api/v1/admin/users?${queryString}` : "/api/v1/admin/users";
2371
2435
  return await this.fetch.get(url);
2372
2436
  }
2437
+ /**
2438
+ * Get a user by ID
2439
+ *
2440
+ * Fetch a single user's details by their user ID
2441
+ *
2442
+ * @param userId - User ID to fetch
2443
+ * @param type - User type ('app' or 'dashboard')
2444
+ * @returns User details with metadata
2445
+ *
2446
+ * @example
2447
+ * ```typescript
2448
+ * // Get an app user
2449
+ * const user = await admin.getUserById('user-123');
2450
+ *
2451
+ * // Get a dashboard user
2452
+ * const dashboardUser = await admin.getUserById('admin-456', 'dashboard');
2453
+ * console.log('User email:', dashboardUser.email);
2454
+ * console.log('Last login:', dashboardUser.last_login_at);
2455
+ * ```
2456
+ */
2457
+ async getUserById(userId, type = "app") {
2458
+ const url = `/api/v1/admin/users/${userId}?type=${type}`;
2459
+ return await this.fetch.get(url);
2460
+ }
2373
2461
  /**
2374
2462
  * Invite a new user
2375
2463
  *
@@ -2942,6 +3030,22 @@ var QueryBuilder = class {
2942
3030
  };
2943
3031
  }
2944
3032
  }
3033
+ /**
3034
+ * Make QueryBuilder awaitable (implements PromiseLike)
3035
+ * This allows using `await client.from('table').select()` without calling `.execute()`
3036
+ *
3037
+ * @example
3038
+ * ```typescript
3039
+ * // Without .execute() (new way)
3040
+ * const { data } = await client.from('users').select('*')
3041
+ *
3042
+ * // With .execute() (old way, still supported)
3043
+ * const { data } = await client.from('users').select('*').execute()
3044
+ * ```
3045
+ */
3046
+ then(onfulfilled, onrejected) {
3047
+ return this.execute().then(onfulfilled, onrejected);
3048
+ }
2945
3049
  /**
2946
3050
  * Build the query string from filters, ordering, etc.
2947
3051
  */