@frontmcp/utils 0.0.1 → 0.7.2
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/CHANGELOG.md +12 -0
- package/README.md +110 -0
- package/content/content.d.ts +43 -0
- package/content/index.d.ts +1 -0
- package/crypto/browser.d.ts +11 -0
- package/crypto/encrypted-blob.d.ts +157 -0
- package/crypto/index.d.ts +98 -0
- package/crypto/jwt-alg.d.ts +8 -0
- package/crypto/node.d.ts +59 -0
- package/crypto/pkce/index.d.ts +9 -0
- package/crypto/pkce/pkce.d.ts +140 -0
- package/crypto/runtime.d.ts +18 -0
- package/crypto/secret-persistence/index.d.ts +25 -0
- package/crypto/secret-persistence/persistence.d.ts +97 -0
- package/crypto/secret-persistence/schema.d.ts +34 -0
- package/crypto/secret-persistence/types.d.ts +65 -0
- package/crypto/types.d.ts +61 -0
- package/escape/escape.d.ts +101 -0
- package/escape/index.d.ts +1 -0
- package/esm/index.mjs +3264 -0
- package/esm/package.json +54 -0
- package/fs/fs.d.ts +254 -0
- package/fs/index.d.ts +1 -0
- package/http/http.d.ts +20 -0
- package/http/index.d.ts +1 -0
- package/index.d.ts +18 -0
- package/index.js +3425 -0
- package/naming/index.d.ts +1 -0
- package/naming/naming.d.ts +79 -0
- package/package.json +4 -2
- package/path/index.d.ts +1 -0
- package/path/path.d.ts +34 -0
- package/regex/index.d.ts +24 -0
- package/regex/patterns.d.ts +155 -0
- package/regex/safe-regex.d.ts +179 -0
- package/serialization/index.d.ts +1 -0
- package/serialization/serialization.d.ts +33 -0
- package/storage/adapters/base.d.ts +90 -0
- package/storage/adapters/index.d.ts +10 -0
- package/storage/adapters/memory.d.ts +99 -0
- package/storage/adapters/redis.d.ts +88 -0
- package/storage/adapters/upstash.d.ts +81 -0
- package/storage/adapters/vercel-kv.d.ts +69 -0
- package/storage/errors.d.ts +117 -0
- package/storage/factory.d.ts +70 -0
- package/storage/index.d.ts +13 -0
- package/storage/namespace.d.ts +88 -0
- package/storage/types.d.ts +428 -0
- package/storage/utils/index.d.ts +5 -0
- package/storage/utils/pattern.d.ts +71 -0
- package/storage/utils/ttl.d.ts +54 -0
- package/uri/index.d.ts +2 -0
- package/uri/uri-template.d.ts +92 -0
- package/uri/uri-validation.d.ts +46 -0
|
@@ -0,0 +1,99 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Memory Storage Adapter
|
|
3
|
+
*
|
|
4
|
+
* In-memory storage implementation for development and testing.
|
|
5
|
+
* Supports TTL, pattern matching, pub/sub via EventEmitter.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseStorageAdapter } from './base';
|
|
8
|
+
import type { MemoryAdapterOptions, SetOptions, MessageHandler, Unsubscribe } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* In-memory storage adapter.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - TTL support with lazy expiration + optional background sweeper
|
|
14
|
+
* - Pattern matching for keys() with ReDoS protection
|
|
15
|
+
* - Pub/sub via EventEmitter
|
|
16
|
+
* - Optional LRU eviction
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const adapter = new MemoryStorageAdapter({
|
|
21
|
+
* enableSweeper: true,
|
|
22
|
+
* sweepIntervalSeconds: 60,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await adapter.connect();
|
|
26
|
+
* await adapter.set('key', 'value', { ttlSeconds: 300 });
|
|
27
|
+
* const value = await adapter.get('key');
|
|
28
|
+
* await adapter.disconnect();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class MemoryStorageAdapter extends BaseStorageAdapter {
|
|
32
|
+
protected readonly backendName = "memory";
|
|
33
|
+
private readonly store;
|
|
34
|
+
private readonly emitter;
|
|
35
|
+
private sweepInterval?;
|
|
36
|
+
private readonly options;
|
|
37
|
+
private accessOrder;
|
|
38
|
+
constructor(options?: MemoryAdapterOptions);
|
|
39
|
+
connect(): Promise<void>;
|
|
40
|
+
disconnect(): Promise<void>;
|
|
41
|
+
ping(): Promise<boolean>;
|
|
42
|
+
get(key: string): Promise<string | null>;
|
|
43
|
+
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
44
|
+
delete(key: string): Promise<boolean>;
|
|
45
|
+
exists(key: string): Promise<boolean>;
|
|
46
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
47
|
+
ttl(key: string): Promise<number | null>;
|
|
48
|
+
keys(pattern?: string): Promise<string[]>;
|
|
49
|
+
incr(key: string): Promise<number>;
|
|
50
|
+
decr(key: string): Promise<number>;
|
|
51
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
52
|
+
supportsPubSub(): boolean;
|
|
53
|
+
publish(channel: string, message: string): Promise<number>;
|
|
54
|
+
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
55
|
+
/**
|
|
56
|
+
* Delete an entry and clear its timeout.
|
|
57
|
+
*/
|
|
58
|
+
private deleteEntry;
|
|
59
|
+
/**
|
|
60
|
+
* Clear timeout for an entry.
|
|
61
|
+
*/
|
|
62
|
+
private clearEntryTimeout;
|
|
63
|
+
/**
|
|
64
|
+
* Clear all timeouts.
|
|
65
|
+
*/
|
|
66
|
+
private clearAllTimeouts;
|
|
67
|
+
/**
|
|
68
|
+
* Update LRU access order.
|
|
69
|
+
*/
|
|
70
|
+
private touchLRU;
|
|
71
|
+
/**
|
|
72
|
+
* Remove key from LRU tracking.
|
|
73
|
+
*/
|
|
74
|
+
private removeLRU;
|
|
75
|
+
/**
|
|
76
|
+
* Evict oldest entry (LRU).
|
|
77
|
+
*/
|
|
78
|
+
private evictOldest;
|
|
79
|
+
/**
|
|
80
|
+
* Start background sweeper.
|
|
81
|
+
*/
|
|
82
|
+
private startSweeper;
|
|
83
|
+
/**
|
|
84
|
+
* Stop background sweeper.
|
|
85
|
+
*/
|
|
86
|
+
private stopSweeper;
|
|
87
|
+
/**
|
|
88
|
+
* Sweep expired entries.
|
|
89
|
+
*/
|
|
90
|
+
private sweep;
|
|
91
|
+
/**
|
|
92
|
+
* Get storage statistics.
|
|
93
|
+
*/
|
|
94
|
+
getStats(): {
|
|
95
|
+
size: number;
|
|
96
|
+
maxEntries: number;
|
|
97
|
+
sweeperActive: boolean;
|
|
98
|
+
};
|
|
99
|
+
}
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Redis Storage Adapter
|
|
3
|
+
*
|
|
4
|
+
* Redis-based storage implementation for production use.
|
|
5
|
+
* Uses ioredis with dynamic import for browser compatibility.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseStorageAdapter } from './base';
|
|
8
|
+
import type { RedisAdapterOptions, SetOptions, MessageHandler, Unsubscribe } from '../types';
|
|
9
|
+
type Redis = import('ioredis').Redis;
|
|
10
|
+
/**
|
|
11
|
+
* Redis storage adapter.
|
|
12
|
+
*
|
|
13
|
+
* Features:
|
|
14
|
+
* - Native Redis TTL support
|
|
15
|
+
* - SCAN for pattern matching (non-blocking)
|
|
16
|
+
* - Pipeline for batch operations
|
|
17
|
+
* - Pub/sub with separate subscriber connection
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const adapter = new RedisStorageAdapter({
|
|
22
|
+
* url: 'redis://localhost:6379',
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await adapter.connect();
|
|
26
|
+
* await adapter.set('key', 'value', { ttlSeconds: 300 });
|
|
27
|
+
* const value = await adapter.get('key');
|
|
28
|
+
* await adapter.disconnect();
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare class RedisStorageAdapter extends BaseStorageAdapter {
|
|
32
|
+
protected readonly backendName = "redis";
|
|
33
|
+
private client?;
|
|
34
|
+
private subscriber?;
|
|
35
|
+
private readonly options;
|
|
36
|
+
private readonly ownsClient;
|
|
37
|
+
private readonly keyPrefix;
|
|
38
|
+
private readonly subscriptionHandlers;
|
|
39
|
+
constructor(options?: RedisAdapterOptions);
|
|
40
|
+
connect(): Promise<void>;
|
|
41
|
+
disconnect(): Promise<void>;
|
|
42
|
+
ping(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the connected Redis client, throwing if not connected.
|
|
45
|
+
*/
|
|
46
|
+
private getConnectedClient;
|
|
47
|
+
/**
|
|
48
|
+
* Get the connected Redis subscriber, throwing if not created.
|
|
49
|
+
*/
|
|
50
|
+
private getConnectedSubscriber;
|
|
51
|
+
get(key: string): Promise<string | null>;
|
|
52
|
+
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
53
|
+
delete(key: string): Promise<boolean>;
|
|
54
|
+
exists(key: string): Promise<boolean>;
|
|
55
|
+
mget(keys: string[]): Promise<(string | null)[]>;
|
|
56
|
+
mset(entries: import('../types').SetEntry[]): Promise<void>;
|
|
57
|
+
mdelete(keys: string[]): Promise<number>;
|
|
58
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
59
|
+
ttl(key: string): Promise<number | null>;
|
|
60
|
+
keys(pattern?: string): Promise<string[]>;
|
|
61
|
+
incr(key: string): Promise<number>;
|
|
62
|
+
decr(key: string): Promise<number>;
|
|
63
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
64
|
+
supportsPubSub(): boolean;
|
|
65
|
+
publish(channel: string, message: string): Promise<number>;
|
|
66
|
+
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
67
|
+
/**
|
|
68
|
+
* Build Redis options from config.
|
|
69
|
+
*/
|
|
70
|
+
private buildRedisOptions;
|
|
71
|
+
/**
|
|
72
|
+
* Create subscriber connection.
|
|
73
|
+
*/
|
|
74
|
+
private createSubscriber;
|
|
75
|
+
/**
|
|
76
|
+
* Add prefix to a key.
|
|
77
|
+
*/
|
|
78
|
+
private prefixKey;
|
|
79
|
+
/**
|
|
80
|
+
* Remove prefix from a key.
|
|
81
|
+
*/
|
|
82
|
+
private unprefixKey;
|
|
83
|
+
/**
|
|
84
|
+
* Get the underlying Redis client (for advanced use).
|
|
85
|
+
*/
|
|
86
|
+
getClient(): Redis | undefined;
|
|
87
|
+
}
|
|
88
|
+
export {};
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Upstash Redis Storage Adapter
|
|
3
|
+
*
|
|
4
|
+
* Upstash Redis (REST-based) storage implementation for edge deployment.
|
|
5
|
+
* Supports pub/sub via Upstash's REST API with polling mechanism.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseStorageAdapter } from './base';
|
|
8
|
+
import type { UpstashAdapterOptions, SetOptions, MessageHandler, Unsubscribe } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* Upstash Redis storage adapter.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - REST-based storage for edge deployment
|
|
14
|
+
* - Native TTL support
|
|
15
|
+
* - Pub/sub support via list-based polling
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* const adapter = new UpstashStorageAdapter({
|
|
20
|
+
* url: process.env.UPSTASH_REDIS_REST_URL,
|
|
21
|
+
* token: process.env.UPSTASH_REDIS_REST_TOKEN,
|
|
22
|
+
* enablePubSub: true,
|
|
23
|
+
* });
|
|
24
|
+
*
|
|
25
|
+
* await adapter.connect();
|
|
26
|
+
* await adapter.set('key', 'value', { ttlSeconds: 300 });
|
|
27
|
+
* const value = await adapter.get('key');
|
|
28
|
+
*
|
|
29
|
+
* // Pub/sub
|
|
30
|
+
* const unsubscribe = await adapter.subscribe('channel', (msg) => console.log(msg));
|
|
31
|
+
* await adapter.publish('channel', 'hello');
|
|
32
|
+
*
|
|
33
|
+
* await adapter.disconnect();
|
|
34
|
+
* ```
|
|
35
|
+
*/
|
|
36
|
+
export declare class UpstashStorageAdapter extends BaseStorageAdapter {
|
|
37
|
+
protected readonly backendName = "upstash";
|
|
38
|
+
private client?;
|
|
39
|
+
private readonly options;
|
|
40
|
+
private readonly keyPrefix;
|
|
41
|
+
private readonly pubSubEnabled;
|
|
42
|
+
private readonly subscriptionHandlers;
|
|
43
|
+
private readonly pollingIntervals;
|
|
44
|
+
constructor(options?: UpstashAdapterOptions);
|
|
45
|
+
connect(): Promise<void>;
|
|
46
|
+
disconnect(): Promise<void>;
|
|
47
|
+
ping(): Promise<boolean>;
|
|
48
|
+
/**
|
|
49
|
+
* Get the connected Upstash client, throwing if not connected.
|
|
50
|
+
*/
|
|
51
|
+
private getConnectedClient;
|
|
52
|
+
get(key: string): Promise<string | null>;
|
|
53
|
+
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
54
|
+
delete(key: string): Promise<boolean>;
|
|
55
|
+
exists(key: string): Promise<boolean>;
|
|
56
|
+
mget(keys: string[]): Promise<(string | null)[]>;
|
|
57
|
+
mdelete(keys: string[]): Promise<number>;
|
|
58
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
59
|
+
ttl(key: string): Promise<number | null>;
|
|
60
|
+
keys(pattern?: string): Promise<string[]>;
|
|
61
|
+
incr(key: string): Promise<number>;
|
|
62
|
+
decr(key: string): Promise<number>;
|
|
63
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
64
|
+
supportsPubSub(): boolean;
|
|
65
|
+
publish(channel: string, message: string): Promise<number>;
|
|
66
|
+
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
67
|
+
/**
|
|
68
|
+
* Publish using list-based approach (for polling subscribers).
|
|
69
|
+
* This is an alternative to native PUBLISH when subscribers are polling.
|
|
70
|
+
*/
|
|
71
|
+
publishToQueue(channel: string, message: string): Promise<void>;
|
|
72
|
+
protected getPubSubSuggestion(): string;
|
|
73
|
+
/**
|
|
74
|
+
* Add prefix to a key.
|
|
75
|
+
*/
|
|
76
|
+
private prefixKey;
|
|
77
|
+
/**
|
|
78
|
+
* Remove prefix from a key.
|
|
79
|
+
*/
|
|
80
|
+
private unprefixKey;
|
|
81
|
+
}
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Vercel KV Storage Adapter
|
|
3
|
+
*
|
|
4
|
+
* Vercel KV (REST-based) storage implementation for edge deployment.
|
|
5
|
+
* NOTE: Vercel KV does NOT support pub/sub. Use Upstash adapter instead.
|
|
6
|
+
*/
|
|
7
|
+
import { BaseStorageAdapter } from './base';
|
|
8
|
+
import type { VercelKvAdapterOptions, SetOptions } from '../types';
|
|
9
|
+
/**
|
|
10
|
+
* Vercel KV storage adapter.
|
|
11
|
+
*
|
|
12
|
+
* Features:
|
|
13
|
+
* - REST-based storage for edge deployment
|
|
14
|
+
* - Native TTL support
|
|
15
|
+
* - Pattern matching via keys() command
|
|
16
|
+
*
|
|
17
|
+
* Limitations:
|
|
18
|
+
* - NO pub/sub support (use Upstash instead)
|
|
19
|
+
* - keys() may be slow for large datasets
|
|
20
|
+
*
|
|
21
|
+
* @example
|
|
22
|
+
* ```typescript
|
|
23
|
+
* const adapter = new VercelKvStorageAdapter({
|
|
24
|
+
* url: process.env.KV_REST_API_URL,
|
|
25
|
+
* token: process.env.KV_REST_API_TOKEN,
|
|
26
|
+
* });
|
|
27
|
+
*
|
|
28
|
+
* await adapter.connect();
|
|
29
|
+
* await adapter.set('key', 'value', { ttlSeconds: 300 });
|
|
30
|
+
* const value = await adapter.get('key');
|
|
31
|
+
* await adapter.disconnect();
|
|
32
|
+
* ```
|
|
33
|
+
*/
|
|
34
|
+
export declare class VercelKvStorageAdapter extends BaseStorageAdapter {
|
|
35
|
+
protected readonly backendName = "vercel-kv";
|
|
36
|
+
private client?;
|
|
37
|
+
private readonly options;
|
|
38
|
+
private readonly keyPrefix;
|
|
39
|
+
constructor(options?: VercelKvAdapterOptions);
|
|
40
|
+
connect(): Promise<void>;
|
|
41
|
+
disconnect(): Promise<void>;
|
|
42
|
+
ping(): Promise<boolean>;
|
|
43
|
+
/**
|
|
44
|
+
* Get the connected Vercel KV client, throwing if not connected.
|
|
45
|
+
*/
|
|
46
|
+
private getConnectedClient;
|
|
47
|
+
get(key: string): Promise<string | null>;
|
|
48
|
+
protected doSet(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
49
|
+
delete(key: string): Promise<boolean>;
|
|
50
|
+
exists(key: string): Promise<boolean>;
|
|
51
|
+
mget(keys: string[]): Promise<(string | null)[]>;
|
|
52
|
+
mdelete(keys: string[]): Promise<number>;
|
|
53
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
54
|
+
ttl(key: string): Promise<number | null>;
|
|
55
|
+
keys(pattern?: string): Promise<string[]>;
|
|
56
|
+
incr(key: string): Promise<number>;
|
|
57
|
+
decr(key: string): Promise<number>;
|
|
58
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
59
|
+
supportsPubSub(): boolean;
|
|
60
|
+
protected getPubSubSuggestion(): string;
|
|
61
|
+
/**
|
|
62
|
+
* Add prefix to a key.
|
|
63
|
+
*/
|
|
64
|
+
private prefixKey;
|
|
65
|
+
/**
|
|
66
|
+
* Remove prefix from a key.
|
|
67
|
+
*/
|
|
68
|
+
private unprefixKey;
|
|
69
|
+
}
|
|
@@ -0,0 +1,117 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Error Classes
|
|
3
|
+
*
|
|
4
|
+
* Custom error types for storage operations.
|
|
5
|
+
* All errors extend StorageError for easy catching.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Base error class for all storage-related errors.
|
|
9
|
+
*/
|
|
10
|
+
export declare class StorageError extends Error {
|
|
11
|
+
readonly cause?: Error;
|
|
12
|
+
constructor(message: string, cause?: Error);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Error thrown when storage connection fails.
|
|
16
|
+
*
|
|
17
|
+
* @example
|
|
18
|
+
* ```typescript
|
|
19
|
+
* throw new StorageConnectionError(
|
|
20
|
+
* 'Failed to connect to Redis',
|
|
21
|
+
* originalError
|
|
22
|
+
* );
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare class StorageConnectionError extends StorageError {
|
|
26
|
+
readonly backend?: string | undefined;
|
|
27
|
+
constructor(message: string, cause?: Error, backend?: string | undefined);
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Error thrown when a storage operation fails.
|
|
31
|
+
*
|
|
32
|
+
* @example
|
|
33
|
+
* ```typescript
|
|
34
|
+
* throw new StorageOperationError(
|
|
35
|
+
* 'set',
|
|
36
|
+
* 'user:123',
|
|
37
|
+
* 'Value too large',
|
|
38
|
+
* originalError
|
|
39
|
+
* );
|
|
40
|
+
* ```
|
|
41
|
+
*/
|
|
42
|
+
export declare class StorageOperationError extends StorageError {
|
|
43
|
+
readonly operation: string;
|
|
44
|
+
readonly key: string;
|
|
45
|
+
constructor(operation: string, key: string, message: string, cause?: Error);
|
|
46
|
+
}
|
|
47
|
+
/**
|
|
48
|
+
* Error thrown when a feature is not supported by the adapter.
|
|
49
|
+
*
|
|
50
|
+
* @example
|
|
51
|
+
* ```typescript
|
|
52
|
+
* throw new StorageNotSupportedError(
|
|
53
|
+
* 'publish',
|
|
54
|
+
* 'vercel-kv',
|
|
55
|
+
* 'Vercel KV does not support pub/sub. Use Upstash instead.'
|
|
56
|
+
* );
|
|
57
|
+
* ```
|
|
58
|
+
*/
|
|
59
|
+
export declare class StorageNotSupportedError extends StorageError {
|
|
60
|
+
readonly operation: string;
|
|
61
|
+
readonly backend: string;
|
|
62
|
+
constructor(operation: string, backend: string, suggestion?: string);
|
|
63
|
+
}
|
|
64
|
+
/**
|
|
65
|
+
* Error thrown when storage configuration is invalid.
|
|
66
|
+
*
|
|
67
|
+
* @example
|
|
68
|
+
* ```typescript
|
|
69
|
+
* throw new StorageConfigError(
|
|
70
|
+
* 'redis',
|
|
71
|
+
* 'Either "client" or "config"/"url" must be provided'
|
|
72
|
+
* );
|
|
73
|
+
* ```
|
|
74
|
+
*/
|
|
75
|
+
export declare class StorageConfigError extends StorageError {
|
|
76
|
+
readonly backend: string;
|
|
77
|
+
constructor(backend: string, message: string);
|
|
78
|
+
}
|
|
79
|
+
/**
|
|
80
|
+
* Error thrown when TTL value is invalid.
|
|
81
|
+
*
|
|
82
|
+
* @example
|
|
83
|
+
* ```typescript
|
|
84
|
+
* throw new StorageTTLError(-1, 'TTL must be a positive integer');
|
|
85
|
+
* ```
|
|
86
|
+
*/
|
|
87
|
+
export declare class StorageTTLError extends StorageError {
|
|
88
|
+
readonly ttl: unknown;
|
|
89
|
+
constructor(ttl: unknown, message?: string);
|
|
90
|
+
}
|
|
91
|
+
/**
|
|
92
|
+
* Error thrown when a key pattern is invalid or potentially dangerous.
|
|
93
|
+
*
|
|
94
|
+
* @example
|
|
95
|
+
* ```typescript
|
|
96
|
+
* throw new StoragePatternError(
|
|
97
|
+
* pattern,
|
|
98
|
+
* 'Pattern is too complex and may cause ReDoS'
|
|
99
|
+
* );
|
|
100
|
+
* ```
|
|
101
|
+
*/
|
|
102
|
+
export declare class StoragePatternError extends StorageError {
|
|
103
|
+
readonly pattern: string;
|
|
104
|
+
constructor(pattern: string, message: string);
|
|
105
|
+
}
|
|
106
|
+
/**
|
|
107
|
+
* Error thrown when storage is not connected.
|
|
108
|
+
*
|
|
109
|
+
* @example
|
|
110
|
+
* ```typescript
|
|
111
|
+
* throw new StorageNotConnectedError('redis');
|
|
112
|
+
* ```
|
|
113
|
+
*/
|
|
114
|
+
export declare class StorageNotConnectedError extends StorageError {
|
|
115
|
+
readonly backend: string;
|
|
116
|
+
constructor(backend: string);
|
|
117
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Storage Factory
|
|
3
|
+
*
|
|
4
|
+
* Factory function to create storage adapters with auto-detection.
|
|
5
|
+
*/
|
|
6
|
+
import type { StorageConfig, StorageType, RootStorage } from './types';
|
|
7
|
+
/**
|
|
8
|
+
* Create a storage instance.
|
|
9
|
+
*
|
|
10
|
+
* @param config - Storage configuration
|
|
11
|
+
* @returns Promise<RootStorage> - Namespaced storage instance
|
|
12
|
+
*
|
|
13
|
+
* @example Basic usage with auto-detection
|
|
14
|
+
* ```typescript
|
|
15
|
+
* const store = await createStorage();
|
|
16
|
+
* await store.set('key', 'value');
|
|
17
|
+
* ```
|
|
18
|
+
*
|
|
19
|
+
* @example Explicit type
|
|
20
|
+
* ```typescript
|
|
21
|
+
* const store = await createStorage({ type: 'redis', redis: { url: 'redis://localhost:6379' } });
|
|
22
|
+
* await store.connect();
|
|
23
|
+
* ```
|
|
24
|
+
*
|
|
25
|
+
* @example With namespaces
|
|
26
|
+
* ```typescript
|
|
27
|
+
* const store = await createStorage({ type: 'memory' });
|
|
28
|
+
* const session = store.namespace('session', sessionId);
|
|
29
|
+
* await session.set('user', JSON.stringify(user));
|
|
30
|
+
* // Key: session:{sessionId}:user
|
|
31
|
+
* ```
|
|
32
|
+
*
|
|
33
|
+
* @example With root prefix
|
|
34
|
+
* ```typescript
|
|
35
|
+
* const store = await createStorage({
|
|
36
|
+
* type: 'redis',
|
|
37
|
+
* prefix: 'myapp:',
|
|
38
|
+
* redis: { host: 'localhost' }
|
|
39
|
+
* });
|
|
40
|
+
* // All keys will be prefixed with 'myapp:'
|
|
41
|
+
* ```
|
|
42
|
+
*/
|
|
43
|
+
export declare function createStorage(config?: StorageConfig): Promise<RootStorage>;
|
|
44
|
+
/**
|
|
45
|
+
* Create a storage instance synchronously (memory only).
|
|
46
|
+
*
|
|
47
|
+
* Use this when you need synchronous creation and are okay with memory storage.
|
|
48
|
+
* For distributed storage, use the async `createStorage` function instead.
|
|
49
|
+
*
|
|
50
|
+
* @param config - Memory adapter options
|
|
51
|
+
* @returns RootStorage - Namespaced storage instance
|
|
52
|
+
*
|
|
53
|
+
* @example
|
|
54
|
+
* ```typescript
|
|
55
|
+
* const store = createMemoryStorage({ maxEntries: 1000 });
|
|
56
|
+
* store.connect().then(() => {
|
|
57
|
+
* store.set('key', 'value');
|
|
58
|
+
* });
|
|
59
|
+
* ```
|
|
60
|
+
*/
|
|
61
|
+
export declare function createMemoryStorage(config?: import('./types').MemoryAdapterOptions & {
|
|
62
|
+
prefix?: string;
|
|
63
|
+
}): RootStorage;
|
|
64
|
+
/**
|
|
65
|
+
* Get the detected storage type without creating an adapter.
|
|
66
|
+
* Useful for logging or conditional logic.
|
|
67
|
+
*
|
|
68
|
+
* @returns The detected storage type
|
|
69
|
+
*/
|
|
70
|
+
export declare function getDetectedStorageType(): StorageType;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* @frontmcp/utils - Storage Module
|
|
3
|
+
*
|
|
4
|
+
* Unified storage abstraction with pluggable backends.
|
|
5
|
+
* Supports Memory (dev), Redis (prod), Vercel KV (edge), and Upstash (edge + pub/sub).
|
|
6
|
+
*/
|
|
7
|
+
export type { StorageAdapter, NamespacedStorage, RootStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe, MemoryAdapterOptions, RedisAdapterOptions, VercelKvAdapterOptions, UpstashAdapterOptions, StorageType, StorageConfig, } from './types';
|
|
8
|
+
export { createStorage, createMemoryStorage, getDetectedStorageType } from './factory';
|
|
9
|
+
export { NamespacedStorageImpl, createRootStorage, createNamespacedStorage, buildPrefix, NAMESPACE_SEPARATOR, } from './namespace';
|
|
10
|
+
export { StorageError, StorageConnectionError, StorageOperationError, StorageNotSupportedError, StorageConfigError, StorageTTLError, StoragePatternError, StorageNotConnectedError, } from './errors';
|
|
11
|
+
export { BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, VercelKvStorageAdapter, UpstashStorageAdapter, } from './adapters';
|
|
12
|
+
export { globToRegex, matchesPattern, validatePattern, escapeGlob } from './utils/pattern';
|
|
13
|
+
export { MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, } from './utils/ttl';
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Namespaced Storage Implementation
|
|
3
|
+
*
|
|
4
|
+
* Wraps a StorageAdapter to provide namespace prefixing.
|
|
5
|
+
* All operations automatically prefix keys with the namespace path.
|
|
6
|
+
*/
|
|
7
|
+
import type { StorageAdapter, NamespacedStorage, SetOptions, SetEntry, MessageHandler, Unsubscribe } from './types';
|
|
8
|
+
/**
|
|
9
|
+
* Separator used between namespace segments.
|
|
10
|
+
*/
|
|
11
|
+
export declare const NAMESPACE_SEPARATOR = ":";
|
|
12
|
+
/**
|
|
13
|
+
* Build a namespace prefix from name and optional id.
|
|
14
|
+
*
|
|
15
|
+
* @param name - Namespace name (e.g., 'session', 'user')
|
|
16
|
+
* @param id - Optional identifier (e.g., session ID, user ID)
|
|
17
|
+
* @returns Prefix string with trailing separator
|
|
18
|
+
*
|
|
19
|
+
* @example
|
|
20
|
+
* ```typescript
|
|
21
|
+
* buildPrefix('session', 'abc123'); // 'session:abc123:'
|
|
22
|
+
* buildPrefix('global'); // 'global:'
|
|
23
|
+
* ```
|
|
24
|
+
*/
|
|
25
|
+
export declare function buildPrefix(name: string, id?: string): string;
|
|
26
|
+
/**
|
|
27
|
+
* Implementation of NamespacedStorage.
|
|
28
|
+
* Wraps a StorageAdapter and prefixes all keys.
|
|
29
|
+
*/
|
|
30
|
+
export declare class NamespacedStorageImpl implements NamespacedStorage {
|
|
31
|
+
private readonly adapter;
|
|
32
|
+
readonly prefix: string;
|
|
33
|
+
readonly root: StorageAdapter;
|
|
34
|
+
constructor(adapter: StorageAdapter, prefix?: string, root?: StorageAdapter);
|
|
35
|
+
/**
|
|
36
|
+
* Add prefix to a key.
|
|
37
|
+
*/
|
|
38
|
+
private prefixKey;
|
|
39
|
+
/**
|
|
40
|
+
* Remove prefix from a key.
|
|
41
|
+
*/
|
|
42
|
+
private unprefixKey;
|
|
43
|
+
/**
|
|
44
|
+
* Add prefix to a pattern (for keys() operation).
|
|
45
|
+
*/
|
|
46
|
+
private prefixPattern;
|
|
47
|
+
/**
|
|
48
|
+
* Add prefix to a channel (for pub/sub).
|
|
49
|
+
*/
|
|
50
|
+
private prefixChannel;
|
|
51
|
+
namespace(name: string, id?: string): NamespacedStorage;
|
|
52
|
+
connect(): Promise<void>;
|
|
53
|
+
disconnect(): Promise<void>;
|
|
54
|
+
ping(): Promise<boolean>;
|
|
55
|
+
get(key: string): Promise<string | null>;
|
|
56
|
+
set(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
57
|
+
delete(key: string): Promise<boolean>;
|
|
58
|
+
exists(key: string): Promise<boolean>;
|
|
59
|
+
mget(keys: string[]): Promise<(string | null)[]>;
|
|
60
|
+
mset(entries: SetEntry[]): Promise<void>;
|
|
61
|
+
mdelete(keys: string[]): Promise<number>;
|
|
62
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
63
|
+
ttl(key: string): Promise<number | null>;
|
|
64
|
+
keys(pattern?: string): Promise<string[]>;
|
|
65
|
+
count(pattern?: string): Promise<number>;
|
|
66
|
+
incr(key: string): Promise<number>;
|
|
67
|
+
decr(key: string): Promise<number>;
|
|
68
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
69
|
+
publish(channel: string, message: string): Promise<number>;
|
|
70
|
+
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
71
|
+
supportsPubSub(): boolean;
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Create a root namespaced storage from an adapter.
|
|
75
|
+
* The root has an empty prefix.
|
|
76
|
+
*
|
|
77
|
+
* @param adapter - Storage adapter to wrap
|
|
78
|
+
* @returns RootStorage (NamespacedStorage with empty prefix)
|
|
79
|
+
*/
|
|
80
|
+
export declare function createRootStorage(adapter: StorageAdapter): NamespacedStorage;
|
|
81
|
+
/**
|
|
82
|
+
* Create a namespaced storage with an initial prefix.
|
|
83
|
+
*
|
|
84
|
+
* @param adapter - Storage adapter to wrap
|
|
85
|
+
* @param prefix - Initial prefix (without trailing separator)
|
|
86
|
+
* @returns NamespacedStorage with the given prefix
|
|
87
|
+
*/
|
|
88
|
+
export declare function createNamespacedStorage(adapter: StorageAdapter, prefix: string): NamespacedStorage;
|