mppx 0.5.9 → 0.5.11

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/CHANGELOG.md CHANGED
@@ -1,5 +1,17 @@
1
1
  # mppx
2
2
 
3
+ ## 0.5.11
4
+
5
+ ### Patch Changes
6
+
7
+ - 2aff2c0: Handled malformed Host headers in the Node request listener instead of letting them crash the process.
8
+
9
+ ## 0.5.10
10
+
11
+ ### Patch Changes
12
+
13
+ - d95c01c: Pruned internal dependencies.
14
+
3
15
  ## 0.5.9
4
16
 
5
17
  ### Patch Changes
@@ -1 +1 @@
1
- {"version":3,"file":"Proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAStC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,kFAAkF;AAClF,MAAM,MAAM,KAAK,GAAG;IAClB,sFAAsF;IACtF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,uFAAuF;IACvF,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CAAA;CACxE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,CA6HnD;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAY,MAAM,GAAG;QACnB,sEAAsE;QACtE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC7B,wDAAwD;QACxD,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;QACjC,0DAA0D;QAC1D,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAChC,kEAAkE;QAClE,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS,CAAA;QAC/B,qEAAqE;QACrE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,GAAG,SAAS,CAAA;QAC3C,qEAAqE;QACrE,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAC3B,8DAA8D;QAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC1B,4DAA4D;QAC5D,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC7B,CAAA;CACF"}
1
+ {"version":3,"file":"Proxy.d.ts","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AAOtC,OAAO,KAAK,OAAO,MAAM,cAAc,CAAA;AAEvC,kFAAkF;AAClF,MAAM,MAAM,KAAK,GAAG;IAClB,sFAAsF;IACtF,KAAK,EAAE,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,CAAA;IAC9C,uFAAuF;IACvF,QAAQ,EAAE,CAAC,GAAG,EAAE,IAAI,CAAC,eAAe,EAAE,GAAG,EAAE,IAAI,CAAC,cAAc,KAAK,IAAI,CAAA;CACxE,CAAA;AAED;;;;;;;;;;;;;;;;;;;;;;;;;GAyBG;AACH,wBAAgB,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,MAAM,GAAG,KAAK,CAyHnD;AAED,MAAM,CAAC,OAAO,WAAW,MAAM,CAAC;IAC9B,KAAY,MAAM,GAAG;QACnB,sEAAsE;QACtE,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC7B,wDAAwD;QACxD,UAAU,CAAC,EAAE,MAAM,EAAE,GAAG,SAAS,CAAA;QACjC,0DAA0D;QAC1D,WAAW,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAChC,kEAAkE;QAClE,IAAI,CAAC,EAAE,OAAO,CAAC,IAAI,GAAG,SAAS,CAAA;QAC/B,qEAAqE;QACrE,KAAK,CAAC,EAAE,OAAO,UAAU,CAAC,KAAK,GAAG,SAAS,CAAA;QAC3C,qEAAqE;QACrE,QAAQ,EAAE,OAAO,CAAC,OAAO,EAAE,CAAA;QAC3B,8DAA8D;QAC9D,KAAK,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;QAC1B,4DAA4D;QAC5D,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;KAC7B,CAAA;CACF"}
@@ -1,4 +1,3 @@
1
- import { createFetchProxy } from '@remix-run/fetch-proxy';
2
1
  import * as Credential from '../Credential.js';
3
2
  import { generateProxy } from '../discovery/OpenApi.js';
4
3
  import * as Request from '../server/Request.js';
@@ -34,11 +33,7 @@ import * as Service from './Service.js';
34
33
  export function create(config) {
35
34
  const fetchImpl = config.fetch ?? globalThis.fetch;
36
35
  const services = new Map(config.services.map((s) => {
37
- const proxy = createFetchProxy(s.baseUrl, {
38
- fetch: fetchImpl,
39
- rewriteCookieDomain: false,
40
- rewriteCookiePath: false,
41
- });
36
+ const proxy = createFetchProxy(s.baseUrl, { fetch: fetchImpl });
42
37
  return [s.id, { service: s, proxy }];
43
38
  }));
44
39
  // Pre-generate static discovery responses once at startup.
@@ -214,4 +209,30 @@ function matchesPaymentBinding(endpoint, binding) {
214
209
  return true;
215
210
  return payment.method === binding.method && payment.intent === binding.intent;
216
211
  }
212
+ function createFetchProxy(target, options) {
213
+ const localFetch = options?.fetch ?? globalThis.fetch;
214
+ const targetUrl = new URL(target);
215
+ if (targetUrl.pathname.endsWith('/'))
216
+ targetUrl.pathname = targetUrl.pathname.replace(/\/+$/, '');
217
+ return async (input, init) => {
218
+ const request = new globalThis.Request(input, init);
219
+ const url = new URL(request.url);
220
+ const proxyUrl = new URL(url.search, targetUrl);
221
+ if (url.pathname !== '/')
222
+ proxyUrl.pathname =
223
+ proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname;
224
+ const proxyInit = {
225
+ method: request.method,
226
+ headers: new globalThis.Headers(request.headers),
227
+ signal: request.signal,
228
+ redirect: request.redirect,
229
+ ...init,
230
+ };
231
+ if (request.method !== 'GET' && request.method !== 'HEAD') {
232
+ proxyInit.body = request.body;
233
+ proxyInit.duplex = 'half';
234
+ }
235
+ return localFetch(proxyUrl, proxyInit);
236
+ };
237
+ }
217
238
  //# sourceMappingURL=Proxy.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Proxy.js","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"Proxy.js","sourceRoot":"","sources":["../../src/proxy/Proxy.ts"],"names":[],"mappings":"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"}
@@ -1,9 +1,9 @@
1
- import * as FetchServer from '@remix-run/node-fetch-server';
1
+ import type * as http from 'node:http';
2
+ import type * as http2 from 'node:http2';
2
3
  /**
3
4
  * Writes a Fetch API `Response` to a Node.js `ServerResponse`.
4
5
  *
5
- * Delegates to `@remix-run/node-fetch-server`. Useful when bridging
6
- * Fetch API handlers with Node.js HTTP servers.
6
+ * Useful when bridging Fetch API handlers with Node.js HTTP servers.
7
7
  */
8
- export declare const sendResponse: typeof FetchServer.sendResponse;
8
+ export declare function sendResponse(res: http.ServerResponse | http2.Http2ServerResponse, response: Response): Promise<void>;
9
9
  //# sourceMappingURL=NodeListener.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeListener.d.ts","sourceRoot":"","sources":["../../src/server/NodeListener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,8BAA8B,CAAA;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,YAAY,iCAA2B,CAAA"}
1
+ {"version":3,"file":"NodeListener.d.ts","sourceRoot":"","sources":["../../src/server/NodeListener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,KAAK,IAAI,MAAM,WAAW,CAAA;AACtC,OAAO,KAAK,KAAK,KAAK,MAAM,YAAY,CAAA;AAExC;;;;GAIG;AACH,wBAAsB,YAAY,CAChC,GAAG,EAAE,IAAI,CAAC,cAAc,GAAG,KAAK,CAAC,mBAAmB,EACpD,QAAQ,EAAE,QAAQ,GACjB,OAAO,CAAC,IAAI,CAAC,CAiCf"}
@@ -1,9 +1,43 @@
1
- import * as FetchServer from '@remix-run/node-fetch-server';
2
1
  /**
3
2
  * Writes a Fetch API `Response` to a Node.js `ServerResponse`.
4
3
  *
5
- * Delegates to `@remix-run/node-fetch-server`. Useful when bridging
6
- * Fetch API handlers with Node.js HTTP servers.
4
+ * Useful when bridging Fetch API handlers with Node.js HTTP servers.
7
5
  */
8
- export const sendResponse = FetchServer.sendResponse;
6
+ export async function sendResponse(res, response) {
7
+ const headers = {};
8
+ for (const [key, value] of response.headers) {
9
+ if (key in headers) {
10
+ const existing = headers[key];
11
+ if (Array.isArray(existing))
12
+ existing.push(value);
13
+ else
14
+ headers[key] = [existing, value];
15
+ }
16
+ else {
17
+ headers[key] = value;
18
+ }
19
+ }
20
+ if ('req' in res && res.req?.httpVersionMajor === 1)
21
+ res.writeHead(response.status, response.statusText, headers);
22
+ else
23
+ res.writeHead(response.status, headers);
24
+ if (response.body != null && res.req?.method !== 'HEAD') {
25
+ const reader = response.body.getReader();
26
+ try {
27
+ while (true) {
28
+ const { done, value } = await reader.read();
29
+ if (done)
30
+ break;
31
+ if (res.write(value) === false)
32
+ await new Promise((resolve) => {
33
+ res.once('drain', resolve);
34
+ });
35
+ }
36
+ }
37
+ finally {
38
+ reader.releaseLock();
39
+ }
40
+ }
41
+ res.end();
42
+ }
9
43
  //# sourceMappingURL=NodeListener.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"NodeListener.js","sourceRoot":"","sources":["../../src/server/NodeListener.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,WAAW,MAAM,8BAA8B,CAAA;AAE3D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,YAAY,GAAG,WAAW,CAAC,YAAY,CAAA"}
1
+ {"version":3,"file":"NodeListener.js","sourceRoot":"","sources":["../../src/server/NodeListener.ts"],"names":[],"mappings":"AAGA;;;;GAIG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,GAAoD,EACpD,QAAkB;IAElB,MAAM,OAAO,GAAsC,EAAE,CAAA;IACrD,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,QAAQ,CAAC,OAAO,EAAE,CAAC;QAC5C,IAAI,GAAG,IAAI,OAAO,EAAE,CAAC;YACnB,MAAM,QAAQ,GAAG,OAAO,CAAC,GAAG,CAAC,CAAA;YAC7B,IAAI,KAAK,CAAC,OAAO,CAAC,QAAQ,CAAC;gBAAE,QAAQ,CAAC,IAAI,CAAC,KAAK,CAAC,CAAA;;gBAC5C,OAAO,CAAC,GAAG,CAAC,GAAG,CAAC,QAAS,EAAE,KAAK,CAAC,CAAA;QACxC,CAAC;aAAM,CAAC;YACN,OAAO,CAAC,GAAG,CAAC,GAAG,KAAK,CAAA;QACtB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,IAAI,GAAG,IAAK,GAA2B,CAAC,GAAG,EAAE,gBAAgB,KAAK,CAAC;QACzE,GAA2B,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAC,CAAA;;QACjF,GAAiC,CAAC,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,OAAO,CAAC,CAAA;IAE3E,IAAI,QAAQ,CAAC,IAAI,IAAI,IAAI,IAAK,GAA2B,CAAC,GAAG,EAAE,MAAM,KAAK,MAAM,EAAE,CAAC;QACjF,MAAM,MAAM,GAAG,QAAQ,CAAC,IAAI,CAAC,SAAS,EAAE,CAAA;QACxC,IAAI,CAAC;YACH,OAAO,IAAI,EAAE,CAAC;gBACZ,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM,CAAC,IAAI,EAAE,CAAA;gBAC3C,IAAI,IAAI;oBAAE,MAAK;gBACf,IAAK,GAA2B,CAAC,KAAK,CAAC,KAAK,CAAC,KAAK,KAAK;oBACrD,MAAM,IAAI,OAAO,CAAO,CAAC,OAAO,EAAE,EAAE;wBAClC,GAAG,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAA;oBAC5B,CAAC,CAAC,CAAA;YACN,CAAC;QACH,CAAC;gBAAS,CAAC;YACT,MAAM,CAAC,WAAW,EAAE,CAAA;QACtB,CAAC;IACH,CAAC;IAED,GAAG,CAAC,GAAG,EAAE,CAAA;AACX,CAAC"}
@@ -1,24 +1,24 @@
1
1
  import type { IncomingMessage, RequestListener, ServerResponse } from 'node:http';
2
- import * as FetchServer from '@remix-run/node-fetch-server';
3
2
  export type FetchHandler = (request: Request) => Promise<Response> | Response;
3
+ export type RequestListenerOptions = {
4
+ host?: string | undefined;
5
+ onError?: ((error: unknown) => void | Response | Promise<void | Response>) | undefined;
6
+ protocol?: string | undefined;
7
+ };
4
8
  /**
5
9
  * Converts a Fetch API handler into a Node.js HTTP request listener.
6
10
  *
7
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
8
- *
9
11
  * @param handler - A Fetch API handler: `(request: Request) => Response`.
10
12
  * @param options - Optional error handler.
11
13
  * @returns A Node.js `(req, res)` listener.
12
14
  */
13
- export declare function toNodeListener(handler: FetchHandler, options?: FetchServer.RequestListenerOptions | undefined): RequestListener;
15
+ export declare function toNodeListener(handler: FetchHandler, options?: RequestListenerOptions | undefined): RequestListener;
14
16
  /**
15
17
  * Converts a Node.js `IncomingMessage`/`ServerResponse` pair to a Fetch API `Request`.
16
18
  *
17
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
18
- *
19
19
  * @param req - The Node.js IncomingMessage.
20
20
  * @param res - The Node.js ServerResponse (used for abort signal lifecycle).
21
21
  * @returns A Fetch API Request.
22
22
  */
23
- export declare function fromNodeListener(req: IncomingMessage, res: ServerResponse): Request;
23
+ export declare function fromNodeListener(req: IncomingMessage, res: ServerResponse, options?: RequestListenerOptions | undefined): Request;
24
24
  //# sourceMappingURL=Request.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAEjF,OAAO,KAAK,WAAW,MAAM,8BAA8B,CAAA;AAE3D,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;AAE7E;;;;;;;;GAQG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,WAAW,CAAC,sBAAsB,GAAG,SAAS,GACvD,eAAe,CAEjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAAC,GAAG,EAAE,eAAe,EAAE,GAAG,EAAE,cAAc,GAAG,OAAO,CAEnF"}
1
+ {"version":3,"file":"Request.d.ts","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,eAAe,EAAE,cAAc,EAAE,MAAM,WAAW,CAAA;AAIjF,MAAM,MAAM,YAAY,GAAG,CAAC,OAAO,EAAE,OAAO,KAAK,OAAO,CAAC,QAAQ,CAAC,GAAG,QAAQ,CAAA;AAE7E,MAAM,MAAM,sBAAsB,GAAG;IACnC,IAAI,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;IACzB,OAAO,CAAC,EAAE,CAAC,CAAC,KAAK,EAAE,OAAO,KAAK,IAAI,GAAG,QAAQ,GAAG,OAAO,CAAC,IAAI,GAAG,QAAQ,CAAC,CAAC,GAAG,SAAS,CAAA;IACtF,QAAQ,CAAC,EAAE,MAAM,GAAG,SAAS,CAAA;CAC9B,CAAA;AAED;;;;;;GAMG;AACH,wBAAgB,cAAc,CAC5B,OAAO,EAAE,YAAY,EACrB,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,GAC3C,eAAe,CAkCjB;AAED;;;;;;GAMG;AACH,wBAAgB,gBAAgB,CAC9B,GAAG,EAAE,eAAe,EACpB,GAAG,EAAE,cAAc,EACnB,OAAO,CAAC,EAAE,sBAAsB,GAAG,SAAS,GAC3C,OAAO,CA0CT"}
@@ -1,26 +1,111 @@
1
- import * as FetchServer from '@remix-run/node-fetch-server';
1
+ import * as NodeListener from './NodeListener.js';
2
2
  /**
3
3
  * Converts a Fetch API handler into a Node.js HTTP request listener.
4
4
  *
5
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
6
- *
7
5
  * @param handler - A Fetch API handler: `(request: Request) => Response`.
8
6
  * @param options - Optional error handler.
9
7
  * @returns A Node.js `(req, res)` listener.
10
8
  */
11
9
  export function toNodeListener(handler, options) {
12
- return FetchServer.createRequestListener(handler, options);
10
+ const onError = options?.onError ??
11
+ ((error) => {
12
+ console.error(error);
13
+ return new Response('Internal Server Error', {
14
+ status: 500,
15
+ headers: { 'Content-Type': 'text/plain' },
16
+ });
17
+ });
18
+ return (async (req, res) => {
19
+ let response;
20
+ try {
21
+ const request = fromNodeListener(req, res, options);
22
+ response = await handler(request);
23
+ }
24
+ catch (error) {
25
+ try {
26
+ response =
27
+ (await onError(error)) ??
28
+ new Response('Internal Server Error', {
29
+ status: 500,
30
+ headers: { 'Content-Type': 'text/plain' },
31
+ });
32
+ }
33
+ catch (innerError) {
34
+ console.error(`There was an error in the error handler: ${innerError}`);
35
+ response = new Response('Internal Server Error', {
36
+ status: 500,
37
+ headers: { 'Content-Type': 'text/plain' },
38
+ });
39
+ }
40
+ }
41
+ await NodeListener.sendResponse(res, response);
42
+ });
13
43
  }
14
44
  /**
15
45
  * Converts a Node.js `IncomingMessage`/`ServerResponse` pair to a Fetch API `Request`.
16
46
  *
17
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
18
- *
19
47
  * @param req - The Node.js IncomingMessage.
20
48
  * @param res - The Node.js ServerResponse (used for abort signal lifecycle).
21
49
  * @returns A Fetch API Request.
22
50
  */
23
- export function fromNodeListener(req, res) {
24
- return FetchServer.createRequest(req, res);
51
+ export function fromNodeListener(req, res, options) {
52
+ let controller = new AbortController();
53
+ res.once('close', () => controller?.abort());
54
+ res.once('finish', () => {
55
+ controller = null;
56
+ });
57
+ const method = req.method ?? 'GET';
58
+ const headers = createHeaders(req);
59
+ const protocol = options?.protocol ??
60
+ ('encrypted' in req.socket && req.socket.encrypted
61
+ ? 'https:'
62
+ : 'http:');
63
+ const host = options?.host ??
64
+ headers.get('Host') ??
65
+ req.headers[':authority'] ??
66
+ 'localhost';
67
+ const url = new URL(normalizeRequestTarget(req.url), `${protocol}//${host}`);
68
+ const init = {
69
+ method,
70
+ headers,
71
+ signal: controller.signal,
72
+ };
73
+ if (method !== 'GET' && method !== 'HEAD') {
74
+ init.body = new ReadableStream({
75
+ start(c) {
76
+ req.on('data', (chunk) => {
77
+ c.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength));
78
+ });
79
+ req.on('end', () => {
80
+ c.close();
81
+ });
82
+ },
83
+ });
84
+ init.duplex = 'half';
85
+ }
86
+ return new Request(url, init);
87
+ }
88
+ function normalizeRequestTarget(url) {
89
+ if (!url)
90
+ return '/';
91
+ try {
92
+ const absoluteUrl = new URL(url);
93
+ // Absolute-form request targets can carry a different origin than the socket host.
94
+ // Keep only path+query so realm detection stays bound to Host/:authority.
95
+ if (absoluteUrl.protocol === 'http:' || absoluteUrl.protocol === 'https:')
96
+ return `${absoluteUrl.pathname}${absoluteUrl.search}`;
97
+ }
98
+ catch { }
99
+ return url;
100
+ }
101
+ function createHeaders(req) {
102
+ const headers = new Headers();
103
+ const raw = req.rawHeaders;
104
+ for (let i = 0; i < raw.length; i += 2) {
105
+ if (raw[i].startsWith(':'))
106
+ continue;
107
+ headers.append(raw[i], raw[i + 1]);
108
+ }
109
+ return headers;
25
110
  }
26
111
  //# sourceMappingURL=Request.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"Request.js","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"AAEA,OAAO,KAAK,WAAW,MAAM,8BAA8B,CAAA;AAI3D;;;;;;;;GAQG;AACH,MAAM,UAAU,cAAc,CAC5B,OAAqB,EACrB,OAAwD;IAExD,OAAO,WAAW,CAAC,qBAAqB,CAAC,OAAO,EAAE,OAAO,CAAU,CAAA;AACrE,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAoB,EAAE,GAAmB;IACxE,OAAO,WAAW,CAAC,aAAa,CAAC,GAAG,EAAE,GAAG,CAAC,CAAA;AAC5C,CAAC"}
1
+ {"version":3,"file":"Request.js","sourceRoot":"","sources":["../../src/server/Request.ts"],"names":[],"mappings":"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"}
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "mppx",
3
3
  "type": "module",
4
- "version": "0.5.9",
4
+ "version": "0.5.11",
5
5
  "main": "./dist/index.js",
6
6
  "license": "MIT",
7
7
  "files": [
@@ -105,7 +105,7 @@
105
105
  "@modelcontextprotocol/sdk": ">=1.25.0",
106
106
  "elysia": ">=1",
107
107
  "express": ">=5",
108
- "hono": ">=4",
108
+ "hono": ">=4.12.12",
109
109
  "viem": ">=2.47.5"
110
110
  },
111
111
  "peerDependenciesMeta": {
@@ -123,8 +123,6 @@
123
123
  }
124
124
  },
125
125
  "dependencies": {
126
- "@remix-run/fetch-proxy": "^0.7.1",
127
- "@remix-run/node-fetch-server": "^0.13.0",
128
126
  "incur": "^0.3.23",
129
127
  "ox": "0.14.7",
130
128
  "zod": "^4.3.6"
@@ -250,6 +250,28 @@ describe('create', () => {
250
250
  expect(await res.json()).toEqual({ path: '/v1/status' })
251
251
  })
252
252
 
253
+ test('behavior: joins upstream base paths with request paths', async () => {
254
+ upstream = await createUpstream((req) =>
255
+ Response.json({
256
+ path: new URL(req.url).pathname,
257
+ search: new URL(req.url).search,
258
+ }),
259
+ )
260
+ const proxy = ApiProxy.create({
261
+ services: [
262
+ Service.from('api', {
263
+ baseUrl: `${upstream.url}/prefix/`,
264
+ routes: { 'GET /v1/status': true },
265
+ }),
266
+ ],
267
+ })
268
+ proxyServer = await Http.createServer(proxy.listener)
269
+
270
+ const res = await fetch(`${proxyServer.url}/api/v1/status?q=ok`)
271
+ expect(res.status).toBe(200)
272
+ expect(await res.json()).toEqual({ path: '/prefix/v1/status', search: '?q=ok' })
273
+ })
274
+
253
275
  test('behavior: returns 402 when no credential', async () => {
254
276
  upstream = await createUpstream(() => Response.json({ result: 'ok' }))
255
277
  const proxy = ApiProxy.create({
@@ -1,7 +1,5 @@
1
1
  import type * as http from 'node:http'
2
2
 
3
- import { createFetchProxy } from '@remix-run/fetch-proxy'
4
-
5
3
  import * as Credential from '../Credential.js'
6
4
  import { generateProxy } from '../discovery/OpenApi.js'
7
5
  import * as Request from '../server/Request.js'
@@ -48,11 +46,7 @@ export function create(config: create.Config): Proxy {
48
46
 
49
47
  const services = new Map(
50
48
  config.services.map((s) => {
51
- const proxy = createFetchProxy(s.baseUrl, {
52
- fetch: fetchImpl,
53
- rewriteCookieDomain: false,
54
- rewriteCookiePath: false,
55
- })
49
+ const proxy = createFetchProxy(s.baseUrl, { fetch: fetchImpl })
56
50
  return [s.id, { service: s, proxy }] as const
57
51
  }),
58
52
  )
@@ -295,3 +289,34 @@ function matchesPaymentBinding(endpoint: unknown, binding: PaymentBinding | null
295
289
  if (!payment) return true
296
290
  return payment.method === binding.method && payment.intent === binding.intent
297
291
  }
292
+
293
+ function createFetchProxy(
294
+ target: string | URL,
295
+ options?: { fetch?: typeof globalThis.fetch },
296
+ ): (input: URL | RequestInfo, init?: RequestInit) => Promise<Response> {
297
+ const localFetch = options?.fetch ?? globalThis.fetch
298
+ const targetUrl = new URL(target)
299
+ if (targetUrl.pathname.endsWith('/')) targetUrl.pathname = targetUrl.pathname.replace(/\/+$/, '')
300
+
301
+ return async (input, init) => {
302
+ const request = new globalThis.Request(input, init)
303
+ const url = new URL(request.url)
304
+ const proxyUrl = new URL(url.search, targetUrl)
305
+ if (url.pathname !== '/')
306
+ proxyUrl.pathname =
307
+ proxyUrl.pathname === '/' ? url.pathname : proxyUrl.pathname + url.pathname
308
+
309
+ const proxyInit: RequestInit & { duplex?: 'half' } = {
310
+ method: request.method,
311
+ headers: new globalThis.Headers(request.headers),
312
+ signal: request.signal,
313
+ redirect: request.redirect,
314
+ ...init,
315
+ }
316
+ if (request.method !== 'GET' && request.method !== 'HEAD') {
317
+ proxyInit.body = request.body
318
+ proxyInit.duplex = 'half'
319
+ }
320
+ return localFetch(proxyUrl, proxyInit)
321
+ }
322
+ }
@@ -1,3 +1,5 @@
1
+ import * as http from 'node:http'
2
+
1
3
  import { Challenge, Credential, Method, z } from 'mppx'
2
4
  import { Mppx, Transport, tempo } from 'mppx/server'
3
5
  import { describe, expect, test } from 'vp/test'
@@ -2422,6 +2424,73 @@ describe('realm auto-detection', () => {
2422
2424
  expect(challenge.realm).toBe(expected)
2423
2425
  })
2424
2426
 
2427
+ test('ignores absolute-form request targets when deriving realm in node listeners', async () => {
2428
+ const handler = Mppx.create({ methods: [mockMethod], secretKey })
2429
+ const server = await Http.createServer(async (req, res) => {
2430
+ const result = await Mppx.toNodeListener(
2431
+ handler.charge({
2432
+ amount: '100',
2433
+ currency: '0x0000000000000000000000000000000000000001',
2434
+ recipient: '0x0000000000000000000000000000000000000002',
2435
+ }),
2436
+ )(req, res)
2437
+
2438
+ if (result.status !== 402) res.end('OK')
2439
+ })
2440
+
2441
+ try {
2442
+ const rawResponse = await new Promise<{
2443
+ body: string
2444
+ headers: http.IncomingHttpHeaders
2445
+ statusCode: number
2446
+ }>((resolve, reject) => {
2447
+ const request = http.request(
2448
+ {
2449
+ host: '127.0.0.1',
2450
+ port: server.port,
2451
+ method: 'GET',
2452
+ path: 'http://unexpected.example/resource',
2453
+ headers: { Host: `localhost:${server.port}` },
2454
+ },
2455
+ (response) => {
2456
+ const chunks: Buffer[] = []
2457
+ response.on('data', (chunk) => chunks.push(Buffer.from(chunk)))
2458
+ response.on('end', () => {
2459
+ resolve({
2460
+ body: Buffer.concat(chunks).toString('utf8'),
2461
+ headers: response.headers,
2462
+ statusCode: response.statusCode ?? 0,
2463
+ })
2464
+ })
2465
+ },
2466
+ )
2467
+
2468
+ request.on('error', reject)
2469
+ request.end()
2470
+ })
2471
+
2472
+ const headers = new Headers()
2473
+ for (const [name, value] of Object.entries(rawResponse.headers)) {
2474
+ if (Array.isArray(value)) {
2475
+ for (const item of value) headers.append(name, item)
2476
+ } else if (value !== undefined) {
2477
+ headers.append(name, value)
2478
+ }
2479
+ }
2480
+
2481
+ const challenge = Challenge.fromResponse(
2482
+ new Response(rawResponse.body, {
2483
+ status: rawResponse.statusCode,
2484
+ headers,
2485
+ }),
2486
+ )
2487
+
2488
+ expect(challenge.realm).toBe('localhost')
2489
+ } finally {
2490
+ server.close()
2491
+ }
2492
+ })
2493
+
2425
2494
  test('credential verifies across different casing of same host', async () => {
2426
2495
  const handler = Mppx.create({ methods: [mockMethod], secretKey })
2427
2496
 
@@ -1,3 +1,6 @@
1
+ import { EventEmitter } from 'node:events'
2
+ import type { IncomingMessage, ServerResponse } from 'node:http'
3
+
1
4
  import { NodeListener, Request } from 'mppx/server'
2
5
  import { afterEach, describe, expect, test } from 'vp/test'
3
6
  import * as Http from '~test/Http.js'
@@ -6,6 +9,63 @@ let server: Awaited<ReturnType<typeof Http.createServer>> | undefined
6
9
 
7
10
  afterEach(() => server?.close())
8
11
 
12
+ function createMockRequest(options: {
13
+ method?: string
14
+ url?: string
15
+ rawHeaders?: string[]
16
+ }): [
17
+ IncomingMessage,
18
+ ServerResponse & { body: Buffer[]; headers?: Record<string, string | string[]> },
19
+ ] {
20
+ type MockResponse = ServerResponse & {
21
+ body: Buffer[]
22
+ headers?: Record<string, string | string[]>
23
+ }
24
+
25
+ const rawHeaders = options.rawHeaders ?? []
26
+ const headers = Object.fromEntries(
27
+ rawHeaders.reduce<[string, string][]>((acc, value, index, values) => {
28
+ if (index % 2 === 0 && values[index + 1]) acc.push([value.toLowerCase(), values[index + 1]!])
29
+ return acc
30
+ }, []),
31
+ )
32
+ const req = Object.assign(new EventEmitter(), {
33
+ method: options.method ?? 'GET',
34
+ url: options.url ?? '/',
35
+ headers,
36
+ rawHeaders,
37
+ socket: {},
38
+ }) as unknown as IncomingMessage
39
+
40
+ const res = Object.assign(new EventEmitter(), {
41
+ req,
42
+ body: [] as Buffer[],
43
+ writeHead(
44
+ this: MockResponse,
45
+ _statusCode: number,
46
+ statusMessageOrHeaders?: string | Record<string, string | string[]>,
47
+ headersMaybe?: Record<string, string | string[]>,
48
+ ) {
49
+ this.headers =
50
+ typeof statusMessageOrHeaders === 'string'
51
+ ? (headersMaybe ?? {})
52
+ : (statusMessageOrHeaders ?? {})
53
+ return this
54
+ },
55
+ write(this: MockResponse, chunk: Uint8Array | string) {
56
+ this.body.push(Buffer.from(chunk))
57
+ return true
58
+ },
59
+ end(this: MockResponse, chunk?: Uint8Array | string) {
60
+ if (chunk) this.body.push(Buffer.from(chunk))
61
+ this.emit('finish')
62
+ return this
63
+ },
64
+ }) as unknown as MockResponse
65
+
66
+ return [req, res]
67
+ }
68
+
9
69
  describe('sendResponse', () => {
10
70
  test('writes status and headers', async () => {
11
71
  server = await Http.createServer(async (_, res) => {
@@ -185,4 +245,22 @@ describe('toNodeListener', () => {
185
245
  const response = await fetch(server.url)
186
246
  expect(await response.text()).toBe('abc')
187
247
  })
248
+
249
+ test('routes malformed host header URL parsing errors through onError', async () => {
250
+ const [req, res] = createMockRequest({
251
+ rawHeaders: ['Host', 'a, b'],
252
+ })
253
+ const onError = vi.fn((error: unknown) => {
254
+ return new Response(error instanceof TypeError ? 'bad host' : 'unexpected', {
255
+ status: 500,
256
+ headers: { 'Content-Type': 'text/plain' },
257
+ })
258
+ })
259
+ const handler = Request.toNodeListener(async () => new Response('ok'), { onError })
260
+
261
+ await expect(Promise.resolve(handler(req, res))).resolves.toBeUndefined()
262
+ expect(onError).toHaveBeenCalledTimes(1)
263
+ expect(onError.mock.calls[0]![0]).toBeInstanceOf(TypeError)
264
+ expect(Buffer.concat(res.body).toString()).toBe('bad host')
265
+ })
188
266
  })
@@ -1,9 +1,45 @@
1
- import * as FetchServer from '@remix-run/node-fetch-server'
1
+ import type * as http from 'node:http'
2
+ import type * as http2 from 'node:http2'
2
3
 
3
4
  /**
4
5
  * Writes a Fetch API `Response` to a Node.js `ServerResponse`.
5
6
  *
6
- * Delegates to `@remix-run/node-fetch-server`. Useful when bridging
7
- * Fetch API handlers with Node.js HTTP servers.
7
+ * Useful when bridging Fetch API handlers with Node.js HTTP servers.
8
8
  */
9
- export const sendResponse = FetchServer.sendResponse
9
+ export async function sendResponse(
10
+ res: http.ServerResponse | http2.Http2ServerResponse,
11
+ response: Response,
12
+ ): Promise<void> {
13
+ const headers: Record<string, string | string[]> = {}
14
+ for (const [key, value] of response.headers) {
15
+ if (key in headers) {
16
+ const existing = headers[key]
17
+ if (Array.isArray(existing)) existing.push(value)
18
+ else headers[key] = [existing!, value]
19
+ } else {
20
+ headers[key] = value
21
+ }
22
+ }
23
+
24
+ if ('req' in res && (res as http.ServerResponse).req?.httpVersionMajor === 1)
25
+ (res as http.ServerResponse).writeHead(response.status, response.statusText, headers)
26
+ else (res as http2.Http2ServerResponse).writeHead(response.status, headers)
27
+
28
+ if (response.body != null && (res as http.ServerResponse).req?.method !== 'HEAD') {
29
+ const reader = response.body.getReader()
30
+ try {
31
+ while (true) {
32
+ const { done, value } = await reader.read()
33
+ if (done) break
34
+ if ((res as http.ServerResponse).write(value) === false)
35
+ await new Promise<void>((resolve) => {
36
+ res.once('drain', resolve)
37
+ })
38
+ }
39
+ } finally {
40
+ reader.releaseLock()
41
+ }
42
+ }
43
+
44
+ res.end()
45
+ }
@@ -62,6 +62,32 @@ describe('fromNodeListener', () => {
62
62
  expect(request.url).toBe('http://localhost/')
63
63
  })
64
64
 
65
+ test('normalizes absolute-form request targets to the host header', () => {
66
+ const [req, res] = createMockRequest({
67
+ url: 'http://unexpected.example/api/resource?q=1',
68
+ rawHeaders: ['Host', 'example.com'],
69
+ })
70
+
71
+ const request = Request.fromNodeListener(req, res)
72
+
73
+ expect(request.url).toBe('http://example.com/api/resource?q=1')
74
+ })
75
+
76
+ test('uses explicit protocol and host overrides', () => {
77
+ const [req, res] = createMockRequest({
78
+ url: '/api/resource',
79
+ rawHeaders: ['Host', 'internal.local'],
80
+ socket: { encrypted: false },
81
+ })
82
+
83
+ const request = Request.fromNodeListener(req, res, {
84
+ host: 'api.example.com',
85
+ protocol: 'https:',
86
+ })
87
+
88
+ expect(request.url).toBe('https://api.example.com/api/resource')
89
+ })
90
+
65
91
  test('preserves multi-value headers via append', () => {
66
92
  const [req, res] = createMockRequest({
67
93
  rawHeaders: ['Host', 'example.com', 'Set-Cookie', 'a=1', 'Set-Cookie', 'b=2'],
@@ -1,34 +1,136 @@
1
1
  import type { IncomingMessage, RequestListener, ServerResponse } from 'node:http'
2
2
 
3
- import * as FetchServer from '@remix-run/node-fetch-server'
3
+ import * as NodeListener from './NodeListener.js'
4
4
 
5
5
  export type FetchHandler = (request: Request) => Promise<Response> | Response
6
6
 
7
+ export type RequestListenerOptions = {
8
+ host?: string | undefined
9
+ onError?: ((error: unknown) => void | Response | Promise<void | Response>) | undefined
10
+ protocol?: string | undefined
11
+ }
12
+
7
13
  /**
8
14
  * Converts a Fetch API handler into a Node.js HTTP request listener.
9
15
  *
10
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
11
- *
12
16
  * @param handler - A Fetch API handler: `(request: Request) => Response`.
13
17
  * @param options - Optional error handler.
14
18
  * @returns A Node.js `(req, res)` listener.
15
19
  */
16
20
  export function toNodeListener(
17
21
  handler: FetchHandler,
18
- options?: FetchServer.RequestListenerOptions | undefined,
22
+ options?: RequestListenerOptions | undefined,
19
23
  ): RequestListener {
20
- return FetchServer.createRequestListener(handler, options) as never
24
+ const onError =
25
+ options?.onError ??
26
+ ((error: unknown) => {
27
+ console.error(error)
28
+ return new Response('Internal Server Error', {
29
+ status: 500,
30
+ headers: { 'Content-Type': 'text/plain' },
31
+ })
32
+ })
33
+
34
+ return (async (req: IncomingMessage, res: ServerResponse) => {
35
+ let response: Response
36
+ try {
37
+ const request = fromNodeListener(req, res, options)
38
+ response = await handler(request)
39
+ } catch (error) {
40
+ try {
41
+ response =
42
+ (await onError(error)) ??
43
+ new Response('Internal Server Error', {
44
+ status: 500,
45
+ headers: { 'Content-Type': 'text/plain' },
46
+ })
47
+ } catch (innerError) {
48
+ console.error(`There was an error in the error handler: ${innerError}`)
49
+ response = new Response('Internal Server Error', {
50
+ status: 500,
51
+ headers: { 'Content-Type': 'text/plain' },
52
+ })
53
+ }
54
+ }
55
+ await NodeListener.sendResponse(res, response)
56
+ }) as RequestListener
21
57
  }
22
58
 
23
59
  /**
24
60
  * Converts a Node.js `IncomingMessage`/`ServerResponse` pair to a Fetch API `Request`.
25
61
  *
26
- * Uses [`@remix-run/node-fetch-server`](https://github.com/remix-run/remix/blob/main/packages/node-fetch-server/src/lib/request-listener.ts).
27
- *
28
62
  * @param req - The Node.js IncomingMessage.
29
63
  * @param res - The Node.js ServerResponse (used for abort signal lifecycle).
30
64
  * @returns A Fetch API Request.
31
65
  */
32
- export function fromNodeListener(req: IncomingMessage, res: ServerResponse): Request {
33
- return FetchServer.createRequest(req, res)
66
+ export function fromNodeListener(
67
+ req: IncomingMessage,
68
+ res: ServerResponse,
69
+ options?: RequestListenerOptions | undefined,
70
+ ): Request {
71
+ let controller: AbortController | null = new AbortController()
72
+ res.once('close', () => controller?.abort())
73
+ res.once('finish', () => {
74
+ controller = null
75
+ })
76
+
77
+ const method = req.method ?? 'GET'
78
+ const headers = createHeaders(req)
79
+ const protocol =
80
+ options?.protocol ??
81
+ ('encrypted' in req.socket && (req.socket as { encrypted?: boolean }).encrypted
82
+ ? 'https:'
83
+ : 'http:')
84
+ const host =
85
+ options?.host ??
86
+ headers.get('Host') ??
87
+ (req.headers as Record<string, string>)[':authority'] ??
88
+ 'localhost'
89
+ const url = new URL(normalizeRequestTarget(req.url), `${protocol}//${host}`)
90
+
91
+ const init: RequestInit & { duplex?: string } = {
92
+ method,
93
+ headers,
94
+ signal: controller.signal,
95
+ }
96
+
97
+ if (method !== 'GET' && method !== 'HEAD') {
98
+ init.body = new ReadableStream({
99
+ start(c) {
100
+ req.on('data', (chunk: Buffer) => {
101
+ c.enqueue(new Uint8Array(chunk.buffer, chunk.byteOffset, chunk.byteLength))
102
+ })
103
+ req.on('end', () => {
104
+ c.close()
105
+ })
106
+ },
107
+ })
108
+ init.duplex = 'half'
109
+ }
110
+
111
+ return new Request(url, init)
112
+ }
113
+
114
+ function normalizeRequestTarget(url: string | undefined): string {
115
+ if (!url) return '/'
116
+
117
+ try {
118
+ const absoluteUrl = new URL(url)
119
+ // Absolute-form request targets can carry a different origin than the socket host.
120
+ // Keep only path+query so realm detection stays bound to Host/:authority.
121
+ if (absoluteUrl.protocol === 'http:' || absoluteUrl.protocol === 'https:')
122
+ return `${absoluteUrl.pathname}${absoluteUrl.search}`
123
+ } catch {}
124
+
125
+ return url
126
+ }
127
+
128
+ function createHeaders(req: IncomingMessage): Headers {
129
+ const headers = new Headers()
130
+ const raw = req.rawHeaders
131
+ for (let i = 0; i < raw.length; i += 2) {
132
+ if (raw[i]!.startsWith(':')) continue
133
+ headers.append(raw[i]!, raw[i + 1]!)
134
+ }
135
+ return headers
34
136
  }