@flipboxlabs/aws-audit-sdk 1.2.0 → 1.2.3
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 +1 -1
- package/dist/config.d.ts +13 -3
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +8 -1
- package/dist/repository.d.ts +16 -2
- package/dist/repository.d.ts.map +1 -1
- package/dist/repository.js +52 -16
- package/dist/repository.utils.d.ts +10 -11
- package/dist/repository.utils.d.ts.map +1 -1
- package/dist/repository.utils.js +13 -38
- package/dist/test-config.d.ts +2 -2
- package/package.json +1 -1
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 (
|
|
123
|
+
if (this.storedAudits.length >= MAX_AUDITS_SIZE) {
|
|
124
124
|
this.publishStoredAudits();
|
|
125
125
|
}
|
|
126
126
|
this.config.schemas.resourceReference.parse(item.target);
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import * as z from "zod/v4";
|
|
2
|
+
/**
|
|
3
|
+
* Default TTL for audit records in seconds (90 days).
|
|
4
|
+
*/
|
|
5
|
+
export declare const DEFAULT_TTL_SECONDS: number;
|
|
2
6
|
/**
|
|
3
7
|
* Input configuration for defining audit apps and resource types.
|
|
4
8
|
*/
|
|
@@ -6,6 +10,12 @@ export interface AuditConfigInput {
|
|
|
6
10
|
readonly apps: readonly string[];
|
|
7
11
|
readonly resourceTypes: readonly string[];
|
|
8
12
|
readonly service?: string;
|
|
13
|
+
/**
|
|
14
|
+
* Time-to-live for audit records in seconds.
|
|
15
|
+
* DynamoDB will automatically delete records after this period.
|
|
16
|
+
* @default 7776000 (90 days)
|
|
17
|
+
*/
|
|
18
|
+
readonly ttlSeconds?: number;
|
|
9
19
|
}
|
|
10
20
|
/**
|
|
11
21
|
* Creates an audit configuration object with typed schemas.
|
|
@@ -33,9 +43,9 @@ export interface AuditConfigInput {
|
|
|
33
43
|
* config.schemas.app.parse('Invalid'); // ❌ throws
|
|
34
44
|
* ```
|
|
35
45
|
*/
|
|
36
|
-
export declare function defineAuditConfig<const C extends AuditConfigInput>(input: C): {
|
|
37
|
-
|
|
38
|
-
|
|
46
|
+
export declare function defineAuditConfig<const C extends AuditConfigInput>(input: C): C & {
|
|
47
|
+
ttlSeconds: number;
|
|
48
|
+
readonly service: string | undefined;
|
|
39
49
|
schemas: {
|
|
40
50
|
app: z.ZodEnum<{
|
|
41
51
|
[x: string]: string;
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAE5B;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAE5B;;GAEG;AACH,eAAO,MAAM,mBAAmB,QAAoB,CAAC;AAErD;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,CAAC;IACjC,QAAQ,CAAC,aAAa,EAAE,SAAS,MAAM,EAAE,CAAC;IAC1C,QAAQ,CAAC,OAAO,CAAC,EAAE,MAAM,CAAC;IAC1B;;;;OAIG;IACH,QAAQ,CAAC,UAAU,CAAC,EAAE,MAAM,CAAC;CAC9B;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,iBAAiB,CAAC,KAAK,CAAC,CAAC,SAAS,gBAAgB,EAAE,KAAK,EAAE,CAAC;;;;;;;;;;;;;;;;;;;;YAqB1D;QACZ,GAAG,oBAAM;QACT,YAAY,6BAAe;KAC5B;EAEJ;AAED;;GAEG;AACH,MAAM,MAAM,WAAW,GAAG,UAAU,CAAC,OAAO,iBAAiB,CAAC,CAAC"}
|
package/dist/config.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
1
|
import * as z from "zod/v4";
|
|
2
|
+
/**
|
|
3
|
+
* Default TTL for audit records in seconds (90 days).
|
|
4
|
+
*/
|
|
5
|
+
export const DEFAULT_TTL_SECONDS = 60 * 60 * 24 * 90;
|
|
2
6
|
/**
|
|
3
7
|
* Creates an audit configuration object with typed schemas.
|
|
4
8
|
*
|
|
@@ -36,8 +40,11 @@ export function defineAuditConfig(input) {
|
|
|
36
40
|
}),
|
|
37
41
|
};
|
|
38
42
|
return {
|
|
39
|
-
service: process.env.SERVICE,
|
|
40
43
|
...input,
|
|
44
|
+
ttlSeconds: input.ttlSeconds ?? DEFAULT_TTL_SECONDS,
|
|
45
|
+
get service() {
|
|
46
|
+
return input.service ?? process.env.SERVICE;
|
|
47
|
+
},
|
|
41
48
|
schemas,
|
|
42
49
|
_types: {},
|
|
43
50
|
};
|
package/dist/repository.d.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Logger } from "@aws-lambda-powertools/logger";
|
|
2
2
|
import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
|
|
3
3
|
import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
|
|
4
|
-
import type
|
|
4
|
+
import { type AuditConfig } from "./config.js";
|
|
5
5
|
import { type Audit } from "./schema/audit.js";
|
|
6
6
|
import { type Pagination } from "./schema/model.js";
|
|
7
7
|
import type { UpsertAuditInput } from "./schema/service.js";
|
|
@@ -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 (
|
|
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
|
*
|
package/dist/repository.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,EAEL,cAAc,EAKf,MAAM,0BAA0B,CAAC;AAClC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,wBAAwB,CAAC;AAEnE,OAAO,KAAK,
|
|
1
|
+
{"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
|
package/dist/repository.js
CHANGED
|
@@ -1,16 +1,12 @@
|
|
|
1
1
|
import { BatchWriteItemCommand, DynamoDBClient, GetItemCommand, QueryCommand, UpdateItemCommand, } from "@aws-sdk/client-dynamodb";
|
|
2
2
|
import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
|
|
3
|
+
import { DEFAULT_TTL_SECONDS } from "./config.js";
|
|
3
4
|
import { DynamoDB } from "./constants.js";
|
|
4
5
|
import { decodeNextPageToken, encodeNextPageToken } from "./repository.utils.js";
|
|
5
6
|
import { AuditListItemPayloadSchema, AuditPayloadSchema, AuditSchema, } from "./schema/audit.js";
|
|
6
7
|
import { PaginationCollectionSchema } from "./schema/model.js";
|
|
7
8
|
import { AuditStorageSchema } from "./schema/storage.js";
|
|
8
9
|
import { getTraceParts } from "./utils.js";
|
|
9
|
-
/**
|
|
10
|
-
* Default TTL for audit records in seconds (90 days).
|
|
11
|
-
* Records will be automatically deleted by DynamoDB after this period.
|
|
12
|
-
*/
|
|
13
|
-
const DEFAULT_TTL = 60 * 60 * 24 * 90; // 90 days
|
|
14
10
|
/**
|
|
15
11
|
* Repository for managing audit records in DynamoDB.
|
|
16
12
|
*
|
|
@@ -126,7 +122,7 @@ export class AuditRepository {
|
|
|
126
122
|
* - Timestamps (createdAt, updatedAt)
|
|
127
123
|
*
|
|
128
124
|
* @param items - Array of audit records to upsert
|
|
129
|
-
* @returns True when the operation completes (
|
|
125
|
+
* @returns True when the operation completes (retries unprocessed items with exponential backoff; throws if max retries exceeded)
|
|
130
126
|
*
|
|
131
127
|
* @example
|
|
132
128
|
* ```typescript
|
|
@@ -165,7 +161,7 @@ export class AuditRepository {
|
|
|
165
161
|
app: payload.target.app,
|
|
166
162
|
}),
|
|
167
163
|
...this.constructSecondaryKeys(payload),
|
|
168
|
-
...this.constructTTLAttribute(
|
|
164
|
+
...this.constructTTLAttribute(this.config.ttlSeconds),
|
|
169
165
|
...payload,
|
|
170
166
|
}, {
|
|
171
167
|
removeUndefinedValues: true,
|
|
@@ -180,13 +176,53 @@ export class AuditRepository {
|
|
|
180
176
|
for (let i = 0, j = Items.length; i < j; i += BATCH_SIZE) {
|
|
181
177
|
ItemBatches.push(Items.slice(i, i + BATCH_SIZE));
|
|
182
178
|
}
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
}))));
|
|
179
|
+
// Process batches sequentially to reduce risk of triggering additional throttling
|
|
180
|
+
for (const ItemBatch of ItemBatches) {
|
|
181
|
+
await this.writeBatchWithRetry(ItemBatch, DynamoDB.Table.Name());
|
|
182
|
+
}
|
|
188
183
|
return true;
|
|
189
184
|
}
|
|
185
|
+
/**
|
|
186
|
+
* Writes a batch of items to DynamoDB with exponential backoff retry for unprocessed items.
|
|
187
|
+
*
|
|
188
|
+
* DynamoDB's BatchWriteItem can return unprocessed items when throttled or under transient
|
|
189
|
+
* errors without throwing an exception. This method retries those items automatically.
|
|
190
|
+
*
|
|
191
|
+
* @param items - Array of WriteRequests to send
|
|
192
|
+
* @param tableName - Target DynamoDB table name
|
|
193
|
+
* @param maxRetries - Maximum number of retry attempts (default: 8)
|
|
194
|
+
* @param baseDelayMs - Initial delay in milliseconds before first retry (default: 100)
|
|
195
|
+
* @throws Error if unprocessed items remain after maxRetries attempts
|
|
196
|
+
* @internal
|
|
197
|
+
*/
|
|
198
|
+
async writeBatchWithRetry(items, tableName, maxRetries = 8, baseDelayMs = 100) {
|
|
199
|
+
let requestItems = { [tableName]: items };
|
|
200
|
+
let attempt = 0;
|
|
201
|
+
let delayMs = baseDelayMs;
|
|
202
|
+
while (attempt <= maxRetries) {
|
|
203
|
+
const response = await this.client.send(new BatchWriteItemCommand({ RequestItems: requestItems }));
|
|
204
|
+
const unprocessed = response.UnprocessedItems;
|
|
205
|
+
if (!unprocessed || Object.keys(unprocessed).length === 0) {
|
|
206
|
+
return; // all items written successfully
|
|
207
|
+
}
|
|
208
|
+
attempt++;
|
|
209
|
+
if (attempt > maxRetries) {
|
|
210
|
+
this.logger.error("BatchWriteItem: unprocessed items remain after max retries", {
|
|
211
|
+
unprocessed,
|
|
212
|
+
attempt,
|
|
213
|
+
});
|
|
214
|
+
throw new Error(`BatchWriteItem failed: unprocessed items after ${maxRetries} retries`);
|
|
215
|
+
}
|
|
216
|
+
this.logger.warn("BatchWriteItem: retrying unprocessed items", {
|
|
217
|
+
count: Object.values(unprocessed).flat().length,
|
|
218
|
+
attempt,
|
|
219
|
+
delayMs,
|
|
220
|
+
});
|
|
221
|
+
await new Promise((resolve) => setTimeout(resolve, delayMs));
|
|
222
|
+
delayMs = Math.min(delayMs * 2, 30_000); // cap at 30 seconds
|
|
223
|
+
requestItems = unprocessed;
|
|
224
|
+
}
|
|
225
|
+
}
|
|
190
226
|
/**
|
|
191
227
|
* Upserts a single audit record with atomic attempt tracking.
|
|
192
228
|
*
|
|
@@ -223,7 +259,7 @@ export class AuditRepository {
|
|
|
223
259
|
app: payload.target.app,
|
|
224
260
|
});
|
|
225
261
|
const secondaryKeys = this.constructSecondaryKeys(payload);
|
|
226
|
-
const ttlAttribute = this.constructTTLAttribute(
|
|
262
|
+
const ttlAttribute = this.constructTTLAttribute(this.config.ttlSeconds);
|
|
227
263
|
const expressionAttributeNames = {};
|
|
228
264
|
const expressionAttributeValues = {
|
|
229
265
|
":emptyList": [],
|
|
@@ -504,7 +540,7 @@ export class AuditRepository {
|
|
|
504
540
|
* @returns TTL attribute with Unix timestamp in seconds
|
|
505
541
|
* @internal
|
|
506
542
|
*/
|
|
507
|
-
constructTTLAttribute(ttlSeconds =
|
|
543
|
+
constructTTLAttribute(ttlSeconds = DEFAULT_TTL_SECONDS, date) {
|
|
508
544
|
const ttl = date || new Date();
|
|
509
545
|
if (ttlSeconds) {
|
|
510
546
|
ttl.setSeconds(ttl.getSeconds() + ttlSeconds);
|
|
@@ -524,11 +560,11 @@ export class AuditRepository {
|
|
|
524
560
|
* @internal
|
|
525
561
|
*/
|
|
526
562
|
transformItem(item) {
|
|
527
|
-
return
|
|
563
|
+
return AuditSchema.parse({
|
|
528
564
|
trace: `${item.GSI1_SN_PK}:${item.GSI1_SN_SK}`,
|
|
529
565
|
...item,
|
|
530
566
|
id: item.id.split("#").pop(),
|
|
531
|
-
})
|
|
567
|
+
});
|
|
532
568
|
}
|
|
533
569
|
/**
|
|
534
570
|
* Transforms a trace listing item into an audit list item payload.
|
|
@@ -1,34 +1,33 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* Encodes a pagination object into
|
|
2
|
+
* Encodes a pagination object into a base64url token string.
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
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
|
|
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
|
|
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
|
|
20
|
+
* Decodes a base64url pagination token back into a DynamoDB key object.
|
|
22
21
|
*
|
|
23
|
-
* Reverses the
|
|
22
|
+
* Reverses the encoding performed by {@link encodeNextPageToken} to
|
|
24
23
|
* restore the original LastEvaluatedKey for DynamoDB queries.
|
|
25
24
|
*
|
|
26
|
-
* @param nextPageString -
|
|
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 = "
|
|
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":"
|
|
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"}
|
package/dist/repository.utils.js
CHANGED
|
@@ -1,70 +1,45 @@
|
|
|
1
|
-
import * as crypto from "node:crypto";
|
|
2
1
|
/**
|
|
3
|
-
*
|
|
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
|
-
*
|
|
15
|
-
*
|
|
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
|
|
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
|
|
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
|
-
|
|
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
|
|
25
|
+
* Decodes a base64url pagination token back into a DynamoDB key object.
|
|
41
26
|
*
|
|
42
|
-
* Reverses the
|
|
27
|
+
* Reverses the encoding performed by {@link encodeNextPageToken} to
|
|
43
28
|
* restore the original LastEvaluatedKey for DynamoDB queries.
|
|
44
29
|
*
|
|
45
|
-
* @param nextPageString -
|
|
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 = "
|
|
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
|
-
|
|
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/dist/test-config.d.ts
CHANGED
|
@@ -3,11 +3,11 @@
|
|
|
3
3
|
* Provides sample apps and resource types for testing.
|
|
4
4
|
*/
|
|
5
5
|
export declare const testConfig: {
|
|
6
|
-
service: string | undefined;
|
|
7
|
-
} & {
|
|
8
6
|
readonly apps: readonly ["App1", "TestApp"];
|
|
9
7
|
readonly resourceTypes: readonly ["Unknown", "User", "Order"];
|
|
10
8
|
} & {
|
|
9
|
+
ttlSeconds: number;
|
|
10
|
+
readonly service: string | undefined;
|
|
11
11
|
schemas: {
|
|
12
12
|
app: import("zod/v4").ZodEnum<{
|
|
13
13
|
[x: string]: string;
|