Repository navigation
feat(errors): typed errors with status and URL for error responses - #43
Merged
Merged
Conversation
A refused login was a plain Error whose only signal was its message, so callers matched "Invalid credentials" to tell a wrong password from a server that is down or not a DAV server, and createAccount did the same when it kept the 401 across root-URL candidates. Against Baikal a 401 on /dav.php/ is followed by a 405 on the server root; only the error knows the login was refused. DAVAuthenticationError carries the status and the URL that refused, with the old message. An OAuth token endpoint refusing the grant (4xx) raises it too; getOauthHeaders reports the failed status so the client can tell. Closes #42
4 tasks done
Discovery, collection queries and status checks threw a plain Error
carrying the status only in its message ("Calendar discovery failed:
401 ...", "Collection query failed: 401 ..."), so a caller still had to
read the text to tell a refused login from a forbidden resource or a
server failure. They throw DAVResponseError with the status and URL,
messages unchanged, and a 401 throws DAVAuthenticationError, which is
now a DAVResponseError too.
The token endpoint counts as refusing the credentials only on 400 or
401 (RFC 6749 5.2). A 429, a 404 from a wrong token URL or a 5xx is a
DAVResponseError with that status, and a 403 at login keeps its status
instead of becoming a bare "cannot find principalUrl".
Refs #42
smartCollectionSync and fetchCalendarUserAddresses still threw a plain Error, so a 401 on a sync REPORT read as anything but a refused login and a 403 on the principal lost its status. They throw DAVResponseError (DAVAuthenticationError on 401) with the status and URL; messages are unchanged. Refs #42
Merged
This branch was successfully deployed
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.
Closes #42
What
New errors (
src/util/authError.ts, exported from the package root):DAVResponseError: a subclass ofErrorwithcode: 'TSDAV_RESPONSE_ERROR',statusandurl.isDAVResponseErrorchecks the class or the code.DAVAuthenticationError: a subclass ofDAVResponseErrorwithcode: 'TSDAV_AUTHENTICATION_FAILED'.isDAVAuthenticationErrorchecks the class or the code.Where they are thrown. Messages are unchanged everywhere; any of these answered with 401 throws
DAVAuthenticationErrorinstead:assertDAVResponses, used by calendar and address-book discovery (Calendar discovery failed: …)assertDAVPropertycollectionQueryisCollectionDirtyfetchPrincipalUrl: a 403 now keeps its statusfetchHomeUrlOAuth:
getOauthHeadersaddsfailure: { status, url }to its result when the token endpoint answers with an error status. On success it returns exactly the fields it did before.DAVAuthenticationErrorfor a token endpoint answering 400 or 401 (RFC 6749 5.2), andDAVResponseErrorwith the status for anything else (429, 404, 5xx).fetchOauthTokensandrefreshAccessTokenare unchanged.Elsewhere:
createAccountkeeps a credentials error across root-URL candidates by its type; it used to checkmessage.startsWith('Invalid credentials').docs/docs/helpers/authHelpers.md. CHANGELOG has an Unreleased section. Version and tag are left to the release.Why
dav-mcp (PhilflowIO/dav-mcp#134) needs to tell a wrong password from a forbidden resource, a rate limit, a wrong URL or a server failure, without reading message text. That holds at login and later on, e.g. when an OAuth refresh token expires mid-session. Against Baïkal a 401 on
/dav.php/is followed by a 405 on the server root, so only the thrown error knows the login was refused.Tests
src/__tests__/unit/authError.test.tscovers:fetchPrincipalUrl: 401 is an auth error with the unchanged message; 403 is aDAVResponseError403 with the unchanged messagecreateAccountwith 401 followed by 405 (Baïkal): typed 401assertDAVResponseswith 401, 403 and 500collectionQuerywith 401DAVResponseErrorsgetOauthHeaderson success: same fields as beforepnpm test: 27 files / 443 tests passed.pnpm typecheck,pnpm lint,pnpm test:examplesandpnpm test:consumerall pass.dist/matches a freshpnpm build.