@parsrun/server 0.1.28 → 0.1.29
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/app.js.map +1 -1
- package/dist/context.d.ts +21 -1
- package/dist/context.js.map +1 -1
- package/dist/index.d.ts +1 -1
- package/dist/index.js.map +1 -1
- package/dist/middleware/index.d.ts +7 -771
- package/dist/middleware/index.js.map +1 -1
- package/dist/module-loader.js.map +1 -1
- package/dist/quota-enforcement-CN3z5bfc.d.ts +744 -0
- package/dist/utils/index.js.map +1 -1
- package/dist/validation/index.js.map +1 -1
- package/package.json +3 -3
|
@@ -1,489 +1,10 @@
|
|
|
1
|
-
|
|
2
|
-
import
|
|
3
|
-
import
|
|
4
|
-
import
|
|
1
|
+
export { h as ApiError, A as AuthMiddlewareOptions, B as BadRequestError, i as ConflictError, C as CsrfOptions, E as ErrorHandlerOptions, F as ForbiddenError, I as InternalError, J as JwtPayload, b as JwtVerifier, M as MemoryRateLimitStorage, N as NotFoundError, D as QuotaCheckResult, y as QuotaEnforcementOptions, Q as QuotaExceededError, z as QuotaManagerLike, R as RateLimitError, k as RateLimitOptions, l as RateLimitStorage, p as RequestLoggerOptions, S as ServiceUnavailableError, U as UnauthorizedError, t as UsageServiceLike, s as UsageTrackingOptions, V as ValidationError, a as auth, d as cors, c as createAuthMiddleware, w as createQuotaEnforcement, j as createRateLimiter, q as createUsageTracking, e as csrf, f as doubleSubmitCookie, g as errorHandler, x as multiQuotaEnforcement, n as notFoundHandler, o as optionalAuth, v as quotaEnforcement, r as rateLimit, m as requestLogger, u as usageTracking } from '../quota-enforcement-CN3z5bfc.js';
|
|
2
|
+
import { HonoContext, HonoNext, TraceContext } from '../context.js';
|
|
3
|
+
import 'hono';
|
|
4
|
+
import 'hono/utils/types';
|
|
5
|
+
import '@parsrun/core/transports';
|
|
5
6
|
import '@parsrun/core';
|
|
6
7
|
|
|
7
|
-
/**
|
|
8
|
-
* @parsrun/server - Auth Middleware
|
|
9
|
-
* JWT authentication middleware
|
|
10
|
-
*/
|
|
11
|
-
|
|
12
|
-
/**
|
|
13
|
-
* JWT payload structure
|
|
14
|
-
*/
|
|
15
|
-
interface JwtPayload {
|
|
16
|
-
sub: string;
|
|
17
|
-
email?: string;
|
|
18
|
-
tenantId?: string;
|
|
19
|
-
role?: string;
|
|
20
|
-
permissions?: string[];
|
|
21
|
-
iat?: number;
|
|
22
|
-
exp?: number;
|
|
23
|
-
jti?: string;
|
|
24
|
-
}
|
|
25
|
-
/**
|
|
26
|
-
* JWT verification function type
|
|
27
|
-
*/
|
|
28
|
-
type JwtVerifier = (token: string) => Promise<JwtPayload | null>;
|
|
29
|
-
/**
|
|
30
|
-
* Auth middleware options
|
|
31
|
-
*/
|
|
32
|
-
interface AuthMiddlewareOptions {
|
|
33
|
-
/** JWT verification function */
|
|
34
|
-
verify: JwtVerifier;
|
|
35
|
-
/** Header name for token (default: Authorization) */
|
|
36
|
-
header?: string;
|
|
37
|
-
/** Token prefix (default: Bearer) */
|
|
38
|
-
prefix?: string;
|
|
39
|
-
/** Cookie name for token (alternative to header) */
|
|
40
|
-
cookie?: string;
|
|
41
|
-
/** Skip auth for certain requests */
|
|
42
|
-
skip?: (c: HonoContext) => boolean;
|
|
43
|
-
/** Custom error message */
|
|
44
|
-
message?: string;
|
|
45
|
-
}
|
|
46
|
-
/**
|
|
47
|
-
* Auth middleware - requires valid JWT
|
|
48
|
-
*
|
|
49
|
-
* @example
|
|
50
|
-
* ```typescript
|
|
51
|
-
* import { verifyJwt } from '@parsrun/auth';
|
|
52
|
-
*
|
|
53
|
-
* const authMiddleware = auth({
|
|
54
|
-
* verify: (token) => verifyJwt(token, secret),
|
|
55
|
-
* cookie: 'auth_token',
|
|
56
|
-
* });
|
|
57
|
-
*
|
|
58
|
-
* app.use('/api/*', authMiddleware);
|
|
59
|
-
*
|
|
60
|
-
* // Access user in handlers
|
|
61
|
-
* app.get('/api/me', (c) => {
|
|
62
|
-
* const user = c.get('user');
|
|
63
|
-
* return c.json({ user });
|
|
64
|
-
* });
|
|
65
|
-
* ```
|
|
66
|
-
*/
|
|
67
|
-
declare function auth(options: AuthMiddlewareOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
68
|
-
/**
|
|
69
|
-
* Optional auth middleware - sets user if token present, but doesn't require it
|
|
70
|
-
*
|
|
71
|
-
* @example
|
|
72
|
-
* ```typescript
|
|
73
|
-
* app.use('/api/public/*', optionalAuth({
|
|
74
|
-
* verify: (token) => verifyJwt(token, secret),
|
|
75
|
-
* }));
|
|
76
|
-
*
|
|
77
|
-
* // User may or may not be present
|
|
78
|
-
* app.get('/api/public/items', (c) => {
|
|
79
|
-
* const user = c.get('user'); // may be undefined
|
|
80
|
-
* // Return different data based on auth status
|
|
81
|
-
* });
|
|
82
|
-
* ```
|
|
83
|
-
*/
|
|
84
|
-
declare function optionalAuth(options: Omit<AuthMiddlewareOptions, "message">): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
85
|
-
/**
|
|
86
|
-
* Create auth middleware from verifier function
|
|
87
|
-
*
|
|
88
|
-
* @example
|
|
89
|
-
* ```typescript
|
|
90
|
-
* const { auth, optionalAuth } = createAuthMiddleware({
|
|
91
|
-
* verify: async (token) => {
|
|
92
|
-
* return verifyJwt(token, process.env.JWT_SECRET);
|
|
93
|
-
* },
|
|
94
|
-
* cookie: 'session',
|
|
95
|
-
* });
|
|
96
|
-
*
|
|
97
|
-
* app.use('/api/*', auth);
|
|
98
|
-
* app.use('/public/*', optionalAuth);
|
|
99
|
-
* ```
|
|
100
|
-
*/
|
|
101
|
-
declare function createAuthMiddleware(baseOptions: Omit<AuthMiddlewareOptions, "skip" | "message">): {
|
|
102
|
-
auth: (options?: Partial<AuthMiddlewareOptions>) => (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
103
|
-
optionalAuth: (options?: Partial<Omit<AuthMiddlewareOptions, "message">>) => (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
104
|
-
};
|
|
105
|
-
|
|
106
|
-
/**
|
|
107
|
-
* @parsrun/server - CORS Middleware
|
|
108
|
-
* Cross-Origin Resource Sharing configuration
|
|
109
|
-
*/
|
|
110
|
-
|
|
111
|
-
/**
|
|
112
|
-
* CORS middleware
|
|
113
|
-
*
|
|
114
|
-
* @example
|
|
115
|
-
* ```typescript
|
|
116
|
-
* app.use('*', cors({
|
|
117
|
-
* origin: ['https://example.com', 'https://app.example.com'],
|
|
118
|
-
* credentials: true,
|
|
119
|
-
* }));
|
|
120
|
-
* ```
|
|
121
|
-
*/
|
|
122
|
-
declare function cors(config?: Partial<CorsConfig>): (c: HonoContext, next: HonoNext) => Promise<Response | void>;
|
|
123
|
-
|
|
124
|
-
/**
|
|
125
|
-
* @parsrun/server - CSRF Middleware
|
|
126
|
-
* Cross-Site Request Forgery protection
|
|
127
|
-
*/
|
|
128
|
-
|
|
129
|
-
/**
|
|
130
|
-
* CSRF options
|
|
131
|
-
*/
|
|
132
|
-
interface CsrfOptions {
|
|
133
|
-
/** Cookie name for CSRF token */
|
|
134
|
-
cookieName?: string;
|
|
135
|
-
/** Header name for CSRF token */
|
|
136
|
-
headerName?: string;
|
|
137
|
-
/** Methods that require CSRF validation */
|
|
138
|
-
methods?: string[];
|
|
139
|
-
/** Paths to exclude from CSRF protection */
|
|
140
|
-
excludePaths?: string[];
|
|
141
|
-
/** Skip CSRF for certain requests */
|
|
142
|
-
skip?: (c: HonoContext) => boolean;
|
|
143
|
-
/** Token generator */
|
|
144
|
-
generateToken?: () => string;
|
|
145
|
-
/** Cookie options */
|
|
146
|
-
cookie?: {
|
|
147
|
-
secure?: boolean;
|
|
148
|
-
httpOnly?: boolean;
|
|
149
|
-
sameSite?: "strict" | "lax" | "none";
|
|
150
|
-
path?: string;
|
|
151
|
-
maxAge?: number;
|
|
152
|
-
};
|
|
153
|
-
}
|
|
154
|
-
/**
|
|
155
|
-
* CSRF protection middleware
|
|
156
|
-
*
|
|
157
|
-
* @example
|
|
158
|
-
* ```typescript
|
|
159
|
-
* app.use('*', csrf({
|
|
160
|
-
* cookieName: '_csrf',
|
|
161
|
-
* headerName: 'X-CSRF-Token',
|
|
162
|
-
* methods: ['POST', 'PUT', 'PATCH', 'DELETE'],
|
|
163
|
-
* cookie: {
|
|
164
|
-
* secure: true,
|
|
165
|
-
* sameSite: 'strict',
|
|
166
|
-
* },
|
|
167
|
-
* }));
|
|
168
|
-
*
|
|
169
|
-
* // Get token in handler
|
|
170
|
-
* app.get('/csrf-token', (c) => {
|
|
171
|
-
* return c.json({ token: c.get('csrfToken') });
|
|
172
|
-
* });
|
|
173
|
-
* ```
|
|
174
|
-
*/
|
|
175
|
-
declare function csrf(options?: CsrfOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
176
|
-
/**
|
|
177
|
-
* Double Submit Cookie pattern
|
|
178
|
-
* Generates a token and validates it matches between cookie and header
|
|
179
|
-
*/
|
|
180
|
-
declare function doubleSubmitCookie(options?: CsrfOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
181
|
-
|
|
182
|
-
/**
|
|
183
|
-
* Base API error class
|
|
184
|
-
*/
|
|
185
|
-
declare class ApiError extends Error {
|
|
186
|
-
readonly statusCode: number;
|
|
187
|
-
readonly code: string;
|
|
188
|
-
readonly details?: Record<string, unknown> | undefined;
|
|
189
|
-
constructor(statusCode: number, code: string, message: string, details?: Record<string, unknown> | undefined);
|
|
190
|
-
toResponse(): ApiResponse<never>;
|
|
191
|
-
}
|
|
192
|
-
/**
|
|
193
|
-
* 400 Bad Request
|
|
194
|
-
*/
|
|
195
|
-
declare class BadRequestError extends ApiError {
|
|
196
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
197
|
-
}
|
|
198
|
-
/**
|
|
199
|
-
* 401 Unauthorized
|
|
200
|
-
*/
|
|
201
|
-
declare class UnauthorizedError extends ApiError {
|
|
202
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
203
|
-
}
|
|
204
|
-
/**
|
|
205
|
-
* 403 Forbidden
|
|
206
|
-
*/
|
|
207
|
-
declare class ForbiddenError extends ApiError {
|
|
208
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
209
|
-
}
|
|
210
|
-
/**
|
|
211
|
-
* 404 Not Found
|
|
212
|
-
*/
|
|
213
|
-
declare class NotFoundError extends ApiError {
|
|
214
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
215
|
-
}
|
|
216
|
-
/**
|
|
217
|
-
* 409 Conflict
|
|
218
|
-
*/
|
|
219
|
-
declare class ConflictError extends ApiError {
|
|
220
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
221
|
-
}
|
|
222
|
-
/**
|
|
223
|
-
* 422 Unprocessable Entity (Validation Error)
|
|
224
|
-
*/
|
|
225
|
-
declare class ValidationError extends ApiError {
|
|
226
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
227
|
-
}
|
|
228
|
-
/**
|
|
229
|
-
* 429 Too Many Requests
|
|
230
|
-
*/
|
|
231
|
-
declare class RateLimitError extends ApiError {
|
|
232
|
-
readonly retryAfter?: number | undefined;
|
|
233
|
-
constructor(message?: string, retryAfter?: number | undefined);
|
|
234
|
-
}
|
|
235
|
-
/**
|
|
236
|
-
* 500 Internal Server Error
|
|
237
|
-
*/
|
|
238
|
-
declare class InternalError extends ApiError {
|
|
239
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
240
|
-
}
|
|
241
|
-
/**
|
|
242
|
-
* 503 Service Unavailable
|
|
243
|
-
*/
|
|
244
|
-
declare class ServiceUnavailableError extends ApiError {
|
|
245
|
-
constructor(message?: string, details?: Record<string, unknown>);
|
|
246
|
-
}
|
|
247
|
-
/**
|
|
248
|
-
* Error handler options
|
|
249
|
-
*/
|
|
250
|
-
interface ErrorHandlerOptions {
|
|
251
|
-
/** Include stack trace in development */
|
|
252
|
-
includeStack?: boolean;
|
|
253
|
-
/** Custom error logger */
|
|
254
|
-
onError?: (error: Error, c: HonoContext) => void;
|
|
255
|
-
/**
|
|
256
|
-
* Error transport for external error tracking (e.g., Sentry)
|
|
257
|
-
* Automatically captures exceptions with request context
|
|
258
|
-
*/
|
|
259
|
-
errorTransport?: ErrorTransport;
|
|
260
|
-
/**
|
|
261
|
-
* Capture all errors including 4xx client errors
|
|
262
|
-
* By default, only 5xx server errors are captured
|
|
263
|
-
* @default false
|
|
264
|
-
*/
|
|
265
|
-
captureAllErrors?: boolean;
|
|
266
|
-
/**
|
|
267
|
-
* Custom function to determine if an error should be captured
|
|
268
|
-
* Overrides the default captureAllErrors behavior
|
|
269
|
-
*/
|
|
270
|
-
shouldCapture?: (error: Error, statusCode: number) => boolean;
|
|
271
|
-
}
|
|
272
|
-
/**
|
|
273
|
-
* Global error handler middleware
|
|
274
|
-
*
|
|
275
|
-
* @example Basic usage
|
|
276
|
-
* ```typescript
|
|
277
|
-
* app.use('*', errorHandler({
|
|
278
|
-
* includeStack: process.env.NODE_ENV === 'development',
|
|
279
|
-
* onError: (error, c) => {
|
|
280
|
-
* console.error(`[${c.get('requestId')}]`, error);
|
|
281
|
-
* },
|
|
282
|
-
* }));
|
|
283
|
-
* ```
|
|
284
|
-
*
|
|
285
|
-
* @example With Sentry error tracking
|
|
286
|
-
* ```typescript
|
|
287
|
-
* import { SentryTransport } from '@parsrun/core/transports';
|
|
288
|
-
*
|
|
289
|
-
* const sentry = new SentryTransport({
|
|
290
|
-
* dsn: process.env.SENTRY_DSN!,
|
|
291
|
-
* environment: process.env.NODE_ENV,
|
|
292
|
-
* });
|
|
293
|
-
*
|
|
294
|
-
* app.use('*', errorHandler({
|
|
295
|
-
* errorTransport: sentry,
|
|
296
|
-
* captureAllErrors: false, // Only capture 5xx errors
|
|
297
|
-
* }));
|
|
298
|
-
* ```
|
|
299
|
-
*/
|
|
300
|
-
declare function errorHandler(options?: ErrorHandlerOptions): (c: HonoContext, next: HonoNext) => Promise<(Response & hono.TypedResponse<{
|
|
301
|
-
success: boolean;
|
|
302
|
-
error?: {
|
|
303
|
-
code: string;
|
|
304
|
-
message: string;
|
|
305
|
-
details?: {
|
|
306
|
-
[x: string]: hono_utils_types.JSONValue;
|
|
307
|
-
} | undefined;
|
|
308
|
-
} | undefined;
|
|
309
|
-
meta?: {
|
|
310
|
-
page?: number | undefined | undefined;
|
|
311
|
-
limit?: number | undefined | undefined;
|
|
312
|
-
total?: number | undefined | undefined;
|
|
313
|
-
requestId?: string | undefined | undefined;
|
|
314
|
-
} | undefined;
|
|
315
|
-
}, 400, "json">) | (Response & hono.TypedResponse<{
|
|
316
|
-
success: boolean;
|
|
317
|
-
error?: {
|
|
318
|
-
code: string;
|
|
319
|
-
message: string;
|
|
320
|
-
details?: {
|
|
321
|
-
[x: string]: hono_utils_types.JSONValue;
|
|
322
|
-
} | undefined;
|
|
323
|
-
} | undefined;
|
|
324
|
-
meta?: {
|
|
325
|
-
page?: number | undefined | undefined;
|
|
326
|
-
limit?: number | undefined | undefined;
|
|
327
|
-
total?: number | undefined | undefined;
|
|
328
|
-
requestId?: string | undefined | undefined;
|
|
329
|
-
} | undefined;
|
|
330
|
-
}, 500, "json">) | undefined>;
|
|
331
|
-
/**
|
|
332
|
-
* Not found handler
|
|
333
|
-
*
|
|
334
|
-
* @example
|
|
335
|
-
* ```typescript
|
|
336
|
-
* app.notFound(notFoundHandler);
|
|
337
|
-
* ```
|
|
338
|
-
*/
|
|
339
|
-
declare function notFoundHandler(c: HonoContext): Response & hono.TypedResponse<{
|
|
340
|
-
success: boolean;
|
|
341
|
-
error?: {
|
|
342
|
-
code: string;
|
|
343
|
-
message: string;
|
|
344
|
-
details?: {
|
|
345
|
-
[x: string]: hono_utils_types.JSONValue;
|
|
346
|
-
} | undefined;
|
|
347
|
-
} | undefined;
|
|
348
|
-
meta?: {
|
|
349
|
-
page?: number | undefined | undefined;
|
|
350
|
-
limit?: number | undefined | undefined;
|
|
351
|
-
total?: number | undefined | undefined;
|
|
352
|
-
requestId?: string | undefined | undefined;
|
|
353
|
-
} | undefined;
|
|
354
|
-
}, 404, "json">;
|
|
355
|
-
|
|
356
|
-
/**
|
|
357
|
-
* @parsrun/server - Rate Limit Middleware
|
|
358
|
-
* Request throttling with multiple storage backends
|
|
359
|
-
*/
|
|
360
|
-
|
|
361
|
-
/**
|
|
362
|
-
* Rate limit storage interface
|
|
363
|
-
*/
|
|
364
|
-
interface RateLimitStorage {
|
|
365
|
-
/** Get current count for key */
|
|
366
|
-
get(key: string): Promise<number>;
|
|
367
|
-
/** Increment count and set expiry */
|
|
368
|
-
increment(key: string, windowMs: number): Promise<number>;
|
|
369
|
-
/** Reset count for key */
|
|
370
|
-
reset(key: string): Promise<void>;
|
|
371
|
-
}
|
|
372
|
-
/**
|
|
373
|
-
* In-memory rate limit storage
|
|
374
|
-
* For single-instance deployments or development
|
|
375
|
-
*/
|
|
376
|
-
declare class MemoryRateLimitStorage implements RateLimitStorage {
|
|
377
|
-
private store;
|
|
378
|
-
get(key: string): Promise<number>;
|
|
379
|
-
increment(key: string, windowMs: number): Promise<number>;
|
|
380
|
-
reset(key: string): Promise<void>;
|
|
381
|
-
/** Clean up expired entries */
|
|
382
|
-
cleanup(): void;
|
|
383
|
-
}
|
|
384
|
-
/**
|
|
385
|
-
* Rate limit options
|
|
386
|
-
*/
|
|
387
|
-
interface RateLimitOptions {
|
|
388
|
-
/** Time window in milliseconds */
|
|
389
|
-
windowMs?: number;
|
|
390
|
-
/** Maximum requests per window */
|
|
391
|
-
max?: number;
|
|
392
|
-
/** Generate key from request (default: IP address) */
|
|
393
|
-
keyGenerator?: (c: HonoContext) => string;
|
|
394
|
-
/** Skip rate limiting for certain requests */
|
|
395
|
-
skip?: (c: HonoContext) => boolean;
|
|
396
|
-
/** Custom storage backend */
|
|
397
|
-
storage?: RateLimitStorage;
|
|
398
|
-
/** Error message */
|
|
399
|
-
message?: string;
|
|
400
|
-
/** Include rate limit headers */
|
|
401
|
-
headers?: boolean;
|
|
402
|
-
/** Handler when limit is exceeded */
|
|
403
|
-
onLimitReached?: (c: HonoContext, key: string) => void;
|
|
404
|
-
}
|
|
405
|
-
/**
|
|
406
|
-
* Rate limit middleware
|
|
407
|
-
*
|
|
408
|
-
* @example
|
|
409
|
-
* ```typescript
|
|
410
|
-
* // Basic usage - 100 requests per minute
|
|
411
|
-
* app.use('/api/*', rateLimit({
|
|
412
|
-
* windowMs: 60 * 1000,
|
|
413
|
-
* max: 100,
|
|
414
|
-
* }));
|
|
415
|
-
*
|
|
416
|
-
* // Per-user rate limiting
|
|
417
|
-
* app.use('/api/*', rateLimit({
|
|
418
|
-
* keyGenerator: (c) => c.get('user')?.id ?? getIP(c),
|
|
419
|
-
* max: 1000,
|
|
420
|
-
* }));
|
|
421
|
-
*
|
|
422
|
-
* // Strict limit for auth endpoints
|
|
423
|
-
* app.use('/api/auth/*', rateLimit({
|
|
424
|
-
* windowMs: 15 * 60 * 1000, // 15 minutes
|
|
425
|
-
* max: 5,
|
|
426
|
-
* message: 'Too many login attempts',
|
|
427
|
-
* }));
|
|
428
|
-
* ```
|
|
429
|
-
*/
|
|
430
|
-
declare function rateLimit(options?: RateLimitOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
431
|
-
/**
|
|
432
|
-
* Create rate limiter for specific routes
|
|
433
|
-
*
|
|
434
|
-
* @example
|
|
435
|
-
* ```typescript
|
|
436
|
-
* const apiLimiter = createRateLimiter({
|
|
437
|
-
* windowMs: 60000,
|
|
438
|
-
* max: 100,
|
|
439
|
-
* });
|
|
440
|
-
*
|
|
441
|
-
* app.use('/api/*', apiLimiter.middleware);
|
|
442
|
-
*
|
|
443
|
-
* // Reset limit for a user after successful auth
|
|
444
|
-
* await apiLimiter.reset('user:123');
|
|
445
|
-
* ```
|
|
446
|
-
*/
|
|
447
|
-
declare function createRateLimiter(options?: RateLimitOptions): {
|
|
448
|
-
middleware: (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
449
|
-
storage: RateLimitStorage;
|
|
450
|
-
reset: (key: string) => Promise<void>;
|
|
451
|
-
get: (key: string) => Promise<number>;
|
|
452
|
-
};
|
|
453
|
-
|
|
454
|
-
/**
|
|
455
|
-
* @parsrun/server - Request Logger Middleware
|
|
456
|
-
* HTTP request/response logging
|
|
457
|
-
*/
|
|
458
|
-
|
|
459
|
-
/**
|
|
460
|
-
* Request logger options
|
|
461
|
-
*/
|
|
462
|
-
interface RequestLoggerOptions {
|
|
463
|
-
/** Skip logging for certain paths */
|
|
464
|
-
skip?: (c: HonoContext) => boolean;
|
|
465
|
-
/** Custom log format */
|
|
466
|
-
format?: "json" | "combined" | "short";
|
|
467
|
-
/** Include request body in logs */
|
|
468
|
-
includeBody?: boolean;
|
|
469
|
-
/** Include response body in logs (be careful with large responses) */
|
|
470
|
-
includeResponseBody?: boolean;
|
|
471
|
-
/** Maximum body length to log */
|
|
472
|
-
maxBodyLength?: number;
|
|
473
|
-
}
|
|
474
|
-
/**
|
|
475
|
-
* Request logger middleware
|
|
476
|
-
*
|
|
477
|
-
* @example
|
|
478
|
-
* ```typescript
|
|
479
|
-
* app.use('*', requestLogger({
|
|
480
|
-
* skip: (c) => c.req.path === '/health',
|
|
481
|
-
* format: 'json',
|
|
482
|
-
* }));
|
|
483
|
-
* ```
|
|
484
|
-
*/
|
|
485
|
-
declare function requestLogger(options?: RequestLoggerOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
486
|
-
|
|
487
8
|
/**
|
|
488
9
|
* @parsrun/server - Tracing Middleware
|
|
489
10
|
* Request correlation and distributed tracing support
|
|
@@ -521,20 +42,7 @@ interface TracingOptions {
|
|
|
521
42
|
*/
|
|
522
43
|
trustIncoming?: boolean;
|
|
523
44
|
}
|
|
524
|
-
|
|
525
|
-
* W3C Trace Context - Parsed traceparent header
|
|
526
|
-
* Format: {version}-{trace-id}-{parent-id}-{trace-flags}
|
|
527
|
-
*/
|
|
528
|
-
interface TraceContext {
|
|
529
|
-
/** Trace version (currently "00") */
|
|
530
|
-
version: string;
|
|
531
|
-
/** 32 hex character trace ID */
|
|
532
|
-
traceId: string;
|
|
533
|
-
/** 16 hex character parent span ID */
|
|
534
|
-
parentId: string;
|
|
535
|
-
/** Trace flags (sampled, etc.) */
|
|
536
|
-
traceFlags: number;
|
|
537
|
-
}
|
|
45
|
+
|
|
538
46
|
/**
|
|
539
47
|
* Parse W3C traceparent header
|
|
540
48
|
* Format: 00-{trace-id}-{parent-id}-{trace-flags}
|
|
@@ -554,20 +62,6 @@ declare function generateSpanId(): string;
|
|
|
554
62
|
* Create a traceparent header value
|
|
555
63
|
*/
|
|
556
64
|
declare function createTraceparent(traceId: string, spanId: string, sampled?: boolean): string;
|
|
557
|
-
/**
|
|
558
|
-
* Extended context for tracing
|
|
559
|
-
* These values are set on the context for downstream middleware/handlers
|
|
560
|
-
*/
|
|
561
|
-
declare module "../context.js" {
|
|
562
|
-
interface ServerContextVariables {
|
|
563
|
-
/** W3C trace context (if propagation is enabled) */
|
|
564
|
-
traceContext?: TraceContext;
|
|
565
|
-
/** Current span ID for this request */
|
|
566
|
-
spanId?: string;
|
|
567
|
-
/** Tracestate header value (for forwarding) */
|
|
568
|
-
traceState?: string;
|
|
569
|
-
}
|
|
570
|
-
}
|
|
571
65
|
/**
|
|
572
66
|
* Tracing middleware
|
|
573
67
|
*
|
|
@@ -627,262 +121,4 @@ declare function tracing(options?: TracingOptions): (c: HonoContext, next: HonoN
|
|
|
627
121
|
*/
|
|
628
122
|
declare const tracingMiddleware: typeof tracing;
|
|
629
123
|
|
|
630
|
-
|
|
631
|
-
* @parsrun/server - Usage Tracking Middleware
|
|
632
|
-
* Automatically track API usage per request
|
|
633
|
-
*/
|
|
634
|
-
|
|
635
|
-
/**
|
|
636
|
-
* Usage service interface (from @parsrun/payments)
|
|
637
|
-
* Defined here to avoid circular dependency
|
|
638
|
-
*/
|
|
639
|
-
interface UsageServiceLike {
|
|
640
|
-
trackUsage(options: {
|
|
641
|
-
tenantId: string;
|
|
642
|
-
customerId: string;
|
|
643
|
-
subscriptionId?: string;
|
|
644
|
-
featureKey: string;
|
|
645
|
-
quantity?: number;
|
|
646
|
-
metadata?: Record<string, unknown>;
|
|
647
|
-
idempotencyKey?: string;
|
|
648
|
-
}): Promise<unknown>;
|
|
649
|
-
}
|
|
650
|
-
/**
|
|
651
|
-
* Usage tracking middleware options
|
|
652
|
-
*/
|
|
653
|
-
interface UsageTrackingOptions {
|
|
654
|
-
/**
|
|
655
|
-
* Usage service instance
|
|
656
|
-
*/
|
|
657
|
-
usageService: UsageServiceLike;
|
|
658
|
-
/**
|
|
659
|
-
* Feature key to track
|
|
660
|
-
* Can be a static string or a function that extracts it from context
|
|
661
|
-
* @default "api_calls"
|
|
662
|
-
*/
|
|
663
|
-
featureKey?: string | ((c: HonoContext) => string);
|
|
664
|
-
/**
|
|
665
|
-
* Quantity to track
|
|
666
|
-
* Can be a static number or a function that calculates it from context
|
|
667
|
-
* @default 1
|
|
668
|
-
*/
|
|
669
|
-
quantity?: number | ((c: HonoContext) => number);
|
|
670
|
-
/**
|
|
671
|
-
* Skip tracking for certain requests
|
|
672
|
-
*/
|
|
673
|
-
skip?: (c: HonoContext) => boolean;
|
|
674
|
-
/**
|
|
675
|
-
* When to track: before or after the request
|
|
676
|
-
* @default "response"
|
|
677
|
-
*/
|
|
678
|
-
trackOn?: "request" | "response";
|
|
679
|
-
/**
|
|
680
|
-
* Only track successful responses (2xx)
|
|
681
|
-
* @default true
|
|
682
|
-
*/
|
|
683
|
-
successOnly?: boolean;
|
|
684
|
-
/**
|
|
685
|
-
* Custom customer ID extractor
|
|
686
|
-
* @default Uses c.get("user")?.id
|
|
687
|
-
*/
|
|
688
|
-
getCustomerId?: (c: HonoContext) => string | undefined;
|
|
689
|
-
/**
|
|
690
|
-
* Custom tenant ID extractor
|
|
691
|
-
* @default Uses c.get("tenant")?.id or c.get("user")?.tenantId
|
|
692
|
-
*/
|
|
693
|
-
getTenantId?: (c: HonoContext) => string | undefined;
|
|
694
|
-
/**
|
|
695
|
-
* Custom subscription ID extractor
|
|
696
|
-
*/
|
|
697
|
-
getSubscriptionId?: (c: HonoContext) => string | undefined;
|
|
698
|
-
/**
|
|
699
|
-
* Include request metadata
|
|
700
|
-
* @default true
|
|
701
|
-
*/
|
|
702
|
-
includeMetadata?: boolean;
|
|
703
|
-
/**
|
|
704
|
-
* Generate idempotency key to prevent duplicates
|
|
705
|
-
*/
|
|
706
|
-
getIdempotencyKey?: (c: HonoContext) => string | undefined;
|
|
707
|
-
}
|
|
708
|
-
/**
|
|
709
|
-
* Usage tracking middleware
|
|
710
|
-
*
|
|
711
|
-
* Automatically tracks API usage for authenticated requests.
|
|
712
|
-
*
|
|
713
|
-
* @example
|
|
714
|
-
* ```typescript
|
|
715
|
-
* import { usageTracking } from "@parsrun/server";
|
|
716
|
-
* import { createUsageService, createMemoryUsageStorage } from "@parsrun/payments";
|
|
717
|
-
*
|
|
718
|
-
* const usageService = createUsageService({
|
|
719
|
-
* storage: createMemoryUsageStorage(),
|
|
720
|
-
* });
|
|
721
|
-
*
|
|
722
|
-
* // Track all API calls
|
|
723
|
-
* app.use("/api/*", usageTracking({
|
|
724
|
-
* usageService,
|
|
725
|
-
* featureKey: "api_calls",
|
|
726
|
-
* }));
|
|
727
|
-
*
|
|
728
|
-
* // Track with custom feature key based on route
|
|
729
|
-
* app.use("/api/ai/*", usageTracking({
|
|
730
|
-
* usageService,
|
|
731
|
-
* featureKey: "ai_requests",
|
|
732
|
-
* quantity: (c) => {
|
|
733
|
-
* // Track tokens used from response
|
|
734
|
-
* return c.get("tokensUsed") ?? 1;
|
|
735
|
-
* },
|
|
736
|
-
* }));
|
|
737
|
-
*
|
|
738
|
-
* // Skip certain routes
|
|
739
|
-
* app.use("/api/*", usageTracking({
|
|
740
|
-
* usageService,
|
|
741
|
-
* skip: (c) => c.req.path.startsWith("/api/health"),
|
|
742
|
-
* }));
|
|
743
|
-
* ```
|
|
744
|
-
*/
|
|
745
|
-
declare function usageTracking(options: UsageTrackingOptions): (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
746
|
-
/**
|
|
747
|
-
* Create usage tracking middleware with pre-configured options
|
|
748
|
-
*/
|
|
749
|
-
declare function createUsageTracking(baseOptions: UsageTrackingOptions): (overrides?: Partial<UsageTrackingOptions>) => (c: HonoContext, next: HonoNext) => Promise<void>;
|
|
750
|
-
|
|
751
|
-
/**
|
|
752
|
-
* @parsrun/server - Quota Enforcement Middleware
|
|
753
|
-
* Enforce usage quotas before processing requests
|
|
754
|
-
*/
|
|
755
|
-
|
|
756
|
-
/**
|
|
757
|
-
* Quota check result interface (from @parsrun/payments)
|
|
758
|
-
*/
|
|
759
|
-
interface QuotaCheckResult {
|
|
760
|
-
allowed: boolean;
|
|
761
|
-
currentUsage: number;
|
|
762
|
-
limit: number | null;
|
|
763
|
-
remaining: number | null;
|
|
764
|
-
wouldExceed: boolean;
|
|
765
|
-
percentAfter: number | null;
|
|
766
|
-
}
|
|
767
|
-
/**
|
|
768
|
-
* Quota manager interface (from @parsrun/payments)
|
|
769
|
-
* Defined here to avoid circular dependency
|
|
770
|
-
*/
|
|
771
|
-
interface QuotaManagerLike {
|
|
772
|
-
checkQuota(customerId: string, featureKey: string, quantity?: number): Promise<QuotaCheckResult>;
|
|
773
|
-
enforceQuota(customerId: string, featureKey: string, quantity?: number): Promise<void>;
|
|
774
|
-
}
|
|
775
|
-
/**
|
|
776
|
-
* Quota exceeded error class
|
|
777
|
-
*/
|
|
778
|
-
declare class QuotaExceededError extends Error {
|
|
779
|
-
readonly featureKey: string;
|
|
780
|
-
readonly limit: number | null;
|
|
781
|
-
readonly currentUsage: number;
|
|
782
|
-
readonly requestedQuantity: number;
|
|
783
|
-
readonly statusCode = 429;
|
|
784
|
-
readonly code = "QUOTA_EXCEEDED";
|
|
785
|
-
constructor(featureKey: string, limit: number | null, currentUsage: number, requestedQuantity?: number);
|
|
786
|
-
}
|
|
787
|
-
/**
|
|
788
|
-
* Quota enforcement middleware options
|
|
789
|
-
*/
|
|
790
|
-
interface QuotaEnforcementOptions {
|
|
791
|
-
/**
|
|
792
|
-
* Quota manager instance
|
|
793
|
-
*/
|
|
794
|
-
quotaManager: QuotaManagerLike;
|
|
795
|
-
/**
|
|
796
|
-
* Feature key to check
|
|
797
|
-
* Can be a static string or a function that extracts it from context
|
|
798
|
-
*/
|
|
799
|
-
featureKey: string | ((c: HonoContext) => string);
|
|
800
|
-
/**
|
|
801
|
-
* Quantity to check (default: 1)
|
|
802
|
-
*/
|
|
803
|
-
quantity?: number | ((c: HonoContext) => number);
|
|
804
|
-
/**
|
|
805
|
-
* Skip quota check for certain requests
|
|
806
|
-
*/
|
|
807
|
-
skip?: (c: HonoContext) => boolean;
|
|
808
|
-
/**
|
|
809
|
-
* Custom customer ID extractor
|
|
810
|
-
* @default Uses c.get("user")?.id
|
|
811
|
-
*/
|
|
812
|
-
getCustomerId?: (c: HonoContext) => string | undefined;
|
|
813
|
-
/**
|
|
814
|
-
* Include quota headers in response
|
|
815
|
-
* @default true
|
|
816
|
-
*/
|
|
817
|
-
includeHeaders?: boolean;
|
|
818
|
-
/**
|
|
819
|
-
* Custom error handler
|
|
820
|
-
*/
|
|
821
|
-
onQuotaExceeded?: (c: HonoContext, result: QuotaCheckResult, featureKey: string) => Response | void;
|
|
822
|
-
/**
|
|
823
|
-
* Soft limit mode - warn but don't block
|
|
824
|
-
* @default false
|
|
825
|
-
*/
|
|
826
|
-
softLimit?: boolean;
|
|
827
|
-
/**
|
|
828
|
-
* Callback when quota is close to limit (>80%)
|
|
829
|
-
*/
|
|
830
|
-
onQuotaWarning?: (c: HonoContext, result: QuotaCheckResult, featureKey: string) => void;
|
|
831
|
-
}
|
|
832
|
-
/**
|
|
833
|
-
* Quota enforcement middleware
|
|
834
|
-
*
|
|
835
|
-
* Checks and enforces usage quotas before processing requests.
|
|
836
|
-
*
|
|
837
|
-
* @example
|
|
838
|
-
* ```typescript
|
|
839
|
-
* import { quotaEnforcement } from "@parsrun/server";
|
|
840
|
-
* import { createQuotaManager, createMemoryUsageStorage } from "@parsrun/payments";
|
|
841
|
-
*
|
|
842
|
-
* const quotaManager = createQuotaManager({
|
|
843
|
-
* storage: createMemoryUsageStorage(),
|
|
844
|
-
* });
|
|
845
|
-
*
|
|
846
|
-
* // Enforce API call quota
|
|
847
|
-
* app.use("/api/*", quotaEnforcement({
|
|
848
|
-
* quotaManager,
|
|
849
|
-
* featureKey: "api_calls",
|
|
850
|
-
* }));
|
|
851
|
-
*
|
|
852
|
-
* // Enforce with dynamic feature key
|
|
853
|
-
* app.use("/api/*", quotaEnforcement({
|
|
854
|
-
* quotaManager,
|
|
855
|
-
* featureKey: (c) => {
|
|
856
|
-
* if (c.req.path.startsWith("/api/ai")) return "ai_requests";
|
|
857
|
-
* return "api_calls";
|
|
858
|
-
* },
|
|
859
|
-
* }));
|
|
860
|
-
*
|
|
861
|
-
* // Soft limit mode (warn but allow)
|
|
862
|
-
* app.use("/api/*", quotaEnforcement({
|
|
863
|
-
* quotaManager,
|
|
864
|
-
* featureKey: "api_calls",
|
|
865
|
-
* softLimit: true,
|
|
866
|
-
* onQuotaWarning: (c, result) => {
|
|
867
|
-
* console.warn("Quota warning:", result);
|
|
868
|
-
* },
|
|
869
|
-
* }));
|
|
870
|
-
* ```
|
|
871
|
-
*/
|
|
872
|
-
declare function quotaEnforcement(options: QuotaEnforcementOptions): (c: HonoContext, next: HonoNext) => Promise<void | Response>;
|
|
873
|
-
/**
|
|
874
|
-
* Create quota enforcement middleware with pre-configured options
|
|
875
|
-
*/
|
|
876
|
-
declare function createQuotaEnforcement(baseOptions: Omit<QuotaEnforcementOptions, "featureKey">): (featureKey: string | ((c: HonoContext) => string)) => (c: HonoContext, next: HonoNext) => Promise<void | Response>;
|
|
877
|
-
/**
|
|
878
|
-
* Multiple quota enforcement
|
|
879
|
-
* Check multiple features at once
|
|
880
|
-
*/
|
|
881
|
-
declare function multiQuotaEnforcement(options: Omit<QuotaEnforcementOptions, "featureKey"> & {
|
|
882
|
-
features: Array<{
|
|
883
|
-
featureKey: string;
|
|
884
|
-
quantity?: number | ((c: HonoContext) => number);
|
|
885
|
-
}>;
|
|
886
|
-
}): (c: HonoContext, next: HonoNext) => Promise<void | Response>;
|
|
887
|
-
|
|
888
|
-
export { ApiError, type AuthMiddlewareOptions, BadRequestError, ConflictError, type CsrfOptions, type ErrorHandlerOptions, ForbiddenError, InternalError, type JwtPayload, type JwtVerifier, MemoryRateLimitStorage, NotFoundError, type QuotaCheckResult, type QuotaEnforcementOptions, QuotaExceededError, type QuotaManagerLike, RateLimitError, type RateLimitOptions, type RateLimitStorage, type RequestLoggerOptions, ServiceUnavailableError, type TraceContext, type TracingOptions, UnauthorizedError, type UsageServiceLike, type UsageTrackingOptions, ValidationError, auth, cors, createAuthMiddleware, createQuotaEnforcement, createRateLimiter, createTraceparent, createUsageTracking, csrf, doubleSubmitCookie, errorHandler, generateSpanId, generateTraceId, multiQuotaEnforcement, notFoundHandler, optionalAuth, parseTraceparent, quotaEnforcement, rateLimit, requestLogger, tracing, tracingMiddleware, usageTracking };
|
|
124
|
+
export { TraceContext, type TracingOptions, createTraceparent, generateSpanId, generateTraceId, parseTraceparent, tracing, tracingMiddleware };
|