Skip to content

Expose real byte-level progress in uploadToSynapse callbacks #326

@HavenCTO

Description

@HavenCTO

Context / Problem

When calling uploadToSynapse, the progress reporting is limited to high-level milestone events (e.g., onUploadComplete, onPieceAdded). While the underlying synapse-core SDK provides real-time, byte-level upload progress via an onProgress callback, this information is not exposed or passed through by filecoin-pin. This prevents consumers from implementing accurate progress bars during the data transfer phase, as bytesUploaded remains unknown until the upload finishes.

Current Implementation

onProgress?.({ type: 'onUploadComplete', data: { pieceCid } })

filecoin-pin/src/core/upload/synapse.ts currently only maps lifecycle callbacks:

const uploadCallbacks: UploadCallbacks = {
  onUploadComplete: (pieceCid) => { ... },
  onPieceAdded: (txHash) => { ... },
  onPieceConfirmed: (pieceIds) => { ... },
  // onProgress: ??? // ✗ NOT PASSED!
};

The SDK's onProgress(bytesUploaded) callback is completely ignored, leaving a gap in telemetry during the actual network transfer.

The SDK Provides Real Progress

https://github.com/FilOzone/synapse-sdk/blob/4be67a838c5b602608b3ac33f9702c1343f87e09/packages/synapse-core/src/sp.ts#L523
File: synapse-sdk/packages/synapse-core/src/sp.ts (line ~520)
The lowest layer already tracks real progress:

let bytesUploaded = 0
const trackingStream = new TransformStream<Uint8Array, Uint8Array>({
  transform(chunk, controller) {
    bytesUploaded += chunk.length
    if (options.onProgress) {
      options.onProgress(bytesUploaded) // Real bytes uploaded!
    }
    controller.enqueue(chunk)
  },
})

File: synapse-sdk/packages/synapse-sdk/src/types.ts
The UploadCallbacks interface supports this:

export interface UploadCallbacks {
  /** Called periodically during upload with bytes uploaded so far */
  onProgress?: (bytesUploaded: number) => void
  onUploadComplete?: (pieceCid: PieceCID) => void
  // ...
}

Requested Changes

Update uploadToSynapse to accept and forward the onProgress callback from the underlying SDK.

  1. Update Callback Interface: Extend the options or callbacks argument in uploadToSynapse to accept a progress handler.
  2. Forward to SDK: Ensure the onProgress callback is passed to UploadCallbacks when calling the SDK, so it receives the bytesUploaded updates.

Suggested Implementation:

// In uploadToSynapse(), add:
const uploadCallbacks: UploadCallbacks = {
  onProgress: (bytesUploaded) => {
    // Expose real progress to caller
    onProgress?.({ type: 'onProgress', data: { bytesUploaded } })
  },
  onUploadComplete: (pieceCid) => { ... },
  // ...
};

Why This Matters

Without access to onProgress, integrations cannot accurately report transfer status to users. Progress bars either jump from 0% to 100% upon completion or rely on synthetic phase markers (e.g., "uploading..."), which degrades the user experience for file uploads.

Environment / Repro

  • Client: Integration using filecoin-pin to track upload progress.
  • Scenario: Uploading a CAR file (100MiB).
  • Current Behavior: onUploadComplete fires only at the end. No intermediate events are received.
  • Desired Behavior: Receive periodic updates with bytesUploaded during the transfer to render a smooth progress bar.

Thanks for considering—happy to test a callback implementation and provide feedback.

Metadata

Metadata

Assignees

No one assigned

    Labels

    team/filecoin-pin"Filecoin Pin" project is a stakeholder for this work.team/fs-wgFOC working group is a stakeholder for this work, and thus wants to track it on their project board.

    Type

    No type

    Projects

    No projects

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions