SDK: auth.broadcast is not deprecated, and a guard so it is not misread again - #1378
SDK: auth.broadcast is not deprecated, and a guard so it is not misread again#1378feruzm wants to merge 1 commit into
Conversation
…ad again Checked whether AuthContext.broadcast could be deleted now that #1376 migrated the four mutations off it. It cannot, and the reason matters more than the answer. Mobile is already fully V2: useAuthContext returns { adapter, enableFallback } and never sets broadcast. But the web app has two live callers, and neither is legacy: - use-login-by-key grants posting permission DURING login, before the user exists to the adapter, so the key comes from a ref. - wallet-operations-sign dispatches on a signing method the user picks mid-flow, which the adapter has no way to know about. Both are the custom-broadcaster case, which useBroadcastMutation supports as case 'custom', the last link of the default fallback chain. It is a feature. So the @deprecated tag was wrong, and plausibly the cause. It said to use broadcastWithKeychain instead, which reads as "this is the old way to broadcast", and four mutations duly treated it as the keychain path: they checked auth?.broadcast and threw when it was absent. Every field on AuthContext is optional, so AuthContextV2 satisfies it structurally and the checks compiled everywhere; each failed only when a real user arrived. The doc now says what the field is for, names both legitimate callers, and says plainly never to use it to detect Keychain. The guard is a syntax scan, since the type system cannot express this. It reads the AST rather than the text because auth.broadcast now appears in prose in these files and a text search reports the comments explaining why not to use it. Sanctioned readers are listed with reasons; anything else fails. Confirmed by reintroducing the exact bug in use-account-revoke-posting: the scan names the file.
|
You have reached your Codex usage limits for code reviews. You can see your limits in the Codex usage dashboard. |
📝 WalkthroughWalkthroughThe SDK documents ChangesCustom broadcast controls
Estimated code review effort: 3 (Moderate) | ~20 minutes Poem
🚥 Pre-merge checks | ✅ 5✅ Passed checks (5 passed)
✨ Finishing Touches📝 Generate docstrings
🧪 Generate unit tests (beta)
Warning There were issues while running some tools. Please review the errors and either fix the tool's configuration or disable the tool if it's a critical failure. 🔧 ESLint
ESLint install failed. For unrecoverable errors, disable the tool in CodeRabbit configuration. 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: 2
🧹 Nitpick comments (1)
packages/sdk/src/modules/core/custom-broadcast-usage.spec.ts (1)
74-77: 📐 Maintainability & Code Quality | 🔵 Trivial | ⚡ Quick winReplace the repository-size threshold with stable assertions.
files.length > 50depends on the current module count. Normal cleanup can fail the test, and an incorrect directory with more than 50 files can still pass. Assert that both sanctioned files are discovered instead.Proposed test change
- expect(files.length).toBeGreaterThan(50); + expect(files).toContain( + join(MODULES, "core/mutations/use-broadcast-mutation.ts") + ); + expect(files).toContain( + join(MODULES, "core/mutations/broadcast-json.ts") + );🤖 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/custom-broadcast-usage.spec.ts` around lines 74 - 77, Replace the files.length threshold assertion in the “finds the modules to scan” test with stable assertions that verify both sanctioned files are present in files, using their established filenames or symbols. Preserve the test’s purpose of confirming the intended directory is scanned without relying on the repository’s total module count.
🤖 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/custom-broadcast-usage.spec.ts`:
- Around line 57-65: Extend the AST detector in the visit function to flag every
read of AuthContext.broadcast, including string-literal element access such as
auth["broadcast"] and broadcast property bindings in object destructuring.
Normalize parenthesized and type-asserted expressions before checking the
receiver so (auth as AuthContext).broadcast and (<AuthContext>auth).broadcast
are covered, while preserving the existing direct and optional property-access
detection.
In `@packages/sdk/src/modules/core/types/auth.ts`:
- Around line 30-31: Update the contract documentation near the caller-supplied
broadcaster declaration to use the complete wording “A caller-supplied
broadcaster for signing operations that the platform adapter cannot perform.”
---
Nitpick comments:
In `@packages/sdk/src/modules/core/custom-broadcast-usage.spec.ts`:
- Around line 74-77: Replace the files.length threshold assertion in the “finds
the modules to scan” test with stable assertions that verify both sanctioned
files are present in files, using their established filenames or symbols.
Preserve the test’s purpose of confirming the intended directory is scanned
without relying on the repository’s total module count.
🪄 Autofix
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 Plus
Run ID: 4d7d1b7c-b9e4-4a63-99a1-ed55dce8ae17
📒 Files selected for processing (2)
packages/sdk/src/modules/core/custom-broadcast-usage.spec.tspackages/sdk/src/modules/core/types/auth.ts
| const visit = (node: ts.Node): void => { | ||
| if ( | ||
| ts.isPropertyAccessExpression(node) && | ||
| node.name.text === "broadcast" && | ||
| /^auth$/i.test(node.expression.getText(sf).replace(/[?!]/g, "")) | ||
| ) { | ||
| found = true; | ||
| } | ||
| ts.forEachChild(node, visit); |
There was a problem hiding this comment.
🎯 Functional Correctness | 🟠 Major | ⚡ Quick win
🧩 Analysis chain
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
rg -nP \
-e "auth[[:space:]]*\\[[[:space:]]*['\"]broadcast" \
-e "auth[[:space:]]+as[[:space:]].*\\.[[:space:]]*broadcast" \
-e "\\([[:space:]]*auth[[:space:]]*\\)[[:space:]]*\\.[[:space:]]*broadcast" \
-e "\\{[[:space:]]*broadcast[[:space:]]*\\}[[:space:]]*=[[:space:]]*auth\\b" \
packages/sdk/src/modules --glob '*.ts' --glob '*.tsx' || trueRepository: ecency/vision-web
Length of output: 155
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
sed -n '1,180p' packages/sdk/src/modules/core/custom-broadcast-usage.spec.ts
printf '\n--- related files ---\n'
rg -n "custom-broadcast|custom.*broadcast|broadcast" packages/sdk/src -g '*.ts' -g '*.tsx' | head -80Repository: ecency/vision-web
Length of output: 13574
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
node - <<'JS'
const ts = require("typescript");
const source = `
auth.broadcast
auth?.broadcast
auth["broadcast"]
auth['broadcast']
(auth as AuthContext).broadcast
(<AuthContext>auth).broadcast
const { broadcast } = auth
const [{ broadcast }] = [auth]
`;
const sf = ts.createSourceFile("<test.ts>", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
function match(node) {
const matches = ts.isPropertyAccessExpression(node)
&& node.name.text === "broadcast"
&& /^auth$/i.test(node.expression.getText(sf).replace(/[?!]/g, ""));
if (matches) {
console.log(node.kind, ts.SyntaxKind[node.kind], node.name.text, JSON.stringify(node.expression.getText(sf)));
}
ts.forEachChild(node, visit);
}
function visit(node) {
match(node);
}
visit(sf);
JSRepository: ecency/vision-web
Length of output: 247
🏁 Script executed:
#!/usr/bin/env bash
set -euo pipefail
node - <<'JS'
const ts = require("typescript");
const cases = [
["dot", "auth.broadcast"],
["optional-dot", "auth?.broadcast"],
["string-index", 'auth["broadcast"]'],
["cast-dot", "(auth as AuthContext).broadcast"],
["angle-cast-dot", "(<AuthContext>auth).broadcast"],
["destructured", "const { broadcast } = auth"],
["array-destructuring", "const [{ broadcast }] = [auth]"],
["safe-destructuring", "const { broadcast = '' } = auth"],
];
for (const [label, source] of cases) {
const sf = ts.createSourceFile(label + ".ts", source, ts.ScriptTarget.Latest, true, ts.ScriptKind.TS);
let matched = false;
function visit(node) {
if (ts.isPropertyAccessExpression(node) && node.name.text === "broadcast") {
console.log(label + " PropertyAccessExpression:", node.expression.getText(sf));
matched = true;
}
if (ts.isElementAccessExpression(node) && node.name?.text === "broadcast") {
console.log(label + " ElementAccessExpression:", JSON.stringify(node.expression.getText(sf)), "argument:", JSON.stringify(node.argumentExpression?.getText(sf)));
matched = true;
}
if (ts.isBindingPattern(node) || ts.isObjectBindingPattern(node) || ts.isArrayBindingPattern(node)) {
node.elements.forEach((e) => {
if (ts.isBindingElement(node) && e.name.getText(sf) === "broadcast") {
console.log(label + " BindingElement:", JSON.stringify(source));
matched = true;
}
});
}
ts.forEachChild(node, visit);
}
visit(sf);
if (!matched) {
console.log(label + " no local match");
}
}
JSRepository: ecency/vision-web
Length of output: 477
Cover all API forms that read AuthContext.broadcast.
The parser accepts auth["broadcast"], (auth as AuthContext).broadcast, (<AuthContext>auth).broadcast, and destructuring, but this detector only blocks auth.broadcast and auth?.broadcast. Add an explicit lint rule or extend the AST checks for string-literal element access and binding patterns so equivalent reads cannot bypass the guard.
🤖 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/custom-broadcast-usage.spec.ts` around lines 57
- 65, Extend the AST detector in the visit function to flag every read of
AuthContext.broadcast, including string-literal element access such as
auth["broadcast"] and broadcast property bindings in object destructuring.
Normalize parenthesized and type-asserted expressions before checking the
receiver so (auth as AuthContext).broadcast and (<AuthContext>auth).broadcast
are covered, while preserving the existing direct and optional property-access
detection.
| * A caller-supplied broadcaster, for signing the platform adapter cannot do. | ||
| * |
There was a problem hiding this comment.
📐 Maintainability & Code Quality | 🟡 Minor | ⚡ Quick win
Fix the incomplete sentence in the contract documentation.
Use A caller-supplied broadcaster for signing operations that the platform adapter cannot perform. The current wording is grammatically incomplete and makes the callback contract harder to read.
Proposed wording
- * A caller-supplied broadcaster, for signing the platform adapter cannot do.
+ * A caller-supplied broadcaster for signing operations that the platform adapter cannot perform.📝 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.
| * A caller-supplied broadcaster, for signing the platform adapter cannot do. | |
| * | |
| * A caller-supplied broadcaster for signing operations that the platform adapter cannot perform. | |
| * |
🤖 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/types/auth.ts` around lines 30 - 31, Update the
contract documentation near the caller-supplied broadcaster declaration to use
the complete wording “A caller-supplied broadcaster for signing operations that
the platform adapter cannot perform.”
You asked whether we could delete
AuthContext.broadcastnow that #1376 migrated the four mutations off it. We can't, and the reason is more useful than the answer.What I checked
Mobile is already fully V2.
useAuthContext()returns{ adapter, enableFallback }and never setsbroadcast. Nothing invision-mobilereads it.The web app has two live callers, and neither is legacy:
use-login-by-key.ts:34grants posting permission during login, before the user exists to the adapter, so the key comes from a ref.wallet-operations-sign.tsx:57dispatches on a signing method the user picks mid-flow, which the adapter has no way to know about.Both are the custom-broadcaster case, which
useBroadcastMutationsupports ascase 'custom'— the last link of the default fallback chain['key', 'hiveauth', 'hivesigner', 'keychain', 'custom']. It is a feature, not a leftover.So the
@deprecatedtag was wrong, and it plausibly caused the bugIt read:
Which parses as "this is the old way to broadcast". Four mutations duly treated it as the keychain path: they checked
auth?.broadcastand threw when it was absent. Every field onAuthContextis optional, soAuthContextV2satisfies it structurally, the checks compiled everywhere, and each site failed only when a real user arrived. That is how four accumulated before one became a Sentry issue.The doc now says what the field is actually for, names both legitimate callers so the next reader can tell their case apart, and says plainly never to use it to detect Keychain.
The guard
A syntax scan, because the type system cannot express "optional, but not the thing you want". It reads the AST, not the text, because
auth.broadcastnow appears in prose throughout these files and a text search reports the comments explaining why not to use it.Sanctioned readers are listed with reasons:
use-broadcast-mutation.tsownscase 'custom'broadcast-json.tskeeps it as the first branch of its own chain so V1 callers still workAnything else fails, with the offending file named. Mutation-checked by reintroducing the exact bug in
use-account-revoke-posting.ts, which the scan reports by name.When it can actually be deleted
When those two web call sites have another way to supply signing. Until then, deleting the field would break login-by-key and the wallet signer. Worth revisiting if the adapter ever grows a "sign with this key I am handing you" method.
681 tests pass, 48 files. Typecheck clean.
Summary by CodeRabbit
Documentation
Tests