Skip to content

fix(keychain): surface real broadcast errors and retry via a known-good node - #823

Merged
feruzm merged 7 commits into
developfrom
bugfix/keychain-broadcast-error-and-fallback
May 23, 2026
Merged

fix(keychain): surface real broadcast errors and retry via a known-good node#823
feruzm merged 7 commits into
developfrom
bugfix/keychain-broadcast-error-and-fallback

Conversation

@feruzm

@feruzmferuzm commented May 22, 2026

Copy link
Copy Markdown
Member

Problem

Promoting a post (or any active-authority op) signed with a browser extension could fail in the console with:

Uncaught (in promise) Error: Extension broadcast failed

Two layered issues:

  1. The real reason was discarded. When Keychain/Hive Keeper/Peak Vault returned success: false, broadcastViaKeychain threw a hardcoded "Extension broadcast failed" and ignored the extension's actual message/error (node error, missing key, RC, or a plain user-cancel). The TxResponse type only declared { success, result }, so those fields weren't even visible.
  2. It defeated the SDK auth-upgrade fallback. The SDK decides whether to prompt for active authority by string-matching the error message (parseChainError/missing active authority/i). A generic string matches nothing, so a recoverable auth failure hard-failed instead of showing the upgrade dialog.
  3. It surfaced as an unhandled rejection. The Promote modal awaited mutateAsync with no try/catch.

Fix

  • Extend TxResponse with the optional message/error fields the extensions actually return.
  • Add a shared extensionErrorMessage() helper and surface the real reason in the unified hive-extensions layer and the legacy keychain.ts call sites.
  • broadcastViaKeychain now retries a failed broadcast once through the first (preferred) node in the curated public-nodes.json, so a flaky/outaged default node (e.g. the common api.hive.blog default during maintenance) no longer hard-blocks the user. Preserves the user's own Keychain node on the first attempt; the retry is gated by isUserCancellation() so a cancel never re-opens the popup, and only runs when the caller didn't pin a node.
  • Promote modal: catch the rejection (no more Uncaught (in promise)) and show the reason inline.
  • Unit tests for extensionErrorMessage / isUserCancellation.

Tradeoff to note

The fallback re-calls requestBroadcast, which re-opens the extension confirmation popup. So in the (rare) genuine node-failure case the user approves a second time. Cancels and the happy path are unaffected. Full node hangs still surface as the existing timeout without a retry.

Summary by CodeRabbit

  • New Features

    • Clearer error messages for keychain/broadcast failures and retry via a known-good node when appropriate.
    • Centralized post-transaction cache refreshes for more consistent UI updates.
    • Broadcasts now default to returning after mempool acceptance (faster feedback).
  • Bug Fixes

    • Prevented unhandled promise rejections in promote/transaction flows.
    • Improved detection and handling of user-cancelled operations.
  • Tests

    • Added tests for error-message parsing, cancellation detection, and retryable node errors.

Review Change Stack

