@frontmcp/sdk 0.6.2 → 0.6.3
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/auth/session/index.d.ts +4 -2
- package/auth/session/redis-session.store.d.ts +26 -3
- package/auth/session/session-crypto.d.ts +86 -0
- package/auth/session/session-rate-limiter.d.ts +113 -0
- package/auth/session/transport-session.types.d.ts +51 -34
- package/auth/session/vercel-kv-session.store.d.ts +22 -2
- package/esm/index.mjs +644 -89
- package/esm/package.json +25 -17
- package/index.js +660 -104
- package/package.json +12 -2
- package/transport/adapters/sse-transport.d.ts +65 -0
- package/transport/adapters/streamable-http-transport.d.ts +69 -0
- package/transport/adapters/transport.local.adapter.d.ts +15 -1
- package/transport/adapters/transport.sse.adapter.d.ts +16 -3
- package/transport/adapters/transport.streamable-http.adapter.d.ts +12 -3
- package/transport/index.d.ts +21 -0
- package/transport/transport.local.d.ts +6 -0
- package/transport/transport.registry.d.ts +7 -1
- package/transport/transport.remote.d.ts +1 -0
- package/transport/transport.types.d.ts +6 -0
package/auth/session/index.d.ts
CHANGED
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
export * from './transport-session.types';
|
|
2
2
|
export { TransportSessionManager, InMemorySessionStore } from './transport-session.manager';
|
|
3
|
-
export { RedisSessionStore } from './redis-session.store';
|
|
4
|
-
export { VercelKvSessionStore } from './vercel-kv-session.store';
|
|
3
|
+
export { RedisSessionStore, RedisSessionStoreConfig } from './redis-session.store';
|
|
4
|
+
export { VercelKvSessionStore, VercelKvSessionConfig } from './vercel-kv-session.store';
|
|
5
|
+
export { SessionRateLimiter, SessionRateLimiterConfig, RateLimitResult, defaultSessionRateLimiter, } from './session-rate-limiter';
|
|
6
|
+
export { signSession, verifySession, verifyOrParseSession, isSignedSession, SignedSession, SessionSigningConfig, } from './session-crypto';
|
|
5
7
|
export * from './authorization.store';
|
|
6
8
|
export * from './authorization-vault';
|
|
@@ -1,11 +1,23 @@
|
|
|
1
1
|
import { Redis } from 'ioredis';
|
|
2
|
-
import { SessionStore, StoredSession, RedisConfig } from './transport-session.types';
|
|
2
|
+
import { SessionStore, StoredSession, RedisConfig, SessionSecurityConfig } from './transport-session.types';
|
|
3
3
|
import { FrontMcpLogger } from '../../common/interfaces/logger.interface';
|
|
4
|
+
/**
|
|
5
|
+
* Extended Redis configuration with security options.
|
|
6
|
+
*/
|
|
7
|
+
export interface RedisSessionStoreConfig extends RedisConfig {
|
|
8
|
+
/** Security hardening options */
|
|
9
|
+
security?: SessionSecurityConfig;
|
|
10
|
+
}
|
|
4
11
|
/**
|
|
5
12
|
* Redis-backed session store implementation
|
|
6
13
|
*
|
|
7
14
|
* Provides persistent session storage for distributed deployments.
|
|
8
15
|
* Sessions are stored as JSON with optional TTL.
|
|
16
|
+
*
|
|
17
|
+
* Security features (configurable via security option):
|
|
18
|
+
* - HMAC signing: Detects session data tampering
|
|
19
|
+
* - Rate limiting: Prevents session enumeration attacks
|
|
20
|
+
* - Max lifetime: Prevents indefinite session extension
|
|
9
21
|
*/
|
|
10
22
|
export declare class RedisSessionStore implements SessionStore {
|
|
11
23
|
private readonly redis;
|
|
@@ -13,10 +25,13 @@ export declare class RedisSessionStore implements SessionStore {
|
|
|
13
25
|
private readonly defaultTtlMs;
|
|
14
26
|
private readonly logger?;
|
|
15
27
|
private externalInstance;
|
|
16
|
-
|
|
28
|
+
private readonly security;
|
|
29
|
+
private readonly rateLimiter?;
|
|
30
|
+
constructor(config: RedisSessionStoreConfig | {
|
|
17
31
|
redis: Redis;
|
|
18
32
|
keyPrefix?: string;
|
|
19
33
|
defaultTtlMs?: number;
|
|
34
|
+
security?: SessionSecurityConfig;
|
|
20
35
|
}, logger?: FrontMcpLogger);
|
|
21
36
|
/**
|
|
22
37
|
* Get the full Redis key for a session ID
|
|
@@ -28,8 +43,16 @@ export declare class RedisSessionStore implements SessionStore {
|
|
|
28
43
|
*
|
|
29
44
|
* Note: Uses atomic GETEX to extend TTL while reading, preventing race conditions
|
|
30
45
|
* where concurrent readers might resurrect expired sessions.
|
|
46
|
+
*
|
|
47
|
+
* @param sessionId - The session ID to look up
|
|
48
|
+
* @param options - Optional parameters for rate limiting
|
|
49
|
+
* @param options.clientIdentifier - Client identifier (e.g., IP address) for rate limiting.
|
|
50
|
+
* When provided, rate limiting is applied per-client to prevent session enumeration.
|
|
51
|
+
* If not provided, falls back to sessionId which provides DoS protection per-session.
|
|
31
52
|
*/
|
|
32
|
-
get(sessionId: string
|
|
53
|
+
get(sessionId: string, options?: {
|
|
54
|
+
clientIdentifier?: string;
|
|
55
|
+
}): Promise<StoredSession | null>;
|
|
33
56
|
/**
|
|
34
57
|
* Store a session with optional TTL
|
|
35
58
|
*/
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Cryptographic Utilities
|
|
3
|
+
*
|
|
4
|
+
* Provides HMAC signing and verification for stored session data.
|
|
5
|
+
* Protects against session data tampering when stored in external
|
|
6
|
+
* systems like Redis that don't provide application-level integrity.
|
|
7
|
+
*/
|
|
8
|
+
import type { StoredSession } from './transport-session.types';
|
|
9
|
+
/**
|
|
10
|
+
* Signed session wrapper structure.
|
|
11
|
+
* Contains the session data and its HMAC signature.
|
|
12
|
+
*/
|
|
13
|
+
export interface SignedSession {
|
|
14
|
+
/** The session data */
|
|
15
|
+
data: StoredSession;
|
|
16
|
+
/** HMAC-SHA256 signature in base64url format */
|
|
17
|
+
sig: string;
|
|
18
|
+
/** Signature version for future algorithm changes */
|
|
19
|
+
v: 1;
|
|
20
|
+
}
|
|
21
|
+
/**
|
|
22
|
+
* Configuration for session signing.
|
|
23
|
+
*/
|
|
24
|
+
export interface SessionSigningConfig {
|
|
25
|
+
/**
|
|
26
|
+
* The secret key used for HMAC signing.
|
|
27
|
+
* Should be at least 32 bytes for security.
|
|
28
|
+
* Uses MCP_SESSION_SECRET environment variable if not provided.
|
|
29
|
+
*/
|
|
30
|
+
secret?: string;
|
|
31
|
+
}
|
|
32
|
+
/**
|
|
33
|
+
* Sign a stored session with HMAC-SHA256.
|
|
34
|
+
*
|
|
35
|
+
* Creates a tamper-evident wrapper around the session data.
|
|
36
|
+
* Any modification to the session will invalidate the signature.
|
|
37
|
+
*
|
|
38
|
+
* @param session - The session to sign
|
|
39
|
+
* @param config - Optional signing configuration
|
|
40
|
+
* @returns JSON string containing signed session
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const signed = signSession(session);
|
|
45
|
+
* await redis.set(key, signed);
|
|
46
|
+
* ```
|
|
47
|
+
*/
|
|
48
|
+
export declare function signSession(session: StoredSession, config?: SessionSigningConfig): string;
|
|
49
|
+
/**
|
|
50
|
+
* Verify and extract a signed session.
|
|
51
|
+
*
|
|
52
|
+
* Validates the HMAC signature and returns the session if valid.
|
|
53
|
+
* Returns null if the signature is invalid or the data is corrupted.
|
|
54
|
+
*
|
|
55
|
+
* @param signedData - JSON string from signSession()
|
|
56
|
+
* @param config - Optional signing configuration
|
|
57
|
+
* @returns The verified session or null if invalid
|
|
58
|
+
*
|
|
59
|
+
* @example
|
|
60
|
+
* ```typescript
|
|
61
|
+
* const raw = await redis.get(key);
|
|
62
|
+
* const session = verifySession(raw);
|
|
63
|
+
* if (!session) {
|
|
64
|
+
* // Session was tampered with or corrupted
|
|
65
|
+
* await redis.del(key);
|
|
66
|
+
* }
|
|
67
|
+
* ```
|
|
68
|
+
*/
|
|
69
|
+
export declare function verifySession(signedData: string, config?: SessionSigningConfig): StoredSession | null;
|
|
70
|
+
/**
|
|
71
|
+
* Check if a stored value is a signed session.
|
|
72
|
+
* Useful for migrating from unsigned to signed sessions.
|
|
73
|
+
*
|
|
74
|
+
* @param data - Raw data from storage
|
|
75
|
+
* @returns true if the data appears to be a signed session
|
|
76
|
+
*/
|
|
77
|
+
export declare function isSignedSession(data: string): boolean;
|
|
78
|
+
/**
|
|
79
|
+
* Verify or parse a session, supporting both signed and unsigned formats.
|
|
80
|
+
* Useful for backwards compatibility during migration.
|
|
81
|
+
*
|
|
82
|
+
* @param data - Raw data from storage
|
|
83
|
+
* @param config - Optional signing configuration
|
|
84
|
+
* @returns The session (verified if signed, parsed if unsigned) or null
|
|
85
|
+
*/
|
|
86
|
+
export declare function verifyOrParseSession(data: string, config?: SessionSigningConfig): StoredSession | null;
|
|
@@ -0,0 +1,113 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session Rate Limiter
|
|
3
|
+
*
|
|
4
|
+
* Simple sliding window rate limiter for session lookup operations.
|
|
5
|
+
* Protects against session enumeration attacks by limiting the rate
|
|
6
|
+
* of session lookups per client IP or identifier.
|
|
7
|
+
*/
|
|
8
|
+
export interface SessionRateLimiterConfig {
|
|
9
|
+
/**
|
|
10
|
+
* Time window in milliseconds for rate limiting.
|
|
11
|
+
* @default 60000 (1 minute)
|
|
12
|
+
*/
|
|
13
|
+
windowMs?: number;
|
|
14
|
+
/**
|
|
15
|
+
* Maximum requests allowed per window per key.
|
|
16
|
+
* @default 100
|
|
17
|
+
*/
|
|
18
|
+
maxRequests?: number;
|
|
19
|
+
/**
|
|
20
|
+
* Interval in milliseconds for automatic cleanup of expired entries.
|
|
21
|
+
* Set to 0 to disable automatic cleanup.
|
|
22
|
+
* @default 60000 (1 minute)
|
|
23
|
+
*/
|
|
24
|
+
cleanupIntervalMs?: number;
|
|
25
|
+
}
|
|
26
|
+
export interface RateLimitResult {
|
|
27
|
+
/** Whether the request is allowed */
|
|
28
|
+
allowed: boolean;
|
|
29
|
+
/** Number of remaining requests in the current window */
|
|
30
|
+
remaining: number;
|
|
31
|
+
/** Timestamp when the rate limit resets (epoch ms) */
|
|
32
|
+
resetAt: number;
|
|
33
|
+
/** Time to wait before retry (only set if not allowed) */
|
|
34
|
+
retryAfterMs?: number;
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Sliding window rate limiter for session operations.
|
|
38
|
+
*
|
|
39
|
+
* Uses an in-memory sliding window algorithm to track request timestamps
|
|
40
|
+
* per key (typically client IP). Automatically cleans up expired entries.
|
|
41
|
+
*
|
|
42
|
+
* @example
|
|
43
|
+
* ```typescript
|
|
44
|
+
* const rateLimiter = new SessionRateLimiter({ maxRequests: 50, windowMs: 60000 });
|
|
45
|
+
*
|
|
46
|
+
* // In session store get()
|
|
47
|
+
* const clientIp = getClientIp(req);
|
|
48
|
+
* const result = rateLimiter.check(clientIp);
|
|
49
|
+
* if (!result.allowed) {
|
|
50
|
+
* throw new Error(`Rate limit exceeded. Retry after ${result.retryAfterMs}ms`);
|
|
51
|
+
* }
|
|
52
|
+
* ```
|
|
53
|
+
*/
|
|
54
|
+
export declare class SessionRateLimiter {
|
|
55
|
+
private readonly windowMs;
|
|
56
|
+
private readonly maxRequests;
|
|
57
|
+
private readonly requests;
|
|
58
|
+
private cleanupTimer;
|
|
59
|
+
constructor(config?: SessionRateLimiterConfig);
|
|
60
|
+
/**
|
|
61
|
+
* Check if a request is allowed for the given key.
|
|
62
|
+
*
|
|
63
|
+
* @param key - Identifier for rate limiting (e.g., client IP, session ID prefix)
|
|
64
|
+
* @returns Rate limit result with allowed status and metadata
|
|
65
|
+
*/
|
|
66
|
+
check(key: string): RateLimitResult;
|
|
67
|
+
/**
|
|
68
|
+
* Check if a request would be allowed without recording it.
|
|
69
|
+
* Useful for pre-checking without consuming quota.
|
|
70
|
+
*
|
|
71
|
+
* @param key - Identifier for rate limiting
|
|
72
|
+
* @returns true if request would be allowed
|
|
73
|
+
*/
|
|
74
|
+
wouldAllow(key: string): boolean;
|
|
75
|
+
/**
|
|
76
|
+
* Reset rate limit for a specific key.
|
|
77
|
+
* Useful for testing or after successful authentication.
|
|
78
|
+
*
|
|
79
|
+
* @param key - Identifier to reset
|
|
80
|
+
*/
|
|
81
|
+
reset(key: string): void;
|
|
82
|
+
/**
|
|
83
|
+
* Clean up expired entries from all keys.
|
|
84
|
+
* Called automatically on configured interval, but can be called manually.
|
|
85
|
+
*/
|
|
86
|
+
cleanup(): void;
|
|
87
|
+
/**
|
|
88
|
+
* Get current statistics for monitoring.
|
|
89
|
+
*/
|
|
90
|
+
getStats(): {
|
|
91
|
+
totalKeys: number;
|
|
92
|
+
totalRequests: number;
|
|
93
|
+
};
|
|
94
|
+
/**
|
|
95
|
+
* Stop the automatic cleanup timer.
|
|
96
|
+
* Call this when disposing of the rate limiter.
|
|
97
|
+
*/
|
|
98
|
+
dispose(): void;
|
|
99
|
+
}
|
|
100
|
+
/**
|
|
101
|
+
* Default shared rate limiter instance for simple single-process scenarios.
|
|
102
|
+
*
|
|
103
|
+
* WARNING: This singleton shares state across all usages in the same process.
|
|
104
|
+
* For most use cases, create a new SessionRateLimiter instance per session store.
|
|
105
|
+
*
|
|
106
|
+
* @example
|
|
107
|
+
* // Preferred: Create instance per store
|
|
108
|
+
* this.rateLimiter = new SessionRateLimiter({ windowMs: 60000, maxRequests: 100 });
|
|
109
|
+
*
|
|
110
|
+
* // Only use default for simple single-tenant scenarios
|
|
111
|
+
* import { defaultSessionRateLimiter } from './session-rate-limiter';
|
|
112
|
+
*/
|
|
113
|
+
export declare const defaultSessionRateLimiter: SessionRateLimiter;
|
|
@@ -135,6 +135,14 @@ export interface StoredSession {
|
|
|
135
135
|
createdAt: number;
|
|
136
136
|
/** Last accessed timestamp */
|
|
137
137
|
lastAccessedAt: number;
|
|
138
|
+
/** Whether the MCP protocol initialization handshake was completed */
|
|
139
|
+
initialized?: boolean;
|
|
140
|
+
/**
|
|
141
|
+
* Absolute maximum lifetime timestamp (epoch ms).
|
|
142
|
+
* Session is invalid after this time regardless of access patterns.
|
|
143
|
+
* This prevents indefinite session extension via sliding expiration.
|
|
144
|
+
*/
|
|
145
|
+
maxLifetimeAt?: number;
|
|
138
146
|
}
|
|
139
147
|
/**
|
|
140
148
|
* Encrypted blob structure (AES-256-GCM)
|
|
@@ -206,6 +214,47 @@ export interface RedisConfig {
|
|
|
206
214
|
/** Default TTL in milliseconds for session extension on access (sliding expiration) */
|
|
207
215
|
defaultTtlMs?: number;
|
|
208
216
|
}
|
|
217
|
+
/**
|
|
218
|
+
* Security configuration options for session stores.
|
|
219
|
+
* These options enable additional security hardening features.
|
|
220
|
+
*/
|
|
221
|
+
export interface SessionSecurityConfig {
|
|
222
|
+
/**
|
|
223
|
+
* Default maximum session lifetime in milliseconds.
|
|
224
|
+
* Sessions will be invalidated after this time regardless of access.
|
|
225
|
+
* Set to prevent indefinite session extension via sliding expiration.
|
|
226
|
+
* @example 86400000 // 24 hours
|
|
227
|
+
*/
|
|
228
|
+
maxLifetimeMs?: number;
|
|
229
|
+
/**
|
|
230
|
+
* Enable HMAC signing for stored sessions.
|
|
231
|
+
* When enabled, sessions are signed to detect tampering.
|
|
232
|
+
* Requires MCP_SESSION_SECRET environment variable or signing.secret config.
|
|
233
|
+
* @default false
|
|
234
|
+
*/
|
|
235
|
+
enableSigning?: boolean;
|
|
236
|
+
/**
|
|
237
|
+
* Secret key for HMAC signing.
|
|
238
|
+
* If not provided, falls back to MCP_SESSION_SECRET environment variable.
|
|
239
|
+
*/
|
|
240
|
+
signingSecret?: string;
|
|
241
|
+
/**
|
|
242
|
+
* Enable rate limiting for session lookups.
|
|
243
|
+
* Protects against session enumeration attacks.
|
|
244
|
+
* @default false
|
|
245
|
+
*/
|
|
246
|
+
enableRateLimiting?: boolean;
|
|
247
|
+
/**
|
|
248
|
+
* Rate limiting configuration.
|
|
249
|
+
* Only used if enableRateLimiting is true.
|
|
250
|
+
*/
|
|
251
|
+
rateLimiting?: {
|
|
252
|
+
/** Time window in milliseconds. @default 60000 */
|
|
253
|
+
windowMs?: number;
|
|
254
|
+
/** Maximum requests per window. @default 100 */
|
|
255
|
+
maxRequests?: number;
|
|
256
|
+
};
|
|
257
|
+
}
|
|
209
258
|
export declare const transportProtocolSchema: z.ZodEnum<{
|
|
210
259
|
"legacy-sse": "legacy-sse";
|
|
211
260
|
sse: "sse";
|
|
@@ -345,22 +394,6 @@ export declare const sessionJwtPayloadSchema: z.ZodObject<{
|
|
|
345
394
|
iat: z.ZodNumber;
|
|
346
395
|
exp: z.ZodOptional<z.ZodNumber>;
|
|
347
396
|
}, z.core.$strip>;
|
|
348
|
-
export declare const statelessSessionJwtPayloadSchema: z.ZodObject<{
|
|
349
|
-
sid: z.ZodString;
|
|
350
|
-
aid: z.ZodString;
|
|
351
|
-
proto: z.ZodEnum<{
|
|
352
|
-
"legacy-sse": "legacy-sse";
|
|
353
|
-
sse: "sse";
|
|
354
|
-
"streamable-http": "streamable-http";
|
|
355
|
-
"stateful-http": "stateful-http";
|
|
356
|
-
"stateless-http": "stateless-http";
|
|
357
|
-
}>;
|
|
358
|
-
nid: z.ZodString;
|
|
359
|
-
iat: z.ZodNumber;
|
|
360
|
-
exp: z.ZodOptional<z.ZodNumber>;
|
|
361
|
-
state: z.ZodOptional<z.ZodString>;
|
|
362
|
-
tokens: z.ZodOptional<z.ZodString>;
|
|
363
|
-
}, z.core.$strip>;
|
|
364
397
|
export declare const encryptedBlobSchema: z.ZodObject<{
|
|
365
398
|
alg: z.ZodLiteral<"A256GCM">;
|
|
366
399
|
kid: z.ZodOptional<z.ZodString>;
|
|
@@ -431,6 +464,8 @@ export declare const storedSessionSchema: z.ZodObject<{
|
|
|
431
464
|
}, z.core.$strip>>>;
|
|
432
465
|
createdAt: z.ZodNumber;
|
|
433
466
|
lastAccessedAt: z.ZodNumber;
|
|
467
|
+
initialized: z.ZodOptional<z.ZodBoolean>;
|
|
468
|
+
maxLifetimeAt: z.ZodOptional<z.ZodNumber>;
|
|
434
469
|
}, z.core.$strip>;
|
|
435
470
|
export declare const redisConfigSchema: z.ZodObject<{
|
|
436
471
|
host: z.ZodString;
|
|
@@ -441,21 +476,3 @@ export declare const redisConfigSchema: z.ZodObject<{
|
|
|
441
476
|
keyPrefix: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
442
477
|
defaultTtlMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
443
478
|
}, z.core.$strip>;
|
|
444
|
-
export declare const sessionStorageConfigSchema: z.ZodUnion<readonly [z.ZodObject<{
|
|
445
|
-
mode: z.ZodLiteral<"stateless">;
|
|
446
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
447
|
-
mode: z.ZodLiteral<"stateful">;
|
|
448
|
-
store: z.ZodLiteral<"memory">;
|
|
449
|
-
}, z.core.$strip>, z.ZodObject<{
|
|
450
|
-
mode: z.ZodLiteral<"stateful">;
|
|
451
|
-
store: z.ZodLiteral<"redis">;
|
|
452
|
-
config: z.ZodObject<{
|
|
453
|
-
host: z.ZodString;
|
|
454
|
-
port: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
455
|
-
password: z.ZodOptional<z.ZodString>;
|
|
456
|
-
db: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
457
|
-
tls: z.ZodDefault<z.ZodOptional<z.ZodBoolean>>;
|
|
458
|
-
keyPrefix: z.ZodDefault<z.ZodOptional<z.ZodString>>;
|
|
459
|
-
defaultTtlMs: z.ZodDefault<z.ZodOptional<z.ZodNumber>>;
|
|
460
|
-
}, z.core.$strip>;
|
|
461
|
-
}, z.core.$strip>]>;
|
|
@@ -4,9 +4,15 @@
|
|
|
4
4
|
* Session store implementation using Vercel KV (edge-compatible REST-based key-value store).
|
|
5
5
|
* Uses dynamic import to avoid bundling @vercel/kv for non-Vercel deployments.
|
|
6
6
|
*
|
|
7
|
+
* @warning **Atomicity Limitation**: Vercel KV does not support atomic GET+EXPIRE (GETEX).
|
|
8
|
+
* The `get()` method uses separate GET and PEXPIRE calls, creating a small race window
|
|
9
|
+
* where the session could expire between these two operations. For mission-critical
|
|
10
|
+
* session handling requiring strict atomicity guarantees, consider using Redis directly
|
|
11
|
+
* via `RedisSessionStore`.
|
|
12
|
+
*
|
|
7
13
|
* @see https://vercel.com/docs/storage/vercel-kv
|
|
8
14
|
*/
|
|
9
|
-
import { SessionStore, StoredSession } from './transport-session.types';
|
|
15
|
+
import { SessionStore, StoredSession, SessionSecurityConfig } from './transport-session.types';
|
|
10
16
|
import { FrontMcpLogger } from '../../common/interfaces/logger.interface';
|
|
11
17
|
import type { VercelKvProviderOptions } from '../../common/types/options/redis.options';
|
|
12
18
|
export interface VercelKvSessionConfig {
|
|
@@ -30,6 +36,10 @@ export interface VercelKvSessionConfig {
|
|
|
30
36
|
* @default 3600000 (1 hour)
|
|
31
37
|
*/
|
|
32
38
|
defaultTtlMs?: number;
|
|
39
|
+
/**
|
|
40
|
+
* Security hardening options
|
|
41
|
+
*/
|
|
42
|
+
security?: SessionSecurityConfig;
|
|
33
43
|
}
|
|
34
44
|
/**
|
|
35
45
|
* Vercel KV-backed session store implementation
|
|
@@ -44,6 +54,8 @@ export declare class VercelKvSessionStore implements SessionStore {
|
|
|
44
54
|
private readonly defaultTtlMs;
|
|
45
55
|
private readonly logger?;
|
|
46
56
|
private readonly config;
|
|
57
|
+
private readonly security;
|
|
58
|
+
private readonly rateLimiter?;
|
|
47
59
|
constructor(config: VercelKvSessionConfig | VercelKvProviderOptions, logger?: FrontMcpLogger);
|
|
48
60
|
/**
|
|
49
61
|
* Connect to Vercel KV
|
|
@@ -63,8 +75,16 @@ export declare class VercelKvSessionStore implements SessionStore {
|
|
|
63
75
|
*
|
|
64
76
|
* Note: Vercel KV doesn't support GETEX, so we use GET + PEXPIRE separately.
|
|
65
77
|
* This is slightly less atomic than Redis GETEX but sufficient for most use cases.
|
|
78
|
+
*
|
|
79
|
+
* @param sessionId - The session ID to look up
|
|
80
|
+
* @param options - Optional parameters for rate limiting
|
|
81
|
+
* @param options.clientIdentifier - Client identifier (e.g., IP address) for rate limiting.
|
|
82
|
+
* When provided, rate limiting is applied per-client to prevent session enumeration.
|
|
83
|
+
* If not provided, falls back to sessionId which provides DoS protection per-session.
|
|
66
84
|
*/
|
|
67
|
-
get(sessionId: string
|
|
85
|
+
get(sessionId: string, options?: {
|
|
86
|
+
clientIdentifier?: string;
|
|
87
|
+
}): Promise<StoredSession | null>;
|
|
68
88
|
/**
|
|
69
89
|
* Store a session with optional TTL
|
|
70
90
|
*/
|