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>
4.1 KiB
4.1 KiB
TASK METADATA
- Target Files:
sdk/mod.ts,sdk/mod.test.ts - Core Objective: Extend
@auth-yes/sdkwith a zero-dependency real-time event bus to listen for Valkey 8 RESP3 push invalidation events and emit them to registered listeners. - Dependencies: None.
- Additional Important Notes: Handlers must support async execution. Errors thrown by handlers must be caught and logged so they do not crash the Valkey push listener or stop other registered handlers. No external EventEmitter libraries are allowed.
Architectural Considerations & Risks
Risks
- Memory Leaks: Downstream consumers registering listeners for
"invalidate"without subsequently callingoffcould result in an unbounded map of listeners. We must clearly document theoffmethod and emphasize its usage during cleanup (e.g., when a consumer class is destroyed or a connection pool closes). - Callback Crash Propagation: If a downstream consumer's callback throws an
exception (e.g., failing to terminate a WebSocket), and it is not caught, it
could crash the internal Valkey
pushevent handler. The implementation must guarantee isolated execution via atry/catchwrapper and gracefully handle Promise rejections. - Payload Alignment: Any discrepancy between the raw key emitted by Valkey
and the expected token by downstream listeners could result in missed
invalidations. As confirmed, Valkey stores and emits the raw
tokenwithout prefixes, so we must emit the token strictly as received.
Alternatives
- Using the web standard
EventTargetnatively supported in Deno. While native, standardEventTargetlimits the payload to customEventobjects (CustomEvent), which adds boilerplate (event.detail.token) and type-casting complexity for downstream users. A custom lightweight callback Set (Set<InvalidationHandler>) allows us to pass thetoken: stringpayload directly and cleanly. - Using an external EventEmitter package. This was rejected per the zero-dependency directive.
Proposed Implementation
1. Define the Handler Type
In sdk/mod.ts, define the TypeScript type for the invalidation handler:
export type InvalidationHandler = (token: string) => void | Promise<void>;
2. Implement the Internal Event Bus
In the AuthSdk class (sdk/mod.ts):
- Add a private property to store listeners:
private listeners: Map<string, Set<InvalidationHandler>> = new Map(); - Implement the
onmethod:/** * Registers a callback to be invoked when a specific event occurs. * Currently, only the "invalidate" event is supported. * * @param event The event name (e.g., "invalidate"). * @param handler The callback function. */ on(event: "invalidate", handler: InvalidationHandler): void; - Implement the
offmethod:/** * Unregisters a previously registered callback. * * @param event The event name (e.g., "invalidate"). * @param handler The callback function to remove. */ off(event: "invalidate", handler: InvalidationHandler): void;
3. Integrate with Valkey push Events
In the initValkeyClient method of AuthSdk (sdk/mod.ts):
- Locate the existing
"push"event listener for the Valkey client. - Inside the loop that iterates over
keysToInvalidate(which represents the raw tokens), add the emission logic. - Retrieve the
Setof listeners for the"invalidate"event. - Iterate over the handlers and invoke them safely using a
try/catchblock andPromise.resolve(...).catch(...)to prevent any single failing handler from impacting the others or crashing the SDK.
4. Write Unit Tests
In sdk/mod.test.ts:
- Write tests to verify that
onandoffcorrectly add and remove handlers. - Simulate the Valkey
"push"event (e.g., by creating an instance with a mockedvalkeyClientor directly testing an internal emit method, or sending mock payloads if the Valkey client is mocked). - Verify that registered listeners are invoked with the correct token.
- Verify that a throwing or rejecting handler does not disrupt the execution of subsequent handlers.