@http-client-toolkit/store-dynamodb 0.0.1 → 0.4.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/lib/index.cjs +518 -392
- package/lib/index.d.cts +195 -139
- package/lib/index.d.ts +195 -139
- package/lib/index.js +542 -395
- package/package.json +4 -4
package/lib/index.cjs
CHANGED
|
@@ -12,15 +12,21 @@ var __getOwnPropSymbols = Object.getOwnPropertySymbols;
|
|
|
12
12
|
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
13
13
|
var __propIsEnum = Object.prototype.propertyIsEnumerable;
|
|
14
14
|
var __pow = Math.pow;
|
|
15
|
-
var __defNormalProp = (obj, key, value) =>
|
|
15
|
+
var __defNormalProp = (obj, key, value) =>
|
|
16
|
+
key in obj
|
|
17
|
+
? __defProp(obj, key, {
|
|
18
|
+
enumerable: true,
|
|
19
|
+
configurable: true,
|
|
20
|
+
writable: true,
|
|
21
|
+
value,
|
|
22
|
+
})
|
|
23
|
+
: (obj[key] = value);
|
|
16
24
|
var __spreadValues = (a, b) => {
|
|
17
25
|
for (var prop in b || (b = {}))
|
|
18
|
-
if (__hasOwnProp.call(b, prop))
|
|
19
|
-
__defNormalProp(a, prop, b[prop]);
|
|
26
|
+
if (__hasOwnProp.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
20
27
|
if (__getOwnPropSymbols)
|
|
21
28
|
for (var prop of __getOwnPropSymbols(b)) {
|
|
22
|
-
if (__propIsEnum.call(b, prop))
|
|
23
|
-
__defNormalProp(a, prop, b[prop]);
|
|
29
|
+
if (__propIsEnum.call(b, prop)) __defNormalProp(a, prop, b[prop]);
|
|
24
30
|
}
|
|
25
31
|
return a;
|
|
26
32
|
};
|
|
@@ -41,7 +47,10 @@ var __async = (__this, __arguments, generator) => {
|
|
|
41
47
|
reject(e);
|
|
42
48
|
}
|
|
43
49
|
};
|
|
44
|
-
var step = (x) =>
|
|
50
|
+
var step = (x) =>
|
|
51
|
+
x.done
|
|
52
|
+
? resolve(x.value)
|
|
53
|
+
: Promise.resolve(x.value).then(fulfilled, rejected);
|
|
45
54
|
step((generator = generator.apply(__this, __arguments)).next());
|
|
46
55
|
});
|
|
47
56
|
};
|
|
@@ -65,23 +74,32 @@ function batchDeleteWithRetries(docClient, tableName, keys) {
|
|
|
65
74
|
const response = yield docClient.send(
|
|
66
75
|
new libDynamodb.BatchWriteCommand({
|
|
67
76
|
RequestItems: {
|
|
68
|
-
[tableName]: pendingWrites
|
|
69
|
-
}
|
|
70
|
-
})
|
|
77
|
+
[tableName]: pendingWrites,
|
|
78
|
+
},
|
|
79
|
+
}),
|
|
71
80
|
);
|
|
72
|
-
const unprocessed =
|
|
81
|
+
const unprocessed =
|
|
82
|
+
(_b =
|
|
83
|
+
(_a = response.UnprocessedItems) == null
|
|
84
|
+
? void 0
|
|
85
|
+
: _a[tableName]) != null
|
|
86
|
+
? _b
|
|
87
|
+
: [];
|
|
73
88
|
if (unprocessed.length === 0) {
|
|
74
89
|
break;
|
|
75
90
|
}
|
|
76
91
|
if (attempt >= MAX_BATCH_WRITE_RETRIES) {
|
|
77
92
|
throw new Error(
|
|
78
|
-
`Failed to delete all items from table "${tableName}" after ${MAX_BATCH_WRITE_RETRIES + 1} attempts
|
|
93
|
+
`Failed to delete all items from table "${tableName}" after ${MAX_BATCH_WRITE_RETRIES + 1} attempts`,
|
|
79
94
|
);
|
|
80
95
|
}
|
|
81
|
-
pendingWrites = unprocessed
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
96
|
+
pendingWrites = unprocessed
|
|
97
|
+
.map((request) => {
|
|
98
|
+
var _a2;
|
|
99
|
+
return (_a2 = request.DeleteRequest) == null ? void 0 : _a2.Key;
|
|
100
|
+
})
|
|
101
|
+
.filter((key) => Boolean(key))
|
|
102
|
+
.map((key) => ({ DeleteRequest: { Key: key } }));
|
|
85
103
|
yield sleep(getRetryDelayMs(attempt));
|
|
86
104
|
}
|
|
87
105
|
}
|
|
@@ -94,9 +112,11 @@ function queryCountAllPages(docClient, input) {
|
|
|
94
112
|
let lastEvaluatedKey;
|
|
95
113
|
do {
|
|
96
114
|
const result = yield docClient.send(
|
|
97
|
-
new libDynamodb.QueryCommand(
|
|
98
|
-
|
|
99
|
-
|
|
115
|
+
new libDynamodb.QueryCommand(
|
|
116
|
+
__spreadProps(__spreadValues({}, input), {
|
|
117
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
118
|
+
}),
|
|
119
|
+
),
|
|
100
120
|
);
|
|
101
121
|
total += (_a = result.Count) != null ? _a : 0;
|
|
102
122
|
lastEvaluatedKey = result.LastEvaluatedKey;
|
|
@@ -111,9 +131,11 @@ function queryItemsAllPages(docClient, input) {
|
|
|
111
131
|
let lastEvaluatedKey;
|
|
112
132
|
do {
|
|
113
133
|
const result = yield docClient.send(
|
|
114
|
-
new libDynamodb.QueryCommand(
|
|
115
|
-
|
|
116
|
-
|
|
134
|
+
new libDynamodb.QueryCommand(
|
|
135
|
+
__spreadProps(__spreadValues({}, input), {
|
|
136
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
137
|
+
}),
|
|
138
|
+
),
|
|
117
139
|
);
|
|
118
140
|
if ((_a = result.Items) == null ? void 0 : _a.length) {
|
|
119
141
|
items.push(...result.Items);
|
|
@@ -134,11 +156,13 @@ function queryCountUpTo(docClient, input, maxCount) {
|
|
|
134
156
|
do {
|
|
135
157
|
const remaining = maxCount - total;
|
|
136
158
|
const result = yield docClient.send(
|
|
137
|
-
new libDynamodb.QueryCommand(
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
159
|
+
new libDynamodb.QueryCommand(
|
|
160
|
+
__spreadProps(__spreadValues({}, input), {
|
|
161
|
+
Select: 'COUNT',
|
|
162
|
+
Limit: remaining,
|
|
163
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
164
|
+
}),
|
|
165
|
+
),
|
|
142
166
|
);
|
|
143
167
|
total += (_a = result.Count) != null ? _a : 0;
|
|
144
168
|
if (total >= maxCount) {
|
|
@@ -151,25 +175,35 @@ function queryCountUpTo(docClient, input, maxCount) {
|
|
|
151
175
|
}
|
|
152
176
|
function isConditionalTransactionFailure(error) {
|
|
153
177
|
var _a;
|
|
154
|
-
if (!error || typeof error !==
|
|
178
|
+
if (!error || typeof error !== 'object') {
|
|
155
179
|
return false;
|
|
156
180
|
}
|
|
157
181
|
const maybeError = error;
|
|
158
|
-
if (maybeError.name !==
|
|
182
|
+
if (maybeError.name !== 'TransactionCanceledException') {
|
|
159
183
|
return false;
|
|
160
184
|
}
|
|
161
|
-
const cancellationReasons =
|
|
185
|
+
const cancellationReasons =
|
|
186
|
+
(_a = maybeError.CancellationReasons) != null
|
|
187
|
+
? _a
|
|
188
|
+
: maybeError.cancellationReasons;
|
|
162
189
|
if (Array.isArray(cancellationReasons)) {
|
|
163
190
|
return cancellationReasons.some((reason) => {
|
|
164
|
-
if (!reason || typeof reason !==
|
|
191
|
+
if (!reason || typeof reason !== 'object') {
|
|
165
192
|
return false;
|
|
166
193
|
}
|
|
167
|
-
return
|
|
194
|
+
return 'Code' in reason && reason.Code === 'ConditionalCheckFailed';
|
|
168
195
|
});
|
|
169
196
|
}
|
|
170
|
-
return
|
|
197
|
+
return (
|
|
198
|
+
typeof maybeError.message === 'string' &&
|
|
199
|
+
maybeError.message.includes('ConditionalCheckFailed')
|
|
200
|
+
);
|
|
171
201
|
}
|
|
172
|
-
function assertDynamoKeyPart(
|
|
202
|
+
function assertDynamoKeyPart(
|
|
203
|
+
value,
|
|
204
|
+
label,
|
|
205
|
+
maxBytes = MAX_DYNAMO_KEY_PART_BYTES,
|
|
206
|
+
) {
|
|
173
207
|
if (value.length === 0) {
|
|
174
208
|
throw new Error(`${label} must not be empty`);
|
|
175
209
|
}
|
|
@@ -179,41 +213,47 @@ function assertDynamoKeyPart(value, label, maxBytes = MAX_DYNAMO_KEY_PART_BYTES)
|
|
|
179
213
|
throw new Error(`${label} contains unsupported control characters`);
|
|
180
214
|
}
|
|
181
215
|
}
|
|
182
|
-
if (Buffer.byteLength(value,
|
|
216
|
+
if (Buffer.byteLength(value, 'utf8') > maxBytes) {
|
|
183
217
|
throw new Error(`${label} exceeds maximum length of ${maxBytes} bytes`);
|
|
184
218
|
}
|
|
185
219
|
}
|
|
186
220
|
function throwIfDynamoTableMissing(error, tableName) {
|
|
187
|
-
if (
|
|
221
|
+
if (
|
|
222
|
+
error instanceof clientDynamodb.ResourceNotFoundException ||
|
|
223
|
+
(error &&
|
|
224
|
+
typeof error === 'object' &&
|
|
225
|
+
'name' in error &&
|
|
226
|
+
error.name === 'ResourceNotFoundException')
|
|
227
|
+
) {
|
|
188
228
|
throw new Error(
|
|
189
|
-
`DynamoDB table "${tableName}" was not found. Create the table using your infrastructure before using DynamoDB stores
|
|
229
|
+
`DynamoDB table "${tableName}" was not found. Create the table using your infrastructure before using DynamoDB stores.`,
|
|
190
230
|
);
|
|
191
231
|
}
|
|
192
232
|
}
|
|
193
233
|
|
|
194
234
|
// src/table.ts
|
|
195
|
-
var DEFAULT_TABLE_NAME =
|
|
235
|
+
var DEFAULT_TABLE_NAME = 'http-client-toolkit';
|
|
196
236
|
var TABLE_SCHEMA = {
|
|
197
237
|
KeySchema: [
|
|
198
|
-
{ AttributeName:
|
|
199
|
-
{ AttributeName:
|
|
238
|
+
{ AttributeName: 'pk', KeyType: 'HASH' },
|
|
239
|
+
{ AttributeName: 'sk', KeyType: 'RANGE' },
|
|
200
240
|
],
|
|
201
241
|
AttributeDefinitions: [
|
|
202
|
-
{ AttributeName:
|
|
203
|
-
{ AttributeName:
|
|
204
|
-
{ AttributeName:
|
|
205
|
-
{ AttributeName:
|
|
242
|
+
{ AttributeName: 'pk', AttributeType: 'S' },
|
|
243
|
+
{ AttributeName: 'sk', AttributeType: 'S' },
|
|
244
|
+
{ AttributeName: 'gsi1pk', AttributeType: 'S' },
|
|
245
|
+
{ AttributeName: 'gsi1sk', AttributeType: 'S' },
|
|
206
246
|
],
|
|
207
247
|
GlobalSecondaryIndexes: [
|
|
208
248
|
{
|
|
209
|
-
IndexName:
|
|
249
|
+
IndexName: 'gsi1',
|
|
210
250
|
KeySchema: [
|
|
211
|
-
{ AttributeName:
|
|
212
|
-
{ AttributeName:
|
|
251
|
+
{ AttributeName: 'gsi1pk', KeyType: 'HASH' },
|
|
252
|
+
{ AttributeName: 'gsi1sk', KeyType: 'RANGE' },
|
|
213
253
|
],
|
|
214
|
-
Projection: { ProjectionType:
|
|
215
|
-
}
|
|
216
|
-
]
|
|
254
|
+
Projection: { ProjectionType: 'ALL' },
|
|
255
|
+
},
|
|
256
|
+
],
|
|
217
257
|
};
|
|
218
258
|
|
|
219
259
|
// src/dynamodb-cache-store.ts
|
|
@@ -222,7 +262,7 @@ var DynamoDBCacheStore = class {
|
|
|
222
262
|
client,
|
|
223
263
|
region,
|
|
224
264
|
tableName = DEFAULT_TABLE_NAME,
|
|
225
|
-
maxEntrySizeBytes = 390 * 1024
|
|
265
|
+
maxEntrySizeBytes = 390 * 1024,
|
|
226
266
|
} = {}) {
|
|
227
267
|
this.isDestroyed = false;
|
|
228
268
|
this.tableName = tableName;
|
|
@@ -244,7 +284,7 @@ var DynamoDBCacheStore = class {
|
|
|
244
284
|
get(hash) {
|
|
245
285
|
return __async(this, null, function* () {
|
|
246
286
|
if (this.isDestroyed) {
|
|
247
|
-
throw new Error(
|
|
287
|
+
throw new Error('Cache store has been destroyed');
|
|
248
288
|
}
|
|
249
289
|
this.assertValidHash(hash);
|
|
250
290
|
const pk = `CACHE#${hash}`;
|
|
@@ -253,8 +293,8 @@ var DynamoDBCacheStore = class {
|
|
|
253
293
|
result = yield this.docClient.send(
|
|
254
294
|
new libDynamodb.GetCommand({
|
|
255
295
|
TableName: this.tableName,
|
|
256
|
-
Key: { pk, sk: pk }
|
|
257
|
-
})
|
|
296
|
+
Key: { pk, sk: pk },
|
|
297
|
+
}),
|
|
258
298
|
);
|
|
259
299
|
} catch (error) {
|
|
260
300
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -264,13 +304,13 @@ var DynamoDBCacheStore = class {
|
|
|
264
304
|
return void 0;
|
|
265
305
|
}
|
|
266
306
|
const now = Math.floor(Date.now() / 1e3);
|
|
267
|
-
if (result.Item[
|
|
307
|
+
if (result.Item['ttl'] > 0 && now >= result.Item['ttl']) {
|
|
268
308
|
yield this.delete(hash);
|
|
269
309
|
return void 0;
|
|
270
310
|
}
|
|
271
311
|
try {
|
|
272
|
-
const value = result.Item[
|
|
273
|
-
if (value ===
|
|
312
|
+
const value = result.Item['value'];
|
|
313
|
+
if (value === '__UNDEFINED__') {
|
|
274
314
|
return void 0;
|
|
275
315
|
}
|
|
276
316
|
return JSON.parse(value);
|
|
@@ -283,7 +323,7 @@ var DynamoDBCacheStore = class {
|
|
|
283
323
|
set(hash, value, ttlSeconds) {
|
|
284
324
|
return __async(this, null, function* () {
|
|
285
325
|
if (this.isDestroyed) {
|
|
286
|
-
throw new Error(
|
|
326
|
+
throw new Error('Cache store has been destroyed');
|
|
287
327
|
}
|
|
288
328
|
this.assertValidHash(hash);
|
|
289
329
|
const now = Date.now();
|
|
@@ -299,16 +339,16 @@ var DynamoDBCacheStore = class {
|
|
|
299
339
|
let serializedValue;
|
|
300
340
|
try {
|
|
301
341
|
if (value === void 0) {
|
|
302
|
-
serializedValue =
|
|
342
|
+
serializedValue = '__UNDEFINED__';
|
|
303
343
|
} else {
|
|
304
344
|
serializedValue = JSON.stringify(value);
|
|
305
345
|
}
|
|
306
346
|
} catch (error) {
|
|
307
347
|
throw new Error(
|
|
308
|
-
`Failed to serialize value: ${error instanceof Error ? error.message : String(error)}
|
|
348
|
+
`Failed to serialize value: ${error instanceof Error ? error.message : String(error)}`,
|
|
309
349
|
);
|
|
310
350
|
}
|
|
311
|
-
if (Buffer.byteLength(serializedValue,
|
|
351
|
+
if (Buffer.byteLength(serializedValue, 'utf8') > this.maxEntrySizeBytes) {
|
|
312
352
|
return;
|
|
313
353
|
}
|
|
314
354
|
const pk = `CACHE#${hash}`;
|
|
@@ -321,9 +361,9 @@ var DynamoDBCacheStore = class {
|
|
|
321
361
|
sk: pk,
|
|
322
362
|
value: serializedValue,
|
|
323
363
|
ttl,
|
|
324
|
-
createdAt: now
|
|
325
|
-
}
|
|
326
|
-
})
|
|
364
|
+
createdAt: now,
|
|
365
|
+
},
|
|
366
|
+
}),
|
|
327
367
|
);
|
|
328
368
|
} catch (error) {
|
|
329
369
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -334,7 +374,7 @@ var DynamoDBCacheStore = class {
|
|
|
334
374
|
delete(hash) {
|
|
335
375
|
return __async(this, null, function* () {
|
|
336
376
|
if (this.isDestroyed) {
|
|
337
|
-
throw new Error(
|
|
377
|
+
throw new Error('Cache store has been destroyed');
|
|
338
378
|
}
|
|
339
379
|
this.assertValidHash(hash);
|
|
340
380
|
const pk = `CACHE#${hash}`;
|
|
@@ -342,8 +382,8 @@ var DynamoDBCacheStore = class {
|
|
|
342
382
|
yield this.docClient.send(
|
|
343
383
|
new libDynamodb.DeleteCommand({
|
|
344
384
|
TableName: this.tableName,
|
|
345
|
-
Key: { pk, sk: pk }
|
|
346
|
-
})
|
|
385
|
+
Key: { pk, sk: pk },
|
|
386
|
+
}),
|
|
347
387
|
);
|
|
348
388
|
} catch (error) {
|
|
349
389
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -355,7 +395,7 @@ var DynamoDBCacheStore = class {
|
|
|
355
395
|
return __async(this, null, function* () {
|
|
356
396
|
var _a;
|
|
357
397
|
if (this.isDestroyed) {
|
|
358
|
-
throw new Error(
|
|
398
|
+
throw new Error('Cache store has been destroyed');
|
|
359
399
|
}
|
|
360
400
|
let lastEvaluatedKey;
|
|
361
401
|
do {
|
|
@@ -364,11 +404,11 @@ var DynamoDBCacheStore = class {
|
|
|
364
404
|
scanResult = yield this.docClient.send(
|
|
365
405
|
new libDynamodb.ScanCommand({
|
|
366
406
|
TableName: this.tableName,
|
|
367
|
-
FilterExpression:
|
|
368
|
-
ExpressionAttributeValues: {
|
|
369
|
-
ProjectionExpression:
|
|
370
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
371
|
-
})
|
|
407
|
+
FilterExpression: 'begins_with(pk, :prefix)',
|
|
408
|
+
ExpressionAttributeValues: { ':prefix': 'CACHE#' },
|
|
409
|
+
ProjectionExpression: 'pk, sk',
|
|
410
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
411
|
+
}),
|
|
372
412
|
);
|
|
373
413
|
} catch (error) {
|
|
374
414
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -380,7 +420,7 @@ var DynamoDBCacheStore = class {
|
|
|
380
420
|
yield batchDeleteWithRetries(
|
|
381
421
|
this.docClient,
|
|
382
422
|
this.tableName,
|
|
383
|
-
items.map((item) => ({ pk: item[
|
|
423
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
384
424
|
);
|
|
385
425
|
} catch (error) {
|
|
386
426
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -403,7 +443,7 @@ var DynamoDBCacheStore = class {
|
|
|
403
443
|
this.close();
|
|
404
444
|
}
|
|
405
445
|
assertValidHash(hash) {
|
|
406
|
-
assertDynamoKeyPart(hash,
|
|
446
|
+
assertDynamoKeyPart(hash, 'hash');
|
|
407
447
|
}
|
|
408
448
|
};
|
|
409
449
|
var DynamoDBDedupeStore = class {
|
|
@@ -412,7 +452,7 @@ var DynamoDBDedupeStore = class {
|
|
|
412
452
|
region,
|
|
413
453
|
tableName = DEFAULT_TABLE_NAME,
|
|
414
454
|
jobTimeoutMs = 3e5,
|
|
415
|
-
pollIntervalMs = 500
|
|
455
|
+
pollIntervalMs = 500,
|
|
416
456
|
} = {}) {
|
|
417
457
|
this.jobPromises = /* @__PURE__ */ new Map();
|
|
418
458
|
this.jobSettlers = /* @__PURE__ */ new Map();
|
|
@@ -437,7 +477,7 @@ var DynamoDBDedupeStore = class {
|
|
|
437
477
|
waitFor(hash) {
|
|
438
478
|
return __async(this, null, function* () {
|
|
439
479
|
if (this.isDestroyed) {
|
|
440
|
-
throw new Error(
|
|
480
|
+
throw new Error('Dedupe store has been destroyed');
|
|
441
481
|
}
|
|
442
482
|
this.assertValidHash(hash);
|
|
443
483
|
const existingPromise = this.jobPromises.get(hash);
|
|
@@ -450,8 +490,8 @@ var DynamoDBDedupeStore = class {
|
|
|
450
490
|
const result = yield this.docClient.send(
|
|
451
491
|
new libDynamodb.GetCommand({
|
|
452
492
|
TableName: this.tableName,
|
|
453
|
-
Key: { pk, sk: pk }
|
|
454
|
-
})
|
|
493
|
+
Key: { pk, sk: pk },
|
|
494
|
+
}),
|
|
455
495
|
);
|
|
456
496
|
item = result.Item;
|
|
457
497
|
} catch (error) {
|
|
@@ -461,10 +501,10 @@ var DynamoDBDedupeStore = class {
|
|
|
461
501
|
if (!item) {
|
|
462
502
|
return void 0;
|
|
463
503
|
}
|
|
464
|
-
if (item[
|
|
465
|
-
return this.deserializeResult(item[
|
|
504
|
+
if (item['status'] === 'completed') {
|
|
505
|
+
return this.deserializeResult(item['result']);
|
|
466
506
|
}
|
|
467
|
-
if (item[
|
|
507
|
+
if (item['status'] === 'failed') {
|
|
468
508
|
return void 0;
|
|
469
509
|
}
|
|
470
510
|
const promise = new Promise((resolve) => {
|
|
@@ -480,58 +520,61 @@ var DynamoDBDedupeStore = class {
|
|
|
480
520
|
resolve(value);
|
|
481
521
|
};
|
|
482
522
|
this.jobSettlers.set(hash, settle);
|
|
483
|
-
const poll = () =>
|
|
484
|
-
|
|
485
|
-
|
|
486
|
-
return;
|
|
487
|
-
}
|
|
488
|
-
try {
|
|
489
|
-
const latest = yield this.docClient.send(
|
|
490
|
-
new libDynamodb.GetCommand({
|
|
491
|
-
TableName: this.tableName,
|
|
492
|
-
Key: { pk, sk: pk }
|
|
493
|
-
})
|
|
494
|
-
);
|
|
495
|
-
const latestItem = latest.Item;
|
|
496
|
-
if (!latestItem) {
|
|
523
|
+
const poll = () =>
|
|
524
|
+
__async(this, null, function* () {
|
|
525
|
+
if (this.isDestroyed) {
|
|
497
526
|
settle(void 0);
|
|
498
527
|
return;
|
|
499
528
|
}
|
|
500
|
-
|
|
501
|
-
|
|
502
|
-
|
|
503
|
-
|
|
504
|
-
|
|
505
|
-
|
|
506
|
-
|
|
507
|
-
|
|
508
|
-
|
|
509
|
-
|
|
510
|
-
|
|
511
|
-
},
|
|
512
|
-
ExpressionAttributeValues: {
|
|
513
|
-
":failed": "failed",
|
|
514
|
-
":error": "Job timed out",
|
|
515
|
-
":now": Date.now()
|
|
516
|
-
}
|
|
517
|
-
})
|
|
518
|
-
);
|
|
519
|
-
} catch (e) {
|
|
529
|
+
try {
|
|
530
|
+
const latest = yield this.docClient.send(
|
|
531
|
+
new libDynamodb.GetCommand({
|
|
532
|
+
TableName: this.tableName,
|
|
533
|
+
Key: { pk, sk: pk },
|
|
534
|
+
}),
|
|
535
|
+
);
|
|
536
|
+
const latestItem = latest.Item;
|
|
537
|
+
if (!latestItem) {
|
|
538
|
+
settle(void 0);
|
|
539
|
+
return;
|
|
520
540
|
}
|
|
521
|
-
|
|
522
|
-
|
|
523
|
-
|
|
524
|
-
|
|
525
|
-
|
|
526
|
-
|
|
527
|
-
|
|
528
|
-
|
|
541
|
+
const isExpired =
|
|
542
|
+
this.jobTimeoutMs > 0 &&
|
|
543
|
+
Date.now() - latestItem['createdAt'] >= this.jobTimeoutMs;
|
|
544
|
+
if (isExpired) {
|
|
545
|
+
try {
|
|
546
|
+
yield this.docClient.send(
|
|
547
|
+
new libDynamodb.UpdateCommand({
|
|
548
|
+
TableName: this.tableName,
|
|
549
|
+
Key: { pk, sk: pk },
|
|
550
|
+
UpdateExpression:
|
|
551
|
+
'SET #status = :failed, #error = :error, updatedAt = :now',
|
|
552
|
+
ExpressionAttributeNames: {
|
|
553
|
+
'#status': 'status',
|
|
554
|
+
'#error': 'error',
|
|
555
|
+
},
|
|
556
|
+
ExpressionAttributeValues: {
|
|
557
|
+
':failed': 'failed',
|
|
558
|
+
':error': 'Job timed out',
|
|
559
|
+
':now': Date.now(),
|
|
560
|
+
},
|
|
561
|
+
}),
|
|
562
|
+
);
|
|
563
|
+
} catch (e) {}
|
|
564
|
+
settle(void 0);
|
|
565
|
+
return;
|
|
566
|
+
}
|
|
567
|
+
if (latestItem['status'] === 'completed') {
|
|
568
|
+
settle(this.deserializeResult(latestItem['result']));
|
|
569
|
+
return;
|
|
570
|
+
}
|
|
571
|
+
if (latestItem['status'] === 'failed') {
|
|
572
|
+
settle(void 0);
|
|
573
|
+
}
|
|
574
|
+
} catch (e) {
|
|
529
575
|
settle(void 0);
|
|
530
576
|
}
|
|
531
|
-
}
|
|
532
|
-
settle(void 0);
|
|
533
|
-
}
|
|
534
|
-
});
|
|
577
|
+
});
|
|
535
578
|
let isPolling = false;
|
|
536
579
|
const pollHandle = setInterval(() => {
|
|
537
580
|
if (isPolling) {
|
|
@@ -542,7 +585,7 @@ var DynamoDBDedupeStore = class {
|
|
|
542
585
|
isPolling = false;
|
|
543
586
|
});
|
|
544
587
|
}, this.pollIntervalMs);
|
|
545
|
-
if (typeof pollHandle.unref ===
|
|
588
|
+
if (typeof pollHandle.unref === 'function') {
|
|
546
589
|
pollHandle.unref();
|
|
547
590
|
}
|
|
548
591
|
void poll();
|
|
@@ -552,31 +595,33 @@ var DynamoDBDedupeStore = class {
|
|
|
552
595
|
settle(void 0);
|
|
553
596
|
return;
|
|
554
597
|
}
|
|
555
|
-
void (() =>
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
598
|
+
void (() =>
|
|
599
|
+
__async(this, null, function* () {
|
|
600
|
+
try {
|
|
601
|
+
yield this.docClient.send(
|
|
602
|
+
new libDynamodb.UpdateCommand({
|
|
603
|
+
TableName: this.tableName,
|
|
604
|
+
Key: { pk, sk: pk },
|
|
605
|
+
UpdateExpression:
|
|
606
|
+
'SET #status = :failed, #error = :error, updatedAt = :now',
|
|
607
|
+
ExpressionAttributeNames: {
|
|
608
|
+
'#status': 'status',
|
|
609
|
+
'#error': 'error',
|
|
610
|
+
},
|
|
611
|
+
ExpressionAttributeValues: {
|
|
612
|
+
':failed': 'failed',
|
|
613
|
+
':error': 'Job timed out',
|
|
614
|
+
':now': Date.now(),
|
|
615
|
+
},
|
|
616
|
+
}),
|
|
617
|
+
);
|
|
618
|
+
} catch (e) {
|
|
619
|
+
} finally {
|
|
620
|
+
settle(void 0);
|
|
621
|
+
}
|
|
622
|
+
}))();
|
|
578
623
|
}, this.jobTimeoutMs);
|
|
579
|
-
if (typeof timeoutHandle.unref ===
|
|
624
|
+
if (typeof timeoutHandle.unref === 'function') {
|
|
580
625
|
timeoutHandle.unref();
|
|
581
626
|
}
|
|
582
627
|
}
|
|
@@ -594,7 +639,7 @@ var DynamoDBDedupeStore = class {
|
|
|
594
639
|
registerOrJoin(hash) {
|
|
595
640
|
return __async(this, null, function* () {
|
|
596
641
|
if (this.isDestroyed) {
|
|
597
|
-
throw new Error(
|
|
642
|
+
throw new Error('Dedupe store has been destroyed');
|
|
598
643
|
}
|
|
599
644
|
this.assertValidHash(hash);
|
|
600
645
|
const pk = `DEDUPE#${hash}`;
|
|
@@ -602,7 +647,10 @@ var DynamoDBDedupeStore = class {
|
|
|
602
647
|
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
603
648
|
const candidateJobId = crypto.randomUUID();
|
|
604
649
|
const now = Date.now();
|
|
605
|
-
const ttl =
|
|
650
|
+
const ttl =
|
|
651
|
+
this.jobTimeoutMs > 0
|
|
652
|
+
? Math.floor((now + this.jobTimeoutMs) / 1e3)
|
|
653
|
+
: 0;
|
|
606
654
|
try {
|
|
607
655
|
yield this.docClient.send(
|
|
608
656
|
new libDynamodb.PutCommand({
|
|
@@ -611,32 +659,38 @@ var DynamoDBDedupeStore = class {
|
|
|
611
659
|
pk,
|
|
612
660
|
sk: pk,
|
|
613
661
|
jobId: candidateJobId,
|
|
614
|
-
status:
|
|
662
|
+
status: 'pending',
|
|
615
663
|
result: null,
|
|
616
664
|
error: null,
|
|
617
665
|
createdAt: now,
|
|
618
666
|
updatedAt: now,
|
|
619
|
-
ttl
|
|
667
|
+
ttl,
|
|
620
668
|
},
|
|
621
|
-
ConditionExpression:
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
669
|
+
ConditionExpression:
|
|
670
|
+
'attribute_not_exists(pk) OR #status <> :pending',
|
|
671
|
+
ExpressionAttributeNames: { '#status': 'status' },
|
|
672
|
+
ExpressionAttributeValues: { ':pending': 'pending' },
|
|
673
|
+
}),
|
|
625
674
|
);
|
|
626
675
|
return { jobId: candidateJobId, isOwner: true };
|
|
627
676
|
} catch (error) {
|
|
628
677
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
629
|
-
if (
|
|
678
|
+
if (
|
|
679
|
+
error &&
|
|
680
|
+
typeof error === 'object' &&
|
|
681
|
+
'name' in error &&
|
|
682
|
+
error.name === 'ConditionalCheckFailedException'
|
|
683
|
+
) {
|
|
630
684
|
const existing = yield this.docClient.send(
|
|
631
685
|
new libDynamodb.GetCommand({
|
|
632
686
|
TableName: this.tableName,
|
|
633
|
-
Key: { pk, sk: pk }
|
|
634
|
-
})
|
|
687
|
+
Key: { pk, sk: pk },
|
|
688
|
+
}),
|
|
635
689
|
);
|
|
636
690
|
if (existing.Item) {
|
|
637
691
|
return {
|
|
638
|
-
jobId: existing.Item[
|
|
639
|
-
isOwner: false
|
|
692
|
+
jobId: existing.Item['jobId'],
|
|
693
|
+
isOwner: false,
|
|
640
694
|
};
|
|
641
695
|
}
|
|
642
696
|
continue;
|
|
@@ -645,27 +699,27 @@ var DynamoDBDedupeStore = class {
|
|
|
645
699
|
}
|
|
646
700
|
}
|
|
647
701
|
throw new Error(
|
|
648
|
-
`Failed to register or join job for hash "${hash}" after ${maxAttempts} attempts
|
|
702
|
+
`Failed to register or join job for hash "${hash}" after ${maxAttempts} attempts`,
|
|
649
703
|
);
|
|
650
704
|
});
|
|
651
705
|
}
|
|
652
706
|
complete(hash, value) {
|
|
653
707
|
return __async(this, null, function* () {
|
|
654
708
|
if (this.isDestroyed) {
|
|
655
|
-
throw new Error(
|
|
709
|
+
throw new Error('Dedupe store has been destroyed');
|
|
656
710
|
}
|
|
657
711
|
this.assertValidHash(hash);
|
|
658
712
|
let serializedResult;
|
|
659
713
|
if (value === void 0) {
|
|
660
|
-
serializedResult =
|
|
714
|
+
serializedResult = '__UNDEFINED__';
|
|
661
715
|
} else if (value === null) {
|
|
662
|
-
serializedResult =
|
|
716
|
+
serializedResult = '__NULL__';
|
|
663
717
|
} else {
|
|
664
718
|
try {
|
|
665
719
|
serializedResult = JSON.stringify(value);
|
|
666
720
|
} catch (error) {
|
|
667
721
|
throw new Error(
|
|
668
|
-
`Failed to serialize result: ${error instanceof Error ? error.message : String(error)}
|
|
722
|
+
`Failed to serialize result: ${error instanceof Error ? error.message : String(error)}`,
|
|
669
723
|
);
|
|
670
724
|
}
|
|
671
725
|
}
|
|
@@ -675,23 +729,29 @@ var DynamoDBDedupeStore = class {
|
|
|
675
729
|
new libDynamodb.UpdateCommand({
|
|
676
730
|
TableName: this.tableName,
|
|
677
731
|
Key: { pk, sk: pk },
|
|
678
|
-
UpdateExpression:
|
|
679
|
-
|
|
732
|
+
UpdateExpression:
|
|
733
|
+
'SET #status = :completed, #result = :result, updatedAt = :now',
|
|
734
|
+
ConditionExpression: 'attribute_exists(pk) AND #status = :pending',
|
|
680
735
|
ExpressionAttributeNames: {
|
|
681
|
-
|
|
682
|
-
|
|
736
|
+
'#status': 'status',
|
|
737
|
+
'#result': 'result',
|
|
683
738
|
},
|
|
684
739
|
ExpressionAttributeValues: {
|
|
685
|
-
|
|
686
|
-
|
|
687
|
-
|
|
688
|
-
|
|
689
|
-
}
|
|
690
|
-
})
|
|
740
|
+
':completed': 'completed',
|
|
741
|
+
':pending': 'pending',
|
|
742
|
+
':result': serializedResult,
|
|
743
|
+
':now': Date.now(),
|
|
744
|
+
},
|
|
745
|
+
}),
|
|
691
746
|
);
|
|
692
747
|
} catch (error) {
|
|
693
748
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
694
|
-
if (
|
|
749
|
+
if (
|
|
750
|
+
error &&
|
|
751
|
+
typeof error === 'object' &&
|
|
752
|
+
'name' in error &&
|
|
753
|
+
error.name === 'ConditionalCheckFailedException'
|
|
754
|
+
) {
|
|
695
755
|
return;
|
|
696
756
|
}
|
|
697
757
|
throw error;
|
|
@@ -705,7 +765,7 @@ var DynamoDBDedupeStore = class {
|
|
|
705
765
|
fail(hash, _error) {
|
|
706
766
|
return __async(this, null, function* () {
|
|
707
767
|
if (this.isDestroyed) {
|
|
708
|
-
throw new Error(
|
|
768
|
+
throw new Error('Dedupe store has been destroyed');
|
|
709
769
|
}
|
|
710
770
|
this.assertValidHash(hash);
|
|
711
771
|
const pk = `DEDUPE#${hash}`;
|
|
@@ -714,17 +774,18 @@ var DynamoDBDedupeStore = class {
|
|
|
714
774
|
new libDynamodb.UpdateCommand({
|
|
715
775
|
TableName: this.tableName,
|
|
716
776
|
Key: { pk, sk: pk },
|
|
717
|
-
UpdateExpression:
|
|
777
|
+
UpdateExpression:
|
|
778
|
+
'SET #status = :failed, #error = :error, updatedAt = :now',
|
|
718
779
|
ExpressionAttributeNames: {
|
|
719
|
-
|
|
720
|
-
|
|
780
|
+
'#status': 'status',
|
|
781
|
+
'#error': 'error',
|
|
721
782
|
},
|
|
722
783
|
ExpressionAttributeValues: {
|
|
723
|
-
|
|
724
|
-
|
|
725
|
-
|
|
726
|
-
}
|
|
727
|
-
})
|
|
784
|
+
':failed': 'failed',
|
|
785
|
+
':error': 'Job failed',
|
|
786
|
+
':now': Date.now(),
|
|
787
|
+
},
|
|
788
|
+
}),
|
|
728
789
|
);
|
|
729
790
|
} catch (dynamoError) {
|
|
730
791
|
throwIfDynamoTableMissing(dynamoError, this.tableName);
|
|
@@ -739,7 +800,7 @@ var DynamoDBDedupeStore = class {
|
|
|
739
800
|
isInProgress(hash) {
|
|
740
801
|
return __async(this, null, function* () {
|
|
741
802
|
if (this.isDestroyed) {
|
|
742
|
-
throw new Error(
|
|
803
|
+
throw new Error('Dedupe store has been destroyed');
|
|
743
804
|
}
|
|
744
805
|
this.assertValidHash(hash);
|
|
745
806
|
const pk = `DEDUPE#${hash}`;
|
|
@@ -748,8 +809,8 @@ var DynamoDBDedupeStore = class {
|
|
|
748
809
|
result = yield this.docClient.send(
|
|
749
810
|
new libDynamodb.GetCommand({
|
|
750
811
|
TableName: this.tableName,
|
|
751
|
-
Key: { pk, sk: pk }
|
|
752
|
-
})
|
|
812
|
+
Key: { pk, sk: pk },
|
|
813
|
+
}),
|
|
753
814
|
);
|
|
754
815
|
} catch (error) {
|
|
755
816
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -758,24 +819,26 @@ var DynamoDBDedupeStore = class {
|
|
|
758
819
|
if (!result.Item) {
|
|
759
820
|
return false;
|
|
760
821
|
}
|
|
761
|
-
const jobExpired =
|
|
822
|
+
const jobExpired =
|
|
823
|
+
this.jobTimeoutMs > 0 &&
|
|
824
|
+
Date.now() - result.Item['createdAt'] >= this.jobTimeoutMs;
|
|
762
825
|
if (jobExpired) {
|
|
763
826
|
yield this.docClient.send(
|
|
764
827
|
new libDynamodb.DeleteCommand({
|
|
765
828
|
TableName: this.tableName,
|
|
766
|
-
Key: { pk, sk: pk }
|
|
767
|
-
})
|
|
829
|
+
Key: { pk, sk: pk },
|
|
830
|
+
}),
|
|
768
831
|
);
|
|
769
832
|
return false;
|
|
770
833
|
}
|
|
771
|
-
return result.Item[
|
|
834
|
+
return result.Item['status'] === 'pending';
|
|
772
835
|
});
|
|
773
836
|
}
|
|
774
837
|
clear() {
|
|
775
838
|
return __async(this, null, function* () {
|
|
776
839
|
var _a;
|
|
777
840
|
if (this.isDestroyed) {
|
|
778
|
-
throw new Error(
|
|
841
|
+
throw new Error('Dedupe store has been destroyed');
|
|
779
842
|
}
|
|
780
843
|
let lastEvaluatedKey;
|
|
781
844
|
do {
|
|
@@ -784,11 +847,11 @@ var DynamoDBDedupeStore = class {
|
|
|
784
847
|
scanResult = yield this.docClient.send(
|
|
785
848
|
new libDynamodb.ScanCommand({
|
|
786
849
|
TableName: this.tableName,
|
|
787
|
-
FilterExpression:
|
|
788
|
-
ExpressionAttributeValues: {
|
|
789
|
-
ProjectionExpression:
|
|
790
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
791
|
-
})
|
|
850
|
+
FilterExpression: 'begins_with(pk, :prefix)',
|
|
851
|
+
ExpressionAttributeValues: { ':prefix': 'DEDUPE#' },
|
|
852
|
+
ProjectionExpression: 'pk, sk',
|
|
853
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
854
|
+
}),
|
|
792
855
|
);
|
|
793
856
|
} catch (error) {
|
|
794
857
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -800,7 +863,7 @@ var DynamoDBDedupeStore = class {
|
|
|
800
863
|
yield batchDeleteWithRetries(
|
|
801
864
|
this.docClient,
|
|
802
865
|
this.tableName,
|
|
803
|
-
items.map((item) => ({ pk: item[
|
|
866
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
804
867
|
);
|
|
805
868
|
} catch (error) {
|
|
806
869
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -834,10 +897,10 @@ var DynamoDBDedupeStore = class {
|
|
|
834
897
|
}
|
|
835
898
|
deserializeResult(serializedResult) {
|
|
836
899
|
try {
|
|
837
|
-
if (serializedResult ===
|
|
900
|
+
if (serializedResult === '__UNDEFINED__') {
|
|
838
901
|
return void 0;
|
|
839
902
|
}
|
|
840
|
-
if (serializedResult ===
|
|
903
|
+
if (serializedResult === '__NULL__') {
|
|
841
904
|
return null;
|
|
842
905
|
}
|
|
843
906
|
if (serializedResult) {
|
|
@@ -849,7 +912,7 @@ var DynamoDBDedupeStore = class {
|
|
|
849
912
|
}
|
|
850
913
|
}
|
|
851
914
|
assertValidHash(hash) {
|
|
852
|
-
assertDynamoKeyPart(hash,
|
|
915
|
+
assertDynamoKeyPart(hash, 'hash');
|
|
853
916
|
}
|
|
854
917
|
};
|
|
855
918
|
var DynamoDBRateLimitStore = class {
|
|
@@ -858,7 +921,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
858
921
|
region,
|
|
859
922
|
tableName = DEFAULT_TABLE_NAME,
|
|
860
923
|
defaultConfig = core.DEFAULT_RATE_LIMIT,
|
|
861
|
-
resourceConfigs = /* @__PURE__ */ new Map()
|
|
924
|
+
resourceConfigs = /* @__PURE__ */ new Map(),
|
|
862
925
|
} = {}) {
|
|
863
926
|
this.isDestroyed = false;
|
|
864
927
|
this.tableName = tableName;
|
|
@@ -882,16 +945,19 @@ var DynamoDBRateLimitStore = class {
|
|
|
882
945
|
return __async(this, null, function* () {
|
|
883
946
|
var _a;
|
|
884
947
|
if (this.isDestroyed) {
|
|
885
|
-
throw new Error(
|
|
948
|
+
throw new Error('Rate limit store has been destroyed');
|
|
886
949
|
}
|
|
887
950
|
this.assertValidResource(resource);
|
|
888
|
-
const config =
|
|
951
|
+
const config =
|
|
952
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
953
|
+
? _a
|
|
954
|
+
: this.defaultConfig;
|
|
889
955
|
const now = Date.now();
|
|
890
956
|
const windowStart = now - config.windowMs;
|
|
891
957
|
const hasCapacity = yield this.hasCapacityInWindow(
|
|
892
958
|
resource,
|
|
893
959
|
windowStart,
|
|
894
|
-
config.limit
|
|
960
|
+
config.limit,
|
|
895
961
|
);
|
|
896
962
|
return hasCapacity;
|
|
897
963
|
});
|
|
@@ -900,10 +966,13 @@ var DynamoDBRateLimitStore = class {
|
|
|
900
966
|
return __async(this, null, function* () {
|
|
901
967
|
var _a;
|
|
902
968
|
if (this.isDestroyed) {
|
|
903
|
-
throw new Error(
|
|
969
|
+
throw new Error('Rate limit store has been destroyed');
|
|
904
970
|
}
|
|
905
971
|
this.assertValidResource(resource);
|
|
906
|
-
const config =
|
|
972
|
+
const config =
|
|
973
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
974
|
+
? _a
|
|
975
|
+
: this.defaultConfig;
|
|
907
976
|
if (config.limit <= 0) {
|
|
908
977
|
return false;
|
|
909
978
|
}
|
|
@@ -926,16 +995,17 @@ var DynamoDBRateLimitStore = class {
|
|
|
926
995
|
pk: slotPrefix,
|
|
927
996
|
sk: `SLOT#${slot}`,
|
|
928
997
|
timestamp: now,
|
|
929
|
-
ttl
|
|
998
|
+
ttl,
|
|
930
999
|
},
|
|
931
|
-
ConditionExpression:
|
|
1000
|
+
ConditionExpression:
|
|
1001
|
+
'attribute_not_exists(pk) OR #timestamp < :windowStart',
|
|
932
1002
|
ExpressionAttributeNames: {
|
|
933
|
-
|
|
1003
|
+
'#timestamp': 'timestamp',
|
|
934
1004
|
},
|
|
935
1005
|
ExpressionAttributeValues: {
|
|
936
|
-
|
|
937
|
-
}
|
|
938
|
-
}
|
|
1006
|
+
':windowStart': windowStart,
|
|
1007
|
+
},
|
|
1008
|
+
},
|
|
939
1009
|
},
|
|
940
1010
|
{
|
|
941
1011
|
Put: {
|
|
@@ -944,12 +1014,12 @@ var DynamoDBRateLimitStore = class {
|
|
|
944
1014
|
pk: `RATELIMIT#${resource}`,
|
|
945
1015
|
sk: `TS#${now}#${eventId}`,
|
|
946
1016
|
ttl,
|
|
947
|
-
timestamp: now
|
|
948
|
-
}
|
|
949
|
-
}
|
|
950
|
-
}
|
|
951
|
-
]
|
|
952
|
-
})
|
|
1017
|
+
timestamp: now,
|
|
1018
|
+
},
|
|
1019
|
+
},
|
|
1020
|
+
},
|
|
1021
|
+
],
|
|
1022
|
+
}),
|
|
953
1023
|
);
|
|
954
1024
|
return true;
|
|
955
1025
|
} catch (error) {
|
|
@@ -967,11 +1037,14 @@ var DynamoDBRateLimitStore = class {
|
|
|
967
1037
|
return __async(this, null, function* () {
|
|
968
1038
|
var _a;
|
|
969
1039
|
if (this.isDestroyed) {
|
|
970
|
-
throw new Error(
|
|
1040
|
+
throw new Error('Rate limit store has been destroyed');
|
|
971
1041
|
}
|
|
972
1042
|
this.assertValidResource(resource);
|
|
973
1043
|
const now = Date.now();
|
|
974
|
-
const config =
|
|
1044
|
+
const config =
|
|
1045
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1046
|
+
? _a
|
|
1047
|
+
: this.defaultConfig;
|
|
975
1048
|
const ttl = Math.floor((now + config.windowMs) / 1e3);
|
|
976
1049
|
const uuid = crypto.randomUUID();
|
|
977
1050
|
try {
|
|
@@ -982,9 +1055,9 @@ var DynamoDBRateLimitStore = class {
|
|
|
982
1055
|
pk: `RATELIMIT#${resource}`,
|
|
983
1056
|
sk: `TS#${now}#${uuid}`,
|
|
984
1057
|
ttl,
|
|
985
|
-
timestamp: now
|
|
986
|
-
}
|
|
987
|
-
})
|
|
1058
|
+
timestamp: now,
|
|
1059
|
+
},
|
|
1060
|
+
}),
|
|
988
1061
|
);
|
|
989
1062
|
} catch (error) {
|
|
990
1063
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -996,28 +1069,31 @@ var DynamoDBRateLimitStore = class {
|
|
|
996
1069
|
return __async(this, null, function* () {
|
|
997
1070
|
var _a;
|
|
998
1071
|
if (this.isDestroyed) {
|
|
999
|
-
throw new Error(
|
|
1072
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1000
1073
|
}
|
|
1001
1074
|
this.assertValidResource(resource);
|
|
1002
|
-
const config =
|
|
1075
|
+
const config =
|
|
1076
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1077
|
+
? _a
|
|
1078
|
+
: this.defaultConfig;
|
|
1003
1079
|
const now = Date.now();
|
|
1004
1080
|
const windowStart = now - config.windowMs;
|
|
1005
1081
|
const currentRequests = yield this.countRequestsInWindow(
|
|
1006
1082
|
resource,
|
|
1007
|
-
windowStart
|
|
1083
|
+
windowStart,
|
|
1008
1084
|
);
|
|
1009
1085
|
const remaining = Math.max(0, config.limit - currentRequests);
|
|
1010
1086
|
return {
|
|
1011
1087
|
remaining,
|
|
1012
1088
|
resetTime: new Date(now + config.windowMs),
|
|
1013
|
-
limit: config.limit
|
|
1089
|
+
limit: config.limit,
|
|
1014
1090
|
};
|
|
1015
1091
|
});
|
|
1016
1092
|
}
|
|
1017
1093
|
reset(resource) {
|
|
1018
1094
|
return __async(this, null, function* () {
|
|
1019
1095
|
if (this.isDestroyed) {
|
|
1020
|
-
throw new Error(
|
|
1096
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1021
1097
|
}
|
|
1022
1098
|
this.assertValidResource(resource);
|
|
1023
1099
|
yield this.deleteResourceItems(resource);
|
|
@@ -1027,10 +1103,13 @@ var DynamoDBRateLimitStore = class {
|
|
|
1027
1103
|
return __async(this, null, function* () {
|
|
1028
1104
|
var _a, _b;
|
|
1029
1105
|
if (this.isDestroyed) {
|
|
1030
|
-
throw new Error(
|
|
1106
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1031
1107
|
}
|
|
1032
1108
|
this.assertValidResource(resource);
|
|
1033
|
-
const config =
|
|
1109
|
+
const config =
|
|
1110
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1111
|
+
? _a
|
|
1112
|
+
: this.defaultConfig;
|
|
1034
1113
|
if (config.limit === 0) {
|
|
1035
1114
|
return config.windowMs;
|
|
1036
1115
|
}
|
|
@@ -1039,7 +1118,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
1039
1118
|
const hasCapacity = yield this.hasCapacityInWindow(
|
|
1040
1119
|
resource,
|
|
1041
1120
|
windowStart,
|
|
1042
|
-
config.limit
|
|
1121
|
+
config.limit,
|
|
1043
1122
|
);
|
|
1044
1123
|
if (hasCapacity) {
|
|
1045
1124
|
return 0;
|
|
@@ -1049,14 +1128,14 @@ var DynamoDBRateLimitStore = class {
|
|
|
1049
1128
|
result = yield this.docClient.send(
|
|
1050
1129
|
new libDynamodb.QueryCommand({
|
|
1051
1130
|
TableName: this.tableName,
|
|
1052
|
-
KeyConditionExpression:
|
|
1131
|
+
KeyConditionExpression: 'pk = :pk AND sk >= :skStart',
|
|
1053
1132
|
ExpressionAttributeValues: {
|
|
1054
|
-
|
|
1055
|
-
|
|
1133
|
+
':pk': `RATELIMIT#${resource}`,
|
|
1134
|
+
':skStart': `TS#${windowStart}`,
|
|
1056
1135
|
},
|
|
1057
1136
|
Limit: 1,
|
|
1058
|
-
ScanIndexForward: true
|
|
1059
|
-
})
|
|
1137
|
+
ScanIndexForward: true,
|
|
1138
|
+
}),
|
|
1060
1139
|
);
|
|
1061
1140
|
} catch (error) {
|
|
1062
1141
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1066,7 +1145,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
1066
1145
|
if (!oldestItem) {
|
|
1067
1146
|
return 0;
|
|
1068
1147
|
}
|
|
1069
|
-
const oldestTimestamp = oldestItem[
|
|
1148
|
+
const oldestTimestamp = oldestItem['timestamp'];
|
|
1070
1149
|
if (!oldestTimestamp) {
|
|
1071
1150
|
return 0;
|
|
1072
1151
|
}
|
|
@@ -1081,13 +1160,15 @@ var DynamoDBRateLimitStore = class {
|
|
|
1081
1160
|
getResourceConfig(resource) {
|
|
1082
1161
|
var _a;
|
|
1083
1162
|
this.assertValidResource(resource);
|
|
1084
|
-
return (_a = this.resourceConfigs.get(resource)) != null
|
|
1163
|
+
return (_a = this.resourceConfigs.get(resource)) != null
|
|
1164
|
+
? _a
|
|
1165
|
+
: this.defaultConfig;
|
|
1085
1166
|
}
|
|
1086
1167
|
clear() {
|
|
1087
1168
|
return __async(this, null, function* () {
|
|
1088
1169
|
var _a;
|
|
1089
1170
|
if (this.isDestroyed) {
|
|
1090
|
-
throw new Error(
|
|
1171
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1091
1172
|
}
|
|
1092
1173
|
let lastEvaluatedKey;
|
|
1093
1174
|
do {
|
|
@@ -1096,14 +1177,15 @@ var DynamoDBRateLimitStore = class {
|
|
|
1096
1177
|
scanResult = yield this.docClient.send(
|
|
1097
1178
|
new libDynamodb.ScanCommand({
|
|
1098
1179
|
TableName: this.tableName,
|
|
1099
|
-
FilterExpression:
|
|
1180
|
+
FilterExpression:
|
|
1181
|
+
'begins_with(pk, :prefix) OR begins_with(pk, :slotPrefix)',
|
|
1100
1182
|
ExpressionAttributeValues: {
|
|
1101
|
-
|
|
1102
|
-
|
|
1183
|
+
':prefix': 'RATELIMIT#',
|
|
1184
|
+
':slotPrefix': 'RATELIMIT_SLOT#',
|
|
1103
1185
|
},
|
|
1104
|
-
ProjectionExpression:
|
|
1105
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
1106
|
-
})
|
|
1186
|
+
ProjectionExpression: 'pk, sk',
|
|
1187
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
1188
|
+
}),
|
|
1107
1189
|
);
|
|
1108
1190
|
} catch (error) {
|
|
1109
1191
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1115,7 +1197,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
1115
1197
|
yield batchDeleteWithRetries(
|
|
1116
1198
|
this.docClient,
|
|
1117
1199
|
this.tableName,
|
|
1118
|
-
items.map((item) => ({ pk: item[
|
|
1200
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
1119
1201
|
);
|
|
1120
1202
|
} catch (error) {
|
|
1121
1203
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1142,12 +1224,12 @@ var DynamoDBRateLimitStore = class {
|
|
|
1142
1224
|
try {
|
|
1143
1225
|
return yield queryCountAllPages(this.docClient, {
|
|
1144
1226
|
TableName: this.tableName,
|
|
1145
|
-
KeyConditionExpression:
|
|
1227
|
+
KeyConditionExpression: 'pk = :pk AND sk >= :skStart',
|
|
1146
1228
|
ExpressionAttributeValues: {
|
|
1147
|
-
|
|
1148
|
-
|
|
1229
|
+
':pk': `RATELIMIT#${resource}`,
|
|
1230
|
+
':skStart': `TS#${windowStart}`,
|
|
1149
1231
|
},
|
|
1150
|
-
Select:
|
|
1232
|
+
Select: 'COUNT',
|
|
1151
1233
|
});
|
|
1152
1234
|
} catch (error) {
|
|
1153
1235
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1162,13 +1244,13 @@ var DynamoDBRateLimitStore = class {
|
|
|
1162
1244
|
this.docClient,
|
|
1163
1245
|
{
|
|
1164
1246
|
TableName: this.tableName,
|
|
1165
|
-
KeyConditionExpression:
|
|
1247
|
+
KeyConditionExpression: 'pk = :pk AND sk >= :skStart',
|
|
1166
1248
|
ExpressionAttributeValues: {
|
|
1167
|
-
|
|
1168
|
-
|
|
1169
|
-
}
|
|
1249
|
+
':pk': `RATELIMIT#${resource}`,
|
|
1250
|
+
':skStart': `TS#${windowStart}`,
|
|
1251
|
+
},
|
|
1170
1252
|
},
|
|
1171
|
-
limit
|
|
1253
|
+
limit,
|
|
1172
1254
|
);
|
|
1173
1255
|
return !reachedLimit;
|
|
1174
1256
|
} catch (error) {
|
|
@@ -1182,7 +1264,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
1182
1264
|
var _a;
|
|
1183
1265
|
const partitionKeys = [
|
|
1184
1266
|
`RATELIMIT#${resource}`,
|
|
1185
|
-
`RATELIMIT_SLOT#${resource}
|
|
1267
|
+
`RATELIMIT_SLOT#${resource}`,
|
|
1186
1268
|
];
|
|
1187
1269
|
for (const pk of partitionKeys) {
|
|
1188
1270
|
let lastEvaluatedKey;
|
|
@@ -1192,11 +1274,11 @@ var DynamoDBRateLimitStore = class {
|
|
|
1192
1274
|
queryResult = yield this.docClient.send(
|
|
1193
1275
|
new libDynamodb.QueryCommand({
|
|
1194
1276
|
TableName: this.tableName,
|
|
1195
|
-
KeyConditionExpression:
|
|
1196
|
-
ExpressionAttributeValues: {
|
|
1197
|
-
ProjectionExpression:
|
|
1198
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
1199
|
-
})
|
|
1277
|
+
KeyConditionExpression: 'pk = :pk',
|
|
1278
|
+
ExpressionAttributeValues: { ':pk': pk },
|
|
1279
|
+
ProjectionExpression: 'pk, sk',
|
|
1280
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
1281
|
+
}),
|
|
1200
1282
|
);
|
|
1201
1283
|
} catch (error) {
|
|
1202
1284
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1208,7 +1290,7 @@ var DynamoDBRateLimitStore = class {
|
|
|
1208
1290
|
yield batchDeleteWithRetries(
|
|
1209
1291
|
this.docClient,
|
|
1210
1292
|
this.tableName,
|
|
1211
|
-
items.map((item) => ({ pk: item[
|
|
1293
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
1212
1294
|
);
|
|
1213
1295
|
} catch (error) {
|
|
1214
1296
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1221,12 +1303,12 @@ var DynamoDBRateLimitStore = class {
|
|
|
1221
1303
|
});
|
|
1222
1304
|
}
|
|
1223
1305
|
assertValidResource(resource) {
|
|
1224
|
-
assertDynamoKeyPart(resource,
|
|
1306
|
+
assertDynamoKeyPart(resource, 'resource');
|
|
1225
1307
|
}
|
|
1226
1308
|
};
|
|
1227
1309
|
var DEFAULT_ADAPTIVE_RATE_LIMIT = {
|
|
1228
1310
|
limit: 200,
|
|
1229
|
-
windowMs: 36e5
|
|
1311
|
+
windowMs: 36e5,
|
|
1230
1312
|
// 1 hour
|
|
1231
1313
|
};
|
|
1232
1314
|
var DynamoDBAdaptiveRateLimitStore = class {
|
|
@@ -1236,7 +1318,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1236
1318
|
tableName = DEFAULT_TABLE_NAME,
|
|
1237
1319
|
defaultConfig = DEFAULT_ADAPTIVE_RATE_LIMIT,
|
|
1238
1320
|
resourceConfigs = /* @__PURE__ */ new Map(),
|
|
1239
|
-
adaptiveConfig = {}
|
|
1321
|
+
adaptiveConfig = {},
|
|
1240
1322
|
} = {}) {
|
|
1241
1323
|
this.isDestroyed = false;
|
|
1242
1324
|
this.activityMetrics = /* @__PURE__ */ new Map();
|
|
@@ -1245,10 +1327,12 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1245
1327
|
this.tableName = tableName;
|
|
1246
1328
|
this.defaultConfig = defaultConfig;
|
|
1247
1329
|
this.resourceConfigs = resourceConfigs;
|
|
1248
|
-
this.capacityCalculator = new core.AdaptiveCapacityCalculator(
|
|
1330
|
+
this.capacityCalculator = new core.AdaptiveCapacityCalculator(
|
|
1331
|
+
adaptiveConfig,
|
|
1332
|
+
);
|
|
1249
1333
|
this.maxMetricSamples = Math.max(
|
|
1250
1334
|
100,
|
|
1251
|
-
this.capacityCalculator.config.highActivityThreshold * 20
|
|
1335
|
+
this.capacityCalculator.config.highActivityThreshold * 20,
|
|
1252
1336
|
);
|
|
1253
1337
|
if (client instanceof libDynamodb.DynamoDBDocumentClient) {
|
|
1254
1338
|
this.docClient = client;
|
|
@@ -1264,26 +1348,26 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1264
1348
|
this.isClientManaged = true;
|
|
1265
1349
|
}
|
|
1266
1350
|
}
|
|
1267
|
-
canProceed(resource, priority =
|
|
1351
|
+
canProceed(resource, priority = 'background') {
|
|
1268
1352
|
return __async(this, null, function* () {
|
|
1269
1353
|
if (this.isDestroyed) {
|
|
1270
|
-
throw new Error(
|
|
1354
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1271
1355
|
}
|
|
1272
1356
|
this.assertValidResource(resource);
|
|
1273
1357
|
yield this.ensureActivityMetrics(resource);
|
|
1274
1358
|
const metrics = this.getOrCreateActivityMetrics(resource);
|
|
1275
1359
|
const capacity = this.calculateCurrentCapacity(resource, metrics);
|
|
1276
|
-
if (priority ===
|
|
1360
|
+
if (priority === 'background' && capacity.backgroundPaused) {
|
|
1277
1361
|
return false;
|
|
1278
1362
|
}
|
|
1279
|
-
if (priority ===
|
|
1363
|
+
if (priority === 'user') {
|
|
1280
1364
|
if (capacity.userReserved <= 0) {
|
|
1281
1365
|
return false;
|
|
1282
1366
|
}
|
|
1283
1367
|
return this.hasPriorityCapacityInWindow(
|
|
1284
1368
|
resource,
|
|
1285
|
-
|
|
1286
|
-
capacity.userReserved
|
|
1369
|
+
'user',
|
|
1370
|
+
capacity.userReserved,
|
|
1287
1371
|
);
|
|
1288
1372
|
} else {
|
|
1289
1373
|
if (capacity.backgroundMax <= 0) {
|
|
@@ -1291,30 +1375,34 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1291
1375
|
}
|
|
1292
1376
|
return this.hasPriorityCapacityInWindow(
|
|
1293
1377
|
resource,
|
|
1294
|
-
|
|
1295
|
-
capacity.backgroundMax
|
|
1378
|
+
'background',
|
|
1379
|
+
capacity.backgroundMax,
|
|
1296
1380
|
);
|
|
1297
1381
|
}
|
|
1298
1382
|
});
|
|
1299
1383
|
}
|
|
1300
|
-
acquire(resource, priority =
|
|
1384
|
+
acquire(resource, priority = 'background') {
|
|
1301
1385
|
return __async(this, null, function* () {
|
|
1302
1386
|
var _a;
|
|
1303
1387
|
if (this.isDestroyed) {
|
|
1304
|
-
throw new Error(
|
|
1388
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1305
1389
|
}
|
|
1306
1390
|
this.assertValidResource(resource);
|
|
1307
1391
|
yield this.ensureActivityMetrics(resource);
|
|
1308
1392
|
const metrics = this.getOrCreateActivityMetrics(resource);
|
|
1309
1393
|
const capacity = this.calculateCurrentCapacity(resource, metrics);
|
|
1310
|
-
if (priority ===
|
|
1394
|
+
if (priority === 'background' && capacity.backgroundPaused) {
|
|
1311
1395
|
return false;
|
|
1312
1396
|
}
|
|
1313
|
-
const limitForPriority =
|
|
1397
|
+
const limitForPriority =
|
|
1398
|
+
priority === 'user' ? capacity.userReserved : capacity.backgroundMax;
|
|
1314
1399
|
if (limitForPriority <= 0) {
|
|
1315
1400
|
return false;
|
|
1316
1401
|
}
|
|
1317
|
-
const config =
|
|
1402
|
+
const config =
|
|
1403
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1404
|
+
? _a
|
|
1405
|
+
: this.defaultConfig;
|
|
1318
1406
|
const now = Date.now();
|
|
1319
1407
|
const windowStart = now - config.windowMs;
|
|
1320
1408
|
const ttl = Math.floor((now + config.windowMs) / 1e3);
|
|
@@ -1334,16 +1422,17 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1334
1422
|
pk: slotPrefix,
|
|
1335
1423
|
sk: `SLOT#${slot}`,
|
|
1336
1424
|
timestamp: now,
|
|
1337
|
-
ttl
|
|
1425
|
+
ttl,
|
|
1338
1426
|
},
|
|
1339
|
-
ConditionExpression:
|
|
1427
|
+
ConditionExpression:
|
|
1428
|
+
'attribute_not_exists(pk) OR #timestamp < :windowStart',
|
|
1340
1429
|
ExpressionAttributeNames: {
|
|
1341
|
-
|
|
1430
|
+
'#timestamp': 'timestamp',
|
|
1342
1431
|
},
|
|
1343
1432
|
ExpressionAttributeValues: {
|
|
1344
|
-
|
|
1345
|
-
}
|
|
1346
|
-
}
|
|
1433
|
+
':windowStart': windowStart,
|
|
1434
|
+
},
|
|
1435
|
+
},
|
|
1347
1436
|
},
|
|
1348
1437
|
{
|
|
1349
1438
|
Put: {
|
|
@@ -1355,21 +1444,22 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1355
1444
|
gsi1sk: `TS#${now}#${uuid}`,
|
|
1356
1445
|
ttl,
|
|
1357
1446
|
timestamp: now,
|
|
1358
|
-
priority
|
|
1359
|
-
}
|
|
1360
|
-
}
|
|
1361
|
-
}
|
|
1362
|
-
]
|
|
1363
|
-
})
|
|
1447
|
+
priority,
|
|
1448
|
+
},
|
|
1449
|
+
},
|
|
1450
|
+
},
|
|
1451
|
+
],
|
|
1452
|
+
}),
|
|
1364
1453
|
);
|
|
1365
|
-
if (priority ===
|
|
1454
|
+
if (priority === 'user') {
|
|
1366
1455
|
this.pushRecentRequest(metrics.recentUserRequests, now);
|
|
1367
1456
|
} else {
|
|
1368
1457
|
this.pushRecentRequest(metrics.recentBackgroundRequests, now);
|
|
1369
1458
|
}
|
|
1370
|
-
metrics.userActivityTrend =
|
|
1371
|
-
|
|
1372
|
-
|
|
1459
|
+
metrics.userActivityTrend =
|
|
1460
|
+
this.capacityCalculator.calculateActivityTrend(
|
|
1461
|
+
metrics.recentUserRequests,
|
|
1462
|
+
);
|
|
1373
1463
|
return true;
|
|
1374
1464
|
} catch (error) {
|
|
1375
1465
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1382,15 +1472,18 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1382
1472
|
return false;
|
|
1383
1473
|
});
|
|
1384
1474
|
}
|
|
1385
|
-
record(resource, priority =
|
|
1475
|
+
record(resource, priority = 'background') {
|
|
1386
1476
|
return __async(this, null, function* () {
|
|
1387
1477
|
var _a;
|
|
1388
1478
|
if (this.isDestroyed) {
|
|
1389
|
-
throw new Error(
|
|
1479
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1390
1480
|
}
|
|
1391
1481
|
this.assertValidResource(resource);
|
|
1392
1482
|
const now = Date.now();
|
|
1393
|
-
const config =
|
|
1483
|
+
const config =
|
|
1484
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1485
|
+
? _a
|
|
1486
|
+
: this.defaultConfig;
|
|
1394
1487
|
const ttl = Math.floor((now + config.windowMs) / 1e3);
|
|
1395
1488
|
const uuid = crypto.randomUUID();
|
|
1396
1489
|
try {
|
|
@@ -1404,42 +1497,49 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1404
1497
|
gsi1sk: `TS#${now}#${uuid}`,
|
|
1405
1498
|
ttl,
|
|
1406
1499
|
timestamp: now,
|
|
1407
|
-
priority
|
|
1408
|
-
}
|
|
1409
|
-
})
|
|
1500
|
+
priority,
|
|
1501
|
+
},
|
|
1502
|
+
}),
|
|
1410
1503
|
);
|
|
1411
1504
|
} catch (error) {
|
|
1412
1505
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
1413
1506
|
throw error;
|
|
1414
1507
|
}
|
|
1415
1508
|
const metrics = this.getOrCreateActivityMetrics(resource);
|
|
1416
|
-
if (priority ===
|
|
1509
|
+
if (priority === 'user') {
|
|
1417
1510
|
this.pushRecentRequest(metrics.recentUserRequests, now);
|
|
1418
1511
|
} else {
|
|
1419
1512
|
this.pushRecentRequest(metrics.recentBackgroundRequests, now);
|
|
1420
1513
|
}
|
|
1421
|
-
metrics.userActivityTrend =
|
|
1422
|
-
|
|
1423
|
-
|
|
1514
|
+
metrics.userActivityTrend =
|
|
1515
|
+
this.capacityCalculator.calculateActivityTrend(
|
|
1516
|
+
metrics.recentUserRequests,
|
|
1517
|
+
);
|
|
1424
1518
|
});
|
|
1425
1519
|
}
|
|
1426
1520
|
getStatus(resource) {
|
|
1427
1521
|
return __async(this, null, function* () {
|
|
1428
1522
|
var _a;
|
|
1429
1523
|
if (this.isDestroyed) {
|
|
1430
|
-
throw new Error(
|
|
1524
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1431
1525
|
}
|
|
1432
1526
|
this.assertValidResource(resource);
|
|
1433
1527
|
yield this.ensureActivityMetrics(resource);
|
|
1434
1528
|
const metrics = this.getOrCreateActivityMetrics(resource);
|
|
1435
1529
|
const capacity = this.calculateCurrentCapacity(resource, metrics);
|
|
1436
1530
|
const [currentUserUsage, currentBackgroundUsage] = yield Promise.all([
|
|
1437
|
-
this.getCurrentUsage(resource,
|
|
1438
|
-
this.getCurrentUsage(resource,
|
|
1531
|
+
this.getCurrentUsage(resource, 'user'),
|
|
1532
|
+
this.getCurrentUsage(resource, 'background'),
|
|
1439
1533
|
]);
|
|
1440
|
-
const config =
|
|
1534
|
+
const config =
|
|
1535
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1536
|
+
? _a
|
|
1537
|
+
: this.defaultConfig;
|
|
1441
1538
|
return {
|
|
1442
|
-
remaining:
|
|
1539
|
+
remaining:
|
|
1540
|
+
capacity.userReserved -
|
|
1541
|
+
currentUserUsage +
|
|
1542
|
+
(capacity.backgroundMax - currentBackgroundUsage),
|
|
1443
1543
|
resetTime: new Date(Date.now() + config.windowMs),
|
|
1444
1544
|
limit: this.getResourceLimit(resource),
|
|
1445
1545
|
adaptive: {
|
|
@@ -1447,17 +1547,17 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1447
1547
|
backgroundMax: capacity.backgroundMax,
|
|
1448
1548
|
backgroundPaused: capacity.backgroundPaused,
|
|
1449
1549
|
recentUserActivity: this.capacityCalculator.getRecentActivity(
|
|
1450
|
-
metrics.recentUserRequests
|
|
1550
|
+
metrics.recentUserRequests,
|
|
1451
1551
|
),
|
|
1452
|
-
reason: capacity.reason
|
|
1453
|
-
}
|
|
1552
|
+
reason: capacity.reason,
|
|
1553
|
+
},
|
|
1454
1554
|
};
|
|
1455
1555
|
});
|
|
1456
1556
|
}
|
|
1457
1557
|
reset(resource) {
|
|
1458
1558
|
return __async(this, null, function* () {
|
|
1459
1559
|
if (this.isDestroyed) {
|
|
1460
|
-
throw new Error(
|
|
1560
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1461
1561
|
}
|
|
1462
1562
|
this.assertValidResource(resource);
|
|
1463
1563
|
yield this.deleteResourceItems(resource);
|
|
@@ -1466,14 +1566,17 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1466
1566
|
this.lastCapacityUpdate.delete(resource);
|
|
1467
1567
|
});
|
|
1468
1568
|
}
|
|
1469
|
-
getWaitTime(resource, priority =
|
|
1569
|
+
getWaitTime(resource, priority = 'background') {
|
|
1470
1570
|
return __async(this, null, function* () {
|
|
1471
1571
|
var _a, _b;
|
|
1472
1572
|
if (this.isDestroyed) {
|
|
1473
|
-
throw new Error(
|
|
1573
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1474
1574
|
}
|
|
1475
1575
|
this.assertValidResource(resource);
|
|
1476
|
-
const config =
|
|
1576
|
+
const config =
|
|
1577
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1578
|
+
? _a
|
|
1579
|
+
: this.defaultConfig;
|
|
1477
1580
|
if (config.limit === 0) {
|
|
1478
1581
|
return config.windowMs;
|
|
1479
1582
|
}
|
|
@@ -1484,7 +1587,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1484
1587
|
yield this.ensureActivityMetrics(resource);
|
|
1485
1588
|
const metrics = this.getOrCreateActivityMetrics(resource);
|
|
1486
1589
|
const capacity = this.calculateCurrentCapacity(resource, metrics);
|
|
1487
|
-
if (priority ===
|
|
1590
|
+
if (priority === 'background' && capacity.backgroundPaused) {
|
|
1488
1591
|
return this.capacityCalculator.config.recalculationIntervalMs;
|
|
1489
1592
|
}
|
|
1490
1593
|
const now = Date.now();
|
|
@@ -1494,15 +1597,15 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1494
1597
|
result = yield this.docClient.send(
|
|
1495
1598
|
new libDynamodb.QueryCommand({
|
|
1496
1599
|
TableName: this.tableName,
|
|
1497
|
-
IndexName:
|
|
1498
|
-
KeyConditionExpression:
|
|
1600
|
+
IndexName: 'gsi1',
|
|
1601
|
+
KeyConditionExpression: 'gsi1pk = :gsi1pk AND gsi1sk >= :skStart',
|
|
1499
1602
|
ExpressionAttributeValues: {
|
|
1500
|
-
|
|
1501
|
-
|
|
1603
|
+
':gsi1pk': `RATELIMIT#${resource}#${priority}`,
|
|
1604
|
+
':skStart': `TS#${windowStart}`,
|
|
1502
1605
|
},
|
|
1503
1606
|
Limit: 1,
|
|
1504
|
-
ScanIndexForward: true
|
|
1505
|
-
})
|
|
1607
|
+
ScanIndexForward: true,
|
|
1608
|
+
}),
|
|
1506
1609
|
);
|
|
1507
1610
|
} catch (error) {
|
|
1508
1611
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1512,7 +1615,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1512
1615
|
if (!oldestItem) {
|
|
1513
1616
|
return 0;
|
|
1514
1617
|
}
|
|
1515
|
-
const oldestTimestamp = oldestItem[
|
|
1618
|
+
const oldestTimestamp = oldestItem['timestamp'];
|
|
1516
1619
|
if (!oldestTimestamp) {
|
|
1517
1620
|
return 0;
|
|
1518
1621
|
}
|
|
@@ -1527,13 +1630,15 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1527
1630
|
getResourceConfig(resource) {
|
|
1528
1631
|
var _a;
|
|
1529
1632
|
this.assertValidResource(resource);
|
|
1530
|
-
return (_a = this.resourceConfigs.get(resource)) != null
|
|
1633
|
+
return (_a = this.resourceConfigs.get(resource)) != null
|
|
1634
|
+
? _a
|
|
1635
|
+
: this.defaultConfig;
|
|
1531
1636
|
}
|
|
1532
1637
|
clear() {
|
|
1533
1638
|
return __async(this, null, function* () {
|
|
1534
1639
|
var _a;
|
|
1535
1640
|
if (this.isDestroyed) {
|
|
1536
|
-
throw new Error(
|
|
1641
|
+
throw new Error('Rate limit store has been destroyed');
|
|
1537
1642
|
}
|
|
1538
1643
|
let lastEvaluatedKey;
|
|
1539
1644
|
do {
|
|
@@ -1542,14 +1647,15 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1542
1647
|
scanResult = yield this.docClient.send(
|
|
1543
1648
|
new libDynamodb.ScanCommand({
|
|
1544
1649
|
TableName: this.tableName,
|
|
1545
|
-
FilterExpression:
|
|
1650
|
+
FilterExpression:
|
|
1651
|
+
'begins_with(pk, :prefix) OR begins_with(pk, :slotPrefix)',
|
|
1546
1652
|
ExpressionAttributeValues: {
|
|
1547
|
-
|
|
1548
|
-
|
|
1653
|
+
':prefix': 'RATELIMIT#',
|
|
1654
|
+
':slotPrefix': 'RATELIMIT_SLOT#',
|
|
1549
1655
|
},
|
|
1550
|
-
ProjectionExpression:
|
|
1551
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
1552
|
-
})
|
|
1656
|
+
ProjectionExpression: 'pk, sk',
|
|
1657
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
1658
|
+
}),
|
|
1553
1659
|
);
|
|
1554
1660
|
} catch (error) {
|
|
1555
1661
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1561,7 +1667,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1561
1667
|
yield batchDeleteWithRetries(
|
|
1562
1668
|
this.docClient,
|
|
1563
1669
|
this.tableName,
|
|
1564
|
-
items.map((item) => ({ pk: item[
|
|
1670
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
1565
1671
|
);
|
|
1566
1672
|
} catch (error) {
|
|
1567
1673
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1589,16 +1695,20 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1589
1695
|
// Private helper methods
|
|
1590
1696
|
calculateCurrentCapacity(resource, metrics) {
|
|
1591
1697
|
var _a, _b;
|
|
1592
|
-
const lastUpdate =
|
|
1593
|
-
|
|
1698
|
+
const lastUpdate =
|
|
1699
|
+
(_a = this.lastCapacityUpdate.get(resource)) != null ? _a : 0;
|
|
1700
|
+
const recalcInterval =
|
|
1701
|
+
this.capacityCalculator.config.recalculationIntervalMs;
|
|
1594
1702
|
if (Date.now() - lastUpdate < recalcInterval) {
|
|
1595
|
-
return (_b = this.cachedCapacity.get(resource)) != null
|
|
1703
|
+
return (_b = this.cachedCapacity.get(resource)) != null
|
|
1704
|
+
? _b
|
|
1705
|
+
: this.getDefaultCapacity(resource);
|
|
1596
1706
|
}
|
|
1597
1707
|
const totalLimit = this.getResourceLimit(resource);
|
|
1598
1708
|
const capacity = this.capacityCalculator.calculateDynamicCapacity(
|
|
1599
1709
|
resource,
|
|
1600
1710
|
totalLimit,
|
|
1601
|
-
metrics
|
|
1711
|
+
metrics,
|
|
1602
1712
|
);
|
|
1603
1713
|
this.cachedCapacity.set(resource, capacity);
|
|
1604
1714
|
this.lastCapacityUpdate.set(resource, Date.now());
|
|
@@ -1609,7 +1719,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1609
1719
|
this.activityMetrics.set(resource, {
|
|
1610
1720
|
recentUserRequests: [],
|
|
1611
1721
|
recentBackgroundRequests: [],
|
|
1612
|
-
userActivityTrend:
|
|
1722
|
+
userActivityTrend: 'none',
|
|
1613
1723
|
});
|
|
1614
1724
|
}
|
|
1615
1725
|
return this.activityMetrics.get(resource);
|
|
@@ -1620,67 +1730,76 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1620
1730
|
return;
|
|
1621
1731
|
}
|
|
1622
1732
|
const now = Date.now();
|
|
1623
|
-
const windowStart =
|
|
1733
|
+
const windowStart =
|
|
1734
|
+
now - this.capacityCalculator.config.monitoringWindowMs;
|
|
1624
1735
|
let userItems;
|
|
1625
1736
|
let backgroundItems;
|
|
1626
1737
|
try {
|
|
1627
1738
|
[userItems, backgroundItems] = yield Promise.all([
|
|
1628
1739
|
queryItemsAllPages(this.docClient, {
|
|
1629
1740
|
TableName: this.tableName,
|
|
1630
|
-
IndexName:
|
|
1631
|
-
KeyConditionExpression:
|
|
1741
|
+
IndexName: 'gsi1',
|
|
1742
|
+
KeyConditionExpression: 'gsi1pk = :gsi1pk AND gsi1sk >= :skStart',
|
|
1632
1743
|
ExpressionAttributeValues: {
|
|
1633
|
-
|
|
1634
|
-
|
|
1744
|
+
':gsi1pk': `RATELIMIT#${resource}#user`,
|
|
1745
|
+
':skStart': `TS#${windowStart}`,
|
|
1635
1746
|
},
|
|
1636
|
-
ProjectionExpression:
|
|
1637
|
-
ExpressionAttributeNames: {
|
|
1747
|
+
ProjectionExpression: '#ts',
|
|
1748
|
+
ExpressionAttributeNames: { '#ts': 'timestamp' },
|
|
1638
1749
|
}),
|
|
1639
1750
|
queryItemsAllPages(this.docClient, {
|
|
1640
1751
|
TableName: this.tableName,
|
|
1641
|
-
IndexName:
|
|
1642
|
-
KeyConditionExpression:
|
|
1752
|
+
IndexName: 'gsi1',
|
|
1753
|
+
KeyConditionExpression: 'gsi1pk = :gsi1pk AND gsi1sk >= :skStart',
|
|
1643
1754
|
ExpressionAttributeValues: {
|
|
1644
|
-
|
|
1645
|
-
|
|
1755
|
+
':gsi1pk': `RATELIMIT#${resource}#background`,
|
|
1756
|
+
':skStart': `TS#${windowStart}`,
|
|
1646
1757
|
},
|
|
1647
|
-
ProjectionExpression:
|
|
1648
|
-
ExpressionAttributeNames: {
|
|
1649
|
-
})
|
|
1758
|
+
ProjectionExpression: '#ts',
|
|
1759
|
+
ExpressionAttributeNames: { '#ts': 'timestamp' },
|
|
1760
|
+
}),
|
|
1650
1761
|
]);
|
|
1651
1762
|
} catch (error) {
|
|
1652
1763
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
1653
1764
|
throw error;
|
|
1654
1765
|
}
|
|
1655
1766
|
const metrics = {
|
|
1656
|
-
recentUserRequests: userItems
|
|
1657
|
-
|
|
1658
|
-
|
|
1767
|
+
recentUserRequests: userItems
|
|
1768
|
+
.map((item) => item['timestamp'])
|
|
1769
|
+
.slice(-this.maxMetricSamples),
|
|
1770
|
+
recentBackgroundRequests: backgroundItems
|
|
1771
|
+
.map((item) => item['timestamp'])
|
|
1772
|
+
.slice(-this.maxMetricSamples),
|
|
1773
|
+
userActivityTrend: 'none',
|
|
1659
1774
|
};
|
|
1660
1775
|
this.cleanupOldRequests(metrics.recentUserRequests);
|
|
1661
1776
|
this.cleanupOldRequests(metrics.recentBackgroundRequests);
|
|
1662
|
-
metrics.userActivityTrend =
|
|
1663
|
-
|
|
1664
|
-
|
|
1777
|
+
metrics.userActivityTrend =
|
|
1778
|
+
this.capacityCalculator.calculateActivityTrend(
|
|
1779
|
+
metrics.recentUserRequests,
|
|
1780
|
+
);
|
|
1665
1781
|
this.activityMetrics.set(resource, metrics);
|
|
1666
1782
|
});
|
|
1667
1783
|
}
|
|
1668
1784
|
getCurrentUsage(resource, priority) {
|
|
1669
1785
|
return __async(this, null, function* () {
|
|
1670
1786
|
var _a;
|
|
1671
|
-
const config =
|
|
1787
|
+
const config =
|
|
1788
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1789
|
+
? _a
|
|
1790
|
+
: this.defaultConfig;
|
|
1672
1791
|
const now = Date.now();
|
|
1673
1792
|
const windowStart = now - config.windowMs;
|
|
1674
1793
|
try {
|
|
1675
1794
|
return yield queryCountAllPages(this.docClient, {
|
|
1676
1795
|
TableName: this.tableName,
|
|
1677
|
-
IndexName:
|
|
1678
|
-
KeyConditionExpression:
|
|
1796
|
+
IndexName: 'gsi1',
|
|
1797
|
+
KeyConditionExpression: 'gsi1pk = :gsi1pk AND gsi1sk >= :skStart',
|
|
1679
1798
|
ExpressionAttributeValues: {
|
|
1680
|
-
|
|
1681
|
-
|
|
1799
|
+
':gsi1pk': `RATELIMIT#${resource}#${priority}`,
|
|
1800
|
+
':skStart': `TS#${windowStart}`,
|
|
1682
1801
|
},
|
|
1683
|
-
Select:
|
|
1802
|
+
Select: 'COUNT',
|
|
1684
1803
|
});
|
|
1685
1804
|
} catch (error) {
|
|
1686
1805
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1691,7 +1810,10 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1691
1810
|
hasPriorityCapacityInWindow(resource, priority, limit) {
|
|
1692
1811
|
return __async(this, null, function* () {
|
|
1693
1812
|
var _a;
|
|
1694
|
-
const config =
|
|
1813
|
+
const config =
|
|
1814
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1815
|
+
? _a
|
|
1816
|
+
: this.defaultConfig;
|
|
1695
1817
|
const now = Date.now();
|
|
1696
1818
|
const windowStart = now - config.windowMs;
|
|
1697
1819
|
try {
|
|
@@ -1699,14 +1821,14 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1699
1821
|
this.docClient,
|
|
1700
1822
|
{
|
|
1701
1823
|
TableName: this.tableName,
|
|
1702
|
-
IndexName:
|
|
1703
|
-
KeyConditionExpression:
|
|
1824
|
+
IndexName: 'gsi1',
|
|
1825
|
+
KeyConditionExpression: 'gsi1pk = :gsi1pk AND gsi1sk >= :skStart',
|
|
1704
1826
|
ExpressionAttributeValues: {
|
|
1705
|
-
|
|
1706
|
-
|
|
1707
|
-
}
|
|
1827
|
+
':gsi1pk': `RATELIMIT#${resource}#${priority}`,
|
|
1828
|
+
':skStart': `TS#${windowStart}`,
|
|
1829
|
+
},
|
|
1708
1830
|
},
|
|
1709
|
-
limit
|
|
1831
|
+
limit,
|
|
1710
1832
|
);
|
|
1711
1833
|
return !reachedLimit;
|
|
1712
1834
|
} catch (error) {
|
|
@@ -1716,7 +1838,8 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1716
1838
|
});
|
|
1717
1839
|
}
|
|
1718
1840
|
cleanupOldRequests(requests) {
|
|
1719
|
-
const cutoff =
|
|
1841
|
+
const cutoff =
|
|
1842
|
+
Date.now() - this.capacityCalculator.config.monitoringWindowMs;
|
|
1720
1843
|
const idx = requests.findIndex((t) => t >= cutoff);
|
|
1721
1844
|
if (idx > 0) {
|
|
1722
1845
|
requests.splice(0, idx);
|
|
@@ -1734,7 +1857,10 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1734
1857
|
}
|
|
1735
1858
|
getResourceLimit(resource) {
|
|
1736
1859
|
var _a;
|
|
1737
|
-
const config =
|
|
1860
|
+
const config =
|
|
1861
|
+
(_a = this.resourceConfigs.get(resource)) != null
|
|
1862
|
+
? _a
|
|
1863
|
+
: this.defaultConfig;
|
|
1738
1864
|
return config.limit;
|
|
1739
1865
|
}
|
|
1740
1866
|
getDefaultCapacity(resource) {
|
|
@@ -1745,7 +1871,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1745
1871
|
userReserved,
|
|
1746
1872
|
backgroundMax,
|
|
1747
1873
|
backgroundPaused: false,
|
|
1748
|
-
reason:
|
|
1874
|
+
reason: 'Default capacity allocation',
|
|
1749
1875
|
};
|
|
1750
1876
|
}
|
|
1751
1877
|
deleteResourceItems(resource) {
|
|
@@ -1754,7 +1880,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1754
1880
|
const partitionKeys = [
|
|
1755
1881
|
`RATELIMIT#${resource}`,
|
|
1756
1882
|
`RATELIMIT_SLOT#${resource}#user`,
|
|
1757
|
-
`RATELIMIT_SLOT#${resource}#background
|
|
1883
|
+
`RATELIMIT_SLOT#${resource}#background`,
|
|
1758
1884
|
];
|
|
1759
1885
|
for (const pk of partitionKeys) {
|
|
1760
1886
|
let lastEvaluatedKey;
|
|
@@ -1764,11 +1890,11 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1764
1890
|
queryResult = yield this.docClient.send(
|
|
1765
1891
|
new libDynamodb.QueryCommand({
|
|
1766
1892
|
TableName: this.tableName,
|
|
1767
|
-
KeyConditionExpression:
|
|
1768
|
-
ExpressionAttributeValues: {
|
|
1769
|
-
ProjectionExpression:
|
|
1770
|
-
ExclusiveStartKey: lastEvaluatedKey
|
|
1771
|
-
})
|
|
1893
|
+
KeyConditionExpression: 'pk = :pk',
|
|
1894
|
+
ExpressionAttributeValues: { ':pk': pk },
|
|
1895
|
+
ProjectionExpression: 'pk, sk',
|
|
1896
|
+
ExclusiveStartKey: lastEvaluatedKey,
|
|
1897
|
+
}),
|
|
1772
1898
|
);
|
|
1773
1899
|
} catch (error) {
|
|
1774
1900
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1780,7 +1906,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1780
1906
|
yield batchDeleteWithRetries(
|
|
1781
1907
|
this.docClient,
|
|
1782
1908
|
this.tableName,
|
|
1783
|
-
items.map((item) => ({ pk: item[
|
|
1909
|
+
items.map((item) => ({ pk: item['pk'], sk: item['sk'] })),
|
|
1784
1910
|
);
|
|
1785
1911
|
} catch (error) {
|
|
1786
1912
|
throwIfDynamoTableMissing(error, this.tableName);
|
|
@@ -1793,7 +1919,7 @@ var DynamoDBAdaptiveRateLimitStore = class {
|
|
|
1793
1919
|
});
|
|
1794
1920
|
}
|
|
1795
1921
|
assertValidResource(resource) {
|
|
1796
|
-
assertDynamoKeyPart(resource,
|
|
1922
|
+
assertDynamoKeyPart(resource, 'resource');
|
|
1797
1923
|
}
|
|
1798
1924
|
};
|
|
1799
1925
|
|
|
@@ -1804,4 +1930,4 @@ exports.DynamoDBDedupeStore = DynamoDBDedupeStore;
|
|
|
1804
1930
|
exports.DynamoDBRateLimitStore = DynamoDBRateLimitStore;
|
|
1805
1931
|
exports.TABLE_SCHEMA = TABLE_SCHEMA;
|
|
1806
1932
|
//# sourceMappingURL=index.cjs.map
|
|
1807
|
-
//# sourceMappingURL=index.cjs.map
|
|
1933
|
+
//# sourceMappingURL=index.cjs.map
|