@getvision/server 0.4.3-d4c761e-develop → 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 (45) hide show
  1. package/CHANGELOG.md +8 -0
  2. package/dist/event-bus.d.ts +87 -0
  3. package/dist/event-bus.d.ts.map +1 -0
  4. package/dist/event-bus.js +265 -0
  5. package/dist/event-bus.js.map +10 -0
  6. package/dist/event-registry.d.ts +79 -0
  7. package/dist/event-registry.d.ts.map +1 -0
  8. package/dist/event-registry.js +93 -0
  9. package/dist/event-registry.js.map +10 -0
  10. package/{src/index.ts → dist/index.d.ts} +14 -28
  11. package/dist/index.d.ts.map +1 -0
  12. package/dist/index.js +33 -0
  13. package/dist/index.js.map +10 -0
  14. package/dist/router.d.ts +16 -0
  15. package/dist/router.d.ts.map +1 -0
  16. package/dist/router.js +117 -0
  17. package/dist/router.js.map +10 -0
  18. package/dist/service.d.ts +151 -0
  19. package/dist/service.d.ts.map +1 -0
  20. package/dist/service.js +341 -0
  21. package/dist/service.js.map +10 -0
  22. package/dist/types.d.ts +71 -0
  23. package/dist/types.d.ts.map +1 -0
  24. package/dist/types.js +2 -0
  25. package/dist/types.js.map +9 -0
  26. package/dist/vision-app.d.ts +166 -0
  27. package/dist/vision-app.d.ts.map +1 -0
  28. package/dist/vision-app.js +611 -0
  29. package/dist/vision-app.js.map +10 -0
  30. package/dist/vision.d.ts +63 -0
  31. package/dist/vision.d.ts.map +1 -0
  32. package/dist/vision.js +223 -0
  33. package/dist/vision.js.map +10 -0
  34. package/package.json +13 -3
  35. package/.env.example +0 -3
  36. package/.eslintrc.cjs +0 -7
  37. package/.turbo/turbo-build.log +0 -1
  38. package/src/event-bus.ts +0 -409
  39. package/src/event-registry.ts +0 -158
  40. package/src/router.ts +0 -118
  41. package/src/service.ts +0 -618
  42. package/src/types.ts +0 -93
  43. package/src/vision-app.ts +0 -880
  44. package/src/vision.ts +0 -319
  45. package/tsconfig.json +0 -9
