@ailura/nestjs-hono-adapter 1.0.0
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 +21 -0
- package/README.md +411 -0
- package/dist/body.d.ts +35 -0
- package/dist/body.d.ts.map +1 -0
- package/dist/body.js +180 -0
- package/dist/body.js.map +1 -0
- package/dist/bridge.d.ts +64 -0
- package/dist/bridge.d.ts.map +1 -0
- package/dist/bridge.js +168 -0
- package/dist/bridge.js.map +1 -0
- package/dist/closing.d.ts +13 -0
- package/dist/closing.d.ts.map +1 -0
- package/dist/closing.js +30 -0
- package/dist/closing.js.map +1 -0
- package/dist/context.d.ts +22 -0
- package/dist/context.d.ts.map +1 -0
- package/dist/context.js +2 -0
- package/dist/context.js.map +1 -0
- package/dist/cors-middleware.d.ts +64 -0
- package/dist/cors-middleware.d.ts.map +1 -0
- package/dist/cors-middleware.js +211 -0
- package/dist/cors-middleware.js.map +1 -0
- package/dist/handler-bridge.d.ts +51 -0
- package/dist/handler-bridge.d.ts.map +1 -0
- package/dist/handler-bridge.js +122 -0
- package/dist/handler-bridge.js.map +1 -0
- package/dist/hono-lifecycle.d.ts +90 -0
- package/dist/hono-lifecycle.d.ts.map +1 -0
- package/dist/hono-lifecycle.js +169 -0
- package/dist/hono-lifecycle.js.map +1 -0
- package/dist/index.d.ts +16 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +8 -0
- package/dist/index.js.map +1 -0
- package/dist/path.d.ts +3 -0
- package/dist/path.d.ts.map +1 -0
- package/dist/path.js +144 -0
- package/dist/path.js.map +1 -0
- package/dist/query.d.ts +19 -0
- package/dist/query.d.ts.map +1 -0
- package/dist/query.js +238 -0
- package/dist/query.js.map +1 -0
- package/dist/response-helpers.d.ts +16 -0
- package/dist/response-helpers.d.ts.map +1 -0
- package/dist/response-helpers.js +45 -0
- package/dist/response-helpers.js.map +1 -0
- package/dist/response-writer.d.ts +28 -0
- package/dist/response-writer.d.ts.map +1 -0
- package/dist/response-writer.js +52 -0
- package/dist/response-writer.js.map +1 -0
- package/dist/route-adapter.d.ts +53 -0
- package/dist/route-adapter.d.ts.map +1 -0
- package/dist/route-adapter.js +141 -0
- package/dist/route-adapter.js.map +1 -0
- package/dist/server-adapter.d.ts +106 -0
- package/dist/server-adapter.d.ts.map +1 -0
- package/dist/server-adapter.js +153 -0
- package/dist/server-adapter.js.map +1 -0
- package/dist/sse.d.ts +67 -0
- package/dist/sse.d.ts.map +1 -0
- package/dist/sse.js +211 -0
- package/dist/sse.js.map +1 -0
- package/dist/static-assets.d.ts +39 -0
- package/dist/static-assets.d.ts.map +1 -0
- package/dist/static-assets.js +155 -0
- package/dist/static-assets.js.map +1 -0
- package/dist/version-filter.d.ts +24 -0
- package/dist/version-filter.d.ts.map +1 -0
- package/dist/version-filter.js +107 -0
- package/dist/version-filter.js.map +1 -0
- package/dist/versioned-route.d.ts +21 -0
- package/dist/versioned-route.d.ts.map +1 -0
- package/dist/versioned-route.js +15 -0
- package/dist/versioned-route.js.map +1 -0
- package/dist/views.d.ts +42 -0
- package/dist/views.d.ts.map +1 -0
- package/dist/views.js +110 -0
- package/dist/views.js.map +1 -0
- package/dist/ws-adapter.d.ts +81 -0
- package/dist/ws-adapter.d.ts.map +1 -0
- package/dist/ws-adapter.js +214 -0
- package/dist/ws-adapter.js.map +1 -0
- package/dist/ws-client.d.ts +68 -0
- package/dist/ws-client.d.ts.map +1 -0
- package/dist/ws-client.js +135 -0
- package/dist/ws-client.js.map +1 -0
- package/dist/ws-server.d.ts +23 -0
- package/dist/ws-server.d.ts.map +1 -0
- package/dist/ws-server.js +37 -0
- package/dist/ws-server.js.map +1 -0
- package/dist/ws.d.ts +14 -0
- package/dist/ws.d.ts.map +1 -0
- package/dist/ws.js +12 -0
- package/dist/ws.js.map +1 -0
- package/package.json +99 -0
- package/src/body.ts +251 -0
- package/src/bridge.ts +308 -0
- package/src/closing.ts +38 -0
- package/src/context.ts +25 -0
- package/src/cors-middleware.ts +347 -0
- package/src/handler-bridge.ts +226 -0
- package/src/hono-lifecycle.ts +259 -0
- package/src/index.ts +27 -0
- package/src/path.ts +169 -0
- package/src/query.ts +304 -0
- package/src/response-helpers.ts +60 -0
- package/src/response-writer.ts +100 -0
- package/src/route-adapter.ts +261 -0
- package/src/server-adapter.ts +294 -0
- package/src/sse.ts +274 -0
- package/src/static-assets.ts +247 -0
- package/src/version-filter.ts +170 -0
- package/src/versioned-route.ts +30 -0
- package/src/views.ts +188 -0
- package/src/ws-adapter.ts +329 -0
- package/src/ws-client.ts +190 -0
- package/src/ws-server.ts +40 -0
- package/src/ws.ts +13 -0
|
@@ -0,0 +1,106 @@
|
|
|
1
|
+
import type { NestHandler, NestRequest } from './bridge.ts';
|
|
2
|
+
import type { NestContext } from './context.ts';
|
|
3
|
+
import type { CorsOptions } from './cors-middleware.ts';
|
|
4
|
+
import type { NestExceptionHandler } from './handler-bridge.ts';
|
|
5
|
+
import { HonoLifecycle } from './hono-lifecycle.ts';
|
|
6
|
+
import type { TransportOptions } from './hono-lifecycle.ts';
|
|
7
|
+
import type { StaticAssetsOptions } from './static-assets.ts';
|
|
8
|
+
import type { ViewOptions } from './views.ts';
|
|
9
|
+
/** The options the adapter itself reads. */
|
|
10
|
+
interface ServerAdapterOptions extends TransportOptions {
|
|
11
|
+
/**
|
|
12
|
+
* The views a handler may render, when the application has
|
|
13
|
+
* any.
|
|
14
|
+
*/
|
|
15
|
+
readonly views?: ViewOptions;
|
|
16
|
+
}
|
|
17
|
+
/** The options Nest hands the parser middleware. */
|
|
18
|
+
interface BodyParserOptions {
|
|
19
|
+
readonly limit?: number | string;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* HTTP adapter that runs Nest on Hono.
|
|
23
|
+
*
|
|
24
|
+
* There is no official Hono adapter for Nest, so this one lives
|
|
25
|
+
* in the repository. It implements the `AbstractHttpAdapter`
|
|
26
|
+
* contract rather than wrapping another framework: routes are
|
|
27
|
+
* registered on a Hono application, and Hono's Web `Request`
|
|
28
|
+
* and `Response` are translated to and from the objects Nest
|
|
29
|
+
* reads and writes. The application, the middleware chain and
|
|
30
|
+
* the server lifecycle are inherited from {@link HonoLifecycle};
|
|
31
|
+
* this class implements the rest of the Nest contract.
|
|
32
|
+
*/
|
|
33
|
+
declare class ServerAdapter extends HonoLifecycle {
|
|
34
|
+
private readonly writer;
|
|
35
|
+
private readonly views;
|
|
36
|
+
constructor(options?: ServerAdapterOptions);
|
|
37
|
+
status(response: NestContext, statusCode: number): void;
|
|
38
|
+
reply(response: NestContext, body: unknown, statusCode?: number): void;
|
|
39
|
+
end(response: NestContext, message?: string): void;
|
|
40
|
+
redirect(response: NestContext, statusCode: number, url: string): void;
|
|
41
|
+
setHeader(response: NestContext, name: string, value: string): void;
|
|
42
|
+
getHeader(response: NestContext, name: string): string | undefined;
|
|
43
|
+
appendHeader(response: NestContext, name: string, value: string): void;
|
|
44
|
+
isHeadersSent(response: NestContext): boolean;
|
|
45
|
+
/** Renders one view with the engine the deployment gave. */
|
|
46
|
+
render(response: NestContext, view: string, options: unknown): Promise<void>;
|
|
47
|
+
/** Names the engine, by the extension it renders. */
|
|
48
|
+
setViewEngine(engine: string): void;
|
|
49
|
+
/** Names the directories a view is read from. */
|
|
50
|
+
setBaseViewsDir(directory: string | readonly string[]): void;
|
|
51
|
+
/**
|
|
52
|
+
* Serves the files in a directory, under the prefix asked
|
|
53
|
+
* for.
|
|
54
|
+
*/
|
|
55
|
+
useStaticAssets(path: string | readonly string[], options?: StaticAssetsOptions): void;
|
|
56
|
+
/**
|
|
57
|
+
* Turns on the CORS middleware for this service.
|
|
58
|
+
*
|
|
59
|
+
* It has to be configured before the first request is served,
|
|
60
|
+
* which is how Nest itself is used: the application is built,
|
|
61
|
+
* `enableCors` is called on it, and only then does it listen.
|
|
62
|
+
* Until it is called no origin is allowed.
|
|
63
|
+
*/
|
|
64
|
+
enableCors(options?: CorsOptions): void;
|
|
65
|
+
getRequestMethod(request: NestRequest): string;
|
|
66
|
+
getRequestUrl(request: NestRequest): string;
|
|
67
|
+
getRequestHostname(request: NestRequest): string;
|
|
68
|
+
/**
|
|
69
|
+
* Records that Nest wants parsed bodies. The payload itself
|
|
70
|
+
* is read per route in the handler bridge, because Hono
|
|
71
|
+
* parses a body on demand rather than through middleware.
|
|
72
|
+
*/
|
|
73
|
+
registerParserMiddleware(_prefix?: string, rawBody?: boolean): void;
|
|
74
|
+
/**
|
|
75
|
+
* `app.useBodyParser()` reaches the adapter here. Every
|
|
76
|
+
* parser reads the same payload, so the type is not branched
|
|
77
|
+
* on; the size limit is, because it is the option a
|
|
78
|
+
* deployment sets.
|
|
79
|
+
*/
|
|
80
|
+
useBodyParser(_type?: string, rawBody?: boolean, options?: BodyParserOptions): void;
|
|
81
|
+
setNotFoundHandler(handler: NestHandler): void;
|
|
82
|
+
setErrorHandler(handler: NestExceptionHandler): void;
|
|
83
|
+
protected register(method: string, path: string, handler: NestHandler): void;
|
|
84
|
+
private get bridgeOptions();
|
|
85
|
+
private applyLimit;
|
|
86
|
+
/** A limit of nothing means the size is not checked. */
|
|
87
|
+
private effectiveBodyLimit;
|
|
88
|
+
}
|
|
89
|
+
declare module '@nestjs/common' {
|
|
90
|
+
/**
|
|
91
|
+
* The application methods this adapter implements. Nest
|
|
92
|
+
* declares them on its own platform interfaces, which an
|
|
93
|
+
* application on Hono does not otherwise have.
|
|
94
|
+
*/
|
|
95
|
+
interface INestApplication<TServer> {
|
|
96
|
+
/** Serves the files in a directory, at the prefix asked for. */
|
|
97
|
+
useStaticAssets: (path: string | readonly string[], options?: StaticAssetsOptions) => this;
|
|
98
|
+
/** Names the directories a view is read from. */
|
|
99
|
+
setBaseViewsDir: (directory: string | readonly string[]) => this;
|
|
100
|
+
/** Names the view engine, by the extension it renders. */
|
|
101
|
+
setViewEngine: (engine: string) => this;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
export { ServerAdapter };
|
|
105
|
+
export type { ServerAdapterOptions };
|
|
106
|
+
//# sourceMappingURL=server-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-adapter.d.ts","sourceRoot":"","sources":["../src/server-adapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { toByteLimit } from './body.js';
|
|
2
|
+
import { createExceptionRunner, createRouteHandler, runNestHandler, } from './handler-bridge.js';
|
|
3
|
+
import { HonoLifecycle } from './hono-lifecycle.js';
|
|
4
|
+
import { toHonoPath } from './path.js';
|
|
5
|
+
import { ResponseWriter } from './response-writer.js';
|
|
6
|
+
import { ALL_METHOD } from './route-adapter.js';
|
|
7
|
+
import { mountStaticAssets } from './static-assets.js';
|
|
8
|
+
import { ViewRenderer } from './views.js';
|
|
9
|
+
/**
|
|
10
|
+
* HTTP adapter that runs Nest on Hono.
|
|
11
|
+
*
|
|
12
|
+
* There is no official Hono adapter for Nest, so this one lives
|
|
13
|
+
* in the repository. It implements the `AbstractHttpAdapter`
|
|
14
|
+
* contract rather than wrapping another framework: routes are
|
|
15
|
+
* registered on a Hono application, and Hono's Web `Request`
|
|
16
|
+
* and `Response` are translated to and from the objects Nest
|
|
17
|
+
* reads and writes. The application, the middleware chain and
|
|
18
|
+
* the server lifecycle are inherited from {@link HonoLifecycle};
|
|
19
|
+
* this class implements the rest of the Nest contract.
|
|
20
|
+
*/
|
|
21
|
+
class ServerAdapter extends HonoLifecycle {
|
|
22
|
+
constructor(options = {}) {
|
|
23
|
+
super(options);
|
|
24
|
+
this.writer = new ResponseWriter();
|
|
25
|
+
this.views = new ViewRenderer(options.views);
|
|
26
|
+
}
|
|
27
|
+
status(response, statusCode) {
|
|
28
|
+
this.writer.status(response, statusCode);
|
|
29
|
+
}
|
|
30
|
+
reply(response, body, statusCode) {
|
|
31
|
+
this.writer.reply(response, body, statusCode);
|
|
32
|
+
}
|
|
33
|
+
end(response, message) {
|
|
34
|
+
this.writer.end(response, message);
|
|
35
|
+
}
|
|
36
|
+
redirect(response, statusCode, url) {
|
|
37
|
+
this.writer.redirect(response, statusCode, url);
|
|
38
|
+
}
|
|
39
|
+
setHeader(response, name, value) {
|
|
40
|
+
this.writer.setHeader(response, name, value);
|
|
41
|
+
}
|
|
42
|
+
getHeader(response, name) {
|
|
43
|
+
return this.writer.getHeader(response, name);
|
|
44
|
+
}
|
|
45
|
+
appendHeader(response, name, value) {
|
|
46
|
+
this.writer.appendHeader(response, name, value);
|
|
47
|
+
}
|
|
48
|
+
isHeadersSent(response) {
|
|
49
|
+
return this.writer.isHeadersSent(response);
|
|
50
|
+
}
|
|
51
|
+
/** Renders one view with the engine the deployment gave. */
|
|
52
|
+
render(response, view, options) {
|
|
53
|
+
return this.views.render(response, view, options);
|
|
54
|
+
}
|
|
55
|
+
/** Names the engine, by the extension it renders. */
|
|
56
|
+
setViewEngine(engine) {
|
|
57
|
+
this.views.useEngine(engine);
|
|
58
|
+
}
|
|
59
|
+
/** Names the directories a view is read from. */
|
|
60
|
+
setBaseViewsDir(directory) {
|
|
61
|
+
this.views.useDirectories(directory);
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Serves the files in a directory, under the prefix asked
|
|
65
|
+
* for.
|
|
66
|
+
*/
|
|
67
|
+
useStaticAssets(path, options) {
|
|
68
|
+
mountStaticAssets(this.hono, path, options ?? {});
|
|
69
|
+
}
|
|
70
|
+
/**
|
|
71
|
+
* Turns on the CORS middleware for this service.
|
|
72
|
+
*
|
|
73
|
+
* It has to be configured before the first request is served,
|
|
74
|
+
* which is how Nest itself is used: the application is built,
|
|
75
|
+
* `enableCors` is called on it, and only then does it listen.
|
|
76
|
+
* Until it is called no origin is allowed.
|
|
77
|
+
*/
|
|
78
|
+
enableCors(options) {
|
|
79
|
+
this.corsOptions = options ?? {};
|
|
80
|
+
}
|
|
81
|
+
getRequestMethod(request) {
|
|
82
|
+
return request.method;
|
|
83
|
+
}
|
|
84
|
+
getRequestUrl(request) {
|
|
85
|
+
return request.originalUrl;
|
|
86
|
+
}
|
|
87
|
+
getRequestHostname(request) {
|
|
88
|
+
return request.hostname;
|
|
89
|
+
}
|
|
90
|
+
/**
|
|
91
|
+
* Records that Nest wants parsed bodies. The payload itself
|
|
92
|
+
* is read per route in the handler bridge, because Hono
|
|
93
|
+
* parses a body on demand rather than through middleware.
|
|
94
|
+
*/
|
|
95
|
+
registerParserMiddleware(_prefix, rawBody) {
|
|
96
|
+
this.bodyParsingEnabled = true;
|
|
97
|
+
this.keepRawBody(rawBody);
|
|
98
|
+
}
|
|
99
|
+
/**
|
|
100
|
+
* `app.useBodyParser()` reaches the adapter here. Every
|
|
101
|
+
* parser reads the same payload, so the type is not branched
|
|
102
|
+
* on; the size limit is, because it is the option a
|
|
103
|
+
* deployment sets.
|
|
104
|
+
*/
|
|
105
|
+
useBodyParser(_type, rawBody, options) {
|
|
106
|
+
this.bodyParsingEnabled = true;
|
|
107
|
+
this.keepRawBody(rawBody);
|
|
108
|
+
this.applyLimit(options);
|
|
109
|
+
}
|
|
110
|
+
setNotFoundHandler(handler) {
|
|
111
|
+
this.hono.notFound((context) => runNestHandler(handler, context, this.bridgeOptions));
|
|
112
|
+
}
|
|
113
|
+
setErrorHandler(handler) {
|
|
114
|
+
const run = createExceptionRunner(handler, this.bridgeOptions);
|
|
115
|
+
this.hono.onError((error, context) => run(error, context));
|
|
116
|
+
}
|
|
117
|
+
register(method, path, handler) {
|
|
118
|
+
const honoPath = toHonoPath(path);
|
|
119
|
+
const honoHandler = createRouteHandler(handler, this.bridgeOptions);
|
|
120
|
+
if (method === ALL_METHOD) {
|
|
121
|
+
this.hono.all(honoPath, honoHandler);
|
|
122
|
+
return;
|
|
123
|
+
}
|
|
124
|
+
this.hono.on(method, honoPath, honoHandler);
|
|
125
|
+
}
|
|
126
|
+
get bridgeOptions() {
|
|
127
|
+
return {
|
|
128
|
+
bodyLimit: () => this.effectiveBodyLimit(),
|
|
129
|
+
bodyParsingEnabled: () => this.bodyParsingEnabled,
|
|
130
|
+
pendingStatus: (context) => this.writer.statusOf(context),
|
|
131
|
+
rawBody: () => this.rawBodyEnabled,
|
|
132
|
+
trustProxy: () => this.trustProxy,
|
|
133
|
+
};
|
|
134
|
+
}
|
|
135
|
+
applyLimit(options) {
|
|
136
|
+
if (options === undefined) {
|
|
137
|
+
return;
|
|
138
|
+
}
|
|
139
|
+
if (options.limit === undefined) {
|
|
140
|
+
return;
|
|
141
|
+
}
|
|
142
|
+
this.bodyLimit = toByteLimit(options.limit);
|
|
143
|
+
}
|
|
144
|
+
/** A limit of nothing means the size is not checked. */
|
|
145
|
+
effectiveBodyLimit() {
|
|
146
|
+
if (this.bodyLimit === 0) {
|
|
147
|
+
return undefined;
|
|
148
|
+
}
|
|
149
|
+
return this.bodyLimit;
|
|
150
|
+
}
|
|
151
|
+
}
|
|
152
|
+
export { ServerAdapter };
|
|
153
|
+
//# sourceMappingURL=server-adapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"server-adapter.js","sourceRoot":"","sources":["../src/server-adapter.ts"],"names":[],"mappings":"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"}
|
package/dist/sse.d.ts
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
import { Writable } from 'node:stream';
|
|
2
|
+
import type { NestContext } from './context.ts';
|
|
3
|
+
/** The callback every Node stream write and finalizer takes. */
|
|
4
|
+
type StreamCallback = (error?: Error | null) => void;
|
|
5
|
+
/** What Nest calls once the stream's headers are chosen. */
|
|
6
|
+
type CommitListener = (response: Response) => void;
|
|
7
|
+
/**
|
|
8
|
+
* The Node writable Nest pipes an event stream into, and the
|
|
9
|
+
* web stream the Hono response reads its frames from.
|
|
10
|
+
*
|
|
11
|
+
* Nest answers `@Sse()` through `SseStream`, a `Transform` that
|
|
12
|
+
* is piped onto the response object. That object has to be a
|
|
13
|
+
* genuine `Writable`, so this one collects what Nest writes and
|
|
14
|
+
* hands the same bytes to a `ReadableStream`, which becomes the
|
|
15
|
+
* Hono response the client reads. The members Nest touches
|
|
16
|
+
* around the pipe — the status, the headers, the flushing and
|
|
17
|
+
* the end — are all here, so it needs nothing from Node's own
|
|
18
|
+
* `ServerResponse`. A client that walks away cancels the web
|
|
19
|
+
* stream, and the writes that follow are dropped rather than
|
|
20
|
+
* thrown at the process.
|
|
21
|
+
*/
|
|
22
|
+
declare class SseResponse extends Writable {
|
|
23
|
+
private readonly onCommit;
|
|
24
|
+
private readonly status;
|
|
25
|
+
private readonly stream;
|
|
26
|
+
private controller;
|
|
27
|
+
private committed;
|
|
28
|
+
private cancelled;
|
|
29
|
+
private headers;
|
|
30
|
+
private answerStatus;
|
|
31
|
+
constructor(status: () => number | undefined, onCommit: CommitListener);
|
|
32
|
+
/**
|
|
33
|
+
* The status Nest read from the adapter before the handler
|
|
34
|
+
* ran, so `@HttpCode()` and a POST default reach the stream.
|
|
35
|
+
*/
|
|
36
|
+
get statusCode(): number | undefined;
|
|
37
|
+
/** Chooses the answer's status and headers, once. */
|
|
38
|
+
writeHead(status: number, headers?: Record<string, string>): this;
|
|
39
|
+
/**
|
|
40
|
+
* Nothing is buffered here, so there is nothing left to
|
|
41
|
+
* flush: Hono already has the response by the time Nest
|
|
42
|
+
* asks.
|
|
43
|
+
*/
|
|
44
|
+
flushHeaders(): void;
|
|
45
|
+
setHeader(name: string, value: string): void;
|
|
46
|
+
/**
|
|
47
|
+
* Turns what Nest wrote into the Hono response, exactly once.
|
|
48
|
+
* The response is handed over before the start event is
|
|
49
|
+
* emitted, so whoever waits on the event reads a live body.
|
|
50
|
+
*/
|
|
51
|
+
private commit;
|
|
52
|
+
private enqueue;
|
|
53
|
+
private finish;
|
|
54
|
+
private logFailure;
|
|
55
|
+
_write(chunk: unknown, _encoding: BufferEncoding, callback: StreamCallback): void;
|
|
56
|
+
_final(callback: StreamCallback): void;
|
|
57
|
+
_destroy(error: Error | null, callback: StreamCallback): void;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Opens an event stream on the response Nest reads, and says
|
|
61
|
+
* when it started. The stream is the destination `SseStream`
|
|
62
|
+
* pipes into, so nothing is buffered until Nest commits the
|
|
63
|
+
* headers, which is also the moment the promise settles.
|
|
64
|
+
*/
|
|
65
|
+
declare function mountSse(context: NestContext, status: () => number | undefined): Promise<unknown>;
|
|
66
|
+
export { SseResponse, mountSse };
|
|
67
|
+
//# sourceMappingURL=sse.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.d.ts","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAC;AAIvC,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAEhD,gEAAgE;AAChE,KAAK,cAAc,GAAG,CAAC,KAAK,CAAC,EAAE,KAAK,GAAG,IAAI,KAAK,IAAI,CAAC;AAgCrD,4DAA4D;AAC5D,KAAK,cAAc,GAAG,CAAC,QAAQ,EAAE,QAAQ,KAAK,IAAI,CAAC;AAEnD;;;;;;;;;;;;;;GAcG;AACH,cAAM,WAAY,SAAQ,QAAQ;IAChC,OAAO,CAAC,QAAQ,CAAC,QAAQ,CAAiB;IAC1C,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA2B;IAClD,OAAO,CAAC,QAAQ,CAAC,MAAM,CAA6B;IACpD,OAAO,CAAC,UAAU,CAEJ;IACd,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,OAAO,CAA8B;IAC7C,OAAO,CAAC,YAAY,CAA0B;IAE9C,YACE,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,EAChC,QAAQ,EAAE,cAAc,EAkBzB;IAED;;;OAGG;IACH,IAAW,UAAU,IAAI,MAAM,GAAG,SAAS,CAE1C;IAED,qDAAqD;IAC9C,SAAS,CACd,MAAM,EAAE,MAAM,EACd,OAAO,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,GAC/B,IAAI,CAKN;IAED;;;;OAIG;IACI,YAAY,IAAI,IAAI,CAE1B;IAEM,SAAS,CAAC,IAAI,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,GAAG,IAAI,CAElD;IAED;;;;OAIG;IACH,OAAO,CAAC,MAAM;IAkBd,OAAO,CAAC,OAAO;IAQf,OAAO,CAAC,MAAM;IASd,OAAO,CAAC,UAAU;IAIF,MAAM,CACpB,KAAK,EAAE,OAAO,EACd,SAAS,EAAE,cAAc,EACzB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAWN;IAEe,MAAM,CAAC,QAAQ,EAAE,cAAc,GAAG,IAAI,CAGrD;IAEe,QAAQ,CACtB,KAAK,EAAE,KAAK,GAAG,IAAI,EACnB,QAAQ,EAAE,cAAc,GACvB,IAAI,CAGN;CACF;AA2DD;;;;;GAKG;AACH,iBAAS,QAAQ,CACf,OAAO,EAAE,WAAW,EACpB,MAAM,EAAE,MAAM,MAAM,GAAG,SAAS,GAC/B,OAAO,CAAC,OAAO,CAAC,CAMlB;AAED,OAAO,EAAE,WAAW,EAAE,QAAQ,EAAE,CAAC"}
|
package/dist/sse.js
ADDED
|
@@ -0,0 +1,211 @@
|
|
|
1
|
+
import { once } from 'node:events';
|
|
2
|
+
import { Writable } from 'node:stream';
|
|
3
|
+
import { Logger } from '@nestjs/common';
|
|
4
|
+
/** The status an event stream answers with when Nest names none. */
|
|
5
|
+
const DEFAULT_STATUS = 200;
|
|
6
|
+
/** The event a stream emits once its headers are on the wire. */
|
|
7
|
+
const STARTED = 'started';
|
|
8
|
+
/** The header that says a proxy must not buffer the stream. */
|
|
9
|
+
const NO_BUFFERING = 'no';
|
|
10
|
+
/** The headers a stream is opened with, whatever Nest added. */
|
|
11
|
+
const STREAM_HEADERS = {
|
|
12
|
+
'cache-control': 'no-cache',
|
|
13
|
+
connection: 'keep-alive',
|
|
14
|
+
'content-type': 'text/event-stream',
|
|
15
|
+
'x-accel-buffering': NO_BUFFERING,
|
|
16
|
+
};
|
|
17
|
+
/** Says why a stream failed, without taking the process down. */
|
|
18
|
+
const logger = new Logger('SseResponse');
|
|
19
|
+
function toBytes(chunk) {
|
|
20
|
+
if (typeof chunk === 'string') {
|
|
21
|
+
return new TextEncoder().encode(chunk);
|
|
22
|
+
}
|
|
23
|
+
if (chunk instanceof Uint8Array) {
|
|
24
|
+
return chunk;
|
|
25
|
+
}
|
|
26
|
+
return undefined;
|
|
27
|
+
}
|
|
28
|
+
/**
|
|
29
|
+
* The Node writable Nest pipes an event stream into, and the
|
|
30
|
+
* web stream the Hono response reads its frames from.
|
|
31
|
+
*
|
|
32
|
+
* Nest answers `@Sse()` through `SseStream`, a `Transform` that
|
|
33
|
+
* is piped onto the response object. That object has to be a
|
|
34
|
+
* genuine `Writable`, so this one collects what Nest writes and
|
|
35
|
+
* hands the same bytes to a `ReadableStream`, which becomes the
|
|
36
|
+
* Hono response the client reads. The members Nest touches
|
|
37
|
+
* around the pipe — the status, the headers, the flushing and
|
|
38
|
+
* the end — are all here, so it needs nothing from Node's own
|
|
39
|
+
* `ServerResponse`. A client that walks away cancels the web
|
|
40
|
+
* stream, and the writes that follow are dropped rather than
|
|
41
|
+
* thrown at the process.
|
|
42
|
+
*/
|
|
43
|
+
class SseResponse extends Writable {
|
|
44
|
+
constructor(status, onCommit) {
|
|
45
|
+
super();
|
|
46
|
+
this.committed = false;
|
|
47
|
+
this.cancelled = false;
|
|
48
|
+
this.headers = {};
|
|
49
|
+
this.answerStatus = DEFAULT_STATUS;
|
|
50
|
+
this.status = status;
|
|
51
|
+
this.onCommit = onCommit;
|
|
52
|
+
this.stream = new ReadableStream({
|
|
53
|
+
cancel: () => {
|
|
54
|
+
this.cancelled = true;
|
|
55
|
+
},
|
|
56
|
+
start: (controller) => {
|
|
57
|
+
this.controller = controller;
|
|
58
|
+
},
|
|
59
|
+
});
|
|
60
|
+
// A client that walked away makes the next write fail; that
|
|
61
|
+
// is the client's business, not a reason to crash.
|
|
62
|
+
this.on('error', (error) => {
|
|
63
|
+
this.logFailure(error);
|
|
64
|
+
});
|
|
65
|
+
}
|
|
66
|
+
/**
|
|
67
|
+
* The status Nest read from the adapter before the handler
|
|
68
|
+
* ran, so `@HttpCode()` and a POST default reach the stream.
|
|
69
|
+
*/
|
|
70
|
+
get statusCode() {
|
|
71
|
+
return this.status();
|
|
72
|
+
}
|
|
73
|
+
/** Chooses the answer's status and headers, once. */
|
|
74
|
+
writeHead(status, headers) {
|
|
75
|
+
this.answerStatus = status;
|
|
76
|
+
this.headers = headers ?? {};
|
|
77
|
+
this.commit();
|
|
78
|
+
return this;
|
|
79
|
+
}
|
|
80
|
+
/**
|
|
81
|
+
* Nothing is buffered here, so there is nothing left to
|
|
82
|
+
* flush: Hono already has the response by the time Nest
|
|
83
|
+
* asks.
|
|
84
|
+
*/
|
|
85
|
+
flushHeaders() {
|
|
86
|
+
this.commit();
|
|
87
|
+
}
|
|
88
|
+
setHeader(name, value) {
|
|
89
|
+
this.headers[name] = value;
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Turns what Nest wrote into the Hono response, exactly once.
|
|
93
|
+
* The response is handed over before the start event is
|
|
94
|
+
* emitted, so whoever waits on the event reads a live body.
|
|
95
|
+
*/
|
|
96
|
+
commit() {
|
|
97
|
+
if (this.committed) {
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
this.committed = true;
|
|
101
|
+
const headers = new Headers(STREAM_HEADERS);
|
|
102
|
+
for (const [name, value] of Object.entries(this.headers)) {
|
|
103
|
+
headers.set(name, value);
|
|
104
|
+
}
|
|
105
|
+
this.onCommit(new Response(this.stream, {
|
|
106
|
+
headers,
|
|
107
|
+
status: this.answerStatus,
|
|
108
|
+
}));
|
|
109
|
+
this.emit(STARTED);
|
|
110
|
+
}
|
|
111
|
+
enqueue(chunk) {
|
|
112
|
+
const { controller } = this;
|
|
113
|
+
if (this.cancelled || controller === undefined) {
|
|
114
|
+
return;
|
|
115
|
+
}
|
|
116
|
+
controller.enqueue(chunk);
|
|
117
|
+
}
|
|
118
|
+
finish() {
|
|
119
|
+
const { controller } = this;
|
|
120
|
+
if (this.cancelled || controller === undefined) {
|
|
121
|
+
return;
|
|
122
|
+
}
|
|
123
|
+
this.cancelled = true;
|
|
124
|
+
controller.close();
|
|
125
|
+
}
|
|
126
|
+
logFailure(error) {
|
|
127
|
+
logger.debug(error.message);
|
|
128
|
+
}
|
|
129
|
+
_write(chunk, _encoding, callback) {
|
|
130
|
+
this.commit();
|
|
131
|
+
const bytes = toBytes(chunk);
|
|
132
|
+
if (bytes === undefined) {
|
|
133
|
+
callback(new TypeError('An event stream carries bytes only.'));
|
|
134
|
+
return;
|
|
135
|
+
}
|
|
136
|
+
this.enqueue(bytes);
|
|
137
|
+
callback();
|
|
138
|
+
}
|
|
139
|
+
_final(callback) {
|
|
140
|
+
this.finish();
|
|
141
|
+
callback();
|
|
142
|
+
}
|
|
143
|
+
_destroy(error, callback) {
|
|
144
|
+
this.finish();
|
|
145
|
+
callback(error);
|
|
146
|
+
}
|
|
147
|
+
}
|
|
148
|
+
/** The headers Hono already recorded for the answer. */
|
|
149
|
+
function recordedHeaders(context) {
|
|
150
|
+
const record = {};
|
|
151
|
+
for (const [name, value] of context.res.headers) {
|
|
152
|
+
if (name !== 'content-type') {
|
|
153
|
+
record[name] = value;
|
|
154
|
+
}
|
|
155
|
+
}
|
|
156
|
+
return record;
|
|
157
|
+
}
|
|
158
|
+
/**
|
|
159
|
+
* Gives the object Nest reads as its response the surface its
|
|
160
|
+
* SSE path touches, so the same object serves every supported
|
|
161
|
+
* Nest major.
|
|
162
|
+
*
|
|
163
|
+
* Nest 11 and 12 both prefer `res.raw` when it is set, and Nest
|
|
164
|
+
* 12 never reads the response's own members then. Pointing
|
|
165
|
+
* `raw` at this writable is what keeps the frames travelling
|
|
166
|
+
* through Hono: writing them straight into `c.env.outgoing`
|
|
167
|
+
* would bypass the `Response` this adapter returns, and the
|
|
168
|
+
* transport would then write that response into the same socket
|
|
169
|
+
* a second time. `req.raw` is the real incoming message, which
|
|
170
|
+
* is what tunes the socket and reports a disconnect.
|
|
171
|
+
*/
|
|
172
|
+
function installSurface(context, response) {
|
|
173
|
+
Object.defineProperties(context, {
|
|
174
|
+
raw: { configurable: true, value: response },
|
|
175
|
+
statusCode: {
|
|
176
|
+
configurable: true,
|
|
177
|
+
get: () => response.statusCode,
|
|
178
|
+
},
|
|
179
|
+
writableEnded: {
|
|
180
|
+
configurable: true,
|
|
181
|
+
get: () => response.writableEnded,
|
|
182
|
+
},
|
|
183
|
+
});
|
|
184
|
+
Object.assign(context, {
|
|
185
|
+
emit: response.emit.bind(response),
|
|
186
|
+
end: response.end.bind(response),
|
|
187
|
+
flushHeaders: response.flushHeaders.bind(response),
|
|
188
|
+
getHeaders: () => recordedHeaders(context),
|
|
189
|
+
on: response.on.bind(response),
|
|
190
|
+
once: response.once.bind(response),
|
|
191
|
+
removeListener: response.removeListener.bind(response),
|
|
192
|
+
setHeader: response.setHeader.bind(response),
|
|
193
|
+
write: response.write.bind(response),
|
|
194
|
+
writeHead: response.writeHead.bind(response),
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
/**
|
|
198
|
+
* Opens an event stream on the response Nest reads, and says
|
|
199
|
+
* when it started. The stream is the destination `SseStream`
|
|
200
|
+
* pipes into, so nothing is buffered until Nest commits the
|
|
201
|
+
* headers, which is also the moment the promise settles.
|
|
202
|
+
*/
|
|
203
|
+
function mountSse(context, status) {
|
|
204
|
+
const response = new SseResponse(status, (answer) => {
|
|
205
|
+
context.res = answer;
|
|
206
|
+
});
|
|
207
|
+
installSurface(context, response);
|
|
208
|
+
return once(response, STARTED);
|
|
209
|
+
}
|
|
210
|
+
export { SseResponse, mountSse };
|
|
211
|
+
//# sourceMappingURL=sse.js.map
|
package/dist/sse.js.map
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"sse.js","sourceRoot":"","sources":["../src/sse.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import type { NestHono } from './context.ts';
|
|
2
|
+
/**
|
|
3
|
+
* The options Nest accepts for static assets. They are declared
|
|
4
|
+
* here because Nest types the parameter as `any` on both the
|
|
5
|
+
* application and the adapter, so nothing can be taken from a
|
|
6
|
+
* signature.
|
|
7
|
+
*
|
|
8
|
+
* The options Hono's handler decides for itself are refused
|
|
9
|
+
* rather than ignored, so a deployment finds out at startup
|
|
10
|
+
* instead of from a response that quietly differs from the one
|
|
11
|
+
* that was asked for.
|
|
12
|
+
*/
|
|
13
|
+
interface StaticAssetsOptions {
|
|
14
|
+
readonly dotfiles?: string;
|
|
15
|
+
readonly etag?: boolean;
|
|
16
|
+
readonly extensions?: readonly string[];
|
|
17
|
+
readonly fallthrough?: boolean;
|
|
18
|
+
readonly immutable?: boolean;
|
|
19
|
+
readonly index?: string | false;
|
|
20
|
+
readonly maxAge?: number | string;
|
|
21
|
+
readonly prefix?: string;
|
|
22
|
+
readonly redirect?: boolean;
|
|
23
|
+
readonly setHeaders?: unknown;
|
|
24
|
+
}
|
|
25
|
+
/** The directories a call named, as a list. */
|
|
26
|
+
declare function toDirectories(path: string | readonly string[]): readonly string[];
|
|
27
|
+
/**
|
|
28
|
+
* Mounts the directories a deployment named, under the prefix
|
|
29
|
+
* it asked for.
|
|
30
|
+
*
|
|
31
|
+
* A request that names no file in them travels on, which is
|
|
32
|
+
* what Nest's own middleware does: the routes behind it answer,
|
|
33
|
+
* and an answer the deployment asked for is written before
|
|
34
|
+
* that.
|
|
35
|
+
*/
|
|
36
|
+
declare function mountStaticAssets(hono: NestHono, path: string | readonly string[], options: StaticAssetsOptions): void;
|
|
37
|
+
export { mountStaticAssets, toDirectories };
|
|
38
|
+
export type { StaticAssetsOptions };
|
|
39
|
+
//# sourceMappingURL=static-assets.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-assets.d.ts","sourceRoot":"","sources":["../src/static-assets.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAEV,QAAQ,EAET,MAAM,cAAc,CAAC;AAEtB;;;;;;;;;;GAUG;AACH,UAAU,mBAAmB;IAC3B,QAAQ,CAAC,QAAQ,CAAC,EAAE,MAAM,CAAC;IAC3B,QAAQ,CAAC,IAAI,CAAC,EAAE,OAAO,CAAC;IACxB,QAAQ,CAAC,UAAU,CAAC,EAAE,SAAS,MAAM,EAAE,CAAC;IACxC,QAAQ,CAAC,WAAW,CAAC,EAAE,OAAO,CAAC;IAC/B,QAAQ,CAAC,SAAS,CAAC,EAAE,OAAO,CAAC;IAC7B,QAAQ,CAAC,KAAK,CAAC,EAAE,MAAM,GAAG,KAAK,CAAC;IAChC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,GAAG,MAAM,CAAC;IAClC,QAAQ,CAAC,MAAM,CAAC,EAAE,MAAM,CAAC;IACzB,QAAQ,CAAC,QAAQ,CAAC,EAAE,OAAO,CAAC;IAC5B,QAAQ,CAAC,UAAU,CAAC,EAAE,OAAO,CAAC;CAC/B;AAwCD,+CAA+C;AAC/C,iBAAS,aAAa,CACpB,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GAC/B,SAAS,MAAM,EAAE,CAMnB;AA6ID;;;;;;;;GAQG;AACH,iBAAS,iBAAiB,CACxB,IAAI,EAAE,QAAQ,EACd,IAAI,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,EAChC,OAAO,EAAE,mBAAmB,GAC3B,IAAI,CASN;AAED,OAAO,EAAE,iBAAiB,EAAE,aAAa,EAAE,CAAC;AAC5C,YAAY,EAAE,mBAAmB,EAAE,CAAC"}
|