srvx 0.7.3 → 0.7.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.
@@ -1,59 +1,3 @@
1
- //#region src/_utils.node.ts
2
- function resolvePortAndHost(opts) {
3
- const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
4
- const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
5
- const hostname = opts.hostname ?? globalThis.process?.env.HOST;
6
- return {
7
- port,
8
- hostname
9
- };
10
- }
11
- function fmtURL(host, port, secure) {
12
- if (!host || !port) return void 0;
13
- if (host.includes(":")) host = `[${host}]`;
14
- return `http${secure ? "s" : ""}://${host}:${port}/`;
15
- }
16
- function printListening(opts, url) {
17
- if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) return;
18
- const _url = new URL(url);
19
- const allInterfaces = _url.hostname === "[::]" || _url.hostname === "0.0.0.0";
20
- if (allInterfaces) {
21
- _url.hostname = "localhost";
22
- url = _url.href;
23
- }
24
- let listeningOn = `➜ Listening on:`;
25
- let additionalInfo = allInterfaces ? " (all interfaces)" : "";
26
- if (globalThis.process.stdout?.isTTY) {
27
- listeningOn = `\u001B[32m${listeningOn}\u001B[0m`;
28
- url = `\u001B[36m${url}\u001B[0m`;
29
- additionalInfo = `\u001B[2m${additionalInfo}\u001B[0m`;
30
- }
31
- console.log(` ${listeningOn} ${url}${additionalInfo}`);
32
- }
33
- function resolveTLSOptions(opts) {
34
- if (!opts.tls || opts.protocol === "http") return;
35
- const cert = resolveCertOrKey(opts.tls.cert);
36
- const key = resolveCertOrKey(opts.tls.key);
37
- if (!cert && !key) {
38
- if (opts.protocol === "https") throw new TypeError("TLS `cert` and `key` must be provided for `https` protocol.");
39
- return;
40
- }
41
- if (!cert || !key) throw new TypeError("TLS `cert` and `key` must be provided together.");
42
- return {
43
- cert,
44
- key,
45
- passphrase: opts.tls.passphrase
46
- };
47
- }
48
- function resolveCertOrKey(value) {
49
- if (!value) return;
50
- if (typeof value !== "string") throw new TypeError("TLS certificate and key must be strings in PEM format or file paths.");
51
- if (value.startsWith("-----BEGIN ")) return value;
52
- const { readFileSync } = process.getBuiltinModule("node:fs");
53
- return readFileSync(value, "utf8");
54
- }
55
-
56
- //#endregion
57
1
  //#region src/_url.ts
58
2
  /**
59
3
  * Wrapper for URL with fast path access to `.pathname` and `.search` props.
@@ -63,7 +7,7 @@ function resolveCertOrKey(value) {
63
7
  * **NOTE:** Triggering the setters or getters on other props will deoptimize to full URL parsing.
64
8
  */
