Skip to content

[pull] main from tldraw:main#480

Merged
pull[bot] merged 4 commits intocode:mainfrom
tldraw:main
Apr 3, 2026
Merged

[pull] main from tldraw:main#480
pull[bot] merged 4 commits intocode:mainfrom
tldraw:main

Conversation

@pull
Copy link
Copy Markdown

@pull pull Bot commented Apr 3, 2026

See Commits and Changes for more details.


Created by pull[bot] (v2.0.0-alpha.4)

Can you help keep this open source service alive? 💖 Please sponsor : )

mimecuvalo and others added 4 commits April 3, 2026 09:08
fixes #5859
fixes #5235

## Summary

- Adds an `AssetUtil` base class following the `ShapeUtil` /
`BindingUtil` patterns, making the asset system extensible
- Previously, assets were a hardcoded union of `TLImageAsset |
TLVideoAsset | TLBookmarkAsset` — this PR allows custom asset types to
be registered
- Scope: `AssetUtil` handles **type-specific behavior** only (MIME
types, file → asset metadata, asset → shape creation). `TLAssetStore`
keeps `upload`/`resolve`/`remove` as cross-cutting concerns

## What changed

**`@tldraw/tlschema`** — extensible asset schema
- Per-key prop validators (`imageAssetProps`, `videoAssetProps`,
`bookmarkAssetProps`)
- `createAssetRecordType()` + `defaultAssetSchemas`, matching
shape/binding patterns
- `assets` parameter on `createTLSchema()`

**`@tldraw/editor`** — `AssetUtil` base class
- `AssetUtil` with `configure()`, `getDefaultProps()`,
`getSupportedMimeTypes()`, `getAssetFromFile()`, `createShape()`
- `Editor` registers asset utils; exposes `getAssetUtil()`,
`hasAssetUtil()`, `getAssetUtilForMimeType()`
- Wired through `TldrawEditor`, `createTLStore`

**`@tldraw/tldraw`** — default implementations + refactoring
- `ImageAssetUtil`, `VideoAssetUtil`, `BookmarkAssetUtil`
- `Tldraw` component accepts `assetUtils` prop (merged with defaults via
`mergeArraysAndReplaceDefaults`)
- `defaultExternalContentHandlers` delegates to asset utils instead of
hardcoded switch/MIME-type checks

### Change type

- [x] `feature`

## Test plan

- [x] `yarn typecheck` passes
- [x] `packages/tldraw` tests pass (129 files, 2028 tests)
- [x] `packages/editor` tests pass (41 files, 764 tests)
- [x] `packages/tlschema` tests pass (9 files, 442 tests)
- [ ] Manual: `yarn dev` → drop images/videos, verify they work as
before
- [ ] Manual: verify custom asset util registration works

### API changes

- Adds `AssetUtil` and a family of classes/helpers to assist with
creating custom assets.
- Breaking: `notifyIfFileNotAllowed` signature changed from (file,
options) to (editor, file, options)
- Breaking: `getAssetInfo` signature changed from (file, options,
assetId?) to (editor, file, assetId?) and now returns `TLAsset | null`
instead of throwing
- Breaking: `getMediaAssetInfoPartial` removed. Use
`AssetUtil.getAssetFromFile` instead
- Breaking: `assetValidator` is removed. Use
`imageAssetValidator`/`videoAssetValidator`/`bookmarkAssetValidator`
- New: `TLGlobalAssetPropsMap` interface for type-safe custom asset
registration (mirrors `TLGlobalShapePropsMap`)
- New: `TLIndexedAssets` type
- New: `TLAsset` now accepts a type parameter for narrowing:
`TLAsset<'image'>`

