@getvision/server 0.0.0-develop-20251031183955
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/.env.example +10 -0
- package/.eslintrc.cjs +7 -0
- package/.turbo/turbo-build.log +1 -0
- package/README.md +542 -0
- package/package.json +42 -0
- package/src/event-bus.ts +286 -0
- package/src/event-registry.ts +158 -0
- package/src/index.ts +64 -0
- package/src/router.ts +100 -0
- package/src/service.ts +412 -0
- package/src/types.ts +74 -0
- package/src/vision-app.ts +685 -0
- package/src/vision.ts +319 -0
- package/tsconfig.json +9 -0
package/.env.example
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
# Inngest Configuration
|
|
2
|
+
INNGEST_DEV=0
|
|
3
|
+
INNGEST_BASE_URL=http://localhost:8288
|
|
4
|
+
INNGEST_REDIS_URI=redis://localhost:6379/8
|
|
5
|
+
INNGEST_EVENT_KEY=a1b2c3d4e5f6789012345678901234567890abcdefabcdef1234567890abcd
|
|
6
|
+
INNGEST_SIGNING_KEY=fedcba0987654321fedcba0987654321fedcba0987654321fedcba0987654321
|
|
7
|
+
|
|
8
|
+
# Vision Server
|
|
9
|
+
VISION_PORT=9500
|
|
10
|
+
NODE_ENV=development
|
package/.eslintrc.cjs
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
$ tsc --noEmit
|
package/README.md
ADDED
|
@@ -0,0 +1,542 @@
|
|
|
1
|
+
# @getvision/server
|
|
2
|
+
|
|
3
|
+
**Meta-framework with built-in observability — everything you need, nothing you don't.**
|
|
4
|
+
|
|
5
|
+
Built on Hono. Automatic tracing. Type-safe APIs. Pub/Sub & Cron. Zero config. Supports both Service Builder and File-based routing.
|
|
6
|
+
|
|
7
|
+
## Why Vision Server?
|
|
8
|
+
|
|
9
|
+
**vs NestJS:** Faster, simpler, better DX
|
|
10
|
+
**vs Encore.ts:** Open source, no vendor lock-in
|
|
11
|
+
**vs Plain Hono:** Built-in observability, type-safety, pub/sub & cron
|
|
12
|
+
|
|
13
|
+
## Quick Start
|
|
14
|
+
|
|
15
|
+
```bash
|
|
16
|
+
npm install @getvision/server
|
|
17
|
+
```
|
|
18
|
+
|
|
19
|
+
```typescript
|
|
20
|
+
import { Vision } from '@getvision/server'
|
|
21
|
+
import { z } from 'zod'
|
|
22
|
+
|
|
23
|
+
const app = new Vision({
|
|
24
|
+
service: {
|
|
25
|
+
name: 'My API',
|
|
26
|
+
version: '1.0.0'
|
|
27
|
+
}
|
|
28
|
+
})
|
|
29
|
+
|
|
30
|
+
// Define services
|
|
31
|
+
app.service('users')
|
|
32
|
+
.endpoint('GET', '/users/:id', {
|
|
33
|
+
input: z.object({ id: z.string() }),
|
|
34
|
+
output: z.object({ id: z.string(), name: z.string() })
|
|
35
|
+
}, async ({ id }, c) => {
|
|
36
|
+
// c.span() is built-in! 🔥
|
|
37
|
+
const user = c.span('db.select', { 'db.table': 'users' }, () => {
|
|
38
|
+
return { id, name: 'John' }
|
|
39
|
+
})
|
|
40
|
+
return user
|
|
41
|
+
})
|
|
42
|
+
.on('user/created', async (event) => {
|
|
43
|
+
console.log('User created:', event.data)
|
|
44
|
+
})
|
|
45
|
+
|
|
46
|
+
// Start server
|
|
47
|
+
app.start(3000)
|
|
48
|
+
```
|
|
49
|
+
|
|
50
|
+
**That's it!** You get:
|
|
51
|
+
- ✅ Vision Dashboard on port 9500
|
|
52
|
+
- ✅ Automatic request tracing
|
|
53
|
+
- ✅ Type-safe validation
|
|
54
|
+
- ✅ Pub/Sub events (BullMQ-based)
|
|
55
|
+
|
|
56
|
+
## Features
|
|
57
|
+
|
|
58
|
+
### 🚀 Zero Configuration
|
|
59
|
+
|
|
60
|
+
Everything works out of the box:
|
|
61
|
+
- Vision Dashboard automatically starts
|
|
62
|
+
- Tracing middleware auto-installed
|
|
63
|
+
- Event bus auto-initialized (BullMQ)
|
|
64
|
+
- Service catalog auto-discovered
|
|
65
|
+
|
|
66
|
+
### 🔥 c.span() Built Into Context
|
|
67
|
+
|
|
68
|
+
No more `useVisionSpan()` or manual imports:
|
|
69
|
+
|
|
70
|
+
```typescript
|
|
71
|
+
async (data, c) => {
|
|
72
|
+
// Just use c.span()!
|
|
73
|
+
const user = c.span('db.select', { 'db.table': 'users' }, () => {
|
|
74
|
+
return db.users.findOne(data.id)
|
|
75
|
+
})
|
|
76
|
+
|
|
77
|
+
const posts = c.span('db.select', { 'db.table': 'posts' }, () => {
|
|
78
|
+
return db.posts.findMany({ userId: user.id })
|
|
79
|
+
})
|
|
80
|
+
|
|
81
|
+
return { user, posts }
|
|
82
|
+
}
|
|
83
|
+
```
|
|
84
|
+
|
|
85
|
+
### ✅ Type-Safe Everything
|
|
86
|
+
|
|
87
|
+
Zod validation for inputs and outputs:
|
|
88
|
+
|
|
89
|
+
```typescript
|
|
90
|
+
.endpoint('POST', '/users', {
|
|
91
|
+
input: z.object({
|
|
92
|
+
name: z.string().min(1),
|
|
93
|
+
email: z.string().email()
|
|
94
|
+
}),
|
|
95
|
+
output: z.object({
|
|
96
|
+
id: z.string()
|
|
97
|
+
})
|
|
98
|
+
}, async (data, c) => {
|
|
99
|
+
// data is fully typed!
|
|
100
|
+
return { id: '123' }
|
|
101
|
+
})
|
|
102
|
+
```
|
|
103
|
+
|
|
104
|
+
### 📡 Pub/Sub & Cron Built-In
|
|
105
|
+
|
|
106
|
+
BullMQ event bus is built-in:
|
|
107
|
+
|
|
108
|
+
```typescript
|
|
109
|
+
// Subscribe to events
|
|
110
|
+
.on('user/created', async (event) => {
|
|
111
|
+
await sendWelcomeEmail(event.data.email)
|
|
112
|
+
})
|
|
113
|
+
|
|
114
|
+
// Schedule cron jobs
|
|
115
|
+
.cron('0 0 * * *', async () => {
|
|
116
|
+
await cleanupInactiveUsers()
|
|
117
|
+
})
|
|
118
|
+
|
|
119
|
+
// Send events from handlers
|
|
120
|
+
await c.emit('user/created', { userId: '123', email: 'user@example.com' })
|
|
121
|
+
```
|
|
122
|
+
|
|
123
|
+
### 🎯 Service Builder Pattern
|
|
124
|
+
|
|
125
|
+
Organize your code by services:
|
|
126
|
+
|
|
127
|
+
```typescript
|
|
128
|
+
app.service('users')
|
|
129
|
+
.on('user/created', handler)
|
|
130
|
+
.endpoint('GET', '/users', schema, handler)
|
|
131
|
+
.endpoint('POST', '/users', schema, handler)
|
|
132
|
+
.cron('0 0 * * *', handler)
|
|
133
|
+
|
|
134
|
+
app.service('orders')
|
|
135
|
+
.on('order/placed', handler)
|
|
136
|
+
.endpoint('GET', '/orders', schema, handler)
|
|
137
|
+
.endpoint('POST', '/orders', schema, handler)
|
|
138
|
+
```
|
|
139
|
+
|
|
140
|
+
> Note: Declare `service.on('event', { schema, handler })` BEFORE any endpoint that calls `c.emit('event', ...)`.
|
|
141
|
+
> This ensures TypeScript can infer the event type for `c.emit`, otherwise you'll get type errors.
|
|
142
|
+
|
|
143
|
+
### 🔐 Middleware Support
|
|
144
|
+
|
|
145
|
+
Add middleware globally or per-service:
|
|
146
|
+
|
|
147
|
+
```typescript
|
|
148
|
+
import { logger } from 'hono/logger'
|
|
149
|
+
import { jwt } from 'hono/jwt'
|
|
150
|
+
|
|
151
|
+
// Global middleware
|
|
152
|
+
app.use('*', logger())
|
|
153
|
+
|
|
154
|
+
// Service-level middleware (applies to all endpoints)
|
|
155
|
+
app.service('admin')
|
|
156
|
+
.use(jwt({ secret: 'secret' })) // Protect all admin endpoints
|
|
157
|
+
.endpoint('GET', '/admin/users', schema, handler)
|
|
158
|
+
.endpoint('POST', '/admin/settings', schema, handler)
|
|
159
|
+
|
|
160
|
+
// Endpoint-level middleware
|
|
161
|
+
app.service('users')
|
|
162
|
+
.endpoint('GET', '/users', schema, handler) // Public
|
|
163
|
+
.endpoint('POST', '/users', schema, handler, {
|
|
164
|
+
middleware: [authMiddleware] // Protected
|
|
165
|
+
})
|
|
166
|
+
```
|
|
167
|
+
|
|
168
|
+
### 🔮 Vision Dashboard Included
|
|
169
|
+
|
|
170
|
+
Automatic observability:
|
|
171
|
+
- 📊 Real-time request tracing
|
|
172
|
+
- 📝 Live logs
|
|
173
|
+
- 🏗️ Service catalog
|
|
174
|
+
- 🔍 Waterfall visualization
|
|
175
|
+
- 📈 Performance metrics
|
|
176
|
+
|
|
177
|
+
Visit `http://localhost:9500` after starting your app!
|
|
178
|
+
|
|
179
|
+
## API Reference
|
|
180
|
+
|
|
181
|
+
### `new Vision(config)`
|
|
182
|
+
|
|
183
|
+
Create a new Vision app.
|
|
184
|
+
|
|
185
|
+
```typescript
|
|
186
|
+
const app = new Vision({
|
|
187
|
+
service: {
|
|
188
|
+
name: 'My API',
|
|
189
|
+
version: '1.0.0',
|
|
190
|
+
description: 'Optional description',
|
|
191
|
+
integrations: {
|
|
192
|
+
database: 'postgresql://localhost/mydb', // Optional
|
|
193
|
+
redis: 'redis://localhost:6379' // Optional
|
|
194
|
+
},
|
|
195
|
+
drizzle: {
|
|
196
|
+
autoStart: true, // Auto-start Drizzle Studio
|
|
197
|
+
port: 4983 // Drizzle Studio port
|
|
198
|
+
}
|
|
199
|
+
},
|
|
200
|
+
vision: {
|
|
201
|
+
enabled: true, // Enable/disable dashboard
|
|
202
|
+
port: 9500, // Dashboard port
|
|
203
|
+
maxTraces: 1000, // Max traces to store
|
|
204
|
+
maxLogs: 10000, // Max logs to store
|
|
205
|
+
logging: true // Console logging
|
|
206
|
+
},
|
|
207
|
+
pubsub: {
|
|
208
|
+
devMode: true // In-memory BullMQ for local dev
|
|
209
|
+
}
|
|
210
|
+
})
|
|
211
|
+
```
|
|
212
|
+
|
|
213
|
+
### `app.service(name)`
|
|
214
|
+
|
|
215
|
+
Create a new service builder.
|
|
216
|
+
|
|
217
|
+
```typescript
|
|
218
|
+
app.service('users')
|
|
219
|
+
.on(...)
|
|
220
|
+
.endpoint(...)
|
|
221
|
+
.cron(...)
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### `service.endpoint(method, path, schema, handler, config?)`
|
|
225
|
+
|
|
226
|
+
Define a type-safe HTTP endpoint.
|
|
227
|
+
|
|
228
|
+
```typescript
|
|
229
|
+
.endpoint(
|
|
230
|
+
'GET',
|
|
231
|
+
'/users/:id',
|
|
232
|
+
{
|
|
233
|
+
input: z.object({ id: z.string() }),
|
|
234
|
+
output: z.object({ id: z.string(), name: z.string() })
|
|
235
|
+
},
|
|
236
|
+
async ({ id }, c) => {
|
|
237
|
+
// handler with c.span() available
|
|
238
|
+
return { id, name: 'John' }
|
|
239
|
+
},
|
|
240
|
+
{
|
|
241
|
+
middleware: [authMiddleware] // Optional
|
|
242
|
+
}
|
|
243
|
+
)
|
|
244
|
+
```
|
|
245
|
+
|
|
246
|
+
### `service.on(eventName, handler)`
|
|
247
|
+
|
|
248
|
+
Subscribe to events.
|
|
249
|
+
|
|
250
|
+
```typescript
|
|
251
|
+
.on('user/created', async (event) => {
|
|
252
|
+
console.log(event.data)
|
|
253
|
+
})
|
|
254
|
+
```
|
|
255
|
+
|
|
256
|
+
### `service.cron(schedule, handler, options?)`
|
|
257
|
+
|
|
258
|
+
Schedule a cron job.
|
|
259
|
+
|
|
260
|
+
```typescript
|
|
261
|
+
.cron('0 0 * * *', async () => {
|
|
262
|
+
console.log('Daily job')
|
|
263
|
+
}, { id: 'custom-id' })
|
|
264
|
+
```
|
|
265
|
+
|
|
266
|
+
### `c.span(name, attributes, fn)`
|
|
267
|
+
|
|
268
|
+
Create a custom span (built into context).
|
|
269
|
+
|
|
270
|
+
```typescript
|
|
271
|
+
const result = c.span('operation.name', {
|
|
272
|
+
'attribute.key': 'value'
|
|
273
|
+
}, () => {
|
|
274
|
+
// Your code here
|
|
275
|
+
return someResult
|
|
276
|
+
})
|
|
277
|
+
```
|
|
278
|
+
|
|
279
|
+
### Event emission
|
|
280
|
+
|
|
281
|
+
Emit events from handlers using the context:
|
|
282
|
+
|
|
283
|
+
```typescript
|
|
284
|
+
await c.emit('user/created', { userId: '123', email: 'user@example.com' })
|
|
285
|
+
```
|
|
286
|
+
|
|
287
|
+
### `app.getVision()`
|
|
288
|
+
|
|
289
|
+
Get the VisionCore instance.
|
|
290
|
+
|
|
291
|
+
```typescript
|
|
292
|
+
const vision = app.getVision()
|
|
293
|
+
const tracer = vision.getTracer()
|
|
294
|
+
```
|
|
295
|
+
|
|
296
|
+
### `app.start(port, options?)`
|
|
297
|
+
|
|
298
|
+
Start the server (convenience method).
|
|
299
|
+
|
|
300
|
+
```typescript
|
|
301
|
+
await app.start(3000)
|
|
302
|
+
// or
|
|
303
|
+
await app.start(3000, { hostname: '0.0.0.0' })
|
|
304
|
+
```
|
|
305
|
+
|
|
306
|
+
## Drizzle Integration
|
|
307
|
+
|
|
308
|
+
Vision Server automatically detects and integrates with Drizzle ORM.
|
|
309
|
+
|
|
310
|
+
### Auto-Start Drizzle Studio
|
|
311
|
+
|
|
312
|
+
```typescript
|
|
313
|
+
const app = new Vision({
|
|
314
|
+
service: {
|
|
315
|
+
name: 'My API',
|
|
316
|
+
integrations: {
|
|
317
|
+
database: 'sqlite://./dev.db'
|
|
318
|
+
},
|
|
319
|
+
drizzle: {
|
|
320
|
+
autoStart: true, // Start Drizzle Studio automatically
|
|
321
|
+
port: 4983 // Default: 4983
|
|
322
|
+
}
|
|
323
|
+
}
|
|
324
|
+
})
|
|
325
|
+
```
|
|
326
|
+
|
|
327
|
+
**What happens:**
|
|
328
|
+
1. ✅ Detects `drizzle.config.ts` in your project
|
|
329
|
+
2. ✅ Auto-starts Drizzle Studio on port 4983
|
|
330
|
+
3. ✅ Displays in Vision Dashboard → Integrations
|
|
331
|
+
4. ✅ Links to https://local.drizzle.studio
|
|
332
|
+
|
|
333
|
+
### Use with c.span()
|
|
334
|
+
|
|
335
|
+
```typescript
|
|
336
|
+
app.service('users')
|
|
337
|
+
.endpoint('GET', '/users/:id', schema, async ({ id }, c) => {
|
|
338
|
+
// Trace database queries
|
|
339
|
+
const user = c.span('db.select', {
|
|
340
|
+
'db.system': 'sqlite',
|
|
341
|
+
'db.table': 'users'
|
|
342
|
+
}, () => {
|
|
343
|
+
return db.select().from(users).where(eq(users.id, id)).get()
|
|
344
|
+
})
|
|
345
|
+
|
|
346
|
+
return user
|
|
347
|
+
})
|
|
348
|
+
```
|
|
349
|
+
|
|
350
|
+
## Hono Compatibility
|
|
351
|
+
|
|
352
|
+
Vision extends Hono, so all Hono features work:
|
|
353
|
+
|
|
354
|
+
```typescript
|
|
355
|
+
// Use any Hono middleware
|
|
356
|
+
app.use('*', logger())
|
|
357
|
+
app.use('*', cors())
|
|
358
|
+
app.use('/admin/*', jwt({ secret: 'secret' }))
|
|
359
|
+
|
|
360
|
+
// Define routes Hono-style
|
|
361
|
+
app.get('/health', (c) => c.json({ status: 'ok' }))
|
|
362
|
+
|
|
363
|
+
// Use Hono routing features
|
|
364
|
+
app.route('/api/v1', apiRoutes)
|
|
365
|
+
|
|
366
|
+
// Access Hono methods
|
|
367
|
+
app.notFound((c) => c.json({ error: 'Not found' }, 404))
|
|
368
|
+
app.onError((err, c) => c.json({ error: err.message }, 500))
|
|
369
|
+
```
|
|
370
|
+
|
|
371
|
+
## Complete Example
|
|
372
|
+
|
|
373
|
+
Here's a full working example with multiple services, pub/sub, and Drizzle:
|
|
374
|
+
|
|
375
|
+
```typescript
|
|
376
|
+
import { Vision } from '@getvision/server'
|
|
377
|
+
import { z } from 'zod'
|
|
378
|
+
import { db } from './db'
|
|
379
|
+
import { users, orders } from './db/schema'
|
|
380
|
+
import { eq } from 'drizzle-orm'
|
|
381
|
+
|
|
382
|
+
const app = new Vision({
|
|
383
|
+
service: {
|
|
384
|
+
name: 'E-Commerce API',
|
|
385
|
+
version: '1.0.0',
|
|
386
|
+
integrations: {
|
|
387
|
+
database: 'sqlite://./dev.db'
|
|
388
|
+
},
|
|
389
|
+
drizzle: {
|
|
390
|
+
autoStart: true,
|
|
391
|
+
port: 4983
|
|
392
|
+
}
|
|
393
|
+
},
|
|
394
|
+
vision: {
|
|
395
|
+
enabled: true,
|
|
396
|
+
port: 9500
|
|
397
|
+
},
|
|
398
|
+
pubsub: {
|
|
399
|
+
schemas: {
|
|
400
|
+
'user/created': {
|
|
401
|
+
data: z.object({
|
|
402
|
+
userId: z.string(),
|
|
403
|
+
email: z.string().email()
|
|
404
|
+
})
|
|
405
|
+
},
|
|
406
|
+
'order/placed': {
|
|
407
|
+
data: z.object({
|
|
408
|
+
orderId: z.string(),
|
|
409
|
+
userId: z.string(),
|
|
410
|
+
total: z.number()
|
|
411
|
+
})
|
|
412
|
+
}
|
|
413
|
+
}
|
|
414
|
+
}
|
|
415
|
+
})
|
|
416
|
+
|
|
417
|
+
// User Service
|
|
418
|
+
app.service('users')
|
|
419
|
+
.endpoint('GET', '/users', {
|
|
420
|
+
input: z.object({}),
|
|
421
|
+
output: z.object({
|
|
422
|
+
users: z.array(z.object({
|
|
423
|
+
id: z.string(),
|
|
424
|
+
name: z.string()
|
|
425
|
+
}))
|
|
426
|
+
})
|
|
427
|
+
}, async (_, c) => {
|
|
428
|
+
const allUsers = c.span('db.select', { 'db.table': 'users' }, () => {
|
|
429
|
+
return db.select().from(users).all()
|
|
430
|
+
})
|
|
431
|
+
return { users: allUsers }
|
|
432
|
+
})
|
|
433
|
+
.on('user/created', async (event) => {
|
|
434
|
+
console.log('Sending welcome email to:', event.data.email)
|
|
435
|
+
})
|
|
436
|
+
.endpoint('POST', '/users', {
|
|
437
|
+
input: z.object({
|
|
438
|
+
name: z.string().min(1),
|
|
439
|
+
email: z.string().email()
|
|
440
|
+
}),
|
|
441
|
+
output: z.object({ id: z.string() })
|
|
442
|
+
}, async (data, c) => {
|
|
443
|
+
const user = c.span('db.insert', { 'db.table': 'users' }, () => {
|
|
444
|
+
return db.insert(users).values(data).returning().get()
|
|
445
|
+
})
|
|
446
|
+
|
|
447
|
+
// Emit event (type-safe)
|
|
448
|
+
await c.emit('user/created', { userId: user.id, email: user.email })
|
|
449
|
+
|
|
450
|
+
return { id: user.id }
|
|
451
|
+
})
|
|
452
|
+
|
|
453
|
+
// Order Service
|
|
454
|
+
app.service('orders')
|
|
455
|
+
.endpoint('POST', '/orders', {
|
|
456
|
+
input: z.object({
|
|
457
|
+
userId: z.string(),
|
|
458
|
+
items: z.array(z.object({
|
|
459
|
+
productId: z.string(),
|
|
460
|
+
quantity: z.number()
|
|
461
|
+
}))
|
|
462
|
+
}),
|
|
463
|
+
output: z.object({ orderId: z.string() })
|
|
464
|
+
}, async (data, c) => {
|
|
465
|
+
const order = c.span('db.insert', { 'db.table': 'orders' }, () => {
|
|
466
|
+
return db.insert(orders).values({
|
|
467
|
+
userId: data.userId,
|
|
468
|
+
total: 100
|
|
469
|
+
}).returning().get()
|
|
470
|
+
})
|
|
471
|
+
|
|
472
|
+
return { orderId: order.id }
|
|
473
|
+
})
|
|
474
|
+
.cron('0 0 * * *', async () => {
|
|
475
|
+
console.log('Daily order summary')
|
|
476
|
+
})
|
|
477
|
+
|
|
478
|
+
app.start(3000)
|
|
479
|
+
```
|
|
480
|
+
|
|
481
|
+
### Run the Example
|
|
482
|
+
|
|
483
|
+
```bash
|
|
484
|
+
# From project root
|
|
485
|
+
bun run example:server
|
|
486
|
+
|
|
487
|
+
# Or directly
|
|
488
|
+
cd examples/vision
|
|
489
|
+
bun run dev
|
|
490
|
+
```
|
|
491
|
+
|
|
492
|
+
Visit:
|
|
493
|
+
- **API:** http://localhost:3000
|
|
494
|
+
- **Vision Dashboard:** http://localhost:9500
|
|
495
|
+
- **Drizzle Studio:** https://local.drizzle.studio
|
|
496
|
+
|
|
497
|
+
## Why Vision Server?
|
|
498
|
+
|
|
499
|
+
### ✅ Advantages
|
|
500
|
+
|
|
501
|
+
**vs NestJS:**
|
|
502
|
+
- 10x faster (Hono vs Express)
|
|
503
|
+
- 10x simpler (no DI, no decorators)
|
|
504
|
+
- Built-in observability
|
|
505
|
+
|
|
506
|
+
**vs Encore.ts:**
|
|
507
|
+
- 100% open source (MIT)
|
|
508
|
+
- No vendor lock-in
|
|
509
|
+
- Deploy anywhere
|
|
510
|
+
|
|
511
|
+
**vs Plain Hono:**
|
|
512
|
+
- Built-in observability
|
|
513
|
+
- Type-safe validation
|
|
514
|
+
- Pub/Sub & Cron included
|
|
515
|
+
- Better code organization
|
|
516
|
+
|
|
517
|
+
### 🎯 Perfect For
|
|
518
|
+
|
|
519
|
+
- Greenfield projects
|
|
520
|
+
- API-first architectures
|
|
521
|
+
- Teams that want great DX
|
|
522
|
+
- Projects that need observability
|
|
523
|
+
- Anyone who wants NestJS features without the complexity
|
|
524
|
+
|
|
525
|
+
## Roadmap
|
|
526
|
+
|
|
527
|
+
- [x] Drizzle integration with auto-start Studio
|
|
528
|
+
- [x] Type-safe validation with Zod
|
|
529
|
+
- [x] Auto-generated API schemas
|
|
530
|
+
- [ ] Cache layer (Redis integration)
|
|
531
|
+
- [ ] Rate limiting (per-endpoint & global)
|
|
532
|
+
- [ ] Testing helpers
|
|
533
|
+
- [ ] OpenAPI generation
|
|
534
|
+
- [ ] WebSocket support
|
|
535
|
+
|
|
536
|
+
## License
|
|
537
|
+
|
|
538
|
+
MIT
|
|
539
|
+
|
|
540
|
+
---
|
|
541
|
+
|
|
542
|
+
**Built with ❤️ by the Vision team**
|
package/package.json
ADDED
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@getvision/server",
|
|
3
|
+
"version": "0.0.0-develop-20251031183955",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Vision Server - Meta-framework with built-in observability, pub/sub, and type-safe APIs",
|
|
6
|
+
"exports": {
|
|
7
|
+
".": "./src/index.ts"
|
|
8
|
+
},
|
|
9
|
+
"scripts": {
|
|
10
|
+
"dev": "tsc --watch",
|
|
11
|
+
"build": "tsc --noEmit",
|
|
12
|
+
"lint": "eslint . --max-warnings 0"
|
|
13
|
+
},
|
|
14
|
+
"license": "MIT",
|
|
15
|
+
"dependencies": {
|
|
16
|
+
"@getvision/core": "0.0.1",
|
|
17
|
+
"@hono/node-server": "^1.19.5",
|
|
18
|
+
"bullmq": "^5.62.0",
|
|
19
|
+
"hono": "^4.10.3",
|
|
20
|
+
"ioredis": "^5.8.2",
|
|
21
|
+
"zod": "^4.1.11"
|
|
22
|
+
},
|
|
23
|
+
"peerDependencies": {},
|
|
24
|
+
"devDependencies": {
|
|
25
|
+
"@repo/eslint-config": "0.0.0",
|
|
26
|
+
"@repo/typescript-config": "0.0.0",
|
|
27
|
+
"@types/node": "^20.14.9",
|
|
28
|
+
"typescript": "5.9.3"
|
|
29
|
+
},
|
|
30
|
+
"keywords": [
|
|
31
|
+
"vision",
|
|
32
|
+
"framework",
|
|
33
|
+
"observability",
|
|
34
|
+
"tracing",
|
|
35
|
+
"hono",
|
|
36
|
+
"bullmq",
|
|
37
|
+
"pub-sub",
|
|
38
|
+
"type-safe",
|
|
39
|
+
"event-driven"
|
|
40
|
+
],
|
|
41
|
+
"config": {}
|
|
42
|
+
}
|