Summary
queryEvents is a single-page call. If a developer wants all events for a contract they have to write a while loop, check has_more, store the next_cursor, and call again. This is boilerplate every single consumer has to write. A higher-level async iterator bakes that pattern into the SDK so callers can just write for await (const event of client.iterEvents(params)) and get every event without thinking about pages.
Context
The cursor system is already in place on the server side — the API returns an opaque next_cursor and a has_more boolean. The SDK just needs a thin wrapper that follows those cursors automatically. This is a pure client-side feature with no server changes required.
What needs to be built
A new function iterEvents(params: QueryEventsParams, options?: IterOptions): AsyncIterable<SorobanEvent> that:
- Calls
queryEvents with the provided params
- Yields each event from the page as it arrives
- When the page is exhausted, checks
has_more; if true, calls queryEvents again with the next_cursor from the previous response
- Continues until
has_more === false or the optional maxPages limit is hit (default: 100 — a safety valve to prevent infinite loops on runaway contracts)
- Propagates any
TridentApiError thrown by queryEvents transparently so the caller's try/catch still works
The function should work with for await...of in Node 18+, modern browsers, and Deno without any polyfills since it uses the standard AsyncIterable protocol.
Acceptance Criteria
Files
sdk/typescript/src/iterator.ts (new)
Summary
queryEventsis a single-page call. If a developer wants all events for a contract they have to write a while loop, checkhas_more, store thenext_cursor, and call again. This is boilerplate every single consumer has to write. A higher-level async iterator bakes that pattern into the SDK so callers can just writefor await (const event of client.iterEvents(params))and get every event without thinking about pages.Context
The cursor system is already in place on the server side — the API returns an opaque
next_cursorand ahas_moreboolean. The SDK just needs a thin wrapper that follows those cursors automatically. This is a pure client-side feature with no server changes required.What needs to be built
A new function
iterEvents(params: QueryEventsParams, options?: IterOptions): AsyncIterable<SorobanEvent>that:queryEventswith the provided paramshas_more; if true, callsqueryEventsagain with thenext_cursorfrom the previous responsehas_more === falseor the optionalmaxPageslimit is hit (default: 100 — a safety valve to prevent infinite loops on runaway contracts)TridentApiErrorthrown byqueryEventstransparently so the caller'stry/catchstill worksThe function should work with
for await...ofin Node 18+, modern browsers, and Deno without any polyfills since it uses the standardAsyncIterableprotocol.Acceptance Criteria
client.iterEvents(params)returns anAsyncIterable<SorobanEvent>for await...ofin Node 18+has_more === falsemaxPagesoption (default 100); throwsTridentApiErrorwith codeITERATION_LIMITif exceededqueryEventsthat returns 3 pages of 5 events each — assert 15 events yielded in orderqueryEventsfor awaitusageFiles
sdk/typescript/src/iterator.ts(new)