@whatwg-node/server 0.9.7 → 0.9.8-alpha-20230806205544-d8f5b36

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.
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.createServerAdapter = void 0;
4
4
  const tslib_1 = require("tslib");
5
5
  /* eslint-disable @typescript-eslint/ban-types */
6
+ const types_1 = require("util/types");
6
7
  const DefaultFetchAPI = tslib_1.__importStar(require("@whatwg-node/fetch"));
7
8
  const utils_js_1 = require("./utils.js");
8
9
  const uwebsockets_js_1 = require("./uwebsockets.js");
@@ -51,7 +52,7 @@ function createServerAdapter(serverAdapterBaseObject, options) {
51
52
  }
52
53
  }
53
54
  }
54
- async function handleRequest(request, serverContext) {
55
+ function handleRequest(request, serverContext) {
55
56
  let url = new Proxy(EMPTY_OBJECT, {
56
57
  get(_target, prop, _receiver) {
57
58
  url = new fetchAPI.URL(request.url, 'http://localhost');
@@ -60,35 +61,48 @@ function createServerAdapter(serverAdapterBaseObject, options) {
60
61
  });
61
62
  let requestHandler = givenHandleRequest;
62
63
  let response;
63
- for (const onRequestHook of onRequestHooks) {
64
- await onRequestHook({
64
+ const onRequestHooksIteration$ = (0, utils_js_1.iterateAsyncVoid)(onRequestHooks, (onRequestHook, stopEarly) => onRequestHook({
65
+ request,
66
+ serverContext,
67
+ fetchAPI,
68
+ url,
69
+ requestHandler,
70
+ setRequestHandler(newRequestHandler) {
71
+ requestHandler = newRequestHandler;
72
+ },
73
+ endResponse(newResponse) {
74
+ response = newResponse;
75
+ if (newResponse) {
76
+ stopEarly();
77
+ }
78
+ },
79
+ }));
80
+ function handleResponse(response) {
81
+ const onResponseHookPayload = {
65
82
  request,
83
+ response,
66
84
  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;
85
+ };
86
+ const onResponseHooksIteration$ = (0, utils_js_1.iterateAsyncVoid)(onResponseHooks, onResponseHook => onResponseHook(onResponseHookPayload));
87
+ if ((0, types_1.isPromise)(onResponseHooksIteration$)) {
88
+ return onResponseHooksIteration$.then(() => response);
79
89
  }
90
+ return response;
80
91
  }
81
- if (!response) {
82
- response = await requestHandler(request, serverContext);
92
+ function handleEarlyResponse() {
93
+ if (!response) {
94
+ const response$ = requestHandler(request, serverContext);
95
+ if ((0, types_1.isPromise)(response$)) {
96
+ return response$.then(handleResponse);
97
+ }
98
+ return handleResponse(response$);
99
+ }
100
+ return handleResponse(response);
83
101
  }
84
- for (const onResponseHook of onResponseHooks) {
85
- await onResponseHook({
86
- request,
87
- response,
88
- serverContext,
89
- });
102
+ if ((0, types_1.isPromise)(onRequestHooksIteration$)) {
103
+ return onRequestHooksIteration$.then(handleEarlyResponse);
90
104
  }
91
- return response;
105
+ return handleEarlyResponse();
92
106
  }
93
107
  function handleNodeRequest(nodeRequest, ...ctx) {
94
108
  const serverContext = ctx.length > 1 ? (0, utils_js_1.completeAssign)(...ctx) : ctx[0] || {};
@@ -102,8 +116,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
102
116
  res: serverResponse,
103
117
  };
104
118
  addWaitUntil(defaultServerContext, waitUntilPromises);
105
- return handleNodeRequest(nodeRequest, defaultServerContext, ...ctx)
106
- .then(response => {
119
+ const response$ = handleNodeRequest(nodeRequest, defaultServerContext, ...ctx);
120
+ function handleFetchResponse(response) {
107
121
  try {
108
122
  if (serverResponse.closed || serverResponse.destroyed) {
109
123
  return;
@@ -117,12 +131,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
117
131
  catch (e) {
118
132
  console.error(`Unexpected error: ${e.message || e}`);
119
133
  }
120
- })
121
- .finally(() => {
122
- if (waitUntilPromises.length > 0) {
123
- return handleWaitUntils(waitUntilPromises);
124
- }
125
- });
134
+ }
135
+ if ((0, types_1.isPromise)(response$)) {
136
+ return response$.then(handleFetchResponse);
137
+ }
138
+ return handleFetchResponse(response$);
126
139
  }
127
140
  function handleUWS(res, req, ...ctx) {
128
141
  const waitUntilPromises = [];
@@ -141,7 +154,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
141
154
  res.onAborted(() => {
142
155
  resAborted = true;
143
156
  });
144
- return handleRequest(request, serverContext).then(response => {
157
+ const response$ = handleRequest(request, serverContext);
158
+ function handleFetchResponse(response) {
145
159
  if (resAborted) {
146
160
  return;
147
161
  }
@@ -159,7 +173,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
159
173
  catch (e) {
160
174
  console.error(`Unexpected error: ${e.message || e}`);
161
175
  }
162
- });
176
+ }
177
+ if ((0, types_1.isPromise)(response$)) {
178
+ return response$.then(handleFetchResponse);
179
+ }
180
+ return handleFetchResponse(response$);
163
181
  }
164
182
  function handleEvent(event, ...ctx) {
165
183
  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,7 @@
1
1
  /* eslint-disable @typescript-eslint/ban-types */
2
+ import { isPromise } from 'util/types';
2
3
  import * as DefaultFetchAPI from '@whatwg-node/fetch';
3
- import { completeAssign, isFetchEvent, isNodeRequest, isRequestInit, isServerResponse, normalizeNodeRequest, sendNodeResponse, } from './utils.js';
4
+ import { completeAssign, isFetchEvent, isNodeRequest, isRequestInit, isServerResponse, iterateAsyncVoid, normalizeNodeRequest, sendNodeResponse, } from './utils.js';
4
5
  import { getRequestFromUWSRequest, isUWSResponse, sendResponseToUwsOpts, } from './uwebsockets.js';
5
6
  async function handleWaitUntils(waitUntilPromises) {
6
7
  const waitUntils = await Promise.allSettled(waitUntilPromises);
@@ -47,7 +48,7 @@ function createServerAdapter(serverAdapterBaseObject, options) {
47
48
  }
48
49
  }
49
50
  }
50
- async function handleRequest(request, serverContext) {
51
+ function handleRequest(request, serverContext) {
51
52
  let url = new Proxy(EMPTY_OBJECT, {
52
53
  get(_target, prop, _receiver) {
53
54
  url = new fetchAPI.URL(request.url, 'http://localhost');
@@ -56,35 +57,48 @@ function createServerAdapter(serverAdapterBaseObject, options) {
56
57
  });
57
58
  let requestHandler = givenHandleRequest;
58
59
  let response;
59
- for (const onRequestHook of onRequestHooks) {
60
- await onRequestHook({
60
+ const onRequestHooksIteration$ = iterateAsyncVoid(onRequestHooks, (onRequestHook, stopEarly) => onRequestHook({
61
+ request,
62
+ serverContext,
63
+ fetchAPI,
64
+ url,
65
+ requestHandler,
66
+ setRequestHandler(newRequestHandler) {
67
+ requestHandler = newRequestHandler;
68
+ },
69
+ endResponse(newResponse) {
70
+ response = newResponse;
71
+ if (newResponse) {
72
+ stopEarly();
73
+ }
74
+ },
75
+ }));
76
+ function handleResponse(response) {
77
+ const onResponseHookPayload = {
61
78
  request,
79
+ response,
62
80
  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;
81
+ };
82
+ const onResponseHooksIteration$ = iterateAsyncVoid(onResponseHooks, onResponseHook => onResponseHook(onResponseHookPayload));
83
+ if (isPromise(onResponseHooksIteration$)) {
84
+ return onResponseHooksIteration$.then(() => response);
75
85
  }
86
+ return response;
76
87
  }
77
- if (!response) {
78
- response = await requestHandler(request, serverContext);
88
+ function handleEarlyResponse() {
89
+ if (!response) {
90
+ const response$ = requestHandler(request, serverContext);
91
+ if (isPromise(response$)) {
92
+ return response$.then(handleResponse);
93
+ }
94
+ return handleResponse(response$);
95
+ }
96
+ return handleResponse(response);
79
97
  }
80
- for (const onResponseHook of onResponseHooks) {
81
- await onResponseHook({
82
- request,
83
- response,
84
- serverContext,
85
- });
98
+ if (isPromise(onRequestHooksIteration$)) {
99
+ return onRequestHooksIteration$.then(handleEarlyResponse);
86
100
  }
87
- return response;
101
+ return handleEarlyResponse();
88
102
  }
89
103
  function handleNodeRequest(nodeRequest, ...ctx) {
90
104
  const serverContext = ctx.length > 1 ? completeAssign(...ctx) : ctx[0] || {};
@@ -98,8 +112,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
98
112
  res: serverResponse,
99
113
  };
100
114
  addWaitUntil(defaultServerContext, waitUntilPromises);
101
- return handleNodeRequest(nodeRequest, defaultServerContext, ...ctx)
102
- .then(response => {
115
+ const response$ = handleNodeRequest(nodeRequest, defaultServerContext, ...ctx);
116
+ function handleFetchResponse(response) {
103
117
  try {
104
118
  if (serverResponse.closed || serverResponse.destroyed) {
105
119
  return;
@@ -113,12 +127,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
113
127
  catch (e) {
114
128
  console.error(`Unexpected error: ${e.message || e}`);
115
129
  }
116
- })
117
- .finally(() => {
118
- if (waitUntilPromises.length > 0) {
119
- return handleWaitUntils(waitUntilPromises);
120
- }
121
- });
130
+ }
131
+ if (isPromise(response$)) {
132
+ return response$.then(handleFetchResponse);
133
+ }
134
+ return handleFetchResponse(response$);
122
135
  }
123
136
  function handleUWS(res, req, ...ctx) {
124
137
  const waitUntilPromises = [];
@@ -137,7 +150,8 @@ function createServerAdapter(serverAdapterBaseObject, options) {
137
150
  res.onAborted(() => {
138
151
  resAborted = true;
139
152
  });
140
- return handleRequest(request, serverContext).then(response => {
153
+ const response$ = handleRequest(request, serverContext);
154
+ function handleFetchResponse(response) {
141
155
  if (resAborted) {
142
156
  return;
143
157
  }
@@ -155,7 +169,11 @@ function createServerAdapter(serverAdapterBaseObject, options) {
155
169
  catch (e) {
156
170
  console.error(`Unexpected error: ${e.message || e}`);
157
171
  }
158
- });
172
+ }
173
+ if (isPromise(response$)) {
174
+ return response$.then(handleFetchResponse);
175
+ }
176
+ return handleFetchResponse(response$);
159
177
  }
160
178
  function handleEvent(event, ...ctx) {
161
179
  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-20230806205544-d8f5b36",
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;