@@ -0,0 +1,341 @@
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/service.ts
21
+ import { generateTemplate } from "@getvision/core";
22
+ import {
23
+ ValidationError,
24
+ createValidationErrorResponse,
25
+ UniversalValidator
26
+ } from "@getvision/core";
27
+ import { getVisionContext } from "./vision-app";
28
+ import { eventRegistry } from "./event-registry";
29
+ import { rateLimiter } from "hono-rate-limiter";
30
+ function parseWindowMs(window) {
31
+ const trimmed = window.trim();
32
+ if (/^\d+$/.test(trimmed))
33
+ return Number(trimmed);
34
+ const match = trimmed.match(/^(\d+)\s*([smhd])$/i);
35
+ if (!match)
36
+ throw new Error(`Invalid ratelimit window: ${window}`);
37
+ const value = Number(match[1]);
38
+ const unit = match[2].toLowerCase();
39
+ const multipliers = { s: 1000, m: 60000, h: 3600000, d: 86400000 };
40
+ return value * multipliers[unit];
41
+ }
42
+ function getClientKey(c, method, path) {
43
+ const ip = c.req.header("x-forwarded-for")?.split(",")[0].trim() || c.req.header("x-real-ip") || c.req.header("cf-connecting-ip") || c.req.header("fly-client-ip") || c.req.header("x-client-ip") || "";
44
+ const ua = c.req.header("user-agent") || "unknown";
45
+ return `${ip || ua}:${method}:${path}`;
46
+ }
47
+ function createEventContext() {
48
+ const store = {};
49
+ const mockRequest = new Request("http://localhost/event-trigger");
50
+ const resHeaders = new Headers;
51
+ const fake = {
52
+ get: (key) => store[key],
53
+ set: (key, value) => {
54
+ store[key] = value;
55
+ },
56
+ header: (key, value) => {
57
+ if (value === undefined) {
58
+ resHeaders.delete(key);
59
+ } else {
60
+ resHeaders.set(key, value);
61
+ }
62
+ },
63
+ status: (code) => {},
64
+ req: {
65
+ header: (name) => name ? undefined : {},
66
+ param: () => ({}),
67
+ query: () => ({}),
68
+ json: async () => ({}),
69
+ raw: mockRequest,
70
+ url: "http://localhost/event-trigger",
71
+ method: "POST"
72
+ },
73
+ res: {
74
+ headers: resHeaders
75
+ }
76
+ };
77
+ return fake;
78
+ }
79
+ async function runMiddlewareChain(middlewares, c) {
80
+ let index = -1;
81
+ const dispatch = async (i) => {
82
+ if (i <= index)
83
+ throw new Error("next() called multiple times");
84
+ index = i;
85
+ const mw = middlewares[i];
86
+ if (!mw)
87
+ return;
88
+ await mw(c, () => dispatch(i + 1));
89
+ };
90
+ await dispatch(0);
91
+ }
92
+
93
+ class ServiceBuilder {
94
+ name;
95
+ eventBus;
96
+ visionCore;
97
+ endpoints = new Map;
98
+ eventHandlers = new Map;
99
+ cronJobs = new Map;
100
+ globalMiddleware = [];
101
+ eventSchemas = {};
102
+ constructor(name, eventBus, visionCore) {
103
+ this.name = name;
104
+ this.eventBus = eventBus;
105
+ this.visionCore = visionCore;
106
+ }
107
+ use(...middleware) {
108
+ this.globalMiddleware.push(...middleware);
109
+ return this;
110
+ }
111
+ getRoutesMetadata() {
112
+ const routes = [];
113
+ this.endpoints.forEach((ep) => {
114
+ let requestBody = undefined;
115
+ let queryParams = undefined;
116
+ if (ep.schema.input) {
117
+ if (["POST", "PUT", "PATCH"].includes(ep.method)) {
118
+ requestBody = generateTemplate(ep.schema.input);
119
+ } else if (ep.method === "GET" || ep.method === "DELETE") {
120
+ const pathParamNames = (ep.path.match(/:([^/]+)/g) || []).map((p) => p.slice(1));
121
+ const fullTemplate = generateTemplate(ep.schema.input);
122
+ if (fullTemplate && pathParamNames.length > 0) {
123
+ const queryFields = fullTemplate.fields.filter((f) => !pathParamNames.includes(f.name));
124
+ if (queryFields.length > 0) {
125
+ queryParams = { ...fullTemplate, fields: queryFields };
126
+ }
127
+ } else {
128
+ queryParams = fullTemplate;
129
+ }
130
+ }
131
+ }
132
+ let responseBody = undefined;
133
+ if (ep.schema.output) {
134
+ responseBody = generateTemplate(ep.schema.output);
135
+ }
136
+ routes.push({
137
+ method: ep.method,
138
+ path: ep.path,
139
+ queryParams,
140
+ requestBody,
141
+ responseBody
142
+ });
143
+ });
144
+ return routes;
145
+ }
146
+ getDisplayName() {
147
+ return this.name.charAt(0).toUpperCase() + this.name.slice(1);
148
+ }
149
+ endpoint(method, path, schema, handler, config) {
150
+ this.endpoints.set(`${method}:${path}`, {
151
+ method,
152
+ path,
153
+ handler,
154
+ schema,
155
+ config: { ...config, method, path },
156
+ middleware: config?.middleware || []
157
+ });
158
+ return this;
159
+ }
160
+ on(eventName, config) {
161
+ const { schema, handler, description, icon, tags } = config;
162
+ this.eventSchemas[eventName] = schema;
163
+ const wrappedHandler = async (data) => {
164
+ const ctx = createEventContext();
165
+ if (this.globalMiddleware.length > 0) {
166
+ await runMiddlewareChain(this.globalMiddleware, ctx);
167
+ }
168
+ await handler(data, ctx);
169
+ };
170
+ eventRegistry.registerEvent(eventName, schema, wrappedHandler, { description, icon, tags });
171
+ this.eventBus.registerHandler(eventName, wrappedHandler, {
172
+ concurrency: config.concurrency
173
+ });
174
+ this.eventHandlers.set(eventName, config);
175
+ return this;
176
+ }
177
+ cron(schedule, config) {
178
+ const { handler, description, icon, tags } = config;
179
+ const cronName = `${this.name}.cron.${schedule}`;
180
+ eventRegistry.registerCron(cronName, schedule, handler, { description, icon, tags });
181
+ this.cronJobs.set(cronName, { schedule, ...config });
182
+ this.setupCronJob(cronName, schedule, handler);
183
+ return this;
184
+ }
185
+ async setupCronJob(cronName, schedule, handler) {
186
+ const queue = await this.eventBus.getQueueForCron(cronName);
187
+ await queue.upsertJobScheduler(cronName, {
188
+ pattern: schedule
189
+ }, {
190
+ name: cronName,
191
+ data: {},
192
+ opts: {}
193
+ });
194
+ this.eventBus.registerCronHandler(cronName, handler);
195
+ }
196
+ build(app, servicesAccumulator) {
197
+ const routes = Array.from(this.endpoints.values()).map((ep) => {
198
+ let requestBody = undefined;
199
+ let queryParams = undefined;
200
+ if (ep.schema.input) {
201
+ if (["POST", "PUT", "PATCH"].includes(ep.method)) {
202
+ requestBody = generateTemplate(ep.schema.input);
203
+ } else if (ep.method === "GET" || ep.method === "DELETE") {
204
+ const pathParamNames = (ep.path.match(/:([^/]+)/g) || []).map((p) => p.slice(1));
205
+ const fullTemplate = generateTemplate(ep.schema.input);
206
+ if (fullTemplate && pathParamNames.length > 0) {
207
+ const queryFields = fullTemplate.fields.filter((f) => !pathParamNames.includes(f.name));
208
+ if (queryFields.length > 0) {
209
+ queryParams = { ...fullTemplate, fields: queryFields };
210
+ }
211
+ } else {
212
+ queryParams = fullTemplate;
213
+ }
214
+ }
215
+ }
216
+ let responseBody = undefined;
217
+ if (ep.schema.output) {
218
+ responseBody = generateTemplate(ep.schema.output);
219
+ }
220
+ return {
221
+ method: ep.method,
222
+ path: ep.path,
223
+ handler: this.name,
224
+ middleware: [],
225
+ queryParams,
226
+ requestBody,
227
+ responseBody
228
+ };
229
+ });
230
+ const capitalizedName = this.name.charAt(0).toUpperCase() + this.name.slice(1);
231
+ if (servicesAccumulator) {
232
+ servicesAccumulator.push({
233
+ name: capitalizedName,
234
+ routes
235
+ });
236
+ }
237
+ this.endpoints.forEach((ep) => {
238
+ let rateLimitMw;
239
+ const rl = ep.config?.ratelimit;
240
+ if (rl) {
241
+ const windowMs = parseWindowMs(rl.window);
242
+ const limit = rl.requests;
243
+ rateLimitMw = rateLimiter({
244
+ windowMs,
245
+ limit,
246
+ standardHeaders: "draft-6",
247
+ keyGenerator: (c) => getClientKey(c, ep.method, ep.path),
248
+ ...rl.store ? { store: rl.store } : {}
249
+ });
250
+ }
251
+ const allMiddleware = [
252
+ ...this.globalMiddleware,
253
+ ...rateLimitMw ? [rateLimitMw] : [],
254
+ ...ep.middleware
255
+ ];
256
+ const finalHandler = async (c) => {
257
+ try {
258
+ const visionCtx = getVisionContext();
259
+ if (visionCtx && this.visionCore) {
260
+ const { vision, traceId, rootSpanId } = visionCtx;
261
+ const tracer = vision.getTracer();
262
+ c.addContext = (context) => {
263
+ const current = getVisionContext();
264
+ const targetTraceId = current?.traceId || traceId;
265
+ const visionTrace = vision.getTraceStore().getTrace(targetTraceId);
266
+ if (visionTrace) {
267
+ visionTrace.metadata = { ...visionTrace.metadata || {}, ...context };
268
+ }
269
+ };
270
+ c.span = (name, attributes = {}, fn) => {
271
+ const span = tracer.startSpan(name, traceId, rootSpanId);
272
+ for (const [key, value] of Object.entries(attributes)) {
273
+ tracer.setAttribute(span.id, key, value);
274
+ }
275
+ try {
276
+ const result2 = fn ? fn() : undefined;
277
+ const completedSpan = tracer.endSpan(span.id);
278
+ if (completedSpan) {
279
+ vision.getTraceStore().addSpan(traceId, completedSpan);
280
+ }
281
+ return result2;
282
+ } catch (error) {
283
+ tracer.setAttribute(span.id, "error", true);
284
+ tracer.setAttribute(span.id, "error.message", error instanceof Error ? error.message : String(error));
285
+ const completedSpan = tracer.endSpan(span.id);
286
+ if (completedSpan) {
287
+ vision.getTraceStore().addSpan(traceId, completedSpan);
288
+ }
289
+ throw error;
290
+ }
291
+ };
292
+ }
293
+ if (!c.emit) {
294
+ c.emit = async (eventName, data) => {
295
+ return this.eventBus.emit(eventName, data);
296
+ };
297
+ }
298
+ const params = c.req.param();
299
+ const query = c.req.query();
300
+ let body = {};
301
+ if (["POST", "PUT", "PATCH"].includes(ep.method)) {
302
+ body = await c.req.json().catch(() => ({}));
303
+ }
304
+ const input = { ...params, ...query, ...body };
305
+ const validated = UniversalValidator.parse(ep.schema.input, input);
306
+ const finalInput = { ...params, ...validated || {} };
307
+ const result = await ep.handler(finalInput, c);
308
+ if (ep.schema.output) {
309
+ const validatedOutput = UniversalValidator.parse(ep.schema.output, result);
310
+ return c.json(validatedOutput);
311
+ }
312
+ if (result instanceof Response) {
313
+ return result;
314
+ }
315
+ return c.json(result);
316
+ } catch (error) {
317
+ if (error instanceof ValidationError) {
318
+ const requestId = c.req.header("x-request-id");
319
+ return c.json(createValidationErrorResponse(error.issues, requestId), 400);
320
+ }
321
+ throw error;
322
+ }
323
+ };
324
+ if (allMiddleware.length > 0) {
325
+ app.on([ep.method], ep.path, ...allMiddleware, finalHandler);
326
+ } else {
327
+ app.on([ep.method], ep.path, finalHandler);
328
+ }
329
+ });
330
+ return {
331
+ endpoints: Array.from(this.endpoints.values()),
332
+ eventHandlers: Array.from(this.eventHandlers.values()),
333
+ cronJobs: Array.from(this.cronJobs.values())
334
+ };
335
+ }
336
+ }
337
+ export {
338
+ ServiceBuilder
339
+ };
340
+
341
+ //# debugId=786008A0EDA35F9864756E2164756E21
@@ -0,0 +1,10 @@
1
+ {
2
+ "version": 3,
3
+ "sources": ["../src/service.ts"],
4
+ "sourcesContent": [
5
+ "import type { Hono, Context, MiddlewareHandler, Env, Input } from 'hono'\nimport type { z } from 'zod'\nimport { VisionCore, generateTemplate } from '@getvision/core'\nimport {\n ValidationError,\n createValidationErrorResponse,\n UniversalValidator\n} from '@getvision/core'\nimport type { EndpointConfig, Handler } from './types'\nimport { getVisionContext } from './vision-app'\nimport { eventRegistry } from './event-registry'\nimport type { EventBus } from './event-bus'\nimport { rateLimiter } from 'hono-rate-limiter'\n\n// Simple window parser supporting values like '15m', '1h', '30s', '2d' or plain milliseconds as number string\nfunction parseWindowMs(window: string): number {\n const trimmed = window.trim()\n if (/^\\d+$/.test(trimmed)) return Number(trimmed)\n const match = trimmed.match(/^(\\d+)\\s*([smhd])$/i)\n if (!match) throw new Error(`Invalid ratelimit window: ${window}`)\n const value = Number(match[1])\n const unit = match[2].toLowerCase()\n const multipliers: Record<string, number> = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }\n return value * multipliers[unit]\n}\n\nfunction getClientKey(c: Context, method: string, path: string): string {\n const ip =\n c.req.header('x-forwarded-for')?.split(',')[0].trim() ||\n c.req.header('x-real-ip') ||\n c.req.header('cf-connecting-ip') ||\n c.req.header('fly-client-ip') ||\n c.req.header('x-client-ip') ||\n ''\n // Fallback to UA if no IP available (still scoped per endpoint)\n const ua = c.req.header('user-agent') || 'unknown'\n return `${ip || ua}:${method}:${path}`\n}\n\n/**\n * Create a minimal Hono-like Context for event handlers\n * so service-level middleware can populate c.set(...)\n */\nfunction createEventContext<E extends Env = any, I extends Input = {}>(): Context<E, any, I> {\n const store: Record<string, any> = {}\n const mockRequest = new Request('http://localhost/event-trigger')\n const resHeaders = new Headers()\n \n const fake: Partial<Context<E, any, I>> = {\n get: (key: string) => store[key],\n set: (key: string, value: any) => { store[key] = value },\n header: (key: string, value: string | undefined) => { \n if (value === undefined) {\n resHeaders.delete(key)\n } else {\n resHeaders.set(key, value) \n }\n },\n status: (code: number) => {},\n req: {\n header: ((name?: string) => name ? undefined : {}) as any,\n param: () => ({}),\n query: () => ({}),\n json: async () => ({}),\n raw: mockRequest,\n url: 'http://localhost/event-trigger',\n method: 'POST',\n } as any,\n res: {\n headers: resHeaders,\n } as any,\n }\n return fake as Context<E, any, I>\n}\n\n/**\n * Run Hono middleware chain on a context\n */\nasync function runMiddlewareChain<E extends Env, I extends Input>(\n middlewares: MiddlewareHandler<E, string, any, any>[],\n c: Context<E, any, I>\n): Promise<void> {\n let index = -1\n const dispatch = async (i: number): Promise<void> => {\n if (i <= index) throw new Error('next() called multiple times')\n index = i\n const mw = middlewares[i]\n if (!mw) return\n await mw(c, () => dispatch(i + 1))\n }\n await dispatch(0)\n}\n\n/**\n * Event schema map - accumulates event types as they're registered\n */\ntype EventSchemaMap = Record<string, z.ZodSchema<any>>\n\n/**\n * ServiceBuilder - Builder pattern API for defining services\n * \n * Automatically infers event types from Zod schemas passed to .on()\n * \n * @example\n * ```ts\n * const userService = app.service('users')\n * .use(logger())\n * .endpoint('GET', '/users/:id', { input, output }, handler)\n * .on('user/created', {\n * schema: z.object({ userId: z.string(), email: z.string() }),\n * handler: async (event) => {\n * // event is fully typed: { userId: string, email: string }\n * }\n * })\n * ```\n */\nexport class ServiceBuilder<\n TEvents extends EventSchemaMap = {},\n E extends Env = Env,\n I extends Input = {}\n> {\n private endpoints: Map<string, any> = new Map()\n private eventHandlers: Map<string, any> = new Map()\n private cronJobs: Map<string, any> = new Map()\n private globalMiddleware: MiddlewareHandler<E, string, any, any>[] = []\n private eventSchemas: EventSchemaMap = {}\n \n constructor(\n private name: string,\n private eventBus: EventBus,\n private visionCore?: VisionCore\n ) {}\n \n /**\n * Add global middleware for all endpoints in this service\n */\n use(...middleware: MiddlewareHandler<E, string, any, any>[]) {\n this.globalMiddleware.push(...middleware)\n return this\n }\n\n /**\n * Get service name (capitalized) and route metadata without registering\n */\n public getRoutesMetadata(): Array<{\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n path: string\n queryParams?: any\n requestBody?: any\n responseBody?: any\n }> {\n const routes: Array<{\n method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH'\n path: string\n queryParams?: any\n requestBody?: any\n responseBody?: any\n }> = []\n this.endpoints.forEach((ep) => {\n let requestBody = undefined\n let queryParams = undefined\n \n if (ep.schema.input) {\n if (['POST', 'PUT', 'PATCH'].includes(ep.method)) {\n requestBody = generateTemplate(ep.schema.input)\n } else if (ep.method === 'GET' || ep.method === 'DELETE') {\n // Exclude path params from query params\n const pathParamNames = (ep.path.match(/:([^/]+)/g) || []).map((p: string) => p.slice(1))\n const fullTemplate = generateTemplate(ep.schema.input)\n \n if (fullTemplate && pathParamNames.length > 0) {\n const queryFields = fullTemplate.fields.filter(\n (f: { name: string }) => !pathParamNames.includes(f.name)\n )\n if (queryFields.length > 0) {\n queryParams = { ...fullTemplate, fields: queryFields }\n }\n } else {\n queryParams = fullTemplate\n }\n }\n }\n \n let responseBody = undefined\n if (ep.schema.output) {\n responseBody = generateTemplate(ep.schema.output)\n }\n routes.push({\n method: ep.method,\n path: ep.path,\n queryParams,\n requestBody,\n responseBody,\n })\n })\n return routes\n }\n\n public getDisplayName(): string {\n return this.name.charAt(0).toUpperCase() + this.name.slice(1)\n }\n \n /**\n * Define an HTTP endpoint with Zod validation\n * \n * @example\n * ```ts\n * service.endpoint(\n * 'GET',\n * '/users/:id',\n * {\n * input: z.object({ id: z.string() }),\n * output: z.object({ id: z.string(), name: z.string() })\n * },\n * async ({ id }, c) => {\n * return { id, name: 'John' }\n * },\n * { middleware: [authMiddleware] }\n * )\n * ```\n */\n endpoint<\n TInputSchema extends z.ZodType,\n TOutputSchema extends z.ZodType | undefined,\n PPath extends string\n >(\n method: EndpointConfig['method'],\n path: PPath,\n schema: {\n input: TInputSchema\n output?: TOutputSchema\n },\n handler: Handler<\n z.infer<TInputSchema>,\n TOutputSchema extends z.ZodType ? z.infer<TOutputSchema> : any,\n TEvents,\n E,\n PPath,\n I\n >,\n config?: Partial<EndpointConfig>\n ) {\n this.endpoints.set(`${method}:${path}`, {\n method,\n path,\n handler,\n schema,\n config: { ...config, method, path },\n middleware: config?.middleware || []\n })\n return this\n }\n \n /**\n * Subscribe to events with Zod schema validation\n * \n * Automatically infers the event type from the Zod schema.\n * TypeScript will ensure that c.emit() calls match the registered schema.\n * \n * @example\n * ```ts\n * service.on('user/created', {\n * schema: z.object({\n * userId: z.string().uuid(),\n * email: z.string().email()\n * }),\n * description: 'User account created',\n * icon: '👤',\n * tags: ['user', 'auth'],\n * handler: async (event) => {\n * // event is fully typed: { userId: string, email: string }\n * console.log('User created:', event.email)\n * }\n * })\n * ```\n */\n on<\n K extends string,\n T extends Record<string, any>\n >(\n eventName: K,\n config: {\n schema: z.ZodSchema<T>\n description?: string\n icon?: string\n tags?: string[]\n /**\n * Max number of concurrent jobs this handler will process.\n * Falls back to EventBus config.workerConcurrency (or 1).\n */\n concurrency?: number\n handler: (event: T, c: Context<E, any, I>) => Promise<void>\n }\n ): ServiceBuilder<TEvents & { [key in K]: T }, E, I> {\n const { schema, handler, description, icon, tags } = config\n \n // Store schema for type inference\n this.eventSchemas[eventName] = schema\n \n // Wrap handler to provide Hono-like context with middleware support\n const wrappedHandler = async (data: T) => {\n const ctx = createEventContext<E, I>()\n // Run service-level middleware to populate ctx (e.g., c.set('db', db))\n if (this.globalMiddleware.length > 0) {\n await runMiddlewareChain(this.globalMiddleware, ctx)\n }\n // Call original handler with event data and context\n await handler(data, ctx)\n }\n \n // Register wrapped handler in event registry (for metadata/stats)\n eventRegistry.registerEvent(\n eventName,\n schema,\n wrappedHandler,\n { description, icon, tags }\n )\n \n // Register wrapped handler in event bus\n this.eventBus.registerHandler(eventName, wrappedHandler, {\n concurrency: config.concurrency,\n })\n \n // Store for later reference\n this.eventHandlers.set(eventName, config)\n \n // Return typed ServiceBuilder with accumulated events\n return this as ServiceBuilder<TEvents & { [key in K]: T }, E, I>\n }\n \n /**\n * Schedule a cron job using BullMQ Repeatable\n * \n * @example\n * ```ts\n * service.cron('0 0 * * *', {\n * description: 'Daily cleanup',\n * icon: '🧹',\n * tags: ['maintenance'],\n * handler: async (c) => {\n * console.log('Daily cleanup')\n * }\n * })\n * ```\n */\n cron(\n schedule: string,\n config: {\n description?: string\n icon?: string\n tags?: string[]\n handler: (context: any) => Promise<void>\n }\n ) {\n const { handler, description, icon, tags } = config\n const cronName = `${this.name}.cron.${schedule}`\n \n // Register in event registry\n eventRegistry.registerCron(\n cronName,\n schedule,\n handler,\n { description, icon, tags }\n )\n \n // Store for later reference\n this.cronJobs.set(cronName, { schedule, ...config })\n \n // Setup BullMQ repeatable job\n // This will be called when the service is built\n this.setupCronJob(cronName, schedule, handler)\n \n return this\n }\n \n /**\n * Setup BullMQ repeatable job for cron\n */\n private async setupCronJob(\n cronName: string,\n schedule: string,\n handler: (context: any) => Promise<void>\n ) {\n // Get queue from EventBus (we'll add a getQueue method)\n const queue = await this.eventBus.getQueueForCron(cronName)\n \n // Register cron job using BullMQ upsertJobScheduler\n await queue.upsertJobScheduler(\n cronName,\n {\n pattern: schedule, // Cron expression (e.g., '0 0 * * *')\n },\n {\n name: cronName,\n data: {},\n opts: {},\n }\n )\n \n // Register worker to process cron jobs\n this.eventBus.registerCronHandler(cronName, handler)\n }\n \n /**\n * Build and register all endpoints with Hono\n */\n build(app: Hono, servicesAccumulator?: Array<{ name: string; routes: any[] }>) {\n // Prepare routes with Zod schemas\n const routes = Array.from(this.endpoints.values()).map(ep => {\n // Generate requestBody schema (input) for POST/PUT/PATCH\n let requestBody = undefined\n let queryParams = undefined\n \n if (ep.schema.input) {\n if (['POST', 'PUT', 'PATCH'].includes(ep.method)) {\n requestBody = generateTemplate(ep.schema.input)\n } else if (ep.method === 'GET' || ep.method === 'DELETE') {\n // For GET/DELETE, input schema represents query parameters\n // BUT we need to exclude path params from query params\n const pathParamNames = (ep.path.match(/:([^/]+)/g) || []).map((p: string) => p.slice(1))\n const fullTemplate = generateTemplate(ep.schema.input)\n \n if (fullTemplate && pathParamNames.length > 0) {\n // Filter out path params from query params\n const queryFields = fullTemplate.fields.filter(\n (f: { name: string }) => !pathParamNames.includes(f.name)\n )\n if (queryFields.length > 0) {\n queryParams = { ...fullTemplate, fields: queryFields }\n }\n } else {\n queryParams = fullTemplate\n }\n }\n }\n \n // Generate responseBody schema (output)\n let responseBody = undefined\n if (ep.schema.output) {\n responseBody = generateTemplate(ep.schema.output)\n }\n \n return {\n method: ep.method,\n path: ep.path,\n handler: this.name,\n middleware: [],\n queryParams,\n requestBody,\n responseBody,\n }\n })\n \n const capitalizedName = this.name.charAt(0).toUpperCase() + this.name.slice(1)\n \n // Add to accumulator (для батч реєстрації в buildAllServices)\n if (servicesAccumulator) {\n servicesAccumulator.push({\n name: capitalizedName,\n routes\n })\n }\n \n // Register HTTP endpoints\n this.endpoints.forEach((ep) => {\n // Prepare rate limiter when configured per-endpoint\n let rateLimitMw: MiddlewareHandler<E, string, any, any> | undefined\n const rl = ep.config?.ratelimit as EndpointConfig['ratelimit'] | undefined\n if (rl) {\n const windowMs = parseWindowMs(rl.window)\n const limit = rl.requests\n rateLimitMw = rateLimiter({\n windowMs,\n limit,\n standardHeaders: 'draft-6',\n keyGenerator: (c) => getClientKey(c, ep.method, ep.path),\n // If user provides a distributed store (e.g., RedisStore), pass it through\n ...(rl.store ? { store: rl.store } : {}),\n })\n }\n\n // Combine global + rate-limit (if any) + endpoint-specific middleware\n const allMiddleware = [\n ...this.globalMiddleware,\n ...(rateLimitMw ? [rateLimitMw] as MiddlewareHandler<E, string, any, any>[] : []),\n ...ep.middleware,\n ]\n \n // Create handler with middleware chain\n const finalHandler = async (c: Context<E, any, I>) => {\n try {\n // Add span helper and emit to context\n const visionCtx = getVisionContext()\n if (visionCtx && this.visionCore) {\n const { vision, traceId, rootSpanId } = visionCtx\n const tracer = vision.getTracer();\n \n // Add addContext() method to context\n (c as any).addContext = (context: Record<string, unknown>) => {\n const current = getVisionContext()\n // Use current traceId from context if available (handles nested spans/async correctly)\n const targetTraceId = current?.traceId || traceId\n \n const visionTrace = vision.getTraceStore().getTrace(targetTraceId)\n if (visionTrace) {\n visionTrace.metadata = { ...(visionTrace.metadata || {}), ...context }\n }\n }\n\n // Add span() method to context\n (c as any).span = <T>(\n name: string,\n attributes: Record<string, any> = {},\n fn?: () => T\n ): T => {\n const span = tracer.startSpan(name, traceId, rootSpanId)\n \n for (const [key, value] of Object.entries(attributes)) {\n tracer.setAttribute(span.id, key, value)\n }\n \n try {\n const result = fn ? fn() : (undefined as any)\n const completedSpan = tracer.endSpan(span.id)\n \n if (completedSpan) {\n vision.getTraceStore().addSpan(traceId, completedSpan)\n }\n \n return result\n } catch (error) {\n tracer.setAttribute(span.id, 'error', true)\n tracer.setAttribute(\n span.id,\n 'error.message',\n error instanceof Error ? error.message : String(error)\n )\n const completedSpan = tracer.endSpan(span.id)\n \n if (completedSpan) {\n vision.getTraceStore().addSpan(traceId, completedSpan)\n }\n \n throw error\n }\n }\n }\n\n // Always provide emit() so events work in sub-apps without local VisionCore\n if (!(c as any).emit) {\n (c as any).emit = async <K extends keyof TEvents>(\n eventName: K,\n data: TEvents[K]\n ): Promise<void> => {\n return this.eventBus.emit(eventName as string, data)\n }\n }\n \n // Parse and merge params, body, query\n const params = c.req.param()\n const query = c.req.query()\n let body = {}\n \n if (['POST', 'PUT', 'PATCH'].includes(ep.method)) {\n body = await c.req.json().catch(() => ({}))\n }\n \n const input = { ...params, ...query, ...body }\n \n // Validate input with UniversalValidator (supports Zod, Valibot, etc.)\n const validated = UniversalValidator.parse(ep.schema.input, input)\n \n // Merge back path params that are not in the schema\n // This ensures path params like :id are always available to the handler\n const finalInput = { ...params, ...(validated || {}) }\n \n // Execute handler\n const result = await ep.handler(finalInput, c as any)\n\n // If an output schema exists, validate and return JSON\n if (ep.schema.output) {\n const validatedOutput = UniversalValidator.parse(ep.schema.output, result)\n return c.json(validatedOutput)\n }\n\n // No output schema: allow raw Response or JSON\n if (result instanceof Response) {\n return result\n }\n return c.json(result)\n } catch (error) {\n if (error instanceof ValidationError) {\n const requestId = c.req.header('x-request-id')\n return c.json(\n createValidationErrorResponse(error.issues, requestId),\n 400\n )\n }\n throw error\n }\n }\n \n // Register with middleware chain\n if (allMiddleware.length > 0) {\n app.on([ep.method], ep.path, ...allMiddleware, finalHandler)\n } else {\n app.on([ep.method], ep.path, finalHandler)\n }\n })\n \n return {\n endpoints: Array.from(this.endpoints.values()),\n eventHandlers: Array.from(this.eventHandlers.values()),\n cronJobs: Array.from(this.cronJobs.values())\n }\n }\n}\n\n"
6
+ ],
7
+ "mappings": "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",
8
+ "debugId": "786008A0EDA35F9864756E2164756E21",
9
+ "names": []
10
+ }
@@ -0,0 +1,71 @@
1
+ import type { Context, Env, Input, MiddlewareHandler } from 'hono';
2
+ import type { VisionCore } from '@getvision/core';
3
+ /**
4
+ * Vision context stored in AsyncLocalStorage
5
+ */
6
+ export interface VisionContext<E extends Env = any, P extends string = any, I extends Input = {}> extends Context<E, P, I> {
7
+ vision: VisionCore;
8
+ traceId: string;
9
+ rootSpanId: string;
10
+ }
11
+ /**
12
+ * Endpoint configuration options
13
+ */
14
+ export interface EndpointConfig {
15
+ method: 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
16
+ path: string;
17
+ middleware?: MiddlewareHandler[];
18
+ auth?: boolean;
19
+ ratelimit?: {
20
+ requests: number;
21
+ window: string;
22
+ store?: any;
23
+ };
24
+ cache?: {
25
+ ttl: number;
26
+ };
27
+ }
28
+ /**
29
+ * Extended Context with span helper and emit
30
+ *
31
+ * Generic TEvents parameter allows type-safe event emission
32
+ */
33
+ export interface ExtendedContext<TEvents extends Record<string, any> = {}, E extends Env = any, P extends string = any, I extends Input = {}> extends Context<E, P, I> {
34
+ span<T>(name: string, attributes?: Record<string, any>, fn?: () => T): T;
35
+ /**
36
+ * Add context to the current active trace
37
+ * This is the "Wide Event" API - allowing adding high-cardinality data
38
+ * to the current request context.
39
+ */
40
+ addContext(context: Record<string, unknown>): void;
41
+ /**
42
+ * Emit an event with type-safe validation
43
+ *
44
+ * The event name and data are validated against registered Zod schemas.
45
+ * TypeScript will ensure:
46
+ * 1. The event name is registered (via .on())
47
+ * 2. The data matches the schema exactly
48
+ *
49
+ * @example
50
+ * ```ts
51
+ * // After .on('user/created', { schema: z.object({ userId: z.string(), email: z.string() }) })
52
+ *
53
+ * // ✅ TypeScript allows this:
54
+ * await c.emit('user/created', {
55
+ * userId: '123',
56
+ * email: 'user@example.com'
57
+ * })
58
+ *
59
+ * // ❌ TypeScript errors:
60
+ * await c.emit('unknown/event', {}) // Event not registered
61
+ * await c.emit('user/created', { userId: '123' }) // Missing email
62
+ * await c.emit('user/created', { userId: '123', email: 'x', extra: 'extra' }) // Extra field
63
+ * ```
64
+ */
65
+ emit<K extends keyof TEvents>(eventName: K, data: TEvents[K]): Promise<void>;
66
+ }
67
+ /**
68
+ * Handler type with Zod-validated input and Vision-enhanced context
69
+ */
70
+ export type Handler<TInput = any, TOutput = any, TEvents extends Record<string, any> = {}, E extends Env = any, P extends string = any, I extends Input = {}> = (req: TInput, ctx: ExtendedContext<TEvents, E, P, I>) => Promise<TOutput> | TOutput;
71
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../src/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,iBAAiB,EAAE,MAAM,MAAM,CAAA;AAClE,OAAO,KAAK,EAAE,UAAU,EAAE,MAAM,iBAAiB,CAAA;AAEjD;;GAEG;AACH,MAAM,WAAW,aAAa,CAAC,CAAC,SAAS,GAAG,GAAG,GAAG,EAAE,CAAC,SAAS,MAAM,GAAG,GAAG,EAAE,CAAC,SAAS,KAAK,GAAG,EAAE,CAAE,SAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACxH,MAAM,EAAE,UAAU,CAAA;IAClB,OAAO,EAAE,MAAM,CAAA;IACf,UAAU,EAAE,MAAM,CAAA;CACnB;AAED;;GAEG;AACH,MAAM,WAAW,cAAc;IAC7B,MAAM,EAAE,KAAK,GAAG,MAAM,GAAG,KAAK,GAAG,QAAQ,GAAG,OAAO,CAAA;IACnD,IAAI,EAAE,MAAM,CAAA;IACZ,UAAU,CAAC,EAAE,iBAAiB,EAAE,CAAA;IAEhC,IAAI,CAAC,EAAE,OAAO,CAAA;IACd,SAAS,CAAC,EAAE;QAAE,QAAQ,EAAE,MAAM,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,GAAG,CAAA;KAAE,CAAA;IAC7D,KAAK,CAAC,EAAE;QAAE,GAAG,EAAE,MAAM,CAAA;KAAE,CAAA;CACxB;AAED;;;;GAIG;AACH,MAAM,WAAW,eAAe,CAC9B,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EACxC,CAAC,SAAS,GAAG,GAAG,GAAG,EACnB,CAAC,SAAS,MAAM,GAAG,GAAG,EACtB,CAAC,SAAS,KAAK,GAAG,EAAE,CACpB,SAAQ,OAAO,CAAC,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC;IACxB,IAAI,CAAC,CAAC,EACJ,IAAI,EAAE,MAAM,EACZ,UAAU,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,EAChC,EAAE,CAAC,EAAE,MAAM,CAAC,GACX,CAAC,CAAA;IAEJ;;;;OAIG;IACH,UAAU,CAAC,OAAO,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAAG,IAAI,CAAA;IAElD;;;;;;;;;;;;;;;;;;;;;;;OAuBG;IACH,IAAI,CAAC,CAAC,SAAS,MAAM,OAAO,EAC1B,SAAS,EAAE,CAAC,EACZ,IAAI,EAAE,OAAO,CAAC,CAAC,CAAC,GACf,OAAO,CAAC,IAAI,CAAC,CAAA;CACjB;AAED;;GAEG;AACH,MAAM,MAAM,OAAO,CACjB,MAAM,GAAG,GAAG,EACZ,OAAO,GAAG,GAAG,EACb,OAAO,SAAS,MAAM,CAAC,MAAM,EAAE,GAAG,CAAC,GAAG,EAAE,EACxC,CAAC,SAAS,GAAG,GAAG,GAAG,EACnB,CAAC,SAAS,MAAM,GAAG,GAAG,EACtB,CAAC,SAAS,KAAK,GAAG,EAAE,IAClB,CACF,GAAG,EAAE,MAAM,EACX,GAAG,EAAE,eAAe,CAAC,OAAO,EAAE,CAAC,EAAE,CAAC,EAAE,CAAC,CAAC,KACnC,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA"}
package/dist/types.js ADDED
@@ -0,0 +1,2 @@
1
+
2
+ //# debugId=9FCB033A2878230664756E2164756E21
@@ -0,0 +1,9 @@
1
+ {
2
+ "version": 3,
3
+ "sources": [],
4
+ "sourcesContent": [
5
+ ],
6
+ "mappings": "",
7
+ "debugId": "9FCB033A2878230664756E2164756E21",
8
+ "names": []
9
+ }
@@ -0,0 +1,166 @@
1
+ import { Hono } from 'hono';
2
+ import type { Env, Schema } from 'hono';
3
+ import { VisionCore } from '@getvision/core';
4
+ import type { RouteMetadata } from '@getvision/core';
5
+ import { ServiceBuilder } from './service';
6
+ import { EventBus } from './event-bus';
7
+ import type { serve as honoServe } from '@hono/node-server';
8
+ import type { QueueEventsOptions, QueueOptions, WorkerOptions } from "bullmq";
9
+ export interface VisionALSContext {
10
+ vision: VisionCore;
11
+ traceId: string;
12
+ rootSpanId: string;
13
+ }
14
+ type BunServeOptions = Parameters<typeof Bun['serve']>[0];
15
+ type NodeServeOptions = Parameters<typeof honoServe>[0];
16
+ type VisionStartOptions = Omit<Partial<BunServeOptions>, 'fetch' | 'port'> & Omit<Partial<NodeServeOptions>, 'fetch' | 'port'>;
17
+ /**
18
+ * Vision Server configuration
19
+ */
20
+ export interface VisionConfig {
21
+ service: {
22
+ name: string;
23
+ version?: string;
24
+ description?: string;
25
+ integrations?: Record<string, string>;
26
+ drizzle?: {
27
+ autoStart?: boolean;
28
+ port?: number;
29
+ };
30
+ };
31
+ vision?: {
32
+ enabled?: boolean;
33
+ port?: number;
34
+ maxTraces?: number;
35
+ maxLogs?: number;
36
+ logging?: boolean;
37
+ apiUrl?: string;
38
+ };
39
+ routes?: {
40
+ autodiscover?: boolean;
41
+ dirs?: string[];
42
+ };
43
+ pubsub?: {
44
+ redis?: {
45
+ host?: string;
46
+ port?: number;
47
+ password?: string;
48
+ /**
49
+ * Enable keepalive to prevent connection timeouts (default: 30000ms)
50
+ */
51
+ keepAlive?: number;
52
+ /**
53
+ * Max retry attempts for failed commands (default: 20)
54
+ */
55
+ maxRetriesPerRequest?: number;
56
+ /**
57
+ * Enable ready check before executing commands (default: true)
58
+ */
59
+ enableReadyCheck?: boolean;
60
+ /**
61
+ * Connection timeout in ms (default: 10000)
62
+ */
63
+ connectTimeout?: number;
64
+ /**
65
+ * Enable offline queue (default: true)
66
+ */
67
+ enableOfflineQueue?: boolean;
68
+ };
69
+ devMode?: boolean;
70
+ eventBus?: EventBus;
71
+ /**
72
+ * Default BullMQ worker concurrency for all handlers (overridable per handler)
73
+ */
74
+ workerConcurrency?: number;
75
+ queue?: Omit<QueueOptions, 'connection'>;
76
+ worker?: Omit<WorkerOptions, 'connection'>;
77
+ queueEvents?: Omit<QueueEventsOptions, 'connection'>;
78
+ };
79
+ }
80
+ /**
81
+ * Vision - Meta-framework built on Hono with observability
82
+ *
83
+ * @example
84
+ * ```ts
85
+ * const app = new Vision({
86
+ * service: {
87
+ * name: 'My API',
88
+ * version: '1.0.0'
89
+ * }
90
+ * })
91
+ *
92
+ * const userService = app.service('users')
93
+ * .on('user/created', handler)
94
+ * .endpoint('GET', '/users/:id', schema, handler)
95
+ *
96
+ * app.start(3000)
97
+ * ```
98
+ */
99
+ export declare class Vision<E extends Env = Env, S extends Schema = {}, BasePath extends string = '/'> extends Hono<E, S, BasePath> {
100
+ private visionCore;
101
+ private eventBus;
102
+ private config;
103
+ private serviceBuilders;
104
+ private bunServer?;
105
+ private signalHandler?;
106
+ constructor(config?: VisionConfig);
107
+ /**
108
+ * Register JSON-RPC methods for events and cron jobs
109
+ */
110
+ private registerEventMethods;
111
+ /**
112
+ * Install Vision tracing middleware
113
+ */
114
+ private installVisionMiddleware;
115
+ /**
116
+ * Create a new service with builder pattern
117
+ *
118
+ * @example
119
+ * ```ts
120
+ * const userService = app.service('users')
121
+ * .endpoint('GET', '/users/:id', schema, handler)
122
+ * .on('user/created', handler)
123
+ * ```
124
+ */
125
+ service<E2 extends Env = E, TEvents extends Record<string, any> = {}>(name: string): ServiceBuilder<TEvents, E2, {}>;
126
+ /**
127
+ * Get services and routes metadata without registering to this VisionCore
128
+ */
129
+ getServiceSummaries(): Array<{
130
+ name: string;
131
+ routes: RouteMetadata[];
132
+ }>;
133
+ /**
134
+ * Build all service builders
135
+ */
136
+ buildAllServices(): {
137
+ name: string;
138
+ routes: RouteMetadata[];
139
+ }[];
140
+ /**
141
+ * Get Vision Core instance
142
+ */
143
+ getVision(): VisionCore;
144
+ /**
145
+ * Get EventBus instance
146
+ */
147
+ getEventBus(): EventBus;
148
+ /**
149
+ * Autoload Vision/Hono sub-apps from configured directories
150
+ */
151
+ private autoloadRoutes;
152
+ /**
153
+ * Start the server (convenience method)
154
+ */
155
+ start(port?: number, options?: VisionStartOptions): Promise<this | undefined>;
156
+ /**
157
+ * Set the EventBus instance (used internally by router to inject shared EventBus)
158
+ */
159
+ setEventBus(eventBus: EventBus): void;
160
+ }
161
+ /**
162
+ * Get Vision context (internal use)
163
+ */
164
+ export declare function getVisionContext(): VisionALSContext | undefined;
165
+ export {};
166
+ //# sourceMappingURL=vision-app.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"vision-app.d.ts","sourceRoot":"","sources":["../src/vision-app.ts"],"names":[],"mappings":"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"}