@chatcops/store-redis 0.0.0-stage → 0.2.0
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/LICENSE +21 -0
- package/README.md +99 -2
- package/dist/adapter.d.ts +30 -0
- package/dist/adapter.d.ts.map +1 -0
- package/dist/adapter.js +96 -0
- package/dist/adapter.js.map +1 -0
- package/dist/conversations.d.ts +26 -0
- package/dist/conversations.d.ts.map +1 -0
- package/dist/conversations.js +581 -0
- package/dist/conversations.js.map +1 -0
- package/dist/counters.d.ts +11 -0
- package/dist/counters.d.ts.map +1 -0
- package/dist/counters.js +86 -0
- package/dist/counters.js.map +1 -0
- package/dist/events.d.ts +31 -0
- package/dist/events.d.ts.map +1 -0
- package/dist/events.js +165 -0
- package/dist/events.js.map +1 -0
- package/dist/index.d.ts +13 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +32 -0
- package/dist/index.js.map +1 -0
- package/dist/kv.d.ts +17 -0
- package/dist/kv.d.ts.map +1 -0
- package/dist/kv.js +84 -0
- package/dist/kv.js.map +1 -0
- package/dist/types.d.ts +31 -0
- package/dist/types.d.ts.map +1 -0
- package/dist/types.js +2 -0
- package/dist/types.js.map +1 -0
- package/package.json +58 -3
|
@@ -0,0 +1,581 @@
|
|
|
1
|
+
import { ConflictError, } from '@chatcops/core';
|
|
2
|
+
import { decodeEvalResult, formatSlotPrefix, normalizeList } from './adapter.js';
|
|
3
|
+
const GET_SCRIPT = `
|
|
4
|
+
local meta = redis.call('HGETALL', KEYS[1])
|
|
5
|
+
if #meta == 0 then
|
|
6
|
+
return nil
|
|
7
|
+
end
|
|
8
|
+
local messages = redis.call('LRANGE', KEYS[2], 0, -1)
|
|
9
|
+
local metaJson = cjson.encode(meta)
|
|
10
|
+
local msgsJson = '[]'
|
|
11
|
+
if #messages > 0 then
|
|
12
|
+
msgsJson = cjson.encode(messages)
|
|
13
|
+
end
|
|
14
|
+
return '{"meta":' .. metaJson .. ',"messages":' .. msgsJson .. '}'
|
|
15
|
+
`;
|
|
16
|
+
const SAVE_SCRIPT = `
|
|
17
|
+
local now = tonumber(ARGV[3])
|
|
18
|
+
local ttl = tonumber(ARGV[4])
|
|
19
|
+
|
|
20
|
+
if ttl > 0 then
|
|
21
|
+
redis.call('ZREMRANGEBYSCORE', KEYS[3], '-inf', '(' .. (now - ttl))
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
local currentVersion = redis.call('HGET', KEYS[1], 'version')
|
|
25
|
+
local newVersion = 1
|
|
26
|
+
if currentVersion then
|
|
27
|
+
newVersion = tonumber(currentVersion) + 1
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
local createdAt = tonumber(ARGV[2])
|
|
31
|
+
if not createdAt or createdAt == 0 then
|
|
32
|
+
local currentCreatedAt = redis.call('HGET', KEYS[1], 'createdAt')
|
|
33
|
+
if currentCreatedAt then
|
|
34
|
+
createdAt = tonumber(currentCreatedAt)
|
|
35
|
+
else
|
|
36
|
+
createdAt = now
|
|
37
|
+
end
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
local updatedAt = now
|
|
41
|
+
|
|
42
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
43
|
+
|
|
44
|
+
redis.call('HSET', KEYS[1], 'id', ARGV[1], 'version', newVersion, 'createdAt', createdAt, 'updatedAt', updatedAt)
|
|
45
|
+
|
|
46
|
+
local numMeta = tonumber(ARGV[5])
|
|
47
|
+
local metaOffset = 5
|
|
48
|
+
for i = 1, numMeta do
|
|
49
|
+
local k = ARGV[metaOffset + (i - 1) * 2 + 1]
|
|
50
|
+
local v = ARGV[metaOffset + (i - 1) * 2 + 2]
|
|
51
|
+
redis.call('HSET', KEYS[1], 'meta:' .. k, v)
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
local msgStart = metaOffset + numMeta * 2 + 1
|
|
55
|
+
for i = msgStart, #ARGV do
|
|
56
|
+
redis.call('RPUSH', KEYS[2], ARGV[i])
|
|
57
|
+
end
|
|
58
|
+
|
|
59
|
+
if ttl <= 0 then
|
|
60
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
61
|
+
redis.call('ZREM', KEYS[3], ARGV[1])
|
|
62
|
+
else
|
|
63
|
+
redis.call('PEXPIRE', KEYS[1], ttl)
|
|
64
|
+
redis.call('PEXPIRE', KEYS[2], ttl)
|
|
65
|
+
redis.call('ZADD', KEYS[3], updatedAt, ARGV[1])
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
return newVersion
|
|
69
|
+
`;
|
|
70
|
+
const APPEND_SCRIPT = `
|
|
71
|
+
local now = tonumber(ARGV[3])
|
|
72
|
+
local ttl = tonumber(ARGV[4])
|
|
73
|
+
|
|
74
|
+
if ttl > 0 then
|
|
75
|
+
redis.call('ZREMRANGEBYSCORE', KEYS[3], '-inf', '(' .. (now - ttl))
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
local rawVersion = redis.call('HGET', KEYS[1], 'version')
|
|
79
|
+
local currentVersion = 0
|
|
80
|
+
if rawVersion then
|
|
81
|
+
currentVersion = tonumber(rawVersion)
|
|
82
|
+
end
|
|
83
|
+
|
|
84
|
+
local expectedVersionStr = ARGV[2]
|
|
85
|
+
if expectedVersionStr ~= '' then
|
|
86
|
+
local expectedVersion = tonumber(expectedVersionStr)
|
|
87
|
+
if expectedVersion ~= currentVersion then
|
|
88
|
+
return cjson.encode({ 'CONFLICT', tostring(currentVersion) })
|
|
89
|
+
end
|
|
90
|
+
end
|
|
91
|
+
|
|
92
|
+
local newVersion = currentVersion + 1
|
|
93
|
+
|
|
94
|
+
local createdAt = now
|
|
95
|
+
local rawCreatedAt = redis.call('HGET', KEYS[1], 'createdAt')
|
|
96
|
+
if rawCreatedAt then
|
|
97
|
+
createdAt = tonumber(rawCreatedAt)
|
|
98
|
+
end
|
|
99
|
+
|
|
100
|
+
redis.call('HSET', KEYS[1], 'id', ARGV[1], 'version', newVersion, 'createdAt', createdAt, 'updatedAt', now)
|
|
101
|
+
|
|
102
|
+
-- Shallow merge metadata fields directly into Redis hash fields without Lua cjson
|
|
103
|
+
local numMeta = tonumber(ARGV[5])
|
|
104
|
+
local metaOffset = 5
|
|
105
|
+
for i = 1, numMeta do
|
|
106
|
+
local k = ARGV[metaOffset + (i - 1) * 2 + 1]
|
|
107
|
+
local v = ARGV[metaOffset + (i - 1) * 2 + 2]
|
|
108
|
+
redis.call('HSET', KEYS[1], 'meta:' .. k, v)
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
local msgStart = metaOffset + numMeta * 2 + 1
|
|
112
|
+
for i = msgStart, #ARGV do
|
|
113
|
+
redis.call('RPUSH', KEYS[2], ARGV[i])
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
if ttl <= 0 then
|
|
117
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
118
|
+
redis.call('ZREM', KEYS[3], ARGV[1])
|
|
119
|
+
else
|
|
120
|
+
redis.call('PEXPIRE', KEYS[1], ttl)
|
|
121
|
+
redis.call('PEXPIRE', KEYS[2], ttl)
|
|
122
|
+
redis.call('ZADD', KEYS[3], now, ARGV[1])
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
return cjson.encode({ 'OK', tostring(newVersion) })
|
|
126
|
+
`;
|
|
127
|
+
const UPDATE_MESSAGE_SCRIPT = `
|
|
128
|
+
local now = tonumber(ARGV[4])
|
|
129
|
+
local ttl = tonumber(ARGV[5])
|
|
130
|
+
|
|
131
|
+
if ttl > 0 then
|
|
132
|
+
redis.call('ZREMRANGEBYSCORE', KEYS[3], '-inf', '(' .. (now - ttl))
|
|
133
|
+
end
|
|
134
|
+
|
|
135
|
+
local rawVersion = redis.call('HGET', KEYS[1], 'version')
|
|
136
|
+
if not rawVersion then
|
|
137
|
+
return 0
|
|
138
|
+
end
|
|
139
|
+
|
|
140
|
+
local msgs = redis.call('LRANGE', KEYS[2], 0, -1)
|
|
141
|
+
local targetId = ARGV[2]
|
|
142
|
+
local foundIndex = -1
|
|
143
|
+
|
|
144
|
+
for i, rawMsg in ipairs(msgs) do
|
|
145
|
+
local decoded = cjson.decode(rawMsg)
|
|
146
|
+
if decoded['id'] == targetId then
|
|
147
|
+
foundIndex = i - 1
|
|
148
|
+
break
|
|
149
|
+
end
|
|
150
|
+
end
|
|
151
|
+
|
|
152
|
+
if foundIndex == -1 then
|
|
153
|
+
return 0
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
redis.call('LSET', KEYS[2], foundIndex, ARGV[3])
|
|
157
|
+
|
|
158
|
+
local newVersion = tonumber(rawVersion) + 1
|
|
159
|
+
|
|
160
|
+
redis.call('HSET', KEYS[1], 'version', newVersion, 'updatedAt', now)
|
|
161
|
+
if ttl <= 0 then
|
|
162
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
163
|
+
redis.call('ZREM', KEYS[3], ARGV[1])
|
|
164
|
+
else
|
|
165
|
+
redis.call('PEXPIRE', KEYS[1], ttl)
|
|
166
|
+
redis.call('PEXPIRE', KEYS[2], ttl)
|
|
167
|
+
redis.call('ZADD', KEYS[3], now, ARGV[1])
|
|
168
|
+
end
|
|
169
|
+
|
|
170
|
+
return 1
|
|
171
|
+
`;
|
|
172
|
+
const REMOVE_MESSAGE_SCRIPT = `
|
|
173
|
+
local now = tonumber(ARGV[3])
|
|
174
|
+
local ttl = tonumber(ARGV[4])
|
|
175
|
+
|
|
176
|
+
if ttl > 0 then
|
|
177
|
+
redis.call('ZREMRANGEBYSCORE', KEYS[3], '-inf', '(' .. (now - ttl))
|
|
178
|
+
end
|
|
179
|
+
|
|
180
|
+
local rawVersion = redis.call('HGET', KEYS[1], 'version')
|
|
181
|
+
if not rawVersion then
|
|
182
|
+
return 0
|
|
183
|
+
end
|
|
184
|
+
|
|
185
|
+
local msgs = redis.call('LRANGE', KEYS[2], 0, -1)
|
|
186
|
+
local targetId = ARGV[2]
|
|
187
|
+
local found = false
|
|
188
|
+
local remaining = {}
|
|
189
|
+
|
|
190
|
+
for _, rawMsg in ipairs(msgs) do
|
|
191
|
+
local decoded = cjson.decode(rawMsg)
|
|
192
|
+
if decoded['id'] == targetId then
|
|
193
|
+
found = true
|
|
194
|
+
else
|
|
195
|
+
table.insert(remaining, rawMsg)
|
|
196
|
+
end
|
|
197
|
+
end
|
|
198
|
+
|
|
199
|
+
if not found then
|
|
200
|
+
return 0
|
|
201
|
+
end
|
|
202
|
+
|
|
203
|
+
redis.call('DEL', KEYS[2])
|
|
204
|
+
for _, m in ipairs(remaining) do
|
|
205
|
+
redis.call('RPUSH', KEYS[2], m)
|
|
206
|
+
end
|
|
207
|
+
|
|
208
|
+
local newVersion = tonumber(rawVersion) + 1
|
|
209
|
+
|
|
210
|
+
redis.call('HSET', KEYS[1], 'version', newVersion, 'updatedAt', now)
|
|
211
|
+
if ttl <= 0 then
|
|
212
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
213
|
+
redis.call('ZREM', KEYS[3], ARGV[1])
|
|
214
|
+
else
|
|
215
|
+
redis.call('PEXPIRE', KEYS[1], ttl)
|
|
216
|
+
redis.call('PEXPIRE', KEYS[2], ttl)
|
|
217
|
+
redis.call('ZADD', KEYS[3], now, ARGV[1])
|
|
218
|
+
end
|
|
219
|
+
|
|
220
|
+
return 1
|
|
221
|
+
`;
|
|
222
|
+
const DELETE_SCRIPT = `
|
|
223
|
+
redis.call('DEL', KEYS[1], KEYS[2])
|
|
224
|
+
redis.call('ZREM', KEYS[3], ARGV[1])
|
|
225
|
+
return 1
|
|
226
|
+
`;
|
|
227
|
+
const PURGE_IDS_SCRIPT = `
|
|
228
|
+
local ids = redis.call('ZRANGEBYSCORE', KEYS[1], '-inf', '(' .. ARGV[1], 'LIMIT', 0, tonumber(ARGV[2]))
|
|
229
|
+
if #ids == 0 then
|
|
230
|
+
return '[]'
|
|
231
|
+
end
|
|
232
|
+
return cjson.encode(ids)
|
|
233
|
+
`;
|
|
234
|
+
const PURGE_EXEC_SCRIPT = `
|
|
235
|
+
local zsetKey = KEYS[1]
|
|
236
|
+
local numIds = tonumber(ARGV[1])
|
|
237
|
+
|
|
238
|
+
for i = 2, #KEYS do
|
|
239
|
+
redis.call('DEL', KEYS[i])
|
|
240
|
+
end
|
|
241
|
+
|
|
242
|
+
for i = 1, numIds do
|
|
243
|
+
redis.call('ZREM', zsetKey, ARGV[1 + i])
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
return numIds
|
|
247
|
+
`;
|
|
248
|
+
const LIST_IDS_SCRIPT = `
|
|
249
|
+
local zsetKey = KEYS[1]
|
|
250
|
+
local limit = tonumber(ARGV[1])
|
|
251
|
+
local cursorScoreStr = ARGV[2]
|
|
252
|
+
local cursorId = ARGV[3]
|
|
253
|
+
local updatedAfterStr = ARGV[4]
|
|
254
|
+
|
|
255
|
+
local minScore = '-inf'
|
|
256
|
+
if updatedAfterStr ~= '' then
|
|
257
|
+
minScore = '(' .. updatedAfterStr
|
|
258
|
+
end
|
|
259
|
+
|
|
260
|
+
local results = {}
|
|
261
|
+
local needed = limit + 1
|
|
262
|
+
local currScore = nil
|
|
263
|
+
|
|
264
|
+
if cursorScoreStr ~= '' and cursorId ~= '' then
|
|
265
|
+
local cursorScore = tonumber(cursorScoreStr)
|
|
266
|
+
local rank = redis.call('ZRANK', zsetKey, cursorId)
|
|
267
|
+
local startRank = nil
|
|
268
|
+
if rank then
|
|
269
|
+
startRank = rank + 1
|
|
270
|
+
else
|
|
271
|
+
local members = redis.call('ZRANGEBYSCORE', zsetKey, cursorScore, cursorScore)
|
|
272
|
+
for _, m in ipairs(members) do
|
|
273
|
+
if m > cursorId then
|
|
274
|
+
startRank = redis.call('ZRANK', zsetKey, m)
|
|
275
|
+
break
|
|
276
|
+
end
|
|
277
|
+
end
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
if startRank then
|
|
281
|
+
local chunk = redis.call('ZRANGE', zsetKey, startRank, startRank + needed - 1, 'WITHSCORES')
|
|
282
|
+
for i = 1, #chunk, 2 do
|
|
283
|
+
local id = chunk[i]
|
|
284
|
+
local s = tonumber(chunk[i + 1])
|
|
285
|
+
if s == cursorScore then
|
|
286
|
+
table.insert(results, { id, s })
|
|
287
|
+
if #results == needed then
|
|
288
|
+
break
|
|
289
|
+
end
|
|
290
|
+
else
|
|
291
|
+
break
|
|
292
|
+
end
|
|
293
|
+
end
|
|
294
|
+
end
|
|
295
|
+
currScore = cursorScore
|
|
296
|
+
else
|
|
297
|
+
local top = redis.call('ZREVRANGEBYSCORE', zsetKey, '+inf', minScore, 'LIMIT', 0, 1, 'WITHSCORES')
|
|
298
|
+
if #top > 0 then
|
|
299
|
+
currScore = tonumber(top[2])
|
|
300
|
+
local chunk = redis.call('ZRANGEBYSCORE', zsetKey, currScore, currScore, 'LIMIT', 0, needed)
|
|
301
|
+
for _, id in ipairs(chunk) do
|
|
302
|
+
table.insert(results, { id, currScore })
|
|
303
|
+
if #results == needed then
|
|
304
|
+
break
|
|
305
|
+
end
|
|
306
|
+
end
|
|
307
|
+
end
|
|
308
|
+
end
|
|
309
|
+
|
|
310
|
+
while #results < needed and currScore ~= nil do
|
|
311
|
+
local nextTop = redis.call('ZREVRANGEBYSCORE', zsetKey, '(' .. currScore, minScore, 'LIMIT', 0, 1, 'WITHSCORES')
|
|
312
|
+
if #nextTop == 0 then
|
|
313
|
+
break
|
|
314
|
+
end
|
|
315
|
+
currScore = tonumber(nextTop[2])
|
|
316
|
+
local countNeeded = needed - #results
|
|
317
|
+
local chunk = redis.call('ZRANGEBYSCORE', zsetKey, currScore, currScore, 'LIMIT', 0, countNeeded)
|
|
318
|
+
for _, id in ipairs(chunk) do
|
|
319
|
+
table.insert(results, { id, currScore })
|
|
320
|
+
if #results == needed then
|
|
321
|
+
break
|
|
322
|
+
end
|
|
323
|
+
end
|
|
324
|
+
end
|
|
325
|
+
|
|
326
|
+
if #results == 0 then
|
|
327
|
+
return '[]'
|
|
328
|
+
end
|
|
329
|
+
return cjson.encode(results)
|
|
330
|
+
`;
|
|
331
|
+
const LIST_ITEMS_SCRIPT = `
|
|
332
|
+
local zsetKey = KEYS[1]
|
|
333
|
+
local numItems = tonumber(ARGV[1])
|
|
334
|
+
local results = {}
|
|
335
|
+
|
|
336
|
+
for i = 1, numItems do
|
|
337
|
+
local metaKey = KEYS[1 + i]
|
|
338
|
+
local msgsKey = KEYS[1 + numItems + i]
|
|
339
|
+
local id = ARGV[1 + i]
|
|
340
|
+
|
|
341
|
+
local meta = redis.call('HGETALL', metaKey)
|
|
342
|
+
if #meta > 0 then
|
|
343
|
+
local count = redis.call('LLEN', msgsKey)
|
|
344
|
+
table.insert(results, { id, meta, count })
|
|
345
|
+
else
|
|
346
|
+
redis.call('ZREM', zsetKey, id)
|
|
347
|
+
table.insert(results, { id, {}, 0 })
|
|
348
|
+
end
|
|
349
|
+
end
|
|
350
|
+
|
|
351
|
+
if #results == 0 then
|
|
352
|
+
return '[]'
|
|
353
|
+
end
|
|
354
|
+
return cjson.encode(results)
|
|
355
|
+
`;
|
|
356
|
+
export class RedisConversationStore {
|
|
357
|
+
redis;
|
|
358
|
+
zsetKey;
|
|
359
|
+
slotPrefix;
|
|
360
|
+
ttlMs;
|
|
361
|
+
constructor(redis, prefix, ttlMs) {
|
|
362
|
+
this.redis = redis;
|
|
363
|
+
this.slotPrefix = formatSlotPrefix(prefix);
|
|
364
|
+
this.zsetKey = `${this.slotPrefix}:conversations`;
|
|
365
|
+
this.ttlMs = Math.ceil(ttlMs);
|
|
366
|
+
}
|
|
367
|
+
metaKey(id) {
|
|
368
|
+
return `${this.slotPrefix}:conv:${id}:meta`;
|
|
369
|
+
}
|
|
370
|
+
messagesKey(id) {
|
|
371
|
+
return `${this.slotPrefix}:conv:${id}:messages`;
|
|
372
|
+
}
|
|
373
|
+
serializeMetadata(metadata) {
|
|
374
|
+
if (!metadata)
|
|
375
|
+
return [];
|
|
376
|
+
const entries = [];
|
|
377
|
+
for (const [k, v] of Object.entries(metadata)) {
|
|
378
|
+
if (v !== undefined) {
|
|
379
|
+
entries.push(k, JSON.stringify(v));
|
|
380
|
+
}
|
|
381
|
+
}
|
|
382
|
+
return entries;
|
|
383
|
+
}
|
|
384
|
+
async get(id) {
|
|
385
|
+
const raw = await this.redis.eval(GET_SCRIPT, [this.metaKey(id), this.messagesKey(id)], []);
|
|
386
|
+
if (!raw)
|
|
387
|
+
return null;
|
|
388
|
+
const res = decodeEvalResult(raw);
|
|
389
|
+
const rawMeta = normalizeList(res?.meta);
|
|
390
|
+
if (rawMeta.length === 0)
|
|
391
|
+
return null;
|
|
392
|
+
const metaMap = {};
|
|
393
|
+
const metadata = {};
|
|
394
|
+
let hasMetadata = false;
|
|
395
|
+
for (let i = 0; i < rawMeta.length; i += 2) {
|
|
396
|
+
const k = String(rawMeta[i]);
|
|
397
|
+
const v = rawMeta[i + 1];
|
|
398
|
+
if (k.startsWith('meta:')) {
|
|
399
|
+
const field = k.slice(5);
|
|
400
|
+
try {
|
|
401
|
+
metadata[field] = typeof v === 'string' ? JSON.parse(v) : v;
|
|
402
|
+
}
|
|
403
|
+
catch {
|
|
404
|
+
metadata[field] = v;
|
|
405
|
+
}
|
|
406
|
+
hasMetadata = true;
|
|
407
|
+
}
|
|
408
|
+
else if (k === 'metadata' && !hasMetadata) {
|
|
409
|
+
// Backwards compatibility with legacy store format
|
|
410
|
+
try {
|
|
411
|
+
const parsed = typeof v === 'string' ? JSON.parse(v) : v;
|
|
412
|
+
if (parsed && typeof parsed === 'object') {
|
|
413
|
+
Object.assign(metadata, parsed);
|
|
414
|
+
hasMetadata = true;
|
|
415
|
+
}
|
|
416
|
+
}
|
|
417
|
+
catch { }
|
|
418
|
+
}
|
|
419
|
+
else {
|
|
420
|
+
metaMap[k] = v;
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
const rawMessages = normalizeList(res?.messages);
|
|
424
|
+
const messages = rawMessages.map((m) => typeof m === 'string' ? JSON.parse(m) : m);
|
|
425
|
+
return {
|
|
426
|
+
id, // Preserve requested id directly
|
|
427
|
+
messages,
|
|
428
|
+
version: Number(metaMap.version ?? 0),
|
|
429
|
+
createdAt: Number(metaMap.createdAt ?? 0),
|
|
430
|
+
updatedAt: Number(metaMap.updatedAt ?? 0),
|
|
431
|
+
...(hasMetadata ? { metadata } : {}),
|
|
432
|
+
};
|
|
433
|
+
}
|
|
434
|
+
async save(conversation) {
|
|
435
|
+
const id = conversation.id;
|
|
436
|
+
const updatedAt = conversation.updatedAt ?? Date.now();
|
|
437
|
+
const createdAt = conversation.createdAt ?? 0;
|
|
438
|
+
const metaPairs = this.serializeMetadata(conversation.metadata);
|
|
439
|
+
const numMeta = metaPairs.length / 2;
|
|
440
|
+
const messagesJson = (conversation.messages ?? []).map((m) => JSON.stringify(m));
|
|
441
|
+
await this.redis.eval(SAVE_SCRIPT, [this.metaKey(id), this.messagesKey(id), this.zsetKey], [id, createdAt, updatedAt, this.ttlMs, numMeta, ...metaPairs, ...messagesJson]);
|
|
442
|
+
}
|
|
443
|
+
async append(id, messages, options = {}) {
|
|
444
|
+
const expectedVersionStr = options.expectedVersion !== undefined ? String(options.expectedVersion) : '';
|
|
445
|
+
const now = Date.now();
|
|
446
|
+
const metaPairs = this.serializeMetadata(options.metadata);
|
|
447
|
+
const numMeta = metaPairs.length / 2;
|
|
448
|
+
const messagesJson = messages.map((m) => JSON.stringify(m));
|
|
449
|
+
const raw = await this.redis.eval(APPEND_SCRIPT, [this.metaKey(id), this.messagesKey(id), this.zsetKey], [id, expectedVersionStr, now, this.ttlMs, numMeta, ...metaPairs, ...messagesJson]);
|
|
450
|
+
const res = decodeEvalResult(raw);
|
|
451
|
+
if (res[0] === 'CONFLICT') {
|
|
452
|
+
const actualVersion = Number(res[1]);
|
|
453
|
+
throw new ConflictError(id, options.expectedVersion ?? 0, actualVersion);
|
|
454
|
+
}
|
|
455
|
+
return { version: Number(res[1]) };
|
|
456
|
+
}
|
|
457
|
+
async updateMessage(id, message) {
|
|
458
|
+
const now = Date.now();
|
|
459
|
+
const messageJson = JSON.stringify(message);
|
|
460
|
+
const res = await this.redis.eval(UPDATE_MESSAGE_SCRIPT, [this.metaKey(id), this.messagesKey(id), this.zsetKey], [id, message.id, messageJson, now, this.ttlMs]);
|
|
461
|
+
return Number(res) === 1;
|
|
462
|
+
}
|
|
463
|
+
async removeMessage(id, messageId) {
|
|
464
|
+
const now = Date.now();
|
|
465
|
+
const res = await this.redis.eval(REMOVE_MESSAGE_SCRIPT, [this.metaKey(id), this.messagesKey(id), this.zsetKey], [id, messageId, now, this.ttlMs]);
|
|
466
|
+
return Number(res) === 1;
|
|
467
|
+
}
|
|
468
|
+
async delete(id) {
|
|
469
|
+
await this.redis.eval(DELETE_SCRIPT, [this.metaKey(id), this.messagesKey(id), this.zsetKey], [id]);
|
|
470
|
+
}
|
|
471
|
+
async list(query) {
|
|
472
|
+
let cursorScore = '';
|
|
473
|
+
let cursorId = '';
|
|
474
|
+
if (query.cursor) {
|
|
475
|
+
const colonIdx = query.cursor.indexOf(':');
|
|
476
|
+
if (colonIdx !== -1) {
|
|
477
|
+
const s = Number(query.cursor.slice(0, colonIdx));
|
|
478
|
+
if (!Number.isNaN(s)) {
|
|
479
|
+
cursorScore = String(s);
|
|
480
|
+
cursorId = query.cursor.slice(colonIdx + 1);
|
|
481
|
+
}
|
|
482
|
+
}
|
|
483
|
+
if (!cursorScore || !cursorId) {
|
|
484
|
+
// Unknown or invalid cursor returns empty items
|
|
485
|
+
return { items: [] };
|
|
486
|
+
}
|
|
487
|
+
}
|
|
488
|
+
const updatedAfterStr = query.updatedAfter !== undefined ? String(query.updatedAfter) : '';
|
|
489
|
+
const rawCandidateResults = await this.redis.eval(LIST_IDS_SCRIPT, [this.zsetKey], [query.limit, cursorScore, cursorId, updatedAfterStr]);
|
|
490
|
+
const candidates = normalizeList(decodeEvalResult(rawCandidateResults));
|
|
491
|
+
if (candidates.length === 0) {
|
|
492
|
+
return { items: [] };
|
|
493
|
+
}
|
|
494
|
+
const hasMore = candidates.length > query.limit;
|
|
495
|
+
const pageCandidates = candidates.slice(0, query.limit);
|
|
496
|
+
const pageIds = pageCandidates.map((c) => c[0]);
|
|
497
|
+
if (pageIds.length === 0) {
|
|
498
|
+
return { items: [] };
|
|
499
|
+
}
|
|
500
|
+
// Step 2: Fetch metadata and message counts with cluster-safe key passing
|
|
501
|
+
const metaKeys = pageIds.map((id) => this.metaKey(id));
|
|
502
|
+
const msgsKeys = pageIds.map((id) => this.messagesKey(id));
|
|
503
|
+
const keys = [this.zsetKey, ...metaKeys, ...msgsKeys];
|
|
504
|
+
const scriptArgs = [pageIds.length, ...pageIds];
|
|
505
|
+
const rawResults = await this.redis.eval(LIST_ITEMS_SCRIPT, keys, scriptArgs);
|
|
506
|
+
const results = normalizeList(decodeEvalResult(rawResults));
|
|
507
|
+
const items = [];
|
|
508
|
+
for (const [id, rawMeta, messageCount] of results) {
|
|
509
|
+
const metaArray = normalizeList(rawMeta);
|
|
510
|
+
if (metaArray.length === 0)
|
|
511
|
+
continue;
|
|
512
|
+
const metaMap = {};
|
|
513
|
+
const metadata = {};
|
|
514
|
+
let hasMetadata = false;
|
|
515
|
+
for (let i = 0; i < metaArray.length; i += 2) {
|
|
516
|
+
const k = String(metaArray[i]);
|
|
517
|
+
const v = metaArray[i + 1];
|
|
518
|
+
if (k.startsWith('meta:')) {
|
|
519
|
+
const field = k.slice(5);
|
|
520
|
+
try {
|
|
521
|
+
metadata[field] = typeof v === 'string' ? JSON.parse(v) : v;
|
|
522
|
+
}
|
|
523
|
+
catch {
|
|
524
|
+
metadata[field] = v;
|
|
525
|
+
}
|
|
526
|
+
hasMetadata = true;
|
|
527
|
+
}
|
|
528
|
+
else if (k === 'metadata' && !hasMetadata) {
|
|
529
|
+
try {
|
|
530
|
+
const parsed = typeof v === 'string' ? JSON.parse(v) : v;
|
|
531
|
+
if (parsed && typeof parsed === 'object') {
|
|
532
|
+
Object.assign(metadata, parsed);
|
|
533
|
+
hasMetadata = true;
|
|
534
|
+
}
|
|
535
|
+
}
|
|
536
|
+
catch { }
|
|
537
|
+
}
|
|
538
|
+
else {
|
|
539
|
+
metaMap[k] = v;
|
|
540
|
+
}
|
|
541
|
+
}
|
|
542
|
+
items.push({
|
|
543
|
+
id: String(id),
|
|
544
|
+
createdAt: Number(metaMap.createdAt ?? 0),
|
|
545
|
+
updatedAt: Number(metaMap.updatedAt ?? 0),
|
|
546
|
+
messageCount: Number(messageCount),
|
|
547
|
+
...(hasMetadata ? { metadata } : {}),
|
|
548
|
+
});
|
|
549
|
+
}
|
|
550
|
+
if (hasMore && items.length > 0) {
|
|
551
|
+
const last = pageCandidates[pageCandidates.length - 1];
|
|
552
|
+
const nextCursor = `${last[1]}:${last[0]}`;
|
|
553
|
+
return { items, cursor: nextCursor };
|
|
554
|
+
}
|
|
555
|
+
return { items };
|
|
556
|
+
}
|
|
557
|
+
async purge(before) {
|
|
558
|
+
let totalPurged = 0;
|
|
559
|
+
const BATCH_SIZE = 100;
|
|
560
|
+
while (true) {
|
|
561
|
+
// Step 1: Query a batch of conversation IDs updated before cutoff
|
|
562
|
+
const rawIds = await this.redis.eval(PURGE_IDS_SCRIPT, [this.zsetKey], [before, BATCH_SIZE]);
|
|
563
|
+
const ids = normalizeList(decodeEvalResult(rawIds));
|
|
564
|
+
if (ids.length === 0) {
|
|
565
|
+
break;
|
|
566
|
+
}
|
|
567
|
+
// Step 2: Delete keys with all keys explicitly passed in KEYS
|
|
568
|
+
const metaKeys = ids.map((id) => this.metaKey(id));
|
|
569
|
+
const msgsKeys = ids.map((id) => this.messagesKey(id));
|
|
570
|
+
const keys = [this.zsetKey, ...metaKeys, ...msgsKeys];
|
|
571
|
+
const scriptArgs = [ids.length, ...ids];
|
|
572
|
+
const res = await this.redis.eval(PURGE_EXEC_SCRIPT, keys, scriptArgs);
|
|
573
|
+
totalPurged += Number(res);
|
|
574
|
+
if (ids.length < BATCH_SIZE) {
|
|
575
|
+
break;
|
|
576
|
+
}
|
|
577
|
+
}
|
|
578
|
+
return totalPurged;
|
|
579
|
+
}
|
|
580
|
+
}
|
|
581
|
+
//# sourceMappingURL=conversations.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"conversations.js","sourceRoot":"","sources":["../src/conversations.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { CounterStore, CounterValue } from '@chatcops/core';
|
|
2
|
+
import type { RedisLike } from './types.js';
|
|
3
|
+
export declare class RedisCounterStore implements CounterStore {
|
|
4
|
+
private readonly redis;
|
|
5
|
+
private readonly slotPrefix;
|
|
6
|
+
constructor(redis: RedisLike, prefix: string);
|
|
7
|
+
private key;
|
|
8
|
+
increment(key: string, by: number, ttlMs: number): Promise<CounterValue>;
|
|
9
|
+
get(key: string): Promise<CounterValue | null>;
|
|
10
|
+
}
|
|
11
|
+
//# sourceMappingURL=counters.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"counters.d.ts","sourceRoot":"","sources":["../src/counters.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,YAAY,EAAE,YAAY,EAAE,MAAM,gBAAgB,CAAC;AAEjE,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;AAwD5C,qBAAa,iBAAkB,YAAW,YAAY;IAIlD,OAAO,CAAC,QAAQ,CAAC,KAAK;IAHxB,OAAO,CAAC,QAAQ,CAAC,UAAU,CAAS;gBAGjB,KAAK,EAAE,SAAS,EACjC,MAAM,EAAE,MAAM;IAKhB,OAAO,CAAC,GAAG;IAIL,SAAS,CAAC,GAAG,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC;IAexE,GAAG,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,GAAG,IAAI,CAAC;CAgBrD"}
|