@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,155 @@
|
|
|
1
|
+
import { serveStatic } from '@hono/node-server/serve-static';
|
|
2
|
+
/** The index file a directory request is answered with. */
|
|
3
|
+
const DEFAULT_INDEX = 'index.html';
|
|
4
|
+
/** The header a cache lifetime is written with. */
|
|
5
|
+
const CACHE_CONTROL = 'cache-control';
|
|
6
|
+
/** How long each named unit lasts, in milliseconds. */
|
|
7
|
+
const MILLISECOND = 1;
|
|
8
|
+
const SECOND = 1000;
|
|
9
|
+
const MINUTE = 60_000;
|
|
10
|
+
const HOUR = 3_600_000;
|
|
11
|
+
const DAY = 86_400_000;
|
|
12
|
+
const WEEK = 604_800_000;
|
|
13
|
+
const YEAR = 31_536_000_000;
|
|
14
|
+
/** The milliseconds one unit of a duration lasts. */
|
|
15
|
+
const UNIT_MS = new Map([
|
|
16
|
+
['d', DAY],
|
|
17
|
+
['h', HOUR],
|
|
18
|
+
['m', MINUTE],
|
|
19
|
+
['ms', MILLISECOND],
|
|
20
|
+
['s', SECOND],
|
|
21
|
+
['w', WEEK],
|
|
22
|
+
['y', YEAR],
|
|
23
|
+
]);
|
|
24
|
+
/** A cache lifetime, spelled the way the `ms` package spells it. */
|
|
25
|
+
const DURATION = /^(?<amount>\d+(?:\.\d+)?)\s*(?<unit>ms|s|m|h|d|w|y)?$/u;
|
|
26
|
+
/** Names the option the Hono handler cannot honour. */
|
|
27
|
+
function unsupported(name) {
|
|
28
|
+
return new TypeError('The Hono adapter cannot honour the static asset ' +
|
|
29
|
+
`option ${name}.`);
|
|
30
|
+
}
|
|
31
|
+
/** The directories a call named, as a list. */
|
|
32
|
+
function toDirectories(path) {
|
|
33
|
+
if (typeof path === 'string') {
|
|
34
|
+
return [path];
|
|
35
|
+
}
|
|
36
|
+
return path;
|
|
37
|
+
}
|
|
38
|
+
/** Refuses the options that hook into another server. */
|
|
39
|
+
function assertNoHooks(options) {
|
|
40
|
+
if (options.setHeaders !== undefined) {
|
|
41
|
+
throw unsupported('setHeaders');
|
|
42
|
+
}
|
|
43
|
+
if (options.extensions !== undefined) {
|
|
44
|
+
throw unsupported('extensions');
|
|
45
|
+
}
|
|
46
|
+
if (options.etag === false) {
|
|
47
|
+
throw unsupported('etag: false');
|
|
48
|
+
}
|
|
49
|
+
}
|
|
50
|
+
/** Refuses the options that ask for another serving mode. */
|
|
51
|
+
function assertNoOtherModes(options) {
|
|
52
|
+
if (options.fallthrough === false) {
|
|
53
|
+
throw unsupported('fallthrough: false');
|
|
54
|
+
}
|
|
55
|
+
if (options.dotfiles !== undefined) {
|
|
56
|
+
throw unsupported('dotfiles');
|
|
57
|
+
}
|
|
58
|
+
if (options.index === false) {
|
|
59
|
+
throw unsupported('index: false');
|
|
60
|
+
}
|
|
61
|
+
if (options.immutable === true &&
|
|
62
|
+
options.maxAge === undefined) {
|
|
63
|
+
throw new TypeError('The Hono adapter writes immutability with a maximum ' +
|
|
64
|
+
'age, so maxAge has to be named with it.');
|
|
65
|
+
}
|
|
66
|
+
}
|
|
67
|
+
function assertSupported(options) {
|
|
68
|
+
assertNoHooks(options);
|
|
69
|
+
assertNoOtherModes(options);
|
|
70
|
+
}
|
|
71
|
+
/** The milliseconds a cache lifetime names. */
|
|
72
|
+
function toMilliseconds(maxAge) {
|
|
73
|
+
if (typeof maxAge === 'number') {
|
|
74
|
+
return maxAge;
|
|
75
|
+
}
|
|
76
|
+
const match = DURATION.exec(maxAge.trim());
|
|
77
|
+
if (match === null) {
|
|
78
|
+
throw unsupported(`maxAge: ${maxAge}`);
|
|
79
|
+
}
|
|
80
|
+
const { amount, unit } = match.groups ?? {};
|
|
81
|
+
const scale = UNIT_MS.get(unit ?? 'ms');
|
|
82
|
+
if (scale === undefined) {
|
|
83
|
+
throw unsupported(`maxAge: ${maxAge}`);
|
|
84
|
+
}
|
|
85
|
+
return Number(amount) * scale;
|
|
86
|
+
}
|
|
87
|
+
/** The header a served file is cached with. */
|
|
88
|
+
function cacheControl(options) {
|
|
89
|
+
const milliseconds = toMilliseconds(options.maxAge ?? 0);
|
|
90
|
+
const seconds = Math.floor(milliseconds / SECOND);
|
|
91
|
+
const base = `public, max-age=${seconds}`;
|
|
92
|
+
if (options.immutable === true) {
|
|
93
|
+
return `${base}, immutable`;
|
|
94
|
+
}
|
|
95
|
+
return base;
|
|
96
|
+
}
|
|
97
|
+
/** Writes the cache lifetime a deployment asked for. */
|
|
98
|
+
function setCacheControl(context, options) {
|
|
99
|
+
if (options.maxAge === undefined) {
|
|
100
|
+
return;
|
|
101
|
+
}
|
|
102
|
+
context.header(CACHE_CONTROL, cacheControl(options));
|
|
103
|
+
}
|
|
104
|
+
/** The index file a directory request is answered with. */
|
|
105
|
+
function indexOf(options) {
|
|
106
|
+
if (typeof options.index === 'string') {
|
|
107
|
+
return options.index;
|
|
108
|
+
}
|
|
109
|
+
return DEFAULT_INDEX;
|
|
110
|
+
}
|
|
111
|
+
/** The request path without the prefix the assets hang under. */
|
|
112
|
+
function withoutPrefix(requestPath, prefix) {
|
|
113
|
+
if (prefix === undefined || prefix === '') {
|
|
114
|
+
return requestPath;
|
|
115
|
+
}
|
|
116
|
+
return requestPath.slice(prefix.length);
|
|
117
|
+
}
|
|
118
|
+
/** The paths one mount answers on. */
|
|
119
|
+
function mountPaths(prefix) {
|
|
120
|
+
if (prefix === undefined || prefix === '') {
|
|
121
|
+
return ['/*'];
|
|
122
|
+
}
|
|
123
|
+
return [prefix, `${prefix}/*`];
|
|
124
|
+
}
|
|
125
|
+
/** The handler that serves one directory. */
|
|
126
|
+
function directoryHandler(directory, options) {
|
|
127
|
+
return serveStatic({
|
|
128
|
+
index: indexOf(options),
|
|
129
|
+
onFound: (_file, context) => {
|
|
130
|
+
setCacheControl(context, options);
|
|
131
|
+
},
|
|
132
|
+
rewriteRequestPath: (path) => withoutPrefix(path, options.prefix),
|
|
133
|
+
root: directory,
|
|
134
|
+
});
|
|
135
|
+
}
|
|
136
|
+
/**
|
|
137
|
+
* Mounts the directories a deployment named, under the prefix
|
|
138
|
+
* it asked for.
|
|
139
|
+
*
|
|
140
|
+
* A request that names no file in them travels on, which is
|
|
141
|
+
* what Nest's own middleware does: the routes behind it answer,
|
|
142
|
+
* and an answer the deployment asked for is written before
|
|
143
|
+
* that.
|
|
144
|
+
*/
|
|
145
|
+
function mountStaticAssets(hono, path, options) {
|
|
146
|
+
assertSupported(options);
|
|
147
|
+
const mounts = mountPaths(options.prefix);
|
|
148
|
+
for (const directory of toDirectories(path)) {
|
|
149
|
+
for (const mount of mounts) {
|
|
150
|
+
hono.use(mount, directoryHandler(directory, options));
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
}
|
|
154
|
+
export { mountStaticAssets, toDirectories };
|
|
155
|
+
//# sourceMappingURL=static-assets.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"static-assets.js","sourceRoot":"","sources":["../src/static-assets.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
import { VERSION_NEUTRAL } from '@nestjs/common';
|
|
2
|
+
import type { VersioningOptions } from '@nestjs/common';
|
|
3
|
+
import type { NestHandler } from './bridge.ts';
|
|
4
|
+
/**
|
|
5
|
+
* Mirrors VersionValue in version-options.interface, which
|
|
6
|
+
*
|
|
7
|
+
* @nestjs/common does not export: reading it from an internal
|
|
8
|
+
* path would tie the package to a path Nest may move.
|
|
9
|
+
*/
|
|
10
|
+
type VersionValue = string | typeof VERSION_NEUTRAL | (string | typeof VERSION_NEUTRAL)[];
|
|
11
|
+
/**
|
|
12
|
+
* Guards a route handler by request version for the versioning
|
|
13
|
+
* styles the route path does not already resolve. The logic
|
|
14
|
+
* mirrors Nest's own adapters, so a versioned route behaves the
|
|
15
|
+
* same way on Hono.
|
|
16
|
+
*
|
|
17
|
+
* URI versioning is a plain path prefix and needs no filter. A
|
|
18
|
+
* request that asks for an unknown version is passed on rather
|
|
19
|
+
* than rejected, which is how Nest keeps an older version
|
|
20
|
+
* serving the same route.
|
|
21
|
+
*/
|
|
22
|
+
declare function createVersionFilter(handler: NestHandler, version: VersionValue, options: VersioningOptions): NestHandler;
|
|
23
|
+
export { createVersionFilter, type VersionValue };
|
|
24
|
+
//# sourceMappingURL=version-filter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-filter.d.ts","sourceRoot":"","sources":["../src/version-filter.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,eAAe,EAEhB,MAAM,gBAAgB,CAAC;AACxB,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,gBAAgB,CAAC;AACxD,OAAO,KAAK,EAAE,WAAW,EAAe,MAAM,aAAa,CAAC;AAE5D;;;;;GAKG;AACH,KAAK,YAAY,GACb,MAAM,GACN,OAAO,eAAe,GACtB,CAAC,MAAM,GAAG,OAAO,eAAe,CAAC,EAAE,CAAC;AAsHxC;;;;;;;;;;GAUG;AACH,iBAAS,mBAAmB,CAC1B,OAAO,EAAE,WAAW,EACpB,OAAO,EAAE,YAAY,EACrB,OAAO,EAAE,iBAAiB,GACzB,WAAW,CAkBb;AAED,OAAO,EAAE,mBAAmB,EAAE,KAAK,YAAY,EAAE,CAAC"}
|
|
@@ -0,0 +1,107 @@
|
|
|
1
|
+
import { VERSION_NEUTRAL, VersioningType, } from '@nestjs/common';
|
|
2
|
+
function readHeader(request, name) {
|
|
3
|
+
return (request.headers[name] ?? request.headers[name.toLowerCase()]);
|
|
4
|
+
}
|
|
5
|
+
function isNeutral(version) {
|
|
6
|
+
return (Array.isArray(version) && version.includes(VERSION_NEUTRAL));
|
|
7
|
+
}
|
|
8
|
+
/**
|
|
9
|
+
* Normalises a version, or a list of them, into a list. The
|
|
10
|
+
* neutral marker is a symbol, so the list type is widened to
|
|
11
|
+
* match it.
|
|
12
|
+
*/
|
|
13
|
+
function toVersionList(value) {
|
|
14
|
+
if (Array.isArray(value)) {
|
|
15
|
+
return value;
|
|
16
|
+
}
|
|
17
|
+
return [value];
|
|
18
|
+
}
|
|
19
|
+
function matchesVersion(version, supplied) {
|
|
20
|
+
if (supplied === undefined) {
|
|
21
|
+
return false;
|
|
22
|
+
}
|
|
23
|
+
const suppliedVersions = toVersionList(supplied);
|
|
24
|
+
const acceptedVersions = toVersionList(version);
|
|
25
|
+
return acceptedVersions.some((accepted) => suppliedVersions.includes(accepted));
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Reads the version parameter out of the `Accept` header, which
|
|
29
|
+
* looks like `application/json;v=1`.
|
|
30
|
+
*/
|
|
31
|
+
function readMediaTypeParameter(request) {
|
|
32
|
+
const accept = readHeader(request, 'accept');
|
|
33
|
+
if (accept === undefined) {
|
|
34
|
+
return undefined;
|
|
35
|
+
}
|
|
36
|
+
const [, parameter] = accept.split(';');
|
|
37
|
+
return parameter;
|
|
38
|
+
}
|
|
39
|
+
/**
|
|
40
|
+
* Answers every request whose version the extractor resolves to
|
|
41
|
+
* one this route serves.
|
|
42
|
+
*/
|
|
43
|
+
function createCustomFilter(handler, version, extractor) {
|
|
44
|
+
return (request, response, next) => {
|
|
45
|
+
if (matchesVersion(version, extractor(request))) {
|
|
46
|
+
return handler(request, response, next);
|
|
47
|
+
}
|
|
48
|
+
return next();
|
|
49
|
+
};
|
|
50
|
+
}
|
|
51
|
+
function createMediaTypeFilter(handler, version, key) {
|
|
52
|
+
return (request, response, next) => {
|
|
53
|
+
const parameter = readMediaTypeParameter(request);
|
|
54
|
+
if (parameter === undefined) {
|
|
55
|
+
if (isNeutral(version)) {
|
|
56
|
+
return handler(request, response, next);
|
|
57
|
+
}
|
|
58
|
+
return next();
|
|
59
|
+
}
|
|
60
|
+
const [, supplied] = parameter.split(key);
|
|
61
|
+
if (matchesVersion(version, supplied)) {
|
|
62
|
+
return handler(request, response, next);
|
|
63
|
+
}
|
|
64
|
+
return next();
|
|
65
|
+
};
|
|
66
|
+
}
|
|
67
|
+
function createHeaderFilter(handler, version, name) {
|
|
68
|
+
return (request, response, next) => {
|
|
69
|
+
const supplied = readHeader(request, name.toLowerCase());
|
|
70
|
+
if (supplied === undefined) {
|
|
71
|
+
if (isNeutral(version)) {
|
|
72
|
+
return handler(request, response, next);
|
|
73
|
+
}
|
|
74
|
+
return next();
|
|
75
|
+
}
|
|
76
|
+
if (matchesVersion(version, supplied)) {
|
|
77
|
+
return handler(request, response, next);
|
|
78
|
+
}
|
|
79
|
+
return next();
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Guards a route handler by request version for the versioning
|
|
84
|
+
* styles the route path does not already resolve. The logic
|
|
85
|
+
* mirrors Nest's own adapters, so a versioned route behaves the
|
|
86
|
+
* same way on Hono.
|
|
87
|
+
*
|
|
88
|
+
* URI versioning is a plain path prefix and needs no filter. A
|
|
89
|
+
* request that asks for an unknown version is passed on rather
|
|
90
|
+
* than rejected, which is how Nest keeps an older version
|
|
91
|
+
* serving the same route.
|
|
92
|
+
*/
|
|
93
|
+
function createVersionFilter(handler, version, options) {
|
|
94
|
+
if (version === VERSION_NEUTRAL ||
|
|
95
|
+
options.type === VersioningType.URI) {
|
|
96
|
+
return handler;
|
|
97
|
+
}
|
|
98
|
+
if (options.type === VersioningType.CUSTOM) {
|
|
99
|
+
return createCustomFilter(handler, version, options.extractor);
|
|
100
|
+
}
|
|
101
|
+
if (options.type === VersioningType.MEDIA_TYPE) {
|
|
102
|
+
return createMediaTypeFilter(handler, version, options.key);
|
|
103
|
+
}
|
|
104
|
+
return createHeaderFilter(handler, version, options.header);
|
|
105
|
+
}
|
|
106
|
+
export { createVersionFilter };
|
|
107
|
+
//# sourceMappingURL=version-filter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"version-filter.js","sourceRoot":"","sources":["../src/version-filter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { AbstractHttpAdapter } from '@nestjs/core';
|
|
2
|
+
import type { NestHandler } from './bridge.ts';
|
|
3
|
+
/**
|
|
4
|
+
* A versioned route as the adapter contract declares it. It is
|
|
5
|
+
* derived from the base class rather than written out, because
|
|
6
|
+
* Nest types the value such a route resolves to as `Function`.
|
|
7
|
+
*/
|
|
8
|
+
type VersionedRoute = ReturnType<AbstractHttpAdapter['applyVersionFilter']>;
|
|
9
|
+
/**
|
|
10
|
+
* Narrows a version filter to the type the contract asks for.
|
|
11
|
+
*
|
|
12
|
+
* The contract says a versioned route resolves to a `Function`,
|
|
13
|
+
* which no handler answering with a response can satisfy. The
|
|
14
|
+
* router only ever calls the function it is handed, so the two
|
|
15
|
+
* differ in the type alone. Confining the assertion here keeps
|
|
16
|
+
* the rest of the adapter free of them, and `no-unsafe-type-
|
|
17
|
+
* assertion` is disabled for this file alone.
|
|
18
|
+
*/
|
|
19
|
+
declare function asVersionedRoute(handler: NestHandler): VersionedRoute;
|
|
20
|
+
export { asVersionedRoute, type VersionedRoute };
|
|
21
|
+
//# sourceMappingURL=versioned-route.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versioned-route.d.ts","sourceRoot":"","sources":["../src/versioned-route.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,mBAAmB,EAAE,MAAM,cAAc,CAAC;AAExD,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAC;AAE/C;;;;GAIG;AACH,KAAK,cAAc,GAAG,UAAU,CAC9B,mBAAmB,CAAC,oBAAoB,CAAC,CAC1C,CAAC;AAEF;;;;;;;;;GASG;AACH,iBAAS,gBAAgB,CACvB,OAAO,EAAE,WAAW,GACnB,cAAc,CAEhB;AAED,OAAO,EAAE,gBAAgB,EAAE,KAAK,cAAc,EAAE,CAAC"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Narrows a version filter to the type the contract asks for.
|
|
3
|
+
*
|
|
4
|
+
* The contract says a versioned route resolves to a `Function`,
|
|
5
|
+
* which no handler answering with a response can satisfy. The
|
|
6
|
+
* router only ever calls the function it is handed, so the two
|
|
7
|
+
* differ in the type alone. Confining the assertion here keeps
|
|
8
|
+
* the rest of the adapter free of them, and `no-unsafe-type-
|
|
9
|
+
* assertion` is disabled for this file alone.
|
|
10
|
+
*/
|
|
11
|
+
function asVersionedRoute(handler) {
|
|
12
|
+
return handler;
|
|
13
|
+
}
|
|
14
|
+
export { asVersionedRoute };
|
|
15
|
+
//# sourceMappingURL=versioned-route.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"versioned-route.js","sourceRoot":"","sources":["../src/versioned-route.ts"],"names":[],"mappings":"AAaA;;;;;;;;;GASG;AACH,SAAS,gBAAgB,CACvB,OAAoB;IAEpB,OAAO,OAAyB,CAAC;AACnC,CAAC;AAED,OAAO,EAAE,gBAAgB,EAAuB,CAAC"}
|
package/dist/views.d.ts
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import type { NestContext } from './context.ts';
|
|
2
|
+
/** The data a template is rendered with. */
|
|
3
|
+
type ViewData = Record<string, unknown>;
|
|
4
|
+
/**
|
|
5
|
+
* Renders a template's source into the answer.
|
|
6
|
+
*
|
|
7
|
+
* The engine is handed the source rather than a file name, so
|
|
8
|
+
* every engine is reached the same way: the lines that compile
|
|
9
|
+
* and run a template belong to the application, which already
|
|
10
|
+
* knows which engine it uses.
|
|
11
|
+
*/
|
|
12
|
+
type ViewEngine = (source: string, data: ViewData) => string | Promise<string>;
|
|
13
|
+
/** The views a deployment configures. */
|
|
14
|
+
interface ViewOptions {
|
|
15
|
+
readonly directory?: string | readonly string[];
|
|
16
|
+
readonly engine: ViewEngine;
|
|
17
|
+
}
|
|
18
|
+
/**
|
|
19
|
+
* Renders the templates a deployment configured.
|
|
20
|
+
*
|
|
21
|
+
* The engine is optional because an application that renders
|
|
22
|
+
* nothing never configures one: naming an engine is what makes
|
|
23
|
+
* it required, and that happens at startup rather than at the
|
|
24
|
+
* first request that renders.
|
|
25
|
+
*/
|
|
26
|
+
declare class ViewRenderer {
|
|
27
|
+
private readonly engine;
|
|
28
|
+
private directories;
|
|
29
|
+
private extension;
|
|
30
|
+
constructor(views: ViewOptions | undefined);
|
|
31
|
+
/** Names the engine, by the extension it renders. */
|
|
32
|
+
useEngine(name: string): void;
|
|
33
|
+
/** Names the directories a view is read from. */
|
|
34
|
+
useDirectories(directory: string | readonly string[]): void;
|
|
35
|
+
/** Renders one view into the response Nest handed over. */
|
|
36
|
+
render(response: NestContext, view: string, options: unknown): Promise<void>;
|
|
37
|
+
/** The directories to read from, the working one by default. */
|
|
38
|
+
private directoriesFor;
|
|
39
|
+
}
|
|
40
|
+
export { ViewRenderer };
|
|
41
|
+
export type { ViewData, ViewEngine, ViewOptions };
|
|
42
|
+
//# sourceMappingURL=views.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.d.ts","sourceRoot":"","sources":["../src/views.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,cAAc,CAAC;AAGhD,4CAA4C;AAC5C,KAAK,QAAQ,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;AAExC;;;;;;;GAOG;AACH,KAAK,UAAU,GAAG,CAChB,MAAM,EAAE,MAAM,EACd,IAAI,EAAE,QAAQ,KACX,MAAM,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;AAE9B,yCAAyC;AACzC,UAAU,WAAW;IACnB,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,CAAC;IAChD,QAAQ,CAAC,MAAM,EAAE,UAAU,CAAC;CAC7B;AAwFD;;;;;;;GAOG;AACH,cAAM,YAAY;IAChB,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAyB;IAChD,OAAO,CAAC,WAAW,CAAyB;IAC5C,OAAO,CAAC,SAAS,CAAM;IAEvB,YAAmB,KAAK,EAAE,WAAW,GAAG,SAAS,EAGhD;IAED,qDAAqD;IAC9C,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,IAAI,CASnC;IAED,iDAAiD;IAC1C,cAAc,CACnB,SAAS,EAAE,MAAM,GAAG,SAAS,MAAM,EAAE,GACpC,IAAI,CAEN;IAED,2DAA2D;IAC9C,MAAM,CACjB,QAAQ,EAAE,WAAW,EACrB,IAAI,EAAE,MAAM,EACZ,OAAO,EAAE,OAAO,GACf,OAAO,CAAC,IAAI,CAAC,CAgBf;IAED,gEAAgE;IAChE,OAAO,CAAC,cAAc;CAOvB;AAED,OAAO,EAAE,YAAY,EAAE,CAAC;AACxB,YAAY,EAAE,QAAQ,EAAE,UAAU,EAAE,WAAW,EAAE,CAAC"}
|
package/dist/views.js
ADDED
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
import { readFile } from 'node:fs/promises';
|
|
2
|
+
import path from 'node:path';
|
|
3
|
+
import { NotFoundException } from '@nestjs/common';
|
|
4
|
+
import { toDirectories } from './static-assets.js';
|
|
5
|
+
function isRecord(value) {
|
|
6
|
+
return (typeof value === 'object' &&
|
|
7
|
+
value !== null &&
|
|
8
|
+
!Array.isArray(value));
|
|
9
|
+
}
|
|
10
|
+
/** The value a handler returned, as the object a template reads. */
|
|
11
|
+
function asData(options) {
|
|
12
|
+
if (isRecord(options)) {
|
|
13
|
+
return options;
|
|
14
|
+
}
|
|
15
|
+
return {};
|
|
16
|
+
}
|
|
17
|
+
/** The engine a deployment configured, when it configured one. */
|
|
18
|
+
function engineOf(views) {
|
|
19
|
+
if (views === undefined) {
|
|
20
|
+
return undefined;
|
|
21
|
+
}
|
|
22
|
+
return views.engine;
|
|
23
|
+
}
|
|
24
|
+
/** The directories a deployment configured, when it named any. */
|
|
25
|
+
function directoriesOf(views) {
|
|
26
|
+
if (views === undefined) {
|
|
27
|
+
return [];
|
|
28
|
+
}
|
|
29
|
+
const { directory } = views;
|
|
30
|
+
if (directory === undefined) {
|
|
31
|
+
return [];
|
|
32
|
+
}
|
|
33
|
+
return toDirectories(directory);
|
|
34
|
+
}
|
|
35
|
+
/** The extension a view engine names. */
|
|
36
|
+
function toExtension(engine) {
|
|
37
|
+
if (engine.startsWith('.')) {
|
|
38
|
+
return engine;
|
|
39
|
+
}
|
|
40
|
+
return `.${engine}`;
|
|
41
|
+
}
|
|
42
|
+
/** The file a view name reads, completed with the extension. */
|
|
43
|
+
function fileNameFor(view, extension) {
|
|
44
|
+
if (extension === '' || path.extname(view) !== '') {
|
|
45
|
+
return view;
|
|
46
|
+
}
|
|
47
|
+
return `${view}${extension}`;
|
|
48
|
+
}
|
|
49
|
+
/** Reads the first template that exists in the directories. */
|
|
50
|
+
async function readFrom(fileName, directories, position) {
|
|
51
|
+
const directory = directories[position];
|
|
52
|
+
if (directory === undefined) {
|
|
53
|
+
throw new NotFoundException(`No view named ${fileName} was found.`);
|
|
54
|
+
}
|
|
55
|
+
try {
|
|
56
|
+
return await readFile(path.join(directory, fileName), 'utf8');
|
|
57
|
+
}
|
|
58
|
+
catch {
|
|
59
|
+
// The next directory may hold it; the last one reports.
|
|
60
|
+
return readFrom(fileName, directories, position + 1);
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Renders the templates a deployment configured.
|
|
65
|
+
*
|
|
66
|
+
* The engine is optional because an application that renders
|
|
67
|
+
* nothing never configures one: naming an engine is what makes
|
|
68
|
+
* it required, and that happens at startup rather than at the
|
|
69
|
+
* first request that renders.
|
|
70
|
+
*/
|
|
71
|
+
class ViewRenderer {
|
|
72
|
+
constructor(views) {
|
|
73
|
+
this.directories = [];
|
|
74
|
+
this.extension = '';
|
|
75
|
+
this.engine = engineOf(views);
|
|
76
|
+
this.directories = directoriesOf(views);
|
|
77
|
+
}
|
|
78
|
+
/** Names the engine, by the extension it renders. */
|
|
79
|
+
useEngine(name) {
|
|
80
|
+
if (this.engine === undefined) {
|
|
81
|
+
throw new TypeError('The adapter renders with the engine it was given, so ' +
|
|
82
|
+
'pass `views.engine` before naming one.');
|
|
83
|
+
}
|
|
84
|
+
this.extension = toExtension(name);
|
|
85
|
+
}
|
|
86
|
+
/** Names the directories a view is read from. */
|
|
87
|
+
useDirectories(directory) {
|
|
88
|
+
this.directories = toDirectories(directory);
|
|
89
|
+
}
|
|
90
|
+
/** Renders one view into the response Nest handed over. */
|
|
91
|
+
async render(response, view, options) {
|
|
92
|
+
const { engine } = this;
|
|
93
|
+
if (engine === undefined) {
|
|
94
|
+
throw new TypeError('No view engine was configured, so no view renders.');
|
|
95
|
+
}
|
|
96
|
+
const fileName = fileNameFor(view, this.extension);
|
|
97
|
+
const source = await readFrom(fileName, this.directoriesFor(), 0);
|
|
98
|
+
const html = await engine(source, asData(options));
|
|
99
|
+
response.html(html);
|
|
100
|
+
}
|
|
101
|
+
/** The directories to read from, the working one by default. */
|
|
102
|
+
directoriesFor() {
|
|
103
|
+
if (this.directories.length === 0) {
|
|
104
|
+
return [process.cwd()];
|
|
105
|
+
}
|
|
106
|
+
return this.directories;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
export { ViewRenderer };
|
|
110
|
+
//# sourceMappingURL=views.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"views.js","sourceRoot":"","sources":["../src/views.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
import type { WsMessageHandler } from '@nestjs/common';
|
|
2
|
+
import { AbstractWsAdapter } from '@nestjs/websockets';
|
|
3
|
+
import type { Observable } from 'rxjs';
|
|
4
|
+
import type { ServerAdapter } from './server-adapter.ts';
|
|
5
|
+
import { HonoSocket } from './ws-client.ts';
|
|
6
|
+
import { GatewayServer } from './ws-server.ts';
|
|
7
|
+
/** What Nest passes to `create()` for one gateway. */
|
|
8
|
+
interface HonoGatewayOptions {
|
|
9
|
+
/** The path the gateway listens on. */
|
|
10
|
+
readonly path?: string;
|
|
11
|
+
/** The namespace the gateway asked for. */
|
|
12
|
+
readonly namespace?: string;
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* WebSocket adapter that runs Nest's gateways on the Hono
|
|
16
|
+
* application the HTTP adapter already serves.
|
|
17
|
+
*
|
|
18
|
+
* `@hono/node-ws` upgrades a request by asking the Hono
|
|
19
|
+
* application for the gateway path, so the upgrade happens on
|
|
20
|
+
* one server rather than on a second one opened beside it. One
|
|
21
|
+
* route is registered per path a gateway named, and each route
|
|
22
|
+
* hands Nest a {@link HonoSocket} to answer on.
|
|
23
|
+
*
|
|
24
|
+
* A gateway that asked for its own port or for a namespace
|
|
25
|
+
* cannot be served this way; both are refused rather than
|
|
26
|
+
* quietly served on the HTTP server.
|
|
27
|
+
*/
|
|
28
|
+
declare class HonoWsAdapter extends AbstractWsAdapter {
|
|
29
|
+
private readonly adapter;
|
|
30
|
+
private readonly node;
|
|
31
|
+
private readonly servers;
|
|
32
|
+
private readonly logger;
|
|
33
|
+
private detach;
|
|
34
|
+
private injected;
|
|
35
|
+
constructor(httpAdapter: ServerAdapter);
|
|
36
|
+
create(port: number, options?: HonoGatewayOptions): GatewayServer;
|
|
37
|
+
/**
|
|
38
|
+
* Bridges the handlers Nest explored for one client onto the
|
|
39
|
+
* frames that client sends. Every subscription is tied to the
|
|
40
|
+
* socket's own close event, so a connection that goes away
|
|
41
|
+
* takes its subscriptions with it.
|
|
42
|
+
*/
|
|
43
|
+
bindMessageHandlers(client: HonoSocket, handlers: WsMessageHandler[], transform: (data: unknown) => Observable<unknown>): void;
|
|
44
|
+
bindClientDisconnect(client: HonoSocket, callback: () => void): void;
|
|
45
|
+
/** Closes every socket a gateway path is serving. */
|
|
46
|
+
close(server: GatewayServer): Promise<void>;
|
|
47
|
+
/**
|
|
48
|
+
* Releases the paths, the sockets and the WebSocket server
|
|
49
|
+
* this adapter created, and takes the upgrade listeners back
|
|
50
|
+
* off the Node server.
|
|
51
|
+
*/
|
|
52
|
+
dispose(): Promise<void>;
|
|
53
|
+
/**
|
|
54
|
+
* Releases the paths, the sockets, the WebSocket server and
|
|
55
|
+
* the upgrade listeners this adapter registered.
|
|
56
|
+
*/
|
|
57
|
+
private release;
|
|
58
|
+
/**
|
|
59
|
+
* Serves one path, reusing the server already serving it:
|
|
60
|
+
* Nest asks once per path, and a repeated ask must not
|
|
61
|
+
* register the route twice.
|
|
62
|
+
*/
|
|
63
|
+
private open;
|
|
64
|
+
/** Registers the upgrade route one gateway path needs. */
|
|
65
|
+
private serve;
|
|
66
|
+
/** Lets the Node server hand upgrades to the Hono app. */
|
|
67
|
+
private inject;
|
|
68
|
+
/** Answers one frame, when a handler claims its event. */
|
|
69
|
+
private answer;
|
|
70
|
+
/** Runs one handler and turns its answer into frames. */
|
|
71
|
+
private invoke;
|
|
72
|
+
/** The frames one handler's stream answers with. */
|
|
73
|
+
private replies;
|
|
74
|
+
/** Reports a handler that failed and answers nothing. */
|
|
75
|
+
private report;
|
|
76
|
+
/** Refuses the gateways this adapter cannot serve. */
|
|
77
|
+
private ensureSupported;
|
|
78
|
+
}
|
|
79
|
+
export { HonoWsAdapter };
|
|
80
|
+
export type { HonoGatewayOptions };
|
|
81
|
+
//# sourceMappingURL=ws-adapter.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ws-adapter.d.ts","sourceRoot":"","sources":["../src/ws-adapter.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,gBAAgB,CAAC;AAEvD,OAAO,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAC;AAYvD,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,MAAM,CAAC;AAEvC,OAAO,KAAK,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACzD,OAAO,EAEL,UAAU,EAKX,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,aAAa,EAAE,MAAM,gBAAgB,CAAC;AAW/C,sDAAsD;AACtD,UAAU,kBAAkB;IAC1B,uCAAuC;IACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,MAAM,CAAC;IACvB,2CAA2C;IAC3C,QAAQ,CAAC,SAAS,CAAC,EAAE,MAAM,CAAC;CAC7B;AAoDD;;;;;;;;;;;;;GAaG;AACH,cAAM,aAAc,SAAQ,iBAAiB;IAC3C,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAgB;IACxC,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,OAAO,CAAC,QAAQ,CAAC,OAAO,CAAoC;IAC5D,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAkC;IACzD,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,QAAQ,CAAS;IAEzB,YAAmB,WAAW,EAAE,aAAa,EAM5C;IAEe,MAAM,CACpB,IAAI,EAAE,MAAM,EACZ,OAAO,GAAE,kBAAuB,GAC/B,aAAa,CAGf;IAED;;;;;OAKG;IACa,mBAAmB,CACjC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,gBAAgB,EAAE,EAC5B,SAAS,EAAE,CAAC,IAAI,EAAE,OAAO,KAAK,UAAU,CAAC,OAAO,CAAC,GAChD,IAAI,CAeN;IAEe,oBAAoB,CAClC,MAAM,EAAE,UAAU,EAClB,QAAQ,EAAE,MAAM,IAAI,GACnB,IAAI,CAEN;IAED,qDAAqD;IACrC,KAAK,CAAC,MAAM,EAAE,aAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CAG1D;IAED;;;;OAIG;IACa,OAAO,IAAI,OAAO,CAAC,IAAI,CAAC,CAGvC;IAED;;;OAGG;IACH,OAAO,CAAC,OAAO;IAef;;;;OAIG;IACH,OAAO,CAAC,IAAI;IAYZ,0DAA0D;IAC1D,OAAO,CAAC,KAAK;IAmBb,0DAA0D;IAC1D,OAAO,CAAC,MAAM;IAad,0DAA0D;IAC1D,OAAO,CAAC,MAAM;IAgBd,yDAAyD;IACzD,OAAO,CAAC,MAAM;IAed,oDAAoD;IACpD,OAAO,CAAC,OAAO;IAWf,yDAAyD;IACzD,OAAO,CAAC,MAAM;IAKd,sDAAsD;IACtD,OAAO,CAAC,eAAe;CAiBxB;AAED,OAAO,EAAE,aAAa,EAAE,CAAC;AACzB,YAAY,EAAE,kBAAkB,EAAE,CAAC"}
|