## What changed
- add an optional Capture setting for image-only File Upload blocks with
None, Back camera, and Front camera choices
- persist the standard `environment` and `user` values and apply them
through the runtime file input `capture` attribute
- preserve existing behavior when capture is unset, including the legacy
Android accept workaround
- normalize extension-based image allowlists for capture while keeping
server-side validation fail-closed
- update schemas, generated OpenAPI specs, embed package versions, and
focused tests
- install Playwright Chromium during Codex worktree setup and ignore
local Revue session state
## Validation
- pre-commit affected format, lint, link, test, and OpenAPI targets:
passed
- affected tests across 14 projects under `.env.dev.example`: passed
- typecheck for builder, viewer, JS embed, File Input, input schemas,
lib, and bot engine: passed
- targeted Viewer Playwright file-upload capture test: passed (2 tests)
- targeted schema, allowlist, runtime helper, and upload validation
suites: passed
## Browser behavior
The standard capture attribute is a browser hint. Supported mobile
browsers may open the selected camera directly; desktop and unsupported
browsers may continue to show a regular file chooser.
## What changed
- Detect image extensions in file upload allowlists using the shared
`extensionFromMimeType` table.
- Add the corresponding image MIME hints while preserving the original
extensions and the existing `capture=camera` Android workaround.
- Normalize casing and leading dots, deduplicate equivalent entries, and
prefer valid dotted extensions regardless of input order.
- Add focused unit coverage for image-only, mixed, non-image, duplicate,
and casing scenarios.
- Bump the JavaScript and React embed packages to `0.10.6` and ignore
local Revue comments.
## Why
The Android camera workaround was only enabled when the configured
allowlist already contained an `image/*` MIME type. Bots configured with
image extensions such as `.jpg`, `.jpeg`, and `.png` therefore never
received the workaround.
## Impact
Android users can access the existing camera option when a file upload
block is configured with image extensions. Browser hints are enriched
only on the client; server-side validation remains based on the block's
original options.
The `capture=camera` token remains a non-standard Android-specific
workaround and may continue to vary across browsers.
## Validation
- `bunx nx test @typebot.io/js` — 7 tests passed
- `bunx nx typecheck @typebot.io/js`
- `bunx nx format-and-lint`
- `git diff --check`
The repository-wide pre-commit affected test suite could not complete
locally because unrelated packages required missing environment
variables and existing SSRF tests failed. The targeted package tests,
typecheck, and repository formatting checks passed.
## Summary
- Keeps video bubbles above the absolute typing/background layer in the
embedded chat renderer.
- Applies the same stacking approach to direct video URLs and embedded
video iframes.
- Bumps `@typebot.io/js` and `@typebot.io/react` from `0.10.4` to
`0.10.5`.
## Root cause
Chrome could place the full-size absolute `bubble-typing` layer over
video bubbles because the media content shared the same stacking level.
That made the overlay sit above the HTML video element in builder embed
preview.
## Validation
- `bunx nx typecheck @typebot.io/react`
- `bunx nx build @typebot.io/react --configuration=development`
- `bunx nx format-and-lint`
- Commit hook: `nx affected -t
format-and-lint,lint-repo,check-broken-links,test --parallel=4`
Note: I could not visually verify the exact provided local typebot URL
in this workspace because it returns `Typebot not found` locally.
- Keep CORS headers on upload proxy error responses.
- Surface failed audio/file uploads as Typebot errors instead of leaving
the recorder stuck.
- Prevent recorded-audio Send clicks from submitting the host page form
in embedded bots.
- Prevent duplicate embed uploads while an upload is already in flight.
- Disable recorder abort while recorded audio is being processed or
uploaded.
- Bump @typebot.io/js and @typebot.io/react to 0.10.4.
When clicking on an image in the chat preview/runtime, the X button to
close the modal appeared misplaced outside the correct area. This
happened because the button was positioned with `position: fixed`,
remaining stuck to the entire page viewport instead of being inside the
modal/chat container.
before:
<img width="490" height="542" alt="image"
src="https://github.com/user-attachments/assets/ed17cf29-6397-46c7-9779-01aec89c3c5b"
/>
after:
<img width="502" height="523" alt="image"
src="https://github.com/user-attachments/assets/8ac64782-6af4-4417-bad1-971450e0f66c"
/>
---------
Co-authored-by: Baptiste Arnaud <baptiste@typebot.io>
Co-authored-by: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
## Summary
- Add `script.onerror` handler in `initGoogleAnalytics` so the promise
resolves even when the GA script fails to load (ad blockers, network
errors), preventing the bot from hanging indefinitely.
- Bump `@typebot.io/js` and `@typebot.io/react` versions to `0.10.2`.
## Test plan
- [ ] Enable a Google Analytics integration block in a bot
- [ ] Block `googletagmanager.com` (e.g. via ad blocker) and verify the
bot still loads
- [ ] Check that `"Failed to load Google Analytics script"` appears in
the console
🤖 Generated with [Claude Code](https://claude.com/claude-code)
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Summary
- Fix stored XSS vulnerability where `javascript:` URIs in text bubble
links, image click links, and toast popup links could execute arbitrary
JS in visitors' browsers
- Add `sanitizeUrl` utility that allowlists only `http:`, `https:`,
`mailto:`, and `tel:` protocols
- Add explicit `typecheck` Nx targets for `builder` and `viewer`
(Next.js projects don't get one inferred by `@nx/js/typescript`)
- Bump `@typebot.io/js` and `@typebot.io/react` to `0.10.1`
## Test plan
- [ ] Create a bot with a text bubble link set to `javascript:alert(1)`
and verify it renders as `#`
- [ ] Same test with an image click link
- [ ] Verify normal `https://` links still work
- [ ] Run `bunx nx typecheck builder` and `bunx nx typecheck viewer`
🤖 Generated with [Claude Code](https://claude.com/claude-code)
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
## Changes
- **Presigned POST → PUT**: Replace `generatePresignedPostPolicy` with
`generatePresignedPutUrl` across all upload endpoints (builder + viewer
v1/v2/v3). This makes uploads compatible with Cloudflare R2 which
doesn't support the S3 POST Object API. Frontend consumers now use `PUT`
with raw file body + `Content-Type`/`Cache-Control` headers instead of
`POST` with FormData.
- **XSS mitigation**: Block dangerous content types (SVG, HTML, XML, JS)
in the builder `generateUploadUrl` endpoint. Restrict frontend `accept`
attributes from `image/*` to an explicit list of safe raster types
(`png, jpeg, gif, webp, avif, bmp, tiff`). Addresses
GHSA-jj87-c343-26vp.
- **Fix file upload URL validation**: `isURL` with `require_tld: true`
rejected `localhost` and `NEXTAUTH_URL` proxy URLs for private files.
Now uses a trusted host allowlist (`localhost`, `NEXTAUTH_URL`,
`S3_PUBLIC_CUSTOM_DOMAIN`) to skip TLD requirement.
- **Docs**: Update S3 CORS policy from `POST` to `PUT`, add Cloudflare
R2 to supported providers list.
- **Bump**: `@typebot.io/js` and `@typebot.io/react` → `0.10.0`
## Verification
- Tested avatar upload on builder with R2 bucket (PUT succeeds, image
displays)
- Verified CORS preflight passes after R2 bucket config
- Confirmed `generateUploadUrl` rejects `image/svg+xml` with 400
- All unit tests pass (`nx affected -t test`)
- Typecheck passes on all affected packages
---------
Co-authored-by: Claude Opus 4.6 (1M context) <noreply@anthropic.com>