@mblaney/holster 1.0.14 → 1.0.16

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@mblaney/holster",
3
- "version": "1.0.14",
3
+ "version": "1.0.16",
4
4
  "description": "Holster is a service that allows synchronising data between devices using Node, Deno, Bun or the browser.",
5
5
  "type": "module",
6
6
  "main": "index.js",
package/src/radisk.js CHANGED
@@ -67,6 +67,8 @@ const Radisk = opt => {
67
67
 
68
68
  // Memory monitoring and cache cleanup
69
69
  const checkMemoryUsage = () => {
70
+ if (typeof process === "undefined" || !process.memoryUsage) return
71
+
70
72
  const now = Date.now()
71
73
  if (now - lastMemoryCheck < MEMORY_CHECK_INTERVAL) return
72
74
  lastMemoryCheck = now
package/src/wire.js CHANGED
@@ -13,13 +13,11 @@ if (typeof globalThis.WebSocket === "undefined") {
13
13
  }
14
14
 
15
15
  // Rate limiting with throttling
16
- const createRateLimiter = opt => {
16
+ const createRateLimiter = isTestEnv => {
17
17
  const clients = new Map()
18
- const maxRequests = opt.maxRequestsPerMinute || 100
19
- const windowMs = opt.rateLimitWindow || 60000
20
- const disconnectThreshold = opt.disconnectThreshold || 10
21
- // Check if test environment (mock-socket usage)
22
- const isTestEnv = opt.wss && opt.wss.constructor.name === "Server"
18
+ const maxRequests = 300 // 5 requests per second
19
+ const windowMs = 60000 // 1 minute window
20
+ const disconnectThreshold = 10 // Disconnect after 10 violations
23
21
  let cleanupInterval = null
24
22
 
25
23
  const cleanup = () => {
@@ -191,7 +189,9 @@ const Wire = opt => {
191
189
  }
192
190
 
193
191
  // Initialize rate limiting and connection management
194
- const rateLimiter = createRateLimiter(opt)
192
+ // Check if test environment (mock-socket usage)
193
+ const isTestEnv = opt.wss && opt.wss.constructor.name === "Server"
194
+ const rateLimiter = createRateLimiter(isTestEnv)
195
195
  const connectionManager = createConnectionManager(opt.maxConnections || 1000)
196
196
 
197
197
  // The check function is required because user data must provide a public key
@@ -463,9 +463,7 @@ const Wire = opt => {
463
463
 
464
464
  // Generate unique client ID for rate limiting
465
465
  const clientId = utils.text.random(9)
466
- console.log(
467
- `[HOLSTER-CONNECT] New WebSocket client connected: ${clientId}`,
468
- )
466
+ console.log(`New WebSocket client connected: ${clientId}`)
469
467
 
470
468
  ws.on("error", error => {
471
469
  console.log("WebSocket error:", error)
@@ -473,9 +471,7 @@ const Wire = opt => {
473
471
  })
474
472
 
475
473
  ws.on("close", () => {
476
- console.log(
477
- `[HOLSTER-DISCONNECT] WebSocket client disconnected: ${clientId}`,
478
- )
474
+ console.log(`WebSocket client disconnected: ${clientId}`)
479
475
  connectionManager.remove(ws)
480
476
  })
481
477
 
@@ -505,14 +501,14 @@ const Wire = opt => {
505
501
  if (delay > 0) {
506
502
  const throttleCount = rateLimiter.getThrottleCount(clientId)
507
503
  console.log(
508
- `[HOLSTER-THROTTLE] Client ${clientId}: rate limit exceeded, delay would be ${delay}ms, dropping message (throttle count: ${throttleCount})`,
504
+ `Client ${clientId}: rate limit exceeded, delay would be ${delay}ms, dropping message (throttle count: ${throttleCount})`,
509
505
  )
510
506
  // Check if we should disconnect the bad actor
511
507
  if (rateLimiter.shouldDisconnect(clientId)) {
512
508
  console.log(
513
- `[HOLSTER-DISCONNECT] Client ${clientId}: Disconnecting bad actor after ${throttleCount} throttle violations`,
509
+ `Client ${clientId}: Disconnecting after ${throttleCount} throttle violations`,
514
510
  )
515
- ws.close(1008, "Rate limit violations - bad actor")
511
+ ws.close(1008, "Rate limit violations")
516
512
  return
517
513
  }
518
514
 
@@ -565,7 +561,7 @@ const Wire = opt => {
565
561
  let throttleUntil = 0
566
562
  let messageQueue = []
567
563
  let queueProcessor = null
568
- const maxQueueLength = opt.maxQueueLength || 1000
564
+ const maxQueueLength = opt.maxQueueLength || 10000
569
565
 
570
566
  const processQueue = () => {
571
567
  if (messageQueue.length === 0) {
@@ -585,9 +581,7 @@ const Wire = opt => {
585
581
 
586
582
  // Throttle period ended, resume processing
587
583
  if (clientThrottled && now >= throttleUntil) {
588
- console.log(
589
- `[CLIENT-THROTTLED] Throttle period ended, resuming queue processing`,
590
- )
584
+ console.log(`Throttle period ended, resuming queue processing`)
591
585
  clientThrottled = false
592
586
  throttleUntil = 0
593
587
  }
@@ -598,8 +592,8 @@ const Wire = opt => {
598
592
 
599
593
  // Schedule processing of next message if queue not empty
600
594
  if (messageQueue.length > 0) {
601
- // Add small delay between messages to avoid immediate re-throttling
602
- queueProcessor = setTimeout(processQueue, 100)
595
+ // Add delay between messages to respect rate limits (300 req/min = 200ms)
596
+ queueProcessor = setTimeout(processQueue, 250)
603
597
  } else {
604
598
  queueProcessor = null
605
599
  }
@@ -629,30 +623,19 @@ const Wire = opt => {
629
623
  }
630
624
 
631
625
  const send = data => {
632
- // Check if client is throttled or queue is active
633
- if (clientThrottled || messageQueue.length > 0) {
634
- if (messageQueue.length >= maxQueueLength) {
635
- return {
636
- err: `Message queue exceeded maximum length (${maxQueueLength}). Update query logic to request less data.`,
637
- queueLength: messageQueue.length,
638
- maxQueueLength: maxQueueLength,
639
- }
640
- }
641
-
642
- // Add message to queue instead of sending immediately
643
- messageQueue.push(data)
644
- console.log(
645
- `Queuing message (queue length: ${messageQueue.length}/${maxQueueLength})`,
646
- )
647
- // Start queue processor if not already running
648
- if (!queueProcessor) {
649
- queueProcessor = setTimeout(processQueue, 100)
626
+ if (messageQueue.length >= maxQueueLength) {
627
+ return {
628
+ err: `Message queue exceeded maximum length (${maxQueueLength}). Update query logic to request less data.`,
629
+ queueLength: messageQueue.length,
630
+ maxQueueLength: maxQueueLength,
650
631
  }
651
- return
652
632
  }
653
633
 
654
- // Normal case - send immediately
655
- sendToPeers(data)
634
+ messageQueue.push(data)
635
+ // Start queue processor if not already running
636
+ if (!queueProcessor) {
637
+ queueProcessor = setTimeout(processQueue, 250)
638
+ }
656
639
  }
657
640
  if (!(opt.peers instanceof Array)) {
658
641
  opt.peers = [`ws://localhost:${opt.port || 8765}`]
@@ -689,7 +672,7 @@ const Wire = opt => {
689
672
 
690
673
  // Handle throttle messages from server
691
674
  if (msg.throttle && msg.err) {
692
- console.log(`[CLIENT-THROTTLED] Server throttling: ${msg.err}`)
675
+ console.log(`Server throttling: ${msg.err}`)
693
676
  clientThrottled = true
694
677
  throttleUntil = Date.now() + msg.throttle
695
678
  return