@whatwg-node/server 0.3.0 → 0.4.0-alpha-20220916163416-8c6abfa
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 +25 -26
- package/index.d.ts +18 -22
- package/index.js +30 -22
- package/index.mjs +30 -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
|
-
|
|
17
|
-
return new Response(`Hello World!`, { status: 200 })
|
|
18
|
-
}
|
|
15
|
+
export default createServerAdapter((request: Request) => {
|
|
16
|
+
return new Response(`Hello World!`, { status: 200 })
|
|
19
17
|
})
|
|
20
18
|
```
|
|
21
19
|
|
|
@@ -203,25 +201,22 @@ 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({
|
|
204
|
+
const myServerAdapter = createServerAdapter(async request => {
|
|
205
|
+
// Parse the request as `FormData`
|
|
206
|
+
const formData = await request.formData()
|
|
207
|
+
// Select the file
|
|
208
|
+
const file = formData.get('file')
|
|
209
|
+
// Process it as a string
|
|
210
|
+
const fileTextContent = await file.text()
|
|
211
|
+
// Select the other text parameter
|
|
212
|
+
const regularTextData = formData.get('additionalStuff')
|
|
207
213
|
// ...
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
214
|
-
const fileTextContent = await file.text()
|
|
215
|
-
// Select the other text parameter
|
|
216
|
-
const regularTextData = formData.get('additionalStuff')
|
|
217
|
-
// ...
|
|
218
|
-
return new Response('{ "message": "ok" }', {
|
|
219
|
-
status: 200,
|
|
220
|
-
headers: {
|
|
221
|
-
'Content-Type': 'application/json'
|
|
222
|
-
}
|
|
223
|
-
})
|
|
224
|
-
}
|
|
214
|
+
return new Response('{ "message": "ok" }', {
|
|
215
|
+
status: 200,
|
|
216
|
+
headers: {
|
|
217
|
+
'Content-Type': 'application/json'
|
|
218
|
+
}
|
|
219
|
+
})
|
|
225
220
|
})
|
|
226
221
|
```
|
|
227
222
|
|
|
@@ -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,22 @@ 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 ||
|
|
265
|
+
prop in genericRequestHandler ||
|
|
266
|
+
(serverAdapterBaseObject && prop in serverAdapterBaseObject));
|
|
257
267
|
},
|
|
258
268
|
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
269
|
if (adapterObj[prop]) {
|
|
268
270
|
if (adapterObj[prop].bind) {
|
|
269
271
|
return adapterObj[prop].bind(adapterObj);
|
|
@@ -276,6 +278,12 @@ function createServerAdapter({ Request: RequestCtor = fetch.Request, handleReque
|
|
|
276
278
|
}
|
|
277
279
|
return genericRequestHandler[prop];
|
|
278
280
|
}
|
|
281
|
+
if (prop in serverAdapterBaseObject) {
|
|
282
|
+
if (serverAdapterBaseObject[prop].bind) {
|
|
283
|
+
return serverAdapterBaseObject[prop].bind(serverAdapterBaseObject);
|
|
284
|
+
}
|
|
285
|
+
return serverAdapterBaseObject[prop];
|
|
286
|
+
}
|
|
279
287
|
},
|
|
280
288
|
apply(_, __, [input, ctx]) {
|
|
281
289
|
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,22 @@ 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 ||
|
|
261
|
+
prop in genericRequestHandler ||
|
|
262
|
+
(serverAdapterBaseObject && prop in serverAdapterBaseObject));
|
|
253
263
|
},
|
|
254
264
|
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
265
|
if (adapterObj[prop]) {
|
|
264
266
|
if (adapterObj[prop].bind) {
|
|
265
267
|
return adapterObj[prop].bind(adapterObj);
|
|
@@ -272,6 +274,12 @@ function createServerAdapter({ Request: RequestCtor = Request, handleRequest, ba
|
|
|
272
274
|
}
|
|
273
275
|
return genericRequestHandler[prop];
|
|
274
276
|
}
|
|
277
|
+
if (prop in serverAdapterBaseObject) {
|
|
278
|
+
if (serverAdapterBaseObject[prop].bind) {
|
|
279
|
+
return serverAdapterBaseObject[prop].bind(serverAdapterBaseObject);
|
|
280
|
+
}
|
|
281
|
+
return serverAdapterBaseObject[prop];
|
|
282
|
+
}
|
|
275
283
|
},
|
|
276
284
|
apply(_, __, [input, ctx]) {
|
|
277
285
|
return genericRequestHandler(input, ctx);
|