@qazuor/claude-code-config 0.5.0 → 0.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +106 -41
- package/dist/bin.cjs +963 -84
- package/dist/bin.cjs.map +1 -1
- package/dist/bin.js +963 -84
- package/dist/bin.js.map +1 -1
- package/dist/index.cjs +73 -56
- package/dist/index.cjs.map +1 -1
- package/dist/index.d.cts +2 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +73 -56
- package/dist/index.js.map +1 -1
- package/package.json +23 -24
- package/templates/CLAUDE.md.template +60 -5
- package/templates/agents/README.md +58 -39
- package/templates/agents/_registry.json +43 -202
- package/templates/agents/engineering/{hono-engineer.md → api-engineer.md} +61 -70
- package/templates/agents/engineering/database-engineer.md +253 -0
- package/templates/agents/engineering/frontend-engineer.md +302 -0
- package/templates/hooks/on-notification.sh +0 -0
- package/templates/scripts/add-changelogs.sh +0 -0
- package/templates/scripts/generate-code-registry.ts +0 -0
- package/templates/scripts/health-check.sh +0 -0
- package/templates/scripts/sync-registry.sh +0 -0
- package/templates/scripts/telemetry-report.ts +0 -0
- package/templates/scripts/validate-docs.sh +0 -0
- package/templates/scripts/validate-registry.sh +0 -0
- package/templates/scripts/validate-structure.sh +0 -0
- package/templates/scripts/worktree-cleanup.sh +0 -0
- package/templates/scripts/worktree-create.sh +0 -0
- package/templates/skills/README.md +99 -90
- package/templates/skills/_registry.json +323 -16
- package/templates/skills/api-frameworks/express-patterns.md +411 -0
- package/templates/skills/api-frameworks/fastify-patterns.md +419 -0
- package/templates/skills/api-frameworks/hono-patterns.md +388 -0
- package/templates/skills/api-frameworks/nestjs-patterns.md +497 -0
- package/templates/skills/database/drizzle-patterns.md +449 -0
- package/templates/skills/database/mongoose-patterns.md +503 -0
- package/templates/skills/database/prisma-patterns.md +487 -0
- package/templates/skills/frontend-frameworks/astro-patterns.md +415 -0
- package/templates/skills/frontend-frameworks/nextjs-patterns.md +470 -0
- package/templates/skills/frontend-frameworks/react-patterns.md +516 -0
- package/templates/skills/frontend-frameworks/tanstack-start-patterns.md +469 -0
- package/templates/skills/patterns/atdd-methodology.md +364 -0
- package/templates/skills/patterns/bdd-methodology.md +281 -0
- package/templates/skills/patterns/clean-architecture.md +444 -0
- package/templates/skills/patterns/hexagonal-architecture.md +567 -0
- package/templates/skills/patterns/vertical-slice-architecture.md +502 -0
- package/templates/agents/engineering/astro-engineer.md +0 -293
- package/templates/agents/engineering/db-drizzle-engineer.md +0 -360
- package/templates/agents/engineering/express-engineer.md +0 -316
- package/templates/agents/engineering/fastify-engineer.md +0 -399
- package/templates/agents/engineering/mongoose-engineer.md +0 -473
- package/templates/agents/engineering/nestjs-engineer.md +0 -429
- package/templates/agents/engineering/nextjs-engineer.md +0 -451
- package/templates/agents/engineering/prisma-engineer.md +0 -432
- package/templates/agents/engineering/react-senior-dev.md +0 -394
- package/templates/agents/engineering/tanstack-start-engineer.md +0 -447
|
@@ -0,0 +1,388 @@
|
|
|
1
|
+
# Hono Framework Patterns
|
|
2
|
+
|
|
3
|
+
## Overview
|
|
4
|
+
|
|
5
|
+
Hono is a lightweight, ultrafast web framework for the Edge. This skill provides patterns for implementing APIs with Hono.
|
|
6
|
+
|
|
7
|
+
---
|
|
8
|
+
|
|
9
|
+
## App Setup
|
|
10
|
+
|
|
11
|
+
**Pattern**: Modular app with middleware chain
|
|
12
|
+
|
|
13
|
+
```typescript
|
|
14
|
+
import { Hono } from 'hono';
|
|
15
|
+
import { cors } from 'hono/cors';
|
|
16
|
+
import { logger } from 'hono/logger';
|
|
17
|
+
import { secureHeaders } from 'hono/secure-headers';
|
|
18
|
+
import { itemRoutes } from './routes/items';
|
|
19
|
+
import { errorHandler } from './middleware/error-handler';
|
|
20
|
+
|
|
21
|
+
const app = new Hono();
|
|
22
|
+
|
|
23
|
+
// Middleware
|
|
24
|
+
app.use('*', logger());
|
|
25
|
+
app.use('*', secureHeaders());
|
|
26
|
+
app.use('*', cors());
|
|
27
|
+
|
|
28
|
+
// Routes
|
|
29
|
+
app.route('/api/v1/items', itemRoutes);
|
|
30
|
+
|
|
31
|
+
// Error handler
|
|
32
|
+
app.onError(errorHandler);
|
|
33
|
+
|
|
34
|
+
export { app };
|
|
35
|
+
```
|
|
36
|
+
|
|
37
|
+
---
|
|
38
|
+
|
|
39
|
+
## Route Definition
|
|
40
|
+
|
|
41
|
+
### Factory-Based Routes (Preferred)
|
|
42
|
+
|
|
43
|
+
```typescript
|
|
44
|
+
import { Hono } from 'hono';
|
|
45
|
+
import { zValidator } from '@hono/zod-validator';
|
|
46
|
+
import { createItemSchema, updateItemSchema } from '../schemas/items';
|
|
47
|
+
import { itemService } from '../services/items';
|
|
48
|
+
import { requireAuth } from '../middleware/auth';
|
|
49
|
+
import { successResponse } from '../utils/response';
|
|
50
|
+
|
|
51
|
+
const app = new Hono();
|
|
52
|
+
|
|
53
|
+
// GET /items
|
|
54
|
+
app.get('/', async (c) => {
|
|
55
|
+
const items = await itemService.findAll();
|
|
56
|
+
return successResponse(c, items);
|
|
57
|
+
});
|
|
58
|
+
|
|
59
|
+
// GET /items/:id
|
|
60
|
+
app.get('/:id', async (c) => {
|
|
61
|
+
const item = await itemService.findById(c.req.param('id'));
|
|
62
|
+
if (!item) {
|
|
63
|
+
return c.json({ error: 'Not found' }, 404);
|
|
64
|
+
}
|
|
65
|
+
return successResponse(c, item);
|
|
66
|
+
});
|
|
67
|
+
|
|
68
|
+
// POST /items
|
|
69
|
+
app.post('/',
|
|
70
|
+
requireAuth,
|
|
71
|
+
zValidator('json', createItemSchema),
|
|
72
|
+
async (c) => {
|
|
73
|
+
const data = c.req.valid('json');
|
|
74
|
+
const actor = c.get('user');
|
|
75
|
+
const item = await itemService.create({ data, actor });
|
|
76
|
+
return successResponse(c, item, 201);
|
|
77
|
+
}
|
|
78
|
+
);
|
|
79
|
+
|
|
80
|
+
// PUT /items/:id
|
|
81
|
+
app.put('/:id',
|
|
82
|
+
requireAuth,
|
|
83
|
+
zValidator('json', updateItemSchema),
|
|
84
|
+
async (c) => {
|
|
85
|
+
const id = c.req.param('id');
|
|
86
|
+
const data = c.req.valid('json');
|
|
87
|
+
const actor = c.get('user');
|
|
88
|
+
const item = await itemService.update({ id, data, actor });
|
|
89
|
+
return successResponse(c, item);
|
|
90
|
+
}
|
|
91
|
+
);
|
|
92
|
+
|
|
93
|
+
// DELETE /items/:id
|
|
94
|
+
app.delete('/:id', requireAuth, async (c) => {
|
|
95
|
+
const id = c.req.param('id');
|
|
96
|
+
const actor = c.get('user');
|
|
97
|
+
await itemService.delete({ id, actor });
|
|
98
|
+
return c.json({ success: true }, 204);
|
|
99
|
+
});
|
|
100
|
+
|
|
101
|
+
export { app as itemRoutes };
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### CRUD Factory Pattern
|
|
105
|
+
|
|
106
|
+
```typescript
|
|
107
|
+
import { Hono } from 'hono';
|
|
108
|
+
import { zValidator } from '@hono/zod-validator';
|
|
109
|
+
import type { z } from 'zod';
|
|
110
|
+
|
|
111
|
+
interface CRUDRouteOptions<T> {
|
|
112
|
+
service: {
|
|
113
|
+
findAll: () => Promise<T[]>;
|
|
114
|
+
findById: (id: string) => Promise<T | null>;
|
|
115
|
+
create: (data: unknown) => Promise<T>;
|
|
116
|
+
update: (id: string, data: unknown) => Promise<T>;
|
|
117
|
+
delete: (id: string) => Promise<void>;
|
|
118
|
+
};
|
|
119
|
+
createSchema: z.ZodSchema;
|
|
120
|
+
updateSchema: z.ZodSchema;
|
|
121
|
+
requireAuth?: boolean;
|
|
122
|
+
}
|
|
123
|
+
|
|
124
|
+
export function createCRUDRoute<T>(options: CRUDRouteOptions<T>) {
|
|
125
|
+
const app = new Hono();
|
|
126
|
+
const { service, createSchema, updateSchema } = options;
|
|
127
|
+
|
|
128
|
+
app.get('/', async (c) => {
|
|
129
|
+
const items = await service.findAll();
|
|
130
|
+
return c.json({ data: items });
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
app.get('/:id', async (c) => {
|
|
134
|
+
const item = await service.findById(c.req.param('id'));
|
|
135
|
+
if (!item) return c.json({ error: 'Not found' }, 404);
|
|
136
|
+
return c.json({ data: item });
|
|
137
|
+
});
|
|
138
|
+
|
|
139
|
+
app.post('/', zValidator('json', createSchema), async (c) => {
|
|
140
|
+
const data = c.req.valid('json');
|
|
141
|
+
const item = await service.create(data);
|
|
142
|
+
return c.json({ data: item }, 201);
|
|
143
|
+
});
|
|
144
|
+
|
|
145
|
+
app.put('/:id', zValidator('json', updateSchema), async (c) => {
|
|
146
|
+
const item = await service.update(c.req.param('id'), c.req.valid('json'));
|
|
147
|
+
return c.json({ data: item });
|
|
148
|
+
});
|
|
149
|
+
|
|
150
|
+
app.delete('/:id', async (c) => {
|
|
151
|
+
await service.delete(c.req.param('id'));
|
|
152
|
+
return c.body(null, 204);
|
|
153
|
+
});
|
|
154
|
+
|
|
155
|
+
return app;
|
|
156
|
+
}
|
|
157
|
+
```
|
|
158
|
+
|
|
159
|
+
---
|
|
160
|
+
|
|
161
|
+
## Middleware Patterns
|
|
162
|
+
|
|
163
|
+
### Authentication Middleware
|
|
164
|
+
|
|
165
|
+
```typescript
|
|
166
|
+
import type { MiddlewareHandler } from 'hono';
|
|
167
|
+
import { HTTPException } from 'hono/http-exception';
|
|
168
|
+
|
|
169
|
+
export const requireAuth: MiddlewareHandler = async (c, next) => {
|
|
170
|
+
const token = c.req.header('Authorization')?.replace('Bearer ', '');
|
|
171
|
+
|
|
172
|
+
if (!token) {
|
|
173
|
+
throw new HTTPException(401, { message: 'Unauthorized' });
|
|
174
|
+
}
|
|
175
|
+
|
|
176
|
+
const user = await verifyToken(token);
|
|
177
|
+
if (!user) {
|
|
178
|
+
throw new HTTPException(401, { message: 'Invalid token' });
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
c.set('user', user);
|
|
182
|
+
await next();
|
|
183
|
+
};
|
|
184
|
+
|
|
185
|
+
export const optionalAuth: MiddlewareHandler = async (c, next) => {
|
|
186
|
+
const token = c.req.header('Authorization')?.replace('Bearer ', '');
|
|
187
|
+
|
|
188
|
+
if (token) {
|
|
189
|
+
const user = await verifyToken(token);
|
|
190
|
+
if (user) {
|
|
191
|
+
c.set('user', user);
|
|
192
|
+
}
|
|
193
|
+
}
|
|
194
|
+
|
|
195
|
+
await next();
|
|
196
|
+
};
|
|
197
|
+
```
|
|
198
|
+
|
|
199
|
+
### Validation Middleware
|
|
200
|
+
|
|
201
|
+
```typescript
|
|
202
|
+
import { zValidator } from '@hono/zod-validator';
|
|
203
|
+
import type { z } from 'zod';
|
|
204
|
+
|
|
205
|
+
// Body validation
|
|
206
|
+
app.post('/', zValidator('json', createItemSchema), handler);
|
|
207
|
+
|
|
208
|
+
// Query validation
|
|
209
|
+
app.get('/', zValidator('query', listQuerySchema), handler);
|
|
210
|
+
|
|
211
|
+
// Params validation
|
|
212
|
+
app.get('/:id', zValidator('param', idParamSchema), handler);
|
|
213
|
+
```
|
|
214
|
+
|
|
215
|
+
### Error Handler
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
import type { ErrorHandler } from 'hono';
|
|
219
|
+
import { HTTPException } from 'hono/http-exception';
|
|
220
|
+
|
|
221
|
+
export const errorHandler: ErrorHandler = (err, c) => {
|
|
222
|
+
if (err instanceof HTTPException) {
|
|
223
|
+
return c.json({
|
|
224
|
+
success: false,
|
|
225
|
+
error: {
|
|
226
|
+
message: err.message,
|
|
227
|
+
code: err.status.toString(),
|
|
228
|
+
},
|
|
229
|
+
}, err.status);
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
console.error('Unhandled error:', err);
|
|
233
|
+
|
|
234
|
+
return c.json({
|
|
235
|
+
success: false,
|
|
236
|
+
error: {
|
|
237
|
+
message: 'Internal server error',
|
|
238
|
+
code: '500',
|
|
239
|
+
},
|
|
240
|
+
}, 500);
|
|
241
|
+
};
|
|
242
|
+
```
|
|
243
|
+
|
|
244
|
+
---
|
|
245
|
+
|
|
246
|
+
## Response Helpers
|
|
247
|
+
|
|
248
|
+
```typescript
|
|
249
|
+
import type { Context } from 'hono';
|
|
250
|
+
|
|
251
|
+
export function successResponse<T>(
|
|
252
|
+
c: Context,
|
|
253
|
+
data: T,
|
|
254
|
+
status: 200 | 201 = 200
|
|
255
|
+
) {
|
|
256
|
+
return c.json({
|
|
257
|
+
success: true,
|
|
258
|
+
data,
|
|
259
|
+
meta: {
|
|
260
|
+
timestamp: new Date().toISOString(),
|
|
261
|
+
requestId: c.get('requestId'),
|
|
262
|
+
},
|
|
263
|
+
}, status);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
export function paginatedResponse<T>(
|
|
267
|
+
c: Context,
|
|
268
|
+
data: T[],
|
|
269
|
+
pagination: {
|
|
270
|
+
total: number;
|
|
271
|
+
page: number;
|
|
272
|
+
pageSize: number;
|
|
273
|
+
}
|
|
274
|
+
) {
|
|
275
|
+
return c.json({
|
|
276
|
+
success: true,
|
|
277
|
+
data,
|
|
278
|
+
pagination: {
|
|
279
|
+
...pagination,
|
|
280
|
+
totalPages: Math.ceil(pagination.total / pagination.pageSize),
|
|
281
|
+
},
|
|
282
|
+
});
|
|
283
|
+
}
|
|
284
|
+
```
|
|
285
|
+
|
|
286
|
+
---
|
|
287
|
+
|
|
288
|
+
## Testing with Hono
|
|
289
|
+
|
|
290
|
+
```typescript
|
|
291
|
+
import { describe, it, expect, beforeEach } from 'vitest';
|
|
292
|
+
import { app } from '../app';
|
|
293
|
+
|
|
294
|
+
describe('Item Routes', () => {
|
|
295
|
+
describe('GET /api/v1/items', () => {
|
|
296
|
+
it('should return all items', async () => {
|
|
297
|
+
const res = await app.request('/api/v1/items');
|
|
298
|
+
|
|
299
|
+
expect(res.status).toBe(200);
|
|
300
|
+
const body = await res.json();
|
|
301
|
+
expect(body.success).toBe(true);
|
|
302
|
+
expect(Array.isArray(body.data)).toBe(true);
|
|
303
|
+
});
|
|
304
|
+
});
|
|
305
|
+
|
|
306
|
+
describe('POST /api/v1/items', () => {
|
|
307
|
+
it('should create item with valid data', async () => {
|
|
308
|
+
const res = await app.request('/api/v1/items', {
|
|
309
|
+
method: 'POST',
|
|
310
|
+
headers: {
|
|
311
|
+
'Content-Type': 'application/json',
|
|
312
|
+
'Authorization': 'Bearer valid-token',
|
|
313
|
+
},
|
|
314
|
+
body: JSON.stringify({ title: 'Test Item' }),
|
|
315
|
+
});
|
|
316
|
+
|
|
317
|
+
expect(res.status).toBe(201);
|
|
318
|
+
const body = await res.json();
|
|
319
|
+
expect(body.data.title).toBe('Test Item');
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
it('should return 400 with invalid data', async () => {
|
|
323
|
+
const res = await app.request('/api/v1/items', {
|
|
324
|
+
method: 'POST',
|
|
325
|
+
headers: {
|
|
326
|
+
'Content-Type': 'application/json',
|
|
327
|
+
'Authorization': 'Bearer valid-token',
|
|
328
|
+
},
|
|
329
|
+
body: JSON.stringify({ title: '' }),
|
|
330
|
+
});
|
|
331
|
+
|
|
332
|
+
expect(res.status).toBe(400);
|
|
333
|
+
});
|
|
334
|
+
|
|
335
|
+
it('should return 401 without auth', async () => {
|
|
336
|
+
const res = await app.request('/api/v1/items', {
|
|
337
|
+
method: 'POST',
|
|
338
|
+
headers: { 'Content-Type': 'application/json' },
|
|
339
|
+
body: JSON.stringify({ title: 'Test' }),
|
|
340
|
+
});
|
|
341
|
+
|
|
342
|
+
expect(res.status).toBe(401);
|
|
343
|
+
});
|
|
344
|
+
});
|
|
345
|
+
});
|
|
346
|
+
```
|
|
347
|
+
|
|
348
|
+
---
|
|
349
|
+
|
|
350
|
+
## Project Structure
|
|
351
|
+
|
|
352
|
+
```
|
|
353
|
+
{API_PATH}/
|
|
354
|
+
├── routes/
|
|
355
|
+
│ ├── index.ts # Route aggregator
|
|
356
|
+
│ ├── items.ts # Item routes
|
|
357
|
+
│ └── users.ts # User routes
|
|
358
|
+
├── middleware/
|
|
359
|
+
│ ├── auth.ts # Authentication
|
|
360
|
+
│ ├── validate.ts # Validation helpers
|
|
361
|
+
│ └── error-handler.ts # Error handling
|
|
362
|
+
├── services/
|
|
363
|
+
│ └── items.service.ts # Business logic
|
|
364
|
+
├── schemas/
|
|
365
|
+
│ └── items.ts # Zod schemas
|
|
366
|
+
├── utils/
|
|
367
|
+
│ └── response.ts # Response helpers
|
|
368
|
+
└── app.ts # App entry point
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
---
|
|
372
|
+
|
|
373
|
+
## Best Practices
|
|
374
|
+
|
|
375
|
+
### Good
|
|
376
|
+
|
|
377
|
+
- Use `zValidator` for request validation
|
|
378
|
+
- Use `HTTPException` for error responses
|
|
379
|
+
- Use middleware composition
|
|
380
|
+
- Keep routes thin, business logic in services
|
|
381
|
+
- Use factory patterns for common CRUD
|
|
382
|
+
|
|
383
|
+
### Bad
|
|
384
|
+
|
|
385
|
+
- Inline validation logic
|
|
386
|
+
- Raw try-catch in every handler
|
|
387
|
+
- Business logic in route handlers
|
|
388
|
+
- Ignoring TypeScript types
|