@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 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,7 @@
1
+ module.exports = {
2
+ extends: ['@repo/eslint-config/library.js'],
3
+ parser: '@typescript-eslint/parser',
4
+ parserOptions: {
5
+ project: true,
6
+ },
7
+ }
@@ -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
+ }