Skip to content

Add pagination and expanded data set, piece, provider, and payment queries - #913

Merged
hugomrdias merged 5 commits into
masterfrom
hugomrdias/753
Aug 20, 2026
Merged

Add pagination and expanded data set, piece, provider, and payment queries#913
hugomrdias merged 5 commits into
masterfrom
hugomrdias/753

Conversation

@hugomrdias

@hugomrdias hugomrdias commented Aug 12, 2026

Copy link
Copy Markdown
Member

Summary

  • Add reusable pagination utilities and paginated PDP, warm-storage, provider registry, and payment queries
  • Return cursor-paginated dataset, piece, provider, and payment results from synapse-core, and update synapse-sdk consumers to traverse those pages explicitly
  • Update CLI commands and flags to support the new query capabilities
  • Add mocks and coverage for pagination and newly supported queries

Pagination examples

Read one bounded page and pass the returned cursor back unchanged:

const page = await getClientDataSets(client, {
  address,
  limit: 100n,
})

if (page.nextCursor !== undefined) {
  const nextPage = await getClientDataSets(client, {
    address,
    cursor: page.nextCursor,
    limit: 100n,
  })
}

Iterate over every item with the shared paginate() generator:

import { paginate } from "@filoz/synapse-core"

for await (const dataSet of paginate(({ cursor }) =>
  getClientDataSets(client, { address, cursor })
)) {
  console.log(dataSet.dataSetId)
}

Accumulate all items when a complete array is required:

const dataSets = await Array.fromAsync(
  paginate(({ cursor }) => getClientDataSets(client, { address, cursor }))
)

Cursors are opaque continuation values. Each action uses a bounded default when limit is omitted, and rejects limit: 0n.

Testing

  • Added unit tests covering pagination, data sets, pieces, providers, payment rails, and storage queries
  • Not run (not requested)

@github-project-automation github-project-automation Bot moved this to 📌 Triage in FOC Aug 12, 2026
@cloudflare-workers-and-pages

cloudflare-workers-and-pages Bot commented Aug 12, 2026

Copy link
Copy Markdown

Deploying with  Cloudflare Workers  Cloudflare Workers

The latest updates on your project. Learn more about integrating Git with Workers.

Status Name Latest Commit Preview URL Updated (UTC)
✅ Deployment successful!
View logs
synapse-dev 5b0d94c Commit Preview URL

Branch Preview URL
Aug 18 2026, 02:59 PM

@SgtPooki SgtPooki 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.

in general lgtm.. huge change, but everything seems legit.. a few callouts that aren't necessarily blocking but could make some things better.

})

// after
const page = await getActivePiecesByCursor(client, {

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.

the name here feels weird, when we're not passing a cursor. the rename seems unnecessary. can we leave it as getActivePieces ?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

I’d prefer to keep this name. Synapse Core actions intentionally match contract function names, and the underlying endpoint is getActivePiecesByCursor. It also avoids conflating this endpoint with the older offset-based getActivePieces contract method.


`findPieceIdsByCid`, `getPieces`, and `getPiecesWithMetadata` also return pages and accept `cursor` rather than `startPieceId` or `offset` at the action level.

Raw `*Call` helpers remain ABI-oriented: provide their required contract-facing `offset` or `startPieceId` and `limit` fields explicitly when constructing multicalls.

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.

and these raw call methods are just in synapse-core, yes? I think it would be nice to normalize synapse-sdk being the "polished" surface and synapse-core being the lego bricks.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes, these raw ABI-oriented helpers are part of @filoz/synapse-core. The higher-level SDK remains the polished surface and either exposes normalized pages or fully traversed arrays depending on the method. I’ll make that package boundary explicit in the migration guide.

}
```

Use `paginate()` when you want to traverse every page. It follows `nextCursor`, yields individual items, and rejects a repeated or non-advancing cursor.

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.

is it possible to break out of a paginate inner loop?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Yes. paginate() is an async generator, so a normal break exits the loop and closes the generator; it won’t fetch another page.

Comment on lines 94 to 98
const hasMore = BigInt(data.length) > limit
return {
items: Array.from(hasMore ? data.slice(0, -1) : data),
...(hasMore ? { nextCursor: cursor + limit } : {}),
}

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.

this is duplicated in three places, and findPieceIdsByCid, getApprovedProviderIds, and getProvidersByProductType are missing limit+1 boundary testing, which means any individual implementation can drift.

Can we pull this out into a shared helper and then test that shared helper so we are sure each implementation is doing what it's supposed to?

Comment on lines +211 to +219
const [pdpProviders, approvedProviders] = await Promise.all([
Array.fromAsync(
paginate(({ cursor }) =>
getPDPProviders(client, { onlyActive: true, cursor, contractAddress: options.contractAddress })
)
),
Array.fromAsync(paginate(({ cursor }) => getApprovedProviderIds(client, { cursor }))),
])
return pdpProviders.filter((provider) => approvedProviders.includes(provider.id))

@SgtPooki SgtPooki Aug 13, 2026

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.

suggestion (non-blocking): getApprovedPDPProviders is only exercised indirectly, via fetch-provider-selection-input.test.ts, and only against single-page responses.. the basic preset never returns limit+1 items or hasMore: true, so paginate()'s multi-page path never runs against a real action anywhere in synapse-core (pagination.test.ts uses an in-memory stub).

The old get-client-data-sets.test.ts covered real multi-call traversal (150 items across 100+50 RPC calls) and was deleted with the old API, so multi-page coverage is net lower after this PR.

Can we add a direct test here with a mock returning 2+ pages? That covers getApprovedPDPProviders itself (including the approved-ids intersection) and restores the traversal coverage in one shot.

],
},
],
hasMore: false,

@SgtPooki SgtPooki Aug 13, 2026

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.

this getProvidersByProductType mock ignores offset/limit and hardcodes hasMore:false.. we could extend this so we can write tests to help catch any cursor handling regression

@github-project-automation github-project-automation Bot moved this from 📌 Triage to ✔️ Approved by reviewer in FOC Aug 13, 2026
limit: 100n,
})

for await (const piece of paginate(({ cursor }) =>

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

Suggested change
for await (const piece of paginate(({ cursor }) =>
// iterate
for await (const piece of paginate(({ cursor }) =>

currently reads like it's part of // after

import { readPdpDataSetInfo } from './get-pdp-data-set.ts'
import type { PdpDataSet } from './types.ts'
const ENRICHMENT_BATCH_SIZE = 20
const DATA_SET_CALL_COUNT = 4

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

I think this one deserves a comment, it's going to be very easy to get this out of syncwith the number of calls

@rvagg rvagg left a comment

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

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

well I don't hate it, I think that's what you wanted to hear?

needs a ! in a commit somewhere to bump major I guess

also utils/sp-tool.js will be broken after this, may as well fix it now, also core-concepts/storage-providers.mdx could do with a look, it has getApprovedProviderIds calls

@hugomrdias
hugomrdias removed request for a team, BigLep, jennijuju and rjan90 August 18, 2026 11:38
@hugomrdias
hugomrdias merged commit 3c9b08f into master Aug 20, 2026
13 checks passed
@hugomrdias
hugomrdias deleted the hugomrdias/753 branch August 20, 2026 10:37
@github-project-automation github-project-automation Bot moved this from ✔️ Approved by reviewer to 🎉 Done in FOC Aug 20, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

Status: 🎉 Done

Development

Successfully merging this pull request may close these issues.

getPdpDataSet fails on large data sets because getActivePieceCount reverts inside multicall Normalize pagination interface

3 participants