@venturekit/runtime 0.0.0-dev.20260312012510 → 0.0.0-dev.20260329102450

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 (122) hide show
  1. package/README.md +1 -1
  2. package/dist/config/env.d.ts +62 -0
  3. package/dist/config/env.d.ts.map +1 -0
  4. package/dist/config/env.js +98 -0
  5. package/dist/config/env.js.map +1 -0
  6. package/dist/config/secrets.d.ts +67 -0
  7. package/dist/config/secrets.d.ts.map +1 -0
  8. package/dist/config/secrets.js +132 -0
  9. package/dist/config/secrets.js.map +1 -0
  10. package/dist/handler/adapter.d.ts.map +1 -0
  11. package/dist/{adapter.js → handler/adapter.js} +5 -44
  12. package/dist/handler/adapter.js.map +1 -0
  13. package/dist/{context.d.ts → handler/context.d.ts} +44 -3
  14. package/dist/handler/context.d.ts.map +1 -0
  15. package/dist/{context.js → handler/context.js} +9 -9
  16. package/dist/handler/context.js.map +1 -0
  17. package/dist/handler/errors.d.ts.map +1 -0
  18. package/dist/{errors.js → handler/errors.js} +11 -25
  19. package/dist/handler/errors.js.map +1 -0
  20. package/dist/{handler.d.ts → handler/handler.d.ts} +36 -3
  21. package/dist/handler/handler.d.ts.map +1 -0
  22. package/dist/{handler.js → handler/handler.js} +59 -23
  23. package/dist/handler/handler.js.map +1 -0
  24. package/dist/handler/response.d.ts.map +1 -0
  25. package/dist/{response.js → handler/response.js} +9 -17
  26. package/dist/handler/response.js.map +1 -0
  27. package/dist/handler/task-handler.d.ts +192 -0
  28. package/dist/handler/task-handler.d.ts.map +1 -0
  29. package/dist/handler/task-handler.js +262 -0
  30. package/dist/handler/task-handler.js.map +1 -0
  31. package/dist/index.d.ts +33 -14
  32. package/dist/index.d.ts.map +1 -1
  33. package/dist/index.js +30 -48
  34. package/dist/index.js.map +1 -1
  35. package/dist/{logger.d.ts → logging/logger.d.ts} +1 -1
  36. package/dist/logging/logger.d.ts.map +1 -0
  37. package/dist/{logger.js → logging/logger.js} +8 -16
  38. package/dist/logging/logger.js.map +1 -0
  39. package/dist/logging/tracing.d.ts +51 -0
  40. package/dist/logging/tracing.d.ts.map +1 -0
  41. package/dist/logging/tracing.js +77 -0
  42. package/dist/logging/tracing.js.map +1 -0
  43. package/dist/middleware/middleware.d.ts +120 -0
  44. package/dist/middleware/middleware.d.ts.map +1 -0
  45. package/dist/middleware/middleware.js +270 -0
  46. package/dist/middleware/middleware.js.map +1 -0
  47. package/dist/middleware/rate-limit-store.d.ts +153 -0
  48. package/dist/middleware/rate-limit-store.d.ts.map +1 -0
  49. package/dist/middleware/rate-limit-store.js +182 -0
  50. package/dist/middleware/rate-limit-store.js.map +1 -0
  51. package/dist/openapi/openapi.d.ts +147 -0
  52. package/dist/openapi/openapi.d.ts.map +1 -0
  53. package/dist/openapi/openapi.js +235 -0
  54. package/dist/openapi/openapi.js.map +1 -0
  55. package/dist/openapi.d.ts +10 -0
  56. package/dist/openapi.d.ts.map +1 -0
  57. package/dist/openapi.js +9 -0
  58. package/dist/openapi.js.map +1 -0
  59. package/dist/patterns/circuit-breaker.d.ts +78 -0
  60. package/dist/patterns/circuit-breaker.d.ts.map +1 -0
  61. package/dist/patterns/circuit-breaker.js +113 -0
  62. package/dist/patterns/circuit-breaker.js.map +1 -0
  63. package/dist/patterns/idempotency.d.ts +175 -0
  64. package/dist/patterns/idempotency.d.ts.map +1 -0
  65. package/dist/patterns/idempotency.js +305 -0
  66. package/dist/patterns/idempotency.js.map +1 -0
  67. package/dist/patterns/invoke.d.ts +279 -0
  68. package/dist/patterns/invoke.d.ts.map +1 -0
  69. package/dist/patterns/invoke.js +581 -0
  70. package/dist/patterns/invoke.js.map +1 -0
  71. package/dist/patterns/saga.d.ts +391 -0
  72. package/dist/patterns/saga.d.ts.map +1 -0
  73. package/dist/patterns/saga.js +556 -0
  74. package/dist/patterns/saga.js.map +1 -0
  75. package/dist/patterns.d.ts +17 -0
  76. package/dist/patterns.d.ts.map +1 -0
  77. package/dist/patterns.js +17 -0
  78. package/dist/patterns.js.map +1 -0
  79. package/dist/rate-limit.d.ts +16 -0
  80. package/dist/rate-limit.d.ts.map +1 -0
  81. package/dist/rate-limit.js +15 -0
  82. package/dist/rate-limit.js.map +1 -0
  83. package/dist/secrets.d.ts +11 -0
  84. package/dist/secrets.d.ts.map +1 -0
  85. package/dist/secrets.js +10 -0
  86. package/dist/secrets.js.map +1 -0
  87. package/dist/testing/test-utils.d.ts +99 -0
  88. package/dist/testing/test-utils.d.ts.map +1 -0
  89. package/dist/testing/test-utils.js +153 -0
  90. package/dist/testing/test-utils.js.map +1 -0
  91. package/dist/testing.d.ts +10 -0
  92. package/dist/testing.d.ts.map +1 -0
  93. package/dist/testing.js +9 -0
  94. package/dist/testing.js.map +1 -0
  95. package/dist/ws/ws.d.ts +139 -0
  96. package/dist/ws/ws.d.ts.map +1 -0
  97. package/dist/ws/ws.js +294 -0
  98. package/dist/ws/ws.js.map +1 -0
  99. package/dist/ws.d.ts +5 -133
  100. package/dist/ws.d.ts.map +1 -1
  101. package/dist/ws.js +4 -291
  102. package/dist/ws.js.map +1 -1
  103. package/package.json +47 -5
  104. package/dist/adapter.d.ts.map +0 -1
  105. package/dist/adapter.js.map +0 -1
  106. package/dist/context.d.ts.map +0 -1
  107. package/dist/context.js.map +0 -1
  108. package/dist/errors.d.ts.map +0 -1
  109. package/dist/errors.js.map +0 -1
  110. package/dist/handler.d.ts.map +0 -1
  111. package/dist/handler.js.map +0 -1
  112. package/dist/logger.d.ts.map +0 -1
  113. package/dist/logger.js.map +0 -1
  114. package/dist/middleware.d.ts +0 -47
  115. package/dist/middleware.d.ts.map +0 -1
  116. package/dist/middleware.js +0 -147
  117. package/dist/middleware.js.map +0 -1
  118. package/dist/response.d.ts.map +0 -1
  119. package/dist/response.js.map +0 -1
  120. /package/dist/{adapter.d.ts → handler/adapter.d.ts} +0 -0
  121. /package/dist/{errors.d.ts → handler/errors.d.ts} +0 -0
  122. /package/dist/{response.d.ts → handler/response.d.ts} +0 -0
