Added a lightweight, zero-dependency event bus to the `AuthSdk` to listen for Valkey RESP3 push invalidation events and emit them to registered listeners. The implementation properly captures errors from synchronous and asynchronous listeners, ensuring they do not crash the primary SDK listener loop. Extracted the Valkey event processor to improve hermetic testability. Co-authored-by: mrteye <1945243+mrteye@users.noreply.github.com>
89 lines
2.5 KiB
TypeScript
89 lines
2.5 KiB
TypeScript
import { assertEquals } from "jsr:@std/assert";
|
|
import { createAuthSdk } from "./mod.ts";
|
|
|
|
Deno.test("AuthSdk - initializes with config", () => {
|
|
const sdk = createAuthSdk({
|
|
authApiUrl: "http://localhost:8000",
|
|
timeoutMs: 3000,
|
|
});
|
|
assertEquals(typeof sdk.validateSession, "function");
|
|
assertEquals(typeof sdk.requireAuth, "function");
|
|
});
|
|
|
|
Deno.test("AuthSdk - Event Bus: registers, receives, and unregisters events", () => {
|
|
const sdk = createAuthSdk({
|
|
authApiUrl: "http://localhost:8000",
|
|
timeoutMs: 3000,
|
|
});
|
|
|
|
const receivedTokens: string[] = [];
|
|
const handler = (token: string) => {
|
|
receivedTokens.push(token);
|
|
};
|
|
|
|
sdk.on("invalidate", handler);
|
|
|
|
// Simulate Valkey push event
|
|
(sdk as any)._handleValkeyPush(["invalidate", ["token1", "token2"]]);
|
|
|
|
assertEquals(receivedTokens, ["token1", "token2"]);
|
|
|
|
sdk.off("invalidate", handler);
|
|
|
|
// Simulate another push event
|
|
(sdk as any)._handleValkeyPush(["invalidate", ["token3"]]);
|
|
|
|
// The tokens should not be added because handler was unregistered
|
|
assertEquals(receivedTokens, ["token1", "token2"]);
|
|
});
|
|
|
|
Deno.test("AuthSdk - Event Bus: failing async handlers do not crash bus", async () => {
|
|
const sdk = createAuthSdk({
|
|
authApiUrl: "http://localhost:8000",
|
|
timeoutMs: 3000,
|
|
});
|
|
|
|
const receivedTokens: string[] = [];
|
|
|
|
const failingHandlerAsync = async (token: string) => {
|
|
throw new Error(`Simulated async failure for ${token}`);
|
|
};
|
|
|
|
const failingHandlerSync = (token: string) => {
|
|
throw new Error(`Simulated sync failure for ${token}`);
|
|
};
|
|
|
|
const successHandler = (token: string) => {
|
|
receivedTokens.push(token);
|
|
};
|
|
|
|
sdk.on("invalidate", failingHandlerAsync);
|
|
sdk.on("invalidate", failingHandlerSync);
|
|
sdk.on("invalidate", successHandler);
|
|
|
|
// Stub console.error to avoid test noise
|
|
const originalConsoleError = console.error;
|
|
let loggedErrors = 0;
|
|
console.error = (...args: any[]) => {
|
|
const msg = args.join(" ");
|
|
if (msg.includes("Error in 'invalidate' listener")) {
|
|
loggedErrors++;
|
|
}
|
|
};
|
|
|
|
try {
|
|
(sdk as any)._handleValkeyPush(["invalidate", ["token4"]]);
|
|
|
|
// Give microtasks a chance to process the async rejection
|
|
await new Promise((resolve) => setTimeout(resolve, 0));
|
|
|
|
// The successful handler should have run despite the failures
|
|
assertEquals(receivedTokens, ["token4"]);
|
|
|
|
// Both the sync and async errors should have been caught and logged
|
|
assertEquals(loggedErrors, 2);
|
|
} finally {
|
|
console.error = originalConsoleError;
|
|
}
|
|
});
|