Something went wrong. Try again.
A Deno-compatible AT Protocol OAuth client that serves as a drop-in replacement for @atproto/oauth-client-node
Something went wrong. Try again.
9.6 kB · 251 lines
TypeScript
at main
123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252import { assert, assertEquals, assertInstanceOf } from "@std/assert";import { AuthorizationError, DPoPError, HandleResolutionError, InvalidHandleError, InvalidStateError, IssuerMismatchError, MetadataValidationError, OAuthError, PDSDiscoveryError, SessionError, TokenExchangeError, TokenValidationError,} from "../src/errors.ts";
Deno.test("OAuthError", async (t) => { await t.step("should create basic error with message", () => { const error = new OAuthError("Test message"); assertEquals(error.message, "Test message"); assertEquals(error.name, "OAuthError"); assertEquals(error.cause, undefined); });
await t.step("should create error with cause", () => { const cause = new Error("Original error"); const error = new OAuthError("Test message", cause); assertEquals(error.message, "Test message"); assertEquals(error.name, "OAuthError"); assertEquals(error.cause, cause); });
await t.step("should be instance of Error", () => { const error = new OAuthError("Test message"); assertInstanceOf(error, Error); assertInstanceOf(error, OAuthError); });});
Deno.test("InvalidHandleError", async (t) => { await t.step("should create error with handle in message", () => { const error = new InvalidHandleError("invalid.handle"); assertEquals(error.message, "Invalid AT Protocol handle: invalid.handle"); assertEquals(error.name, "InvalidHandleError"); });
await t.step("should be instance of OAuthError", () => { const error = new InvalidHandleError("invalid.handle"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, InvalidHandleError); });});
Deno.test("HandleResolutionError", async (t) => { await t.step("should create error with handle in message", () => { const error = new HandleResolutionError("test.handle"); assertEquals(error.message, "Failed to resolve handle test.handle to DID and PDS"); assertEquals(error.name, "HandleResolutionError"); assertEquals(error.cause, undefined); });
await t.step("should create error with cause", () => { const cause = new Error("Network error"); const error = new HandleResolutionError("test.handle", cause); assertEquals(error.message, "Failed to resolve handle test.handle to DID and PDS"); assertEquals(error.name, "HandleResolutionError"); assertEquals(error.cause, cause); });
await t.step("should be instance of OAuthError", () => { const error = new HandleResolutionError("test.handle"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, HandleResolutionError); });});
Deno.test("PDSDiscoveryError", async (t) => { await t.step("should create error with PDS URL in message", () => { const error = new PDSDiscoveryError("https://example.com"); assertEquals(error.message, "Failed to discover OAuth endpoints for PDS: https://example.com"); assertEquals(error.name, "PDSDiscoveryError"); assertEquals(error.cause, undefined); });
await t.step("should create error with cause", () => { const cause = new Error("Discovery failed"); const error = new PDSDiscoveryError("https://example.com", cause); assertEquals(error.message, "Failed to discover OAuth endpoints for PDS: https://example.com"); assertEquals(error.name, "PDSDiscoveryError"); assertEquals(error.cause, cause); });
await t.step("should be instance of OAuthError", () => { const error = new PDSDiscoveryError("https://example.com"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, PDSDiscoveryError); });});
Deno.test("TokenExchangeError", async (t) => { await t.step("should create error with message", () => { const error = new TokenExchangeError("Invalid grant"); assertEquals(error.message, "Token exchange failed: Invalid grant"); assertEquals(error.name, "TokenExchangeError"); assertEquals(error.errorCode, undefined); assertEquals(error.cause, undefined); });
await t.step("should create error with error code", () => { const error = new TokenExchangeError("Invalid grant", "invalid_grant"); assertEquals(error.message, "Token exchange failed: Invalid grant"); assertEquals(error.name, "TokenExchangeError"); assertEquals(error.errorCode, "invalid_grant"); assertEquals(error.cause, undefined); });
await t.step("should create error with error code and cause", () => { const cause = new Error("HTTP 400"); const error = new TokenExchangeError("Invalid grant", "invalid_grant", cause); assertEquals(error.message, "Token exchange failed: Invalid grant"); assertEquals(error.name, "TokenExchangeError"); assertEquals(error.errorCode, "invalid_grant"); assertEquals(error.cause, cause); });
await t.step("should be instance of OAuthError", () => { const error = new TokenExchangeError("Invalid grant"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, TokenExchangeError); });});
Deno.test("DPoPError", async (t) => { await t.step("should create error with message", () => { const error = new DPoPError("Key generation failed"); assertEquals(error.message, "DPoP operation failed: Key generation failed"); assertEquals(error.name, "DPoPError"); assertEquals(error.cause, undefined); });
await t.step("should create error with cause", () => { const cause = new Error("Crypto error"); const error = new DPoPError("Key generation failed", cause); assertEquals(error.message, "DPoP operation failed: Key generation failed"); assertEquals(error.name, "DPoPError"); assertEquals(error.cause, cause); });
await t.step("should be instance of OAuthError", () => { const error = new DPoPError("Key generation failed"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, DPoPError); });});
Deno.test("SessionError", async (t) => { await t.step("should create error with message", () => { const error = new SessionError("Invalid session data"); assertEquals(error.message, "Session error: Invalid session data"); assertEquals(error.name, "SessionError"); assertEquals(error.cause, undefined); });
await t.step("should create error with cause", () => { const cause = new Error("Serialization failed"); const error = new SessionError("Invalid session data", cause); assertEquals(error.message, "Session error: Invalid session data"); assertEquals(error.name, "SessionError"); assertEquals(error.cause, cause); });
await t.step("should be instance of OAuthError", () => { const error = new SessionError("Invalid session data"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, SessionError); });});
Deno.test("InvalidStateError", async (t) => { await t.step("should create error with fixed message", () => { const error = new InvalidStateError(); assertEquals(error.message, "Invalid or expired OAuth state parameter"); assertEquals(error.name, "InvalidStateError"); assertEquals(error.cause, undefined); });
await t.step("should be instance of OAuthError", () => { const error = new InvalidStateError(); assertInstanceOf(error, OAuthError); assertInstanceOf(error, InvalidStateError); });});
Deno.test("AuthorizationError", async (t) => { await t.step("should create error with error code only", () => { const error = new AuthorizationError("access_denied"); assertEquals(error.message, "Authorization failed: access_denied"); assertEquals(error.name, "AuthorizationError"); });
await t.step("should create error with error code and description", () => { const error = new AuthorizationError("access_denied", "User denied the request"); assertEquals(error.message, "Authorization failed: access_denied - User denied the request"); assertEquals(error.name, "AuthorizationError"); });
await t.step("should be instance of OAuthError", () => { const error = new AuthorizationError("access_denied"); assertInstanceOf(error, OAuthError); assertInstanceOf(error, AuthorizationError); });});
// New error types
Deno.test("MetadataValidationError", async (t) => { await t.step("should create error with message", () => { const error = new MetadataValidationError("missing issuer field"); assertEquals(error.name, "MetadataValidationError"); assert(error.message.includes("missing issuer field")); assertInstanceOf(error, OAuthError); });
await t.step("should chain cause", () => { const cause = new Error("parse error"); const error = new MetadataValidationError("invalid metadata", cause); assertEquals(error.cause, cause); });});
Deno.test("IssuerMismatchError", async (t) => { await t.step("should include expected and actual issuers", () => { const error = new IssuerMismatchError("https://expected.com", "https://actual.com"); assertEquals(error.name, "IssuerMismatchError"); assertEquals(error.expected, "https://expected.com"); assertEquals(error.actual, "https://actual.com"); assert(error.message.includes("https://expected.com")); assert(error.message.includes("https://actual.com")); assertInstanceOf(error, OAuthError); });});
Deno.test("TokenValidationError", async (t) => { await t.step("should create error with message", () => { const error = new TokenValidationError("missing sub claim"); assertEquals(error.name, "TokenValidationError"); assert(error.message.includes("missing sub claim")); assertInstanceOf(error, TokenExchangeError); assertInstanceOf(error, OAuthError); });});