@hono/node-server 1.11.4 → 1.12.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/README.md CHANGED
@@ -169,7 +169,7 @@ my-hono-project/
169
169
  index.html
170
170
  ```
171
171
 
172
- Typically, you would run your app from the project's root directory (`my-hono-project`),
172
+ Typically, you would run your app from the project's root directory (`my-hono-project`),
173
173
  so you would need the following code to serve the `static` folder:
174
174
 
175
175
  ```ts
@@ -210,6 +210,19 @@ app.use(
210
210
  )
211
211
  ```
212
212
 
213
+ ## ConnInfo Helper
214
+
215
+ You can use the [ConnInfo Helper](https://hono.dev/docs/helpers/conninfo) by importing `getConnInfo` from `@hono/node-server/conninfo`.
216
+
217
+ ```ts
218
+ import { getConnInfo } from '@hono/node-server/conninfo'
219
+
220
+ app.get('/', (c) => {
221
+ const info = getConnInfo(c) // info is `ConnInfo`
222
+ return c.text(`Your remote address is ${info.remote.address}`)
223
+ })
224
+ ```
225
+
213
226
  ## Accessing Node.js API
214
227
 
215
228
  You can access the Node.js API from `c.env` in Node.js. For example, if you want to specify a type, you can write the following.
@@ -0,0 +1,10 @@
1
+ import { GetConnInfo } from 'hono/conninfo';
2
+
3
+ /**
4
+ * ConnInfo Helper for Node.js
5
+ * @param c Context
6
+ * @returns ConnInfo
7
+ */
8
+ declare const getConnInfo: GetConnInfo;
9
+
10
+ export { getConnInfo };
@@ -0,0 +1,10 @@
1
+ import { GetConnInfo } from 'hono/conninfo';
2
+
3
+ /**
4
+ * ConnInfo Helper for Node.js
5
+ * @param c Context
6
+ * @returns ConnInfo
7
+ */
8
+ declare const getConnInfo: GetConnInfo;
9
+
10
+ export { getConnInfo };
@@ -0,0 +1,45 @@
1
+ "use strict";
2
+ var __defProp = Object.defineProperty;
3
+ var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
4
+ var __getOwnPropNames = Object.getOwnPropertyNames;
5
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
6
+ var __export = (target, all) => {
7
+ for (var name in all)
8
+ __defProp(target, name, { get: all[name], enumerable: true });
9
+ };
10
+ var __copyProps = (to, from, except, desc) => {
11
+ if (from && typeof from === "object" || typeof from === "function") {
12
+ for (let key of __getOwnPropNames(from))
13
+ if (!__hasOwnProp.call(to, key) && key !== except)
14
+ __defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
15
+ }
16
+ return to;
17
+ };
18
+ var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
19
+
20
+ // src/conninfo.ts
21
+ var conninfo_exports = {};
22
+ __export(conninfo_exports, {
23
+ getConnInfo: () => getConnInfo
24
+ });
25
+ module.exports = __toCommonJS(conninfo_exports);
26
+ var getConnInfo = (c) => {
27
+ const bindings = c.env.server ? c.env.server : c.env;
28
+ const address = bindings.incoming.socket.address();
29
+ if (!("address" in address)) {
30
+ return {
31
+ remote: {}
32
+ };
33
+ }
34
+ return {
35
+ remote: {
36
+ address: address.address,
37
+ addressType: address.family === "IPv4" ? "IPv4" : address.family === "IPv6" ? "IPv6" : "unknown",
38
+ port: address.port
39
+ }
40
+ };
41
+ };
42
+ // Annotate the CommonJS export names for ESM import in node:
43
+ 0 && (module.exports = {
44
+ getConnInfo
45
+ });
@@ -0,0 +1,20 @@
1
+ // src/conninfo.ts
2
+ var getConnInfo = (c) => {
3
+ const bindings = c.env.server ? c.env.server : c.env;
4
+ const address = bindings.incoming.socket.address();
5
+ if (!("address" in address)) {
6
+ return {
7
+ remote: {}
8
+ };
9
+ }
10
+ return {
11
+ remote: {
12
+ address: address.address,
13
+ addressType: address.family === "IPv4" ? "IPv4" : address.family === "IPv6" ? "IPv6" : "unknown",
14
+ port: address.port
15
+ }
16
+ };
17
+ };
18
+ export {
19
+ getConnInfo
20
+ };
@@ -24,100 +24,8 @@ __export(serve_static_exports, {
24
24
  });
25
25
  module.exports = __toCommonJS(serve_static_exports);
26
26
  var import_fs = require("fs");
27
-
28
- // node_modules/hono/dist/utils/filepath.js
29
- var getFilePath = (options) => {
30
- let filename = options.filename;
31
- if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
32
- return;
33
- }
34
- let root = options.root || "";
35
- const defaultDocument = options.defaultDocument || "index.html";
36
- if (filename.endsWith("/")) {
37
- filename = filename.concat(defaultDocument);
38
- } else if (!filename.match(/\.[a-zA-Z0-9]+$/)) {
39
- filename = filename.concat("/" + defaultDocument);
40
- }
41
- filename = filename.replace(/^\.?[\/\\]/, "");
42
- filename = filename.replace(/\\/, "/");
43
- root = root.replace(/\/$/, "");
44
- let path = root ? root + "/" + filename : filename;
45
- path = path.replace(/^\.?\//, "");
46
- return path;
47
- };
48
-
49
- // node_modules/hono/dist/utils/mime.js
50
- var getMimeType = (filename, mimes = baseMimes) => {
51
- const regexp = /\.([a-zA-Z0-9]+?)$/;
52
- const match = filename.match(regexp);
53
- if (!match) {
54
- return;
55
- }
56
- let mimeType = mimes[match[1]];
57
- if (mimeType && mimeType.startsWith("text") || mimeType === "application/json") {
58
- mimeType += "; charset=utf-8";
59
- }
60
- return mimeType;
61
- };
62
- var baseMimes = {
63
- aac: "audio/aac",
64
- avi: "video/x-msvideo",
65
- avif: "image/avif",
66
- av1: "video/av1",
67
- bin: "application/octet-stream",
68
- bmp: "image/bmp",
69
- css: "text/css",
70
- csv: "text/csv",
71
- eot: "application/vnd.ms-fontobject",
72
- epub: "application/epub+zip",
73
- gif: "image/gif",
74
- gz: "application/gzip",
75
- htm: "text/html",
76
- html: "text/html",
77
- ico: "image/x-icon",
78
- ics: "text/calendar",
79
- jpeg: "image/jpeg",
80
- jpg: "image/jpeg",
81
- js: "text/javascript",
82
- json: "application/json",
83
- jsonld: "application/ld+json",
84
- map: "application/json",
85
- mid: "audio/x-midi",
86
- midi: "audio/x-midi",
87
- mjs: "text/javascript",
88
- mp3: "audio/mpeg",
89
- mp4: "video/mp4",
90
- mpeg: "video/mpeg",
91
- oga: "audio/ogg",
92
- ogv: "video/ogg",
93
- ogx: "application/ogg",
94
- opus: "audio/opus",
95
- otf: "font/otf",
96
- pdf: "application/pdf",
97
- png: "image/png",
98
- rtf: "application/rtf",
99
- svg: "image/svg+xml",
100
- tif: "image/tiff",
101
- tiff: "image/tiff",
102
- ts: "video/mp2t",
103
- ttf: "font/ttf",
104
- txt: "text/plain",
105
- wasm: "application/wasm",
106
- webm: "video/webm",
107
- weba: "audio/webm",
108
- webp: "image/webp",
109
- woff: "font/woff",
110
- woff2: "font/woff2",
111
- xhtml: "application/xhtml+xml",
112
- xml: "application/xml",
113
- zip: "application/zip",
114
- "3gp": "video/3gpp",
115
- "3g2": "video/3gpp2",
116
- gltf: "model/gltf+json",
117
- glb: "model/gltf-binary"
118
- };
119
-
120
- // src/serve-static.ts
27
+ var import_filepath = require("hono/utils/filepath");
28
+ var import_mime = require("hono/utils/mime");
121
29
  var createStreamBody = (stream) => {
122
30
  const body = new ReadableStream({
123
31
  start(controller) {
@@ -134,31 +42,55 @@ var createStreamBody = (stream) => {
134
42
  });
135
43
  return body;
136
44
  };
45
+ var addCurrentDirPrefix = (path) => {
46
+ return `./${path}`;
47
+ };
48
+ var getStats = (path) => {
49
+ let stats;
50
+ try {
51
+ stats = (0, import_fs.lstatSync)(path);
52
+ } catch {
53
+ }
54
+ return stats;
55
+ };
137
56
  var serveStatic = (options = { root: "" }) => {
138
57
  return async (c, next) => {
139
58
  if (c.finalized) {
140
59
  return next();
141
60
  }
142
61
  const filename = options.path ?? decodeURIComponent(c.req.path);
143
- let path = getFilePath({
62
+ let path = (0, import_filepath.getFilePathWithoutDefaultDocument)({
144
63
  filename: options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename,
145
- root: options.root,
146
- defaultDocument: options.index ?? "index.html"
64
+ root: options.root
147
65
  });
148
- if (!path) {
66
+ if (path) {
67
+ path = addCurrentDirPrefix(path);
68
+ } else {
149
69
  return next();
150
70
  }
151
- path = `./${path}`;
152
- if (!(0, import_fs.existsSync)(path)) {
71
+ let stats = getStats(path);
72
+ if (stats && stats.isDirectory()) {
73
+ path = (0, import_filepath.getFilePath)({
74
+ filename: options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename,
75
+ root: options.root,
76
+ defaultDocument: options.index ?? "index.html"
77
+ });
78
+ if (path) {
79
+ path = addCurrentDirPrefix(path);
80
+ } else {
81
+ return next();
82
+ }
83
+ stats = getStats(path);
84
+ }
85
+ if (!stats) {
153
86
  await options.onNotFound?.(path, c);
154
87
  return next();
155
88
  }
156
- const mimeType = getMimeType(path);
89
+ const mimeType = (0, import_mime.getMimeType)(path);
157
90
  if (mimeType) {
158
91
  c.header("Content-Type", mimeType);
159
92
  }
160
- const stat = (0, import_fs.lstatSync)(path);
161
- const size = stat.size;
93
+ const size = stats.size;
162
94
  if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
163
95
  c.header("Content-Length", size.toString());
164
96
  c.status(200);
@@ -170,17 +102,17 @@ var serveStatic = (options = { root: "" }) => {
170
102
  return c.body(createStreamBody((0, import_fs.createReadStream)(path)), 200);
171
103
  }
172
104
  c.header("Accept-Ranges", "bytes");
173
- c.header("Date", stat.birthtime.toUTCString());
105
+ c.header("Date", stats.birthtime.toUTCString());
174
106
  const parts = range.replace(/bytes=/, "").split("-", 2);
175
107
  const start = parts[0] ? parseInt(parts[0], 10) : 0;
176
- let end = parts[1] ? parseInt(parts[1], 10) : stat.size - 1;
108
+ let end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
177
109
  if (size < end - start + 1) {
178
110
  end = size - 1;
179
111
  }
180
112
  const chunksize = end - start + 1;
181
113
  const stream = (0, import_fs.createReadStream)(path, { start, end });
182
114
  c.header("Content-Length", chunksize.toString());
183
- c.header("Content-Range", `bytes ${start}-${end}/${stat.size}`);
115
+ c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
184
116
  return c.body(createStreamBody(stream), 206);
185
117
  };
186
118
  };
@@ -1,99 +1,7 @@
1
1
  // src/serve-static.ts
2
- import { createReadStream, existsSync, lstatSync } from "fs";
3
-
4
- // node_modules/hono/dist/utils/filepath.js
5
- var getFilePath = (options) => {
6
- let filename = options.filename;
7
- if (/(?:^|[\/\\])\.\.(?:$|[\/\\])/.test(filename)) {
8
- return;
9
- }
10
- let root = options.root || "";
11
- const defaultDocument = options.defaultDocument || "index.html";
12
- if (filename.endsWith("/")) {
13
- filename = filename.concat(defaultDocument);
14
- } else if (!filename.match(/\.[a-zA-Z0-9]+$/)) {
15
- filename = filename.concat("/" + defaultDocument);
16
- }
17
- filename = filename.replace(/^\.?[\/\\]/, "");
18
- filename = filename.replace(/\\/, "/");
19
- root = root.replace(/\/$/, "");
20
- let path = root ? root + "/" + filename : filename;
21
- path = path.replace(/^\.?\//, "");
22
- return path;
23
- };
24
-
25
- // node_modules/hono/dist/utils/mime.js
26
- var getMimeType = (filename, mimes = baseMimes) => {
27
- const regexp = /\.([a-zA-Z0-9]+?)$/;
28
- const match = filename.match(regexp);
29
- if (!match) {
30
- return;
31
- }
32
- let mimeType = mimes[match[1]];
33
- if (mimeType && mimeType.startsWith("text") || mimeType === "application/json") {
34
- mimeType += "; charset=utf-8";
35
- }
36
- return mimeType;
37
- };
38
- var baseMimes = {
39
- aac: "audio/aac",
40
- avi: "video/x-msvideo",
41
- avif: "image/avif",
42
- av1: "video/av1",
43
- bin: "application/octet-stream",
44
- bmp: "image/bmp",
45
- css: "text/css",
46
- csv: "text/csv",
47
- eot: "application/vnd.ms-fontobject",
48
- epub: "application/epub+zip",
49
- gif: "image/gif",
50
- gz: "application/gzip",
51
- htm: "text/html",
52
- html: "text/html",
53
- ico: "image/x-icon",
54
- ics: "text/calendar",
55
- jpeg: "image/jpeg",
56
- jpg: "image/jpeg",
57
- js: "text/javascript",
58
- json: "application/json",
59
- jsonld: "application/ld+json",
60
- map: "application/json",
61
- mid: "audio/x-midi",
62
- midi: "audio/x-midi",
63
- mjs: "text/javascript",
64
- mp3: "audio/mpeg",
65
- mp4: "video/mp4",
66
- mpeg: "video/mpeg",
67
- oga: "audio/ogg",
68
- ogv: "video/ogg",
69
- ogx: "application/ogg",
70
- opus: "audio/opus",
71
- otf: "font/otf",
72
- pdf: "application/pdf",
73
- png: "image/png",
74
- rtf: "application/rtf",
75
- svg: "image/svg+xml",
76
- tif: "image/tiff",
77
- tiff: "image/tiff",
78
- ts: "video/mp2t",
79
- ttf: "font/ttf",
80
- txt: "text/plain",
81
- wasm: "application/wasm",
82
- webm: "video/webm",
83
- weba: "audio/webm",
84
- webp: "image/webp",
85
- woff: "font/woff",
86
- woff2: "font/woff2",
87
- xhtml: "application/xhtml+xml",
88
- xml: "application/xml",
89
- zip: "application/zip",
90
- "3gp": "video/3gpp",
91
- "3g2": "video/3gpp2",
92
- gltf: "model/gltf+json",
93
- glb: "model/gltf-binary"
94
- };
95
-
96
- // src/serve-static.ts
2
+ import { createReadStream, lstatSync } from "fs";
3
+ import { getFilePath, getFilePathWithoutDefaultDocument } from "hono/utils/filepath";
4
+ import { getMimeType } from "hono/utils/mime";
97
5
  var createStreamBody = (stream) => {
98
6
  const body = new ReadableStream({
99
7
  start(controller) {
@@ -110,22 +18,47 @@ var createStreamBody = (stream) => {
110
18
  });
111
19
  return body;
112
20
  };
21
+ var addCurrentDirPrefix = (path) => {
22
+ return `./${path}`;
23
+ };
24
+ var getStats = (path) => {
25
+ let stats;
26
+ try {
27
+ stats = lstatSync(path);
28
+ } catch {
29
+ }
30
+ return stats;
31
+ };
113
32
  var serveStatic = (options = { root: "" }) => {
114
33
  return async (c, next) => {
115
34
  if (c.finalized) {
116
35
  return next();
117
36
  }
118
37
  const filename = options.path ?? decodeURIComponent(c.req.path);
119
- let path = getFilePath({
38
+ let path = getFilePathWithoutDefaultDocument({
120
39
  filename: options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename,
121
- root: options.root,
122
- defaultDocument: options.index ?? "index.html"
40
+ root: options.root
123
41
  });
124
- if (!path) {
42
+ if (path) {
43
+ path = addCurrentDirPrefix(path);
44
+ } else {
125
45
  return next();
126
46
  }
127
- path = `./${path}`;
128
- if (!existsSync(path)) {
47
+ let stats = getStats(path);
48
+ if (stats && stats.isDirectory()) {
49
+ path = getFilePath({
50
+ filename: options.rewriteRequestPath ? options.rewriteRequestPath(filename) : filename,
51
+ root: options.root,
52
+ defaultDocument: options.index ?? "index.html"
53
+ });
54
+ if (path) {
55
+ path = addCurrentDirPrefix(path);
56
+ } else {
57
+ return next();
58
+ }
59
+ stats = getStats(path);
60
+ }
61
+ if (!stats) {
129
62
  await options.onNotFound?.(path, c);
130
63
  return next();
131
64
  }
@@ -133,8 +66,7 @@ var serveStatic = (options = { root: "" }) => {
133
66
  if (mimeType) {
134
67
  c.header("Content-Type", mimeType);
135
68
  }
136
- const stat = lstatSync(path);
137
- const size = stat.size;
69
+ const size = stats.size;
138
70
  if (c.req.method == "HEAD" || c.req.method == "OPTIONS") {
139
71
  c.header("Content-Length", size.toString());
140
72
  c.status(200);
@@ -146,17 +78,17 @@ var serveStatic = (options = { root: "" }) => {
146
78
  return c.body(createStreamBody(createReadStream(path)), 200);
147
79
  }
148
80
  c.header("Accept-Ranges", "bytes");
149
- c.header("Date", stat.birthtime.toUTCString());
81
+ c.header("Date", stats.birthtime.toUTCString());
150
82
  const parts = range.replace(/bytes=/, "").split("-", 2);
151
83
  const start = parts[0] ? parseInt(parts[0], 10) : 0;
152
- let end = parts[1] ? parseInt(parts[1], 10) : stat.size - 1;
84
+ let end = parts[1] ? parseInt(parts[1], 10) : stats.size - 1;
153
85
  if (size < end - start + 1) {
154
86
  end = size - 1;
155
87
  }
156
88
  const chunksize = end - start + 1;
157
89
  const stream = createReadStream(path, { start, end });
158
90
  c.header("Content-Length", chunksize.toString());
159
- c.header("Content-Range", `bytes ${start}-${end}/${stat.size}`);
91
+ c.header("Content-Range", `bytes ${start}-${end}/${stats.size}`);
160
92
  return c.body(createStreamBody(stream), 206);
161
93
  };
162
94
  };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@hono/node-server",
3
- "version": "1.11.4",
3
+ "version": "1.12.0",
4
4
  "description": "Node.js Adapter for Hono",
5
5
  "main": "dist/index.js",
6
6
  "types": "dist/index.d.ts",
@@ -27,6 +27,11 @@
27
27
  "types": "./dist/utils/*.d.ts",
28
28
  "require": "./dist/utils/*.js",
29
29
  "import": "./dist/utils/*.mjs"
30
+ },
31
+ "./conninfo": {
32
+ "types": "./dist/conninfo.d.ts",
33
+ "require": "./dist/conninfo.js",
34
+ "import": "./dist/conninfo.mjs"
30
35
  }
31
36
  },
32
37
  "typesVersions": {
@@ -42,12 +47,15 @@
42
47
  ],
43
48
  "utils/*": [
44
49
  "./dist/utils/*.d.ts"
50
+ ],
51
+ "conninfo": [
52
+ "./dist/conninfo.d.ts"
45
53
  ]
46
54
  }
47
55
  },
48
56
  "scripts": {
49
57
  "test": "node --expose-gc ./node_modules/.bin/jest",
50
- "build": "tsup",
58
+ "build": "tsup --external hono",
51
59
  "watch": "tsup --watch",
52
60
  "postbuild": "publint",
53
61
  "prerelease": "yarn build && yarn test",
@@ -78,7 +86,7 @@
78
86
  "@types/supertest": "^2.0.12",
79
87
  "@whatwg-node/fetch": "^0.9.14",
80
88
  "eslint": "^8.55.0",
81
- "hono": "^4.0.3",
89
+ "hono": "^4.4.10",
82
90
  "jest": "^29.6.1",
83
91
  "np": "^7.7.0",
84
92
  "prettier": "^3.2.4",