chore: add coverage badges (#1023)

* chore: add coverage badges

* ci(casbin): fix spelling
pull/1025/head
Jonathan Haines 2025-03-19 19:53:11 +11:00 committed by GitHub
parent 6c8ba4cdcd
commit 783a082c12
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
37 changed files with 402 additions and 299 deletions

View File

@ -1,13 +1,13 @@
name: ci-cabin
name: ci-casbin
on:
push:
branches: [main]
paths:
- 'packages/cabin/**'
- 'packages/casbin/**'
pull_request:
branches: ['*']
paths:
- 'packages/cabin/**'
- 'packages/casbin/**'
jobs:
ci:
@ -17,13 +17,13 @@ jobs:
- uses: actions/setup-node@v4
with:
node-version: 20.x
- run: yarn workspaces focus hono-middleware @hono/ci-cabin
- run: yarn workspace @hono/ci-cabin build
- run: yarn test --coverage --project @hono/ci-cabin
- run: yarn workspaces focus hono-middleware @hono/casbin
- run: yarn workspace @hono/casbin build
- run: yarn test --coverage --project @hono/casbin
- uses: codecov/codecov-action@v5
with:
fail_ci_if_error: true
directory: ./coverage
flags: ci-cabin
flags: casbin
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@ -1,23 +0,0 @@
name: initial-coverage
on:
push:
branches: [main]
pull_request:
branches: ['*']
jobs:
ci:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20.x
- run: yarn install
- run: yarn vitest --coverage
- uses: codecov/codecov-action@v5
with:
fail_ci_if_error: true
directory: ./coverage
env:
CODECOV_TOKEN: ${{ secrets.CODECOV_TOKEN }}

View File

@ -1,5 +1,7 @@
# Ajv validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=ajv-validator)](https://codecov.io/github/honojs/middleware)
Validator middleware using [Ajv](https://github.com/ajv-validator/ajv) for [Hono](https://honojs.dev) applications.
Define your schema with Ajv and validate incoming requests.
@ -8,9 +10,9 @@ Define your schema with Ajv and validate incoming requests.
No Hook:
```ts
import { type JSONSchemaType } from 'ajv';
import { ajvValidator } from '@hono/ajv-validator';
import { type JSONSchemaType } from 'ajv'
import { ajvValidator } from '@hono/ajv-validator'
const schema: JSONSchemaType<{ name: string; age: number }> = {
type: 'object',
properties: {
@ -19,19 +21,19 @@ const schema: JSONSchemaType<{ name: string; age: number }> = {
},
required: ['name', 'age'],
additionalProperties: false,
} as const;
} as const
const route = app.post('/user', ajvValidator('json', schema), (c) => {
const user = c.req.valid('json');
return c.json({ success: true, message: `${user.name} is ${user.age}` });
});
const user = c.req.valid('json')
return c.json({ success: true, message: `${user.name} is ${user.age}` })
})
```
Hook:
```ts
import { type JSONSchemaType } from 'ajv';
import { ajvValidator } from '@hono/ajv-validator';
import { type JSONSchemaType } from 'ajv'
import { ajvValidator } from '@hono/ajv-validator'
const schema: JSONSchemaType<{ name: string; age: number }> = {
type: 'object',
@ -41,17 +43,17 @@ const schema: JSONSchemaType<{ name: string; age: number }> = {
},
required: ['name', 'age'],
additionalProperties: false,
};
}
app.post(
'/user',
ajvValidator('json', schema, (result, c) => {
if (!result.success) {
return c.text('Invalid!', 400);
return c.text('Invalid!', 400)
}
})
//...
);
)
```
## Author

View File

@ -1,5 +1,7 @@
# ArkType validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=arktype-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [ArkType](https://arktype.io/) for [Hono](https://honojs.dev) applications.
You can write a schema with ArkType and validate the incoming values.
@ -11,7 +13,7 @@ import { arktypeValidator } from '@hono/arktype-validator'
const schema = type({
name: 'string',
age: 'number'
age: 'number',
})
app.post('/author', arktypeValidator('json', schema), (c) => {

View File

@ -1,5 +1,7 @@
# Auth.js middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=auth-js)](https://codecov.io/github/honojs/middleware)
This is a [Auth.js](https://authjs.dev) third-party middleware for [Hono](https://github.com/honojs/hono).
This middleware can be used to inject the Auth.js session into the request context.
@ -112,6 +114,7 @@ const useSession = () => {
return { session: data, status }
}
```
For more details on how to Popup Oauth Login see [example](https://github.com/divyam234/next-auth-hono-react)
## Author

View File

@ -1,5 +1,7 @@
# Bun Transpiler middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=bun-transpiler)](https://codecov.io/github/honojs/middleware)
The Bun Transpiler middleware is a Hono middleware designed to transpile content such as TypeScript or TSX. You can place your script written in TypeScript in a directory and serve it using `serveStatic`. When you apply this middleware, your script will automatically be served transpiled into JavaScript code.
This middleware works only with [Bun](https://bun.sh/).

View File

@ -1,5 +1,7 @@
# Casbin Middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=casbin)](https://codecov.io/github/honojs/middleware)
This is a third-party [Casbin](https://casbin.org) middleware for [Hono](https://github.com/honojs/hono).
This middleware can be used to enforce authorization policies defined using Casbin in your Hono routes.
@ -56,7 +58,8 @@ import { casbin } from '@hono/casbin'
import { basicAuthorizer } from '@hono/casbin/helper'
const app = new Hono()
app.use('*',
app.use(
'*',
basicAuth(
{
username: 'alice', // alice has full access to /dataset1/test
@ -69,7 +72,7 @@ app.use('*',
),
casbin({
newEnforcer: newEnforcer('examples/model.conf', 'examples/policy.csv'),
authorizer: basicAuthorizer
authorizer: basicAuthorizer,
})
)
app.get('/dataset1/test', (c) => c.text('dataset1 test')) // alice and bob can access /dataset1/test
@ -89,13 +92,14 @@ import { casbin } from '@hono/casbin'
import { jwtAuthorizer } from '@hono/casbin/helper'
const app = new Hono()
app.use('*',
app.use(
'*',
jwt({
secret: 'it-is-very-secret',
}),
casbin({
newEnforcer: newEnforcer('examples/model.conf', 'examples/policy.csv'),
authorizer: jwtAuthorizer
authorizer: jwtAuthorizer,
})
)
app.get('/dataset1/test', (c) => c.text('dataset1 test')) // alice and bob can access /dataset1/test
@ -112,7 +116,7 @@ const claimMapping = {
// ...
casbin({
newEnforcer: newEnforcer('examples/model.conf', 'examples/policy.csv'),
authorizer: (c, e) => jwtAuthorizer(c, e, claimMapping)
authorizer: (c, e) => jwtAuthorizer(c, e, claimMapping),
})
```
@ -126,13 +130,16 @@ import { newEnforcer } from 'casbin'
import { casbin } from '@hono/casbin'
const app = new Hono()
app.use('*', casbin({
newEnforcer: newEnforcer('path-to-your-model.conf', 'path-to-your-policy.csv'),
authorizer: async (c, enforcer) => {
const { user, path, method } = c
return await enforcer.enforce(user, path, method)
}
}))
app.use(
'*',
casbin({
newEnforcer: newEnforcer('path-to-your-model.conf', 'path-to-your-policy.csv'),
authorizer: async (c, enforcer) => {
const { user, path, method } = c
return await enforcer.enforce(user, path, method)
},
})
)
```
## Author

View File

@ -1,5 +1,7 @@
# Class-validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=class-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [class-validator](https://github.com/typestack/class-validator) for [Hono](https://github.com/honojs/hono) applications.
## Usage
@ -7,16 +9,15 @@ The validator middleware using [class-validator](https://github.com/typestack/cl
```ts
import { classValidator } from '@hono/class-validator'
import { IsInt, IsString } from 'class-validator'
class CreateUserDto {
@IsString()
name!: string;
name!: string
@IsInt()
age!: number;
age!: number
}
const route = app.post('/user', classValidator('json', CreateUserDto), (c) => {
const user = c.req.valid('json')
return c.json({ success: true, message: `${user.name} is ${user.age}` })
@ -31,17 +32,18 @@ import { IsInt, IsString } from 'class-validator'
class CreateUserDto {
@IsString()
name!: string;
name!: string
@IsInt()
age!: number;
@IsInt()
age!: number
}
app.post(
'/user', classValidator('json', CreateUserDto, (result, c) => {
'/user',
classValidator('json', CreateUserDto, (result, c) => {
if (!result.success) {
return c.text('Invalid!', 400)
}
}
})
//...
)
@ -53,4 +55,4 @@ app.post(
## License
MIT
MIT

View File

@ -1,5 +1,7 @@
# Clerk middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=clerk-auth)](https://codecov.io/github/honojs/middleware)
This is a [Clerk](https://clerk.com) third-party middleware for [Hono](https://github.com/honojs/hono).
This middleware can be used to inject the active Clerk session into the request context.
@ -33,13 +35,13 @@ app.get('/', (c) => {
if (!auth?.userId) {
return c.json({
message: 'You are not logged in.'
message: 'You are not logged in.',
})
}
return c.json({
message: 'You are logged in!',
userId: auth.userId
userId: auth.userId,
})
})
@ -65,9 +67,12 @@ app.get('/', async (c) => {
user,
})
} catch (e) {
return c.json({
message: 'User not found.'
}, 404)
return c.json(
{
message: 'User not found.',
},
404
)
}
})

View File

@ -1,5 +1,7 @@
# Cloudflare Access middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=cloudflare-access)](https://codecov.io/github/honojs/middleware)
This is a [Cloudflare Access](https://www.cloudflare.com/zero-trust/products/access/) third-party middleware
for [Hono](https://github.com/honojs/hono).
@ -48,7 +50,7 @@ export default app
## Errors throw by the middleware
| Error | HTTP Code |
|--------------------------------------------------------------------------------------------------------|-----------|
| ------------------------------------------------------------------------------------------------------ | --------- |
| Authentication error: Missing bearer token | 401 |
| Authentication error: Unable to decode Bearer token | 401 |
| Authentication error: Token is expired | 401 |

View File

@ -1,5 +1,7 @@
# Conform validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=conform-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [conform](https://conform.guide) for [Hono](https://honojs.dev) applications. This middleware allows you to validate submitted FormValue and making better use of [Hono RPC](https://hono.dev/docs/guides/rpc).
## Usage

View File

@ -1,5 +1,7 @@
# Effect Schema Validator Middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=effect-validator)](https://codecov.io/github/honojs/middleware)
This package provides a validator middleware using [Effect Schema](https://github.com/Effect-TS/effect/blob/main/packages/schema/README.md) for [Hono](https://honojs.dev) applications. With this middleware, you can define schemas using Effect Schema and validate incoming data in your Hono routes.
## Why Effect Schema?

View File

@ -1,5 +1,7 @@
# esbuild Transpiler Middleware
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=esbuild-transpiler)](https://codecov.io/github/honojs/middleware)
The **esbuild Transpiler Middleware** is a Hono Middleware designed to transpile content such as TypeScript or TSX.
You can place your script written in TypeScript in a directory and serve it using `serveStatic`.
When you apply this Middleware, the script will be transpiled into JavaScript code.

View File

@ -1,23 +1,26 @@
# Event Emitter middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=event-emitter)](https://codecov.io/github/honojs/middleware)
### Minimal, lightweight and edge compatible Event Emitter middleware for [Hono](https://github.com/honojs/hono).
## Table of Contents
1. [Introduction](#introduction)
2. [Installation](#installation)
3. [Usage Examples](#usage-examples)
- [1. As Hono middleware](#1-as-hono-middleware)
- [2. Standalone](#2-standalone)
- [1. As Hono middleware](#1-as-hono-middleware)
- [2. Standalone](#2-standalone)
4. [API Reference](#api-reference)
- [emitter](#emitter)
- [createEmitter](#createemitter)
- [defineHandler](#definehandler)
- [defineHandlers](#definehandlers)
- [Emitter API Documentation](#emitter)
- [emitter](#emitter)
- [createEmitter](#createemitter)
- [defineHandler](#definehandler)
- [defineHandlers](#definehandlers)
- [Emitter API Documentation](#emitter)
5. [Types](#types)
## Introduction
This library provides an event emitter middleware for Hono, allowing you to easily implement and manage event-driven architectures in your Hono applications.
It enables event driven logic flow, allowing you to decouple your code and make it more modular and maintainable.
@ -52,13 +55,13 @@ bun install @hono/event-emitter
// Define event handlers
export const handlers = {
'user:created': [
(c, payload) => {} // c is current Context, payload is whatever the emit method passes
(c, payload) => {}, // c is current Context, payload is whatever the emit method passes
],
'user:deleted': [
async (c, payload) => {} // c is current Context, payload is whatever the emit method passes
async (c, payload) => {}, // c is current Context, payload is whatever the emit method passes
],
'foo': [
(c, payload) => {} // c is current Context, payload is whatever the emit method passes
foo: [
(c, payload) => {}, // c is current Context, payload is whatever the emit method passes
],
}
@ -68,7 +71,6 @@ export const handlers = {
// // ...
// console.log('New foo created:', payload)
// }
```
```js
@ -115,7 +117,6 @@ but because middlewares are called on every request, you can only use named func
### 2 Standalone
```js
// events.js
@ -124,11 +125,11 @@ import { createEmitter } from '@hono/event-emitter'
// Define event handlers
export const handlers = {
'user:created': [
(c, payload) => {} // c is current Context, payload will be whatever you pass to emit method
(c, payload) => {}, // c is current Context, payload will be whatever you pass to emit method
],
'user:deleted': [
async (c, payload) => {} // c is current Context, payload will be whatever you pass to emit method
]
async (c, payload) => {}, // c is current Context, payload will be whatever you pass to emit method
],
}
// Initialize emitter with handlers
@ -141,7 +142,6 @@ const ee = createEmitter(handlers)
// })
export default ee
```
```js
@ -154,17 +154,17 @@ import ee from './events'
const app = new Hono()
app.post('/users', async (c) => {
// ...
// Emit event and pass current context plus the payload
ee.emit(c, 'user:created', user)
// ...
// ...
// Emit event and pass current context plus the payload
ee.emit(c, 'user:created', user)
// ...
})
app.delete('/users/:id', async (c) => {
// ...
// Emit event and pass current context plus the payload
await ee.emitAsync(c, 'user:deleted', id )
// ...
// ...
// Emit event and pass current context plus the payload
await ee.emitAsync(c, 'user:deleted', id)
// ...
})
export default app
@ -180,27 +180,25 @@ export default app
import type { Emitter } from '@hono/event-emitter'
export type User = {
id: string,
title: string,
role: string
id: string
title: string
role: string
}
export type AvailableEvents = {
// event key: payload type
'user:created': User;
'user:deleted': string;
'foo': { bar: number };
};
// event key: payload type
'user:created': User
'user:deleted': string
foo: { bar: number }
}
export type Env = {
Bindings: {};
Variables: {
// Define emitter variable type
emitter: Emitter<AvailableEvents>;
};
};
Bindings: {}
Variables: {
// Define emitter variable type
emitter: Emitter<AvailableEvents>
}
}
```
```ts
@ -212,11 +210,11 @@ import { AvailableEvents } from './types'
// Define event handlers
export const handlers = defineHandlers<AvailableEvents>({
'user:created': [
(c, user) => {} // c is current Context, payload will be correctly inferred as User
(c, user) => {}, // c is current Context, payload will be correctly inferred as User
],
'user:deleted': [
async (c, payload) => {} // c is current Context, payload will be inferred as string
]
async (c, payload) => {}, // c is current Context, payload will be inferred as string
],
})
// You can also define single event handler as named function using defineHandler to leverage typings
@ -225,7 +223,6 @@ export const handlers = defineHandlers<AvailableEvents>({
// // ...
// console.log('Foo:', payload)
// })
```
```ts
@ -277,35 +274,39 @@ but because middlewares are called on every request, you can only use named func
// types.ts
type User = {
id: string,
title: string,
id: string
title: string
role: string
}
type AvailableEvents = {
// event key: payload type
'user:created': User;
'user:updated': User;
'user:deleted': string,
'foo': { bar: number };
'user:created': User
'user:updated': User
'user:deleted': string
foo: { bar: number }
}
```
```ts
// events.ts
import { createEmitter, defineHandlers, type Emitter, type EventHandlers } from '@hono/event-emitter'
import {
createEmitter,
defineHandlers,
type Emitter,
type EventHandlers,
} from '@hono/event-emitter'
import { AvailableEvents } from './types'
// Define event handlers
export const handlers = defineHandlers<AvailableEvents>({
'user:created': [
(c, user) => {} // c is current Context, payload will be correctly inferred as User
(c, user) => {}, // c is current Context, payload will be correctly inferred as User
],
'user:deleted': [
async (c, payload) => {} // c is current Context, payload will be inferred as string
]
async (c, payload) => {}, // c is current Context, payload will be inferred as string
],
})
// You can also define single event handler using defineHandler to leverage typings
@ -318,12 +319,12 @@ const ee = createEmitter(handlers)
// And you can add more listeners on the fly.
// Here you can use anonymous or closure function because .on() is only called once.
ee.on('foo', async (c, payload) => { // Payload will be correctly inferred as User
console.log('User updated:', payload)
ee.on('foo', async (c, payload) => {
// Payload will be correctly inferred as User
console.log('User updated:', payload)
})
export default ee
```
```ts
@ -345,7 +346,7 @@ app.post('/user', async (c) => {
app.delete('/user/:id', async (c) => {
// ...
// Emit event and pass current context plus the payload (string)
ee.emit(c, 'user:deleted', id )
ee.emit(c, 'user:deleted', id)
// ...
})
@ -355,26 +356,29 @@ export default app
## API Reference
### emitter
Creates a Hono middleware that adds an event emitter to the context.
```ts
function emitter<EPMap extends EventPayloadMap>(
eventHandlers?: EventHandlers<EPMap>,
options?: EventEmitterOptions
eventHandlers?: EventHandlers<EPMap>,
options?: EventEmitterOptions
): MiddlewareHandler
```
#### Parameters
- `eventHandlers` - (optional): An object containing initial event handlers. Each key is event name and value is array of event handlers. Use `defineHandlers` function to create fully typed event handlers.
- `options` - (optional): An object containing options for the emitter. Currently, the only option is `maxHandlers`, which is the maximum number of handlers that can be added to an event. The default is `10`.
#### Returns
A Hono middleware function that adds an `Emitter` instance to the context under the key 'emitter'.
#### Example
```ts
app.use(emitter(eventHandlers));
app.use(emitter(eventHandlers))
```
### createEmitter
@ -383,12 +387,13 @@ Creates new instance of event emitter with provided handlers. This is usefull wh
```ts
function createEmitter<EPMap extends EventPayloadMap>(
eventHandlers?: EventHandlers<EPMap>,
options?: EventEmitterOptions
eventHandlers?: EventHandlers<EPMap>,
options?: EventEmitterOptions
): Emitter<EPMap>
```
#### Parameters
- `eventHandlers` - (optional): An object containing initial event handlers. Each key is event name and value is array of event handlers.
- `options` - (optional): An object containing options for the emitter. Currently, the only option is `maxHandlers`, which is the maximum number of handlers that can be added to an event. The default is `10`.
@ -399,7 +404,7 @@ An `Emitter` instance:
#### Example
```ts
const ee = createEmitter(eventHandlers);
const ee = createEmitter(eventHandlers)
```
### defineHandler
@ -408,14 +413,16 @@ A utility function to define a typed event handler.
```ts
function defineHandler<EPMap extends EventPayloadMap, Key extends keyof EPMap, E extends Env = Env>(
handler: EventHandler<EPMap[Key], E>,
handler: EventHandler<EPMap[Key], E>
): EventHandler<EPMap[Key], E>
```
#### Parameters
- `handler`: The event handler function to be defined.
#### Type parameters
- `EPMap`: The available event key to payload map i.e.: `type AvailableEvents = { 'user:created': { name: string } };`.
- `Key`: The key of the event type.
- `E`: (optional) - The Hono environment, so that the context within the handler has the right info.
@ -428,11 +435,11 @@ The same event handler function with proper type inference.
```ts
type AvailableEvents = {
'user:created': { name: string };
};
'user:created': { name: string }
}
const handler = defineHandler<AvailableEvents, 'user:created'>((c, payload) => {
console.log('New user created:', payload)
console.log('New user created:', payload)
})
```
@ -441,15 +448,17 @@ const handler = defineHandler<AvailableEvents, 'user:created'>((c, payload) => {
A utility function to define multiple typed event handlers.
```ts
function defineHandlers<EPMap extends EventPayloadMap, E extends Env = Env>(
handlers: { [K in keyof EPMap]?: EventHandler<EPMap[K], E>[] },
): { [K in keyof EPMap]?: EventHandler<EPMap[K], E>[] }
function defineHandlers<EPMap extends EventPayloadMap, E extends Env = Env>(handlers: {
[K in keyof EPMap]?: EventHandler<EPMap[K], E>[]
}): { [K in keyof EPMap]?: EventHandler<EPMap[K], E>[] }
```
#### Parameters
- `handlers`: An object containing event handlers for multiple event types/keys.
#### Type parameters
- `EPMap`: The available event key to payload map i.e.: `type AvailableEvents = { 'user:created': { name: string } };`.
- `E`: (optional) - The Hono environment, so that the context within the handler has the right info.
@ -461,18 +470,20 @@ The same handlers object with proper type inference.
```ts
type AvailableEvents = {
'user:created': { name: string };
};
'user:created': { name: string }
}
const handlers = defineHandlers<AvailableEvents>({
'user:created': [
(c, payload) => {
console.log('New user created:', pyload)
}
]
'user:created': [
(c, payload) => {
console.log('New user created:', pyload)
},
],
})
```
## Emitter instance methods
The `Emitter` interface provides methods for managing and triggering events. Here's a detailed look at each method:
### on
@ -483,8 +494,8 @@ Adds an event handler for the specified event key.
```ts
function on<Key extends keyof EventPayloadMap>(
key: Key,
handler: EventHandler<EventPayloadMap[Key]>
key: Key,
handler: EventHandler<EventPayloadMap[Key]>
): void
```
@ -493,8 +504,8 @@ function on<Key extends keyof EventPayloadMap>(
- `key`: The event key to listen for. Must be a key of `EventHandlerPayloads`.
- `handler`: The function to be called when the event is emitted. If using within a Hono middleware or request handler, do not use anonymous or closure functions!
It should accept two parameters:
- `c`: The current Hono context object.
- `payload`: The payload passed when the event is emitted. The type of the payload is inferred from the `EventHandlerPayloads` type.
- `c`: The current Hono context object.
- `payload`: The payload passed when the event is emitted. The type of the payload is inferred from the `EventHandlerPayloads` type.
#### Returns
@ -503,33 +514,36 @@ function on<Key extends keyof EventPayloadMap>(
#### Example
Using outside the Hono middleware or request handler:
```ts
type AvailableEvents = {
'user:created': { name: string };
};
const ee = createEmitter<AvailableEvents>();
'user:created': { name: string }
}
const ee = createEmitter<AvailableEvents>()
// If adding event handler outside of Hono middleware or request handler, you can use both, named or anonymous function.
ee.on('user:created', (c, user) => {
console.log('New user created:', user)
console.log('New user created:', user)
})
```
Using within Hono middleware or request handler:
```ts
type AvailableEvents = {
'user:created': { name: string };
};
'user:created': { name: string }
}
// Define event handler as named function, outside of the Hono middleware or request handler to prevent duplicates/memory leaks
const namedHandler = defineHandler<AvailableEvents, 'user:created'>((c, user) => {
console.log('New user created:', user)
console.log('New user created:', user)
})
app.use(emitter<AvailableEvents>());
app.use(emitter<AvailableEvents>())
app.use((c, next) => {
c.get('emitter').on('user:created', namedHandler)
return next()
c.get('emitter').on('user:created', namedHandler)
return next()
})
```
@ -541,41 +555,42 @@ Removes an event handler for the specified event key.
```ts
function off<Key extends keyof EventPayloadMap>(
key: Key,
handler?: EventHandler<EventPayloadMap[Key]>
key: Key,
handler?: EventHandler<EventPayloadMap[Key]>
): void
```
#### Parameters
- `key`: The event key to remove the handler from. Must be a key of `EventPayloadMap`.
- `handler` (optional): The specific handler function to remove. If not provided, all handlers for the given key will be removed.
#### Returns
`void`
#### Example
```ts
type AvailableEvents = {
'user:created': { name: string };
};
'user:created': { name: string }
}
const ee = createEmitter<AvailableEvents>();
const ee = createEmitter<AvailableEvents>()
const logUser = defineHandler<AvailableEvents, 'user:created'>((c, user) => {
console.log(`User: ${user.name}`);
});
console.log(`User: ${user.name}`)
})
ee.on('user:created', logUser);
ee.on('user:created', logUser)
// Later, to remove the specific handler:
ee.off('user:created', logUser);
ee.off('user:created', logUser)
// Or to remove all handlers for 'user:created':
ee.off('user:created');
ee.off('user:created')
```
### emit
Synchronously emits an event with the specified key and payload.
@ -591,6 +606,7 @@ emit<Key extends keyof EventPayloadMap>(
```
#### Parameters
- `c`: The current Hono context object.
- `key`: The event key to emit. Must be a key of `EventPayloadMap`.
- `payload`: The payload to pass to the event handlers. The type of the payload is inferred from the `EventPayloadMap` type.
@ -603,9 +619,9 @@ emit<Key extends keyof EventPayloadMap>(
```ts
app.post('/users', (c) => {
const user = { name: 'Alice' };
c.get('emitter').emit(c, 'user:created', user);
});
const user = { name: 'Alice' }
c.get('emitter').emit(c, 'user:created', user)
})
```
### emitAsync
@ -624,13 +640,14 @@ emitAsync<Key extends keyof EventPayloadMap>(
```
#### Parameters
- `c`: The current Hono context object.
- `key`: The event key to emit. Must be a key of `EventPayloadMap`.
- `payload`: The payload to pass to the event handlers. The type of the payload is inferred from the `EventPayloadMap` type.
- `options` (optional): An object containing options for the asynchronous emission.
Currently, the only option is `mode`, which can be `'concurrent'` (default) or `'sequencial'`.
- The `'concurrent'` mode will call all handlers concurrently (at the same time) and resolve or reject (with aggregated errors) after all handlers settle.
- The `'sequencial'` mode will call handlers one by one and resolve when all handlers are done or reject when the first error is thrown, not executing rest of the handlers.
- The `'concurrent'` mode will call all handlers concurrently (at the same time) and resolve or reject (with aggregated errors) after all handlers settle.
- The `'sequencial'` mode will call handlers one by one and resolve when all handlers are done or reject when the first error is thrown, not executing rest of the handlers.
#### Returns
@ -640,15 +657,16 @@ emitAsync<Key extends keyof EventPayloadMap>(
```ts
app.post('/users', async (c) => {
const user = { name: 'Alice' };
await c.get('emitter').emitAsync(c, 'user:created', user);
// await c.get('emitter').emitAsync(c, 'user:created', user, { mode: 'sequencial' });
});
const user = { name: 'Alice' }
await c.get('emitter').emitAsync(c, 'user:created', user)
// await c.get('emitter').emitAsync(c, 'user:created', user, { mode: 'sequencial' });
})
```
## Types
### EventKey
A string literal type representing an event key.
```ts
@ -656,6 +674,7 @@ type EventKey = string | symbol
```
### EventHandler
A function type that handles an event.
```ts
@ -663,6 +682,7 @@ type EventHandler<T, E extends Env = Env> = (c: Context<E>, payload: T) => void
```
### EventHandlers
An object type containing event handlers for multiple event types/keys.
```ts
@ -670,6 +690,7 @@ type EventHandlers<T, E extends Env = Env> = { [K in keyof T]?: EventHandler<T[K
```
### EventPayloadMap
An object type containing event keys and their corresponding payload types.
```ts
@ -681,15 +702,16 @@ type EventPayloadMap = Record<EventKey, any>
An object type containing options for the `Emitter` class.
```ts
type EventEmitterOptions = { maxHandlers?: number };
type EventEmitterOptions = { maxHandlers?: number }
```
### EmitAsyncOptions
An object type containing options for the `emitAsync` method.
```ts
type EmitAsyncOptions = {
mode?: 'concurrent' | 'sequencial'
mode?: 'concurrent' | 'sequencial'
}
```
@ -699,45 +721,65 @@ An interface representing an event emitter.
```ts
interface Emitter<EventPayloadMap> {
on<Key extends keyof EventPayloadMap>(key: Key, handler: EventHandler<EventPayloadMap[Key]>): void;
off<Key extends keyof EventPayloadMap>(key: Key, handler?: EventHandler<EventPayloadMap[Key]>): void;
emit<Key extends keyof EventPayloadMap>(c: Context, key: Key, payload: EventPayloadMap[Key]): void;
emitAsync<Key extends keyof EventPayloadMap>(
c: Context,
key: Key,
payload: EventPayloadMap[Key],
options?: EmitAsyncOptions
): Promise<void>;
on<Key extends keyof EventPayloadMap>(key: Key, handler: EventHandler<EventPayloadMap[Key]>): void
off<Key extends keyof EventPayloadMap>(
key: Key,
handler?: EventHandler<EventPayloadMap[Key]>
): void
emit<Key extends keyof EventPayloadMap>(c: Context, key: Key, payload: EventPayloadMap[Key]): void
emitAsync<Key extends keyof EventPayloadMap>(
c: Context,
key: Key,
payload: EventPayloadMap[Key],
options?: EmitAsyncOptions
): Promise<void>
}
```
For more usage examples, see the [tests](src/index.test.ts) or [Hono REST API starter kit](https://github.com/DavidHavl/hono-rest-api-starter)
## FAQ
### What the heck is event emitter and why should I use it?
Event emitter is a pattern that allows you to decouple your code and make it more modular and maintainable.
It's a way to implement the observer pattern in your application.
It's especially useful in larger projects or projects with a lot of interactions between features.
Just imagine you have a user registration feature, and you want to send a welcome email after the user is created. You can do this by emitting an event `user:created` and then listen to this event in another part of your application (e.g. email service).
### How is this different to the built-in EventEmitter in Node.js?
The build-in EventEmitter has huge API surface, weak TypeScript support and does only synchronous event emitting. Hono's event emitter is designed to be minimal, lightweight, edge compatible and fully typed. Additionally, it supports async event handlers.
### Is there a way to define event handlers with types?
Yes, you can use `defineHandlers` and `defineHandler` functions to define event handlers with types. This way you can leverage TypeScript's type inference and get better type checking.
### Does it support async event handlers?
Yes, it does. You can use async functions as event handlers and emit the events using `emitAsync` method.
### What happens if I emit an event that has no handlers?
Nothing. The event will be emitted, but no handlers will be called.
### Using `emitAsync` function, what happens if one or more of the handlers reject?
- If using `{ mode = 'concurrent' }` in the options (which is the default), it will call all handlers concurrently (at the same time) and resolve or reject (with aggregated errors) after all handlers settle.
- If using `{ mode = 'sequencial' }` in the options, it will call handlers one by one and resolve when all handlers are done or reject when the first error is thrown, not executing rest of the handlers.
### Is it request scoped?
No, by design it's not request scoped. The same Emitter instance is shared across all requests.
This aproach prevents memory leaks (especially when using closures or dealing with large data structures within the handlers) and additional strain on Javascript garbage collector.
### Why can't I use anonymous functions or closures as event handlers when adding them inside of middleware?
This is because middleware or request handlers run repeatedly on every request, and because anonymous functions are created as new unique object in memory every time,
you would be instructing the event emitter to add new handler for same key every time the request/middleware runs.
Since they are each different objects in memory they can't be checked for equality and would result in memory leaks and duplicate handlers.
You should use named functions if you really want to use the `on()` method inside of middleware or request handler.
## Author
David Havl <https://github.com/DavidHavl>

View File

@ -1,5 +1,7 @@
# Hono Firebase Auth middleware for Cloudflare Workers
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=firebase-auth)](https://codecov.io/github/honojs/middleware)
This is a Firebase Auth middleware library for [Hono](https://github.com/honojs/hono) which is used [firebase-auth-cloudflare-workers](https://github.com/Code-Hex/firebase-auth-cloudflare-workers).
Currently only Cloudflare Workers are supported officially. However, it may work in other environments as well, so please let us know in an issue if it works.
@ -106,23 +108,23 @@ If not specified, check the [`FIREBASE_AUTH_EMULATOR_HOST` environment variable
```ts
import { Hono } from 'hono'
import { setCookie } from 'hono/cookie';
import { csrf } from 'hono/csrf';
import { html } from 'hono/html';
import { setCookie } from 'hono/cookie'
import { csrf } from 'hono/csrf'
import { html } from 'hono/html'
import {
VerifySessionCookieFirebaseAuthConfig,
VerifyFirebaseAuthEnv,
verifySessionCookieFirebaseAuth,
getFirebaseToken,
} from '@hono/firebase-auth'
import { AdminAuthApiClient, ServiceAccountCredential } from 'firebase-auth-cloudflare-workers';
import { AdminAuthApiClient, ServiceAccountCredential } from 'firebase-auth-cloudflare-workers'
const config: VerifySessionCookieFirebaseAuthConfig = {
// specify your firebase project ID.
projectId: 'your-project-id',
redirects: {
signIn: "/login"
}
signIn: '/login',
},
}
// You can specify here the extended VerifyFirebaseAuthEnv type.
@ -140,7 +142,7 @@ type MyEnv = VerifyFirebaseAuthEnv & {
const app = new Hono<{ Bindings: MyEnv }>()
// set middleware
app.get('/login', csrf(), async c => {
app.get('/login', csrf(), async (c) => {
// You can copy code from here
// https://github.com/Code-Hex/firebase-auth-cloudflare-workers/blob/0ce610fff257b0b60e2f8e38d89c8e012497d537/example/index.ts#L63C25-L63C37
const content = await html`...`
@ -148,13 +150,13 @@ app.get('/login', csrf(), async c => {
})
app.post('/login_session', csrf(), (c) => {
const json = await c.req.json();
const idToken = json.idToken;
const json = await c.req.json()
const idToken = json.idToken
if (!idToken || typeof idToken !== 'string') {
return c.json({ message: 'invalid idToken' }, 400);
return c.json({ message: 'invalid idToken' }, 400)
}
// Set session expiration to 5 days.
const expiresIn = 60 * 60 * 24 * 5 * 1000;
const expiresIn = 60 * 60 * 24 * 5 * 1000
// Create the session cookie. This will also verify the ID token in the process.
// The session cookie will have the same claims as the ID token.
@ -163,26 +165,22 @@ app.post('/login_session', csrf(), (c) => {
const auth = AdminAuthApiClient.getOrInitialize(
c.env.PROJECT_ID,
new ServiceAccountCredential(c.env.SERVICE_ACCOUNT_JSON)
);
const sessionCookie = await auth.createSessionCookie(
idToken,
expiresIn,
);
)
const sessionCookie = await auth.createSessionCookie(idToken, expiresIn)
setCookie(c, 'session', sessionCookie, {
maxAge: expiresIn,
httpOnly: true,
secure: true
});
return c.json({ message: 'success' });
secure: true,
})
return c.json({ message: 'success' })
})
app.use('/admin/*', csrf(), verifySessionCookieFirebaseAuth(config));
app.use('/admin/*', csrf(), verifySessionCookieFirebaseAuth(config))
app.get('/admin/hello', (c) => {
const idToken = getFirebaseToken(c) // get id-token object.
return c.json(idToken)
})
export default app
```

View File

@ -1,5 +1,7 @@
# GraphQL Server Middleware
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=graphql-server)](https://codecov.io/github/honojs/middleware)
## Requirements
This middleware depends on [GraphQL.js](https://www.npmjs.com/package/graphql).

View File

@ -1,5 +1,7 @@
# Hello middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=hello)](https://codecov.io/github/honojs/middleware)
An example project of the third-party middleware for [Hono](https://github.com/honojs/hono).
This middleware add `X-Message` header to the Response.

View File

@ -1,5 +1,7 @@
# Router using @medley/router
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=medley-router)](https://codecov.io/github/honojs/middleware)
Just a PoC.
## Usage

View File

@ -1,5 +1,7 @@
# WebSocket helper for Node.js
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=node-ws)](https://codecov.io/github/honojs/middleware)
A WebSocket helper for Node.js
## Usage
@ -13,9 +15,12 @@ const app = new Hono()
const { injectWebSocket, upgradeWebSocket } = createNodeWebSocket({ app })
app.get('/ws', upgradeWebSocket((c) => ({
// https://hono.dev/helpers/websocket
})))
app.get(
'/ws',
upgradeWebSocket((c) => ({
// https://hono.dev/helpers/websocket
}))
)
const server = serve(app)
injectWebSocket(server)
@ -27,4 +32,4 @@ Shotaro Nakamura <https://github.com/nakasyou>
## License
MIT
MIT

View File

@ -1,5 +1,7 @@
# OAuth Providers Middleware
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=oauth-providers)](https://codecov.io/github/honojs/middleware)
Authentication middleware for [Hono](https://github.com/honojs/hono). This package offers a straightforward API for social login with platforms such as Facebook, GitHub, Google, LinkedIn and X(Twitter).
## Installation
@ -1079,7 +1081,6 @@ You can validate a Twitch access token to verify it's still valid or to obtain i
You can use `validateToken` method, which accepts the `token` to be validated as parameter and returns `TwitchValidateSuccess` if valid or throws `HTTPException` upon failure.
> **IMPORTANT:** Twitch requires applications to validate OAuth tokens when they start and on an hourly basis thereafter. Failure to validate tokens may result in Twitch taking punitive action, such as revoking API keys or throttling performance. When a token becomes invalid, your app should terminate all sessions using that token immediately. [Read more](https://dev.twitch.tv/docs/authentication/validate-tokens)
The validation endpoint helps your application detect when tokens become invalid for reasons other than expiration, such as when users disconnect your integration from their Twitch account. When a token becomes invalid, your app should terminate all sessions using that token.
@ -1099,36 +1100,39 @@ This parameters can be useful if
3. Or, in need to encode more info into `redirect_uri`.
```ts
const app = new Hono();
const app = new Hono()
const SITE_ORIGIN = `https://my-site.com`;
const OAUTH_CALLBACK_PATH = `/oauth/google`;
const SITE_ORIGIN = `https://my-site.com`
const OAUTH_CALLBACK_PATH = `/oauth/google`
app.get('/*',
app.get(
'/*',
async (c, next) => {
const session = readSession(c);
const session = readSession(c)
if (!session) {
// start oauth flow
const redirectUri = `${SITE_ORIGIN}${OAUTH_CALLBACK_PATH}?redirect=${encodeURIComponent(c.req.path)}`;
const oauth = googleAuth({ redirect_uri: redirectUri, ...more });
const redirectUri = `${SITE_ORIGIN}${OAUTH_CALLBACK_PATH}?redirect=${encodeURIComponent(
c.req.path
)}`
const oauth = googleAuth({ redirect_uri: redirectUri, ...more })
return await oauth(c, next)
}
},
async (c, next) => {
// if we are here, the req should contain either a valid session or a valid auth code
const session = readSession(c);
const session = readSession(c)
const authedGoogleUser = c.get('user-google')
if (authedGoogleUser) {
await saveSession(c, authedGoogleUser);
await saveSession(c, authedGoogleUser)
} else if (!session) {
throw new HttpException(401)
}
return next();
return next()
},
async (c, next) => {
// serve protected content
}
);
)
```
## Author

View File

@ -1,5 +1,7 @@
# OpenID Connect Authentication middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=oidc-auth)](https://codecov.io/github/honojs/middleware)
This is an OpenID Connect (OIDC) authentication third-party middleware for [Hono](https://github.com/honojs/hono), which depends on [oauth4webapi](https://www.npmjs.com/package/oauth4webapi).
This middleware provides storage-less login sessions.
@ -144,7 +146,7 @@ If the middleware is applied to the callback URL, the default callback handling
```typescript
// Before other oidc-auth APIs are used
app.use(initOidcAuthMiddleware(config));
app.use(initOidcAuthMiddleware(config))
```
Or to leverage context, use the [`Context access inside Middleware arguments`](https://hono.dev/docs/guides/middleware#context-access-inside-middleware-arguments) pattern.

View File

@ -1,5 +1,7 @@
# OpenTelemetry middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=otel)](https://codecov.io/github/honojs/middleware)
This package provides a [Hono](https://hono.dev/) middleware that instruments your application with [OpenTelemetry](https://opentelemetry.io/).
## Usage

View File

@ -1,5 +1,7 @@
# Prometheus middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=prometheus)](https://codecov.io/github/honojs/middleware)
This middleware adds basic [RED metrics](https://www.weave.works/blog/the-red-method-key-metrics-for-microservices-architecture/) to your Hono application, and exposes them on the `/metrics` endpoint for Prometheus to scrape.
## Installation
@ -81,13 +83,13 @@ An options object can be passed in the `prometheus()` middleware factory to conf
### `prefix`
Type: *string*
Type: _string_
Prefix all metrics with this string.
### `registry`
Type: *[Registry](https://www.npmjs.com/package/prom-client)*
Type: _[Registry](https://www.npmjs.com/package/prom-client)_
A prom-client Registry instance to store the metrics. If not provided, a new one will be created.
@ -95,7 +97,7 @@ Useful when you want to register some custom metrics while exposing them on the
### `collectDefaultMetrics`
Type: *boolean | [CollectDefaultMetricsOptions](https://www.npmjs.com/package/prom-client#default-metrics)*
Type: _boolean | [CollectDefaultMetricsOptions](https://www.npmjs.com/package/prom-client#default-metrics)_
There are some default metrics recommended by prom-client, like event loop delay, garbage collection statistics etc.
@ -103,34 +105,37 @@ To enable these metrics, set this option to `true`. To configure the default met
### `metricOptions`
Type: *object (see below)*
Type: _object (see below)_
Modify the standard metrics (*requestDuration* and *requestsTotal*) with any of the [Counter](https://www.npmjs.com/package/prom-client#counter) / [Histogram](https://www.npmjs.com/package/prom-client#histogram) metric options, including:
Modify the standard metrics (_requestDuration_ and _requestsTotal_) with any of the [Counter](https://www.npmjs.com/package/prom-client#counter) / [Histogram](https://www.npmjs.com/package/prom-client#histogram) metric options, including:
#### `disabled`
Type: *boolean*
Type: _boolean_
Disables the metric.
#### `customLabels`
Type: *Record<string, (context) => string>*
Type: _Record<string, (context) => string>_
A record where the keys are the labels to add to the metrics, and the values are functions that receive the Hono context and return the value for that label. This is useful when adding labels to the metrics that are specific to your application or your needs. These functions are executed after all the other middlewares finished.
The following example adds a label to the *requestsTotal* metric with the `contentType` name where the value is the content type of the response:
The following example adds a label to the _requestsTotal_ metric with the `contentType` name where the value is the content type of the response:
```ts
app.use('*', prometheus({
metricOptions: {
requestsTotal: {
customLabels: {
content_type: (c) => c.res.headers.get('content-type'),
}
app.use(
'*',
prometheus({
metricOptions: {
requestsTotal: {
customLabels: {
content_type: (c) => c.res.headers.get('content-type'),
},
},
},
}
}))
})
)
```
## Examples

View File

@ -1,5 +1,7 @@
# Qwik City middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=qwik-city)](https://codecov.io/github/honojs/middleware)
**WIP**
## Usage

View File

@ -1,5 +1,7 @@
# Alias of hono/jsx for replacement of React
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=react-compat)](https://codecov.io/github/honojs/middleware)
This package is used to install the React compatibility API provided by [Hono](https://github.com/honojs/hono). This package allows you to replace the "react" and "react-dom" entities with "@hono/react-compat".
## Usage

View File

@ -1,5 +1,7 @@
# React Renderer Middleware
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=react-renderer)](https://codecov.io/github/honojs/middleware)
React Renderer Middleware allows for the easy creation of a renderer based on React for Hono.
## Installation

View File

@ -1,5 +1,7 @@
# Sentry Middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=sentry)](https://codecov.io/github/honojs/middleware)
This middleware integrates [Hono](https://github.com/honojs/hono) with Sentry. It captures exceptions and sends them to the specified Sentry data source name (DSN) using [toucan-js](https://github.com/robertcepa/toucan-js).
## Installation

View File

@ -1,12 +1,14 @@
# Standard Schema validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=standard-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [Standard Schema Spec](https://github.com/standard-schema/standard-schema) for [Hono](https://honojs.dev) applications.
You can write a schema with any validation library supporting Standard Schema and validate the incoming values.
## Usage
### Basic:
```ts
import { z } from 'zod'
import { sValidator } from '@hono/standard-validator'
@ -14,7 +16,7 @@ import { sValidator } from '@hono/standard-validator'
const schema = z.object({
name: z.string(),
age: z.number(),
});
})
app.post('/author', sValidator('json', schema), (c) => {
const data = c.req.valid('json')
@ -26,6 +28,7 @@ app.post('/author', sValidator('json', schema), (c) => {
```
### Hook:
```ts
app.post(
'/post',
@ -39,15 +42,17 @@ app.post(
```
### Headers:
Headers are internally transformed to lower-case in Hono. Hence, you will have to make them lower-cased in validation object.
```ts
import { object, string } from 'valibot'
import { sValidator } from '@hono/standard-validator'
const schema = object({
'content-type': string(),
'user-agent': string()
});
'user-agent': string(),
})
app.post('/author', sValidator('header', schema), (c) => {
const headers = c.req.valid('header')
@ -55,7 +60,6 @@ app.post('/author', sValidator('header', schema), (c) => {
})
```
## Author
Rokas Muningis <https://github.com/muningis>

View File

@ -1,5 +1,7 @@
# Swagger Editor Middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=swagger-editor)](https://codecov.io/github/honojs/middleware)
This library, `@hono/swagger-editor` is the middleware for integrating Swagger Editor with Hono applications. The Swagger Editor is an open source editor to design, define and document RESTful APIs in the Swagger Specification.
## Installation
@ -14,7 +16,6 @@ yarn add @hono/swagger-editor
You can use the `swaggerEditor` middleware to serve Swagger Editor on a specific route in your Hono application. Here's how you can do it:
```ts
import { Hono } from 'hono'
import { swaggerUI } from '@hono/swagger-ui'
@ -37,4 +38,4 @@ Middleware supports almost all swagger-editor options. See full documentation: <
## License
MIT
MIT

View File

@ -1,5 +1,7 @@
# Swagger UI Middleware and Component for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=swagger-ui)](https://codecov.io/github/honojs/middleware)
This library, `@hono/swagger-ui`, provides a middleware and a component for integrating Swagger UI with Hono applications. Swagger UI is an interactive documentation interface for APIs compliant with the OpenAPI Specification, making it easier to understand and test API endpoints.
## Installation
@ -83,16 +85,16 @@ app.openapi(
content: {
'application/json': {
schema: z.object({
message: z.string()
})
}
}
}
}
message: z.string(),
}),
},
},
},
},
}),
(c) => {
return c.json({
message: 'hello'
message: 'hello',
})
}
)
@ -100,16 +102,16 @@ app.openapi(
app.get(
'/ui',
swaggerUI({
url: '/doc'
url: '/doc',
})
)
app.doc('/doc', {
info: {
title: 'An API',
version: 'v1'
version: 'v1',
},
openapi: '3.1.0'
openapi: '3.1.0',
})
export default app
@ -124,11 +126,10 @@ The following options are available:
- `version` (string, optional): The version of Swagger UI to use, defaults to `latest`.
- `manuallySwaggerUIHtml` (string, optional): If you want to use your own custom HTML, you can specify it here. If this option is specified, the all options except `version` will be ignored.
and most of options from [Swagger UI](
https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/
) are supported as well.
and most of options from [Swagger UI](https://swagger.io/docs/open-source-tools/swagger-ui/usage/configuration/) are supported as well.
such as:
- `url` (string, optional): The URL pointing to the OpenAPI definition (v2 or v3) that describes the API.
- `urls` (array, optional): An array of OpenAPI definitions (v2 or v3) that describe the APIs. Each definition must have a `name` and `url`.
- `presets` (array, optional): An array of presets to use for Swagger UI.

View File

@ -1,5 +1,7 @@
# tRPC Server Middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=trpc-server)](https://codecov.io/github/honojs/middleware)
tRPC Server Middleware adapts a [tRPC](https://trpc.io) server as middleware for Hono.
Hono works on almost any JavaScript runtime, including Cloudflare Workers, Deno, and Bun. So, with this middleware, the same code will run as tRPC server.
@ -76,11 +78,11 @@ import { initTRPC } from '@trpc/server'
import { z } from 'zod'
type Env = {
DB: D1Database;
DB: D1Database
}
type HonoContext = {
env: Env,
};
env: Env
}
const t = initTRPC.context<HonoContext>().create()
@ -89,8 +91,8 @@ const router = t.router
export const appRouter = router({
usersCount: publicProcedure.query(({ input, ctx }) => {
const result = await ctx.env.DB.prepare("SELECT count(*) from user;").all();
return result.results[0].count;
const result = await ctx.env.DB.prepare('SELECT count(*) from user;').all()
return result.results[0].count
}),
})
@ -108,10 +110,11 @@ app.use(
// c is the hono context
var1: c.env.MY_VAR1,
var2: c.req.header('X-VAR2'),
})
}),
})
)
```
## Custom Endpoints
To set up custom endpoints ensure the endpoint parameter matches the middleware's path. This alignment allows `@trpc/server` to accurately extract your procedure paths.

View File

@ -1,11 +1,13 @@
# tsyringe middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=tsyringe)](https://codecov.io/github/honojs/middleware)
The [tsyringe](https://github.com/microsoft/tsyringe) middleware provides a way to use dependency injection in [Hono](https://hono.dev/).
## Usage
```ts
import "reflect-metadata" // tsyringe requires reflect-metadata or polyfill
import 'reflect-metadata' // tsyringe requires reflect-metadata or polyfill
import { container, inject, injectable } from 'tsyringe'
import { tsyringe } from '@hono/tsyringe'
import { Hono } from 'hono'
@ -21,13 +23,16 @@ class Hello {
const app = new Hono()
app.use('*', tsyringe((container) => {
app.use(
'*',
tsyringe((container) => {
container.register('name', { useValue: 'world' })
}))
})
)
app.get('/', (c) => {
const hello = container.resolve(Hello)
return c.text(hello.greet())
const hello = container.resolve(Hello)
return c.text(hello.greet())
})
export default app
@ -39,12 +44,12 @@ export default app
const app = new Hono()
app.use('/tenant/:name/*', async (c, next) => {
await tsyringe((container) => {
// Allowing to inject `c.var` or `c.req.param` in the providers
const tenantName = c.req.param('name')
await tsyringe((container) => {
// Allowing to inject `c.var` or `c.req.param` in the providers
const tenantName = c.req.param('name')
container.register(Config, { useFactory: () => new Config(tenantName) })
})(c, next)
container.register(Config, { useFactory: () => new Config(tenantName) })
})(c, next)
})
```

View File

@ -1,5 +1,7 @@
# TypeBox validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?typebox-validator)](https://codecov.io/github/honojs/middleware)
Validator middleware using [TypeBox](https://github.com/sinclairzx81/typebox) for [Hono](https://honojs.dev) applications.
Define your schema with TypeBox and validate incoming requests.

View File

@ -1,5 +1,7 @@
# Typia validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=typia-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [Typia](https://typia.io/docs/) for [Hono](https://honojs.dev) applications.
## Usage
@ -83,7 +85,8 @@ const validate = typia.createValidate<Author>()
const validateQuery = typia.http.createValidateQuery<IQuery>()
const validateHeaders = typia.http.createValidateHeaders<IHeaders>()
app.get('/items',
app.get(
'/items',
typiaValidator('json', validate),
typiaValidator('query', validateQuery),
typiaValidator('header', validateHeaders),
@ -98,6 +101,7 @@ app.get('/items',
}
)
```
## Author
Patryk Dwórznik <https://github.com/dworznik>

View File

@ -1,5 +1,7 @@
# Valibot validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=valibot-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [Valibot](https://valibot.dev) for [Hono](https://honojs.dev) applications.
You can write a schema with Valibot and validate the incoming values.

View File

@ -1,5 +1,7 @@
# Zod OpenAPI Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=zod-openapi)](https://codecov.io/github/honojs/middleware)
**Zod OpenAPI Hono** is an extended Hono class that supports OpenAPI. With it, you can validate values and types using [**Zod**](https://zod.dev/) and generate OpenAPI Swagger documentation. This is based on [**Zod to OpenAPI**](https://github.com/asteasolutions/zod-to-openapi) (thanks a lot!). For details on creating schemas and defining routes, please refer to [the "Zod to OpenAPI" resource](https://github.com/asteasolutions/zod-to-openapi).
_Note: This is not standalone middleware but is hosted on the monorepo "[github.com/honojs/middleware](https://github.com/honojs/middleware)"._

View File

@ -1,5 +1,7 @@
# Zod validator middleware for Hono
[![codecov](https://codecov.io/github/honojs/middleware/graph/badge.svg?flag=zod-validator)](https://codecov.io/github/honojs/middleware)
The validator middleware using [Zod](https://zod.dev) for [Hono](https://honojs.dev) applications.
You can write a schema with Zod and validate the incoming values.
@ -43,22 +45,19 @@ throw a zod validate error instead of directly returning an error response.
```ts
// file: validator-wrapper.ts
import { ZodSchema } from "zod";
import type { ValidationTargets } from "hono";
import { zValidator as zv } from "@hono/zod-validator";
import { ZodSchema } from 'zod'
import type { ValidationTargets } from 'hono'
import { zValidator as zv } from '@hono/zod-validator'
export const zValidator = <
T extends ZodSchema,
Target extends keyof ValidationTargets
>(
export const zValidator = <T extends ZodSchema, Target extends keyof ValidationTargets>(
target: Target,
schema: T
) =>
zv(target, schema, (result, c) => {
if (!result.success) {
throw new HTTPException(400, { cause: result.error });
throw new HTTPException(400, { cause: result.error })
}
});
})
// usage
import { zValidator } from './validator-wrapper'