@getvision/server 0.4.3 → 0.4.4-44d79d9-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.
Files changed (44) hide show
  1. package/dist/event-bus.d.ts +87 -0
  2. package/dist/event-bus.d.ts.map +1 -0
  3. package/dist/event-bus.js +265 -0
  4. package/dist/event-bus.js.map +10 -0
  5. package/dist/event-registry.d.ts +79 -0
  6. package/dist/event-registry.d.ts.map +1 -0
  7. package/dist/event-registry.js +93 -0
  8. package/dist/event-registry.js.map +10 -0
  9. package/{src/index.ts → dist/index.d.ts} +14 -28
  10. package/dist/index.d.ts.map +1 -0
  11. package/dist/index.js +33 -0
  12. package/dist/index.js.map +10 -0
  13. package/dist/router.d.ts +16 -0
  14. package/dist/router.d.ts.map +1 -0
  15. package/dist/router.js +117 -0
  16. package/dist/router.js.map +10 -0
  17. package/dist/service.d.ts +151 -0
  18. package/dist/service.d.ts.map +1 -0
  19. package/dist/service.js +341 -0
  20. package/dist/service.js.map +10 -0
  21. package/dist/types.d.ts +71 -0
  22. package/dist/types.d.ts.map +1 -0
  23. package/dist/types.js +2 -0
  24. package/dist/types.js.map +9 -0
  25. package/dist/vision-app.d.ts +166 -0
  26. package/dist/vision-app.d.ts.map +1 -0
  27. package/dist/vision-app.js +611 -0
  28. package/dist/vision-app.js.map +10 -0
  29. package/dist/vision.d.ts +63 -0
  30. package/dist/vision.d.ts.map +1 -0
  31. package/dist/vision.js +223 -0
  32. package/dist/vision.js.map +10 -0
  33. package/package.json +13 -3
  34. package/.env.example +0 -3
  35. package/.eslintrc.cjs +0 -7
  36. package/.turbo/turbo-build.log +0 -1
  37. package/src/event-bus.ts +0 -409
  38. package/src/event-registry.ts +0 -158
  39. package/src/router.ts +0 -118
  40. package/src/service.ts +0 -618
  41. package/src/types.ts +0 -93
  42. package/src/vision-app.ts +0 -880
  43. package/src/vision.ts +0 -319
  44. package/tsconfig.json +0 -9
