Repository navigation
refactor(core): share the oauth state failure union and fold callback narrowing - #4624
Merged
Merged
Conversation
… narrowing #4588 added `oauthCallbackFailureReason` in core with a hand-copied `"malformed" | "invalidSignature" | "expired" | "stateMismatch"` union mirroring `OAuthStateFailure` in sync. Core cannot import sync, so the two could only drift: adding a fifth verification failure would leave the analytics mapper silently unable to accept it. Move the union to `connection.contracts` next to the other consent-flow contracts, as a Zod enum like its `ConnectionStateReason` sibling, and have both the verifier and the analytics mapper read it from there. Also tidy two smells in the same mapper: - `state` and `code` were each narrowed from `unknown` twice, with different idioms (`?? null` in one branch, `.length > 0` in another). Narrow each callback value once up front via `asNonEmptyString`. Behavior is unchanged: `oauthFailedReasonFromCallbackQuery` already tests these falsily, so a blank value took the absent path either way. - `isTokenExchangeFailure` and `providerErrorFromExchange` repeated the same object guard and cast and were only ever called together. Fold them into one `tokenExchangeFailure` and route the result through `withProviderError` like every other branch, so a reasonless failure omits `provider_error` rather than sending an explicit `undefined` to PostHog. bun run verify --strict VERDICT: PASS Co-Authored-By: Claude Opus 5 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01GSTPkN9FL7t93wAj8442Y3
tyler-dane
enabled auto-merge
October 20, 2026 10:07
Contributor
|
Boot bundle: 509.8 KB gzip (+0.0 KB vs main) |
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
What and why
Technical-debt cleanup in the OAuth callback analytics added by #4588 and partly reworked by #4617. No behavior change for any outcome the mapper reports today.
A duplicated type that could only drift. #4588 added
oauthCallbackFailureReasontopackages/corewith a hand-copied"malformed" | "invalidSignature" | "expired" | "stateMismatch"union mirroringOAuthStateFailureinpackages/sync/src/oauth/oauth-state.ts. Core cannot import sync, so nothing tied the two together: adding a fifth state-verification failure in sync would leave the analytics mapper unable to accept it, and widening the inline copy by hand would let the two definitions disagree silently. This moves the union intoconnection.contractsbeside the other consent-flow contracts, as a Zod enum like itsConnectionStateReasonsibling, and has both the verifier and the analytics mapper read it from there. One definition, correct dependency direction.stateandcodewere each narrowed fromunknowntwice, with different idioms (typeof x === "string" ? x : nullin thedeclinedbranch,typeof x === "string" && x.length > 0in theerrorbranch). Each callback value is now narrowed once up front throughasNonEmptyString. This is behavior-preserving:oauthFailedReasonFromCallbackQueryalready testsstateandcodefalsily, so""took the absent path under both idioms. The inconsistency was the kind that eventually becomes a bug, not one today.isTokenExchangeFailureandproviderErrorFromExchangerepeated the same object guard and the same cast, and were only ever called together on the same input. They fold into onetokenExchangeFailure, whose result now routes throughwithProviderErrorlike every other branch in the function. That also drops the one inconsistency with real effect: the token-exchange branch built its result literal by hand, so aProviderAuthErrorcarrying noreasonsent an explicitprovider_error: undefinedto PostHog instead of omitting the property.Added regression tests for the folded paths: a reasonless exchange failure, a non-
ProviderAuthErroron the exchange path, blankstate/code, and theinvalidSignature/expiredmapping.Verify
Generated by Claude Code