@leaven-graphql/nestjs 0.1.0 → 0.2.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +1 -1
- package/README.md +408 -23
- package/dist/decorators.d.ts +92 -3
- package/dist/decorators.d.ts.map +1 -1
- package/dist/driver.d.ts +107 -8
- package/dist/driver.d.ts.map +1 -1
- package/dist/execution-context.d.ts +46 -2
- package/dist/execution-context.d.ts.map +1 -1
- package/dist/graphql-driver.d.ts +180 -0
- package/dist/graphql-driver.d.ts.map +1 -0
- package/dist/guards.d.ts +57 -11
- package/dist/guards.d.ts.map +1 -1
- package/dist/index.d.ts +10 -5
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +1577 -792
- package/dist/interceptors.d.ts +41 -5
- package/dist/interceptors.d.ts.map +1 -1
- package/dist/middleware.d.ts +100 -4
- package/dist/middleware.d.ts.map +1 -1
- package/dist/module.d.ts +77 -12
- package/dist/module.d.ts.map +1 -1
- package/dist/schema-builder.d.ts +39 -10
- package/dist/schema-builder.d.ts.map +1 -1
- package/dist/subscriptions.d.ts +346 -22
- package/dist/subscriptions.d.ts.map +1 -1
- package/dist/types.d.ts +188 -18
- package/dist/types.d.ts.map +1 -1
- package/package.json +19 -12
package/dist/subscriptions.d.ts
CHANGED
|
@@ -1,20 +1,77 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* @leaven-graphql/nestjs - Subscriptions Support
|
|
3
3
|
*
|
|
4
|
-
* Provides
|
|
4
|
+
* Provides graphql-ws protocol handling over WebSocket for NestJS.
|
|
5
5
|
*
|
|
6
|
-
*
|
|
6
|
+
* Single-result operations (queries and mutations) are answered with one
|
|
7
|
+
* `next` message followed by `complete`. Streaming `subscription` operations
|
|
8
|
+
* are executed through the Leaven executor and each event is forwarded as a
|
|
9
|
+
* `next` message until the stream ends, the client sends `complete`, or the
|
|
10
|
+
* connection closes. Topic-keyed delivery driven by an external pub/sub
|
|
11
|
+
* engine is available via `SubscriptionManager.registerSubscription` and
|
|
12
|
+
* `SubscriptionManager.publishToTopic`.
|
|
13
|
+
*
|
|
14
|
+
* TRANSPORT: this module speaks the protocol, it does NOT own a server. Two
|
|
15
|
+
* equivalent entry points are provided, one per socket shape:
|
|
16
|
+
*
|
|
17
|
+
* - A DOM-shaped `WebSocket` (`addEventListener`) — hand it to
|
|
18
|
+
* `SubscriptionManager.handleConnection` and the manager wires its own
|
|
19
|
+
* listeners.
|
|
20
|
+
* - A Bun `ServerWebSocket` (no `addEventListener`; the server invokes
|
|
21
|
+
* `open`/`message`/`close` handlers) — use `handleOpen`, `handleMessage`
|
|
22
|
+
* and `handleClose`, or pass `getWebSocketConfig()` straight into
|
|
23
|
+
* `Bun.serve({ websocket })`.
|
|
24
|
+
*
|
|
25
|
+
* Nothing here calls `server.upgrade()`: the HTTP route that upgrades a
|
|
26
|
+
* request to a WebSocket belongs to whoever owns the server.
|
|
27
|
+
* `SubscriptionManager.getPath()` exposes the configured
|
|
28
|
+
* `subscriptions.path` so that route can be registered in the right place.
|
|
29
|
+
*
|
|
30
|
+
* Copyright 2026 Joseph Quinn
|
|
7
31
|
* Licensed under the Apache License, Version 2.0
|
|
8
32
|
*/
|
|
9
33
|
import { type OnModuleInit, type OnModuleDestroy } from '@nestjs/common';
|
|
34
|
+
import type { ServerWebSocket } from 'bun';
|
|
10
35
|
import { LeavenDriver } from './driver';
|
|
11
|
-
import type
|
|
36
|
+
import { type LeavenModuleOptions, type GqlContext } from './types';
|
|
37
|
+
/**
|
|
38
|
+
* The minimal socket surface this manager depends on.
|
|
39
|
+
*
|
|
40
|
+
* Deliberately structural rather than `WebSocket` or `ServerWebSocket`: both
|
|
41
|
+
* satisfy it, so protocol handling has ONE implementation regardless of which
|
|
42
|
+
* transport delivered the frame. The DOM-only `addEventListener` is
|
|
43
|
+
* conspicuously absent — it is used exactly once, in
|
|
44
|
+
* {@link SubscriptionManager.handleConnection}, which is the only entry point
|
|
45
|
+
* that requires a DOM socket.
|
|
46
|
+
*/
|
|
47
|
+
export interface SubscriptionSocket {
|
|
48
|
+
/** `1` while the socket may be written to. */
|
|
49
|
+
readonly readyState: number;
|
|
50
|
+
/** Bun returns a byte count here, the DOM returns `void`; neither is used. */
|
|
51
|
+
send(data: string): unknown;
|
|
52
|
+
close(code?: number, reason?: string): void;
|
|
53
|
+
}
|
|
54
|
+
/**
|
|
55
|
+
* Bun WebSocket handlers, shaped for `Bun.serve({ websocket })`.
|
|
56
|
+
*
|
|
57
|
+
* @see SubscriptionManager.getWebSocketConfig
|
|
58
|
+
*/
|
|
59
|
+
export interface BunWebSocketConfig<TData = unknown> {
|
|
60
|
+
open: (socket: ServerWebSocket<TData>) => void;
|
|
61
|
+
message: (socket: ServerWebSocket<TData>, message: string | Buffer) => void;
|
|
62
|
+
close: (socket: ServerWebSocket<TData>) => void;
|
|
63
|
+
}
|
|
12
64
|
/**
|
|
13
65
|
* Subscription configuration
|
|
14
66
|
*/
|
|
15
67
|
export interface SubscriptionConfig {
|
|
16
68
|
/**
|
|
17
|
-
* WebSocket path for subscriptions
|
|
69
|
+
* WebSocket path for subscriptions.
|
|
70
|
+
*
|
|
71
|
+
* The manager does not own an HTTP server and therefore cannot bind this
|
|
72
|
+
* itself; it is surfaced by {@link SubscriptionManager.getPath} so the code
|
|
73
|
+
* that does own the server can register the upgrade route there.
|
|
74
|
+
*
|
|
18
75
|
* @default '/graphql'
|
|
19
76
|
*/
|
|
20
77
|
path?: string;
|
|
@@ -50,7 +107,8 @@ export interface SubscriptionConfig {
|
|
|
50
107
|
*/
|
|
51
108
|
onSubscribe?: (ctx: SubscriptionContext, message: SubscribeMessage) => void | Promise<void>;
|
|
52
109
|
/**
|
|
53
|
-
* Operation callback - called
|
|
110
|
+
* Operation callback - called before each operation is executed.
|
|
111
|
+
* May return modified execution args (e.g. to swap the context value).
|
|
54
112
|
*/
|
|
55
113
|
onOperation?: (ctx: SubscriptionContext, message: SubscribeMessage, args: ExecutionArgs) => ExecutionArgs | Promise<ExecutionArgs>;
|
|
56
114
|
/**
|
|
@@ -63,9 +121,14 @@ export interface SubscriptionConfig {
|
|
|
63
121
|
*/
|
|
64
122
|
export interface SubscriptionContext {
|
|
65
123
|
/**
|
|
66
|
-
* The WebSocket connection
|
|
124
|
+
* The WebSocket connection.
|
|
125
|
+
*
|
|
126
|
+
* Typed as the transport-neutral {@link SubscriptionSocket} because the
|
|
127
|
+
* connection may be either a DOM `WebSocket` or a Bun `ServerWebSocket`;
|
|
128
|
+
* narrow with an instance/duck check before touching members outside that
|
|
129
|
+
* surface.
|
|
67
130
|
*/
|
|
68
|
-
socket:
|
|
131
|
+
socket: SubscriptionSocket;
|
|
69
132
|
/**
|
|
70
133
|
* Connection parameters from client
|
|
71
134
|
*/
|
|
@@ -113,7 +176,25 @@ export interface ExecutionArgs {
|
|
|
113
176
|
/**
|
|
114
177
|
* Subscription manager
|
|
115
178
|
*
|
|
116
|
-
* Manages WebSocket connections
|
|
179
|
+
* Manages WebSocket connections speaking the graphql-ws protocol.
|
|
180
|
+
*
|
|
181
|
+
* Single-result operations (queries and mutations) receive one `next`
|
|
182
|
+
* message followed by `complete`. Streaming `subscription` operations are
|
|
183
|
+
* executed through the driver and each event is forwarded as a `next`
|
|
184
|
+
* message; the stream is cancelled when the client sends `complete` or the
|
|
185
|
+
* connection closes. Server-side, topic-keyed delivery driven by an external
|
|
186
|
+
* pub/sub engine is available via {@link registerSubscription} and
|
|
187
|
+
* {@link publishToTopic}.
|
|
188
|
+
*
|
|
189
|
+
* Configuration is read from `LeavenModuleOptions.subscriptions` and merged
|
|
190
|
+
* over built-in defaults.
|
|
191
|
+
*
|
|
192
|
+
* The manager is transport-agnostic and does NOT bind a server. Feed it a
|
|
193
|
+
* DOM `WebSocket` via {@link handleConnection}, or a Bun `ServerWebSocket`
|
|
194
|
+
* via {@link handleOpen}/{@link handleMessage}/{@link handleClose} —
|
|
195
|
+
* {@link getWebSocketConfig} packages the latter trio for
|
|
196
|
+
* `Bun.serve({ websocket })`. The upgrade route itself is the caller's
|
|
197
|
+
* responsibility; {@link getPath} reports where it should live.
|
|
117
198
|
*/
|
|
118
199
|
export declare class SubscriptionManager implements OnModuleInit, OnModuleDestroy {
|
|
119
200
|
private readonly options;
|
|
@@ -126,37 +207,196 @@ export declare class SubscriptionManager implements OnModuleInit, OnModuleDestro
|
|
|
126
207
|
*/
|
|
127
208
|
onModuleInit(): Promise<void>;
|
|
128
209
|
/**
|
|
129
|
-
*
|
|
210
|
+
* Tear every connection down, then close it.
|
|
211
|
+
*
|
|
212
|
+
* Teardown is driven EXPLICITLY here rather than being left to the sockets'
|
|
213
|
+
* own `close` events. A real close is asynchronous: the listener installed
|
|
214
|
+
* by {@link handleConnection} — or Bun's `close` handler — runs a tick or
|
|
215
|
+
* more after `socket.close()` returns, which is long after this method has
|
|
216
|
+
* finished. Relying on it meant `handleClose` found no entry in the map and
|
|
217
|
+
* bailed on its first line, so on every shutdown the keep-alive interval
|
|
218
|
+
* and the `connection_init` timeout were never cleared and no subscription
|
|
219
|
+
* iterator was released: every in-flight resolver generator stayed
|
|
220
|
+
* suspended holding whatever it held. The late close event still fires and
|
|
221
|
+
* is still a no-op — but now because the work is already done.
|
|
130
222
|
*/
|
|
131
223
|
onModuleDestroy(): Promise<void>;
|
|
132
224
|
/**
|
|
133
|
-
* Normalize subscription configuration
|
|
225
|
+
* Normalize subscription configuration.
|
|
226
|
+
*
|
|
227
|
+
* Merges the user-supplied `LeavenModuleOptions.subscriptions` config
|
|
228
|
+
* (including the `context`, `onConnect`, `onDisconnect`, `onSubscribe`,
|
|
229
|
+
* `onOperation` and `onComplete` hooks) over built-in defaults.
|
|
134
230
|
*/
|
|
135
231
|
private normalizeConfig;
|
|
136
232
|
/**
|
|
137
|
-
*
|
|
233
|
+
* The GraphQL-over-WebSocket path this manager is configured for.
|
|
234
|
+
*
|
|
235
|
+
* The manager owns no HTTP server, so it CANNOT bind this itself. Whoever
|
|
236
|
+
* owns the server is responsible for upgrading requests at this path and
|
|
237
|
+
* routing the resulting socket into {@link handleOpen} /
|
|
238
|
+
* {@link handleMessage} / {@link handleClose} — see
|
|
239
|
+
* {@link getWebSocketConfig} for the Bun form. Without that step the
|
|
240
|
+
* configured `subscriptions.path` is inert and no client can ever connect.
|
|
241
|
+
*
|
|
242
|
+
* @returns The configured `subscriptions.path`, falling back to the
|
|
243
|
+
* module's `path`, then `/graphql`
|
|
244
|
+
*/
|
|
245
|
+
getPath(): string;
|
|
246
|
+
/**
|
|
247
|
+
* Bun WebSocket handlers for `Bun.serve({ websocket })`.
|
|
248
|
+
*
|
|
249
|
+
* Mirrors `@leaven-graphql/ws`'s `WebSocketHandler.getWebSocketConfig` so
|
|
250
|
+
* both packages plug into a Bun server the same way.
|
|
251
|
+
*
|
|
252
|
+
* The returned handlers cover the socket lifecycle ONLY. The upgrade itself
|
|
253
|
+
* is not — and cannot be — done here: `server.upgrade(request)` needs the
|
|
254
|
+
* `Server` instance, which this manager never sees. Route it yourself at
|
|
255
|
+
* {@link getPath}.
|
|
256
|
+
*
|
|
257
|
+
* @example
|
|
258
|
+
* ```typescript
|
|
259
|
+
* const manager = app.get(SubscriptionManager);
|
|
260
|
+
*
|
|
261
|
+
* Bun.serve({
|
|
262
|
+
* fetch(request, server) {
|
|
263
|
+
* if (new URL(request.url).pathname === manager.getPath()) {
|
|
264
|
+
* // The manager does NOT call this for you.
|
|
265
|
+
* if (server.upgrade(request)) return undefined;
|
|
266
|
+
* }
|
|
267
|
+
* return new Response('Not found', { status: 404 });
|
|
268
|
+
* },
|
|
269
|
+
* websocket: manager.getWebSocketConfig(),
|
|
270
|
+
* });
|
|
271
|
+
* ```
|
|
272
|
+
*/
|
|
273
|
+
getWebSocketConfig<TData = unknown>(): BunWebSocketConfig<TData>;
|
|
274
|
+
/**
|
|
275
|
+
* Register a Bun `ServerWebSocket` (or any {@link SubscriptionSocket}) that
|
|
276
|
+
* the server has just opened.
|
|
277
|
+
*
|
|
278
|
+
* The Bun counterpart of {@link handleConnection}: a `ServerWebSocket` has
|
|
279
|
+
* no `addEventListener`, so the server delivers frames by calling
|
|
280
|
+
* {@link handleMessage} and {@link handleClose} instead of the manager
|
|
281
|
+
* subscribing to events. Connections are keyed by socket identity, so
|
|
282
|
+
* nothing is written to `socket.data` and any per-connection data the
|
|
283
|
+
* caller keeps there is left untouched.
|
|
284
|
+
*
|
|
285
|
+
* @param socket - The freshly opened socket
|
|
286
|
+
* @param request - The upgrade request, exposed to the `context` and
|
|
287
|
+
* `onConnect` hooks
|
|
288
|
+
*/
|
|
289
|
+
handleOpen(socket: SubscriptionSocket, request?: Request): void;
|
|
290
|
+
/**
|
|
291
|
+
* Handle a new DOM-shaped `WebSocket` connection.
|
|
292
|
+
*
|
|
293
|
+
* Use this when the socket dispatches events (`addEventListener`) — the
|
|
294
|
+
* manager wires `message`/`close`/`error` itself. Bun's server-side socket
|
|
295
|
+
* does NOT: use {@link handleOpen} and friends for that shape.
|
|
138
296
|
*/
|
|
139
297
|
handleConnection(socket: WebSocket, request?: Request): Promise<void>;
|
|
140
298
|
/**
|
|
141
|
-
*
|
|
299
|
+
* Register a connection and arm its `connection_init` deadline.
|
|
300
|
+
*
|
|
301
|
+
* Shared by both transports so protocol state is created identically no
|
|
302
|
+
* matter which entry point the socket arrived through; only the event
|
|
303
|
+
* wiring differs.
|
|
142
304
|
*/
|
|
143
|
-
private
|
|
305
|
+
private openConnection;
|
|
306
|
+
/**
|
|
307
|
+
* Handle an incoming WebSocket frame.
|
|
308
|
+
*
|
|
309
|
+
* Public so a Bun server can deliver frames directly (a `ServerWebSocket`
|
|
310
|
+
* has no events to listen to); {@link handleConnection} routes DOM `message`
|
|
311
|
+
* events here too, so both transports share this one implementation.
|
|
312
|
+
*
|
|
313
|
+
* Per the graphql-ws protocol, an unparseable message or an unrecognized
|
|
314
|
+
* message type closes the connection with 4400 (Bad Request). Errors thrown
|
|
315
|
+
* while handling a `subscribe`/`complete` message are contained to that
|
|
316
|
+
* operation id (a graphql-ws `error` message) so a single failing operation
|
|
317
|
+
* does not tear down the whole connection.
|
|
318
|
+
*
|
|
319
|
+
* @param socket - A socket previously passed to {@link handleOpen} or
|
|
320
|
+
* {@link handleConnection}; frames for an unknown socket are ignored
|
|
321
|
+
* @param data - The frame payload. Binary frames are decoded as UTF-8:
|
|
322
|
+
* graphql-ws is a JSON sub-protocol, and Bun hands binary frames over as
|
|
323
|
+
* a `Buffer`
|
|
324
|
+
*/
|
|
325
|
+
handleMessage(socket: SubscriptionSocket, data: string | Uint8Array | ArrayBuffer): Promise<void>;
|
|
144
326
|
/**
|
|
145
327
|
* Handle connection initialization
|
|
146
328
|
*/
|
|
147
329
|
private handleConnectionInit;
|
|
148
330
|
/**
|
|
149
|
-
* Handle subscribe message
|
|
331
|
+
* Handle subscribe message.
|
|
332
|
+
*
|
|
333
|
+
* Single-result operations (queries and mutations) are answered with a
|
|
334
|
+
* `next` message followed by `complete`. Streaming `subscription`
|
|
335
|
+
* operations are handed to {@link startStream}, which forwards each event
|
|
336
|
+
* as it arrives.
|
|
150
337
|
*/
|
|
151
338
|
private handleSubscribe;
|
|
339
|
+
/**
|
|
340
|
+
* Subscribe to a streaming operation and pump its events to the client.
|
|
341
|
+
*
|
|
342
|
+
* The subscription is registered before the first event is awaited so that
|
|
343
|
+
* a `complete` from the client, or a connection close, can cancel a stream
|
|
344
|
+
* that has not yet produced anything. Cancellation works by calling
|
|
345
|
+
* `return()` on the iterator, which resumes the resolver's generator at its
|
|
346
|
+
* suspension point and runs its cleanup.
|
|
347
|
+
*/
|
|
348
|
+
private startStream;
|
|
349
|
+
/**
|
|
350
|
+
* Forward every event from a subscription iterator to the client, then
|
|
351
|
+
* send `complete`.
|
|
352
|
+
*
|
|
353
|
+
* Runs detached from the message handler so a long-lived stream never
|
|
354
|
+
* blocks other messages on the same connection.
|
|
355
|
+
*/
|
|
356
|
+
private pumpStream;
|
|
357
|
+
/**
|
|
358
|
+
* Cancel a subscription iterator, waiting at most
|
|
359
|
+
* {@link ITERATOR_TEARDOWN_TIMEOUT_MS} for it to finish.
|
|
360
|
+
*
|
|
361
|
+
* Teardown errors are logged and swallowed: rethrowing would mask the
|
|
362
|
+
* reason the stream was cancelled, but silence would hide a resolver whose
|
|
363
|
+
* `finally` fails to release a pooled connection or unsubscribe.
|
|
364
|
+
*
|
|
365
|
+
* The deadline exists because `return()` on an async generator suspended at
|
|
366
|
+
* an `await` is queued behind that await, so a resolver waiting on an event
|
|
367
|
+
* that never arrives never resumes and its `return()` never settles. Every
|
|
368
|
+
* caller here awaits this method — `handleComplete` from the message loop,
|
|
369
|
+
* `handleClose` on disconnect, `onModuleDestroy` on shutdown — so an
|
|
370
|
+
* unbounded wait turns one stuck generator into a stuck connection, or a
|
|
371
|
+
* process that will not exit.
|
|
372
|
+
*/
|
|
373
|
+
private closeIterator;
|
|
374
|
+
/**
|
|
375
|
+
* Determine whether a query string is a streaming `subscription` operation.
|
|
376
|
+
*
|
|
377
|
+
* Parse failures return `false` so that syntax errors surface through the
|
|
378
|
+
* normal execution/error path instead of being masked here.
|
|
379
|
+
*/
|
|
380
|
+
private isSubscriptionOperation;
|
|
152
381
|
/**
|
|
153
382
|
* Handle complete message
|
|
154
383
|
*/
|
|
155
384
|
private handleComplete;
|
|
156
385
|
/**
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
386
|
+
* Handle WebSocket close.
|
|
387
|
+
*
|
|
388
|
+
* Public so a Bun server can report the close directly (a `ServerWebSocket`
|
|
389
|
+
* dispatches no `close` event); {@link handleConnection} routes the DOM
|
|
390
|
+
* `close` event here, and {@link onModuleDestroy} calls it explicitly.
|
|
391
|
+
* Idempotent: a socket already torn down is ignored.
|
|
392
|
+
*
|
|
393
|
+
* Teardown runs FIRST and the user's `onDisconnect` hook runs LAST, inside
|
|
394
|
+
* its own try/catch. A rejecting hook must never strand resolver generators
|
|
395
|
+
* at their suspension point (holding a DB cursor, a Redis subscription, an
|
|
396
|
+
* interval) or leave the connection in `this.connections` — that would grow
|
|
397
|
+
* without bound, one entry per disconnect.
|
|
398
|
+
*/
|
|
399
|
+
handleClose(ws: SubscriptionSocket): Promise<void>;
|
|
160
400
|
/**
|
|
161
401
|
* Handle WebSocket error
|
|
162
402
|
*/
|
|
@@ -170,9 +410,57 @@ export declare class SubscriptionManager implements OnModuleInit, OnModuleDestro
|
|
|
170
410
|
*/
|
|
171
411
|
private sendError;
|
|
172
412
|
/**
|
|
173
|
-
*
|
|
413
|
+
* Register an active subscription for topic-keyed delivery via
|
|
414
|
+
* {@link publishToTopic}.
|
|
415
|
+
*
|
|
416
|
+
* This is the integration point for a pub/sub engine (e.g. the future
|
|
417
|
+
* `@leaven-graphql/ws` integration): the graphql-ws operation id chosen by
|
|
418
|
+
* the client is only unique per connection, so deliveries must be routed by
|
|
419
|
+
* a server-side topic and translated back to each subscriber's own
|
|
420
|
+
* operation id.
|
|
421
|
+
*
|
|
422
|
+
* @param socket - A WebSocket connection managed by this manager that has
|
|
423
|
+
* completed `connection_init`
|
|
424
|
+
* @param clientId - The client-chosen graphql-ws operation id (unique per
|
|
425
|
+
* connection only)
|
|
426
|
+
* @param topic - Server-side topic used to route {@link publishToTopic} calls
|
|
427
|
+
* @param context - Optional GraphQL context associated with the subscription
|
|
428
|
+
* @returns `true` if the subscription was registered; `false` if the socket
|
|
429
|
+
* is unknown or uninitialized, the id is already registered on that
|
|
430
|
+
* connection, or the per-connection subscription limit has been reached
|
|
174
431
|
*/
|
|
175
|
-
|
|
432
|
+
registerSubscription(socket: SubscriptionSocket, clientId: string, topic: string, context?: GqlContext): boolean;
|
|
433
|
+
/**
|
|
434
|
+
* Publish a payload to every active subscription registered for a topic.
|
|
435
|
+
*
|
|
436
|
+
* Delivery is keyed on the server-side topic supplied to
|
|
437
|
+
* {@link registerSubscription} — NEVER on the client-chosen operation id,
|
|
438
|
+
* which is only unique per connection (most clients use "1", "2", …), so
|
|
439
|
+
* keying on it would broadcast payloads across unrelated clients. Each
|
|
440
|
+
* matching subscriber receives the payload in a `next` message addressed to
|
|
441
|
+
* its own operation id.
|
|
442
|
+
*
|
|
443
|
+
* @param topic - Server-side topic to publish to
|
|
444
|
+
* @param payload - Value delivered as the `data` of the `next` message
|
|
445
|
+
*/
|
|
446
|
+
publishToTopic(topic: string, payload: unknown): void;
|
|
447
|
+
/**
|
|
448
|
+
* Publish a payload to every active subscription registered for a topic.
|
|
449
|
+
*
|
|
450
|
+
* @deprecated Renamed to {@link publishToTopic}. The rename exists because
|
|
451
|
+
* the first argument CHANGED MEANING without changing type: it used to be
|
|
452
|
+
* the graphql-ws operation id chosen by the client, and it is now a
|
|
453
|
+
* server-side topic supplied to {@link registerSubscription}. Existing
|
|
454
|
+
* `publish(operationId, payload)` calls still compile and still run, but
|
|
455
|
+
* match nothing — streams started by `subscribe` deliberately carry no
|
|
456
|
+
* topic — so subscribers silently stop receiving events. Migrate to
|
|
457
|
+
* `publishToTopic(topic, payload)` and confirm the first argument is a
|
|
458
|
+
* topic. Scheduled for removal in v1.0.0.
|
|
459
|
+
*
|
|
460
|
+
* @param topic - Server-side topic to publish to (NOT an operation id)
|
|
461
|
+
* @param payload - Value delivered as the `data` of the `next` message
|
|
462
|
+
*/
|
|
463
|
+
publish(topic: string, payload: unknown): void;
|
|
176
464
|
/**
|
|
177
465
|
* Get connection count
|
|
178
466
|
*/
|
|
@@ -183,13 +471,49 @@ export declare class SubscriptionManager implements OnModuleInit, OnModuleDestro
|
|
|
183
471
|
getSubscriptionCount(): number;
|
|
184
472
|
}
|
|
185
473
|
/**
|
|
186
|
-
* Create a subscription decorator for NestJS resolvers
|
|
474
|
+
* Create a subscription decorator for NestJS resolvers.
|
|
475
|
+
*
|
|
476
|
+
* When `options.filter` is supplied the decorated method is wrapped so the
|
|
477
|
+
* async iterator it returns yields only the events the predicate accepts, and
|
|
478
|
+
* the predicate is recorded under {@link SUBSCRIPTION_FILTER_KEY} — fully
|
|
479
|
+
* equivalent to applying `@SubscriptionFilter` with the same predicate, down
|
|
480
|
+
* to the metadata a schema builder can inspect.
|
|
481
|
+
*
|
|
482
|
+
* SCOPE: this decorator only RECORDS metadata under `leaven:subscription`. It
|
|
483
|
+
* does not register a subscription field with any schema — code-first schema
|
|
484
|
+
* construction is not implemented, so a decorated method still needs a
|
|
485
|
+
* matching `subscribe` in the schema you hand to `LeavenModule`. The
|
|
486
|
+
* `filter` option is the part that takes effect unconditionally, because it
|
|
487
|
+
* wraps the method itself.
|
|
488
|
+
*
|
|
489
|
+
* @param returns - Thunk naming the subscription's GraphQL type. RESERVED FOR
|
|
490
|
+
* FUTURE USE: it is stored in the metadata verbatim and nothing reads it
|
|
491
|
+
* today; a future code-first schema builder is what will consume it. Supply
|
|
492
|
+
* the accurate type anyway so that builder does not have to guess.
|
|
493
|
+
* @param options - `filter` narrows the streamed events, exactly as
|
|
494
|
+
* `@SubscriptionFilter` does; it is also stored in the metadata.
|
|
187
495
|
*/
|
|
188
496
|
export declare function Subscription(returns: () => unknown, options?: {
|
|
189
|
-
filter?: (payload: unknown, variables: unknown, context: unknown) => boolean
|
|
497
|
+
filter?: (payload: unknown, variables: unknown, context: unknown) => boolean | Promise<boolean>;
|
|
190
498
|
}): MethodDecorator;
|
|
191
499
|
/**
|
|
192
|
-
*
|
|
500
|
+
* Inject the module's shared {@link PubSub} instance.
|
|
501
|
+
*
|
|
502
|
+
* Resolves the `LEAVEN_PUBSUB` provider registered by `LeavenModule`, so a
|
|
503
|
+
* provider can publish events and a subscription field can return
|
|
504
|
+
* `pubSub.asyncIterator(topic)`.
|
|
505
|
+
*
|
|
506
|
+
* @example
|
|
507
|
+
* ```typescript
|
|
508
|
+
* @Injectable()
|
|
509
|
+
* export class CommentService {
|
|
510
|
+
* constructor(@InjectPubSub() private readonly pubSub: PubSub) {}
|
|
511
|
+
*
|
|
512
|
+
* add(comment: Comment): void {
|
|
513
|
+
* this.pubSub.publish('COMMENT_ADDED', comment);
|
|
514
|
+
* }
|
|
515
|
+
* }
|
|
516
|
+
* ```
|
|
193
517
|
*/
|
|
194
518
|
export declare function InjectPubSub(): ParameterDecorator;
|
|
195
519
|
//# sourceMappingURL=subscriptions.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"AAAA
|
|
1
|
+
{"version":3,"file":"subscriptions.d.ts","sourceRoot":"","sources":["../src/subscriptions.ts"],"names":[],"mappings":"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"}
|