ioredis-toolkit 0.0.6 → 0.0.8

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/client.js CHANGED
@@ -295,6 +295,7 @@ export class RedisClientWrapper {
295
295
  revocationStore: options.revocationStore ?? this.revocationStore,
296
296
  };
297
297
  this._session = createSessionManager(params);
298
+ void this._session.init();
298
299
  this.config.sessionOptions = params;
299
300
  }
300
301
  return this._session;
@@ -1,7 +1,8 @@
1
1
  -- create.lua (version 1)
2
2
  -- Atomically creates a session record, registers it in the user index
3
- -- (ZSET, score = createdAt), optionally claims an idempotency key, and
4
- -- enforces maxSessionsPerUser with bounded oldest-first eviction.
3
+ -- (ZSET, score = microsecond-resolution Redis server time, used purely
4
+ -- for eviction ordering - see below), optionally claims an idempotency
5
+ -- key, and enforces maxSessionsPerUser with bounded oldest-first eviction.
5
6
  --
6
7
  -- KEYS[1] = session record key
7
8
  -- KEYS[2] = user session index key (ZSET)
@@ -44,7 +45,21 @@ if redis.call('EXISTS', key) == 1 then
44
45
  end
45
46
 
46
47
  redis.call('SET', key, ARGV[1], 'EX', tonumber(ARGV[4]))
47
- redis.call('ZADD', index, tonumber(ARGV[3]), ARGV[2])
48
+
49
+ -- The user index score is used purely for oldest-first eviction ordering
50
+ -- (never as the record's createdAt, which is app-stamped seconds inside the
51
+ -- envelope). Redis breaks equal ZSET scores by lexicographic member order,
52
+ -- not insertion order, so scoring by second-granularity createdAt would
53
+ -- make eviction pick an arbitrary (jti-lexicographic) session rather than
54
+ -- the actual oldest one whenever a user creates more than one session in
55
+ -- the same wall-clock second - a realistic case under normal traffic, not
56
+ -- just a burst edge case. Redis is single-threaded, so two scripts touching
57
+ -- the same user slot never observe the same TIME() reading in practice;
58
+ -- microsecond-resolution server time therefore gives a strictly monotonic,
59
+ -- clock-skew-free ordering key for this user's index.
60
+ local t = redis.call('TIME')
61
+ local orderScore = tonumber(t[1]) + (tonumber(t[2]) / 1000000)
62
+ redis.call('ZADD', index, orderScore, ARGV[2])
48
63
 
49
64
  local evicted = {}
50
65
  local limit = tonumber(ARGV[5])
@@ -37,7 +37,8 @@ if env.v ~= 2 then
37
37
  return 6
38
38
  end
39
39
 
40
- local now = tonumber(redis.call('TIME')[1])
40
+ local t = redis.call('TIME')
41
+ local now = tonumber(t[1])
41
42
 
42
43
  -- Retry-safe replay detection BEFORE rejecting consumed records.
43
44
  -- The rotation nonce uniquely identifies the rotation: when the consumed
@@ -102,6 +103,8 @@ end
102
103
 
103
104
  redis.call('SET', KEYS[2], cjson.encode(nextEnv), 'EX', nextTtl)
104
105
  redis.call('ZREM', KEYS[3], ARGV[7])
105
- redis.call('ZADD', KEYS[3], now, ARGV[3])
106
+ -- Microsecond-resolution ordering score - see create.lua for why
107
+ -- second-granularity scores break oldest-first eviction ordering.
108
+ redis.call('ZADD', KEYS[3], tonumber(t[1]) + (tonumber(t[2]) / 1000000), ARGV[3])
106
109
 
107
110
  return { 1, ARGV[3] }
@@ -44,7 +44,8 @@ if env.v ~= 1 then
44
44
  end
45
45
 
46
46
  local s = env.s
47
- local now = tonumber(redis.call('TIME')[1])
47
+ local t = redis.call('TIME')
48
+ local now = tonumber(t[1])
48
49
 
49
50
  -- Retry-safe replay detection BEFORE rejecting consumed records.
50
51
  -- The rotation nonce uniquely identifies the rotation: when the consumed
@@ -114,6 +115,8 @@ end
114
115
 
115
116
  redis.call('SET', KEYS[2], cjson.encode(nextEnv), 'EX', nextTtl)
116
117
  redis.call('ZREM', KEYS[3], ARGV[6])
117
- redis.call('ZADD', KEYS[3], now, ARGV[2])
118
+ -- Microsecond-resolution ordering score - see create.lua for why
119
+ -- second-granularity scores break oldest-first eviction ordering.
120
+ redis.call('ZADD', KEYS[3], tonumber(t[1]) + (tonumber(t[2]) / 1000000), ARGV[2])
118
121
 
119
122
  return { 1, ARGV[2] }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "ioredis-toolkit",
3
- "version": "0.0.6",
3
+ "version": "0.0.8",
4
4
  "description": "Production-grade, type-safe Redis infrastructure for standalone, Sentinel, and Cluster deployments",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",