@getvision/server 0.1.2 → 0.2.0-b49d8db-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.
@@ -0,0 +1 @@
1
+ $ tsc --noEmit
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@getvision/server",
3
- "version": "0.1.2",
3
+ "version": "0.2.0-b49d8db-develop",
4
4
  "type": "module",
5
5
  "description": "Vision Server - Meta-framework with built-in observability, pub/sub, and type-safe APIs",
6
6
  "exports": {
@@ -13,17 +13,18 @@
13
13
  },
14
14
  "license": "MIT",
15
15
  "dependencies": {
16
- "@getvision/core": "0.0.2",
16
+ "@getvision/core": "0.0.3",
17
17
  "@hono/node-server": "^1.19.5",
18
18
  "bullmq": "^5.62.0",
19
+ "hono-rate-limiter": "^0.4.2",
19
20
  "hono": "^4.10.4",
20
21
  "ioredis": "^5.8.2",
21
22
  "zod": "^4.1.11"
22
23
  },
23
24
  "peerDependencies": {},
24
25
  "devDependencies": {
25
- "@repo/eslint-config": "workspace:*",
26
- "@repo/typescript-config": "workspace:*",
26
+ "@repo/eslint-config": "0.0.1",
27
+ "@repo/typescript-config": "0.0.1",
27
28
  "@types/node": "^20.14.9",
28
29
  "typescript": "5.9.3"
29
30
  },
package/src/service.ts CHANGED
@@ -5,6 +5,32 @@ import type { EndpointConfig, Handler } from './types'
5
5
  import { getVisionContext } from './vision-app'
6
6
  import { eventRegistry } from './event-registry'
7
7
  import type { EventBus } from './event-bus'
8
+ import { rateLimiter } from 'hono-rate-limiter'
9
+
10
+ // Simple window parser supporting values like '15m', '1h', '30s', '2d' or plain milliseconds as number string
11
+ function parseWindowMs(window: string): number {
12
+ const trimmed = window.trim()
13
+ if (/^\d+$/.test(trimmed)) return Number(trimmed)
14
+ const match = trimmed.match(/^(\d+)\s*([smhd])$/i)
15
+ if (!match) throw new Error(`Invalid ratelimit window: ${window}`)
16
+ const value = Number(match[1])
17
+ const unit = match[2].toLowerCase()
18
+ const multipliers: Record<string, number> = { s: 1000, m: 60_000, h: 3_600_000, d: 86_400_000 }
19
+ return value * multipliers[unit]
20
+ }
21
+
22
+ function getClientKey(c: Context, method: string, path: string): string {
23
+ const ip =
24
+ c.req.header('x-forwarded-for')?.split(',')[0].trim() ||
25
+ c.req.header('x-real-ip') ||
26
+ c.req.header('cf-connecting-ip') ||
27
+ c.req.header('fly-client-ip') ||
28
+ c.req.header('x-client-ip') ||
29
+ ''
30
+ // Fallback to UA if no IP available (still scoped per endpoint)
31
+ const ua = c.req.header('user-agent') || 'unknown'
32
+ return `${ip || ua}:${method}:${path}`
33
+ }
8
34
 
9
35
  /**
10
36
  * Event schema map - accumulates event types as they're registered
@@ -315,8 +341,28 @@ export class ServiceBuilder<
315
341
 
316
342
  // Register HTTP endpoints
317
343
  this.endpoints.forEach((ep) => {
318
- // Combine global + endpoint-specific middleware
319
- const allMiddleware = [...this.globalMiddleware, ...ep.middleware]
344
+ // Prepare rate limiter when configured per-endpoint
345
+ let rateLimitMw: MiddlewareHandler<E, string, any, any> | undefined
346
+ const rl = ep.config?.ratelimit as EndpointConfig['ratelimit'] | undefined
347
+ if (rl) {
348
+ const windowMs = parseWindowMs(rl.window)
349
+ const limit = rl.requests
350
+ rateLimitMw = rateLimiter({
351
+ windowMs,
352
+ limit,
353
+ standardHeaders: 'draft-6',
354
+ keyGenerator: (c) => getClientKey(c, ep.method, ep.path),
355
+ // If user provides a distributed store (e.g., RedisStore), pass it through
356
+ ...(rl.store ? { store: rl.store } : {}),
357
+ })
358
+ }
359
+
360
+ // Combine global + rate-limit (if any) + endpoint-specific middleware
361
+ const allMiddleware = [
362
+ ...this.globalMiddleware,
363
+ ...(rateLimitMw ? [rateLimitMw] as MiddlewareHandler<E, string, any, any>[] : []),
364
+ ...ep.middleware,
365
+ ]
320
366
 
321
367
  // Create handler with middleware chain
322
368
  const finalHandler = async (c: Context<E, any, I>) => {
package/src/types.ts CHANGED
@@ -19,7 +19,7 @@ export interface EndpointConfig {
19
19
  middleware?: MiddlewareHandler[]
20
20
  // TODO: Below not implemented yet features
21
21
  auth?: boolean
22
- ratelimit?: { requests: number; window: string }
22
+ ratelimit?: { requests: number; window: string; store?: any }
23
23
  cache?: { ttl: number }
24
24
  }
25
25