exguard-backend 1.0.29 → 1.0.31

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
@@ -283,6 +283,16 @@ var ExGuardCache = class {
283
283
  var cache = new ExGuardCache();
284
284
 
285
285
  // src/realtime.ts
286
+ var WebSocketImpl;
287
+ if (typeof window === "undefined") {
288
+ try {
289
+ WebSocketImpl = require("ws");
290
+ } catch {
291
+ WebSocketImpl = null;
292
+ }
293
+ } else {
294
+ WebSocketImpl = WebSocket;
295
+ }
286
296
  var ExGuardRealtime = class {
287
297
  handlers = /* @__PURE__ */ new Map();
288
298
  websocket = null;
@@ -291,6 +301,7 @@ var ExGuardRealtime = class {
291
301
  currentUrl = null;
292
302
  currentToken = null;
293
303
  shouldReconnect = true;
304
+ isNode = typeof window === "undefined";
294
305
  constructor(config = {}) {
295
306
  this.config = {
296
307
  autoReconnect: config.autoReconnect ?? true,
@@ -301,15 +312,33 @@ var ExGuardRealtime = class {
301
312
  }),
302
313
  onDisconnect: config.onDisconnect ?? (() => {
303
314
  }),
304
- onError: config.onError ?? ((error) => console.error("[ExGuardRealtime] Error:", error))
315
+ onError: config.onError ?? ((error) => console.error("[ExGuardRealtime] Error:", error)),
316
+ autoConnect: config.autoConnect ?? false
305
317
  };
306
318
  }
319
+ /**
320
+ * Initialize and optionally connect to realtime server
321
+ */
322
+ async init(url, accessToken) {
323
+ if (url) {
324
+ this.currentUrl = url;
325
+ this.currentToken = accessToken ?? null;
326
+ if (this.config.autoConnect) {
327
+ try {
328
+ await this.connect(url, accessToken);
329
+ } catch (error) {
330
+ console.warn("[ExGuardRealtime] Auto-connect failed, will retry on demand:", error);
331
+ }
332
+ }
333
+ }
334
+ }
307
335
  /**
308
336
  * Connect to realtime server
309
337
  * @param url - WebSocket URL (e.g., wss://api.example.com/realtime)
310
338
  * @param auth - Authentication options (accessToken, apiKey, bearerToken) - optional
339
+ * @param silent - If true, won't throw error on connection failure
311
340
  */
312
- connect(url, auth) {
341
+ connect(url, auth, silent = false) {
313
342
  let authToken;
314
343
  let authType = null;
315
344
  if (typeof auth === "string") {
@@ -329,6 +358,12 @@ var ExGuardRealtime = class {
329
358
  this.shouldReconnect = true;
330
359
  this.currentUrl = url;
331
360
  this.currentToken = authToken ?? null;
361
+ if (!WebSocketImpl) {
362
+ const err = new Error('WebSocket is not available. Install "ws" package for Node.js: npm install ws');
363
+ this.config.onError(err);
364
+ if (!silent) reject(err);
365
+ return;
366
+ }
332
367
  try {
333
368
  let wsUrl = url;
334
369
  if (authToken && authType) {
@@ -338,43 +373,90 @@ var ExGuardRealtime = class {
338
373
  wsUrl = `${url}?${authType}=${encodeURIComponent(authToken)}`;
339
374
  }
340
375
  }
341
- this.websocket = new WebSocket(wsUrl);
342
- const timeout = setTimeout(() => {
343
- reject(new Error("Connection timeout"));
344
- }, 1e4);
345
- this.websocket.onopen = () => {
346
- clearTimeout(timeout);
347
- this.reconnectAttempts = 0;
348
- console.log("[ExGuardRealtime] Connected to realtime server");
349
- this.config.onConnect();
350
- resolve();
351
- };
352
- this.websocket.onmessage = (event) => {
353
- try {
354
- const realtimeEvent = JSON.parse(event.data);
355
- this.handleEvent(realtimeEvent);
356
- } catch (error) {
357
- console.error("[ExGuardRealtime] Failed to parse event:", error);
358
- }
359
- };
360
- this.websocket.onclose = () => {
361
- clearTimeout(timeout);
362
- console.log("[ExGuardRealtime] Disconnected from realtime server");
363
- this.config.onDisconnect();
364
- this.handleReconnect();
365
- };
366
- this.websocket.onerror = (error) => {
367
- clearTimeout(timeout);
368
- console.error("[ExGuardRealtime] WebSocket error:", error);
369
- const err = new Error("WebSocket connection error");
370
- this.config.onError(err);
371
- reject(err);
372
- };
376
+ if (this.isNode && WebSocketImpl === require("ws")) {
377
+ this.websocket = new WebSocketImpl(wsUrl);
378
+ this.setupNodeWebSocket(resolve, reject);
379
+ } else {
380
+ this.websocket = new WebSocketImpl(wsUrl);
381
+ this.setupBrowserWebSocket(resolve, reject);
382
+ }
373
383
  } catch (error) {
374
384
  reject(error);
375
385
  }
376
386
  });
377
387
  }
388
+ setupBrowserWebSocket(resolve, reject) {
389
+ const timeout = setTimeout(() => {
390
+ reject(new Error("Connection timeout"));
391
+ }, 1e4);
392
+ this.websocket.onopen = () => {
393
+ clearTimeout(timeout);
394
+ this.reconnectAttempts = 0;
395
+ console.log("[ExGuardRealtime] Connected to realtime server");
396
+ this.config.onConnect();
397
+ resolve();
398
+ };
399
+ this.websocket.onmessage = (event) => {
400
+ try {
401
+ const realtimeEvent = JSON.parse(event.data);
402
+ this.handleEvent(realtimeEvent);
403
+ } catch (error) {
404
+ console.error("[ExGuardRealtime] Failed to parse event:", error);
405
+ }
406
+ };
407
+ this.websocket.onclose = () => {
408
+ clearTimeout(timeout);
409
+ console.log("[ExGuardRealtime] Disconnected from realtime server");
410
+ this.config.onDisconnect();
411
+ this.handleReconnect();
412
+ };
413
+ this.websocket.onerror = (error) => {
414
+ clearTimeout(timeout);
415
+ console.error("[ExGuardRealtime] WebSocket error:", error);
416
+ const err = new Error("WebSocket connection error");
417
+ this.config.onError(err);
418
+ if (!this.shouldReconnect) {
419
+ reject(err);
420
+ }
421
+ };
422
+ }
423
+ setupNodeWebSocket(resolve, reject) {
424
+ const timeout = setTimeout(() => {
425
+ reject(new Error("Connection timeout"));
426
+ }, 1e4);
427
+ this.websocket.on("open", () => {
428
+ clearTimeout(timeout);
429
+ this.reconnectAttempts = 0;
430
+ console.log("[ExGuardRealtime] Connected to realtime server (Node.js)");
431
+ this.config.onConnect();
432
+ resolve();
433
+ });
434
+ this.websocket.on("message", (data) => {
435
+ try {
436
+ const realtimeEvent = JSON.parse(data.toString());
437
+ this.handleEvent(realtimeEvent);
438
+ } catch (error) {
439
+ console.error("[ExGuardRealtime] Failed to parse event:", error);
440
+ }
441
+ });
442
+ this.websocket.on("close", () => {
443
+ clearTimeout(timeout);
444
+ console.log("[ExGuardRealtime] Disconnected from realtime server");
445
+ this.config.onDisconnect();
446
+ this.handleReconnect();
447
+ });
448
+ this.websocket.on("error", (error) => {
449
+ clearTimeout(timeout);
450
+ console.error("[ExGuardRealtime] WebSocket error:", error);
451
+ const err = new Error("WebSocket connection error: " + (error?.message || error));
452
+ this.config.onError(err);
453
+ if (this.shouldReconnect) {
454
+ this.handleReconnect();
455
+ } else {
456
+ reject(err);
457
+ }
458
+ });
459
+ }
378
460
  /**
379
461
  * Disconnect from realtime server
380
462
  */
@@ -466,16 +548,33 @@ var ExGuardRealtime = class {
466
548
  return Promise.reject(new Error("No URL configured"));
467
549
  }
468
550
  /**
469
- * Check if connected
470
- */
551
+ * Check if connected
552
+ */
471
553
  isConnected() {
472
- return this.websocket?.readyState === WebSocket.OPEN;
554
+ if (!this.websocket) return false;
555
+ if (this.isNode) {
556
+ return this.websocket.readyState === 1;
557
+ }
558
+ return this.websocket.readyState === WebSocket.OPEN;
473
559
  }
474
560
  /**
475
561
  * Get connection status
476
562
  */
477
563
  getStatus() {
478
564
  if (!this.websocket) return "disconnected";
565
+ if (this.isNode) {
566
+ switch (this.websocket.readyState) {
567
+ case 0:
568
+ return "connecting";
569
+ case 1:
570
+ return "connected";
571
+ case 2:
572
+ case 3:
573
+ return "disconnected";
574
+ default:
575
+ return "disconnected";
576
+ }
577
+ }
479
578
  switch (this.websocket.readyState) {
480
579
  case WebSocket.CONNECTING:
481
580
  return "connecting";
@@ -505,6 +604,17 @@ var ExGuardRealtime = class {
505
604
  ...config
506
605
  };
507
606
  }
607
+ /**
608
+ * Connect on-demand with user's access token from request
609
+ * Call this in your guard or middleware with the user's token
610
+ */
611
+ async connectWithUserToken(url, accessToken) {
612
+ try {
613
+ await this.connect(url, accessToken, true);
614
+ } catch (error) {
615
+ console.warn("[ExGuardRealtime] Failed to connect with user token:", error);
616
+ }
617
+ }
508
618
  };
509
619
  function createRealtime(config) {
510
620
  return new ExGuardRealtime(config);
@@ -567,10 +677,13 @@ var ExGuardBackendEnhanced = class {
567
677
  }, 6e4);
568
678
  }
569
679
  async setupRealtime() {
680
+ if (!this.config.realtime?.url) {
681
+ return;
682
+ }
570
683
  try {
571
684
  await this.realtime.connect(
572
685
  this.config.realtime.url,
573
- this.config.realtime.token
686
+ this.config.realtime.accessToken
574
687
  );
575
688
  this.realtime.subscribe("rbac_update", (event) => {
576
689
  console.log("[ExGuardBackend] RBAC update received:", event);
@@ -605,15 +718,15 @@ var ExGuardBackendEnhanced = class {
605
718
  }
606
719
  });
607
720
  } catch (error) {
608
- console.error("[ExGuardBackend] Failed to setup realtime:", error);
721
+ console.warn("[ExGuardBackend] Realtime connection failed (will retry on demand):", error);
609
722
  }
610
723
  }
611
724
  /**
612
725
  * Manually connect to realtime server
613
726
  */
614
- async connectRealtime(url, token) {
727
+ async connectRealtime(url, accessToken) {
615
728
  const wsUrl = url || this.config.realtime?.url;
616
- const wsToken = token || this.config.realtime?.token;
729
+ const wsToken = accessToken || this.config.realtime?.accessToken;
617
730
  if (!wsUrl) {
618
731
  throw new Error("WebSocket URL is required");
619
732
  }