feat(uploads): add web page screenshot capabilities - #448
Merged
Merged
Conversation
Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
BROWSER_TOKEN falls back to PLACE_SERVER_SECRET / SERVER_SECRET (as dispatch does) and is sent as an Authorization: Bearer header rather than ?token=, so the long secret stays out of browserless access logs. Co-Authored-By: Claude Opus 5.5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
Your trial has ended. Reactivate Greptile to resume code reviews.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Summary
Adds
POST /api/engine/v2/uploads/screenshot. It renders a web page in headless Chromium (browserless), saves the image to the authority's default storage, and returns the completedUpload(201).Request body:
url(required)width/height(default 1920×1080)scaleformat(png|jpeg|webp)full_pagesettle(ms, default 1000)file_name,public,tagsWidth, height, scale, settle and tags are validated. The storage's allowed file types and mime types apply, and a
screenshottag is always added.Page readiness
We send a single request to browserless's
/chromium/screenshot. It waits in this order:networkidle2document.fonts.readyrequestAnimationFramessettlemsSteps 2–5 are a single async
waitForFunction, because browserless runswaitForTimeoutbeforewaitForFunction.Internal service protection
httpsURLs are accepted (400 otherwise).rejectRequestPattern: ["^http:"], which blocks every plain-http load, including redirects and subresources. Internal services only speak http.Errors
Error::BadGateway/Error::GatewayTimeout.Uploadrow is removed.Refactor
ImageGen::Store.putinto a sharedObjectStore.put.ImageGen::Store.putnow delegates to it and keeps itsImageGen::Vendorerror.deleterather thandestroy.destroy'sbefore_destroystorage cleanup could fail against the same broken storage and leave an orphaned, incomplete row. Raised IO/socket errors now roll back too.docker-compose
browserservice:ghcr.io/browserless/chromium, amd64 + arm64, token auth. It's configured throughBROWSER_URI,BROWSER_TOKENandSCREENSHOT_TIMEOUT.pgsty/minio/pgsty/mc, because the upstreamquay.io/docker.iominio/*images return 401.testbucketnow runsmc alias set, sincemc config host addhas been removed.Deployment
Deployments need a browserless instance reachable at
BROWSER_URI(defaulthttp://browser:3000). Ideally it's network-isolated from internal services as defence in depth.Testing
spec/controllers/uploads_screenshot_spec.cr(9 examples) covers:./test spec/controllers/uploads_screenshot_spec.cr spec/controllers/uploads_spec.cr spec/controllers/signage/signage_ai_spec.cr: 54 examples, 0 failures, run on the plain compose file.OPENAPI_DOC.ymlregenerated.🤖 Generated with Claude Code