srvx 0.8.2 → 0.8.3
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 +45 -18
- package/bin/srvx.mjs +8 -0
- package/dist/_chunks/{_utils-ek-l5xdY.mjs → _utils-DRF_4b_y.mjs} +1 -1
- package/dist/_chunks/_utils.cli-4eOGyiAa.mjs +17 -0
- package/dist/_chunks/package-BxkQNJ8Z.mjs +104 -0
- package/dist/adapters/bun.d.mts +2 -2
- package/dist/adapters/bun.mjs +3 -3
- package/dist/adapters/cloudflare.d.mts +1 -1
- package/dist/adapters/cloudflare.mjs +2 -2
- package/dist/adapters/deno.d.mts +2 -2
- package/dist/adapters/deno.mjs +3 -3
- package/dist/adapters/generic.d.mts +1 -1
- package/dist/adapters/generic.mjs +3 -3
- package/dist/adapters/node.d.mts +2 -2
- package/dist/adapters/node.mjs +4 -4
- package/dist/adapters/service-worker.d.mts +1 -1
- package/dist/adapters/service-worker.mjs +2 -2
- package/dist/cli.d.mts +10 -0
- package/dist/cli.mjs +270 -0
- package/dist/log.d.mts +8 -0
- package/dist/log.mjs +15 -0
- package/dist/static.d.mts +9 -0
- package/dist/static.mjs +70 -0
- package/dist/types.d.mts +1 -1
- package/package.json +10 -6
- /package/dist/_chunks/{_middleware-Bz7WmB2e.mjs → _middleware-BvRR7B4M.mjs} +0 -0
- /package/dist/_chunks/{_plugins-ta8pkwXd.mjs → _plugins-CbGQstxC.mjs} +0 -0
- /package/dist/_chunks/{_url-CE8HuNzA.d.mts → _url-Bu46KnwC.d.mts} +0 -0
- /package/dist/_chunks/{_url-0eSmxIIk.mjs → _url-CdE4ce6F.mjs} +0 -0
- /package/dist/_chunks/{types-IGvUeyh_.d.mts → types-GwbH0R0m.d.mts} +0 -0
package/README.md
CHANGED
|
@@ -1,47 +1,74 @@
|
|
|
1
|
-
#
|
|
1
|
+
# λ srvx
|
|
2
2
|
|
|
3
|
-
<!-- automd:badges color=yellow -->
|
|
3
|
+
<!-- automd:badges color=yellow packagephobia -->
|
|
4
4
|
|
|
5
5
|
[](https://npmjs.com/package/srvx)
|
|
6
6
|
[](https://npm.chart.dev/srvx)
|
|
7
|
+
[](https://packagephobia.com/result?p=srvx)
|
|
7
8
|
|
|
8
9
|
<!-- /automd -->
|
|
9
10
|
|
|
10
|
-
Universal Server
|
|
11
|
+
Universal Server based on web standards. Works with [Deno](https://deno.com/), [Bun](https://bun.sh/) and [Node.js](https://nodejs.org/en).
|
|
11
12
|
|
|
12
|
-
- ✅
|
|
13
|
-
- ✅
|
|
14
|
-
- ✅ [
|
|
13
|
+
- ✅ Zero dependency
|
|
14
|
+
- ✅ Full featured CLI with watcher, error handler, serve static and logger
|
|
15
|
+
- ✅ Seamless runtime integration with same API ([handler](https://srvx.h3.dev/guide/handler) and [instance](https://srvx.h3.dev/guide/server)).
|
|
16
|
+
- ✅ [Node.js compatibility](https://srvx.h3.dev/guide/node) with up to [~96.98%](https://github.com/h3js/srvx/tree/main/test/bench-node) native performance.
|
|
17
|
+
- ✅ Zero overhead [Deno](https://deno.com/) and [Bun](https://bun.sh/) support.
|
|
15
18
|
|
|
16
19
|
## Quick start
|
|
17
20
|
|
|
18
21
|
```js
|
|
19
|
-
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
port: 3000,
|
|
23
|
-
fetch(request) {
|
|
24
|
-
return new Response("👋 Hello there!");
|
|
22
|
+
export default {
|
|
23
|
+
fetch(req: Request) {
|
|
24
|
+
return Response.json({ hello: "world!" });
|
|
25
25
|
},
|
|
26
|
-
}
|
|
26
|
+
};
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
Then, run the server using your favorite runtime:
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Node.js
|
|
33
|
+
$ npx srvx # npm
|
|
34
|
+
$ pnpx srvx # pnpm
|
|
35
|
+
$ yarn dlx srvx # yarn
|
|
36
|
+
|
|
37
|
+
# Deno
|
|
38
|
+
$ deno -A npm:srvx
|
|
39
|
+
|
|
40
|
+
# Bun
|
|
41
|
+
$ bunx --bun srvx
|
|
27
42
|
```
|
|
28
43
|
|
|
29
44
|
👉 **Visit the 📖 [Documentation](https://srvx.h3.dev/) to learn more.**
|
|
30
45
|
|
|
31
|
-
##
|
|
46
|
+
## Starter Examples
|
|
32
47
|
|
|
33
|
-
|
|
48
|
+
[➤ Online Playground](https://stackblitz.com/fork/github/h3js/srvx/tree/main/examples/stackblitz?startScript=dev&file=server.mjs)
|
|
34
49
|
|
|
35
|
-
|
|
50
|
+
<!-- automd:examples -->
|
|
51
|
+
|
|
52
|
+
| Example | Source | Try |
|
|
53
|
+
| ---------------- | ------------------------------------------------------------------------------------------ | -------------------------------------------------------------------- |
|
|
54
|
+
| `elysia` | [examples/elysia](https://github.com/h3js/srvx/tree/main/examples/elysia/) | `npx giget gh:h3js/srvx/examples/elysia srvx-elysia` |
|
|
55
|
+
| `h3` | [examples/h3](https://github.com/h3js/srvx/tree/main/examples/h3/) | `npx giget gh:h3js/srvx/examples/h3 srvx-h3` |
|
|
56
|
+
| `hello-world` | [examples/hello-world](https://github.com/h3js/srvx/tree/main/examples/hello-world/) | `npx giget gh:h3js/srvx/examples/hello-world srvx-hello-world` |
|
|
57
|
+
| `hono` | [examples/hono](https://github.com/h3js/srvx/tree/main/examples/hono/) | `npx giget gh:h3js/srvx/examples/hono srvx-hono` |
|
|
58
|
+
| `service-worker` | [examples/service-worker](https://github.com/h3js/srvx/tree/main/examples/service-worker/) | `npx giget gh:h3js/srvx/examples/service-worker srvx-service-worker` |
|
|
59
|
+
| `websocket` | [examples/websocket](https://github.com/h3js/srvx/tree/main/examples/websocket/) | `npx giget gh:h3js/srvx/examples/websocket srvx-websocket` |
|
|
60
|
+
|
|
61
|
+
<!-- /automd -->
|
|
62
|
+
|
|
63
|
+
## Contribution
|
|
36
64
|
|
|
37
65
|
- Clone this repository
|
|
38
66
|
- Install the latest LTS version of [Node.js](https://nodejs.org/en/)
|
|
39
67
|
- Enable [Corepack](https://github.com/nodejs/corepack) using `corepack enable`
|
|
40
68
|
- Install dependencies using `pnpm install`
|
|
69
|
+
- **Prepare stub mode using `pnpm build --stub`**
|
|
41
70
|
- Run interactive tests using `pnpm dev`
|
|
42
71
|
|
|
43
|
-
</details>
|
|
44
|
-
|
|
45
72
|
## License
|
|
46
73
|
|
|
47
74
|
<!-- automd:contributors author=pi0 license=MIT -->
|
package/bin/srvx.mjs
ADDED
|
@@ -28,7 +28,7 @@ function printListening(opts, url) {
|
|
|
28
28
|
url = `\u001B[36m${url}\u001B[0m`;
|
|
29
29
|
additionalInfo = `\u001B[2m${additionalInfo}\u001B[0m`;
|
|
30
30
|
}
|
|
31
|
-
console.log(
|
|
31
|
+
console.log(`${listeningOn} ${url}${additionalInfo}`);
|
|
32
32
|
}
|
|
33
33
|
function resolveTLSOptions(opts) {
|
|
34
34
|
if (!opts.tls || opts.protocol === "http") return;
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
//#region src/_utils.cli.ts
|
|
2
|
+
const noColor = globalThis.process?.env?.NO_COLOR === "1" || globalThis.process?.env?.TERM === "dumb";
|
|
3
|
+
const _c = (c) => (t) => noColor ? t : `\u001B[${c}m${t}\u001B[0m`;
|
|
4
|
+
const Colors = {
|
|
5
|
+
bold: _c(1),
|
|
6
|
+
red: _c(31),
|
|
7
|
+
green: _c(32),
|
|
8
|
+
yellow: _c(33),
|
|
9
|
+
blue: _c(34),
|
|
10
|
+
magenta: _c(35),
|
|
11
|
+
cyan: _c(36),
|
|
12
|
+
gray: _c(90),
|
|
13
|
+
url: (title, url) => noColor ? `${title} (${url})` : `\u001B]8;;${url}\u001B\\${title}\u001B]8;;\u001B\\`
|
|
14
|
+
};
|
|
15
|
+
|
|
16
|
+
//#endregion
|
|
17
|
+
export { Colors };
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
//#region package.json
|
|
2
|
+
var name = "srvx";
|
|
3
|
+
var version = "0.8.3";
|
|
4
|
+
var description = "Universal Server API based on web platform standards. Works seamlessly with Deno, Bun and Node.js.";
|
|
5
|
+
var homepage = "https://srvx.h3.dev";
|
|
6
|
+
var repository = "h3js/srvx";
|
|
7
|
+
var license = "MIT";
|
|
8
|
+
var sideEffects = false;
|
|
9
|
+
var type = "module";
|
|
10
|
+
var exports = {
|
|
11
|
+
"./deno": "./dist/adapters/deno.mjs",
|
|
12
|
+
"./bun": "./dist/adapters/bun.mjs",
|
|
13
|
+
"./node": "./dist/adapters/node.mjs",
|
|
14
|
+
"./cloudflare": "./dist/adapters/cloudflare.mjs",
|
|
15
|
+
"./generic": "./dist/adapters/generic.mjs",
|
|
16
|
+
"./service-worker": "./dist/adapters/service-worker.mjs",
|
|
17
|
+
"./cli": "./dist/cli.mjs",
|
|
18
|
+
"./static": "./dist/static.mjs",
|
|
19
|
+
"./log": "./dist/log.mjs",
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/types.d.mts",
|
|
22
|
+
"deno": "./dist/adapters/deno.mjs",
|
|
23
|
+
"bun": "./dist/adapters/bun.mjs",
|
|
24
|
+
"workerd": "./dist/adapters/cloudflare.mjs",
|
|
25
|
+
"browser": "./dist/adapters/service-worker.mjs",
|
|
26
|
+
"node": "./dist/adapters/node.mjs",
|
|
27
|
+
"default": "./dist/adapters/generic.mjs"
|
|
28
|
+
}
|
|
29
|
+
};
|
|
30
|
+
var types = "./dist/types.d.mts";
|
|
31
|
+
var bin = { "srvx": "./bin/srvx.mjs" };
|
|
32
|
+
var files = ["bin", "dist"];
|
|
33
|
+
var scripts = {
|
|
34
|
+
"bench:node": "node test/bench-node/_run.mjs",
|
|
35
|
+
"bench:url:bun": "bun run ./test/url.bench.ts",
|
|
36
|
+
"bench:url:deno": "deno run -A ./test/url.bench.ts",
|
|
37
|
+
"bench:url:node": "pnpm node-ts --expose-gc --allow-natives-syntax ./test/url.bench.ts",
|
|
38
|
+
"build": "obuild",
|
|
39
|
+
"dev": "vitest dev",
|
|
40
|
+
"lint": "eslint . && prettier -c .",
|
|
41
|
+
"lint:fix": "automd && eslint . --fix && prettier -w .",
|
|
42
|
+
"node-ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types",
|
|
43
|
+
"prepack": "pnpm build",
|
|
44
|
+
"play:mkcert": "openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 365 -subj /CN=srvx.local",
|
|
45
|
+
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
|
|
46
|
+
"srvx": "./bin/srvx.mjs",
|
|
47
|
+
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
|
|
48
|
+
"test:types": "tsc --noEmit --skipLibCheck"
|
|
49
|
+
};
|
|
50
|
+
var resolutions = { "srvx": "link:." };
|
|
51
|
+
var dependencies = { "cookie-es": "^2.0.0" };
|
|
52
|
+
var devDependencies = {
|
|
53
|
+
"@cloudflare/workers-types": "^4.20250627.0",
|
|
54
|
+
"@hono/node-server": "^1.14.4",
|
|
55
|
+
"@mitata/counters": "^0.0.8",
|
|
56
|
+
"@mjackson/node-fetch-server": "^0.7.0",
|
|
57
|
+
"@types/bun": "^1.2.17",
|
|
58
|
+
"@types/deno": "^2.3.0",
|
|
59
|
+
"@types/node": "^24.0.4",
|
|
60
|
+
"@types/node-forge": "^1.3.11",
|
|
61
|
+
"@types/serviceworker": "^0.0.139",
|
|
62
|
+
"@vitest/coverage-v8": "^3.2.4",
|
|
63
|
+
"@whatwg-node/server": "^0.10.10",
|
|
64
|
+
"automd": "^0.4.0",
|
|
65
|
+
"changelogen": "^0.6.1",
|
|
66
|
+
"eslint": "^9.29.0",
|
|
67
|
+
"eslint-config-unjs": "^0.5.0",
|
|
68
|
+
"execa": "^9.6.0",
|
|
69
|
+
"get-port-please": "^3.1.2",
|
|
70
|
+
"mdbox": "^0.1.1",
|
|
71
|
+
"mitata": "^1.0.34",
|
|
72
|
+
"node-forge": "^1.3.1",
|
|
73
|
+
"obuild": "^0.2.1",
|
|
74
|
+
"prettier": "^3.6.2",
|
|
75
|
+
"tslib": "^2.8.1",
|
|
76
|
+
"typescript": "^5.8.3",
|
|
77
|
+
"undici": "^7.11.0",
|
|
78
|
+
"vitest": "^3.2.4"
|
|
79
|
+
};
|
|
80
|
+
var packageManager = "pnpm@10.12.4";
|
|
81
|
+
var engines = { "node": ">=20.16.0" };
|
|
82
|
+
var package_default = {
|
|
83
|
+
name,
|
|
84
|
+
version,
|
|
85
|
+
description,
|
|
86
|
+
homepage,
|
|
87
|
+
repository,
|
|
88
|
+
license,
|
|
89
|
+
sideEffects,
|
|
90
|
+
type,
|
|
91
|
+
exports,
|
|
92
|
+
types,
|
|
93
|
+
bin,
|
|
94
|
+
files,
|
|
95
|
+
scripts,
|
|
96
|
+
resolutions,
|
|
97
|
+
dependencies,
|
|
98
|
+
devDependencies,
|
|
99
|
+
packageManager,
|
|
100
|
+
engines
|
|
101
|
+
};
|
|
102
|
+
|
|
103
|
+
//#endregion
|
|
104
|
+
export { package_default as default };
|
package/dist/adapters/bun.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { BunFetchHandler, Server, ServerOptions } from "../_chunks/types-
|
|
2
|
-
import { FastURL$2 as FastURL } from "../_chunks/_url-
|
|
1
|
+
import { BunFetchHandler, Server, ServerOptions } from "../_chunks/types-GwbH0R0m.mjs";
|
|
2
|
+
import { FastURL$2 as FastURL } from "../_chunks/_url-Bu46KnwC.mjs";
|
|
3
3
|
import * as bun from "bun";
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/bun.d.ts
|
package/dist/adapters/bun.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-
|
|
2
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
3
|
-
import { FastURL$1 as FastURL } from "../_chunks/_url-
|
|
1
|
+
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DRF_4b_y.mjs";
|
|
2
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
3
|
+
import { FastURL$1 as FastURL } from "../_chunks/_url-CdE4ce6F.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/bun.ts
|
|
6
6
|
const FastResponse = Response;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
2
|
-
import { errorPlugin } from "../_chunks/_plugins-
|
|
1
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
2
|
+
import { errorPlugin } from "../_chunks/_plugins-CbGQstxC.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/cloudflare.ts
|
|
5
5
|
const FastURL = URL;
|
package/dist/adapters/deno.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { DenoFetchHandler, Server, ServerOptions } from "../_chunks/types-
|
|
2
|
-
import { FastURL$2 as FastURL } from "../_chunks/_url-
|
|
1
|
+
import { DenoFetchHandler, Server, ServerOptions } from "../_chunks/types-GwbH0R0m.mjs";
|
|
2
|
+
import { FastURL$2 as FastURL } from "../_chunks/_url-Bu46KnwC.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/deno.d.ts
|
|
5
5
|
declare const FastResponse: typeof globalThis.Response;
|
package/dist/adapters/deno.mjs
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-
|
|
2
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
3
|
-
import { FastURL$1 as FastURL } from "../_chunks/_url-
|
|
1
|
+
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DRF_4b_y.mjs";
|
|
2
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
3
|
+
import { FastURL$1 as FastURL } from "../_chunks/_url-CdE4ce6F.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/deno.ts
|
|
6
6
|
const FastResponse = Response;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
|
-
import { createWaitUntil } from "../_chunks/_utils-
|
|
2
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
3
|
-
import { errorPlugin } from "../_chunks/_plugins-
|
|
1
|
+
import { createWaitUntil } from "../_chunks/_utils-DRF_4b_y.mjs";
|
|
2
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
3
|
+
import { errorPlugin } from "../_chunks/_plugins-CbGQstxC.mjs";
|
|
4
4
|
|
|
5
5
|
//#region src/adapters/generic.ts
|
|
6
6
|
const FastURL = URL;
|
package/dist/adapters/node.d.mts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../_chunks/types-
|
|
2
|
-
import { FastURL$2 as FastURL } from "../_chunks/_url-
|
|
1
|
+
import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../_chunks/types-GwbH0R0m.mjs";
|
|
2
|
+
import { FastURL$2 as FastURL } from "../_chunks/_url-Bu46KnwC.mjs";
|
|
3
3
|
import NodeHttp from "node:http";
|
|
4
4
|
import { Readable } from "node:stream";
|
|
5
5
|
|
package/dist/adapters/node.mjs
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
|
-
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-
|
|
2
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
3
|
-
import { FastURL$1 as FastURL } from "../_chunks/_url-
|
|
4
|
-
import { errorPlugin } from "../_chunks/_plugins-
|
|
1
|
+
import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-DRF_4b_y.mjs";
|
|
2
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
3
|
+
import { FastURL$1 as FastURL } from "../_chunks/_url-CdE4ce6F.mjs";
|
|
4
|
+
import { errorPlugin } from "../_chunks/_plugins-CbGQstxC.mjs";
|
|
5
5
|
import { splitSetCookieString } from "cookie-es";
|
|
6
6
|
|
|
7
7
|
//#region src/adapters/_node/send.ts
|
|
@@ -1,5 +1,5 @@
|
|
|
1
|
-
import { wrapFetch } from "../_chunks/_middleware-
|
|
2
|
-
import { errorPlugin } from "../_chunks/_plugins-
|
|
1
|
+
import { wrapFetch } from "../_chunks/_middleware-BvRR7B4M.mjs";
|
|
2
|
+
import { errorPlugin } from "../_chunks/_plugins-CbGQstxC.mjs";
|
|
3
3
|
|
|
4
4
|
//#region src/adapters/service-worker.ts
|
|
5
5
|
const FastURL = URL;
|
package/dist/cli.d.mts
ADDED
package/dist/cli.mjs
ADDED
|
@@ -0,0 +1,270 @@
|
|
|
1
|
+
import { Colors } from "./_chunks/_utils.cli-4eOGyiAa.mjs";
|
|
2
|
+
import { parseArgs } from "node:util";
|
|
3
|
+
import { fileURLToPath, pathToFileURL } from "node:url";
|
|
4
|
+
import { dirname, extname, relative, resolve } from "node:path";
|
|
5
|
+
import { fork } from "node:child_process";
|
|
6
|
+
import { existsSync } from "node:fs";
|
|
7
|
+
|
|
8
|
+
//#region src/cli.ts
|
|
9
|
+
const defaultEntries = [
|
|
10
|
+
"server",
|
|
11
|
+
"src/server",
|
|
12
|
+
"index",
|
|
13
|
+
"src/index"
|
|
14
|
+
];
|
|
15
|
+
const defaultExts = [
|
|
16
|
+
".mts",
|
|
17
|
+
".ts",
|
|
18
|
+
".cts",
|
|
19
|
+
".js",
|
|
20
|
+
".mjs",
|
|
21
|
+
".cjs"
|
|
22
|
+
];
|
|
23
|
+
const args = process.argv.slice(2);
|
|
24
|
+
const options = parseArgs$1(args);
|
|
25
|
+
if (process.send) {
|
|
26
|
+
setupProcessErrorHandlers();
|
|
27
|
+
await serve();
|
|
28
|
+
}
|
|
29
|
+
async function main(mainOpts) {
|
|
30
|
+
setupProcessErrorHandlers();
|
|
31
|
+
if (options._version) {
|
|
32
|
+
console.log(await version());
|
|
33
|
+
process.exit(0);
|
|
34
|
+
}
|
|
35
|
+
if (options._help) {
|
|
36
|
+
console.log(usage(mainOpts));
|
|
37
|
+
process.exit(options._help ? 0 : 1);
|
|
38
|
+
}
|
|
39
|
+
if (options._prod) await serve();
|
|
40
|
+
else {
|
|
41
|
+
const isBun = !!process.versions.bun;
|
|
42
|
+
const isDeno = !!process.versions.deno;
|
|
43
|
+
const isNode = !isBun && !isDeno;
|
|
44
|
+
const runtimeArgs = ["--watch"];
|
|
45
|
+
if (isNode || isDeno) runtimeArgs.push(...[".env", ".env.local"].filter((f) => existsSync(f)).map((f) => `--env-file=${f}`));
|
|
46
|
+
const child = fork(fileURLToPath(import.meta.url), args, { execArgv: [...process.execArgv, ...runtimeArgs].filter(Boolean) });
|
|
47
|
+
child.on("error", (error) => {
|
|
48
|
+
console.error("Error in child process:", error);
|
|
49
|
+
process.exit(1);
|
|
50
|
+
});
|
|
51
|
+
child.on("exit", (code) => {
|
|
52
|
+
if (code !== 0) {
|
|
53
|
+
console.error(`Child process exited with code ${code}`);
|
|
54
|
+
process.exit(code);
|
|
55
|
+
}
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
}
|
|
59
|
+
async function serve() {
|
|
60
|
+
try {
|
|
61
|
+
const { serve: srvxServe } = await import("srvx");
|
|
62
|
+
const { serveStatic } = await import("srvx/static");
|
|
63
|
+
const { log } = await import("srvx/log");
|
|
64
|
+
const entry = await loadEntry(options);
|
|
65
|
+
const staticDir = resolve(options._dir, options._static);
|
|
66
|
+
options._static = existsSync(staticDir) ? staticDir : "";
|
|
67
|
+
const server = await srvxServe({
|
|
68
|
+
error: (error) => {
|
|
69
|
+
console.error(error);
|
|
70
|
+
return renderError(error);
|
|
71
|
+
},
|
|
72
|
+
middleware: [
|
|
73
|
+
log(),
|
|
74
|
+
options._static ? serveStatic({ dir: options._static }) : void 0,
|
|
75
|
+
...entry.middleware || []
|
|
76
|
+
].filter(Boolean),
|
|
77
|
+
...entry
|
|
78
|
+
}).ready();
|
|
79
|
+
printInfo();
|
|
80
|
+
const cleanup = () => {
|
|
81
|
+
server.close(true).catch(() => {});
|
|
82
|
+
process.exit(0);
|
|
83
|
+
};
|
|
84
|
+
process.on("SIGINT", () => {
|
|
85
|
+
console.log(Colors.gray("\rStopping server..."));
|
|
86
|
+
cleanup();
|
|
87
|
+
});
|
|
88
|
+
process.on("SIGTERM", cleanup);
|
|
89
|
+
} catch (error) {
|
|
90
|
+
console.error(error);
|
|
91
|
+
process.exit(1);
|
|
92
|
+
}
|
|
93
|
+
}
|
|
94
|
+
async function loadEntry(opts) {
|
|
95
|
+
try {
|
|
96
|
+
if (!opts._entry) for (const entry of defaultEntries) {
|
|
97
|
+
for (const ext of defaultExts) {
|
|
98
|
+
const entryPath = resolve(opts._dir, `${entry}${ext}`);
|
|
99
|
+
if (existsSync(entryPath)) {
|
|
100
|
+
opts._entry = entryPath;
|
|
101
|
+
break;
|
|
102
|
+
}
|
|
103
|
+
}
|
|
104
|
+
if (opts._entry) break;
|
|
105
|
+
}
|
|
106
|
+
if (!opts._entry) return {
|
|
107
|
+
fetch: () => renderError(`No server entry file found.\nPlease specify an entry file or ensure one of the default entries exists (${defaultEntries.join(", ")}).`, 404, "No Server Entry"),
|
|
108
|
+
...opts
|
|
109
|
+
};
|
|
110
|
+
const entryURL = opts._entry.startsWith("file://") ? opts._entry : pathToFileURL(resolve(opts._entry)).href;
|
|
111
|
+
const entryModule = await import(entryURL);
|
|
112
|
+
return {
|
|
113
|
+
fetch: () => renderError(`The entry file "${relative(".", opts._entry)}" does not export a valid fetch handler.`, 500, "Invalid Entry"),
|
|
114
|
+
...entryModule.default,
|
|
115
|
+
...opts
|
|
116
|
+
};
|
|
117
|
+
} catch (error) {
|
|
118
|
+
console.error(Colors.red(`${Colors.bold(opts._entry)}`));
|
|
119
|
+
if (error instanceof Error) Error.captureStackTrace?.(error, serve);
|
|
120
|
+
throw error;
|
|
121
|
+
}
|
|
122
|
+
}
|
|
123
|
+
function renderError(error, status = 500, title = "Server Error") {
|
|
124
|
+
let html = `<!DOCTYPE html><html><head><title>${title}</title></head><body>`;
|
|
125
|
+
if (options._prod) html += `<h1>${title}</h1><p>Something went wrong while processing your request.</p>`;
|
|
126
|
+
else html += `
|
|
127
|
+
<style>
|
|
128
|
+
body { font-family: Arial, sans-serif; margin: 0; padding: 20px; background: #f8f9fa; color: #333; }
|
|
129
|
+
h1 { color: #dc3545; }
|
|
130
|
+
pre { background: #fff; padding: 10px; border-radius: 5px; overflow: auto; }
|
|
131
|
+
code { font-family: monospace; }
|
|
132
|
+
#error { display: flex; flex-direction: column; justify-content: center; align-items: center; height: 100vh; }
|
|
133
|
+
</style>
|
|
134
|
+
<div id="error"><h1>${title}</h1><pre>${error instanceof Error ? error.stack || error.message : String(error)}</pre></div>
|
|
135
|
+
`;
|
|
136
|
+
return new Response(html, {
|
|
137
|
+
status,
|
|
138
|
+
headers: { "Content-Type": "text/html; charset=utf-8" }
|
|
139
|
+
});
|
|
140
|
+
}
|
|
141
|
+
function printInfo() {
|
|
142
|
+
if (options._entry) console.log(Colors.gray(`${Colors.bold(Colors.gray("λ"))} Server entry: ${Colors.cyan("./" + relative(".", options._entry))} ${options._prod ? "" : Colors.gray("(watching for changes)")}`));
|
|
143
|
+
if (options._static) console.log(Colors.gray(`${Colors.bold(Colors.gray("⊟"))} Static files: ${Colors.cyan("./" + relative(".", options._static) + "/")}`));
|
|
144
|
+
}
|
|
145
|
+
async function version() {
|
|
146
|
+
const { default: pkg } = await import("../package.json", { with: { type: "json" } });
|
|
147
|
+
return `srvx v${pkg.version}\n${runtime()}`;
|
|
148
|
+
}
|
|
149
|
+
function runtime() {
|
|
150
|
+
if (process.versions.bun) return `bun v${process.versions.bun}`;
|
|
151
|
+
else if (process.versions.deno) return `deno v${process.versions.deno}`;
|
|
152
|
+
else return `node v${process.versions.node}`;
|
|
153
|
+
}
|
|
154
|
+
function parseArgs$1(args$1) {
|
|
155
|
+
const { values, positionals } = parseArgs({
|
|
156
|
+
args: args$1,
|
|
157
|
+
allowPositionals: true,
|
|
158
|
+
options: {
|
|
159
|
+
help: {
|
|
160
|
+
type: "boolean",
|
|
161
|
+
short: "h"
|
|
162
|
+
},
|
|
163
|
+
version: {
|
|
164
|
+
type: "boolean",
|
|
165
|
+
short: "v"
|
|
166
|
+
},
|
|
167
|
+
prod: { type: "boolean" },
|
|
168
|
+
port: {
|
|
169
|
+
type: "string",
|
|
170
|
+
short: "p"
|
|
171
|
+
},
|
|
172
|
+
host: {
|
|
173
|
+
type: "string",
|
|
174
|
+
short: "H"
|
|
175
|
+
},
|
|
176
|
+
static: {
|
|
177
|
+
type: "string",
|
|
178
|
+
short: "s"
|
|
179
|
+
},
|
|
180
|
+
tls: { type: "boolean" },
|
|
181
|
+
cert: { type: "string" },
|
|
182
|
+
key: { type: "string" }
|
|
183
|
+
}
|
|
184
|
+
});
|
|
185
|
+
const input = positionals[0] || ".";
|
|
186
|
+
let dir;
|
|
187
|
+
let entry = "";
|
|
188
|
+
if (extname(input) === "") dir = resolve(input);
|
|
189
|
+
else {
|
|
190
|
+
entry = resolve(input);
|
|
191
|
+
dir = dirname(entry);
|
|
192
|
+
}
|
|
193
|
+
return {
|
|
194
|
+
_dir: dir,
|
|
195
|
+
_entry: entry,
|
|
196
|
+
_prod: values.prod ?? process.env.NODE_ENV === "production",
|
|
197
|
+
_help: values.help,
|
|
198
|
+
_static: values.static || "public",
|
|
199
|
+
_version: values.version,
|
|
200
|
+
port: values.port ? Number.parseInt(values.port, 10) : void 0,
|
|
201
|
+
hostname: values.host,
|
|
202
|
+
tls: values.tls ? {
|
|
203
|
+
cert: values.cert,
|
|
204
|
+
key: values.key
|
|
205
|
+
} : void 0
|
|
206
|
+
};
|
|
207
|
+
}
|
|
208
|
+
function example() {
|
|
209
|
+
const useTs = !options._entry || options._entry.endsWith(".ts");
|
|
210
|
+
return `${Colors.bold(Colors.gray("// server.ts"))}
|
|
211
|
+
${Colors.magenta("export default")} {
|
|
212
|
+
${Colors.cyan("fetch")}(req${useTs ? ": Request" : ""}) {
|
|
213
|
+
${Colors.magenta("return")} new Response(${Colors.green("\"Hello, World!\"")});
|
|
214
|
+
}
|
|
215
|
+
}`;
|
|
216
|
+
}
|
|
217
|
+
function usage(mainOpts) {
|
|
218
|
+
const command = mainOpts.command;
|
|
219
|
+
return `
|
|
220
|
+
${Colors.cyan(command)} - Start an HTTP server with the specified entry path.
|
|
221
|
+
|
|
222
|
+
${Colors.bold("USAGE")}
|
|
223
|
+
${existsSync(options._entry) ? "" : `\n${example()}\n`}
|
|
224
|
+
${Colors.gray("# srvx [options] [entry]")}
|
|
225
|
+
${Colors.gray("$")} ${Colors.cyan(command)} ${Colors.gray("./server.ts")} ${Colors.gray("# Start development server")}
|
|
226
|
+
${Colors.gray("$")} ${Colors.cyan(command)} --prod ${Colors.gray("# Start production server")}
|
|
227
|
+
${Colors.gray("$")} ${Colors.cyan(command)} --port=8080 ${Colors.gray("# Listen on port 8080")}
|
|
228
|
+
${Colors.gray("$")} ${Colors.cyan(command)} --host=localhost ${Colors.gray("# Bind to localhost only")}
|
|
229
|
+
${Colors.gray("$")} ${Colors.cyan(command)} --tls --cert=cert.pem --key=key.pem ${Colors.gray("# Enable TLS (HTTPS/HTTP2)")}
|
|
230
|
+
|
|
231
|
+
${Colors.bold("ARGUMENTS")}
|
|
232
|
+
|
|
233
|
+
${Colors.yellow("<entry>")} Server entry path to serve.
|
|
234
|
+
Default: ${defaultEntries.map((e) => Colors.cyan(e)).join(", ")} ${Colors.gray(`(${defaultExts.join(",")})`)}
|
|
235
|
+
|
|
236
|
+
${Colors.bold("OPTIONS")}
|
|
237
|
+
|
|
238
|
+
${Colors.green("-p, --port")} ${Colors.yellow("<port>")} Port to listen on (default: ${Colors.yellow("3000")})
|
|
239
|
+
${Colors.green("--host")} ${Colors.yellow("<host>")} Host to bind to (default: all interfaces)
|
|
240
|
+
${Colors.green("-s, --static")} ${Colors.yellow("<dir>")} Serve static files from the specified directory (default: ${Colors.yellow("public")})
|
|
241
|
+
${Colors.green("--prod")} Run in production mode (no watch, no debug)
|
|
242
|
+
${Colors.green("--tls")} Enable TLS (HTTPS/HTTP2)
|
|
243
|
+
${Colors.green("--cert")} ${Colors.yellow("<file>")} TLS certificate file
|
|
244
|
+
${Colors.green("--key")} ${Colors.yellow("<file>")} TLS private key file
|
|
245
|
+
${Colors.green("-h, --help")} Show this help message
|
|
246
|
+
${Colors.green("-v, --version")} Show server and runtime versions
|
|
247
|
+
|
|
248
|
+
${Colors.bold("ENVIRONMENT")}
|
|
249
|
+
|
|
250
|
+
${Colors.green("PORT")} Override port
|
|
251
|
+
${Colors.green("HOST")} Override host
|
|
252
|
+
${Colors.green("NODE_ENV")} Set to ${Colors.yellow("production")} for production mode.
|
|
253
|
+
|
|
254
|
+
➤ ${Colors.url("Documentation", mainOpts.docs || "https://srvx.h3.dev")}
|
|
255
|
+
➤ ${Colors.url("Report issues", mainOpts.issues || "https://github.com/h3js/srvx/issues")}
|
|
256
|
+
`.trim();
|
|
257
|
+
}
|
|
258
|
+
function setupProcessErrorHandlers() {
|
|
259
|
+
process.on("uncaughtException", (error) => {
|
|
260
|
+
console.error("Uncaught exception:", error);
|
|
261
|
+
process.exit(1);
|
|
262
|
+
});
|
|
263
|
+
process.on("unhandledRejection", (reason) => {
|
|
264
|
+
console.error("Unhandled rejection:", reason);
|
|
265
|
+
process.exit(1);
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
|
|
269
|
+
//#endregion
|
|
270
|
+
export { main, usage };
|
package/dist/log.d.mts
ADDED
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
import { ServerMiddleware } from "./_chunks/types-GwbH0R0m.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/log.d.ts
|
|
4
|
+
// eslint-disable-next-line @typescript-eslint/no-empty-object-type
|
|
5
|
+
interface LogOptions {}
|
|
6
|
+
declare const log: (_options?: LogOptions) => ServerMiddleware;
|
|
7
|
+
//#endregion
|
|
8
|
+
export { LogOptions, log };
|
package/dist/log.mjs
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { Colors } from "./_chunks/_utils.cli-4eOGyiAa.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/log.ts
|
|
4
|
+
const log = (_options = {}) => {
|
|
5
|
+
return async (req, next) => {
|
|
6
|
+
const start = performance.now();
|
|
7
|
+
const res = await next();
|
|
8
|
+
const duration = performance.now() - start;
|
|
9
|
+
console.log(`${Colors.gray(`[${new Date().toLocaleTimeString()}]`)} ${Colors.bold(req.method)} ${Colors.blue(req.url)} [${Colors[res.ok ? "green" : "red"](res.status + "")}] ${Colors.gray(`(${duration.toFixed(2)}ms)`)}`);
|
|
10
|
+
return res;
|
|
11
|
+
};
|
|
12
|
+
};
|
|
13
|
+
|
|
14
|
+
//#endregion
|
|
15
|
+
export { log };
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { ServerMiddleware } from "./_chunks/types-GwbH0R0m.mjs";
|
|
2
|
+
|
|
3
|
+
//#region src/static.d.ts
|
|
4
|
+
interface ServeStaticOptions {
|
|
5
|
+
dir: string;
|
|
6
|
+
}
|
|
7
|
+
declare const serveStatic: (options: ServeStaticOptions) => ServerMiddleware;
|
|
8
|
+
//#endregion
|
|
9
|
+
export { ServeStaticOptions, serveStatic };
|
package/dist/static.mjs
ADDED
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
import { extname, join, resolve } from "node:path";
|
|
2
|
+
import { createReadStream } from "node:fs";
|
|
3
|
+
import { stat } from "node:fs/promises";
|
|
4
|
+
import { FastResponse } from "srvx";
|
|
5
|
+
import { createBrotliCompress, createGzip } from "node:zlib";
|
|
6
|
+
|
|
7
|
+
//#region src/static.ts
|
|
8
|
+
const COMMON_MIME_TYPES = {
|
|
9
|
+
".html": "text/html",
|
|
10
|
+
".htm": "text/html",
|
|
11
|
+
".css": "text/css",
|
|
12
|
+
".js": "text/javascript",
|
|
13
|
+
".mjs": "text/javascript",
|
|
14
|
+
".json": "application/json",
|
|
15
|
+
".txt": "text/plain",
|
|
16
|
+
".xml": "application/xml",
|
|
17
|
+
".gif": "image/gif",
|
|
18
|
+
".ico": "image/vnd.microsoft.icon",
|
|
19
|
+
".jpeg": "image/jpeg",
|
|
20
|
+
".jpg": "image/jpeg",
|
|
21
|
+
".png": "image/png",
|
|
22
|
+
".svg": "image/svg+xml",
|
|
23
|
+
".webp": "image/webp",
|
|
24
|
+
".woff": "font/woff",
|
|
25
|
+
".woff2": "font/woff2",
|
|
26
|
+
".mp4": "video/mp4",
|
|
27
|
+
".webm": "video/webm",
|
|
28
|
+
".zip": "application/zip",
|
|
29
|
+
".pdf": "application/pdf"
|
|
30
|
+
};
|
|
31
|
+
const serveStatic = (options) => {
|
|
32
|
+
const dir = resolve(options.dir) + "/";
|
|
33
|
+
return async (req, next) => {
|
|
34
|
+
if (req.method !== "GET" && req.method !== "HEAD") return next();
|
|
35
|
+
const path = new URL(req.url).pathname.slice(1).replace(/\/$/, "");
|
|
36
|
+
let paths;
|
|
37
|
+
if (path === "") paths = ["index.html"];
|
|
38
|
+
else if (extname(path) === "") paths = [`${path}.html`, `${path}/index.html`];
|
|
39
|
+
else paths = [path];
|
|
40
|
+
for (const path$1 of paths) {
|
|
41
|
+
const filePath = join(dir, path$1);
|
|
42
|
+
if (!filePath.startsWith(dir)) continue;
|
|
43
|
+
const fileStat = await stat(filePath).catch(() => null);
|
|
44
|
+
if (fileStat?.isFile()) {
|
|
45
|
+
const headers = {
|
|
46
|
+
"Content-Length": fileStat.size.toString(),
|
|
47
|
+
"Content-Type": COMMON_MIME_TYPES[extname(filePath)] || "application/octet-stream"
|
|
48
|
+
};
|
|
49
|
+
let stream = createReadStream(filePath);
|
|
50
|
+
const acceptEncoding = req.headers.get("accept-encoding") || "";
|
|
51
|
+
if (acceptEncoding.includes("br")) {
|
|
52
|
+
headers["Content-Encoding"] = "br";
|
|
53
|
+
delete headers["Content-Length"];
|
|
54
|
+
headers["Vary"] = "Accept-Encoding";
|
|
55
|
+
stream = stream.pipe(createBrotliCompress());
|
|
56
|
+
} else if (acceptEncoding.includes("gzip")) {
|
|
57
|
+
headers["Content-Encoding"] = "gzip";
|
|
58
|
+
delete headers["Content-Length"];
|
|
59
|
+
headers["Vary"] = "Accept-Encoding";
|
|
60
|
+
stream = stream.pipe(createGzip());
|
|
61
|
+
}
|
|
62
|
+
return new FastResponse(stream, { headers });
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return next();
|
|
66
|
+
};
|
|
67
|
+
};
|
|
68
|
+
|
|
69
|
+
//#endregion
|
|
70
|
+
export { serveStatic };
|
package/dist/types.d.mts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
import { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRuntimeContext, serve } from "./_chunks/types-
|
|
1
|
+
import { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRuntimeContext, serve } from "./_chunks/types-GwbH0R0m.mjs";
|
|
2
2
|
export { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRuntimeContext, serve };
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srvx",
|
|
3
|
-
"version": "0.8.
|
|
3
|
+
"version": "0.8.3",
|
|
4
4
|
"description": "Universal Server API based on web platform standards. Works seamlessly with Deno, Bun and Node.js.",
|
|
5
5
|
"homepage": "https://srvx.h3.dev",
|
|
6
6
|
"repository": "h3js/srvx",
|
|
@@ -14,6 +14,9 @@
|
|
|
14
14
|
"./cloudflare": "./dist/adapters/cloudflare.mjs",
|
|
15
15
|
"./generic": "./dist/adapters/generic.mjs",
|
|
16
16
|
"./service-worker": "./dist/adapters/service-worker.mjs",
|
|
17
|
+
"./cli": "./dist/cli.mjs",
|
|
18
|
+
"./static": "./dist/static.mjs",
|
|
19
|
+
"./log": "./dist/log.mjs",
|
|
17
20
|
".": {
|
|
18
21
|
"types": "./dist/types.d.mts",
|
|
19
22
|
"deno": "./dist/adapters/deno.mjs",
|
|
@@ -25,7 +28,11 @@
|
|
|
25
28
|
}
|
|
26
29
|
},
|
|
27
30
|
"types": "./dist/types.d.mts",
|
|
31
|
+
"bin": {
|
|
32
|
+
"srvx": "./bin/srvx.mjs"
|
|
33
|
+
},
|
|
28
34
|
"files": [
|
|
35
|
+
"bin",
|
|
29
36
|
"dist"
|
|
30
37
|
],
|
|
31
38
|
"scripts": {
|
|
@@ -39,13 +46,9 @@
|
|
|
39
46
|
"lint:fix": "automd && eslint . --fix && prettier -w .",
|
|
40
47
|
"node-ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types",
|
|
41
48
|
"prepack": "pnpm build",
|
|
42
|
-
"play:bun": "bun --watch playground/app.mjs",
|
|
43
|
-
"play:cf": "pnpx wrangler dev playground/app.mjs",
|
|
44
|
-
"play:deno": "deno run -A --watch playground/app.mjs",
|
|
45
49
|
"play:mkcert": "openssl req -x509 -newkey rsa:2048 -nodes -keyout server.key -out server.crt -days 365 -subj /CN=srvx.local",
|
|
46
|
-
"play:node": "pnpm node-ts --watch playground/app.mjs",
|
|
47
|
-
"play:sw": "pnpm build && pnpx serve playground",
|
|
48
50
|
"release": "pnpm test && changelogen --release && npm publish && git push --follow-tags",
|
|
51
|
+
"srvx": "./bin/srvx.mjs",
|
|
49
52
|
"test": "pnpm lint && pnpm test:types && vitest run --coverage",
|
|
50
53
|
"test:types": "tsc --noEmit --skipLibCheck"
|
|
51
54
|
},
|
|
@@ -73,6 +76,7 @@
|
|
|
73
76
|
"eslint-config-unjs": "^0.5.0",
|
|
74
77
|
"execa": "^9.6.0",
|
|
75
78
|
"get-port-please": "^3.1.2",
|
|
79
|
+
"mdbox": "^0.1.1",
|
|
76
80
|
"mitata": "^1.0.34",
|
|
77
81
|
"node-forge": "^1.3.1",
|
|
78
82
|
"obuild": "^0.2.1",
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|
|
File without changes
|