honertia 0.1.0 → 0.1.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 +201 -121
- package/dist/effect/bridge.d.ts +27 -3
- package/dist/effect/bridge.d.ts.map +1 -1
- package/dist/effect/bridge.js +5 -0
- package/dist/effect/routing.d.ts +12 -12
- package/dist/effect/routing.d.ts.map +1 -1
- package/dist/setup.d.ts +3 -3
- package/dist/setup.d.ts.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -1,8 +1,18 @@
|
|
|
1
1
|
# Honertia
|
|
2
2
|
|
|
3
3
|
[](https://www.npmjs.com/package/honertia)
|
|
4
|
+
[](https://bundlephobia.com/package/honertia)
|
|
5
|
+
[](https://www.typescriptlang.org/)
|
|
4
6
|
[](https://opensource.org/licenses/MIT)
|
|
5
7
|
|
|
8
|
+
[](https://hono.dev/)
|
|
9
|
+
[](https://workers.cloudflare.com/)
|
|
10
|
+
[](https://effect.website/)
|
|
11
|
+
|
|
12
|
+
## Raison d'être
|
|
13
|
+
|
|
14
|
+
I've found myself wanting to use Cloudflare Workers for everything, but having come from a Laravel background nothing quite matched the DX and simplicity of Laravel x Inertia.js. When building Laravel projects I would always use Loris Leiva's laravel-actions package among other opinionated architecture decisions such as Vite, Tailwind, Bun, React etc., all of which have or will be incorporated into this project. With Cloudflare Workers the obvious choice is Hono and so we've adapted the Inertia.js protocol to run on workers+hono to mimic a Laravel-style app. Ever since learning of Effect.ts I've known that I wanted to use it for something bigger, and so we've utilised it here. Ultimately this is a workers+hono+vite+bun+laravel+inertia+effect+betterauth+planetscale mashup that delivers clean, readable, and powerful web app scaffolding.
|
|
15
|
+
|
|
6
16
|
An Inertia.js-style adapter for Hono with Effect.js integration. Build full-stack applications with type-safe server actions, Laravel-inspired validation, and seamless React rendering.
|
|
7
17
|
|
|
8
18
|
## Requirements
|
|
@@ -25,157 +35,142 @@ bun add honertia
|
|
|
25
35
|
```typescript
|
|
26
36
|
// src/index.ts
|
|
27
37
|
import { Hono } from 'hono'
|
|
28
|
-
import {
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
loadUser,
|
|
32
|
-
shareAuthMiddleware,
|
|
33
|
-
effectBridge,
|
|
34
|
-
effectRoutes,
|
|
35
|
-
effectAuthRoutes,
|
|
36
|
-
RequireAuthLayer,
|
|
37
|
-
} from 'honertia'
|
|
38
|
+
import { logger } from 'hono/logger'
|
|
39
|
+
import { setupHonertia, createTemplate, registerErrorHandlers, vite } from 'honertia'
|
|
40
|
+
import { Context, Layer } from 'effect'
|
|
38
41
|
|
|
39
|
-
|
|
42
|
+
import { createDb } from './db'
|
|
43
|
+
import type { Env } from './types'
|
|
44
|
+
import { createAuth } from './lib/auth'
|
|
45
|
+
import { registerRoutes } from './routes'
|
|
40
46
|
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
44
|
-
|
|
45
|
-
|
|
46
|
-
|
|
47
|
-
}),
|
|
48
|
-
}))
|
|
47
|
+
const app = new Hono<Env>()
|
|
48
|
+
|
|
49
|
+
class BindingsService extends Context.Tag('app/Bindings')<
|
|
50
|
+
BindingsService,
|
|
51
|
+
{ KV: KVNamespace }
|
|
52
|
+
>() {}
|
|
49
53
|
|
|
50
|
-
// Database & Auth
|
|
54
|
+
// Database & Auth
|
|
51
55
|
app.use('*', async (c, next) => {
|
|
52
56
|
c.set('db', createDb(c.env.DATABASE_URL))
|
|
53
|
-
c.set('auth', createAuth({
|
|
57
|
+
c.set('auth', createAuth({
|
|
58
|
+
db: c.var.db,
|
|
59
|
+
secret: c.env.BETTER_AUTH_SECRET,
|
|
60
|
+
baseURL: new URL(c.req.url).origin,
|
|
61
|
+
}))
|
|
54
62
|
await next()
|
|
55
63
|
})
|
|
56
64
|
|
|
57
|
-
//
|
|
58
|
-
app.use('*',
|
|
59
|
-
app.use('*', shareAuthMiddleware())
|
|
60
|
-
|
|
61
|
-
// Effect bridge (sets up Effect runtime per request)
|
|
62
|
-
app.use('*', effectBridge())
|
|
63
|
-
|
|
64
|
-
// Register routes
|
|
65
|
-
effectAuthRoutes(app, {
|
|
66
|
-
loginComponent: 'Auth/Login',
|
|
67
|
-
registerComponent: 'Auth/Register',
|
|
68
|
-
})
|
|
69
|
-
|
|
70
|
-
effectRoutes(app)
|
|
71
|
-
.provide(RequireAuthLayer)
|
|
72
|
-
.group((route) => {
|
|
73
|
-
route.get('/', showDashboard)
|
|
74
|
-
route.get('/projects', listProjects)
|
|
75
|
-
route.post('/projects', createProject)
|
|
76
|
-
})
|
|
77
|
-
|
|
78
|
-
export default app
|
|
79
|
-
```
|
|
80
|
-
|
|
81
|
-
### Using `setupHonertia` (Recommended)
|
|
82
|
-
|
|
83
|
-
For a cleaner setup, use `setupHonertia` which bundles all core middleware into a single call:
|
|
84
|
-
|
|
85
|
-
```typescript
|
|
86
|
-
import { Hono } from 'hono'
|
|
87
|
-
import { setupHonertia, createTemplate, effectRoutes } from 'honertia'
|
|
88
|
-
|
|
89
|
-
const app = new Hono()
|
|
90
|
-
|
|
91
|
-
app.use('*', setupHonertia({
|
|
65
|
+
// Honertia (bundles core middleware, auth loading, and Effect bridge)
|
|
66
|
+
app.use('*', setupHonertia<Env, BindingsService>({
|
|
92
67
|
honertia: {
|
|
93
68
|
version: '1.0.0',
|
|
94
|
-
render: createTemplate({
|
|
95
|
-
|
|
96
|
-
|
|
69
|
+
render: createTemplate((ctx) => {
|
|
70
|
+
const isProd = ctx.env.ENVIRONMENT === 'production'
|
|
71
|
+
return {
|
|
72
|
+
title: 'Dashboard',
|
|
73
|
+
scripts: isProd ? ['/assets/main.js'] : [vite.script()],
|
|
74
|
+
head: isProd ? '' : vite.hmrHead(),
|
|
75
|
+
}
|
|
97
76
|
}),
|
|
98
77
|
},
|
|
99
|
-
auth: {
|
|
100
|
-
userKey: 'user',
|
|
101
|
-
sessionCookie: 'session',
|
|
102
|
-
},
|
|
103
78
|
effect: {
|
|
104
|
-
|
|
79
|
+
services: (c) => Layer.succeed(BindingsService, {
|
|
80
|
+
KV: c.env.MY_KV,
|
|
81
|
+
}),
|
|
105
82
|
},
|
|
83
|
+
middleware: [
|
|
84
|
+
logger(),
|
|
85
|
+
// register additional middleware here...
|
|
86
|
+
],
|
|
106
87
|
}))
|
|
107
88
|
|
|
89
|
+
registerRoutes(app)
|
|
90
|
+
registerErrorHandlers(app)
|
|
91
|
+
|
|
108
92
|
export default app
|
|
109
93
|
```
|
|
110
94
|
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
95
|
+
```typescript
|
|
96
|
+
// src/routes.ts
|
|
97
|
+
import type { Hono } from 'hono'
|
|
98
|
+
import type { Env } from './types'
|
|
99
|
+
import { effectRoutes } from 'honertia/effect'
|
|
100
|
+
import { effectAuthRoutes, RequireAuthLayer } from 'honertia/auth'
|
|
101
|
+
import { showDashboard, listProjects, createProject, showProject, deleteProject } from './actions'
|
|
102
|
+
|
|
103
|
+
export function registerRoutes(app: Hono<Env>) {
|
|
104
|
+
// Auth routes (login, register, logout, API handler)
|
|
105
|
+
effectAuthRoutes(app, {
|
|
106
|
+
loginComponent: 'Auth/Login',
|
|
107
|
+
registerComponent: 'Auth/Register',
|
|
108
|
+
})
|
|
116
109
|
|
|
117
|
-
|
|
110
|
+
// Routes that require the user to be authenticated
|
|
111
|
+
effectRoutes(app)
|
|
112
|
+
.provide(RequireAuthLayer)
|
|
113
|
+
.group((route) => {
|
|
114
|
+
route.get('/', showDashboard) // GET example.com
|
|
115
|
+
|
|
116
|
+
route.prefix('/projects').group((route) => {
|
|
117
|
+
route.get('/', listProjects) // GET example.com/projects
|
|
118
|
+
route.post('/', createProject) // POST example.com/projects
|
|
119
|
+
route.get('/:id', showProject) // GET example.com/projects/2
|
|
120
|
+
route.delete('/:id', deleteProject) // DELETE example.com/projects/2
|
|
121
|
+
})
|
|
122
|
+
})
|
|
123
|
+
}
|
|
124
|
+
```
|
|
118
125
|
|
|
119
|
-
|
|
126
|
+
### Example Action
|
|
127
|
+
|
|
128
|
+
Here's the `listProjects` action referenced above:
|
|
120
129
|
|
|
121
130
|
```typescript
|
|
122
|
-
|
|
123
|
-
import {
|
|
131
|
+
// src/actions/projects/list.ts
|
|
132
|
+
import { Effect } from 'effect'
|
|
133
|
+
import { eq } from 'drizzle-orm'
|
|
134
|
+
import { DatabaseService, AuthUserService, render, type AuthUser } from 'honertia/effect'
|
|
135
|
+
import { schema, type Database, type Project } from '../../db'
|
|
124
136
|
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
render: createTemplate({ title: 'My App', scripts: [...] }),
|
|
129
|
-
},
|
|
130
|
-
middleware: [
|
|
131
|
-
cors(),
|
|
132
|
-
logger(),
|
|
133
|
-
myCustomMiddleware(),
|
|
134
|
-
],
|
|
135
|
-
}))
|
|
136
|
-
```
|
|
137
|
+
interface ProjectsIndexProps {
|
|
138
|
+
projects: Project[]
|
|
139
|
+
}
|
|
137
140
|
|
|
138
|
-
|
|
141
|
+
const fetchProjects = (
|
|
142
|
+
db: Database,
|
|
143
|
+
user: AuthUser
|
|
144
|
+
): Effect.Effect<ProjectsIndexProps, Error, never> =>
|
|
145
|
+
Effect.tryPromise({
|
|
146
|
+
try: async () => {
|
|
147
|
+
const projects = await db.query.projects.findMany({
|
|
148
|
+
where: eq(schema.projects.userId, user.user.id),
|
|
149
|
+
orderBy: (projects, { desc }) => [desc(projects.createdAt)],
|
|
150
|
+
})
|
|
151
|
+
return { projects }
|
|
152
|
+
},
|
|
153
|
+
catch: (error) => error instanceof Error ? error : new Error(String(error)),
|
|
154
|
+
})
|
|
139
155
|
|
|
140
|
-
|
|
156
|
+
export const listProjects = Effect.gen(function* () {
|
|
157
|
+
const db = yield* DatabaseService
|
|
158
|
+
const user = yield* AuthUserService
|
|
159
|
+
const props = yield* fetchProjects(db as Database, user)
|
|
160
|
+
return yield* render('Dashboard/Projects/Index', props)
|
|
161
|
+
})
|
|
162
|
+
```
|
|
163
|
+
|
|
164
|
+
### Vite Helpers
|
|
141
165
|
|
|
142
|
-
`
|
|
166
|
+
The `vite` helper provides dev/prod asset management:
|
|
143
167
|
|
|
144
168
|
```typescript
|
|
145
|
-
|
|
146
|
-
<script type="module">
|
|
147
|
-
import RefreshRuntime from 'http://localhost:5173/@react-refresh'
|
|
148
|
-
RefreshRuntime.injectIntoGlobalHook(window)
|
|
149
|
-
window.$RefreshReg$ = () => {}
|
|
150
|
-
window.$RefreshSig$ = () => (type) => type
|
|
151
|
-
window.__vite_plugin_react_preamble_installed__ = true
|
|
152
|
-
</script>
|
|
153
|
-
<script type="module" src="http://localhost:5173/@vite/client"></script>
|
|
154
|
-
`
|
|
155
|
-
|
|
156
|
-
app.use('*', setupHonertia({
|
|
157
|
-
honertia: {
|
|
158
|
-
version: '1.0.0',
|
|
159
|
-
render: createTemplate((ctx) => {
|
|
160
|
-
const isProd = ctx.env.ENVIRONMENT === 'production'
|
|
161
|
-
return {
|
|
162
|
-
title: 'My App',
|
|
163
|
-
scripts: isProd
|
|
164
|
-
? ['/assets/main.js']
|
|
165
|
-
: ['http://localhost:5173/src/main.tsx'],
|
|
166
|
-
head: isProd
|
|
167
|
-
? '<link rel="icon" href="/favicon.svg" />'
|
|
168
|
-
: `${viteHmrHead}<link rel="icon" href="/favicon.svg" />`,
|
|
169
|
-
}
|
|
170
|
-
}),
|
|
171
|
-
},
|
|
172
|
-
}))
|
|
173
|
-
```
|
|
169
|
+
import { vite } from 'honertia'
|
|
174
170
|
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
- Dynamically configure any template option based on request context
|
|
171
|
+
vite.script() // 'http://localhost:5173/src/main.tsx'
|
|
172
|
+
vite.hmrHead() // HMR preamble script tags for React Fast Refresh
|
|
173
|
+
```
|
|
179
174
|
|
|
180
175
|
## Core Concepts
|
|
181
176
|
|
|
@@ -237,6 +232,91 @@ Honertia provides these services via Effect's dependency injection:
|
|
|
237
232
|
| `RequestService` | Request context (params, query, body) |
|
|
238
233
|
| `ResponseFactoryService` | Response builders |
|
|
239
234
|
|
|
235
|
+
#### Custom Services
|
|
236
|
+
|
|
237
|
+
You can inject Cloudflare Worker bindings (KV, D1, Queues, Analytics Engine) as services using the `services` option in `setupHonertia`, `effectBridge`, or `effectRoutes`.
|
|
238
|
+
|
|
239
|
+
Choose the option that matches your setup:
|
|
240
|
+
|
|
241
|
+
- `setupHonertia`: recommended for most apps; keeps config in one place and applies services to every Effect handler.
|
|
242
|
+
- `effectBridge`: use when wiring middleware manually or when you need precise middleware ordering; applies services to all Effect handlers.
|
|
243
|
+
- `effectRoutes`: use when you want services scoped to a route group or different services per group.
|
|
244
|
+
|
|
245
|
+
```typescript
|
|
246
|
+
import { Effect, Layer, Context } from 'effect'
|
|
247
|
+
import { setupHonertia, effectBridge, effectRoutes } from 'honertia'
|
|
248
|
+
|
|
249
|
+
// Define your custom service
|
|
250
|
+
export class BindingsService extends Context.Tag('app/Bindings')<
|
|
251
|
+
BindingsService,
|
|
252
|
+
{
|
|
253
|
+
KV: KVNamespace
|
|
254
|
+
ANALYTICS: AnalyticsEngineDataset
|
|
255
|
+
DB: D1Database
|
|
256
|
+
}
|
|
257
|
+
>() {}
|
|
258
|
+
|
|
259
|
+
// Option 1: setupHonertia (global services via the one-liner setup)
|
|
260
|
+
app.use('*', setupHonertia<Env, BindingsService>({
|
|
261
|
+
honertia: {
|
|
262
|
+
version: '1.0.0',
|
|
263
|
+
render: (page) => JSON.stringify(page),
|
|
264
|
+
},
|
|
265
|
+
effect: {
|
|
266
|
+
services: (c) => Layer.succeed(BindingsService, {
|
|
267
|
+
KV: c.env.MY_KV,
|
|
268
|
+
ANALYTICS: c.env.ANALYTICS,
|
|
269
|
+
DB: c.env.DB,
|
|
270
|
+
}),
|
|
271
|
+
},
|
|
272
|
+
}))
|
|
273
|
+
|
|
274
|
+
// Option 2: effectBridge (manual middleware wiring)
|
|
275
|
+
app.use('*', effectBridge<Env, BindingsService>({
|
|
276
|
+
database: (c) => createDb(c.env.DATABASE_URL),
|
|
277
|
+
services: (c) => Layer.succeed(BindingsService, {
|
|
278
|
+
KV: c.env.MY_KV,
|
|
279
|
+
ANALYTICS: c.env.ANALYTICS,
|
|
280
|
+
DB: c.env.DB,
|
|
281
|
+
}),
|
|
282
|
+
}))
|
|
283
|
+
|
|
284
|
+
// Option 3: effectRoutes (scoped to a route group)
|
|
285
|
+
effectRoutes<Env, BindingsService>(app, {
|
|
286
|
+
services: (c) => Layer.succeed(BindingsService, {
|
|
287
|
+
KV: c.env.MY_KV,
|
|
288
|
+
ANALYTICS: c.env.ANALYTICS,
|
|
289
|
+
DB: c.env.DB,
|
|
290
|
+
}),
|
|
291
|
+
}).group((route) => {
|
|
292
|
+
route.get('/data', getDataFromKV)
|
|
293
|
+
})
|
|
294
|
+
|
|
295
|
+
// Use the custom service in your actions
|
|
296
|
+
const getDataFromKV = Effect.gen(function* () {
|
|
297
|
+
const bindings = yield* BindingsService
|
|
298
|
+
const value = yield* Effect.tryPromise(() =>
|
|
299
|
+
bindings.KV.get('my-key')
|
|
300
|
+
)
|
|
301
|
+
return yield* json({ value })
|
|
302
|
+
})
|
|
303
|
+
```
|
|
304
|
+
|
|
305
|
+
You can provide multiple bindings in any option using `Layer.mergeAll` (for example, a `QueueService` tag for a queue binding):
|
|
306
|
+
|
|
307
|
+
```typescript
|
|
308
|
+
app.use('*', effectBridge<Env, BindingsService | QueueService>({
|
|
309
|
+
services: (c) => Layer.mergeAll(
|
|
310
|
+
Layer.succeed(BindingsService, {
|
|
311
|
+
KV: c.env.MY_KV,
|
|
312
|
+
ANALYTICS: c.env.ANALYTICS,
|
|
313
|
+
DB: c.env.DB,
|
|
314
|
+
}),
|
|
315
|
+
Layer.succeed(QueueService, c.env.MY_QUEUE),
|
|
316
|
+
),
|
|
317
|
+
}))
|
|
318
|
+
```
|
|
319
|
+
|
|
240
320
|
### Routing
|
|
241
321
|
|
|
242
322
|
Use `effectRoutes` for Laravel-style route definitions:
|
package/dist/effect/bridge.d.ts
CHANGED
|
@@ -8,9 +8,33 @@ import type { Context as HonoContext, MiddlewareHandler, Env } from 'hono';
|
|
|
8
8
|
import { DatabaseService, AuthService, AuthUserService, HonertiaService, RequestService, ResponseFactoryService } from './services.js';
|
|
9
9
|
/**
|
|
10
10
|
* Configuration for the Effect bridge.
|
|
11
|
+
*
|
|
12
|
+
* @typeParam E - Hono environment type
|
|
13
|
+
* @typeParam CustomServices - Custom services provided via the `services` option
|
|
14
|
+
*
|
|
15
|
+
* @example
|
|
16
|
+
* // Provide Cloudflare Worker bindings as a service
|
|
17
|
+
* effectBridge<Env, BindingsService>({
|
|
18
|
+
* database: (c) => createDb(c.env.DATABASE_URL),
|
|
19
|
+
* services: (c) => Layer.succeed(BindingsService, c.env),
|
|
20
|
+
* })
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* // Provide multiple custom services
|
|
24
|
+
* effectBridge<Env, BindingsService | LoggerService>({
|
|
25
|
+
* services: (c) => Layer.mergeAll(
|
|
26
|
+
* Layer.succeed(BindingsService, c.env),
|
|
27
|
+
* Layer.succeed(LoggerService, createLogger(c)),
|
|
28
|
+
* ),
|
|
29
|
+
* })
|
|
11
30
|
*/
|
|
12
|
-
export interface EffectBridgeConfig<E extends Env> {
|
|
31
|
+
export interface EffectBridgeConfig<E extends Env, CustomServices = never> {
|
|
13
32
|
database?: (c: HonoContext<E>) => unknown;
|
|
33
|
+
/**
|
|
34
|
+
* Custom services to provide to all Effect handlers.
|
|
35
|
+
* Return a Layer that provides your custom services.
|
|
36
|
+
*/
|
|
37
|
+
services?: (c: HonoContext<E>) => Layer.Layer<CustomServices, never, never>;
|
|
14
38
|
}
|
|
15
39
|
/**
|
|
16
40
|
* Symbol for storing Effect runtime in Hono context.
|
|
@@ -27,7 +51,7 @@ declare module 'hono' {
|
|
|
27
51
|
/**
|
|
28
52
|
* Build the Effect layer from Hono context.
|
|
29
53
|
*/
|
|
30
|
-
export declare function buildContextLayer<E extends Env>(c: HonoContext<E>, config?: EffectBridgeConfig<E>): Layer.Layer<RequestService | ResponseFactoryService | HonertiaService | DatabaseService | AuthService | AuthUserService, never, never>;
|
|
54
|
+
export declare function buildContextLayer<E extends Env, CustomServices = never>(c: HonoContext<E>, config?: EffectBridgeConfig<E, CustomServices>): Layer.Layer<RequestService | ResponseFactoryService | HonertiaService | DatabaseService | AuthService | AuthUserService | CustomServices, never, never>;
|
|
31
55
|
/**
|
|
32
56
|
* Get the Effect runtime from Hono context.
|
|
33
57
|
*/
|
|
@@ -35,6 +59,6 @@ export declare function getEffectRuntime<E extends Env>(c: HonoContext<E>): Mana
|
|
|
35
59
|
/**
|
|
36
60
|
* Middleware that sets up the Effect runtime for each request.
|
|
37
61
|
*/
|
|
38
|
-
export declare function effectBridge<E extends Env>(config?: EffectBridgeConfig<E>): MiddlewareHandler<E>;
|
|
62
|
+
export declare function effectBridge<E extends Env, CustomServices = never>(config?: EffectBridgeConfig<E, CustomServices>): MiddlewareHandler<E>;
|
|
39
63
|
export {};
|
|
40
64
|
//# sourceMappingURL=bridge.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAU,KAAK,EAAE,cAAc,EAAW,MAAM,QAAQ,CAAA;AAC/D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAC1E,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EAKvB,MAAM,eAAe,CAAA;AAEtB
|
|
1
|
+
{"version":3,"file":"bridge.d.ts","sourceRoot":"","sources":["../../src/effect/bridge.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAU,KAAK,EAAE,cAAc,EAAW,MAAM,QAAQ,CAAA;AAC/D,OAAO,KAAK,EAAE,OAAO,IAAI,WAAW,EAAE,iBAAiB,EAAE,GAAG,EAAE,MAAM,MAAM,CAAA;AAC1E,OAAO,EACL,eAAe,EACf,WAAW,EACX,eAAe,EACf,eAAe,EACf,cAAc,EACd,sBAAsB,EAKvB,MAAM,eAAe,CAAA;AAEtB;;;;;;;;;;;;;;;;;;;;;GAqBG;AACH,MAAM,WAAW,kBAAkB,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK;IACvE,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,OAAO,CAAA;IACzC;;;OAGG;IACH,QAAQ,CAAC,EAAE,CAAC,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,KAAK,KAAK,CAAC,KAAK,CAAC,cAAc,EAAE,KAAK,EAAE,KAAK,CAAC,CAAA;CAC5E;AAED;;GAEG;AACH,QAAA,MAAM,cAAc,eAA0B,CAAA;AAE9C;;GAEG;AACH,OAAO,QAAQ,MAAM,CAAC;IACpB,UAAU,kBAAkB;QAC1B,CAAC,cAAc,CAAC,CAAC,EAAE,cAAc,CAAC,cAAc,CAC5C,eAAe,GACf,WAAW,GACX,eAAe,GACf,eAAe,GACf,cAAc,GACd,sBAAsB,EACxB,KAAK,CACN,CAAA;KACF;CACF;AAqDD;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK,EACrE,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,EACjB,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,cAAc,CAAC,GAC7C,KAAK,CAAC,KAAK,CACV,cAAc,GACd,sBAAsB,GACtB,eAAe,GACf,eAAe,GACf,WAAW,GACX,eAAe,GACf,cAAc,EAChB,KAAK,EACL,KAAK,CACN,CA0CA;AAED;;GAEG;AACH,wBAAgB,gBAAgB,CAAC,CAAC,SAAS,GAAG,EAC5C,CAAC,EAAE,WAAW,CAAC,CAAC,CAAC,GAChB,cAAc,CAAC,cAAc,CAAC,GAAG,EAAE,KAAK,CAAC,GAAG,SAAS,CAEvD;AAED;;GAEG;AACH,wBAAgB,YAAY,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK,EAChE,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,cAAc,CAAC,GAC7C,iBAAiB,CAAC,CAAC,CAAC,CAetB"}
|
package/dist/effect/bridge.js
CHANGED
|
@@ -75,6 +75,11 @@ export function buildContextLayer(c, config) {
|
|
|
75
75
|
if (c.var?.authUser) {
|
|
76
76
|
baseLayer = Layer.merge(baseLayer, Layer.succeed(AuthUserService, c.var.authUser));
|
|
77
77
|
}
|
|
78
|
+
// Merge custom services if provided
|
|
79
|
+
if (config?.services) {
|
|
80
|
+
const customServicesLayer = config.services(c);
|
|
81
|
+
baseLayer = Layer.merge(baseLayer, customServicesLayer);
|
|
82
|
+
}
|
|
78
83
|
return baseLayer;
|
|
79
84
|
}
|
|
80
85
|
/**
|
package/dist/effect/routing.d.ts
CHANGED
|
@@ -21,25 +21,25 @@ export type BaseServices = RequestService | ResponseFactoryService | HonertiaSer
|
|
|
21
21
|
/**
|
|
22
22
|
* Effect Route Builder with layer composition.
|
|
23
23
|
*/
|
|
24
|
-
export declare class EffectRouteBuilder<E extends Env, ProvidedServices = never> {
|
|
24
|
+
export declare class EffectRouteBuilder<E extends Env, ProvidedServices = never, CustomServices = never> {
|
|
25
25
|
private readonly app;
|
|
26
26
|
private readonly layers;
|
|
27
27
|
private readonly pathPrefix;
|
|
28
28
|
private readonly bridgeConfig?;
|
|
29
|
-
constructor(app: Hono<E>, layers?: Layer.Layer<any, never, never>[], pathPrefix?: string, bridgeConfig?: EffectBridgeConfig<E> | undefined);
|
|
29
|
+
constructor(app: Hono<E>, layers?: Layer.Layer<any, never, never>[], pathPrefix?: string, bridgeConfig?: EffectBridgeConfig<E, CustomServices> | undefined);
|
|
30
30
|
/**
|
|
31
31
|
* Add a layer to provide services to all routes in this builder.
|
|
32
32
|
* The layer's error type must be handled by the effect bridge (AppError or subtype).
|
|
33
33
|
*/
|
|
34
|
-
provide<S, LayerErr extends AppError>(layer: Layer.Layer<S, LayerErr, never>): EffectRouteBuilder<E, ProvidedServices | S>;
|
|
34
|
+
provide<S, LayerErr extends AppError>(layer: Layer.Layer<S, LayerErr, never>): EffectRouteBuilder<E, ProvidedServices | S, CustomServices>;
|
|
35
35
|
/**
|
|
36
36
|
* Set path prefix for all routes in this builder.
|
|
37
37
|
*/
|
|
38
|
-
prefix(path: string): EffectRouteBuilder<E, ProvidedServices>;
|
|
38
|
+
prefix(path: string): EffectRouteBuilder<E, ProvidedServices, CustomServices>;
|
|
39
39
|
/**
|
|
40
40
|
* Create a nested group with the same configuration.
|
|
41
41
|
*/
|
|
42
|
-
group(callback: (route: EffectRouteBuilder<E, ProvidedServices>) => void): void;
|
|
42
|
+
group(callback: (route: EffectRouteBuilder<E, ProvidedServices, CustomServices>) => void): void;
|
|
43
43
|
/**
|
|
44
44
|
* Resolve the full path.
|
|
45
45
|
*/
|
|
@@ -51,27 +51,27 @@ export declare class EffectRouteBuilder<E extends Env, ProvidedServices = never>
|
|
|
51
51
|
/**
|
|
52
52
|
* Register a GET route.
|
|
53
53
|
*/
|
|
54
|
-
get<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
54
|
+
get<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
55
55
|
/**
|
|
56
56
|
* Register a POST route.
|
|
57
57
|
*/
|
|
58
|
-
post<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
58
|
+
post<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
59
59
|
/**
|
|
60
60
|
* Register a PUT route.
|
|
61
61
|
*/
|
|
62
|
-
put<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
62
|
+
put<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
63
63
|
/**
|
|
64
64
|
* Register a PATCH route.
|
|
65
65
|
*/
|
|
66
|
-
patch<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
66
|
+
patch<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
67
67
|
/**
|
|
68
68
|
* Register a DELETE route.
|
|
69
69
|
*/
|
|
70
|
-
delete<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
70
|
+
delete<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
71
71
|
/**
|
|
72
72
|
* Register a route for all HTTP methods.
|
|
73
73
|
*/
|
|
74
|
-
all<R extends BaseServices | ProvidedServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
74
|
+
all<R extends BaseServices | ProvidedServices | CustomServices>(path: string, effect: EffectHandler<R, AppError | Error>): void;
|
|
75
75
|
}
|
|
76
76
|
/**
|
|
77
77
|
* Create an Effect route builder for an app.
|
|
@@ -86,5 +86,5 @@ export declare class EffectRouteBuilder<E extends Env, ProvidedServices = never>
|
|
|
86
86
|
* route.post('/projects', createProject)
|
|
87
87
|
* })
|
|
88
88
|
*/
|
|
89
|
-
export declare function effectRoutes<E extends Env>(app: Hono<E>, config?: EffectBridgeConfig<E>): EffectRouteBuilder<E, never>;
|
|
89
|
+
export declare function effectRoutes<E extends Env, CustomServices = never>(app: Hono<E>, config?: EffectBridgeConfig<E, CustomServices>): EffectRouteBuilder<E, never, CustomServices>;
|
|
90
90
|
//# sourceMappingURL=routing.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/effect/routing.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AAEH,OAAO,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,QAAQ,CAAA;AACtC,OAAO,KAAK,EAAE,IAAI,EAAqB,GAAG,EAAE,MAAM,MAAM,CAAA;AAExD,OAAO,EAAqB,KAAK,kBAAkB,EAAE,MAAM,aAAa,CAAA;AACxE,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AAC3C,OAAO,EAAE,QAAQ,EAAE,MAAM,aAAa,CAAA;AACtC,OAAO,EACL,eAAe,EACf,WAAW,EAEX,eAAe,EACf,cAAc,EACd,sBAAsB,EACvB,MAAM,eAAe,CAAA;AAEtB;;;GAGG;AACH,MAAM,MAAM,aAAa,CAAC,CAAC,GAAG,KAAK,EAAE,CAAC,SAAS,QAAQ,GAAG,KAAK,GAAG,QAAQ,GAAG,KAAK,IAAI,MAAM,CAAC,MAAM,CACjG,QAAQ,GAAG,QAAQ,EACnB,CAAC,EACD,CAAC,CACF,CAAA;AAED;;GAEG;AACH,MAAM,MAAM,YAAY,GACpB,cAAc,GACd,sBAAsB,GACtB,eAAe,GACf,eAAe,GACf,WAAW,CAAA;AAEf;;GAEG;AACH,qBAAa,kBAAkB,CAC7B,CAAC,SAAS,GAAG,EACb,gBAAgB,GAAG,KAAK;
|
|
1
|
+
{"version":3,"file":"routing.d.ts","sourceRoot":"","sources":["../../src/effect/routing.ts"],"names":[],"mappings":"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"}
|
package/dist/setup.d.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { type EffectBridgeConfig } from './effect/bridge.js';
|
|
|
10
10
|
/**
|
|
11
11
|
* Configuration for Honertia setup.
|
|
12
12
|
*/
|
|
13
|
-
export interface HonertiaSetupConfig<E extends Env = Env> {
|
|
13
|
+
export interface HonertiaSetupConfig<E extends Env = Env, CustomServices = never> {
|
|
14
14
|
/**
|
|
15
15
|
* Honertia core configuration.
|
|
16
16
|
*/
|
|
@@ -18,7 +18,7 @@ export interface HonertiaSetupConfig<E extends Env = Env> {
|
|
|
18
18
|
/**
|
|
19
19
|
* Effect bridge configuration (optional).
|
|
20
20
|
*/
|
|
21
|
-
effect?: EffectBridgeConfig<E>;
|
|
21
|
+
effect?: EffectBridgeConfig<E, CustomServices>;
|
|
22
22
|
/**
|
|
23
23
|
* Auth configuration (optional).
|
|
24
24
|
*/
|
|
@@ -53,7 +53,7 @@ export interface HonertiaSetupConfig<E extends Env = Env> {
|
|
|
53
53
|
* }))
|
|
54
54
|
* ```
|
|
55
55
|
*/
|
|
56
|
-
export declare function setupHonertia<E extends Env>(config: HonertiaSetupConfig<E>): MiddlewareHandler<E>;
|
|
56
|
+
export declare function setupHonertia<E extends Env, CustomServices = never>(config: HonertiaSetupConfig<E, CustomServices>): MiddlewareHandler<E>;
|
|
57
57
|
/**
|
|
58
58
|
* Error handler configuration.
|
|
59
59
|
*/
|
package/dist/setup.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG;
|
|
1
|
+
{"version":3,"file":"setup.d.ts","sourceRoot":"","sources":["../src/setup.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,GAAG,EAAE,OAAO,EAAE,MAAM,MAAM,CAAA;AAE3D,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAA;AAEhD,OAAO,EAAgB,KAAK,kBAAkB,EAAE,MAAM,oBAAoB,CAAA;AAE1E;;GAEG;AACH,MAAM,WAAW,mBAAmB,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,cAAc,GAAG,KAAK;IAC9E;;OAEG;IACH,QAAQ,EAAE,cAAc,CAAA;IAExB;;OAEG;IACH,MAAM,CAAC,EAAE,kBAAkB,CAAC,CAAC,EAAE,cAAc,CAAC,CAAA;IAE9C;;OAEG;IACH,IAAI,CAAC,EAAE;QACL,OAAO,CAAC,EAAE,MAAM,CAAA;QAChB,aAAa,CAAC,EAAE,MAAM,CAAA;KACvB,CAAA;IAED;;;OAGG;IACH,UAAU,CAAC,EAAE,iBAAiB,CAAC,CAAC,CAAC,EAAE,CAAA;CACpC;AAED;;;;;;;;;;;;;;;;;;;;GAoBG;AACH,wBAAgB,aAAa,CAAC,CAAC,SAAS,GAAG,EAAE,cAAc,GAAG,KAAK,EACjE,MAAM,EAAE,mBAAmB,CAAC,CAAC,EAAE,cAAc,CAAC,GAC7C,iBAAiB,CAAC,CAAC,CAAC,CAmBtB;AAED;;GAEG;AACH,MAAM,WAAW,kBAAkB;IACjC;;;OAGG;IACH,SAAS,CAAC,EAAE,MAAM,CAAA;IAElB;;;OAGG;IACH,aAAa,CAAC,EAAE,OAAO,CAAA;IAEvB;;;OAGG;IACH,MAAM,CAAC,EAAE,MAAM,CAAA;IAEf;;;OAGG;IACH,QAAQ,CAAC,EAAE,MAAM,CAAA;CAClB;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,mBAAmB,CAAC,CAAC,SAAS,GAAG,EAAE,MAAM,GAAE,kBAAuB;kBAQ3D,OAAO,CAAC,CAAC,CAAC;mBAOT,KAAK,KAAK,OAAO,CAAC,CAAC,CAAC;EAU3C;AAED;;;;;;;;;GASG;AACH,wBAAgB,qBAAqB,CAAC,CAAC,SAAS,GAAG,EACjD,GAAG,EAAE;IAAE,QAAQ,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAC;IAAC,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,IAAI,CAAA;CAAE,EAC1E,MAAM,GAAE,kBAAuB,GAC9B,IAAI,CAIN"}
|