feat: add Sonar-compatible sticker support#875
Conversation
|
Warning Review limit reached
Next review available in: 50 minutes Enable usage-based reviews in Billing to review now. Otherwise, wait until the next included review is available. How can I continue?After more reviews become available, a review can be triggered using the To avoid repeated limits, reduce automatic review volume by pausing incremental auto-reviews earlier, using label-based review opt-in, excluding WIP or generated PR titles, or requesting reviews manually when the PR is ready. If your team needs uninterrupted high-volume reviews, an organization admin can enable usage-based reviews. How do review limits work?CodeRabbit enforces per-developer PR review limits for each organization. Most developers receive the normal plan review availability. For paid Pro and Pro+ PR reviews, CodeRabbit uses adaptive limits for sustained high-volume activity. When a developer's recent PR review activity reaches the 95th percentile or higher among CodeRabbit users, additional reviews become available more gradually as earlier reviews age out of the rolling window. Please refer docs for additional details. Review details⚙️ Run configurationConfiguration used: Organization UI Review profile: CHILL Plan: Pro Run ID: ⛔ Files ignored due to path filters (1)
📒 Files selected for processing (34)
WalkthroughAdds Sonar sticker-pack storage, validation, relay synchronization, Signal import, sticker messaging, chat projections, and UniFFI APIs. The workspace version advances to 0.10.0, with new typed sticker data and error mappings across application layers. ChangesSonar sticker integration
Estimated code review effort: 5 (Critical) | ~120 minutes Possibly related PRs
🚥 Pre-merge checks | ✅ 4 | ❌ 1❌ Failed checks (1 warning)
✅ Passed checks (4 passed)
✨ Finishing Touches🧪 Generate unit tests (beta)
Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out. Comment |
|
Ready to review this PR? Stage has broken it down into 9 individual chapters for you: Chapters generated by Stage for commit e0e12be on Jul 16, 2026 10:57am UTC. |
There was a problem hiding this comment.
Actionable comments posted: 10
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/storage-sqlite/src/timeline.rs (1)
797-805: 🩺 Stability & Availability | 🟠 Major | ⚡ Quick winHandle
NULLvalues when parsingtags_json.If
tags_jsonin themessage_timelinetable can beNULL(e.g., for rows created before the schema migration), usingrow.get::<_, String>will return arusqlite::Error::InvalidColumnTypeand fail the query. Consider reading it as anOption<String>.🐛 Proposed fix
Ok(( row.get::<_, String>(0)?, row.get::<_, String>(1)?, row.get::<_, String>(2)?, row.get::<_, i64>(3)?, - row.get::<_, String>(4)?, + row.get::<_, Option<String>>(4)?, row.get::<_, i64>(5)?, row.get::<_, i64>(6)?, ))🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/storage-sqlite/src/timeline.rs` around lines 797 - 805, Update the row-mapping tuple in the timeline query to read the nullable tags_json column as Option<String> instead of String, preserving successful parsing for existing non-NULL values and allowing legacy NULL rows without InvalidColumnType errors.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@crates/marmot-app/src/relay_plane/mod.rs`:
- Around line 381-393: Update the relay connection loop in fetch_public_events
so failures from add_relay, connection timeout, or connect_relay are handled per
relay without propagating via ?. Log or otherwise record each individual
failure, then continue iterating through relay_urls so successfully connected
relays can still be used for fetching.
- Around line 381-393: Update the relay connection loop in fetch_public_events
so failures from add_relay, connection timeout, or connect_relay do not
propagate through ?. Handle each relay independently, optionally logging the
failure, and continue processing the remaining relay_urls so fetching proceeds
with all successfully connected relays.
In `@crates/marmot-app/src/stickers.rs`:
- Around line 1030-1048: Update the PNG parsing loop around the acTL handling to
count each fcTL chunk as an actual APNG frame, enforce the existing frame limit
against that count, and require exactly one valid acTL declaration whose frame
count matches the observed fcTL total before accepting the image. Do not rely
solely on the declared frames value.
- Around line 459-528: Update the sticker import flow surrounding the upload
loop and pack publication to persist a staged import intent before the first
external side effect. Advance that intent after each successful upload, signing,
publication, and install-operation step, and add compensation or resumable
recovery for failures after any step has completed so no orphaned assets or
published packs remain without durable state.
- Around line 239-247: Update the sticker listing flow around
desired_installed_sticker_packs and sticker_packs so installed_only is evaluated
against the desired installed coordinate set rather than the remote base
projection. Pass that desired set into storage filtering, while preserving the
existing search behavior and applying limit semantics to the resulting
desired-state-filtered packs.
- Around line 324-325: In the sync flow around sync_sticker_packs, call
refresh_installed_base(self, &context) before flush_sticker_outbox(self,
&context). Ensure the outbox replay and resulting publication are regenerated
from the refreshed remote winner so pending kind-10031 operations are not
cleared against a stale local base.
- Around line 454-456: In the imported sticker loop, add a
MAX_STICKER_ASSET_BYTES validation for imported_sticker.bytes before
inspect_image and upload processing. Reject oversized sticker data using the
existing error-handling pattern, while preserving the current inspection and
upload flow for buffers within the limit.
In `@crates/storage-sqlite/src/chat_list.rs`:
- Around line 902-904: Handle nullable tags_json consistently across
crates/storage-sqlite/src/chat_list.rs:902-904,
crates/storage-sqlite/src/timeline.rs:797-805, and
crates/storage-sqlite/src/timeline.rs:2418-2420: read column 4 as
Option<String>, preserve the row tuple mapping at timeline.rs:797-805, and make
the chat-list and timeline tag parsing fall back to an empty vector when the
value is None or invalid JSON.
- Around line 902-904: Update the tags parsing in the row-conversion function
around the tags field to read tags_json as an Option<String>, then fall back to
the same default used by chat_list_row_from_row when it is NULL before
deserializing. Preserve the existing FromSqlConversionFailure mapping for
invalid JSON.
In `@crates/storage-sqlite/src/timeline.rs`:
- Around line 2418-2420: Update the tags parsing in the row-mapping code around
the tags field to read the column as Option<String> instead of String, then fall
back to the existing default tags value when it is NULL before deserializing.
Preserve the current serde_json error-to-rusqlite conversion for present values.
---
Outside diff comments:
In `@crates/storage-sqlite/src/timeline.rs`:
- Around line 797-805: Update the row-mapping tuple in the timeline query to
read the nullable tags_json column as Option<String> instead of String,
preserving successful parsing for existing non-NULL values and allowing legacy
NULL rows without InvalidColumnType errors.
🪄 Autofix (Beta)
Fix all unresolved CodeRabbit comments on this PR:
- Push a commit to this branch (recommended)
- Create a new PR with the fixes
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 89219b8a-5074-46b1-bd4f-1b8faebd7fc2
⛔ Files ignored due to path filters (1)
Cargo.lockis excluded by!**/*.lock
📒 Files selected for processing (34)
Cargo.tomlcrates/marmot-app/Cargo.tomlcrates/marmot-app/src/client/audit.rscrates/marmot-app/src/client/mod.rscrates/marmot-app/src/client/projection.rscrates/marmot-app/src/client/push.rscrates/marmot-app/src/error.rscrates/marmot-app/src/lib.rscrates/marmot-app/src/media/blossom.rscrates/marmot-app/src/media/mod.rscrates/marmot-app/src/messages/intents.rscrates/marmot-app/src/notifications.rscrates/marmot-app/src/relay_plane/mod.rscrates/marmot-app/src/runtime/mod.rscrates/marmot-app/src/stickers.rscrates/marmot-app/src/tests.rscrates/marmot-uniffi/src/commands/message.rscrates/marmot-uniffi/src/commands/mod.rscrates/marmot-uniffi/src/commands/sticker.rscrates/marmot-uniffi/src/conversions/chat_list.rscrates/marmot-uniffi/src/conversions/message.rscrates/marmot-uniffi/src/conversions/mod.rscrates/marmot-uniffi/src/conversions/notification.rscrates/marmot-uniffi/src/conversions/sticker.rscrates/marmot-uniffi/src/conversions/timeline.rscrates/marmot-uniffi/src/errors.rscrates/marmot-uniffi/src/lib.rscrates/marmot-uniffi/tests/smoke.rscrates/storage-sqlite/src/chat_list.rscrates/storage-sqlite/src/lib.rscrates/storage-sqlite/src/migrations.rscrates/storage-sqlite/src/migrations/0026_sonar_stickers.rscrates/storage-sqlite/src/stickers.rscrates/storage-sqlite/src/timeline.rs
There was a problem hiding this comment.
Caution
Some comments are outside the diff and can’t be posted inline due to platform limitations.
⚠️ Outside diff range comments (1)
crates/storage-sqlite/src/stickers.rs (1)
180-192: 🎯 Functional Correctness | 🟡 Minor | ⚡ Quick winEscape SQL
LIKEmetacharacters to preserve literal search semantics.The installed path uses literal
contains, while this path treats%and_as wildcards. The same query therefore returns different matches depending oninstalled_only.Proposed fix
- let pattern = format!("%{}%", search.to_ascii_lowercase()); + let escaped = search + .replace('!', "!!") + .replace('%', "!%") + .replace('_', "!_"); + let pattern = format!("%{escaped}%"); ... - WHERE lower(title) LIKE ?1 - OR lower(COALESCE(description, '')) LIKE ?1 + WHERE lower(title) LIKE ?1 ESCAPE '!' + OR lower(COALESCE(description, '')) LIKE ?1 ESCAPE '!'🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the rest with a brief reason, keep changes minimal, and validate. In `@crates/storage-sqlite/src/stickers.rs` around lines 180 - 192, Update the searched branch of the sticker-pack lookup around the search pattern and SQL in the coordinates query to escape LIKE metacharacters (`%`, `_`, and the escape character) before binding the value, then add the matching ESCAPE clause. Preserve case-insensitive contains semantics so installed and non-installed searches return equivalent literal matches.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Outside diff comments:
In `@crates/storage-sqlite/src/stickers.rs`:
- Around line 180-192: Update the searched branch of the sticker-pack lookup
around the search pattern and SQL in the coordinates query to escape LIKE
metacharacters (`%`, `_`, and the escape character) before binding the value,
then add the matching ESCAPE clause. Preserve case-insensitive contains
semantics so installed and non-installed searches return equivalent literal
matches.
ℹ️ Review info
⚙️ Run configuration
Configuration used: Organization UI
Review profile: CHILL
Plan: Pro
Run ID: 02f27817-87f0-483f-b20b-9ade3aa669c6
📒 Files selected for processing (3)
crates/marmot-app/src/relay_plane/mod.rscrates/marmot-app/src/stickers.rscrates/storage-sqlite/src/stickers.rs
🚧 Files skipped from review as they are similar to previous changes (2)
- crates/marmot-app/src/relay_plane/mod.rs
- crates/marmot-app/src/stickers.rs
|
Addressed the remaining non-inline CodeRabbit feedback in 9b8f3cb: sticker-pack searches now escape SQLite LIKE metacharacters ( |
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
cb64f17 to
e0e12be
Compare
Summary
Security and privacy
Verification
Summary by CodeRabbit
New Features
Bug Fixes
Tests