Skip to content

Commit

Permalink
Merge pull request #482 from honojs/v4.6
Browse files Browse the repository at this point in the history
v4.6
  • Loading branch information
yusukebe authored Sep 11, 2024
2 parents d223aca + 6934488 commit 2977458
Show file tree
Hide file tree
Showing 11 changed files with 217 additions and 2 deletions.
1 change: 1 addition & 0 deletions .vitepress/config.ts
Original file line number Diff line number Diff line change
Expand Up @@ -155,6 +155,7 @@ const sidebars = (): DefaultTheme.SidebarItem[] => [
{ text: 'Cache', link: '/docs/middleware/builtin/cache' },
{ text: 'Combine', link: '/docs/middleware/builtin/combine' },
{ text: 'Compress', link: '/docs/middleware/builtin/compress' },
{ text: 'Context Storage', link: '/docs/middleware/builtin/context-storage' },
{ text: 'CORS', link: '/docs/middleware/builtin/cors' },
{
text: 'CSRF Protection',
Expand Down
29 changes: 29 additions & 0 deletions docs/getting-started/bun.md
Original file line number Diff line number Diff line change
Expand Up @@ -135,6 +135,22 @@ app.get(
)
```

### `onFound`

You can specify handling when the requested file is found with `onFound`:

```ts
app.get(
'/static/*',
serveStatic({
// ...
onFound: (_path, c) => {
c.header('Cache-Control', `public, immutable, max-age=31536000`)
},
})
)
```

### `onNotFound`

You can specify handling when the requested file is not found with `onNotFound`:
Expand All @@ -150,6 +166,19 @@ app.get(
)
```

### `precompressed`

The `precompressed` option checks if files with extensions like `.br` or `.gz` are available and serves them based on the `Accept-Encoding` header. It prioritizes Brotli, then Zstd, and Gzip. If none are available, it serves the original file.

```ts
app.get(
'/static/*',
serveStatic({
precompressed: true,
})
)
```

## Testing

You can use `bun:test` for testing on Bun.
Expand Down
42 changes: 42 additions & 0 deletions docs/getting-started/cloudflare-pages.md
Original file line number Diff line number Diff line change
Expand Up @@ -361,3 +361,45 @@ export const onRequest = [
handleMiddleware(middleware3),
]
```

### Accessing `EventContext`

You can access [`EventContext`](https://developers.cloudflare.com/pages/functions/api-reference/#eventcontext) object via `c.env` in `handleMiddleware`.

```ts
// functions/_middleware.ts
import { handleMiddleware } from 'hono/cloudflare-pages'

export const onRequest = [
handleMiddleware(async (c, next) => {
c.env.eventContext.data.user = 'Joe'
await next()
}),
]
```

Then, you can access the data value in via `c.env.eventContext` in the handler:

```ts
// functions/api/[[route]].ts
import type { EventContext } from 'hono/cloudflare-pages'
import { handle } from 'hono/cloudflare-pages'

// ...

type Env = {
Bindings: {
eventContext: EventContext
}
}

const app = new Hono<Env>()

app.get('/hello', (c) => {
return c.json({
message: `Hello, ${c.env.eventContext.data.user}!`, // 'Joe'
})
})

export const onRequest = handle(app)
```
29 changes: 29 additions & 0 deletions docs/getting-started/deno.md
Original file line number Diff line number Diff line change
Expand Up @@ -122,6 +122,22 @@ app.get(
)
```

### `onFound`

You can specify handling when the requested file is found with `onFound`:

```ts
app.get(
'/static/*',
serveStatic({
// ...
onFound: (_path, c) => {
c.header('Cache-Control', `public, immutable, max-age=31536000`)
},
})
)
```

### `onNotFound`

You can specify handling when the requested file is not found with `onNotFound`:
Expand All @@ -137,6 +153,19 @@ app.get(
)
```

### `precompressed`

The `precompressed` option checks if files with extensions like `.br` or `.gz` are available and serves them based on the `Accept-Encoding` header. It prioritizes Brotli, then Zstd, and Gzip. If none are available, it serves the original file.

```ts
app.get(
'/static/*',
serveStatic({
precompressed: true,
})
)
```

## Deno Deploy

Deno Deploy is an edge runtime platform for Deno.
Expand Down
4 changes: 3 additions & 1 deletion docs/helpers/websocket.md
Original file line number Diff line number Diff line change
Expand Up @@ -20,8 +20,10 @@ import { upgradeWebSocket } from 'hono/deno'
```ts [Bun]
import { Hono } from 'hono'
import { createBunWebSocket } from 'hono/bun'
import type { ServerWebSocket } from 'bun'

const { upgradeWebSocket, websocket } = createBunWebSocket()
const { upgradeWebSocket, websocket } =
createBunWebSocket<ServerWebSocket>()

// ...

Expand Down
1 change: 1 addition & 0 deletions docs/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -159,6 +159,7 @@ Out of the box, Hono provides middleware and helpers for:
- [Body Limit](/docs/middleware/builtin/body-limit)
- [Cache](/docs/middleware/builtin/cache)
- [Compress](/docs/middleware/builtin/compress)
- [Context Storage](/docs/middleware/builtin/context-storage)
- [Cookie](/docs/helpers/cookie)
- [CORS](/docs/middleware/builtin/cors)
- [ETag](/docs/middleware/builtin/etag)
Expand Down
4 changes: 4 additions & 0 deletions docs/middleware/builtin/basic-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -87,6 +87,10 @@ A function to handle hashing for safe comparison of passwords.

The function to verify the user.

### <Badge type="info" text="optional" /> invalidUserMessage: `string | object | MessageFunction`

`MessageFunction` is `(c: Context) => string | object | Promise<string | object>`. The custom message if the user is invalid.

## More Options

### <Badge type="info" text="optional" /> ...users: `{ username: string, password: string }[]`
Expand Down
12 changes: 12 additions & 0 deletions docs/middleware/builtin/bearer-auth.md
Original file line number Diff line number Diff line change
Expand Up @@ -110,3 +110,15 @@ A function to handle hashing for safe comparison of authentication tokens.
### <Badge type="info" text="optional" /> verifyToken: `(token: string, c: Context) => boolean | Promise<boolean>`

The function to verify the token.

### <Badge type="info" text="optional" /> noAuthenticationHeaderMessage: `string | object | MessageFunction`

`MessageFunction` is `(c: Context) => string | object | Promise<string | object>`. The custom message if it does not have an authentication header.

### <Badge type="info" text="optional" /> invalidAuthenticationHeaderMessage: `string | object | MessageFunction`

The custom message if the authentication header is invalid.

### <Badge type="info" text="optional" /> invalidTokenMessage: `string | object | MessageFunction`

The custom message if the token is invalid.
64 changes: 64 additions & 0 deletions docs/middleware/builtin/context-storage.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,64 @@
# Context Storage Middleware

The Context Storage Middleware stores the Hono `Context` in the `AsyncLocalStorage`, to make it globally accessible.

::: info
**Note** This middleware uses `AsyncLocalStorage`. The runtime should support it.

**Cloudflare Workers**: To enable `AsyncLocalStorage`, add the [`nodejs_compat` or `nodejs_als` flag](https://developers.cloudflare.com/workers/configuration/compatibility-dates/#nodejs-compatibility-flag) to your `wrangler.toml` file.
:::

## Import

```ts
import { Hono } from 'hono'
import { contextStorage, getContext } from 'hono/context-storage'
```

## Usage

The `getContext()` will return the current Context object if the `contextStorage()` is applied as a middleware.

```ts
type Env = {
Variables: {
message: string
}
}

const app = new Hono<Env>()

app.use(contextStorage())

app.use(async (c, next) => {
c.set('message', 'Hello!')
await next()
})

// You can access the variable outside the handler.
const getMessage = () => {
return getContext<Env>().var.message
}

app.get('/', (c) => {
return c.text(getMessage())
})
```

On Cloudflare Workers, you can access the bindings outside the handler.

```ts
type Env = {
Bindings: {
KV: KVNamespace
}
}

const app = new Hono<Env>()

app.use(contextStorage())

const setKV = (value: string) => {
return getContext<Env>().env.KV.put('key', value)
}
```
3 changes: 2 additions & 1 deletion docs/middleware/builtin/jsx-renderer.md
Original file line number Diff line number Diff line change
Expand Up @@ -117,7 +117,8 @@ If `true` is set, the following headers are added:
```ts
{
'Transfer-Encoding': 'chunked',
'Content-Type': 'text/html; charset=UTF-8'
'Content-Type': 'text/html; charset=UTF-8',
'Content-Encoding': 'Identity'
}
```

Expand Down
30 changes: 30 additions & 0 deletions docs/middleware/builtin/secure-headers.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,7 @@ Each option corresponds to the following Header Key-Value pairs.
| xFrameOptions | [X-Frame-Options](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Frame-Options) | SAMEORIGIN | True |
| xPermittedCrossDomainPolicies | [X-Permitted-Cross-Domain-Policies](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-Permitted-Cross-Domain-Policies) | none | True |
| xXssProtection | [X-XSS-Protection](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/X-XSS-Protection) | 0 | True |
| permissionPolicy | [Permissions-Policy](https://developer.mozilla.org/en-US/docs/Web/HTTP/Headers/Permissions-Policy) | Usage: [Setting Permission-Policy](#setting-permission-policy) | No Setting |

## Middleware Conflict

Expand Down Expand Up @@ -211,3 +212,32 @@ app.get('/', (c) => {
)
})
```

## Setting Permission-Policy

The Permission-Policy header allows you to control which features and APIs can be used in the browser. Here's an example of how to set it:

```ts
const app = new Hono()
app.use(
'*',
secureHeaders({
permissionsPolicy: {
fullscreen: ['self'], // fullscreen=(self)
bluetooth: ['none'], // bluetooth=(none)
payment: ['self', 'https://example.com'], // payment=(self "https://example.com")
syncXhr: [], // sync-xhr=()
camera: false, // camera=none
microphone: true, // microphone=*
geolocation: ['*'], // geolocation=*
usb: ['self', 'https://a.example.com', 'https://b.example.com'], // usb=(self "https://a.example.com" "https://b.example.com")
accelerometer: ['https://*.example.com'], // accelerometer=("https://*.example.com")
gyroscope: ['src'], // gyroscope=(src)
magnetometer: [
'https://a.example.com',
'https://b.example.com',
], // magnetometer=("https://a.example.com" "https://b.example.com")
},
})
)
```

0 comments on commit 2977458

Please sign in to comment.