@keetanetwork/anchor 0.0.33 → 0.0.35

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.
Files changed (61) hide show
  1. package/lib/http-server/index.d.ts +7 -1
  2. package/lib/http-server/index.d.ts.map +1 -1
  3. package/lib/http-server/index.js +2 -0
  4. package/lib/http-server/index.js.map +1 -1
  5. package/lib/queue/common.d.ts +26 -0
  6. package/lib/queue/common.d.ts.map +1 -0
  7. package/lib/queue/common.js +47 -0
  8. package/lib/queue/common.js.map +1 -0
  9. package/lib/queue/drivers/queue_file.d.ts +17 -0
  10. package/lib/queue/drivers/queue_file.d.ts.map +1 -0
  11. package/lib/queue/drivers/queue_file.js +100 -0
  12. package/lib/queue/drivers/queue_file.js.map +1 -0
  13. package/lib/queue/drivers/queue_postgres.d.ts +28 -0
  14. package/lib/queue/drivers/queue_postgres.d.ts.map +1 -0
  15. package/lib/queue/drivers/queue_postgres.js +360 -0
  16. package/lib/queue/drivers/queue_postgres.js.map +1 -0
  17. package/lib/queue/drivers/queue_redis.d.ts +27 -0
  18. package/lib/queue/drivers/queue_redis.d.ts.map +1 -0
  19. package/lib/queue/drivers/queue_redis.js +359 -0
  20. package/lib/queue/drivers/queue_redis.js.map +1 -0
  21. package/lib/queue/drivers/queue_sqlite3.d.ts +28 -0
  22. package/lib/queue/drivers/queue_sqlite3.d.ts.map +1 -0
  23. package/lib/queue/drivers/queue_sqlite3.js +378 -0
  24. package/lib/queue/drivers/queue_sqlite3.js.map +1 -0
  25. package/lib/queue/index.d.ts +341 -0
  26. package/lib/queue/index.d.ts.map +1 -0
  27. package/lib/queue/index.js +946 -0
  28. package/lib/queue/index.js.map +1 -0
  29. package/lib/queue/internal.d.ts +20 -0
  30. package/lib/queue/internal.d.ts.map +1 -0
  31. package/lib/queue/internal.js +66 -0
  32. package/lib/queue/internal.js.map +1 -0
  33. package/lib/queue/pipeline.d.ts +152 -0
  34. package/lib/queue/pipeline.d.ts.map +1 -0
  35. package/lib/queue/pipeline.js +296 -0
  36. package/lib/queue/pipeline.js.map +1 -0
  37. package/lib/resolver.d.ts +1 -1
  38. package/lib/resolver.d.ts.map +1 -1
  39. package/lib/resolver.js.map +1 -1
  40. package/lib/utils/asleep.d.ts +2 -0
  41. package/lib/utils/asleep.d.ts.map +1 -0
  42. package/lib/utils/asleep.js +3 -0
  43. package/lib/utils/asleep.js.map +1 -0
  44. package/lib/utils/defer.d.ts +4 -0
  45. package/lib/utils/defer.d.ts.map +1 -0
  46. package/lib/utils/defer.js +3 -0
  47. package/lib/utils/defer.js.map +1 -0
  48. package/npm-shrinkwrap.json +2 -2
  49. package/package.json +1 -1
  50. package/services/fx/client.d.ts +1 -1
  51. package/services/fx/client.d.ts.map +1 -1
  52. package/services/fx/client.js +2 -2
  53. package/services/fx/client.js.map +1 -1
  54. package/services/fx/common.d.ts +19 -4
  55. package/services/fx/common.d.ts.map +1 -1
  56. package/services/fx/common.js +8 -5
  57. package/services/fx/common.js.map +1 -1
  58. package/services/fx/server.d.ts +105 -8
  59. package/services/fx/server.d.ts.map +1 -1
  60. package/services/fx/server.js +609 -43
  61. package/services/fx/server.js.map +1 -1
