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 +154 -41
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +21 -5
- package/dist/index.d.ts +21 -5
- package/dist/index.js +161 -41
- package/dist/index.js.map +1 -1
- package/package.json +3 -2
- package/scripts/setup-nestjs.cjs +3 -2
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.
|
|
342
|
-
|
|
343
|
-
|
|
344
|
-
}
|
|
345
|
-
|
|
346
|
-
|
|
347
|
-
|
|
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
|
-
|
|
470
|
-
|
|
551
|
+
* Check if connected
|
|
552
|
+
*/
|
|
471
553
|
isConnected() {
|
|
472
|
-
|
|
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.
|
|
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.
|
|
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,
|
|
727
|
+
async connectRealtime(url, accessToken) {
|
|
615
728
|
const wsUrl = url || this.config.realtime?.url;
|
|
616
|
-
const wsToken =
|
|
729
|
+
const wsToken = accessToken || this.config.realtime?.accessToken;
|
|
617
730
|
if (!wsUrl) {
|
|
618
731
|
throw new Error("WebSocket URL is required");
|
|
619
732
|
}
|