Skip to content

Conversation

@joshua-journey-apps
Copy link

This a port of the Swift, Dart and Kotlin attachment's API to the JS SDK.

This addresses the following issues #715 and #714 by adding the meta_data column to the table and persisting it in the attachments table.

It is currently still a work-in-progress so there are a couple things that still needs to be done:

  • Update demos
  • Improve testing
  • Update the readme
  • Implement sync throttling
  • Implement clearing archived attachments
  • Removing some holdovers from the previous implementation

@changeset-bot
Copy link

changeset-bot bot commented Oct 7, 2025

⚠️ No Changeset found

Latest commit: ce33bab

Merging this PR will not cause a version bump for any packages. If these changes should not result in a new version, you're good to go. If these changes should result in a version bump, you need to add a changeset.

This PR includes no changesets

When changesets are added to this PR, you'll see the packages that this PR includes changesets for and the associated semver types

Click here to learn what changesets are, and how to add one.

Click here if you're a maintainer who wants to add a changeset to this PR

Copy link
Collaborator

@stevensJourney stevensJourney left a comment

Choose a reason for hiding this comment

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

This looks like a good improvement so far. I've added some comments for some items I spotted.

this.logger = logger;
}

watchActiveAttachments(onUpdate: () => void): AbortController {
Copy link
Collaborator

Choose a reason for hiding this comment

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

The AttachmentContext here is typically an exclusive access context (provided by the AttachmentsService). The context provides general methods for reading and writing AttachmentRecords in a safe context.
The watchActiveAttachments method does fall in to the category of reading Attachment records, but it does not typically require being executed in an exclusive context. It's usually only called once when the sync starts for initialisation. Furthermore, the handler in onUpdate typically will request an AttachmentContext in order to process the active attachments, which can produce a rather interesting code flow.
For consistency with other SDKs, I'd recommend moving this to the AttachmentService.

onUpdate should probably be an async handler.

Alternatively, we could use the Differentially Watched queries here. That would have the advantage of only triggering when there are actual changes to the result set. It also could make closing/aborting and listening for changes simpler.

watchActiveAttachments(): DifferentialWatchedQuery<AttachmentRecord> 

Choose a reason for hiding this comment

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

I see, okay the separation makes sense - improved the consistency in the latest batch of commits. Also took the differential watched query approach.

import { AbstractPowerSyncDatabase, ILogger, Transaction } from '@powersync/common';
import { AttachmentRecord, AttachmentState, attachmentFromSql } from './Schema.js';

export class AttachmentContext {
Copy link
Collaborator

Choose a reason for hiding this comment

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

Just a reminder to add doc comments to all public classes and interfaces

Choose a reason for hiding this comment

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

I added doc comments all of the public classes, functions and interfaces - should have total coverage now.

import { SyncErrorHandler } from './SyncErrorHandler.js';

export class StorageService {
context: AttachmentContext;
Copy link
Collaborator

Choose a reason for hiding this comment

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

The SyncingService is usually instantiated when the attachment queue is initialised. The SyncingService then dynamically requests a lock on an AttachmentContext via the AttachmentService. This implementation should receive a reference to an AttachmentService here.


async downloadAttachment(attachment: AttachmentRecord): Promise<AttachmentRecord> {
try {
const fileBlob = await this.remoteStorage.downloadFile(attachment);
Copy link
Collaborator

Choose a reason for hiding this comment

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

I think we should have the local storage adapter support writing the same type as returned from the remote downloadFile method without a conversion here.


const config: UserConfigExport = {
plugins: [topLevelAwait()],
worker: {
Copy link
Collaborator

Choose a reason for hiding this comment

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

An alternative could be to use the Node.js SDK for tests instead. That should require less config here.

metaData,
id
}: {
data: ArrayBuffer | Blob | string;
Copy link
Collaborator

Choose a reason for hiding this comment

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

It would be nice to export this to it's own dedicated type instead of inlining.

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.

4 participants