@@ -0,0 +1,359 @@
1
+ import { MethodLogger, ManageStatusUpdates, ConvertStringToRequestID } from '../internal.js';
2
+ import { Errors } from '../common.js';
3
+ export default class KeetaAnchorQueueStorageDriverRedis {
4
+ logger;
5
+ redisInternal = null;
6
+ name = 'KeetaAnchorQueueStorageDriverRedis';
7
+ id;
8
+ path = [];
9
+ pathStr;
10
+ constructor(options) {
11
+ this.id = options?.id ?? crypto.randomUUID();
12
+ this.logger = options?.logger;
13
+ this.redisInternal = options.redis;
14
+ this.path = options.path ?? [];
15
+ this.pathStr = ['root', ...this.path].join('.');
16
+ Object.freeze(this.path);
17
+ this.methodLogger('new')?.debug('Initialized Redis queue storage driver');
18
+ }
19
+ methodLogger(method) {
20
+ return (MethodLogger(this.logger, {
21
+ class: 'KeetaAnchorQueueStorageDriverRedis',
22
+ file: 'src/lib/queue/drivers/queue_redis.ts',
23
+ method: method,
24
+ instanceID: this.id
25
+ }));
26
+ }
27
+ async getRedis() {
28
+ if (this.redisInternal === null) {
29
+ throw (new Error('Redis connection is not available'));
30
+ }
31
+ return (await this.redisInternal());
32
+ }
33
+ queueKey(id) {
34
+ return (`queue:${this.pathStr}:entry:${String(id)}`);
35
+ }
36
+ idempotentKey(idempotentID) {
37
+ return (`queue:${this.pathStr}:idempotent:${String(idempotentID)}`);
38
+ }
39
+ indexKey(status) {
40
+ if (status) {
41
+ return (`queue:${this.pathStr}:index:${status}`);
42
+ }
43
+ return (`queue:${this.pathStr}:index:all`);
44
+ }
45
+ async add(request, info) {
46
+ const redis = await this.getRedis();
47
+ const logger = this.methodLogger('add');
48
+ let entryID = ConvertStringToRequestID(info?.id);
49
+ if (entryID) {
50
+ const exists = await redis.exists(this.queueKey(entryID));
51
+ if (exists) {
52
+ logger?.debug(`Request with id ${String(entryID)} already exists, ignoring`);
53
+ return (entryID);
54
+ }
55
+ }
56
+ const idempotentIDs = info?.idempotentKeys;
57
+ if (idempotentIDs) {
58
+ const matchingIdempotentEntries = new Set();
59
+ for (const idempotentID of idempotentIDs) {
60
+ const existingEntryID = await redis.get(this.idempotentKey(idempotentID));
61
+ if (existingEntryID) {
62
+ matchingIdempotentEntries.add(idempotentID);
63
+ }
64
+ }
65
+ if (matchingIdempotentEntries.size !== 0) {
66
+ throw (new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', matchingIdempotentEntries));
67
+ }
68
+ }
69
+ entryID ??= ConvertStringToRequestID(crypto.randomUUID());
70
+ logger?.debug(`Enqueuing request with id ${String(entryID)}`);
71
+ const currentTime = Date.now();
72
+ const requestJSON = JSON.stringify(request);
73
+ /**
74
+ * The status to use for the new entry
75
+ */
76
+ const status = info?.status ?? 'pending';
77
+ const entryData = {
78
+ id: String(entryID),
79
+ request: requestJSON,
80
+ output: null,
81
+ lastError: null,
82
+ status: status,
83
+ created: currentTime,
84
+ updated: currentTime,
85
+ worker: null,
86
+ failures: 0
87
+ };
88
+ if (idempotentIDs && idempotentIDs.size > 0) {
89
+ entryData.idempotentKeys = Array.from(idempotentIDs).map(String);
90
+ }
91
+ if (idempotentIDs && idempotentIDs.size > 0) {
92
+ const idempotentKeysArr = Array.from(idempotentIDs).map(String);
93
+ const luaScript = `
94
+ local entryKey = KEYS[1]
95
+ local statusIndexKey = KEYS[2]
96
+ local allIndexKey = KEYS[3]
97
+
98
+ local entryData = ARGV[1]
99
+ local score = ARGV[2]
100
+ local entryId = ARGV[3]
101
+ local numIdempotentKeys = tonumber(ARGV[4])
102
+
103
+ -- Check if any idempotent keys already exist
104
+ for i = 1, numIdempotentKeys do
105
+ local idempotentKey = ARGV[4 + i]
106
+ if redis.call('EXISTS', idempotentKey) == 1 then
107
+ return redis.error_reply('IDEMPOTENT_EXISTS')
108
+ end
109
+ end
110
+
111
+ -- Add the entry
112
+ redis.call('SET', entryKey, entryData)
113
+ redis.call('ZADD', statusIndexKey, score, entryId)
114
+ redis.call('ZADD', allIndexKey, score, entryId)
115
+
116
+ -- Set idempotent keys
117
+ for i = 1, numIdempotentKeys do
118
+ local idempotentKey = ARGV[4 + i]
119
+ redis.call('SET', idempotentKey, entryId)
120
+ end
121
+
122
+ return 'OK'
123
+ `;
124
+ const idempotentKeyPairs = idempotentKeysArr.map((idKey) => {
125
+ return (this.idempotentKey(ConvertStringToRequestID(idKey)));
126
+ });
127
+ try {
128
+ await redis.eval(luaScript, {
129
+ keys: [
130
+ this.queueKey(entryID),
131
+ this.indexKey(status),
132
+ this.indexKey()
133
+ ],
134
+ arguments: [
135
+ JSON.stringify(entryData),
136
+ String(currentTime),
137
+ String(entryID),
138
+ String(idempotentKeysArr.length),
139
+ ...idempotentKeyPairs
140
+ ]
141
+ });
142
+ }
143
+ catch (error) {
144
+ if (error instanceof Error && error.message.includes('IDEMPOTENT_EXISTS')) {
145
+ throw (new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', idempotentIDs));
146
+ }
147
+ throw (error);
148
+ }
149
+ }
150
+ else {
151
+ const multi = redis.multi();
152
+ multi.set(this.queueKey(entryID), JSON.stringify(entryData));
153
+ multi.zAdd(this.indexKey(status), { score: currentTime, value: String(entryID) });
154
+ multi.zAdd(this.indexKey(), { score: currentTime, value: String(entryID) });
155
+ await multi.exec();
156
+ }
157
+ return (entryID);
158
+ }
159
+ async setStatus(id, status, ancillary) {
160
+ const { oldStatus } = ancillary ?? {};
161
+ const redis = await this.getRedis();
162
+ const logger = this.methodLogger('setStatus');
163
+ const entryJSON = await redis.get(this.queueKey(id));
164
+ if (!entryJSON) {
165
+ throw (new Error(`Request with ID ${String(id)} not found`));
166
+ }
167
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
168
+ const existingEntry = JSON.parse(entryJSON);
169
+ if (oldStatus && existingEntry.status !== oldStatus) {
170
+ throw (new Errors.IncorrectStateAssertedError(id, oldStatus, existingEntry.status));
171
+ }
172
+ const newEntryRaw = ManageStatusUpdates(id, existingEntry, status, ancillary, logger);
173
+ const newEntry = {
174
+ status: newEntryRaw.status,
175
+ worker: newEntryRaw.worker,
176
+ failures: newEntryRaw.failures ?? existingEntry.failures,
177
+ updated: newEntryRaw.updated.getTime(),
178
+ lastError: newEntryRaw.lastError !== undefined ? newEntryRaw.lastError : existingEntry.lastError,
179
+ output: newEntryRaw.output !== undefined ? newEntryRaw.output ? JSON.stringify(newEntryRaw.output) : null : existingEntry.output
180
+ };
181
+ const updatedEntry = {
182
+ ...existingEntry,
183
+ ...newEntry
184
+ };
185
+ const currentTime = updatedEntry.updated;
186
+ if (oldStatus) {
187
+ const luaScript = `
188
+ local key = KEYS[1]
189
+ local expectedStatus = ARGV[1]
190
+ local newData = ARGV[2]
191
+ local oldIndexKey = ARGV[3]
192
+ local newIndexKey = ARGV[4]
193
+ local allIndexKey = ARGV[5]
194
+ local entryId = ARGV[6]
195
+ local score = ARGV[7]
196
+
197
+ local current = redis.call('GET', key)
198
+ if not current then
199
+ return {err = 'NOT_FOUND'}
200
+ end
201
+
202
+ local currentData = cjson.decode(current)
203
+ if currentData.status ~= expectedStatus then
204
+ return {err = 'STATUS_MISMATCH'}
205
+ end
206
+
207
+ redis.call('SET', key, newData)
208
+ if oldIndexKey ~= newIndexKey then
209
+ redis.call('ZREM', oldIndexKey, entryId)
210
+ end
211
+ redis.call('ZADD', newIndexKey, score, entryId)
212
+ redis.call('ZADD', allIndexKey, score, entryId)
213
+
214
+ return {ok = 'OK'}
215
+ `;
216
+ const result = await redis.eval(luaScript, {
217
+ keys: [this.queueKey(id)],
218
+ arguments: [
219
+ oldStatus,
220
+ JSON.stringify(updatedEntry),
221
+ this.indexKey(oldStatus),
222
+ this.indexKey(status),
223
+ this.indexKey(),
224
+ String(id),
225
+ String(currentTime)
226
+ ]
227
+ });
228
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
229
+ const resultObj = result;
230
+ if (resultObj.err === 'NOT_FOUND') {
231
+ throw (new Error(`Request with ID ${String(id)} not found`));
232
+ }
233
+ if (resultObj.err === 'STATUS_MISMATCH') {
234
+ throw (new Errors.IncorrectStateAssertedError(id, oldStatus, existingEntry.status));
235
+ }
236
+ }
237
+ else {
238
+ const multi = redis.multi();
239
+ multi.set(this.queueKey(id), JSON.stringify(updatedEntry));
240
+ if (existingEntry.status !== status) {
241
+ multi.zRem(this.indexKey(existingEntry.status), String(id));
242
+ }
243
+ multi.zAdd(this.indexKey(status), { score: currentTime, value: String(id) });
244
+ multi.zAdd(this.indexKey(), { score: currentTime, value: String(id) });
245
+ await multi.exec();
246
+ }
247
+ }
248
+ async get(id) {
249
+ const redis = await this.getRedis();
250
+ const entryJSON = await redis.get(this.queueKey(id));
251
+ if (!entryJSON) {
252
+ return (null);
253
+ }
254
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
255
+ const entryData = JSON.parse(entryJSON);
256
+ const idempotentKeys = entryData.idempotentKeys && entryData.idempotentKeys.length > 0
257
+ ? new Set(entryData.idempotentKeys.map(function (key) {
258
+ return (ConvertStringToRequestID(key));
259
+ }))
260
+ : undefined;
261
+ return ({
262
+ id: ConvertStringToRequestID(entryData.id),
263
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
264
+ request: JSON.parse(entryData.request),
265
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
266
+ output: entryData.output ? JSON.parse(entryData.output) : null,
267
+ lastError: entryData.lastError,
268
+ status: entryData.status,
269
+ created: new Date(entryData.created),
270
+ updated: new Date(entryData.updated),
271
+ // eslint-disable-next-line @typescript-eslint/consistent-type-assertions
272
+ worker: entryData.worker,
273
+ failures: entryData.failures,
274
+ idempotentKeys: idempotentKeys
275
+ });
276
+ }
277
+ async query(filter) {
278
+ const redis = await this.getRedis();
279
+ const logger = this.methodLogger('query');
280
+ logger?.debug(`Querying queue with id ${this.id} with filter:`, filter);
281
+ let entryIDs;
282
+ if (filter?.status) {
283
+ const count = filter.limit ?? -1;
284
+ const allIDs = await redis.zRange(this.indexKey(filter.status), 0, -1);
285
+ if (filter.updatedBefore) {
286
+ const maxScore = filter.updatedBefore.getTime();
287
+ const filteredIDs = [];
288
+ for (const entryID of allIDs) {
289
+ const score = await redis.zScore(this.indexKey(filter.status), entryID);
290
+ if (score !== null && score < maxScore) {
291
+ filteredIDs.push(entryID);
292
+ }
293
+ }
294
+ entryIDs = filteredIDs;
295
+ }
296
+ else {
297
+ entryIDs = allIDs;
298
+ }
299
+ if (count !== -1) {
300
+ entryIDs = entryIDs.slice(0, count);
301
+ }
302
+ }
303
+ else {
304
+ const count = filter?.limit ?? -1;
305
+ const allIDs = await redis.zRange(this.indexKey(), 0, -1);
306
+ if (filter?.updatedBefore) {
307
+ const maxScore = filter.updatedBefore.getTime();
308
+ const filteredIDs = [];
309
+ for (const entryID of allIDs) {
310
+ const score = await redis.zScore(this.indexKey(), entryID);
311
+ if (score !== null && score < maxScore) {
312
+ filteredIDs.push(entryID);
313
+ }
314
+ }
315
+ entryIDs = filteredIDs;
316
+ }
317
+ else {
318
+ entryIDs = allIDs;
319
+ }
320
+ if (count !== -1) {
321
+ entryIDs = entryIDs.slice(0, count);
322
+ }
323
+ }
324
+ const entries = [];
325
+ for (const entryIDStr of entryIDs) {
326
+ const entryID = ConvertStringToRequestID(entryIDStr);
327
+ const entry = await this.get(entryID);
328
+ if (entry) {
329
+ if (filter?.status && entry.status !== filter.status) {
330
+ continue;
331
+ }
332
+ entries.push(entry);
333
+ }
334
+ }
335
+ logger?.debug(`Queried queue with id ${this.id} with filter:`, filter, '-- found', entries.length, 'entries');
336
+ return (entries);
337
+ }
338
+ async partition(path) {
339
+ this.methodLogger('partition')?.debug(`Creating partitioned queue storage driver for path: ${path}`);
340
+ if (this.redisInternal === null) {
341
+ throw (new Error('Asked to partition but the instance has been destroyed'));
342
+ }
343
+ const retval = new KeetaAnchorQueueStorageDriverRedis({
344
+ id: `${this.id}::${path}`,
345
+ logger: this.logger,
346
+ redis: this.redisInternal,
347
+ path: [...this.path, path]
348
+ });
349
+ return (retval);
350
+ }
351
+ async destroy() {
352
+ this.methodLogger('destroy')?.debug('Destroying instance');
353
+ this.redisInternal = null;
354
+ }
355
+ async [Symbol.asyncDispose]() {
356
+ return (await this.destroy());
357
+ }
358
+ }
359
+ //# sourceMappingURL=queue_redis.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue_redis.js","sourceRoot":"","sources":["../../../../src/lib/queue/drivers/queue_redis.ts"],"names":[],"mappings":"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","sourcesContent":["import type {\n\tKeetaAnchorQueueStorageDriver,\n\tKeetaAnchorQueueStorageDriverConstructor,\n\tKeetaAnchorQueueRequest,\n\tKeetaAnchorQueueRequestID,\n\tKeetaAnchorQueueEntry,\n\tKeetaAnchorQueueEntryExtra,\n\tKeetaAnchorQueueEntryAncillaryData,\n\tKeetaAnchorQueueStatus,\n\tKeetaAnchorQueueFilter,\n\tKeetaAnchorQueueWorkerID\n} from '../index.ts';\nimport {\n\tMethodLogger,\n\tManageStatusUpdates,\n\tConvertStringToRequestID\n} from '../internal.js';\nimport { Errors } from '../common.js';\n\nimport type { Logger } from '../../log/index.ts';\nimport type { JSONSerializable } from '../../utils/json.js';\n\nimport type { RedisClientType } from 'redis';\n\ntype QueueEntryData = {\n\tid: string;\n\trequest: string;\n\toutput: string | null;\n\tlastError: string | null;\n\tstatus: KeetaAnchorQueueStatus;\n\tcreated: number;\n\tupdated: number;\n\tworker: number | null;\n\tfailures: number;\n\tidempotentKeys?: string[];\n};\n\nexport default class KeetaAnchorQueueStorageDriverRedis<QueueRequest extends JSONSerializable = JSONSerializable, QueueResult extends JSONSerializable = JSONSerializable> implements KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult> {\n\tprivate readonly logger: Logger | undefined;\n\tprivate redisInternal: (() => Promise<RedisClientType>) | null = null;\n\n\treadonly name = 'KeetaAnchorQueueStorageDriverRedis';\n\treadonly id: string;\n\treadonly path: string[] = [];\n\tprivate readonly pathStr: string;\n\n\tconstructor(options: NonNullable<ConstructorParameters<KeetaAnchorQueueStorageDriverConstructor<QueueRequest, QueueResult>>[0]> & { redis: () => Promise<RedisClientType>; }) {\n\t\tthis.id = options?.id ?? crypto.randomUUID();\n\t\tthis.logger = options?.logger\n\t\tthis.redisInternal = options.redis;\n\t\tthis.path = options.path ?? [];\n\t\tthis.pathStr = ['root', ...this.path].join('.');\n\t\tObject.freeze(this.path);\n\n\t\tthis.methodLogger('new')?.debug('Initialized Redis queue storage driver');\n\t}\n\n\tprivate methodLogger(method: string): Logger | undefined {\n\t\treturn(MethodLogger(this.logger, {\n\t\t\tclass: 'KeetaAnchorQueueStorageDriverRedis',\n\t\t\tfile: 'src/lib/queue/drivers/queue_redis.ts',\n\t\t\tmethod: method,\n\t\t\tinstanceID: this.id\n\t\t}));\n\t}\n\n\tprivate async getRedis(): Promise<RedisClientType> {\n\t\tif (this.redisInternal === null) {\n\t\t\tthrow(new Error('Redis connection is not available'));\n\t\t}\n\t\treturn(await this.redisInternal());\n\t}\n\n\tprivate queueKey(id: KeetaAnchorQueueRequestID): string {\n\t\treturn(`queue:${this.pathStr}:entry:${String(id)}`);\n\t}\n\n\tprivate idempotentKey(idempotentID: KeetaAnchorQueueRequestID): string {\n\t\treturn(`queue:${this.pathStr}:idempotent:${String(idempotentID)}`);\n\t}\n\n\tprivate indexKey(status?: KeetaAnchorQueueStatus): string {\n\t\tif (status) {\n\t\t\treturn(`queue:${this.pathStr}:index:${status}`);\n\t\t}\n\t\treturn(`queue:${this.pathStr}:index:all`);\n\t}\n\n\tasync add(request: KeetaAnchorQueueRequest<QueueRequest>, info?: KeetaAnchorQueueEntryExtra): Promise<KeetaAnchorQueueRequestID> {\n\t\tconst redis = await this.getRedis();\n\t\tconst logger = this.methodLogger('add');\n\n\t\tlet entryID = ConvertStringToRequestID(info?.id);\n\t\tif (entryID) {\n\t\t\tconst exists = await redis.exists(this.queueKey(entryID));\n\t\t\tif (exists) {\n\t\t\t\tlogger?.debug(`Request with id ${String(entryID)} already exists, ignoring`);\n\t\t\t\treturn(entryID);\n\t\t\t}\n\t\t}\n\n\t\tconst idempotentIDs = info?.idempotentKeys;\n\t\tif (idempotentIDs) {\n\t\t\tconst matchingIdempotentEntries = new Set<KeetaAnchorQueueRequestID>();\n\t\t\tfor (const idempotentID of idempotentIDs) {\n\t\t\t\tconst existingEntryID = await redis.get(this.idempotentKey(idempotentID));\n\t\t\t\tif (existingEntryID) {\n\t\t\t\t\tmatchingIdempotentEntries.add(idempotentID);\n\t\t\t\t}\n\t\t\t}\n\n\t\t\tif (matchingIdempotentEntries.size !== 0) {\n\t\t\t\tthrow(new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', matchingIdempotentEntries));\n\t\t\t}\n\t\t}\n\n\t\tentryID ??= ConvertStringToRequestID(crypto.randomUUID());\n\n\t\tlogger?.debug(`Enqueuing request with id ${String(entryID)}`);\n\n\t\tconst currentTime = Date.now();\n\t\tconst requestJSON = JSON.stringify(request);\n\n\t\t/**\n\t\t * The status to use for the new entry\n\t\t */\n\t\tconst status = info?.status ?? 'pending';\n\n\t\tconst entryData: QueueEntryData = {\n\t\t\tid: String(entryID),\n\t\t\trequest: requestJSON,\n\t\t\toutput: null,\n\t\t\tlastError: null,\n\t\t\tstatus: status,\n\t\t\tcreated: currentTime,\n\t\t\tupdated: currentTime,\n\t\t\tworker: null,\n\t\t\tfailures: 0\n\t\t};\n\n\t\tif (idempotentIDs && idempotentIDs.size > 0) {\n\t\t\tentryData.idempotentKeys = Array.from(idempotentIDs).map(String);\n\t\t}\n\n\t\tif (idempotentIDs && idempotentIDs.size > 0) {\n\t\t\tconst idempotentKeysArr = Array.from(idempotentIDs).map(String);\n\t\t\tconst luaScript = `\n\t\t\t\tlocal entryKey = KEYS[1]\n\t\t\t\tlocal statusIndexKey = KEYS[2]\n\t\t\t\tlocal allIndexKey = KEYS[3]\n\t\t\t\t\n\t\t\t\tlocal entryData = ARGV[1]\n\t\t\t\tlocal score = ARGV[2]\n\t\t\t\tlocal entryId = ARGV[3]\n\t\t\t\tlocal numIdempotentKeys = tonumber(ARGV[4])\n\t\t\t\t\n\t\t\t\t-- Check if any idempotent keys already exist\n\t\t\t\tfor i = 1, numIdempotentKeys do\n\t\t\t\t\tlocal idempotentKey = ARGV[4 + i]\n\t\t\t\t\tif redis.call('EXISTS', idempotentKey) == 1 then\n\t\t\t\t\t\treturn redis.error_reply('IDEMPOTENT_EXISTS')\n\t\t\t\t\tend\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\t-- Add the entry\n\t\t\t\tredis.call('SET', entryKey, entryData)\n\t\t\t\tredis.call('ZADD', statusIndexKey, score, entryId)\n\t\t\t\tredis.call('ZADD', allIndexKey, score, entryId)\n\t\t\t\t\n\t\t\t\t-- Set idempotent keys\n\t\t\t\tfor i = 1, numIdempotentKeys do\n\t\t\t\t\tlocal idempotentKey = ARGV[4 + i]\n\t\t\t\t\tredis.call('SET', idempotentKey, entryId)\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\treturn 'OK'\n\t\t\t`;\n\n\t\t\tconst idempotentKeyPairs = idempotentKeysArr.map((idKey) => {\n\t\t\t\treturn(this.idempotentKey(ConvertStringToRequestID(idKey)));\n\t\t\t});\n\n\t\t\ttry {\n\t\t\t\tawait redis.eval(luaScript, {\n\t\t\t\t\tkeys: [\n\t\t\t\t\t\tthis.queueKey(entryID),\n\t\t\t\t\t\tthis.indexKey(status),\n\t\t\t\t\t\tthis.indexKey()\n\t\t\t\t\t],\n\t\t\t\t\targuments: [\n\t\t\t\t\t\tJSON.stringify(entryData),\n\t\t\t\t\t\tString(currentTime),\n\t\t\t\t\t\tString(entryID),\n\t\t\t\t\t\tString(idempotentKeysArr.length),\n\t\t\t\t\t\t...idempotentKeyPairs\n\t\t\t\t\t]\n\t\t\t\t});\n\t\t\t} catch (error: unknown) {\n\t\t\t\tif (error instanceof Error && error.message.includes('IDEMPOTENT_EXISTS')) {\n\t\t\t\t\tthrow(new Errors.IdempotentExistsError('One or more idempotent entries already exist in the queue', idempotentIDs));\n\t\t\t\t}\n\t\t\t\tthrow(error);\n\t\t\t}\n\t\t} else {\n\t\t\tconst multi = redis.multi();\n\t\t\tmulti.set(this.queueKey(entryID), JSON.stringify(entryData));\n\t\t\tmulti.zAdd(this.indexKey(status), { score: currentTime, value: String(entryID) });\n\t\t\tmulti.zAdd(this.indexKey(), { score: currentTime, value: String(entryID) });\n\n\t\t\tawait multi.exec();\n\t\t}\n\n\t\treturn(entryID);\n\t}\n\n\tasync setStatus(id: KeetaAnchorQueueRequestID, status: KeetaAnchorQueueStatus, ancillary?: KeetaAnchorQueueEntryAncillaryData<QueueResult>): Promise<void> {\n\t\tconst { oldStatus } = ancillary ?? {};\n\t\tconst redis = await this.getRedis();\n\t\tconst logger = this.methodLogger('setStatus');\n\n\t\tconst entryJSON = await redis.get(this.queueKey(id));\n\t\tif (!entryJSON) {\n\t\t\tthrow(new Error(`Request with ID ${String(id)} not found`));\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tconst existingEntry = JSON.parse(entryJSON) as QueueEntryData;\n\n\t\tif (oldStatus && existingEntry.status !== oldStatus) {\n\t\t\tthrow(new Errors.IncorrectStateAssertedError(id, oldStatus, existingEntry.status));\n\t\t}\n\n\t\tconst newEntryRaw = ManageStatusUpdates<QueueResult>(id, existingEntry, status, ancillary, logger);\n\t\tconst newEntry: Partial<QueueEntryData> = {\n\t\t\tstatus: newEntryRaw.status,\n\t\t\tworker: newEntryRaw.worker,\n\t\t\tfailures: newEntryRaw.failures ?? existingEntry.failures,\n\t\t\tupdated: newEntryRaw.updated.getTime(),\n\t\t\tlastError: newEntryRaw.lastError !== undefined ? newEntryRaw.lastError : existingEntry.lastError,\n\t\t\toutput: newEntryRaw.output !== undefined ? newEntryRaw.output ? JSON.stringify(newEntryRaw.output) : null : existingEntry.output\n\t\t};\n\n\t\tconst updatedEntry: QueueEntryData = {\n\t\t\t...existingEntry,\n\t\t\t...newEntry\n\t\t};\n\n\t\tconst currentTime = updatedEntry.updated;\n\n\t\tif (oldStatus) {\n\t\t\tconst luaScript = `\n\t\t\t\tlocal key = KEYS[1]\n\t\t\t\tlocal expectedStatus = ARGV[1]\n\t\t\t\tlocal newData = ARGV[2]\n\t\t\t\tlocal oldIndexKey = ARGV[3]\n\t\t\t\tlocal newIndexKey = ARGV[4]\n\t\t\t\tlocal allIndexKey = ARGV[5]\n\t\t\t\tlocal entryId = ARGV[6]\n\t\t\t\tlocal score = ARGV[7]\n\t\t\t\t\n\t\t\t\tlocal current = redis.call('GET', key)\n\t\t\t\tif not current then\n\t\t\t\t\treturn {err = 'NOT_FOUND'}\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\tlocal currentData = cjson.decode(current)\n\t\t\t\tif currentData.status ~= expectedStatus then\n\t\t\t\t\treturn {err = 'STATUS_MISMATCH'}\n\t\t\t\tend\n\t\t\t\t\n\t\t\t\tredis.call('SET', key, newData)\n\t\t\t\tif oldIndexKey ~= newIndexKey then\n\t\t\t\t\tredis.call('ZREM', oldIndexKey, entryId)\n\t\t\t\tend\n\t\t\t\tredis.call('ZADD', newIndexKey, score, entryId)\n\t\t\t\tredis.call('ZADD', allIndexKey, score, entryId)\n\t\t\t\t\n\t\t\t\treturn {ok = 'OK'}\n\t\t\t`;\n\n\t\t\tconst result = await redis.eval(luaScript, {\n\t\t\t\tkeys: [this.queueKey(id)],\n\t\t\t\targuments: [\n\t\t\t\t\toldStatus,\n\t\t\t\t\tJSON.stringify(updatedEntry),\n\t\t\t\t\tthis.indexKey(oldStatus),\n\t\t\t\t\tthis.indexKey(status),\n\t\t\t\t\tthis.indexKey(),\n\t\t\t\t\tString(id),\n\t\t\t\t\tString(currentTime)\n\t\t\t\t]\n\t\t\t});\n\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tconst resultObj = result as { err?: string; ok?: string };\n\t\t\tif (resultObj.err === 'NOT_FOUND') {\n\t\t\t\tthrow(new Error(`Request with ID ${String(id)} not found`));\n\t\t\t}\n\t\t\tif (resultObj.err === 'STATUS_MISMATCH') {\n\t\t\t\tthrow(new Errors.IncorrectStateAssertedError(id, oldStatus, existingEntry.status));\n\t\t\t}\n\t\t} else {\n\t\t\tconst multi = redis.multi();\n\t\t\tmulti.set(this.queueKey(id), JSON.stringify(updatedEntry));\n\n\t\t\tif (existingEntry.status !== status) {\n\t\t\t\tmulti.zRem(this.indexKey(existingEntry.status), String(id));\n\t\t\t}\n\t\t\tmulti.zAdd(this.indexKey(status), { score: currentTime, value: String(id) });\n\t\t\tmulti.zAdd(this.indexKey(), { score: currentTime, value: String(id) });\n\n\t\t\tawait multi.exec();\n\t\t}\n\t}\n\n\tasync get(id: KeetaAnchorQueueRequestID): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult> | null> {\n\t\tconst redis = await this.getRedis();\n\n\t\tconst entryJSON = await redis.get(this.queueKey(id));\n\t\tif (!entryJSON) {\n\t\t\treturn(null);\n\t\t}\n\n\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\tconst entryData = JSON.parse(entryJSON) as QueueEntryData;\n\n\t\tconst idempotentKeys = entryData.idempotentKeys && entryData.idempotentKeys.length > 0\n\t\t\t? new Set(entryData.idempotentKeys.map(function(key: string) {\n\t\t\t\treturn(ConvertStringToRequestID(key));\n\t\t\t}))\n\t\t\t: undefined;\n\n\t\treturn({\n\t\t\tid: ConvertStringToRequestID(entryData.id),\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\trequest: JSON.parse(entryData.request) as QueueRequest,\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\toutput: entryData.output ? JSON.parse(entryData.output) as QueueResult : null,\n\t\t\tlastError: entryData.lastError,\n\t\t\tstatus: entryData.status,\n\t\t\tcreated: new Date(entryData.created),\n\t\t\tupdated: new Date(entryData.updated),\n\t\t\t// eslint-disable-next-line @typescript-eslint/consistent-type-assertions\n\t\t\tworker: entryData.worker as unknown as KeetaAnchorQueueWorkerID | null,\n\t\t\tfailures: entryData.failures,\n\t\t\tidempotentKeys: idempotentKeys\n\t\t});\n\t}\n\n\tasync query(filter?: KeetaAnchorQueueFilter): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult>[]> {\n\t\tconst redis = await this.getRedis();\n\t\tconst logger = this.methodLogger('query');\n\n\t\tlogger?.debug(`Querying queue with id ${this.id} with filter:`, filter);\n\n\t\tlet entryIDs: string[];\n\n\t\tif (filter?.status) {\n\t\t\tconst count = filter.limit ?? -1;\n\t\t\tconst allIDs = await redis.zRange(this.indexKey(filter.status), 0, -1);\n\n\t\t\tif (filter.updatedBefore) {\n\t\t\t\tconst maxScore = filter.updatedBefore.getTime();\n\t\t\t\tconst filteredIDs: string[] = [];\n\t\t\t\tfor (const entryID of allIDs) {\n\t\t\t\t\tconst score = await redis.zScore(this.indexKey(filter.status), entryID);\n\t\t\t\t\tif (score !== null && score < maxScore) {\n\t\t\t\t\t\tfilteredIDs.push(entryID);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tentryIDs = filteredIDs;\n\t\t\t} else {\n\t\t\t\tentryIDs = allIDs;\n\t\t\t}\n\n\t\t\tif (count !== -1) {\n\t\t\t\tentryIDs = entryIDs.slice(0, count);\n\t\t\t}\n\t\t} else {\n\t\t\tconst count = filter?.limit ?? -1;\n\t\t\tconst allIDs = await redis.zRange(this.indexKey(), 0, -1);\n\n\t\t\tif (filter?.updatedBefore) {\n\t\t\t\tconst maxScore = filter.updatedBefore.getTime();\n\t\t\t\tconst filteredIDs: string[] = [];\n\t\t\t\tfor (const entryID of allIDs) {\n\t\t\t\t\tconst score = await redis.zScore(this.indexKey(), entryID);\n\t\t\t\t\tif (score !== null && score < maxScore) {\n\t\t\t\t\t\tfilteredIDs.push(entryID);\n\t\t\t\t\t}\n\t\t\t\t}\n\t\t\t\tentryIDs = filteredIDs;\n\t\t\t} else {\n\t\t\t\tentryIDs = allIDs;\n\t\t\t}\n\n\t\t\tif (count !== -1) {\n\t\t\t\tentryIDs = entryIDs.slice(0, count);\n\t\t\t}\n\t\t}\n\n\t\tconst entries: KeetaAnchorQueueEntry<QueueRequest, QueueResult>[] = [];\n\n\t\tfor (const entryIDStr of entryIDs) {\n\t\t\tconst entryID = ConvertStringToRequestID(entryIDStr);\n\t\t\tconst entry = await this.get(entryID);\n\t\t\tif (entry) {\n\t\t\t\tif (filter?.status && entry.status !== filter.status) {\n\t\t\t\t\tcontinue;\n\t\t\t\t}\n\t\t\t\tentries.push(entry);\n\t\t\t}\n\t\t}\n\n\t\tlogger?.debug(`Queried queue with id ${this.id} with filter:`, filter, '-- found', entries.length, 'entries');\n\n\t\treturn(entries);\n\t}\n\n\tasync partition(path: string): Promise<KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult>> {\n\t\tthis.methodLogger('partition')?.debug(`Creating partitioned queue storage driver for path: ${path}`);\n\n\t\tif (this.redisInternal === null) {\n\t\t\tthrow(new Error('Asked to partition but the instance has been destroyed'));\n\t\t}\n\n\t\tconst retval = new KeetaAnchorQueueStorageDriverRedis<QueueRequest, QueueResult>({\n\t\t\tid: `${this.id}::${path}`,\n\t\t\tlogger: this.logger,\n\t\t\tredis: this.redisInternal,\n\t\t\tpath: [...this.path, path]\n\t\t});\n\n\t\treturn(retval);\n\t}\n\n\tasync destroy(): Promise<void> {\n\t\tthis.methodLogger('destroy')?.debug('Destroying instance');\n\n\t\tthis.redisInternal = null;\n\t}\n\n\tasync [Symbol.asyncDispose](): Promise<void> {\n\t\treturn(await this.destroy());\n\t}\n}\n"]}
@@ -0,0 +1,28 @@
1
+ import type { KeetaAnchorQueueStorageDriver, KeetaAnchorQueueStorageDriverConstructor, KeetaAnchorQueueRequest, KeetaAnchorQueueRequestID, KeetaAnchorQueueEntry, KeetaAnchorQueueEntryExtra, KeetaAnchorQueueEntryAncillaryData, KeetaAnchorQueueStatus, KeetaAnchorQueueFilter } from '../index.ts';
2
+ import type { JSONSerializable } from '../../utils/json.js';
3
+ import type * as sqlite from 'sqlite';
4
+ export default class KeetaAnchorQueueStorageDriverSQLite3<QueueRequest extends JSONSerializable = JSONSerializable, QueueResult extends JSONSerializable = JSONSerializable> implements KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult> {
5
+ private readonly logger;
6
+ private dbInternal;
7
+ private dbInitializationPromise?;
8
+ readonly name = "KeetaAnchorQueueStorageDriverSQLite3";
9
+ readonly id: string;
10
+ readonly path: string[];
11
+ private readonly pathStr;
12
+ constructor(options: NonNullable<ConstructorParameters<KeetaAnchorQueueStorageDriverConstructor<QueueRequest, QueueResult>>[0]> & {
13
+ db: () => Promise<sqlite.Database>;
14
+ });
15
+ private initializeDBConnection;
16
+ private methodLogger;
17
+ private runWithBusyHandler;
18
+ private newDBConnection;
19
+ private dbTransaction;
20
+ add(request: KeetaAnchorQueueRequest<QueueRequest>, info?: KeetaAnchorQueueEntryExtra): Promise<KeetaAnchorQueueRequestID>;
21
+ setStatus(id: KeetaAnchorQueueRequestID, status: KeetaAnchorQueueStatus, ancillary?: KeetaAnchorQueueEntryAncillaryData<QueueResult>): Promise<void>;
22
+ get(id: KeetaAnchorQueueRequestID): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult> | null>;
23
+ query(filter?: KeetaAnchorQueueFilter): Promise<KeetaAnchorQueueEntry<QueueRequest, QueueResult>[]>;
24
+ partition(path: string): Promise<KeetaAnchorQueueStorageDriver<QueueRequest, QueueResult>>;
25
+ destroy(): Promise<void>;
26
+ [Symbol.asyncDispose](): Promise<void>;
27
+ }
28
+ //# sourceMappingURL=queue_sqlite3.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"queue_sqlite3.d.ts","sourceRoot":"","sources":["../../../../src/lib/queue/drivers/queue_sqlite3.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EACX,6BAA6B,EAC7B,wCAAwC,EACxC,uBAAuB,EACvB,yBAAyB,EACzB,qBAAqB,EACrB,0BAA0B,EAC1B,kCAAkC,EAClC,sBAAsB,EACtB,sBAAsB,EAEtB,MAAM,aAAa,CAAC;AAWrB,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,KAAK,KAAK,MAAM,MAAM,QAAQ,CAAC;AAkBtC,MAAM,CAAC,OAAO,OAAO,oCAAoC,CAAC,YAAY,SAAS,gBAAgB,GAAG,gBAAgB,EAAE,WAAW,SAAS,gBAAgB,GAAG,gBAAgB,CAAE,YAAW,6BAA6B,CAAC,YAAY,EAAE,WAAW,CAAC;IAC/O,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAqB;IAC5C,OAAO,CAAC,UAAU,CAAiD;IACnE,OAAO,CAAC,uBAAuB,CAAC,CAAmB;IAEnD,QAAQ,CAAC,IAAI,0CAA0C;IACvD,QAAQ,CAAC,EAAE,EAAE,MAAM,CAAC;IACpB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,CAAM;IAC7B,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAS;gBAErB,OAAO,EAAE,WAAW,CAAC,qBAAqB,CAAC,wCAAwC,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG;QAAE,EAAE,EAAE,MAAM,OAAO,CAAC,MAAM,CAAC,QAAQ,CAAC,CAAC;KAAE;YAW3J,sBAAsB;IAqDpC,OAAO,CAAC,YAAY;YASN,kBAAkB;IA8ChC,OAAO,CAAC,eAAe;YAyBT,aAAa;IAkCrB,GAAG,CAAC,OAAO,EAAE,uBAAuB,CAAC,YAAY,CAAC,EAAE,IAAI,CAAC,EAAE,0BAA0B,GAAG,OAAO,CAAC,yBAAyB,CAAC;IAqE1H,SAAS,CAAC,EAAE,EAAE,yBAAyB,EAAE,MAAM,EAAE,sBAAsB,EAAE,SAAS,CAAC,EAAE,kCAAkC,CAAC,WAAW,CAAC,GAAG,OAAO,CAAC,IAAI,CAAC;IAwDpJ,GAAG,CAAC,EAAE,EAAE,yBAAyB,GAAG,OAAO,CAAC,qBAAqB,CAAC,YAAY,EAAE,WAAW,CAAC,GAAG,IAAI,CAAC;IAyCpG,KAAK,CAAC,MAAM,CAAC,EAAE,sBAAsB,GAAG,OAAO,CAAC,qBAAqB,CAAC,YAAY,EAAE,WAAW,CAAC,EAAE,CAAC;IAsEnG,SAAS,CAAC,IAAI,EAAE,MAAM,GAAI,OAAO,CAAC,6BAA6B,CAAC,YAAY,EAAE,WAAW,CAAC,CAAC;IAiB3F,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC;IAMxB,CAAC,MAAM,CAAC,YAAY,CAAC,IAAI,OAAO,CAAC,IAAI,CAAC;CAG5C"}