Skip to content

fix(waves): recover when ecency.app posting authority is missing#3320

Open
feruzm wants to merge 2 commits into
developmentfrom
fix/hivesigner-posting-authority-recovery
Open

fix(waves): recover when ecency.app posting authority is missing#3320
feruzm wants to merge 2 commits into
developmentfrom
fix/hivesigner-posting-authority-recovery

Conversation

@feruzm

@feruzm feruzm commented Jul 4, 2026

Copy link
Copy Markdown
Member

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.

Changes

  • 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.

Testing

  • yarn test:ci — full suite passes (adds 13 tests for the posting-authority helpers).
  • Lint + typecheck clean.

Summary by CodeRabbit

  • Bug Fixes
    • Improved detection of missing posting authority and enabled a smoother recovery flow when permission can be granted or skipped.
    • Refined when authority prompts appear, suppressing them when posting access is already available and tightening conditions for which account/login scenarios trigger prompting.
  • Tests
    • Added Jest coverage for posting-authority detection, prompt eligibility logic, and correct handling of permission-related rejection cases.

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.

@chatgpt-codex-connector chatgpt-codex-connector Bot 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: 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;

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 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-apps

greptile-apps Bot commented Jul 4, 2026

Copy link
Copy Markdown

Greptile Summary

This PR fixes a silent failure for HiveSigner and active-key-only users whose ecency.app posting authority is missing: instead of dumping a raw unauthorized_client JSON to the user, the app now detects the rejection, shows the grant/re-authorize sheet, and retries once if the user grants. shouldPromptPostingAuthority is also broadened to fire the grant prompt pre-flight for these users, not just for HiveAuth.

  • hive.ts: Exports hasEcencyPostingAuthority, adds usesHivesignerTokenBroadcast and isMissingEcencyPostingAuthorityError helpers, and widens shouldPromptPostingAuthority to cover token-broadcast logins (HiveSigner + active-key-only).
  • usePostSubmitter.ts: Adds _promptPostingAuthorityRecovery, an isAuthorityRetry flag to prevent re-entrant authority prompts, and authority-error catch handling in both the inner (commentMutation.mutateAsync) and outer try-catch blocks with proper submit-lock management.
  • postingAuthority.test.ts: New file adding 13 unit tests for the posting-authority helpers.

Confidence Score: 4/5

Safe to merge with one targeted fix: the ecency.app substring condition in isMissingEcencyPostingAuthorityError should be removed so unrelated errors that happen to contain the domain name don't open the grant sheet instead of showing the real error.

The authority-recovery retry logic in usePostSubmitter.ts is well-structured — the isAuthorityRetry guard prevents infinite loops, submit-lock management is handled correctly for both the wave and quick-post paths, and the new pre-flight broadening in shouldPromptPostingAuthority is accurate. The one concrete defect is in isMissingEcencyPostingAuthorityError: the haystack.includes('ecency.app') branch will match any error message that references the domain — network timeouts, server errors, or other SDK-wrapped rejections — and show the posting-authority grant sheet as the recovery UI instead of the actual error.

src/providers/hive/hive.ts — specifically the isMissingEcencyPostingAuthorityError function's second haystack.includes condition.

Important Files Changed

Filename Overview
src/providers/hive/hive.ts Adds usesHivesignerTokenBroadcast, isMissingEcencyPostingAuthorityError, and broadens shouldPromptPostingAuthority; the error-detection function's ecency.app substring condition is broader than needed and can false-match unrelated errors.
src/components/quickPostModal/usePostSubmitter.ts Adds isAuthorityRetry guard and post-broadcast authority recovery with _promptPostingAuthorityRecovery; retry logic handles both inner and outer catch correctly including submit-lock management for wave and non-wave paths.
src/providers/hive/postingAuthority.test.ts New unit tests covering hasEcencyPostingAuthority, usesHivesignerTokenBroadcast, isMissingEcencyPostingAuthorityError, and shouldPromptPostingAuthority; does not include a test for false-positive ecency.app substring matches in isMissingEcencyPostingAuthorityError.

Reviews (2): Last reviewed commit: "fix(waves): preserve recovery retry resu..." | Re-trigger Greptile

Comment thread src/components/quickPostModal/usePostSubmitter.ts Outdated
Comment thread src/providers/hive/hive.ts Outdated
@coderabbitai

coderabbitai Bot commented Jul 4, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

This PR adds posting-authority detection helpers in hive.ts, updates prompting rules, and adds a retry/recovery path in usePostSubmitter for missing ecency.app authority errors. Unit tests cover the new helpers and prompt behavior.

Changes

Posting Authority Detection and Retry Flow

Layer / File(s) Summary
Posting authority detection helpers and prompt gating
src/providers/hive/hive.ts
Adds exported hasEcencyPostingAuthority, usesHivesignerTokenBroadcast, and isMissingEcencyPostingAuthorityError helpers; updates shouldPromptPostingAuthority to use token-broadcast detection alongside HiveAuth checks and the existing authority early-exit.
Retry and recovery wiring in post submission
src/components/quickPostModal/usePostSubmitter.ts
Imports new helpers, adds _promptPostingAuthorityRecovery, adds isAuthorityRetry parameter to _submitReply, and intercepts missing-authority errors in inner and outer catch blocks to trigger a recovery prompt and a single retry.
Posting authority unit tests
src/providers/hive/postingAuthority.test.ts
Adds Jest tests validating the new detection helpers and updated prompt-gating behavior across various auth types and authority states.

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
Loading

Possibly related PRs

  • ecency/ecency-mobile#3109: Extends the same missing ecency.app posting authority detection/recovery codepath in HiveAuth/broadcast error handling.

Poem

A rabbit hops through Hive's own gate,
To find the key that came too late,
"No authority?" — no need to fret,
Prompt, retry, and post it yet! 🐇
Tests confirm each careful hop,
Errors caught before they stop. 🥕

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly matches the main change: recovering when ecency.app posting authority is missing.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ 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 fix/hivesigner-posting-authority-recovery

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.

@coderabbitai coderabbitai Bot 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.

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

📥 Commits

Reviewing files that changed from the base of the PR and between 069e34d and 680fce5.

📒 Files selected for processing (3)
  • src/components/quickPostModal/usePostSubmitter.ts
  • src/providers/hive/hive.ts
  • src/providers/hive/postingAuthority.test.ts

Comment thread src/components/quickPostModal/usePostSubmitter.ts Outdated
Comment thread src/components/quickPostModal/usePostSubmitter.ts
Comment thread src/providers/hive/hive.ts Outdated
… 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.

@coderabbitai coderabbitai Bot 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.

Actionable comments posted: 1

🧹 Nitpick comments (1)
src/components/quickPostModal/usePostSubmitter.ts (1)

378-395: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick win

Duplicated 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

📥 Commits

Reviewing files that changed from the base of the PR and between 680fce5 and f70880b.

📒 Files selected for processing (3)
  • src/components/quickPostModal/usePostSubmitter.ts
  • src/providers/hive/hive.ts
  • src/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

Comment on lines +335 to +357
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,
);
}

Copy link
Copy Markdown

Choose a reason for hiding this comment

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

🩺 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.

Suggested change
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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant