Skip to content

Releases

v0.35.0-devnet-20261108182734

Pre-release

Choose a tag to compare

@github-actions github-actions released this 08 Nov 18:27
b45ad38

Minor Changes

  • Breaking: realtime.isConnected is removed. It was true whenever a socket object existed, even one that never connected. Read realtime.connection instead: { public, private }, each { state, error }, where state is "connecting", "connected" or "disconnected" and error is the first failure of the current outage (a socket failure after a connection token failure replaces it), cleared once the socket connects. realtime.onConnectionChange(listener) calls the listener with the current value after each change, in a microtask, and returns an unsubscribe function. Private order streams run on their own socket and are not included. Custom PolyesterRealtime implementations must add both members. (#232)

    A realtime socket that cannot connect now reports it. On the first failed attempt, every channel on that socket gets one onError with type: "transport" and a retryable RealtimeError, not one per reconnect retry; a channel subscribed while the socket is still failing gets it on subscribe. On the private socket, a failed connection token request is reported as "connection_token" on each attempt instead. The order book (whose snapshot waits for the channel to open) and trades no longer wait silently forever when the socket is unreachable; onOpen follows once it recovers.

    Once a channel's unsubscribe function has run, that consumer gets no further onError or onUnsubscribed, even from a notification already in progress (for example, unsubscribing from inside a terminal close's onError no longer also calls onUnsubscribed). Channels that actually closed are still told, even if a handler calls disconnect() meanwhile.

