@getvision/server 0.2.2 → 0.2.4-b0ab5ad-develop

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/CHANGELOG.md CHANGED
@@ -1,5 +1,12 @@
1
1
  # @getvision/server
2
2
 
3
+ ## 0.2.3
4
+
5
+ ### Patch Changes
6
+
7
+ - Updated dependencies [d227b1d]
8
+ - @getvision/core@0.0.5
9
+
3
10
  ## 0.2.2
4
11
 
5
12
  ### Patch Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvision/server",
3
- "version": "0.2.2",
3
+ "version": "0.2.4-b0ab5ad-develop",
4
4
  "type": "module",
5
5
  "description": "Vision Server - Meta-framework with built-in observability, pub/sub, and type-safe APIs",
6
6
  "exports": {
@@ -13,7 +13,7 @@
13
13
  },
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "@getvision/core": "0.0.3",
16
+ "@getvision/core": "0.0.5",
17
17
  "@hono/node-server": "^1.19.6",
18
18
  "bullmq": "^5.62.0",
19
19
  "hono-rate-limiter": "^0.4.2",
package/src/vision-app.ts CHANGED
@@ -4,7 +4,7 @@ import { VisionCore } from '@getvision/core'
4
4
  import type { RouteMetadata } from '@getvision/core'
5
5
  import { AsyncLocalStorage } from 'async_hooks'
6
6
  import { existsSync } from 'fs'
7
- import { spawn, type ChildProcess } from 'child_process'
7
+ import { spawn, spawnSync, type ChildProcess } from 'child_process'
8
8
  import { ServiceBuilder } from './service'
9
9
  import { EventBus } from './event-bus'
10
10
  import { eventRegistry } from './event-registry'
@@ -106,6 +106,8 @@ export class Vision<
106
106
  private config: VisionConfig
107
107
  private serviceBuilders: ServiceBuilder<any, E>[] = []
108
108
  private fileBasedRoutes: RouteMetadata[] = []
109
+ private bunServer?: any
110
+ private shuttingDown = false
109
111
 
110
112
  constructor(config?: VisionConfig) {
111
113
  super()
@@ -599,18 +601,53 @@ export class Vision<
599
601
  console.log(`🚀 Starting ${this.config.service.name}...`)
600
602
  console.log(`📡 API Server: http://localhost:${port}`)
601
603
 
602
- // Setup cleanup on exit
604
+ // Setup cleanup on exit (ensure it runs once)
603
605
  const cleanup = async () => {
606
+ if (this.shuttingDown) return
607
+ this.shuttingDown = true
604
608
  console.log('🛑 Shutting down...')
605
- await this.eventBus.close()
609
+ try {
610
+ if (this.bunServer && typeof this.bunServer.stop === 'function') {
611
+ try { this.bunServer.stop() } catch {}
612
+ }
613
+ try { if ((globalThis as any).__vision_bun_server === this.bunServer) (globalThis as any).__vision_bun_server = undefined } catch {}
614
+ } catch {}
615
+ try { stopDrizzleStudio() } catch {}
616
+ try { await this.eventBus.close() } catch {}
606
617
  }
607
618
 
608
- process.on('SIGINT', cleanup)
609
- process.on('SIGTERM', cleanup)
619
+ const wrappedCleanup = async () => {
620
+ await cleanup()
621
+ try { process.exit(0) } catch {}
622
+ }
623
+ process.once('SIGINT', wrappedCleanup)
624
+ process.once('SIGTERM', wrappedCleanup)
625
+ try { process.once('SIGQUIT', wrappedCleanup) } catch {}
610
626
 
611
- // For Node.js
612
- if (typeof process !== 'undefined' && process.versions && process.versions.node) {
627
+ // Prefer Bun if available, then Node.js; otherwise instruct the user to serve manually
628
+ if (typeof process !== 'undefined' && process.versions?.bun) {
629
+ const BunServe = (globalThis as any).Bun?.serve
630
+ if (typeof BunServe === 'function') {
631
+ console.log(`Bun detected`)
632
+ try {
633
+ const existing = (globalThis as any).__vision_bun_server
634
+ if (existing && typeof existing.stop === 'function') {
635
+ try { existing.stop() } catch {}
636
+ }
637
+ } catch {}
638
+ this.bunServer = BunServe({
639
+ fetch: this.fetch.bind(this),
640
+ port,
641
+ hostname: options?.hostname
642
+ })
643
+ try { (globalThis as any).__vision_bun_server = this.bunServer } catch {}
644
+ } else {
645
+ console.warn('Bun detected but Bun.serve is unavailable')
646
+ return this
647
+ }
648
+ } else if (typeof process !== 'undefined' && process.versions?.node) {
613
649
  const { serve } = await import('@hono/node-server')
650
+ console.log(`Node.js detected`)
614
651
  serve({
615
652
  fetch: this.fetch.bind(this),
616
653
  port,
@@ -671,7 +708,22 @@ function startDrizzleStudio(port: number): boolean {
671
708
  return false
672
709
  }
673
710
 
674
- console.log(`🗄️ Starting Drizzle Studio on port ${port}...`)
711
+ // If Drizzle Studio is already listening on this port, skip spawning but report available
712
+ try {
713
+ if (process.platform === 'win32') {
714
+ const res = spawnSync('powershell', ['-NoProfile', '-Command', `netstat -ano | Select-String -Pattern "LISTENING\\s+.*:${port}\\s"`], { encoding: 'utf-8' })
715
+ if ((res.stdout || '').trim().length > 0) {
716
+ console.log(`⚠️ Drizzle Studio port ${port} already in use; assuming it is running. Skipping auto-start.`)
717
+ return true
718
+ }
719
+ } else {
720
+ const res = spawnSync('lsof', ['-i', `tcp:${port}`, '-sTCP:LISTEN'], { encoding: 'utf-8' })
721
+ if ((res.stdout || '').trim().length > 0) {
722
+ console.log(`⚠️ Drizzle Studio port ${port} already in use; assuming it is running. Skipping auto-start.`)
723
+ return true
724
+ }
725
+ }
726
+ } catch {}
675
727
 
676
728
  try {
677
729
  drizzleStudioProcess = spawn('npx', ['drizzle-kit', 'studio', '--port', String(port), '--host', '0.0.0.0'], {