Default to adding idempotecy-key to audit-logs/events if not present#1383
Conversation
There was a problem hiding this comment.
Greptile Overview
Greptile Summary
This PR enhances the audit logs event creation with automatic idempotency key generation and retry capabilities. When createEvent is called without an idempotency key, the SDK now auto-generates a UUID v4, ensuring safe retries even when users don't provide one. The PR also enables retry logic (up to 4 total attempts with exponential backoff) for the /audit_logs/events endpoint for status codes 408, 500, 502, and 504.
Key changes:
- Auto-generates UUID v4 idempotency key in
createEventif not provided - Extended
isPathRetryableto include/audit_logs/eventsendpoint - Added comprehensive test coverage for both features including retry scenarios
Implementation quality:
- Clean implementation using spread operator to preserve user options
- Properly maintains same idempotency key across retry attempts
- Thorough test coverage including edge cases (multiple requests, max retries, key persistence)
Confidence Score: 5/5
- This PR is safe to merge with no identified risks
- The implementation is straightforward and well-tested. The auto-generation of idempotency keys improves reliability without breaking existing functionality (users can still provide their own keys). The retry logic follows existing patterns and is correctly scoped to the specific endpoint. All custom security rules are satisfied, and the comprehensive test suite validates both happy paths and edge cases.
- No files require special attention
Important Files Changed
File Analysis
| Filename | Score | Overview |
|---|---|---|
| src/audit-logs/audit-logs.ts | 5/5 | Added automatic UUID generation for idempotency keys when not provided by the user |
| src/common/net/http-client.ts | 5/5 | Extended retry logic to include /audit_logs/events endpoint |
| src/audit-logs/audit-logs.spec.ts | 5/5 | Added comprehensive test coverage for idempotency key auto-generation and retry behavior |
Sequence Diagram
sequenceDiagram
participant Client
participant AuditLogs
participant WorkOS
participant HttpClient
participant API
Client->>AuditLogs: createEvent(org, event, options?)
AuditLogs->>AuditLogs: Generate UUID if idempotencyKey missing
Note over AuditLogs: options.idempotencyKey || randomUUID()
AuditLogs->>WorkOS: post('/audit_logs/events', data, optionsWithIdempotency)
WorkOS->>WorkOS: Add Idempotency-Key header
WorkOS->>HttpClient: post(path, entity, headers)
HttpClient->>HttpClient: Check isPathRetryable('/audit_logs/events')
Note over HttpClient: Returns true (new behavior)
loop Retry up to 4 attempts
HttpClient->>API: POST request with same idempotency key
alt Success (201)
API-->>HttpClient: Success response
HttpClient-->>WorkOS: Response
WorkOS-->>AuditLogs: void
AuditLogs-->>Client: Success
else Retryable error (408, 500, 502, 504)
API-->>HttpClient: Error response
HttpClient->>HttpClient: Sleep with exponential backoff
Note over HttpClient: Retry with same idempotency key
end
end
alt Max retries exceeded
HttpClient-->>WorkOS: Throw error
WorkOS-->>AuditLogs: Exception
AuditLogs-->>Client: Exception
end
3 files reviewed, no comments
nave91
left a comment
There was a problem hiding this comment.
Changes looks great! One tiny nitpick if we want to differentiate between sdk generated idempotency key vs customer.
src/audit-logs/audit-logs.ts
Outdated
| // Auto-generate idempotency key if not provided | ||
| const optionsWithIdempotency: CreateAuditLogEventRequestOptions = { | ||
| ...options, | ||
| idempotencyKey: options.idempotencyKey || randomUUID(), |
There was a problem hiding this comment.
can you prefix the randomUUID() with ws_ or workos_ so we know this was generated by us and not the customer?
| expect(fetch).toHaveBeenCalledTimes(3); | ||
| }); | ||
|
|
||
| it('succeeds on the last retry attempt (4th attempt)', async () => { |
| idempotencyKey: options.idempotencyKey || randomUUID(), | ||
| }; | ||
|
|
||
| await this.workos.post( |
There was a problem hiding this comment.
Do you know if this await throws an exception for 4xx? For cases where schema validation fails, we return 400 but I'm not sure if this gets propagated to the caller?
There was a problem hiding this comment.
When schema validation fails, it throws InvalidAuditLogEventException (400), which propagates t to the workOS-node,

Description
Updating node sdk to always generating an idempotencyKey if not present when POSTing audit-logs events. Also enabled retrying for POST