opinionated-machine
Version:
Very opinionated DI framework for fastify, built on top of awilix
79 lines • 3.04 kB
JavaScript
import { AbstractSSEController } from "../sse/AbstractSSEController.js";
/**
* Abstract base class for dual-mode controllers.
*
* Dual-mode controllers handle both SSE streaming and sync responses on the
* same route path, automatically branching based on the `Accept` header.
*
* This class extends `AbstractSSEController` to reuse connection management,
* broadcasting, and lifecycle hooks for the SSE mode.
*
* @template APIContracts - Map of route names to dual-mode route definitions
*
* @example
* ```typescript
* class ChatController extends AbstractDualModeController<typeof contracts> {
* public static contracts = {
* chatCompletion: buildSseContract({ requestBodySchema: ..., successResponseBodySchema: ..., ... }),
* } as const
*
* constructor(deps: Dependencies, config?: DualModeControllerConfig) {
* super(deps, config)
* }
*
* public buildDualModeRoutes() {
* return {
* chatCompletion: this.handleChatCompletion,
* }
* }
*
* private handleChatCompletion = buildHandler(ChatController.contracts.chatCompletion, {
* sync: async (request, reply) => {
* // Return complete response
* return { reply: 'Hello', usage: { tokens: 5 } }
* },
* sse: async (request, sse) => {
* // Stream SSE events with autoClose mode
* const session = sse.start('autoClose')
* await session.send('chunk', { delta: 'Hello' })
* await session.send('done', { usage: { total: 5 } })
* // Connection closes automatically when handler returns
* },
* })
* }
* ```
*/
export class AbstractDualModeController extends AbstractSSEController {
/**
* Dual-mode controllers must override this constructor and call super with their
* dependencies object and the dual-mode config.
*
* @param _dependencies - The dependencies object (cradle proxy in awilix)
* @param config - Optional dual-mode controller configuration
*/
constructor(_dependencies, config) {
// Pass config to AbstractSSEController (it accepts SSEControllerConfig which has the same shape)
super(_dependencies, config);
}
/**
* SSE routes are not used directly - dual-mode uses buildDualModeRoutes() instead.
* This returns an empty object to satisfy the AbstractSSEController contract.
*/
buildSSERoutes() {
return {};
}
/**
* Send an event to a connection with type-safe event names and data.
*
* This method provides autocomplete and type checking for event names and data
* that match any event defined in the controller's dual-mode contracts.
*
* @param connectionId - The connection to send to
* @param message - The event message with typed event name and data
* @returns true if sent successfully, false if connection not found
*/
sendDualModeEventInternal(connectionId, message) {
return this._sendEventRaw(connectionId, message);
}
}
//# sourceMappingURL=AbstractDualModeController.js.map