feat(ts-sdk): account activity resource - #310
Open
majesticwizardcat wants to merge 5 commits into
Open
majesticwizardcat wants to merge 5 commits into
majesticwizardcat wants to merge 5 commits into
Conversation
client.activity(account, query) seeds one account's history from
GET /clob/activity/{account} and streams pod_activity_v2, mirroring
OrderHistory: the subscribe, resume and re-seed machine is lifted out
of OrderHistory into a shared ResumableStream with no behaviour change,
the order events fold through applyOrdersFrame with the book now read
from the entity, and the backstop, bridge_transfer and transfer events
land as signed money entries. Entries carry a tagged activityType and
sort newest first with the node's ordinal as the tiebreak.
Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
majesticwizardcat
marked this pull request as ready for review
September 30, 2026 14:28
poszu
added this pull request to stack #312
October 2, 2026 06:16
Contributor
There was a problem hiding this comment.
Copilot review overview
🟡 Changes recommended
Activity timestamps and paginated rows can be lost or reordered, and transient initial seed failures can leave resources permanently idle.
Review effort: Balanced
Findings: 4
Open (7)
Use page-independent keys for activity deduplication · New Treat empty activity types as an omitted filter · New Preserve REST order timestamps during activity reconstruction · New Retry failed initial REST seeding · New Clarify that orders() uses a separate feed · New Correct the limit unit in the public API comment · New Use the correct pod_activity_v2 channel name · New
What changed in this PR
Adds account activity history combining orders and money movements through REST and WebSocket synchronization.
Changes:
- Adds activity wire/public types, codecs, REST endpoint, and client resource.
- Extracts reusable resumable-stream lifecycle logic from order history.
- Adds activity decoding and synchronization tests.
| File | Description |
|---|---|
ts-sdk/src/types/wire.ts |
Defines activity wire payloads. |
ts-sdk/src/types/public.ts |
Adds public activity types. |
ts-sdk/src/transport/ws.ts |
Registers the activity channel. |
ts-sdk/src/transport/rest.ts |
Adds activity REST transport. |
ts-sdk/src/sync/stream.ts |
Extracts resumable streaming logic. |
ts-sdk/src/sync/orders.ts |
Migrates orders to the shared stream. |
ts-sdk/src/sync/activity.ts |
Implements activity history synchronization. |
ts-sdk/src/sync/activity.test.ts |
Tests activity history behavior. |
ts-sdk/src/index.ts |
Exports activity APIs. |
ts-sdk/src/codec/orders-v2.ts |
Supports entity-level books. |
ts-sdk/src/codec/decode.ts |
Decodes activity entries. |
ts-sdk/src/codec/activity-v2.ts |
Folds activity stream frames. |
ts-sdk/src/codec/activity-v2.test.ts |
Tests activity codecs. |
ts-sdk/src/client.ts |
Exposes client.activity(). |
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Money entries are keyed by what identifies the row, the transfer id, the bridge tx hash and its idx, or the tick and book of a backstop, so a page boundary inside a same-tick run loses nothing. An order keeps the node's time when seeded and takes the batch only when a frame is first to report it. An empty types filter means no filter on the stream as it does on REST. A failed initial seed retries through the re-seed backoff instead of leaving the resource idle, which also fixes OrderHistory through the shared stream. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
There was never a v1 to version against. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
One decoder serves a money entry on the seed and its event on the stream, since the node now sends both with the same short keys. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
A windowed history drops frames outside its window. A known order is never retimed by a re-seed. The shared stream resets its retry budget when a retried seed subscribes, cancels a pending retry once a seed lands, stops on a 4xx, and both resources seed single-flight and keep their pagination across reconnects. One normaliser serves the memo key and the constructor, unknown seed kinds are skipped like unknown frame events, the sort has a stable tiebreak, and a frame's money events are folded in wire order through a hook on the orders codec. The stream's one-value options are gone. Tests for the two-part cursor path, the REST wire query and each fix. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com>
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.


Client side of the account activity feed (node: pod PR #113, ADR 0057). That PR is merged; the wire shapes here are main's.
client.activity(account, query?)returns anActivityHistory, aSeriesResource<ActivityEntry>with the same lifecycle asOrderHistory: seed fromGET /clob/activity/{account}, subscribepod_activitywith the page's watermark assince, drop frames at or below the cursor, fast-resume on a resumable close, re-seed with backoff,loadOlderby cursor,onEventfor toasts.ActivityEntryis tagged onactivityType:order(the existingOrder, fills included),backstop(the existingBackstopTransferplusrealizedPnl),bridge_transferandtransfer(signedamount, negative left the account). Sorted newest first, the node's ordinal breaks ties.ActivityQuery { types?, from?, to?, limit? }, times in ms; the transport converts to µs and joinsactivity_types.OrderHistoryintosync/stream.ts(ResumableStream) andOrderHistoryuses it with no behaviour change;orders.test.tsis byte-unchanged.orders()itself is untouched: the orders stream is retired later, once everything is on activity.applyOrdersFramereads the entity'sbookwhen present and falls back to the frame's, so one fold serves both channels.pod_activityjoins theChannelunion;SubParamsis unchanged, the cursor is the batch alone.Tests:
codec/activity-v2.test.ts(entry decode, frame fold, unknown kinds ignored) andsync/activity.test.ts(seed, subscribe from the watermark, query passthrough, frame apply and emit, cursor rule, resume then re-seed, type filter,loadOlderdedupe, ordinal tiebreak,onEventref-counting). 210 tests, typecheck and build green.Review fixes. Window applied to live frames; a known order is never retimed by a re-seed (the seed times orders by signed deadline, the stream by inclusion batch, accepted while clients sign a tick or two ahead); the shared stream resets its retry budget on a successful retry, cancels a pending retry once a seed lands, stops on a 4xx, seeds single-flight and keeps pagination across reconnects; one query normaliser for memo key and constructor; unknown seed kinds skipped; stable sort tiebreak; money events folded in wire order through a small hook on the orders codec; the stream's one-value options removed. New tests for the two-part cursor path and the REST wire query. Version 0.11.0.
🤖 Generated with Claude Code