balda-js 0.0.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.
Files changed (69) hide show
  1. package/.github/workflows/publish.yml +38 -0
  2. package/.husky/pre-commit +19 -0
  3. package/.nvmrc +1 -0
  4. package/LICENSE +21 -0
  5. package/README.md +46 -0
  6. package/deno.lock +2454 -0
  7. package/docs/README.md +135 -0
  8. package/docs/blog/authors.yml +6 -0
  9. package/docs/blog/tags.yml +4 -0
  10. package/docs/cli.md +109 -0
  11. package/docs/docs/core-concepts/controllers.md +393 -0
  12. package/docs/docs/core-concepts/middleware.md +302 -0
  13. package/docs/docs/core-concepts/request-response.md +486 -0
  14. package/docs/docs/core-concepts/routing.md +388 -0
  15. package/docs/docs/core-concepts/server.md +332 -0
  16. package/docs/docs/cron/overview.md +70 -0
  17. package/docs/docs/examples/rest-api.md +595 -0
  18. package/docs/docs/getting-started/configuration.md +168 -0
  19. package/docs/docs/getting-started/installation.md +125 -0
  20. package/docs/docs/getting-started/quick-start.md +273 -0
  21. package/docs/docs/intro.md +46 -0
  22. package/docs/docs/plugins/cookie.md +424 -0
  23. package/docs/docs/plugins/cors.md +295 -0
  24. package/docs/docs/plugins/file.md +382 -0
  25. package/docs/docs/plugins/helmet.md +388 -0
  26. package/docs/docs/plugins/json.md +338 -0
  27. package/docs/docs/plugins/log.md +592 -0
  28. package/docs/docs/plugins/overview.md +390 -0
  29. package/docs/docs/plugins/rate-limiter.md +347 -0
  30. package/docs/docs/plugins/static.md +352 -0
  31. package/docs/docs/plugins/swagger.md +411 -0
  32. package/docs/docs/plugins/urlencoded.md +76 -0
  33. package/docs/docs/testing/examples.md +384 -0
  34. package/docs/docs/testing/mock-server.md +311 -0
  35. package/docs/docs/testing/overview.md +76 -0
  36. package/docs/docusaurus.config.ts +144 -0
  37. package/docs/intro.md +78 -0
  38. package/docs/package.json +46 -0
  39. package/docs/sidebars.ts +72 -0
  40. package/docs/static/.nojekyll +0 -0
  41. package/docs/static/img/docusaurus-social-card.jpg +0 -0
  42. package/docs/static/img/docusaurus.png +0 -0
  43. package/docs/static/img/favicon.ico +0 -0
  44. package/docs/static/img/logo.svg +1 -0
  45. package/docs/static/img/undraw_docusaurus_mountain.svg +37 -0
  46. package/docs/static/img/undraw_docusaurus_react.svg +170 -0
  47. package/docs/static/img/undraw_docusaurus_tree.svg +40 -0
  48. package/docs/tsconfig.json +8 -0
  49. package/package.json +91 -0
  50. package/speed_test.sh +3 -0
  51. package/test/benchmark/index.ts +17 -0
  52. package/test/cli/cli.ts +7 -0
  53. package/test/commands/test.ts +42 -0
  54. package/test/controllers/file_upload.ts +29 -0
  55. package/test/controllers/urlencoded.ts +13 -0
  56. package/test/controllers/users.ts +111 -0
  57. package/test/cron/index.ts +6 -0
  58. package/test/cron/test_cron.ts +8 -0
  59. package/test/cron/test_cron_imported.ts +8 -0
  60. package/test/native_env.ts +16 -0
  61. package/test/resources/test.txt +1 -0
  62. package/test/server/index.ts +3 -0
  63. package/test/server/instance.ts +63 -0
  64. package/test/suite/upload.test.ts +23 -0
  65. package/test/suite/urlencoded.test.ts +23 -0
  66. package/test/suite/users.test.ts +76 -0
  67. package/todo.md +9 -0
  68. package/tsconfig.json +24 -0
  69. package/vitest.config.ts +17 -0