Patch Changes

  • API-key auth takes an optional recvWindow: a whole number of milliseconds from 1 to 60000, sent as X-API-RECV-WINDOW and signed on the line after the timestamp. The backend processes a request only until its timestamp plus the window, which defaults to 10000 when omitted. A value outside the range throws ConfigurationError before the request is sent. An AUTH_RECV_WINDOW_INVALID refusal maps to a non-retryable ValidationError rather than AuthenticationError, because the credentials are not at fault. (#237)

  • The orders.batchCreate JSDoc now gives the batch's 15-minute idempotency window. It previously said 60 seconds, which is the batchReplace window. Within 15 minutes, a retry with the same requestId and payload returns each decided item's original result and retries the unresolved ones. After that the ID is free, and a repeat can place its orders again. (#235)

  • The orders.getBatchReplaceStatus JSDoc now gives the 60-second status window. The status is readable as soon as batchReplace returns. Retry a ServiceUnavailableError with the same request within the window. A ResourceNotFoundError never means the replacement was rejected: reconcile the individual orders and never resubmit an accepted batch. An item's updatedTsNs can be a later recovery time, so it does not identify a refusal. (#236)

  • Changelog post summaries add revision and updatedAt. A post can now be republished to correct its copy or withdraw a change: revision starts at 1 and increases with each republication, and updatedAt is when the current revision was published. To follow edits, read a post again when its revision changes. listChanges restarts paging at the first change of a post republished during the walk, so deduplicate changes by id. (#236)

  • Checkpoint now carries openingValueUsd, the season-end USD value of the holdings restored when the season opened ("0" when it opened with no balances, undefined when a restored balance had no USD value). With it, seasonResultUsd reconciles as finalValueUsd - openingValueUsd - netInflowUsd. (#235)

  • expandColumnarTimestampsSec and columnarTimestampSecAt now end at endTsSec, so the last columnar history point is no longer one bucket early. (#233)

  • lifecycle.listFlows with an accountSelector now also returns the transfers the account received from other accounts, such as transfers from other users or subaccounts and reward payouts. Each row carries participation: "owner" for a flow the account owns, including a transfer it sent, and "recipient" for a received transfer. Rows are "unspecified" without an account selector and in flow detail and realtime updates. Pass participation: "owner" to keep the previous owner-only list or "recipient" for received transfers only. participation requires accountSelector and throws ValidationError without one. A pageToken now resumes only the request it came from, so change nothing but limit between pages. (#237)

  • A ConnectRPC resource_exhausted that carries a RateLimitDetail, as wallet sign-in and the public catalog calls now send, maps to a RateLimitError with rateLimit set and retryAfterMs taken from the detail. Its detail is { service: "rate_limit", code: "RATE_LIMIT_EXCEEDED", rateLimit }. The gateway's own refusal has no detail: retryAfterMs comes from Retry-After when present and is undefined for a concurrency refusal, so back off without a server hint. (#236)

  • Realtime token requests honor Retry-After. When the connection or subscription token endpoint answers 429 with a Retry-After header, the RateLimitError carries it as retryAfterMs, and the realtime client sends no further token request until it has passed (at most 60 seconds), even when the socket retries sooner. This covers public, private and private order stream sockets. (#232)

  • A signed request refused with AUTH_REPLAY_CAPACITY_EXHAUSTED maps to a retryable RateLimitError without retryAfterMs. Before, a full replay store answered SIGNATURE_INVALID. Now each API key and account holds a fixed share, so only the key or account at its share is refused. Back off briefly and retry, which signs again. A shorter recvWindow frees room sooner. (#237)

  • An order or trigger write refused with REQUEST_DEADLINE_EXCEEDED maps to the new RequestDeadlineExceededError (code "REQUEST_DEADLINE_EXCEEDED", retryable), a subclass of TimestampSkewError. The signed request passed authentication, but its receive window ended before admission. Nothing changed, and this is never an unknown outcome, so retrying, which signs again with a fresh timestamp, is safe. Every signed request now has this deadline, including requests sent without recvWindow, which get the 10-second default. (#237)

  • An HTTP 413 now maps to the new RequestTooLargeError (code "REQUEST_TOO_LARGE", not retryable) instead of a plain RequestError. Every service now refuses an oversized body with the same 413 problem, including ledger reads and API-key authentication of ConnectRPC calls. Send a smaller request; the size limit does not change. A ConnectRPC message over the limit still arrives as resource_exhausted and maps as before. (#236)

  • rewards.listAwards now returns awardsMayChange. It is true while a campaign can still publish awards or one of the account's awards is awaiting a destination, ready for payout, or failed and retryable. When it is false, polling cannot return new awards or award changes until a new campaign is created. (#235)

  • PolyesterErrorCode now includes "SUBACCOUNT_CHALLENGE_INVALID", the code SubaccountChallengeInvalidError already carries, so an exhaustive switch over the union covers it. (#235)

  • Subaccount records now carry removed. subaccounts.subscribe emits removed: true (with role: "unspecified") when the caller loses access to a subaccount, for example after the owner removes them as a member, so drop it from local state. List and get responses always return false. Access and role changes do not bump revision or updatedAt, so apply them in arrival order. (#235)

  • tradeWsPb in @polyester/sdk/unstable/gen adds the cancelAllAfter client command and acknowledgement, which arm, refresh or disarm the account's dead-man switch, plus the ClientFrame fields timestampMs and recvWindowMs, which set a per-command receive window. The SDK has no trading WebSocket client yet. (#237)

  • A wallet login refused with AUTH_WALLET_ALREADY_LINKED maps to a non-retryable AlreadyExistsError. The wallet already belongs to another account, so the same login fails again. Log in with the account address the wallet already uses. (#236)

v0.34.0

Choose a tag to compare

@github-actions github-actions released this 05 Nov 17:59
48d59e0

Minor Changes

  • Breaking: every SDK label, key and filter value now uses the canceled spelling. Trigger status (output and the triggers.list status filter), sub-account invite status and social-verification status change from "cancelled" to "canceled", matching order status and trigger events. The orders.cancelAll result renames cancelledOrders to canceledOrders and totalCancelled to totalCanceled. There are no aliases: update any code that compares against "cancelled" or reads the old keys. (#230)

Patch Changes

  • Order, trade, market trade, balance and candle streams (and their list reads) no longer re-validate protobuf-decoded messages with Valibot before formatting them. Payloads are unchanged; per-message formatting is roughly 1.5-2.5x faster. (#231)

  • ValidationError messages name the field that failed. When an input matches none of the shapes a method accepts, the message now comes from the closest shape and is prefixed with its path, such as items.0.symbolId: Invalid key: Expected "symbolId" but received undefined for orders.batchCreate with symbolId on the request instead of each item. Before, this was the generic Invalid type: Expected Object but received Object. The same applies to an unsupported execution.clientRefPrice on orders.create, and triggers.create now reports sliceIntervalMs cannot exceed durationMs for a TWAP. Messages that already name their field are unchanged. (#228)

v0.34.0-devnet-20261105175510

Pre-release

Choose a tag to compare

@github-actions github-actions released this 05 Nov 17:55
509e5fe

Minor Changes

  • Breaking: every SDK label, key and filter value now uses the canceled spelling. Trigger status (output and the triggers.list status filter), sub-account invite status and social-verification status change from "cancelled" to "canceled", matching order status and trigger events. The orders.cancelAll result renames cancelledOrders to canceledOrders and totalCancelled to totalCanceled. There are no aliases: update any code that compares against "cancelled" or reads the old keys. (#230)

Patch Changes

  • Order, trade, market trade, balance and candle streams (and their list reads) no longer re-validate protobuf-decoded messages with Valibot before formatting them. Payloads are unchanged; per-message formatting is roughly 1.5-2.5x faster. (#231)

  • ValidationError messages name the field that failed. When an input matches none of the shapes a method accepts, the message now comes from the closest shape and is prefixed with its path, such as items.0.symbolId: Invalid key: Expected "symbolId" but received undefined for orders.batchCreate with symbolId on the request instead of each item. Before, this was the generic Invalid type: Expected Object but received Object. The same applies to an unsupported execution.clientRefPrice on orders.create, and triggers.create now reports sliceIntervalMs cannot exceed durationMs for a TWAP. Messages that already name their field are unchanged. (#228)

v0.33.0

Choose a tag to compare

@github-actions github-actions released this 05 Nov 15:39
d396a13

Minor Changes

  • Breaking: the holds list is removed. ledgerReadPb in @polyester/sdk/unstable/gen drops LedgerReadService.ListHolds, ListHoldsRequest, ListHoldsResponse and HoldRow. Read held amounts from each asset's reserved amount in balances.list. (#225)

  • trades.list takes symbolId as a number, like every other symbol filter and like the symbolId on returned trades, orders and triggers. A string, 0, negative or fractional symbolId is rejected. "symbolId is required when afterMatchId is set" now appears only when afterMatchId is set without symbolId. (#226)

Patch Changes

  • API key refusals on ConnectRPC now carry an auth detail.code that names the reason: AUTH_SIGNATURE_INVALID, AUTH_TIMESTAMP_SKEW, AUTH_MISSING_HEADERS, AUTH_KEY_EXPIRED, AUTH_KEY_DISABLED, AUTH_IP_NOT_ALLOWED or AUTH_API_KEY_NOT_ACCEPTED. AUTH_TIMESTAMP_SKEW still maps to the retryable TimestampSkewError, and a retry signs the request again. (#223)

  • Attached take-profit, stop-loss and trailing stop exits never trade with the order they protect. Order cancelReason adds attached_exit_fired: the exit fired while the order still rested, so its unfilled remainder was canceled first. Fills before the cancel stand. Trigger failure reasons add self_trade_prevented, reported only as a "fire_refused" event's fireRefusalReason: self-trade prevention expired the exit's order against another of the account's resting orders, and the trigger stays live and fires again. That event's childSeq names the expired child order. (#224)

  • An order's attachedRisk.trailingStop now carries limitPrice, the most its buy-back pays per unit, set when the order sells and undefined when it buys. Previously it was dropped, so a selling order's trailing stop read back and passed to modifyOrder lost its limit price and was rejected with a bad-price error. (#227)

  • Add autoWithdraw, which manages an account's scheduled auto-withdraw rule: getRule, setRule, disableRule and listRuns. setRule and disableRule need a fresh stepUpToken, and a stale expectedVersion throws RevisionConflictError. (#222)

  • Changelog surfaces add market_data, quickswap and rewards, for output and for listChanges filters. Each post section has a surface, the product area it covers, or "unspecified" when it covers more than one. (#223)

  • Order and trigger cancelReason add market_halted: the exchange halted the market and canceled every open order and trigger of it, attached take-profit and stop-loss included, and released their reserved funds. Fills before the cancel stand, and the market refuses new orders until it trades again. Show it as "market halted", not as a user cancel. (#221)

  • Orders carry their exact execution totals. avgPx is now the exact average execution price, up to 18 decimal places instead of rounded down to 9. cumQuote is the quote amount the fills used before fees, "0" with no fills. feeTotal ({ amount, isRebate, qty }) is the net fee in the order's feeAsset: order history and getDetails include it, open orders leave it out. It covers every fill once feeTotal.qty equals cumQty. (#223)

  • Add changelog, a public reader for the environment's product changelog: listPosts, getPost({ slug }) and listChanges, which filters changes by category, audience, surface and time. The generated protobufs are exported as changelogPb. (#218)

  • fees.getSpotRates rows add reserveFeeRatePercent and postOnlyReserveFeeRatePercent, the rates a new order reserves its quote-asset fee at: the highest rate of any VIP tier on the market, so at least the effective rates. Size buy orders by the reserve rate, not the effective one. breakdown lists the components of the effective rates: the VIP tier rates, an optional marketMultiplier, accountDiscounts ([] when none) and an optional referralDiscount, with effectiveFrom and effectiveTo in Unix milliseconds. nextChangeAt is when a component next starts or ends, or undefined when no change is scheduled. (#225)

  • subaccounts.get accepts includeBalances: true and then returns the sub-account's current balances, in the shape of balances.list. It needs the read-balances action on the sub-account or fails with PermissionDenied. When balances cannot be read right now it fails with the retryable AUTH_TEMPORARILY_UNAVAILABLE. Without includeBalances, get is unchanged and returns no balances. (#224)

  • Trigger events add the "fire_refused" event type: a fire was refused and the trigger stayed live, so it is not terminal. The event's fireRefusalReason says why, using the trigger failure reason labels. listEvents accepts eventType: "fire_refused" as a filter, and trigger failure reasons add account_repairing. (#223)

v0.33.0-devnet-20261104214343

Pre-release

Choose a tag to compare

@github-actions github-actions released this 04 Nov 21:44
8a02873

Minor Changes

  • Breaking: the holds list is removed. ledgerReadPb in @polyester/sdk/unstable/gen drops LedgerReadService.ListHolds, ListHoldsRequest, ListHoldsResponse and HoldRow. Read held amounts from each asset's reserved amount in balances.list. (#225)

  • trades.list takes symbolId as a number, like every other symbol filter and like the symbolId on returned trades, orders and triggers. A string, 0, negative or fractional symbolId is rejected. "symbolId is required when afterMatchId is set" now appears only when afterMatchId is set without symbolId. (#226)

Patch Changes

  • API key refusals on ConnectRPC now carry an auth detail.code that names the reason: AUTH_SIGNATURE_INVALID, AUTH_TIMESTAMP_SKEW, AUTH_MISSING_HEADERS, AUTH_KEY_EXPIRED, AUTH_KEY_DISABLED, AUTH_IP_NOT_ALLOWED or AUTH_API_KEY_NOT_ACCEPTED. AUTH_TIMESTAMP_SKEW still maps to the retryable TimestampSkewError, and a retry signs the request again. (#223)

  • Attached take-profit, stop-loss and trailing stop exits never trade with the order they protect. Order cancelReason adds attached_exit_fired: the exit fired while the order still rested, so its unfilled remainder was canceled first. Fills before the cancel stand. Trigger failure reasons add self_trade_prevented, reported only as a "fire_refused" event's fireRefusalReason: self-trade prevention expired the exit's order against another of the account's resting orders, and the trigger stays live and fires again. That event's childSeq names the expired child order. (#224)

  • An order's attachedRisk.trailingStop now carries limitPrice, the most its buy-back pays per unit, set when the order sells and undefined when it buys. Previously it was dropped, so a selling order's trailing stop read back and passed to modifyOrder lost its limit price and was rejected with a bad-price error. (#227)

  • Add autoWithdraw, which manages an account's scheduled auto-withdraw rule: getRule, setRule, disableRule and listRuns. setRule and disableRule need a fresh stepUpToken, and a stale expectedVersion throws RevisionConflictError. (#222)

  • Changelog surfaces add market_data, quickswap and rewards, for output and for listChanges filters. Each post section has a surface, the product area it covers, or "unspecified" when it covers more than one. (#223)

  • Order and trigger cancelReason add market_halted: the exchange halted the market and canceled every open order and trigger of it, attached take-profit and stop-loss included, and released their reserved funds. Fills before the cancel stand, and the market refuses new orders until it trades again. Show it as "market halted", not as a user cancel. (#221)

  • Orders carry their exact execution totals. avgPx is now the exact average execution price, up to 18 decimal places instead of rounded down to 9. cumQuote is the quote amount the fills used before fees, "0" with no fills. feeTotal ({ amount, isRebate, qty }) is the net fee in the order's feeAsset: order history and getDetails include it, open orders leave it out. It covers every fill once feeTotal.qty equals cumQty. (#223)

  • Add changelog, a public reader for the environment's product changelog: listPosts, getPost({ slug }) and listChanges, which filters changes by category, audience, surface and time. The generated protobufs are exported as changelogPb. (#218)

  • fees.getSpotRates rows add reserveFeeRatePercent and postOnlyReserveFeeRatePercent, the rates a new order reserves its quote-asset fee at: the highest rate of any VIP tier on the market, so at least the effective rates. Size buy orders by the reserve rate, not the effective one. breakdown lists the components of the effective rates: the VIP tier rates, an optional marketMultiplier, accountDiscounts ([] when none) and an optional referralDiscount, with effectiveFrom and effectiveTo in Unix milliseconds. nextChangeAt is when a component next starts or ends, or undefined when no change is scheduled. (#225)

  • subaccounts.get accepts includeBalances: true and then returns the sub-account's current balances, in the shape of balances.list. It needs the read-balances action on the sub-account or fails with PermissionDenied. When balances cannot be read right now it fails with the retryable AUTH_TEMPORARILY_UNAVAILABLE. Without includeBalances, get is unchanged and returns no balances. (#224)

  • Trigger events add the "fire_refused" event type: a fire was refused and the trigger stayed live, so it is not terminal. The event's fireRefusalReason says why, using the trigger failure reason labels. listEvents accepts eventType: "fire_refused" as a filter, and trigger failure reasons add account_repairing. (#223)

v0.32.1

Choose a tag to compare

@github-actions github-actions released this 02 Nov 14:12
36686e5

Patch Changes

  • An order's attached risk.trailingStop takes limitPrice, the most its buy-back pays per unit. A selling order's attached trailing stop buys back, and the API now rejects it without this price, so limitPrice is required when the order sells and must be omitted when it buys; the SDK rejects either mismatch with ValidationError before sending. It must be at least activationPrice when both are set. orders.modify and batch replace pass it through; the API checks it against the order's side. (#216)

v0.32.0

Choose a tag to compare

@aiiven aiiven released this 02 Nov 13:55
5b97d67

Minor Changes

  • Add a timeoutMs request option, passed to Connect as the call deadline, so timed-out requests reject with TimeoutError. It must be a positive integer of at most 2147483647; other values throw ValidationError. AbortSignal.timeout() expiries also map to TimeoutError, whether the signal comes from the caller or an interceptor; previously they rejected as an abort or as a ConnectError with Code.Canceled. A caller signal that already expired before the call started still rejects as a non-retryable abort, so retry loops stop instead of spinning on it. isTimeoutAbortError is exported alongside isAbortError. (#190)

  • Trailing-stop triggers can buy. Pass side: "buy" with a limitPrice, the most the child pays. It must be at least activationPrice when that is set. A sell trailing stop is still the default and rejects limitPrice. Trigger configurations decode limitPrice for a buy trailing stop. (#209)

  • orders.cancelAllAfter returns the armed switch's effectiveScope: { accountId, symbolId, side }, where an unset symbolId or side covers all of them. It is absent while the switch is disabled. (#209)

  • orders.cancelAll returns listingStatus. A retry with the same requestId returns "not_retained_read_open_orders" with an empty cancelledOrders, which does not mean nothing was canceled; read open orders instead. (#209)

  • orders.cancelAll returns cancelledOrders: up to 200 { orderId, clientOrderId } entries, oldest first. It also returns totalCancelled, and truncated when not every canceled order is listed. (#209)

  • Candle timeframes add 3m, 2h, 6h, 8h and 3d. (#209)

  • Checkpoint asset amounts add excludedFromValue. When it is true, the asset is not account equity (for example a testnet faucet token): it is listed by amount only, usd is always absent, and it counts toward no USD total. A missing usd on such an asset is not a pricing gap. A response that gives such an asset a usd value is rejected with ValidationError. (#210)

  • Daily claims add the payout_delayed state and payoutDelayReason, a claims error code name such as CLAIM_PAYOUT_UNAVAILABLE. Claims errors add CLAIM_PAYOUT_UNAVAILABLE. (#209)

  • claims.claimDailyReward takes an input object before the request options, so claimDailyReward({ subaccountId }) pays the daily reward to a subaccount owned by the authenticated root account. Omit subaccountId to pay the root account as before. Breaking: pass request options as the second argument, as in claimDailyReward({}, { signal }); options passed first now throw ValidationError. A subaccountId that decodes to zero also throws ValidationError instead of silently paying the root account. The first claim of the day fixes the destination, and retries return that claim and its destination. DailyClaimStatus and ClaimDailyRewardResult add subaccountId, which is undefined when the reward goes to the root account. Claims errors add SUBACCOUNT_NOT_FOUND and SUBACCOUNT_INACTIVE. (#202)

  • Stop-loss, take-profit and trailing-stop triggers, and the attached takeProfit, stopLoss and trailingStop legs of an order, take triggerPriceSource: "last" | "index". Omitted watches the last traded price as before. "index" watches the market's index price and waits while it is stale. Spot markets do not support "mark", which the SDK rejects with ValidationError. Attached legs decode their triggerPriceSource. (#209)

  • Lifecycle flows add isDelayed on summaries, milestoneTxChainId on steps and txChainId on step activities. The lifecycle reason adds deposit_source_not_confirmed and the lifecycle source adds lifecycle. (#209)

  • Buy stop-loss and take-profit triggers accept a market_ioc child. A market_ioc child takes an optional maxSlippage: 1 to 10000 bps for a buy, 1 to 9999 for a sell. Without it, the pair's default market slippage applies. Trigger configurations decode the child's maxSlippage. (#209)

  • OrderErrorCode adds MAX_OPEN_ORDERS_PER_PAIR, and trigger failure reasons add max_open_orders_per_pair. Order error details add existingOrderId: on a CONFLICT_DUPLICATE_CLIENT_ORDER_ID rejection, it is the ID of the order that already holds the client order ID, when that order is known. Batch create rejections carry it too. (#210)

  • Breaking: triggers.modify no longer takes limitPrice, because the backend rejects any change to a child's limit price. Cancel the trigger and create a new one instead. (#209)

  • OrderErrorCode gains the new order validation, capacity, auction, trigger, TWAP, ladder, batch, and Quick Swap codes. Breaking: TRIGGER_CANCEL_REJECTED is removed; a refused trigger cancel now returns TRIGGER_STATUS_INVALID or TRIGGER_NOT_MODIFIABLE. (#209)

  • orders.getDetails returns executionsComplete. It is true once the trades across every page add up to the filled quantity; while it is false, read again for the rest. (#209)

  • Breaking: order reads drop terminalReason and terminalReasonCode. A rejected order carries rejectReason, the OrderErrorCode the Orders API returns for the same refusal, such as "TWAP_CAPACITY_REACHED". A canceled order carries cancelReason, such as "user_request", "ioc_remainder", "stp_expire_maker", "replaced", "gtd_expired", "pair_drain" (market disabled), "cancel_all_after" or "twap_rollover". Both are omitted for every other status. A code newer than this build reads as "UNSPECIFIED" or "unspecified": treat it as a generic refusal or cancel. On orders.subscribe, order updates drop reasonCode: read rejectReason for a rejected order and cancelReason for a canceled order or for the replaced update of the order a replace ended. OrderErrorCode adds ATTACHED_LEGS_EXCEEDED, FEE_ASSET_INVALID, FEE_CEILING_INVALID, UNSUPPORTED_FIELD_SET, TRIGGER_FIRE_LIMIT_REACHED, CONDITION_FLAGS_INVALID, CONDITION_PARAMETER_SET, TWAP_CAPACITY_REACHED and CHILD_ORDER_INCONSISTENT. (#212)

  • orders.subscribe's onStale receives orderIds when only those orders are behind. Their rows show an earlier state while the rest of the view is current. A later call replaces the earlier one, and onStale(false) means every order is current again. (#209)

  • Breaking: every order and trigger outcome-unknown code (ORDER_CREATE_OUTCOME_UNKNOWN, ORDER_CANCEL_OUTCOME_UNKNOWN, ORDER_MODIFY_OUTCOME_UNKNOWN, TRIGGER_CREATE_OUTCOME_UNKNOWN and TRIGGER_CONTROL_OUTCOME_UNKNOWN) now throws the new non-retryable OutcomeUnknownError instead of a retryable TimeoutError. The change may already have applied, so read the order by its client order ID, or list triggers by client trigger ID, before sending it again. detail.code names the operation. A deadline without one of these details is still a retryable TimeoutError. (#209)

  • Pair status adds halted: only cancellations are accepted. (#209)

  • Stream orders.subscribe over the private WebSocket (/v1/ws/private), since the realtime channels private:spot:orders:<account> (JSON and :proto) and private:spot:orders:batch-replace:<account> are no longer served. onEvent still receives each changed order complete; keep the copy with the higher version. A new order now arrives with version 0 while it is still pending. Orders on symbols missing from the catalog are skipped, as order reads already do, instead of reaching onError. New optional callbacks: onSnapshot receives the account's full live view when the subscription starts and after a server resync, and it takes over snapshot orders from onEvent. onRemoved receives IDs of orders that left the live view, including, without onSnapshot, orders missing from a resync snapshot. onStale reports when that view is temporarily behind. Subscriptions to the same account share one server subscription, and one that joins later starts from the current live view; a connection carries up to 64 accounts. The stream resumes from its last cursor after a sequence gap, an expired token, a dropped heartbeat, or a reconnect, reporting each interruption through onClose and onOpen rather than onError; token fetch failures along the way still reach onError. Reconnects back off from 0.5 to 10 seconds with jitter; close codes 4400 and 4403 end the stream instead. (#203)

    Breaking: orders.subscribe throws ValidationError unless accountId is the account's base58 public ID. Custom PolyesterRealtime implementations passed as realtimeClient must add connectPrivateOrders.
    -...

Read more

v0.31.0

Choose a tag to compare

@github-actions github-actions released this 10 Oct 23:17
5501656

Minor Changes

  • Realtime onError contexts now always carry an Error. Server and websocket failures arrive as the new RealtimeError (code REALTIME_ERROR) with the Centrifugo code on realtimeCode, instead of plain { code, message } objects. retryable is true for errors the realtime client is already retrying on its own, such as code 109 (token expired), so callers can skip reporting them. Snapshot failures keep their original typed SDK error. (#193)

    Browser clients end the session and emit loggedOut when an authenticated RPC is rejected as unauthenticated with the current token, for example when the backend revoked it or the device clock lags. Rejections of a token that has since been replaced, and those arriving while a login or refresh is in flight, are ignored. AccountSignerAuthService.handleRejectedToken exposes the same check.

    PreparedTradingWithdraw exposes the signed deadline and isExpired(), which turns true a minute before the deadline. Prepare again before resubmitting an expired withdraw, for example after a slow MFA enrollment.

v0.30.2

Choose a tag to compare

@github-actions github-actions released this 07 Oct 04:02
fbf3829

Patch Changes

  • patchZipperCatalogSupply caches the snapshot it returns as already validated, so passing it to catalog.setSnapshot no longer re-validates the whole catalog on every supply update. (#191)

v0.30.1

Choose a tag to compare

@github-actions github-actions released this 02 Oct 12:51
a5bc14a

Patch Changes

  • Add rewards.listAwards (also rewardsService(core) from @polyester/sdk/services/rewards) to list published reward campaign awards for the authenticated root account, newest first. Each award includes its campaign, asset, exact amountBaseUnits, fulfillmentMethod, fulfillmentState, publishedAt, payout network, fulfillmentRevision, destinationAddress, and transactionId. limit accepts 0 through 100 (0 or omitted uses 50), and pageToken is capped at 256 characters. Requires a session token; API keys are not accepted. (#187)

  • Add rewards.setDestination to record a write-once payout destination for an award owned by the authenticated root account. Pass the award's fulfillmentRevision as expectedRevision (a positive decimal string) and a client-generated requestId (1 through 128 characters, reused on retry); awardId accepts 1 through 128 characters and destinationAddress 1 through 512. Requires a session token and a fresh step-up proof via stepUpToken; it does not execute a transfer or mark the award delivered. (#189)