@riligar/agents-kit 1.10.0 → 1.12.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.
Files changed (24) hide show
  1. package/.agent/skills/riligar-business-startup/SKILL.md +70 -0
  2. package/.agent/skills/{riligar-business-startup-analyst/SKILL.md → riligar-business-startup/references/business-case.md} +24 -251
  3. package/.agent/skills/riligar-business-startup/references/financial-model.md +215 -0
  4. package/.agent/skills/riligar-business-startup/references/market-analysis.md +151 -0
  5. package/.agent/skills/riligar-dev-backend/SKILL.md +122 -87
  6. package/.agent/skills/riligar-dev-backend/references/elysia-basics.md +224 -0
  7. package/.agent/skills/riligar-dev-backend/references/elysia-lifecycle.md +268 -0
  8. package/.agent/skills/riligar-dev-backend/references/elysia-patterns.md +324 -0
  9. package/.agent/skills/riligar-dev-backend/references/elysia-plugins.md +202 -0
  10. package/.agent/skills/riligar-dev-backend/references/elysia-validation.md +247 -0
  11. package/.agent/skills/riligar-dev-clean-code/SKILL.md +81 -133
  12. package/package.json +1 -1
  13. package/.agent/skills/riligar-business-startup-financial/SKILL.md +0 -391
  14. package/.agent/skills/riligar-business-startup-market/SKILL.md +0 -265
  15. package/.agent/skills/riligar-dev-backend/api-style.md +0 -42
  16. package/.agent/skills/riligar-dev-backend/auth.md +0 -24
  17. package/.agent/skills/riligar-dev-backend/documentation.md +0 -26
  18. package/.agent/skills/riligar-dev-backend/graphql.md +0 -41
  19. package/.agent/skills/riligar-dev-backend/rate-limiting.md +0 -31
  20. package/.agent/skills/riligar-dev-backend/response.md +0 -37
  21. package/.agent/skills/riligar-dev-backend/rest.md +0 -40
  22. package/.agent/skills/riligar-dev-backend/security-testing.md +0 -122
  23. package/.agent/skills/riligar-dev-backend/trpc.md +0 -41
  24. package/.agent/skills/riligar-dev-backend/versioning.md +0 -22
