@ldtr/nestjs-webtransport 0.0.3 → 0.0.5

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/README.md CHANGED
@@ -10,7 +10,7 @@ npm install @ldtr/nestjs-webtransport
10
10
  Usage
11
11
  =====
12
12
 
13
- Declare a server and a gateway:
13
+ First, declare a server:
14
14
  ```ts
15
15
  import {
16
16
  WtSession,
@@ -40,7 +40,10 @@ export class MainWebTransportServer implements WebTransportServerOptionsFactory
40
40
  }
41
41
  }
42
42
  }
43
+ ```
43
44
 
45
+ then, declare a gateway:
46
+ ```ts
44
47
  @WebTransportGateway({ server: "main", path: "/events" })
45
48
  export class EventsGateway implements WebTransportGatewayLifecycle {
46
49
  async onSession(session: WtSession): Promise<void> {
@@ -109,4 +112,46 @@ import { Module } from "@nestjs/common"
109
112
  })
110
113
  export class AppModule {
111
114
  }
112
- ```
115
+ ```
116
+
117
+ Session and stream data
118
+ =======================
119
+
120
+ Gateways are singleton providers in NestJS. Do not store session-specific or stream-specific state in gateway class properties. Instead, use the `data` object available on sessions and streams.
121
+
122
+ You can type this data by passing a generic type to `WebTransportGatewayLifecycle`:
123
+
124
+ ```ts
125
+ import {
126
+ WtSession,
127
+ WtStreamRW,
128
+ type GatewayData,
129
+ type WebTransportGatewayLifecycle
130
+ } from "@ldtr/nestjs-webtransport"
131
+
132
+ type EventsGatewayData = {
133
+ session: {
134
+ connectedAt: Date
135
+ totalBytes: number
136
+ }
137
+ streamRW: {
138
+ receivedBytes: number
139
+ }
140
+ }
141
+
142
+ @WebTransportGateway({ server: "main", path: "/events" })
143
+ export class EventsGateway implements WebTransportGatewayLifecycle<EventsGatewayData> {
144
+ async onSession(session: WtSession<EventsGatewayData>): Promise<void> {
145
+ session.data.connectedAt = new Date()
146
+ session.data.totalBytes = 0
147
+ }
148
+
149
+ async onStreamRW(stream: WtStreamRW<EventsGatewayData>): Promise<void> {
150
+ stream.data.receivedBytes = 0
151
+
152
+ for await (const chunk of stream.read()) {
153
+ stream.data.receivedBytes += chunk.length
154
+ stream.session.data.totalBytes += chunk.length
155
+ }
156
+ }
157
+ }
package/dist/index.cjs CHANGED
@@ -50,6 +50,10 @@ async function* generateUStream(session) {
50
50
  reader.releaseLock();
51
51
  }
52
52
  }