…od node
Extension broadcast failures threw a hardcoded "Extension broadcast failed",
discarding the extension's actual message/error. That hid the real cause and,
because the SDK classifies auth errors by string-matching the message, defeated
the auth-upgrade fallback (a generic string never matches "missing active
authority").
- Extend TxResponse with the optional message/error fields the extensions
actually return.
- Surface them via a shared extensionErrorMessage() helper, used by the unified
hive-extensions layer and the legacy keychain.ts call sites.
- broadcastViaKeychain retries a failed broadcast once through the first node in
the curated public-nodes.json, so a flaky/outaged default node (e.g. the
common api.hive.blog default during maintenance) no longer hard-blocks the
user. Gated via isUserCancellation() so a user-cancel never re-opens the
popup, and only when the caller didn't pin a node.
- Promote modal: catch the mutateAsync rejection so a failed/declined sign no
longer surfaces as an "Uncaught (in promise)", and show the reason inline.
- Add unit tests for extensionErrorMessage / isUserCancellation.

@chatgpt-codex-connectorchatgpt-codex-connectorBot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

💡 Codex Review

Here are some automated review suggestions for this pull request.

Reviewed commit:6378c87687

ℹ️ About Codex in GitHub

Your team has set up Codex to review pull requests in this repo. Reviews are triggered when you

  • Open a pull request for review
  • Mark a draft as ready
  • Comment "@codex review".

If Codex has suggestions, it will comment; otherwise it will react with 👍.

Codex can also answer questions or update the PR. Try commenting "@codex address that feedback".

Comment on lines +377 to +378
if (fallbackNode && !isUserCancellation(response)) {
return attempt(fallbackNode).then((retry) => {

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

P2 Badge Retry fallback only for node/transport failures

The retry path is currently triggered for every non-cancellation broadcast failure, so deterministic chain errors (for example, missing required active authority or RC/validation failures) will re-open the extension approval popup and run the same transaction again even though changing RPC nodes cannot fix it. This can also hide the original actionable error if the user cancels the second prompt. Gate this retry to node/transport outage signatures and otherwise throw the first failure immediately.

Useful? React with 👍 / 👎.

@coderabbitai

coderabbitaiBot commented May 22, 2026

Copy link
Copy Markdown
Contributor

Caution

Review failed

The pull request is closed.

ℹ️ Recent review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: c7452d35-5553-40de-98e6-72bf4e0cd716

📥 Commits

Reviewing files that changed from the base of the PR and between 9ff003a and 37e3f31.

⛔ Files ignored due to path filters (13)
  • packages/sdk/dist/browser/hive.js is excluded by !**/dist/**
  • packages/sdk/dist/browser/hive.js.map is excluded by !**/dist/**, !**/*.map
  • packages/sdk/dist/browser/index.d.ts is excluded by !**/dist/**
  • packages/sdk/dist/browser/index.js is excluded by !**/dist/**
  • packages/sdk/dist/browser/index.js.map is excluded by !**/dist/**, !**/*.map
  • packages/sdk/dist/node/hive.cjs is excluded by !**/dist/**
  • packages/sdk/dist/node/hive.cjs.map is excluded by !**/dist/**, !**/*.map
  • packages/sdk/dist/node/hive.mjs is excluded by !**/dist/**
  • packages/sdk/dist/node/hive.mjs.map is excluded by !**/dist/**, !**/*.map
  • packages/sdk/dist/node/index.cjs is excluded by !**/dist/**
  • packages/sdk/dist/node/index.cjs.map is excluded by !**/dist/**, !**/*.map
  • packages/sdk/dist/node/index.mjs is excluded by !**/dist/**
  • packages/sdk/dist/node/index.mjs.map is excluded by !**/dist/**, !**/*.map
📒 Files selected for processing (19)
  • apps/web/src/specs/utils/extension-error.spec.ts
  • apps/web/src/utils/extension-error.ts
  • packages/sdk/CHANGELOG.md
  • packages/sdk/package.json
  • packages/sdk/src/hive-tx/helpers/ByteBuffer.ts
  • packages/sdk/src/hive-tx/helpers/serializer.ts
  • packages/sdk/src/modules/accounts/utils/account-power.spec.ts
  • packages/sdk/src/modules/accounts/utils/parse-accounts.spec.ts
  • packages/sdk/src/modules/accounts/utils/profile-metadata.spec.ts
  • packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts
  • packages/sdk/src/modules/core/utils/parse-asset.spec.ts
  • packages/sdk/src/modules/posts/queries/get-account-posts-query-options.spec.ts
  • packages/sdk/src/modules/posts/queries/get-post-query-options.spec.ts
  • packages/sdk/src/modules/posts/queries/get-posts-ranked-query-options.spec.ts
  • packages/sdk/src/modules/posts/utils/filter-dmca-entries.spec.ts
  • packages/sdk/src/modules/posts/utils/filter-dmca-entries.ts
  • packages/sdk/src/modules/posts/utils/waves-helpers.spec.ts
  • packages/wallets/CHANGELOG.md
  • packages/wallets/package.json

📝 Walkthrough

Walkthrough

This PR adds normalized extension error utilities and tests, applies them across Keychain helpers and Hive extension broadcasts (including a one-shot fallback RPC retry), surfaces mutation errors in Promote, introduces invalidateAfterBroadcast, and switches many SDK mutation post-broadcast invalidations to use it while changing broadcastMode default to 'async'.

Changes

Keychain error handling and RPC failover

Layer / File(s)Summary
Types and error utilities
apps/web/src/types/keychain-impl.ts, apps/web/src/utils/extension-error.ts, apps/web/src/specs/utils/extension-error.spec.ts
Add message?: string and error?: unknown to TxResponse; implement extensionErrorMessage, isUserCancellation, and isRetryableNodeError; include Jest tests covering behaviors.
Keychain methods with standardized error messages
apps/web/src/utils/keychain.ts
Replace hardcoded "Operation cancelled" rejections in multiple Keychain helpers with extensionErrorMessage(resp, "Operation cancelled").
Hive extensions broadcast with RPC failover
apps/web/src/utils/hive-extensions.ts
Rewrite broadcast to promise-based attempt(node) with timeout; on non-cancellation and when rpc was not pinned, retry once via curated fallback RPC if classified retryable; final failures reject with extensionErrorMessage(...).
Promote component error state and display
apps/web/src/features/shared/promote/index.tsx
Destructure promoteError/resetPromote from mutation, reset prior error before submit, wrap submit in try/catch, and conditionally render promoteError.message when present and postError is absent.
Invalidate-after-broadcast and broadcast defaults
packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts, packages/sdk/src/modules/core/mutations/use-broadcast-mutation.ts, packages/sdk/src/modules/core/mutations/index.ts
Add invalidateAfterBroadcast (with BROADCAST_INCLUSION_DELAY_MS) and re-export it; mark 'sync' deprecated and change default broadcastMode to 'async' in useBroadcastMutation internals/docs.
SDK mutations: centralized post-broadcast invalidation
packages/sdk/src/modules/... (many account/wallet mutation files)
Update numerous mutation modules to call invalidateAfterBroadcast(auth?.adapter, broadcastMode, keys) instead of conditionally calling auth.adapter.invalidateQueries, preserving invalidation targets while centralizing timing/behavior.

Sequence Diagram(s)

sequenceDiagram
participant Client
participant HiveExtensions
participant KeychainRPC
participant FallbackRPC
Client->>HiveExtensions: broadcast(tx, rpc?)
HiveExtensions->>KeychainRPC: attempt broadcast on primary
alt success
KeychainRPC-->>Client: return result
else failure and rpc == null and not user-cancel and isRetryableNodeError
HiveExtensions->>FallbackRPC: retry on fallback RPC
alt success
FallbackRPC-->>Client: return result
else failure
HiveExtensions-->>Client: reject(extensionErrorMessage)
end
else user cancellation or rpc pinned
HiveExtensions-->>Client: reject(extensionErrorMessage)
end
Loading

Estimated code review effort

🎯 4 (Complex) | ⏱️ ~45 minutes

Possibly related PRs

Poem

🐰 Errors untangled, gentle and bright,

When broadcasts wobble, we try once more,
Messages clearer than cryptic lore,
Promote now tells what went wrong in sight,
A hopping cheer for stable flight!

🚥 Pre-merge checks | ✅ 4 | ❌ 1

❌ Failed checks (1 warning)

Check nameStatusExplanationResolution
Docstring Coverage⚠️ WarningDocstring coverage is 45.24% which is insufficient. The required threshold is 80.00%.Write docstrings for the functions missing them to satisfy the coverage threshold.
✅ Passed checks (4 passed)
Check nameStatusExplanation
Description Check✅ PassedCheck skipped - CodeRabbit’s high-level summary is enabled.
Title check✅ PassedThe title accurately captures the main fix: improving Keychain broadcast error handling and adding fallback retry logic via a known-good RPC node.
Linked Issues check✅ PassedCheck skipped because no linked issues were found for this pull request.
Out of Scope Changes check✅ PassedCheck skipped because no linked issues were found for this pull request.

✏️ Tip: You can configure your own custom pre-merge checks in the settings.

✨ Finishing Touches
📝 Generate docstrings
  • Create stacked PR
  • Commit on current branch
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch bugfix/keychain-broadcast-error-and-fallback

Thanks for using CodeRabbit! It's free for OSS, and your support helps us grow. If you like it, consider giving us a shout-out.

❤️ Share

Comment @coderabbitai help to get the list of available commands and usage tips.

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

Actionable comments posted: 1

🧹 Nitpick comments (1)
apps/web/src/specs/utils/extension-error.spec.ts (1)

39-45: ⚡ Quick win

Add an object-shaped cancellation case to the positive matrix.

Please add a case like { error: { message: "user_cancel" } } so cancellation detection won’t regress for non-string extension payloads.

Suggested test addition
 it.each([
[{ error: "user_cancel" }],
+ [{ error: { message: "user_cancel" } }],
[{ message: "Request was canceled by the user." }],
[{ message: "User declined the transaction" }],
])("treats %o as a cancellation", (resp) => {
expect(isUserCancellation(resp)).toBe(true);
});
🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@apps/web/src/specs/utils/extension-error.spec.ts` around lines 39 - 45, Add
an extra positive test case to the existing it.each matrix in
extension-error.spec.ts to cover object-shaped payloads so isUserCancellation
continues to detect cancellations for non-string extension payloads;
specifically, add a case like { error: { message: "user_cancel" } } to the array
passed to it.each so the test invoking isUserCancellation(resp) expects true for
that shape as well.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@apps/web/src/utils/extension-error.ts`:
- Around line 47-53: isUserCancellation currently only checks resp.error when
it's a string, so object-shaped errors (e.g., { message: "user_cancel" } or
other serialized payloads) are missed; update isUserCancellation to derive a
normalized string from resp.error even when it's an object by checking
resp.error.message, resp.error.type, or JSON.stringify(resp.error) and
lowercasing that value (e.g., compute errVal from typeof resp.error === "string"
? resp.error : resp.error?.message ?? resp.error?.type ??
JSON.stringify(resp.error) ?? ""), then use errVal alongside resp.message to
detect "cancel"/"user_cancel"/"declined" occurrences; keep the existing boolean
checks but replace use of resp.error with the normalized errVal to ensure
object-shaped cancellation errors are recognized.
---
Nitpick comments:
In `@apps/web/src/specs/utils/extension-error.spec.ts`:
- Around line 39-45: Add an extra positive test case to the existing it.each
matrix in extension-error.spec.ts to cover object-shaped payloads so
isUserCancellation continues to detect cancellations for non-string extension
payloads; specifically, add a case like { error: { message: "user_cancel" } } to
the array passed to it.each so the test invoking isUserCancellation(resp)
expects true for that shape as well.
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: bf43cf7a-b797-4c9a-b494-886ca5e34091

📥 Commits

Reviewing files that changed from the base of the PR and between 27a924a and 6378c87.

📒 Files selected for processing (6)
  • apps/web/src/features/shared/promote/index.tsx
  • apps/web/src/specs/utils/extension-error.spec.ts
  • apps/web/src/types/keychain-impl.ts
  • apps/web/src/utils/extension-error.ts
  • apps/web/src/utils/hive-extensions.ts
  • apps/web/src/utils/keychain.ts

Comment threadapps/web/src/utils/extension-error.ts Outdated
@greptile-apps

greptile-appsBot commented May 22, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes two layered issues in extension-based broadcast flows: the real extension error was previously discarded in favour of a hardcoded string, which also blocked the SDK's missing active authority auth-upgrade detection; and the Promote modal's mutateAsync lacked a try/catch, producing unhandled rejections. The fix surfaces real extension errors through a shared extensionErrorMessage helper, adds a targeted retry through a curated fallback node for genuine node/transport failures, and catches rejections in the modal.

  • extension-error.ts: new extensionErrorMessage, isUserCancellation, and isRetryableNodeError helpers with full unit-test coverage; isRetryableNodeError uses an explicit allowlist of connectivity patterns so deterministic chain errors (RC, missing authority, already-broadcasted) don't trigger a retry.
  • hive-extensions.ts / keychain.ts: all hardcoded "Extension broadcast failed" / "Operation cancelled" strings replaced with extensionErrorMessage(resp, <fallback>); retry in broadcastViaKeychain is gated on both !isUserCancellation and isRetryableNodeError.
  • SDK: default broadcastMode flipped from 'sync' to 'async'; new invalidateAfterBroadcast helper centralises query-invalidation timing (immediate for sync, ~4 s delay for async to avoid refetching pre-tx state).

Confidence Score: 5/5

Safe to merge. Error surfacing is additive, the retry is gated by two independent guards, and the promote modal now catches rejections instead of propagating them unhandled.

All issues from previous review threads appear addressed: isRetryableNodeError prevents retrying on RC/authority failures, the first-attempt error is re-thrown on resolved-failure retries, resetPromote() clears stale errors before each submission, and object-shaped cancellation codes are handled through normalizeErrorText. The two remaining suggestions are minor defensive hardening, not present defects on the happy or common-failure paths.

apps/web/src/utils/hive-extensions.ts — the retry rejection path (fallback node timeout) still propagates the fallback node's error instead of the first attempt's. packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts — the fire-and-forget setTimeout could silently swallow an invalidateQueries exception.

Important Files Changed

FilenameOverview
apps/web/src/utils/extension-error.tsNew utility: extensionErrorMessage, isUserCancellation, isRetryableNodeError. Object-shaped errors handled via normalizeErrorText; retryable list is conservative (allowlist of transport signals, excludes 500/deterministic errors).
apps/web/src/utils/hive-extensions.tsbroadcastViaKeychain refactored to retry once via a fallback node, gated by isRetryableNodeError; first-attempt error surfaced on resolved-failure retries; rejected retry (timeout on fallback) still propagates the fallback error.
apps/web/src/features/shared/promote/index.tsxhandleSubmit wraps preCheck+promote in try/catch; resetPromote() clears stale error before each attempt; promoteError rendered inline with postError guard.
packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.tsNew helper centralises post-broadcast cache invalidation: sync mode awaits immediately, async mode defers via setTimeout(4 s). The async path returns void so callers awaiting it proceed immediately while invalidation fires later.
packages/sdk/src/modules/core/mutations/use-broadcast-mutation.tsDefault broadcastMode flipped from 'sync' to 'async'. All callers without an explicit broadcastMode now get mempool-acceptance semantics instead of block-inclusion.
apps/web/src/specs/utils/extension-error.spec.tsGood coverage: extensionErrorMessage fallback/dedup, isUserCancellation for string and object-shaped errors (EIP-1193 code 4001), isRetryableNodeError allowlist vs. deterministic/cancel failures.
apps/web/src/utils/keychain.tsAll hardcoded 'Operation cancelled' fallback strings replaced with extensionErrorMessage uniformly across 9 call sites.
apps/web/src/types/keychain-impl.tsTxResponse extended with optional message?: string and error?: unknown fields matching what Keychain-compatible extensions actually return.

Sequence Diagram

sequenceDiagram
participant UI as Promote Modal
participant EXT as Browser Extension
participant NODE1 as User Keychain Node
participant NODE2 as Fallback Node
UI->>EXT: "requestBroadcast(ops, rpc=null)"
EXT->>NODE1: broadcast_transaction
alt Node outage / transport failure
NODE1-->>EXT: 502 / ECONNREFUSED
EXT-->>UI: "success=false, message=status code 502"
Note over UI: isRetryableNodeError=true AND not cancel
UI->>EXT: "requestBroadcast(ops, rpc=fallbackNode)"
EXT->>NODE2: broadcast_transaction
NODE2-->>EXT: ok
EXT-->>UI: "success=true"
UI->>UI: setStep(2)
else User cancels
EXT-->>UI: "success=false, error=user_cancel"
Note over UI: isUserCancellation=true — no retry
UI->>UI: promoteError shown inline
else Deterministic chain error
NODE1-->>EXT: missing required active authority
EXT-->>UI: "success=false, message=missing required active authority"
Note over UI: isRetryableNodeError=false — no retry
UI->>UI: SDK auth-upgrade flow triggers
end
Loading

Fix All in Claude Code

Reviews (5): Last reviewed commit: "chore: apply changeset versioning for PR..." | Re-trigger Greptile

Comment threadapps/web/src/utils/hive-extensions.ts
Comment threadapps/web/src/utils/hive-extensions.ts
Comment threadapps/web/src/features/shared/promote/index.tsx Outdated
Comment threadapps/web/src/utils/extension-error.ts
feruzm added 3 commits May 22, 2026 20:18
…iew)
Addresses PR review feedback:
- Only retry the broadcast through the fallback node on node/transport failures
(new isRetryableNodeError) — not on deterministic chain errors (missing
authority, RC, already-broadcast), which fail identically on any node and
would needlessly re-open the extension popup.
- On a failed retry, surface the FIRST attempt's error (more semantically
relevant — e.g. lets the SDK detect missing-authority) instead of the
fallback node's error.
- isUserCancellation now handles object-shaped errors (e.g. { code: 4001,
message: "User rejected request" }) and "reject"/"declined" wording.
- Promote modal: reset the mutation error before each attempt and don't render a
stale promote error alongside a live preCheck error.
- Extend tests for object cancellations and isRetryableNodeError.
Switch the default BroadcastMode from 'sync' to 'async' so the SDK uses
broadcast_transaction instead of the deprecated broadcast_transaction_synchronous.
Transport/RPC errors are still thrown immediately; only the block-inclusion wait
is dropped. 'sync' remains available as an explicit opt-in and broadcastOperations
is marked @deprecated. No callers currently pass an explicit broadcastMode, and
block_num consumers already use optional chaining.
The sync→async default flip introduced a stale-read window: hooks invalidated
chain-derived queries (balances, account, follow state) synchronously in
onSuccess, but async broadcast resolves at mempool acceptance — before the tx is
in a block — so the refetch returned pre-transaction state.
- Add invalidateAfterBroadcast(adapter, mode, keys): refetch immediately for
'sync', defer ~1 block (4s) for 'async'/default.
- Route all 28 balance/chain-state mutation hooks through it. This also fixes the
3 hooks whose existing async-delay branched on the hook's local broadcastMode
(undefined when omitted), bypassing the delay while the broadcast ran async.
- Fix use-claim-account invalidation key: ["accounts", creator] matched no query
(account-full is keyed get-account-full); use QueryKeys.accounts.full(creator).

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

Actionable comments posted: 1

🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
Inline comments:
In `@packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts`:
- Around line 22-26: The exported function invalidateAfterBroadcast currently
types the keys parameter as any[][]; change this to a non-any shape such as
unknown[][] (or Array<Array<unknown>>) so the public API is strictly typed while
remaining compatible with PlatformAdapter.invalidateQueries; update the function
signature in invalidateAfterBroadcast(..., keys: unknown[][]) and ensure any
other references/overloads use the same unknown[][] type before forwarding keys
to adapter.invalidateQueries(keys).
🪄 Autofix (Beta)

Fix all unresolved CodeRabbit comments on this PR:

  • Push a commit to this branch (recommended)
  • Create a new PR with the fixes

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro

Run ID: 0279ba46-a14e-4247-b735-45b16097b23c

📥 Commits

Reviewing files that changed from the base of the PR and between 6378c87 and 9ff003a.

📒 Files selected for processing (36)
  • apps/web/src/features/shared/promote/index.tsx
  • apps/web/src/specs/utils/extension-error.spec.ts
  • apps/web/src/utils/extension-error.ts
  • apps/web/src/utils/hive-extensions.ts
  • packages/sdk/src/modules/accounts/mutations/use-account-update.ts
  • packages/sdk/src/modules/accounts/mutations/use-claim-account.ts
  • packages/sdk/src/modules/accounts/mutations/use-create-account.ts
  • packages/sdk/src/modules/accounts/mutations/use-follow.ts
  • packages/sdk/src/modules/accounts/mutations/use-grant-posting-permission.ts
  • packages/sdk/src/modules/accounts/mutations/use-unfollow.ts
  • packages/sdk/src/modules/core/hive-tx.ts
  • packages/sdk/src/modules/core/mutations/index.ts
  • packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts
  • packages/sdk/src/modules/core/mutations/use-broadcast-mutation.ts
  • packages/sdk/src/modules/wallet/mutations/use-claim-engine-rewards.ts
  • packages/sdk/src/modules/wallet/mutations/use-claim-interest.ts
  • packages/sdk/src/modules/wallet/mutations/use-convert.ts
  • packages/sdk/src/modules/wallet/mutations/use-delegate-engine-token.ts
  • packages/sdk/src/modules/wallet/mutations/use-delegate-rc.ts
  • packages/sdk/src/modules/wallet/mutations/use-delegate-vesting-shares.ts
  • packages/sdk/src/modules/wallet/mutations/use-engine-market-order.ts
  • packages/sdk/src/modules/wallet/mutations/use-lock-larynx.ts
  • packages/sdk/src/modules/wallet/mutations/use-power-larynx.ts
  • packages/sdk/src/modules/wallet/mutations/use-set-withdraw-vesting-route.ts
  • packages/sdk/src/modules/wallet/mutations/use-stake-engine-token.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-engine-token.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-from-savings.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-larynx.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-point.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-spk.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-to-savings.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer-to-vesting.ts
  • packages/sdk/src/modules/wallet/mutations/use-transfer.ts
  • packages/sdk/src/modules/wallet/mutations/use-undelegate-engine-token.ts
  • packages/sdk/src/modules/wallet/mutations/use-unstake-engine-token.ts
  • packages/sdk/src/modules/wallet/mutations/use-withdraw-vesting.ts
✅ Files skipped from review due to trivial changes (1)
  • packages/sdk/src/modules/core/hive-tx.ts

Comment on lines +22 to +26
export function invalidateAfterBroadcast(
adapter: PlatformAdapter | null | undefined,
broadcastMode: BroadcastMode | undefined,
keys: any[][]
): void | Promise<void> {

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.

⚠️ Potential issue | 🟠 Major | ⚡ Quick win

🧩 Analysis chain

🏁 Script executed:

#!/bin/bashset -euo pipefail
# Locate PlatformAdapter.invalidateQueries signature
rg -n --type=ts -C3 'interface\s+PlatformAdapter|type\s+PlatformAdapter|invalidateQueries\s*\('# Locate invalidateAfterBroadcast signature/usages
rg -n --type=ts -C2 '\binvalidateAfterBroadcast\s*\('
rg -n --type=ts -C2 '\bkeys:\s*any\[\]\[\]'

Repository: ecency/vision-next

Length of output: 50377


🏁 Script executed:

#!/bin/bashset -euo pipefail
# 1) Show the current signature in the reviewed file
sed -n '1,120p' packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts | nl -ba | sed -n '1,120p'# 2) Show the relevant lines around keys type (if file is larger, this still should include it)
rg -n --no-heading 'export function invalidateAfterBroadcast|keys:' packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts -n -S
# 3) Print PlatformAdapter.invalidateQueries signature from source
rg -n --no-heading 'invalidateQueries\s*\(' packages/sdk/src/modules/core/types/platform-adapter.ts -n -S
sed -n '1,120p' packages/sdk/src/modules/core/types/platform-adapter.ts | nl -ba | sed -n '1,140p'# 4) Find call sites of invalidateAfterBroadcast and inspect how keys are passed
rg -n --no-heading '\binvalidateAfterBroadcast\s*\(' packages/sdk/src -S
# 5) Find any usage that passes any[][]-shaped values (fallback: locate "keys" variable near calls)
rg -n --no-heading -C3 '\binvalidateAfterBroadcast\s*\(' packages/sdk/src | head -n 200

Repository: ecency/vision-next

Length of output: 105


🏁 Script executed:

#!/bin/bashset -euo pipefail
FILE="packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts"# 1) Print the exact function signature block (around the export) with line numbers via awk
awk 'NR>=1 && NR<=120 {print NR ":" $0}'"$FILE"| rg -n 'invalidateAfterBroadcast|keys:' -n -S ||true# Also print a wider window around where the signature is
SIG_LINE=$(rg -n --no-heading 'export function invalidateAfterBroadcast'"$FILE"| cut -d: -f1 | head -n1 || true)if [[ -n"${SIG_LINE:-}" ]];then
START=$((SIG_LINE-10)); END=$((SIG_LINE+20))
awk -v s="$START" -v e="$END"'NR>=s && NR<=e {print NR ":" $0}'"$FILE"fi# 2) Print the invalidateQueries type from PlatformAdapter
PA="packages/sdk/src/modules/core/types/platform-adapter.ts"
rg -n --no-heading 'invalidateQueries\s*\('"$PA" -S
awk 'NR>=1 && NR<=120 {print NR ":" $0}'"$PA"| rg -n 'interface PlatformAdapter|invalidateQueries|queryKey' -n -S ||true# 3) Locate call sites of invalidateAfterBroadcast (inspect how keys are passed)
rg -n --no-heading '\binvalidateAfterBroadcast\s*\(' packages/sdk/src -S
# 4) For each call site, print the surrounding lines (small windows)
rg -n --no-heading '\binvalidateAfterBroadcast\s*\(' packages/sdk/src -S | cut -d: -f1 | head -n 20 |whileread -r line;do# line numbers refer to file-local, so we need file too. We'll re-grep per file for that line.:done# Better approach: print small contexts directly around matches
rg -n -C4 --no-heading '\binvalidateAfterBroadcast\s*\(' packages/sdk/src -S | head -n 200

Repository: ecency/vision-next

Length of output: 1014


🏁 Script executed:

#!/bin/bashset -euo pipefail
# Show exact PlatformAdapter.invalidateQueries signature/type
PA="packages/sdk/src/modules/core/types/platform-adapter.ts"
rg -n --no-heading 'invalidateQueries\s*\('"$PA" -S
awk 'NR>=1 && NR<=220 {print NR ":" $0}'"$PA"| rg -n 'invalidateQueries|queryKey|QueryKey|PartialMatchKey|prefix|interface PlatformAdapter' -n -S ||true# Show all call sites of invalidateAfterBroadcast (small windows)
rg -n -C4 --no-heading '\binvalidateAfterBroadcast\s*\(' packages/sdk/src -S
rg -n -C4 --no-heading '\binvalidateAfterBroadcast\s*\(' packages -S

Repository: ecency/vision-next

Length of output: 44


🏁 Script executed:

#!/bin/bashset -euo pipefail
# 1) Show PlatformAdapter interface section including invalidateQueries type
PA="packages/sdk/src/modules/core/types/platform-adapter.ts"
IFACE_LINE=$(rg -n --no-heading 'interface PlatformAdapter'"$PA"| head -n1 | cut -d: -f1 || true)if [[ -n"${IFACE_LINE:-}" ]];then
START=$((IFACE_LINE-10)); END=$((IFACE_LINE+120))
awk -v s="$START" -v e="$END"'NR>=s && NR<=e {print NR ":" $0}'"$PA"fi# 2) Locate any usages of invalidateAfterBroadcast
rg -n --no-heading '\binvalidateAfterBroadcast\s*\(' packages -S | head -n 50 ||true# 3) If there are usages, inspect those files' keys argument shapes# (prints 8 lines before/after each match)
rg -n -C8 --no-heading '\binvalidateAfterBroadcast\s*\(' packages -S | head -n 200 ||true

Repository: ecency/vision-next

Length of output: 28798


🏁 Script executed:

#!/bin/bashset -euo pipefail
PA="packages/sdk/src/modules/core/types/platform-adapter.ts"# Show the invalidateQueries member block (likely later in file)
line=$(rg -n --no-heading 'invalidateQueries\s*'"$PA"| head -n 1 | cut -d: -f1 || true)if [[ -n"${line:-}" ]];then
START=$((line-20)); END=$((line+60))
awk -v s="$START" -v e="$END"'NR>=s && NR<=e {print NR ":" $0}'"$PA"elseecho"No invalidateQueries found in $PA"fi# Also show entire type of QueryKey if present (optional)
rg -n --no-heading 'QueryKey|PartialMatchKey|queryKey\s*:'"$PA" -S

Repository: ecency/vision-next

Length of output: 2904


🏁 Script executed:

#!/bin/bashset -euo pipefail
# Find adapter implementations / assignments of invalidateQueries
rg -n --no-heading 'invalidateQueries\s*:\s*\(' packages -S ||true
rg -n --no-heading 'invalidateQueries\s*\?' packages/sdk/src -S ||true
rg -n --no-heading '\binvalidateQueries\s*=' packages -S ||true# Also find any casts/usages of invalidateAfterBroadcast keys that might affect typing
rg -n --no-heading 'invalidateAfterBroadcast\s*\(' packages/sdk/src/modules -S

Repository: ecency/vision-next

Length of output: 4171


Remove explicit any from invalidateAfterBroadcastkeys parameter

packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts exports invalidateAfterBroadcast(..., keys: any[][]) and forwards keys to adapter.invalidateQueries(keys). Replace any[][] with a non-any key shape (e.g., unknown[][] / Array<Array<unknown>>) so the helper’s public API is strictly typed (while still matching the current PlatformAdapter.invalidateQueries parameter type).

🧰 Tools
🪛 ESLint

[error] 25-25: Unexpected any. Specify a different type.

(@typescript-eslint/no-explicit-any)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.
In `@packages/sdk/src/modules/core/mutations/invalidate-after-broadcast.ts` around
lines 22 - 26, The exported function invalidateAfterBroadcast currently types
the keys parameter as any[][]; change this to a non-any shape such as
unknown[][] (or Array<Array<unknown>>) so the public API is strictly typed while
remaining compatible with PlatformAdapter.invalidateQueries; update the function
signature in invalidateAfterBroadcast(..., keys: unknown[][]) and ensure any
other references/overloads use the same unknown[][] type before forwarding keys
to adapter.invalidateQueries(keys).

feruzm added 2 commits May 22, 2026 21:39
- isRetryableNodeError: drop the over-broad bare "network" and the 500/"internal
server error" signals (they can wrap deterministic chain rejections); keep
specific transport/gateway signatures (ECONN*, ETIMEDOUT, network error,
failed to fetch, 502/503/504, bad gateway, origin servers unavailable, ...).
- invalidateAfterBroadcast: call adapter.invalidateQueries as a method instead of
extracting it, so `this` stays bound.
- Tests for the tightened classification.
The SDK ships via tsup (no type-check), so type errors had accumulated. Fixed
all of them; 366 tests still pass.
Production (5): ByteBuffer Uint8Array->BufferSource casts; drop unused
Int8/Int32 serializers; precise non-null array result in filterDmcaEntry.
Tests (107): cast loosely-invoked queryFn in query-option specs; assert
possibly-undefined array/profile access in parse-accounts; SMTAsset.amount is a
string (matches the Hive API; parseAsset parseFloats it) so snapshots are
unchanged; loosen profile-metadata token literals; drop unused imports.
@feruzmferuzm added the patch Bug fixes and patches (1.0.0 → 1.0.1) label May 23, 2026
@feruzm
feruzm merged commit 466a4ba into developMay 23, 2026
2 of 3 checks passed
@feruzm
feruzm deleted the bugfix/keychain-broadcast-error-and-fallback branch May 23, 2026 04:48
Sign up for freeto join this conversation on GitHub. Already have an account? Sign in to comment

Labels

patchBug fixes and patches (1.0.0 → 1.0.1)

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant

@feruzm