@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 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
@@ -0,0 +1,2 @@
1
+ export * from "./src/Config";
2
+ export * from "./src/serve";
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,5 @@
1
+ export type Config = {
2
+ url?: string;
3
+ path?: string;
4
+ dirs?: string[];
5
+ };
@@ -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
+ }
@@ -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
+ }