create-buntok 0.1.0 → 0.1.3
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/package.json +1 -1
- package/templates/.vscode/settings.json +4 -2
- package/templates/README.md +313 -0
- package/templates/package.json +2 -1
- package/templates/src/db/index.ts +1 -1
- package/templates/src/db/schemas/index.ts +3 -0
- package/templates/src/index.ts +1 -5
- package/templates/tsconfig.json +5 -1
package/package.json
CHANGED
|
@@ -1,8 +1,10 @@
|
|
|
1
1
|
{
|
|
2
2
|
"editor.formatOnSave": true,
|
|
3
3
|
"editor.defaultFormatter": "biomejs.biome",
|
|
4
|
-
"editor.
|
|
5
|
-
|
|
4
|
+
"editor.codeActionsOnSave": {
|
|
5
|
+
"source.organizeImports.biome": "explicit",
|
|
6
|
+
"quickfix.biome": "explicit"
|
|
7
|
+
},
|
|
6
8
|
"[typescript]": {
|
|
7
9
|
"editor.defaultFormatter": "biomejs.biome"
|
|
8
10
|
},
|
|
@@ -0,0 +1,313 @@
|
|
|
1
|
+
# Buntok Project
|
|
2
|
+
|
|
3
|
+
> High-performance web framework for [Bun](https://bun.sh) runtime
|
|
4
|
+
|
|
5
|
+
## Getting Started
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
# Development
|
|
9
|
+
bun run dev
|
|
10
|
+
|
|
11
|
+
# Production
|
|
12
|
+
bun run start
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
Server starts on port `3000` (or `PORT` env var).
|
|
16
|
+
|
|
17
|
+
## Project Structure
|
|
18
|
+
|
|
19
|
+
```
|
|
20
|
+
src/
|
|
21
|
+
├── controllers/ # Request handlers
|
|
22
|
+
├── db/
|
|
23
|
+
│ └── schemas/ # Drizzle ORM schemas
|
|
24
|
+
├── repositories/ # Database queries
|
|
25
|
+
├── routes/ # Route definitions
|
|
26
|
+
├── services/ # Business logic
|
|
27
|
+
└── index.ts # Entry point
|
|
28
|
+
```
|
|
29
|
+
|
|
30
|
+
## Code Generation
|
|
31
|
+
|
|
32
|
+
Generate CRUD files for an entity:
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
# Generate all files
|
|
36
|
+
bunx buntok create user
|
|
37
|
+
|
|
38
|
+
# Generate specific files
|
|
39
|
+
bunx buntok create user --schema
|
|
40
|
+
bunx buntok create user --repo --service
|
|
41
|
+
bunx buntok create user --controller
|
|
42
|
+
bunx buntok create user --route
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
### What Gets Generated
|
|
46
|
+
|
|
47
|
+
| File | Description |
|
|
48
|
+
|------|-------------|
|
|
49
|
+
| `src/db/schemas/user.ts` | Drizzle schema |
|
|
50
|
+
| `src/repositories/user.repository.ts` | Database queries |
|
|
51
|
+
| `src/services/user.service.ts` | Business logic |
|
|
52
|
+
| `src/controllers/user.controller.ts` | Request handlers |
|
|
53
|
+
| `src/routes/user.routes.ts` | Route definitions + DI registration |
|
|
54
|
+
|
|
55
|
+
### After Generation
|
|
56
|
+
|
|
57
|
+
1. Add columns to schema in `src/db/schemas/user.ts`
|
|
58
|
+
2. Run migrations:
|
|
59
|
+
```bash
|
|
60
|
+
bun run db:push # Push schema to database
|
|
61
|
+
bun run db:generate # Generate migration files
|
|
62
|
+
bun run db:migrate # Run migrations
|
|
63
|
+
bun run db:studio # Open Drizzle Studio
|
|
64
|
+
```
|
|
65
|
+
|
|
66
|
+
3. Register routes in `src/index.ts`:
|
|
67
|
+
```ts
|
|
68
|
+
import { registerUserRoutes } from "@/routes/user.routes";
|
|
69
|
+
|
|
70
|
+
registerUserRoutes(app);
|
|
71
|
+
```
|
|
72
|
+
|
|
73
|
+
## Basic Usage
|
|
74
|
+
|
|
75
|
+
### Simple Route
|
|
76
|
+
|
|
77
|
+
```ts
|
|
78
|
+
import { App } from "buntok";
|
|
79
|
+
|
|
80
|
+
const app = new App();
|
|
81
|
+
|
|
82
|
+
app.get("/", (ctx) => {
|
|
83
|
+
return ctx.json({ message: "Hello!" });
|
|
84
|
+
});
|
|
85
|
+
```
|
|
86
|
+
|
|
87
|
+
### Route with Params
|
|
88
|
+
|
|
89
|
+
```ts
|
|
90
|
+
app.get("/users/:id", (ctx) => {
|
|
91
|
+
const { id } = ctx.params;
|
|
92
|
+
return ctx.json({ id });
|
|
93
|
+
});
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
### POST with Body
|
|
97
|
+
|
|
98
|
+
```ts
|
|
99
|
+
app.post("/users", async (ctx) => {
|
|
100
|
+
const body = await ctx.body<{ name: string }>();
|
|
101
|
+
return ctx.json({ created: true, data: body }, 201);
|
|
102
|
+
});
|
|
103
|
+
```
|
|
104
|
+
|
|
105
|
+
### QUERY (Complex Queries)
|
|
106
|
+
|
|
107
|
+
Like GET but with body support - idempotent and cacheable:
|
|
108
|
+
|
|
109
|
+
```ts
|
|
110
|
+
app.query("/search", async (ctx) => {
|
|
111
|
+
const filters = await ctx.body<{
|
|
112
|
+
query: string;
|
|
113
|
+
limit: number;
|
|
114
|
+
sort: string;
|
|
115
|
+
}>();
|
|
116
|
+
|
|
117
|
+
const results = await db.search(filters);
|
|
118
|
+
return ctx.json({ data: results });
|
|
119
|
+
});
|
|
120
|
+
```
|
|
121
|
+
|
|
122
|
+
**Why QUERY over GET/POST?**
|
|
123
|
+
- Body allowed (unlike GET)
|
|
124
|
+
- Idempotent & cacheable (unlike POST)
|
|
125
|
+
- Safe for complex queries
|
|
126
|
+
|
|
127
|
+
### Route Group
|
|
128
|
+
|
|
129
|
+
```ts
|
|
130
|
+
const api = app.group("/api");
|
|
131
|
+
|
|
132
|
+
api.get("/users", getUsers);
|
|
133
|
+
api.post("/users", createUser);
|
|
134
|
+
```
|
|
135
|
+
|
|
136
|
+
### Middleware
|
|
137
|
+
|
|
138
|
+
```ts
|
|
139
|
+
// Global middleware
|
|
140
|
+
app.use(async (ctx, next) => {
|
|
141
|
+
console.log(`→ ${ctx.request.method}`);
|
|
142
|
+
const response = await next();
|
|
143
|
+
console.log(`← ${response.status}`);
|
|
144
|
+
return response;
|
|
145
|
+
});
|
|
146
|
+
|
|
147
|
+
// Per-route middleware
|
|
148
|
+
app.get("/admin", authMiddleware, (ctx) => {
|
|
149
|
+
return ctx.json({ message: "Admin only" });
|
|
150
|
+
});
|
|
151
|
+
```
|
|
152
|
+
|
|
153
|
+
### Dependency Injection
|
|
154
|
+
|
|
155
|
+
```ts
|
|
156
|
+
// Register
|
|
157
|
+
app.set("userService", new UserService());
|
|
158
|
+
|
|
159
|
+
// Access in handler
|
|
160
|
+
app.get("/users", (ctx) => {
|
|
161
|
+
const users = ctx.di.userService.getAll();
|
|
162
|
+
return ctx.json({ data: users });
|
|
163
|
+
});
|
|
164
|
+
```
|
|
165
|
+
|
|
166
|
+
## Built-in Middlewares
|
|
167
|
+
|
|
168
|
+
### CORS
|
|
169
|
+
|
|
170
|
+
```ts
|
|
171
|
+
import { cors } from "buntok";
|
|
172
|
+
|
|
173
|
+
app.use(cors({ origin: "*" }));
|
|
174
|
+
```
|
|
175
|
+
|
|
176
|
+
### Rate Limiter
|
|
177
|
+
|
|
178
|
+
```ts
|
|
179
|
+
import { rateLimiter } from "buntok";
|
|
180
|
+
|
|
181
|
+
app.use(rateLimiter({ max: 100, windowMs: 60000 }));
|
|
182
|
+
```
|
|
183
|
+
|
|
184
|
+
### Request ID
|
|
185
|
+
|
|
186
|
+
```ts
|
|
187
|
+
import { requestId } from "buntok";
|
|
188
|
+
|
|
189
|
+
app.use(requestId());
|
|
190
|
+
|
|
191
|
+
// Access: ctx.store.requestId
|
|
192
|
+
```
|
|
193
|
+
|
|
194
|
+
### Response Time
|
|
195
|
+
|
|
196
|
+
```ts
|
|
197
|
+
import { responseTime } from "buntok";
|
|
198
|
+
|
|
199
|
+
app.use(responseTime());
|
|
200
|
+
|
|
201
|
+
// Access: ctx.store.responseTime
|
|
202
|
+
```
|
|
203
|
+
|
|
204
|
+
### Health Check
|
|
205
|
+
|
|
206
|
+
```ts
|
|
207
|
+
import { healthCheck } from "buntok";
|
|
208
|
+
|
|
209
|
+
app.use(healthCheck({
|
|
210
|
+
path: "/health",
|
|
211
|
+
checks: {
|
|
212
|
+
database: async () => {
|
|
213
|
+
await db.query("SELECT 1");
|
|
214
|
+
return { status: "ok" };
|
|
215
|
+
},
|
|
216
|
+
},
|
|
217
|
+
}));
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
## Context Methods
|
|
221
|
+
|
|
222
|
+
```ts
|
|
223
|
+
app.get("/example", async (ctx) => {
|
|
224
|
+
// Body
|
|
225
|
+
const body = await ctx.body<{ name: string }>();
|
|
226
|
+
|
|
227
|
+
// Params
|
|
228
|
+
const id = ctx.params.id;
|
|
229
|
+
|
|
230
|
+
// JSON response
|
|
231
|
+
return ctx.json({ data: "ok" });
|
|
232
|
+
|
|
233
|
+
// Text response
|
|
234
|
+
return ctx.text("Hello");
|
|
235
|
+
|
|
236
|
+
// HTML response
|
|
237
|
+
return ctx.html("<h1>Hello</h1>");
|
|
238
|
+
|
|
239
|
+
// Status only
|
|
240
|
+
return ctx.status(204);
|
|
241
|
+
|
|
242
|
+
// Redirect
|
|
243
|
+
return ctx.redirect("/login", 302);
|
|
244
|
+
|
|
245
|
+
// Cookies
|
|
246
|
+
const token = ctx.getCookie("token");
|
|
247
|
+
});
|
|
248
|
+
```
|
|
249
|
+
|
|
250
|
+
## Error Handling
|
|
251
|
+
|
|
252
|
+
```ts
|
|
253
|
+
import { NotFoundError, BadRequestError } from "buntok";
|
|
254
|
+
|
|
255
|
+
// Throw errors - automatically returns proper status code
|
|
256
|
+
throw new NotFoundError("User not found"); // 404
|
|
257
|
+
throw new BadRequestError("Invalid data"); // 400
|
|
258
|
+
|
|
259
|
+
// Or use asyncHandler in controllers (auto-catches errors)
|
|
260
|
+
import { asyncHandler } from "buntok";
|
|
261
|
+
|
|
262
|
+
export class UserController {
|
|
263
|
+
getAll = asyncHandler(async (ctx) => {
|
|
264
|
+
const users = await this.service.getAll();
|
|
265
|
+
return ctx.json({ data: users });
|
|
266
|
+
});
|
|
267
|
+
}
|
|
268
|
+
```
|
|
269
|
+
|
|
270
|
+
## Database Commands
|
|
271
|
+
|
|
272
|
+
```bash
|
|
273
|
+
bun run db:push # Push schema to database
|
|
274
|
+
bun run db:generate # Generate migration files
|
|
275
|
+
bun run db:migrate # Run migrations
|
|
276
|
+
bun run db:studio # Open Drizzle Studio
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
## Configuration
|
|
280
|
+
|
|
281
|
+
### Environment Variables
|
|
282
|
+
|
|
283
|
+
```bash
|
|
284
|
+
# .env
|
|
285
|
+
DATABASE_URL=postgresql://user:password@localhost:5432/mydb
|
|
286
|
+
PORT=3000
|
|
287
|
+
NODE_ENV=development
|
|
288
|
+
```
|
|
289
|
+
|
|
290
|
+
### tsconfig.json
|
|
291
|
+
|
|
292
|
+
Path aliases are configured:
|
|
293
|
+
```json
|
|
294
|
+
{
|
|
295
|
+
"paths": {
|
|
296
|
+
"@/*": ["./src/*"]
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
```
|
|
300
|
+
|
|
301
|
+
Use `@/` for imports:
|
|
302
|
+
```ts
|
|
303
|
+
import { UserService } from "@/services/user.service";
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Learn More
|
|
307
|
+
|
|
308
|
+
- [Buntok Documentation](https://www.npmjs.com/package/buntok)
|
|
309
|
+
- [Bun Documentation](https://bun.sh/docs)
|
|
310
|
+
|
|
311
|
+
## License
|
|
312
|
+
|
|
313
|
+
MIT
|
package/templates/package.json
CHANGED
|
@@ -15,11 +15,12 @@
|
|
|
15
15
|
},
|
|
16
16
|
"dependencies": {
|
|
17
17
|
"buntok": "latest",
|
|
18
|
-
"drizzle-orm": "^0.
|
|
18
|
+
"drizzle-orm": "^0.45.2"
|
|
19
19
|
},
|
|
20
20
|
"devDependencies": {
|
|
21
21
|
"@biomejs/biome": "2.5.3",
|
|
22
22
|
"@types/bun": "latest",
|
|
23
|
+
"@types/node": "^22",
|
|
23
24
|
"drizzle-kit": "^0.30.0",
|
|
24
25
|
"typescript": "^5"
|
|
25
26
|
}
|
package/templates/src/index.ts
CHANGED
|
@@ -3,9 +3,5 @@ import { App } from "buntok";
|
|
|
3
3
|
const app = new App();
|
|
4
4
|
|
|
5
5
|
app.get("/", (ctx) => {
|
|
6
|
-
return ctx.json({ message: "Welcome to
|
|
7
|
-
});
|
|
8
|
-
|
|
9
|
-
app.listen(3000, () => {
|
|
10
|
-
console.log("Server running on http://localhost:3000");
|
|
6
|
+
return ctx.json({ message: "Welcome to BUNTOK!" });
|
|
11
7
|
});
|
package/templates/tsconfig.json
CHANGED