Comparing version 0.0.12 to 0.0.13
@@ -0,9 +1,23 @@ | ||
/// <reference types="@cloudflare/workers-types" /> | ||
declare type Headers = { | ||
[key: string]: string; | ||
}; | ||
export interface Env { | ||
} | ||
export declare class Context { | ||
req: Request; | ||
res: Response; | ||
constructor(req: Request, res: Response); | ||
env: Env; | ||
event: FetchEvent; | ||
constructor(req: Request, opts?: { | ||
res: Response; | ||
env: Env; | ||
event: FetchEvent; | ||
}); | ||
newResponse(body?: BodyInit | null | undefined, init?: ResponseInit | undefined): Response; | ||
text(body: string): Response; | ||
json(object: object, replacer?: (string | number)[], space?: string | number): Response; | ||
html(body: string): Response; | ||
text(text: string, status?: number, headers?: Headers): Response; | ||
json(object: object, status?: number, headers?: Headers): Response; | ||
html(html: string, status?: number, headers?: Headers): Response; | ||
redirect(location: string, status?: number): Response; | ||
} | ||
export {}; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Context = void 0; | ||
const util_1 = require("./util"); | ||
class Context { | ||
constructor(req, res) { | ||
constructor(req, opts) { | ||
this.req = req; | ||
this.res = res; | ||
if (opts) { | ||
this.res = opts.res; | ||
this.env = opts.env; | ||
this.event = opts.event; | ||
} | ||
} | ||
@@ -12,33 +17,46 @@ newResponse(body, init) { | ||
} | ||
text(body) { | ||
if (typeof body !== 'string') { | ||
text(text, status = 200, headers = {}) { | ||
if (typeof text !== 'string') { | ||
throw new TypeError('text method arg must be a string!'); | ||
} | ||
return this.newResponse(body, { | ||
status: 200, | ||
headers: { | ||
'Content-Type': 'text/plain', | ||
}, | ||
headers['Content-Type'] = 'text/plain'; | ||
return this.newResponse(text, { | ||
status: status, | ||
headers: headers, | ||
}); | ||
} | ||
json(object, replacer, space) { | ||
json(object, status = 200, headers = {}) { | ||
if (typeof object !== 'object') { | ||
throw new TypeError('json method arg must be a object!'); | ||
} | ||
const body = JSON.stringify(object, replacer, space); | ||
const body = JSON.stringify(object); | ||
headers['Content-Type'] = 'application/json; charset=UTF-8'; | ||
return this.newResponse(body, { | ||
status: 200, | ||
headers: { | ||
'Content-Type': 'application/json; charset=UTF-8', | ||
}, | ||
status: status, | ||
headers: headers, | ||
}); | ||
} | ||
html(body) { | ||
if (typeof body !== 'string') { | ||
html(html, status = 200, headers = {}) { | ||
if (typeof html !== 'string') { | ||
throw new TypeError('html method arg must be a string!'); | ||
} | ||
return this.newResponse(body, { | ||
status: 200, | ||
headers['Content-Type'] = 'text/html; charset=UTF-8'; | ||
return this.newResponse(html, { | ||
status: status, | ||
headers: headers, | ||
}); | ||
} | ||
redirect(location, status = 302) { | ||
if (typeof location !== 'string') { | ||
throw new TypeError('location must be a string!'); | ||
} | ||
if (!(0, util_1.isAbsoluteURL)(location)) { | ||
const url = new URL(this.req.url); | ||
url.pathname = location; | ||
location = url.toString(); | ||
} | ||
return this.newResponse(null, { | ||
status: status, | ||
headers: { | ||
'Content-Type': 'text/html; charset=UTF-8', | ||
Location: location, | ||
}, | ||
@@ -45,0 +63,0 @@ }); |
/// <reference types="@cloudflare/workers-types" /> | ||
import type { Result } from './node'; | ||
import { Node } from './node'; | ||
import { Middleware } from './middleware'; | ||
import { Context } from './context'; | ||
export { Middleware }; | ||
import type { Env } from './context'; | ||
declare global { | ||
interface Request { | ||
params: (key: string) => any; | ||
params: (key: string) => string; | ||
query: (key: string) => string | null; | ||
parsedBody: any; | ||
} | ||
} | ||
declare type Handler = (c: Context, next?: Function) => Response | Promise<Response>; | ||
declare type MiddlwareHandler = (c: Context, next: Function) => Promise<void>; | ||
export declare type Handler = (c: Context, next?: Function) => Response | Promise<Response>; | ||
export declare type MiddlewareHandler = (c: Context, next: Function) => Promise<void>; | ||
export declare class Router<T> { | ||
@@ -23,3 +23,3 @@ node: Node<T>; | ||
router: Router<Handler[]>; | ||
middlewareRouters: Router<MiddlwareHandler>[]; | ||
middlewareRouters: Router<MiddlewareHandler>[]; | ||
tempPath: string; | ||
@@ -36,9 +36,10 @@ constructor(); | ||
route(path: string): Hono; | ||
use(path: string, middleware: MiddlwareHandler): void; | ||
use(path: string, middleware: MiddlewareHandler): void; | ||
addRoute(method: string, arg: string | Handler, ...args: Handler[]): Hono; | ||
matchRoute(method: string, path: string): Promise<Result<Handler[]>>; | ||
dispatch(request: Request, response?: Response): Promise<Response>; | ||
dispatch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>; | ||
handleEvent(event: FetchEvent): Promise<Response>; | ||
fetch(request: Request, env?: Env, event?: FetchEvent): Promise<Response>; | ||
fire(): void; | ||
notFound(): Response; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Hono = exports.Router = exports.Middleware = void 0; | ||
exports.Hono = exports.Router = void 0; | ||
const node_1 = require("./node"); | ||
@@ -8,3 +8,2 @@ const compose_1 = require("./compose"); | ||
const middleware_1 = require("./middleware"); | ||
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return middleware_1.Middleware; } }); | ||
const context_1 = require("./context"); | ||
@@ -98,3 +97,3 @@ const METHOD_NAME_OF_ALL = 'ALL'; | ||
} | ||
async dispatch(request, response) { | ||
async dispatch(request, env, event) { | ||
const [method, path] = [request.method, (0, util_1.getPathFromURL)(request.url)]; | ||
@@ -120,6 +119,6 @@ const result = await this.matchRoute(method, path); | ||
}; | ||
middleware.push(middleware_1.Middleware.defaultFilter); | ||
middleware.push(middleware_1.Middleware.default); | ||
middleware.push(wrappedHandler); | ||
const composed = (0, compose_1.compose)(middleware); | ||
const c = new context_1.Context(request, response); | ||
const c = new context_1.Context(request, { env: env, event: event, res: null }); | ||
await composed(c); | ||
@@ -129,4 +128,7 @@ return c.res; | ||
async handleEvent(event) { | ||
return this.dispatch(event.request); | ||
return this.dispatch(event.request, {}, event); | ||
} | ||
async fetch(request, env, event) { | ||
return this.dispatch(request, env, event); | ||
} | ||
fire() { | ||
@@ -133,0 +135,0 @@ addEventListener('fetch', (event) => { |
@@ -1,2 +0,5 @@ | ||
export { Hono, Middleware } from './hono'; | ||
export { Hono } from './hono'; | ||
export type { Handler, MiddlewareHandler } from './hono'; | ||
export { Middleware } from './middleware'; | ||
export { Context } from './context'; | ||
export type { Env } from './context'; |
@@ -6,4 +6,5 @@ "use strict"; | ||
Object.defineProperty(exports, "Hono", { enumerable: true, get: function () { return hono_1.Hono; } }); | ||
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return hono_1.Middleware; } }); | ||
var middleware_1 = require("./middleware"); | ||
Object.defineProperty(exports, "Middleware", { enumerable: true, get: function () { return middleware_1.Middleware; } }); | ||
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("./context").Context, next: Function) => Promise<void>; | ||
static default: (c: import("./context").Context, next: Function) => Promise<void>; | ||
static poweredBy: () => (c: import("./context").Context, next: Function) => Promise<void>; | ||
@@ -14,2 +14,3 @@ static logger: (fn?: { | ||
}) => (ctx: import("./context").Context, next: Function) => Promise<any>; | ||
static bodyParse: () => (ctx: import("./context").Context, next: Function) => Promise<void>; | ||
} |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.Middleware = void 0; | ||
const defaultFilter_1 = require("./middleware/defaultFilter"); | ||
const poweredBy_1 = require("./middleware/poweredBy/poweredBy"); | ||
const default_1 = require("./middleware/default"); | ||
const powered_by_1 = require("./middleware/powered-by/powered-by"); | ||
const logger_1 = require("./middleware/logger/logger"); | ||
const basic_auth_1 = require("./middleware/basic-auth/basic-auth"); | ||
const body_parse_1 = require("./middleware/body-parse/body-parse"); | ||
class Middleware { | ||
} | ||
exports.Middleware = Middleware; | ||
Middleware.defaultFilter = defaultFilter_1.defaultFilter; | ||
Middleware.poweredBy = poweredBy_1.poweredBy; | ||
Middleware.default = default_1.defaultMiddleware; | ||
Middleware.poweredBy = powered_by_1.poweredBy; | ||
Middleware.logger = logger_1.logger; | ||
Middleware.basicAuth = basic_auth_1.basicAuth; | ||
Middleware.bodyParse = body_parse_1.bodyParse; |
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 isAbsoluteURL: (url: string) => boolean; | ||
export declare const timingSafeEqual: (a: any, b: any) => Promise<boolean>; |
"use strict"; | ||
Object.defineProperty(exports, "__esModule", { value: true }); | ||
exports.timingSafeEqual = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0; | ||
exports.timingSafeEqual = exports.isAbsoluteURL = exports.getPathFromURL = exports.getPattern = exports.splitPath = void 0; | ||
const URL_REGEXP = /^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/; | ||
const splitPath = (path) => { | ||
@@ -30,3 +31,3 @@ const paths = path.split(/\//); // faster than path.split('/') | ||
// XXX | ||
const match = url.match(/^(([^:\/?#]+):)?(\/\/([^\/?#]*))?([^?#]*)(\?([^#]*))?(#(.*))?/); | ||
const match = url.match(URL_REGEXP); | ||
if (match) { | ||
@@ -38,2 +39,10 @@ return match[5]; | ||
exports.getPathFromURL = getPathFromURL; | ||
const isAbsoluteURL = (url) => { | ||
const match = url.match(URL_REGEXP); | ||
if (match && match[1]) { | ||
return true; | ||
} | ||
return false; | ||
}; | ||
exports.isAbsoluteURL = isAbsoluteURL; | ||
const bufferEqual = (a, b) => { | ||
@@ -40,0 +49,0 @@ if (a === b) { |
{ | ||
"name": "hono", | ||
"version": "0.0.12", | ||
"description": "Tiny web framework for Cloudflare Workers and others.", | ||
"version": "0.0.13", | ||
"description": "Ultrafast web framework for Cloudflare Workers.", | ||
"main": "dist/index.js", | ||
@@ -40,4 +40,4 @@ "types": "dist/index.d.ts", | ||
"@types/node": "^17.0.8", | ||
"@types/service-worker-mock": "^2.0.1", | ||
"@typescript-eslint/eslint-plugin": "^5.9.0", | ||
"@typescript-eslint/parser": "^5.9.0", | ||
"eslint": "^7.26.0", | ||
@@ -52,7 +52,7 @@ "eslint-config-prettier": "^8.1.0", | ||
"eslint-plugin-prettier": "^4.0.0", | ||
"form-data": "^4.0.0", | ||
"jest": "^27.4.5", | ||
"jest-environment-miniflare": "^2.0.0", | ||
"rimraf": "^3.0.2", | ||
"service-worker-mock": "^2.0.5", | ||
"ts-jest": "^27.1.2", | ||
"@typescript-eslint/parser": "^5.9.0", | ||
"typescript": "^4.5.4" | ||
@@ -59,0 +59,0 @@ }, |
105
README.md
# Hono | ||
Hono [炎] - Tiny web framework for Cloudflare Workers and others. | ||
Hono[炎] - _**means flame🔥 in Japanese**_ - is small, simple, and ultrafast web flamework for a Service Workers API based serverless such as Cloudflare Workers and Fastly Compute@Edge. | ||
```js | ||
const { Hono } = require('hono') | ||
import { Hono } from 'hono' | ||
const app = new Hono() | ||
@@ -14,11 +14,8 @@ | ||
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. | ||
## Features | ||
- **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. | ||
- **Ultra Fast** - the router is implemented with Trie-Tree structure. | ||
- **Zero dependencies** - using only Web standard API. | ||
- **Middleware** - builtin middleware, and you can make your own middleware. | ||
- **Optimized** - for Cloudflare Workers. | ||
@@ -29,8 +26,9 @@ ## Benchmark | ||
``` | ||
hono x 758,264 ops/sec ±5.41% (75 runs sampled) | ||
itty-router x 158,359 ops/sec ±3.21% (89 runs sampled) | ||
sunder x 297,581 ops/sec ±4.74% (83 runs sampled) | ||
```plain | ||
hono x 748,188 ops/sec ±5.40% (77 runs sampled) | ||
itty-router x 158,817 ops/sec ±3.62% (87 runs sampled) | ||
sunder x 332,339 ops/sec ±1.11% (95 runs sampled) | ||
worktop x 205,906 ops/sec ±4.43% (83 runs sampled) | ||
Fastest is hono | ||
✨ Done in 42.84s. | ||
✨ Done in 52.79s. | ||
``` | ||
@@ -48,5 +46,5 @@ | ||
```sh | ||
yarn add hono | ||
``` | ||
$ yarn add hono | ||
``` | ||
@@ -56,3 +54,3 @@ or | ||
```sh | ||
$ npm install hono | ||
npm install hono | ||
``` | ||
@@ -69,2 +67,3 @@ | ||
- app.**fire**() | ||
- app.**fetch**(request, env, event) | ||
@@ -137,6 +136,8 @@ ## Routing | ||
```js | ||
const { Hono, Middleware } = require('hono') | ||
import { Hono, Middleware } from 'hono' | ||
... | ||
app.use('*', Middleware.poweredBy()) | ||
app.use('*', Middleware.logger()) | ||
app.use( | ||
@@ -244,2 +245,24 @@ '/auth/*', | ||
### c.event | ||
```js | ||
// FetchEvent objest | ||
app.use('*', async (c, next) => { | ||
c.event.waitUntil( | ||
... | ||
) | ||
await next() | ||
}) | ||
``` | ||
### c.env | ||
```js | ||
// Environment object for Cloudflare Workers | ||
app.get('*', async c => { | ||
const counter = c.env.COUNTER | ||
... | ||
}) | ||
``` | ||
### c.text() | ||
@@ -270,3 +293,3 @@ | ||
```js | ||
app.get('/api', (c) => { | ||
app.get('/', (c) => { | ||
return c.html('<h1>Hello! Hono!</h1>') | ||
@@ -276,2 +299,11 @@ }) | ||
### c.redirect() | ||
Redirect, default status code is `302`: | ||
```js | ||
app.get('/redirect', (c) => c.redirect('/')) | ||
app.get('/redirect-permanently', (c) => c.redirect('/', 301)) | ||
``` | ||
## fire | ||
@@ -287,2 +319,14 @@ | ||
## fetch | ||
`app.fetch()` is for Cloudflare Module Worker syntax. | ||
```js | ||
export default { | ||
fetch(request: Request, env: Env, event: FetchEvent) { | ||
return app.fetch(request, env, event) | ||
}, | ||
} | ||
``` | ||
## Cloudflare Workers with Hono | ||
@@ -299,3 +343,3 @@ | ||
```sh | ||
$ npm i @cloudflare/wrangler -g | ||
npm i @cloudflare/wrangler -g | ||
``` | ||
@@ -308,5 +352,5 @@ | ||
```sh | ||
$ mkdir hono-example | ||
$ ch hono-example | ||
$ npm init -y | ||
mkdir hono-example | ||
ch hono-example | ||
npm init -y | ||
``` | ||
@@ -319,3 +363,3 @@ | ||
```sh | ||
$ wrangler init | ||
wrangler init | ||
``` | ||
@@ -327,5 +371,5 @@ | ||
```sh | ||
npm i hono | ||
``` | ||
$ npm i hono | ||
``` | ||
@@ -337,3 +381,3 @@ ### 5. Write your app | ||
```js | ||
const { Hono } = require('hono') | ||
import { Hono } from 'hono' | ||
const app = new Hono() | ||
@@ -351,3 +395,3 @@ | ||
```sh | ||
$ wrangler dev | ||
wrangler dev | ||
``` | ||
@@ -360,3 +404,3 @@ | ||
```sh | ||
$ wrangler publish | ||
wrangler publish | ||
``` | ||
@@ -366,3 +410,3 @@ | ||
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. | ||
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), [Sunder](https://github.com/SunderJS/sunder), and [worktop](https://github.com/lukeed/worktop) are the other routers or frameworks for Cloudflare Workers. | ||
@@ -374,2 +418,3 @@ - express <https://github.com/expressjs/express> | ||
- goblin <https://github.com/bmf-san/goblin> | ||
- worktop <https://github.com/lukeed/worktop> | ||
@@ -376,0 +421,0 @@ ## Contributing |
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
34692
27
724
421