Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
[node] Add isomorphic functions (#9947)
This PR allow using Web APIs in Serverless functions ```js // api/serverless.js export const GET = () => { return new Response(`new Response('👋 Hello from Serverless Web!)`) } ``` More about that https://nextjs.org/docs/app/building-your-application/routing/router-handlers --------- Co-authored-by: Sean Massa <EndangeredMassa@gmail.com>
- Loading branch information
1 parent
49c7178
commit 0039c8b
Showing
12 changed files
with
226 additions
and
53 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,6 @@ | ||
--- | ||
"vercel": minor | ||
"@vercel/node": minor | ||
--- | ||
|
||
[node] Add isomorphic functions |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,76 @@ | ||
import type { ServerResponse, IncomingMessage } from 'http'; | ||
import type { NodeHandler } from '@edge-runtime/node-utils'; | ||
import { buildToNodeHandler } from '@edge-runtime/node-utils'; | ||
|
||
class FetchEvent { | ||
public request: Request; | ||
public awaiting: Set<Promise<void>>; | ||
public response: Response | null; | ||
|
||
constructor(request: Request) { | ||
this.request = request; | ||
this.response = null; | ||
this.awaiting = new Set(); | ||
} | ||
|
||
respondWith(response: Response) { | ||
this.response = response; | ||
} | ||
|
||
waitUntil() { | ||
throw new Error('waitUntil is not implemented yet for Node.js'); | ||
} | ||
} | ||
|
||
const webHandlerToNodeHandler = buildToNodeHandler( | ||
{ | ||
Headers, | ||
ReadableStream, | ||
Request: class extends Request { | ||
constructor(input: RequestInfo | URL, init?: RequestInit | undefined) { | ||
super(input, addDuplexToInit(init)); | ||
} | ||
}, | ||
Uint8Array: Uint8Array, | ||
FetchEvent: FetchEvent, | ||
}, | ||
{ defaultOrigin: 'https://vercel.com' } | ||
); | ||
|
||
/** | ||
* When users export at least one HTTP handler, we will generate | ||
* a generic handler routing to the right method. If there is no | ||
* handler function exported returns null. | ||
*/ | ||
export function getWebExportsHandler(listener: any, methods: string[]) { | ||
const handlerByMethod: { [key: string]: NodeHandler } = {}; | ||
|
||
for (const key of methods) { | ||
handlerByMethod[key] = | ||
typeof listener[key] !== 'undefined' | ||
? webHandlerToNodeHandler(listener[key]) | ||
: defaultHttpHandler; | ||
} | ||
|
||
return (req: IncomingMessage, res: ServerResponse) => { | ||
const method = req.method ?? 'GET'; | ||
handlerByMethod[method](req, res); | ||
}; | ||
} | ||
|
||
/** | ||
* Add `duplex: 'half'` by default to all requests | ||
* https://github.com/vercel/edge-runtime/blob/bf167c418247a79d3941bfce4a5d43c37f512502/packages/primitives/src/primitives/fetch.js#L22-L26 | ||
* https://developer.chrome.com/articles/fetch-streaming-requests/#streaming-request-bodies | ||
*/ | ||
function addDuplexToInit(init: RequestInit | undefined) { | ||
if (typeof init === 'undefined' || typeof init === 'object') { | ||
return { duplex: 'half', ...init }; | ||
} | ||
return init; | ||
} | ||
|
||
function defaultHttpHandler(_: IncomingMessage, res: ServerResponse) { | ||
res.statusCode = 405; | ||
res.end(); | ||
} |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,10 @@ | ||
/* global Response */ | ||
|
||
const baseUrl = ({ headers }) => | ||
`${headers.get('x-forwarded-proto')}://${headers.get('x-forwarded-host')}`; | ||
|
||
export function GET(request) { | ||
const { searchParams } = new URL(request.url, baseUrl(request)); | ||
const name = searchParams.get('name'); | ||
return new Response(`Greetings, ${name}`); | ||
} |
Oops, something went wrong.