honovajs 0.0.1
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/README.md +366 -0
- package/dist/adapters/db/drizzle.d.ts +7 -0
- package/dist/adapters/db/drizzle.d.ts.map +1 -0
- package/dist/adapters/db/drizzle.js +8 -0
- package/dist/adapters/db/drizzle.js.map +1 -0
- package/dist/adapters/db/index.d.ts +5 -0
- package/dist/adapters/db/index.d.ts.map +1 -0
- package/dist/adapters/db/index.js +5 -0
- package/dist/adapters/db/index.js.map +1 -0
- package/dist/adapters/db/mondel.d.ts +2 -0
- package/dist/adapters/db/mondel.d.ts.map +1 -0
- package/dist/adapters/db/mondel.js +2 -0
- package/dist/adapters/db/mondel.js.map +1 -0
- package/dist/adapters/db/mongodb.d.ts +7 -0
- package/dist/adapters/db/mongodb.d.ts.map +1 -0
- package/dist/adapters/db/mongodb.js +8 -0
- package/dist/adapters/db/mongodb.js.map +1 -0
- package/dist/adapters/db/prisma.d.ts +9 -0
- package/dist/adapters/db/prisma.d.ts.map +1 -0
- package/dist/adapters/db/prisma.js +16 -0
- package/dist/adapters/db/prisma.js.map +1 -0
- package/dist/core/application.d.ts +45 -0
- package/dist/core/application.d.ts.map +1 -0
- package/dist/core/application.js +138 -0
- package/dist/core/application.js.map +1 -0
- package/dist/core/constants.d.ts +9 -0
- package/dist/core/constants.d.ts.map +1 -0
- package/dist/core/constants.js +9 -0
- package/dist/core/constants.js.map +1 -0
- package/dist/core/container/container.d.ts +34 -0
- package/dist/core/container/container.d.ts.map +1 -0
- package/dist/core/container/container.js +243 -0
- package/dist/core/container/container.js.map +1 -0
- package/dist/core/container/index.d.ts +3 -0
- package/dist/core/container/index.d.ts.map +1 -0
- package/dist/core/container/index.js +3 -0
- package/dist/core/container/index.js.map +1 -0
- package/dist/core/container/inject.d.ts +3 -0
- package/dist/core/container/inject.d.ts.map +1 -0
- package/dist/core/container/inject.js +9 -0
- package/dist/core/container/inject.js.map +1 -0
- package/dist/core/decorators/context.d.ts +12 -0
- package/dist/core/decorators/context.d.ts.map +1 -0
- package/dist/core/decorators/context.js +2 -0
- package/dist/core/decorators/context.js.map +1 -0
- package/dist/core/decorators/controller.d.ts +2 -0
- package/dist/core/decorators/controller.d.ts.map +1 -0
- package/dist/core/decorators/controller.js +52 -0
- package/dist/core/decorators/controller.js.map +1 -0
- package/dist/core/decorators/http-methods.d.ts +9 -0
- package/dist/core/decorators/http-methods.d.ts.map +1 -0
- package/dist/core/decorators/http-methods.js +45 -0
- package/dist/core/decorators/http-methods.js.map +1 -0
- package/dist/core/decorators/index.d.ts +8 -0
- package/dist/core/decorators/index.d.ts.map +1 -0
- package/dist/core/decorators/index.js +8 -0
- package/dist/core/decorators/index.js.map +1 -0
- package/dist/core/decorators/inject.d.ts +3 -0
- package/dist/core/decorators/inject.d.ts.map +1 -0
- package/dist/core/decorators/inject.js +8 -0
- package/dist/core/decorators/inject.js.map +1 -0
- package/dist/core/decorators/injectable.d.ts +6 -0
- package/dist/core/decorators/injectable.d.ts.map +1 -0
- package/dist/core/decorators/injectable.js +10 -0
- package/dist/core/decorators/injectable.js.map +1 -0
- package/dist/core/decorators/middleware.d.ts +3 -0
- package/dist/core/decorators/middleware.d.ts.map +1 -0
- package/dist/core/decorators/middleware.js +45 -0
- package/dist/core/decorators/middleware.js.map +1 -0
- package/dist/core/decorators/module.d.ts +3 -0
- package/dist/core/decorators/module.d.ts.map +1 -0
- package/dist/core/decorators/module.js +7 -0
- package/dist/core/decorators/module.js.map +1 -0
- package/dist/core/metadata.d.ts +17 -0
- package/dist/core/metadata.d.ts.map +1 -0
- package/dist/core/metadata.js +72 -0
- package/dist/core/metadata.js.map +1 -0
- package/dist/core/router/index.d.ts +2 -0
- package/dist/core/router/index.d.ts.map +1 -0
- package/dist/core/router/index.js +2 -0
- package/dist/core/router/index.js.map +1 -0
- package/dist/core/router/router.d.ts +14 -0
- package/dist/core/router/router.d.ts.map +1 -0
- package/dist/core/router/router.js +60 -0
- package/dist/core/router/router.js.map +1 -0
- package/dist/core/types.d.ts +29 -0
- package/dist/core/types.d.ts.map +1 -0
- package/dist/core/types.js +2 -0
- package/dist/core/types.js.map +1 -0
- package/dist/database/index.d.ts +4 -0
- package/dist/database/index.d.ts.map +1 -0
- package/dist/database/index.js +4 -0
- package/dist/database/index.js.map +1 -0
- package/dist/database/manager.d.ts +72 -0
- package/dist/database/manager.d.ts.map +1 -0
- package/dist/database/manager.js +160 -0
- package/dist/database/manager.js.map +1 -0
- package/dist/database/middleware.d.ts +21 -0
- package/dist/database/middleware.d.ts.map +1 -0
- package/dist/database/middleware.js +23 -0
- package/dist/database/middleware.js.map +1 -0
- package/dist/database/types.d.ts +31 -0
- package/dist/database/types.d.ts.map +1 -0
- package/dist/database/types.js +24 -0
- package/dist/database/types.js.map +1 -0
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +10 -0
- package/dist/index.js.map +1 -0
- package/dist/middleware/auth/apikey.d.ts +16 -0
- package/dist/middleware/auth/apikey.d.ts.map +1 -0
- package/dist/middleware/auth/apikey.js +37 -0
- package/dist/middleware/auth/apikey.js.map +1 -0
- package/dist/middleware/auth/bearer.d.ts +17 -0
- package/dist/middleware/auth/bearer.d.ts.map +1 -0
- package/dist/middleware/auth/bearer.js +41 -0
- package/dist/middleware/auth/bearer.js.map +1 -0
- package/dist/middleware/auth/index.d.ts +3 -0
- package/dist/middleware/auth/index.d.ts.map +1 -0
- package/dist/middleware/auth/index.js +3 -0
- package/dist/middleware/auth/index.js.map +1 -0
- package/package.json +47 -0
package/README.md
ADDED
|
@@ -0,0 +1,366 @@
|
|
|
1
|
+
# Honova
|
|
2
|
+
|
|
3
|
+
Nest-like framework for Cloudflare Workers built on top of Hono.
|
|
4
|
+
|
|
5
|
+
Honova provides a module system, decorators, dependency injection, route metadata, request-aware lifecycle, and typed database middleware so you can build structured APIs on the edge without bringing a full Node-centric runtime.
|
|
6
|
+
|
|
7
|
+
## Status
|
|
8
|
+
|
|
9
|
+
- Package version: `0.0.1`
|
|
10
|
+
- Runtime target: Cloudflare Workers (also works anywhere Hono runs)
|
|
11
|
+
- Module format: ESM
|
|
12
|
+
|
|
13
|
+
## Feature Checklist
|
|
14
|
+
|
|
15
|
+
### Core Framework
|
|
16
|
+
|
|
17
|
+
- [x] `@Module()` with `controllers`, `providers`, and `imports`
|
|
18
|
+
- [x] `@Controller()` with route prefixing
|
|
19
|
+
- [x] HTTP method decorators: `@Get`, `@Post`, `@Put`, `@Patch`, `@Delete`, `@Options`, `@Head`
|
|
20
|
+
- [x] Dependency Injection container
|
|
21
|
+
- [x] `@Injectable()` scopes (`singleton`, `request`, `transient`)
|
|
22
|
+
- [x] `@Inject()` token-based constructor injection
|
|
23
|
+
- [x] Provider auto-inference by constructor parameter name
|
|
24
|
+
- [x] Request-aware provider resolution (`resolveWithContext`)
|
|
25
|
+
- [x] `OnModuleInit` lifecycle hook (sync)
|
|
26
|
+
- [x] Global middleware registration
|
|
27
|
+
- [x] Controller-level and route-level middleware via `@UseMiddleware`
|
|
28
|
+
- [x] Built-in `not_found` and `internal_error` JSON responses
|
|
29
|
+
|
|
30
|
+
### Security and Observability
|
|
31
|
+
|
|
32
|
+
- [x] CORS integration (`hono/cors`)
|
|
33
|
+
- [x] Optional secure headers (`hono/secure-headers`)
|
|
34
|
+
- [x] Request ID propagation (`x-request-id` by default)
|
|
35
|
+
- [x] Access logs with log level control (`debug`, `info`, `warn`, `error`)
|
|
36
|
+
- [x] Header redaction in debug logs
|
|
37
|
+
|
|
38
|
+
### Authentication Middleware
|
|
39
|
+
|
|
40
|
+
- [x] Bearer auth middleware (`UseBearerAuth`, `BearerAuth`)
|
|
41
|
+
- [x] API key middleware (`UseApiKey`, `ApiKeyAuth`)
|
|
42
|
+
- [x] Auth principal injection into context (`c.set("auth", principal)`)
|
|
43
|
+
- [x] Overrideable auth error handling
|
|
44
|
+
|
|
45
|
+
### Database Layer
|
|
46
|
+
|
|
47
|
+
- [x] `defineDatabase()` typed config helper
|
|
48
|
+
- [x] `DatabaseManager` with per-request lifecycle
|
|
49
|
+
- [x] Single and multi-connection support
|
|
50
|
+
- [x] `defaultConnection` enforcement for multi-DB setups
|
|
51
|
+
- [x] URL resolution from static URL, env binding, or async resolver
|
|
52
|
+
- [x] Eager connection initialization
|
|
53
|
+
- [x] Connection cleanup hooks
|
|
54
|
+
- [x] Context bindings: `c.db`, `c.get("db")`, `c.get("dbConnections")`
|
|
55
|
+
- [x] Adapter helpers: Drizzle, Prisma, MongoDB (`createMongoDbAdapter`) with legacy alias (`createMondelAdapter`)
|
|
56
|
+
|
|
57
|
+
### Tests
|
|
58
|
+
|
|
59
|
+
- [x] DI behavior tests
|
|
60
|
+
- [x] Provider validation tests (`@Injectable` required)
|
|
61
|
+
- [x] Lifecycle behavior tests (`onModuleInit` with request context)
|
|
62
|
+
- [x] Database manager and middleware tests
|
|
63
|
+
|
|
64
|
+
### Planned / Missing Features
|
|
65
|
+
|
|
66
|
+
- [x] Request-scoped and transient instance caching semantics validated by tests
|
|
67
|
+
- [ ] Async `onModuleInit` support in runtime
|
|
68
|
+
- [ ] Validation pipes and DTO validation layer
|
|
69
|
+
- [ ] Guard/interceptor abstraction (Nest-style)
|
|
70
|
+
- [ ] Exception filter abstraction
|
|
71
|
+
- [ ] First-class OpenAPI/Swagger generation
|
|
72
|
+
- [ ] CLI scaffolding (`create-honova-app`, generators)
|
|
73
|
+
- [ ] Official Cloudflare starter templates (D1, KV, R2 examples)
|
|
74
|
+
- [ ] More auth primitives (JWT helper, role/permission guard, session middleware)
|
|
75
|
+
- [ ] E2E test suite with Worker runtime integration
|
|
76
|
+
- [ ] Benchmark/performance suite and guidance
|
|
77
|
+
- [ ] Complete API docs website
|
|
78
|
+
|
|
79
|
+
## Installation
|
|
80
|
+
|
|
81
|
+
```bash
|
|
82
|
+
npm i honovajs
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
```bash
|
|
86
|
+
pnpm add honovajs
|
|
87
|
+
```
|
|
88
|
+
|
|
89
|
+
```bash
|
|
90
|
+
yarn add honovajs
|
|
91
|
+
```
|
|
92
|
+
|
|
93
|
+
```bash
|
|
94
|
+
bun add honovajs
|
|
95
|
+
```
|
|
96
|
+
|
|
97
|
+
## Quick Start
|
|
98
|
+
|
|
99
|
+
```ts
|
|
100
|
+
import { Controller, Get, Injectable, Module, createApp } from "honovajs";
|
|
101
|
+
|
|
102
|
+
@Injectable()
|
|
103
|
+
class HealthService {
|
|
104
|
+
getStatus() {
|
|
105
|
+
return { ok: true };
|
|
106
|
+
}
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
@Controller("/health")
|
|
110
|
+
class HealthController {
|
|
111
|
+
constructor(private readonly healthService: HealthService) {}
|
|
112
|
+
|
|
113
|
+
@Get("/")
|
|
114
|
+
handle(): Response {
|
|
115
|
+
return Response.json(this.healthService.getStatus());
|
|
116
|
+
}
|
|
117
|
+
}
|
|
118
|
+
|
|
119
|
+
@Module({
|
|
120
|
+
controllers: [HealthController],
|
|
121
|
+
providers: [HealthService],
|
|
122
|
+
})
|
|
123
|
+
class AppModule {}
|
|
124
|
+
|
|
125
|
+
const app = createApp({ basePath: "/api" });
|
|
126
|
+
app.registerModule(AppModule);
|
|
127
|
+
|
|
128
|
+
export default {
|
|
129
|
+
fetch: app.fetch,
|
|
130
|
+
};
|
|
131
|
+
```
|
|
132
|
+
|
|
133
|
+
## Core Concepts
|
|
134
|
+
|
|
135
|
+
### Modules
|
|
136
|
+
|
|
137
|
+
`@Module()` organizes app boundaries:
|
|
138
|
+
|
|
139
|
+
- `controllers`: classes that expose HTTP handlers
|
|
140
|
+
- `providers`: services managed by the DI container
|
|
141
|
+
- `imports`: other modules to compose features
|
|
142
|
+
|
|
143
|
+
All providers listed in `providers` must have `@Injectable()`.
|
|
144
|
+
|
|
145
|
+
### Controllers and Routes
|
|
146
|
+
|
|
147
|
+
`@Controller("/prefix")` defines a route prefix. Route handlers are defined with HTTP decorators.
|
|
148
|
+
|
|
149
|
+
```ts
|
|
150
|
+
@Controller("/users")
|
|
151
|
+
class UserController {
|
|
152
|
+
@Get("/")
|
|
153
|
+
list() {
|
|
154
|
+
return Response.json([]);
|
|
155
|
+
}
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
### Dependency Injection
|
|
160
|
+
|
|
161
|
+
Providers are resolved through the container. Constructor dependencies can be resolved by:
|
|
162
|
+
|
|
163
|
+
- explicit token with `@Inject(token)`
|
|
164
|
+
- inferred class token by constructor parameter name
|
|
165
|
+
|
|
166
|
+
Strict DI mode is enabled by default and throws on unresolved dependencies.
|
|
167
|
+
|
|
168
|
+
Provider scopes:
|
|
169
|
+
|
|
170
|
+
- `singleton`: one instance per app container
|
|
171
|
+
- `request`: one instance per request context (reused within the same request)
|
|
172
|
+
- `transient`: new instance on each resolution
|
|
173
|
+
|
|
174
|
+
### Lifecycle: `OnModuleInit`
|
|
175
|
+
|
|
176
|
+
A provider can implement `onModuleInit(context?)`.
|
|
177
|
+
|
|
178
|
+
Current runtime behavior:
|
|
179
|
+
|
|
180
|
+
- It runs when the provider is resolved for the first time.
|
|
181
|
+
- For singleton providers, it runs once per app instance.
|
|
182
|
+
- Request context is passed when the provider is resolved during a request.
|
|
183
|
+
- It must be synchronous in `0.0.1`.
|
|
184
|
+
|
|
185
|
+
## Middleware
|
|
186
|
+
|
|
187
|
+
### Global Middleware
|
|
188
|
+
|
|
189
|
+
```ts
|
|
190
|
+
const app = createApp({
|
|
191
|
+
globalMiddlewares: [async (c, next) => { await next(); }],
|
|
192
|
+
});
|
|
193
|
+
```
|
|
194
|
+
|
|
195
|
+
### Decorator Middleware
|
|
196
|
+
|
|
197
|
+
```ts
|
|
198
|
+
import { Controller, Get, UseMiddleware } from "honovajs";
|
|
199
|
+
|
|
200
|
+
const requireHeader = async (c: any, next: any) => {
|
|
201
|
+
if (!c.req.header("x-trace")) {
|
|
202
|
+
return c.json({ error: "missing x-trace" }, 400);
|
|
203
|
+
}
|
|
204
|
+
await next();
|
|
205
|
+
};
|
|
206
|
+
|
|
207
|
+
@UseMiddleware(requireHeader)
|
|
208
|
+
@Controller("/demo")
|
|
209
|
+
class DemoController {
|
|
210
|
+
@Get("/")
|
|
211
|
+
handle() {
|
|
212
|
+
return Response.json({ ok: true });
|
|
213
|
+
}
|
|
214
|
+
}
|
|
215
|
+
```
|
|
216
|
+
|
|
217
|
+
## Security and Observability
|
|
218
|
+
|
|
219
|
+
Configure at app creation:
|
|
220
|
+
|
|
221
|
+
```ts
|
|
222
|
+
const app = createApp({
|
|
223
|
+
security: {
|
|
224
|
+
cors: { origin: ["https://app.example.com"] },
|
|
225
|
+
secureHeaders: true,
|
|
226
|
+
},
|
|
227
|
+
observability: {
|
|
228
|
+
requestIdHeader: "x-request-id",
|
|
229
|
+
enableAccessLogs: true,
|
|
230
|
+
logLevel: "info",
|
|
231
|
+
redactHeaders: ["authorization", "cookie", "x-api-key"],
|
|
232
|
+
},
|
|
233
|
+
});
|
|
234
|
+
```
|
|
235
|
+
|
|
236
|
+
## Authentication
|
|
237
|
+
|
|
238
|
+
### Bearer Token
|
|
239
|
+
|
|
240
|
+
```ts
|
|
241
|
+
import { Controller, Get, UseBearerAuth } from "honovajs";
|
|
242
|
+
|
|
243
|
+
@UseBearerAuth({
|
|
244
|
+
verify: async (token) => (token === "valid-token" ? { id: "user_1" } : null),
|
|
245
|
+
})
|
|
246
|
+
@Controller("/me")
|
|
247
|
+
class MeController {
|
|
248
|
+
@Get("/")
|
|
249
|
+
handle() {
|
|
250
|
+
return Response.json({ ok: true });
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
```
|
|
254
|
+
|
|
255
|
+
### API Key
|
|
256
|
+
|
|
257
|
+
```ts
|
|
258
|
+
import { Controller, Get, UseApiKey } from "honovajs";
|
|
259
|
+
|
|
260
|
+
@UseApiKey({
|
|
261
|
+
header: "x-api-key",
|
|
262
|
+
verify: async (key) => (key === "secret" ? { id: "service_1" } : null),
|
|
263
|
+
})
|
|
264
|
+
@Controller("/internal")
|
|
265
|
+
class InternalController {
|
|
266
|
+
@Get("/")
|
|
267
|
+
handle() {
|
|
268
|
+
return Response.json({ ok: true });
|
|
269
|
+
}
|
|
270
|
+
}
|
|
271
|
+
```
|
|
272
|
+
|
|
273
|
+
## Database Integration
|
|
274
|
+
|
|
275
|
+
### Define Connections
|
|
276
|
+
|
|
277
|
+
```ts
|
|
278
|
+
import { createDbManagerMiddleware, defineDatabase } from "honovajs";
|
|
279
|
+
|
|
280
|
+
type Env = { DATABASE_URL: string; ANALYTICS_URL: string };
|
|
281
|
+
|
|
282
|
+
const database = defineDatabase<Env>()({
|
|
283
|
+
lifecycle: { strategy: "request" }, // default
|
|
284
|
+
defaultConnection: "main",
|
|
285
|
+
connections: [
|
|
286
|
+
{
|
|
287
|
+
connectionName: "main",
|
|
288
|
+
adapter: {
|
|
289
|
+
name: "custom",
|
|
290
|
+
connect: async ({ url }) => ({ url }),
|
|
291
|
+
},
|
|
292
|
+
urlFromEnv: "DATABASE_URL",
|
|
293
|
+
// default connection is always initialized per request
|
|
294
|
+
},
|
|
295
|
+
{
|
|
296
|
+
connectionName: "analytics",
|
|
297
|
+
adapter: {
|
|
298
|
+
name: "custom",
|
|
299
|
+
connect: async ({ url }) => ({ url }),
|
|
300
|
+
},
|
|
301
|
+
urlFromEnv: "ANALYTICS_URL",
|
|
302
|
+
eager: true, // optional; initialize this non-default connection on every request
|
|
303
|
+
},
|
|
304
|
+
],
|
|
305
|
+
});
|
|
306
|
+
|
|
307
|
+
const app = createApp<Env>({
|
|
308
|
+
database,
|
|
309
|
+
});
|
|
310
|
+
```
|
|
311
|
+
|
|
312
|
+
Inside handlers:
|
|
313
|
+
|
|
314
|
+
- `c.db` points to the default connection and also exposes named connections.
|
|
315
|
+
- `c.get("dbConnections")` returns all named connections.
|
|
316
|
+
- Non-default connections are lazy by default (`eager: false`).
|
|
317
|
+
- `lifecycle.strategy` defaults to `"request"` (cleanup after each request). Use `"manual"` only when you intentionally manage connection lifecycle yourself.
|
|
318
|
+
|
|
319
|
+
## Cloudflare Workers Deployment
|
|
320
|
+
|
|
321
|
+
Honova exposes `app.fetch`, so Worker export is direct:
|
|
322
|
+
|
|
323
|
+
```ts
|
|
324
|
+
export default {
|
|
325
|
+
fetch: app.fetch,
|
|
326
|
+
};
|
|
327
|
+
```
|
|
328
|
+
|
|
329
|
+
Use your standard Worker workflow with Wrangler:
|
|
330
|
+
|
|
331
|
+
```bash
|
|
332
|
+
npm run build
|
|
333
|
+
wrangler deploy
|
|
334
|
+
```
|
|
335
|
+
|
|
336
|
+
## API Surface
|
|
337
|
+
|
|
338
|
+
Main exports include:
|
|
339
|
+
|
|
340
|
+
- App/runtime: `createApp`, `Application`
|
|
341
|
+
- Decorators: `Module`, `Controller`, `Injectable`, `Inject`, `UseMiddleware`, HTTP method decorators
|
|
342
|
+
- DI helper: `inject`
|
|
343
|
+
- Database: `defineDatabase`, `DatabaseManager`, `createDbManagerMiddleware`, `createDrizzleAdapter`, `createPrismaAdapter`, `createMongoDbAdapter` (legacy `createMondelAdapter`), helpers from `database/types`
|
|
344
|
+
- Auth middleware: `UseBearerAuth`, `BearerAuth`, `UseApiKey`, `ApiKeyAuth`
|
|
345
|
+
|
|
346
|
+
## Development Scripts
|
|
347
|
+
|
|
348
|
+
```bash
|
|
349
|
+
npm run typecheck
|
|
350
|
+
npm run test
|
|
351
|
+
npm run build
|
|
352
|
+
```
|
|
353
|
+
|
|
354
|
+
## Publish Checklist (npm)
|
|
355
|
+
|
|
356
|
+
- [x] Version set to `0.0.1`
|
|
357
|
+
- [x] ESM build output in `dist/`
|
|
358
|
+
- [x] Type declarations emitted
|
|
359
|
+
- [x] Package `files` restricted to `dist`
|
|
360
|
+
- [x] `prepublishOnly` runs typecheck + tests + build
|
|
361
|
+
- [ ] npm organization metadata (`repository`, `bugs`, `homepage`) if needed
|
|
362
|
+
- [ ] `npm publish --access public`
|
|
363
|
+
|
|
364
|
+
## License
|
|
365
|
+
|
|
366
|
+
MIT
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "../../database/manager";
|
|
2
|
+
export interface DrizzleAdapterOptions<TClient> {
|
|
3
|
+
connect: (url: string) => Promise<TClient> | TClient;
|
|
4
|
+
disconnect?: (client: TClient) => Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createDrizzleAdapter<Env extends Record<string, unknown>, TClient>(options: DrizzleAdapterOptions<TClient>): DatabaseAdapter<Env, TClient, unknown>;
|
|
7
|
+
//# sourceMappingURL=drizzle.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.d.ts","sourceRoot":"","sources":["../../../src/adapters/db/drizzle.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,qBAAqB,CAAC,OAAO;IAC5C,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED,wBAAgB,oBAAoB,CAClC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,EAEP,OAAO,EAAE,qBAAqB,CAAC,OAAO,CAAC,GACtC,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAMxC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"drizzle.js","sourceRoot":"","sources":["../../../src/adapters/db/drizzle.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,oBAAoB,CAIlC,OAAuC;IAEvC,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;QAChD,UAAU,EAAE,OAAO,CAAC,UAAU;KAC/B,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/adapters/db/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/adapters/db/index.ts"],"names":[],"mappings":"AAAA,cAAc,WAAW,CAAC;AAC1B,cAAc,WAAW,CAAC;AAC1B,cAAc,UAAU,CAAC;AACzB,cAAc,UAAU,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mondel.d.ts","sourceRoot":"","sources":["../../../src/adapters/db/mondel.ts"],"names":[],"mappings":"AAAA,OAAO,EACL,KAAK,qBAAqB,IAAI,oBAAoB,EAClD,oBAAoB,IAAI,mBAAmB,GAC5C,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mondel.js","sourceRoot":"","sources":["../../../src/adapters/db/mondel.ts"],"names":[],"mappings":"AAAA,OAAO,EAEL,oBAAoB,IAAI,mBAAmB,GAC5C,MAAM,WAAW,CAAC"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "../../database/manager";
|
|
2
|
+
export interface MongoDbAdapterOptions<TClient, TConnectOptions> {
|
|
3
|
+
connect: (url: string, options: TConnectOptions) => Promise<TClient> | TClient;
|
|
4
|
+
disconnect?: (client: TClient) => Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createMongoDbAdapter<Env extends Record<string, unknown>, TClient, TConnectOptions>(adapterOptions: MongoDbAdapterOptions<TClient, TConnectOptions>): DatabaseAdapter<Env, TClient, TConnectOptions>;
|
|
7
|
+
//# sourceMappingURL=mongodb.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongodb.d.ts","sourceRoot":"","sources":["../../../src/adapters/db/mongodb.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,qBAAqB,CAAC,OAAO,EAAE,eAAe;IAC7D,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,EAAE,OAAO,EAAE,eAAe,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IAC/E,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED,wBAAgB,oBAAoB,CAClC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,EACP,eAAe,EAEf,cAAc,EAAE,qBAAqB,CAAC,OAAO,EAAE,eAAe,CAAC,GAC9D,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,eAAe,CAAC,CAMhD"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mongodb.js","sourceRoot":"","sources":["../../../src/adapters/db/mongodb.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,oBAAoB,CAKlC,cAA+D;IAE/D,OAAO;QACL,IAAI,EAAE,SAAS;QACf,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,OAAO,EAAE,EAAE,EAAE,CAAC,cAAc,CAAC,OAAO,CAAC,GAAG,EAAE,OAAO,CAAC;QACzE,UAAU,EAAE,cAAc,CAAC,UAAU;KACtC,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import type { DatabaseAdapter } from "../../database/manager";
|
|
2
|
+
export interface PrismaAdapterOptions<TClient> {
|
|
3
|
+
connect: (url: string) => Promise<TClient> | TClient;
|
|
4
|
+
disconnect?: (client: TClient) => Promise<void> | void;
|
|
5
|
+
}
|
|
6
|
+
export declare function createPrismaAdapter<Env extends Record<string, unknown>, TClient extends {
|
|
7
|
+
$disconnect?: () => Promise<void> | void;
|
|
8
|
+
}>(options: PrismaAdapterOptions<TClient>): DatabaseAdapter<Env, TClient, unknown>;
|
|
9
|
+
//# sourceMappingURL=prisma.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma.d.ts","sourceRoot":"","sources":["../../../src/adapters/db/prisma.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,eAAe,EAAE,MAAM,wBAAwB,CAAC;AAE9D,MAAM,WAAW,oBAAoB,CAAC,OAAO;IAC3C,OAAO,EAAE,CAAC,GAAG,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;IACrD,UAAU,CAAC,EAAE,CAAC,MAAM,EAAE,OAAO,KAAK,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC;CACxD;AAED,wBAAgB,mBAAmB,CACjC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACnC,OAAO,SAAS;IAAE,WAAW,CAAC,EAAE,MAAM,OAAO,CAAC,IAAI,CAAC,GAAG,IAAI,CAAA;CAAE,EAE5D,OAAO,EAAE,oBAAoB,CAAC,OAAO,CAAC,GACrC,eAAe,CAAC,GAAG,EAAE,OAAO,EAAE,OAAO,CAAC,CAexC"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
export function createPrismaAdapter(options) {
|
|
2
|
+
return {
|
|
3
|
+
name: "prisma",
|
|
4
|
+
connect: async ({ url }) => options.connect(url),
|
|
5
|
+
disconnect: async (client) => {
|
|
6
|
+
if (options.disconnect) {
|
|
7
|
+
await options.disconnect(client);
|
|
8
|
+
return;
|
|
9
|
+
}
|
|
10
|
+
if (typeof client.$disconnect === "function") {
|
|
11
|
+
await client.$disconnect();
|
|
12
|
+
}
|
|
13
|
+
},
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=prisma.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"prisma.js","sourceRoot":"","sources":["../../../src/adapters/db/prisma.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,mBAAmB,CAIjC,OAAsC;IAEtC,OAAO;QACL,IAAI,EAAE,QAAQ;QACd,OAAO,EAAE,KAAK,EAAE,EAAE,GAAG,EAAE,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,GAAG,CAAC;QAChD,UAAU,EAAE,KAAK,EAAE,MAAM,EAAE,EAAE;YAC3B,IAAI,OAAO,CAAC,UAAU,EAAE,CAAC;gBACvB,MAAM,OAAO,CAAC,UAAU,CAAC,MAAM,CAAC,CAAC;gBACjC,OAAO;YACT,CAAC;YAED,IAAI,OAAO,MAAM,CAAC,WAAW,KAAK,UAAU,EAAE,CAAC;gBAC7C,MAAM,MAAM,CAAC,WAAW,EAAE,CAAC;YAC7B,CAAC;QACH,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
import { Hono, type MiddlewareHandler } from "hono";
|
|
2
|
+
import { cors } from "hono/cors";
|
|
3
|
+
import { secureHeaders } from "hono/secure-headers";
|
|
4
|
+
import { Container } from "./container/container";
|
|
5
|
+
import { type DbManagerMiddlewareOptions } from "../database/middleware";
|
|
6
|
+
import type { Constructor } from "./types";
|
|
7
|
+
export interface SecurityOptions {
|
|
8
|
+
cors?: Parameters<typeof cors>[0];
|
|
9
|
+
secureHeaders?: boolean | Parameters<typeof secureHeaders>[0];
|
|
10
|
+
}
|
|
11
|
+
export interface ObservabilityOptions {
|
|
12
|
+
requestIdHeader?: string;
|
|
13
|
+
enableAccessLogs?: boolean;
|
|
14
|
+
logLevel?: "debug" | "info" | "warn" | "error";
|
|
15
|
+
redactHeaders?: string[];
|
|
16
|
+
}
|
|
17
|
+
export interface ApplicationOptions<Env extends Record<string, unknown>> {
|
|
18
|
+
basePath?: string;
|
|
19
|
+
globalMiddlewares?: MiddlewareHandler[];
|
|
20
|
+
database?: DbManagerMiddlewareOptions<Env>;
|
|
21
|
+
security?: SecurityOptions;
|
|
22
|
+
observability?: ObservabilityOptions;
|
|
23
|
+
di?: {
|
|
24
|
+
strict?: boolean;
|
|
25
|
+
};
|
|
26
|
+
}
|
|
27
|
+
export declare class Application<Env extends Record<string, unknown> = Record<string, unknown>> {
|
|
28
|
+
private app;
|
|
29
|
+
private readonly container;
|
|
30
|
+
private readonly router;
|
|
31
|
+
private readonly registeredProviders;
|
|
32
|
+
private readonly registeredControllers;
|
|
33
|
+
private readonly registeredModules;
|
|
34
|
+
private readonly moduleResolutionStack;
|
|
35
|
+
constructor(options?: ApplicationOptions<Env>);
|
|
36
|
+
registerModule(moduleClass: Constructor): this;
|
|
37
|
+
use(middleware: MiddlewareHandler): this;
|
|
38
|
+
getContainer(): Container;
|
|
39
|
+
getHono(): Hono<{
|
|
40
|
+
Bindings: Env;
|
|
41
|
+
}>;
|
|
42
|
+
fetch: (request: Request, env: Env, ctx: any) => Response | Promise<Response>;
|
|
43
|
+
}
|
|
44
|
+
export declare function createApp<Env extends Record<string, unknown> = Record<string, unknown>>(options?: ApplicationOptions<Env>): Application<Env>;
|
|
45
|
+
//# sourceMappingURL=application.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"application.d.ts","sourceRoot":"","sources":["../../src/core/application.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,IAAI,EAAE,KAAK,iBAAiB,EAAE,MAAM,MAAM,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AACjC,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AAEpD,OAAO,EAAE,SAAS,EAAE,MAAM,uBAAuB,CAAC;AAClD,OAAO,EAA6B,KAAK,0BAA0B,EAAE,MAAM,wBAAwB,CAAC;AAEpG,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,SAAS,CAAC;AAG3C,MAAM,WAAW,eAAe;IAC9B,IAAI,CAAC,EAAE,UAAU,CAAC,OAAO,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC;IAClC,aAAa,CAAC,EAAE,OAAO,GAAG,UAAU,CAAC,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC,CAAC;CAC/D;AAED,MAAM,WAAW,oBAAoB;IACnC,eAAe,CAAC,EAAE,MAAM,CAAC;IACzB,gBAAgB,CAAC,EAAE,OAAO,CAAC;IAC3B,QAAQ,CAAC,EAAE,OAAO,GAAG,MAAM,GAAG,MAAM,GAAG,OAAO,CAAC;IAC/C,aAAa,CAAC,EAAE,MAAM,EAAE,CAAC;CAC1B;AAED,MAAM,WAAW,kBAAkB,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACrE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,iBAAiB,CAAC,EAAE,iBAAiB,EAAE,CAAC;IACxC,QAAQ,CAAC,EAAE,0BAA0B,CAAC,GAAG,CAAC,CAAC;IAC3C,QAAQ,CAAC,EAAE,eAAe,CAAC;IAC3B,aAAa,CAAC,EAAE,oBAAoB,CAAC;IACrC,EAAE,CAAC,EAAE;QAAE,MAAM,CAAC,EAAE,OAAO,CAAA;KAAE,CAAC;CAC3B;AA6CD,qBAAa,WAAW,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC;IACpF,OAAO,CAAC,GAAG,CAA0B;IACrC,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAY;IACtC,OAAO,CAAC,QAAQ,CAAC,MAAM,CAAc;IACrC,OAAO,CAAC,QAAQ,CAAC,mBAAmB,CAA0B;IAC9D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAA0B;IAChE,OAAO,CAAC,QAAQ,CAAC,iBAAiB,CAA0B;IAC5D,OAAO,CAAC,QAAQ,CAAC,qBAAqB,CAAqB;gBAE/C,OAAO,GAAE,kBAAkB,CAAC,GAAG,CAAM;IA0CjD,cAAc,CAAC,WAAW,EAAE,WAAW,GAAG,IAAI;IA2D9C,GAAG,CAAC,UAAU,EAAE,iBAAiB,GAAG,IAAI;IAKxC,YAAY,IAAI,SAAS;IAIzB,OAAO,IAAI,IAAI,CAAC;QAAE,QAAQ,EAAE,GAAG,CAAA;KAAE,CAAC;IAIlC,KAAK,GAAI,SAAS,OAAO,EAAE,KAAK,GAAG,EAAE,KAAK,GAAG,KAAG,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC,CAE1E;CACH;AAED,wBAAgB,SAAS,CAAC,GAAG,SAAS,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EACrF,OAAO,GAAE,kBAAkB,CAAC,GAAG,CAAM,GACpC,WAAW,CAAC,GAAG,CAAC,CAElB"}
|
|
@@ -0,0 +1,138 @@
|
|
|
1
|
+
import { Hono } from "hono";
|
|
2
|
+
import { cors } from "hono/cors";
|
|
3
|
+
import { secureHeaders } from "hono/secure-headers";
|
|
4
|
+
import { Container } from "./container/container";
|
|
5
|
+
import { createDbManagerMiddleware } from "../database/middleware";
|
|
6
|
+
import { Router } from "./router/router";
|
|
7
|
+
import { getInjectableMetadata, getModuleMetadata } from "./metadata";
|
|
8
|
+
const defaultRedactHeaders = ["authorization", "cookie", "set-cookie", "x-api-key"];
|
|
9
|
+
function createObservabilityMiddleware(options) {
|
|
10
|
+
const requestIdHeader = options?.requestIdHeader ?? "x-request-id";
|
|
11
|
+
const accessLogs = options?.enableAccessLogs ?? true;
|
|
12
|
+
const level = options?.logLevel ?? "info";
|
|
13
|
+
const redactHeaders = options?.redactHeaders ?? defaultRedactHeaders;
|
|
14
|
+
return async (c, next) => {
|
|
15
|
+
const requestId = c.req.header(requestIdHeader) ?? crypto.randomUUID();
|
|
16
|
+
const start = Date.now();
|
|
17
|
+
await next();
|
|
18
|
+
c.res.headers.set(requestIdHeader, requestId);
|
|
19
|
+
if (!accessLogs) {
|
|
20
|
+
return;
|
|
21
|
+
}
|
|
22
|
+
const status = c.res.status;
|
|
23
|
+
const line = `[${requestId}] ${c.req.method} ${c.req.path} -> ${status} (${Date.now() - start}ms)`;
|
|
24
|
+
if (status >= 500) {
|
|
25
|
+
console.error(line);
|
|
26
|
+
}
|
|
27
|
+
else if (status >= 400) {
|
|
28
|
+
console.warn(line);
|
|
29
|
+
}
|
|
30
|
+
else if (level !== "error" && level !== "warn") {
|
|
31
|
+
console.info(line);
|
|
32
|
+
}
|
|
33
|
+
if (level === "debug") {
|
|
34
|
+
const headers = {};
|
|
35
|
+
const redacted = new Set(redactHeaders.map((h) => h.toLowerCase()));
|
|
36
|
+
c.req.raw.headers.forEach((value, key) => {
|
|
37
|
+
headers[key] = redacted.has(key.toLowerCase()) ? "[REDACTED]" : value;
|
|
38
|
+
});
|
|
39
|
+
console.debug(`[${requestId}] request_headers`, headers);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
|
43
|
+
export class Application {
|
|
44
|
+
constructor(options = {}) {
|
|
45
|
+
this.registeredProviders = new Set();
|
|
46
|
+
this.registeredControllers = new Set();
|
|
47
|
+
this.registeredModules = new Set();
|
|
48
|
+
this.moduleResolutionStack = [];
|
|
49
|
+
this.fetch = (request, env, ctx) => {
|
|
50
|
+
return this.app.fetch(request, env, ctx);
|
|
51
|
+
};
|
|
52
|
+
this.app = new Hono({ strict: false });
|
|
53
|
+
this.container = new Container();
|
|
54
|
+
this.container.configure({ strict: options.di?.strict ?? true });
|
|
55
|
+
if (options.basePath) {
|
|
56
|
+
this.app = this.app.basePath(options.basePath);
|
|
57
|
+
}
|
|
58
|
+
this.app.use("*", createObservabilityMiddleware(options.observability));
|
|
59
|
+
this.app.use("*", cors(options.security?.cors));
|
|
60
|
+
if (options.security?.secureHeaders) {
|
|
61
|
+
const settings = typeof options.security.secureHeaders === "boolean"
|
|
62
|
+
? undefined
|
|
63
|
+
: options.security.secureHeaders;
|
|
64
|
+
this.app.use("*", secureHeaders(settings));
|
|
65
|
+
}
|
|
66
|
+
if (options.database) {
|
|
67
|
+
this.app.use("*", createDbManagerMiddleware(options.database));
|
|
68
|
+
}
|
|
69
|
+
for (const middleware of options.globalMiddlewares ?? []) {
|
|
70
|
+
this.app.use("*", middleware);
|
|
71
|
+
}
|
|
72
|
+
this.app.notFound((c) => c.json({ error: { code: "not_found", message: "Route not found" } }, 404));
|
|
73
|
+
this.app.onError((err, c) => {
|
|
74
|
+
console.error(err);
|
|
75
|
+
return c.json({ error: { code: "internal_error", message: "Internal server error" } }, 500);
|
|
76
|
+
});
|
|
77
|
+
this.router = new Router(this.app, this.container);
|
|
78
|
+
}
|
|
79
|
+
registerModule(moduleClass) {
|
|
80
|
+
if (this.registeredModules.has(moduleClass)) {
|
|
81
|
+
return this;
|
|
82
|
+
}
|
|
83
|
+
const cycleStartIndex = this.moduleResolutionStack.indexOf(moduleClass);
|
|
84
|
+
if (cycleStartIndex >= 0) {
|
|
85
|
+
const cycle = [...this.moduleResolutionStack.slice(cycleStartIndex), moduleClass]
|
|
86
|
+
.map((moduleToken) => moduleToken.name)
|
|
87
|
+
.join(" -> ");
|
|
88
|
+
throw new Error(`Circular module import detected: ${cycle}`);
|
|
89
|
+
}
|
|
90
|
+
this.moduleResolutionStack.push(moduleClass);
|
|
91
|
+
try {
|
|
92
|
+
const metadata = getModuleMetadata(moduleClass);
|
|
93
|
+
if (!metadata) {
|
|
94
|
+
throw new Error(`Class ${moduleClass.name} is not decorated with @Module()`);
|
|
95
|
+
}
|
|
96
|
+
for (const imported of metadata.imports ?? []) {
|
|
97
|
+
this.registerModule(imported);
|
|
98
|
+
}
|
|
99
|
+
for (const provider of metadata.providers ?? []) {
|
|
100
|
+
const injectableMetadata = getInjectableMetadata(provider);
|
|
101
|
+
if (!injectableMetadata) {
|
|
102
|
+
throw new Error(`Provider ${provider.name} in ${moduleClass.name} must be decorated with @Injectable().`);
|
|
103
|
+
}
|
|
104
|
+
if (!this.registeredProviders.has(provider)) {
|
|
105
|
+
this.container.register(provider);
|
|
106
|
+
this.registeredProviders.add(provider);
|
|
107
|
+
}
|
|
108
|
+
}
|
|
109
|
+
for (const controller of metadata.controllers ?? []) {
|
|
110
|
+
if (this.registeredControllers.has(controller)) {
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
this.container.register(controller);
|
|
114
|
+
this.router.registerController(controller);
|
|
115
|
+
this.registeredControllers.add(controller);
|
|
116
|
+
}
|
|
117
|
+
this.registeredModules.add(moduleClass);
|
|
118
|
+
return this;
|
|
119
|
+
}
|
|
120
|
+
finally {
|
|
121
|
+
this.moduleResolutionStack.pop();
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
use(middleware) {
|
|
125
|
+
this.app.use("*", middleware);
|
|
126
|
+
return this;
|
|
127
|
+
}
|
|
128
|
+
getContainer() {
|
|
129
|
+
return this.container;
|
|
130
|
+
}
|
|
131
|
+
getHono() {
|
|
132
|
+
return this.app;
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
export function createApp(options = {}) {
|
|
136
|
+
return new Application(options);
|
|
137
|
+
}
|
|
138
|
+
//# sourceMappingURL=application.js.map
|