@flipboxlabs/aws-audit-sdk 1.1.3 → 1.2.2

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/dist/audits.js CHANGED
@@ -120,7 +120,7 @@ export class Audits {
120
120
  * @param item - The audit entry to buffer
121
121
  */
122
122
  addAudit(item) {
123
- if (Object.keys(this.storedAudits).length >= MAX_AUDITS_SIZE) {
123
+ if (this.storedAudits.length >= MAX_AUDITS_SIZE) {
124
124
  this.publishStoredAudits();
125
125
  }
126
126
  this.config.schemas.resourceReference.parse(item.target);
@@ -176,7 +176,7 @@ export declare class AuditRepository<C extends AuditConfig> {
176
176
  * - Timestamps (createdAt, updatedAt)
177
177
  *
178
178
  * @param items - Array of audit records to upsert
179
- * @returns True when the operation completes (does not check for unprocessed items)
179
+ * @returns True when the operation completes (retries unprocessed items with exponential backoff; throws if max retries exceeded)
180
180
  *
181
181
  * @example
182
182
  * ```typescript
@@ -197,6 +197,20 @@ export declare class AuditRepository<C extends AuditConfig> {
197
197
  * ```
198
198
  */
199
199
  upsertBatch(items: Array<UpsertAuditInput>): Promise<boolean>;
200
+ /**
201
+ * Writes a batch of items to DynamoDB with exponential backoff retry for unprocessed items.
202
+ *
203
+ * DynamoDB's BatchWriteItem can return unprocessed items when throttled or under transient
204
+ * errors without throwing an exception. This method retries those items automatically.
205
+ *
206
+ * @param items - Array of WriteRequests to send
207
+ * @param tableName - Target DynamoDB table name
208
+ * @param maxRetries - Maximum number of retry attempts (default: 8)
209
+ * @param baseDelayMs - Initial delay in milliseconds before first retry (default: 100)
210
+ * @throws Error if unprocessed items remain after maxRetries attempts
211
+ * @internal
212
+ */
213
+ private writeBatchWithRetry;
200
214
  /**
201
215
  * Upserts a single audit record with atomic attempt tracking.
202
216
  *
@@ -1 +1 @@
1
- {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
@@ -126,7 +126,7 @@ export class AuditRepository {
126
126
  * - Timestamps (createdAt, updatedAt)
127
127
  *
128
128
  * @param items - Array of audit records to upsert
129
- * @returns True when the operation completes (does not check for unprocessed items)
129
+ * @returns True when the operation completes (retries unprocessed items with exponential backoff; throws if max retries exceeded)
130
130
  *
131
131
  * @example
132
132
  * ```typescript
@@ -180,13 +180,53 @@ export class AuditRepository {
180
180
  for (let i = 0, j = Items.length; i < j; i += BATCH_SIZE) {
181
181
  ItemBatches.push(Items.slice(i, i + BATCH_SIZE));
182
182
  }
183
- await Promise.all(ItemBatches.map((ItemBatch) => this.client.send(new BatchWriteItemCommand({
184
- RequestItems: {
185
- [DynamoDB.Table.Name()]: ItemBatch,
186
- },
187
- }))));
183
+ // Process batches sequentially to reduce risk of triggering additional throttling
184
+ for (const ItemBatch of ItemBatches) {
185
+ await this.writeBatchWithRetry(ItemBatch, DynamoDB.Table.Name());
186
+ }
188
187
  return true;
189
188
  }
189
+ /**
190
+ * Writes a batch of items to DynamoDB with exponential backoff retry for unprocessed items.
191
+ *
192
+ * DynamoDB's BatchWriteItem can return unprocessed items when throttled or under transient
193
+ * errors without throwing an exception. This method retries those items automatically.
194
+ *
195
+ * @param items - Array of WriteRequests to send
196
+ * @param tableName - Target DynamoDB table name
197
+ * @param maxRetries - Maximum number of retry attempts (default: 8)
198
+ * @param baseDelayMs - Initial delay in milliseconds before first retry (default: 100)
199
+ * @throws Error if unprocessed items remain after maxRetries attempts
200
+ * @internal
201
+ */
202
+ async writeBatchWithRetry(items, tableName, maxRetries = 8, baseDelayMs = 100) {
203
+ let requestItems = { [tableName]: items };
204
+ let attempt = 0;
205
+ let delayMs = baseDelayMs;
206
+ while (attempt <= maxRetries) {
207
+ const response = await this.client.send(new BatchWriteItemCommand({ RequestItems: requestItems }));
208
+ const unprocessed = response.UnprocessedItems;
209
+ if (!unprocessed || Object.keys(unprocessed).length === 0) {
210
+ return; // all items written successfully
211
+ }
212
+ attempt++;
213
+ if (attempt > maxRetries) {
214
+ this.logger.error("BatchWriteItem: unprocessed items remain after max retries", {
215
+ unprocessed,
216
+ attempt,
217
+ });
218
+ throw new Error(`BatchWriteItem failed: unprocessed items after ${maxRetries} retries`);
219
+ }
220
+ this.logger.warn("BatchWriteItem: retrying unprocessed items", {
221
+ count: Object.values(unprocessed).flat().length,
222
+ attempt,
223
+ delayMs,
224
+ });
225
+ await new Promise((resolve) => setTimeout(resolve, delayMs));
226
+ delayMs = Math.min(delayMs * 2, 30_000); // cap at 30 seconds
227
+ requestItems = unprocessed;
228
+ }
229
+ }
190
230
  /**
191
231
  * Upserts a single audit record with atomic attempt tracking.
192
232
  *
@@ -524,11 +564,11 @@ export class AuditRepository {
524
564
  * @internal
525
565
  */
526
566
  transformItem(item) {
527
- return Promise.resolve(AuditSchema.parse({
567
+ return AuditSchema.parse({
528
568
  trace: `${item.GSI1_SN_PK}:${item.GSI1_SN_SK}`,
529
569
  ...item,
530
570
  id: item.id.split("#").pop(),
531
- }));
571
+ });
532
572
  }
533
573
  /**
534
574
  * Transforms a trace listing item into an audit list item payload.
@@ -1,34 +1,33 @@
1
1
  /**
2
- * Encodes a pagination object into an encrypted token string.
2
+ * Encodes a pagination object into a base64url token string.
3
3
  *
4
- * Uses AES-256-CTR encryption to obfuscate the DynamoDB LastEvaluatedKey,
5
- * preventing clients from tampering with pagination state.
6
- *
7
- * The token format is: `{iv}:{encryptedData}` where both parts are hex-encoded.
4
+ * Pagination tokens are opaque cursors representing DynamoDB LastEvaluatedKey
5
+ * objects. They do not require confidentiality — base64url encoding provides
6
+ * a compact, URL-safe representation.
8
7
  *
9
8
  * @param nextPageObject - DynamoDB LastEvaluatedKey object to encode
10
- * @returns Encrypted pagination token string, or undefined if input is null/undefined
9
+ * @returns Base64url-encoded pagination token string, or undefined if input is null/undefined
11
10
  *
12
11
  * @example
13
12
  * ```typescript
14
13
  * const lastKey = { PK: 'App1.USER', SK: 'audit-123' };
15
14
  * const token = encodeNextPageToken(lastKey);
16
- * // Returns something like: "a1b2c3d4...:e5f6g7h8..."
15
+ * // Returns a base64url string like: "eyJQSyI6IkFwcDEuVVNFUiIsIlNLIjoiYXVkaXQtMTIzIn0"
17
16
  * ```
18
17
  */
19
18
  export declare function encodeNextPageToken(nextPageObject?: Record<string, string>): string | undefined;
20
19
  /**
21
- * Decodes an encrypted pagination token back into a DynamoDB key object.
20
+ * Decodes a base64url pagination token back into a DynamoDB key object.
22
21
  *
23
- * Reverses the encryption performed by {@link encodeNextPageToken} to
22
+ * Reverses the encoding performed by {@link encodeNextPageToken} to
24
23
  * restore the original LastEvaluatedKey for DynamoDB queries.
25
24
  *
26
- * @param nextPageString - Encrypted pagination token from a previous response
25
+ * @param nextPageString - Base64url-encoded pagination token from a previous response
27
26
  * @returns Decoded DynamoDB key object, or undefined if input is null/undefined/invalid
28
27
  *
29
28
  * @example
30
29
  * ```typescript
31
- * const token = "a1b2c3d4...:e5f6g7h8...";
30
+ * const token = "eyJQSyI6IkFwcDEuVVNFUiIsIlNLIjoiYXVkaXQtMTIzIn0";
32
31
  * const lastKey = decodeNextPageToken(token);
33
32
  * // Returns: { PK: 'App1.USER', SK: 'audit-123' }
34
33
  * ```
@@ -1 +1 @@
1
- {"version":3,"file":"repository.utils.d.ts","sourceRoot":"","sources":["../src/repository.utils.ts"],"names":[],"mappings":"AAaA;;;;;;;;;;;;;;;;;GAiBG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAgB/F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAuBpC"}
1
+ {"version":3,"file":"repository.utils.d.ts","sourceRoot":"","sources":["../src/repository.utils.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;GAgBG;AACH,wBAAgB,mBAAmB,CAAC,cAAc,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,MAAM,GAAG,SAAS,CAM/F;AAED;;;;;;;;;;;;;;;GAeG;AACH,wBAAgB,mBAAmB,CACjC,cAAc,CAAC,EAAE,MAAM,GAAG,IAAI,GAAG,SAAS,GACzC,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAAG,SAAS,CAMpC"}
@@ -1,70 +1,45 @@
1
- import * as crypto from "node:crypto";
2
1
  /**
3
- * Encryption algorithm used for pagination tokens.
4
- * AES-256-CTR provides symmetric encryption with counter mode.
5
- */
6
- const ENCRYPTION_ALGORITHM = "aes-256-ctr";
7
- /**
8
- * Key size in bytes for AES-256 encryption.
9
- */
10
- const KEY_SIZE = 32;
11
- /**
12
- * Encodes a pagination object into an encrypted token string.
2
+ * Encodes a pagination object into a base64url token string.
13
3
  *
14
- * Uses AES-256-CTR encryption to obfuscate the DynamoDB LastEvaluatedKey,
15
- * preventing clients from tampering with pagination state.
16
- *
17
- * The token format is: `{iv}:{encryptedData}` where both parts are hex-encoded.
4
+ * Pagination tokens are opaque cursors representing DynamoDB LastEvaluatedKey
5
+ * objects. They do not require confidentiality — base64url encoding provides
6
+ * a compact, URL-safe representation.
18
7
  *
19
8
  * @param nextPageObject - DynamoDB LastEvaluatedKey object to encode
20
- * @returns Encrypted pagination token string, or undefined if input is null/undefined
9
+ * @returns Base64url-encoded pagination token string, or undefined if input is null/undefined
21
10
  *
22
11
  * @example
23
12
  * ```typescript
24
13
  * const lastKey = { PK: 'App1.USER', SK: 'audit-123' };
25
14
  * const token = encodeNextPageToken(lastKey);
26
- * // Returns something like: "a1b2c3d4...:e5f6g7h8..."
15
+ * // Returns a base64url string like: "eyJQSyI6IkFwcDEuVVNFUiIsIlNLIjoiYXVkaXQtMTIzIn0"
27
16
  * ```
28
17
  */
29
18
  export function encodeNextPageToken(nextPageObject) {
30
19
  if (nextPageObject == null) {
31
20
  return undefined;
32
21
  }
33
- const nextPageString = JSON.stringify(nextPageObject);
34
- const iv = crypto.randomBytes(16);
35
- const cipher = crypto.createCipheriv(ENCRYPTION_ALGORITHM, Buffer.concat([Buffer.alloc(KEY_SIZE)], KEY_SIZE), iv);
36
- const encrypted = cipher.update(nextPageString);
37
- return [iv.toString("hex"), encrypted.toString("hex")].join(":");
22
+ return Buffer.from(JSON.stringify(nextPageObject)).toString("base64url");
38
23
  }
39
24
  /**
40
- * Decodes an encrypted pagination token back into a DynamoDB key object.
25
+ * Decodes a base64url pagination token back into a DynamoDB key object.
41
26
  *
42
- * Reverses the encryption performed by {@link encodeNextPageToken} to
27
+ * Reverses the encoding performed by {@link encodeNextPageToken} to
43
28
  * restore the original LastEvaluatedKey for DynamoDB queries.
44
29
  *
45
- * @param nextPageString - Encrypted pagination token from a previous response
30
+ * @param nextPageString - Base64url-encoded pagination token from a previous response
46
31
  * @returns Decoded DynamoDB key object, or undefined if input is null/undefined/invalid
47
32
  *
48
33
  * @example
49
34
  * ```typescript
50
- * const token = "a1b2c3d4...:e5f6g7h8...";
35
+ * const token = "eyJQSyI6IkFwcDEuVVNFUiIsIlNLIjoiYXVkaXQtMTIzIn0";
51
36
  * const lastKey = decodeNextPageToken(token);
52
37
  * // Returns: { PK: 'App1.USER', SK: 'audit-123' }
53
38
  * ```
54
39
  */
55
40
  export function decodeNextPageToken(nextPageString) {
56
- if (nextPageString == null) {
57
- return undefined;
58
- }
59
- const textParts = nextPageString.split(":");
60
- const iv = textParts.shift();
61
- if (!iv) {
41
+ if (nextPageString == null || nextPageString === "") {
62
42
  return undefined;
63
43
  }
64
- const decipher = crypto.createDecipheriv(ENCRYPTION_ALGORITHM, Buffer.concat([Buffer.alloc(KEY_SIZE)], KEY_SIZE), Buffer.from(iv, "hex"));
65
- const decrypted = Buffer.concat([
66
- decipher.update(Buffer.from(textParts.join(":"), "hex")),
67
- decipher.final(),
68
- ]);
69
- return JSON.parse(decrypted.toString());
44
+ return JSON.parse(Buffer.from(nextPageString, "base64url").toString());
70
45
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flipboxlabs/aws-audit-sdk",
3
- "version": "1.1.3",
3
+ "version": "1.2.2",
4
4
  "description": "AWS Audit SDK - Core SDK for audit logging and event management",
5
5
  "keywords": [
6
6
  "audit",