@getvision/server 0.2.1-d0f3a53-develop → 0.2.1

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,16 @@
1
1
  # @getvision/server
2
2
 
3
+ ## 0.2.1
4
+
5
+ ### Patch Changes
6
+
7
+ - ec9cf8b: Redis password is now passed correctly and REDIS_URL is honored.
8
+ - d0f3a53: Add event handler context
9
+
10
+ Event handlers receive a Hono-like `Context` as the second argument. You can run service-level middleware to inject resources using `c.set(...)` and then access them in the handler via `c.get(...)`.
11
+
12
+ - 648a711: If Redis is configured use production mode in PubSub
13
+
3
14
  ## 0.2.0
4
15
 
5
16
  ### Minor Changes
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvision/server",
3
- "version": "0.2.1-d0f3a53-develop",
3
+ "version": "0.2.1",
4
4
  "type": "module",
5
5
  "description": "Vision Server - Meta-framework with built-in observability, pub/sub, and type-safe APIs",
6
6
  "exports": {
package/src/event-bus.ts CHANGED
@@ -26,12 +26,52 @@ export class EventBus {
26
26
  private devModeHandlers = new Map<string, Array<(data: any) => Promise<void>>>()
27
27
 
28
28
  constructor(config: EventBusConfig = {}) {
29
- this.config = {
30
- devMode: config.devMode ?? process.env.NODE_ENV === 'development',
31
- redis: config.redis ?? {
29
+ // Build Redis config from environment variables
30
+ const envUrl = process.env.REDIS_URL
31
+ let envRedis: { host?: string; port?: number; password?: string } | undefined
32
+ if (envUrl) {
33
+ try {
34
+ const u = new URL(envUrl)
35
+ envRedis = {
36
+ host: u.hostname || undefined,
37
+ port: u.port ? parseInt(u.port) : 6379,
38
+ // URL password takes precedence over REDIS_PASSWORD
39
+ password: u.password || process.env.REDIS_PASSWORD || undefined,
40
+ }
41
+ } catch {
42
+ // Fallback to individual env vars if URL is invalid
43
+ envRedis = undefined
44
+ }
45
+ }
46
+
47
+ if (!envRedis) {
48
+ envRedis = {
32
49
  host: process.env.REDIS_HOST || 'localhost',
33
50
  port: parseInt(process.env.REDIS_PORT || '6379'),
34
- },
51
+ password: process.env.REDIS_PASSWORD || undefined,
52
+ }
53
+ }
54
+
55
+ // Merge: explicit config.redis overrides env-derived values
56
+ const mergedRedis = { ...(envRedis || {}), ...(config.redis || {}) }
57
+
58
+ // Determine if Redis is configured by env or explicit config
59
+ const hasRedisFromEnv = Boolean(envUrl)
60
+ const hasRedisFromConfig = Boolean(
61
+ config.redis && (config.redis.host || config.redis.port || config.redis.password)
62
+ )
63
+ const hasRedis = hasRedisFromEnv || hasRedisFromConfig
64
+
65
+ // devMode precedence:
66
+ // 1) Respect explicit config.devMode when provided (true/false)
67
+ // 2) Otherwise, if Redis is configured (env or config), use production mode (devMode=false)
68
+ // 3) Otherwise, default to devMode=true (in-memory)
69
+ const resolvedDevMode =
70
+ typeof config.devMode === 'boolean' ? config.devMode : !hasRedis
71
+
72
+ this.config = {
73
+ devMode: resolvedDevMode,
74
+ redis: mergedRedis,
35
75
  }
36
76
  }
37
77
 
package/src/vision-app.ts CHANGED
@@ -17,6 +17,30 @@ export interface VisionALSContext {
17
17
 
18
18
  const visionContext = new AsyncLocalStorage<VisionALSContext>()
19
19
 
20
+ // Simple deep merge utility (objects only, arrays are overwritten by source)
21
+ function deepMerge<T extends Record<string, any>>(target: T, source: Partial<T>): T {
22
+ const output: any = { ...target }
23
+ if (source && typeof source === 'object') {
24
+ for (const key of Object.keys(source)) {
25
+ const srcVal = source[key]
26
+ const tgtVal = output[key]
27
+ if (
28
+ srcVal &&
29
+ typeof srcVal === 'object' &&
30
+ !Array.isArray(srcVal) &&
31
+ tgtVal &&
32
+ typeof tgtVal === 'object' &&
33
+ !Array.isArray(tgtVal)
34
+ ) {
35
+ output[key] = deepMerge(tgtVal, srcVal)
36
+ } else {
37
+ output[key] = srcVal
38
+ }
39
+ }
40
+ }
41
+ return output as T
42
+ }
43
+
20
44
  /**
21
45
  * Vision Server configuration
22
46
  */
@@ -61,20 +85,13 @@ export interface VisionConfig {
61
85
  * service: {
62
86
  * name: 'My API',
63
87
  * version: '1.0.0'
64
- * },
65
- * pubsub: {
66
- * schemas: {
67
- * 'user/created': {
68
- * data: z.object({ userId: z.string() })
69
- * }
70
- * }
71
88
  * }
72
89
  * })
73
90
  *
74
91
  * const userService = app.service('users')
75
- * .endpoint('GET', '/users/:id', schema, handler)
76
92
  * .on('user/created', handler)
77
- *
93
+ * .endpoint('GET', '/users/:id', schema, handler)
94
+ *
78
95
  * app.start(3000)
79
96
  * ```
80
97
  */
@@ -100,24 +117,16 @@ export class Vision<
100
117
  enabled: false,
101
118
  port: 9500,
102
119
  },
103
- pubsub: {
104
- devMode: true,
105
- },
120
+ // Do not set a default devMode here; let EventBus derive from Redis presence
121
+ pubsub: {},
106
122
  routes: {
107
123
  autodiscover: true,
108
124
  dirs: ['app/routes'],
109
125
  },
110
126
  }
111
127
 
112
- // Merge shallowly (good enough for our config structure)
113
- this.config = {
114
- ...defaultConfig,
115
- ...(config || {}),
116
- service: { ...defaultConfig.service, ...(config?.service || {}) },
117
- vision: { ...defaultConfig.vision, ...(config?.vision || {}) },
118
- pubsub: { ...defaultConfig.pubsub, ...(config?.pubsub || {}) },
119
- routes: { ...defaultConfig.routes, ...(config?.routes || {}) },
120
- }
128
+ // Deep merge to respect nested overrides
129
+ this.config = deepMerge(defaultConfig, config || {})
121
130
 
122
131
  // Initialize Vision Core
123
132
  const visionEnabled = this.config.vision?.enabled !== false