srvx 0.5.0 → 0.5.2
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/dist/adapters/bun.d.mts +1 -0
- package/dist/adapters/bun.mjs +2 -1
- package/dist/adapters/cloudflare.d.mts +2 -1
- package/dist/adapters/cloudflare.mjs +2 -1
- package/dist/adapters/deno.d.mts +1 -0
- package/dist/adapters/deno.mjs +2 -1
- package/dist/adapters/generic.d.mts +2 -1
- package/dist/adapters/generic.mjs +2 -1
- package/dist/adapters/node.d.mts +1 -0
- package/dist/adapters/node.mjs +2 -1
- package/dist/adapters/service-worker.d.mts +2 -1
- package/dist/adapters/service-worker.mjs +36 -25
- package/dist/shared/srvx.Ctaz0clH.mjs +172 -0
- package/dist/shared/srvx.DEE2RO4O.d.mts +5 -0
- package/dist/types.d.mts +2 -1
- package/package.json +9 -3
- package/dist/shared/srvx.FQfHxe2J.mjs +0 -75
package/dist/adapters/bun.d.mts
CHANGED
package/dist/adapters/bun.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.
|
|
1
|
+
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
2
|
+
export { F as URL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
2
3
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
3
4
|
import 'node:fs';
|
|
4
5
|
|
|
@@ -5,7 +5,8 @@ import 'node:https';
|
|
|
5
5
|
import 'node:net';
|
|
6
6
|
import 'bun';
|
|
7
7
|
|
|
8
|
+
declare const URL: typeof globalThis.URL;
|
|
8
9
|
declare const Response: typeof globalThis.Response;
|
|
9
10
|
declare function serve(options: ServerOptions): Server<CF.ExportedHandlerFetchHandler>;
|
|
10
11
|
|
|
11
|
-
export { Response, serve };
|
|
12
|
+
export { Response, URL, serve };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
2
2
|
import { w as wrapFetchOnError } from '../shared/srvx.BD9sRkkl.mjs';
|
|
3
3
|
|
|
4
|
+
const URL = globalThis.URL;
|
|
4
5
|
const Response = globalThis.Response;
|
|
5
6
|
function serve(options) {
|
|
6
7
|
return new CloudflareServer(options);
|
|
@@ -49,4 +50,4 @@ class CloudflareServer {
|
|
|
49
50
|
}
|
|
50
51
|
}
|
|
51
52
|
|
|
52
|
-
export { Response, serve };
|
|
53
|
+
export { Response, URL, serve };
|
package/dist/adapters/deno.d.mts
CHANGED
package/dist/adapters/deno.mjs
CHANGED
|
@@ -1,4 +1,5 @@
|
|
|
1
|
-
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.
|
|
1
|
+
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
2
|
+
export { F as URL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
2
3
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
3
4
|
import 'node:fs';
|
|
4
5
|
|
|
@@ -5,7 +5,8 @@ import 'node:net';
|
|
|
5
5
|
import 'bun';
|
|
6
6
|
import '@cloudflare/workers-types';
|
|
7
7
|
|
|
8
|
+
declare const URL: typeof globalThis.URL;
|
|
8
9
|
declare const Response: typeof globalThis.Response;
|
|
9
10
|
declare function serve(options: ServerOptions): Server;
|
|
10
11
|
|
|
11
|
-
export { Response, serve };
|
|
12
|
+
export { Response, URL, serve };
|
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
2
2
|
import { w as wrapFetchOnError } from '../shared/srvx.BD9sRkkl.mjs';
|
|
3
3
|
|
|
4
|
+
const URL = globalThis.URL;
|
|
4
5
|
const Response = globalThis.Response;
|
|
5
6
|
function serve(options) {
|
|
6
7
|
return new GenericServer(options);
|
|
@@ -27,4 +28,4 @@ class GenericServer {
|
|
|
27
28
|
}
|
|
28
29
|
}
|
|
29
30
|
|
|
30
|
-
export { Response, serve };
|
|
31
|
+
export { Response, URL, serve };
|
package/dist/adapters/node.d.mts
CHANGED
package/dist/adapters/node.mjs
CHANGED
|
@@ -1,7 +1,8 @@
|
|
|
1
1
|
import NodeHttp from 'node:http';
|
|
2
2
|
import NodeHttps from 'node:https';
|
|
3
3
|
import { splitSetCookieString } from 'cookie-es';
|
|
4
|
-
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.
|
|
4
|
+
import { r as resolveTLSOptions, a as resolvePortAndHost, p as printListening, f as fmtURL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
5
|
+
export { F as URL } from '../shared/srvx.Ctaz0clH.mjs';
|
|
5
6
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
6
7
|
import { w as wrapFetchOnError } from '../shared/srvx.BD9sRkkl.mjs';
|
|
7
8
|
import 'node:fs';
|
|
@@ -5,9 +5,10 @@ import 'node:net';
|
|
|
5
5
|
import 'bun';
|
|
6
6
|
import '@cloudflare/workers-types';
|
|
7
7
|
|
|
8
|
+
declare const URL: typeof globalThis.URL;
|
|
8
9
|
declare const Response: typeof globalThis.Response;
|
|
9
10
|
type ServiceWorkerHandler = (request: ServerRequest, event: FetchEvent) => Response | Promise<Response>;
|
|
10
11
|
declare function serve(options: ServerOptions): Server<ServiceWorkerHandler>;
|
|
11
12
|
|
|
12
|
-
export { Response, serve };
|
|
13
|
+
export { Response, URL, serve };
|
|
13
14
|
export type { ServiceWorkerHandler };
|
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
import { w as wrapFetch } from '../shared/srvx.DhN4g5wJ.mjs';
|
|
2
2
|
import { w as wrapFetchOnError } from '../shared/srvx.BD9sRkkl.mjs';
|
|
3
3
|
|
|
4
|
+
const URL = globalThis.URL;
|
|
4
5
|
const Response = globalThis.Response;
|
|
5
|
-
const
|
|
6
|
+
const isBrowserWindow = typeof window !== "undefined" && typeof navigator !== "undefined";
|
|
7
|
+
const isServiceWorker = typeof self !== "undefined" && "skipWaiting" in self;
|
|
6
8
|
function serve(options) {
|
|
7
9
|
return new ServiceWorkerServer(options);
|
|
8
10
|
}
|
|
@@ -30,7 +32,12 @@ class ServiceWorkerServer {
|
|
|
30
32
|
#fetchListener;
|
|
31
33
|
#listeningPromise;
|
|
32
34
|
serve() {
|
|
33
|
-
if (
|
|
35
|
+
if (isBrowserWindow) {
|
|
36
|
+
if (!navigator.serviceWorker) {
|
|
37
|
+
throw new Error(
|
|
38
|
+
"Service worker is not supported in the current window."
|
|
39
|
+
);
|
|
40
|
+
}
|
|
34
41
|
const swURL = this.options.serviceWorker?.url;
|
|
35
42
|
if (!swURL) {
|
|
36
43
|
throw new Error(
|
|
@@ -41,28 +48,32 @@ class ServiceWorkerServer {
|
|
|
41
48
|
type: "module",
|
|
42
49
|
scope: this.options.serviceWorker?.scope
|
|
43
50
|
}).then((registration) => {
|
|
44
|
-
registration.
|
|
51
|
+
if (registration.active) {
|
|
45
52
|
location.replace(location.href);
|
|
46
|
-
}
|
|
53
|
+
} else {
|
|
54
|
+
registration.addEventListener("updatefound", () => {
|
|
55
|
+
location.replace(location.href);
|
|
56
|
+
});
|
|
57
|
+
}
|
|
58
|
+
});
|
|
59
|
+
} else if (isServiceWorker) {
|
|
60
|
+
this.#fetchListener = async (event) => {
|
|
61
|
+
if (/\/[^/]*\.[a-zA-Z0-9]+$/.test(new URL(event.request.url).pathname)) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
const response = await this.fetch(event.request, event);
|
|
65
|
+
if (response.status !== 404) {
|
|
66
|
+
event.respondWith(response);
|
|
67
|
+
}
|
|
68
|
+
};
|
|
69
|
+
addEventListener("fetch", this.#fetchListener);
|
|
70
|
+
self.addEventListener("install", () => {
|
|
71
|
+
self.skipWaiting();
|
|
72
|
+
});
|
|
73
|
+
self.addEventListener("activate", () => {
|
|
74
|
+
self.clients?.claim?.();
|
|
47
75
|
});
|
|
48
|
-
return;
|
|
49
76
|
}
|
|
50
|
-
this.#fetchListener = async (event) => {
|
|
51
|
-
if (/\/[^/]*\.[a-zA-Z0-9]+$/.test(new URL(event.request.url).pathname)) {
|
|
52
|
-
return;
|
|
53
|
-
}
|
|
54
|
-
const response = await this.fetch(event.request, event);
|
|
55
|
-
if (response.status !== 404) {
|
|
56
|
-
event.respondWith(response);
|
|
57
|
-
}
|
|
58
|
-
};
|
|
59
|
-
addEventListener("fetch", this.#fetchListener);
|
|
60
|
-
globalThis.addEventListener("install", () => {
|
|
61
|
-
globalThis.skipWaiting();
|
|
62
|
-
});
|
|
63
|
-
globalThis.addEventListener("activate", (event) => {
|
|
64
|
-
event.waitUntil(globalThis.clients?.claim?.());
|
|
65
|
-
});
|
|
66
77
|
}
|
|
67
78
|
ready() {
|
|
68
79
|
return Promise.resolve(this.#listeningPromise).then(() => this);
|
|
@@ -71,17 +82,17 @@ class ServiceWorkerServer {
|
|
|
71
82
|
if (this.#fetchListener) {
|
|
72
83
|
removeEventListener("fetch", this.#fetchListener);
|
|
73
84
|
}
|
|
74
|
-
if (
|
|
85
|
+
if (isBrowserWindow) {
|
|
75
86
|
const registrations = await navigator.serviceWorker.getRegistrations();
|
|
76
87
|
for (const registration of registrations) {
|
|
77
88
|
if (registration.active) {
|
|
78
89
|
await registration.unregister();
|
|
79
90
|
}
|
|
80
91
|
}
|
|
81
|
-
} else {
|
|
82
|
-
await
|
|
92
|
+
} else if (isServiceWorker) {
|
|
93
|
+
await self.registration.unregister();
|
|
83
94
|
}
|
|
84
95
|
}
|
|
85
96
|
}
|
|
86
97
|
|
|
87
|
-
export { Response, serve };
|
|
98
|
+
export { Response, URL, serve };
|
|
@@ -0,0 +1,172 @@
|
|
|
1
|
+
import { readFileSync } from 'node:fs';
|
|
2
|
+
|
|
3
|
+
function resolvePortAndHost(opts) {
|
|
4
|
+
const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
|
|
5
|
+
const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
|
|
6
|
+
const hostname = opts.hostname ?? globalThis.process?.env.HOST;
|
|
7
|
+
return { port, hostname };
|
|
8
|
+
}
|
|
9
|
+
function fmtURL(host, port, secure) {
|
|
10
|
+
if (!host || !port) {
|
|
11
|
+
return void 0;
|
|
12
|
+
}
|
|
13
|
+
if (host.includes(":")) {
|
|
14
|
+
host = `[${host}]`;
|
|
15
|
+
}
|
|
16
|
+
return `http${secure ? "s" : ""}://${host}:${port}/`;
|
|
17
|
+
}
|
|
18
|
+
function printListening(opts, url) {
|
|
19
|
+
if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const _url = new URL(url);
|
|
23
|
+
const allInterfaces = _url.hostname === "[::]" || _url.hostname === "0.0.0.0";
|
|
24
|
+
if (allInterfaces) {
|
|
25
|
+
_url.hostname = "localhost";
|
|
26
|
+
url = _url.href;
|
|
27
|
+
}
|
|
28
|
+
let listeningOn = `\u279C Listening on:`;
|
|
29
|
+
let additionalInfo = allInterfaces ? " (all interfaces)" : "";
|
|
30
|
+
if (globalThis.process.stdout?.isTTY) {
|
|
31
|
+
listeningOn = `\x1B[32m${listeningOn}\x1B[0m`;
|
|
32
|
+
url = `\x1B[36m${url}\x1B[0m`;
|
|
33
|
+
additionalInfo = `\x1B[2m${additionalInfo}\x1B[0m`;
|
|
34
|
+
}
|
|
35
|
+
console.log(` ${listeningOn} ${url}${additionalInfo}`);
|
|
36
|
+
}
|
|
37
|
+
function resolveTLSOptions(opts) {
|
|
38
|
+
if (!opts.tls || opts.protocol === "http") {
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
const cert = resolveCertOrKey(opts.tls.cert);
|
|
42
|
+
const key = resolveCertOrKey(opts.tls.key);
|
|
43
|
+
if (!cert && !key) {
|
|
44
|
+
if (opts.protocol === "https") {
|
|
45
|
+
throw new TypeError(
|
|
46
|
+
"TLS `cert` and `key` must be provided for `https` protocol."
|
|
47
|
+
);
|
|
48
|
+
}
|
|
49
|
+
return;
|
|
50
|
+
}
|
|
51
|
+
if (!cert || !key) {
|
|
52
|
+
throw new TypeError("TLS `cert` and `key` must be provided together.");
|
|
53
|
+
}
|
|
54
|
+
return {
|
|
55
|
+
cert,
|
|
56
|
+
key,
|
|
57
|
+
passphrase: opts.tls.passphrase
|
|
58
|
+
};
|
|
59
|
+
}
|
|
60
|
+
function resolveCertOrKey(value) {
|
|
61
|
+
if (!value) {
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (typeof value !== "string") {
|
|
65
|
+
throw new TypeError(
|
|
66
|
+
"TLS certificate and key must be strings in PEM format or file paths."
|
|
67
|
+
);
|
|
68
|
+
}
|
|
69
|
+
if (value.startsWith("-----BEGIN ")) {
|
|
70
|
+
return value;
|
|
71
|
+
}
|
|
72
|
+
return readFileSync(value, "utf8");
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
const FastURL = /* @__PURE__ */ (() => {
|
|
76
|
+
const FastURL2 = class URL {
|
|
77
|
+
#originalURL;
|
|
78
|
+
#parsedURL;
|
|
79
|
+
constructor(url) {
|
|
80
|
+
this.#originalURL = url;
|
|
81
|
+
}
|
|
82
|
+
get _url() {
|
|
83
|
+
if (!this.#parsedURL) {
|
|
84
|
+
this.#parsedURL = new globalThis.URL(this.#originalURL);
|
|
85
|
+
}
|
|
86
|
+
return this.#parsedURL;
|
|
87
|
+
}
|
|
88
|
+
toString() {
|
|
89
|
+
return this._url.toString();
|
|
90
|
+
}
|
|
91
|
+
toJSON() {
|
|
92
|
+
return this.toString();
|
|
93
|
+
}
|
|
94
|
+
get pathname() {
|
|
95
|
+
if (this.#parsedURL) {
|
|
96
|
+
return this.#parsedURL.pathname;
|
|
97
|
+
}
|
|
98
|
+
if (!this._pathname) {
|
|
99
|
+
const url = this.#originalURL;
|
|
100
|
+
const protoIndex = url.indexOf("://");
|
|
101
|
+
if (protoIndex === -1) {
|
|
102
|
+
return this._url.pathname;
|
|
103
|
+
}
|
|
104
|
+
const pIndex = url.indexOf(
|
|
105
|
+
"/",
|
|
106
|
+
protoIndex + 4
|
|
107
|
+
/* :// */
|
|
108
|
+
);
|
|
109
|
+
if (pIndex === -1) {
|
|
110
|
+
return this._url.pathname;
|
|
111
|
+
}
|
|
112
|
+
const qIndex = this._urlqindex = url.indexOf("?", pIndex);
|
|
113
|
+
this._pathname = url.slice(pIndex, qIndex === -1 ? void 0 : qIndex);
|
|
114
|
+
}
|
|
115
|
+
return this._pathname;
|
|
116
|
+
}
|
|
117
|
+
set pathname(value) {
|
|
118
|
+
this._url.pathname = value;
|
|
119
|
+
}
|
|
120
|
+
get searchParams() {
|
|
121
|
+
if (this.#parsedURL) {
|
|
122
|
+
return this.#parsedURL.searchParams;
|
|
123
|
+
}
|
|
124
|
+
if (!this._query) {
|
|
125
|
+
this._query = new URLSearchParams(this.search);
|
|
126
|
+
}
|
|
127
|
+
return this._query;
|
|
128
|
+
}
|
|
129
|
+
get search() {
|
|
130
|
+
if (this.#parsedURL) {
|
|
131
|
+
return this.#parsedURL.search;
|
|
132
|
+
}
|
|
133
|
+
if (!this._search) {
|
|
134
|
+
const qIndex = this._urlqindex;
|
|
135
|
+
if (qIndex === -1) {
|
|
136
|
+
this._search = "";
|
|
137
|
+
} else {
|
|
138
|
+
this._search = qIndex === void 0 ? this._url.search : this.#originalURL.slice(this._urlqindex);
|
|
139
|
+
}
|
|
140
|
+
}
|
|
141
|
+
return this._search;
|
|
142
|
+
}
|
|
143
|
+
set search(value) {
|
|
144
|
+
this._url.search = value;
|
|
145
|
+
}
|
|
146
|
+
};
|
|
147
|
+
const slowProps = [
|
|
148
|
+
"hash",
|
|
149
|
+
"host",
|
|
150
|
+
"hostname",
|
|
151
|
+
"href",
|
|
152
|
+
"origin",
|
|
153
|
+
"password",
|
|
154
|
+
"port",
|
|
155
|
+
"protocol",
|
|
156
|
+
"username"
|
|
157
|
+
];
|
|
158
|
+
for (const prop of slowProps) {
|
|
159
|
+
Object.defineProperty(FastURL2.prototype, prop, {
|
|
160
|
+
get() {
|
|
161
|
+
return this._url[prop];
|
|
162
|
+
},
|
|
163
|
+
set(value) {
|
|
164
|
+
this._url[prop] = value;
|
|
165
|
+
}
|
|
166
|
+
});
|
|
167
|
+
}
|
|
168
|
+
Object.setPrototypeOf(FastURL2, globalThis.URL);
|
|
169
|
+
return FastURL2;
|
|
170
|
+
})();
|
|
171
|
+
|
|
172
|
+
export { FastURL as F, resolvePortAndHost as a, fmtURL as f, printListening as p, resolveTLSOptions as r };
|
package/dist/types.d.mts
CHANGED
|
@@ -6,6 +6,7 @@ import * as CF from '@cloudflare/workers-types';
|
|
|
6
6
|
|
|
7
7
|
type MaybePromise<T> = T | Promise<T>;
|
|
8
8
|
declare const Response: typeof globalThis.Response;
|
|
9
|
+
declare const URL: typeof globalThis.URL;
|
|
9
10
|
/**
|
|
10
11
|
* Create a new server instance.
|
|
11
12
|
*/
|
|
@@ -231,5 +232,5 @@ type DenoFetchHandler = (request: Request, info?: Deno.ServeHandlerInfo<Deno.Net
|
|
|
231
232
|
type NodeHttpHandler = (nodeReq: NodeHttp.IncomingMessage, nodeRes: NodeHttp.ServerResponse) => void | Promise<void>;
|
|
232
233
|
type CloudflareFetchHandler = CF.ExportedHandlerFetchHandler;
|
|
233
234
|
|
|
234
|
-
export { Response, serve };
|
|
235
|
+
export { Response, URL, serve };
|
|
235
236
|
export type { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FetchHandler, NodeHttpHandler, Server, ServerHandler, ServerOptions, ServerPlugin, ServerPluginInstance, ServerRequest, ServerRuntimeContext };
|
package/package.json
CHANGED
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "srvx",
|
|
3
|
-
"version": "0.5.
|
|
3
|
+
"version": "0.5.2",
|
|
4
4
|
"description": "Universal Server API based on web platform standards. Works seamlessly with Deno, Bun and Node.js.",
|
|
5
|
-
"repository": "h3js/srvx",
|
|
6
5
|
"homepage": "https://srvx.h3.dev",
|
|
6
|
+
"repository": "h3js/srvx",
|
|
7
7
|
"license": "MIT",
|
|
8
8
|
"sideEffects": false,
|
|
9
9
|
"type": "module",
|
|
@@ -31,10 +31,14 @@
|
|
|
31
31
|
],
|
|
32
32
|
"scripts": {
|
|
33
33
|
"bench:node": "node test/bench-node/_run.mjs",
|
|
34
|
+
"bench:url:bun": "bun run ./test/url.bench.ts",
|
|
35
|
+
"bench:url:deno": "deno run -A ./test/url.bench.ts",
|
|
36
|
+
"bench:url:node": "pnpm node-ts --expose-gc --allow-natives-syntax ./test/url.bench.ts",
|
|
34
37
|
"build": "unbuild",
|
|
35
38
|
"dev": "vitest dev",
|
|
36
39
|
"lint": "eslint . && prettier -c .",
|
|
37
40
|
"lint:fix": "automd && eslint . --fix && prettier -w .",
|
|
41
|
+
"node-ts": "node --disable-warning=ExperimentalWarning --experimental-strip-types",
|
|
38
42
|
"prepack": "pnpm build",
|
|
39
43
|
"play:bun": "bun playground/app.mjs",
|
|
40
44
|
"play:cf": "pnpx wrangler dev playground/app.mjs",
|
|
@@ -55,10 +59,12 @@
|
|
|
55
59
|
"devDependencies": {
|
|
56
60
|
"@cloudflare/workers-types": "^4.20250423.0",
|
|
57
61
|
"@hono/node-server": "^1.14.1",
|
|
62
|
+
"@mitata/counters": "^0.0.8",
|
|
58
63
|
"@mjackson/node-fetch-server": "^0.6.1",
|
|
59
64
|
"@types/bun": "^1.2.10",
|
|
60
65
|
"@types/deno": "^2.2.0",
|
|
61
66
|
"@types/node": "^22.14.1",
|
|
67
|
+
"@types/serviceworker": "^0.0.132",
|
|
62
68
|
"@vitest/coverage-v8": "^3.1.2",
|
|
63
69
|
"automd": "^0.4.0",
|
|
64
70
|
"changelogen": "^0.6.1",
|
|
@@ -66,7 +72,7 @@
|
|
|
66
72
|
"eslint-config-unjs": "^0.4.2",
|
|
67
73
|
"execa": "^9.5.2",
|
|
68
74
|
"get-port-please": "^3.1.2",
|
|
69
|
-
"
|
|
75
|
+
"mitata": "^1.0.34",
|
|
70
76
|
"prettier": "^3.5.3",
|
|
71
77
|
"typescript": "^5.8.3",
|
|
72
78
|
"unbuild": "^3.5.0",
|
|
@@ -1,75 +0,0 @@
|
|
|
1
|
-
import { readFileSync } from 'node:fs';
|
|
2
|
-
|
|
3
|
-
function resolvePortAndHost(opts) {
|
|
4
|
-
const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
|
|
5
|
-
const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
|
|
6
|
-
const hostname = opts.hostname ?? globalThis.process?.env.HOST;
|
|
7
|
-
return { port, hostname };
|
|
8
|
-
}
|
|
9
|
-
function fmtURL(host, port, secure) {
|
|
10
|
-
if (!host || !port) {
|
|
11
|
-
return void 0;
|
|
12
|
-
}
|
|
13
|
-
if (host.includes(":")) {
|
|
14
|
-
host = `[${host}]`;
|
|
15
|
-
}
|
|
16
|
-
return `http${secure ? "s" : ""}://${host}:${port}/`;
|
|
17
|
-
}
|
|
18
|
-
function printListening(opts, url) {
|
|
19
|
-
if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) {
|
|
20
|
-
return;
|
|
21
|
-
}
|
|
22
|
-
const _url = new URL(url);
|
|
23
|
-
const allInterfaces = _url.hostname === "[::]" || _url.hostname === "0.0.0.0";
|
|
24
|
-
if (allInterfaces) {
|
|
25
|
-
_url.hostname = "localhost";
|
|
26
|
-
url = _url.href;
|
|
27
|
-
}
|
|
28
|
-
let listeningOn = `\u279C Listening on:`;
|
|
29
|
-
let additionalInfo = allInterfaces ? " (all interfaces)" : "";
|
|
30
|
-
if (globalThis.process.stdout?.isTTY) {
|
|
31
|
-
listeningOn = `\x1B[32m${listeningOn}\x1B[0m`;
|
|
32
|
-
url = `\x1B[36m${url}\x1B[0m`;
|
|
33
|
-
additionalInfo = `\x1B[2m${additionalInfo}\x1B[0m`;
|
|
34
|
-
}
|
|
35
|
-
console.log(` ${listeningOn} ${url}${additionalInfo}`);
|
|
36
|
-
}
|
|
37
|
-
function resolveTLSOptions(opts) {
|
|
38
|
-
if (!opts.tls || opts.protocol === "http") {
|
|
39
|
-
return;
|
|
40
|
-
}
|
|
41
|
-
const cert = resolveCertOrKey(opts.tls.cert);
|
|
42
|
-
const key = resolveCertOrKey(opts.tls.key);
|
|
43
|
-
if (!cert && !key) {
|
|
44
|
-
if (opts.protocol === "https") {
|
|
45
|
-
throw new TypeError(
|
|
46
|
-
"TLS `cert` and `key` must be provided for `https` protocol."
|
|
47
|
-
);
|
|
48
|
-
}
|
|
49
|
-
return;
|
|
50
|
-
}
|
|
51
|
-
if (!cert || !key) {
|
|
52
|
-
throw new TypeError("TLS `cert` and `key` must be provided together.");
|
|
53
|
-
}
|
|
54
|
-
return {
|
|
55
|
-
cert,
|
|
56
|
-
key,
|
|
57
|
-
passphrase: opts.tls.passphrase
|
|
58
|
-
};
|
|
59
|
-
}
|
|
60
|
-
function resolveCertOrKey(value) {
|
|
61
|
-
if (!value) {
|
|
62
|
-
return;
|
|
63
|
-
}
|
|
64
|
-
if (typeof value !== "string") {
|
|
65
|
-
throw new TypeError(
|
|
66
|
-
"TLS certificate and key must be strings in PEM format or file paths."
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
if (value.startsWith("-----BEGIN ")) {
|
|
70
|
-
return value;
|
|
71
|
-
}
|
|
72
|
-
return readFileSync(value, "utf8");
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
export { resolvePortAndHost as a, fmtURL as f, printListening as p, resolveTLSOptions as r };
|