srvx 0.11.3 → 0.11.5

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.
@@ -10,8 +10,9 @@ declare class BunServer implements Server<BunFetchHandler> {
10
10
  readonly runtime = "bun";
11
11
  readonly options: Server["options"];
12
12
  readonly bun: Server["bun"];
13
- readonly serveOptions: bun.Serve.Options<any>;
13
+ readonly serveOptions: bun.Serve.Options<any> | undefined;
14
14
  readonly fetch: BunFetchHandler;
15
+ readonly waitUntil?: Server["waitUntil"];
15
16
  constructor(options: ServerOptions);
16
17
  serve(): Promise<this>;
17
18
  get url(): string | undefined;
@@ -11,6 +11,7 @@ var BunServer = class {
11
11
  bun = {};
12
12
  serveOptions;
13
13
  fetch;
14
+ waitUntil;
14
15
  #wait;
15
16
  constructor(options) {
16
17
  this.options = {
@@ -20,10 +21,17 @@ var BunServer = class {
20
21
  for (const plugin of options.plugins || []) plugin(this);
21
22
  gracefulShutdownPlugin(this);
22
23
  const fetchHandler = wrapFetch(this);
24
+ const loader = globalThis.__srvxLoader__;
25
+ if (loader) {
26
+ this.fetch = fetchHandler;
27
+ loader(fetchHandler);
28
+ return;
29
+ }
23
30
  this.#wait = createWaitUntil();
31
+ this.waitUntil = this.#wait.waitUntil;
24
32
  this.fetch = (request, server) => {
25
33
  Object.defineProperties(request, {
26
- waitUntil: { value: this.#wait.waitUntil },
34
+ waitUntil: { value: this.#wait?.waitUntil },
27
35
  runtime: {
28
36
  enumerable: true,
29
37
  value: {
@@ -72,7 +80,7 @@ var BunServer = class {
72
80
  return Promise.resolve(this);
73
81
  }
74
82
  async close(closeAll) {
75
- await Promise.all([this.#wait.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
83
+ await Promise.all([this.#wait?.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
76
84
  }
77
85
  };
78
86
  export { FastResponse, FastURL, serve };
@@ -0,0 +1,8 @@
1
+ import { Server, ServerOptions } from "../types.mjs";
2
+
3
+ //#region src/adapters/bunny.d.ts
4
+ declare const FastURL: typeof globalThis.URL;
5
+ declare const FastResponse: typeof globalThis.Response;
6
+ declare function serve(options: ServerOptions): Server;
7
+ //#endregion
8
+ export { FastResponse, FastURL, serve };
@@ -0,0 +1,55 @@
1
+ import { t as createWaitUntil } from "../_chunks/_utils2.mjs";
2
+ import { r as wrapFetch, t as errorPlugin } from "../_chunks/_plugins.mjs";
3
+ const FastURL = URL;
4
+ const FastResponse = Response;
5
+ function serve(options) {
6
+ return new BunnyServer(options);
7
+ }
8
+ var BunnyServer = class {
9
+ runtime = "bunny";
10
+ options;
11
+ fetch;
12
+ _started = false;
13
+ #wait;
14
+ constructor(options) {
15
+ this.options = {
16
+ ...options,
17
+ middleware: [...options.middleware || []]
18
+ };
19
+ for (const plugin of options.plugins || []) plugin(this);
20
+ errorPlugin(this);
21
+ const fetchHandler = wrapFetch(this);
22
+ this.#wait = createWaitUntil();
23
+ this.fetch = (request) => {
24
+ Object.defineProperties(request, {
25
+ waitUntil: { value: this.#wait?.waitUntil },
26
+ runtime: {
27
+ enumerable: true,
28
+ value: { name: "bunny" }
29
+ },
30
+ ip: {
31
+ enumerable: true,
32
+ get() {
33
+ return request.headers.get("x-real-ip");
34
+ }
35
+ }
36
+ });
37
+ return fetchHandler(request);
38
+ };
39
+ if (!options.manual) this.serve();
40
+ }
41
+ serve() {
42
+ if (typeof Bunny !== "undefined" && Bunny.v1?.serve) {
43
+ if (this._started) return;
44
+ this._started = true;
45
+ Bunny.v1.serve(this.fetch);
46
+ } else throw new Error("[srvx] Bunny runtime not detected.");
47
+ }
48
+ ready() {
49
+ return Promise.resolve(this);
50
+ }
51
+ async close() {
52
+ await this.#wait?.wait();
53
+ }
54
+ };
55
+ export { FastResponse, FastURL, serve };
@@ -9,8 +9,9 @@ declare class DenoServer implements Server<DenoFetchHandler> {
9
9
  readonly runtime = "deno";
10
10
  readonly options: Server["options"];
11
11
  readonly deno: Server["deno"];
12
- readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem);
12
+ readonly serveOptions: Deno.ServeTcpOptions | (Deno.ServeTcpOptions & Deno.TlsCertifiedKeyPem) | undefined;
13
13
  readonly fetch: DenoFetchHandler;
14
+ readonly waitUntil?: Server["waitUntil"];
14
15
  constructor(options: ServerOptions);
15
16
  serve(): Promise<this>;
16
17
  get url(): string | undefined;
@@ -11,6 +11,7 @@ var DenoServer = class {
11
11
  deno = {};
12
12
  serveOptions;
13
13
  fetch;
14
+ waitUntil;
14
15
  #listeningPromise;
15
16
  #listeningInfo;
16
17
  #wait;
@@ -22,10 +23,17 @@ var DenoServer = class {
22
23
  for (const plugin of options.plugins || []) plugin(this);
23
24
  gracefulShutdownPlugin(this);
24
25
  const fetchHandler = wrapFetch(this);
26
+ const loader = globalThis.__srvxLoader__;
27
+ if (loader) {
28
+ this.fetch = fetchHandler;
29
+ loader(fetchHandler);
30
+ return;
31
+ }
25
32
  this.#wait = createWaitUntil();
33
+ this.waitUntil = this.#wait.waitUntil;
26
34
  this.fetch = (request, info) => {
27
35
  Object.defineProperties(request, {
28
- waitUntil: { value: this.#wait.waitUntil },
36
+ waitUntil: { value: this.#wait?.waitUntil },
29
37
  runtime: {
30
38
  enumerable: true,
31
39
  value: {
@@ -81,7 +89,7 @@ var DenoServer = class {
81
89
  return Promise.resolve(this.#listeningPromise).then(() => this);
82
90
  }
83
91
  async close() {
84
- await Promise.all([this.#wait.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
92
+ await Promise.all([this.#wait?.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
85
93
  }
86
94
  };
87
95
  export { FastResponse, FastURL, serve };
@@ -9,6 +9,7 @@ var GenericServer = class {
9
9
  runtime = "generic";
10
10
  options;
11
11
  fetch;
12
+ waitUntil;
12
13
  #wait;
13
14
  constructor(options) {
14
15
  this.options = {
@@ -18,6 +19,7 @@ var GenericServer = class {
18
19
  for (const plugin of options.plugins || []) plugin(this);
19
20
  errorPlugin(this);
20
21
  this.#wait = createWaitUntil();
22
+ this.waitUntil = this.#wait.waitUntil;
21
23
  const fetchHandler = wrapFetch(this);
22
24
  this.fetch = (request) => {
23
25
  Object.defineProperties(request, { waitUntil: { value: this.#wait.waitUntil } });
@@ -660,6 +660,7 @@ var NodeServer = class {
660
660
  node;
661
661
  serveOptions;
662
662
  fetch;
663
+ waitUntil;
663
664
  #isSecure;
664
665
  #listeningPromise;
665
666
  #wait;
@@ -670,15 +671,21 @@ var NodeServer = class {
670
671
  };
671
672
  for (const plugin of options.plugins || []) plugin(this);
672
673
  errorPlugin(this);
673
- gracefulShutdownPlugin(this);
674
674
  const fetchHandler = this.fetch = wrapFetch(this);
675
+ const loader = globalThis.__srvxLoader__;
676
+ if (loader) {
677
+ loader(fetchHandler);
678
+ return;
679
+ }
680
+ gracefulShutdownPlugin(this);
675
681
  this.#wait = createWaitUntil();
682
+ this.waitUntil = this.#wait.waitUntil;
676
683
  const handler = (nodeReq, nodeRes) => {
677
684
  const request = new NodeRequest({
678
685
  req: nodeReq,
679
686
  res: nodeRes
680
687
  });
681
- request.waitUntil = this.#wait.waitUntil;
688
+ request.waitUntil = this.#wait?.waitUntil;
682
689
  const res = fetchHandler(request);
683
690
  return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
684
691
  };
@@ -728,7 +735,7 @@ var NodeServer = class {
728
735
  return Promise.resolve(this.#listeningPromise).then(() => this);
729
736
  }
730
737
  async close(closeAll) {
731
- await Promise.all([this.#wait.wait(), new Promise((resolve, reject) => {
738
+ await Promise.all([this.#wait?.wait(), new Promise((resolve, reject) => {
732
739
  const server = this.node?.server;
733
740
  if (server && closeAll && "closeAllConnections" in server) server.closeAllConnections();
734
741
  if (!server || !server.listening) return resolve();
package/dist/cli.mjs CHANGED
@@ -174,7 +174,7 @@ function getResponseFormat(res) {
174
174
  }
175
175
  const srvxMeta = {
176
176
  name: "srvx",
177
- version: "0.11.3",
177
+ version: "0.11.5",
178
178
  description: "Universal Server."
179
179
  };
180
180
  function usage(mainOpts) {
package/dist/loader.mjs CHANGED
@@ -34,12 +34,14 @@ async function loadServerEntry(opts) {
34
34
  }
35
35
  const url = entry.startsWith("file://") ? entry : pathToFileURL(resolve(entry)).href;
36
36
  let mod;
37
- let listenHandler;
37
+ let interceptedNodeHandler;
38
+ let interceptedFetchHandler;
38
39
  try {
39
40
  if (opts.interceptHttpListen !== false) {
40
41
  const loaded = await interceptListen(() => import(url));
41
42
  mod = loaded.res;
42
- listenHandler = loaded.listenHandler;
43
+ interceptedNodeHandler = loaded.listenHandler;
44
+ interceptedFetchHandler = loaded.fetchHandler;
43
45
  } else mod = await import(url);
44
46
  } catch (error) {
45
47
  if (error?.code === "ERR_UNKNOWN_FILE_EXTENSION") {
@@ -50,11 +52,11 @@ async function loadServerEntry(opts) {
50
52
  throw error;
51
53
  }
52
54
  mod = await opts?.onLoad?.(mod) || mod;
53
- let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch;
55
+ let fetchHandler = mod?.fetch || mod?.default?.fetch || mod?.default?.default?.fetch || interceptedFetchHandler;
54
56
  if (!fetchHandler && typeof mod?.default === "function" && mod.default.length < 2) fetchHandler = mod.default;
55
57
  let nodeCompat = false;
56
58
  if (!fetchHandler && opts.nodeCompat !== false) {
57
- const nodeHandler = listenHandler || (typeof mod?.default === "function" ? mod.default : void 0);
59
+ const nodeHandler = interceptedNodeHandler || (typeof mod?.default === "function" ? mod.default : void 0);
58
60
  if (nodeHandler) {
59
61
  nodeCompat = true;
60
62
  const { fetchNodeHandler } = await import("srvx/node");
@@ -74,6 +76,10 @@ async function interceptListen(cb) {
74
76
  const originalListen = nodeHTTP$1.Server.prototype.listen;
75
77
  let res;
76
78
  let listenHandler;
79
+ let fetchHandler;
80
+ globalThis.__srvxLoader__ = (handler) => {
81
+ fetchHandler = handler;
82
+ };
77
83
  try {
78
84
  nodeHTTP$1.Server.prototype.listen = function(arg1, arg2) {
79
85
  listenHandler = this._events.request;
@@ -96,10 +102,12 @@ async function interceptListen(cb) {
96
102
  res = await cb();
97
103
  } finally {
98
104
  nodeHTTP$1.Server.prototype.listen = originalListen;
105
+ delete globalThis.__srvxLoader__;
99
106
  }
100
107
  return {
101
108
  res,
102
- listenHandler
109
+ listenHandler,
110
+ fetchHandler
103
111
  };
104
112
  });
105
113
  _interceptQueue = result.catch(() => {});
package/dist/types.d.mts CHANGED
@@ -154,7 +154,7 @@ interface Server<Handler = ServerHandler> {
154
154
  /**
155
155
  * Current runtime name
156
156
  */
157
- readonly runtime: "node" | "deno" | "bun" | "cloudflare" | "service-worker" | "aws-lambda" | "generic";
157
+ readonly runtime: "node" | "deno" | "bun" | "bunny" | "cloudflare" | "service-worker" | "aws-lambda" | "generic";
158
158
  /**
159
159
  * Server options
160
160
  */
@@ -198,6 +198,12 @@ interface Server<Handler = ServerHandler> {
198
198
  */
199
199
  ready(): Promise<Server<Handler>>;
200
200
  /**
201
+ * Register a background task that the server should await before closing.
202
+ *
203
+ * Same as `request.waitUntil` but available at the server level for use outside of request handlers.
204
+ */
205
+ readonly waitUntil?: (promise: Promise<unknown>) => void;
206
+ /**
201
207
  * Stop listening to prevent new connections from being accepted.
202
208
  *
203
209
  * By default, it does not cancel in-flight requests or websockets. That means it may take some time before all network activity stops.
@@ -208,7 +214,7 @@ interface Server<Handler = ServerHandler> {
208
214
  close(closeActiveConnections?: boolean): Promise<void>;
209
215
  }
210
216
  interface ServerRuntimeContext {
211
- name: "node" | "deno" | "bun" | "cloudflare" | "aws-lambda" | (string & {});
217
+ name: "node" | "deno" | "bun" | "bunny" | "cloudflare" | "aws-lambda" | (string & {});
212
218
  /**
213
219
  * Underlying Node.js server request info.
214
220
  */
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "srvx",
3
- "version": "0.11.3",
3
+ "version": "0.11.5",
4
4
  "description": "Universal Server.",
5
5
  "homepage": "https://srvx.h3.dev",
6
6
  "license": "MIT",
@@ -20,6 +20,7 @@
20
20
  "./bun": "./dist/adapters/bun.mjs",
21
21
  "./node": "./dist/adapters/node.mjs",
22
22
  "./cloudflare": "./dist/adapters/cloudflare.mjs",
23
+ "./bunny": "./dist/adapters/bunny.mjs",
23
24
  "./generic": "./dist/adapters/generic.mjs",
24
25
  "./service-worker": "./dist/adapters/service-worker.mjs",
25
26
  "./aws-lambda": "./dist/adapters/aws-lambda.mjs",
@@ -58,18 +59,18 @@
58
59
  "vitest": "vitest"
59
60
  },
60
61
  "devDependencies": {
61
- "@cloudflare/workers-types": "^4.20260210.0",
62
+ "@cloudflare/workers-types": "^4.20260217.0",
62
63
  "@hono/node-server": "^1.19.9",
63
64
  "@mitata/counters": "^0.0.8",
64
65
  "@mjackson/node-fetch-server": "^0.7.0",
65
66
  "@types/aws-lambda": "^8.10.160",
66
- "@types/bun": "^1.3.8",
67
+ "@types/bun": "^1.3.9",
67
68
  "@types/deno": "^2.5.0",
68
69
  "@types/express": "^5.0.6",
69
70
  "@types/node": "^25.2.3",
70
71
  "@types/node-forge": "^1.3.14",
71
- "@types/serviceworker": "^0.0.186",
72
- "@typescript/native-preview": "^7.0.0-dev.20260210.1",
72
+ "@types/serviceworker": "^0.0.191",
73
+ "@typescript/native-preview": "^7.0.0-dev.20260217.1",
73
74
  "@vitest/coverage-v8": "^4.0.18",
74
75
  "@whatwg-node/server": "^0.10.18",
75
76
  "automd": "^0.4.3",
@@ -83,12 +84,12 @@
83
84
  "mitata": "^1.0.34",
84
85
  "node-forge": "^1.3.3",
85
86
  "obuild": "^0.4.27",
86
- "oxfmt": "^0.28.0",
87
- "oxlint": "^1.43.0",
88
- "srvx-release": "npm:srvx@^0.10.1",
87
+ "oxfmt": "^0.33.0",
88
+ "oxlint": "^1.48.0",
89
+ "srvx-release": "npm:srvx@^0.11.4",
89
90
  "tslib": "^2.8.1",
90
91
  "typescript": "^5.9.3",
91
- "undici": "^7.21.0",
92
+ "undici": "^7.22.0",
92
93
  "vitest": "^4.0.18"
93
94
  },
94
95
  "resolutions": {
@@ -97,5 +98,5 @@
97
98
  "engines": {
98
99
  "node": ">=20.16.0"
99
100
  },
100
- "packageManager": "pnpm@10.29.2"
101
+ "packageManager": "pnpm@10.29.3"
101
102
  }