@flipboxlabs/aws-audit-sdk 1.1.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.
Files changed (72) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +30 -0
  3. package/dist/audits.d.ts +188 -0
  4. package/dist/audits.d.ts.map +1 -0
  5. package/dist/audits.js +225 -0
  6. package/dist/batch/batch-processor.d.ts +81 -0
  7. package/dist/batch/batch-processor.d.ts.map +1 -0
  8. package/dist/batch/batch-processor.js +102 -0
  9. package/dist/batch/index.d.ts +2 -0
  10. package/dist/batch/index.d.ts.map +1 -0
  11. package/dist/batch/index.js +1 -0
  12. package/dist/config.d.ts +65 -0
  13. package/dist/config.d.ts.map +1 -0
  14. package/dist/config.js +44 -0
  15. package/dist/constants.d.ts +147 -0
  16. package/dist/constants.d.ts.map +1 -0
  17. package/dist/constants.js +191 -0
  18. package/dist/events/batch-handler.d.ts +62 -0
  19. package/dist/events/batch-handler.d.ts.map +1 -0
  20. package/dist/events/batch-handler.js +92 -0
  21. package/dist/events/bus.d.ts +79 -0
  22. package/dist/events/bus.d.ts.map +1 -0
  23. package/dist/events/bus.js +86 -0
  24. package/dist/events/index.d.ts +3 -0
  25. package/dist/events/index.d.ts.map +1 -0
  26. package/dist/events/index.js +2 -0
  27. package/dist/index.d.ts +9 -0
  28. package/dist/index.d.ts.map +1 -0
  29. package/dist/index.js +8 -0
  30. package/dist/middleware/middy.d.ts +66 -0
  31. package/dist/middleware/middy.d.ts.map +1 -0
  32. package/dist/middleware/middy.js +105 -0
  33. package/dist/repository.d.ts +421 -0
  34. package/dist/repository.d.ts.map +1 -0
  35. package/dist/repository.js +486 -0
  36. package/dist/repository.utils.d.ts +37 -0
  37. package/dist/repository.utils.d.ts.map +1 -0
  38. package/dist/repository.utils.js +70 -0
  39. package/dist/schema/audit.d.ts +202 -0
  40. package/dist/schema/audit.d.ts.map +1 -0
  41. package/dist/schema/audit.js +48 -0
  42. package/dist/schema/common.d.ts +128 -0
  43. package/dist/schema/common.d.ts.map +1 -0
  44. package/dist/schema/common.js +148 -0
  45. package/dist/schema/index.d.ts +27 -0
  46. package/dist/schema/index.d.ts.map +1 -0
  47. package/dist/schema/index.js +26 -0
  48. package/dist/schema/log.d.ts +211 -0
  49. package/dist/schema/log.d.ts.map +1 -0
  50. package/dist/schema/log.js +179 -0
  51. package/dist/schema/model.d.ts +110 -0
  52. package/dist/schema/model.d.ts.map +1 -0
  53. package/dist/schema/model.js +86 -0
  54. package/dist/schema/service.d.ts +189 -0
  55. package/dist/schema/service.d.ts.map +1 -0
  56. package/dist/schema/service.js +89 -0
  57. package/dist/schema/storage.d.ts +105 -0
  58. package/dist/schema/storage.d.ts.map +1 -0
  59. package/dist/schema/storage.js +63 -0
  60. package/dist/service.d.ts +285 -0
  61. package/dist/service.d.ts.map +1 -0
  62. package/dist/service.js +237 -0
  63. package/dist/test-config.d.ts +56 -0
  64. package/dist/test-config.d.ts.map +1 -0
  65. package/dist/test-config.js +24 -0
  66. package/dist/types.d.ts +40 -0
  67. package/dist/types.d.ts.map +1 -0
  68. package/dist/types.js +1 -0
  69. package/dist/utils.d.ts +231 -0
  70. package/dist/utils.d.ts.map +1 -0
  71. package/dist/utils.js +313 -0
  72. package/package.json +85 -0