@@ -0,0 +1,77 @@
1
+ /**
2
+ * VentureKit Distributed Tracing
3
+ *
4
+ * Correlation ID / trace ID propagation across Lambda invocations.
5
+ * Integrates with X-Ray trace IDs and custom trace context.
6
+ */
7
+ /**
8
+ * Trace headers used for propagation
9
+ */
10
+ export const TRACE_HEADERS = {
11
+ TRACE_ID: 'x-trace-id',
12
+ SPAN_ID: 'x-span-id',
13
+ PARENT_SPAN_ID: 'x-parent-span-id',
14
+ BAGGAGE: 'x-trace-baggage',
15
+ };
16
+ /**
17
+ * Generate a random ID (16 hex chars)
18
+ */
19
+ export function generateId() {
20
+ const bytes = new Uint8Array(8);
21
+ crypto.getRandomValues(bytes);
22
+ return Array.from(bytes).map(b => b.toString(16).padStart(2, '0')).join('');
23
+ }
24
+ /**
25
+ * Extract trace context from request headers
26
+ */
27
+ export function extractTraceContext(headers) {
28
+ const traceId = headers[TRACE_HEADERS.TRACE_ID] || generateId();
29
+ const parentSpanId = headers[TRACE_HEADERS.SPAN_ID]; // caller's span becomes our parent
30
+ const spanId = generateId(); // new span for this request
31
+ let baggage = {};
32
+ const baggageHeader = headers[TRACE_HEADERS.BAGGAGE];
33
+ if (baggageHeader) {
34
+ try {
35
+ baggage = JSON.parse(baggageHeader);
36
+ }
37
+ catch {
38
+ // Invalid baggage header, ignore
39
+ }
40
+ }
41
+ return { traceId, spanId, parentSpanId, baggage };
42
+ }
43
+ /**
44
+ * Serialize trace context into headers for outbound requests
45
+ */
46
+ export function injectTraceHeaders(trace) {
47
+ const headers = {
48
+ [TRACE_HEADERS.TRACE_ID]: trace.traceId,
49
+ [TRACE_HEADERS.SPAN_ID]: trace.spanId,
50
+ };
51
+ if (trace.parentSpanId) {
52
+ headers[TRACE_HEADERS.PARENT_SPAN_ID] = trace.parentSpanId;
53
+ }
54
+ if (Object.keys(trace.baggage).length > 0) {
55
+ headers[TRACE_HEADERS.BAGGAGE] = JSON.stringify(trace.baggage);
56
+ }
57
+ return headers;
58
+ }
59
+ /**
60
+ * Create a child trace context (for outbound calls)
61
+ */
62
+ export function createChildTrace(parent) {
63
+ return {
64
+ traceId: parent.traceId,
65
+ spanId: generateId(),
66
+ parentSpanId: parent.spanId,
67
+ baggage: { ...parent.baggage },
68
+ };
69
+ }
70
+ /**
71
+ * Extract trace context from a RequestContext
72
+ * (reads from rawEvent headers)
73
+ */
74
+ export function traceFromRequest(ctx) {
75
+ return extractTraceContext(ctx.rawEvent.headers || {});
76
+ }
77
+ //# sourceMappingURL=tracing.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tracing.js","sourceRoot":"","sources":["../../src/logging/tracing.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAkBH;;GAEG;AACH,MAAM,CAAC,MAAM,aAAa,GAAG;IAC3B,QAAQ,EAAE,YAAY;IACtB,OAAO,EAAE,WAAW;IACpB,cAAc,EAAE,kBAAkB;IAClC,OAAO,EAAE,iBAAiB;CAClB,CAAC;AAEX;;GAEG;AACH,MAAM,UAAU,UAAU;IACxB,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,CAAC,CAAC,CAAC;IAChC,MAAM,CAAC,eAAe,CAAC,KAAK,CAAC,CAAC;IAC9B,OAAO,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,QAAQ,CAAC,EAAE,CAAC,CAAC,QAAQ,CAAC,CAAC,EAAE,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;AAC9E,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,mBAAmB,CAAC,OAA2C;IAC7E,MAAM,OAAO,GAAG,OAAO,CAAC,aAAa,CAAC,QAAQ,CAAC,IAAI,UAAU,EAAE,CAAC;IAChE,MAAM,YAAY,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC,CAAC,mCAAmC;IACxF,MAAM,MAAM,GAAG,UAAU,EAAE,CAAC,CAAC,4BAA4B;IAEzD,IAAI,OAAO,GAA2B,EAAE,CAAC;IACzC,MAAM,aAAa,GAAG,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,CAAC;IACrD,IAAI,aAAa,EAAE,CAAC;QAClB,IAAI,CAAC;YACH,OAAO,GAAG,IAAI,CAAC,KAAK,CAAC,aAAa,CAAC,CAAC;QACtC,CAAC;QAAC,MAAM,CAAC;YACP,iCAAiC;QACnC,CAAC;IACH,CAAC;IAED,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,YAAY,EAAE,OAAO,EAAE,CAAC;AACpD,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,kBAAkB,CAAC,KAAmB;IACpD,MAAM,OAAO,GAA2B;QACtC,CAAC,aAAa,CAAC,QAAQ,CAAC,EAAE,KAAK,CAAC,OAAO;QACvC,CAAC,aAAa,CAAC,OAAO,CAAC,EAAE,KAAK,CAAC,MAAM;KACtC,CAAC;IAEF,IAAI,KAAK,CAAC,YAAY,EAAE,CAAC;QACvB,OAAO,CAAC,aAAa,CAAC,cAAc,CAAC,GAAG,KAAK,CAAC,YAAY,CAAC;IAC7D,CAAC;IAED,IAAI,MAAM,CAAC,IAAI,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1C,OAAO,CAAC,aAAa,CAAC,OAAO,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;IACjE,CAAC;IAED,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAoB;IACnD,OAAO;QACL,OAAO,EAAE,MAAM,CAAC,OAAO;QACvB,MAAM,EAAE,UAAU,EAAE;QACpB,YAAY,EAAE,MAAM,CAAC,MAAM;QAC3B,OAAO,EAAE,EAAE,GAAG,MAAM,CAAC,OAAO,EAAE;KAC/B,CAAC;AACJ,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,GAAmB;IAClD,OAAO,mBAAmB,CAAC,GAAG,CAAC,QAAQ,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC;AACzD,CAAC"}
@@ -0,0 +1,120 @@
1
+ /**
2
+ * VentureKit Middleware
3
+ *
4
+ * Composable middleware for request processing.
5
+ * Extensible for auth, tenancy, rate limiting, etc.
6
+ */
7
+ import type { APIGatewayProxyResultV2 } from 'aws-lambda';
8
+ import { BaseContext, RequestContext } from '../handler/context.js';
9
+ import { Logger } from '../logging/logger.js';
10
+ /**
11
+ * Middleware function signature.
12
+ *
13
+ * Generic over the context type so the same interface works for both
14
+ * HTTP route handlers (`RequestContext`) and task handlers (`TaskContext`).
15
+ * Middleware written against `BaseContext` is reusable across all handler types.
16
+ */
17
+ export type MiddlewareFn<TCtx extends BaseContext = BaseContext> = (ctx: TCtx, next: () => Promise<any>) => Promise<any>;
18
+ /**
19
+ * Middleware with configuration.
20
+ *
21
+ * Use without a type parameter to write middleware that works everywhere:
22
+ * ```typescript
23
+ * const timing: Middleware = {
24
+ * name: 'timing',
25
+ * fn: async (ctx, next) => {
26
+ * const start = Date.now();
27
+ * const result = await next();
28
+ * console.log(`${ctx.requestId} took ${Date.now() - start}ms`);
29
+ * return result;
30
+ * },
31
+ * };
32
+ * ```
33
+ */
34
+ export interface Middleware<TCtx extends BaseContext = BaseContext> {
35
+ name: string;
36
+ fn: MiddlewareFn<TCtx>;
37
+ }
38
+ /**
39
+ * Compose multiple middleware into a single function
40
+ */
41
+ export declare function compose(middlewares: Middleware<RequestContext>[]): MiddlewareFn<RequestContext>;
42
+ /**
43
+ * Logging middleware - logs request/response
44
+ */
45
+ export declare function loggingMiddleware(logger: Logger): Middleware<RequestContext>;
46
+ /**
47
+ * CORS middleware - adds CORS headers
48
+ */
49
+ export declare function corsMiddleware(options: {
50
+ allowOrigins: string[];
51
+ allowMethods: string[];
52
+ allowHeaders: string[];
53
+ allowCredentials: boolean;
54
+ maxAge: number;
55
+ }): Middleware<RequestContext>;
56
+ /**
57
+ * Timeout middleware - enforces request timeout
58
+ */
59
+ export declare function timeoutMiddleware(timeoutMs: number): Middleware<RequestContext>;
60
+ /**
61
+ * Error boundary middleware - catches and formats errors
62
+ */
63
+ export declare function errorBoundaryMiddleware(errorHandler: (error: unknown, ctx: RequestContext) => APIGatewayProxyResultV2): Middleware<RequestContext>;
64
+ /**
65
+ * Rate limit check function type.
66
+ * Returns { allowed, remaining, resetAt } for the given key.
67
+ */
68
+ export interface RateLimitCheck {
69
+ (key: string): Promise<{
70
+ allowed: boolean;
71
+ remaining: number;
72
+ limit: number;
73
+ resetAt: number;
74
+ }>;
75
+ }
76
+ /**
77
+ * Rate limiting middleware options
78
+ */
79
+ export interface RateLimitOptions {
80
+ /** Function that checks and increments the rate limit counter */
81
+ check: RateLimitCheck;
82
+ /** Extract the rate limit key from the request (default: sourceIp) */
83
+ keyExtractor?: (ctx: RequestContext) => string;
84
+ }
85
+ /**
86
+ * Rate limiting middleware
87
+ *
88
+ * Uses an external check function so the storage backend is pluggable
89
+ * (DynamoDB, Redis, in-memory, etc.).
90
+ */
91
+ export declare function rateLimitMiddleware(options: RateLimitOptions): Middleware<RequestContext>;
92
+ /**
93
+ * Request ID propagation middleware
94
+ *
95
+ * Ensures every response includes an X-Request-Id header.
96
+ * Uses the existing requestId from context (from API Gateway)
97
+ * or an incoming X-Request-Id header for distributed tracing.
98
+ */
99
+ export declare function requestIdMiddleware(): Middleware<RequestContext>;
100
+ /**
101
+ * Timing/metrics middleware
102
+ *
103
+ * Adds Server-Timing header with total request duration.
104
+ * Optionally calls a metrics callback for custom reporting.
105
+ */
106
+ export declare function timingMiddleware(options?: {
107
+ onMetrics?: (ctx: RequestContext, durationMs: number, statusCode?: number) => void;
108
+ }): Middleware<RequestContext>;
109
+ /**
110
+ * API Key authentication middleware
111
+ *
112
+ * Validates an API key from a configurable header against a validation function.
113
+ */
114
+ export declare function apiKeyAuthMiddleware(options: {
115
+ /** Header name to read the API key from (default: x-api-key) */
116
+ headerName?: string;
117
+ /** Validate the API key. Return true if valid. */
118
+ validate: (apiKey: string) => Promise<boolean> | boolean;
119
+ }): Middleware<RequestContext>;
120
+ //# sourceMappingURL=middleware.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.d.ts","sourceRoot":"","sources":["../../src/middleware/middleware.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAEH,OAAO,KAAK,EAA0B,uBAAuB,EAAqC,MAAM,YAAY,CAAC;AACrH,OAAO,EAAE,WAAW,EAAE,cAAc,EAAE,MAAM,uBAAuB,CAAC;AACpE,OAAO,EAAE,MAAM,EAAE,MAAM,sBAAsB,CAAC;AAE9C;;;;;;GAMG;AACH,MAAM,MAAM,YAAY,CAAC,IAAI,SAAS,WAAW,GAAG,WAAW,IAAI,CACjE,GAAG,EAAE,IAAI,EACT,IAAI,EAAE,MAAM,OAAO,CAAC,GAAG,CAAC,KACrB,OAAO,CAAC,GAAG,CAAC,CAAC;AAElB;;;;;;;;;;;;;;;GAeG;AACH,MAAM,WAAW,UAAU,CAAC,IAAI,SAAS,WAAW,GAAG,WAAW;IAChE,IAAI,EAAE,MAAM,CAAC;IACb,EAAE,EAAE,YAAY,CAAC,IAAI,CAAC,CAAC;CACxB;AAED;;GAEG;AACH,wBAAgB,OAAO,CAAC,WAAW,EAAE,UAAU,CAAC,cAAc,CAAC,EAAE,GAAG,YAAY,CAAC,cAAc,CAAC,CAoB/F;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAsC5E;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,OAAO,EAAE;IACtC,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,YAAY,EAAE,MAAM,EAAE,CAAC;IACvB,gBAAgB,EAAE,OAAO,CAAC;IAC1B,MAAM,EAAE,MAAM,CAAC;CAChB,GAAG,UAAU,CAAC,cAAc,CAAC,CA2C7B;AAED;;GAEG;AACH,wBAAgB,iBAAiB,CAAC,SAAS,EAAE,MAAM,GAAG,UAAU,CAAC,cAAc,CAAC,CAa/E;AAED;;GAEG;AACH,wBAAgB,uBAAuB,CACrC,YAAY,EAAE,CAAC,KAAK,EAAE,OAAO,EAAE,GAAG,EAAE,cAAc,KAAK,uBAAuB,GAC7E,UAAU,CAAC,cAAc,CAAC,CAW5B;AAED;;;GAGG;AACH,MAAM,WAAW,cAAc;IAC7B,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC;QACrB,OAAO,EAAE,OAAO,CAAC;QACjB,SAAS,EAAE,MAAM,CAAC;QAClB,KAAK,EAAE,MAAM,CAAC;QACd,OAAO,EAAE,MAAM,CAAC;KACjB,CAAC,CAAC;CACJ;AAED;;GAEG;AACH,MAAM,WAAW,gBAAgB;IAC/B,iEAAiE;IACjE,KAAK,EAAE,cAAc,CAAC;IACtB,sEAAsE;IACtE,YAAY,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,KAAK,MAAM,CAAC;CAChD;AAED;;;;;GAKG;AACH,wBAAgB,mBAAmB,CAAC,OAAO,EAAE,gBAAgB,GAAG,UAAU,CAAC,cAAc,CAAC,CAwCzF;AAED;;;;;;GAMG;AACH,wBAAgB,mBAAmB,IAAI,UAAU,CAAC,cAAc,CAAC,CAwBhE;AAED;;;;;GAKG;AACH,wBAAgB,gBAAgB,CAAC,OAAO,CAAC,EAAE;IACzC,SAAS,CAAC,EAAE,CAAC,GAAG,EAAE,cAAc,EAAE,UAAU,EAAE,MAAM,EAAE,UAAU,CAAC,EAAE,MAAM,KAAK,IAAI,CAAC;CACpF,GAAG,UAAU,CAAC,cAAc,CAAC,CAsB7B;AAED;;;;GAIG;AACH,wBAAgB,oBAAoB,CAAC,OAAO,EAAE;IAC5C,gEAAgE;IAChE,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,kDAAkD;IAClD,QAAQ,EAAE,CAAC,MAAM,EAAE,MAAM,KAAK,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAC;CAC1D,GAAG,UAAU,CAAC,cAAc,CAAC,CA+B7B"}
@@ -0,0 +1,270 @@
1
+ /**
2
+ * VentureKit Middleware
3
+ *
4
+ * Composable middleware for request processing.
5
+ * Extensible for auth, tenancy, rate limiting, etc.
6
+ */
7
+ /**
8
+ * Compose multiple middleware into a single function
9
+ */
10
+ export function compose(middlewares) {
11
+ return async (ctx, finalHandler) => {
12
+ let index = -1;
13
+ const dispatch = async (i) => {
14
+ if (i <= index) {
15
+ throw new Error('next() called multiple times');
16
+ }
17
+ index = i;
18
+ if (i >= middlewares.length) {
19
+ return finalHandler();
20
+ }
21
+ const middleware = middlewares[i];
22
+ return middleware.fn(ctx, () => dispatch(i + 1));
23
+ };
24
+ return dispatch(0);
25
+ };
26
+ }
27
+ /**
28
+ * Logging middleware - logs request/response
29
+ */
30
+ export function loggingMiddleware(logger) {
31
+ return {
32
+ name: 'logging',
33
+ fn: async (ctx, next) => {
34
+ const start = Date.now();
35
+ logger.info('Request started', {
36
+ method: ctx.method,
37
+ path: ctx.path,
38
+ sourceIp: ctx.sourceIp,
39
+ });
40
+ try {
41
+ const response = await next();
42
+ const duration = Date.now() - start;
43
+ logger.info('Request completed', {
44
+ method: ctx.method,
45
+ path: ctx.path,
46
+ statusCode: typeof response === 'object' ? response.statusCode : undefined,
47
+ duration,
48
+ });
49
+ return response;
50
+ }
51
+ catch (error) {
52
+ const duration = Date.now() - start;
53
+ logger.error('Request failed', {
54
+ method: ctx.method,
55
+ path: ctx.path,
56
+ duration,
57
+ error: error instanceof Error ? error.message : 'Unknown error',
58
+ });
59
+ throw error;
60
+ }
61
+ },
62
+ };
63
+ }
64
+ /**
65
+ * CORS middleware - adds CORS headers
66
+ */
67
+ export function corsMiddleware(options) {
68
+ return {
69
+ name: 'cors',
70
+ fn: async (ctx, next) => {
71
+ const origin = ctx.rawEvent.headers?.origin || '';
72
+ const allowedOrigin = options.allowOrigins.includes('*')
73
+ ? '*'
74
+ : options.allowOrigins.includes(origin)
75
+ ? origin
76
+ : '';
77
+ // Handle preflight
78
+ if (ctx.method === 'OPTIONS') {
79
+ return {
80
+ statusCode: 204,
81
+ headers: {
82
+ 'Access-Control-Allow-Origin': allowedOrigin,
83
+ 'Access-Control-Allow-Methods': options.allowMethods.join(', '),
84
+ 'Access-Control-Allow-Headers': options.allowHeaders.join(', '),
85
+ 'Access-Control-Allow-Credentials': String(options.allowCredentials),
86
+ 'Access-Control-Max-Age': String(options.maxAge),
87
+ },
88
+ body: '',
89
+ };
90
+ }
91
+ const response = await next();
92
+ // Add CORS headers to response
93
+ if (typeof response !== 'object' || response === null) {
94
+ return response;
95
+ }
96
+ const resp = response;
97
+ const corsHeaders = {
98
+ 'Access-Control-Allow-Origin': allowedOrigin,
99
+ };
100
+ if (options.allowCredentials) {
101
+ corsHeaders['Access-Control-Allow-Credentials'] = 'true';
102
+ }
103
+ resp.headers = { ...resp.headers, ...corsHeaders };
104
+ return resp;
105
+ },
106
+ };
107
+ }
108
+ /**
109
+ * Timeout middleware - enforces request timeout
110
+ */
111
+ export function timeoutMiddleware(timeoutMs) {
112
+ return {
113
+ name: 'timeout',
114
+ fn: async (ctx, next) => {
115
+ const timeoutPromise = new Promise((_, reject) => {
116
+ setTimeout(() => {
117
+ reject(new Error(`Request timeout after ${timeoutMs}ms`));
118
+ }, timeoutMs);
119
+ });
120
+ return Promise.race([next(), timeoutPromise]);
121
+ },
122
+ };
123
+ }
124
+ /**
125
+ * Error boundary middleware - catches and formats errors
126
+ */
127
+ export function errorBoundaryMiddleware(errorHandler) {
128
+ return {
129
+ name: 'errorBoundary',
130
+ fn: async (ctx, next) => {
131
+ try {
132
+ return await next();
133
+ }
134
+ catch (error) {
135
+ return errorHandler(error, ctx);
136
+ }
137
+ },
138
+ };
139
+ }
140
+ /**
141
+ * Rate limiting middleware
142
+ *
143
+ * Uses an external check function so the storage backend is pluggable
144
+ * (DynamoDB, Redis, in-memory, etc.).
145
+ */
146
+ export function rateLimitMiddleware(options) {
147
+ const { check, keyExtractor = (ctx) => ctx.sourceIp } = options;
148
+ return {
149
+ name: 'rateLimit',
150
+ fn: async (ctx, next) => {
151
+ const key = keyExtractor(ctx);
152
+ const result = await check(key);
153
+ if (!result.allowed) {
154
+ return {
155
+ statusCode: 429,
156
+ headers: {
157
+ 'Retry-After': String(Math.ceil((result.resetAt - Date.now()) / 1000)),
158
+ 'X-RateLimit-Limit': String(result.limit),
159
+ 'X-RateLimit-Remaining': '0',
160
+ 'X-RateLimit-Reset': String(result.resetAt),
161
+ },
162
+ body: JSON.stringify({
163
+ error: { code: 'RATE_LIMITED', message: 'Too many requests' },
164
+ }),
165
+ };
166
+ }
167
+ const response = await next();
168
+ // Add rate limit headers to response
169
+ if (typeof response === 'object' && response !== null) {
170
+ const resp = response;
171
+ resp.headers = {
172
+ ...resp.headers,
173
+ 'X-RateLimit-Limit': String(result.limit),
174
+ 'X-RateLimit-Remaining': String(result.remaining),
175
+ 'X-RateLimit-Reset': String(result.resetAt),
176
+ };
177
+ }
178
+ return response;
179
+ },
180
+ };
181
+ }
182
+ /**
183
+ * Request ID propagation middleware
184
+ *
185
+ * Ensures every response includes an X-Request-Id header.
186
+ * Uses the existing requestId from context (from API Gateway)
187
+ * or an incoming X-Request-Id header for distributed tracing.
188
+ */
189
+ export function requestIdMiddleware() {
190
+ return {
191
+ name: 'requestId',
192
+ fn: async (ctx, next) => {
193
+ // Prefer incoming header for distributed tracing, fall back to API Gateway request ID
194
+ const incomingId = ctx.rawEvent.headers?.['x-request-id'];
195
+ if (incomingId) {
196
+ ctx.requestId = incomingId;
197
+ }
198
+ const response = await next();
199
+ // Inject X-Request-Id into response
200
+ if (typeof response === 'object' && response !== null) {
201
+ const resp = response;
202
+ resp.headers = {
203
+ ...resp.headers,
204
+ 'X-Request-Id': ctx.requestId,
205
+ };
206
+ }
207
+ return response;
208
+ },
209
+ };
210
+ }
211
+ /**
212
+ * Timing/metrics middleware
213
+ *
214
+ * Adds Server-Timing header with total request duration.
215
+ * Optionally calls a metrics callback for custom reporting.
216
+ */
217
+ export function timingMiddleware(options) {
218
+ return {
219
+ name: 'timing',
220
+ fn: async (ctx, next) => {
221
+ const start = Date.now();
222
+ const response = await next();
223
+ const duration = Date.now() - start;
224
+ // Add Server-Timing header
225
+ if (typeof response === 'object' && response !== null) {
226
+ const resp = response;
227
+ resp.headers = {
228
+ ...resp.headers,
229
+ 'Server-Timing': `total;dur=${duration}`,
230
+ };
231
+ options?.onMetrics?.(ctx, duration, resp.statusCode);
232
+ }
233
+ return response;
234
+ },
235
+ };
236
+ }
237
+ /**
238
+ * API Key authentication middleware
239
+ *
240
+ * Validates an API key from a configurable header against a validation function.
241
+ */
242
+ export function apiKeyAuthMiddleware(options) {
243
+ const headerName = (options.headerName ?? 'x-api-key').toLowerCase();
244
+ return {
245
+ name: 'apiKeyAuth',
246
+ fn: async (ctx, next) => {
247
+ // Read API key from header (headers are lowercased in API Gateway V2)
248
+ const apiKey = ctx.rawEvent.headers?.[headerName];
249
+ if (!apiKey) {
250
+ return {
251
+ statusCode: 401,
252
+ body: JSON.stringify({
253
+ error: { code: 'UNAUTHORIZED', message: 'API key is required' },
254
+ }),
255
+ };
256
+ }
257
+ const isValid = await options.validate(apiKey);
258
+ if (!isValid) {
259
+ return {
260
+ statusCode: 401,
261
+ body: JSON.stringify({
262
+ error: { code: 'UNAUTHORIZED', message: 'Invalid API key' },
263
+ }),
264
+ };
265
+ }
266
+ return next();
267
+ },
268
+ };
269
+ }
270
+ //# sourceMappingURL=middleware.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"middleware.js","sourceRoot":"","sources":["../../src/middleware/middleware.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,153 @@
1
+ /**
2
+ * VentureKit Rate Limit Stores
3
+ *
4
+ * Pluggable backends for the rateLimitMiddleware.
5
+ *
6
+ * - `createDynamoDBRateLimitStore()` — production-ready, distributed
7
+ * - `createMemoryRateLimitStore()` — for local dev/testing only
8
+ * - `createDefaultRateLimiter()` — zero-config rate limiter with sensible defaults
9
+ */
10
+ import type { RateLimitCheck } from './middleware.js';
11
+ /**
12
+ * Rate limit preset name.
13
+ */
14
+ export type RateLimitPreset = 'relaxed' | 'standard' | 'strict' | 'api-key';
15
+ /**
16
+ * Rate limit preset configuration.
17
+ */
18
+ export interface RateLimitPresetConfig {
19
+ /** Max requests per window */
20
+ limit: number;
21
+ /** Window size in milliseconds */
22
+ windowMs: number;
23
+ }
24
+ /**
25
+ * Built-in rate limit presets covering common requirements.
26
+ *
27
+ * | Preset | Limit | Window | Use Case |
28
+ * |------------|---------|--------|---------------------------------------|
29
+ * | `relaxed` | 200/min | 60s | Internal APIs, dev environments |
30
+ * | `standard` | 100/min | 60s | Public APIs, most production needs |
31
+ * | `strict` | 20/min | 60s | Auth endpoints, sensitive operations |
32
+ * | `api-key` | 1000/min| 60s | Authenticated API-key consumers |
33
+ */
34
+ export declare const RATE_LIMIT_PRESETS: Record<RateLimitPreset, RateLimitPresetConfig>;
35
+ /**
36
+ * Create an in-memory rate limit check function.
37
+ *
38
+ * **WARNING:** This stores counters in the Lambda process memory.
39
+ * It does NOT work correctly with multiple Lambda instances.
40
+ * Use only for local development and testing.
41
+ *
42
+ * For production, use `createDynamoDBRateLimitStore()`.
43
+ */
44
+ export declare function createMemoryRateLimitStore(options?: {
45
+ /** Max requests per window (default: 100) */
46
+ limit?: number;
47
+ /** Window size in ms (default: 60000 = 1 minute) */
48
+ windowMs?: number;
49
+ /** Or use a preset */
50
+ preset?: RateLimitPreset;
51
+ }): RateLimitCheck;
52
+ /**
53
+ * DynamoDB rate limit store options.
54
+ */
55
+ export interface DynamoDBRateLimitStoreOptions {
56
+ /** DynamoDB table name (default: 'venturekit-rate-limits') */
57
+ tableName?: string;
58
+ /** Max requests per window (default: 100) */
59
+ limit?: number;
60
+ /** Window size in ms (default: 60000 = 1 minute) */
61
+ windowMs?: number;
62
+ /** Or use a preset */
63
+ preset?: RateLimitPreset;
64
+ /** AWS region (default: process.env.AWS_REGION) */
65
+ region?: string;
66
+ }
67
+ /**
68
+ * Create a DynamoDB-backed rate limit check function.
69
+ *
70
+ * Uses atomic `UpdateItem` with `ADD` to safely increment counters
71
+ * across multiple Lambda instances. Expired entries are automatically
72
+ * cleaned up via DynamoDB TTL.
73
+ *
74
+ * ### DynamoDB Table Schema
75
+ *
76
+ * The table must have:
77
+ * - **Partition key:** `pk` (String) — the rate limit key
78
+ * - **TTL attribute:** `ttl` (Number) — epoch seconds for auto-cleanup
79
+ *
80
+ * You can create this table via infrastructure intents or manually:
81
+ *
82
+ * ```bash
83
+ * aws dynamodb create-table \
84
+ * --table-name venturekit-rate-limits \
85
+ * --attribute-definitions AttributeName=pk,AttributeType=S \
86
+ * --key-schema AttributeName=pk,KeyType=HASH \
87
+ * --billing-mode PAY_PER_REQUEST
88
+ *
89
+ * aws dynamodb update-time-to-live \
90
+ * --table-name venturekit-rate-limits \
91
+ * --time-to-live-specification "Enabled=true, AttributeName=ttl"
92
+ * ```
93
+ *
94
+ * @example
95
+ * ```typescript
96
+ * import { rateLimitMiddleware } from '@venturekit/runtime';
97
+ * import { createDynamoDBRateLimitStore } from '@venturekit/runtime';
98
+ *
99
+ * const rateLimit = rateLimitMiddleware({
100
+ * check: await createDynamoDBRateLimitStore({ preset: 'standard' }),
101
+ * });
102
+ * ```
103
+ */
104
+ export declare function createDynamoDBRateLimitStore(options?: DynamoDBRateLimitStoreOptions): Promise<RateLimitCheck>;
105
+ /**
106
+ * Options for the default rate limiter.
107
+ *
108
+ * Resolution order for `limit` and `windowMs`:
109
+ * 1. Explicit value (`limit` / `windowMs`) — highest priority
110
+ * 2. Preset values (if `preset` is provided)
111
+ * 3. Built-in defaults (100 req / 60 000 ms)
112
+ *
113
+ * This means you can use a preset as a base and selectively override
114
+ * individual values, e.g. `{ preset: 'strict', limit: 50 }`.
115
+ */
116
+ export interface DefaultRateLimiterOptions {
117
+ /** Preset to use (no default — uses built-in 100 req/min when omitted) */
118
+ preset?: RateLimitPreset;
119
+ /** Custom limit (overrides preset if both are provided) */
120
+ limit?: number;
121
+ /** Custom window in ms (overrides preset if both are provided) */
122
+ windowMs?: number;
123
+ /** DynamoDB table name (default: 'venturekit-rate-limits') */
124
+ tableName?: string;
125
+ /** Force in-memory store even in production (NOT recommended) */
126
+ forceMemory?: boolean;
127
+ }
128
+ /**
129
+ * Create a rate limit check function with sensible defaults.
130
+ *
131
+ * - In production (Lambda): uses DynamoDB for distributed rate limiting
132
+ * - In local dev: uses in-memory store
133
+ *
134
+ * This is the recommended way to add rate limiting with minimal configuration.
135
+ *
136
+ * @example
137
+ * ```typescript
138
+ * import { rateLimitMiddleware } from '@venturekit/runtime';
139
+ * import { createDefaultRateLimiter } from '@venturekit/runtime';
140
+ *
141
+ * // Zero-config — uses 'standard' preset (100 req/min)
142
+ * const rateLimit = rateLimitMiddleware({
143
+ * check: await createDefaultRateLimiter(),
144
+ * });
145
+ *
146
+ * // Strict for auth endpoints
147
+ * const authRateLimit = rateLimitMiddleware({
148
+ * check: await createDefaultRateLimiter({ preset: 'strict' }),
149
+ * });
150
+ * ```
151
+ */
152
+ export declare function createDefaultRateLimiter(options?: DefaultRateLimiterOptions): Promise<RateLimitCheck>;
153
+ //# sourceMappingURL=rate-limit-store.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"rate-limit-store.d.ts","sourceRoot":"","sources":["../../src/middleware/rate-limit-store.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,iBAAiB,CAAC;AAMtD;;GAEG;AACH,MAAM,MAAM,eAAe,GAAG,SAAS,GAAG,UAAU,GAAG,QAAQ,GAAG,SAAS,CAAC;AAE5E;;GAEG;AACH,MAAM,WAAW,qBAAqB;IACpC,8BAA8B;IAC9B,KAAK,EAAE,MAAM,CAAC;IACd,kCAAkC;IAClC,QAAQ,EAAE,MAAM,CAAC;CAClB;AAED;;;;;;;;;GASG;AACH,eAAO,MAAM,kBAAkB,EAAE,MAAM,CAAC,eAAe,EAAE,qBAAqB,CAK7E,CAAC;AAMF;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,OAAO,CAAC,EAAE;IACnD,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,eAAe,CAAC;CAC1B,GAAG,cAAc,CAwBjB;AAMD;;GAEG;AACH,MAAM,WAAW,6BAA6B;IAC5C,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,6CAA6C;IAC7C,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,oDAAoD;IACpD,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,sBAAsB;IACtB,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,mDAAmD;IACnD,MAAM,CAAC,EAAE,MAAM,CAAC;CACjB;AAED;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAoCG;AACH,wBAAsB,4BAA4B,CAChD,OAAO,GAAE,6BAAkC,GAC1C,OAAO,CAAC,cAAc,CAAC,CAqDzB;AAMD;;;;;;;;;;GAUG;AACH,MAAM,WAAW,yBAAyB;IACxC,0EAA0E;IAC1E,MAAM,CAAC,EAAE,eAAe,CAAC;IACzB,2DAA2D;IAC3D,KAAK,CAAC,EAAE,MAAM,CAAC;IACf,kEAAkE;IAClE,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,iEAAiE;IACjE,WAAW,CAAC,EAAE,OAAO,CAAC;CACvB;AAED;;;;;;;;;;;;;;;;;;;;;;;GAuBG;AACH,wBAAsB,wBAAwB,CAC5C,OAAO,GAAE,yBAA8B,GACtC,OAAO,CAAC,cAAc,CAAC,CAiBzB"}