hono-crud 0.13.2 → 0.13.4
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/CHANGELOG.md +19 -1
- package/README.md +15 -416
- package/dist/audit/index.d.ts +2 -2
- package/dist/audit/index.js +1 -1
- package/dist/auth/index.d.ts +4 -677
- package/dist/auth/index.js +1 -1
- package/dist/chunk-25YGWSRQ.js +11 -0
- package/dist/chunk-3UHAENW7.js +1 -0
- package/dist/chunk-6EYS3CNV.js +1 -0
- package/dist/chunk-CTU6AAXM.js +1 -0
- package/dist/{chunk-QRXEQTNE.js → chunk-DZ3EM3AE.js} +1 -1
- package/dist/chunk-NMK4MUR3.js +1 -0
- package/dist/chunk-PDHKGPGZ.js +1 -0
- package/dist/{chunk-PCPU5A2Q.js → chunk-Q373HVMW.js} +1 -1
- package/dist/chunk-RO5IUV4O.js +1 -0
- package/dist/chunk-RU3RY5SC.js +1 -0
- package/dist/chunk-VTIGDVUR.js +1 -0
- package/dist/chunk-YM6W23MT.js +1 -0
- package/dist/{emitter-vW4MflrJ.d.ts → emitter-BgVwpiRd.d.ts} +50 -2
- package/dist/encryption/index.js +1 -1
- package/dist/events/index.d.ts +2 -4
- package/dist/events/index.js +1 -1
- package/dist/index-_ymQzFJo.d.ts +764 -0
- package/dist/index.d.ts +4333 -274
- package/dist/index.js +1 -2
- package/dist/internal.d.ts +65 -0
- package/dist/internal.js +1 -0
- package/dist/logging/index.d.ts +2 -2
- package/dist/logging/index.js +1 -1
- package/dist/serialization/index.d.ts +1 -1
- package/dist/serialization/index.js +1 -1
- package/dist/storage/index.d.ts +5 -72
- package/dist/storage/index.js +1 -1
- package/dist/{types-Dfi9RdjS.d.ts → types-38Hj6wN4.d.ts} +2 -2
- package/dist/{types-SnlsH9UT.d.ts → types-CpinG1az.d.ts} +1 -1
- package/dist/{types-B5wq2iKZ.d.ts → types-DcRAcexC.d.ts} +1 -1
- package/dist/versioning/index.d.ts +2 -2
- package/dist/versioning/index.js +1 -1
- package/package.json +15 -99
- package/dist/adapters/drizzle/index.d.ts +0 -1004
- package/dist/adapters/drizzle/index.js +0 -1
- package/dist/adapters/memory/index.d.ts +0 -373
- package/dist/adapters/memory/index.js +0 -1
- package/dist/adapters/prisma/index.d.ts +0 -450
- package/dist/adapters/prisma/index.js +0 -1
- package/dist/bulk-patch-DC4NS656.d.ts +0 -57
- package/dist/cache/index.d.ts +0 -488
- package/dist/cache/index.js +0 -1
- package/dist/chunk-2M5BM4VD.js +0 -1
- package/dist/chunk-7DDNX2F2.js +0 -1
- package/dist/chunk-7ZUZICKI.js +0 -1
- package/dist/chunk-BJTWQHEV.js +0 -0
- package/dist/chunk-CCGZ5UPB.js +0 -0
- package/dist/chunk-EWKQ6BPV.js +0 -33
- package/dist/chunk-FJCWFB5L.js +0 -1
- package/dist/chunk-FXIMMYFV.js +0 -1
- package/dist/chunk-GBQQ3YQX.js +0 -1
- package/dist/chunk-GF2EC5G4.js +0 -1
- package/dist/chunk-H3H65KZF.js +0 -1
- package/dist/chunk-HRAGVQWS.js +0 -4
- package/dist/chunk-IPMPKM4J.js +0 -1
- package/dist/chunk-KUFOENSK.js +0 -1
- package/dist/chunk-NGUMNUOP.js +0 -1
- package/dist/chunk-QXFY6NYI.js +0 -1
- package/dist/chunk-R3WESU6C.js +0 -1
- package/dist/chunk-SDNXN7M5.js +0 -1
- package/dist/chunk-SPICOFUM.js +0 -84
- package/dist/chunk-UU7V63VS.js +0 -1
- package/dist/chunk-V4YEHNEZ.js +0 -11
- package/dist/chunk-XH7DEPW2.js +0 -1
- package/dist/chunk-XI7HT5ZM.js +0 -1
- package/dist/chunk-ZAVXHUKP.js +0 -1
- package/dist/exceptions-BEvDdXFC.d.ts +0 -70
- package/dist/health/index.d.ts +0 -103
- package/dist/health/index.js +0 -1
- package/dist/idempotency/index.d.ts +0 -80
- package/dist/idempotency/index.js +0 -1
- package/dist/import-Gx0ZUJjI.d.ts +0 -3183
- package/dist/index-B1QEfh5v.d.ts +0 -812
- package/dist/rate-limit/index.d.ts +0 -386
- package/dist/rate-limit/index.js +0 -1
- package/dist/route-UXFfftVm.d.ts +0 -94
- package/dist/types-BNui1SQl.d.ts +0 -89
- package/dist/types-BdRvpp1z.d.ts +0 -141
- package/dist/types-Bjef1r9u.d.ts +0 -236
- package/dist/types-rJSyOxkJ.d.ts +0 -50
- package/dist/ui-CNJUoCg1.d.ts +0 -148
- package/dist/ui.d.ts +0 -2
- package/dist/ui.js +0 -1
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## 0.13.4
|
|
4
|
+
|
|
5
|
+
### Patch Changes
|
|
6
|
+
|
|
7
|
+
- 6c22eaa: Restructure the project into a pnpm-workspaces monorepo. `hono-crud` is now the thin core; the database adapters, documentation UIs, and optional middleware ship as separate installable packages under the `@hono-crud/*` scope:
|
|
8
|
+
|
|
9
|
+
- `@hono-crud/memory`, `@hono-crud/drizzle`, `@hono-crud/prisma` — CRUD adapters (was `hono-crud/adapters/*`)
|
|
10
|
+
- `@hono-crud/swagger`, `@hono-crud/scalar` — documentation UIs (was exported from the `hono-crud` barrel / `hono-crud/ui`)
|
|
11
|
+
- `@hono-crud/cache`, `@hono-crud/rate-limit`, `@hono-crud/idempotency`, `@hono-crud/health` — optional middleware (was `hono-crud/{cache,rate-limit,idempotency,health}`)
|
|
12
|
+
|
|
13
|
+
Breaking: these symbols are no longer re-exported from `hono-crud`; install the corresponding `@hono-crud/*` package and import from it. The unified `createCrudMiddleware`, `HonoCrudEnv`, and `StorageEnv` no longer cover cache/rate-limit/idempotency — compose those packages' own middleware instead. A `hono-crud/internal` entrypoint is available for authoring adapters.
|
|
14
|
+
|
|
3
15
|
All notable changes to this project will be documented in this file.
|
|
4
16
|
|
|
5
17
|
The format is based on [Keep a Changelog](https://keepachangelog.com/en/1.1.0/),
|
|
@@ -17,15 +29,20 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
17
29
|
%b
|
|
18
30
|
%b
|
|
19
31
|
%b
|
|
32
|
+
%b
|
|
33
|
+
|
|
20
34
|
## [0.8.0] — 2026-05-03
|
|
21
35
|
|
|
22
36
|
### Added
|
|
37
|
+
|
|
23
38
|
- `middlewares?: MiddlewareHandler[]` slot on every per-endpoint config in `EndpointsConfig<M>` (`create`, `list`, `read`, `update`, `delete`, `search`, `aggregate`, `restore`, `batchCreate`, `batchUpdate`, `batchDelete`, `batchRestore`, `batchUpsert`, `export`, `import`, `upsert`, `clone`). Middleware listed here runs before the endpoint handler. The existing `RegisterCrudOptions.endpointMiddlewares` continues to work and overrides config-API middlewares for the same verb. Coverage: `tests/per-endpoint-middlewares.test.ts`.
|
|
24
39
|
|
|
25
40
|
### Fixed
|
|
41
|
+
|
|
26
42
|
- `HonoOpenAPIHandler.registerRoute` was passing the OpenAPI-style path (`/widgets/{id}`) to `app.use(...)` for per-route middleware. Hono's `use` expects the route-syntax form (`/widgets/:id`), so middleware on dynamic-segment routes (e.g., `delete`, `read`, `update`, `restore`, `clone`) silently never fired. The fix passes the raw path to `app.use(...)` and keeps the OpenAPI conversion only for `createRoute({ path })`. This unblocks both the new config-API `middlewares` slot and the existing `RegisterCrudOptions.endpointMiddlewares` option on `:id` routes.
|
|
27
43
|
|
|
28
44
|
### Compatibility
|
|
45
|
+
|
|
29
46
|
- Additive. Existing consumers see no behaviour change other than the bugfix above (middleware that previously was silently dropped on `:id` routes will now run as documented).
|
|
30
47
|
|
|
31
48
|
%b
|
|
@@ -46,6 +63,7 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
46
63
|
%b
|
|
47
64
|
%b
|
|
48
65
|
%b
|
|
66
|
+
|
|
49
67
|
## [0.1.0] - 2025-01-29
|
|
50
68
|
|
|
51
69
|
### Added
|
|
@@ -66,7 +84,6 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
66
84
|
- Edge runtime support (Cloudflare Workers, Deno, Bun, Node.js)
|
|
67
85
|
|
|
68
86
|
[0.1.0]: https://github.com/ksh-us/hono-crud/releases/tag/v0.1.0
|
|
69
|
-
|
|
70
87
|
[0.1.1]: https://github.com/ksh-us/hono-crud/compare/v0.0.0...v0.1.1
|
|
71
88
|
[0.1.2]: https://github.com/ksh-us/hono-crud/compare/v0.1.1...v0.1.2
|
|
72
89
|
[0.1.3]: https://github.com/ksh-us/hono-crud/compare/v0.1.2...v0.1.3
|
|
@@ -99,3 +116,4 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
|
|
|
99
116
|
[0.13.0]: https://github.com/kshdotdev/hono-crud/compare/v0.12.5...v0.13.0
|
|
100
117
|
[0.13.1]: https://github.com/kshdotdev/hono-crud/compare/v0.13.0...v0.13.1
|
|
101
118
|
[0.13.2]: https://github.com/kshdotdev/hono-crud/compare/v0.13.1...v0.13.2
|
|
119
|
+
[0.13.3]: https://github.com/kshdotdev/hono-crud/compare/v0.13.2...v0.13.3
|
package/README.md
CHANGED
|
@@ -1,435 +1,34 @@
|
|
|
1
1
|
# hono-crud
|
|
2
2
|
|
|
3
|
-
[
|
|
4
|
-
[](https://opensource.org/licenses/MIT)
|
|
5
|
-
[](https://www.typescriptlang.org/)
|
|
3
|
+
CRUD generator for [Hono](https://hono.dev) with Zod validation and OpenAPI generation.
|
|
6
4
|
|
|
7
|
-
|
|
5
|
+
Define a model once and register fully-typed Create / Read / Update / Delete / List endpoints. Core also ships auth, logging, events, encryption, serialization, audit, versioning, multi-tenant, and API-versioning helpers. Persistence adapters and docs UIs live in separate `@hono-crud/*` packages.
|
|
8
6
|
|
|
9
|
-
##
|
|
10
|
-
|
|
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
|
|
15
|
-
- **Zod Validation** - Type-safe request/response validation
|
|
16
|
-
- **TypeScript First** - Full type inference and autocompletion
|
|
17
|
-
- **Edge Ready** - Works with Cloudflare Workers, Deno, Bun, and Node.js
|
|
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
|
|
22
|
-
|
|
23
|
-
## Installation
|
|
7
|
+
## Install
|
|
24
8
|
|
|
25
9
|
```bash
|
|
26
10
|
npm install hono-crud hono zod
|
|
27
11
|
```
|
|
28
12
|
|
|
29
|
-
|
|
13
|
+
You will also want a storage adapter, e.g. `@hono-crud/memory`, `@hono-crud/drizzle`, or `@hono-crud/prisma`.
|
|
30
14
|
|
|
31
|
-
##
|
|
15
|
+
## Usage
|
|
32
16
|
|
|
33
|
-
```
|
|
34
|
-
import { Hono } from 'hono';
|
|
17
|
+
```ts
|
|
35
18
|
import { z } from 'zod';
|
|
36
|
-
import { fromHono, registerCrud,
|
|
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
|
-
const UserSchema = z.object({
|
|
47
|
-
id: z.uuid(),
|
|
48
|
-
email: z.email(),
|
|
49
|
-
name: z.string().min(1),
|
|
50
|
-
role: z.enum(['admin', 'user']),
|
|
51
|
-
});
|
|
52
|
-
|
|
53
|
-
// 2. Create model + meta
|
|
54
|
-
const UserModel = defineModel({
|
|
55
|
-
tableName: 'users',
|
|
56
|
-
schema: UserSchema,
|
|
57
|
-
primaryKeys: ['id'],
|
|
58
|
-
});
|
|
59
|
-
|
|
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
|
-
}
|
|
19
|
+
import { fromHono, registerCrud, defineModel, defineMeta } from 'hono-crud';
|
|
20
|
+
import { MemoryCreateEndpoint, MemoryReadEndpoint, MemoryListEndpoint } from '@hono-crud/memory';
|
|
67
21
|
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
filterFields = ['role'];
|
|
72
|
-
searchFields = ['name', 'email'];
|
|
73
|
-
}
|
|
22
|
+
const UserSchema = z.object({ id: z.string(), name: z.string() });
|
|
23
|
+
const model = defineModel({ schema: UserSchema, primaryKey: 'id' });
|
|
24
|
+
const meta = defineMeta({ tableName: 'users' });
|
|
74
25
|
|
|
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
26
|
const app = fromHono(new Hono());
|
|
93
|
-
|
|
94
27
|
registerCrud(app, '/users', {
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
read:
|
|
98
|
-
update: UserUpdate,
|
|
99
|
-
delete: UserDelete,
|
|
28
|
+
model,
|
|
29
|
+
meta,
|
|
30
|
+
endpoints: { create: MemoryCreateEndpoint, read: MemoryReadEndpoint, list: MemoryListEndpoint },
|
|
100
31
|
});
|
|
101
|
-
|
|
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' });
|
|
108
|
-
|
|
109
|
-
export default app;
|
|
110
32
|
```
|
|
111
33
|
|
|
112
|
-
|
|
113
|
-
|
|
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 |
|
|
121
|
-
|
|
122
|
-
## API Patterns
|
|
123
|
-
|
|
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)` |
|
|
132
|
-
|
|
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);
|
|
161
|
-
```
|
|
162
|
-
|
|
163
|
-
See [docs/alternative-api-patterns.md](./docs/alternative-api-patterns.md) for the full reference.
|
|
164
|
-
|
|
165
|
-
## Database Adapters
|
|
166
|
-
|
|
167
|
-
### Memory
|
|
168
|
-
|
|
169
|
-
Zero-config, perfect for prototyping and tests:
|
|
170
|
-
|
|
171
|
-
```typescript
|
|
172
|
-
import { MemoryCreateEndpoint, MemoryListEndpoint /* ... */ } from 'hono-crud/adapters/memory';
|
|
173
|
-
```
|
|
174
|
-
|
|
175
|
-
### Drizzle
|
|
176
|
-
|
|
177
|
-
Use `createDrizzleCrud` for minimal boilerplate:
|
|
178
|
-
|
|
179
|
-
```typescript
|
|
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
|
-
}
|
|
188
|
-
|
|
189
|
-
class UserList extends User.List {
|
|
190
|
-
schema = { tags: ['Users'], summary: 'List users' };
|
|
191
|
-
filterFields = ['role'];
|
|
192
|
-
}
|
|
193
|
-
```
|
|
194
|
-
|
|
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
|
-
```
|
|
206
|
-
|
|
207
|
-
### Prisma
|
|
208
|
-
|
|
209
|
-
```typescript
|
|
210
|
-
import { PrismaListEndpoint } from 'hono-crud/adapters/prisma';
|
|
211
|
-
|
|
212
|
-
class UserList extends PrismaListEndpoint {
|
|
213
|
-
_meta = userMeta;
|
|
214
|
-
prisma = prismaClient;
|
|
215
|
-
filterFields = ['role'];
|
|
216
|
-
}
|
|
217
|
-
```
|
|
218
|
-
|
|
219
|
-
See [docs/database-adapters.md](./docs/database-adapters.md) for complete setup guides.
|
|
220
|
-
|
|
221
|
-
## Authentication
|
|
222
|
-
|
|
223
|
-
Built-in JWT and API Key middleware with composable guards:
|
|
224
|
-
|
|
225
|
-
```typescript
|
|
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',
|
|
232
|
-
}));
|
|
233
|
-
|
|
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
|
-
));
|
|
247
|
-
```
|
|
248
|
-
|
|
249
|
-
See [docs/authentication.md](./docs/authentication.md) for JWT, API Key, guards, and better-auth integration.
|
|
250
|
-
|
|
251
|
-
## Middleware
|
|
252
|
-
|
|
253
|
-
### Caching
|
|
254
|
-
|
|
255
|
-
```typescript
|
|
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
|
-
}
|
|
262
|
-
```
|
|
263
|
-
|
|
264
|
-
See [docs/caching.md](./docs/caching.md).
|
|
265
|
-
|
|
266
|
-
### Rate Limiting
|
|
267
|
-
|
|
268
|
-
```typescript
|
|
269
|
-
import { createRateLimitMiddleware, setRateLimitStorage, MemoryRateLimitStorage } from 'hono-crud';
|
|
270
|
-
|
|
271
|
-
setRateLimitStorage(new MemoryRateLimitStorage());
|
|
272
|
-
|
|
273
|
-
app.use('/api/*', createRateLimitMiddleware({
|
|
274
|
-
limit: 100,
|
|
275
|
-
windowSeconds: 60,
|
|
276
|
-
keyStrategy: 'ip',
|
|
277
|
-
}));
|
|
278
|
-
```
|
|
279
|
-
|
|
280
|
-
See [docs/rate-limiting.md](./docs/rate-limiting.md).
|
|
281
|
-
|
|
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
|
-
}));
|
|
293
|
-
```
|
|
294
|
-
|
|
295
|
-
See [docs/logging.md](./docs/logging.md).
|
|
296
|
-
|
|
297
|
-
## Response shape
|
|
298
|
-
|
|
299
|
-
Every CRUD endpoint defaults to a small, predictable response envelope so consumers always know where to find `result` and `error`:
|
|
300
|
-
|
|
301
|
-
```jsonc
|
|
302
|
-
// Success — single item (Create / Read / Update / Restore / Upsert / Clone / …)
|
|
303
|
-
{ "success": true, "result": { "id": "…", … } }
|
|
304
|
-
|
|
305
|
-
// Success — list / search (with pagination metadata)
|
|
306
|
-
{ "success": true, "result": [ … ], "result_info": { "page": 1, "per_page": 20, … } }
|
|
307
|
-
|
|
308
|
-
// Error — produced by `ApiException`s thrown from the endpoint or by
|
|
309
|
-
// `createErrorHandler` for everything else
|
|
310
|
-
{ "success": false, "error": { "code": "NOT_FOUND", "message": "…", "details": … } }
|
|
311
|
-
```
|
|
312
|
-
|
|
313
|
-
### Pluggable envelope (`responseEnvelope`)
|
|
314
|
-
|
|
315
|
-
If your house API standard prefers a different shape — RFC 7807 Problem Details, JSON:API `{ data, meta }`, or any custom envelope — pass `responseEnvelope` to `registerCrud`. The two functions are the **final formatting step** before the response body is serialised:
|
|
316
|
-
|
|
317
|
-
```typescript
|
|
318
|
-
import { registerCrud, type ResponseEnvelope } from 'hono-crud';
|
|
319
|
-
|
|
320
|
-
const envelope: ResponseEnvelope = {
|
|
321
|
-
success: (result, info) =>
|
|
322
|
-
info ? { data: result, meta: info } : { data: result },
|
|
323
|
-
error: (err) => ({
|
|
324
|
-
errors: [{ status: err.code, title: err.message, source: err.details }],
|
|
325
|
-
}),
|
|
326
|
-
};
|
|
327
|
-
|
|
328
|
-
registerCrud(app, '/users', endpoints, { responseEnvelope: envelope });
|
|
329
|
-
```
|
|
330
|
-
|
|
331
|
-
The `info` argument is the pagination metadata for list/search responses; it's `undefined` for single-item responses, so a single envelope works across the whole CRUD surface.
|
|
332
|
-
|
|
333
|
-
### Composition with `createErrorHandler`
|
|
334
|
-
|
|
335
|
-
For errors, the envelope composes with the existing `mappers` chain on `createErrorHandler`. The order is fixed:
|
|
336
|
-
|
|
337
|
-
1. `mappers[]` (and the built-in `zodErrorMapper`) transform the raw `Error` into a structured `ApiException` (`{ code, message, details? }`).
|
|
338
|
-
2. `responseEnvelope.error(...)` wraps that structured object into the final response body.
|
|
339
|
-
|
|
340
|
-
```typescript
|
|
341
|
-
import { createErrorHandler, type ErrorMapper } from 'hono-crud';
|
|
342
|
-
|
|
343
|
-
const prismaMapper: ErrorMapper = (err) => {
|
|
344
|
-
if ((err as { code?: string }).code === 'P2002') {
|
|
345
|
-
return new ConflictException('Duplicate key', { /* … */ });
|
|
346
|
-
}
|
|
347
|
-
};
|
|
348
|
-
|
|
349
|
-
app.onError(createErrorHandler({
|
|
350
|
-
mappers: [prismaMapper],
|
|
351
|
-
// Handler-level default — applies to errors that propagate to onError
|
|
352
|
-
// (i.e. anything that's not already an ApiException). Per-route envelope
|
|
353
|
-
// set via `registerCrud({ responseEnvelope })` always wins.
|
|
354
|
-
responseEnvelope: envelope,
|
|
355
|
-
}));
|
|
356
|
-
```
|
|
357
|
-
|
|
358
|
-
This split lets you keep your domain-error mappers (Prisma codes, Drizzle constraint violations, …) unchanged and layer a custom shape on top — no response-rewriting middleware required.
|
|
359
|
-
|
|
360
|
-
When `responseEnvelope` is omitted (the default), the response body is byte-identical to pre-0.10.0 — existing consumers see no behaviour change.
|
|
361
|
-
|
|
362
|
-
## Advanced Features
|
|
363
|
-
|
|
364
|
-
- **Soft Delete & Restore** - `softDelete: true` in model, `?withDeleted=true`, restore endpoint
|
|
365
|
-
- **Relations** - `hasOne`, `hasMany`, `belongsTo` with `?include=posts,profile`
|
|
366
|
-
- **Nested Writes** - Create/update related records in a single request
|
|
367
|
-
- **Batch Operations** - Batch create, update, delete, restore, upsert
|
|
368
|
-
- **Upsert** - Create or update by unique keys
|
|
369
|
-
- **Versioning** - Record version history with rollback
|
|
370
|
-
- **Audit Logging** - Track who changed what and when
|
|
371
|
-
- **Full-Text Search** - Weighted search with highlighting
|
|
372
|
-
- **Aggregation** - Sum, count, avg, min, max with grouping
|
|
373
|
-
- **Export/Import** - CSV and JSON export/import
|
|
374
|
-
- **Computed Fields** - Virtual fields calculated on read
|
|
375
|
-
- **Field Selection** - `?fields=id,name,email`
|
|
376
|
-
- **Events & Webhooks** - Event emitter with webhook delivery
|
|
377
|
-
- **Encryption** - Field-level encryption with Web Crypto API
|
|
378
|
-
- **Idempotency** - Idempotency key middleware for safe retries
|
|
379
|
-
- **Multi-Tenancy** - Tenant isolation via header, path, query, or JWT
|
|
380
|
-
- **Health Checks** - Liveness and readiness endpoints
|
|
381
|
-
- **Error Handling** - Typed exceptions with custom error handlers
|
|
382
|
-
|
|
383
|
-
See [docs/advanced-features.md](./docs/advanced-features.md) for examples of every feature.
|
|
384
|
-
|
|
385
|
-
### Subpath Imports
|
|
386
|
-
|
|
387
|
-
Every advanced feature is also exposed as a tree-shakeable subpath, so apps that only need one feature can import it directly without pulling in the rest of the library:
|
|
388
|
-
|
|
389
|
-
```typescript
|
|
390
|
-
import { multiTenant } from 'hono-crud/multi-tenant';
|
|
391
|
-
import { createAuditLogger, MemoryAuditLogStorage } from 'hono-crud/audit';
|
|
392
|
-
import { VersionManager, MemoryVersioningStorage } from 'hono-crud/versioning';
|
|
393
|
-
import { CrudEventEmitter, registerWebhooks } from 'hono-crud/events';
|
|
394
|
-
import { idempotency, MemoryIdempotencyStorage } from 'hono-crud/idempotency';
|
|
395
|
-
import { createHealthEndpoints } from 'hono-crud/health';
|
|
396
|
-
import { encryptFields, decryptFields, StaticKeyProvider } from 'hono-crud/encryption';
|
|
397
|
-
import { applyProfile, type SerializationProfile } from 'hono-crud/serialization';
|
|
398
|
-
import { apiVersion, getApiVersion } from 'hono-crud/api-version';
|
|
399
|
-
```
|
|
400
|
-
|
|
401
|
-
The same symbols remain available from `'hono-crud'` for convenience.
|
|
402
|
-
|
|
403
|
-
## API Documentation
|
|
404
|
-
|
|
405
|
-
```typescript
|
|
406
|
-
import { setupSwaggerUI, setupReDoc, setupScalar } from 'hono-crud';
|
|
407
|
-
|
|
408
|
-
// OpenAPI spec
|
|
409
|
-
app.doc('/openapi.json', {
|
|
410
|
-
openapi: '3.1.0',
|
|
411
|
-
info: { title: 'My API', version: '1.0.0' },
|
|
412
|
-
});
|
|
413
|
-
|
|
414
|
-
// Documentation UIs
|
|
415
|
-
setupSwaggerUI(app, { docsPath: '/docs', specPath: '/openapi.json' });
|
|
416
|
-
setupReDoc(app, { redocPath: '/redoc', specPath: '/openapi.json' });
|
|
417
|
-
setupScalar(app, '/reference', { specUrl: '/openapi.json' });
|
|
418
|
-
```
|
|
419
|
-
|
|
420
|
-
## Examples
|
|
421
|
-
|
|
422
|
-
See the [examples/](./examples) directory for complete working applications:
|
|
423
|
-
|
|
424
|
-
- [Memory Adapter](./examples/memory) - Basic CRUD, alternative APIs, comprehensive features
|
|
425
|
-
- [Drizzle + PostgreSQL](./examples/drizzle) - Schema, relations, filtering, batch operations
|
|
426
|
-
- [Prisma + PostgreSQL](./examples/prisma) - Schema, relations, filtering, batch operations
|
|
427
|
-
|
|
428
|
-
## Requirements
|
|
429
|
-
|
|
430
|
-
- Node.js >= 20
|
|
431
|
-
- TypeScript >= 5.0
|
|
432
|
-
|
|
433
|
-
## License
|
|
434
|
-
|
|
435
|
-
[MIT](./LICENSE) - Kauan Guesser
|
|
34
|
+
See the [repository README](https://github.com/kshdotdev/hono-crud) for the full guide.
|
package/dist/audit/index.d.ts
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import { Context, Env } from 'hono';
|
|
2
|
-
import { A as AuditConfig,
|
|
2
|
+
import { A as AuditConfig, a as AuditLogEntry, b as AuditAction } from '../types-38Hj6wN4.js';
|
|
3
3
|
import { S as StorageRegistry } from '../registry-PNJjvSvm.js';
|
|
4
4
|
import 'zod';
|
|
5
|
-
import '../types-
|
|
5
|
+
import '../types-DcRAcexC.js';
|
|
6
6
|
import '../types-BAcN7U0B.js';
|
|
7
7
|
import '@hono/zod-openapi';
|
|
8
8
|
|
package/dist/audit/index.js
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export{e as AuditLogger,a as MemoryAuditLogStorage,b as auditStorageRegistry,f as createAuditLogger,d as getAuditStorage,c as setAuditStorage}from'../chunk-
|
|
1
|
+
export{e as AuditLogger,a as MemoryAuditLogStorage,b as auditStorageRegistry,f as createAuditLogger,d as getAuditStorage,c as setAuditStorage}from'../chunk-CTU6AAXM.js';import'../chunk-RU3RY5SC.js';import'../chunk-MDHMZPXK.js';import'../chunk-VJRDAVID.js';
|