hono-crud 0.4.1 → 0.4.2

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.
Files changed (3) hide show
  1. package/CHANGELOG.md +2 -0
  2. package/README.md +268 -116
  3. package/package.json +1 -1
package/CHANGELOG.md CHANGED
@@ -15,6 +15,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
15
15
  %b
16
16
  %b
17
17
  %b
18
+ %b
18
19
  ## [0.1.0] - 2025-01-29
19
20
 
20
21
  ### Added
@@ -46,3 +47,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
46
47
  [0.3.2]: https://github.com/kshdotdev/hono-crud/compare/v0.3.1...v0.3.2
47
48
  [0.4.0]: https://github.com/kshdotdev/hono-crud/compare/v0.3.2...v0.4.0
48
49
  [0.4.1]: https://github.com/kshdotdev/hono-crud/compare/v0.4.0...v0.4.1
50
+ [0.4.2]: https://github.com/kshdotdev/hono-crud/compare/v0.4.1...v0.4.2
package/README.md CHANGED
@@ -4,196 +4,348 @@
4
4
  [![License: MIT](https://img.shields.io/badge/License-MIT-yellow.svg)](https://opensource.org/licenses/MIT)
5
5
  [![TypeScript](https://img.shields.io/badge/TypeScript-5.0+-blue.svg)](https://www.typescriptlang.org/)
6
6
 
7
- A powerful CRUD generator for [Hono](https://hono.dev) with Zod validation and automatic OpenAPI documentation.
7
+ Type-safe CRUD generator for [Hono](https://hono.dev) with Zod validation and automatic OpenAPI documentation.
8
8
 
9
9
  ## Features
10
10
 
11
- - **Full CRUD Operations** - Automatically generate Create, Read, Update, Delete endpoints
12
- - **OpenAPI/Swagger** - Auto-generated API documentation with Swagger UI and Scalar support
13
- - **Database Adapters** - Built-in support for Prisma, Drizzle ORM, and in-memory storage
11
+ - **Full CRUD Operations** - Generate Create, Read, Update, Delete, List endpoints with one call
12
+ - **OpenAPI/Swagger** - Auto-generated docs with Swagger UI, Scalar, and ReDoc
13
+ - **Database Adapters** - Memory (prototyping), Drizzle ORM, and Prisma
14
+ - **4 API Patterns** - Class-based, functional, builder, and config-based
14
15
  - **Zod Validation** - Type-safe request/response validation
15
16
  - **TypeScript First** - Full type inference and autocompletion
16
17
  - **Edge Ready** - Works with Cloudflare Workers, Deno, Bun, and Node.js
17
- - **Customizable** - Override any generated route or add custom middleware
18
+ - **Authentication** - JWT, API Key middleware with role/permission guards
19
+ - **Caching** - Response caching with automatic invalidation
20
+ - **Rate Limiting** - Fixed/sliding window with tier-based limits
21
+ - **Advanced Features** - Soft delete, relations, batch operations, search, versioning, audit logging, and more
18
22
 
19
23
  ## Installation
20
24
 
21
25
  ```bash
22
- # npm
23
- npm install hono-crud
24
-
25
- # pnpm
26
- pnpm add hono-crud
27
-
28
- # yarn
29
- yarn add hono-crud
30
-
31
- # bun
32
- bun add hono-crud
26
+ npm install hono-crud hono zod
33
27
  ```
34
28
 
29
+ Peer dependencies: `hono >= 4.0.0` and `zod >= 4.0.0` are required.
30
+
35
31
  ## Quick Start
36
32
 
37
33
  ```typescript
38
- import { Hono } from "hono";
39
- import { HonoCrud } from "hono-crud";
40
- import { MemoryAdapter } from "hono-crud/adapters/memory";
41
- import { z } from "zod";
42
-
43
- const app = new Hono();
44
-
45
- // Define your schema
34
+ import { Hono } from 'hono';
35
+ import { z } from 'zod';
36
+ import { fromHono, registerCrud, setupSwaggerUI, defineModel, defineMeta } from 'hono-crud';
37
+ import {
38
+ MemoryCreateEndpoint,
39
+ MemoryReadEndpoint,
40
+ MemoryUpdateEndpoint,
41
+ MemoryDeleteEndpoint,
42
+ MemoryListEndpoint,
43
+ } from 'hono-crud/adapters/memory';
44
+
45
+ // 1. Define your schema
46
46
  const UserSchema = z.object({
47
- id: z.string(),
48
- name: z.string(),
49
- email: z.string().email(),
47
+ id: z.uuid(),
48
+ email: z.email(),
49
+ name: z.string().min(1),
50
+ role: z.enum(['admin', 'user']),
50
51
  });
51
52
 
52
- // Create CRUD instance
53
- const crud = new HonoCrud({
54
- adapter: new MemoryAdapter(),
53
+ // 2. Create model + meta
54
+ const UserModel = defineModel({
55
+ tableName: 'users',
56
+ schema: UserSchema,
57
+ primaryKeys: ['id'],
55
58
  });
56
59
 
57
- // Register resource
58
- crud.resource("users", {
59
- schema: UserSchema,
60
+ const userMeta = defineMeta({ model: UserModel });
61
+
62
+ // 3. Define endpoints
63
+ class UserCreate extends MemoryCreateEndpoint {
64
+ _meta = userMeta;
65
+ schema = { tags: ['Users'], summary: 'Create a user' };
66
+ }
67
+
68
+ class UserList extends MemoryListEndpoint {
69
+ _meta = userMeta;
70
+ schema = { tags: ['Users'], summary: 'List users' };
71
+ filterFields = ['role'];
72
+ searchFields = ['name', 'email'];
73
+ }
74
+
75
+ class UserRead extends MemoryReadEndpoint {
76
+ _meta = userMeta;
77
+ schema = { tags: ['Users'], summary: 'Get a user' };
78
+ }
79
+
80
+ class UserUpdate extends MemoryUpdateEndpoint {
81
+ _meta = userMeta;
82
+ schema = { tags: ['Users'], summary: 'Update a user' };
83
+ allowedUpdateFields = ['name', 'role'];
84
+ }
85
+
86
+ class UserDelete extends MemoryDeleteEndpoint {
87
+ _meta = userMeta;
88
+ schema = { tags: ['Users'], summary: 'Delete a user' };
89
+ }
90
+
91
+ // 4. Wire it up
92
+ const app = fromHono(new Hono());
93
+
94
+ registerCrud(app, '/users', {
95
+ create: UserCreate,
96
+ list: UserList,
97
+ read: UserRead,
98
+ update: UserUpdate,
99
+ delete: UserDelete,
60
100
  });
61
101
 
62
- // Mount to your app
63
- app.route("/api", crud.routes());
102
+ // 5. OpenAPI docs
103
+ app.doc('/openapi.json', {
104
+ openapi: '3.1.0',
105
+ info: { title: 'My API', version: '1.0.0' },
106
+ });
107
+ setupSwaggerUI(app, { docsPath: '/docs', specPath: '/openapi.json' });
64
108
 
65
109
  export default app;
66
110
  ```
67
111
 
68
- ## Database Adapters
112
+ This generates:
69
113
 
70
- ### Memory Adapter
114
+ | Method | Route | Description |
115
+ |--------|-------|-------------|
116
+ | `POST` | `/users` | Create a user |
117
+ | `GET` | `/users` | List users (with filtering, search, pagination) |
118
+ | `GET` | `/users/:id` | Get a user by ID |
119
+ | `PATCH` | `/users/:id` | Update a user |
120
+ | `DELETE` | `/users/:id` | Delete a user |
71
121
 
72
- Perfect for prototyping and testing:
122
+ ## API Patterns
73
123
 
74
- ```typescript
75
- import { MemoryAdapter } from "hono-crud/adapters/memory";
124
+ hono-crud supports four ways to define endpoints. All produce classes compatible with `registerCrud()` and can be mixed.
125
+
126
+ | Pattern | Best For | Style |
127
+ |---------|----------|-------|
128
+ | **Class-based** | Complex logic, database adapters | `class UserList extends MemoryListEndpoint { ... }` |
129
+ | **Functional** | Quick setup | `createList({ meta, filterFields: ['role'] }, MemoryListEndpoint)` |
130
+ | **Builder** | Readable chains | `crud(meta).list().filter('role').build(MemoryListEndpoint)` |
131
+ | **Config-based** | Declarative, all-in-one | `defineEndpoints({ meta, list: { ... } }, MemoryAdapters)` |
76
132
 
77
- const adapter = new MemoryAdapter();
133
+ ```typescript
134
+ import { createList, crud, defineEndpoints, MemoryAdapters } from 'hono-crud';
135
+
136
+ // Functional
137
+ const UserList = createList(
138
+ { meta: userMeta, filterFields: ['role'], searchFields: ['name'] },
139
+ MemoryListEndpoint
140
+ );
141
+
142
+ // Builder
143
+ const UserList = crud(userMeta)
144
+ .list()
145
+ .filter('role')
146
+ .search('name')
147
+ .pagination(20, 100)
148
+ .build(MemoryListEndpoint);
149
+
150
+ // Config-based (all endpoints at once)
151
+ const endpoints = defineEndpoints({
152
+ meta: userMeta,
153
+ create: { openapi: { tags: ['Users'], summary: 'Create user' } },
154
+ list: { filtering: { fields: ['role'] }, search: { fields: ['name'] } },
155
+ read: {},
156
+ update: { fields: { allowed: ['name', 'role'] } },
157
+ delete: {},
158
+ }, MemoryAdapters);
159
+
160
+ registerCrud(app, '/users', endpoints);
78
161
  ```
79
162
 
80
- ### Drizzle Adapter
163
+ See [docs/alternative-api-patterns.md](./docs/alternative-api-patterns.md) for the full reference.
81
164
 
82
- For production use with Drizzle ORM:
165
+ ## Database Adapters
83
166
 
84
- ```typescript
85
- import { DrizzleAdapter } from "hono-crud/adapters/drizzle";
86
- import { db } from "./db";
87
- import { users } from "./schema";
167
+ ### Memory
88
168
 
89
- const adapter = new DrizzleAdapter(db, {
90
- users: users,
91
- });
169
+ Zero-config, perfect for prototyping and tests:
170
+
171
+ ```typescript
172
+ import { MemoryCreateEndpoint, MemoryListEndpoint /* ... */ } from 'hono-crud/adapters/memory';
92
173
  ```
93
174
 
94
- ### Prisma Adapter
175
+ ### Drizzle
95
176
 
96
- For production use with Prisma:
177
+ Use `createDrizzleCrud` for minimal boilerplate:
97
178
 
98
179
  ```typescript
99
- import { PrismaAdapter } from "hono-crud/adapters/prisma";
100
- import { PrismaClient } from "@prisma/client";
180
+ import { createDrizzleCrud } from 'hono-crud/adapters/drizzle';
181
+ import { db } from './db';
182
+
183
+ const User = createDrizzleCrud(db, userMeta);
184
+
185
+ class UserCreate extends User.Create {
186
+ schema = { tags: ['Users'], summary: 'Create user' };
187
+ }
101
188
 
102
- const prisma = new PrismaClient();
103
- const adapter = new PrismaAdapter(prisma);
189
+ class UserList extends User.List {
190
+ schema = { tags: ['Users'], summary: 'List users' };
191
+ filterFields = ['role'];
192
+ }
104
193
  ```
105
194
 
106
- ## API Documentation
195
+ Or set `db` directly on each endpoint class:
196
+
197
+ ```typescript
198
+ import { DrizzleListEndpoint } from 'hono-crud/adapters/drizzle';
199
+
200
+ class UserList extends DrizzleListEndpoint {
201
+ _meta = userMeta;
202
+ db = drizzleDb;
203
+ filterFields = ['role'];
204
+ }
205
+ ```
107
206
 
108
- OpenAPI documentation is automatically generated. Access it at:
207
+ ### Prisma
109
208
 
110
- - **Swagger UI**: `/docs`
111
- - **Scalar**: `/reference`
112
- - **OpenAPI JSON**: `/openapi.json`
209
+ ```typescript
210
+ import { PrismaListEndpoint } from 'hono-crud/adapters/prisma';
113
211
 
114
- ## Authentication with better-auth
212
+ class UserList extends PrismaListEndpoint {
213
+ _meta = userMeta;
214
+ prisma = prismaClient;
215
+ filterFields = ['role'];
216
+ }
217
+ ```
115
218
 
116
- hono-crud integrates seamlessly with [better-auth](https://www.better-auth.com) for comprehensive authentication.
219
+ See [docs/database-adapters.md](./docs/database-adapters.md) for complete setup guides.
117
220
 
118
- ### Setup
221
+ ## Authentication
119
222
 
120
- 1. **Mount better-auth handler** for authentication routes:
223
+ Built-in JWT and API Key middleware with composable guards:
121
224
 
122
225
  ```typescript
123
- import { Hono } from "hono";
124
- import { auth } from "./auth"; // your better-auth instance
125
- import { cors } from "hono/cors";
126
-
127
- const app = new Hono<{
128
- Variables: {
129
- user: typeof auth.$Infer.Session.user | null;
130
- session: typeof auth.$Infer.Session.session | null;
131
- };
132
- }>();
133
-
134
- // CORS (must be before routes)
135
- app.use("/api/auth/*", cors({
136
- origin: "http://localhost:3000",
137
- credentials: true,
226
+ import { createJWTMiddleware, requireRoles, requireAuthenticated, anyOf } from 'hono-crud';
227
+
228
+ // JWT middleware
229
+ app.use('/api/*', createJWTMiddleware({
230
+ secret: process.env.JWT_SECRET!,
231
+ issuer: 'my-app',
138
232
  }));
139
233
 
140
- // Mount better-auth
141
- app.on(["POST", "GET"], "/api/auth/*", (c) => auth.handler(c.req.raw));
234
+ // Guards on specific endpoints
235
+ registerCrud(app, '/users', endpoints, {
236
+ middlewares: [requireAuthenticated()],
237
+ endpointMiddlewares: {
238
+ delete: [requireRoles('admin')],
239
+ },
240
+ });
241
+
242
+ // Composable guards
243
+ app.use('/admin/*', anyOf(
244
+ requireRoles('admin'),
245
+ requireOwnership((ctx) => ctx.req.param('id'))
246
+ ));
142
247
  ```
143
248
 
144
- 2. **Add session middleware** to inject user into context:
249
+ See [docs/authentication.md](./docs/authentication.md) for JWT, API Key, guards, and better-auth integration.
250
+
251
+ ## Middleware
252
+
253
+ ### Caching
145
254
 
146
255
  ```typescript
147
- app.use("*", async (c, next) => {
148
- const session = await auth.api.getSession({ headers: c.req.raw.headers });
149
- c.set("user", session?.user || null);
150
- c.set("session", session?.session || null);
151
- await next();
152
- });
256
+ import { withCache, withCacheInvalidation, setCacheStorage, MemoryCacheStorage } from 'hono-crud';
257
+
258
+ class UserRead extends withCache(MemoryReadEndpoint) {
259
+ _meta = userMeta;
260
+ cacheConfig = { ttl: 300, perUser: false };
261
+ }
153
262
  ```
154
263
 
155
- 3. **Protect CRUD routes** with hono-crud guards:
264
+ See [docs/caching.md](./docs/caching.md).
265
+
266
+ ### Rate Limiting
156
267
 
157
268
  ```typescript
158
- import { registerCrud, requireAuth, requireRoles } from "hono-crud";
269
+ import { createRateLimitMiddleware, setRateLimitStorage, MemoryRateLimitStorage } from 'hono-crud';
159
270
 
160
- registerCrud(app, "/api/users", {
161
- list: UserList,
162
- read: UserRead,
163
- update: UserUpdate,
164
- delete: UserDelete,
165
- }, {
166
- middlewares: [requireAuth()],
167
- endpointMiddlewares: {
168
- delete: [requireRoles(["admin"])],
169
- },
170
- });
271
+ setRateLimitStorage(new MemoryRateLimitStorage());
272
+
273
+ app.use('/api/*', createRateLimitMiddleware({
274
+ limit: 100,
275
+ windowSeconds: 60,
276
+ keyStrategy: 'ip',
277
+ }));
171
278
  ```
172
279
 
173
- ### Architecture
280
+ See [docs/rate-limiting.md](./docs/rate-limiting.md).
174
281
 
175
- ```
176
- Request → CORS → Session MW → Auth Guards → CRUD Endpoint
177
-
178
- better-auth
179
- (validates session)
282
+ ### Logging
283
+
284
+ ```typescript
285
+ import { createLoggingMiddleware, setLoggingStorage, MemoryLoggingStorage } from 'hono-crud';
286
+
287
+ setLoggingStorage(new MemoryLoggingStorage());
288
+
289
+ app.use('*', createLoggingMiddleware({
290
+ redactHeaders: ['authorization', 'cookie'],
291
+ redactBodyFields: ['password'],
292
+ }));
180
293
  ```
181
294
 
182
- - **better-auth** handles: login, signup, OAuth, 2FA, session management
183
- - **hono-crud** handles: CRUD operations with authorization guards
295
+ See [docs/logging.md](./docs/logging.md).
296
+
297
+ ## Advanced Features
298
+
299
+ - **Soft Delete & Restore** - `softDelete: true` in model, `?withDeleted=true`, restore endpoint
300
+ - **Relations** - `hasOne`, `hasMany`, `belongsTo` with `?include=posts,profile`
301
+ - **Nested Writes** - Create/update related records in a single request
302
+ - **Batch Operations** - Batch create, update, delete, restore, upsert
303
+ - **Upsert** - Create or update by unique keys
304
+ - **Versioning** - Record version history with rollback
305
+ - **Audit Logging** - Track who changed what and when
306
+ - **Full-Text Search** - Weighted search with highlighting
307
+ - **Aggregation** - Sum, count, avg, min, max with grouping
308
+ - **Export/Import** - CSV and JSON export/import
309
+ - **Computed Fields** - Virtual fields calculated on read
310
+ - **Field Selection** - `?fields=id,name,email`
311
+ - **Events & Webhooks** - Event emitter with webhook delivery
312
+ - **Encryption** - Field-level encryption with Web Crypto API
313
+ - **Idempotency** - Idempotency key middleware for safe retries
314
+ - **Multi-Tenancy** - Tenant isolation via header, path, query, or JWT
315
+ - **Health Checks** - Liveness and readiness endpoints
316
+ - **Error Handling** - Typed exceptions with custom error handlers
317
+
318
+ See [docs/advanced-features.md](./docs/advanced-features.md) for examples of every feature.
319
+
320
+ ## API Documentation
321
+
322
+ ```typescript
323
+ import { setupSwaggerUI, setupReDoc, setupScalar } from 'hono-crud';
324
+
325
+ // OpenAPI spec
326
+ app.doc('/openapi.json', {
327
+ openapi: '3.1.0',
328
+ info: { title: 'My API', version: '1.0.0' },
329
+ });
330
+
331
+ // Documentation UIs
332
+ setupSwaggerUI(app, { docsPath: '/docs', specPath: '/openapi.json' });
333
+ setupReDoc(app, { redocPath: '/redoc', specPath: '/openapi.json' });
334
+ setupScalar(app, '/reference', { specUrl: '/openapi.json' });
335
+ ```
184
336
 
185
337
  ## Examples
186
338
 
187
- Check out the [examples](./examples) directory for complete working examples:
339
+ See the [examples/](./examples) directory for complete working applications:
188
340
 
189
- - [Memory Adapter Examples](./examples/memory)
190
- - [Drizzle Examples](./examples/drizzle)
191
- - [Prisma Examples](./examples/prisma)
341
+ - [Memory Adapter](./examples/memory) - Basic CRUD, alternative APIs, comprehensive features
342
+ - [Drizzle + PostgreSQL](./examples/drizzle) - Schema, relations, filtering, batch operations
343
+ - [Prisma + PostgreSQL](./examples/prisma) - Schema, relations, filtering, batch operations
192
344
 
193
345
  ## Requirements
194
346
 
195
- - Node.js >= 18.0.0
196
- - TypeScript >= 5.0 (recommended)
347
+ - Node.js >= 20
348
+ - TypeScript >= 5.0
197
349
 
198
350
  ## License
199
351
 
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "hono-crud",
3
- "version": "0.4.1",
3
+ "version": "0.4.2",
4
4
  "description": "CRUD generator for Hono with Zod validation and OpenAPI generation",
5
5
  "author": "Kauan Guesser <contato@kauan.net>",
6
6
  "license": "MIT",