@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 +47 -2
- package/dist/index.cjs +45 -37
- package/dist/index.d.cts +33 -19
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -10,7 +10,7 @@ npm install @ldtr/nestjs-webtransport
|
|
|
10
10
|
Usage
|
|
11
11
|
=====
|
|
12
12
|
|
|
13
|
-
|
|
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", [
|
|
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", [
|
|
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/
|
|
74
|
-
type
|
|
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 };
|