diff --git a/CHANGELOG.md b/CHANGELOG.md
index 40dc9d5..1735b61 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -2,6 +2,18 @@
All notable changes to this project will be documented in this file. See [standard-version](https://github.com/conventional-changelog/standard-version) for commit guidelines.
+### [0.17.2](https://github.com/frouriojs/frourio/compare/v0.17.1...v0.17.2) (2020-10-13)
+
+
+### Features
+
+* optimize methodToHandler ([b8d4625](https://github.com/frouriojs/frourio/commit/b8d4625f86a8622ed428d570ce548a8db76a8d4a))
+
+
+### Documentation
+
+* add ja README ([a2c3107](https://github.com/frouriojs/frourio/commit/a2c3107f30fb1310c046684f4f6059ba426e8626))
+
### [0.17.1](https://github.com/frouriojs/frourio/compare/v0.17.0...v0.17.1) (2020-10-11)
diff --git a/README.md b/README.md
index 39b7169..c017f4a 100644
--- a/README.md
+++ b/README.md
@@ -22,6 +22,10 @@
Frourio is a perfectly type-checkable REST framework for TypeScript.
+
@@ -76,6 +80,7 @@ overhead.
- [Case 1 - Define GET: /tasks?limit={number}](#Controller-case1)
- [Case 2 - Define POST: /tasks](#Controller-case2)
- [Case 3 - Define GET: /tasks/{taskId}](#Controller-case3)
+- [HTTP client](#HttpClient)
- [Hooks](#Hooks)
- [Lifecycle](#Lifecycle)
- [Directory level hooks](#Hooks-dir)
@@ -95,6 +100,9 @@ overhead.
- [Prisma](#ORM-prisma)
- [TypeORM](#ORM-typeorm)
- [CORS / Helmet](#CORS-Helmet)
+- [Deployment](#Deployment)
+ - [Frontend](#Deployment-frontend)
+ - [Server](#Deployment-server)
- [Dependency Injection](#DI)
## Install
@@ -121,15 +129,15 @@ $ yarn create frourio-app
## Express.js mode
-Frourio uses fastify.js as its HTTP server.
-If you choose express.js in create-frourio-app, please refer to the following repositories.
+Frourio uses [Fastify](https://www.fastify.io/) as its HTTP server.
+If you choose [Express](https://expressjs.com/) in create-frourio-app, please refer to the following repositories.
[GitHub: frourio-express](https://github.com/frouriojs/frourio-express)
Note: frourio is 5x faster than frourio-express
## Environment
-Frourio requires TypeScript 3.9 or higher.
+Frourio requires TypeScript >= v3.9 and Node.js >= v12.
If the TypeScript version of VSCode is low, an error is displayed during development.
## Entrypoint
@@ -260,9 +268,18 @@ export default defineController(() => ({
}))
```
+
+
+## HTTP client
+
+Use [aspida](https://github.com/aspida/aspida) for the frontend HTTP client.
+(Frourio and aspida are maintained by the same developer)
+
+Next.js also uses [@aspida/swr](https://github.com/aspida/aspida/tree/master/packages/aspida-swr).
+
## Hooks
-Frourio can use hooks of fastify.js.
+Frourio can use hooks of Fastify.
There are four types of hooks, onRequest / preParsing / preValidation / preHandler.
### Lifecycle
@@ -825,6 +842,38 @@ server(fastify, { basePath: '/api/v1' })
fastify.listen(3000)
```
+## Deployment
+
+Frourio is complete in one directory, but not monolithic.
+Frontend and server are just statically connected by a type and are separate projects.
+So they can be deployed in different environments.
+
+
+
+### Frontend
+
+```sh
+$ npm run build:front
+$ npm run start:front
+```
+
+
+
+### Server
+
+```sh
+$ npm run build:server
+$ npm run start:server
+```
+
+or
+
+```sh
+$ cd server
+$ npm run build
+$ npm run start
+```
+
## Dependency Injection
diff --git a/docs/ja/README.md b/docs/ja/README.md
new file mode 100644
index 0000000..2c1f979
--- /dev/null
+++ b/docs/ja/README.md
@@ -0,0 +1,995 @@
+
+
+
+
+
+
+
+Frourio is a perfectly type-checkable REST framework for TypeScript.
+
+
+
+
+
+## Why frourio ?
+
+フロントエンドとバックエンドの両方をTypeScriptで書いたとしても、APIの疎通を静的に型検査することは出来ない
+
+常に "2つのTypeScript" を書かされている
+我々はブラウザとサーバーを動的にテストすることに多くの時間を浪費している
+
+
+
+
+
+
+
+Frourio は "1つのTypeScript" で速く安全に開発するためのフレームワーク
+
+
+
+
+
+
+
+## Benchmarks
+
+__Machine:__ Linux fv-az18 5.4.0-1026-azure #26~18.04.1-Ubuntu SMP Thu Sep 10 16:19:25 UTC 2020 x86_64 x86_64 x86_64 GNU/Linux | 2 vCPUs | 7GB.
+__Method:__ `autocannon -c 100 -d 40 -p 10 localhost:3000` (two rounds; one to warm-up, one to measure).
+
+| Framework | Version | Requests/sec | Latency |
+| :------------------ | :--------------- | ------------: | --------: |
+| fastify | 3.5.1 | 38,018 | 2.54 |
+| **frourio** | **0.17.0** | **36,815** | **2.62** |
+| nest-fastify | 7.4.4 | 31,960 | 3.04 |
+| micro | 9.3.4 | 29,672 | 3.28 |
+| express | 4.17.1 | 8,239 | 11.98 |
+| nest | 7.4.4 | 7,311 | 13.54 |
+| frourio-express | 0.17.0 | 7,235 | 13.67 |
+
+出典: https://github.com/frouriojs/benchmarks
+
+## Table of Contents
+
+- [Install](#Install)
+- [Express.js mode](#Expressjs)
+- [Environment](#Environment)
+- [Entrypoint](#Entrypoint)
+- [Controller](#Controller)
+ - [Case 1 - Define GET: /tasks?limit={number}](#Controller-case1)
+ - [Case 2 - Define POST: /tasks](#Controller-case2)
+ - [Case 3 - Define GET: /tasks/{taskId}](#Controller-case3)
+- [HTTP client](#HttpClient)
+- [Hooks](#Hooks)
+ - [Lifecycle](#Lifecycle)
+ - [Directory level hooks](#Hooks-dir)
+ - [Controller level hooks](#Hooks-ctrl)
+ - [Login with fastify-auth](#Hooks-login)
+- [Validation](#Validation)
+ - [Path parameter](#Validation-path)
+ - [URL query](#Validation-query)
+ - [JSON body](#Validation-json)
+ - [Custom validation](#Validation-custom)
+- [Error handling](#Error)
+ - [Controller error handler](#Error-controller)
+ - [The default error handler](#Error-default)
+- [FormData](#FormData)
+ - [Options](#FormData-options)
+- [O/R mapping tool](#ORM)
+ - [Prisma](#ORM-prisma)
+ - [TypeORM](#ORM-typeorm)
+- [CORS / Helmet](#CORS-Helmet)
+- [Deployment](#Deployment)
+ - [Frontend](#Deployment-frontend)
+ - [Server](#Deployment-server)
+- [Dependency Injection](#DI)
+
+## Install
+
+Make sure you have [npx](https://www.npmjs.com/package/npx) installed (`npx` is shipped by default since [npm](https://www.npmjs.com/get-npm) `5.2.0`)
+
+```sh
+$ npx create-frourio-app
+```
+
+Or starting with npm v6.1 you can do:
+
+```sh
+$ npm init frourio-app
+```
+
+Or with [yarn](https://yarnpkg.com/en/):
+
+```sh
+$ yarn create frourio-app
+```
+
+
+
+## Express.js mode
+
+frourio は HTTPサーバーに [Fastify](https://www.fastify.io/) を採用している
+もし create-frourio-app で [Express](https://expressjs.com/) を選んだ場合は以下リポジトリを参照
+[GitHub: frourio-express](https://github.com/frouriojs/frourio-express)
+
+※ frourio は frourio-express よりも5倍以上速い
+
+## Environment
+
+frourio は TypeScript >= v3.9 と Node.js >= v12 の環境で動作する
+もし VSCode の TypeScript バージョンが低いと開発中にエラーが表示される
+
+## Entrypoint
+
+`server/index.ts`
+
+```ts
+import Fastify from 'fastify'
+import server from './$server' // '$server.ts' は frourio が自動生成
+
+const fastify = Fastify()
+
+server(fastify, { basePath: '/api/v1' })
+fastify.listen(3000)
+```
+
+## Controller
+
+```sh
+$ npm run dev
+```
+
+
+
+### Case 1 - Define GET: /tasks?limit={number}
+
+`server/types/index.ts`
+
+```ts
+export type Task = {
+ id: number
+ label: string
+ done: boolean
+}
+```
+
+`server/api/tasks/index.ts`
+
+```ts
+import { Task } from '$/types' // path alias $ -> server
+
+export type Methods = {
+ get: {
+ query: {
+ limit: number
+ }
+
+ resBody: Task[]
+ }
+}
+```
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay' // '$relay.ts' は frourio が自動生成
+import { getTasks } from '$/service/tasks'
+
+export default defineController(() => ({
+ get: async ({ query }) => ({
+ status: 200,
+ body: (await getTasks()).slice(0, query.limit)
+ })
+}))
+```
+
+
+
+### Case 2 - Define POST: /tasks
+
+`server/api/tasks/index.ts`
+
+```ts
+import { Task } from '$/types' // path alias $ -> server
+
+export type Methods = {
+ post: {
+ reqBody: Pick
+ status: 201
+ resBody: Task
+ }
+}
+```
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay' // '$relay.ts' は frourio が自動生成
+import { createTask } from '$/service/tasks'
+
+export default defineController(() => ({
+ post: async ({ body }) => {
+ const task = await createTask(body.label)
+
+ return { status: 201, body: task }
+ }
+}))
+```
+
+
+
+### Case 3 - Define GET: /tasks/{taskId}
+
+`server/api/tasks/_taskId@number/index.ts`
+
+```ts
+import { Task } from '$/types' // path alias $ -> server
+
+export type Methods = {
+ get: {
+ resBody: Task
+ }
+}
+```
+
+`server/api/tasks/_taskId@number/controller.ts`
+
+```ts
+import { defineController } from './$relay' // '$relay.ts' is は frourio が自動生成
+import { findTask } from '$/service/tasks'
+
+export default defineController(() => ({
+ get: async ({ params }) => {
+ const task = await findTask(params.taskId)
+
+ return task ? { status: 200, body: task } : { status: 404 }
+ }
+}))
+```
+
+
+
+## HTTP client
+
+[aspida](https://github.com/aspida/aspida) を HTTP クライアントとして利用する
+(frourio と aspida は同じ開発者によってメンテナンスされている)
+
+Next.js は [@aspida/swr](https://github.com/aspida/aspida/tree/master/packages/aspida-swr) も併用する
+
+## Hooks
+
+frourio は Fastify の hooks を扱える
+onRequest / preParsing / preValidation / preHandler の4種類のみ
+
+### Lifecycle
+
+```
+Incoming Request
+ │
+ └─▶ Routing
+ │
+ 404 ◀─┴─▶ onRequest Hook
+ │
+ 4**/5** ◀─┴─▶ preParsing Hook
+ │
+ 4**/5** ◀─┴─▶ Parsing
+ │
+ 4**/5** ◀─┴─▶ preValidation Hook
+ │
+ 4**/5** ◀─┴─▶ Validation
+ │
+ 400 ◀─┴─▶ preHandler Hook
+ │
+ 4**/5** ◀─┴─▶ User Handler
+ │
+ 4**/5** ◀─┴─▶ Outgoing Response
+```
+
+
+
+### Directory level hooks
+
+Directory level hooks は自身と配下のエンドポイントで呼ばれる
+
+`server/api/tasks/hooks.ts`
+
+```ts
+import { defineHooks } from './$relay' // '$relay.ts' is automatically generated by frourio
+
+export default defineHooks(() => ({
+ onRequest: [
+ (req, reply, done) => {
+ console.log('Directory level onRequest first hook:', req.url)
+ done()
+ },
+ (req, reply, done) => {
+ console.log('Directory level onRequest second hook:', req.url)
+ done()
+ }
+ ],
+ preParsing: (req, reply, payload, done) => {
+ console.log('Directory level preParsing single hook:', req.url)
+ done()
+ }
+}))
+```
+
+
+
+### Controller level hooks
+
+Controller level hooks は自身のエンドポイントのみで Directory level hooks のあとに呼ばれる
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineHooks, defineController } from './$relay' // '$relay.ts' is automatically generated by frourio
+import { getTasks, createTask } from '$/service/tasks'
+
+export const hooks = defineHooks(() => ({
+ onRequest: (req, reply, done) => {
+ console.log('Controller level onRequest single hook:', req.url)
+ done()
+ },
+ preParsing: [
+ (req, reply, payload, done) => {
+ console.log('Controller level preParsing first hook:', req.url)
+ done()
+ },
+ (req, reply, payload, done) => {
+ console.log('Controller level preParsing second hook:', req.url)
+ done()
+ }
+ ]
+}))
+
+export default defineController(() => ({
+ get: async ({ query }) => ({
+ status: 200,
+ body: (await getTasks()).slice(0, query.limit)
+ }),
+ post: async ({ body }) => {
+ const task = await createTask(body.label)
+
+ return { status: 201, body: task }
+ }
+}))
+```
+
+
+
+### Login with fastify-auth
+
+```sh
+$ cd server
+$ npm install fastify-auth
+```
+
+```sh
+$ cd server
+$ yarn add fastify-auth
+```
+
+`server/index.ts`
+
+```ts
+import Fastify from 'fastify'
+import fastifyAuth from 'fastify-auth'
+import server from './$server' // '$server.ts' is automatically generated by frourio
+
+const fastify = Fastify()
+
+fastify.register(fastifyAuth).after(() => {
+ server(fastify, { basePath: '/api/v1' })
+})
+fastify.listen(3000)
+```
+
+`server/api/user/hooks.ts`
+
+```ts
+import { defineHooks } from './$relay' // '$relay.ts' is automatically generated by frourio
+import { getUserIdByToken } from '$/service/user'
+
+// Export the User in hooks.ts to receive the user in controller.ts
+export type User = {
+ id: string
+}
+
+export default defineHooks((fastify) => ({
+ preHandler: fastify.auth([
+ (req, _, done) => {
+ const user =
+ typeof req.headers.token === 'string' &&
+ getUserIdByToken(req.headers.token)
+
+ if (user) {
+ // eslint-disable-next-line
+ // @ts-expect-error
+ req.user = user
+ done()
+ } else {
+ done(new Error('Unauthorized'))
+ }
+ }
+ ])
+}))
+```
+
+`server/api/user/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { getUserNameById } from '$/service/user'
+
+export default defineController(() => ({
+ get: async ({ user }) => ({ status: 200, body: await getUserNameById(user.id) })
+}))
+```
+
+## Validation
+
+
+
+### Path parameter
+
+Path parameter can be specified as string or number type after `@`.
+(Default is `string | number`)
+
+`server/api/tasks/_taskId@number/index.ts`
+
+```ts
+import { Task } from '$/types'
+
+export type Methods = {
+ get: {
+ resBody: Task
+ }
+}
+```
+
+`server/api/tasks/_taskId@number/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { findTask } from '$/service/tasks'
+
+export default defineController(() => ({
+ get: async ({ params }) => {
+ const task = await findTask(params.taskId)
+
+ return task ? { status: 200, body: task } : { status: 404 }
+ }
+}))
+```
+
+```sh
+$ curl http://localhost:8080/api/tasks
+[{"id":0,"label":"sample task","done":false}]
+
+$ curl http://localhost:8080/api/tasks/0
+{"id":0,"label":"sample task","done":false}
+
+$ curl http://localhost:8080/api/tasks/1 -i
+HTTP/1.1 404 Not Found
+
+$ curl http://localhost:8080/api/tasks/abc -i
+HTTP/1.1 400 Bad Request
+```
+
+
+
+### URL query
+
+number または number[] のプロパティは自動でバリデーションされる
+
+`server/api/tasks/index.ts`
+
+```ts
+import { Task } from '$/types'
+
+export type Methods = {
+ get: {
+ query?: {
+ limit: number
+ }
+ resBody: Task[]
+ }
+}
+```
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { getTasks } from '$/service/tasks'
+
+export default defineController(() => ({
+ get: async ({ query }) => ({
+ status: 200,
+ body: (await getTasks()).slice(0, query?.limit)
+ })
+}))
+```
+
+```sh
+$ curl http://localhost:8080/api/tasks
+[{"id":0,"label":"sample task 0","done":false},{"id":1,"label":"sample task 1","done":false},{"id":1,"label":"sample task 2","done":false}]
+
+$ curl http://localhost:8080/api/tasks?limit=1
+[{"id":0,"label":"sample task 0","done":false}]
+
+$ curl http://localhost:8080/api/tasks?limit=abc -i
+HTTP/1.1 400 Bad Request
+```
+
+
+
+### JSON body
+
+reqFormat の指定がない場合、 reqBody は `application/json` としてパースされる
+
+`server/api/tasks/index.ts`
+
+```ts
+import { Task } from '$/types'
+
+export type Methods = {
+ post: {
+ reqBody: Pick
+ resBody: Task
+ }
+}
+```
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { createTask } from '$/service/tasks'
+
+export default defineController(() => ({
+ post: async ({ body }) => {
+ const task = await createTask(body.label)
+
+ return { status: 201, body: task }
+ }
+}))
+```
+
+```sh
+$ curl -X POST -H "Content-Type: application/json" -d '{"label":"sample task3"}' http://localhost:8080/api/tasks
+{"id":3,"label":"sample task 3","done":false}
+
+$ curl -X POST -H "Content-Type: application/json" -d '{Invalid JSON}' http://localhost:8080/api/tasks -i
+HTTP/1.1 400 Bad Request
+```
+
+
+
+### Custom validation
+
+クラスで定義された query / reqHeaders / reqBody は [class-validator](https://github.com/typestack/class-validator) でバリデーションされる
+このクラスは `server/validators/index.ts` でエクスポートする必要がある
+
+`server/validators/index.ts`
+
+```ts
+import { MinLength, IsString } from 'class-validator'
+
+export class LoginBody {
+ @MinLength(5)
+ id: string
+
+ @MinLength(8)
+ pass: string
+}
+
+export class TokenHeader {
+ @IsString()
+ @MinLength(10)
+ token: string
+}
+```
+
+`server/api/token/index.ts`
+
+```ts
+import { LoginBody, TokenHeader } from '$/validators'
+
+export type Methods = {
+ post: {
+ reqBody: LoginBody
+ resBody: {
+ token: string
+ }
+ }
+
+ delete: {
+ reqHeaders: TokenHeader
+ }
+}
+```
+
+```sh
+$ curl -X POST -H "Content-Type: application/json" -d '{"id":"correctId","pass":"correctPass"}' http://localhost:8080/api/token
+{"token":"XXXXXXXXXX"}
+
+$ curl -X POST -H "Content-Type: application/json" -d '{"id":"abc","pass":"12345"}' http://localhost:8080/api/token -i
+HTTP/1.1 400 Bad Request
+
+$ curl -X POST -H "Content-Type: application/json" -d '{"id":"incorrectId","pass":"incorrectPass"}' http://localhost:8080/api/token -i
+HTTP/1.1 401 Unauthorized
+```
+
+
+
+## Error handling
+
+
+
+### Controller error handler
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { createTask } from '$/service/tasks'
+
+export default defineController(() => ({
+ post: async ({ body }) => {
+ try {
+ const task = await createTask(body.label)
+
+ return { status: 201, body: task }
+ } catch (e) {
+ return { status: 500, body: 'Something broke!' }
+ }
+ }
+}))
+```
+
+
+
+### The default error handler
+
+https://github.com/fastify/fastify/blob/master/docs/Hooks.md#onerror
+
+`server/index.ts`
+
+```ts
+import Fastify from 'fastify'
+import server from './$server'
+
+const fastify = Fastify()
+
+server(fastify, { basePath: '/api/v1' })
+
+fastify.addHook('onError', (req, reply, err) => {
+ console.error(err.stack)
+})
+fastify.listen(3000)
+```
+
+## FormData
+
+FormData は [fastify-multipart](https://github.com/fastify/fastify-multipart) で自動パースされる
+
+`server/api/user/index.ts`
+
+```ts
+export type Methods = {
+ post: {
+ reqFormat: FormData
+ reqBody: { icon: Blob }
+ status: 204
+ }
+}
+```
+
+Blob または Blob[] のプロパティは Multipart object に変換される
+
+`server/api/user/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { changeIcon } from '$/service/user'
+
+export default defineController(() => ({
+ post: async ({ params, body }) => {
+ // body.icon is multer object
+ await changeIcon(params.userId, body.icon)
+
+ return { status: 204 }
+ }
+}))
+```
+
+
+
+### Options
+
+https://github.com/mscdex/busboy#busboy-methods
+
+`server/index.ts`
+
+```ts
+import Fastify from 'fastify'
+import server from './$server' // '$server.ts' is automatically generated by frourio
+
+const fastify = Fastify()
+
+server(fastify, { basePath: '/api/v1', multipart: { /* limit, ... */} })
+fastify.listen(3000)
+```
+
+
+
+## O/R mapping tool
+
+
+
+### Prisma
+
+1. create-frourio-app でDBを選択
+1. DB を起動
+1. 開発コマンドを呼ぶ
+ ```sh
+ $ npm run dev
+ ```
+1. スキーマファイルを作成
+ `server/prisma/schema.prisma`
+
+ ```ts
+ datasource db {
+ provider = "mysql"
+ url = env("DATABASE_URL")
+ }
+
+ generator client {
+ provider = "prisma-client-js"
+ }
+
+ model Task {
+ id Int @id @default(autoincrement())
+ label String
+ done Boolean @default(false)
+ }
+ ```
+1. マイグレーションコマンドを呼ぶ
+ ```sh
+ $ npm run migrate
+ ```
+1. DB がマイグレーションされる
+
+
+
+### TypeORM
+
+1. create-frourio-app でDBを選択
+1. DB を起動
+1. 開発コマンドを呼ぶ
+ ```sh
+ $ npm run dev
+ ```
+1. エンティティファイルを作成
+ `server/entity/Task.ts`
+
+ ```ts
+ import { Entity, PrimaryGeneratedColumn, Column } from 'typeorm'
+
+ @Entity()
+ export class Task {
+ @PrimaryGeneratedColumn()
+ id: number
+
+ @Column({ length: 100 })
+ label: string
+
+ @Column({ default: false })
+ done: boolean
+ }
+ ```
+1. マイグレーションコマンドを呼ぶ
+ ```sh
+ $ npm run migration:generate
+ ```
+1. DB がマイグレーションされる
+
+
+
+## CORS / Helmet
+
+```sh
+$ cd server
+$ npm install fastify-cors fastify-helmet
+```
+
+`server/index.ts`
+
+```ts
+import Fastify from 'fastify'
+import helmet from 'helmet'
+import cors from 'fastify-cors'
+import server from './$server'
+
+const fastify = Fastify()
+fastify.register(helmet)
+fastify.register(cors)
+
+server(fastify, { basePath: '/api/v1' })
+fastify.listen(3000)
+```
+
+## Deployment
+
+frourio は一つのディレクトリで完結しているが、モノリシックではない
+フロントエンドとバックエンドは静的に型で繋がっているだけで個別のプロジェクトである
+なのでそれぞれ異なる環境にデプロイができる
+
+
+
+### Frontend
+
+```sh
+$ npm run build:front
+$ npm run start:front
+```
+
+
+
+### Server
+
+```sh
+$ npm run build:server
+$ npm run start:server
+```
+
+or
+
+```sh
+$ cd server
+$ npm run build
+$ npm run start
+```
+
+
+
+## Dependency Injection
+
+Frourio use [frouriojs/velona](https://github.com/frouriojs/velona) for dependency injection.
+
+`server/api/tasks/index.ts`
+
+```ts
+import { Task } from '$/types'
+
+export type Methods = {
+ get: {
+ query?: {
+ limit?: number
+ message?: string
+ }
+
+ resBody: Task[]
+ }
+}
+```
+
+`server/service/tasks.ts`
+
+```ts
+import { PrismaClient } from '@prisma/client'
+import { depend } from 'velona' // dependency of frourio
+import { Task } from '$/types'
+
+const prisma = new PrismaClient()
+
+export const getTasks = depend(
+ { prisma: prisma as { task: { findMany(): Promise } } }, // inject prisma
+ async ({ prisma }, limit?: number) => // prisma is injected object
+ (await prisma.task.findMany()).slice(0, limit)
+)
+```
+
+`server/api/tasks/controller.ts`
+
+```ts
+import { defineController } from './$relay'
+import { getTasks } from '$/service/tasks'
+
+const print = (text: string) => console.log(text)
+
+export default defineController(
+ { getTasks, print }, // inject functions
+ ({ getTasks, print }) => ({ // getTasks and print are injected function
+ get: async ({ query }) => {
+ if (query?.message) print(query.message)
+
+ return { status: 200, body: await getTasks(query?.limit) }
+ }
+ })
+)
+```
+
+`server/test/server.test.ts`
+
+```ts
+import controller from '$/api/tasks/controller'
+import { getTasks } from '$/service/tasks'
+
+test('dependency injection into controller', async () => {
+ let printedMessage = ''
+
+ const injectedController = controller.inject({
+ getTasks: getTasks.inject({
+ prisma: {
+ task: {
+ findMany: () =>
+ Promise.resolve([
+ { id: 0, label: 'task1', done: false },
+ { id: 1, label: 'task2', done: false },
+ { id: 2, label: 'task3', done: true },
+ { id: 3, label: 'task4', done: true },
+ { id: 4, label: 'task5', done: false }
+ ])
+ }
+ }
+ }),
+ print: (text: string) => {
+ printedMessage = text
+ }
+ })()
+
+ const limit = 3
+ const message = 'test message'
+ const res = await injectedController.get({
+ query: { limit, message }
+ })
+
+ expect(res.body).toHaveLength(limit)
+ expect(printedMessage).toBe(message)
+})
+```
+
+```sh
+$ npm test
+
+PASS server/test/server.test.ts
+ ✓ dependency injection into controller (4 ms)
+
+Test Suites: 1 passed, 1 total
+Tests: 1 passed, 1 total
+Snapshots: 0 total
+Time: 0.67 s, estimated 8 s
+Ran all test suites.
+```
+
+## Support
+
+
+
+
+
+## License
+
+Frourio is licensed under a [MIT License](https://github.com/frouriojs/frourio/blob/master/LICENSE).
diff --git a/package.json b/package.json
index f35ad00..2d32242 100644
--- a/package.json
+++ b/package.json
@@ -1,6 +1,6 @@
{
"name": "frourio",
- "version": "0.17.1",
+ "version": "0.17.2",
"description": "Perfectly type-checkable REST framework for TypeScript",
"author": "Solufa ",
"license": "MIT",
@@ -90,11 +90,11 @@
"@aspida/axios": "^0.12.0",
"@types/busboy": "^0.2.3",
"@types/jest": "^26.0.14",
- "@typescript-eslint/eslint-plugin": "^4.4.0",
- "@typescript-eslint/parser": "^4.4.0",
+ "@typescript-eslint/eslint-plugin": "^4.4.1",
+ "@typescript-eslint/parser": "^4.4.1",
"axios": "^0.20.0",
"class-validator": "^0.12.2",
- "eslint": "^7.10.0",
+ "eslint": "^7.11.0",
"eslint-config-prettier": "^6.12.0",
"eslint-config-standard": "^14.1.1",
"eslint-plugin-import": "^2.22.1",
@@ -103,10 +103,10 @@
"eslint-plugin-prettier": "^3.1.4",
"eslint-plugin-promise": "^4.2.1",
"eslint-plugin-standard": "^4.0.1",
- "fastify": "^3.5.1",
+ "fastify": "^3.6.0",
"fastify-multipart": "^3.2.0",
"form-data": "^3.0.0",
- "jest": "^26.5.2",
+ "jest": "^26.5.3",
"prettier": "^2.1.2",
"standard-version": "^9.0.0",
"ts-jest": "^26.4.1",
diff --git a/servers/all/$server.ts b/servers/all/$server.ts
index a9f1fd6..e9b7151 100644
--- a/servers/all/$server.ts
+++ b/servers/all/$server.ts
@@ -165,16 +165,20 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
const asyncMethodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => async (req, reply) => {
const data = await methodCallback(req as any)
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
export default (fastify: FastifyInstance, options: FrourioOptions = {}) => {
diff --git a/servers/minimum/$server.ts b/servers/minimum/$server.ts
index 9fd55ac..aafe936 100644
--- a/servers/minimum/$server.ts
+++ b/servers/minimum/$server.ts
@@ -55,8 +55,10 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
export default (fastify: FastifyInstance, options: FrourioOptions = {}) => {
diff --git a/servers/noMulter/$server.ts b/servers/noMulter/$server.ts
index d0cd1c8..d680cf6 100644
--- a/servers/noMulter/$server.ts
+++ b/servers/noMulter/$server.ts
@@ -84,16 +84,20 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
const asyncMethodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => async (req, reply) => {
const data = await methodCallback(req as any)
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
export default (fastify: FastifyInstance, options: FrourioOptions = {}) => {
diff --git a/servers/noTypedParams/$server.ts b/servers/noTypedParams/$server.ts
index 24028cc..9205376 100644
--- a/servers/noTypedParams/$server.ts
+++ b/servers/noTypedParams/$server.ts
@@ -104,16 +104,20 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
const asyncMethodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => async (req, reply) => {
const data = await methodCallback(req as any)
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
export default (fastify: FastifyInstance, options: FrourioOptions = {}) => {
diff --git a/servers/noValidator/$server.ts b/servers/noValidator/$server.ts
index fc34c34..643e122 100644
--- a/servers/noValidator/$server.ts
+++ b/servers/noValidator/$server.ts
@@ -117,16 +117,20 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
const asyncMethodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => async (req, reply) => {
const data = await methodCallback(req as any)
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
export default (fastify: FastifyInstance, options: FrourioOptions = {}) => {
diff --git a/src/buildServerFile.ts b/src/buildServerFile.ts
index 8848993..e6d5883 100644
--- a/src/buildServerFile.ts
+++ b/src/buildServerFile.ts
@@ -192,8 +192,10 @@ const methodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => (req, reply) => {
const data = methodCallback(req as any) as any
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
`
: ''
@@ -204,8 +206,10 @@ const asyncMethodToHandler = (
methodCallback: ServerMethods[LowerHttpMethod]
): RouteHandlerMethod => async (req, reply) => {
const data = await methodCallback(req as any)
-
- reply.code(data.status).headers(data.headers ?? {}).send(data.body)
+
+ if (data.headers) reply.headers(data.headers)
+
+ reply.code(data.status).send(data.body)
}
`
: ''
diff --git a/yarn.lock b/yarn.lock
index e7c2407..77c448b 100644
--- a/yarn.lock
+++ b/yarn.lock
@@ -322,13 +322,13 @@
jest-util "^26.5.2"
slash "^3.0.0"
-"@jest/core@^26.5.2":
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.5.2.tgz#e39f14676f4ba4632ecabfdc374071ab22131f22"
- integrity sha512-LLTo1LQMg7eJjG/+P1NYqFof2B25EV1EqzD5FonklihG4UJKiK2JBIvWonunws6W7e+DhNLoFD+g05tCY03eyA==
+"@jest/core@^26.5.3":
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/@jest/core/-/core-26.5.3.tgz#712ed4adb64c3bda256a3f400ff1d3eb2a031f13"
+ integrity sha512-CiU0UKFF1V7KzYTVEtFbFmGLdb2g4aTtY0WlyUfLgj/RtoTnJFhh50xKKr7OYkdmBUlGFSa2mD1TU3UZ6OLd4g==
dependencies:
"@jest/console" "^26.5.2"
- "@jest/reporters" "^26.5.2"
+ "@jest/reporters" "^26.5.3"
"@jest/test-result" "^26.5.2"
"@jest/transform" "^26.5.2"
"@jest/types" "^26.5.2"
@@ -338,17 +338,17 @@
exit "^0.1.2"
graceful-fs "^4.2.4"
jest-changed-files "^26.5.2"
- jest-config "^26.5.2"
+ jest-config "^26.5.3"
jest-haste-map "^26.5.2"
jest-message-util "^26.5.2"
jest-regex-util "^26.0.0"
jest-resolve "^26.5.2"
- jest-resolve-dependencies "^26.5.2"
- jest-runner "^26.5.2"
- jest-runtime "^26.5.2"
- jest-snapshot "^26.5.2"
+ jest-resolve-dependencies "^26.5.3"
+ jest-runner "^26.5.3"
+ jest-runtime "^26.5.3"
+ jest-snapshot "^26.5.3"
jest-util "^26.5.2"
- jest-validate "^26.5.2"
+ jest-validate "^26.5.3"
jest-watcher "^26.5.2"
micromatch "^4.0.2"
p-each-series "^2.1.0"
@@ -378,19 +378,19 @@
jest-mock "^26.5.2"
jest-util "^26.5.2"
-"@jest/globals@^26.5.2":
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.5.2.tgz#c333f82c29e19ecb609a75d1a532915a5c956c59"
- integrity sha512-9PmnFsAUJxpPt1s/stq02acS1YHliVBDNfAWMe1bwdRr1iTCfhbNt3ERQXrO/ZfZSweftoA26Q/2yhSVSWQ3sw==
+"@jest/globals@^26.5.3":
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/@jest/globals/-/globals-26.5.3.tgz#90769b40e0af3fa0b28f6d8c5bbe3712467243fd"
+ integrity sha512-7QztI0JC2CuB+Wx1VdnOUNeIGm8+PIaqngYsZXQCkH2QV0GFqzAYc9BZfU0nuqA6cbYrWh5wkuMzyii3P7deug==
dependencies:
"@jest/environment" "^26.5.2"
"@jest/types" "^26.5.2"
- expect "^26.5.2"
+ expect "^26.5.3"
-"@jest/reporters@^26.5.2":
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.5.2.tgz#0f1c900c6af712b46853d9d486c9c0382e4050f6"
- integrity sha512-zvq6Wvy6MmJq/0QY0YfOPb49CXKSf42wkJbrBPkeypVa8I+XDxijvFuywo6TJBX/ILPrdrlE/FW9vJZh6Rf9vA==
+"@jest/reporters@^26.5.3":
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/@jest/reporters/-/reporters-26.5.3.tgz#e810e9c2b670f33f1c09e9975749260ca12f1c17"
+ integrity sha512-X+vR0CpfMQzYcYmMFKNY9n4jklcb14Kffffp7+H/MqitWnb0440bW2L76NGWKAa+bnXhNoZr+lCVtdtPmfJVOQ==
dependencies:
"@bcoe/v8-coverage" "^0.2.3"
"@jest/console" "^26.5.2"
@@ -415,7 +415,7 @@
source-map "^0.6.0"
string-length "^4.0.1"
terminal-link "^2.0.0"
- v8-to-istanbul "^5.0.1"
+ v8-to-istanbul "^6.0.1"
optionalDependencies:
node-notifier "^8.0.0"
@@ -438,16 +438,16 @@
"@types/istanbul-lib-coverage" "^2.0.0"
collect-v8-coverage "^1.0.0"
-"@jest/test-sequencer@^26.5.2":
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.5.2.tgz#c4559c7e134b27b020317303ee5399bf62917a4b"
- integrity sha512-XmGEh7hh07H2B8mHLFCIgr7gA5Y6Hw1ZATIsbz2fOhpnQ5AnQtZk0gmP0Q5/+mVB2xygO64tVFQxOajzoptkNA==
+"@jest/test-sequencer@^26.5.3":
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/@jest/test-sequencer/-/test-sequencer-26.5.3.tgz#9ae0ab9bc37d5171b28424029192e50229814f8d"
+ integrity sha512-Wqzb7aQ13L3T47xHdpUqYMOpiqz6Dx2QDDghp5AV/eUDXR7JieY+E1s233TQlNyl+PqtqgjVokmyjzX/HA51BA==
dependencies:
"@jest/test-result" "^26.5.2"
graceful-fs "^4.2.4"
jest-haste-map "^26.5.2"
- jest-runner "^26.5.2"
- jest-runtime "^26.5.2"
+ jest-runner "^26.5.3"
+ jest-runtime "^26.5.3"
"@jest/transform@^26.5.2":
version "26.5.2"
@@ -676,28 +676,28 @@
dependencies:
"@types/yargs-parser" "*"
-"@typescript-eslint/eslint-plugin@^4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.4.0.tgz#0321684dd2b902c89128405cf0385e9fe8561934"
- integrity sha512-RVt5wU9H/2H+N/ZrCasTXdGbUTkbf7Hfi9eLiA8vPQkzUJ/bLDCC3CsoZioPrNcnoyN8r0gT153dC++A4hKBQQ==
+"@typescript-eslint/eslint-plugin@^4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/eslint-plugin/-/eslint-plugin-4.4.1.tgz#b8acea0373bd2a388ac47df44652f00bf8b368f5"
+ integrity sha512-O+8Utz8pb4OmcA+Nfi5THQnQpHSD2sDUNw9AxNHpuYOo326HZTtG8gsfT+EAYuVrFNaLyNb2QnUNkmTRDskuRA==
dependencies:
- "@typescript-eslint/experimental-utils" "4.4.0"
- "@typescript-eslint/scope-manager" "4.4.0"
+ "@typescript-eslint/experimental-utils" "4.4.1"
+ "@typescript-eslint/scope-manager" "4.4.1"
debug "^4.1.1"
functional-red-black-tree "^1.0.1"
regexpp "^3.0.0"
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/experimental-utils@4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.4.0.tgz#62a05d3f543b8fc5dec4982830618ea4d030e1a9"
- integrity sha512-01+OtK/oWeSJTjQcyzDztfLF1YjvKpLFo+JZmurK/qjSRcyObpIecJ4rckDoRCSh5Etw+jKfdSzVEHevh9gJ1w==
+"@typescript-eslint/experimental-utils@4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/experimental-utils/-/experimental-utils-4.4.1.tgz#40613b9757fa0170de3e0043254dbb077cafac0c"
+ integrity sha512-Nt4EVlb1mqExW9cWhpV6pd1a3DkUbX9DeyYsdoeziKOpIJ04S2KMVDO+SEidsXRH/XHDpbzXykKcMTLdTXH6cQ==
dependencies:
"@types/json-schema" "^7.0.3"
- "@typescript-eslint/scope-manager" "4.4.0"
- "@typescript-eslint/types" "4.4.0"
- "@typescript-eslint/typescript-estree" "4.4.0"
+ "@typescript-eslint/scope-manager" "4.4.1"
+ "@typescript-eslint/types" "4.4.1"
+ "@typescript-eslint/typescript-estree" "4.4.1"
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
@@ -713,14 +713,14 @@
eslint-scope "^5.0.0"
eslint-utils "^2.0.0"
-"@typescript-eslint/parser@^4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.4.0.tgz#65974db9a75f23b036f17b37e959b5f99b659ec0"
- integrity sha512-yc14iEItCxoGb7W4Nx30FlTyGpU9r+j+n1LUK/exlq2eJeFxczrz/xFRZUk2f6yzWfK+pr1DOTyQnmDkcC4TnA==
+"@typescript-eslint/parser@^4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/parser/-/parser-4.4.1.tgz#25fde9c080611f303f2f33cedb145d2c59915b80"
+ integrity sha512-S0fuX5lDku28Au9REYUsV+hdJpW/rNW0gWlc4SXzF/kdrRaAVX9YCxKpziH7djeWT/HFAjLZcnY7NJD8xTeUEg==
dependencies:
- "@typescript-eslint/scope-manager" "4.4.0"
- "@typescript-eslint/types" "4.4.0"
- "@typescript-eslint/typescript-estree" "4.4.0"
+ "@typescript-eslint/scope-manager" "4.4.1"
+ "@typescript-eslint/types" "4.4.1"
+ "@typescript-eslint/typescript-estree" "4.4.1"
debug "^4.1.1"
"@typescript-eslint/scope-manager@4.3.0":
@@ -731,23 +731,23 @@
"@typescript-eslint/types" "4.3.0"
"@typescript-eslint/visitor-keys" "4.3.0"
-"@typescript-eslint/scope-manager@4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.4.0.tgz#2f3dd27692a12cc9a046a90ba6a9d8cb7731190a"
- integrity sha512-r2FIeeU1lmW4K3CxgOAt8djI5c6Q/5ULAgdVo9AF3hPMpu0B14WznBAtxrmB/qFVbVIB6fSx2a+EVXuhSVMEyA==
+"@typescript-eslint/scope-manager@4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/scope-manager/-/scope-manager-4.4.1.tgz#d19447e60db2ce9c425898d62fa03b2cce8ea3f9"
+ integrity sha512-2oD/ZqD4Gj41UdFeWZxegH3cVEEH/Z6Bhr/XvwTtGv66737XkR4C9IqEkebCuqArqBJQSj4AgNHHiN1okzD/wQ==
dependencies:
- "@typescript-eslint/types" "4.4.0"
- "@typescript-eslint/visitor-keys" "4.4.0"
+ "@typescript-eslint/types" "4.4.1"
+ "@typescript-eslint/visitor-keys" "4.4.1"
"@typescript-eslint/types@4.3.0":
version "4.3.0"
resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.3.0.tgz#1f0b2d5e140543e2614f06d48fb3ae95193c6ddf"
integrity sha512-Cx9TpRvlRjOppGsU6Y6KcJnUDOelja2NNCX6AZwtVHRzaJkdytJWMuYiqi8mS35MRNA3cJSwDzXePfmhU6TANw==
-"@typescript-eslint/types@4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.4.0.tgz#63440ef87a54da7399a13bdd4b82060776e9e621"
- integrity sha512-nU0VUpzanFw3jjX+50OTQy6MehVvf8pkqFcURPAE06xFNFenMj1GPEI6IESvp7UOHAnq+n/brMirZdR+7rCrlA==
+"@typescript-eslint/types@4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/types/-/types-4.4.1.tgz#c507b35cf523bc7ba00aae5f75ee9b810cdabbc1"
+ integrity sha512-KNDfH2bCyax5db+KKIZT4rfA8rEk5N0EJ8P0T5AJjo5xrV26UAzaiqoJCxeaibqc0c/IvZxp7v2g3difn2Pn3w==
"@typescript-eslint/typescript-estree@4.3.0":
version "4.3.0"
@@ -763,13 +763,13 @@
semver "^7.3.2"
tsutils "^3.17.1"
-"@typescript-eslint/typescript-estree@4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.4.0.tgz#16a2df7c16710ddd5406b32b86b9c1124b1ca526"
- integrity sha512-Fh85feshKXwki4nZ1uhCJHmqKJqCMba+8ZicQIhNi5d5jSQFteWiGeF96DTjO8br7fn+prTP+t3Cz/a/3yOKqw==
+"@typescript-eslint/typescript-estree@4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/typescript-estree/-/typescript-estree-4.4.1.tgz#598f6de488106c2587d47ca2462c60f6e2797cb8"
+ integrity sha512-wP/V7ScKzgSdtcY1a0pZYBoCxrCstLrgRQ2O9MmCUZDtmgxCO/TCqOTGRVwpP4/2hVfqMz/Vw1ZYrG8cVxvN3g==
dependencies:
- "@typescript-eslint/types" "4.4.0"
- "@typescript-eslint/visitor-keys" "4.4.0"
+ "@typescript-eslint/types" "4.4.1"
+ "@typescript-eslint/visitor-keys" "4.4.1"
debug "^4.1.1"
globby "^11.0.1"
is-glob "^4.0.1"
@@ -785,12 +785,12 @@
"@typescript-eslint/types" "4.3.0"
eslint-visitor-keys "^2.0.0"
-"@typescript-eslint/visitor-keys@4.4.0":
- version "4.4.0"
- resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.4.0.tgz#0a9118344082f14c0f051342a74b42dfdb012640"
- integrity sha512-oBWeroUZCVsHLiWRdcTXJB7s1nB3taFY8WGvS23tiAlT6jXVvsdAV4rs581bgdEjOhn43q6ro7NkOiLKu6kFqA==
+"@typescript-eslint/visitor-keys@4.4.1":
+ version "4.4.1"
+ resolved "https://registry.yarnpkg.com/@typescript-eslint/visitor-keys/-/visitor-keys-4.4.1.tgz#1769dc7a9e2d7d2cfd3318b77ed8249187aed5c3"
+ integrity sha512-H2JMWhLaJNeaylSnMSQFEhT/S/FsJbebQALmoJxMPMxLtlVAMy2uJP/Z543n9IizhjRayLSqoInehCeNW9rWcw==
dependencies:
- "@typescript-eslint/types" "4.4.0"
+ "@typescript-eslint/types" "4.4.1"
eslint-visitor-keys "^2.0.0"
JSONStream@^1.0.4:
@@ -2073,10 +2073,10 @@ eslint-visitor-keys@^2.0.0:
resolved "https://registry.yarnpkg.com/eslint-visitor-keys/-/eslint-visitor-keys-2.0.0.tgz#21fdc8fbcd9c795cc0321f0563702095751511a8"
integrity sha512-QudtT6av5WXels9WjIM7qz1XD1cWGvX4gGXvp/zBn9nXG02D0utdU3Em2m/QjTnrsk6bBjmCygl3rmj118msQQ==
-eslint@^7.10.0:
- version "7.10.0"
- resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.10.0.tgz#494edb3e4750fb791133ca379e786a8f648c72b9"
- integrity sha512-BDVffmqWl7JJXqCjAK6lWtcQThZB/aP1HXSH1JKwGwv0LQEdvpR7qzNrUT487RM39B5goWuboFad5ovMBmD8yA==
+eslint@^7.11.0:
+ version "7.11.0"
+ resolved "https://registry.yarnpkg.com/eslint/-/eslint-7.11.0.tgz#aaf2d23a0b5f1d652a08edacea0c19f7fadc0b3b"
+ integrity sha512-G9+qtYVCHaDi1ZuWzBsOWo2wSwd70TXnU6UHA3cTYHp7gCTXZcpggWFoUVAMRarg68qtPoNfFbzPh+VdOgmwmw==
dependencies:
"@babel/code-frame" "^7.0.0"
"@eslint/eslintrc" "^0.1.3"
@@ -2088,7 +2088,7 @@ eslint@^7.10.0:
enquirer "^2.3.5"
eslint-scope "^5.1.1"
eslint-utils "^2.1.0"
- eslint-visitor-keys "^1.3.0"
+ eslint-visitor-keys "^2.0.0"
espree "^7.3.0"
esquery "^1.2.0"
esutils "^2.0.2"
@@ -2210,10 +2210,10 @@ expand-brackets@^2.1.4:
snapdragon "^0.8.1"
to-regex "^3.0.1"
-expect@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/expect/-/expect-26.5.2.tgz#3e0631c4a657a83dbec769ad246a2998953a55a6"
- integrity sha512-ccTGrXZd8DZCcvCz4htGXTkd/LOoy6OEtiDS38x3/VVf6E4AQL0QoeksBiw7BtGR5xDNiRYPB8GN6pfbuTOi7w==
+expect@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/expect/-/expect-26.5.3.tgz#89d9795036f7358b0a9a5243238eb8086482d741"
+ integrity sha512-kkpOhGRWGOr+TEFUnYAjfGvv35bfP+OlPtqPIJpOCR9DVtv8QV+p8zG0Edqafh80fsjeE+7RBcVUq1xApnYglw==
dependencies:
"@jest/types" "^26.5.2"
ansi-styles "^4.0.0"
@@ -2352,10 +2352,10 @@ fastify-warning@^0.2.0:
resolved "https://registry.yarnpkg.com/fastify-warning/-/fastify-warning-0.2.0.tgz#e717776026a4493dc9a2befa44db6d17f618008f"
integrity sha512-s1EQguBw/9qtc1p/WTY4eq9WMRIACkj+HTcOIK1in4MV5aFaQC9ZCIt0dJ7pr5bIf4lPpHvAtP2ywpTNgs7hqw==
-fastify@^3.5.1:
- version "3.5.1"
- resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.5.1.tgz#753a6909e3154d61fcde7402500ed92177132c1a"
- integrity sha512-SO/ZZSbbAUrRxxz9zIsf1Ek5qqRux5EN03UF1lJGt/xwFzVpmW4h+p8kRCD08VCL1sItFy2dhFlR8FPaQfRGBw==
+fastify@^3.6.0:
+ version "3.6.0"
+ resolved "https://registry.yarnpkg.com/fastify/-/fastify-3.6.0.tgz#b5fae09eccecb2be9e4ff24abc98cd7f0f0d10c3"
+ integrity sha512-nz35mhJpJNjSPZzw05x+ITXokeIMmG3MFPzzS/yNzDfw24sGol7Gr3cN3+X3t3PZV1kQG9vJbKDUzgDA+YbbCA==
dependencies:
abstract-logging "^2.0.0"
ajv "^6.12.2"
@@ -2365,7 +2365,7 @@ fastify@^3.5.1:
fastify-warning "^0.2.0"
find-my-way "^3.0.0"
flatstr "^1.0.12"
- light-my-request "^4.0.2"
+ light-my-request "^4.1.0"
pino "^6.2.1"
proxy-addr "^2.0.5"
readable-stream "^3.4.0"
@@ -3213,12 +3213,12 @@ jest-changed-files@^26.5.2:
execa "^4.0.0"
throat "^5.0.0"
-jest-cli@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.5.2.tgz#0df114399b4036a3f046f0a9f25c50372c76b3a2"
- integrity sha512-usm48COuUvRp8YEG5OWOaxbSM0my7eHn3QeBWxiGUuFhvkGVBvl1fic4UjC02EAEQtDv8KrNQUXdQTV6ZZBsoA==
+jest-cli@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-cli/-/jest-cli-26.5.3.tgz#f936b98f247b76b7bc89c7af50af82c88e356a80"
+ integrity sha512-HkbSvtugpSXBf2660v9FrNVUgxvPkssN8CRGj9gPM8PLhnaa6zziFiCEKQAkQS4uRzseww45o0TR+l6KeRYV9A==
dependencies:
- "@jest/core" "^26.5.2"
+ "@jest/core" "^26.5.3"
"@jest/test-result" "^26.5.2"
"@jest/types" "^26.5.2"
chalk "^4.0.0"
@@ -3226,19 +3226,19 @@ jest-cli@^26.5.2:
graceful-fs "^4.2.4"
import-local "^3.0.2"
is-ci "^2.0.0"
- jest-config "^26.5.2"
+ jest-config "^26.5.3"
jest-util "^26.5.2"
- jest-validate "^26.5.2"
+ jest-validate "^26.5.3"
prompts "^2.0.1"
yargs "^15.4.1"
-jest-config@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.5.2.tgz#6e828e25f10124433dd008fbd83348636de0972a"
- integrity sha512-dqJOnSegNdE5yDiuGHsjTM5gec7Z4AcAMHiW+YscbOYJAlb3LEtDSobXCq0or9EmGQI5SFmKy4T7P1FxetJOfg==
+jest-config@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-config/-/jest-config-26.5.3.tgz#baf51c9be078c2c755c8f8a51ec0f06c762c1d3f"
+ integrity sha512-NVhZiIuN0GQM6b6as4CI5FSCyXKxdrx5ACMCcv/7Pf+TeCajJhJc+6dwgdAVPyerUFB9pRBIz3bE7clSrRge/w==
dependencies:
"@babel/core" "^7.1.0"
- "@jest/test-sequencer" "^26.5.2"
+ "@jest/test-sequencer" "^26.5.3"
"@jest/types" "^26.5.2"
babel-jest "^26.5.2"
chalk "^4.0.0"
@@ -3248,11 +3248,11 @@ jest-config@^26.5.2:
jest-environment-jsdom "^26.5.2"
jest-environment-node "^26.5.2"
jest-get-type "^26.3.0"
- jest-jasmine2 "^26.5.2"
+ jest-jasmine2 "^26.5.3"
jest-regex-util "^26.0.0"
jest-resolve "^26.5.2"
jest-util "^26.5.2"
- jest-validate "^26.5.2"
+ jest-validate "^26.5.3"
micromatch "^4.0.2"
pretty-format "^26.5.2"
@@ -3350,10 +3350,10 @@ jest-haste-map@^26.5.2:
optionalDependencies:
fsevents "^2.1.2"
-jest-jasmine2@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.5.2.tgz#0e33819d31b1f2aab5efd1e02ce502209c0e64a2"
- integrity sha512-2J+GYcgLVPTkpmvHEj0/IDTIAuyblGNGlyGe4fLfDT2aktEPBYvoxUwFiOmDDxxzuuEAD2uxcYXr0+1Yw4tjFA==
+jest-jasmine2@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-jasmine2/-/jest-jasmine2-26.5.3.tgz#baad2114ce32d16aff25aeb877d18bb4e332dc4c"
+ integrity sha512-nFlZOpnGlNc7y/+UkkeHnvbOM+rLz4wB1AimgI9QhtnqSZte0wYjbAm8hf7TCwXlXgDwZxAXo6z0a2Wzn9FoOg==
dependencies:
"@babel/traverse" "^7.1.0"
"@jest/environment" "^26.5.2"
@@ -3363,13 +3363,13 @@ jest-jasmine2@^26.5.2:
"@types/node" "*"
chalk "^4.0.0"
co "^4.6.0"
- expect "^26.5.2"
+ expect "^26.5.3"
is-generator-fn "^2.0.0"
jest-each "^26.5.2"
jest-matcher-utils "^26.5.2"
jest-message-util "^26.5.2"
- jest-runtime "^26.5.2"
- jest-snapshot "^26.5.2"
+ jest-runtime "^26.5.3"
+ jest-snapshot "^26.5.3"
jest-util "^26.5.2"
pretty-format "^26.5.2"
throat "^5.0.0"
@@ -3424,14 +3424,14 @@ jest-regex-util@^26.0.0:
resolved "https://registry.yarnpkg.com/jest-regex-util/-/jest-regex-util-26.0.0.tgz#d25e7184b36e39fd466c3bc41be0971e821fee28"
integrity sha512-Gv3ZIs/nA48/Zvjrl34bf+oD76JHiGDUxNOVgUjh3j890sblXryjY4rss71fPtD/njchl6PSE2hIhvyWa1eT0A==
-jest-resolve-dependencies@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.5.2.tgz#ee30b7cfea81c81bf5e195a9287d7ec07f893170"
- integrity sha512-LLkc8LuRtxqOx0AtX/Npa2C4I23WcIrwUgNtHYXg4owYF/ZDQShcwBAHjYZIFR06+HpQcZ43+kCTMlQ3aDCYTg==
+jest-resolve-dependencies@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-resolve-dependencies/-/jest-resolve-dependencies-26.5.3.tgz#11483f91e534bdcd257ab21e8622799e59701aba"
+ integrity sha512-+KMDeke/BFK+mIQ2IYSyBz010h7zQaVt4Xie6cLqUGChorx66vVeQVv4ErNoMwInnyYHi1Ud73tDS01UbXbfLQ==
dependencies:
"@jest/types" "^26.5.2"
jest-regex-util "^26.0.0"
- jest-snapshot "^26.5.2"
+ jest-snapshot "^26.5.3"
jest-resolve@^26.5.2:
version "26.5.2"
@@ -3447,10 +3447,10 @@ jest-resolve@^26.5.2:
resolve "^1.17.0"
slash "^3.0.0"
-jest-runner@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.5.2.tgz#4f9e6b0bb7eb4710c209a9e145b8a10894f4c19f"
- integrity sha512-GKhYxtSX5+tXZsd2QwfkDqPIj5C2HqOdXLRc2x2qYqWE26OJh17xo58/fN/mLhRkO4y6o60ZVloan7Kk5YA6hg==
+jest-runner@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-runner/-/jest-runner-26.5.3.tgz#800787459ea59c68e7505952933e33981dc3db38"
+ integrity sha512-qproP0Pq7IIule+263W57k2+8kWCszVJTC9TJWGUz0xJBr+gNiniGXlG8rotd0XxwonD5UiJloYoSO5vbUr5FQ==
dependencies:
"@jest/console" "^26.5.2"
"@jest/environment" "^26.5.2"
@@ -3461,27 +3461,27 @@ jest-runner@^26.5.2:
emittery "^0.7.1"
exit "^0.1.2"
graceful-fs "^4.2.4"
- jest-config "^26.5.2"
+ jest-config "^26.5.3"
jest-docblock "^26.0.0"
jest-haste-map "^26.5.2"
jest-leak-detector "^26.5.2"
jest-message-util "^26.5.2"
jest-resolve "^26.5.2"
- jest-runtime "^26.5.2"
+ jest-runtime "^26.5.3"
jest-util "^26.5.2"
jest-worker "^26.5.0"
source-map-support "^0.5.6"
throat "^5.0.0"
-jest-runtime@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.5.2.tgz#b72f5f79eb2fe0c46bfef4cdb9c1e01d1c69ba41"
- integrity sha512-zArr4DatX/Sn0wswX/AnAuJgmwgAR5rNtrUz36HR8BfMuysHYNq5sDbYHuLC4ICyRdy5ae/KQ+sczxyS9G6Qvw==
+jest-runtime@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-runtime/-/jest-runtime-26.5.3.tgz#5882ae91fd88304310f069549e6bf82f3f198bea"
+ integrity sha512-IDjalmn2s/Tc4GvUwhPHZ0iaXCdMRq5p6taW9P8RpU+FpG01O3+H8z+p3rDCQ9mbyyyviDgxy/LHPLzrIOKBkQ==
dependencies:
"@jest/console" "^26.5.2"
"@jest/environment" "^26.5.2"
"@jest/fake-timers" "^26.5.2"
- "@jest/globals" "^26.5.2"
+ "@jest/globals" "^26.5.3"
"@jest/source-map" "^26.5.0"
"@jest/test-result" "^26.5.2"
"@jest/transform" "^26.5.2"
@@ -3492,15 +3492,15 @@ jest-runtime@^26.5.2:
exit "^0.1.2"
glob "^7.1.3"
graceful-fs "^4.2.4"
- jest-config "^26.5.2"
+ jest-config "^26.5.3"
jest-haste-map "^26.5.2"
jest-message-util "^26.5.2"
jest-mock "^26.5.2"
jest-regex-util "^26.0.0"
jest-resolve "^26.5.2"
- jest-snapshot "^26.5.2"
+ jest-snapshot "^26.5.3"
jest-util "^26.5.2"
- jest-validate "^26.5.2"
+ jest-validate "^26.5.3"
slash "^3.0.0"
strip-bom "^4.0.0"
yargs "^15.4.1"
@@ -3513,17 +3513,17 @@ jest-serializer@^26.5.0:
"@types/node" "*"
graceful-fs "^4.2.4"
-jest-snapshot@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.5.2.tgz#0cf7642eaf8e8d2736bd443f619959bf237f9ccf"
- integrity sha512-MkXIDvEefzDubI/WaDVSRH4xnkuirP/Pz8LhAIDXcVQTmcEfwxywj5LGwBmhz+kAAIldA7XM4l96vbpzltSjqg==
+jest-snapshot@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-snapshot/-/jest-snapshot-26.5.3.tgz#f6b4b4b845f85d4b0dadd7cf119c55d0c1688601"
+ integrity sha512-ZgAk0Wm0JJ75WS4lGaeRfa0zIgpL0KD595+XmtwlIEMe8j4FaYHyZhP1LNOO+8fXq7HJ3hll54+sFV9X4+CGVw==
dependencies:
"@babel/types" "^7.0.0"
"@jest/types" "^26.5.2"
"@types/babel__traverse" "^7.0.4"
"@types/prettier" "^2.0.0"
chalk "^4.0.0"
- expect "^26.5.2"
+ expect "^26.5.3"
graceful-fs "^4.2.4"
jest-diff "^26.5.2"
jest-get-type "^26.3.0"
@@ -3559,10 +3559,10 @@ jest-util@^26.5.2:
is-ci "^2.0.0"
micromatch "^4.0.2"
-jest-validate@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.5.2.tgz#7ea266700b64234cd1c0cee982490c5a80e9b0f0"
- integrity sha512-FmJks0zY36mp6Af/5sqO6CTL9bNMU45yKCJk3hrz8d2aIqQIlN1pr9HPIwZE8blLaewOla134nt5+xAmWsx3SQ==
+jest-validate@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest-validate/-/jest-validate-26.5.3.tgz#eefd5a5c87059550548c5ad8d6589746c66929e3"
+ integrity sha512-LX07qKeAtY+lsU0o3IvfDdN5KH9OulEGOMN1sFo6PnEf5/qjS1LZIwNk9blcBeW94pQUI9dLN9FlDYDWI5tyaA==
dependencies:
"@jest/types" "^26.5.2"
camelcase "^6.0.0"
@@ -3593,14 +3593,14 @@ jest-worker@^26.5.0:
merge-stream "^2.0.0"
supports-color "^7.0.0"
-jest@^26.5.2:
- version "26.5.2"
- resolved "https://registry.yarnpkg.com/jest/-/jest-26.5.2.tgz#c6791642b331fe7abd2f993b0a74aa546f7be0fb"
- integrity sha512-4HFabJVwsgDwul/7rhXJ3yFAF/aUkVIXiJWmgFxb+WMdZG39fVvOwYAs8/3r4AlFPc4m/n5sTMtuMbOL3kNtrQ==
+jest@^26.5.3:
+ version "26.5.3"
+ resolved "https://registry.yarnpkg.com/jest/-/jest-26.5.3.tgz#5e7a322d16f558dc565ca97639e85993ef5affe6"
+ integrity sha512-uJi3FuVSLmkZrWvaDyaVTZGLL8WcfynbRnFXyAHuEtYiSZ+ijDDIMOw1ytmftK+y/+OdAtsG9QrtbF7WIBmOyA==
dependencies:
- "@jest/core" "^26.5.2"
+ "@jest/core" "^26.5.3"
import-local "^3.0.2"
- jest-cli "^26.5.2"
+ jest-cli "^26.5.3"
js-tokens@^4.0.0:
version "4.0.0"
@@ -3766,10 +3766,10 @@ levn@~0.3.0:
prelude-ls "~1.1.2"
type-check "~0.3.2"
-light-my-request@^4.0.2:
- version "4.1.0"
- resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.1.0.tgz#77a2230fb9bdb4c559832c7ee74acef7154ac20f"
- integrity sha512-MweHfXZh1olI/7orXZ19WL1cpm7TyrKtvgSeBAC2jojJlMEqaDxb0VgvZ3azUHVqVVLffgdai43ty/E0Nhdgvw==
+light-my-request@^4.1.0:
+ version "4.1.1"
+ resolved "https://registry.yarnpkg.com/light-my-request/-/light-my-request-4.1.1.tgz#71a4f5742affd21d54e70895b6c6cec08feb9bad"
+ integrity sha512-4H0T0PQcFB/fGTIkNV5ShuftWnuUKdtLWq5t2zt+lwMWRZkVviTfmJqGOXeAAqkdREnGJQXa8zJ4wXJ0LrzrTA==
dependencies:
ajv "^6.12.2"
cookie "^0.4.0"
@@ -5797,10 +5797,10 @@ v8-compile-cache@^2.0.3:
resolved "https://registry.yarnpkg.com/v8-compile-cache/-/v8-compile-cache-2.1.1.tgz#54bc3cdd43317bca91e35dcaf305b1a7237de745"
integrity sha512-8OQ9CL+VWyt3JStj7HX7/ciTL2V3Rl1Wf5OL+SNTm0yK1KvtReVulksyeRnCANHHuUxHlQig+JJDlUhBt1NQDQ==
-v8-to-istanbul@^5.0.1:
- version "5.0.1"
- resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-5.0.1.tgz#0608f5b49a481458625edb058488607f25498ba5"
- integrity sha512-mbDNjuDajqYe3TXFk5qxcQy8L1msXNE37WTlLoqqpBfRsimbNcrlhQlDPntmECEcUvdC+AQ8CyMMf6EUx1r74Q==
+v8-to-istanbul@^6.0.1:
+ version "6.0.1"
+ resolved "https://registry.yarnpkg.com/v8-to-istanbul/-/v8-to-istanbul-6.0.1.tgz#7ef0e32faa10f841fe4c1b0f8de96ed067c0be1e"
+ integrity sha512-PzM1WlqquhBvsV+Gco6WSFeg1AGdD53ccMRkFeyHRE/KRZaVacPOmQYP3EeVgDBtKD2BJ8kgynBQ5OtKiHCH+w==
dependencies:
"@types/istanbul-lib-coverage" "^2.0.1"
convert-source-map "^1.6.0"