nuxt-devkit-server 0.0.1

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 ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 lonewolfyx
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,192 @@
1
+ # nuxt-devkit-server
2
+
3
+ A lightweight Node.js library for creating a local HTTP server that runs Nitro/Nuxt build outputs in CLI tools.
4
+
5
+ It dynamically imports the Nitro server entry point from a build output directory, wraps it in a `node:http` server, and optionally sets up WebSocket support via `crossws`.
6
+
7
+ ## Installation
8
+
9
+ ```bash
10
+ pnpm add nuxt-devkit-server
11
+ ```
12
+
13
+ If you need WebSocket support, install `crossws` as well:
14
+
15
+ ```bash
16
+ pnpm add crossws
17
+ ```
18
+
19
+ ## Usage
20
+
21
+ ### Basic
22
+
23
+ ```ts
24
+ import { createRuntimeServer } from 'nuxt-devkit-server'
25
+
26
+ const app = await createRuntimeServer({
27
+ path: '.output',
28
+ })
29
+
30
+ console.log(`Server running at ${app.url}`) // http://127.0.0.1:7777
31
+
32
+ // Close the server when done
33
+ await app.close()
34
+ ```
35
+
36
+ ### Custom Host and Port
37
+
38
+ ```ts
39
+ const app = await createRuntimeServer({
40
+ path: '.output/server/index.mjs',
41
+ host: '0.0.0.0',
42
+ port: 3000,
43
+ })
44
+ ```
45
+
46
+ ### Using the `onReady` Callback
47
+
48
+ ```ts
49
+ const app = await createRuntimeServer({
50
+ path: 'dist',
51
+ onReady({ info, app, port }) {
52
+ console.log(`Listening on ${info.address}:${port}`)
53
+ },
54
+ })
55
+ ```
56
+
57
+ ### Direct Path to Server Entry
58
+
59
+ You can pass either a Nitro build output directory or a direct path to `server/index.mjs`:
60
+
61
+ ```ts
62
+ // Directory — automatically resolves to <path>/server/index.mjs
63
+ const app = await createRuntimeServer({ path: '.output' })
64
+
65
+ // Direct file path
66
+ const app = await createRuntimeServer({ path: 'dist/server/index.mjs' })
67
+ ```
68
+
69
+ ## API Reference
70
+
71
+ ### `createRuntimeServer(options): Promise<RuntimeServer>`
72
+
73
+ Creates and starts an HTTP server backed by a Nitro/Nuxt build output.
74
+
75
+ | Parameter | Type | Required | Default | Description |
76
+ |---|---|---|---|---|
77
+ | `options` | `CreateRuntimeServerOptions` | Yes | — | Configuration options |
78
+
79
+ Returns a `Promise<RuntimeServer>` that resolves once the server is listening.
80
+
81
+ ---
82
+
83
+ ### `CreateRuntimeServerOptions`
84
+
85
+ ```ts
86
+ interface CreateRuntimeServerOptions {
87
+ /**
88
+ * Nitro / Nuxt build output directory, or the direct path to server/index.mjs.
89
+ *
90
+ * Supported:
91
+ * - dist
92
+ * - .output
93
+ * - dist/server/index.mjs
94
+ * - .output/server/index.mjs
95
+ */
96
+ path: string
97
+
98
+ /**
99
+ * Server port.
100
+ * Defaults to a dynamic port in the range [7777, 9000].
101
+ */
102
+ port?: number
103
+
104
+ /**
105
+ * Server listen address.
106
+ * Defaults to '127.0.0.1'.
107
+ */
108
+ host?: string
109
+
110
+ /**
111
+ * Callback fired once the server is listening.
112
+ */
113
+ onReady?: (info: {
114
+ info: AddressInfo
115
+ app: RuntimeServer
116
+ port: number
117
+ }) => void
118
+ }
119
+ ```
120
+
121
+ ### `RuntimeServer`
122
+
123
+ ```ts
124
+ interface RuntimeServer {
125
+ /** The underlying Node.js HTTP server instance. */
126
+ server: Server
127
+
128
+ /** The full URL of the running server (e.g. http://127.0.0.1:7777). */
129
+ url: string
130
+
131
+ /** Gracefully shuts down the server. */
132
+ close: () => Promise<void>
133
+ }
134
+ ```
135
+
136
+ ### `NitroModule`
137
+
138
+ The shape of a dynamically imported Nitro server module.
139
+
140
+ ```ts
141
+ interface NitroModule {
142
+ listener?: unknown
143
+ middleware?: unknown
144
+ handler?: unknown
145
+ default?: unknown
146
+ websocket?: unknown
147
+ }
148
+ ```
149
+
150
+ The library resolves the HTTP handler in priority order: `listener` > `middleware` > `handler` > `default`.
151
+
152
+ ### `NitroNodeListener`
153
+
154
+ The type of a Nitro HTTP handler function.
155
+
156
+ ```ts
157
+ type NitroNodeListener = (
158
+ req: IncomingMessage,
159
+ res: ServerResponse,
160
+ ) => MaybePromise<void>
161
+ ```
162
+
163
+ ### `MaybePromise<T>`
164
+
165
+ A value that may or may not be a promise.
166
+
167
+ ```ts
168
+ type MaybePromise<T> = T | Promise<T>
169
+ ```
170
+
171
+ ## Development
172
+
173
+ ```bash
174
+ # Install dependencies
175
+ pnpm install
176
+
177
+ # Start development with watch mode
178
+ pnpm dev
179
+
180
+ # Run tests
181
+ pnpm test
182
+
183
+ # Lint
184
+ pnpm lint
185
+
186
+ # Build for production
187
+ pnpm build
188
+ ```
189
+
190
+ ## License
191
+
192
+ [MIT](./LICENSE) &copy; [lonewolfyx](https://github.com/lonewolfyx)
@@ -0,0 +1,51 @@
1
+ import { IncomingMessage, Server, ServerResponse } from "node:http";
2
+ import { AddressInfo } from "node:net";
3
+
4
+ //#region src/types.d.ts
5
+ type MaybePromise<T> = T | Promise<T>;
6
+ type NitroNodeListener = (req: IncomingMessage, res: ServerResponse) => MaybePromise<void>;
7
+ interface NitroModule {
8
+ listener?: unknown;
9
+ middleware?: unknown;
10
+ handler?: unknown;
11
+ default?: unknown;
12
+ websocket?: unknown;
13
+ }
14
+ interface CreateRuntimeServerOptions {
15
+ /**
16
+ * Nitro / Nuxt build output directory, or the direct path to server/index.mjs.
17
+ *
18
+ * Supported:
19
+ * - dist
20
+ * - .output
21
+ * - dist/server/index.mjs
22
+ * - .output/server/index.mjs
23
+ */
24
+ path: string;
25
+ /**
26
+ * Server port, defaults to 7777
27
+ */
28
+ port?: number;
29
+ /**
30
+ * Server listen address, defaults to 127.0.0.1
31
+ */
32
+ host?: string;
33
+ /**
34
+ * Callback fired once the server is listening.
35
+ */
36
+ onReady?: (info: {
37
+ info: AddressInfo;
38
+ app: RuntimeServer;
39
+ port: number;
40
+ }) => void;
41
+ }
42
+ interface RuntimeServer {
43
+ server: Server;
44
+ url: string;
45
+ close: () => Promise<void>;
46
+ }
47
+ //#endregion
48
+ //#region src/runtime.d.ts
49
+ declare function createRuntimeServer(options: CreateRuntimeServerOptions): Promise<RuntimeServer>;
50
+ //#endregion
51
+ export { type CreateRuntimeServerOptions, type MaybePromise, type NitroModule, type NitroNodeListener, type RuntimeServer, createRuntimeServer };
package/dist/index.mjs ADDED
@@ -0,0 +1,88 @@
1
+ import { existsSync, statSync } from "node:fs";
2
+ import { createServer } from "node:http";
3
+ import { isAbsolute, resolve } from "node:path";
4
+ import { pathToFileURL } from "node:url";
5
+ import { getPort } from "get-port-please";
6
+ //#region src/runtime.ts
7
+ function toAbsolutePath(path) {
8
+ return isAbsolute(path) ? path : resolve(process.cwd(), path);
9
+ }
10
+ function resolveNitroEntry(inputPath) {
11
+ const absolutePath = toAbsolutePath(inputPath);
12
+ if (!existsSync(absolutePath)) throw new Error(`Runtime path does not exist: ${absolutePath}`);
13
+ const entryPath = statSync(absolutePath).isDirectory() ? resolve(absolutePath, "server/index.mjs") : absolutePath;
14
+ if (!existsSync(entryPath)) throw new Error(`Nitro entry not found: ${entryPath}`);
15
+ return entryPath;
16
+ }
17
+ function pickNitroListener(mod) {
18
+ const listener = mod.listener ?? mod.middleware ?? mod.handler ?? mod.default;
19
+ if (typeof listener !== "function") throw new TypeError("Cannot find a valid Nitro node listener export. Expected one of: listener, middleware, handler, default.");
20
+ return listener;
21
+ }
22
+ async function loadNitroEntrypoint(path) {
23
+ const mod = await import(pathToFileURL(resolveNitroEntry(path)).href);
24
+ return {
25
+ listener: pickNitroListener(mod),
26
+ websocket: mod.websocket
27
+ };
28
+ }
29
+ function listen(server, host, port) {
30
+ return new Promise((res, rej) => {
31
+ server.once("error", rej);
32
+ server.listen(port, host, () => {
33
+ server.off("error", rej);
34
+ res(server.address().port);
35
+ });
36
+ });
37
+ }
38
+ function closeServer(server) {
39
+ return new Promise((res, rej) => {
40
+ server.close((error) => {
41
+ if (error) {
42
+ rej(error);
43
+ return;
44
+ }
45
+ res();
46
+ });
47
+ });
48
+ }
49
+ async function setupWebSocket(server, websocket) {
50
+ if (!websocket) return;
51
+ const { default: nodeAdapter } = await import("crossws/adapters/node");
52
+ const { handleUpgrade } = nodeAdapter(websocket);
53
+ server.on("upgrade", (req, socket, head) => {
54
+ handleUpgrade(req, socket, head);
55
+ });
56
+ }
57
+ async function createRuntimeServer(options) {
58
+ const port = options.port ?? await getPort({ portRange: [7777, 9e3] });
59
+ const host = options.host ?? "127.0.0.1";
60
+ const nitro = await loadNitroEntrypoint(options.path);
61
+ const server = createServer(async (req, res) => {
62
+ try {
63
+ await nitro.listener(req, res);
64
+ } catch (error) {
65
+ if (!res.headersSent) {
66
+ res.statusCode = 500;
67
+ res.setHeader("content-type", "text/plain; charset=utf-8");
68
+ }
69
+ const message = error instanceof Error ? error.stack ?? error.message : String(error);
70
+ res.end(message);
71
+ }
72
+ });
73
+ await setupWebSocket(server, nitro.websocket);
74
+ const actualPort = await listen(server, host, port);
75
+ const app = {
76
+ server,
77
+ url: `http://${host}:${actualPort}`,
78
+ close: () => closeServer(server)
79
+ };
80
+ if (options.onReady) options.onReady({
81
+ info: server.address(),
82
+ app,
83
+ port: actualPort
84
+ });
85
+ return app;
86
+ }
87
+ //#endregion
88
+ export { createRuntimeServer };
package/package.json ADDED
@@ -0,0 +1,76 @@
1
+ {
2
+ "name": "nuxt-devkit-server",
3
+ "type": "module",
4
+ "version": "0.0.1",
5
+ "packageManager": "pnpm@10.33.2",
6
+ "description": "Create a local server for running Nuxt outputs in CLI tools.",
7
+ "author": "lonewolfyx",
8
+ "license": "MIT",
9
+ "homepage": "https://github.com/lonewolfyx/nuxt-devkit-server",
10
+ "bugs": {
11
+ "url": "https://github.com/lonewolfyx/nuxt-devkit-server/issues"
12
+ },
13
+ "keywords": [
14
+ "nuxt",
15
+ "dev",
16
+ "server"
17
+ ],
18
+ "exports": {
19
+ ".": {
20
+ "types": "./dist/index.d.ts",
21
+ "import": "./dist/index.mjs"
22
+ }
23
+ },
24
+ "main": "./dist/index.mjs",
25
+ "types": "./dist/index.d.ts",
26
+ "files": [
27
+ "dist"
28
+ ],
29
+ "scripts": {
30
+ "dev": "tsdown --watch",
31
+ "build": "tsdown",
32
+ "test": "vitest run",
33
+ "test:watch": "vitest",
34
+ "lint": "eslint .",
35
+ "lint:fix": "eslint --fix",
36
+ "prepare": "simple-git-hooks",
37
+ "prepublishOnly": "pnpm build"
38
+ },
39
+ "publishConfig": {
40
+ "registry": "https://registry.npmjs.org",
41
+ "access": "public"
42
+ },
43
+ "peerDependencies": {
44
+ "crossws": ">=0.4"
45
+ },
46
+ "peerDependenciesMeta": {
47
+ "crossws": {
48
+ "optional": true
49
+ }
50
+ },
51
+ "dependencies": {
52
+ "get-port-please": "^3.2.0"
53
+ },
54
+ "devDependencies": {
55
+ "@antfu/eslint-config": "^9.0.0",
56
+ "@lonewolfyx/tsconfig": "^0.0.6",
57
+ "@types/node": "^25.9.1",
58
+ "crossws": "^0.4.5",
59
+ "eslint": "^10.4.0",
60
+ "jiti": "^2.7.0",
61
+ "nano-staged": "^1.0.2",
62
+ "picocolors": "^1.1.1",
63
+ "simple-git-hooks": "^2.13.1",
64
+ "tsdown": "^0.22.0",
65
+ "tsx": "^4.22.3",
66
+ "typescript": "^6.0.3",
67
+ "vitest": "^4.1.7"
68
+ },
69
+ "simple-git-hooks": {
70
+ "pre-commit": "npx nano-staged",
71
+ "commit-msg": "node scripts/verify-commit.js"
72
+ },
73
+ "nano-staged": {
74
+ "*": "eslint --fix"
75
+ }
76
+ }