65
9
  const FastURL = /* @__PURE__ */ (() => {
66
- const FastURL$1 = class URL$1 {
10
+ const FastURL$1 = class URL {
67
11
  #originalURL;
68
12
  #parsedURL;
69
13
  _pathname;
@@ -144,4 +88,4 @@ const FastURL = /* @__PURE__ */ (() => {
144
88
  })();
145
89
 
146
90
  //#endregion
147
- export { FastURL as FastURL$1, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions };
91
+ export { FastURL as FastURL$1 };
@@ -0,0 +1,70 @@
1
+ //#region src/_utils.ts
2
+ function resolvePortAndHost(opts) {
3
+ const _port = opts.port ?? globalThis.process?.env.PORT ?? 3e3;
4
+ const port = typeof _port === "number" ? _port : Number.parseInt(_port, 10);
5
+ const hostname = opts.hostname ?? globalThis.process?.env.HOST;
6
+ return {
7
+ port,
8
+ hostname
9
+ };
10
+ }
11
+ function fmtURL(host, port, secure) {
12
+ if (!host || !port) return void 0;
13
+ if (host.includes(":")) host = `[${host}]`;
14
+ return `http${secure ? "s" : ""}://${host}:${port}/`;
15
+ }
16
+ function printListening(opts, url) {
17
+ if (!url || (opts.silent ?? globalThis.process?.env?.TEST)) return;
18
+ const _url = new URL(url);
19
+ const allInterfaces = _url.hostname === "[::]" || _url.hostname === "0.0.0.0";
20
+ if (allInterfaces) {
21
+ _url.hostname = "localhost";
22
+ url = _url.href;
23
+ }
24
+ let listeningOn = `➜ Listening on:`;
25
+ let additionalInfo = allInterfaces ? " (all interfaces)" : "";
26
+ if (globalThis.process.stdout?.isTTY) {
27
+ listeningOn = `\u001B[32m${listeningOn}\u001B[0m`;
28
+ url = `\u001B[36m${url}\u001B[0m`;
29
+ additionalInfo = `\u001B[2m${additionalInfo}\u001B[0m`;
30
+ }
31
+ console.log(` ${listeningOn} ${url}${additionalInfo}`);
32
+ }
33
+ function resolveTLSOptions(opts) {
34
+ if (!opts.tls || opts.protocol === "http") return;
35
+ const cert = resolveCertOrKey(opts.tls.cert);
36
+ const key = resolveCertOrKey(opts.tls.key);
37
+ if (!cert && !key) {
38
+ if (opts.protocol === "https") throw new TypeError("TLS `cert` and `key` must be provided for `https` protocol.");
39
+ return;
40
+ }
41
+ if (!cert || !key) throw new TypeError("TLS `cert` and `key` must be provided together.");
42
+ return {
43
+ cert,
44
+ key,
45
+ passphrase: opts.tls.passphrase
46
+ };
47
+ }
48
+ function resolveCertOrKey(value) {
49
+ if (!value) return;
50
+ if (typeof value !== "string") throw new TypeError("TLS certificate and key must be strings in PEM format or file paths.");
51
+ if (value.startsWith("-----BEGIN ")) return value;
52
+ const { readFileSync } = process.getBuiltinModule("node:fs");
53
+ return readFileSync(value, "utf8");
54
+ }
55
+ function createWaitUntil() {
56
+ const promises = new Set();
57
+ return {
58
+ waitUntil: (promise) => {
59
+ promises.add(promise.catch(console.error).finally(() => {
60
+ promises.delete(promise);
61
+ }));
62
+ },
63
+ wait: () => {
64
+ return Promise.all(promises);
65
+ }
66
+ };
67
+ }
68
+
69
+ //#endregion
70
+ export { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions };
@@ -231,6 +231,10 @@ interface ServerRequest extends Request {
231
231
  * IP address of the client.
232
232
  */
233
233
  ip?: string | undefined;
234
+ /**
235
+ * Tell the runtime about an ongoing operation that shouldn't close until the promise resolves.
236
+ */
237
+ waitUntil?: (promise: Promise<unknown>) => void | Promise<void>;
234
238
  }
235
239
  // ----------------------------------------------------------------------------
236
240
  // Different handler types
@@ -1,5 +1,5 @@
1
- import { BunFetchHandler, Server, ServerOptions } from "../_chunks/types-CAoaOHnD.mjs";
2
- import { FastURL$2 as FastURL } from "../_chunks/_url-0kFTYgtJ.mjs";
1
+ import { BunFetchHandler, Server, ServerOptions } from "../_chunks/types-mRjDOdKf.mjs";
2
+ import { FastURL$2 as FastURL } from "../_chunks/_url-CE8HuNzA.mjs";
3
3
  import * as bun from "bun";
4
4
 
5
5
  //#region src/adapters/bun.d.ts
@@ -7,6 +7,7 @@ declare const FastResponse: typeof globalThis.Response;
7
7
  declare function serve(options: ServerOptions): BunServer;
8
8
  // https://bun.sh/docs/api/http
9
9
  declare class BunServer implements Server<BunFetchHandler> {
10
+ #private;
10
11
  readonly runtime = "bun";
11
12
  readonly options: Server["options"];
12
13
  readonly bun: Server["bun"];
@@ -1,5 +1,6 @@
1
- import { FastURL$1 as FastURL, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_url-Dsik4Hgl.mjs";
1
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-ek-l5xdY.mjs";
2
2
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
3
+ import { FastURL$1 as FastURL } from "../_chunks/_url-0eSmxIIk.mjs";
3
4
 
4
5
  //#region src/adapters/bun.ts
5
6
  const FastResponse = Response;
@@ -12,6 +13,7 @@ var BunServer = class {
12
13
  bun = {};
13
14
  serveOptions;
14
15
  fetch;
16
+ #wait;
15
17
  constructor(options) {
16
18
  this.options = {
17
19
  ...options,
@@ -19,8 +21,10 @@ var BunServer = class {
19
21
  };
20
22
  for (const plugin of options.plugins || []) plugin(this);
21
23
  const fetchHandler = wrapFetch(this);
24
+ this.#wait = createWaitUntil();
22
25
  this.fetch = (request, server) => {
23
26
  Object.defineProperties(request, {
27
+ waitUntil: { value: this.#wait.waitUntil },
24
28
  runtime: {
25
29
  enumerable: true,
26
30
  value: {
@@ -68,8 +72,8 @@ var BunServer = class {
68
72
  ready() {
69
73
  return Promise.resolve(this);
70
74
  }
71
- close(closeAll) {
72
- return Promise.resolve(this.bun?.server?.stop(closeAll));
75
+ async close(closeAll) {
76
+ await Promise.all([this.#wait.wait(), Promise.resolve(this.bun?.server?.stop(closeAll))]);
73
77
  }
74
78
  };
75
79
 
@@ -1,4 +1,4 @@
1
- import { Server, ServerOptions } from "../_chunks/types-CAoaOHnD.mjs";
1
+ import { Server, ServerOptions } from "../_chunks/types-mRjDOdKf.mjs";
2
2
  import * as CF from "@cloudflare/workers-types";
3
3
 
4
4
  //#region src/adapters/cloudflare.d.ts
@@ -1,5 +1,5 @@
1
1
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
2
- import { errorPlugin } from "../_chunks/_plugins-CDyQtZq-.mjs";
2
+ import { errorPlugin } from "../_chunks/_plugins-ta8pkwXd.mjs";
3
3
 
4
4
  //#region src/adapters/cloudflare.ts
5
5
  const FastURL = URL;
@@ -21,16 +21,19 @@ var CloudflareServer = class {
21
21
  errorPlugin(this);
22
22
  const fetchHandler = wrapFetch(this);
23
23
  this.fetch = (request, env, context) => {
24
- Object.defineProperties(request, { runtime: {
25
- enumerable: true,
26
- value: {
27
- name: "cloudflare",
28
- cloudflare: {
29
- env,
30
- context
24
+ Object.defineProperties(request, {
25
+ waitUntil: { value: context.waitUntil.bind(context) },
26
+ runtime: {
27
+ enumerable: true,
28
+ value: {
29
+ name: "cloudflare",
30
+ cloudflare: {
31
+ env,
32
+ context
33
+ }
31
34
  }
32
35
  }
33
- } });
36
+ });
34
37
  return fetchHandler(request);
35
38
  };
36
39
  this.serveOptions = { fetch: this.fetch };
@@ -1,5 +1,5 @@
1
- import { DenoFetchHandler, Server, ServerOptions } from "../_chunks/types-CAoaOHnD.mjs";
2
- import { FastURL$2 as FastURL } from "../_chunks/_url-0kFTYgtJ.mjs";
1
+ import { DenoFetchHandler, Server, ServerOptions } from "../_chunks/types-mRjDOdKf.mjs";
2
+ import { FastURL$2 as FastURL } from "../_chunks/_url-CE8HuNzA.mjs";
3
3
 
4
4
  //#region src/adapters/deno.d.ts
5
5
  declare const FastResponse: typeof globalThis.Response;
@@ -16,7 +16,7 @@ declare class DenoServer implements Server<DenoFetchHandler> {
16
16
  serve(): Promise<this>;
17
17
  get url(): string | undefined;
18
18
  ready(): Promise<Server>;
19
- close(): Promise<void | undefined>;
19
+ close(): Promise<void>;
20
20
  }
21
21
  //#endregion
22
22
  export { FastResponse, FastURL, serve };
@@ -1,5 +1,6 @@
1
- import { FastURL$1 as FastURL, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_url-Dsik4Hgl.mjs";
1
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-ek-l5xdY.mjs";
2
2
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
3
+ import { FastURL$1 as FastURL } from "../_chunks/_url-0eSmxIIk.mjs";
3
4
 
4
5
  //#region src/adapters/deno.ts
5
6
  const FastResponse = Response;
@@ -14,6 +15,7 @@ var DenoServer = class {
14
15
  fetch;
15
16
  #listeningPromise;
16
17
  #listeningInfo;
18
+ #wait;
17
19
  constructor(options) {
18
20
  this.options = {
19
21
  ...options,
@@ -21,8 +23,10 @@ var DenoServer = class {
21
23
  };
22
24
  for (const plugin of options.plugins || []) plugin(this);
23
25
  const fetchHandler = wrapFetch(this);
26
+ this.#wait = createWaitUntil();
24
27
  this.fetch = (request, info) => {
25
28
  Object.defineProperties(request, {
29
+ waitUntil: { value: this.#wait.waitUntil },
26
30
  runtime: {
27
31
  enumerable: true,
28
32
  value: {
@@ -77,8 +81,8 @@ var DenoServer = class {
77
81
  ready() {
78
82
  return Promise.resolve(this.#listeningPromise).then(() => this);
79
83
  }
80
- close() {
81
- return Promise.resolve(this.deno?.server?.shutdown());
84
+ async close() {
85
+ await Promise.all([this.#wait.wait(), Promise.resolve(this.deno?.server?.shutdown())]);
82
86
  }
83
87
  };
84
88
 
@@ -1,4 +1,4 @@
1
- import { Server, ServerOptions } from "../_chunks/types-CAoaOHnD.mjs";
1
+ import { Server, ServerOptions } from "../_chunks/types-mRjDOdKf.mjs";
2
2
 
3
3
  //#region src/adapters/generic.d.ts
4
4
  declare const FastURL: typeof globalThis.URL;
@@ -1,5 +1,6 @@
1
+ import { createWaitUntil } from "../_chunks/_utils-ek-l5xdY.mjs";
1
2
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
2
- import { errorPlugin } from "../_chunks/_plugins-CDyQtZq-.mjs";
3
+ import { errorPlugin } from "../_chunks/_plugins-ta8pkwXd.mjs";
3
4
 
4
5
  //#region src/adapters/generic.ts
5
6
  const FastURL = URL;
@@ -11,6 +12,7 @@ var GenericServer = class {
11
12
  runtime = "generic";
12
13
  options;
13
14
  fetch;
15
+ #wait;
14
16
  constructor(options) {
15
17
  this.options = {
16
18
  ...options,
@@ -18,8 +20,10 @@ var GenericServer = class {
18
20
  };
19
21
  for (const plugin of options.plugins || []) plugin(this);
20
22
  errorPlugin(this);
23
+ this.#wait = createWaitUntil();
21
24
  const fetchHandler = wrapFetch(this);
22
25
  this.fetch = (request) => {
26
+ Object.defineProperties(request, { waitUntil: { value: this.#wait.waitUntil } });
23
27
  return Promise.resolve(fetchHandler(request));
24
28
  };
25
29
  }
@@ -27,8 +31,8 @@ var GenericServer = class {
27
31
  ready() {
28
32
  return Promise.resolve(this);
29
33
  }
30
- close() {
31
- return Promise.resolve();
34
+ async close() {
35
+ await this.#wait.wait();
32
36
  }
33
37
  };
34
38
 
@@ -1,5 +1,5 @@
1
- import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../_chunks/types-CAoaOHnD.mjs";
2
- import { FastURL$2 as FastURL } from "../_chunks/_url-0kFTYgtJ.mjs";
1
+ import { FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerOptions, ServerRequest } from "../_chunks/types-mRjDOdKf.mjs";
2
+ import { FastURL$2 as FastURL } from "../_chunks/_url-CE8HuNzA.mjs";
3
3
  import NodeHttp from "node:http";
4
4
  import { Readable } from "node:stream";
5
5
 
@@ -1,6 +1,7 @@
1
- import { FastURL$1 as FastURL, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_url-Dsik4Hgl.mjs";
1
+ import { createWaitUntil, fmtURL, printListening, resolvePortAndHost, resolveTLSOptions } from "../_chunks/_utils-ek-l5xdY.mjs";
2
2
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
3
- import { errorPlugin } from "../_chunks/_plugins-CDyQtZq-.mjs";
3
+ import { FastURL$1 as FastURL } from "../_chunks/_url-0eSmxIIk.mjs";
4
+ import { errorPlugin } from "../_chunks/_plugins-ta8pkwXd.mjs";
4
5
  import { splitSetCookieString } from "cookie-es";
5
6
 
6
7
  //#region src/adapters/_node/send.ts
@@ -744,6 +745,7 @@ var NodeServer = class {
744
745
  fetch;
745
746
  #isSecure;
746
747
  #listeningPromise;
748
+ #wait;
747
749
  constructor(options) {
748
750
  this.options = {
749
751
  ...options,
@@ -752,11 +754,13 @@ var NodeServer = class {
752
754
  for (const plugin of options.plugins || []) plugin(this);
753
755
  errorPlugin(this);
754
756
  const fetchHandler = this.fetch = wrapFetch(this);
757
+ this.#wait = createWaitUntil();
755
758
  const handler = (nodeReq, nodeRes) => {
756
759
  const request = new NodeRequest({
757
760
  req: nodeReq,
758
761
  res: nodeRes
759
762
  });
763
+ request.waitUntil = this.#wait.waitUntil;
760
764
  const res = fetchHandler(request);
761
765
  return res instanceof Promise ? res.then((resolvedRes) => sendNodeResponse(nodeRes, resolvedRes)) : sendNodeResponse(nodeRes, res);
762
766
  };
@@ -813,13 +817,13 @@ var NodeServer = class {
813
817
  ready() {
814
818
  return Promise.resolve(this.#listeningPromise).then(() => this);
815
819
  }
816
- close(closeAll) {
817
- return new Promise((resolve, reject) => {
820
+ async close(closeAll) {
821
+ await Promise.all([this.#wait.wait(), new Promise((resolve, reject) => {
818
822
  const server = this.node?.server;
819
823
  if (!server) return resolve();
820
824
  if (closeAll && "closeAllConnections" in server) server.closeAllConnections();
821
825
  server.close((error) => error ? reject(error) : resolve());
822
- });
826
+ })]);
823
827
  }
824
828
  };
825
829
 
@@ -1,4 +1,4 @@
1
- import { Server, ServerOptions, ServerRequest } from "../_chunks/types-CAoaOHnD.mjs";
1
+ import { Server, ServerOptions, ServerRequest } from "../_chunks/types-mRjDOdKf.mjs";
2
2
 
3
3
  //#region src/adapters/service-worker.d.ts
4
4
  declare const FastURL: typeof globalThis.URL;
@@ -1,11 +1,11 @@
1
1
  import { wrapFetch } from "../_chunks/_middleware-Bz7WmB2e.mjs";
2
- import { errorPlugin } from "../_chunks/_plugins-CDyQtZq-.mjs";
2
+ import { errorPlugin } from "../_chunks/_plugins-ta8pkwXd.mjs";
3
3
 
4
4
  //#region src/adapters/service-worker.ts
5
5
  const FastURL = URL;
6
6
  const FastResponse = Response;
7
7
  const isBrowserWindow = typeof window !== "undefined" && typeof navigator !== "undefined";
8
- const isServiceWorker = typeof self !== "undefined" && "skipWaiting" in self;
8
+ const isServiceWorker = /* @__PURE__ */ (() => typeof self !== "undefined" && "skipWaiting" in self)();
9
9
  function serve(options) {
10
10
  return new ServiceWorkerServer(options);
11
11
  }
@@ -52,6 +52,7 @@ var ServiceWorkerServer = class {
52
52
  } else if (isServiceWorker) {
53
53
  this.#fetchListener = async (event) => {
54
54
  if (/\/[^/]*\.[a-zA-Z0-9]+$/.test(new URL(event.request.url).pathname)) return;
55
+ Object.defineProperty(event.request, "waitUntil", { value: event.waitUntil.bind(event) });
55
56
  const response = await this.fetch(event.request, event);
56
57
  if (response.status !== 404) event.respondWith(response);
57
58
  };
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-CAoaOHnD.mjs";
1
+ import { BunFetchHandler, CloudflareFetchHandler, DenoFetchHandler, ErrorHandler, FastResponse, FastURL, FetchHandler, NodeHttpHandler, NodeServerRequest, NodeServerResponse, Server, ServerHandler, ServerMiddleware, ServerOptions, ServerPlugin, ServerRequest, ServerRuntimeContext, serve } from "./_chunks/types-mRjDOdKf.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.7.3",
3
+ "version": "0.7.5",
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",