@asenajs/hono-adapter 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +149 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/HonoAdapter.d.ts +26 -0
- package/dist/lib/HonoAdapter.js +116 -0
- package/dist/lib/HonoAdapter.js.map +1 -0
- package/dist/lib/HonoContextWrapper.d.ts +31 -0
- package/dist/lib/HonoContextWrapper.js +109 -0
- package/dist/lib/HonoContextWrapper.js.map +1 -0
- package/dist/lib/HonoWebsocketAdapter.d.ts +17 -0
- package/dist/lib/HonoWebsocketAdapter.js +87 -0
- package/dist/lib/HonoWebsocketAdapter.js.map +1 -0
- package/dist/lib/defaults/ConfigService.d.ts +4 -0
- package/dist/lib/defaults/ConfigService.js +3 -0
- package/dist/lib/defaults/ConfigService.js.map +1 -0
- package/dist/lib/defaults/Context.d.ts +3 -0
- package/dist/lib/defaults/Context.js +2 -0
- package/dist/lib/defaults/Context.js.map +1 -0
- package/dist/lib/defaults/MiddlewareService.d.ts +5 -0
- package/dist/lib/defaults/MiddlewareService.js +4 -0
- package/dist/lib/defaults/MiddlewareService.js.map +1 -0
- package/dist/lib/defaults/ValidationService.d.ts +10 -0
- package/dist/lib/defaults/ValidationService.js +3 -0
- package/dist/lib/defaults/ValidationService.js.map +1 -0
- package/dist/lib/defaults/index.d.ts +4 -0
- package/dist/lib/defaults/index.js +5 -0
- package/dist/lib/defaults/index.js.map +1 -0
- package/dist/lib/types/HonoHandler.d.ts +4 -0
- package/dist/lib/types/HonoHandler.js +2 -0
- package/dist/lib/types/HonoHandler.js.map +1 -0
- package/dist/lib/types/index.d.ts +2 -0
- package/dist/lib/types/index.js +3 -0
- package/dist/lib/types/index.js.map +1 -0
- package/dist/lib/utils/createHonoAdapter.d.ts +3 -0
- package/dist/lib/utils/createHonoAdapter.js +5 -0
- package/dist/lib/utils/createHonoAdapter.js.map +1 -0
- package/dist/lib/utils/middlewareParser.d.ts +4 -0
- package/dist/lib/utils/middlewareParser.js +15 -0
- package/dist/lib/utils/middlewareParser.js.map +1 -0
- package/package.json +47 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2024 AsenaJs
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,149 @@
|
|
|
1
|
+
# Asena Hono Adapter
|
|
2
|
+
|
|
3
|
+
HTTP and WebSocket adapter implementation based on Hono web framework for Asena.js.
|
|
4
|
+
|
|
5
|
+
## Features
|
|
6
|
+
|
|
7
|
+
- Fast and modern API endpoints with [Hono](https://hono.dev/) web framework
|
|
8
|
+
- High performance with Bun runtime
|
|
9
|
+
- Full type support with TypeScript
|
|
10
|
+
- HTTP and WebSocket adapter support
|
|
11
|
+
- Easy integration and usage
|
|
12
|
+
- Validation support with Zod
|
|
13
|
+
- Decorators for controller-based routing
|
|
14
|
+
|
|
15
|
+
## Requirements
|
|
16
|
+
|
|
17
|
+
- [Bun](https://bun.sh)
|
|
18
|
+
- TypeScript v5.8.2 or above
|
|
19
|
+
|
|
20
|
+
## Installation
|
|
21
|
+
|
|
22
|
+
1. Install with NPM package manager:
|
|
23
|
+
```bash
|
|
24
|
+
bun add @asenajs/hono-adapter
|
|
25
|
+
```
|
|
26
|
+
|
|
27
|
+
## Usage
|
|
28
|
+
|
|
29
|
+
### Server Setup (index.ts)
|
|
30
|
+
|
|
31
|
+
```typescript
|
|
32
|
+
import { AsenaServer } from '@asenajs/asena';
|
|
33
|
+
import { DefaultLogger } from "@asenajs/asena/logger";
|
|
34
|
+
import { createHonoAdapter } from '@asenajs/hono-adapter';
|
|
35
|
+
|
|
36
|
+
const [adapter, logger] = createHonoAdapter(new DefaultLogger());
|
|
37
|
+
|
|
38
|
+
await new AsenaServer(adapter)
|
|
39
|
+
.logger(logger)
|
|
40
|
+
.port(3000)
|
|
41
|
+
.start(true);
|
|
42
|
+
```
|
|
43
|
+
|
|
44
|
+
### Controller Example
|
|
45
|
+
|
|
46
|
+
```typescript
|
|
47
|
+
import { Controller } from '@asenajs/asena/server';
|
|
48
|
+
import { Get } from '@asenajs/asena/web';
|
|
49
|
+
import type { Context } from '@asenajs/hono-adapter';
|
|
50
|
+
|
|
51
|
+
@Controller()
|
|
52
|
+
export class TestController {
|
|
53
|
+
@Get("/")
|
|
54
|
+
public async me(context: Context) {
|
|
55
|
+
return context.send("Hello World!");
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
```
|
|
59
|
+
|
|
60
|
+
## API Documentation
|
|
61
|
+
|
|
62
|
+
### createHonoAdapter(logger, options)
|
|
63
|
+
|
|
64
|
+
Helper function used to create a Hono adapter.
|
|
65
|
+
|
|
66
|
+
**Parameters:**
|
|
67
|
+
- `logger` (Logger): Logger instance from Asena
|
|
68
|
+
|
|
69
|
+
**Returns:**
|
|
70
|
+
- A tuple with [adapter, logger]
|
|
71
|
+
|
|
72
|
+
## Testing
|
|
73
|
+
|
|
74
|
+
Asena Hono Adapter uses Bun's built-in test framework for unit and integration testing.
|
|
75
|
+
|
|
76
|
+
### Running Tests
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# Run all tests
|
|
80
|
+
bun test
|
|
81
|
+
|
|
82
|
+
# Run tests with watch mode
|
|
83
|
+
bun test:watch
|
|
84
|
+
|
|
85
|
+
# Run tests with coverage report
|
|
86
|
+
bun test:coverage
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
### Test Structure
|
|
90
|
+
|
|
91
|
+
- **Unit Tests**: Test individual components in isolation
|
|
92
|
+
- `HonoAdapter.test.ts` - Tests for the HTTP adapter
|
|
93
|
+
- `HonoContextWrapper.test.ts` - Tests for the context wrapper
|
|
94
|
+
- `HonoWebsocketAdapter.test.ts` - Tests for the WebSocket adapter
|
|
95
|
+
|
|
96
|
+
- **Integration Tests**: Test how components work together
|
|
97
|
+
- `integration.test.ts` - End-to-end tests for the adapter
|
|
98
|
+
|
|
99
|
+
### Writing Tests
|
|
100
|
+
|
|
101
|
+
Example test for a controller:
|
|
102
|
+
|
|
103
|
+
```typescript
|
|
104
|
+
import { describe, expect, it } from "bun:test";
|
|
105
|
+
import { AsenaServer } from "@asenajs/asena";
|
|
106
|
+
import { createHonoAdapter } from "@asenajs/hono-adapter";
|
|
107
|
+
import { DefaultLogger } from "@asenajs/asena/logger";
|
|
108
|
+
import { YourController } from "../path/to/your/controller";
|
|
109
|
+
|
|
110
|
+
describe("YourController", () => {
|
|
111
|
+
let server;
|
|
112
|
+
let baseUrl;
|
|
113
|
+
|
|
114
|
+
beforeEach(async () => {
|
|
115
|
+
const port = Math.floor(Math.random() * 55000) + 10000;
|
|
116
|
+
const [adapter, logger] = createHonoAdapter(new DefaultLogger());
|
|
117
|
+
const app = new AsenaServer(adapter).logger(logger).port(port);
|
|
118
|
+
|
|
119
|
+
app.register(YourController);
|
|
120
|
+
|
|
121
|
+
server = await app.start();
|
|
122
|
+
baseUrl = `http://localhost:${port}`;
|
|
123
|
+
});
|
|
124
|
+
|
|
125
|
+
afterEach(() => {
|
|
126
|
+
server.stop();
|
|
127
|
+
});
|
|
128
|
+
|
|
129
|
+
it("should respond correctly", async () => {
|
|
130
|
+
const response = await fetch(`${baseUrl}/your-endpoint`);
|
|
131
|
+
const data = await response.json();
|
|
132
|
+
|
|
133
|
+
expect(response.status).toBe(200);
|
|
134
|
+
expect(data).toEqual({ /* expected response */ });
|
|
135
|
+
});
|
|
136
|
+
});
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## Development
|
|
140
|
+
|
|
141
|
+
To run the project in development mode:
|
|
142
|
+
|
|
143
|
+
```bash
|
|
144
|
+
bun run build
|
|
145
|
+
```
|
|
146
|
+
|
|
147
|
+
## License
|
|
148
|
+
|
|
149
|
+
This project is licensed under the MIT License. See the [LICENSE](LICENSE) file for details.
|
package/dist/index.d.ts
ADDED
package/dist/index.js
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../index.ts"],"names":[],"mappings":"AAAA,cAAc,mBAAmB,CAAC;AAClC,cAAc,4BAA4B,CAAC;AAC3C,cAAc,aAAa,CAAC;AAC5B,cAAc,gBAAgB,CAAC;AAC/B,cAAc,+BAA+B,CAAC"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import type { Server } from "bun";
|
|
3
|
+
import type { AsenaWebsocketAdapter } from "@asenajs/asena/adapter";
|
|
4
|
+
import { AsenaAdapter, type AsenaServeOptions, type BaseMiddleware, type RouteParams } from "@asenajs/asena/adapter";
|
|
5
|
+
import type { HonoErrorHandler } from "./types";
|
|
6
|
+
import { type ServerLogger } from "@asenajs/asena/logger";
|
|
7
|
+
import type { ValidationSchema } from "./defaults";
|
|
8
|
+
import type { Context as HonoAdapterContext } from "./defaults/Context";
|
|
9
|
+
export declare class HonoAdapter extends AsenaAdapter<Hono, HonoAdapterContext, ValidationSchema, AsenaWebsocketAdapter<Hono, HonoAdapterContext>> {
|
|
10
|
+
name: string;
|
|
11
|
+
app: Hono<import("hono/types").BlankEnv, import("hono/types").BlankSchema, "/">;
|
|
12
|
+
private server;
|
|
13
|
+
private options;
|
|
14
|
+
private readonly methodMap;
|
|
15
|
+
constructor(websocketAdapter: AsenaWebsocketAdapter<Hono, HonoAdapterContext>, logger?: ServerLogger);
|
|
16
|
+
use(middleware: BaseMiddleware<HonoAdapterContext>, path?: string): void;
|
|
17
|
+
registerRoute({ method, path, middleware, handler, staticServe, validator, }: RouteParams<HonoAdapterContext, ValidationSchema>): Promise<void>;
|
|
18
|
+
start(): Promise<Server>;
|
|
19
|
+
onError(errorHandler: HonoErrorHandler): void;
|
|
20
|
+
serveOptions(options: () => Promise<AsenaServeOptions> | AsenaServeOptions): Promise<void>;
|
|
21
|
+
setPort(port: number): void;
|
|
22
|
+
private prepareMiddlewares;
|
|
23
|
+
private prepareHandler;
|
|
24
|
+
private prepareValidator;
|
|
25
|
+
private normalizePath;
|
|
26
|
+
}
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { Hono, } from "hono";
|
|
2
|
+
import * as bun from "bun";
|
|
3
|
+
import { HonoContextWrapper } from "./HonoContextWrapper";
|
|
4
|
+
import { AsenaAdapter, VALIDATOR_METHODS, } from "@asenajs/asena/adapter";
|
|
5
|
+
import { green, yellow } from "@asenajs/asena/logger";
|
|
6
|
+
import { zValidator } from "@hono/zod-validator";
|
|
7
|
+
import { middlewareParser } from "./utils/middlewareParser";
|
|
8
|
+
import { HttpMethod } from "@asenajs/asena/web-types";
|
|
9
|
+
export class HonoAdapter extends AsenaAdapter {
|
|
10
|
+
name = "HonoAdapter";
|
|
11
|
+
app = new Hono();
|
|
12
|
+
server;
|
|
13
|
+
// @ts-ignore
|
|
14
|
+
options = {};
|
|
15
|
+
methodMap = {
|
|
16
|
+
[HttpMethod.GET]: (path, ...handlers) => this.app.get(path, ...handlers),
|
|
17
|
+
[HttpMethod.POST]: (path, ...handlers) => this.app.post(path, ...handlers),
|
|
18
|
+
[HttpMethod.PUT]: (path, ...handlers) => this.app.put(path, ...handlers),
|
|
19
|
+
[HttpMethod.DELETE]: (path, ...handlers) => this.app.delete(path, ...handlers),
|
|
20
|
+
[HttpMethod.PATCH]: (path, ...handlers) => this.app.patch(path, ...handlers),
|
|
21
|
+
[HttpMethod.OPTIONS]: (path, ...handlers) => this.app.options(path, ...handlers),
|
|
22
|
+
[HttpMethod.CONNECT]: (path, ...handlers) => this.app.on(HttpMethod.CONNECT.toUpperCase(), path, ...handlers),
|
|
23
|
+
[HttpMethod.HEAD]: (path, ...handlers) => this.app.on(HttpMethod.HEAD.toUpperCase(), path, ...handlers),
|
|
24
|
+
[HttpMethod.TRACE]: (path, ...handlers) => this.app.on(HttpMethod.TRACE.toUpperCase(), path, ...handlers),
|
|
25
|
+
};
|
|
26
|
+
constructor(websocketAdapter, logger) {
|
|
27
|
+
super(websocketAdapter, logger);
|
|
28
|
+
this.websocketAdapter.app = this.app;
|
|
29
|
+
// to ensure that the logger is set
|
|
30
|
+
if (!this.websocketAdapter.logger && logger) {
|
|
31
|
+
this.websocketAdapter.logger = this.logger;
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
use(middleware, path) {
|
|
35
|
+
const normalizedPath = path ? this.normalizePath(path) : undefined;
|
|
36
|
+
const preparedMiddlewares = this.prepareMiddlewares([middleware]);
|
|
37
|
+
if (normalizedPath) {
|
|
38
|
+
this.app.use(normalizedPath, ...preparedMiddlewares);
|
|
39
|
+
return;
|
|
40
|
+
}
|
|
41
|
+
this.app.use(...preparedMiddlewares);
|
|
42
|
+
}
|
|
43
|
+
async registerRoute({ method, path, middleware, handler, staticServe, validator, }) {
|
|
44
|
+
const middlewares = this.prepareMiddlewares(middleware);
|
|
45
|
+
const allMiddlewares = validator
|
|
46
|
+
? [...(await this.prepareValidator(validator)), ...middlewares]
|
|
47
|
+
: middlewares;
|
|
48
|
+
const routeHandler = staticServe
|
|
49
|
+
? allMiddlewares
|
|
50
|
+
: [...allMiddlewares, this.prepareHandler(handler)];
|
|
51
|
+
const methodHandler = this.methodMap[method];
|
|
52
|
+
if (!methodHandler) {
|
|
53
|
+
throw new Error("Invalid method");
|
|
54
|
+
}
|
|
55
|
+
methodHandler(path, ...routeHandler);
|
|
56
|
+
this.logger.info(`${green("Successfully")} registered ${yellow(method.toUpperCase())} route for PATH: ${green(`${path}`)}`);
|
|
57
|
+
}
|
|
58
|
+
async start() {
|
|
59
|
+
this.websocketAdapter.buildWebsocket(this.options?.wsOptions);
|
|
60
|
+
this.server = bun.serve({
|
|
61
|
+
...this.options.serveOptions,
|
|
62
|
+
port: this.port,
|
|
63
|
+
fetch: this.app.fetch,
|
|
64
|
+
websocket: this.websocketAdapter.websocket,
|
|
65
|
+
});
|
|
66
|
+
this.websocketAdapter.startWebsocket(this.server);
|
|
67
|
+
return this.server;
|
|
68
|
+
}
|
|
69
|
+
onError(errorHandler) {
|
|
70
|
+
this.app.onError((error, context) => {
|
|
71
|
+
return errorHandler(error, new HonoContextWrapper(context));
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
async serveOptions(options) {
|
|
75
|
+
this.options = await options();
|
|
76
|
+
}
|
|
77
|
+
setPort(port) {
|
|
78
|
+
this.port = port;
|
|
79
|
+
}
|
|
80
|
+
prepareMiddlewares(middlewares) {
|
|
81
|
+
return middlewareParser(middlewares);
|
|
82
|
+
}
|
|
83
|
+
prepareHandler(handler) {
|
|
84
|
+
return (c) => handler(new HonoContextWrapper(c));
|
|
85
|
+
}
|
|
86
|
+
async prepareValidator(baseValidator) {
|
|
87
|
+
if (!baseValidator) {
|
|
88
|
+
return [];
|
|
89
|
+
}
|
|
90
|
+
const validators = [];
|
|
91
|
+
for (const key of VALIDATOR_METHODS) {
|
|
92
|
+
// if the key is not a validator method, skip
|
|
93
|
+
if (typeof baseValidator[key]
|
|
94
|
+
?.handle !== "function") {
|
|
95
|
+
continue;
|
|
96
|
+
}
|
|
97
|
+
const validator = baseValidator[key];
|
|
98
|
+
const validationSchema = await validator.handle();
|
|
99
|
+
let schema;
|
|
100
|
+
let hook;
|
|
101
|
+
if ("schema" in validationSchema) {
|
|
102
|
+
schema = validationSchema["schema"];
|
|
103
|
+
hook = validationSchema["hook"];
|
|
104
|
+
}
|
|
105
|
+
else {
|
|
106
|
+
schema = validationSchema;
|
|
107
|
+
}
|
|
108
|
+
validators.push(zValidator(key, schema, hook));
|
|
109
|
+
}
|
|
110
|
+
return validators;
|
|
111
|
+
}
|
|
112
|
+
normalizePath(path) {
|
|
113
|
+
return `${path.endsWith("/") ? path : `${path}/`}*`;
|
|
114
|
+
}
|
|
115
|
+
}
|
|
116
|
+
//# sourceMappingURL=HonoAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HonoAdapter.js","sourceRoot":"","sources":["../../lib/HonoAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
import type { Context, HonoRequest } from "hono";
|
|
2
|
+
import type { AsenaContext, CookieExtra, SendOptions } from "@asenajs/asena/adapter";
|
|
3
|
+
import type { CookieOptions } from "hono/utils/cookie";
|
|
4
|
+
import type { ContentfulStatusCode } from "hono/utils/http-status";
|
|
5
|
+
export declare class HonoContextWrapper implements AsenaContext<HonoRequest<any, any>, Response> {
|
|
6
|
+
private _context;
|
|
7
|
+
constructor(context: Context);
|
|
8
|
+
get req(): HonoRequest<any, unknown>;
|
|
9
|
+
get res(): Response;
|
|
10
|
+
get headers(): Record<string, string>;
|
|
11
|
+
getArrayBuffer(): Promise<ArrayBuffer>;
|
|
12
|
+
getParseBody(): Promise<any>;
|
|
13
|
+
getBlob(): Promise<Blob>;
|
|
14
|
+
getFormData(): Promise<FormData>;
|
|
15
|
+
getParam(s: string): string;
|
|
16
|
+
getBody<T>(): Promise<T>;
|
|
17
|
+
getQuery(query: string): Promise<string>;
|
|
18
|
+
getQueryAll(query: string): Promise<string[]>;
|
|
19
|
+
send(data: string | any, statusOrOptions?: SendOptions | number): (Response & import("hono").TypedResponse<string, ContentfulStatusCode, "text">) | (Response & import("hono").TypedResponse<any, ContentfulStatusCode, "json">);
|
|
20
|
+
getCookie(name: string, secret?: string | BufferSource): Promise<string | false>;
|
|
21
|
+
setCookie(name: string, value: string, options?: CookieExtra<CookieOptions>): Promise<void>;
|
|
22
|
+
deleteCookie(name: string, options?: CookieExtra<CookieOptions>): Promise<void>;
|
|
23
|
+
redirect(url: string): Response & import("hono").TypedResponse<undefined, 302, "redirect">;
|
|
24
|
+
getValue<T>(key: string): T;
|
|
25
|
+
setValue(key: string, value: any): void;
|
|
26
|
+
setWebSocketValue(value: any): void;
|
|
27
|
+
getWebSocketValue<T>(): T;
|
|
28
|
+
html(data: string, statusOrOptions?: SendOptions | number): Response;
|
|
29
|
+
get context(): Context;
|
|
30
|
+
set context(value: Context);
|
|
31
|
+
}
|
|
@@ -0,0 +1,109 @@
|
|
|
1
|
+
import { deleteCookie, getCookie, getSignedCookie, setCookie, setSignedCookie, } from "hono/cookie"; // add delete cookie
|
|
2
|
+
export class HonoContextWrapper {
|
|
3
|
+
_context;
|
|
4
|
+
constructor(context) {
|
|
5
|
+
this._context = context;
|
|
6
|
+
}
|
|
7
|
+
get req() {
|
|
8
|
+
return this._context.req;
|
|
9
|
+
}
|
|
10
|
+
get res() {
|
|
11
|
+
return this._context.res;
|
|
12
|
+
}
|
|
13
|
+
get headers() {
|
|
14
|
+
return this._context.req.header();
|
|
15
|
+
}
|
|
16
|
+
getArrayBuffer() {
|
|
17
|
+
return this._context.req.arrayBuffer();
|
|
18
|
+
}
|
|
19
|
+
getParseBody() {
|
|
20
|
+
return this._context.req.parseBody();
|
|
21
|
+
}
|
|
22
|
+
getBlob() {
|
|
23
|
+
return this._context.req.blob();
|
|
24
|
+
}
|
|
25
|
+
getFormData() {
|
|
26
|
+
return this._context.req.formData();
|
|
27
|
+
}
|
|
28
|
+
getParam(s) {
|
|
29
|
+
return this._context.req.param(s);
|
|
30
|
+
}
|
|
31
|
+
async getBody() {
|
|
32
|
+
return await this._context.req.json();
|
|
33
|
+
}
|
|
34
|
+
async getQuery(query) {
|
|
35
|
+
return this._context.req.query(query);
|
|
36
|
+
}
|
|
37
|
+
async getQueryAll(query) {
|
|
38
|
+
return this._context.req.queries(query);
|
|
39
|
+
}
|
|
40
|
+
send(data, statusOrOptions) {
|
|
41
|
+
const { headers = {}, status = 200 } = typeof statusOrOptions === "number"
|
|
42
|
+
? { status: statusOrOptions }
|
|
43
|
+
: statusOrOptions || {};
|
|
44
|
+
if (headers !== undefined) {
|
|
45
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
46
|
+
this._context.res.headers.append(key, value);
|
|
47
|
+
});
|
|
48
|
+
}
|
|
49
|
+
if (typeof data === "string") {
|
|
50
|
+
return this._context.text(data);
|
|
51
|
+
}
|
|
52
|
+
return this._context.json(data, status, headers);
|
|
53
|
+
}
|
|
54
|
+
async getCookie(name, secret) {
|
|
55
|
+
return secret
|
|
56
|
+
? await getSignedCookie(this._context, secret, name)
|
|
57
|
+
: getCookie(this._context, name);
|
|
58
|
+
}
|
|
59
|
+
async setCookie(name, value, options) {
|
|
60
|
+
const { secret, extraOptions } = options ?? {
|
|
61
|
+
secret: undefined,
|
|
62
|
+
extraOptions: undefined,
|
|
63
|
+
};
|
|
64
|
+
return secret
|
|
65
|
+
? setSignedCookie(this._context, name, value, secret, extraOptions)
|
|
66
|
+
: setCookie(this._context, name, value, extraOptions);
|
|
67
|
+
}
|
|
68
|
+
async deleteCookie(name, options) {
|
|
69
|
+
const { extraOptions } = options ?? {
|
|
70
|
+
secret: undefined,
|
|
71
|
+
extraOptions: undefined,
|
|
72
|
+
};
|
|
73
|
+
deleteCookie(this._context, name, extraOptions);
|
|
74
|
+
}
|
|
75
|
+
redirect(url) {
|
|
76
|
+
return this._context.redirect(url);
|
|
77
|
+
}
|
|
78
|
+
getValue(key) {
|
|
79
|
+
return this._context.get(key);
|
|
80
|
+
}
|
|
81
|
+
setValue(key, value) {
|
|
82
|
+
this._context.set(key, value);
|
|
83
|
+
}
|
|
84
|
+
setWebSocketValue(value) {
|
|
85
|
+
this._context.set("_websocketData", value);
|
|
86
|
+
}
|
|
87
|
+
getWebSocketValue() {
|
|
88
|
+
return this._context.get("_websocketData");
|
|
89
|
+
}
|
|
90
|
+
html(data, statusOrOptions) {
|
|
91
|
+
const { headers = {}, status = 200 } = typeof statusOrOptions === "number"
|
|
92
|
+
? { status: statusOrOptions }
|
|
93
|
+
: statusOrOptions || {};
|
|
94
|
+
if (typeof data === "string") {
|
|
95
|
+
return this._context.html(data, status, headers);
|
|
96
|
+
}
|
|
97
|
+
Object.entries(headers).forEach(([key, value]) => {
|
|
98
|
+
this._context.res.headers.append(key, value);
|
|
99
|
+
});
|
|
100
|
+
return this._context.html(data, status, headers);
|
|
101
|
+
}
|
|
102
|
+
get context() {
|
|
103
|
+
return this._context;
|
|
104
|
+
}
|
|
105
|
+
set context(value) {
|
|
106
|
+
this._context = value;
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
//# sourceMappingURL=HonoContextWrapper.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HonoContextWrapper.js","sourceRoot":"","sources":["../../lib/HonoContextWrapper.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import type { Context as HonoAdapterContext } from "./defaults/Context";
|
|
2
|
+
import { AsenaWebsocketAdapter, type BaseMiddleware, type WebsocketAdapterParams } from "@asenajs/asena/adapter";
|
|
3
|
+
import type { Hono } from "hono";
|
|
4
|
+
import { type Server } from "bun";
|
|
5
|
+
import { AsenaWebSocketService, type WSOptions } from "@asenajs/asena/web-socket";
|
|
6
|
+
export declare class HonoWebsocketAdapter extends AsenaWebsocketAdapter<Hono, HonoAdapterContext> {
|
|
7
|
+
name: string;
|
|
8
|
+
private _server;
|
|
9
|
+
constructor(params?: WebsocketAdapterParams<Hono>);
|
|
10
|
+
registerWebSocket(webSocketService: AsenaWebSocketService<any>, middlewares: BaseMiddleware<HonoAdapterContext>[]): void;
|
|
11
|
+
buildWebsocket(options?: WSOptions): void;
|
|
12
|
+
startWebsocket(server: Server): void;
|
|
13
|
+
private prepareWebSocket;
|
|
14
|
+
private upgradeWebSocket;
|
|
15
|
+
private createHandler;
|
|
16
|
+
private prepareMiddlewares;
|
|
17
|
+
}
|
|
@@ -0,0 +1,87 @@
|
|
|
1
|
+
import { middlewareParser } from "./utils/middlewareParser";
|
|
2
|
+
import { AsenaWebsocketAdapter, } from "@asenajs/asena/adapter";
|
|
3
|
+
import * as bun from "bun";
|
|
4
|
+
import {} from "bun";
|
|
5
|
+
import { AsenaSocket, AsenaWebSocketServer, AsenaWebSocketService, } from "@asenajs/asena/web-socket";
|
|
6
|
+
import { green, yellow } from "@asenajs/asena/logger";
|
|
7
|
+
export class HonoWebsocketAdapter extends AsenaWebsocketAdapter {
|
|
8
|
+
name = "HonoWebsocketAdapter";
|
|
9
|
+
_server;
|
|
10
|
+
constructor(params) {
|
|
11
|
+
super(params);
|
|
12
|
+
}
|
|
13
|
+
registerWebSocket(webSocketService, middlewares) {
|
|
14
|
+
if (!webSocketService) {
|
|
15
|
+
throw new Error("Websocket service is not provided");
|
|
16
|
+
}
|
|
17
|
+
if (this.websockets === undefined) {
|
|
18
|
+
this.websockets = new Map();
|
|
19
|
+
}
|
|
20
|
+
const namespace = webSocketService.namespace;
|
|
21
|
+
if (!namespace) {
|
|
22
|
+
throw new Error("Namespace is not provided");
|
|
23
|
+
}
|
|
24
|
+
this.logger.info(`${green("Successfully")} registered ${yellow("WEBSOCKET")} route for PATH: ${green(`/${webSocketService.namespace}`)}`);
|
|
25
|
+
this.websockets.set(namespace, { socket: webSocketService, middlewares });
|
|
26
|
+
}
|
|
27
|
+
buildWebsocket(options) {
|
|
28
|
+
if (!this.websockets || !this.websockets?.size)
|
|
29
|
+
return;
|
|
30
|
+
for (const [, websocket] of this.websockets) {
|
|
31
|
+
this.upgradeWebSocket(websocket.socket, websocket.middlewares);
|
|
32
|
+
}
|
|
33
|
+
this.prepareWebSocket(options);
|
|
34
|
+
}
|
|
35
|
+
startWebsocket(server) {
|
|
36
|
+
this._server = server;
|
|
37
|
+
if (!this.websockets) {
|
|
38
|
+
return;
|
|
39
|
+
}
|
|
40
|
+
for (const [namespace, websocket] of this.websockets) {
|
|
41
|
+
websocket.socket.server = new AsenaWebSocketServer(server, namespace);
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
prepareWebSocket(options) {
|
|
45
|
+
if (this.websockets?.size < 1) {
|
|
46
|
+
return;
|
|
47
|
+
}
|
|
48
|
+
this.websocket = {
|
|
49
|
+
open: this.createHandler("onOpenInternal"),
|
|
50
|
+
message: this.createHandler("onMessage"),
|
|
51
|
+
drain: this.createHandler("onDrain"),
|
|
52
|
+
close: this.createHandler("onCloseInternal"),
|
|
53
|
+
ping: this.createHandler("onPing"),
|
|
54
|
+
pong: this.createHandler("onPong"),
|
|
55
|
+
...options,
|
|
56
|
+
};
|
|
57
|
+
}
|
|
58
|
+
upgradeWebSocket(websocket, middlewares) {
|
|
59
|
+
const path = websocket.namespace;
|
|
60
|
+
const preparedMiddlewares = this.prepareMiddlewares(middlewares);
|
|
61
|
+
this.app.get(`/${path}`, ...preparedMiddlewares, async (c, next) => {
|
|
62
|
+
const websocketData = c.get("_websocketData") || {};
|
|
63
|
+
const id = bun.randomUUIDv7();
|
|
64
|
+
const data = { values: websocketData, id, path: path };
|
|
65
|
+
const upgradeResult = this._server.upgrade(c.req.raw, { data });
|
|
66
|
+
if (upgradeResult) {
|
|
67
|
+
return new Response(null);
|
|
68
|
+
}
|
|
69
|
+
await next(); // Failed
|
|
70
|
+
});
|
|
71
|
+
}
|
|
72
|
+
createHandler(type) {
|
|
73
|
+
return (ws, ...args) => {
|
|
74
|
+
const websocket = this.websockets.get(ws.data.path);
|
|
75
|
+
let handler = websocket?.socket[type];
|
|
76
|
+
if (!handler) {
|
|
77
|
+
return;
|
|
78
|
+
}
|
|
79
|
+
handler = handler.bind(websocket.socket);
|
|
80
|
+
handler(new AsenaSocket(ws, websocket.socket), ...args);
|
|
81
|
+
};
|
|
82
|
+
}
|
|
83
|
+
prepareMiddlewares(middlewares) {
|
|
84
|
+
return middlewareParser(middlewares);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
//# sourceMappingURL=HonoWebsocketAdapter.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HonoWebsocketAdapter.js","sourceRoot":"","sources":["../../lib/HonoWebsocketAdapter.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ConfigService.js","sourceRoot":"","sources":["../../../lib/defaults/ConfigService.ts"],"names":[],"mappings":"AAGA,MAAM,OAAgB,aAAa;CAAmC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"Context.js","sourceRoot":"","sources":["../../../lib/defaults/Context.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { AsenaMiddlewareService } from "@asenajs/asena/middleware";
|
|
2
|
+
import type { HonoRequest } from "hono";
|
|
3
|
+
import type { AsenaContext } from "@asenajs/asena/adapter";
|
|
4
|
+
export declare abstract class MiddlewareService<P extends string = any, I = any> extends AsenaMiddlewareService<AsenaContext<HonoRequest<P, I>, Response>> {
|
|
5
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"MiddlewareService.js","sourceRoot":"","sources":["../../../lib/defaults/MiddlewareService.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,sBAAsB,EAAE,MAAM,2BAA2B,CAAC;AAInE,MAAM,OAAgB,iBAGpB,SAAQ,sBAAiE;CAAG"}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { z } from "zod";
|
|
2
|
+
import type { Hook } from "@hono/zod-validator";
|
|
3
|
+
import type { AsenaValidationService } from "@asenajs/asena/middleware";
|
|
4
|
+
export type ValidationSchema = z.ZodType<any, z.ZodTypeDef, any>;
|
|
5
|
+
export interface ValidationSchemaWithHook {
|
|
6
|
+
schema: z.ZodType<any, z.ZodTypeDef, any>;
|
|
7
|
+
hook?: Hook<any, any, any>;
|
|
8
|
+
}
|
|
9
|
+
export declare abstract class ValidationService implements AsenaValidationService<ValidationSchema | ValidationSchemaWithHook> {
|
|
10
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"ValidationService.js","sourceRoot":"","sources":["../../../lib/defaults/ValidationService.ts"],"names":[],"mappings":"AAWA,MAAM,OAAgB,iBAAiB;CAEmC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/defaults/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,qBAAqB,CAAC;AACpC,cAAc,qBAAqB,CAAC;AACpC,cAAc,iBAAiB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"HonoHandler.js","sourceRoot":"","sources":["../../../lib/types/HonoHandler.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../lib/types/index.ts"],"names":[],"mappings":"AAAA,cAAc,eAAe,CAAC;AAC9B,cAAc,qBAAqB,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"createHonoAdapter.js","sourceRoot":"","sources":["../../../lib/utils/createHonoAdapter.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,WAAW,EAAE,oBAAoB,EAAE,MAAM,aAAa,CAAC;AAGhE,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAC/B,MAAqB,EACQ,EAAE;IAC/B,OAAO,CAAC,IAAI,WAAW,CAAC,IAAI,oBAAoB,EAAE,EAAE,MAAM,CAAC,EAAE,MAAM,CAAC,CAAC;AACvE,CAAC,CAAC"}
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import type { MiddlewareHandler } from "hono";
|
|
2
|
+
import type { Context as HonoAdapterContext } from "../defaults";
|
|
3
|
+
import type { BaseMiddleware } from "@asenajs/asena/adapter";
|
|
4
|
+
export declare const middlewareParser: (middlewares: BaseMiddleware<HonoAdapterContext>[]) => MiddlewareHandler[];
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import { HonoContextWrapper } from "../HonoContextWrapper";
|
|
2
|
+
import { createFactory } from "hono/factory";
|
|
3
|
+
export const middlewareParser = (middlewares) => {
|
|
4
|
+
const factory = createFactory();
|
|
5
|
+
return middlewares.map((middleware) => {
|
|
6
|
+
if (middleware.override) {
|
|
7
|
+
// @ts-ignore
|
|
8
|
+
return (c, next) => middleware.handle(c, next);
|
|
9
|
+
}
|
|
10
|
+
return factory.createMiddleware(async (context, next) => {
|
|
11
|
+
await middleware.handle(new HonoContextWrapper(context), next);
|
|
12
|
+
});
|
|
13
|
+
});
|
|
14
|
+
};
|
|
15
|
+
//# sourceMappingURL=middlewareParser.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"middlewareParser.js","sourceRoot":"","sources":["../../../lib/utils/middlewareParser.ts"],"names":[],"mappings":"AACA,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,aAAa,EAAE,MAAM,cAAc,CAAC;AAI7C,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAC9B,WAAiD,EAC5B,EAAE;IACvB,MAAM,OAAO,GAAG,aAAa,EAAE,CAAC;IAEhC,OAAO,WAAW,CAAC,GAAG,CAAC,CAAC,UAAU,EAAE,EAAE;QACpC,IAAI,UAAU,CAAC,QAAQ,EAAE,CAAC;YACxB,aAAa;YACb,OAAO,CAAC,CAAU,EAAE,IAAc,EAAE,EAAE,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,IAAI,CAAC,CAAC;QACpE,CAAC;QAED,OAAO,OAAO,CAAC,gBAAgB,CAAC,KAAK,EAAE,OAAgB,EAAE,IAAU,EAAE,EAAE;YACrE,MAAM,UAAU,CAAC,MAAM,CAAC,IAAI,kBAAkB,CAAC,OAAO,CAAC,EAAE,IAAI,CAAC,CAAC;QACjE,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACL,CAAC,CAAC"}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@asenajs/hono-adapter",
|
|
3
|
+
"module": "index.ts",
|
|
4
|
+
"description": "Hono server and websocket adapter for Asenajs ",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"main": "dist/index.js",
|
|
7
|
+
"types": "dist/index.d.ts",
|
|
8
|
+
"files": [
|
|
9
|
+
"dist",
|
|
10
|
+
"README.md",
|
|
11
|
+
"LICENSE"
|
|
12
|
+
],
|
|
13
|
+
"version": "1.0.0",
|
|
14
|
+
"author": "LibirSoft",
|
|
15
|
+
"license": "MIT",
|
|
16
|
+
"scripts": {
|
|
17
|
+
"test": "bun test",
|
|
18
|
+
"test:watch": "bun test --watch",
|
|
19
|
+
"test:coverage": "bun test --coverage",
|
|
20
|
+
"build": "bun run clean && tsc",
|
|
21
|
+
"clean": "rm -rf dist",
|
|
22
|
+
"prepublishOnly": "bun run build"
|
|
23
|
+
},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@asenajs/asena": "link:@asenajs/asena",
|
|
26
|
+
"@changesets/cli": "^2.28.1",
|
|
27
|
+
"@types/bun": "latest",
|
|
28
|
+
"@typescript-eslint/eslint-plugin": "^6.21.0",
|
|
29
|
+
"eslint": "^8.57.1",
|
|
30
|
+
"eslint-config-alloy": "^5.1.2",
|
|
31
|
+
"eslint-config-prettier": "^9.1.0",
|
|
32
|
+
"eslint-plugin-alloy": "^1.2.1",
|
|
33
|
+
"eslint-plugin-import": "^2.31.0",
|
|
34
|
+
"eslint-plugin-n": "^16.6.2",
|
|
35
|
+
"eslint-plugin-prettier": "^5.2.5",
|
|
36
|
+
"eslint-plugin-promise": "^6.6.0",
|
|
37
|
+
"prettier": "^3.5.3"
|
|
38
|
+
},
|
|
39
|
+
"peerDependencies": {
|
|
40
|
+
"typescript": "^5.8.2"
|
|
41
|
+
},
|
|
42
|
+
"dependencies": {
|
|
43
|
+
"@hono/zod-validator": "^0.4.3",
|
|
44
|
+
"hono": "^4.7.5",
|
|
45
|
+
"zod": "^3.24.2"
|
|
46
|
+
}
|
|
47
|
+
}
|