Comparing version 0.0.11 to 0.0.12
/// <reference types="@cloudflare/workers-types" /> | ||
import { Node, Result } from './node'; | ||
import type { Result } from './node'; | ||
import { Node } from './node'; | ||
import { Middleware } from './middleware'; | ||
import { Context } from './context'; | ||
export { Middleware }; | ||
@@ -11,9 +13,2 @@ declare global { | ||
} | ||
export declare class Context { | ||
req: Request; | ||
res: Response; | ||
constructor(req: Request, res: Response); | ||
newResponse(body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response; | ||
text(body: string): Response; | ||
} | ||
declare type Handler = (c: Context, next?: Function) => Response | Promise<Response>; | ||
@@ -20,0 +15,0 @@ declare type MiddlwareHandler = (c: Context, next: Function) => Promise<void>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Hono = exports.Router = exports.Context = exports.Middleware = void 0; | ||
exports.Hono = exports.Router = exports.Middleware = void 0; | ||
const node_1 = require("./node"); | ||
@@ -9,21 +9,4 @@ const compose_1 = require("./compose"); | ||
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return middleware_1.Middleware; } }); | ||
const context_1 = require("./context"); | ||
const METHOD_NAME_OF_ALL = 'ALL'; | ||
class Context { | ||
constructor(req, res) { | ||
this.req = req; | ||
this.res = res; | ||
} | ||
newResponse(body, init) { | ||
return new Response(body, init); | ||
} | ||
text(body) { | ||
return this.newResponse(body, { | ||
status: 200, | ||
headers: { | ||
'Content-Type': 'text/plain', | ||
}, | ||
}); | ||
} | ||
} | ||
exports.Context = Context; | ||
class Router { | ||
@@ -103,2 +86,3 @@ constructor() { | ||
if (typeof arg === 'string') { | ||
this.tempPath = arg; | ||
this.router.add(method, arg, args); | ||
@@ -124,3 +108,3 @@ } | ||
}; | ||
let handler = result ? result.handler[0] : this.notFound; // XXX | ||
const handler = result ? result.handler[0] : this.notFound; // XXX | ||
const middleware = []; | ||
@@ -133,3 +117,3 @@ for (const mr of this.middlewareRouters) { | ||
} | ||
let wrappedHandler = async (context, next) => { | ||
const wrappedHandler = async (context, next) => { | ||
context.res = await handler(context); | ||
@@ -141,3 +125,3 @@ await next(); | ||
const composed = (0, compose_1.compose)(middleware); | ||
const c = new Context(request, response); | ||
const c = new context_1.Context(request, response); | ||
await composed(c); | ||
@@ -144,0 +128,0 @@ return c.res; |
@@ -1,1 +0,2 @@ | ||
export { Hono, Middleware, Context } from './hono'; | ||
export { Hono, Middleware } from './hono'; | ||
export { Context } from './context'; |
@@ -7,2 +7,3 @@ "use strict"; | ||
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return hono_1.Middleware; } }); | ||
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return hono_1.Context; } }); | ||
var context_1 = require("./context"); | ||
Object.defineProperty(exports, "Context", { enumerable: true, get: function () { return context_1.Context; } }); |
export declare class Middleware { | ||
static defaultFilter: (c: import("./hono").Context, next: Function) => Promise<void>; | ||
static poweredBy: () => (c: import("./hono").Context, next: Function) => Promise<void>; | ||
static defaultFilter: (c: import("./context").Context, next: Function) => Promise<void>; | ||
static poweredBy: () => (c: import("./context").Context, next: Function) => Promise<void>; | ||
static logger: (fn?: { | ||
(...data: any[]): void; | ||
(...data: any[]): void; | ||
}) => (c: import("./hono").Context, next: Function) => Promise<void>; | ||
(message?: any, ...optionalParams: any[]): void; | ||
}) => (c: import("./context").Context, next: Function) => Promise<void>; | ||
static basicAuth: (options: { | ||
username: string; | ||
password: string; | ||
realm?: string; | ||
}) => (ctx: import("./context").Context, next: Function) => Promise<any>; | ||
} |
@@ -7,2 +7,3 @@ "use strict"; | ||
const logger_1 = require("./middleware/logger/logger"); | ||
const basic_auth_1 = require("./middleware/basic-auth/basic-auth"); | ||
class Middleware { | ||
@@ -14,1 +15,2 @@ } | ||
Middleware.logger = logger_1.logger; | ||
Middleware.basicAuth = basic_auth_1.basicAuth; |
@@ -1,2 +0,2 @@ | ||
import { Context } from '../hono'; | ||
import type { Context } from '../context'; | ||
export declare const defaultFilter: (c: Context, next: Function) => Promise<void>; |
@@ -6,2 +6,3 @@ "use strict"; | ||
c.req.query = (key) => { | ||
// eslint-disable-next-line | ||
const url = new URL(c.req.url); | ||
@@ -8,0 +9,0 @@ return url.searchParams.get(key); |
@@ -1,5 +0,6 @@ | ||
import { Context } from '../../hono'; | ||
import type { Context } from '../../context'; | ||
export declare const logger: (fn?: { | ||
(...data: any[]): void; | ||
(...data: any[]): void; | ||
(message?: any, ...optionalParams: any[]): void; | ||
}) => (c: Context, next: Function) => Promise<void>; |
@@ -15,3 +15,5 @@ "use strict"; | ||
const delta = Date.now() - start; | ||
return humanize([delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's']); | ||
return humanize([ | ||
delta < 10000 ? delta + 'ms' : Math.round(delta / 1000) + 's', | ||
]); | ||
}; | ||
@@ -18,0 +20,0 @@ const LogPrefix = { |
@@ -1,2 +0,2 @@ | ||
import { Context } from '../../hono'; | ||
import type { Context } from '../../context'; | ||
export declare const poweredBy: () => (c: Context, next: Function) => Promise<void>; |
@@ -26,2 +26,3 @@ "use strict"; | ||
insert(method, path, handler) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
let curNode = this; | ||
@@ -42,5 +43,6 @@ const parts = (0, util_1.splitPath)(path); | ||
search(method, path) { | ||
// eslint-disable-next-line @typescript-eslint/no-this-alias | ||
let curNode = this; | ||
const params = {}; | ||
let parts = (0, util_1.splitPath)(path); | ||
const parts = (0, util_1.splitPath)(path); | ||
for (let i = 0, len = parts.length; i < len; i++) { | ||
@@ -47,0 +49,0 @@ const p = parts[i]; |
export declare const splitPath: (path: string) => string[]; | ||
export declare const getPattern: (label: string) => string[] | null; | ||
export declare const getPathFromURL: (url: string) => string; | ||
export declare const timingSafeEqual: (a: any, b: any) => Promise<boolean>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0; | ||
exports.timingSafeEqual = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0; | ||
const splitPath = (path) => { | ||
@@ -37,1 +37,28 @@ const paths = path.split(/\//); // faster than path.split('/') | ||
exports.getPathFromURL = getPathFromURL; | ||
const bufferEqual = (a, b) => { | ||
if (a === b) { | ||
return true; | ||
} | ||
if (a.byteLength !== b.byteLength) { | ||
return false; | ||
} | ||
const va = new DataView(a); | ||
const vb = new DataView(b); | ||
let i = va.byteLength; | ||
while (i--) { | ||
if (va.getUint8(i) !== vb.getUint8(i)) { | ||
return false; | ||
} | ||
} | ||
return true; | ||
}; | ||
const timingSafeEqual = async (a, b) => { | ||
const sa = await crypto.subtle.digest({ | ||
name: 'SHA-256', | ||
}, new TextEncoder().encode(String(a))); | ||
const sb = await crypto.subtle.digest({ | ||
name: 'SHA-256', | ||
}, new TextEncoder().encode(String(b))); | ||
return bufferEqual(sa, sb) && a === b; | ||
}; | ||
exports.timingSafeEqual = timingSafeEqual; |
{ | ||
"name": "hono", | ||
"version": "0.0.11", | ||
"version": "0.0.12", | ||
"description": "Tiny web framework for Cloudflare Workers and others.", | ||
@@ -12,2 +12,3 @@ "main": "dist/index.js", | ||
"test": "jest", | ||
"lint": "eslint --ext js,ts src .eslintrc.js test", | ||
"build": "rimraf dist && tsc", | ||
@@ -39,3 +40,14 @@ "watch": "tsc -w", | ||
"@types/jest": "^27.4.0", | ||
"@types/node": "^17.0.8", | ||
"@types/service-worker-mock": "^2.0.1", | ||
"@typescript-eslint/eslint-plugin": "^5.9.0", | ||
"eslint": "^7.26.0", | ||
"eslint-config-prettier": "^8.1.0", | ||
"eslint-define-config": "^1.2.1", | ||
"eslint-import-resolver-typescript": "^2.0.0", | ||
"eslint-plugin-eslint-comments": "^3.2.0", | ||
"eslint-plugin-flowtype": "^5.7.2", | ||
"eslint-plugin-import": "^2.20.2", | ||
"eslint-plugin-node": "^11.1.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"jest": "^27.4.5", | ||
@@ -45,4 +57,8 @@ "rimraf": "^3.0.2", | ||
"ts-jest": "^27.1.2", | ||
"@typescript-eslint/parser": "^5.9.0", | ||
"typescript": "^4.5.4" | ||
}, | ||
"engines": { | ||
"node": ">=11.0.0" | ||
} | ||
} |
134
README.md
@@ -9,3 +9,3 @@ # Hono | ||
app.get('/', () => new Response('Hono!!')) | ||
app.get('/', (c) => c.text('Hono!!')) | ||
@@ -15,15 +15,15 @@ app.fire() | ||
![carbon](https://user-images.githubusercontent.com/10682/147877725-bce9bd46-953d-4d70-9c2b-3eae47ad4df9.png) | ||
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, fast and simple web flamework for a Service Workers API based serverless such as **Cloudflare Workers** and **Fastly Compute@Edge**. Hono does not depend on any npm packages. However, Hono has a router, context object, and middleware including the builtins. It's easy to make a web application. | ||
## Feature | ||
## Features | ||
- Fast - the router is implemented with Trie-Tree structure. | ||
- Portable - zero dependencies. | ||
- Flexible - you can make your own middlewares. | ||
- Easy - simple API, builtin middleware, and TypeScript support. | ||
- Optimized - for Cloudflare Workers or Fastly Compute@Edge. | ||
- **Fast** - the router is implemented with Trie-Tree structure. | ||
- **Tiny** - zero dependencies, using Web standard API. | ||
- **Flexible** - you can make your own middleware. | ||
- **Easy** - simple API, builtin middleware, and written in TypeScript. | ||
- **Optimized** - for Cloudflare Workers or Fastly Compute@Edge. | ||
## Benchmark | ||
Hono is fastest!! | ||
**Hono is fastest** compared to other routers for Cloudflare Workers. | ||
@@ -38,4 +38,12 @@ ``` | ||
## Hono in 1 minute | ||
Below is a demonstration to create an application of Cloudflare Workers with Hono. | ||
![Demo](https://user-images.githubusercontent.com/10682/148223268-2484a891-57c1-472f-9df3-936a5586f002.gif) | ||
## Install | ||
You can install from npm registry: | ||
``` | ||
@@ -53,2 +61,4 @@ $ yarn add hono | ||
Instance of `Hono` has these methods: | ||
- app.**HTTP_METHOD**(path, handler) | ||
@@ -58,2 +68,3 @@ - app.**all**(path, handler) | ||
- app.**use**(path, middleware) | ||
- app.**fire**() | ||
@@ -112,3 +123,3 @@ ## Routing | ||
## Async | ||
## async/await | ||
@@ -131,9 +142,17 @@ ```js | ||
app.use('*', Middleware.poweredBy()) | ||
app.use('*', Middleware.logger()) | ||
app.use( | ||
'/auth/*', | ||
Middleware.basicAuth({ | ||
username: 'hono', | ||
password: 'acoolproject', | ||
}) | ||
) | ||
``` | ||
Available builtin middleware are listed on [src/middleware](https://github.com/yusukebe/hono/tree/master/src/middleware). | ||
### Custom Middleware | ||
You can write your own middleware: | ||
```js | ||
@@ -146,3 +165,3 @@ // Custom logger | ||
// Add custom header | ||
// Add a custom header | ||
app.use('/message/*', async (c, next) => { | ||
@@ -158,2 +177,4 @@ await next() | ||
You can customize 404 Not Found response: | ||
```js | ||
@@ -170,2 +191,4 @@ app.use('*', async (c, next) => { | ||
You can also do this: | ||
```js | ||
@@ -190,4 +213,6 @@ // Output response time | ||
### req | ||
To handle Request and Reponse easily, you can use Context object: | ||
### c.req | ||
```js | ||
@@ -214,3 +239,3 @@ | ||
### res | ||
### c.res | ||
@@ -225,4 +250,6 @@ ```js | ||
### text | ||
### c.text() | ||
Render text as `Content-Type:text/plain`: | ||
```js | ||
@@ -234,10 +261,38 @@ app.get('/say', (c) => { | ||
## Hono in 1 minute | ||
### c.json() | ||
Create your first Cloudflare Workers with Hono from scratch. | ||
Render JSON as `Content-Type:application/json`: | ||
### How to setup | ||
```js | ||
app.get('/api', (c) => { | ||
return c.json({ message: 'Hello!' }) | ||
}) | ||
``` | ||
![Demo](https://user-images.githubusercontent.com/10682/147877447-ff5907cd-49be-4976-b3b4-5df2ac6dfda4.gif) | ||
### c.html() | ||
Render HTML as `Content-Type:text/html`: | ||
```js | ||
app.get('/api', (c) => { | ||
return c.html('<h1>Hello! Hono!</h1>') | ||
}) | ||
``` | ||
## fire | ||
`app.fire()` do: | ||
```js | ||
addEventListener('fetch', (event) => { | ||
event.respondWith(this.handleEvent(event)) | ||
}) | ||
``` | ||
## Cloudflare Workers with Hono | ||
Using `wrangler` or `miniflare`, you can develop the application locally and publish it with few commands. | ||
Let's write your first code for Cloudflare Workers with Hono. | ||
### 1. Install Wrangler | ||
@@ -271,3 +326,3 @@ | ||
Install `hono` from npm repository. | ||
Install `hono` from npm registry. | ||
@@ -280,3 +335,3 @@ ``` | ||
Only 4 line!! | ||
Only 4 lines!! | ||
@@ -287,3 +342,3 @@ ```js | ||
app.get('/', () => new Response('Hello! Hono!')) | ||
app.get('/', (c) => c.text('Hello! Hono!')) | ||
@@ -293,5 +348,5 @@ app.fire() | ||
### 6. Run! | ||
### 6. Run | ||
Run the development server locally. | ||
Run the development server locally. Then, access like `http://127.0.0.1:8787/` in your Web browser. | ||
@@ -302,7 +357,16 @@ ```sh | ||
### Publish | ||
Deploy to Cloudflare. That's all! | ||
```sh | ||
$ wrangler publish | ||
``` | ||
## Related projects | ||
Implementation of the router is inspired by [goblin](https://github.com/bmf-san/goblin). API design is inspired by [express](https://github.com/expressjs/express) and [koa](https://github.com/koajs/koa). [itty-router](https://github.com/kwhitley/itty-router) and [Sunder](https://github.com/SunderJS/sunder) are the other routers or frameworks for Cloudflare Workers. | ||
- express <https://github.com/expressjs/express> | ||
- koa <https://github.com/koajs/koa> | ||
- express <https://github.com/expressjs/express> | ||
- oak <https://github.com/oakserver/oak> | ||
- itty-router <https://github.com/kwhitley/itty-router> | ||
@@ -312,2 +376,14 @@ - Sunder <https://github.com/SunderJS/sunder> | ||
## Contributing | ||
Contributions Welcome! You can contribute by the following way: | ||
- Write or fix documents | ||
- Write code of middleware | ||
- Fix bugs | ||
- Refactor the code | ||
- etc. | ||
If you can, let's make Hono together! | ||
## Author | ||
@@ -319,2 +395,2 @@ | ||
MIT | ||
Distributed under the MIT License. See [LICENSE](LICENSE) for more information. |
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
License Policy Violation
LicenseThis package is not allowed per your license policy. Review the package's license to ensure compliance.
Found 1 instance in 1 package
Major refactor
Supply chain riskPackage has recently undergone a major refactor. It may be unstable or indicate significant internal changes. Use caution when updating to versions that include significant changes.
Found 1 instance in 1 package
31213
25
643
376
0
20