@riligar/agents-kit 1.11.0 → 1.13.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-dev-backend/SKILL.md +122 -87
  2. package/.agent/skills/riligar-dev-backend/references/elysia-basics.md +224 -0
  3. package/.agent/skills/riligar-dev-backend/references/elysia-lifecycle.md +268 -0
  4. package/.agent/skills/riligar-dev-backend/references/elysia-patterns.md +324 -0
  5. package/.agent/skills/riligar-dev-backend/references/elysia-plugins.md +202 -0
  6. package/.agent/skills/riligar-dev-backend/references/elysia-validation.md +247 -0
  7. package/.agent/skills/riligar-dev-stripe/SKILL.md +196 -91
  8. package/.agent/skills/riligar-dev-stripe/assets/stripe-client.js +422 -0
  9. package/.agent/skills/riligar-dev-stripe/assets/stripe-server.js +300 -0
  10. package/.agent/skills/riligar-dev-stripe/references/stripe-database.md +369 -0
  11. package/.agent/skills/riligar-dev-stripe/references/stripe-elysia.md +342 -0
  12. package/.agent/skills/riligar-dev-stripe/references/stripe-react.md +478 -0
  13. package/.agent/skills/riligar-dev-stripe/references/stripe-webhooks.md +376 -0
  14. package/package.json +1 -1
  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,202 @@
1
+ # Elysia Plugins
2
+
3
+ Plugins are the core pattern for organizing Elysia applications. Each plugin is a self-contained Elysia instance that can be composed into larger applications.
4
+
5
+ ## Creating a Plugin
6
+
7
+ ```javascript
8
+ // routes/users.js
9
+ import { Elysia } from 'elysia'
10
+
11
+ export const userRoutes = new Elysia({ prefix: '/users' })
12
+ .get('/', () => getAllUsers())
13
+ .get('/:id', ({ params }) => getUserById(params.id))
14
+ .post('/', ({ body }) => createUser(body))
15
+ .delete('/:id', ({ params }) => deleteUser(params.id))
16
+ ```
17
+
18
+ ## Using Plugins
19
+
20
+ ```javascript
21
+ // index.js
22
+ import { Elysia } from 'elysia'
23
+ import { userRoutes } from './routes/users'
24
+ import { postRoutes } from './routes/posts'
25
+
26
+ const app = new Elysia()
27
+ .use(userRoutes)
28
+ .use(postRoutes)
29
+ .listen(3000)
30
+ ```
31
+
32
+ ## Plugin with Configuration
33
+
34
+ ```javascript
35
+ // plugins/logger.js
36
+ export const loggerPlugin = (options = {}) => {
37
+ const { prefix = '[LOG]' } = options
38
+
39
+ return new Elysia({ name: 'logger' })
40
+ .onRequest(({ request }) => {
41
+ console.log(`${prefix} ${request.method} ${request.url}`)
42
+ })
43
+ }
44
+
45
+ // Usage
46
+ app.use(loggerPlugin({ prefix: '[API]' }))
47
+ ```
48
+
49
+ ## Named Plugins (Deduplication)
50
+
51
+ Use `name` to prevent duplicate plugin registration:
52
+
53
+ ```javascript
54
+ const dbPlugin = new Elysia({ name: 'database' })
55
+ .decorate('db', database)
56
+
57
+ // Even if used multiple times, only registers once
58
+ app.use(dbPlugin).use(dbPlugin)
59
+ ```
60
+
61
+ ## Decorators (Dependency Injection)
62
+
63
+ Add custom properties to the context:
64
+
65
+ ```javascript
66
+ const app = new Elysia()
67
+ .decorate('db', database)
68
+ .decorate('config', { apiKey: process.env.API_KEY })
69
+ .get('/users', ({ db }) => db.query.users.findMany())
70
+ ```
71
+
72
+ ## State (Global Mutable State)
73
+
74
+ ```javascript
75
+ const app = new Elysia()
76
+ .state('counter', 0)
77
+ .get('/count', ({ store }) => {
78
+ store.counter++
79
+ return { count: store.counter }
80
+ })
81
+ ```
82
+
83
+ ## Guard Pattern
84
+
85
+ Apply validation/hooks to multiple routes:
86
+
87
+ ```javascript
88
+ const app = new Elysia()
89
+ .guard({
90
+ beforeHandle: ({ headers, set }) => {
91
+ if (!headers.authorization) {
92
+ set.status = 401
93
+ return { error: 'Unauthorized' }
94
+ }
95
+ }
96
+ }, app => app
97
+ .get('/profile', () => getProfile())
98
+ .get('/settings', () => getSettings())
99
+ .put('/settings', ({ body }) => updateSettings(body))
100
+ )
101
+ ```
102
+
103
+ ## Group with Prefix
104
+
105
+ ```javascript
106
+ const app = new Elysia()
107
+ .group('/api/v1', app => app
108
+ .get('/users', () => getUsers())
109
+ .get('/posts', () => getPosts())
110
+ )
111
+
112
+ // Routes: /api/v1/users, /api/v1/posts
113
+ ```
114
+
115
+ ## Combining Guard + Group
116
+
117
+ ```javascript
118
+ const app = new Elysia()
119
+ .group('/api/v1', app => app
120
+ // Public routes
121
+ .get('/health', () => ({ status: 'ok' }))
122
+
123
+ // Protected routes
124
+ .guard({
125
+ beforeHandle: requireAuth
126
+ }, app => app
127
+ .get('/profile', () => getProfile())
128
+ .put('/profile', ({ body }) => updateProfile(body))
129
+ )
130
+ )
131
+ ```
132
+
133
+ ## Plugin Scope
134
+
135
+ ### Local Scope (Default)
136
+
137
+ Hooks only apply to the plugin and its children:
138
+
139
+ ```javascript
140
+ const plugin = new Elysia()
141
+ .onBeforeHandle(() => console.log('Only in this plugin'))
142
+ .get('/local', () => 'Hello')
143
+
144
+ app.use(plugin)
145
+ app.get('/other', () => 'No hook here')
146
+ ```
147
+
148
+ ### Global Scope
149
+
150
+ Hooks apply to all routes:
151
+
152
+ ```javascript
153
+ const globalLogger = new Elysia()
154
+ .onBeforeHandle({ as: 'global' }, () => {
155
+ console.log('Runs on ALL routes')
156
+ })
157
+
158
+ app.use(globalLogger)
159
+ ```
160
+
161
+ ## Recommended Structure
162
+
163
+ ```
164
+ src/
165
+ ├── index.js # Main app
166
+ ├── routes/
167
+ │ ├── index.js # Route aggregator
168
+ │ ├── users.js # User routes plugin
169
+ │ ├── posts.js # Post routes plugin
170
+ │ └── auth.js # Auth routes plugin
171
+ ├── plugins/
172
+ │ ├── database.js # DB connection plugin
173
+ │ ├── logger.js # Logging plugin
174
+ │ └── cors.js # CORS plugin
175
+ ├── services/
176
+ │ ├── user.js # User business logic
177
+ │ └── post.js # Post business logic
178
+ └── middleware/
179
+ └── auth.js # Auth middleware
180
+ ```
181
+
182
+ ## Route Aggregator Example
183
+
184
+ ```javascript
185
+ // routes/index.js
186
+ import { Elysia } from 'elysia'
187
+ import { userRoutes } from './users'
188
+ import { postRoutes } from './posts'
189
+ import { authRoutes } from './auth'
190
+
191
+ export const routes = new Elysia()
192
+ .use(authRoutes)
193
+ .use(userRoutes)
194
+ .use(postRoutes)
195
+
196
+ // index.js
197
+ import { routes } from './routes'
198
+
199
+ const app = new Elysia()
200
+ .use(routes)
201
+ .listen(3000)
202
+ ```
@@ -0,0 +1,247 @@
1
+ # Elysia Validation
2
+
3
+ Elysia uses TypeBox for runtime validation. Import `t` from Elysia to define schemas.
4
+
5
+ ## Basic Validation
6
+
7
+ ```javascript
8
+ import { Elysia, t } from 'elysia'
9
+
10
+ const app = new Elysia()
11
+ .post('/users', ({ body }) => createUser(body), {
12
+ body: t.Object({
13
+ name: t.String(),
14
+ email: t.String()
15
+ })
16
+ })
17
+ ```
18
+
19
+ ## Validation Targets
20
+
21
+ ### Body Validation
22
+
23
+ ```javascript
24
+ app.post('/users', ({ body }) => body, {
25
+ body: t.Object({
26
+ name: t.String(),
27
+ email: t.String({ format: 'email' }),
28
+ age: t.Number({ minimum: 0 })
29
+ })
30
+ })
31
+ ```
32
+
33
+ ### Query Validation
34
+
35
+ ```javascript
36
+ // GET /search?q=hello&limit=10
37
+ app.get('/search', ({ query }) => search(query), {
38
+ query: t.Object({
39
+ q: t.String(),
40
+ limit: t.Optional(t.Numeric({ default: 10 }))
41
+ })
42
+ })
43
+ ```
44
+
45
+ ### Params Validation
46
+
47
+ ```javascript
48
+ app.get('/users/:id', ({ params }) => getUser(params.id), {
49
+ params: t.Object({
50
+ id: t.Numeric()
51
+ })
52
+ })
53
+ ```
54
+
55
+ ### Headers Validation
56
+
57
+ ```javascript
58
+ app.get('/protected', ({ headers }) => getData(), {
59
+ headers: t.Object({
60
+ authorization: t.String()
61
+ })
62
+ })
63
+ ```
64
+
65
+ ## TypeBox Types
66
+
67
+ ### Primitives
68
+
69
+ ```javascript
70
+ t.String() // string
71
+ t.Number() // number
72
+ t.Boolean() // boolean
73
+ t.Null() // null
74
+ t.Literal('active') // exact value
75
+ ```
76
+
77
+ ### String Constraints
78
+
79
+ ```javascript
80
+ t.String({ minLength: 1 })
81
+ t.String({ maxLength: 100 })
82
+ t.String({ format: 'email' })
83
+ t.String({ format: 'uuid' })
84
+ t.String({ pattern: '^[a-z]+$' }) // regex
85
+ ```
86
+
87
+ ### Number Constraints
88
+
89
+ ```javascript
90
+ t.Number({ minimum: 0 })
91
+ t.Number({ maximum: 100 })
92
+ t.Number({ exclusiveMinimum: 0 })
93
+ t.Integer() // whole numbers only
94
+ ```
95
+
96
+ ### Numeric (String to Number)
97
+
98
+ For query params that come as strings:
99
+
100
+ ```javascript
101
+ t.Numeric() // Converts "10" to 10
102
+ t.Numeric({ minimum: 1, maximum: 100 })
103
+ ```
104
+
105
+ ### Optional & Nullable
106
+
107
+ ```javascript
108
+ t.Optional(t.String()) // string | undefined
109
+ t.Nullable(t.String()) // string | null
110
+ t.Optional(t.Nullable(t.String())) // string | null | undefined
111
+ ```
112
+
113
+ ### Default Values
114
+
115
+ ```javascript
116
+ t.String({ default: 'guest' })
117
+ t.Number({ default: 10 })
118
+ t.Boolean({ default: false })
119
+ ```
120
+
121
+ ### Objects
122
+
123
+ ```javascript
124
+ t.Object({
125
+ name: t.String(),
126
+ email: t.String(),
127
+ profile: t.Optional(t.Object({
128
+ bio: t.String(),
129
+ avatar: t.String()
130
+ }))
131
+ })
132
+ ```
133
+
134
+ ### Arrays
135
+
136
+ ```javascript
137
+ t.Array(t.String()) // string[]
138
+ t.Array(t.Number(), { minItems: 1 }) // at least 1 item
139
+ t.Array(t.Object({ id: t.Number() })) // object array
140
+ ```
141
+
142
+ ### Union (One of)
143
+
144
+ ```javascript
145
+ t.Union([
146
+ t.Literal('active'),
147
+ t.Literal('inactive'),
148
+ t.Literal('pending')
149
+ ])
150
+
151
+ // Or with different types
152
+ t.Union([t.String(), t.Number()])
153
+ ```
154
+
155
+ ### Enum Pattern
156
+
157
+ ```javascript
158
+ const Status = t.Union([
159
+ t.Literal('draft'),
160
+ t.Literal('published'),
161
+ t.Literal('archived')
162
+ ])
163
+
164
+ app.post('/posts', ({ body }) => body, {
165
+ body: t.Object({
166
+ title: t.String(),
167
+ status: Status
168
+ })
169
+ })
170
+ ```
171
+
172
+ ## Complete Example
173
+
174
+ ```javascript
175
+ import { Elysia, t } from 'elysia'
176
+
177
+ const CreateUserSchema = t.Object({
178
+ name: t.String({ minLength: 1, maxLength: 100 }),
179
+ email: t.String({ format: 'email' }),
180
+ age: t.Optional(t.Number({ minimum: 0 })),
181
+ role: t.Union([
182
+ t.Literal('user'),
183
+ t.Literal('admin')
184
+ ]),
185
+ tags: t.Optional(t.Array(t.String()))
186
+ })
187
+
188
+ const app = new Elysia()
189
+ .post('/users', ({ body }) => {
190
+ return createUser(body)
191
+ }, {
192
+ body: CreateUserSchema
193
+ })
194
+ ```
195
+
196
+ ## Custom Error Messages
197
+
198
+ ```javascript
199
+ t.String({
200
+ minLength: 1,
201
+ error: 'Name is required'
202
+ })
203
+
204
+ t.Number({
205
+ minimum: 0,
206
+ error: 'Age must be positive'
207
+ })
208
+ ```
209
+
210
+ ## Reusable Models
211
+
212
+ Register schemas for reuse:
213
+
214
+ ```javascript
215
+ const app = new Elysia()
216
+ .model({
217
+ user: t.Object({
218
+ name: t.String(),
219
+ email: t.String({ format: 'email' })
220
+ }),
221
+ pagination: t.Object({
222
+ page: t.Numeric({ default: 1 }),
223
+ limit: t.Numeric({ default: 10 })
224
+ })
225
+ })
226
+ .post('/users', ({ body }) => body, {
227
+ body: 'user' // Reference by name
228
+ })
229
+ .get('/users', ({ query }) => query, {
230
+ query: 'pagination'
231
+ })
232
+ ```
233
+
234
+ ## Validation Error Handling
235
+
236
+ ```javascript
237
+ const app = new Elysia()
238
+ .onError(({ code, error, set }) => {
239
+ if (code === 'VALIDATION') {
240
+ set.status = 422
241
+ return {
242
+ error: 'Validation failed',
243
+ details: error.all // Array of all errors
244
+ }
245
+ }
246
+ })
247
+ ```