@flipboxlabs/aws-audit-sdk 1.2.3 → 1.4.1

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.
@@ -79,6 +79,10 @@ export declare const DynamoDB: {
79
79
  readonly LSI1_S_SORT_KEY: "LSI1_S_SK";
80
80
  /** LSI1 (Numeric) sort key */
81
81
  readonly LSI1_N_SORT_KEY: "LSI1_N_SK";
82
+ /** GSI2 (String-String) partition key - for status-based queries */
83
+ readonly GSI2_SS_PARTITION_KEY: "GSI2_SS_PK";
84
+ /** GSI2 (String-String) sort key - for status-based queries */
85
+ readonly GSI2_SS_SORT_KEY: "GSI2_SS_SK";
82
86
  };
83
87
  /** Secondary index names */
84
88
  readonly Indexes: {
@@ -86,6 +90,8 @@ export declare const DynamoDB: {
86
90
  readonly GSI1_SS: "GSI1_SS";
87
91
  /** Global Secondary Index 1 - String partition, Numeric sort */
88
92
  readonly GSI1_SN: "GSI1_SN";
93
+ /** Global Secondary Index 2 - String partition, String sort (status-based queries) */
94
+ readonly GSI2_SS: "GSI2_SS";
89
95
  /** Local Secondary Index 1 - String sort key */
90
96
  readonly LSI1_S: "LSI1_S";
91
97
  /** Local Secondary Index 1 - Numeric sort key */
@@ -1 +1 @@
1
- {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;GAEG;AACH,KAAK,UAAU,GAAG;IAChB,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IAEZ,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,KAAK,SAAS,GAAG,UAAU,GAAG;IAC5B,yCAAyC;IACzC,GAAG,EAAE;QACH,qCAAqC;QACrC,MAAM,EAAE,MAAM,CAAC;QACf,qBAAqB;QACrB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,QAAQ;IACnB,oCAAoC;;QAElC,6DAA6D;iCAC7C,UAAU;QAC1B,4CAA4C;gCAC7B,SAAS;;IAE1B,mCAAmC;;QAEjC,4BAA4B;;QAE5B,uBAAuB;;QAGvB,yCAAyC;;QAEzC,oCAAoC;;QAGpC,yCAAyC;;QAEzC,oCAAoC;;QAGpC,6BAA6B;;QAE7B,8BAA8B;;;IAGhC,4BAA4B;;QAE1B,+DAA+D;;QAE/D,gEAAgE;;QAGhE,gDAAgD;;QAEhD,iDAAiD;;;IAGnD,8BAA8B;;QAE5B,2DAA2D;;;CAGrD,CAAC;AA0CX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,WAAW;IACtB,wCAAwC;;QAEtC,8DAA8D;iCAC9C,UAAU;QAC1B,6CAA6C;gCAC9B,SAAS;;IAE1B,yCAAyC;;IAEzC,wDAAwD;;QAEtD,yDAAyD;;QAEzD,8CAA8C;;;CAGxC,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC"}
1
+ {"version":3,"file":"constants.d.ts","sourceRoot":"","sources":["../src/constants.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AACH,eAAO,MAAM,oBAAoB,WAAW,CAAC;AAE7C;;GAEG;AACH,KAAK,UAAU,GAAG;IAChB,wDAAwD;IACxD,GAAG,EAAE,MAAM,CAAC;IAEZ,4CAA4C;IAC5C,OAAO,CAAC,EAAE,MAAM,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,KAAK,SAAS,GAAG,UAAU,GAAG;IAC5B,yCAAyC;IACzC,GAAG,EAAE;QACH,qCAAqC;QACrC,MAAM,EAAE,MAAM,CAAC;QACf,qBAAqB;QACrB,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC;CACH,CAAC;AAEF;;;;;;;;;;;;;;;;GAgBG;AACH,eAAO,MAAM,QAAQ;IACnB,oCAAoC;;QAElC,6DAA6D;iCAC7C,UAAU;QAC1B,4CAA4C;gCAC7B,SAAS;;IAE1B,mCAAmC;;QAEjC,4BAA4B;;QAE5B,uBAAuB;;QAGvB,yCAAyC;;QAEzC,oCAAoC;;QAGpC,yCAAyC;;QAEzC,oCAAoC;;QAGpC,6BAA6B;;QAE7B,8BAA8B;;QAG9B,oEAAoE;;QAEpE,+DAA+D;;;IAGjE,4BAA4B;;QAE1B,+DAA+D;;QAE/D,gEAAgE;;QAGhE,sFAAsF;;QAGtF,gDAAgD;;QAEhD,iDAAiD;;;IAGnD,8BAA8B;;QAE5B,2DAA2D;;;CAGrD,CAAC;AA0CX;;;;;;;;;;;;;;;;;;;GAmBG;AACH,eAAO,MAAM,WAAW;IACtB,wCAAwC;;QAEtC,8DAA8D;iCAC9C,UAAU;QAC1B,6CAA6C;gCAC9B,SAAS;;IAE1B,yCAAyC;;IAEzC,wDAAwD;;QAEtD,yDAAyD;;QAEzD,8CAA8C;;;CAGxC,CAAC;AAEX;;GAEG;AACH,MAAM,MAAM,wBAAwB,GAClC,CAAC,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC,MAAM,OAAO,WAAW,CAAC,UAAU,CAAC,CAAC"}
package/dist/constants.js CHANGED
@@ -57,6 +57,10 @@ export const DynamoDB = {
57
57
  LSI1_S_SORT_KEY: "LSI1_S_SK",
58
58
  /** LSI1 (Numeric) sort key */
59
59
  LSI1_N_SORT_KEY: "LSI1_N_SK",
60
+ /** GSI2 (String-String) partition key - for status-based queries */
61
+ GSI2_SS_PARTITION_KEY: "GSI2_SS_PK",
62
+ /** GSI2 (String-String) sort key - for status-based queries */
63
+ GSI2_SS_SORT_KEY: "GSI2_SS_SK",
60
64
  },
61
65
  /** Secondary index names */
62
66
  Indexes: {
@@ -64,6 +68,8 @@ export const DynamoDB = {
64
68
  GSI1_SS: "GSI1_SS",
65
69
  /** Global Secondary Index 1 - String partition, Numeric sort */
66
70
  GSI1_SN: "GSI1_SN",
71
+ /** Global Secondary Index 2 - String partition, String sort (status-based queries) */
72
+ GSI2_SS: "GSI2_SS",
67
73
  /** Local Secondary Index 1 - String sort key */
68
74
  LSI1_S: "LSI1_S",
69
75
  /** Local Secondary Index 1 - Numeric sort key */
@@ -3,6 +3,7 @@ import { DynamoDBClient } from "@aws-sdk/client-dynamodb";
3
3
  import type { NativeAttributeValue } from "@aws-sdk/util-dynamodb";
4
4
  import { type AuditConfig } from "./config.js";
5
5
  import { type Audit } from "./schema/audit.js";
6
+ import type { AnyStatus } from "./schema/log.js";
6
7
  import { type Pagination } from "./schema/model.js";
7
8
  import type { UpsertAuditInput } from "./schema/service.js";
8
9
  import type { AnyApp, AnyResourceType, InferApp, InferResourceType } from "./types.js";
@@ -87,6 +88,25 @@ export type TypedListTraceItems<C extends AuditConfig> = {
87
88
  id?: string;
88
89
  };
89
90
  };
91
+ /**
92
+ * Options for listing audit items by status with typed App and ResourceType.
93
+ * @typeParam C - The audit config type for type inference
94
+ */
95
+ export type TypedListByStatusOptions<C extends AuditConfig> = {
96
+ /** Tenant/organization identifier for multi-tenancy support (optional) */
97
+ tenantId?: string;
98
+ /** Status to filter by (success, warn, fail, skip) */
99
+ status: AnyStatus;
100
+ /** Optional application filter */
101
+ app?: InferApp<C>;
102
+ /** Optional resource filter */
103
+ resource?: {
104
+ /** Filter by resource type */
105
+ type?: InferResourceType<C>;
106
+ /** Filter by resource ID */
107
+ id?: string;
108
+ };
109
+ };
90
110
  /**
91
111
  * Repository for managing audit records in DynamoDB.
92
112
  *
@@ -276,6 +296,9 @@ export declare class AuditRepository<C extends AuditConfig> {
276
296
  id?: string | number | undefined;
277
297
  };
278
298
  operation: string;
299
+ message: string | undefined;
300
+ updatedAt?: string | undefined;
301
+ createdAt?: string | undefined;
279
302
  tenantId?: string | undefined;
280
303
  source?: {
281
304
  app: string;
@@ -285,7 +308,6 @@ export declare class AuditRepository<C extends AuditConfig> {
285
308
  context?: Record<string, string | number | boolean | {
286
309
  [key: string]: string | number | boolean | /*elided*/ any;
287
310
  }> | undefined;
288
- message?: string | undefined;
289
311
  rerunable?: boolean | undefined;
290
312
  trace?: string | undefined;
291
313
  event?: {
@@ -346,6 +368,63 @@ export declare class AuditRepository<C extends AuditConfig> {
346
368
  id?: string | number | undefined;
347
369
  };
348
370
  operation: string;
371
+ message: string | undefined;
372
+ updatedAt?: string | undefined;
373
+ createdAt?: string | undefined;
374
+ tenantId?: string | undefined;
375
+ source?: {
376
+ app: string;
377
+ type: string;
378
+ id?: string | number | undefined;
379
+ } | undefined;
380
+ context?: Record<string, string | number | boolean | {
381
+ [key: string]: string | number | boolean | /*elided*/ any;
382
+ }> | undefined;
383
+ rerunable?: boolean | undefined;
384
+ trace?: string | undefined;
385
+ event?: {
386
+ detail: string | undefined;
387
+ source?: string | undefined;
388
+ "detail-type"?: string | undefined;
389
+ } | undefined;
390
+ error?: any;
391
+ attempts?: {
392
+ number: number;
393
+ status: "success" | "warn" | "fail" | "skip";
394
+ at: string;
395
+ error?: any;
396
+ }[] | undefined;
397
+ }[];
398
+ pagination?: {
399
+ pageSize?: string | number | null | undefined;
400
+ nextToken?: string | null | undefined;
401
+ } | undefined;
402
+ }>;
403
+ /**
404
+ * Lists audit records by status with date ordering and optional filters.
405
+ *
406
+ * Queries the GSI2_SS index to retrieve all audits with a specific status,
407
+ * ordered by creation date (most recent first by default).
408
+ * Supports optional filtering by app, resource type, and resource ID.
409
+ *
410
+ * @param params - Query parameters including status and optional filters
411
+ * @param pagination - Optional pagination settings (pageSize, nextToken)
412
+ * @returns Paginated collection of audit records in reverse date order
413
+ */
414
+ listByStatus(params: TypedListByStatusOptions<C>, pagination?: Pagination): Promise<{
415
+ items: {
416
+ id: string;
417
+ status: "success" | "warn" | "fail" | "skip";
418
+ tier: number;
419
+ target: {
420
+ app: string;
421
+ type: string;
422
+ id?: string | number | undefined;
423
+ };
424
+ operation: string;
425
+ message: string | undefined;
426
+ updatedAt?: string | undefined;
427
+ createdAt?: string | undefined;
349
428
  tenantId?: string | undefined;
350
429
  source?: {
351
430
  app: string;
@@ -355,7 +434,6 @@ export declare class AuditRepository<C extends AuditConfig> {
355
434
  context?: Record<string, string | number | boolean | {
356
435
  [key: string]: string | number | boolean | /*elided*/ any;
357
436
  }> | undefined;
358
- message?: string | undefined;
359
437
  rerunable?: boolean | undefined;
360
438
  trace?: string | undefined;
361
439
  event?: {
@@ -423,6 +501,18 @@ export declare class AuditRepository<C extends AuditConfig> {
423
501
  * @internal
424
502
  */
425
503
  private constructGSI1_SN;
504
+ /**
505
+ * Constructs GSI2_SS (String-String) index keys for status-based queries.
506
+ *
507
+ * The partition key is the status value (optionally prefixed with tenantId),
508
+ * and the sort key combines createdAt timestamp with id for date ordering
509
+ * while ensuring uniqueness.
510
+ *
511
+ * @param item - The audit storage item
512
+ * @returns GSI2_SS key attributes
513
+ * @internal
514
+ */
515
+ private constructGSI2_SS;
426
516
  /**
427
517
  * Constructs the TTL attribute for automatic item expiration.
428
518
  *
@@ -459,5 +549,13 @@ export declare class AuditRepository<C extends AuditConfig> {
459
549
  * @internal
460
550
  */
461
551
  private transformListItem;
552
+ /**
553
+ * Transforms a status listing item into an audit list item payload.
554
+ *
555
+ * @param item - Raw listing item from GSI2_SS query
556
+ * @returns Parsed audit list item payload
557
+ * @internal
558
+ */
559
+ private transformStatusListItem;
462
560
  }
463
561
  //# sourceMappingURL=repository.d.ts.map
@@ -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,EAAuB,KAAK,WAAW,EAAE,MAAM,aAAa,CAAC;AAGpE,OAAO,EACL,KAAK,KAAK,EAIX,MAAM,mBAAmB,CAAC;AAC3B,OAAO,EAAE,KAAK,UAAU,EAA8B,MAAM,mBAAmB,CAAC;AAChF,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAE5D,OAAO,KAAK,EAAE,MAAM,EAAE,eAAe,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGvF;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,4DAA4D;IAC5D,GAAG,EAAE,MAAM,CAAC;CACb;AAED;;GAEG;AACH,MAAM,MAAM,sBAAsB,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,oBAAoB,CAAA;CAAE,CAAC;AAiE7E;;;GAGG;AACH,MAAM,MAAM,WAAW,GAAG;IACxB,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,8CAA8C;IAC9C,GAAG,EAAE,MAAM,CAAC;IACZ,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,qCAAqC;IACrC,YAAY,EAAE,eAAe,CAAC;CAC/B,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,IAAI;IACpD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,8CAA8C;IAC9C,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,qCAAqC;IACrC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAyCF;;;GAGG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,WAAW,IAAI;IACzD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,EAAE;QACR,2BAA2B;QAC3B,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC3B,wCAAwC;QACxC,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,sCAAsC;IACtC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IAAI;IACvD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE;QACT,8BAA8B;QAC9B,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC5B,4BAA4B;QAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;CACH,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAyCG;AACH,qBAAa,eAAe,CAAC,CAAC,SAAS,WAAW;IAS9C,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IACvB,OAAO,CAAC,QAAQ,CAAC,MAAM;IAVzB;;;;;;OAMG;gBAEgB,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,CAAC,EACT,MAAM,GAAE,cAGvB;IAGJ;;;;;;;;;;;;;;;;;;;;;OAqBG;IACU,OAAO,CAClB,WAAW,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,GACnD,OAAO,CAAC,KAAK,GAAG,SAAS,CAAC;IAwB7B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA+BG;IACU,WAAW,CAAC,KAAK,EAAE,KAAK,CAAC,gBAAgB,CAAC,GAAG,OAAO,CAAC,OAAO,CAAC;IAqD1E;;;;;;;;;;;;OAYG;YACW,mBAAmB;IAyCjC;;;;;;;;;;;;;;;;;;;;;OAqBG;IACU,UAAU,CACrB,IAAI,EAAE,gBAAgB,EACtB,cAAc,EAAE;QACd,MAAM,EAAE,MAAM,CAAC;QACf,MAAM,EAAE,MAAM,CAAC;QACf,KAAK,CAAC,EAAE,OAAO,CAAC;QAChB,EAAE,EAAE,MAAM,CAAC;KACZ,GACA,OAAO,CAAC,MAAM,CAAC;IA8ElB;;;;;;;;;;;;;;;;;;;;;;;;;OAyBG;IACU,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAuChF;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA4BG;IACU,cAAc,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IA8DnF;;;;;;;;OAQG;IACH,OAAO,CAAC,mBAAmB;IAa3B;;;;;;;;;;;OAWG;IACH,OAAO,CAAC,sBAAsB;IAc9B;;;;;;;;;;OAUG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;;;;;;;;;OAUG;IACH,OAAO,CAAC,gBAAgB;IAgBxB;;;;;;;OAOG;IACH,OAAO,CAAC,qBAAqB;IAe7B;;;;;;;;;OASG;IACH,OAAO,CAAC,aAAa;IAQrB;;;;;;OAMG;IACH,OAAO,CAAC,sBAAsB;IAU9B;;;;;;OAMG;IACH,OAAO,CAAC,iBAAiB;CAS1B"}
1
+ {"version":3,"file":"repository.d.ts","sourceRoot":"","sources":["../src/repository.ts"],"names":[],"mappings":"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"}
@@ -3,7 +3,7 @@ import { marshall, unmarshall } from "@aws-sdk/util-dynamodb";
3
3
  import { DEFAULT_TTL_SECONDS } from "./config.js";
4
4
  import { DynamoDB } from "./constants.js";
5
5
  import { decodeNextPageToken, encodeNextPageToken } from "./repository.utils.js";
6
- import { AuditListItemPayloadSchema, AuditPayloadSchema, AuditSchema, } from "./schema/audit.js";
6
+ import { AuditPayloadSchema, AuditSchema } from "./schema/audit.js";
7
7
  import { PaginationCollectionSchema } from "./schema/model.js";
8
8
  import { AuditStorageSchema } from "./schema/storage.js";
9
9
  import { getTraceParts } from "./utils.js";
@@ -447,6 +447,74 @@ export class AuditRepository {
447
447
  },
448
448
  });
449
449
  }
450
+ /**
451
+ * Lists audit records by status with date ordering and optional filters.
452
+ *
453
+ * Queries the GSI2_SS index to retrieve all audits with a specific status,
454
+ * ordered by creation date (most recent first by default).
455
+ * Supports optional filtering by app, resource type, and resource ID.
456
+ *
457
+ * @param params - Query parameters including status and optional filters
458
+ * @param pagination - Optional pagination settings (pageSize, nextToken)
459
+ * @returns Paginated collection of audit records in reverse date order
460
+ */
461
+ async listByStatus(params, pagination) {
462
+ const startKey = decodeNextPageToken(pagination?.nextToken);
463
+ const pageSize = Number(pagination?.pageSize || 100);
464
+ const pkBase = params.status;
465
+ const pk = params.tenantId ? `${params.tenantId}#${pkBase}` : pkBase;
466
+ const filters = [];
467
+ const ExpressionAttributeValues = {
468
+ ":PK": pk,
469
+ };
470
+ const ExpressionAttributeNames = {
471
+ "#PK": DynamoDB.Keys.GSI2_SS_PARTITION_KEY,
472
+ };
473
+ if (params?.resource?.id) {
474
+ Object.assign(ExpressionAttributeValues, {
475
+ ":resourceId": params.resource.id,
476
+ });
477
+ ExpressionAttributeNames["#target"] = "target";
478
+ ExpressionAttributeNames["#id"] = "id";
479
+ filters.push("#target.#id = :resourceId");
480
+ }
481
+ if (params?.resource?.type) {
482
+ Object.assign(ExpressionAttributeValues, {
483
+ ":resourceType": params.resource.type,
484
+ });
485
+ ExpressionAttributeNames["#target"] = "target";
486
+ ExpressionAttributeNames["#type"] = "type";
487
+ filters.push("#target.#type = :resourceType");
488
+ }
489
+ if (params?.app) {
490
+ Object.assign(ExpressionAttributeValues, {
491
+ ":app": params.app,
492
+ });
493
+ ExpressionAttributeNames["#target"] = "target";
494
+ ExpressionAttributeNames["#app"] = "app";
495
+ filters.push("#target.#app = :app");
496
+ }
497
+ // Audits with other resources will have a compound id, filter these out
498
+ Object.assign(ExpressionAttributeValues, { ":isParent": "#" });
499
+ filters.push("not contains(SK, :isParent)");
500
+ const { Items: items, LastEvaluatedKey: lastEvaluatedKey } = await this.client.send(new QueryCommand({
501
+ ScanIndexForward: false,
502
+ IndexName: DynamoDB.Indexes.GSI2_SS,
503
+ ExpressionAttributeValues: marshall(ExpressionAttributeValues),
504
+ ExpressionAttributeNames,
505
+ KeyConditionExpression: "#PK = :PK",
506
+ TableName: DynamoDB.Table.Name(),
507
+ Limit: pageSize,
508
+ ExclusiveStartKey: startKey ? marshall(startKey) : undefined,
509
+ FilterExpression: filters.length > 0 ? filters.join(" AND ") : undefined,
510
+ }));
511
+ return PaginationCollectionSchema(AuditPayloadSchema).parse({
512
+ items: items?.map((i) => this.transformStatusListItem(unmarshall(i))),
513
+ pagination: {
514
+ nextToken: lastEvaluatedKey ? encodeNextPageToken(unmarshall(lastEvaluatedKey)) : undefined,
515
+ },
516
+ });
517
+ }
450
518
  /**
451
519
  * Constructs the DynamoDB primary key from identifiers.
452
520
  *
@@ -486,6 +554,7 @@ export class AuditRepository {
486
554
  app: item.target.app,
487
555
  }),
488
556
  ...this.constructGSI1_SN(item),
557
+ ...this.constructGSI2_SS(item),
489
558
  };
490
559
  }
491
560
  /**
@@ -532,6 +601,26 @@ export class AuditRepository {
532
601
  [DynamoDB.Keys.GSI1_SN_SORT_KEY]: stage,
533
602
  };
534
603
  }
604
+ /**
605
+ * Constructs GSI2_SS (String-String) index keys for status-based queries.
606
+ *
607
+ * The partition key is the status value (optionally prefixed with tenantId),
608
+ * and the sort key combines createdAt timestamp with id for date ordering
609
+ * while ensuring uniqueness.
610
+ *
611
+ * @param item - The audit storage item
612
+ * @returns GSI2_SS key attributes
613
+ * @internal
614
+ */
615
+ constructGSI2_SS(item) {
616
+ const pkBase = item.status;
617
+ return {
618
+ [DynamoDB.Keys.GSI2_SS_PARTITION_KEY]: (item.tenantId
619
+ ? `${item.tenantId}#${pkBase}`
620
+ : pkBase),
621
+ [DynamoDB.Keys.GSI2_SS_SORT_KEY]: `${item.createdAt}#${item.id}`,
622
+ };
623
+ }
535
624
  /**
536
625
  * Constructs the TTL attribute for automatic item expiration.
537
626
  *
@@ -575,7 +664,7 @@ export class AuditRepository {
575
664
  */
576
665
  transformTraceListItem(item) {
577
666
  const [id] = item.SK.split("#");
578
- return AuditListItemPayloadSchema.parse({
667
+ return AuditPayloadSchema.parse({
579
668
  trace: `${item.GSI1_SN_PK}:${item.GSI1_SN_SK}`,
580
669
  ...item,
581
670
  id: id,
@@ -590,10 +679,28 @@ export class AuditRepository {
590
679
  */
591
680
  transformListItem(item) {
592
681
  const [id] = item.SK.split("#");
593
- return AuditListItemPayloadSchema.parse({
682
+ return AuditPayloadSchema.parse({
594
683
  trace: `${item.GSI1_SN_PK}:${item.GSI1_SN_SK}`,
595
684
  ...item,
596
685
  id: id,
597
686
  });
598
687
  }
688
+ /**
689
+ * Transforms a status listing item into an audit list item payload.
690
+ *
691
+ * @param item - Raw listing item from GSI2_SS query
692
+ * @returns Parsed audit list item payload
693
+ * @internal
694
+ */
695
+ transformStatusListItem(item) {
696
+ const [id] = item.SK.split("#");
697
+ const trace = item.GSI1_SN_PK !== undefined && item.GSI1_SN_SK !== undefined
698
+ ? `${item.GSI1_SN_PK}:${item.GSI1_SN_SK}`
699
+ : undefined;
700
+ return AuditPayloadSchema.parse({
701
+ trace,
702
+ ...item,
703
+ id: id,
704
+ });
705
+ }
599
706
  }
@@ -52,7 +52,7 @@ export declare const AuditSchema: z.ZodObject<{
52
52
  [key: string]: string | number | boolean | /*elided*/ any;
53
53
  }, unknown>>>>;
54
54
  operation: z.ZodString;
55
- message: z.ZodOptional<z.ZodString>;
55
+ message: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | undefined, string | null | undefined>>;
56
56
  rerunable: z.ZodOptional<z.ZodBoolean>;
57
57
  trace: z.ZodOptional<z.ZodString>;
58
58
  event: z.ZodOptional<z.ZodObject<{
@@ -92,6 +92,8 @@ export type Audit = z.output<typeof AuditSchema>;
92
92
  * suitable for JSON serialization in API responses.
93
93
  */
94
94
  export declare const AuditPayloadSchema: z.ZodObject<{
95
+ updatedAt: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodISODateTime, z.ZodCustom<Date, Date>]>, z.ZodTransform<string, string | Date>>>;
96
+ createdAt: z.ZodOptional<z.ZodPipe<z.ZodUnion<readonly [z.ZodISODateTime, z.ZodCustom<Date, Date>]>, z.ZodTransform<string, string | Date>>>;
95
97
  id: z.ZodString;
96
98
  tenantId: z.ZodOptional<z.ZodString>;
97
99
  status: z.ZodEnum<{
@@ -117,7 +119,7 @@ export declare const AuditPayloadSchema: z.ZodObject<{
117
119
  [key: string]: string | number | boolean | /*elided*/ any;
118
120
  }, unknown>>>>;
119
121
  operation: z.ZodString;
120
- message: z.ZodOptional<z.ZodString>;
122
+ message: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | undefined, string | null | undefined>>;
121
123
  rerunable: z.ZodOptional<z.ZodBoolean>;
122
124
  trace: z.ZodOptional<z.ZodString>;
123
125
  event: z.ZodOptional<z.ZodObject<{
@@ -142,61 +144,4 @@ export declare const AuditPayloadSchema: z.ZodObject<{
142
144
  * Output type for audit payloads.
143
145
  */
144
146
  export type AuditPayload = z.output<typeof AuditPayloadSchema>;
145
- /**
146
- * Schema for audit list item payloads.
147
- *
148
- * Same as AuditPayloadSchema, used for items in list responses
149
- * where a lighter payload is sufficient.
150
- */
151
- export declare const AuditListItemPayloadSchema: z.ZodObject<{
152
- id: z.ZodString;
153
- tenantId: z.ZodOptional<z.ZodString>;
154
- status: z.ZodEnum<{
155
- success: "success";
156
- warn: "warn";
157
- fail: "fail";
158
- skip: "skip";
159
- }>;
160
- tier: z.ZodDefault<z.ZodNumber>;
161
- target: z.ZodObject<{
162
- app: z.ZodString;
163
- id: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
164
- type: z.ZodString;
165
- }, z.core.$strip>;
166
- source: z.ZodOptional<z.ZodObject<{
167
- app: z.ZodString;
168
- id: z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNumber]>>;
169
- type: z.ZodString;
170
- }, z.core.$strip>>;
171
- context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<string | number | boolean | {
172
- [key: string]: string | number | boolean | /*elided*/ any;
173
- }, unknown, z.core.$ZodTypeInternals<string | number | boolean | {
174
- [key: string]: string | number | boolean | /*elided*/ any;
175
- }, unknown>>>>;
176
- operation: z.ZodString;
177
- message: z.ZodOptional<z.ZodString>;
178
- rerunable: z.ZodOptional<z.ZodBoolean>;
179
- trace: z.ZodOptional<z.ZodString>;
180
- event: z.ZodOptional<z.ZodObject<{
181
- source: z.ZodOptional<z.ZodString>;
182
- "detail-type": z.ZodOptional<z.ZodString>;
183
- detail: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodRecord<z.ZodString, z.ZodAny>]>>, z.ZodTransform<string | undefined, string | Record<string, any> | undefined>>;
184
- }, z.core.$strip>>;
185
- error: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<any, string>>, z.ZodPipe<z.ZodCustom<Error, Error>, z.ZodTransform<any, Error>>, z.ZodRecord<z.ZodAny, z.ZodAny>]>>;
186
- attempts: z.ZodOptional<z.ZodArray<z.ZodObject<{
187
- number: z.ZodNumber;
188
- status: z.ZodEnum<{
189
- success: "success";
190
- warn: "warn";
191
- fail: "fail";
192
- skip: "skip";
193
- }>;
194
- error: z.ZodOptional<z.ZodUnion<readonly [z.ZodPipe<z.ZodString, z.ZodTransform<any, string>>, z.ZodPipe<z.ZodCustom<Error, Error>, z.ZodTransform<any, Error>>, z.ZodRecord<z.ZodAny, z.ZodAny>]>>;
195
- at: z.ZodDefault<z.ZodPipe<z.ZodUnion<readonly [z.ZodISODateTime, z.ZodCustom<Date, Date>]>, z.ZodTransform<string, string | Date>>>;
196
- }, z.core.$strip>>>;
197
- }, z.core.$strip>;
198
- /**
199
- * Output type for audit list item payloads.
200
- */
201
- export type AuditAuditListItemPayload = z.output<typeof AuditListItemPayloadSchema>;
202
147
  //# sourceMappingURL=audit.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/schema/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMtB,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAa,CAAC;AAE7C;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC;AAE/D;;;;;GAKG;AACH,eAAO,MAAM,0BAA0B;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAAa,CAAC;AAErD;;GAEG;AACH,MAAM,MAAM,yBAAyB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,0BAA0B,CAAC,CAAC"}
1
+ {"version":3,"file":"audit.d.ts","sourceRoot":"","sources":["../../src/schema/audit.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAG5B;;;;;;;;;;;;;;;;;;;;;;;;GAwBG;AACH,eAAO,MAAM,WAAW;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAMtB,CAAC;AAEH;;;;GAIG;AACH,MAAM,MAAM,UAAU,GAAG,CAAC,CAAC,KAAK,CAAC,OAAO,WAAW,CAAC,CAAC;AAErD;;;;GAIG;AACH,MAAM,MAAM,KAAK,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,WAAW,CAAC,CAAC;AAEjD;;;;;GAKG;AACH,eAAO,MAAM,kBAAkB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAM7B,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,kBAAkB,CAAC,CAAC"}
@@ -1,5 +1,5 @@
1
1
  import * as z from "zod/v4";
2
- import { BaseSchema, DateTimeObjectSchema } from "./common.js";
2
+ import { BaseSchema, DateTimeObjectSchema, DateTimeStringSchema } from "./common.js";
3
3
  /**
4
4
  * Schema for fully-hydrated audit records retrieved from storage.
5
5
  *
@@ -38,11 +38,10 @@ export const AuditSchema = z.object({
38
38
  * Uses the base schema without timestamp transformation,
39
39
  * suitable for JSON serialization in API responses.
40
40
  */
41
- export const AuditPayloadSchema = BaseSchema;
42
- /**
43
- * Schema for audit list item payloads.
44
- *
45
- * Same as AuditPayloadSchema, used for items in list responses
46
- * where a lighter payload is sufficient.
47
- */
48
- export const AuditListItemPayloadSchema = BaseSchema;
41
+ export const AuditPayloadSchema = z.object({
42
+ ...BaseSchema.shape,
43
+ /** Last update timestamp - ISO string suitable for JSON API responses */
44
+ updatedAt: DateTimeStringSchema.optional(),
45
+ /** Creation timestamp - ISO string suitable for JSON API responses */
46
+ createdAt: DateTimeStringSchema.optional(),
47
+ });
@@ -103,7 +103,7 @@ export declare const BaseSchema: z.ZodObject<{
103
103
  }, z.core.$strip>>;
104
104
  context: z.ZodOptional<z.ZodRecord<z.ZodString, z.ZodType<ContextValue, unknown, z.core.$ZodTypeInternals<ContextValue, unknown>>>>;
105
105
  operation: z.ZodString;
106
- message: z.ZodOptional<z.ZodString>;
106
+ message: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | undefined, string | null | undefined>>;
107
107
  rerunable: z.ZodOptional<z.ZodBoolean>;
108
108
  trace: z.ZodOptional<z.ZodString>;
109
109
  event: z.ZodOptional<z.ZodObject<{
@@ -1 +1 @@
1
- {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/schema/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAI5B;;;;;GAKG;AACH,eAAO,MAAM,IAAI;;;;CAIP,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAOvD;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;EAAgC,CAAC;AAc1D;;;GAGG;AACH,QAAA,MAAM,uBAAuB;;;;iBAI3B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAEzE;;;GAGG;AACH,QAAA,MAAM,wBAAwB;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE3E;;;GAGG;AACH,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAsChF,eAAO,MAAM,oBAAoB,kHAEG,CAAC;AAErC;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,oHAEqC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;iBASxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBA6BrB,CAAC"}
1
+ {"version":3,"file":"common.d.ts","sourceRoot":"","sources":["../../src/schema/common.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,CAAC,MAAM,QAAQ,CAAC;AAI5B;;;;;GAKG;AACH,eAAO,MAAM,IAAI;;;;CAIP,CAAC;AACX,MAAM,MAAM,OAAO,GAAG,CAAC,OAAO,IAAI,CAAC,CAAC,MAAM,OAAO,IAAI,CAAC,CAAC;AAOvD;;GAEG;AACH,eAAO,MAAM,YAAY;;;;;EAAgC,CAAC;AAc1D;;;GAGG;AACH,QAAA,MAAM,uBAAuB;;;;iBAI3B,CAAC;AACH,MAAM,MAAM,iBAAiB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,uBAAuB,CAAC,CAAC;AAEzE;;;GAGG;AACH,QAAA,MAAM,wBAAwB;;;;iBAE5B,CAAC;AACH,MAAM,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,wBAAwB,CAAC,CAAC;AAE3E;;;GAGG;AACH,KAAK,YAAY,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,GAAG;IAAE,CAAC,GAAG,EAAE,MAAM,GAAG,YAAY,CAAA;CAAE,CAAC;AAsChF,eAAO,MAAM,oBAAoB,kHAEG,CAAC;AAErC;;;;;;;;;GASG;AACH,eAAO,MAAM,oBAAoB,oHAEqC,CAAC;AAEvE;;;GAGG;AACH,eAAO,MAAM,aAAa;;;;;;;;;;iBASxB,CAAC;AACH,MAAM,MAAM,OAAO,GAAG,CAAC,CAAC,MAAM,CAAC,OAAO,aAAa,CAAC,CAAC;AAErD;;;;;GAKG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;iBAgCrB,CAAC"}
@@ -134,7 +134,10 @@ export const BaseSchema = z.object({
134
134
  /** Name of the operation being audited */
135
135
  operation: z.string(),
136
136
  /** Human-readable description of the audit */
137
- message: z.string().optional(),
137
+ message: z
138
+ .union([z.string(), z.null()])
139
+ .optional()
140
+ .transform((value) => value ?? undefined),
138
141
  /** Whether this audit can be re-run/retried */
139
142
  rerunable: z.boolean().optional(),
140
143
  /** Trace identifier for distributed tracing */
@@ -67,7 +67,7 @@ export declare const AuditStorageSchema: z.ZodObject<{
67
67
  [key: string]: string | number | boolean | /*elided*/ any;
68
68
  }, unknown>>>>;
69
69
  operation: z.ZodString;
70
- message: z.ZodOptional<z.ZodString>;
70
+ message: z.ZodPipe<z.ZodOptional<z.ZodUnion<readonly [z.ZodString, z.ZodNull]>>, z.ZodTransform<string | undefined, string | null | undefined>>;
71
71
  rerunable: z.ZodOptional<z.ZodBoolean>;
72
72
  trace: z.ZodOptional<z.ZodString>;
73
73
  event: z.ZodOptional<z.ZodObject<{
package/dist/service.d.ts CHANGED
@@ -3,6 +3,7 @@ import type { AuditConfig } from "./config.js";
3
3
  import { AuditEventBus } from "./events/bus.js";
4
4
  import { AuditRepository } from "./repository.js";
5
5
  import type { Audit } from "./schema/audit.js";
6
+ import type { AnyStatus } from "./schema/log.js";
6
7
  import type { Pagination } from "./schema/model.js";
7
8
  import { type UpsertAuditInput } from "./schema/service.js";
8
9
  import type { InferApp, InferResourceType } from "./types.js";
@@ -58,6 +59,25 @@ export type TypedListTraceItems<C extends AuditConfig> = {
58
59
  id?: string;
59
60
  };
60
61
  };
62
+ /**
63
+ * Typed options for listing audit items by status.
64
+ * Uses config-derived App and ResourceType types for strict typing.
65
+ */
66
+ export type TypedListByStatusOptions<C extends AuditConfig> = {
67
+ /** Tenant/organization identifier for multi-tenancy support (optional) */
68
+ tenantId?: string;
69
+ /** Status to filter by (success, warn, fail, skip) */
70
+ status: AnyStatus;
71
+ /** Optional application filter */
72
+ app?: InferApp<C>;
73
+ /** Optional resource filter */
74
+ resource?: {
75
+ /** Filter by resource type */
76
+ type?: InferResourceType<C>;
77
+ /** Filter by resource ID */
78
+ id?: string;
79
+ };
80
+ };
61
81
  /**
62
82
  * High-level service for managing audit records with typed App and ResourceType.
63
83
  *
@@ -192,6 +212,9 @@ export declare class AuditService<C extends AuditConfig> {
192
212
  id?: string | number | undefined;
193
213
  };
194
214
  operation: string;
215
+ message: string | undefined;
216
+ updatedAt?: string | undefined;
217
+ createdAt?: string | undefined;
195
218
  tenantId?: string | undefined;
196
219
  source?: {
197
220
  app: string;
@@ -201,7 +224,6 @@ export declare class AuditService<C extends AuditConfig> {
201
224
  context?: Record<string, string | number | boolean | {
202
225
  [key: string]: string | number | boolean | /*elided*/ any;
203
226
  }> | undefined;
204
- message?: string | undefined;
205
227
  rerunable?: boolean | undefined;
206
228
  trace?: string | undefined;
207
229
  event?: {
@@ -251,6 +273,64 @@ export declare class AuditService<C extends AuditConfig> {
251
273
  id?: string | number | undefined;
252
274
  };
253
275
  operation: string;
276
+ message: string | undefined;
277
+ updatedAt?: string | undefined;
278
+ createdAt?: string | undefined;
279
+ tenantId?: string | undefined;
280
+ source?: {
281
+ app: string;
282
+ type: string;
283
+ id?: string | number | undefined;
284
+ } | undefined;
285
+ context?: Record<string, string | number | boolean | {
286
+ [key: string]: string | number | boolean | /*elided*/ any;
287
+ }> | undefined;
288
+ rerunable?: boolean | undefined;
289
+ trace?: string | undefined;
290
+ event?: {
291
+ detail: string | undefined;
292
+ source?: string | undefined;
293
+ "detail-type"?: string | undefined;
294
+ } | undefined;
295
+ error?: any;
296
+ attempts?: {
297
+ number: number;
298
+ status: "success" | "warn" | "fail" | "skip";
299
+ at: string;
300
+ error?: any;
301
+ }[] | undefined;
302
+ }[];
303
+ pagination?: {
304
+ pageSize?: string | number | null | undefined;
305
+ nextToken?: string | null | undefined;
306
+ } | undefined;
307
+ }>;
308
+ /**
309
+ * Lists audit records by status with date ordering and pagination.
310
+ *
311
+ * Retrieves all audits with a specific status (e.g., 'fail', 'warn'),
312
+ * ordered by creation date (most recent first).
313
+ * Supports optional filtering by app, resource type, and resource ID.
314
+ *
315
+ * @param params - Query parameters including status and optional filters
316
+ * @param pagination - Optional pagination settings
317
+ * @returns Paginated collection of status-filtered audit records
318
+ * @throws Re-throws any storage errors after logging
319
+ */
320
+ listByStatus(params: TypedListByStatusOptions<C>, pagination?: Pagination): Promise<{
321
+ items: {
322
+ id: string;
323
+ status: "success" | "warn" | "fail" | "skip";
324
+ tier: number;
325
+ target: {
326
+ app: string;
327
+ type: string;
328
+ id?: string | number | undefined;
329
+ };
330
+ operation: string;
331
+ message: string | undefined;
332
+ updatedAt?: string | undefined;
333
+ createdAt?: string | undefined;
254
334
  tenantId?: string | undefined;
255
335
  source?: {
256
336
  app: string;
@@ -260,7 +340,6 @@ export declare class AuditService<C extends AuditConfig> {
260
340
  context?: Record<string, string | number | boolean | {
261
341
  [key: string]: string | number | boolean | /*elided*/ any;
262
342
  }> | undefined;
263
- message?: string | undefined;
264
343
  rerunable?: boolean | undefined;
265
344
  trace?: string | undefined;
266
345
  event?: {
@@ -1 +1 @@
1
- {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"service.d.ts","sourceRoot":"","sources":["../src/service.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,+BAA+B,CAAC;AAC5D,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAC/C,OAAO,EAAE,aAAa,EAAE,MAAM,iBAAiB,CAAC;AAChD,OAAO,EAAE,eAAe,EAAE,MAAM,iBAAiB,CAAC;AAClD,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,mBAAmB,CAAC;AAC/C,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,iBAAiB,CAAC;AACjD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAAgC,KAAK,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAC1F,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,IAAI;IACpD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,qCAAqC;IACrC,EAAE,EAAE,MAAM,GAAG,MAAM,CAAC;IACpB,8CAA8C;IAC9C,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IACjB,0DAA0D;IAC1D,UAAU,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAC7B,qCAAqC;IACrC,YAAY,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;CACpC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,WAAW,IAAI;IACzD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,EAAE;QACR,2BAA2B;QAC3B,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC3B,wCAAwC;QACxC,EAAE,EAAE,MAAM,CAAC;KACZ,CAAC;IACF,sCAAsC;IACtC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CAClB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IAAI;IACvD,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,kDAAkD;IAClD,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE;QACT,8BAA8B;QAC9B,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC5B,4BAA4B;QAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;CACH,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,wBAAwB,CAAC,CAAC,SAAS,WAAW,IAAI;IAC5D,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sDAAsD;IACtD,MAAM,EAAE,SAAS,CAAC;IAClB,kCAAkC;IAClC,GAAG,CAAC,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;IAClB,+BAA+B;IAC/B,QAAQ,CAAC,EAAE;QACT,8BAA8B;QAC9B,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC5B,4BAA4B;QAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;KACb,CAAC;CACH,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,WAAW;IAa3C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAGvB,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa;IAfnD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAI;IAE3B;;;;;;;OAOG;gBAEgB,MAAM,EAAE,MAAM,EAC/B,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,EACnB,MAAM,GAAE,IAAI,GAAG,SAAS,GAAG,aAAyC;IAM/E;;;;;;;;;;;;;;;OAeG;IACU,OAAO,CAAC,WAAW,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,GAAG,OAAO,CAAC,KAAK,CAAC;IAc1F;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACU,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IA8C/D;;;;;;;;;;;;;;;;;;OAkBG;IACU,SAAS,CAAC,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAYhF;;;;;;;;;;;;;;;;;OAiBG;IACU,cAAc,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAYnF;;;;;;;;;;;OAWG;IACU,YAAY,CAAC,MAAM,EAAE,wBAAwB,CAAC,CAAC,CAAC,EAAE,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAWvF"}
package/dist/service.js CHANGED
@@ -212,4 +212,27 @@ export class AuditService {
212
212
  throw error;
213
213
  }
214
214
  }
215
+ /**
216
+ * Lists audit records by status with date ordering and pagination.
217
+ *
218
+ * Retrieves all audits with a specific status (e.g., 'fail', 'warn'),
219
+ * ordered by creation date (most recent first).
220
+ * Supports optional filtering by app, resource type, and resource ID.
221
+ *
222
+ * @param params - Query parameters including status and optional filters
223
+ * @param pagination - Optional pagination settings
224
+ * @returns Paginated collection of status-filtered audit records
225
+ * @throws Re-throws any storage errors after logging
226
+ */
227
+ async listByStatus(params, pagination) {
228
+ try {
229
+ return await this.storage.listByStatus(params, pagination);
230
+ }
231
+ catch (error) {
232
+ this.logger.error("An error occurred while trying to list items by status", {
233
+ error,
234
+ });
235
+ throw error;
236
+ }
237
+ }
215
238
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@flipboxlabs/aws-audit-sdk",
3
- "version": "1.2.3",
3
+ "version": "1.4.1",
4
4
  "description": "AWS Audit SDK - Core SDK for audit logging and event management",
5
5
  "keywords": [
6
6
  "audit",