@@ -0,0 +1,411 @@
1
+ ---
2
+ sidebar_position: 9
3
+ ---
4
+
5
+ # Swagger Plugin
6
+
7
+ The Swagger plugin automatically generates OpenAPI 3.0 documentation for your Balda.js API. It provides interactive documentation with three UI options: Swagger UI, ReDoc, and RapiDoc.
8
+
9
+ ## Features
10
+
11
+ - **Automatic Route Discovery**: Automatically discovers and documents all your routes
12
+ - **Multiple UI Options**: Choose between Swagger UI, ReDoc, or RapiDoc
13
+ - **Type Integration**: Uses your validation schemas to generate accurate request/response documentation
14
+ - **Security Support**: Document authentication schemes and security requirements
15
+ - **Custom Models**: Define reusable data models for your API
16
+
17
+ ## Global Configuration
18
+
19
+ ### Basic Setup
20
+
21
+ ```typescript
22
+ import { Server } from 'balda-js';
23
+
24
+ const server = new Server({
25
+ port: 3000,
26
+ swagger: {
27
+ type: "standard", // "standard" | "redoc" | "rapidoc"
28
+ path: "/docs",
29
+ title: "My API Documentation",
30
+ description: "API documentation for my application",
31
+ version: "1.0.0",
32
+ servers: ["http://localhost:3000"]
33
+ }
34
+ });
35
+ ```
36
+
37
+ ### Advanced Configuration
38
+
39
+ ```typescript
40
+ const server = new Server({
41
+ port: 3000,
42
+ swagger: {
43
+ type: "standard",
44
+ path: "/api-docs",
45
+ title: "E-Commerce API",
46
+ description: "Complete API for our e-commerce platform",
47
+ version: "2.1.0",
48
+ servers: [
49
+ "http://localhost:3000",
50
+ "https://api.staging.example.com",
51
+ "https://api.example.com"
52
+ ],
53
+ security: [
54
+ { bearer: [] }
55
+ ],
56
+ securitySchemes: {
57
+ bearer: {
58
+ type: "http",
59
+ scheme: "bearer",
60
+ bearerFormat: "JWT"
61
+ },
62
+ apiKey: {
63
+ type: "apiKey",
64
+ name: "X-API-Key",
65
+ in: "header"
66
+ }
67
+ },
68
+ tags: {
69
+ users: {
70
+ description: "User management operations"
71
+ },
72
+ products: {
73
+ description: "Product catalog operations"
74
+ },
75
+ orders: {
76
+ description: "Order processing operations"
77
+ }
78
+ },
79
+ models: {
80
+ User: {
81
+ type: "object",
82
+ properties: {
83
+ id: { type: "string", format: "uuid" },
84
+ email: { type: "string", format: "email" },
85
+ name: { type: "string" },
86
+ createdAt: { type: "string", format: "date-time" }
87
+ },
88
+ required: ["email", "name"]
89
+ },
90
+ Product: {
91
+ type: "object",
92
+ properties: {
93
+ id: { type: "string" },
94
+ name: { type: "string" },
95
+ price: { type: "number" },
96
+ category: { type: "string" }
97
+ },
98
+ required: ["name", "price"]
99
+ }
100
+ }
101
+ }
102
+ });
103
+ ```
104
+
105
+ ## Route-Level Documentation
106
+
107
+ ### Basic Route Documentation
108
+
109
+ ```typescript
110
+ import { controller, get, post } from 'balda-js';
111
+ import { Request, Response } from 'balda-js';
112
+
113
+ @controller('/users')
114
+ export class UsersController {
115
+ @get('/', {
116
+ swagger: {
117
+ name: "Get All Users",
118
+ description: "Retrieve a list of all users",
119
+ service: "users",
120
+ responses: {
121
+ "200": {
122
+ type: "array",
123
+ items: { $ref: "#/components/schemas/User" }
124
+ }
125
+ }
126
+ }
127
+ })
128
+ async getAllUsers(req: Request, res: Response) {
129
+ const users = await getUsers();
130
+ res.json(users);
131
+ }
132
+
133
+ @post('/', {
134
+ swagger: {
135
+ name: "Create User",
136
+ description: "Create a new user account",
137
+ service: "users",
138
+ requestBody: {
139
+ type: "object",
140
+ properties: {
141
+ email: { type: "string", format: "email" },
142
+ name: { type: "string" },
143
+ password: { type: "string", minLength: 8 }
144
+ },
145
+ required: ["email", "name", "password"]
146
+ },
147
+ responses: {
148
+ "201": {
149
+ type: "object",
150
+ properties: {
151
+ user: { $ref: "#/components/schemas/User" },
152
+ message: { type: "string" }
153
+ }
154
+ },
155
+ "400": {
156
+ type: "object",
157
+ properties: {
158
+ error: { type: "string" },
159
+ details: { type: "array", items: { type: "string" } }
160
+ }
161
+ }
162
+ }
163
+ }
164
+ })
165
+ async createUser(req: Request, res: Response) {
166
+ const user = await createUser(req.body);
167
+ res.created({ user, message: "User created successfully" });
168
+ }
169
+ }
170
+ ```
171
+
172
+ ### Path Parameters
173
+
174
+ ```typescript
175
+ @get('/:id', {
176
+ swagger: {
177
+ name: "Get User by ID",
178
+ description: "Retrieve a specific user by their ID",
179
+ service: "users",
180
+ params: {
181
+ type: "object",
182
+ properties: {
183
+ id: { type: "string", format: "uuid" }
184
+ }
185
+ },
186
+ responses: {
187
+ "200": { $ref: "#/components/schemas/User" },
188
+ "404": {
189
+ type: "object",
190
+ properties: {
191
+ error: { type: "string" }
192
+ }
193
+ }
194
+ }
195
+ }
196
+ })
197
+ async getUserById(req: Request, res: Response) {
198
+ const { id } = req.params;
199
+ const user = await getUserById(id);
200
+ if (!user) {
201
+ return res.notFound({ error: "User not found" });
202
+ }
203
+ res.json(user);
204
+ }
205
+ ```
206
+
207
+ ### Query Parameters
208
+
209
+ ```typescript
210
+ @get('/search', {
211
+ swagger: {
212
+ name: "Search Users",
213
+ description: "Search users with filters",
214
+ service: "users",
215
+ query: {
216
+ type: "object",
217
+ properties: {
218
+ q: { type: "string", description: "Search query" },
219
+ limit: { type: "number", minimum: 1, maximum: 100, default: 10 },
220
+ offset: { type: "number", minimum: 0, default: 0 },
221
+ sort: { type: "string", enum: ["name", "email", "createdAt"] }
222
+ },
223
+ required: ["q"]
224
+ },
225
+ responses: {
226
+ "200": {
227
+ type: "object",
228
+ properties: {
229
+ users: {
230
+ type: "array",
231
+ items: { $ref: "#/components/schemas/User" }
232
+ },
233
+ total: { type: "number" },
234
+ limit: { type: "number" },
235
+ offset: { type: "number" }
236
+ }
237
+ }
238
+ }
239
+ }
240
+ })
241
+ async searchUsers(req: Request, res: Response) {
242
+ const { q, limit = 10, offset = 0, sort } = req.query;
243
+ const result = await searchUsers({ q, limit, offset, sort });
244
+ res.json(result);
245
+ }
246
+ ```
247
+
248
+ ### Security Requirements
249
+
250
+ ```typescript
251
+ @post('/profile', {
252
+ swagger: {
253
+ name: "Update Profile",
254
+ description: "Update user profile (requires authentication)",
255
+ service: "users",
256
+ security: [
257
+ { type: "bearer", bearerFormat: "JWT" }
258
+ ],
259
+ requestBody: {
260
+ type: "object",
261
+ properties: {
262
+ name: { type: "string" },
263
+ bio: { type: "string" }
264
+ }
265
+ },
266
+ responses: {
267
+ "200": { $ref: "#/components/schemas/User" },
268
+ "401": {
269
+ type: "object",
270
+ properties: {
271
+ error: { type: "string" }
272
+ }
273
+ }
274
+ }
275
+ }
276
+ })
277
+ async updateProfile(req: Request, res: Response) {
278
+ // Implementation with authentication
279
+ const user = await updateUserProfile(req.user.id, req.body);
280
+ res.json(user);
281
+ }
282
+ ```
283
+
284
+ ### File Upload Documentation
285
+
286
+ ```typescript
287
+ @post('/avatar', {
288
+ swagger: {
289
+ name: "Upload Avatar",
290
+ description: "Upload user avatar image",
291
+ service: "users",
292
+ bodyType: "form-data",
293
+ requestBody: {
294
+ type: "object",
295
+ properties: {
296
+ avatar: {
297
+ type: "string",
298
+ format: "binary",
299
+ description: "Avatar image file"
300
+ }
301
+ },
302
+ required: ["avatar"]
303
+ },
304
+ responses: {
305
+ "200": {
306
+ type: "object",
307
+ properties: {
308
+ url: { type: "string", format: "uri" },
309
+ message: { type: "string" }
310
+ }
311
+ }
312
+ }
313
+ }
314
+ })
315
+ async uploadAvatar(req: Request, res: Response) {
316
+ const file = req.files.avatar;
317
+ const url = await uploadFile(file);
318
+ res.json({ url, message: "Avatar uploaded successfully" });
319
+ }
320
+ ```
321
+
322
+ ### Excluding Routes
323
+
324
+ ```typescript
325
+ @get('/internal/health', {
326
+ swagger: {
327
+ excludeFromSwagger: true
328
+ }
329
+ })
330
+ async healthCheck(req: Request, res: Response) {
331
+ res.json({ status: "ok" });
332
+ }
333
+ ```
334
+
335
+ ## UI Options
336
+
337
+ ### Swagger UI (Standard)
338
+
339
+ ```typescript
340
+ swagger: {
341
+ type: "standard",
342
+ path: "/docs"
343
+ }
344
+ ```
345
+
346
+ ### ReDoc
347
+
348
+ ```typescript
349
+ swagger: {
350
+ type: "redoc",
351
+ path: "/docs"
352
+ }
353
+ ```
354
+
355
+ ### RapiDoc
356
+
357
+ ```typescript
358
+ swagger: {
359
+ type: "rapidoc",
360
+ path: "/docs"
361
+ }
362
+ ```
363
+
364
+ ## Integration with Validation
365
+
366
+ Balda.js automatically integrates your validation schemas with Swagger documentation:
367
+
368
+ ```typescript
369
+ import { Type } from '@sinclair/typebox';
370
+
371
+ const CreateUserSchema = Type.Object({
372
+ email: Type.String({ format: 'email' }),
373
+ name: Type.String({ minLength: 1 }),
374
+ password: Type.String({ minLength: 8 })
375
+ });
376
+
377
+ @post('/', {
378
+ validate: { body: CreateUserSchema },
379
+ swagger: {
380
+ name: "Create User",
381
+ requestBody: CreateUserSchema,
382
+ responses: {
383
+ "201": { $ref: "#/components/schemas/User" },
384
+ "400": { $ref: "#/components/schemas/ValidationError" }
385
+ }
386
+ }
387
+ })
388
+ async createUser(req: Request, res: Response) {
389
+ // The validation schema automatically becomes the OpenAPI schema
390
+ const user = await createUser(req.body);
391
+ res.created(user);
392
+ }
393
+ ```
394
+
395
+ ## Accessing Documentation
396
+
397
+ Once configured, your API documentation will be available at:
398
+
399
+ - **Swagger UI**: `http://localhost:3000/docs`
400
+ - **OpenAPI JSON**: `http://localhost:3000/docs/json`
401
+
402
+ The JSON specification can be used with other OpenAPI tools or imported into external documentation systems.
403
+
404
+ ## Best Practices
405
+
406
+ 1. **Use Descriptive Names**: Give your routes meaningful names and descriptions
407
+ 2. **Group Related Routes**: Use the `service` property to group related endpoints
408
+ 3. **Document All Responses**: Include success and error responses
409
+ 4. **Use Reusable Models**: Define models in the global configuration for reuse
410
+ 5. **Keep Security Simple**: Use standard security schemes when possible
411
+ 6. **Test Your Documentation**: Use the generated documentation to test your API
@@ -0,0 +1,76 @@
1
+ ---
2
+ sidebar_position: 3
3
+ ---
4
+
5
+ # URL Encoded Plugin
6
+
7
+ The **URL Encoded** plugin parses `application/x-www-form-urlencoded` request bodies and exposes the parsed data on `req.body` for easy access.
8
+
9
+ ## Features
10
+
11
+ - Parses standard HTML form submissions
12
+ - Supports nested objects and arrays
13
+ - Configurable size limit
14
+ - Works across Node.js, Bun, and Deno
15
+
16
+ ## Basic Usage
17
+
18
+ ```typescript
19
+ import { Server } from 'balda-js';
20
+
21
+ const server = new Server({
22
+ plugins: {
23
+ urlencoded: true // Enable with default options
24
+ }
25
+ });
26
+ ```
27
+
28
+ ## Custom Configuration
29
+
30
+ ```typescript
31
+ const server = new Server({
32
+ plugins: {
33
+ urlencoded: {
34
+ limit: '2mb', // Maximum body size
35
+ extended: true // Use qs library for rich objects (default: true)
36
+ }
37
+ }
38
+ });
39
+ ```
40
+
41
+ ## Disabling the Plugin
42
+
43
+ ```typescript
44
+ const server = new Server({
45
+ plugins: {
46
+ urlencoded: false // Disable entirely
47
+ }
48
+ });
49
+ ```
50
+
51
+ ## Options Reference
52
+
53
+ | Option | Type | Default | Description |
54
+ |----------|---------|---------|-----------------------------------------------|
55
+ | `limit` | string | `1mb` | Maximum allowed body size before rejection |
56
+ | `extended` | boolean | `true` | Use rich object parsing (qs) if `true`, or the built-in querystring parser if `false` |
57
+
58
+ ## Example Route
59
+
60
+ ```typescript
61
+ import { post, Server } from 'balda-js';
62
+
63
+ @post('/submit')
64
+ async handleSubmit(req, res) {
65
+ const data = req.body; // Parsed form data
66
+ res.json({ received: data });
67
+ }
68
+
69
+ const server = new Server({
70
+ plugins: { urlencoded: true }
71
+ });
72
+
73
+ server.listen();
74
+ ```
75
+
76
+ The URL Encoded plugin makes handling traditional HTML form submissions in Balda.js straightforward and type-safe.