forked from remix-run/remix
-
Notifications
You must be signed in to change notification settings - Fork 19
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
Add initial
@vercel/remix
package (#14)
- Loading branch information
1 parent
1c6c670
commit 9a16847
Showing
19 changed files
with
577 additions
and
8 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
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,13 @@ | ||
# Welcome to Remix! | ||
|
||
[Remix](https://remix.run) is a web framework that helps you build better websites with React. | ||
|
||
To get started, open a new shell and run: | ||
|
||
```sh | ||
npx create-remix@latest | ||
``` | ||
|
||
Then follow the prompts you see in your terminal. | ||
|
||
For more information about Remix, [visit remix.run](https://remix.run)! |
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,53 @@ | ||
import type { SignFunction, UnsignFunction } from "@remix-run/server-runtime"; | ||
|
||
const encoder = new TextEncoder(); | ||
|
||
export const sign: SignFunction = async (value, secret) => { | ||
let key = await createKey(secret, ["sign"]); | ||
let data = encoder.encode(value); | ||
let signature = await crypto.subtle.sign("HMAC", key, data); | ||
let hash = btoa(String.fromCharCode(...new Uint8Array(signature))).replace( | ||
/=+$/, | ||
"" | ||
); | ||
|
||
return value + "." + hash; | ||
}; | ||
|
||
export const unsign: UnsignFunction = async (signed, secret) => { | ||
let index = signed.lastIndexOf("."); | ||
let value = signed.slice(0, index); | ||
let hash = signed.slice(index + 1); | ||
|
||
let key = await createKey(secret, ["verify"]); | ||
let data = encoder.encode(value); | ||
let signature = byteStringToUint8Array(atob(hash)); | ||
let valid = await crypto.subtle.verify("HMAC", key, signature, data); | ||
|
||
return valid ? value : false; | ||
}; | ||
|
||
async function createKey( | ||
secret: string, | ||
usages: CryptoKey["usages"] | ||
): Promise<CryptoKey> { | ||
let key = await crypto.subtle.importKey( | ||
"raw", | ||
encoder.encode(secret), | ||
{ name: "HMAC", hash: "SHA-256" }, | ||
false, | ||
usages | ||
); | ||
|
||
return key; | ||
} | ||
|
||
function byteStringToUint8Array(byteString: string): Uint8Array { | ||
let array = new Uint8Array(byteString.length); | ||
|
||
for (let i = 0; i < byteString.length; i++) { | ||
array[i] = byteString.charCodeAt(i); | ||
} | ||
|
||
return array; | ||
} |
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,27 @@ | ||
import isbot from 'isbot'; | ||
import { renderToReadableStream } from 'react-dom/server'; | ||
|
||
export async function handleRequest( | ||
request: Request, | ||
responseStatusCode: number, | ||
responseHeaders: Headers, | ||
remixServer: JSX.Element | ||
) { | ||
let body = await renderToReadableStream(remixServer, { | ||
signal: request.signal, | ||
onError(error) { | ||
console.error(error); | ||
responseStatusCode = 500; | ||
}, | ||
}); | ||
|
||
if (isbot(request.headers.get('user-agent'))) { | ||
await body.allReady; | ||
} | ||
|
||
responseHeaders.set('Content-Type', 'text/html'); | ||
return new Response(body, { | ||
headers: responseHeaders, | ||
status: responseStatusCode, | ||
}); | ||
} |
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,13 @@ | ||
import { | ||
createCookieFactory, | ||
createCookieSessionStorageFactory, | ||
createSessionStorageFactory, | ||
} from "@remix-run/server-runtime"; | ||
|
||
import { sign, unsign } from "./crypto"; | ||
|
||
export const createCookie = createCookieFactory({ sign, unsign }); | ||
export const createCookieSessionStorage = | ||
createCookieSessionStorageFactory(createCookie); | ||
export const createSessionStorage = createSessionStorageFactory(createCookie); | ||
|
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,67 @@ | ||
export { | ||
createCookie, | ||
createCookieSessionStorage, | ||
createSessionStorage, | ||
} from './implementations'; | ||
|
||
export { | ||
createRequestHandler, | ||
createSession, | ||
defer, | ||
isCookie, | ||
isSession, | ||
json, | ||
MaxPartSizeExceededError, | ||
redirect, | ||
unstable_composeUploadHandlers, | ||
unstable_createMemoryUploadHandler, | ||
unstable_parseMultipartFormData, | ||
} from '@remix-run/server-runtime'; | ||
|
||
export type { | ||
ActionArgs, | ||
ActionFunction, | ||
AppData, | ||
AppLoadContext, | ||
Cookie, | ||
CookieOptions, | ||
CookieParseOptions, | ||
CookieSerializeOptions, | ||
CookieSignatureOptions, | ||
DataFunctionArgs, | ||
EntryContext, | ||
ErrorBoundaryComponent, | ||
HandleDataRequestFunction, | ||
HandleDocumentRequestFunction, | ||
HeadersFunction, | ||
HtmlLinkDescriptor, | ||
HtmlMetaDescriptor, | ||
V2_HtmlMetaDescriptor, | ||
JsonFunction, | ||
LinkDescriptor, | ||
LinksFunction, | ||
LoaderArgs, | ||
LoaderFunction, | ||
MemoryUploadHandlerFilterArgs, | ||
MemoryUploadHandlerOptions, | ||
MetaDescriptor, | ||
MetaFunction, | ||
V2_MetaFunction, | ||
PageLinkDescriptor, | ||
RequestHandler, | ||
RouteComponent, | ||
RouteHandle, | ||
SerializeFrom, | ||
ServerBuild, | ||
ServerEntryModule, | ||
Session, | ||
SessionData, | ||
SessionIdStorageStrategy, | ||
SessionStorage, | ||
SignFunction, | ||
TypedDeferredData, | ||
TypedResponse, | ||
UnsignFunction, | ||
UploadHandler, | ||
UploadHandlerPart, | ||
} from '@remix-run/server-runtime'; |
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,21 @@ | ||
import type { ServerBuild, AppLoadContext, RequestHandler } from "@remix-run/server-runtime"; | ||
import { createRequestHandler as createRemixRequestHandler } from "@remix-run/server-runtime"; | ||
|
||
export type GetLoadContextFunction = (req: Request) => AppLoadContext; | ||
|
||
export function createRequestHandler({ | ||
build, | ||
getLoadContext, | ||
mode, | ||
}: { | ||
build: ServerBuild; | ||
getLoadContext?: GetLoadContextFunction; | ||
mode?: string; | ||
}): RequestHandler { | ||
let handleRequest = createRemixRequestHandler(build, mode); | ||
|
||
return (request) => { | ||
let loadContext = getLoadContext?.(request); | ||
return handleRequest(request, loadContext); | ||
}; | ||
} |
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,81 @@ | ||
import { PassThrough } from 'stream'; | ||
import { renderToPipeableStream } from 'react-dom/server'; | ||
import { Response } from '@remix-run/node'; | ||
import isbot from 'isbot'; | ||
|
||
const ABORT_DELAY = 5000; | ||
|
||
export function handleRequest( | ||
request: Request, | ||
responseStatusCode: number, | ||
responseHeaders: Headers, | ||
remixServer: JSX.Element | ||
) { | ||
// If the request is from a bot, we want to wait for the full | ||
// response to render before sending it to the client. This | ||
// ensures that bots can see the full page content. | ||
if (isbot(request.headers.get('user-agent'))) { | ||
return serveTheBots(responseStatusCode, responseHeaders, remixServer); | ||
} | ||
|
||
return serveBrowsers(responseStatusCode, responseHeaders, remixServer); | ||
} | ||
|
||
function serveTheBots( | ||
responseStatusCode: number, | ||
responseHeaders: Headers, | ||
remixServer: JSX.Element | ||
) { | ||
return new Promise((resolve, reject) => { | ||
let { pipe, abort } = renderToPipeableStream(remixServer, { | ||
// Use onAllReady to wait for the entire document to be ready | ||
onAllReady() { | ||
responseHeaders.set('Content-Type', 'text/html'); | ||
let body = new PassThrough(); | ||
pipe(body); | ||
resolve( | ||
new Response(body, { | ||
status: responseStatusCode, | ||
headers: responseHeaders, | ||
}) | ||
); | ||
}, | ||
onShellError(err) { | ||
reject(err); | ||
}, | ||
}); | ||
setTimeout(abort, ABORT_DELAY); | ||
}); | ||
} | ||
|
||
function serveBrowsers( | ||
responseStatusCode: number, | ||
responseHeaders: Headers, | ||
remixServer: JSX.Element | ||
) { | ||
return new Promise((resolve, reject) => { | ||
let didError = false; | ||
let { pipe, abort } = renderToPipeableStream(remixServer, { | ||
// use onShellReady to wait until a suspense boundary is triggered | ||
onShellReady() { | ||
responseHeaders.set('Content-Type', 'text/html'); | ||
let body = new PassThrough(); | ||
pipe(body); | ||
resolve( | ||
new Response(body, { | ||
status: didError ? 500 : responseStatusCode, | ||
headers: responseHeaders, | ||
}) | ||
); | ||
}, | ||
onShellError(err) { | ||
reject(err); | ||
}, | ||
onError(err) { | ||
didError = true; | ||
console.error(err); | ||
}, | ||
}); | ||
setTimeout(abort, ABORT_DELAY); | ||
}); | ||
} |
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,2 @@ | ||
import { installGlobals } from "@remix-run/node"; | ||
installGlobals(); |
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,67 @@ | ||
export { | ||
createCookie, | ||
createCookieSessionStorage, | ||
createSessionStorage, | ||
} from "@remix-run/node"; | ||
|
||
export { | ||
createRequestHandler, | ||
createSession, | ||
defer, | ||
isCookie, | ||
isSession, | ||
json, | ||
MaxPartSizeExceededError, | ||
redirect, | ||
unstable_composeUploadHandlers, | ||
unstable_createMemoryUploadHandler, | ||
unstable_parseMultipartFormData, | ||
} from "@remix-run/server-runtime"; | ||
|
||
export type { | ||
ActionArgs, | ||
ActionFunction, | ||
AppData, | ||
AppLoadContext, | ||
Cookie, | ||
CookieOptions, | ||
CookieParseOptions, | ||
CookieSerializeOptions, | ||
CookieSignatureOptions, | ||
DataFunctionArgs, | ||
EntryContext, | ||
ErrorBoundaryComponent, | ||
HandleDataRequestFunction, | ||
HandleDocumentRequestFunction, | ||
HeadersFunction, | ||
HtmlLinkDescriptor, | ||
HtmlMetaDescriptor, | ||
V2_HtmlMetaDescriptor, | ||
JsonFunction, | ||
LinkDescriptor, | ||
LinksFunction, | ||
LoaderArgs, | ||
LoaderFunction, | ||
MemoryUploadHandlerFilterArgs, | ||
MemoryUploadHandlerOptions, | ||
MetaDescriptor, | ||
MetaFunction, | ||
V2_MetaFunction, | ||
PageLinkDescriptor, | ||
RequestHandler, | ||
RouteComponent, | ||
RouteHandle, | ||
SerializeFrom, | ||
ServerBuild, | ||
ServerEntryModule, | ||
Session, | ||
SessionData, | ||
SessionIdStorageStrategy, | ||
SessionStorage, | ||
SignFunction, | ||
TypedDeferredData, | ||
TypedResponse, | ||
UnsignFunction, | ||
UploadHandler, | ||
UploadHandlerPart, | ||
} from "@remix-run/server-runtime"; |
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,5 @@ | ||
/** @type {import('@jest/types').Config.InitialOptions} */ | ||
module.exports = { | ||
...require("../../jest/jest.config.shared"), | ||
displayName: "vercel", | ||
}; |
Oops, something went wrong.