@whatwg-node/server 0.3.0 → 0.4.0-alpha-20220916163145-ea58ba1
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/README.md +11 -12
- package/index.d.ts +18 -22
- package/index.js +28 -22
- package/index.mjs +28 -22
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -12,10 +12,8 @@ Let's create a basic Hello World server adapter.
|
|
|
12
12
|
// myServerAdapter.ts
|
|
13
13
|
import { createServerAdapter } from '@whatwg-node/server'
|
|
14
14
|
|
|
15
|
-
export default createServerAdapter({
|
|
16
|
-
handleRequest(request: Request) {
|
|
15
|
+
export default createServerAdapter((request: Request) => {
|
|
17
16
|
return new Response(`Hello World!`, { status: 200 })
|
|
18
|
-
}
|
|
19
17
|
})
|
|
20
18
|
```
|
|
21
19
|
|
|
@@ -203,9 +201,7 @@ For example, if you send a multipart request from a browser with `FormData`, you
|
|
|
203
201
|
```ts
|
|
204
202
|
import { createServerAdapter } from '@whatwg-node/server'
|
|
205
203
|
|
|
206
|
-
const myServerAdapter = createServerAdapter({
|
|
207
|
-
// ...
|
|
208
|
-
async handleRequest(request) {
|
|
204
|
+
const myServerAdapter = createServerAdapter(async request => {
|
|
209
205
|
// Parse the request as `FormData`
|
|
210
206
|
const formData = await request.formData()
|
|
211
207
|
// Select the file
|
|
@@ -221,8 +217,7 @@ const myServerAdapter = createServerAdapter({
|
|
|
221
217
|
'Content-Type': 'application/json'
|
|
222
218
|
}
|
|
223
219
|
})
|
|
224
|
-
}
|
|
225
|
-
})
|
|
220
|
+
})
|
|
226
221
|
```
|
|
227
222
|
|
|
228
223
|
You can learn more about [File API](https://developer.mozilla.org/en-US/docs/Web/API/File) on MDN documentation.
|
|
@@ -236,6 +231,7 @@ We'd recommend to use [itty-router](https://github.com/kwhitley/itty-router) to
|
|
|
236
231
|
```ts
|
|
237
232
|
import { Router } from 'itty-router'
|
|
238
233
|
import { createServerAdapter } from '@whatwg-node/server'
|
|
234
|
+
|
|
239
235
|
// now let's create a router (note the lack of "new")
|
|
240
236
|
const router = Router()
|
|
241
237
|
// GET collection index
|
|
@@ -247,12 +243,15 @@ router.post('/todos', async request => {
|
|
|
247
243
|
const content = await request.json()
|
|
248
244
|
return new Response('Creating Todo: ' + JSON.stringify(content))
|
|
249
245
|
})
|
|
246
|
+
|
|
247
|
+
// Redirect to a URL
|
|
248
|
+
router.get('/google', () => Response.redirect('http://www.google.com'))
|
|
249
|
+
|
|
250
250
|
// 404 for everything else
|
|
251
251
|
router.all('*', () => new Response('Not Found.', { status: 404 }))
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
})
|
|
252
|
+
|
|
253
|
+
// attach the router to our server adapter
|
|
254
|
+
const myServerAdapter = createServerAdapter(router)
|
|
256
255
|
|
|
257
256
|
// Then use it in any environment
|
|
258
257
|
import { createServer } from 'http'
|
package/index.d.ts
CHANGED
|
@@ -2,38 +2,30 @@
|
|
|
2
2
|
/// <reference lib="webworker" />
|
|
3
3
|
import type { RequestListener, ServerResponse } from 'node:http';
|
|
4
4
|
import { NodeRequest } from './utils';
|
|
5
|
-
export interface
|
|
6
|
-
/**
|
|
7
|
-
* WHATWG Fetch spec compliant `Request` constructor.
|
|
8
|
-
*/
|
|
9
|
-
Request?: typeof Request;
|
|
5
|
+
export interface ServerAdapterBaseObject<TServerContext, THandleRequest extends HandleRequestFn<TServerContext>> {
|
|
10
6
|
/**
|
|
11
7
|
* An async function that takes `Request` and the server context and returns a `Response`.
|
|
12
8
|
* If you use `requestListener`, the server context is `{ req: IncomingMessage, res: ServerResponse }`.
|
|
13
9
|
*/
|
|
14
|
-
|
|
15
|
-
/**
|
|
16
|
-
* If you extend a server object with this, you can pass the original object and it will be extended with the required methods and functionalities.
|
|
17
|
-
*/
|
|
18
|
-
baseObject?: TBaseObject;
|
|
10
|
+
handle: THandleRequest;
|
|
19
11
|
}
|
|
20
|
-
export interface ServerAdapterObject<TServerContext
|
|
12
|
+
export interface ServerAdapterObject<TServerContext, TBaseObject extends ServerAdapterBaseObject<TServerContext, HandleRequestFn<TServerContext>>> extends EventListenerObject {
|
|
21
13
|
/**
|
|
22
14
|
* A basic request listener that takes a `Request` with the server context and returns a `Response`.
|
|
23
15
|
*/
|
|
24
|
-
handleRequest:
|
|
16
|
+
handleRequest: TBaseObject['handle'];
|
|
25
17
|
/**
|
|
26
18
|
* WHATWG Fetch spec compliant `fetch` function that can be used for testing purposes.
|
|
27
19
|
*/
|
|
28
|
-
fetch(request: Request, ...ctx: any[]): Promise<Response
|
|
29
|
-
fetch(urlStr: string, ...ctx: any[]): Promise<Response
|
|
30
|
-
fetch(urlStr: string, init: RequestInit, ...ctx: any[]): Promise<Response
|
|
31
|
-
fetch(url: URL, ...ctx: any[]): Promise<Response
|
|
32
|
-
fetch(url: URL, init: RequestInit, ...ctx: any[]): Promise<Response
|
|
20
|
+
fetch(request: Request, ...ctx: any[]): Promise<Response> | Response;
|
|
21
|
+
fetch(urlStr: string, ...ctx: any[]): Promise<Response> | Response;
|
|
22
|
+
fetch(urlStr: string, init: RequestInit, ...ctx: any[]): Promise<Response> | Response;
|
|
23
|
+
fetch(url: URL, ...ctx: any[]): Promise<Response> | Response;
|
|
24
|
+
fetch(url: URL, init: RequestInit, ...ctx: any[]): Promise<Response> | Response;
|
|
33
25
|
/**
|
|
34
26
|
* This function takes Node's request object and returns a WHATWG Fetch spec compliant `Response` object.
|
|
35
27
|
**/
|
|
36
|
-
handleNodeRequest(nodeRequest: NodeRequest, serverContext: TServerContext): Promise<Response
|
|
28
|
+
handleNodeRequest(nodeRequest: NodeRequest, serverContext: TServerContext): Promise<Response> | Response;
|
|
37
29
|
/**
|
|
38
30
|
* A request listener function that can be used with any Node server variation.
|
|
39
31
|
*/
|
|
@@ -41,11 +33,15 @@ export interface ServerAdapterObject<TServerContext> extends EventListenerObject
|
|
|
41
33
|
/**
|
|
42
34
|
* Proxy to requestListener to mimic Node middlewares
|
|
43
35
|
*/
|
|
44
|
-
handle: RequestListener;
|
|
36
|
+
handle: RequestListener & ServerAdapterObject<TServerContext, TBaseObject>['fetch'];
|
|
45
37
|
}
|
|
46
|
-
export declare type ServerAdapter<TServerContext, TBaseObject
|
|
47
|
-
|
|
38
|
+
export declare type ServerAdapter<TServerContext, THandleRequest extends HandleRequestFn<TServerContext>, TBaseObject extends ServerAdapterBaseObject<TServerContext, THandleRequest>> = Omit<TBaseObject, 'handle'> & RequestListener & ServerAdapterObject<TServerContext, TBaseObject>['fetch'] & ServerAdapterObject<TServerContext, TBaseObject>;
|
|
39
|
+
declare type HandleRequestFn<TServerContext> = (request: Request, serverContext: TServerContext) => Promise<Response> | Response;
|
|
40
|
+
declare type DefaultServerContext = {
|
|
48
41
|
req: NodeRequest;
|
|
49
42
|
res: ServerResponse;
|
|
50
43
|
waitUntil(promise: Promise<unknown>): void;
|
|
51
|
-
}
|
|
44
|
+
};
|
|
45
|
+
declare function createServerAdapter<TServerContext = DefaultServerContext, THandleRequest extends HandleRequestFn<TServerContext> = HandleRequestFn<TServerContext>>(serverAdapterBaseObject: THandleRequest): ServerAdapter<TServerContext, THandleRequest, ServerAdapterBaseObject<TServerContext, THandleRequest>>;
|
|
46
|
+
declare function createServerAdapter<TServerContext = DefaultServerContext, THandleRequest extends HandleRequestFn<TServerContext> = HandleRequestFn<TServerContext>, TBaseObject extends ServerAdapterBaseObject<TServerContext, THandleRequest> = ServerAdapterBaseObject<TServerContext, THandleRequest>>(serverAdapterBaseObject: TBaseObject): ServerAdapter<TServerContext, THandleRequest, TBaseObject>;
|
|
47
|
+
export { createServerAdapter };
|
package/index.js
CHANGED
|
@@ -156,14 +156,20 @@ async function sendNodeResponse({ headers, status, statusText, body }, serverRes
|
|
|
156
156
|
}
|
|
157
157
|
|
|
158
158
|
/// <reference lib="webworker" />
|
|
159
|
-
function handleWaitUntils(waitUntilPromises) {
|
|
160
|
-
|
|
159
|
+
async function handleWaitUntils(waitUntilPromises) {
|
|
160
|
+
const waitUntils = await Promise.allSettled(waitUntilPromises);
|
|
161
|
+
waitUntils.forEach(waitUntil => {
|
|
161
162
|
if (waitUntil.status === 'rejected') {
|
|
162
163
|
console.error(waitUntil.reason);
|
|
163
164
|
}
|
|
164
|
-
})
|
|
165
|
+
});
|
|
165
166
|
}
|
|
166
|
-
function createServerAdapter(
|
|
167
|
+
function createServerAdapter(serverAdapterBaseObject,
|
|
168
|
+
/**
|
|
169
|
+
* WHATWG Fetch spec compliant `Request` constructor.
|
|
170
|
+
*/
|
|
171
|
+
RequestCtor = fetch.Request) {
|
|
172
|
+
const handleRequest = typeof serverAdapterBaseObject === 'function' ? serverAdapterBaseObject : serverAdapterBaseObject.handle;
|
|
167
173
|
function fetchFn(input, init, ...ctx) {
|
|
168
174
|
if (typeof input === 'string' || input instanceof URL) {
|
|
169
175
|
return handleRequest(new RequestCtor(input, init), Object.assign({}, ...ctx));
|
|
@@ -192,7 +198,9 @@ function createServerAdapter({ Request: RequestCtor = fetch.Request, handleReque
|
|
|
192
198
|
serverResponse.end(resolve);
|
|
193
199
|
});
|
|
194
200
|
}
|
|
195
|
-
|
|
201
|
+
if (waitUntilPromises.length > 0) {
|
|
202
|
+
await handleWaitUntils(waitUntilPromises);
|
|
203
|
+
}
|
|
196
204
|
}
|
|
197
205
|
function handleEvent(event) {
|
|
198
206
|
if (!event.respondWith || !event.request) {
|
|
@@ -201,14 +209,6 @@ function createServerAdapter({ Request: RequestCtor = fetch.Request, handleReque
|
|
|
201
209
|
const response$ = handleRequest(event.request, event);
|
|
202
210
|
event.respondWith(response$);
|
|
203
211
|
}
|
|
204
|
-
const adapterObj = {
|
|
205
|
-
handleRequest,
|
|
206
|
-
fetch: fetchFn,
|
|
207
|
-
handleNodeRequest,
|
|
208
|
-
requestListener,
|
|
209
|
-
handleEvent,
|
|
210
|
-
handle: requestListener,
|
|
211
|
-
};
|
|
212
212
|
function genericRequestHandler(input, ctx, ...rest) {
|
|
213
213
|
var _a;
|
|
214
214
|
if ('process' in globalThis && ((_a = process.versions) === null || _a === void 0 ? void 0 : _a['bun']) != null) {
|
|
@@ -250,20 +250,20 @@ function createServerAdapter({ Request: RequestCtor = fetch.Request, handleReque
|
|
|
250
250
|
}
|
|
251
251
|
return handleRequest(input, ctx);
|
|
252
252
|
}
|
|
253
|
+
const adapterObj = {
|
|
254
|
+
handleRequest,
|
|
255
|
+
fetch: fetchFn,
|
|
256
|
+
handleNodeRequest,
|
|
257
|
+
requestListener,
|
|
258
|
+
handleEvent,
|
|
259
|
+
handle: genericRequestHandler,
|
|
260
|
+
};
|
|
253
261
|
return new Proxy(genericRequestHandler, {
|
|
254
262
|
// It should have all the attributes of the handler function and the server instance
|
|
255
263
|
has: (_, prop) => {
|
|
256
|
-
return
|
|
264
|
+
return prop in adapterObj || prop in genericRequestHandler || (serverAdapterBaseObject && prop in serverAdapterBaseObject);
|
|
257
265
|
},
|
|
258
266
|
get: (_, prop) => {
|
|
259
|
-
if (baseObject) {
|
|
260
|
-
if (prop in baseObject) {
|
|
261
|
-
if (baseObject[prop].bind) {
|
|
262
|
-
return baseObject[prop].bind(baseObject);
|
|
263
|
-
}
|
|
264
|
-
return baseObject[prop];
|
|
265
|
-
}
|
|
266
|
-
}
|
|
267
267
|
if (adapterObj[prop]) {
|
|
268
268
|
if (adapterObj[prop].bind) {
|
|
269
269
|
return adapterObj[prop].bind(adapterObj);
|
|
@@ -276,6 +276,12 @@ function createServerAdapter({ Request: RequestCtor = fetch.Request, handleReque
|
|
|
276
276
|
}
|
|
277
277
|
return genericRequestHandler[prop];
|
|
278
278
|
}
|
|
279
|
+
if (prop in serverAdapterBaseObject) {
|
|
280
|
+
if (serverAdapterBaseObject[prop].bind) {
|
|
281
|
+
return serverAdapterBaseObject[prop].bind(serverAdapterBaseObject);
|
|
282
|
+
}
|
|
283
|
+
return serverAdapterBaseObject[prop];
|
|
284
|
+
}
|
|
279
285
|
},
|
|
280
286
|
apply(_, __, [input, ctx]) {
|
|
281
287
|
return genericRequestHandler(input, ctx);
|
package/index.mjs
CHANGED
|
@@ -152,14 +152,20 @@ async function sendNodeResponse({ headers, status, statusText, body }, serverRes
|
|
|
152
152
|
}
|
|
153
153
|
|
|
154
154
|
/// <reference lib="webworker" />
|
|
155
|
-
function handleWaitUntils(waitUntilPromises) {
|
|
156
|
-
|
|
155
|
+
async function handleWaitUntils(waitUntilPromises) {
|
|
156
|
+
const waitUntils = await Promise.allSettled(waitUntilPromises);
|
|
157
|
+
waitUntils.forEach(waitUntil => {
|
|
157
158
|
if (waitUntil.status === 'rejected') {
|
|
158
159
|
console.error(waitUntil.reason);
|
|
159
160
|
}
|
|
160
|
-
})
|
|
161
|
+
});
|
|
161
162
|
}
|
|
162
|
-
function createServerAdapter(
|
|
163
|
+
function createServerAdapter(serverAdapterBaseObject,
|
|
164
|
+
/**
|
|
165
|
+
* WHATWG Fetch spec compliant `Request` constructor.
|
|
166
|
+
*/
|
|
167
|
+
RequestCtor = Request) {
|
|
168
|
+
const handleRequest = typeof serverAdapterBaseObject === 'function' ? serverAdapterBaseObject : serverAdapterBaseObject.handle;
|
|
163
169
|
function fetchFn(input, init, ...ctx) {
|
|
164
170
|
if (typeof input === 'string' || input instanceof URL) {
|
|
165
171
|
return handleRequest(new RequestCtor(input, init), Object.assign({}, ...ctx));
|
|
@@ -188,7 +194,9 @@ function createServerAdapter({ Request: RequestCtor = Request, handleRequest, ba
|
|
|
188
194
|
serverResponse.end(resolve);
|
|
189
195
|
});
|
|
190
196
|
}
|
|
191
|
-
|
|
197
|
+
if (waitUntilPromises.length > 0) {
|
|
198
|
+
await handleWaitUntils(waitUntilPromises);
|
|
199
|
+
}
|
|
192
200
|
}
|
|
193
201
|
function handleEvent(event) {
|
|
194
202
|
if (!event.respondWith || !event.request) {
|
|
@@ -197,14 +205,6 @@ function createServerAdapter({ Request: RequestCtor = Request, handleRequest, ba
|
|
|
197
205
|
const response$ = handleRequest(event.request, event);
|
|
198
206
|
event.respondWith(response$);
|
|
199
207
|
}
|
|
200
|
-
const adapterObj = {
|
|
201
|
-
handleRequest,
|
|
202
|
-
fetch: fetchFn,
|
|
203
|
-
handleNodeRequest,
|
|
204
|
-
requestListener,
|
|
205
|
-
handleEvent,
|
|
206
|
-
handle: requestListener,
|
|
207
|
-
};
|
|
208
208
|
function genericRequestHandler(input, ctx, ...rest) {
|
|
209
209
|
var _a;
|
|
210
210
|
if ('process' in globalThis && ((_a = process.versions) === null || _a === void 0 ? void 0 : _a['bun']) != null) {
|
|
@@ -246,20 +246,20 @@ function createServerAdapter({ Request: RequestCtor = Request, handleRequest, ba
|
|
|
246
246
|
}
|
|
247
247
|
return handleRequest(input, ctx);
|
|
248
248
|
}
|
|
249
|
+
const adapterObj = {
|
|
250
|
+
handleRequest,
|
|
251
|
+
fetch: fetchFn,
|
|
252
|
+
handleNodeRequest,
|
|
253
|
+
requestListener,
|
|
254
|
+
handleEvent,
|
|
255
|
+
handle: genericRequestHandler,
|
|
256
|
+
};
|
|
249
257
|
return new Proxy(genericRequestHandler, {
|
|
250
258
|
// It should have all the attributes of the handler function and the server instance
|
|
251
259
|
has: (_, prop) => {
|
|
252
|
-
return
|
|
260
|
+
return prop in adapterObj || prop in genericRequestHandler || (serverAdapterBaseObject && prop in serverAdapterBaseObject);
|
|
253
261
|
},
|
|
254
262
|
get: (_, prop) => {
|
|
255
|
-
if (baseObject) {
|
|
256
|
-
if (prop in baseObject) {
|
|
257
|
-
if (baseObject[prop].bind) {
|
|
258
|
-
return baseObject[prop].bind(baseObject);
|
|
259
|
-
}
|
|
260
|
-
return baseObject[prop];
|
|
261
|
-
}
|
|
262
|
-
}
|
|
263
263
|
if (adapterObj[prop]) {
|
|
264
264
|
if (adapterObj[prop].bind) {
|
|
265
265
|
return adapterObj[prop].bind(adapterObj);
|
|
@@ -272,6 +272,12 @@ function createServerAdapter({ Request: RequestCtor = Request, handleRequest, ba
|
|
|
272
272
|
}
|
|
273
273
|
return genericRequestHandler[prop];
|
|
274
274
|
}
|
|
275
|
+
if (prop in serverAdapterBaseObject) {
|
|
276
|
+
if (serverAdapterBaseObject[prop].bind) {
|
|
277
|
+
return serverAdapterBaseObject[prop].bind(serverAdapterBaseObject);
|
|
278
|
+
}
|
|
279
|
+
return serverAdapterBaseObject[prop];
|
|
280
|
+
}
|
|
275
281
|
},
|
|
276
282
|
apply(_, __, [input, ctx]) {
|
|
277
283
|
return genericRequestHandler(input, ctx);
|