@@ -0,0 +1,87 @@
1
+ import { Queue } from 'bullmq';
2
+ import type { QueueEventsOptions, QueueOptions, WorkerOptions } from 'bullmq';
3
+ /**
4
+ * EventBus configuration
5
+ */
6
+ export interface EventBusConfig {
7
+ redis?: {
8
+ host?: string;
9
+ port?: number;
10
+ password?: string;
11
+ /**
12
+ * Enable keepalive to prevent connection timeouts (default: true in production)
13
+ */
14
+ keepAlive?: number;
15
+ /**
16
+ * Max retry attempts for failed commands (default: 20)
17
+ */
18
+ maxRetriesPerRequest?: number;
19
+ /**
20
+ * Enable ready check before executing commands (default: true)
21
+ */
22
+ enableReadyCheck?: boolean;
23
+ /**
24
+ * Connection timeout in ms (default: 10000)
25
+ */
26
+ connectTimeout?: number;
27
+ /**
28
+ * Enable offline queue (default: true)
29
+ */
30
+ enableOfflineQueue?: boolean;
31
+ };
32
+ queue?: Omit<QueueOptions, 'connection'>;
33
+ worker?: Omit<WorkerOptions, 'connection'>;
34
+ queueEvents?: Omit<QueueEventsOptions, 'connection'>;
35
+ /**
36
+ * Default BullMQ worker concurrency (per event). Per-handler options override this.
37
+ */
38
+ workerConcurrency?: number;
39
+ devMode?: boolean;
40
+ }
41
+ /**
42
+ * EventBus - Abstraction over BullMQ
43
+ */
44
+ export declare class EventBus {
45
+ private queues;
46
+ private workers;
47
+ private queueEvents;
48
+ private config;
49
+ private devModeHandlers;
50
+ constructor(config?: EventBusConfig);
51
+ /**
52
+ * Get Redis connection configuration
53
+ * Includes keepalive, retry strategy, and connection pooling
54
+ */
55
+ private getRedisConnection;
56
+ /**
57
+ * Get or create a queue for an event
58
+ */
59
+ private getQueue;
60
+ /**
61
+ * Get or create a queue for a cron job
62
+ */
63
+ getQueueForCron(cronName: string): Promise<Queue>;
64
+ /**
65
+ * Emit an event
66
+ */
67
+ emit<T extends Record<string, any>>(eventName: string, data: T): Promise<void>;
68
+ /**
69
+ * Register event handler
70
+ */
71
+ registerHandler<T>(eventName: string, handler: (data: T) => Promise<void>, options?: {
72
+ /**
73
+ * Max number of concurrent jobs this handler will process.
74
+ * Defaults to config.workerConcurrency (or 1).
75
+ */
76
+ concurrency?: number;
77
+ }): void;
78
+ /**
79
+ * Register cron job handler
80
+ */
81
+ registerCronHandler(cronName: string, handler: (context: any) => Promise<void>): void;
82
+ /**
83
+ * Close all connections
84
+ */
85
+ close(): Promise<void>;
86
+ }
87
+ //# sourceMappingURL=event-bus.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-bus.d.ts","sourceRoot":"","sources":["../src/event-bus.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,KAAK,EAAuB,MAAM,QAAQ,CAAA;AACnD,OAAO,KAAK,EAAE,kBAAkB,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,QAAQ,CAAA;AAG7E;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,KAAK,CAAC,EAAE;QACN,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,QAAQ,CAAC,EAAE,MAAM,CAAA;QACjB;;WAEG;QACH,SAAS,CAAC,EAAE,MAAM,CAAA;QAClB;;WAEG;QACH,oBAAoB,CAAC,EAAE,MAAM,CAAA;QAC7B;;WAEG;QACH,gBAAgB,CAAC,EAAE,OAAO,CAAA;QAC1B;;WAEG;QACH,cAAc,CAAC,EAAE,MAAM,CAAA;QACvB;;WAEG;QACH,kBAAkB,CAAC,EAAE,OAAO,CAAA;KAC7B,CAAA;IACD,KAAK,CAAC,EAAE,IAAI,CAAC,YAAY,EAAE,YAAY,CAAC,CAAA;IACxC,MAAM,CAAC,EAAE,IAAI,CAAC,aAAa,EAAE,YAAY,CAAC,CAAA;IAC1C,WAAW,CAAC,EAAE,IAAI,CAAC,kBAAkB,EAAE,YAAY,CAAC,CAAA;IACpD;;OAEG;IACH,iBAAiB,CAAC,EAAE,MAAM,CAAA;IAE1B,OAAO,CAAC,EAAE,OAAO,CAAA;CAClB;AAED;;GAEG;AACH,qBAAa,QAAQ;IACnB,OAAO,CAAC,MAAM,CAA2B;IACzC,OAAO,CAAC,OAAO,CAA4B;IAC3C,OAAO,CAAC,WAAW,CAAiC;IACpD,OAAO,CAAC,MAAM,CAAgB;IAC9B,OAAO,CAAC,eAAe,CAAyD;gBAEpE,MAAM,GAAE,cAAmB;IAsDvC;;;OAGG;IACH,OAAO,CAAC,kBAAkB;IA4B1B;;OAEG;IACH,OAAO,CAAC,QAAQ;IAiBhB;;OAEG;IACG,eAAe,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,KAAK,CAAC;IAWvD;;OAEG;IACG,IAAI,CAAC,CAAC,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EACtC,SAAS,EAAE,MAAM,EACjB,IAAI,EAAE,CAAC,GACN,OAAO,CAAC,IAAI,CAAC;IAuDhB;;OAEG;IACH,eAAe,CAAC,CAAC,EACf,SAAS,EAAE,MAAM,EACjB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACnC,OAAO,CAAC,EAAE;QACR;;;WAGG;QACH,WAAW,CAAC,EAAE,MAAM,CAAA;KACrB,GACA,IAAI;IA4DP;;OAEG;IACH,mBAAmB,CACjB,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,GACvC,IAAI;IAkEP;;OAEG;IACG,KAAK,IAAI,OAAO,CAAC,IAAI,CAAC;CAyB7B"}
@@ -0,0 +1,265 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/event-bus.ts
21
+ import { Queue, Worker, QueueEvents } from "bullmq";
22
+ import { eventRegistry } from "./event-registry";
23
+
24
+ class EventBus {
25
+ queues = new Map;
26
+ workers = new Map;
27
+ queueEvents = new Map;
28
+ config;
29
+ devModeHandlers = new Map;
30
+ constructor(config = {}) {
31
+ const envUrl = process.env.REDIS_URL;
32
+ let envRedis;
33
+ if (envUrl) {
34
+ try {
35
+ const u = new URL(envUrl);
36
+ envRedis = {
37
+ host: u.hostname || undefined,
38
+ port: u.port ? parseInt(u.port) : 6379,
39
+ password: u.password || process.env.REDIS_PASSWORD || undefined
40
+ };
41
+ } catch {
42
+ envRedis = undefined;
43
+ }
44
+ }
45
+ if (!envRedis) {
46
+ envRedis = {
47
+ host: process.env.REDIS_HOST || "localhost",
48
+ port: parseInt(process.env.REDIS_PORT || "6379"),
49
+ password: process.env.REDIS_PASSWORD || undefined
50
+ };
51
+ }
52
+ const mergedRedis = { ...envRedis || {}, ...config.redis || {} };
53
+ const hasRedisFromEnv = Boolean(envUrl);
54
+ const hasRedisFromConfig = Boolean(config.redis && (config.redis.host || config.redis.port || config.redis.password));
55
+ const hasRedis = hasRedisFromEnv || hasRedisFromConfig;
56
+ const resolvedDevMode = typeof config.devMode === "boolean" ? config.devMode : !hasRedis;
57
+ this.config = {
58
+ devMode: resolvedDevMode,
59
+ redis: mergedRedis,
60
+ workerConcurrency: config.workerConcurrency,
61
+ queue: config.queue,
62
+ worker: config.worker,
63
+ queueEvents: config.queueEvents
64
+ };
65
+ }
66
+ getRedisConnection() {
67
+ const baseConfig = this.config.redis || {
68
+ host: "localhost",
69
+ port: 6379
70
+ };
71
+ return {
72
+ host: baseConfig.host,
73
+ port: baseConfig.port,
74
+ password: baseConfig.password,
75
+ keepAlive: baseConfig.keepAlive ?? 30000,
76
+ maxRetriesPerRequest: baseConfig.maxRetriesPerRequest ?? 20,
77
+ enableReadyCheck: baseConfig.enableReadyCheck ?? true,
78
+ connectTimeout: baseConfig.connectTimeout ?? 1e4,
79
+ enableOfflineQueue: baseConfig.enableOfflineQueue ?? true,
80
+ retryStrategy: (times) => {
81
+ if (times > 10) {
82
+ console.error("❌ Redis connection failed after 10 retries");
83
+ return null;
84
+ }
85
+ const delay = Math.min(times * 200, 3000);
86
+ console.log(`\uD83D\uDD04 Redis reconnecting... attempt ${times}, delay ${delay}ms`);
87
+ return delay;
88
+ }
89
+ };
90
+ }
91
+ getQueue(eventName) {
92
+ if (this.config.devMode) {
93
+ return null;
94
+ }
95
+ let queue = this.queues.get(eventName);
96
+ if (!queue) {
97
+ queue = new Queue(eventName, {
98
+ ...this.config.queue || {},
99
+ connection: this.getRedisConnection()
100
+ });
101
+ this.queues.set(eventName, queue);
102
+ }
103
+ return queue;
104
+ }
105
+ async getQueueForCron(cronName) {
106
+ if (this.config.devMode) {
107
+ return {
108
+ upsertJobScheduler: async () => {}
109
+ };
110
+ }
111
+ return this.getQueue(cronName);
112
+ }
113
+ async emit(eventName, data) {
114
+ const eventMeta = eventRegistry.getEvent(eventName);
115
+ if (!eventMeta) {
116
+ throw new Error(`Event "${eventName}" not registered. Did you forget to add .on('${eventName}', {...})?`);
117
+ }
118
+ try {
119
+ const maybeStrictSchema = eventMeta.schema;
120
+ const strictSchema = typeof maybeStrictSchema?.strict === "function" ? maybeStrictSchema.strict() : eventMeta.schema;
121
+ const validatedData = strictSchema.parse(data);
122
+ if (this.config.devMode) {
123
+ const handlers = this.devModeHandlers.get(eventName) || [];
124
+ for (const handler of handlers) {
125
+ try {
126
+ await handler(validatedData);
127
+ eventRegistry.incrementEventCount(eventName, false);
128
+ } catch (error) {
129
+ console.error(`Error in handler for event "${eventName}":`, error);
130
+ eventRegistry.incrementEventCount(eventName, true);
131
+ throw error;
132
+ }
133
+ }
134
+ } else {
135
+ const queue = this.getQueue(eventName);
136
+ await queue.add(eventName, validatedData, {
137
+ attempts: 3,
138
+ backoff: {
139
+ type: "exponential",
140
+ delay: 2000
141
+ }
142
+ });
143
+ eventRegistry.incrementEventCount(eventName, false);
144
+ }
145
+ } catch (error) {
146
+ if (error instanceof Error && error.name === "ZodError") {
147
+ const zodError = error;
148
+ const errorMessages = zodError.errors?.map((e) => ` - ${e.path.join(".")}: ${e.message}`).join(`
149
+ `) || error.message;
150
+ throw new Error(`Invalid data for event "${eventName}":
151
+ ${errorMessages}`);
152
+ }
153
+ throw error;
154
+ }
155
+ }
156
+ registerHandler(eventName, handler, options) {
157
+ if (this.config.devMode) {
158
+ const handlers = this.devModeHandlers.get(eventName) || [];
159
+ handlers.push(handler);
160
+ this.devModeHandlers.set(eventName, handlers);
161
+ } else {
162
+ const workerKey = `${eventName}-handler`;
163
+ const existingWorker = this.workers.get(workerKey);
164
+ if (existingWorker) {
165
+ existingWorker.close().catch(() => {});
166
+ this.workers.delete(workerKey);
167
+ }
168
+ const worker = new Worker(eventName, async (job) => {
169
+ try {
170
+ await handler(job.data);
171
+ } catch (error) {
172
+ eventRegistry.incrementEventCount(eventName, true);
173
+ throw error;
174
+ }
175
+ }, {
176
+ ...this.config.worker || {},
177
+ connection: this.getRedisConnection(),
178
+ concurrency: options?.concurrency ?? this.config.workerConcurrency ?? this.config.worker?.concurrency ?? 1
179
+ });
180
+ this.workers.set(workerKey, worker);
181
+ if (!this.queueEvents.has(eventName)) {
182
+ const queueEvents = new QueueEvents(eventName, {
183
+ ...this.config.queueEvents || {},
184
+ connection: this.getRedisConnection()
185
+ });
186
+ queueEvents.on("completed", ({ jobId }) => {
187
+ console.log(`✅ Event "${eventName}" completed (job: ${jobId})`);
188
+ });
189
+ queueEvents.on("failed", ({ jobId, failedReason }) => {
190
+ console.error(`❌ Event "${eventName}" failed (job: ${jobId}):`, failedReason);
191
+ });
192
+ this.queueEvents.set(eventName, queueEvents);
193
+ }
194
+ }
195
+ }
196
+ registerCronHandler(cronName, handler) {
197
+ if (this.config.devMode) {
198
+ console.log(`\uD83E\uDDF9 Cron job "${cronName}" registered (dev mode - manual trigger only)`);
199
+ const handlers = this.devModeHandlers.get(cronName) || [];
200
+ handlers.push(handler);
201
+ this.devModeHandlers.set(cronName, handlers);
202
+ } else {
203
+ const cronWorkerKey = `${cronName}-handler`;
204
+ const existingCronWorker = this.workers.get(cronWorkerKey);
205
+ if (existingCronWorker) {
206
+ existingCronWorker.close().catch(() => {});
207
+ this.workers.delete(cronWorkerKey);
208
+ }
209
+ const worker = new Worker(cronName, async (job) => {
210
+ try {
211
+ const context = {
212
+ jobId: job.id,
213
+ timestamp: Date.now()
214
+ };
215
+ await handler(context);
216
+ eventRegistry.incrementCronCount(cronName, false);
217
+ } catch (error) {
218
+ eventRegistry.incrementCronCount(cronName, true);
219
+ throw error;
220
+ }
221
+ }, {
222
+ ...this.config.worker || {},
223
+ connection: this.getRedisConnection(),
224
+ concurrency: this.config.worker?.concurrency ?? 1
225
+ });
226
+ this.workers.set(cronWorkerKey, worker);
227
+ if (!this.queueEvents.has(cronName)) {
228
+ const queueEvents = new QueueEvents(cronName, {
229
+ ...this.config.queueEvents || {},
230
+ connection: this.getRedisConnection()
231
+ });
232
+ queueEvents.on("completed", ({ jobId }) => {
233
+ console.log(`✅ Cron job "${cronName}" completed (job: ${jobId})`);
234
+ });
235
+ queueEvents.on("failed", ({ jobId, failedReason }) => {
236
+ console.error(`❌ Cron job "${cronName}" failed (job: ${jobId}):`, failedReason);
237
+ });
238
+ this.queueEvents.set(cronName, queueEvents);
239
+ }
240
+ }
241
+ }
242
+ async close() {
243
+ if (this.config.devMode) {
244
+ this.devModeHandlers.clear();
245
+ return;
246
+ }
247
+ for (const queue of this.queues.values()) {
248
+ await queue.close();
249
+ }
250
+ for (const worker of this.workers.values()) {
251
+ await worker.close();
252
+ }
253
+ for (const queueEvent of this.queueEvents.values()) {
254
+ await queueEvent.close();
255
+ }
256
+ this.queues.clear();
257
+ this.workers.clear();
258
+ this.queueEvents.clear();
259
+ }
260
+ }
261
+ export {
262
+ EventBus
263
+ };
264
+
265
+ //# debugId=5BB653CA9921A74564756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/event-bus.ts"],
4
+ "sourcesContent": [
5
+ "import { Queue, Worker, QueueEvents } from 'bullmq'\nimport type { QueueEventsOptions, QueueOptions, WorkerOptions } from 'bullmq'\nimport { eventRegistry } from './event-registry'\n\n/**\n * EventBus configuration\n */\nexport interface EventBusConfig {\n redis?: {\n host?: string\n port?: number\n password?: string\n /**\n * Enable keepalive to prevent connection timeouts (default: true in production)\n */\n keepAlive?: number\n /**\n * Max retry attempts for failed commands (default: 20)\n */\n maxRetriesPerRequest?: number\n /**\n * Enable ready check before executing commands (default: true)\n */\n enableReadyCheck?: boolean\n /**\n * Connection timeout in ms (default: 10000)\n */\n connectTimeout?: number\n /**\n * Enable offline queue (default: true)\n */\n enableOfflineQueue?: boolean\n }\n queue?: Omit<QueueOptions, 'connection'>\n worker?: Omit<WorkerOptions, 'connection'>\n queueEvents?: Omit<QueueEventsOptions, 'connection'>\n /**\n * Default BullMQ worker concurrency (per event). Per-handler options override this.\n */\n workerConcurrency?: number\n // Dev mode - use in-memory (no Redis required)\n devMode?: boolean\n}\n\n/**\n * EventBus - Abstraction over BullMQ\n */\nexport class EventBus {\n private queues = new Map<string, Queue>()\n private workers = new Map<string, Worker>()\n private queueEvents = new Map<string, QueueEvents>()\n private config: EventBusConfig\n private devModeHandlers = new Map<string, Array<(data: any) => Promise<void>>>()\n\n constructor(config: EventBusConfig = {}) {\n // Build Redis config from environment variables\n const envUrl = process.env.REDIS_URL\n let envRedis: { host?: string; port?: number; password?: string } | undefined\n if (envUrl) {\n try {\n const u = new URL(envUrl)\n envRedis = {\n host: u.hostname || undefined,\n port: u.port ? parseInt(u.port) : 6379,\n // URL password takes precedence over REDIS_PASSWORD\n password: u.password || process.env.REDIS_PASSWORD || undefined,\n }\n } catch {\n // Fallback to individual env vars if URL is invalid\n envRedis = undefined\n }\n }\n\n if (!envRedis) {\n envRedis = {\n host: process.env.REDIS_HOST || 'localhost',\n port: parseInt(process.env.REDIS_PORT || '6379'),\n password: process.env.REDIS_PASSWORD || undefined,\n }\n }\n\n // Merge: explicit config.redis overrides env-derived values\n const mergedRedis = { ...(envRedis || {}), ...(config.redis || {}) }\n\n // Determine if Redis is configured by env or explicit config\n const hasRedisFromEnv = Boolean(envUrl)\n const hasRedisFromConfig = Boolean(\n config.redis && (config.redis.host || config.redis.port || config.redis.password)\n )\n const hasRedis = hasRedisFromEnv || hasRedisFromConfig\n\n // devMode precedence:\n // 1) Respect explicit config.devMode when provided (true/false)\n // 2) Otherwise, if Redis is configured (env or config), use production mode (devMode=false)\n // 3) Otherwise, default to devMode=true (in-memory)\n const resolvedDevMode =\n typeof config.devMode === 'boolean' ? config.devMode : !hasRedis\n\n this.config = {\n devMode: resolvedDevMode,\n redis: mergedRedis,\n workerConcurrency: config.workerConcurrency,\n queue: config.queue,\n worker: config.worker,\n queueEvents: config.queueEvents,\n }\n }\n\n /**\n * Get Redis connection configuration\n * Includes keepalive, retry strategy, and connection pooling\n */\n private getRedisConnection() {\n const baseConfig = this.config.redis || {\n host: 'localhost',\n port: 6379,\n }\n\n return {\n host: baseConfig.host,\n port: baseConfig.port,\n password: baseConfig.password,\n keepAlive: baseConfig.keepAlive ?? 30000, // 30 seconds keepalive\n maxRetriesPerRequest: baseConfig.maxRetriesPerRequest ?? 20,\n enableReadyCheck: baseConfig.enableReadyCheck ?? true,\n connectTimeout: baseConfig.connectTimeout ?? 10000,\n enableOfflineQueue: baseConfig.enableOfflineQueue ?? true,\n // Retry strategy for automatic reconnection\n retryStrategy: (times: number) => {\n if (times > 10) {\n console.error('❌ Redis connection failed after 10 retries')\n return null // Stop retrying\n }\n const delay = Math.min(times * 200, 3000)\n console.log(`🔄 Redis reconnecting... attempt ${times}, delay ${delay}ms`)\n return delay\n },\n }\n }\n\n /**\n * Get or create a queue for an event\n */\n private getQueue(eventName: string): Queue {\n if (this.config.devMode) {\n // In dev mode, we don't use actual queues\n return null as any\n }\n\n let queue = this.queues.get(eventName)\n if (!queue) {\n queue = new Queue(eventName, {\n ...(this.config.queue || {}),\n connection: this.getRedisConnection(),\n })\n this.queues.set(eventName, queue)\n }\n return queue\n }\n\n /**\n * Get or create a queue for a cron job\n */\n async getQueueForCron(cronName: string): Promise<Queue> {\n if (this.config.devMode) {\n // In dev mode, return a mock queue\n return {\n upsertJobScheduler: async () => {},\n } as any\n }\n\n return this.getQueue(cronName)\n }\n\n /**\n * Emit an event\n */\n async emit<T extends Record<string, any>>(\n eventName: string,\n data: T\n ): Promise<void> {\n // Get event metadata from registry\n const eventMeta = eventRegistry.getEvent(eventName)\n if (!eventMeta) {\n throw new Error(`Event \"${eventName}\" not registered. Did you forget to add .on('${eventName}', {...})?`)\n }\n\n // Validate data with Zod schema (enforce no unknown keys when possible)\n try {\n // If the event schema is a ZodObject, use strict() to disallow unknown keys\n const maybeStrictSchema: any = (eventMeta.schema as any)\n const strictSchema = typeof maybeStrictSchema?.strict === 'function'\n ? maybeStrictSchema.strict()\n : eventMeta.schema\n\n const validatedData = (strictSchema as typeof eventMeta.schema).parse(data)\n\n if (this.config.devMode) {\n // Dev mode - execute handlers immediately (in-memory)\n const handlers = this.devModeHandlers.get(eventName) || []\n \n for (const handler of handlers) {\n try {\n await handler(validatedData)\n eventRegistry.incrementEventCount(eventName, false)\n } catch (error) {\n console.error(`Error in handler for event \"${eventName}\":`, error)\n eventRegistry.incrementEventCount(eventName, true)\n throw error\n }\n }\n } else {\n // Production mode - use BullMQ\n const queue = this.getQueue(eventName)\n await queue.add(eventName, validatedData, {\n attempts: 3,\n backoff: {\n type: 'exponential',\n delay: 2000,\n },\n })\n eventRegistry.incrementEventCount(eventName, false)\n }\n } catch (error) {\n if (error instanceof Error && error.name === 'ZodError') {\n const zodError = error as any\n const errorMessages = zodError.errors?.map((e: any) => ` - ${e.path.join('.')}: ${e.message}`).join('\\n') || error.message\n throw new Error(\n `Invalid data for event \"${eventName}\":\\n${errorMessages}`\n )\n }\n throw error\n }\n }\n\n /**\n * Register event handler\n */\n registerHandler<T>(\n eventName: string,\n handler: (data: T) => Promise<void>,\n options?: {\n /**\n * Max number of concurrent jobs this handler will process.\n * Defaults to config.workerConcurrency (or 1).\n */\n concurrency?: number\n }\n ): void {\n if (this.config.devMode) {\n // Dev mode - store handlers in memory\n const handlers = this.devModeHandlers.get(eventName) || []\n handlers.push(handler)\n this.devModeHandlers.set(eventName, handlers)\n } else {\n // Production mode - create BullMQ worker\n const workerKey = `${eventName}-handler`\n \n // Close existing worker if it exists\n const existingWorker = this.workers.get(workerKey)\n if (existingWorker) {\n void existingWorker.close().catch(() => {})\n this.workers.delete(workerKey)\n }\n \n const worker = new Worker(\n eventName,\n async (job) => {\n try {\n await handler(job.data)\n } catch (error) {\n eventRegistry.incrementEventCount(eventName, true)\n throw error\n }\n },\n {\n ...(this.config.worker || {}),\n connection: this.getRedisConnection(),\n concurrency:\n options?.concurrency ??\n this.config.workerConcurrency ??\n this.config.worker?.concurrency ??\n 1,\n }\n )\n\n this.workers.set(workerKey, worker)\n\n // Listen to queue events\n if (!this.queueEvents.has(eventName)) {\n const queueEvents = new QueueEvents(eventName, {\n ...(this.config.queueEvents || {}),\n connection: this.getRedisConnection(),\n })\n\n queueEvents.on('completed', ({ jobId }) => {\n console.log(`✅ Event \"${eventName}\" completed (job: ${jobId})`)\n })\n\n queueEvents.on('failed', ({ jobId, failedReason }) => {\n console.error(`❌ Event \"${eventName}\" failed (job: ${jobId}):`, failedReason)\n })\n\n this.queueEvents.set(eventName, queueEvents)\n }\n }\n }\n\n /**\n * Register cron job handler\n */\n registerCronHandler(\n cronName: string,\n handler: (context: any) => Promise<void>\n ): void {\n if (this.config.devMode) {\n // Dev mode - cron jobs run immediately for testing\n // We'll implement a simple interval-based scheduler\n console.log(`🧹 Cron job \"${cronName}\" registered (dev mode - manual trigger only)`)\n \n // Store handler for manual trigger\n const handlers = this.devModeHandlers.get(cronName) || []\n handlers.push(handler)\n this.devModeHandlers.set(cronName, handlers)\n } else {\n // Production mode - create BullMQ worker for cron jobs\n const cronWorkerKey = `${cronName}-handler`\n \n // Close existing cron worker if it exists\n const existingCronWorker = this.workers.get(cronWorkerKey)\n if (existingCronWorker) {\n void existingCronWorker.close().catch(() => {})\n this.workers.delete(cronWorkerKey)\n }\n \n const worker = new Worker(\n cronName,\n async (job) => {\n try {\n // Create a simple context for cron handler\n const context = {\n jobId: job.id,\n timestamp: Date.now(),\n }\n await handler(context)\n eventRegistry.incrementCronCount(cronName, false)\n } catch (error) {\n eventRegistry.incrementCronCount(cronName, true)\n throw error\n }\n },\n {\n ...(this.config.worker || {}),\n connection: this.getRedisConnection(),\n concurrency: this.config.worker?.concurrency ?? 1,\n }\n )\n\n this.workers.set(cronWorkerKey, worker)\n\n // Listen to cron job events\n if (!this.queueEvents.has(cronName)) {\n const queueEvents = new QueueEvents(cronName, {\n ...(this.config.queueEvents || {}),\n connection: this.getRedisConnection(),\n })\n\n queueEvents.on('completed', ({ jobId }) => {\n console.log(`✅ Cron job \"${cronName}\" completed (job: ${jobId})`)\n })\n\n queueEvents.on('failed', ({ jobId, failedReason }) => {\n console.error(`❌ Cron job \"${cronName}\" failed (job: ${jobId}):`, failedReason)\n })\n\n this.queueEvents.set(cronName, queueEvents)\n }\n }\n }\n\n /**\n * Close all connections\n */\n async close(): Promise<void> {\n if (this.config.devMode) {\n this.devModeHandlers.clear()\n return\n }\n\n // Close all queues\n for (const queue of this.queues.values()) {\n await queue.close()\n }\n\n // Close all workers\n for (const worker of this.workers.values()) {\n await worker.close()\n }\n\n // Close all queue events\n for (const queueEvent of this.queueEvents.values()) {\n await queueEvent.close()\n }\n\n this.queues.clear()\n this.workers.clear()\n this.queueEvents.clear()\n }\n}\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "5BB653CA9921A74564756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,79 @@
1
+ import type { z } from 'zod';
2
+ /**
3
+ * Event metadata for UI and runtime
4
+ */
5
+ export interface EventMetadata<T = any> {
6
+ name: string;
7
+ description?: string;
8
+ icon?: string;
9
+ tags?: string[];
10
+ schema: z.ZodSchema<T>;
11
+ handlers: Array<(data: T) => Promise<void>>;
12
+ lastTriggered?: Date;
13
+ totalCount: number;
14
+ failedCount: number;
15
+ }
16
+ /**
17
+ * Cron job metadata
18
+ */
19
+ export interface CronMetadata {
20
+ name: string;
21
+ schedule: string;
22
+ description?: string;
23
+ icon?: string;
24
+ tags?: string[];
25
+ handler: (context: any) => Promise<void>;
26
+ lastRun?: Date;
27
+ nextRun?: Date;
28
+ totalRuns: number;
29
+ failedRuns: number;
30
+ }
31
+ /**
32
+ * Global event registry
33
+ */
34
+ export declare class EventRegistry {
35
+ private events;
36
+ private crons;
37
+ /**
38
+ * Register an event with schema and handler
39
+ */
40
+ registerEvent<T>(name: string, schema: z.ZodSchema<T>, handler: (data: T) => Promise<void>, metadata?: {
41
+ description?: string;
42
+ icon?: string;
43
+ tags?: string[];
44
+ }): void;
45
+ /**
46
+ * Register a cron job
47
+ */
48
+ registerCron(name: string, schedule: string, handler: (context: any) => Promise<void>, metadata?: {
49
+ description?: string;
50
+ icon?: string;
51
+ tags?: string[];
52
+ }): void;
53
+ /**
54
+ * Get event metadata
55
+ */
56
+ getEvent(name: string): EventMetadata | undefined;
57
+ /**
58
+ * Get all events
59
+ */
60
+ getAllEvents(): EventMetadata[];
61
+ /**
62
+ * Get all cron jobs
63
+ */
64
+ getAllCrons(): CronMetadata[];
65
+ /**
66
+ * Increment event count
67
+ */
68
+ incrementEventCount(name: string, failed?: boolean): void;
69
+ /**
70
+ * Increment cron run count
71
+ */
72
+ incrementCronCount(name: string, failed?: boolean): void;
73
+ /**
74
+ * Clear all registrations (for testing)
75
+ */
76
+ clear(): void;
77
+ }
78
+ export declare const eventRegistry: EventRegistry;
79
+ //# sourceMappingURL=event-registry.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"event-registry.d.ts","sourceRoot":"","sources":["../src/event-registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,CAAC,EAAE,MAAM,KAAK,CAAA;AAE5B;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,GAAG,GAAG;IACpC,IAAI,EAAE,MAAM,CAAA;IACZ,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,CAAA;IACtB,QAAQ,EAAE,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,CAAC,CAAA;IAC3C,aAAa,CAAC,EAAE,IAAI,CAAA;IACpB,UAAU,EAAE,MAAM,CAAA;IAClB,WAAW,EAAE,MAAM,CAAA;CACpB;AAED;;GAEG;AACH,MAAM,WAAW,YAAY;IAC3B,IAAI,EAAE,MAAM,CAAA;IACZ,QAAQ,EAAE,MAAM,CAAA;IAChB,WAAW,CAAC,EAAE,MAAM,CAAA;IACpB,IAAI,CAAC,EAAE,MAAM,CAAA;IACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;IACf,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,CAAA;IACxC,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,OAAO,CAAC,EAAE,IAAI,CAAA;IACd,SAAS,EAAE,MAAM,CAAA;IACjB,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,qBAAa,aAAa;IACxB,OAAO,CAAC,MAAM,CAAmC;IACjD,OAAO,CAAC,KAAK,CAAkC;IAE/C;;OAEG;IACH,aAAa,CAAC,CAAC,EACb,IAAI,EAAE,MAAM,EACZ,MAAM,EAAE,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,EACtB,OAAO,EAAE,CAAC,IAAI,EAAE,CAAC,KAAK,OAAO,CAAC,IAAI,CAAC,EACnC,QAAQ,CAAC,EAAE;QACT,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAChB,GACA,IAAI;IAqBP;;OAEG;IACH,YAAY,CACV,IAAI,EAAE,MAAM,EACZ,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,CAAC,OAAO,EAAE,GAAG,KAAK,OAAO,CAAC,IAAI,CAAC,EACxC,QAAQ,CAAC,EAAE;QACT,WAAW,CAAC,EAAE,MAAM,CAAA;QACpB,IAAI,CAAC,EAAE,MAAM,CAAA;QACb,IAAI,CAAC,EAAE,MAAM,EAAE,CAAA;KAChB,GACA,IAAI;IAaP;;OAEG;IACH,QAAQ,CAAC,IAAI,EAAE,MAAM,GAAG,aAAa,GAAG,SAAS;IAIjD;;OAEG;IACH,YAAY,IAAI,aAAa,EAAE;IAI/B;;OAEG;IACH,WAAW,IAAI,YAAY,EAAE;IAI7B;;OAEG;IACH,mBAAmB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI;IAWvD;;OAEG;IACH,kBAAkB,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,UAAQ,GAAG,IAAI;IAWtD;;OAEG;IACH,KAAK,IAAI,IAAI;CAId;AAGD,eAAO,MAAM,aAAa,eAAsB,CAAA"}
@@ -0,0 +1,93 @@
1
+ import { createRequire } from "node:module";
2
+ var __create = Object.create;
3
+ var __getProtoOf = Object.getPrototypeOf;
4
+ var __defProp = Object.defineProperty;
5
+ var __getOwnPropNames = Object.getOwnPropertyNames;
6
+ var __hasOwnProp = Object.prototype.hasOwnProperty;
7
+ var __toESM = (mod, isNodeMode, target) => {
8
+ target = mod != null ? __create(__getProtoOf(mod)) : {};
9
+ const to = isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target;
10
+ for (let key of __getOwnPropNames(mod))
11
+ if (!__hasOwnProp.call(to, key))
12
+ __defProp(to, key, {
13
+ get: () => mod[key],
14
+ enumerable: true
15
+ });
16
+ return to;
17
+ };
18
+ var __require = /* @__PURE__ */ createRequire(import.meta.url);
19
+
20
+ // src/event-registry.ts
21
+ class EventRegistry {
22
+ events = new Map;
23
+ crons = new Map;
24
+ registerEvent(name, schema, handler, metadata) {
25
+ const existing = this.events.get(name);
26
+ if (existing) {
27
+ existing.handlers.push(handler);
28
+ } else {
29
+ this.events.set(name, {
30
+ name,
31
+ schema,
32
+ handlers: [handler],
33
+ description: metadata?.description,
34
+ icon: metadata?.icon,
35
+ tags: metadata?.tags,
36
+ totalCount: 0,
37
+ failedCount: 0
38
+ });
39
+ }
40
+ }
41
+ registerCron(name, schedule, handler, metadata) {
42
+ this.crons.set(name, {
43
+ name,
44
+ schedule,
45
+ handler,
46
+ description: metadata?.description,
47
+ icon: metadata?.icon,
48
+ tags: metadata?.tags,
49
+ totalRuns: 0,
50
+ failedRuns: 0
51
+ });
52
+ }
53
+ getEvent(name) {
54
+ return this.events.get(name);
55
+ }
56
+ getAllEvents() {
57
+ return Array.from(this.events.values());
58
+ }
59
+ getAllCrons() {
60
+ return Array.from(this.crons.values());
61
+ }
62
+ incrementEventCount(name, failed = false) {
63
+ const event = this.events.get(name);
64
+ if (event) {
65
+ event.totalCount++;
66
+ if (failed) {
67
+ event.failedCount++;
68
+ }
69
+ event.lastTriggered = new Date;
70
+ }
71
+ }
72
+ incrementCronCount(name, failed = false) {
73
+ const cron = this.crons.get(name);
74
+ if (cron) {
75
+ cron.totalRuns++;
76
+ if (failed) {
77
+ cron.failedRuns++;
78
+ }
79
+ cron.lastRun = new Date;
80
+ }
81
+ }
82
+ clear() {
83
+ this.events.clear();
84
+ this.crons.clear();
85
+ }
86
+ }
87
+ var eventRegistry = new EventRegistry;
88
+ export {
89
+ eventRegistry,
90
+ EventRegistry
91
+ };
92
+
93
+ //# debugId=BE322C66D6CB104A64756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/event-registry.ts"],
4
+ "sourcesContent": [
5
+ "import type { z } from 'zod'\n\n/**\n * Event metadata for UI and runtime\n */\nexport interface EventMetadata<T = any> {\n name: string\n description?: string\n icon?: string\n tags?: string[]\n schema: z.ZodSchema<T>\n handlers: Array<(data: T) => Promise<void>>\n lastTriggered?: Date\n totalCount: number\n failedCount: number\n}\n\n/**\n * Cron job metadata\n */\nexport interface CronMetadata {\n name: string\n schedule: string\n description?: string\n icon?: string\n tags?: string[]\n handler: (context: any) => Promise<void>\n lastRun?: Date\n nextRun?: Date\n totalRuns: number\n failedRuns: number\n}\n\n/**\n * Global event registry\n */\nexport class EventRegistry {\n private events = new Map<string, EventMetadata>()\n private crons = new Map<string, CronMetadata>()\n\n /**\n * Register an event with schema and handler\n */\n registerEvent<T>(\n name: string,\n schema: z.ZodSchema<T>,\n handler: (data: T) => Promise<void>,\n metadata?: {\n description?: string\n icon?: string\n tags?: string[]\n }\n ): void {\n const existing = this.events.get(name)\n \n if (existing) {\n // Add handler to existing event\n existing.handlers.push(handler)\n } else {\n // Create new event\n this.events.set(name, {\n name,\n schema,\n handlers: [handler],\n description: metadata?.description,\n icon: metadata?.icon,\n tags: metadata?.tags,\n totalCount: 0,\n failedCount: 0,\n })\n }\n }\n\n /**\n * Register a cron job\n */\n registerCron(\n name: string,\n schedule: string,\n handler: (context: any) => Promise<void>,\n metadata?: {\n description?: string\n icon?: string\n tags?: string[]\n }\n ): void {\n this.crons.set(name, {\n name,\n schedule,\n handler,\n description: metadata?.description,\n icon: metadata?.icon,\n tags: metadata?.tags,\n totalRuns: 0,\n failedRuns: 0,\n })\n }\n\n /**\n * Get event metadata\n */\n getEvent(name: string): EventMetadata | undefined {\n return this.events.get(name)\n }\n\n /**\n * Get all events\n */\n getAllEvents(): EventMetadata[] {\n return Array.from(this.events.values())\n }\n\n /**\n * Get all cron jobs\n */\n getAllCrons(): CronMetadata[] {\n return Array.from(this.crons.values())\n }\n\n /**\n * Increment event count\n */\n incrementEventCount(name: string, failed = false): void {\n const event = this.events.get(name)\n if (event) {\n event.totalCount++\n if (failed) {\n event.failedCount++\n }\n event.lastTriggered = new Date()\n }\n }\n\n /**\n * Increment cron run count\n */\n incrementCronCount(name: string, failed = false): void {\n const cron = this.crons.get(name)\n if (cron) {\n cron.totalRuns++\n if (failed) {\n cron.failedRuns++\n }\n cron.lastRun = new Date()\n }\n }\n\n /**\n * Clear all registrations (for testing)\n */\n clear(): void {\n this.events.clear()\n this.crons.clear()\n }\n}\n\n// Global singleton\nexport const eventRegistry = new EventRegistry()\n"
6
+ ],
7
+ "mappings": ";;;;;;;;;;;;;;;;;;;;AAoCO,MAAM,cAAc;AAAA,EACjB,SAAS,IAAI;AAAA,EACb,QAAQ,IAAI;AAAA,EAKpB,aAAgB,CACd,MACA,QACA,SACA,UAKM;AAAA,IACN,MAAM,WAAW,KAAK,OAAO,IAAI,IAAI;AAAA,IAErC,IAAI,UAAU;AAAA,MAEZ,SAAS,SAAS,KAAK,OAAO;AAAA,IAChC,EAAO;AAAA,MAEL,KAAK,OAAO,IAAI,MAAM;AAAA,QACpB;AAAA,QACA;AAAA,QACA,UAAU,CAAC,OAAO;AAAA,QAClB,aAAa,UAAU;AAAA,QACvB,MAAM,UAAU;AAAA,QAChB,MAAM,UAAU;AAAA,QAChB,YAAY;AAAA,QACZ,aAAa;AAAA,MACf,CAAC;AAAA;AAAA;AAAA,EAOL,YAAY,CACV,MACA,UACA,SACA,UAKM;AAAA,IACN,KAAK,MAAM,IAAI,MAAM;AAAA,MACnB;AAAA,MACA;AAAA,MACA;AAAA,MACA,aAAa,UAAU;AAAA,MACvB,MAAM,UAAU;AAAA,MAChB,MAAM,UAAU;AAAA,MAChB,WAAW;AAAA,MACX,YAAY;AAAA,IACd,CAAC;AAAA;AAAA,EAMH,QAAQ,CAAC,MAAyC;AAAA,IAChD,OAAO,KAAK,OAAO,IAAI,IAAI;AAAA;AAAA,EAM7B,YAAY,GAAoB;AAAA,IAC9B,OAAO,MAAM,KAAK,KAAK,OAAO,OAAO,CAAC;AAAA;AAAA,EAMxC,WAAW,GAAmB;AAAA,IAC5B,OAAO,MAAM,KAAK,KAAK,MAAM,OAAO,CAAC;AAAA;AAAA,EAMvC,mBAAmB,CAAC,MAAc,SAAS,OAAa;AAAA,IACtD,MAAM,QAAQ,KAAK,OAAO,IAAI,IAAI;AAAA,IAClC,IAAI,OAAO;AAAA,MACT,MAAM;AAAA,MACN,IAAI,QAAQ;AAAA,QACV,MAAM;AAAA,MACR;AAAA,MACA,MAAM,gBAAgB,IAAI;AAAA,IAC5B;AAAA;AAAA,EAMF,kBAAkB,CAAC,MAAc,SAAS,OAAa;AAAA,IACrD,MAAM,OAAO,KAAK,MAAM,IAAI,IAAI;AAAA,IAChC,IAAI,MAAM;AAAA,MACR,KAAK;AAAA,MACL,IAAI,QAAQ;AAAA,QACV,KAAK;AAAA,MACP;AAAA,MACA,KAAK,UAAU,IAAI;AAAA,IACrB;AAAA;AAAA,EAMF,KAAK,GAAS;AAAA,IACZ,KAAK,OAAO,MAAM;AAAA,IAClB,KAAK,MAAM,MAAM;AAAA;AAErB;AAGO,IAAM,gBAAgB,IAAI;",
8
+ "debugId": "BE322C66D6CB104A64756E2164756E21",
9
+ "names": []
10
+ }
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * @getvision/server - Meta-framework with built-in observability
3
- *
3
+ *
4
4
  * Features:
5
5
  * - Built on Hono (ultra-fast, edge-ready)
6
6
  * - Built-in Vision Dashboard (tracing, logging)
@@ -8,12 +8,12 @@
8
8
  * - Pub/Sub & Cron via BullMQ (automatic)
9
9
  * - Service builder pattern
10
10
  * - c.span() for custom tracing
11
- *
11
+ *
12
12
  * @example
13
13
  * ```ts
14
14
  * import { Vision } from '@getvision/server'
15
15
  * import { z } from 'zod'
16
- *
16
+ *
17
17
  * const app = new Vision({
18
18
  * service: {
19
19
  * name: 'My API',
@@ -27,7 +27,7 @@
27
27
  * }
28
28
  * }
29
29
  * })
30
- *
30
+ *
31
31
  * const userService = app.service('users')
32
32
  * .endpoint('GET', '/users/:id', schema, async (data, c) => {
33
33
  * // c.span() is built-in!
@@ -39,30 +39,16 @@
39
39
  * .on('user/created', async (event) => {
40
40
  * console.log('User created:', event.data)
41
41
  * })
42
- *
42
+ *
43
43
  * app.start(3000)
44
44
  * ```
45
45
  */
46
-
47
- // Main Vision class
48
- export { Vision, getVisionContext } from './vision-app'
49
- export type { VisionConfig } from './vision-app'
50
-
51
- // Service builder (usually accessed via app.service())
52
- export { ServiceBuilder } from './service'
53
-
54
- // Event bus
55
- export { EventBus } from './event-bus'
56
- export type { EventBusConfig } from './event-bus'
57
-
58
- // Types
59
- export type {
60
- EndpointConfig,
61
- Handler,
62
- VisionContext,
63
- ExtendedContext
64
- } from './types'
65
-
66
- // Re-export from core for convenience
67
- export { VisionCore } from '@getvision/core'
68
- export type * from '@getvision/core'
46
+ export { Vision, getVisionContext } from './vision-app';
47
+ export type { VisionConfig } from './vision-app';
48
+ export { ServiceBuilder } from './service';
49
+ export { EventBus } from './event-bus';
50
+ export type { EventBusConfig } from './event-bus';
51
+ export type { EndpointConfig, Handler, VisionContext, ExtendedContext } from './types';
52
+ export { VisionCore } from '@getvision/core';
53
+ export type * from '@getvision/core';
54
+ //# sourceMappingURL=index.d.ts.map