Conversation
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 |
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 subscribe to this conversation on GitHub.
Already have an account?
Sign in.
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.
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 : )