🤖 Generated with [Claude Code](https://claude.com/claude-code)

---------

Co-authored-by: Claude Opus 4.6 <noreply@anthropic.com>
Co-authored-by: Mitja Bezenšek <mitja.bezensek@gmail.com>
… behind it (#8434)

In order to fix right-click changing the selection when clicking over a
filled shape behind the current selection, this PR reorders the checks
in `onRightClick` so that the selection bounds check runs before
shape-at-point detection. This matches the priority order already used
by `onPointerDown`. Closes #8433

<img width="2354" height="1110" alt="image"
src="https://github.com/user-attachments/assets/a0ab6eab-7d45-4815-b236-dfb4e2c042a3"
/>

### Change type

- [x] `bugfix`

### Test plan

1. Create a large filled shape (e.g., a rectangle with solid fill)
2. Create several smaller shapes on top of it
3. Select the smaller shapes (not the large one behind them)
4. Right-click at a point within the selection bounding box but over the
filled area of the back shape
5. Verify the multi-selection is preserved and the context menu shows
options for the selection
6. Also verify: right-clicking outside the selection bounds still
selects the clicked shape

- [x] Unit tests

### Release notes

- Fix right-clicking inside a multi-selection over a filled background
shape no longer changes the selection.

### Code changes

| Section   | LOC change |
| --------- | ---------- |
| Core code | +21 / -19  |
| Tests     | +23 / -0   |
…ure stalls (#8435)

Zero's replication manager stalled in production after ~10 hours of
normal operation. The Storer's back-pressure mechanism activated (83,500
queued changes, ~82MB) and never recovered, leaving the pipeline frozen
with 16+ hours of replication lag.

Investigation showed the Storer's change DB writes couldn't keep up with
the incoming replication stream, likely exacerbated by a transient
Postgres rollback spike (5,124 rollbacks). With only 5 change DB
connections and `statement_timeout=0`, the queue couldn't drain and
`readyForMore()` never resolved.

This PR increases the RM's connection limits while keeping VS unchanged
(was working fine):

| | Before | After | Zero default |
|---|---|---|---|
| RM upstream | 1 | 5 | 20 |
| RM cvr | 3 | 10 | 30 |
| RM change | 5 | **15** | 5 |
| VS (unchanged) | 8/10/3 | 8/10/3 | 20/30/5 |

Full investigation report: `zero-stall-investigation.md` (not committed,
shared separately with Rocicorp).

### Change type

- [x] `bugfix`

### Test plan

1. Deploy to production
2. Restart RM and monitor replication catches up
3. Watch for back-pressure warnings under load

### Release notes

- Increase Zero replication manager connection limits to prevent storer
back-pressure stalls

### Code changes

| Section        | LOC change |
| -------------- | ---------- |
| Apps           | +1 / -1    |
After the 16+ hour Zero replication stall with no automated detection,
this adds a health check endpoint and a safety net for stuck queries.

**Health check** (`/health-check/zero-replicator`): queries
`pg_stat_replication` for the `zero-replicator` application and returns
500 if it's disconnected, stalled (`write_lsn IS NULL`), or lagging
(`write_lag > 1 minute`). Uses the existing Kysely pool, same pattern as
`/health-check/db`. Configure Updown.io to hit this endpoint every 60s
with the `HEALTH_CHECK_BEARER_TOKEN`.

**Statement timeout**: changes `statement_timeout=0` (infinite) to
`statement_timeout=1800000` (30 min) on Zero's connection strings.
Prevents stuck queries from blocking forever while still allowing
initial sync to complete.

### Change type

- [x] `improvement`

### Test plan

1. Deploy to staging
2. Hit `/health-check/zero-replicator` with bearer token — should return
200
3. Stop the zero-replicator process — endpoint should return 500 after
Updown confirmation
4. Verify Zero still boots and completes initial sync with the 30-min
statement timeout

### Code changes

| Section        | LOC change |
| -------------- | ---------- |
| Apps           | +25 / -0   |
| Config/tooling | +1 / -1    |
@pull pull Bot locked and limited conversation to collaborators Apr 3, 2026
@pull pull Bot added the ⤵️ pull label Apr 3, 2026
@pull pull Bot had a problem deploying to bemo-canary April 3, 2026 15:13 Failure
@pull pull Bot merged commit d426ffe into code:main Apr 3, 2026
3 of 5 checks passed
@pull pull Bot had a problem deploying to deploy-production April 3, 2026 15:13 Failure
@pull pull Bot had a problem deploying to deploy-staging April 3, 2026 15:13 Error
@pull pull Bot had a problem deploying to deploy-staging April 3, 2026 15:13 Failure
@pull pull Bot had a problem deploying to vsce publish April 3, 2026 15:13 Failure
@pull pull Bot had a problem deploying to bemo-canary April 3, 2026 15:13 Failure
Sign up for free to subscribe to this conversation on GitHub. Already have an account? Sign in.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants