@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 +11 -0
- package/package.json +1 -1
- package/src/event-bus.ts +44 -4
- package/src/vision-app.ts +30 -21
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
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
|
-
|
|
30
|
-
|
|
31
|
-
|
|
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
|
-
|
|
104
|
-
|
|
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
|
-
//
|
|
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
|