@@ -0,0 +1,224 @@
1
+ # Elysia Basics
2
+
3
+ ## Installation
4
+
5
+ ```bash
6
+ bun add elysia
7
+ ```
8
+
9
+ ## Minimal Server
10
+
11
+ ```javascript
12
+ import { Elysia } from 'elysia'
13
+
14
+ const app = new Elysia()
15
+ .get('/', () => 'Hello World')
16
+ .listen(3000)
17
+
18
+ console.log(`Server running at ${app.server?.url}`)
19
+ ```
20
+
21
+ ## HTTP Methods
22
+
23
+ ```javascript
24
+ const app = new Elysia()
25
+ .get('/users', () => getUsers()) // Read
26
+ .post('/users', ({ body }) => create(body)) // Create
27
+ .put('/users/:id', ({ params, body }) => replace(params.id, body)) // Replace
28
+ .patch('/users/:id', ({ params, body }) => update(params.id, body)) // Update
29
+ .delete('/users/:id', ({ params }) => remove(params.id)) // Delete
30
+ ```
31
+
32
+ ## Context Object
33
+
34
+ Every handler receives a context object with request data:
35
+
36
+ ```javascript
37
+ app.post('/example', (ctx) => {
38
+ // Request data
39
+ ctx.body // Parsed request body
40
+ ctx.query // Query string (?key=value)
41
+ ctx.params // Path parameters (/:id)
42
+ ctx.headers // Request headers
43
+ ctx.cookie // Cookies
44
+ ctx.request // Raw Request object
45
+ ctx.path // Request pathname
46
+
47
+ // Response helpers
48
+ ctx.set.status = 201 // Set status code
49
+ ctx.set.headers['X-Custom'] = 'value' // Set header
50
+ ctx.redirect('/other') // Redirect
51
+
52
+ return { success: true }
53
+ })
54
+ ```
55
+
56
+ ## Destructuring Context
57
+
58
+ ```javascript
59
+ // Clean handler with destructuring
60
+ app.post('/users', ({ body, set }) => {
61
+ const user = createUser(body)
62
+ set.status = 201
63
+ return user
64
+ })
65
+
66
+ app.get('/users/:id', ({ params }) => {
67
+ return getUserById(params.id)
68
+ })
69
+
70
+ app.get('/search', ({ query }) => {
71
+ return search(query.q, query.limit)
72
+ })
73
+ ```
74
+
75
+ ## Response Types
76
+
77
+ ### JSON (default)
78
+
79
+ ```javascript
80
+ app.get('/json', () => {
81
+ return { message: 'Hello' } // Automatically JSON
82
+ })
83
+ ```
84
+
85
+ ### String
86
+
87
+ ```javascript
88
+ app.get('/text', () => {
89
+ return 'Plain text response'
90
+ })
91
+ ```
92
+
93
+ ### Status Codes
94
+
95
+ ```javascript
96
+ app.post('/users', ({ body, set }) => {
97
+ const user = createUser(body)
98
+ set.status = 201 // Created
99
+ return user
100
+ })
101
+
102
+ app.get('/users/:id', ({ params, set }) => {
103
+ const user = findUser(params.id)
104
+ if (!user) {
105
+ set.status = 404
106
+ return { error: 'User not found' }
107
+ }
108
+ return user
109
+ })
110
+ ```
111
+
112
+ ### Redirect
113
+
114
+ ```javascript
115
+ app.get('/old-path', ({ redirect }) => {
116
+ return redirect('/new-path')
117
+ })
118
+ ```
119
+
120
+ ## Route Parameters
121
+
122
+ ### Path Parameters
123
+
124
+ ```javascript
125
+ // Single parameter
126
+ app.get('/users/:id', ({ params }) => {
127
+ return getUserById(params.id)
128
+ })
129
+
130
+ // Multiple parameters
131
+ app.get('/users/:userId/posts/:postId', ({ params }) => {
132
+ return getPost(params.userId, params.postId)
133
+ })
134
+ ```
135
+
136
+ ### Query Parameters
137
+
138
+ ```javascript
139
+ // GET /search?q=hello&limit=10
140
+ app.get('/search', ({ query }) => {
141
+ const { q, limit = '10' } = query
142
+ return search(q, parseInt(limit))
143
+ })
144
+ ```
145
+
146
+ ## Headers
147
+
148
+ ### Reading Headers
149
+
150
+ ```javascript
151
+ app.get('/protected', ({ headers, set }) => {
152
+ const token = headers.authorization
153
+ if (!token) {
154
+ set.status = 401
155
+ return { error: 'Unauthorized' }
156
+ }
157
+ return { message: 'Welcome' }
158
+ })
159
+ ```
160
+
161
+ ### Setting Headers
162
+
163
+ ```javascript
164
+ app.get('/api/data', ({ set }) => {
165
+ set.headers['X-Custom-Header'] = 'value'
166
+ set.headers['Cache-Control'] = 'max-age=3600'
167
+ return { data: 'example' }
168
+ })
169
+ ```
170
+
171
+ ## Cookies
172
+
173
+ ```javascript
174
+ app.get('/set-cookie', ({ cookie }) => {
175
+ cookie.session.set({
176
+ value: 'abc123',
177
+ httpOnly: true,
178
+ maxAge: 60 * 60 * 24 // 1 day
179
+ })
180
+ return { message: 'Cookie set' }
181
+ })
182
+
183
+ app.get('/read-cookie', ({ cookie }) => {
184
+ return { session: cookie.session.value }
185
+ })
186
+ ```
187
+
188
+ ## Static Files
189
+
190
+ ```javascript
191
+ import { Elysia } from 'elysia'
192
+ import { staticPlugin } from '@elysiajs/static'
193
+
194
+ const app = new Elysia()
195
+ .use(staticPlugin({
196
+ prefix: '/public',
197
+ assets: 'public'
198
+ }))
199
+ ```
200
+
201
+ ## Environment Variables
202
+
203
+ ```javascript
204
+ // Use Bun's built-in env
205
+ const port = process.env.PORT || 3000
206
+ const dbUrl = process.env.DATABASE_URL
207
+
208
+ const app = new Elysia()
209
+ .listen(port)
210
+ ```
211
+
212
+ ## Graceful Shutdown
213
+
214
+ ```javascript
215
+ const app = new Elysia()
216
+ .get('/', () => 'Hello')
217
+ .listen(3000)
218
+
219
+ process.on('SIGINT', () => {
220
+ console.log('Shutting down...')
221
+ app.stop()
222
+ process.exit(0)
223
+ })
224
+ ```
@@ -0,0 +1,268 @@
1
+ # Elysia Lifecycle Hooks
2
+
3
+ Lifecycle hooks allow you to intercept requests at different stages. They're the foundation for middleware, auth, logging, and error handling.
4
+
5
+ ## Lifecycle Order
6
+
7
+ ```
8
+ Request → onRequest → onParse → onBeforeHandle → Handler → onAfterHandle → onAfterResponse
9
+
10
+ onError (if error thrown)
11
+ ```
12
+
13
+ ## onRequest
14
+
15
+ First hook executed. Minimal context, best for early checks.
16
+
17
+ ```javascript
18
+ const app = new Elysia()
19
+ .onRequest(({ request }) => {
20
+ console.log(`${request.method} ${request.url}`)
21
+ })
22
+ ```
23
+
24
+ **Use cases:**
25
+ - Request logging
26
+ - Rate limiting
27
+ - IP blocking
28
+ - CORS headers
29
+
30
+ **Early return skips remaining lifecycle:**
31
+
32
+ ```javascript
33
+ .onRequest(({ request, set }) => {
34
+ if (isBlocked(request)) {
35
+ set.status = 403
36
+ return { error: 'Forbidden' }
37
+ }
38
+ })
39
+ ```
40
+
41
+ ## onBeforeHandle
42
+
43
+ Runs after validation, before handler. Has full context.
44
+
45
+ ```javascript
46
+ const app = new Elysia()
47
+ .onBeforeHandle(({ headers, set }) => {
48
+ if (!headers.authorization) {
49
+ set.status = 401
50
+ return { error: 'Unauthorized' }
51
+ }
52
+ })
53
+ ```
54
+
55
+ **Use cases:**
56
+ - Authentication checks
57
+ - Authorization
58
+ - Custom validation
59
+ - Request transformation
60
+
61
+ ## onAfterHandle
62
+
63
+ Runs after handler, can transform response.
64
+
65
+ ```javascript
66
+ const app = new Elysia()
67
+ .onAfterHandle(({ response, set }) => {
68
+ // Add header to all responses
69
+ set.headers['X-Powered-By'] = 'Elysia'
70
+
71
+ // Transform response
72
+ if (typeof response === 'object') {
73
+ return {
74
+ success: true,
75
+ data: response,
76
+ timestamp: Date.now()
77
+ }
78
+ }
79
+ })
80
+ ```
81
+
82
+ **Use cases:**
83
+ - Response transformation
84
+ - Adding headers
85
+ - Logging response
86
+
87
+ ## onError
88
+
89
+ Catches any error thrown during lifecycle.
90
+
91
+ ```javascript
92
+ const app = new Elysia()
93
+ .onError(({ code, error, set }) => {
94
+ console.error(error)
95
+
96
+ switch (code) {
97
+ case 'VALIDATION':
98
+ set.status = 422
99
+ return { error: 'Validation failed', details: error.all }
100
+
101
+ case 'NOT_FOUND':
102
+ set.status = 404
103
+ return { error: 'Not found' }
104
+
105
+ default:
106
+ set.status = 500
107
+ return { error: 'Internal server error' }
108
+ }
109
+ })
110
+ ```
111
+
112
+ **Error codes:**
113
+ - `VALIDATION` - Schema validation failed
114
+ - `NOT_FOUND` - Route not found
115
+ - `PARSE` - Body parsing failed
116
+ - `INTERNAL_SERVER_ERROR` - Unhandled error
117
+ - `UNKNOWN` - Unknown error type
118
+
119
+ ## onAfterResponse
120
+
121
+ Runs after response is sent. Cannot modify response.
122
+
123
+ ```javascript
124
+ const app = new Elysia()
125
+ .onAfterResponse(({ request, set }) => {
126
+ console.log(`Completed: ${request.method} ${request.url} - ${set.status}`)
127
+ })
128
+ ```
129
+
130
+ **Use cases:**
131
+ - Logging
132
+ - Analytics
133
+ - Cleanup
134
+
135
+ ## Local vs Interceptor Hooks
136
+
137
+ ### Local Hook (single route)
138
+
139
+ ```javascript
140
+ app.get('/users', () => getUsers(), {
141
+ beforeHandle: ({ headers, set }) => {
142
+ if (!headers.authorization) {
143
+ set.status = 401
144
+ return { error: 'Unauthorized' }
145
+ }
146
+ }
147
+ })
148
+ ```
149
+
150
+ ### Interceptor Hook (all subsequent routes)
151
+
152
+ ```javascript
153
+ const app = new Elysia()
154
+ .onBeforeHandle(() => console.log('Runs on all routes below'))
155
+ .get('/a', () => 'A') // Hook runs
156
+ .get('/b', () => 'B') // Hook runs
157
+ ```
158
+
159
+ ## Practical Examples
160
+
161
+ ### Authentication Middleware
162
+
163
+ ```javascript
164
+ const requireAuth = ({ headers, set }) => {
165
+ const token = headers.authorization?.replace('Bearer ', '')
166
+
167
+ if (!token) {
168
+ set.status = 401
169
+ return { error: 'Missing token' }
170
+ }
171
+
172
+ try {
173
+ const user = verifyToken(token)
174
+ // User available in handler
175
+ } catch {
176
+ set.status = 401
177
+ return { error: 'Invalid token' }
178
+ }
179
+ }
180
+
181
+ const app = new Elysia()
182
+ // Public routes
183
+ .get('/health', () => ({ status: 'ok' }))
184
+
185
+ // Protected routes
186
+ .guard({ beforeHandle: requireAuth }, app => app
187
+ .get('/profile', () => getProfile())
188
+ .put('/profile', ({ body }) => updateProfile(body))
189
+ )
190
+ ```
191
+
192
+ ### Request Logging
193
+
194
+ ```javascript
195
+ const logger = new Elysia({ name: 'logger' })
196
+ .onRequest(({ request }) => {
197
+ const start = Date.now()
198
+ request.startTime = start
199
+ })
200
+ .onAfterResponse(({ request, set }) => {
201
+ const duration = Date.now() - request.startTime
202
+ console.log(`${request.method} ${request.url} ${set.status} ${duration}ms`)
203
+ })
204
+
205
+ app.use(logger)
206
+ ```
207
+
208
+ ### Error Wrapper
209
+
210
+ ```javascript
211
+ const app = new Elysia()
212
+ .onError(({ code, error, path, set }) => {
213
+ // Log error
214
+ console.error({
215
+ path,
216
+ code,
217
+ message: error.message,
218
+ stack: error.stack
219
+ })
220
+
221
+ // Don't expose internal errors
222
+ if (code === 'INTERNAL_SERVER_ERROR') {
223
+ set.status = 500
224
+ return {
225
+ error: 'Something went wrong',
226
+ requestId: generateRequestId()
227
+ }
228
+ }
229
+
230
+ // Validation errors - expose details
231
+ if (code === 'VALIDATION') {
232
+ set.status = 422
233
+ return {
234
+ error: 'Validation failed',
235
+ details: error.all
236
+ }
237
+ }
238
+ })
239
+ ```
240
+
241
+ ### Rate Limiting
242
+
243
+ ```javascript
244
+ const rateLimits = new Map()
245
+
246
+ const rateLimit = (limit = 100, windowMs = 60000) => {
247
+ return new Elysia({ name: 'rate-limit' })
248
+ .onRequest(({ request, set }) => {
249
+ const ip = request.headers.get('x-forwarded-for') || 'unknown'
250
+ const now = Date.now()
251
+ const windowStart = now - windowMs
252
+
253
+ const requests = rateLimits.get(ip) || []
254
+ const recentRequests = requests.filter(t => t > windowStart)
255
+
256
+ if (recentRequests.length >= limit) {
257
+ set.status = 429
258
+ set.headers['Retry-After'] = Math.ceil(windowMs / 1000)
259
+ return { error: 'Too many requests' }
260
+ }
261
+
262
+ recentRequests.push(now)
263
+ rateLimits.set(ip, recentRequests)
264
+ })
265
+ }
266
+
267
+ app.use(rateLimit(100, 60000)) // 100 requests per minute
268
+ ```