Skip to content

feat(PowerSync): add attachments support#1616

Open
Chriztiaan wants to merge 12 commits into
TanStack:mainfrom
powersync-ja:feat/powersync-attachments
Open

feat(PowerSync): add attachments support#1616
Chriztiaan wants to merge 12 commits into
TanStack:mainfrom
powersync-ja:feat/powersync-attachments

Conversation

@Chriztiaan

@Chriztiaan Chriztiaan commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

🎯 Changes

Derived from Steven's efforts in powersync-ja/powersync-js#983, and addresses #1563.

Problem

PowerSync ships an attachment helper for syncing files (photos, documents) between local and remote storage. It's separate from regular synced tables: a local-only attachments table tracks each file's lifecycle (QUEUED_UPLOAD, SYNCED, QUEUED_DELETE), and an AttachmentQueue drives uploads/downloads in the background.

TanStackDB, on the other hand, gives you an optimistic, reactive, joinable view over synced data. For users who want to use the attachment helper alongside the PowerSync+TanstackDB integration there are blockers. Saving a file (in the local-only attachments table) and associating it with a record (e.g. setting user.photo_id) are two independent writes which could make data races and fatal errors a problem for data consistency.

The original POC (powersync-js#983) proved this integration was viable. This PR productionises a a subset of it as reusable functionality.

Solution

A TanStackDBAttachmentQueue that extends the SDK's AttachmentQueue (for saving and deleting a file) and backs it with a TanStack DB collection.

The package owns the collection-backed saveFile/delete implementation and leaves the wiring to the application (covered in documentation).

✅ Checklist

  • I have tested this code locally with pnpm test.

🚀 Release Impact

  • This change affects published code, and I have generated a changeset.

Summary by CodeRabbit

  • New Features

    • Added attachment support for PowerSync DB collections, including atomic save and delete flows.
    • Attachment changes can now be committed alongside related data updates in the same transaction.
  • Documentation

    • Added guidance for setting up, saving, displaying, and removing attachments.
  • Bug Fixes

    • Improved attachment handling to keep local files, database records, and related data in sync more reliably.

@coderabbitai

coderabbitai Bot commented Jun 25, 2026

Copy link
Copy Markdown
Contributor

Review Change Stack

📝 Walkthrough

Walkthrough

Adds a TanStack DB-backed attachment queue with new public exports, setup docs, and tests. The queue saves and deletes attachments inside collection transactions, and the examples cover watching attachment IDs, syncing files, clearing references, and reading local cached URIs.

Changes

TanStackDB attachment queue

Layer / File(s) Summary
API surface and package wiring
packages/powersync-db-collection/src/attachments.ts, packages/powersync-db-collection/src/index.ts, packages/powersync-db-collection/package.json, .changeset/curly-planets-lead.md
Adds the attachment queue types and class, re-exports them from the package entrypoint, and updates package metadata for the new release.
Queue setup and attachment watching
docs/collections/powersync-collection.md, packages/powersync-db-collection/tests/attachments.test.ts
Adds TanStack DB collection setup, watchAttachments wiring, and shared test harness helpers for attachment state tracking.
Atomic save flow and attachment readback
packages/powersync-db-collection/src/attachments.ts, docs/collections/powersync-collection.md, packages/powersync-db-collection/tests/attachments.test.ts
Implements and documents queued uploads, transactional update hooks, local file persistence, and live-query display of attachment URIs, with tests for sync transitions and caller-supplied IDs.
Atomic delete flow
packages/powersync-db-collection/src/attachments.ts, docs/collections/powersync-collection.md, packages/powersync-db-collection/tests/attachments.test.ts
Implements and documents queued deletes, foreign-key clearing, and post-sync removal, with tests covering missing IDs and final cleanup.

Sequence Diagram(s)

sequenceDiagram
  participant TanStackDBAttachmentQueue
  participant withAttachmentContext
  participant PowerSyncTransactor
  participant attachmentsCollection
  participant updateHook
  TanStackDBAttachmentQueue->>withAttachmentContext: delete()
  withAttachmentContext->>PowerSyncTransactor: open non-auto-committing transaction
  PowerSyncTransactor->>attachmentsCollection: load attachment by id
  PowerSyncTransactor->>attachmentsCollection: set QUEUED_DELETE and reset has_synced
  TanStackDBAttachmentQueue->>updateHook: clear linked foreign key
  PowerSyncTransactor-->>TanStackDBAttachmentQueue: commit
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~60 minutes

Suggested reviewers

  • KyleAMathews
  • samwillis

Poem

🐇 I hopped through the queue with a twitchy nose,
Saved tiny file bytes where the soft database grows.
Deletes went poof in a tidy sync dance,
And URIs sparkled in a live-query trance.

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check name Status Explanation Resolution
Docstring Coverage ⚠️ Warning Docstring coverage is 33.33% which is insufficient. The required threshold is 80.00%. Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check name Status Explanation
Title check ✅ Passed The title clearly summarizes the main change: adding PowerSync attachment support.
Description check ✅ Passed The description includes the required Changes, Checklist, and Release Impact sections with relevant implementation context.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests

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.

❤️ Share

Comment @coderabbitai help to get the list of available commands.

@socket-security

socket-security Bot commented Jun 25, 2026

Copy link
Copy Markdown

Review the following changes in direct dependencies. Learn more about Socket for GitHub.

Diff Package Supply Chain
Security
Vulnerability Quality Maintenance License
Updatednpm/​@​powersync/​common@​1.49.0 ⏵ 1.57.098 +91008098100

View full report

@Chriztiaan Chriztiaan marked this pull request as ready for review June 25, 2026 07:45

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 3

🤖 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 @.changeset/curly-planets-lead.md:
- Around line 1-3: The changeset for `@tanstack/powersync-db-collection` is
labeled patch, but this release introduces a new public export and raises the
`@powersync/common` peer minimum, so update the changeset in curly-planets-lead.md
to at least minor (or the appropriate breaking level per your policy). Keep the
package name the same and change only the release type so the generated release
notes reflect the expanded surface area and peer dependency bump.

In `@docs/collections/powersync-collection.md`:
- Around line 1195-1207: The watcher example in the referenced attachment-ID
flow is fire-and-forgetting onUpdate, which can let overlapping updates resolve
out of order. Update the example around livePhotoIds.stateWhenReady,
livePhotoIds.subscribeChanges, and the onUpdate callback to serialize each async
invocation by awaiting the previous one (for example through a chained promise
or equivalent queue) so the initial state and later change notifications are
processed in order. Also mirror the same awaited pattern in the test helper that
currently reproduces this race.

In `@packages/powersync-db-collection/src/attachments.ts`:
- Around line 79-80: The `addAttachment` flow in `Attachments` writes the blob
with `localStorage.saveFile()` before the transaction, but failures in `insert`,
`updateHook`, or `commit()` leave the file orphaned on disk. Update the
attachment write path to track the just-saved local URI and delete it on every
exception path, including transaction rollback and any thrown hook/commit error,
while keeping successful saves intact. Also add a regression test around
`updateHook` that throws to verify the DB changes roll back and the local file
is cleaned up.
🪄 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: defaults

Review profile: CHILL

Plan: Pro

Run ID: 9f1f73be-698d-4312-886c-aeb36c8b4f13

📥 Commits

Reviewing files that changed from the base of the PR and between 45617c4 and cd8b191.

⛔ Files ignored due to path filters (1)
  • pnpm-lock.yaml is excluded by !**/pnpm-lock.yaml
📒 Files selected for processing (6)
  • .changeset/curly-planets-lead.md
  • docs/collections/powersync-collection.md
  • packages/powersync-db-collection/package.json
  • packages/powersync-db-collection/src/attachments.ts
  • packages/powersync-db-collection/src/index.ts
  • packages/powersync-db-collection/tests/attachments.test.ts

Comment thread .changeset/curly-planets-lead.md
Comment thread docs/collections/powersync-collection.md
Comment thread packages/powersync-db-collection/src/attachments.ts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

2 participants