@t8/serve 0.1.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 +0 -0
- package/dist/index.js +106 -0
- package/dist/run.cjs +87 -0
- package/dist/run.mjs +86 -0
- package/index.ts +2 -0
- package/package.json +36 -0
- package/src/Config.ts +5 -0
- package/src/getFilePath.ts +23 -0
- package/src/isValidFilePath.ts +12 -0
- package/src/mimeTypes.ts +13 -0
- package/src/run.ts +15 -0
- package/src/serve.ts +43 -0
- package/tsconfig.json +12 -0
package/README.md
ADDED
|
File without changes
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,106 @@
|
|
|
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
|
+
// index.ts
|
|
21
|
+
var index_exports = {};
|
|
22
|
+
__export(index_exports, {
|
|
23
|
+
serve: () => serve
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(index_exports);
|
|
26
|
+
|
|
27
|
+
// src/serve.ts
|
|
28
|
+
var import_node_fs = require("node:fs");
|
|
29
|
+
var import_node_http = require("node:http");
|
|
30
|
+
var import_node_path2 = require("node:path");
|
|
31
|
+
|
|
32
|
+
// src/getFilePath.ts
|
|
33
|
+
var import_node_path = require("node:path");
|
|
34
|
+
|
|
35
|
+
// src/isValidFilePath.ts
|
|
36
|
+
var import_promises = require("node:fs/promises");
|
|
37
|
+
async function isValidFilePath(filePath, dirPath) {
|
|
38
|
+
if (!filePath.startsWith(dirPath)) return false;
|
|
39
|
+
try {
|
|
40
|
+
await (0, import_promises.access)(filePath);
|
|
41
|
+
return true;
|
|
42
|
+
} catch {
|
|
43
|
+
return false;
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
// src/getFilePath.ts
|
|
48
|
+
var cwd = process.cwd();
|
|
49
|
+
async function getFilePath(urlPath = "", { path = "", dirs = [""] }) {
|
|
50
|
+
for (let dir of dirs) {
|
|
51
|
+
let dirPath = (0, import_node_path.join)(cwd, path, dir);
|
|
52
|
+
let filePath = (0, import_node_path.join)(dirPath, urlPath);
|
|
53
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
54
|
+
if (!/\.\w+$/.test(filePath)) {
|
|
55
|
+
filePath = (0, import_node_path.join)(dirPath, urlPath, "index.html");
|
|
56
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
}
|
|
60
|
+
|
|
61
|
+
// src/mimeTypes.ts
|
|
62
|
+
var mimeTypes = {
|
|
63
|
+
html: "text/html; charset=utf-8",
|
|
64
|
+
js: "text/javascript",
|
|
65
|
+
json: "application/json",
|
|
66
|
+
css: "text/css",
|
|
67
|
+
svg: "image/svg+xml",
|
|
68
|
+
png: "image/png",
|
|
69
|
+
jpg: "image/jpeg",
|
|
70
|
+
gif: "image/gif",
|
|
71
|
+
ico: "image/x-icon",
|
|
72
|
+
txt: "text/plain",
|
|
73
|
+
md: "text/markdown"
|
|
74
|
+
};
|
|
75
|
+
|
|
76
|
+
// src/serve.ts
|
|
77
|
+
var defaultHost = "localhost";
|
|
78
|
+
var defaultPort = 3e3;
|
|
79
|
+
function serve(config = {}) {
|
|
80
|
+
let [, , host, , port] = config.url?.match(/^(https?:\/\/)?([^:/]+)(:(\d+))?\/?/) ?? [];
|
|
81
|
+
if (!port && /^\d+$/.test(host)) {
|
|
82
|
+
port = host;
|
|
83
|
+
host = defaultHost;
|
|
84
|
+
}
|
|
85
|
+
let server = (0, import_node_http.createServer)(async (req, res) => {
|
|
86
|
+
let filePath = await getFilePath(req.url, config);
|
|
87
|
+
if (filePath === void 0) {
|
|
88
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
89
|
+
res.end("Not found");
|
|
90
|
+
return;
|
|
91
|
+
}
|
|
92
|
+
let ext = (0, import_node_path2.extname)(filePath).slice(1).toLowerCase();
|
|
93
|
+
let mimeType = mimeTypes[ext] ?? "application/octet-stream";
|
|
94
|
+
res.writeHead(200, { "content-type": mimeType });
|
|
95
|
+
(0, import_node_fs.createReadStream)(filePath).pipe(res);
|
|
96
|
+
});
|
|
97
|
+
server.on("close", () => {
|
|
98
|
+
process.exit(0);
|
|
99
|
+
});
|
|
100
|
+
server.listen(Number(port) || defaultPort, host || defaultHost);
|
|
101
|
+
return server;
|
|
102
|
+
}
|
|
103
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
104
|
+
0 && (module.exports = {
|
|
105
|
+
serve
|
|
106
|
+
});
|
package/dist/run.cjs
ADDED
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
"use strict";
|
|
3
|
+
|
|
4
|
+
// src/serve.ts
|
|
5
|
+
var import_node_fs = require("node:fs");
|
|
6
|
+
var import_node_http = require("node:http");
|
|
7
|
+
var import_node_path2 = require("node:path");
|
|
8
|
+
|
|
9
|
+
// src/getFilePath.ts
|
|
10
|
+
var import_node_path = require("node:path");
|
|
11
|
+
|
|
12
|
+
// src/isValidFilePath.ts
|
|
13
|
+
var import_promises = require("node:fs/promises");
|
|
14
|
+
async function isValidFilePath(filePath, dirPath) {
|
|
15
|
+
if (!filePath.startsWith(dirPath)) return false;
|
|
16
|
+
try {
|
|
17
|
+
await (0, import_promises.access)(filePath);
|
|
18
|
+
return true;
|
|
19
|
+
} catch {
|
|
20
|
+
return false;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
|
|
24
|
+
// src/getFilePath.ts
|
|
25
|
+
var cwd = process.cwd();
|
|
26
|
+
async function getFilePath(urlPath = "", { path = "", dirs = [""] }) {
|
|
27
|
+
for (let dir of dirs) {
|
|
28
|
+
let dirPath = (0, import_node_path.join)(cwd, path, dir);
|
|
29
|
+
let filePath = (0, import_node_path.join)(dirPath, urlPath);
|
|
30
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
31
|
+
if (!/\.\w+$/.test(filePath)) {
|
|
32
|
+
filePath = (0, import_node_path.join)(dirPath, urlPath, "index.html");
|
|
33
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
|
|
38
|
+
// src/mimeTypes.ts
|
|
39
|
+
var mimeTypes = {
|
|
40
|
+
html: "text/html; charset=utf-8",
|
|
41
|
+
js: "text/javascript",
|
|
42
|
+
json: "application/json",
|
|
43
|
+
css: "text/css",
|
|
44
|
+
svg: "image/svg+xml",
|
|
45
|
+
png: "image/png",
|
|
46
|
+
jpg: "image/jpeg",
|
|
47
|
+
gif: "image/gif",
|
|
48
|
+
ico: "image/x-icon",
|
|
49
|
+
txt: "text/plain",
|
|
50
|
+
md: "text/markdown"
|
|
51
|
+
};
|
|
52
|
+
|
|
53
|
+
// src/serve.ts
|
|
54
|
+
var defaultHost = "localhost";
|
|
55
|
+
var defaultPort = 3e3;
|
|
56
|
+
function serve(config = {}) {
|
|
57
|
+
let [, , host, , port] = config.url?.match(/^(https?:\/\/)?([^:/]+)(:(\d+))?\/?/) ?? [];
|
|
58
|
+
if (!port && /^\d+$/.test(host)) {
|
|
59
|
+
port = host;
|
|
60
|
+
host = defaultHost;
|
|
61
|
+
}
|
|
62
|
+
let server = (0, import_node_http.createServer)(async (req, res) => {
|
|
63
|
+
let filePath = await getFilePath(req.url, config);
|
|
64
|
+
if (filePath === void 0) {
|
|
65
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
66
|
+
res.end("Not found");
|
|
67
|
+
return;
|
|
68
|
+
}
|
|
69
|
+
let ext = (0, import_node_path2.extname)(filePath).slice(1).toLowerCase();
|
|
70
|
+
let mimeType = mimeTypes[ext] ?? "application/octet-stream";
|
|
71
|
+
res.writeHead(200, { "content-type": mimeType });
|
|
72
|
+
(0, import_node_fs.createReadStream)(filePath).pipe(res);
|
|
73
|
+
});
|
|
74
|
+
server.on("close", () => {
|
|
75
|
+
process.exit(0);
|
|
76
|
+
});
|
|
77
|
+
server.listen(Number(port) || defaultPort, host || defaultHost);
|
|
78
|
+
return server;
|
|
79
|
+
}
|
|
80
|
+
|
|
81
|
+
// src/run.ts
|
|
82
|
+
var args = process.argv.slice(2);
|
|
83
|
+
serve({
|
|
84
|
+
url: args[0],
|
|
85
|
+
path: args[1],
|
|
86
|
+
dirs: args.slice(2)
|
|
87
|
+
});
|
package/dist/run.mjs
ADDED
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/serve.ts
|
|
4
|
+
import { createReadStream } from "node:fs";
|
|
5
|
+
import { createServer } from "node:http";
|
|
6
|
+
import { extname } from "node:path";
|
|
7
|
+
|
|
8
|
+
// src/getFilePath.ts
|
|
9
|
+
import { join } from "node:path";
|
|
10
|
+
|
|
11
|
+
// src/isValidFilePath.ts
|
|
12
|
+
import { access } from "node:fs/promises";
|
|
13
|
+
async function isValidFilePath(filePath, dirPath) {
|
|
14
|
+
if (!filePath.startsWith(dirPath)) return false;
|
|
15
|
+
try {
|
|
16
|
+
await access(filePath);
|
|
17
|
+
return true;
|
|
18
|
+
} catch {
|
|
19
|
+
return false;
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
|
|
23
|
+
// src/getFilePath.ts
|
|
24
|
+
var cwd = process.cwd();
|
|
25
|
+
async function getFilePath(urlPath = "", { path = "", dirs = [""] }) {
|
|
26
|
+
for (let dir of dirs) {
|
|
27
|
+
let dirPath = join(cwd, path, dir);
|
|
28
|
+
let filePath = join(dirPath, urlPath);
|
|
29
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
30
|
+
if (!/\.\w+$/.test(filePath)) {
|
|
31
|
+
filePath = join(dirPath, urlPath, "index.html");
|
|
32
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
33
|
+
}
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// src/mimeTypes.ts
|
|
38
|
+
var mimeTypes = {
|
|
39
|
+
html: "text/html; charset=utf-8",
|
|
40
|
+
js: "text/javascript",
|
|
41
|
+
json: "application/json",
|
|
42
|
+
css: "text/css",
|
|
43
|
+
svg: "image/svg+xml",
|
|
44
|
+
png: "image/png",
|
|
45
|
+
jpg: "image/jpeg",
|
|
46
|
+
gif: "image/gif",
|
|
47
|
+
ico: "image/x-icon",
|
|
48
|
+
txt: "text/plain",
|
|
49
|
+
md: "text/markdown"
|
|
50
|
+
};
|
|
51
|
+
|
|
52
|
+
// src/serve.ts
|
|
53
|
+
var defaultHost = "localhost";
|
|
54
|
+
var defaultPort = 3e3;
|
|
55
|
+
function serve(config = {}) {
|
|
56
|
+
let [, , host, , port] = config.url?.match(/^(https?:\/\/)?([^:/]+)(:(\d+))?\/?/) ?? [];
|
|
57
|
+
if (!port && /^\d+$/.test(host)) {
|
|
58
|
+
port = host;
|
|
59
|
+
host = defaultHost;
|
|
60
|
+
}
|
|
61
|
+
let server = createServer(async (req, res) => {
|
|
62
|
+
let filePath = await getFilePath(req.url, config);
|
|
63
|
+
if (filePath === void 0) {
|
|
64
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
65
|
+
res.end("Not found");
|
|
66
|
+
return;
|
|
67
|
+
}
|
|
68
|
+
let ext = extname(filePath).slice(1).toLowerCase();
|
|
69
|
+
let mimeType = mimeTypes[ext] ?? "application/octet-stream";
|
|
70
|
+
res.writeHead(200, { "content-type": mimeType });
|
|
71
|
+
createReadStream(filePath).pipe(res);
|
|
72
|
+
});
|
|
73
|
+
server.on("close", () => {
|
|
74
|
+
process.exit(0);
|
|
75
|
+
});
|
|
76
|
+
server.listen(Number(port) || defaultPort, host || defaultHost);
|
|
77
|
+
return server;
|
|
78
|
+
}
|
|
79
|
+
|
|
80
|
+
// src/run.ts
|
|
81
|
+
var args = process.argv.slice(2);
|
|
82
|
+
serve({
|
|
83
|
+
url: args[0],
|
|
84
|
+
path: args[1],
|
|
85
|
+
dirs: args.slice(2)
|
|
86
|
+
});
|
package/index.ts
ADDED
package/package.json
ADDED
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@t8/serve",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "",
|
|
5
|
+
"keywords": [
|
|
6
|
+
"node",
|
|
7
|
+
"server",
|
|
8
|
+
"static"
|
|
9
|
+
],
|
|
10
|
+
"bin": {
|
|
11
|
+
"serve": "dist/run.js"
|
|
12
|
+
},
|
|
13
|
+
"repository": {
|
|
14
|
+
"type": "git",
|
|
15
|
+
"url": "git+https://github.com/t8js/serve.git"
|
|
16
|
+
},
|
|
17
|
+
"license": "ISC",
|
|
18
|
+
"author": "axtk",
|
|
19
|
+
"type": "module",
|
|
20
|
+
"main": "dist/index.js",
|
|
21
|
+
"scripts": {
|
|
22
|
+
"build": "npx npm-run-all clean -p compile compile-mjs-bin compile-cjs-bin",
|
|
23
|
+
"clean": "node -e \"require('node:fs').rmSync('dist', {force: true, recursive: true});\"",
|
|
24
|
+
"compile": "npx esbuild index.ts --bundle --outdir=dist --platform=node",
|
|
25
|
+
"compile-mjs-bin": "npx esbuild src/run.ts --bundle --outfile=dist/run.mjs --platform=node --format=esm",
|
|
26
|
+
"compile-cjs-bin": "npx esbuild src/run.ts --bundle --outfile=dist/run.cjs --platform=node --format=cjs",
|
|
27
|
+
"prepublishOnly": "npm run build",
|
|
28
|
+
"preversion": "npx npm-run-all typecheck shape build",
|
|
29
|
+
"shape": "npx codeshape",
|
|
30
|
+
"typecheck": "tsc --noEmit"
|
|
31
|
+
},
|
|
32
|
+
"devDependencies": {
|
|
33
|
+
"@types/node": "^24.5.2",
|
|
34
|
+
"typescript": "^5.9.2"
|
|
35
|
+
}
|
|
36
|
+
}
|
package/src/Config.ts
ADDED
|
@@ -0,0 +1,23 @@
|
|
|
1
|
+
import { join } from "node:path";
|
|
2
|
+
import type { Config } from "./Config";
|
|
3
|
+
import { isValidFilePath } from "./isValidFilePath";
|
|
4
|
+
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
|
|
7
|
+
export async function getFilePath(
|
|
8
|
+
urlPath: string = "",
|
|
9
|
+
{ path = "", dirs = [""] }: Config,
|
|
10
|
+
) {
|
|
11
|
+
for (let dir of dirs) {
|
|
12
|
+
let dirPath = join(cwd, path, dir);
|
|
13
|
+
let filePath = join(dirPath, urlPath);
|
|
14
|
+
|
|
15
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
16
|
+
|
|
17
|
+
if (!/\.\w+$/.test(filePath)) {
|
|
18
|
+
filePath = join(dirPath, urlPath, "index.html");
|
|
19
|
+
|
|
20
|
+
if (await isValidFilePath(filePath, dirPath)) return filePath;
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { access } from "node:fs/promises";
|
|
2
|
+
|
|
3
|
+
export async function isValidFilePath(filePath: string, dirPath: string) {
|
|
4
|
+
if (!filePath.startsWith(dirPath)) return false;
|
|
5
|
+
|
|
6
|
+
try {
|
|
7
|
+
await access(filePath);
|
|
8
|
+
return true;
|
|
9
|
+
} catch {
|
|
10
|
+
return false;
|
|
11
|
+
}
|
|
12
|
+
}
|
package/src/mimeTypes.ts
ADDED
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export const mimeTypes: Record<string, string> = {
|
|
2
|
+
html: "text/html; charset=utf-8",
|
|
3
|
+
js: "text/javascript",
|
|
4
|
+
json: "application/json",
|
|
5
|
+
css: "text/css",
|
|
6
|
+
svg: "image/svg+xml",
|
|
7
|
+
png: "image/png",
|
|
8
|
+
jpg: "image/jpeg",
|
|
9
|
+
gif: "image/gif",
|
|
10
|
+
ico: "image/x-icon",
|
|
11
|
+
txt: "text/plain",
|
|
12
|
+
md: "text/markdown",
|
|
13
|
+
};
|
package/src/run.ts
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
import { serve } from "./serve";
|
|
3
|
+
|
|
4
|
+
let args = process.argv.slice(2);
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* @example
|
|
8
|
+
* serve 3000 app public dist
|
|
9
|
+
* serve 127.0.0.1:3000 app public dist
|
|
10
|
+
*/
|
|
11
|
+
serve({
|
|
12
|
+
url: args[0],
|
|
13
|
+
path: args[1],
|
|
14
|
+
dirs: args.slice(2),
|
|
15
|
+
});
|
package/src/serve.ts
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
import { createReadStream } from "node:fs";
|
|
2
|
+
import { createServer } from "node:http";
|
|
3
|
+
import { extname } from "node:path";
|
|
4
|
+
import type { Config } from "./Config";
|
|
5
|
+
import { getFilePath } from "./getFilePath";
|
|
6
|
+
import { mimeTypes } from "./mimeTypes";
|
|
7
|
+
|
|
8
|
+
const defaultHost = "localhost";
|
|
9
|
+
const defaultPort = 3000;
|
|
10
|
+
|
|
11
|
+
export function serve(config: Config = {}) {
|
|
12
|
+
let [, , host, , port] =
|
|
13
|
+
config.url?.match(/^(https?:\/\/)?([^:/]+)(:(\d+))?\/?/) ?? [];
|
|
14
|
+
|
|
15
|
+
if (!port && /^\d+$/.test(host)) {
|
|
16
|
+
port = host;
|
|
17
|
+
host = defaultHost;
|
|
18
|
+
}
|
|
19
|
+
|
|
20
|
+
let server = createServer(async (req, res) => {
|
|
21
|
+
let filePath = await getFilePath(req.url, config);
|
|
22
|
+
|
|
23
|
+
if (filePath === undefined) {
|
|
24
|
+
res.writeHead(404, { "content-type": "text/plain" });
|
|
25
|
+
res.end("Not found");
|
|
26
|
+
return;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
let ext = extname(filePath).slice(1).toLowerCase();
|
|
30
|
+
let mimeType = mimeTypes[ext] ?? "application/octet-stream";
|
|
31
|
+
|
|
32
|
+
res.writeHead(200, { "content-type": mimeType });
|
|
33
|
+
createReadStream(filePath).pipe(res);
|
|
34
|
+
});
|
|
35
|
+
|
|
36
|
+
server.on("close", () => {
|
|
37
|
+
process.exit(0);
|
|
38
|
+
});
|
|
39
|
+
|
|
40
|
+
server.listen(Number(port) || defaultPort, host || defaultHost);
|
|
41
|
+
|
|
42
|
+
return server;
|
|
43
|
+
}
|
package/tsconfig.json
ADDED
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
{
|
|
2
|
+
"include": ["index.ts", "src"],
|
|
3
|
+
"compilerOptions": {
|
|
4
|
+
"lib": ["ESNext", "DOM", "DOM.Iterable"],
|
|
5
|
+
"target": "ESNext",
|
|
6
|
+
"outDir": "dist",
|
|
7
|
+
"moduleResolution": "node",
|
|
8
|
+
"strict": true,
|
|
9
|
+
"noUnusedLocals": true,
|
|
10
|
+
"noUnusedParameters": true
|
|
11
|
+
}
|
|
12
|
+
}
|