UNPKG

@nestjs/common

Version:

Nest - modern, fast, powerful node.js web framework (@common)

56 lines (55 loc) 2.35 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.SseSignal = exports.SSE_ABORT_CONTROLLER = void 0; const create_route_param_metadata_decorator_1 = require("./create-route-param-metadata.decorator"); /** * Symbol used to carry the per-request SSE `AbortController` on the request object. * * The controller is attached by the framework before the route handler runs and is * aborted when the client disconnects. Its signal is exposed to route handlers * through the `@SseSignal()` parameter decorator. * * @publicApi */ exports.SSE_ABORT_CONTROLLER = Symbol('SSE_ABORT_CONTROLLER'); /** * Route handler parameter decorator that injects the `AbortSignal` associated * with a Server-Sent-Events (SSE) request. * * The signal represents the lifetime of the SSE response: it is aborted once the * stream terminates, whether because the client disconnected, the `Observable` * completed, or it errored. Tying setup-phase resources to the signal therefore * releases them exactly once on every exit path, including resources allocated * before the returned `Observable` exists — which would otherwise leak, since the * producer is never subscribed once the client has disconnected. * * Because the signal also aborts on normal completion, `signal.aborted` is only * meaningful as a "did the client go away?" check *during setup*, before the * `Observable` is returned; at that point the stream cannot have completed yet. * Cleanup wired to the `abort` event should be idempotent, as it may run * alongside the `Observable`'s own teardown. * * @example * ```ts * @Sse('stream') * async stream(@SseSignal() signal: AbortSignal): Promise<Observable<MessageEvent>> { * const session = await createSession(); * if (signal.aborted) { * await session.close(); * return EMPTY; * } * return new Observable(subscriber => { * const stream = startGeneration(session); * signal.addEventListener('abort', () => stream.stop(), { once: true }); * return () => stream.stop(); * }); * } * ``` * * @publicApi */ exports.SseSignal = (0, create_route_param_metadata_decorator_1.createParamDecorator)((_data, ctx) => { const request = ctx.switchToHttp().getRequest(); const controller = request?.[exports.SSE_ABORT_CONTROLLER]; return controller?.signal; });