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