fix(waves): recover when ecency.app posting authority is missing#3320
fix(waves): recover when ecency.app posting authority is missing#3320feruzm wants to merge 2 commits into
Conversation
Posting through the HiveSigner token path requires ecency.app to be present
in the account's posting authorities. When it is absent, HiveSigner rejects
the broadcast with `unauthorized_client` ("The app @ecency.app doesn't have
permission to broadcast for @user") and the raw JSON was shown to the user
with no way to recover.
- Broaden shouldPromptPostingAuthority to cover token-broadcast logins
(HiveSigner and active-key-only), not just HiveAuth, so the grant prompt
fires pre-flight for any user whose posts would otherwise fail. Key logins
grant directly with the local key; token-only logins are routed through
HiveSigner by the platform adapter.
- Detect the unauthorized_client rejection in the quick-post/wave submitter
and open the grant/re-authorise sheet with a single guarded retry, instead
of surfacing the raw error.
- Add unit tests for the posting-authority helpers.
There was a problem hiding this comment.
💡 Codex Review
Here are some automated review suggestions for this pull request.
Reviewed commit: 680fce5a4f
ℹ️ 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".
| true, | ||
| ); | ||
| }); | ||
| return false; |
There was a problem hiding this comment.
Preserve submit success handling after authority recovery
When a HiveSigner broadcast hits the missing-authority error, this branch schedules the retry in the sheet callback but immediately returns false to the original quick-post caller. In that scenario the later successful retry is detached from _submitPost/_submitWave: comment submissions skip the modal/draft cleanup and can be submitted again, and wave submissions bypass the _submitWave success path that calls pusblishWaveMutation.mutate(...) to prepend the wave to the feed.
Useful? React with 👍 / 👎.
Greptile SummaryThis PR fixes a silent failure for HiveSigner and active-key-only users whose
Confidence Score: 4/5Safe to merge with one targeted fix: the The authority-recovery retry logic in
Important Files Changed
Reviews (2): Last reviewed commit: "fix(waves): preserve recovery retry resu..." | Re-trigger Greptile |
📝 WalkthroughWalkthroughThis PR adds posting-authority detection helpers in ChangesPosting Authority Detection and Retry Flow
Estimated code review effort: 3 (Moderate) | ~25 minutes Sequence Diagram(s)sequenceDiagram
participant User
participant usePostSubmitter
participant HiveProvider
participant HiveSigner
User->>usePostSubmitter: submit reply
usePostSubmitter->>HiveSigner: broadcast posting operation
HiveSigner-->>usePostSubmitter: unauthorized_client error
usePostSubmitter->>HiveProvider: isMissingEcencyPostingAuthorityError(error)
HiveProvider-->>usePostSubmitter: true
usePostSubmitter->>User: show posting authority recovery sheet
User-->>usePostSubmitter: onGranted
usePostSubmitter->>usePostSubmitter: retry _submitReply(isAuthorityRetry=true)
usePostSubmitter->>HiveSigner: retry broadcast posting operation
HiveSigner-->>usePostSubmitter: success
Possibly related PRs
Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
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. Comment |
There was a problem hiding this comment.
Actionable comments posted: 3
🤖 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 `@src/components/quickPostModal/usePostSubmitter.ts`:
- Around line 57-68: The recovery flow in usePostSubmitter is returning false
immediately after opening the posting authority sheet, so the retried submit
result from _submitReply is never propagated back to _submitWave. Update
_promptPostingAuthorityRecovery and the surrounding submit/recovery logic so the
grant sheet is awaited and its retry result is returned to the caller, allowing
_submitWave to continue and call pusblishWaveMutation.mutate with the cached
comment data after a successful re-authorisation. Apply the same
return/replacement behavior in the outer catch path that handles the
unauthorized_client recovery.
- Line 80: The retry path in usePostSubmitter is still going through the
pre-flight authority prompt gate, which can re-open the prompt or get blocked by
the recursion guard. Update the submit flow around
shouldPromptPostingAuthority/currentAccount so that isAuthorityRetry bypasses
the prompt check and proceeds directly with the guarded one-time broadcast. Make
the change in the submit logic and any related retry branches in
usePostSubmitter, ensuring the retry path uses the retry flag instead of
re-evaluating the pre-grant account state.
In `@src/providers/hive/hive.ts`:
- Around line 638-640: The unauthorized_client check in hive.ts is too broad and
can misclassify unrelated HiveSigner/OAuth failures as missing ecency.app
authority. Tighten the logic in the error-handling path that returns true for
posting-authority fallback by also requiring evidence from error_description,
message, or a broadcast/permission-related signal before matching
unauthorized_client. Update the conditional around the existing code/error
fields so only the posting-authority failure routes into the grant sheet and
retry flow.
🪄 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: e6095cad-9178-4a96-948d-8a0168231028
📒 Files selected for processing (3)
src/components/quickPostModal/usePostSubmitter.tssrc/providers/hive/hive.tssrc/providers/hive/postingAuthority.test.ts
… match Address review feedback on the authority-recovery path: - Make the recovery sheet awaitable and return the retry's result, so a successful recovery still runs the caller's success handling (e.g. _submitWave prepending the wave to the feed) instead of returning false and dropping it. Release the submit lock before the retry so its entry guard doesn't short-circuit. - Skip the pre-flight authority prompt on the recovery retry so it can't re-open the sheet against a stale currentAccount snapshot. - Narrow isMissingEcencyPostingAuthorityError to the missing-authority context (permission-to-broadcast / ecency.app) instead of any bare unauthorized_client, which HiveSigner also returns for expired tokens or wrong scope.
There was a problem hiding this comment.
Actionable comments posted: 1
🧹 Nitpick comments (1)
src/components/quickPostModal/usePostSubmitter.ts (1)
378-395: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winDuplicated recovery-and-retry block.
Lines 378-395 duplicate the inner catch recovery logic (335-357). Extracting a small
_recoverAndRetry(...)helper would centralize the lock handling so the dismissal fix above can't diverge between the two paths.🤖 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 `@src/components/quickPostModal/usePostSubmitter.ts` around lines 378 - 395, The recovery-and-retry flow in _submitReply duplicates the same authority prompt and retry logic already used in the earlier catch path, which risks the two branches drifting apart. Extract that shared logic into a small _recoverAndRetry(...) helper (or similarly named helper alongside _promptPostingAuthorityRecovery and _submitReply) that handles prompting, resetting submitting state, and re-invoking the reply submission, then call it from both places so the lock/dismissal behavior stays consistent.
🤖 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 `@src/components/quickPostModal/usePostSubmitter.ts`:
- Around line 335-357: The submit lock handling in usePostSubmitter’s
_submitReply path can wedge isSubmitting if _promptPostingAuthorityRecovery()
never resolves, so release the submitting state before awaiting the recovery
sheet and re-arm it only for the retry path. Update the
isMissingEcencyPostingAuthorityError branch (and the matching outer catch path)
to mirror the pre-flight POSTING_AUTHORITY_PROMPT flow, ensuring
dismissals/background kills do not leave the component stuck in a submitting
state.
---
Nitpick comments:
In `@src/components/quickPostModal/usePostSubmitter.ts`:
- Around line 378-395: The recovery-and-retry flow in _submitReply duplicates
the same authority prompt and retry logic already used in the earlier catch
path, which risks the two branches drifting apart. Extract that shared logic
into a small _recoverAndRetry(...) helper (or similarly named helper alongside
_promptPostingAuthorityRecovery and _submitReply) that handles prompting,
resetting submitting state, and re-invoking the reply submission, then call it
from both places so the lock/dismissal behavior stays consistent.
🪄 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: fff5e0af-1e8f-4f71-9a18-a3fd114c3589
📒 Files selected for processing (3)
src/components/quickPostModal/usePostSubmitter.tssrc/providers/hive/hive.tssrc/providers/hive/postingAuthority.test.ts
🚧 Files skipped from review as they are similar to previous changes (2)
- src/providers/hive/postingAuthority.test.ts
- src/providers/hive/hive.ts
| if (isMissingEcencyPostingAuthorityError(error) && !isAuthorityRetry) { | ||
| // A grant failure surfaces its own toast from the sheet, so treat a | ||
| // rejection as "not granted" here. | ||
| const granted = await _promptPostingAuthorityRecovery().catch(() => false); | ||
| if (!granted) { | ||
| return false; | ||
| } | ||
| // Release the submit lock before retrying: the retry re-arms it via | ||
| // its own `if (manageSubmittingState) setIsSubmitting(true)`, and | ||
| // leaving it armed would trip the retry's entry guard. | ||
| if (manageSubmittingState) { | ||
| setIsSubmitting(false); | ||
| } | ||
| return await _submitReply( | ||
| commentBody, | ||
| parentPost, | ||
| postType, | ||
| pollDraft, | ||
| manageSubmittingState, | ||
| videoThumbUrls, | ||
| true, | ||
| ); | ||
| } |
There was a problem hiding this comment.
🩺 Stability & Availability | 🟠 Major | ⚡ Quick win
Release the submit lock before awaiting the recovery sheet, or a dismissed sheet wedges isSubmitting.
_promptPostingAuthorityRecovery() opens the same POSTING_AUTHORITY_PROMPT sheet that the pre-flight path at Lines 113-121 explicitly guards: if the user dismisses it (swipe, app backgrounded, system kill) without firing onGranted/onSkipped/onError, the promise never settles, the await here hangs, the outer finally (Line 411) never runs, and isSubmitting stays true for the component lifetime — permanently disabling publish.
The lock is only released at Line 346 after a grant, so the dismissal case is unprotected. Mirror the pre-flight fix by releasing before the await (and re-arming for the wave path, matching Lines 145-147).
The outer catch at Lines 378-395 has the identical gap.
🔒 Proposed fix (apply equivalently in the outer catch)
if (isMissingEcencyPostingAuthorityError(error) && !isAuthorityRetry) {
+ // Release the lock before the await: a dismissed sheet (no
+ // callback) leaves the promise pending, which would otherwise
+ // wedge isSubmitting permanently. Mirrors the pre-flight guard.
+ setIsSubmitting(false);
// A grant failure surfaces its own toast from the sheet, so treat a
// rejection as "not granted" here.
const granted = await _promptPostingAuthorityRecovery().catch(() => false);
if (!granted) {
return false;
}
- // Release the submit lock before retrying: the retry re-arms it via
- // its own `if (manageSubmittingState) setIsSubmitting(true)`, and
- // leaving it armed would trip the retry's entry guard.
- if (manageSubmittingState) {
- setIsSubmitting(false);
+ // Re-arm only for the wave path; the quick-post retry re-arms via
+ // its own `if (manageSubmittingState) setIsSubmitting(true)`.
+ if (!manageSubmittingState) {
+ setIsSubmitting(true);
}
return await _submitReply(📝 Committable suggestion
‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation. Thoroughly test & benchmark the code to ensure it meets the requirements.
| if (isMissingEcencyPostingAuthorityError(error) && !isAuthorityRetry) { | |
| // A grant failure surfaces its own toast from the sheet, so treat a | |
| // rejection as "not granted" here. | |
| const granted = await _promptPostingAuthorityRecovery().catch(() => false); | |
| if (!granted) { | |
| return false; | |
| } | |
| // Release the submit lock before retrying: the retry re-arms it via | |
| // its own `if (manageSubmittingState) setIsSubmitting(true)`, and | |
| // leaving it armed would trip the retry's entry guard. | |
| if (manageSubmittingState) { | |
| setIsSubmitting(false); | |
| } | |
| return await _submitReply( | |
| commentBody, | |
| parentPost, | |
| postType, | |
| pollDraft, | |
| manageSubmittingState, | |
| videoThumbUrls, | |
| true, | |
| ); | |
| } | |
| if (isMissingEcencyPostingAuthorityError(error) && !isAuthorityRetry) { | |
| // Release the lock before the await: a dismissed sheet (no | |
| // callback) leaves the promise pending, which would otherwise | |
| // wedge isSubmitting permanently. Mirrors the pre-flight guard. | |
| setIsSubmitting(false); | |
| // A grant failure surfaces its own toast from the sheet, so treat a | |
| // rejection as "not granted" here. | |
| const granted = await _promptPostingAuthorityRecovery().catch(() => false); | |
| if (!granted) { | |
| return false; | |
| } | |
| // Re-arm only for the wave path; the quick-post retry re-arms via | |
| // its own `if (manageSubmittingState) setIsSubmitting(true)`. | |
| if (!manageSubmittingState) { | |
| setIsSubmitting(true); | |
| } | |
| return await _submitReply( | |
| commentBody, | |
| parentPost, | |
| postType, | |
| pollDraft, | |
| manageSubmittingState, | |
| videoThumbUrls, | |
| 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 `@src/components/quickPostModal/usePostSubmitter.ts` around lines 335 - 357,
The submit lock handling in usePostSubmitter’s _submitReply path can wedge
isSubmitting if _promptPostingAuthorityRecovery() never resolves, so release the
submitting state before awaiting the recovery sheet and re-arm it only for the
retry path. Update the isMissingEcencyPostingAuthorityError branch (and the
matching outer catch path) to mirror the pre-flight POSTING_AUTHORITY_PROMPT
flow, ensuring dismissals/background kills do not leave the component stuck in a
submitting state.
Posting through the HiveSigner token path requires
ecency.appto be present in the account's posting authorities. When it is absent, HiveSigner rejects the broadcast withunauthorized_client("The app @ecency.app doesn't have permission to broadcast for @user") and the raw JSON was shown to the user with no way to recover.Changes
shouldPromptPostingAuthorityto cover token-broadcast logins (HiveSigner and active-key-only), not just HiveAuth, so the grant prompt fires pre-flight for any user whose posts would otherwise fail. Key logins grant directly with the local key; token-only logins are routed through HiveSigner by the platform adapter.unauthorized_clientrejection in the quick-post/wave submitter and open the grant / re-authorise sheet with a single guarded retry, instead of surfacing the raw error.Testing
yarn test:ci— full suite passes (adds 13 tests for the posting-authority helpers).Summary by CodeRabbit