53
+ function isSessionClosedNormally(error) {
54
+ if (!(error instanceof Error)) return false;
55
+ return error.name === "WebTransportError" && /session closed/i.test(error.message) && /code 0/i.test(error.message);
56
+ }
53
57
  async function* generateChunks(reader) {
54
58
  try {
55
59
  while (true) {
@@ -57,6 +61,8 @@ async function* generateChunks(reader) {
57
61
  if (done) break;
58
62
  yield value;
59
63
  }
64
+ } catch (error) {
65
+ if (!isSessionClosedNormally(error)) throw error;
60
66
  } finally {
61
67
  reader.releaseLock();
62
68
  }
@@ -114,6 +120,7 @@ var WritableStreamHandler = class extends AbstractStreamHandler {
114
120
  var AbstractWtStream = class {
115
121
  session;
116
122
  webTransportStream;
123
+ data;
117
124
  constructor(session, webTransportStream) {
118
125
  this.session = session;
119
126
  this.webTransportStream = webTransportStream;
@@ -233,6 +240,41 @@ let WebTransportServerExplorer = class WebTransportServerExplorer {
233
240
  };
234
241
  WebTransportServerExplorer = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof _nestjs_core.DiscoveryService === "undefined" ? Object : _nestjs_core.DiscoveryService])], WebTransportServerExplorer);
235
242
  //#endregion
243
+ //#region src/lib/bootstraps/web-transport-bootstrapper.ts
244
+ var _WebTransportBootstrapper;
245
+ let WebTransportBootstrapper = _WebTransportBootstrapper = class WebTransportBootstrapper {
246
+ serverFactory;
247
+ webTransportExplorer;
248
+ logger = new _nestjs_common.Logger(_WebTransportBootstrapper.name);
249
+ h3ServersWithInfo = [];
250
+ constructor(serverFactory, webTransportExplorer) {
251
+ this.serverFactory = serverFactory;
252
+ this.webTransportExplorer = webTransportExplorer;
253
+ }
254
+ async onApplicationBootstrap() {
255
+ const serverBindings = this.webTransportExplorer.discover();
256
+ this.h3ServersWithInfo = await this.serverFactory.createH3Servers(serverBindings);
257
+ await Promise.all(this.h3ServersWithInfo.map(async ({ options, name, h3Server }) => {
258
+ try {
259
+ h3Server.startServer();
260
+ await h3Server.ready;
261
+ this.logger.log(`WebTransport server "${name}" is ready on ${options.host}:${options.port}`);
262
+ } catch (e) {
263
+ this.logger.error(`Failed to start WebTransport server "${name}" on ${options.host}:${options.port}`);
264
+ throw e;
265
+ }
266
+ }));
267
+ }
268
+ async onApplicationShutdown() {
269
+ await Promise.all(this.h3ServersWithInfo.map(async ({ name, h3Server }) => {
270
+ h3Server.stopServer();
271
+ await h3Server.closed;
272
+ this.logger.log(`WebTransport server "${name}" stopped`);
273
+ }));
274
+ }
275
+ };
276
+ WebTransportBootstrapper = _WebTransportBootstrapper = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [Object, Object])], WebTransportBootstrapper);
277
+ //#endregion
236
278
  //#region src/lib/explorers/web-transport.explorer.ts
237
279
  var _WebTransportExplorer;
238
280
  let WebTransportExplorer = _WebTransportExplorer = class WebTransportExplorer {
@@ -259,7 +301,7 @@ let WebTransportExplorer = _WebTransportExplorer = class WebTransportExplorer {
259
301
  return serverBindings;
260
302
  }
261
303
  };
262
- WebTransportExplorer = _WebTransportExplorer = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof WebTransportServerExplorer === "undefined" ? Object : WebTransportServerExplorer, typeof WebTransportGatewayExplorer === "undefined" ? Object : WebTransportGatewayExplorer])], WebTransportExplorer);
304
+ WebTransportExplorer = _WebTransportExplorer = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [Object, Object])], WebTransportExplorer);
263
305
  //#endregion
264
306
  //#region src/lib/bootstraps/consumers/abstract-stream.consumer.ts
265
307
  var AbstractStreamConsumer = class {
@@ -307,6 +349,7 @@ StreamRWConsumer = _StreamRWConsumer = __decorate([(0, _nestjs_common.Injectable
307
349
  //#region src/lib/classes/wt-session.ts
308
350
  var WtSession = class {
309
351
  webTransportSession;
352
+ data;
310
353
  constructor(webTransportSession) {
311
354
  this.webTransportSession = webTransportSession;
312
355
  }
@@ -395,42 +438,7 @@ let ServerFactory = _ServerFactory = class ServerFactory {
395
438
  this.streamROConsumer.consume(gateway, webTransportSession, session).catch((error) => this.logger.error(error));
396
439
  }
397
440
  };
398
- ServerFactory = _ServerFactory = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof StreamRWConsumer === "undefined" ? Object : StreamRWConsumer, typeof StreamROConsumer === "undefined" ? Object : StreamROConsumer])], ServerFactory);
399
- //#endregion
400
- //#region src/lib/bootstraps/web-transport-bootstrapper.ts
401
- var _WebTransportBootstrapper;
402
- let WebTransportBootstrapper = _WebTransportBootstrapper = class WebTransportBootstrapper {
403
- serverFactory;
404
- webTransportExplorer;
405
- logger = new _nestjs_common.Logger(_WebTransportBootstrapper.name);
406
- h3ServersWithInfo = [];
407
- constructor(serverFactory, webTransportExplorer) {
408
- this.serverFactory = serverFactory;
409
- this.webTransportExplorer = webTransportExplorer;
410
- }
411
- async onApplicationBootstrap() {
412
- const serverBindings = this.webTransportExplorer.discover();
413
- this.h3ServersWithInfo = await this.serverFactory.createH3Servers(serverBindings);
414
- await Promise.all(this.h3ServersWithInfo.map(async ({ options, name, h3Server }) => {
415
- try {
416
- h3Server.startServer();
417
- await h3Server.ready;
418
- this.logger.log(`WebTransport server "${name}" is ready on ${options.host}:${options.port}`);
419
- } catch (e) {
420
- this.logger.error(`Failed to start WebTransport server "${name}" on ${options.host}:${options.port}`);
421
- throw e;
422
- }
423
- }));
424
- }
425
- async onApplicationShutdown() {
426
- await Promise.all(this.h3ServersWithInfo.map(async ({ name, h3Server }) => {
427
- h3Server.stopServer();
428
- await h3Server.closed;
429
- this.logger.log(`WebTransport server "${name}" stopped`);
430
- }));
431
- }
432
- };
433
- WebTransportBootstrapper = _WebTransportBootstrapper = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [typeof ServerFactory === "undefined" ? Object : ServerFactory, typeof WebTransportExplorer === "undefined" ? Object : WebTransportExplorer])], WebTransportBootstrapper);
441
+ ServerFactory = _ServerFactory = __decorate([(0, _nestjs_common.Injectable)(), __decorateMetadata("design:paramtypes", [Object, Object])], ServerFactory);
434
442
  //#endregion
