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