Skip to content

Add presigned S3 URL support for large blob payloads#66

Merged
elffjs merged 5 commits intomainfrom
claude/s3-presigned-links-I0cvr
Mar 31, 2026
Merged

Add presigned S3 URL support for large blob payloads#66
elffjs merged 5 commits intomainfrom
claude/s3-presigned-links-I0cvr

Conversation

@elffjs
Copy link
Copy Markdown
Member

@elffjs elffjs commented Mar 31, 2026

Summary

This PR adds support for serving large binary blob payloads via presigned S3 URLs instead of inline in GraphQL responses. When a cloud event's payload is stored with the blob prefix, a short-lived presigned URL is returned in the new dataUrl field instead of the raw data.

Key Changes

  • GraphQL Schema: Added dataUrl: String field to the CloudEvent type to return presigned S3 URLs for blob payloads
  • Event Repository:
    • Added Presigner interface for generating presigned S3 GET URLs
    • Introduced BlobKeyPrefix constant ("cloudevent/blobs/") to identify blob objects
    • Implemented PresignBlobURL() method to generate 15-minute presigned URLs
    • Updated New() constructor to accept a presigner dependency
  • Query Resolvers:
    • Modified LatestCloudEvent() to detect blob keys and return presigned URLs instead of fetching full payloads
    • Modified CloudEvents() to handle mixed blob and non-blob events, presigning blob URLs while fetching regular event data
  • CloudEventWrapper: Added DataURL field to carry presigned URLs through the resolver chain
  • Resolver Implementation: Added DataUrl() resolver that returns the presigned URL from the wrapper
  • App Initialization: Wired up S3 presigner client using AWS SDK's s3.NewPresignClient()

Implementation Details

  • Blob detection is based on S3 key prefix matching (eventrepo.BlobKeyPrefix)
  • Presigned URLs expire after 15 minutes (presignTTL)
  • The CloudEvents query efficiently separates blob and non-blob events, presigning blobs while concurrently fetching non-blob payloads
  • All existing tests updated to pass nil presigner where not needed
  • Mock presigner added to test utilities for future testing

https://claude.ai/code/session_015ReeLGeCywJfYkkrrng5wU

claude and others added 5 commits March 30, 2026 10:58
Objects stored under the cloudevent/blobs/ key prefix are now served
via a short-lived presigned S3 GET URL (dataUrl field) instead of being
downloaded and embedded inline in the GraphQL response. This avoids
ballooning the JSON payload for large binary objects (e.g. scans).

- Add Presigner interface + PresignBlobURL method to eventrepo.Service
- Export BlobKeyPrefix constant ("cloudevent/blobs/")
- Add dataUrl: String field to GraphQL CloudEvent type
- Detect blob prefix in LatestCloudEvent / CloudEvents resolvers;
  skip GetObject and presign against the primary bucket instead
- Wire s3.NewPresignClient into both GraphQL and gRPC app paths
- Update eventrepo.New signature; pass nil in tests that don't need presigning
- Add MockPresigner to generated mock file

https://claude.ai/code/session_015ReeLGeCywJfYkkrrng5wU
Describe the field in terms of behavior (large files) rather than the
internal key prefix convention, which is an implementation detail that
may change.

https://claude.ai/code/session_015ReeLGeCywJfYkkrrng5wU
- pkg/eventrepo/presign_test.go: unit tests for PresignBlobURL covering
  correct bucket/key routing, 15-minute TTL, presigner error propagation,
  and nil-presigner guard
- internal/graph/blob_resolver_test.go: unit tests for the DataUrl resolver
  (nil wrapper, empty DataURL, populated DataURL) and a composite test that
  a blob wrapper returns nil for data/dataBase64 and a URL for dataUrl

https://claude.ai/code/session_015ReeLGeCywJfYkkrrng5wU
@elffjs elffjs merged commit 0779bd1 into main Mar 31, 2026
4 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants