@whatwg-node/server 0.9.7 → 0.9.8-alpha-20230806210100-04a8ea2

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.
@@ -51,7 +51,7 @@ function createServerAdapter(serverAdapterBaseObject, options) {
51
51
  }
52
52
  }
53
53
  }
54
- async function handleRequest(request, serverContext) {
54
+ function handleRequest(request, serverContext) {
55
55
  let url = new Proxy(EMPTY_OBJECT, {
56
56
  get(_target, prop, _receiver) {
57
57
  url = new fetchAPI.URL(request.url, 'http://localhost');
@@ -60,35 +60,48 @@ function createServerAdapter(serverAdapterBaseObject, options) {
60
60
  });
61
61
  let requestHandler = givenHandleRequest;
62
62
  let response;
63
- for (const onRequestHook of onRequestHooks) {
64
- await onRequestHook({
63
+ const onRequestHooksIteration$ = (0, utils_js_1.iterateAsyncVoid)(onRequestHooks, (onRequestHook, stopEarly) => onRequestHook({
64
+ request,
65
+ serverContext,
66
+ fetchAPI,
67
+ url,
68
+ requestHandler,
69
+ setRequestHandler(newRequestHandler) {
70
+ requestHandler = newRequestHandler;
71
+ },
72
+ endResponse(newResponse) {
73
+ response = newResponse;
74
+ if (newResponse) {
75
+ stopEarly();
76
+ }
77
+ },
78
+ }));
79
+ function handleResponse(response) {
80
+ const onResponseHookPayload = {
65
81
  request,
82
+ response,
66
83
  serverContext,
67
- fetchAPI,
68
- url,
69
- requestHandler,
70
- setRequestHandler(newRequestHandler) {
71
- requestHandler = newRequestHandler;
72
- },
73
- endResponse(newResponse) {
74
- response = newResponse;
75
- },
76
- });
77
- if (response) {
78
- break;
84
+ };
85
+ const onResponseHooksIteration$ = (0, utils_js_1.iterateAsyncVoid)(onResponseHooks, onResponseHook => onResponseHook(onResponseHookPayload));
86
+ if ((0, utils_js_1.isPromise)(onResponseHooksIteration$)) {
87
+ return onResponseHooksIteration$.then(() => response);
79
88
  }
89
+ return response;
80
90
  }
81
- if (!response) {
82
- response = await requestHandler(request, serverContext);
91
+ function handleEarlyResponse() {
92
+ if (!response) {
93
+ const response$ = requestHandler(request, serverContext);
94
+ if ((0, utils_js_1.isPromise)(response$)) {
95
+ return response$.then(handleResponse);
96
+ }
97
+ return handleResponse(response$);
98
+ }
99
+ return handleResponse(response);
83
100
  }
84
- for (const onResponseHook of onResponseHooks) {
85
- await onResponseHook({
86
- request,
87
- response,
88
- serverContext,
89
- });
101
+ if ((0, utils_js_1.isPromise)(onRequestHooksIteration$)) {
102
+ return onRequestHooksIteration$.then(handleEarlyResponse);
90
103
  }
91
- return response;
104
+ return handleEarlyResponse();
92
105
  }
93
106
  function handleNodeRequest(nodeRequest, ...ctx) {
94
107
  const serverContext = ctx.length > 1 ? (0, utils_js_1.completeAssign)(...ctx) : ctx[0] || {};
@@ -102,8 +115,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
102
115
  res: serverResponse,
103
116
  };
104
117
  addWaitUntil(defaultServerContext, waitUntilPromises);
105
- return handleNodeRequest(nodeRequest, defaultServerContext, ...ctx)
106
- .then(response => {
118
+ const response$ = handleNodeRequest(nodeRequest, defaultServerContext, ...ctx);
119
+ function handleFetchResponse(response) {
107
120
  try {
108
121
  if (serverResponse.closed || serverResponse.destroyed) {
109
122
  return;
@@ -117,12 +130,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
117
130
  catch (e) {
118
131
  console.error(`Unexpected error: ${e.message || e}`);
119
132
  }
120
- })
121
- .finally(() => {
122
- if (waitUntilPromises.length > 0) {
123
- return handleWaitUntils(waitUntilPromises);
124
- }
125
- });
133
+ }
134
+ if ((0, utils_js_1.isPromise)(response$)) {
135
+ return response$.then(handleFetchResponse);
136
+ }
137
+ return handleFetchResponse(response$);
126
138
  }
127
139
  function handleUWS(res, req, ...ctx) {
128
140
  const waitUntilPromises = [];
@@ -141,7 +153,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
141
153
  res.onAborted(() => {
142
154
  resAborted = true;
143
155
  });
144
- return handleRequest(request, serverContext).then(response => {
156
+ const response$ = handleRequest(request, serverContext);
157
+ function handleFetchResponse(response) {
145
158
  if (resAborted) {
146
159
  return;
147
160
  }
@@ -159,7 +172,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
159
172
  catch (e) {
160
173
  console.error(`Unexpected error: ${e.message || e}`);
161
174
  }
162
- });
175
+ }
176
+ if ((0, utils_js_1.isPromise)(response$)) {
177
+ return response$.then(handleFetchResponse);
178
+ }
179
+ return handleFetchResponse(response$);
163
180
  }
164
181
  function handleEvent(event, ...ctx) {
165
182
  if (!event.respondWith || !event.request) {
package/cjs/utils.js CHANGED
@@ -1,6 +1,6 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.isPromise = exports.completeAssign = exports.isRequestInit = exports.sendNodeResponse = exports.isFetchEvent = exports.isReadableStream = exports.isServerResponse = exports.isNodeRequest = exports.isReadable = exports.normalizeNodeRequest = exports.isAsyncIterable = void 0;
3
+ exports.iterateAsyncVoid = exports.isPromise = exports.completeAssign = exports.isRequestInit = exports.sendNodeResponse = exports.isFetchEvent = exports.isReadableStream = exports.isServerResponse = exports.isNodeRequest = exports.isReadable = exports.normalizeNodeRequest = exports.isAsyncIterable = void 0;
4
4
  const fetch_1 = require("@whatwg-node/fetch");
5
5
  function isAsyncIterable(body) {
6
6
  return (body != null && typeof body === 'object' && typeof body[Symbol.asyncIterator] === 'function');
@@ -244,6 +244,34 @@ function completeAssign(...args) {
244
244
  }
245
245
  exports.completeAssign = completeAssign;
246
246
  function isPromise(val) {
247
- return val != null && typeof val === 'object' && typeof val.then === 'function';
247
+ return val?.then != null;
248
248
  }
249
249
  exports.isPromise = isPromise;
250
+ function iterateAsyncVoid(iterable, callback) {
251
+ const iterator = iterable[Symbol.iterator]();
252
+ let stopEarlyFlag = false;
253
+ function stopEarlyFn() {
254
+ stopEarlyFlag = true;
255
+ }
256
+ function iterate() {
257
+ const { done: endOfIterator, value } = iterator.next();
258
+ if (endOfIterator) {
259
+ return;
260
+ }
261
+ const result$ = callback(value, stopEarlyFn);
262
+ if (isPromise(result$)) {
263
+ return result$.then(() => {
264
+ if (stopEarlyFlag) {
265
+ return;
266
+ }
267
+ return iterate();
268
+ });
269
+ }
270
+ if (stopEarlyFlag) {
271
+ return;
272
+ }
273
+ return iterate();
274
+ }
275
+ return iterate();
276
+ }
277
+ exports.iterateAsyncVoid = iterateAsyncVoid;
@@ -1,6 +1,6 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
2
  import * as DefaultFetchAPI from '@whatwg-node/fetch';
3
- import { completeAssign, isFetchEvent, isNodeRequest, isRequestInit, isServerResponse, normalizeNodeRequest, sendNodeResponse, } from './utils.js';
3
+ import { completeAssign, isFetchEvent, isNodeRequest, isPromise, isRequestInit, isServerResponse, iterateAsyncVoid, normalizeNodeRequest, sendNodeResponse, } from './utils.js';
4
4
  import { getRequestFromUWSRequest, isUWSResponse, sendResponseToUwsOpts, } from './uwebsockets.js';
5
5
  async function handleWaitUntils(waitUntilPromises) {
6
6
  const waitUntils = await Promise.allSettled(waitUntilPromises);
@@ -47,7 +47,7 @@ function createServerAdapter(serverAdapterBaseObject, options) {
47
47
  }
48
48
  }
49
49
  }
50
- async function handleRequest(request, serverContext) {
50
+ function handleRequest(request, serverContext) {
51
51
  let url = new Proxy(EMPTY_OBJECT, {
52
52
  get(_target, prop, _receiver) {
53
53
  url = new fetchAPI.URL(request.url, 'http://localhost');
@@ -56,35 +56,48 @@ function createServerAdapter(serverAdapterBaseObject, options) {
56
56
  });
57
57
  let requestHandler = givenHandleRequest;
58
58
  let response;
59
- for (const onRequestHook of onRequestHooks) {
60
- await onRequestHook({
59
+ const onRequestHooksIteration$ = iterateAsyncVoid(onRequestHooks, (onRequestHook, stopEarly) => onRequestHook({
60
+ request,
61
+ serverContext,
62
+ fetchAPI,
63
+ url,
64
+ requestHandler,
65
+ setRequestHandler(newRequestHandler) {
66
+ requestHandler = newRequestHandler;
67
+ },
68
+ endResponse(newResponse) {
69
+ response = newResponse;
70
+ if (newResponse) {
71
+ stopEarly();
72
+ }
73
+ },
74
+ }));
75
+ function handleResponse(response) {
76
+ const onResponseHookPayload = {
61
77
  request,
78
+ response,
62
79
  serverContext,
63
- fetchAPI,
64
- url,
65
- requestHandler,
66
- setRequestHandler(newRequestHandler) {
67
- requestHandler = newRequestHandler;
68
- },
69
- endResponse(newResponse) {
70
- response = newResponse;
71
- },
72
- });
73
- if (response) {
74
- break;
80
+ };
81
+ const onResponseHooksIteration$ = iterateAsyncVoid(onResponseHooks, onResponseHook => onResponseHook(onResponseHookPayload));
82
+ if (isPromise(onResponseHooksIteration$)) {
83
+ return onResponseHooksIteration$.then(() => response);
75
84
  }
85
+ return response;
76
86
  }
77
- if (!response) {
78
- response = await requestHandler(request, serverContext);
87
+ function handleEarlyResponse() {
88
+ if (!response) {
89
+ const response$ = requestHandler(request, serverContext);
90
+ if (isPromise(response$)) {
91
+ return response$.then(handleResponse);
92
+ }
93
+ return handleResponse(response$);
94
+ }
95
+ return handleResponse(response);
79
96
  }
80
- for (const onResponseHook of onResponseHooks) {
81
- await onResponseHook({
82
- request,
83
- response,
84
- serverContext,
85
- });
97
+ if (isPromise(onRequestHooksIteration$)) {
98
+ return onRequestHooksIteration$.then(handleEarlyResponse);
86
99
  }
87
- return response;
100
+ return handleEarlyResponse();
88
101
  }
89
102
  function handleNodeRequest(nodeRequest, ...ctx) {
90
103
  const serverContext = ctx.length > 1 ? completeAssign(...ctx) : ctx[0] || {};
@@ -98,8 +111,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
98
111
  res: serverResponse,
99
112
  };
100
113
  addWaitUntil(defaultServerContext, waitUntilPromises);
101
- return handleNodeRequest(nodeRequest, defaultServerContext, ...ctx)
102
- .then(response => {
114
+ const response$ = handleNodeRequest(nodeRequest, defaultServerContext, ...ctx);
115
+ function handleFetchResponse(response) {
103
116
  try {
104
117
  if (serverResponse.closed || serverResponse.destroyed) {
105
118
  return;
@@ -113,12 +126,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
113
126
  catch (e) {
114
127
  console.error(`Unexpected error: ${e.message || e}`);
115
128
  }
116
- })
117
- .finally(() => {
118
- if (waitUntilPromises.length > 0) {
119
- return handleWaitUntils(waitUntilPromises);
120
- }
121
- });
129
+ }
130
+ if (isPromise(response$)) {
131
+ return response$.then(handleFetchResponse);
132
+ }
133
+ return handleFetchResponse(response$);
122
134
  }
123
135
  function handleUWS(res, req, ...ctx) {
124
136
  const waitUntilPromises = [];
@@ -137,7 +149,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
137
149
  res.onAborted(() => {
138
150
  resAborted = true;
139
151
  });
140
- return handleRequest(request, serverContext).then(response => {
152
+ const response$ = handleRequest(request, serverContext);
153
+ function handleFetchResponse(response) {
141
154
  if (resAborted) {
142
155
  return;
143
156
  }
@@ -155,7 +168,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
155
168
  catch (e) {
156
169
  console.error(`Unexpected error: ${e.message || e}`);
157
170
  }
158
- });
171
+ }
172
+ if (isPromise(response$)) {
173
+ return response$.then(handleFetchResponse);
174
+ }
175
+ return handleFetchResponse(response$);
159
176
  }
160
177
  function handleEvent(event, ...ctx) {
161
178
  if (!event.respondWith || !event.request) {
package/esm/utils.js CHANGED
@@ -231,5 +231,32 @@ export function completeAssign(...args) {
231
231
  return target;
232
232
  }
233
233
  export function isPromise(val) {
234
- return val != null && typeof val === 'object' && typeof val.then === 'function';
234
+ return val?.then != null;
235
+ }
236
+ export function iterateAsyncVoid(iterable, callback) {
237
+ const iterator = iterable[Symbol.iterator]();
238
+ let stopEarlyFlag = false;
239
+ function stopEarlyFn() {
240
+ stopEarlyFlag = true;
241
+ }
242
+ function iterate() {
243
+ const { done: endOfIterator, value } = iterator.next();
244
+ if (endOfIterator) {
245
+ return;
246
+ }
247
+ const result$ = callback(value, stopEarlyFn);
248
+ if (isPromise(result$)) {
249
+ return result$.then(() => {
250
+ if (stopEarlyFlag) {
251
+ return;
252
+ }
253
+ return iterate();
254
+ });
255
+ }
256
+ if (stopEarlyFlag) {
257
+ return;
258
+ }
259
+ return iterate();
260
+ }
261
+ return iterate();
235
262
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@whatwg-node/server",
3
- "version": "0.9.7",
3
+ "version": "0.9.8-alpha-20230806210100-04a8ea2",
4
4
  "description": "Fetch API compliant HTTP Server adapter",
5
5
  "sideEffects": false,
6
6
  "dependencies": {
@@ -18,7 +18,7 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
18
18
  /**
19
19
  * A basic request listener that takes a `Request` with the server context and returns a `Response`.
20
20
  */
21
- handleRequest: (request: Request, ctx: TServerContext) => Promise<Response>;
21
+ handleRequest: (request: Request, ctx: TServerContext) => Promise<Response> | Response;
22
22
  /**
23
23
  * WHATWG Fetch spec compliant `fetch` function that can be used for testing purposes.
24
24
  */
@@ -18,7 +18,7 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
18
18
  /**
19
19
  * A basic request listener that takes a `Request` with the server context and returns a `Response`.
20
20
  */
21
- handleRequest: (request: Request, ctx: TServerContext) => Promise<Response>;
21
+ handleRequest: (request: Request, ctx: TServerContext) => Promise<Response> | Response;
22
22
  /**
23
23
  * WHATWG Fetch spec compliant `fetch` function that can be used for testing purposes.
24
24
  */
@@ -31,4 +31,5 @@ export declare function isFetchEvent(event: any): event is FetchEvent;
31
31
  export declare function sendNodeResponse(fetchResponse: Response, serverResponse: NodeResponse, nodeRequest: NodeRequest): Promise<void> | undefined;
32
32
  export declare function isRequestInit(val: unknown): val is RequestInit;
33
33
  export declare function completeAssign(...args: any[]): any;
34
- export declare function isPromise(val: unknown): val is Promise<unknown>;
34
+ export declare function isPromise<T>(val: T | Promise<T>): val is Promise<T>;
35
+ export declare function iterateAsyncVoid<TInput>(iterable: Iterable<TInput>, callback: (input: TInput, stopEarly: () => void) => Promise<void> | void): Promise<void> | void;
@@ -31,4 +31,5 @@ export declare function isFetchEvent(event: any): event is FetchEvent;
31
31
  export declare function sendNodeResponse(fetchResponse: Response, serverResponse: NodeResponse, nodeRequest: NodeRequest): Promise<void> | undefined;
32
32
  export declare function isRequestInit(val: unknown): val is RequestInit;
33
33
  export declare function completeAssign(...args: any[]): any;
34
- export declare function isPromise(val: unknown): val is Promise<unknown>;
34
+ export declare function isPromise<T>(val: T | Promise<T>): val is Promise<T>;
35
+ export declare function iterateAsyncVoid<TInput>(iterable: Iterable<TInput>, callback: (input: TInput, stopEarly: () => void) => Promise<void> | void): Promise<void> | void;