@@ -0,0 +1,285 @@
1
+ import type { Logger } from "@aws-lambda-powertools/logger";
2
+ import type { AuditConfig } from "./config.js";
3
+ import { AuditEventBus } from "./events/bus.js";
4
+ import { AuditRepository } from "./repository.js";
5
+ import type { Audit } from "./schema/audit.js";
6
+ import type { Pagination } from "./schema/model.js";
7
+ import { type UpsertAuditInput } from "./schema/service.js";
8
+ import type { InferApp, InferResourceType } from "./types.js";
9
+ /**
10
+ * Typed identifiers for locating audit records.
11
+ * Uses config-derived App and ResourceType types for strict typing.
12
+ */
13
+ export type TypedIdentifiers<C extends AuditConfig> = {
14
+ /** Tenant/organization identifier for multi-tenancy support (optional) */
15
+ tenantId?: string;
16
+ /** Unique audit record identifier */
17
+ id: string | number;
18
+ /** Application that owns this audit record */
19
+ app: InferApp<C>;
20
+ /** Optional resource identifier within the application */
21
+ resourceId?: string | number;
22
+ /** Type of resource being audited */
23
+ resourceType: InferResourceType<C>;
24
+ };
25
+ /**
26
+ * Typed options for listing audit items by resource.
27
+ * Uses config-derived App and ResourceType types for strict typing.
28
+ */
29
+ export type TypedListItemsOptions<C extends AuditConfig> = {
30
+ /** Tenant/organization identifier for multi-tenancy support (optional) */
31
+ tenantId?: string;
32
+ /** Resource identification */
33
+ resource: {
34
+ /** Type of the resource */
35
+ type: InferResourceType<C>;
36
+ /** Unique identifier of the resource */
37
+ id: string;
38
+ };
39
+ /** Application owning the resource */
40
+ app: InferApp<C>;
41
+ };
42
+ /**
43
+ * Typed options for listing audit items by trace ID.
44
+ * Uses config-derived App and ResourceType types for strict typing.
45
+ */
46
+ export type TypedListTraceItems<C extends AuditConfig> = {
47
+ /** Tenant/organization identifier for multi-tenancy support (optional) */
48
+ tenantId?: string;
49
+ /** Trace ID to query for related audit records */
50
+ trace: string;
51
+ /** Optional application filter */
52
+ app?: InferApp<C>;
53
+ /** Optional resource filter */
54
+ resource?: {
55
+ /** Filter by resource type */
56
+ type?: InferResourceType<C>;
57
+ /** Filter by resource ID */
58
+ id?: string;
59
+ };
60
+ };
61
+ /**
62
+ * High-level service for managing audit records with typed App and ResourceType.
63
+ *
64
+ * Provides a business logic layer over the AuditRepository for CRUD operations
65
+ * and coordinates with EventBridge for event-driven notifications.
66
+ *
67
+ * Features:
68
+ * - Type-safe app and resourceType parameters derived from config
69
+ * - Automatic creation of related resource audit entries
70
+ * - Schema validation on upsert operations
71
+ * - EventBridge integration for audit event notifications
72
+ * - Paginated list queries with filtering
73
+ *
74
+ * @typeParam C - The audit config type for type inference
75
+ *
76
+ * @example
77
+ * ```typescript
78
+ * const config = defineAuditConfig({
79
+ * apps: ['Orders', 'Inventory'] as const,
80
+ * resourceTypes: ['Order', 'Product'] as const,
81
+ * });
82
+ *
83
+ * const service = new AuditService(logger, config);
84
+ *
85
+ * // Upsert an audit with related resources
86
+ * await service.upsertItem({
87
+ * operation: 'createOrder',
88
+ * target: { app: 'Orders', type: 'Order', id: '123' },
89
+ * resources: [
90
+ * { app: 'Inventory', type: 'Product', id: '456' },
91
+ * ],
92
+ * });
93
+ *
94
+ * // Retrieve a specific audit - app and resourceType are typed!
95
+ * const audit = await service.getItem({
96
+ * id: 'audit-123',
97
+ * app: 'Orders', // TypeScript knows valid values
98
+ * resourceType: 'Order', // Autocomplete works
99
+ * });
100
+ * ```
101
+ */
102
+ export declare class AuditService<C extends AuditConfig> {
103
+ private readonly logger;
104
+ readonly events: null | undefined | AuditEventBus;
105
+ private readonly storage;
106
+ private readonly config;
107
+ /**
108
+ * Creates a new AuditService instance.
109
+ *
110
+ * @param logger - Logger instance for error logging
111
+ * @param config - Audit configuration for type inference
112
+ * @param storage - Repository for DynamoDB operations (defaults to new AuditRepository)
113
+ * @param events - EventBridge bus for audit notifications (defaults to new AuditEventBus, can be null/undefined to disable)
114
+ */
115
+ constructor(logger: Logger, config: C, storage?: AuditRepository<C>, events?: null | undefined | AuditEventBus);
116
+ /**
117
+ * Retrieves a single audit record by its identifiers.
118
+ *
119
+ * @param identifiers - The audit identifiers (id, app, resourceType)
120
+ * @returns The audit record
121
+ * @throws Error if the audit record is not found
122
+ *
123
+ * @example
124
+ * ```typescript
125
+ * const audit = await service.getItem({
126
+ * id: 'audit-123',
127
+ * app: 'MyApp',
128
+ * resourceType: 'User',
129
+ * });
130
+ * ```
131
+ */
132
+ getItem(identifiers: Omit<TypedIdentifiers<C>, "resourceId">): Promise<Audit>;
133
+ /**
134
+ * Creates or updates an audit record and its related resource entries.
135
+ *
136
+ * For each resource in the `resources` array that has an ID:
137
+ * - Creates a separate audit entry with the resource as the target
138
+ * - Links it to the parent audit via a generated composite ID
139
+ * - Sets the original target as the source
140
+ * - Inherits rerunable status from the parent or event presence
141
+ *
142
+ * When an audit with the same ID already exists (retry scenario):
143
+ * - Appends the current execution to the `attempts` array
144
+ * - Preserves the original `createdAt` timestamp
145
+ * - Increments the attempt number automatically
146
+ *
147
+ * After storage, publishes an "Upserted" event to EventBridge (if events is configured).
148
+ *
149
+ * @param input - The audit data to upsert
150
+ *
151
+ * @example
152
+ * ```typescript
153
+ * await service.upsertItem({
154
+ * operation: 'processPayment',
155
+ * target: { app: 'Payments', type: 'Transaction', id: 'txn-123' },
156
+ * status: 'success',
157
+ * resources: [
158
+ * { app: 'Users', type: 'User', id: 'user-456' },
159
+ * { app: 'Orders', type: 'Order', id: 'order-789' },
160
+ * ],
161
+ * });
162
+ * ```
163
+ */
164
+ upsertItem(input: UpsertAuditInput): Promise<void>;
165
+ /**
166
+ * Lists audit records with filtering and pagination.
167
+ *
168
+ * Queries audits based on resource type, app, and optional resource ID.
169
+ * Results are paginated and can be filtered by various criteria.
170
+ *
171
+ * @param params - Query parameters for filtering
172
+ * @param pagination - Optional pagination settings
173
+ * @returns Paginated collection of audit records
174
+ * @throws Re-throws any storage errors after logging
175
+ *
176
+ * @example
177
+ * ```typescript
178
+ * const { items, pagination } = await service.listItems({
179
+ * resource: { type: 'Order', id: '123' },
180
+ * app: 'Orders',
181
+ * });
182
+ * ```
183
+ */
184
+ listItems(params: TypedListItemsOptions<C>, pagination?: Pagination): Promise<{
185
+ items: {
186
+ id: string;
187
+ status: "success" | "warn" | "fail" | "skip";
188
+ tier: number;
189
+ target: {
190
+ app: string;
191
+ type: string;
192
+ id?: string | number | undefined;
193
+ };
194
+ operation: string;
195
+ tenantId?: string | undefined;
196
+ source?: {
197
+ app: string;
198
+ type: string;
199
+ id?: string | number | undefined;
200
+ } | undefined;
201
+ context?: Record<string, string | number | boolean | {
202
+ [key: string]: string | number | boolean | /*elided*/ any;
203
+ }> | undefined;
204
+ message?: string | undefined;
205
+ rerunable?: boolean | undefined;
206
+ trace?: string | undefined;
207
+ event?: {
208
+ detail: string | undefined;
209
+ source?: string | undefined;
210
+ "detail-type"?: string | undefined;
211
+ } | undefined;
212
+ error?: any;
213
+ attempts?: {
214
+ number: number;
215
+ status: "success" | "warn" | "fail" | "skip";
216
+ at: string;
217
+ error?: any;
218
+ }[] | undefined;
219
+ }[];
220
+ pagination?: {
221
+ pageSize?: string | number | null | undefined;
222
+ nextToken?: string | null | undefined;
223
+ } | undefined;
224
+ }>;
225
+ /**
226
+ * Lists audit records by trace ID with pagination.
227
+ *
228
+ * Retrieves all audits associated with a distributed trace,
229
+ * ordered by their stage in the processing pipeline.
230
+ *
231
+ * @param params - Query parameters including the trace ID
232
+ * @param pagination - Optional pagination settings
233
+ * @returns Paginated collection of trace-related audit records
234
+ * @throws Re-throws any storage errors after logging
235
+ *
236
+ * @example
237
+ * ```typescript
238
+ * const { items } = await service.listTraceItems({
239
+ * trace: 'trace-abc-123',
240
+ * });
241
+ * ```
242
+ */
243
+ listTraceItems(params: TypedListTraceItems<C>, pagination?: Pagination): Promise<{
244
+ items: {
245
+ id: string;
246
+ status: "success" | "warn" | "fail" | "skip";
247
+ tier: number;
248
+ target: {
249
+ app: string;
250
+ type: string;
251
+ id?: string | number | undefined;
252
+ };
253
+ operation: string;
254
+ tenantId?: string | undefined;
255
+ source?: {
256
+ app: string;
257
+ type: string;
258
+ id?: string | number | undefined;
259
+ } | undefined;
260
+ context?: Record<string, string | number | boolean | {
261
+ [key: string]: string | number | boolean | /*elided*/ any;
262
+ }> | undefined;
263
+ message?: string | undefined;
264
+ rerunable?: boolean | undefined;
265
+ trace?: string | undefined;
266
+ event?: {
267
+ detail: string | undefined;
268
+ source?: string | undefined;
269
+ "detail-type"?: string | undefined;
270
+ } | undefined;
271
+ error?: any;
272
+ attempts?: {
273
+ number: number;
274
+ status: "success" | "warn" | "fail" | "skip";
275
+ at: string;
276
+ error?: any;
277
+ }[] | undefined;
278
+ }[];
279
+ pagination?: {
280
+ pageSize?: string | number | null | undefined;
281
+ nextToken?: string | null | undefined;
282
+ } | undefined;
283
+ }>;
284
+ }
285
+ //# sourceMappingURL=service.d.ts.map
@@ -0,0 +1 @@
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,UAAU,EAAE,MAAM,mBAAmB,CAAC;AACpD,OAAO,EAEN,KAAK,gBAAgB,EACrB,MAAM,qBAAqB,CAAC;AAC7B,OAAO,KAAK,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAE9D;;;GAGG;AACH,MAAM,MAAM,gBAAgB,CAAC,CAAC,SAAS,WAAW,IAAI;IACrD,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;CACnC,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,qBAAqB,CAAC,CAAC,SAAS,WAAW,IAAI;IAC1D,0EAA0E;IAC1E,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8BAA8B;IAC9B,QAAQ,EAAE;QACT,2BAA2B;QAC3B,IAAI,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC3B,wCAAwC;QACxC,EAAE,EAAE,MAAM,CAAC;KACX,CAAC;IACF,sCAAsC;IACtC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,mBAAmB,CAAC,CAAC,SAAS,WAAW,IAAI;IACxD,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;QACV,8BAA8B;QAC9B,IAAI,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,CAAC;QAC5B,4BAA4B;QAC5B,EAAE,CAAC,EAAE,MAAM,CAAC;KACZ,CAAC;CACF,CAAC;AAEF;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAwCG;AACH,qBAAa,YAAY,CAAC,CAAC,SAAS,WAAW;IAa7C,OAAO,CAAC,QAAQ,CAAC,MAAM;IAGvB,QAAQ,CAAC,MAAM,EAAE,IAAI,GAAG,SAAS,GAAG,aAAa;IAflD,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAqB;IAC7C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAI;IAE3B;;;;;;;OAOG;gBAEe,MAAM,EAAE,MAAM,EAC/B,MAAM,EAAE,CAAC,EACT,OAAO,CAAC,EAAE,eAAe,CAAC,CAAC,CAAC,EACnB,MAAM,GAAE,IAAI,GAAG,SAAS,GAAG,aAEnC;IAMF;;;;;;;;;;;;;;;OAeG;IACU,OAAO,CACnB,WAAW,EAAE,IAAI,CAAC,gBAAgB,CAAC,CAAC,CAAC,EAAE,YAAY,CAAC,GAClD,OAAO,CAAC,KAAK,CAAC;IAcjB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;OA8BG;IACU,UAAU,CAAC,KAAK,EAAE,gBAAgB,GAAG,OAAO,CAAC,IAAI,CAAC;IAoE/D;;;;;;;;;;;;;;;;;;OAkBG;IACU,SAAS,CACrB,MAAM,EAAE,qBAAqB,CAAC,CAAC,CAAC,EAChC,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;IAaxB;;;;;;;;;;;;;;;;;OAiBG;IACU,cAAc,CAC1B,MAAM,EAAE,mBAAmB,CAAC,CAAC,CAAC,EAC9B,UAAU,CAAC,EAAE,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;CAYxB"}
@@ -0,0 +1,237 @@
1
+ import { AuditEventBus } from "./events/bus.js";
2
+ import { AuditRepository } from "./repository.js";
3
+ import { createTypedUpsertAuditSchema, } from "./schema/service.js";
4
+ /**
5
+ * High-level service for managing audit records with typed App and ResourceType.
6
+ *
7
+ * Provides a business logic layer over the AuditRepository for CRUD operations
8
+ * and coordinates with EventBridge for event-driven notifications.
9
+ *
10
+ * Features:
11
+ * - Type-safe app and resourceType parameters derived from config
12
+ * - Automatic creation of related resource audit entries
13
+ * - Schema validation on upsert operations
14
+ * - EventBridge integration for audit event notifications
15
+ * - Paginated list queries with filtering
16
+ *
17
+ * @typeParam C - The audit config type for type inference
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const config = defineAuditConfig({
22
+ * apps: ['Orders', 'Inventory'] as const,
23
+ * resourceTypes: ['Order', 'Product'] as const,
24
+ * });
25
+ *
26
+ * const service = new AuditService(logger, config);
27
+ *
28
+ * // Upsert an audit with related resources
29
+ * await service.upsertItem({
30
+ * operation: 'createOrder',
31
+ * target: { app: 'Orders', type: 'Order', id: '123' },
32
+ * resources: [
33
+ * { app: 'Inventory', type: 'Product', id: '456' },
34
+ * ],
35
+ * });
36
+ *
37
+ * // Retrieve a specific audit - app and resourceType are typed!
38
+ * const audit = await service.getItem({
39
+ * id: 'audit-123',
40
+ * app: 'Orders', // TypeScript knows valid values
41
+ * resourceType: 'Order', // Autocomplete works
42
+ * });
43
+ * ```
44
+ */
45
+ export class AuditService {
46
+ logger;
47
+ events;
48
+ storage;
49
+ config;
50
+ /**
51
+ * Creates a new AuditService instance.
52
+ *
53
+ * @param logger - Logger instance for error logging
54
+ * @param config - Audit configuration for type inference
55
+ * @param storage - Repository for DynamoDB operations (defaults to new AuditRepository)
56
+ * @param events - EventBridge bus for audit notifications (defaults to new AuditEventBus, can be null/undefined to disable)
57
+ */
58
+ constructor(logger, config, storage, events = new AuditEventBus(logger)) {
59
+ this.logger = logger;
60
+ this.events = events;
61
+ this.config = config;
62
+ this.storage = storage ?? new AuditRepository(logger, config);
63
+ }
64
+ /**
65
+ * Retrieves a single audit record by its identifiers.
66
+ *
67
+ * @param identifiers - The audit identifiers (id, app, resourceType)
68
+ * @returns The audit record
69
+ * @throws Error if the audit record is not found
70
+ *
71
+ * @example
72
+ * ```typescript
73
+ * const audit = await service.getItem({
74
+ * id: 'audit-123',
75
+ * app: 'MyApp',
76
+ * resourceType: 'User',
77
+ * });
78
+ * ```
79
+ */
80
+ async getItem(identifiers) {
81
+ const result = await this.storage.getItem(identifiers);
82
+ if (result == null) {
83
+ throw new Error(`Unable to find Audit ${Array.from(Object.entries(identifiers))
84
+ .map(([key, value]) => `${key}:${value}`)
85
+ .join(" | ")}`);
86
+ }
87
+ return result;
88
+ }
89
+ /**
90
+ * Creates or updates an audit record and its related resource entries.
91
+ *
92
+ * For each resource in the `resources` array that has an ID:
93
+ * - Creates a separate audit entry with the resource as the target
94
+ * - Links it to the parent audit via a generated composite ID
95
+ * - Sets the original target as the source
96
+ * - Inherits rerunable status from the parent or event presence
97
+ *
98
+ * When an audit with the same ID already exists (retry scenario):
99
+ * - Appends the current execution to the `attempts` array
100
+ * - Preserves the original `createdAt` timestamp
101
+ * - Increments the attempt number automatically
102
+ *
103
+ * After storage, publishes an "Upserted" event to EventBridge (if events is configured).
104
+ *
105
+ * @param input - The audit data to upsert
106
+ *
107
+ * @example
108
+ * ```typescript
109
+ * await service.upsertItem({
110
+ * operation: 'processPayment',
111
+ * target: { app: 'Payments', type: 'Transaction', id: 'txn-123' },
112
+ * status: 'success',
113
+ * resources: [
114
+ * { app: 'Users', type: 'User', id: 'user-456' },
115
+ * { app: 'Orders', type: 'Order', id: 'order-789' },
116
+ * ],
117
+ * });
118
+ * ```
119
+ */
120
+ async upsertItem(input) {
121
+ const schema = createTypedUpsertAuditSchema(this.config.schemas.resourceReference);
122
+ const item = schema.parse(input);
123
+ const now = new Date().toISOString();
124
+ // Build current attempt record
125
+ const currentAttempt = {
126
+ number: 1,
127
+ status: item.status,
128
+ error: item.error,
129
+ at: now,
130
+ };
131
+ // Check for existing audit to handle retry tracking
132
+ if (item.id) {
133
+ try {
134
+ const existing = await this.storage.getItem({
135
+ id: item.id,
136
+ app: item.target.app,
137
+ resourceType: item.target.type,
138
+ tenantId: item.tenantId,
139
+ });
140
+ if (existing) {
141
+ // Append to existing attempts array
142
+ const existingAttempts = existing.attempts ?? [];
143
+ currentAttempt.number = existingAttempts.length + 1;
144
+ item.attempts = [...existingAttempts, currentAttempt];
145
+ // Preserve original createdAt
146
+ item.createdAt = existing.createdAt.toISOString();
147
+ }
148
+ else {
149
+ item.attempts = [currentAttempt];
150
+ }
151
+ }
152
+ catch {
153
+ // Audit doesn't exist, this is the first attempt
154
+ item.attempts = [currentAttempt];
155
+ }
156
+ }
157
+ else {
158
+ item.attempts = [currentAttempt];
159
+ }
160
+ const batch = Array.from(item.resources || [])
161
+ .filter((resource) => !!resource.id)
162
+ .map((resource) => ({
163
+ ...item,
164
+ ...resource,
165
+ id: `${item.id}#${resource.app}.${resource.type}#${resource.id}`, // deterministic ID for retry correlation
166
+ // Source
167
+ source: item.target,
168
+ rerunable: item.rerunable !== undefined ? item.rerunable : !!item.event,
169
+ // Remove these (they are only needed on the parent)
170
+ event: undefined,
171
+ result: undefined,
172
+ error: undefined,
173
+ attempts: undefined,
174
+ }));
175
+ await this.storage.upsertBatch([item, ...batch]);
176
+ await this.events?.upserted([item]);
177
+ }
178
+ /**
179
+ * Lists audit records with filtering and pagination.
180
+ *
181
+ * Queries audits based on resource type, app, and optional resource ID.
182
+ * Results are paginated and can be filtered by various criteria.
183
+ *
184
+ * @param params - Query parameters for filtering
185
+ * @param pagination - Optional pagination settings
186
+ * @returns Paginated collection of audit records
187
+ * @throws Re-throws any storage errors after logging
188
+ *
189
+ * @example
190
+ * ```typescript
191
+ * const { items, pagination } = await service.listItems({
192
+ * resource: { type: 'Order', id: '123' },
193
+ * app: 'Orders',
194
+ * });
195
+ * ```
196
+ */
197
+ async listItems(params, pagination) {
198
+ try {
199
+ return await this.storage.listItems(params, pagination);
200
+ }
201
+ catch (error) {
202
+ this.logger.error("An error occurred while trying to list items", {
203
+ error,
204
+ });
205
+ throw error;
206
+ }
207
+ }
208
+ /**
209
+ * Lists audit records by trace ID with pagination.
210
+ *
211
+ * Retrieves all audits associated with a distributed trace,
212
+ * ordered by their stage in the processing pipeline.
213
+ *
214
+ * @param params - Query parameters including the trace ID
215
+ * @param pagination - Optional pagination settings
216
+ * @returns Paginated collection of trace-related audit records
217
+ * @throws Re-throws any storage errors after logging
218
+ *
219
+ * @example
220
+ * ```typescript
221
+ * const { items } = await service.listTraceItems({
222
+ * trace: 'trace-abc-123',
223
+ * });
224
+ * ```
225
+ */
226
+ async listTraceItems(params, pagination) {
227
+ try {
228
+ return await this.storage.listTraceItems(params, pagination);
229
+ }
230
+ catch (error) {
231
+ this.logger.error("An error occurred while trying to list trace items", {
232
+ error,
233
+ });
234
+ throw error;
235
+ }
236
+ }
237
+ }
@@ -0,0 +1,56 @@
1
+ /**
2
+ * Test configuration for SDK tests.
3
+ * Provides sample apps and resource types for testing.
4
+ */
5
+ export declare const testConfig: {
6
+ service: string | undefined;
7
+ } & {
8
+ readonly apps: readonly ["App1", "TestApp"];
9
+ readonly resourceTypes: readonly ["Unknown", "User", "Order"];
10
+ } & {
11
+ schemas: {
12
+ app: import("zod").ZodEnum<{
13
+ [x: string]: string;
14
+ }>;
15
+ resourceType: import("zod").ZodEnum<{
16
+ [x: string]: string;
17
+ }>;
18
+ resourceReference: import("zod").ZodObject<{
19
+ app: import("zod").ZodEnum<{
20
+ [x: string]: string;
21
+ }>;
22
+ type: import("zod").ZodEnum<{
23
+ [x: string]: string;
24
+ }>;
25
+ id: import("zod").ZodOptional<import("zod").ZodUnion<readonly [import("zod").ZodString, import("zod").ZodNumber]>>;
26
+ }, import("zod/v4/core").$strip>;
27
+ };
28
+ _types: {
29
+ App: "App1" | "TestApp";
30
+ ResourceType: "Unknown" | "User" | "Order";
31
+ };
32
+ };
33
+ /**
34
+ * Type alias for the App union type from the test config.
35
+ */
36
+ export type App = (typeof testConfig)["_types"]["App"];
37
+ /**
38
+ * Type alias for the ResourceType union type from the test config.
39
+ */
40
+ export type ResourceType = (typeof testConfig)["_types"]["ResourceType"];
41
+ /**
42
+ * Enum-like object for App values in tests.
43
+ */
44
+ export declare const App: {
45
+ readonly App1: "App1";
46
+ readonly TestApp: "TestApp";
47
+ };
48
+ /**
49
+ * Enum-like object for ResourceType values in tests.
50
+ */
51
+ export declare const ResourceType: {
52
+ readonly UNKNOWN: "Unknown";
53
+ readonly USER: "User";
54
+ readonly ORDER: "Order";
55
+ };
56
+ //# sourceMappingURL=test-config.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"test-config.d.ts","sourceRoot":"","sources":["../src/test-config.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,eAAO,MAAM,UAAU;;;;;;;;;;;;;;;;;;;;;;;;;;;CAGrB,CAAC;AAEH;;GAEG;AACH,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;AAEvD;;GAEG;AACH,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,UAAU,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC;AAEzE;;GAEG;AACH,eAAO,MAAM,GAAG;;;CAGN,CAAC;AAEX;;GAEG;AACH,eAAO,MAAM,YAAY;;;;CAIf,CAAC"}
@@ -0,0 +1,24 @@
1
+ import { defineAuditConfig } from "./config.js";
2
+ /**
3
+ * Test configuration for SDK tests.
4
+ * Provides sample apps and resource types for testing.
5
+ */
6
+ export const testConfig = defineAuditConfig({
7
+ apps: ["App1", "TestApp"],
8
+ resourceTypes: ["Unknown", "User", "Order"],
9
+ });
10
+ /**
11
+ * Enum-like object for App values in tests.
12
+ */
13
+ export const App = {
14
+ App1: "App1",
15
+ TestApp: "TestApp",
16
+ };
17
+ /**
18
+ * Enum-like object for ResourceType values in tests.
19
+ */
20
+ export const ResourceType = {
21
+ UNKNOWN: "Unknown",
22
+ USER: "User",
23
+ ORDER: "Order",
24
+ };
@@ -0,0 +1,40 @@
1
+ import type { AuditConfig } from "./config.js";
2
+ /**
3
+ * Extracts the App type from an AuditConfig.
4
+ *
5
+ * @example
6
+ * ```typescript
7
+ * const config = defineAuditConfig({
8
+ * apps: ['Orders', 'Inventory'] as const,
9
+ * resourceTypes: ['Order', 'Product'] as const,
10
+ * });
11
+ *
12
+ * type App = InferApp<typeof config>; // 'Orders' | 'Inventory'
13
+ * ```
14
+ */
15
+ export type InferApp<C extends AuditConfig> = C["_types"]["App"];
16
+ /**
17
+ * Extracts the ResourceType type from an AuditConfig.
18
+ *
19
+ * @example
20
+ * ```typescript
21
+ * const config = defineAuditConfig({
22
+ * apps: ['Orders', 'Inventory'] as const,
23
+ * resourceTypes: ['Order', 'Product'] as const,
24
+ * });
25
+ *
26
+ * type ResourceType = InferResourceType<typeof config>; // 'Order' | 'Product'
27
+ * ```
28
+ */
29
+ export type InferResourceType<C extends AuditConfig> = C["_types"]["ResourceType"];
30
+ /**
31
+ * Generic App type - accepts any string.
32
+ * For strict typing, use InferApp<typeof config> with your config.
33
+ */
34
+ export type AnyApp = string;
35
+ /**
36
+ * Generic ResourceType type - accepts any string.
37
+ * For strict typing, use InferResourceType<typeof config> with your config.
38
+ */
39
+ export type AnyResourceType = string;
40
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,QAAQ,CAAC,CAAC,SAAS,WAAW,IAAI,CAAC,CAAC,QAAQ,CAAC,CAAC,KAAK,CAAC,CAAC;AAEjE;;;;;;;;;;;;GAYG;AACH,MAAM,MAAM,iBAAiB,CAAC,CAAC,SAAS,WAAW,IAClD,CAAC,CAAC,QAAQ,CAAC,CAAC,cAAc,CAAC,CAAC;AAE7B;;;GAGG;AACH,MAAM,MAAM,MAAM,GAAG,MAAM,CAAC;AAE5B;;;GAGG;AACH,MAAM,MAAM,eAAe,GAAG,MAAM,CAAC"}
package/dist/types.js ADDED
@@ -0,0 +1 @@
1
+ export {};