435
443
  //#region src/lib/webtransport.module.ts
436
444
  let WebTransportModule = class WebTransportModule {};
package/dist/index.d.cts CHANGED
@@ -12,23 +12,20 @@ interface WebTransportServerOptions {
12
12
  }
13
13
  declare function WebTransportServer(options: WebTransportServerOptions): ClassDecorator;
14
14
  //#endregion
15
- //#region src/lib/explorers/webtransport-server.explorer.d.ts
16
- type WebTransportServerOptionsFactory = {
17
- options(): HttpServerInit$1 | Promise<HttpServerInit$1>;
18
- };
19
- //#endregion
20
15
  //#region src/lib/classes/wt-session.d.ts
21
- declare class WtSession {
16
+ declare class WtSession<GD extends GatewayData = GatewayDefaultData> {
22
17
  private readonly webTransportSession;
18
+ data?: GD["session"];
23
19
  constructor(webTransportSession: WebTransportSession);
24
- createStreamWO(): Promise<WtStreamWO>;
25
- createStreamRW(): Promise<WtStreamRW>;
20
+ createStreamWO(): Promise<WtStreamWO<GD>>;
21
+ createStreamRW(): Promise<WtStreamRW<GD>>;
26
22
  }
27
23
  //#endregion
28
24
  //#region src/lib/classes/wt-stream.d.ts
29
- declare abstract class AbstractWtStream<TWebStream> {
25
+ declare abstract class AbstractWtStream<TWebStream, Data extends object | undefined> {
30
26
  readonly session: WtSession;
31
27
  protected readonly webTransportStream: TWebStream;
28
+ data?: Data;
32
29
  protected constructor(session: WtSession, webTransportStream: TWebStream);
33
30
  }
34
31
  interface WtReadableStream {
@@ -39,7 +36,7 @@ interface WtWritableStream {
39
36
  write(data: Uint8Array): Promise<void>;
40
37
  closeWritable(): Promise<void>;
41
38
  }
42
- declare class WtStreamRW extends AbstractWtStream<WebTransportBidirectionalStream> implements WtReadableStream, WtWritableStream {
39
+ declare class WtStreamRW<GD extends GatewayData = GatewayDefaultData> extends AbstractWtStream<WebTransportBidirectionalStream, GD["streamRW"]> implements WtReadableStream, WtWritableStream {
43
40
  private readonly readableStreamHandler;
44
41
  private readonly writableStreamHandler;
45
42
  constructor(session: WtSession, webTransportStream: WebTransportBidirectionalStream);
@@ -49,19 +46,24 @@ declare class WtStreamRW extends AbstractWtStream<WebTransportBidirectionalStrea
49
46
  closeWritable(): Promise<void>;
50
47
  close(): Promise<void>;
51
48
  }
52
- declare class WtStreamRO extends AbstractWtStream<WebTransportReceiveStream> implements WtReadableStream {
49
+ declare class WtStreamRO<GD extends GatewayData = GatewayDefaultData> extends AbstractWtStream<WebTransportReceiveStream, GD["streamRO"]> implements WtReadableStream {
53
50
  private readonly readableStreamHandler;
54
51
  constructor(session: WtSession, webTransportStream: WebTransportReceiveStream);
55
52
  read(): AsyncIterableIterator<Uint8Array>;
56
53
  closeReadable(): Promise<void>;
57
54
  }
58
- declare class WtStreamWO extends AbstractWtStream<WebTransportSendStream> implements WtWritableStream {
55
+ declare class WtStreamWO<GD extends GatewayData = GatewayDefaultData> extends AbstractWtStream<WebTransportSendStream, GD["streamWO"]> implements WtWritableStream {
59
56
  private readonly writableStreamHandler;
60
57
  constructor(session: WtSession, webTransportStream: WebTransportSendStream);
61
58
  write(data: Uint8Array): Promise<void>;
62
59
  closeWritable(): Promise<void>;
63
60
  }
64
61
  //#endregion
62
+ //#region src/lib/explorers/webtransport-server.explorer.d.ts
63
+ type WebTransportServerOptionsFactory = {
64
+ options(): HttpServerInit$1 | Promise<HttpServerInit$1>;
65
+ };
66
+ //#endregion
65
67
  //#region src/lib/bootstraps/types.d.ts
66
68
  type WebTransportRequestHeader = {
67
69
  readonly ':path': string;
@@ -70,16 +72,28 @@ type WebTransportRequest = {
70
72
  readonly header: WebTransportRequestHeader;
71
73
  };
72
74
  //#endregion
73
- //#region src/lib/explorers/webtransport-gateway.explorer.d.ts
74
- type WebTransportGatewayLifecycle = {
75
+ //#region src/lib/types/web-transport-gateway-lifecycle.d.ts
76
+ type GatewayData = {
77
+ session?: object;
78
+ streamRW?: object;
79
+ streamWO?: object;
80
+ streamRO?: object;
81
+ };
82
+ type GatewayDefaultData = {
83
+ session: undefined;
84
+ streamRW: undefined;
85
+ streamWO: undefined;
86
+ streamRO: undefined;
87
+ };
88
+ type WebTransportGatewayLifecycle<GD extends GatewayData = GatewayDefaultData> = {
75
89
  allowRequest?(request: WebTransportRequest): void | Promise<void>;
76
- onSession?(session: WtSession): void | Promise<void>;
77
- onSessionClosed?(session: WtSession): void | Promise<void>;
78
- onStreamRW?(stream: WtStreamRW): void | Promise<void>;
79
- onStreamRO?(stream: WtStreamRO): void | Promise<void>;
90
+ onSession?(session: WtSession<GD>): void | Promise<void>;
91
+ onSessionClosed?(session: WtSession<GD>): void | Promise<void>;
92
+ onStreamRW?(stream: WtStreamRW<GD>): void | Promise<void>;
93
+ onStreamRO?(stream: WtStreamRO<GD>): void | Promise<void>;
80
94
  };
81
95
  //#endregion
82
96
  //#region src/lib/webtransport.module.d.ts
83
97
  declare class WebTransportModule {}
84
98
  //#endregion
85
- export { type HttpServerInit, WebTransportGateway, type WebTransportGatewayLifecycle, type WebTransportGatewayOptions, WebTransportModule, WebTransportServer, type WebTransportServerOptions, type WebTransportServerOptionsFactory, WtSession, WtStreamRO, WtStreamRW, WtStreamWO };
99
+ export { type GatewayData, type HttpServerInit, WebTransportGateway, type WebTransportGatewayLifecycle, type WebTransportGatewayOptions, WebTransportModule, WebTransportServer, type WebTransportServerOptions, type WebTransportServerOptionsFactory, WtSession, WtStreamRO, WtStreamRW, WtStreamWO };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ldtr/nestjs-webtransport",
3
- "version": "0.0.3",
3
+ "version": "0.0.5",
4
4
  "description": "NestJS module for creating WebTransport servers and gateways.",
5
5
  "type": "module",
6
6
  "files": [