forked from remix-run/remix
-
Notifications
You must be signed in to change notification settings - Fork 0
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
feat: add deno package (remix-run#1397)
fix: added history as a dep to @remix-run/react
- Loading branch information
1 parent
ff43654
commit bd823e9
Showing
19 changed files
with
486 additions
and
1 deletion.
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
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 @@ | ||
export { join } from "path"; |
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,193 @@ | ||
import { createRequestHandler as createRemixRequestHandler } from "@remix-run/server-runtime"; | ||
|
||
import { | ||
createRequestHandler, | ||
createRequestHandlerWithStaticFiles, | ||
serveStaticFiles | ||
} from "../server"; | ||
|
||
jest.mock("@remix-run/server-runtime/server"); | ||
let mockedCreateRequestHandler = | ||
createRemixRequestHandler as jest.MockedFunction< | ||
typeof createRemixRequestHandler | ||
>; | ||
|
||
describe("deno request handler", () => { | ||
let consoleSpy: jest.SpyInstance = jest | ||
.spyOn(global.console, "error") | ||
.mockImplementation(() => {}) as any; | ||
|
||
afterEach(() => { | ||
consoleSpy.mockReset(); | ||
mockedCreateRequestHandler.mockReset(); | ||
}); | ||
|
||
afterAll(() => { | ||
consoleSpy.mockRestore(); | ||
jest.restoreAllMocks(); | ||
}); | ||
|
||
it("handles requests", async () => { | ||
mockedCreateRequestHandler.mockImplementation(() => async req => { | ||
return new Response(`URL: ${new URL(req.url).pathname}`); | ||
}); | ||
let handler = createRequestHandler({ | ||
build: undefined | ||
}); | ||
|
||
let response = await handler(new Request("http://test.com/foo/bar")); | ||
expect(response.status).toBe(200); | ||
expect(await response.text()).toBe("URL: /foo/bar"); | ||
}); | ||
|
||
it("handles errors", async () => { | ||
let error = new Error("test error"); | ||
mockedCreateRequestHandler.mockImplementation(() => async req => { | ||
throw error; | ||
}); | ||
let handler = createRequestHandler({ | ||
build: undefined | ||
}); | ||
|
||
let response = await handler(new Request("http://test.com/foo/bar")); | ||
expect(response.status).toBe(500); | ||
expect(await response.text()).toBe("Internal Error"); | ||
|
||
expect(consoleSpy).toHaveBeenCalledWith(error); | ||
}); | ||
|
||
it("passes request context", async () => { | ||
let loadContext; | ||
mockedCreateRequestHandler.mockImplementation(() => async (req, ctx) => { | ||
loadContext = ctx; | ||
return new Response(`URL: ${new URL(req.url).pathname}`); | ||
}); | ||
let context = {}; | ||
let handler = createRequestHandler({ | ||
build: undefined, | ||
getLoadContext: async () => context | ||
}); | ||
|
||
let response = await handler(new Request("http://test.com/foo/bar")); | ||
expect(loadContext).toBe(context); | ||
expect(response.status).toBe(200); | ||
expect(await response.text()).toBe("URL: /foo/bar"); | ||
}); | ||
}); | ||
|
||
describe("deno static files", () => { | ||
let options = { | ||
publicDir: "./public", | ||
assetsPublicPath: "/build/" | ||
}; | ||
|
||
it("throws when no file", async () => { | ||
let error = new Error("test error"); | ||
global.Deno.readFile.mockImplementation(() => { | ||
throw error; | ||
}); | ||
|
||
let request = new Request("http://test.com/foo/bar"); | ||
await expect(() => serveStaticFiles(request, options)).rejects.toThrow( | ||
error | ||
); | ||
}); | ||
|
||
it("reads file and applies long cache control", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
return "file content"; | ||
}); | ||
|
||
let request = new Request("http://test.com/build/bar.css"); | ||
let response = await serveStaticFiles(request, options); | ||
expect(response.status).toBe(200); | ||
expect(response.headers.get("Content-Type")).toBe("text/css"); | ||
expect(response.headers.get("Cache-Control")).toBe( | ||
"public, max-age=31536000, immutable" | ||
); | ||
expect(await response.text()).toBe("file content"); | ||
}); | ||
|
||
it("reads file and applies short cache control", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
return "file content"; | ||
}); | ||
|
||
let request = new Request("http://test.com/test/bar.css"); | ||
let response = await serveStaticFiles(request, options); | ||
expect(response.status).toBe(200); | ||
expect(response.headers.get("Content-Type")).toBe("text/css"); | ||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=600"); | ||
expect(await response.text()).toBe("file content"); | ||
}); | ||
|
||
it("reads file and applies custom cache control string", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
return "file content"; | ||
}); | ||
|
||
let request = new Request("http://test.com/test/bar.css"); | ||
let response = await serveStaticFiles(request, { | ||
cacheControl: "public, max-age=1" | ||
}); | ||
expect(response.status).toBe(200); | ||
expect(response.headers.get("Content-Type")).toBe("text/css"); | ||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=1"); | ||
expect(await response.text()).toBe("file content"); | ||
}); | ||
|
||
it("reads file and applies custom cache control function", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
return "file content"; | ||
}); | ||
|
||
let request = new Request("http://test.com/test/bar.css"); | ||
let response = await serveStaticFiles(request, { | ||
cacheControl: () => "public, max-age=2" | ||
}); | ||
expect(response.status).toBe(200); | ||
expect(response.headers.get("Content-Type")).toBe("text/css"); | ||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=2"); | ||
expect(await response.text()).toBe("file content"); | ||
}); | ||
}); | ||
|
||
describe("deno combined request handler", () => { | ||
it("handles requests", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
let error = new Error("test error"); | ||
(error as any).code = "ENOENT"; | ||
throw error; | ||
}); | ||
|
||
mockedCreateRequestHandler.mockImplementation(() => async req => { | ||
return new Response(`URL: ${new URL(req.url).pathname}`); | ||
}); | ||
let handler = createRequestHandlerWithStaticFiles({ | ||
build: undefined | ||
}); | ||
|
||
let response = await handler(new Request("http://test.com/foo/bar")); | ||
expect(response.status).toBe(200); | ||
expect(await response.text()).toBe("URL: /foo/bar"); | ||
}); | ||
|
||
it("handles static assets", async () => { | ||
global.Deno.readFile.mockImplementation(() => { | ||
return "file content"; | ||
}); | ||
|
||
mockedCreateRequestHandler.mockImplementation(() => async req => { | ||
return new Response(`URL: ${new URL(req.url).pathname}`); | ||
}); | ||
let handler = createRequestHandlerWithStaticFiles({ | ||
build: undefined | ||
}); | ||
|
||
let response = await handler(new Request("http://test.com/foo/bar.css")); | ||
expect(response.status).toBe(200); | ||
expect(response.headers.get("Content-Type")).toBe("text/css"); | ||
expect(response.headers.get("Cache-Control")).toBe("public, max-age=600"); | ||
expect(await response.text()).toBe("file content"); | ||
}); | ||
}); |
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 @@ | ||
global.Deno = { | ||
readFile: jest.fn() | ||
}; | ||
|
||
global.window = {}; |
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,52 @@ | ||
const encoder = new TextEncoder(); | ||
|
||
export async function sign(value: string, secret: string): Promise<string> { | ||
let key = await crypto.subtle.importKey( | ||
"raw", | ||
encoder.encode(secret), | ||
{ name: "HMAC", hash: "SHA-256" }, | ||
false, | ||
["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 async function unsign( | ||
cookie: string, | ||
secret: string | ||
): Promise<string | false> { | ||
let key = await crypto.subtle.importKey( | ||
"raw", | ||
encoder.encode(secret), | ||
{ name: "HMAC", hash: "SHA-256" }, | ||
false, | ||
["verify"] | ||
); | ||
|
||
let value = cookie.slice(0, cookie.lastIndexOf(".")); | ||
let hash = cookie.slice(cookie.lastIndexOf(".") + 1); | ||
|
||
let data = encoder.encode(value); | ||
let signature = byteStringToUint8Array(atob(hash)); | ||
let valid = await crypto.subtle.verify("HMAC", key, signature, data); | ||
|
||
return valid ? value : false; | ||
} | ||
|
||
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,6 @@ | ||
import { sign, unsign } from "./cookieSigning"; | ||
|
||
export function installGlobals() { | ||
window.sign = sign; | ||
window.unsign = unsign; | ||
} |
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,9 @@ | ||
import { installGlobals } from "./globals"; | ||
|
||
export { | ||
createRequestHandler, | ||
createRequestHandlerWithStaticFiles, | ||
serveStaticFiles | ||
} from "./server"; | ||
|
||
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,21 @@ | ||
{ | ||
"name": "@remix-run/deno", | ||
"description": "Deno platform abstractions for Remix", | ||
"version": "1.1.3", | ||
"license": "MIT", | ||
"module": "./index.js", | ||
"types": "./index.d.ts", | ||
"repository": { | ||
"type": "git", | ||
"url": "https://github.com/remix-run/remix", | ||
"directory": "packages/remix-deno" | ||
}, | ||
"bugs": { | ||
"url": "https://github.com/remix-run/remix/issues" | ||
}, | ||
"dependencies": { | ||
"@remix-run/server-runtime": "1.1.3", | ||
"mime": "^3.0.0" | ||
}, | ||
"sideEffects": false | ||
} |
Oops, something went wrong.