@frontmcp/utils 0.0.1 → 0.7.1
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 +53 -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 +3 -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,428 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Unified Storage Abstraction Types
|
|
3
|
+
*
|
|
4
|
+
* Provides a common interface for key-value storage backends.
|
|
5
|
+
* Supports Memory (dev), Redis (prod), Vercel KV (edge), and Upstash (edge + pub/sub).
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Options for set operations.
|
|
9
|
+
*/
|
|
10
|
+
export interface SetOptions {
|
|
11
|
+
/**
|
|
12
|
+
* Time-to-live in seconds.
|
|
13
|
+
* Must be a positive integer if provided.
|
|
14
|
+
*/
|
|
15
|
+
ttlSeconds?: number;
|
|
16
|
+
/**
|
|
17
|
+
* Only set if key doesn't exist (NX in Redis).
|
|
18
|
+
* Mutually exclusive with `ifExists`.
|
|
19
|
+
*/
|
|
20
|
+
ifNotExists?: boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Only set if key already exists (XX in Redis).
|
|
23
|
+
* Mutually exclusive with `ifNotExists`.
|
|
24
|
+
*/
|
|
25
|
+
ifExists?: boolean;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* Entry for batch set operations.
|
|
29
|
+
*/
|
|
30
|
+
export interface SetEntry {
|
|
31
|
+
key: string;
|
|
32
|
+
value: string;
|
|
33
|
+
options?: SetOptions;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Message handler for pub/sub subscriptions.
|
|
37
|
+
*/
|
|
38
|
+
export type MessageHandler = (message: string, channel: string) => void;
|
|
39
|
+
/**
|
|
40
|
+
* Unsubscribe function returned by subscribe().
|
|
41
|
+
*/
|
|
42
|
+
export type Unsubscribe = () => Promise<void>;
|
|
43
|
+
/**
|
|
44
|
+
* Unified storage adapter interface.
|
|
45
|
+
*
|
|
46
|
+
* All values are stored as strings - callers handle serialization.
|
|
47
|
+
* This matches Redis behavior and provides consistent semantics across backends.
|
|
48
|
+
*
|
|
49
|
+
* @example
|
|
50
|
+
* ```typescript
|
|
51
|
+
* const adapter = new MemoryStorageAdapter();
|
|
52
|
+
* await adapter.connect();
|
|
53
|
+
*
|
|
54
|
+
* // Store JSON data
|
|
55
|
+
* await adapter.set('user:123', JSON.stringify({ name: 'John' }), { ttlSeconds: 3600 });
|
|
56
|
+
*
|
|
57
|
+
* // Retrieve and parse
|
|
58
|
+
* const raw = await adapter.get('user:123');
|
|
59
|
+
* const user = raw ? JSON.parse(raw) : null;
|
|
60
|
+
*
|
|
61
|
+
* await adapter.disconnect();
|
|
62
|
+
* ```
|
|
63
|
+
*/
|
|
64
|
+
export interface StorageAdapter {
|
|
65
|
+
/**
|
|
66
|
+
* Initialize the storage connection.
|
|
67
|
+
* For memory adapter, this is a no-op.
|
|
68
|
+
* For Redis/Upstash, this establishes the connection.
|
|
69
|
+
*
|
|
70
|
+
* @throws StorageConnectionError if connection fails
|
|
71
|
+
*/
|
|
72
|
+
connect(): Promise<void>;
|
|
73
|
+
/**
|
|
74
|
+
* Gracefully close the storage connection.
|
|
75
|
+
* For memory adapter, clears data and stops timers.
|
|
76
|
+
* For Redis, closes the connection (if owned by this adapter).
|
|
77
|
+
*/
|
|
78
|
+
disconnect(): Promise<void>;
|
|
79
|
+
/**
|
|
80
|
+
* Check if storage is connected and healthy.
|
|
81
|
+
*
|
|
82
|
+
* @returns true if connected and responsive
|
|
83
|
+
*/
|
|
84
|
+
ping(): Promise<boolean>;
|
|
85
|
+
/**
|
|
86
|
+
* Get a value by key.
|
|
87
|
+
*
|
|
88
|
+
* @param key - Storage key
|
|
89
|
+
* @returns The value as string, or null if not found or expired
|
|
90
|
+
*/
|
|
91
|
+
get(key: string): Promise<string | null>;
|
|
92
|
+
/**
|
|
93
|
+
* Set a value with optional TTL.
|
|
94
|
+
*
|
|
95
|
+
* @param key - Storage key
|
|
96
|
+
* @param value - String value to store
|
|
97
|
+
* @param options - Optional TTL and conditional flags
|
|
98
|
+
* @throws StorageOperationError if operation fails
|
|
99
|
+
*/
|
|
100
|
+
set(key: string, value: string, options?: SetOptions): Promise<void>;
|
|
101
|
+
/**
|
|
102
|
+
* Delete a key.
|
|
103
|
+
*
|
|
104
|
+
* @param key - Storage key
|
|
105
|
+
* @returns true if key existed and was deleted, false otherwise
|
|
106
|
+
*/
|
|
107
|
+
delete(key: string): Promise<boolean>;
|
|
108
|
+
/**
|
|
109
|
+
* Check if a key exists (and is not expired).
|
|
110
|
+
*
|
|
111
|
+
* @param key - Storage key
|
|
112
|
+
* @returns true if key exists
|
|
113
|
+
*/
|
|
114
|
+
exists(key: string): Promise<boolean>;
|
|
115
|
+
/**
|
|
116
|
+
* Get multiple values.
|
|
117
|
+
* Maintains order - returns null for missing keys.
|
|
118
|
+
*
|
|
119
|
+
* @param keys - Array of storage keys
|
|
120
|
+
* @returns Array of values (null for missing keys)
|
|
121
|
+
*/
|
|
122
|
+
mget(keys: string[]): Promise<(string | null)[]>;
|
|
123
|
+
/**
|
|
124
|
+
* Set multiple values atomically (where supported).
|
|
125
|
+
* For memory adapter, operations are sequential.
|
|
126
|
+
* For Redis, uses MSET/pipeline for atomicity.
|
|
127
|
+
*
|
|
128
|
+
* @param entries - Array of key-value-options entries
|
|
129
|
+
*/
|
|
130
|
+
mset(entries: SetEntry[]): Promise<void>;
|
|
131
|
+
/**
|
|
132
|
+
* Delete multiple keys.
|
|
133
|
+
*
|
|
134
|
+
* @param keys - Array of storage keys
|
|
135
|
+
* @returns Number of keys actually deleted
|
|
136
|
+
*/
|
|
137
|
+
mdelete(keys: string[]): Promise<number>;
|
|
138
|
+
/**
|
|
139
|
+
* Update TTL on an existing key.
|
|
140
|
+
*
|
|
141
|
+
* @param key - Storage key
|
|
142
|
+
* @param ttlSeconds - New TTL in seconds (must be positive integer)
|
|
143
|
+
* @returns true if key exists and TTL was set, false if key doesn't exist
|
|
144
|
+
*/
|
|
145
|
+
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
146
|
+
/**
|
|
147
|
+
* Get remaining TTL for a key.
|
|
148
|
+
*
|
|
149
|
+
* @param key - Storage key
|
|
150
|
+
* @returns TTL in seconds, -1 if no TTL, or null if key doesn't exist
|
|
151
|
+
*/
|
|
152
|
+
ttl(key: string): Promise<number | null>;
|
|
153
|
+
/**
|
|
154
|
+
* List keys matching a pattern.
|
|
155
|
+
* Pattern supports glob-style wildcards:
|
|
156
|
+
* - `*` matches any sequence of characters
|
|
157
|
+
* - `?` matches a single character
|
|
158
|
+
*
|
|
159
|
+
* @param pattern - Glob pattern (default: '*' for all keys)
|
|
160
|
+
* @returns Array of matching keys
|
|
161
|
+
*
|
|
162
|
+
* @example
|
|
163
|
+
* ```typescript
|
|
164
|
+
* // Find all session keys
|
|
165
|
+
* const sessionKeys = await adapter.keys('session:*');
|
|
166
|
+
*
|
|
167
|
+
* // Find keys with specific format
|
|
168
|
+
* const userKeys = await adapter.keys('user:???:profile');
|
|
169
|
+
* ```
|
|
170
|
+
*/
|
|
171
|
+
keys(pattern?: string): Promise<string[]>;
|
|
172
|
+
/**
|
|
173
|
+
* Count keys matching a pattern.
|
|
174
|
+
* More efficient than keys().length for large datasets.
|
|
175
|
+
*
|
|
176
|
+
* @param pattern - Glob pattern (default: '*' for all keys)
|
|
177
|
+
* @returns Number of matching keys
|
|
178
|
+
*/
|
|
179
|
+
count(pattern?: string): Promise<number>;
|
|
180
|
+
/**
|
|
181
|
+
* Atomically increment a numeric value.
|
|
182
|
+
* Creates key with value 1 if it doesn't exist.
|
|
183
|
+
*
|
|
184
|
+
* @param key - Storage key
|
|
185
|
+
* @returns New value after increment
|
|
186
|
+
* @throws StorageOperationError if value is not a valid integer
|
|
187
|
+
*/
|
|
188
|
+
incr(key: string): Promise<number>;
|
|
189
|
+
/**
|
|
190
|
+
* Atomically decrement a numeric value.
|
|
191
|
+
* Creates key with value -1 if it doesn't exist.
|
|
192
|
+
*
|
|
193
|
+
* @param key - Storage key
|
|
194
|
+
* @returns New value after decrement
|
|
195
|
+
* @throws StorageOperationError if value is not a valid integer
|
|
196
|
+
*/
|
|
197
|
+
decr(key: string): Promise<number>;
|
|
198
|
+
/**
|
|
199
|
+
* Atomically increment by a specific amount.
|
|
200
|
+
* Creates key with value `amount` if it doesn't exist.
|
|
201
|
+
*
|
|
202
|
+
* @param key - Storage key
|
|
203
|
+
* @param amount - Amount to increment (can be negative)
|
|
204
|
+
* @returns New value after increment
|
|
205
|
+
* @throws StorageOperationError if value is not a valid integer
|
|
206
|
+
*/
|
|
207
|
+
incrBy(key: string, amount: number): Promise<number>;
|
|
208
|
+
/**
|
|
209
|
+
* Publish a message to a channel.
|
|
210
|
+
* Not all adapters support pub/sub (e.g., Vercel KV doesn't).
|
|
211
|
+
*
|
|
212
|
+
* @param channel - Channel name
|
|
213
|
+
* @param message - Message string
|
|
214
|
+
* @returns Number of subscribers that received the message
|
|
215
|
+
* @throws StorageNotSupportedError if adapter doesn't support pub/sub
|
|
216
|
+
*/
|
|
217
|
+
publish(channel: string, message: string): Promise<number>;
|
|
218
|
+
/**
|
|
219
|
+
* Subscribe to a channel.
|
|
220
|
+
* Not all adapters support pub/sub (e.g., Vercel KV doesn't).
|
|
221
|
+
*
|
|
222
|
+
* @param channel - Channel name
|
|
223
|
+
* @param handler - Function called when message is received
|
|
224
|
+
* @returns Unsubscribe function
|
|
225
|
+
* @throws StorageNotSupportedError if adapter doesn't support pub/sub
|
|
226
|
+
*/
|
|
227
|
+
subscribe(channel: string, handler: MessageHandler): Promise<Unsubscribe>;
|
|
228
|
+
/**
|
|
229
|
+
* Check if this adapter supports pub/sub.
|
|
230
|
+
*
|
|
231
|
+
* @returns true if publish/subscribe are supported
|
|
232
|
+
*/
|
|
233
|
+
supportsPubSub(): boolean;
|
|
234
|
+
}
|
|
235
|
+
/**
|
|
236
|
+
* A namespaced view of a storage adapter.
|
|
237
|
+
* Automatically prefixes all keys with the namespace path.
|
|
238
|
+
*
|
|
239
|
+
* @example
|
|
240
|
+
* ```typescript
|
|
241
|
+
* const store = createStorage({ type: 'memory' });
|
|
242
|
+
* await store.connect();
|
|
243
|
+
*
|
|
244
|
+
* // Create nested namespaces
|
|
245
|
+
* const session = store.namespace('session', 'abc123');
|
|
246
|
+
* // prefix: "session:abc123:"
|
|
247
|
+
*
|
|
248
|
+
* const user = session.namespace('user', '456');
|
|
249
|
+
* // prefix: "session:abc123:user:456:"
|
|
250
|
+
*
|
|
251
|
+
* await user.set('theme', 'dark');
|
|
252
|
+
* // Actual key: "session:abc123:user:456:theme"
|
|
253
|
+
* ```
|
|
254
|
+
*/
|
|
255
|
+
export interface NamespacedStorage extends StorageAdapter {
|
|
256
|
+
/**
|
|
257
|
+
* The full namespace prefix (e.g., "session:abc123:user:456:").
|
|
258
|
+
* Empty string for root storage.
|
|
259
|
+
*/
|
|
260
|
+
readonly prefix: string;
|
|
261
|
+
/**
|
|
262
|
+
* Create a child namespace.
|
|
263
|
+
* Keys become: {parentPrefix}{name}:{id}:{key}
|
|
264
|
+
*
|
|
265
|
+
* @param name - Namespace name (e.g., 'session', 'user')
|
|
266
|
+
* @param id - Optional identifier (e.g., session ID, user ID)
|
|
267
|
+
* @returns A new NamespacedStorage with extended prefix
|
|
268
|
+
*/
|
|
269
|
+
namespace(name: string, id?: string): NamespacedStorage;
|
|
270
|
+
/**
|
|
271
|
+
* Get the underlying root adapter (for advanced use).
|
|
272
|
+
* Use with caution - operations bypass namespace prefixing.
|
|
273
|
+
*/
|
|
274
|
+
readonly root: StorageAdapter;
|
|
275
|
+
}
|
|
276
|
+
/**
|
|
277
|
+
* Root storage with namespace capability.
|
|
278
|
+
* The root itself has an empty prefix.
|
|
279
|
+
*/
|
|
280
|
+
export type RootStorage = NamespacedStorage;
|
|
281
|
+
/**
|
|
282
|
+
* Options for memory storage adapter.
|
|
283
|
+
*/
|
|
284
|
+
export interface MemoryAdapterOptions {
|
|
285
|
+
/**
|
|
286
|
+
* Enable periodic sweeping of expired entries.
|
|
287
|
+
* @default true
|
|
288
|
+
*/
|
|
289
|
+
enableSweeper?: boolean;
|
|
290
|
+
/**
|
|
291
|
+
* Sweep interval in seconds.
|
|
292
|
+
* @default 60
|
|
293
|
+
*/
|
|
294
|
+
sweepIntervalSeconds?: number;
|
|
295
|
+
/**
|
|
296
|
+
* Maximum number of entries (LRU eviction when exceeded).
|
|
297
|
+
* @default unlimited (0)
|
|
298
|
+
*/
|
|
299
|
+
maxEntries?: number;
|
|
300
|
+
}
|
|
301
|
+
/**
|
|
302
|
+
* Options for Redis storage adapter.
|
|
303
|
+
*/
|
|
304
|
+
export interface RedisAdapterOptions {
|
|
305
|
+
/**
|
|
306
|
+
* Use an existing Redis client (we won't close it).
|
|
307
|
+
* Mutually exclusive with `config` and `url`.
|
|
308
|
+
*/
|
|
309
|
+
client?: unknown;
|
|
310
|
+
/**
|
|
311
|
+
* Redis connection configuration.
|
|
312
|
+
* Mutually exclusive with `client`.
|
|
313
|
+
*/
|
|
314
|
+
config?: {
|
|
315
|
+
host: string;
|
|
316
|
+
port?: number;
|
|
317
|
+
password?: string;
|
|
318
|
+
db?: number;
|
|
319
|
+
tls?: boolean;
|
|
320
|
+
};
|
|
321
|
+
/**
|
|
322
|
+
* Redis connection URI.
|
|
323
|
+
* e.g., "redis://user:pass@host:6379/0"
|
|
324
|
+
* Mutually exclusive with `client`.
|
|
325
|
+
*/
|
|
326
|
+
url?: string;
|
|
327
|
+
/**
|
|
328
|
+
* Key prefix applied to all keys.
|
|
329
|
+
* @default ''
|
|
330
|
+
*/
|
|
331
|
+
keyPrefix?: string;
|
|
332
|
+
}
|
|
333
|
+
/**
|
|
334
|
+
* Options for Vercel KV storage adapter.
|
|
335
|
+
* Note: Vercel KV does NOT support pub/sub.
|
|
336
|
+
*/
|
|
337
|
+
export interface VercelKvAdapterOptions {
|
|
338
|
+
/**
|
|
339
|
+
* KV REST API URL.
|
|
340
|
+
* @default process.env.KV_REST_API_URL
|
|
341
|
+
*/
|
|
342
|
+
url?: string;
|
|
343
|
+
/**
|
|
344
|
+
* KV REST API Token.
|
|
345
|
+
* @default process.env.KV_REST_API_TOKEN
|
|
346
|
+
*/
|
|
347
|
+
token?: string;
|
|
348
|
+
/**
|
|
349
|
+
* Key prefix applied to all keys.
|
|
350
|
+
* @default ''
|
|
351
|
+
*/
|
|
352
|
+
keyPrefix?: string;
|
|
353
|
+
}
|
|
354
|
+
/**
|
|
355
|
+
* Options for Upstash Redis storage adapter.
|
|
356
|
+
* Upstash supports pub/sub via REST API.
|
|
357
|
+
*/
|
|
358
|
+
export interface UpstashAdapterOptions {
|
|
359
|
+
/**
|
|
360
|
+
* Upstash Redis REST URL.
|
|
361
|
+
* @default process.env.UPSTASH_REDIS_REST_URL
|
|
362
|
+
*/
|
|
363
|
+
url?: string;
|
|
364
|
+
/**
|
|
365
|
+
* Upstash Redis REST Token.
|
|
366
|
+
* @default process.env.UPSTASH_REDIS_REST_TOKEN
|
|
367
|
+
*/
|
|
368
|
+
token?: string;
|
|
369
|
+
/**
|
|
370
|
+
* Key prefix applied to all keys.
|
|
371
|
+
* @default ''
|
|
372
|
+
*/
|
|
373
|
+
keyPrefix?: string;
|
|
374
|
+
/**
|
|
375
|
+
* Enable pub/sub support.
|
|
376
|
+
* When enabled, creates additional connections for subscriptions.
|
|
377
|
+
* @default false
|
|
378
|
+
*/
|
|
379
|
+
enablePubSub?: boolean;
|
|
380
|
+
}
|
|
381
|
+
/**
|
|
382
|
+
* Storage backend type.
|
|
383
|
+
*/
|
|
384
|
+
export type StorageType = 'memory' | 'redis' | 'vercel-kv' | 'upstash' | 'auto';
|
|
385
|
+
/**
|
|
386
|
+
* Configuration for createStorage factory.
|
|
387
|
+
*/
|
|
388
|
+
export interface StorageConfig {
|
|
389
|
+
/**
|
|
390
|
+
* Storage backend type.
|
|
391
|
+
* - 'memory': In-memory (development/testing)
|
|
392
|
+
* - 'redis': Redis (production)
|
|
393
|
+
* - 'vercel-kv': Vercel KV (edge deployment, no pub/sub)
|
|
394
|
+
* - 'upstash': Upstash Redis (edge deployment, with pub/sub)
|
|
395
|
+
* - 'auto': Auto-detect based on environment variables
|
|
396
|
+
* @default 'auto'
|
|
397
|
+
*/
|
|
398
|
+
type?: StorageType;
|
|
399
|
+
/**
|
|
400
|
+
* Memory adapter options (when type='memory').
|
|
401
|
+
*/
|
|
402
|
+
memory?: MemoryAdapterOptions;
|
|
403
|
+
/**
|
|
404
|
+
* Redis adapter options (when type='redis').
|
|
405
|
+
*/
|
|
406
|
+
redis?: RedisAdapterOptions;
|
|
407
|
+
/**
|
|
408
|
+
* Vercel KV adapter options (when type='vercel-kv').
|
|
409
|
+
*/
|
|
410
|
+
vercelKv?: VercelKvAdapterOptions;
|
|
411
|
+
/**
|
|
412
|
+
* Upstash adapter options (when type='upstash').
|
|
413
|
+
*/
|
|
414
|
+
upstash?: UpstashAdapterOptions;
|
|
415
|
+
/**
|
|
416
|
+
* Root namespace prefix for all keys.
|
|
417
|
+
* Applied on top of any adapter-specific prefix.
|
|
418
|
+
* @default ''
|
|
419
|
+
*/
|
|
420
|
+
prefix?: string;
|
|
421
|
+
/**
|
|
422
|
+
* Fallback behavior when preferred backend is unavailable.
|
|
423
|
+
* - 'error': Throw error (default for production)
|
|
424
|
+
* - 'memory': Fall back to memory with warning
|
|
425
|
+
* @default 'error' in production (NODE_ENV=production), 'memory' otherwise
|
|
426
|
+
*/
|
|
427
|
+
fallback?: 'error' | 'memory';
|
|
428
|
+
}
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Pattern Matching Utilities
|
|
3
|
+
*
|
|
4
|
+
* Convert glob patterns to regex for key matching.
|
|
5
|
+
* Includes ReDoS protection to prevent denial-of-service attacks.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Convert a glob pattern to a RegExp.
|
|
9
|
+
*
|
|
10
|
+
* Supports:
|
|
11
|
+
* - `*` matches any sequence of characters (including empty)
|
|
12
|
+
* - `?` matches exactly one character
|
|
13
|
+
*
|
|
14
|
+
* @param pattern - Glob pattern (e.g., "user:*:profile")
|
|
15
|
+
* @returns RegExp for matching keys
|
|
16
|
+
* @throws StoragePatternError if pattern is invalid or too complex
|
|
17
|
+
*
|
|
18
|
+
* @example
|
|
19
|
+
* ```typescript
|
|
20
|
+
* const regex = globToRegex('user:*:profile');
|
|
21
|
+
* regex.test('user:123:profile'); // true
|
|
22
|
+
* regex.test('user:abc:profile'); // true
|
|
23
|
+
* regex.test('user:profile'); // false (missing segment)
|
|
24
|
+
*
|
|
25
|
+
* const regex2 = globToRegex('session:???');
|
|
26
|
+
* regex2.test('session:abc'); // true
|
|
27
|
+
* regex2.test('session:ab'); // false (too short)
|
|
28
|
+
* regex2.test('session:abcd'); // false (too long)
|
|
29
|
+
* ```
|
|
30
|
+
*/
|
|
31
|
+
export declare function globToRegex(pattern: string): RegExp;
|
|
32
|
+
/**
|
|
33
|
+
* Test if a key matches a glob pattern.
|
|
34
|
+
*
|
|
35
|
+
* @param key - Key to test
|
|
36
|
+
* @param pattern - Glob pattern
|
|
37
|
+
* @returns true if key matches pattern
|
|
38
|
+
*
|
|
39
|
+
* @example
|
|
40
|
+
* ```typescript
|
|
41
|
+
* matchesPattern('user:123:profile', 'user:*:profile'); // true
|
|
42
|
+
* matchesPattern('session:abc', 'session:???'); // true
|
|
43
|
+
* matchesPattern('other:key', 'user:*'); // false
|
|
44
|
+
* ```
|
|
45
|
+
*/
|
|
46
|
+
export declare function matchesPattern(key: string, pattern: string): boolean;
|
|
47
|
+
/**
|
|
48
|
+
* Check if a pattern is valid without throwing.
|
|
49
|
+
*
|
|
50
|
+
* @param pattern - Glob pattern to validate
|
|
51
|
+
* @returns Object with valid flag and optional error message
|
|
52
|
+
*/
|
|
53
|
+
export declare function validatePattern(pattern: string): {
|
|
54
|
+
valid: boolean;
|
|
55
|
+
error?: string;
|
|
56
|
+
};
|
|
57
|
+
/**
|
|
58
|
+
* Escape a string for use as a literal in a glob pattern.
|
|
59
|
+
* Escapes * and ? characters.
|
|
60
|
+
*
|
|
61
|
+
* @param literal - String to escape
|
|
62
|
+
* @returns Escaped string safe for use in patterns
|
|
63
|
+
*
|
|
64
|
+
* @example
|
|
65
|
+
* ```typescript
|
|
66
|
+
* const id = 'user*123?';
|
|
67
|
+
* const pattern = `key:${escapeGlob(id)}:*`;
|
|
68
|
+
* // pattern = 'key:user\\*123\\?:*'
|
|
69
|
+
* ```
|
|
70
|
+
*/
|
|
71
|
+
export declare function escapeGlob(literal: string): string;
|
|
@@ -0,0 +1,54 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* TTL Validation Utilities
|
|
3
|
+
*
|
|
4
|
+
* Helper functions for validating and normalizing TTL values.
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Maximum TTL in seconds (roughly 100 years).
|
|
8
|
+
* Prevents integer overflow issues.
|
|
9
|
+
*/
|
|
10
|
+
export declare const MAX_TTL_SECONDS = 3153600000;
|
|
11
|
+
/**
|
|
12
|
+
* Validate a TTL value.
|
|
13
|
+
*
|
|
14
|
+
* @param ttlSeconds - TTL in seconds
|
|
15
|
+
* @throws StorageTTLError if TTL is invalid
|
|
16
|
+
*/
|
|
17
|
+
export declare function validateTTL(ttlSeconds: number): void;
|
|
18
|
+
/**
|
|
19
|
+
* Validate TTL if provided (optional TTL).
|
|
20
|
+
*
|
|
21
|
+
* @param ttlSeconds - Optional TTL in seconds
|
|
22
|
+
* @throws StorageTTLError if TTL is provided but invalid
|
|
23
|
+
*/
|
|
24
|
+
export declare function validateOptionalTTL(ttlSeconds: number | undefined): void;
|
|
25
|
+
/**
|
|
26
|
+
* Calculate expiration timestamp from TTL.
|
|
27
|
+
*
|
|
28
|
+
* @param ttlSeconds - TTL in seconds
|
|
29
|
+
* @returns Expiration timestamp (Date.now() + ttlSeconds * 1000)
|
|
30
|
+
*/
|
|
31
|
+
export declare function ttlToExpiresAt(ttlSeconds: number): number;
|
|
32
|
+
/**
|
|
33
|
+
* Calculate remaining TTL from expiration timestamp.
|
|
34
|
+
*
|
|
35
|
+
* @param expiresAt - Expiration timestamp
|
|
36
|
+
* @returns Remaining seconds, or 0 if expired
|
|
37
|
+
*/
|
|
38
|
+
export declare function expiresAtToTTL(expiresAt: number): number;
|
|
39
|
+
/**
|
|
40
|
+
* Check if an expiration timestamp has passed.
|
|
41
|
+
*
|
|
42
|
+
* @param expiresAt - Expiration timestamp
|
|
43
|
+
* @returns true if expired (current time >= expiresAt)
|
|
44
|
+
*/
|
|
45
|
+
export declare function isExpired(expiresAt: number | undefined): boolean;
|
|
46
|
+
/**
|
|
47
|
+
* Normalize TTL to seconds if provided in milliseconds.
|
|
48
|
+
* Useful for adapting from APIs that use milliseconds.
|
|
49
|
+
*
|
|
50
|
+
* @param ttl - TTL value
|
|
51
|
+
* @param unit - 'seconds' or 'milliseconds'
|
|
52
|
+
* @returns TTL in seconds
|
|
53
|
+
*/
|
|
54
|
+
export declare function normalizeTTL(ttl: number, unit: 'seconds' | 'milliseconds'): number;
|
package/uri/index.d.ts
ADDED
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* RFC 6570 Level 1 URI Template utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides parsing, matching, and expansion of URI templates using simple
|
|
5
|
+
* string substitution ({param} syntax). This implements RFC 6570 Level 1 only;
|
|
6
|
+
* advanced operators like {+path}, {#fragment}, or {?query} are not supported.
|
|
7
|
+
*/
|
|
8
|
+
/**
|
|
9
|
+
* Parsed URI template information.
|
|
10
|
+
*/
|
|
11
|
+
export interface ParsedUriTemplate {
|
|
12
|
+
/** Compiled regex pattern for matching URIs */
|
|
13
|
+
pattern: RegExp;
|
|
14
|
+
/** Ordered list of parameter names extracted from template */
|
|
15
|
+
paramNames: string[];
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Parse a URI template (RFC 6570 Level 1) into a regex pattern and parameter names.
|
|
19
|
+
* Supports simple string substitution: {param}
|
|
20
|
+
*
|
|
21
|
+
* @param template - The URI template to parse
|
|
22
|
+
* @returns Parsed template with pattern and parameter names
|
|
23
|
+
* @throws Error if template is too long (>1000 chars) or has too many parameters (>50)
|
|
24
|
+
*
|
|
25
|
+
* @example
|
|
26
|
+
* parseUriTemplate("file:///{path}")
|
|
27
|
+
* // { pattern: /^file:\/\/\/([^/]+)$/, paramNames: ["path"] }
|
|
28
|
+
*
|
|
29
|
+
* parseUriTemplate("users/{userId}/posts/{postId}")
|
|
30
|
+
* // { pattern: /^users\/([^/]+)\/posts\/([^/]+)$/, paramNames: ["userId", "postId"] }
|
|
31
|
+
*/
|
|
32
|
+
export declare function parseUriTemplate(template: string): ParsedUriTemplate;
|
|
33
|
+
/**
|
|
34
|
+
* Match a URI against a URI template and extract parameters.
|
|
35
|
+
* Returns null if no match, or an object with extracted parameters.
|
|
36
|
+
*
|
|
37
|
+
* @param template - The URI template
|
|
38
|
+
* @param uri - The URI to match against the template
|
|
39
|
+
* @returns Object with extracted parameters, or null if no match
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* matchUriTemplate("file:///{path}", "file:///documents")
|
|
43
|
+
* // { path: "documents" }
|
|
44
|
+
*
|
|
45
|
+
* matchUriTemplate("users/{userId}/posts/{postId}", "users/123/posts/456")
|
|
46
|
+
* // { userId: "123", postId: "456" }
|
|
47
|
+
*
|
|
48
|
+
* matchUriTemplate("users/{id}", "products/123")
|
|
49
|
+
* // null (no match)
|
|
50
|
+
*/
|
|
51
|
+
export declare function matchUriTemplate(template: string, uri: string): Record<string, string> | null;
|
|
52
|
+
/**
|
|
53
|
+
* Expand a URI template with the given parameters.
|
|
54
|
+
*
|
|
55
|
+
* @param template - The URI template
|
|
56
|
+
* @param params - Object with parameter values
|
|
57
|
+
* @returns Expanded URI with parameters substituted
|
|
58
|
+
* @throws Error if a required parameter is missing
|
|
59
|
+
*
|
|
60
|
+
* @example
|
|
61
|
+
* expandUriTemplate("file:///{path}", { path: "documents" })
|
|
62
|
+
* // "file:///documents"
|
|
63
|
+
*
|
|
64
|
+
* expandUriTemplate("users/{userId}/posts/{postId}", { userId: "123", postId: "456" })
|
|
65
|
+
* // "users/123/posts/456"
|
|
66
|
+
*/
|
|
67
|
+
export declare function expandUriTemplate(template: string, params: Record<string, string>): string;
|
|
68
|
+
/**
|
|
69
|
+
* Extract parameter names from a URI template.
|
|
70
|
+
*
|
|
71
|
+
* @param template - The URI template
|
|
72
|
+
* @returns Array of parameter names in order of appearance
|
|
73
|
+
*
|
|
74
|
+
* @example
|
|
75
|
+
* extractTemplateParams("users/{userId}/posts/{postId}")
|
|
76
|
+
* // ["userId", "postId"]
|
|
77
|
+
*
|
|
78
|
+
* extractTemplateParams("file:///static/path")
|
|
79
|
+
* // []
|
|
80
|
+
*/
|
|
81
|
+
export declare function extractTemplateParams(template: string): string[];
|
|
82
|
+
/**
|
|
83
|
+
* Check if a string is a URI template (contains {param} placeholders).
|
|
84
|
+
*
|
|
85
|
+
* @param uri - The string to check
|
|
86
|
+
* @returns true if the string contains template placeholders
|
|
87
|
+
*
|
|
88
|
+
* @example
|
|
89
|
+
* isUriTemplate("users/{userId}") // true
|
|
90
|
+
* isUriTemplate("users/123") // false
|
|
91
|
+
*/
|
|
92
|
+
export declare function isUriTemplate(uri: string): boolean;
|
|
@@ -0,0 +1,46 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* URI validation utilities.
|
|
3
|
+
*
|
|
4
|
+
* Provides RFC 3986 compliant URI validation including scheme validation
|
|
5
|
+
* and extraction. These utilities are commonly used for validating resource URIs.
|
|
6
|
+
*/
|
|
7
|
+
/**
|
|
8
|
+
* Validate that a URI has a valid scheme per RFC 3986.
|
|
9
|
+
*
|
|
10
|
+
* @param uri - The URI to validate
|
|
11
|
+
* @returns true if the URI has a valid scheme, false otherwise
|
|
12
|
+
*
|
|
13
|
+
* @example
|
|
14
|
+
* isValidMcpUri('file:///path/to/file') // true
|
|
15
|
+
* isValidMcpUri('https://example.com/resource') // true
|
|
16
|
+
* isValidMcpUri('custom://my-resource') // true
|
|
17
|
+
* isValidMcpUri('/path/to/file') // false (no scheme)
|
|
18
|
+
* isValidMcpUri('123://invalid') // false (scheme must start with letter)
|
|
19
|
+
*/
|
|
20
|
+
export declare function isValidMcpUri(uri: string): boolean;
|
|
21
|
+
/**
|
|
22
|
+
* Extract the scheme from a URI.
|
|
23
|
+
*
|
|
24
|
+
* @param uri - The URI to extract the scheme from
|
|
25
|
+
* @returns The scheme in lowercase, or null if no valid scheme found
|
|
26
|
+
*
|
|
27
|
+
* @example
|
|
28
|
+
* extractUriScheme('file:///path') // 'file'
|
|
29
|
+
* extractUriScheme('HTTPS://example.com') // 'https'
|
|
30
|
+
* extractUriScheme('/no/scheme') // null
|
|
31
|
+
*/
|
|
32
|
+
export declare function extractUriScheme(uri: string): string | null;
|
|
33
|
+
/**
|
|
34
|
+
* Validate that a URI template has a valid scheme per RFC 3986.
|
|
35
|
+
* URI templates follow RFC 6570 and can contain template expressions like {var}.
|
|
36
|
+
* The scheme portion should still be a valid static scheme.
|
|
37
|
+
*
|
|
38
|
+
* @param uriTemplate - The URI template to validate
|
|
39
|
+
* @returns true if the URI template has a valid scheme, false otherwise
|
|
40
|
+
*
|
|
41
|
+
* @example
|
|
42
|
+
* isValidMcpUriTemplate('users://{userId}/profile') // true
|
|
43
|
+
* isValidMcpUriTemplate('file:///{path}') // true
|
|
44
|
+
* isValidMcpUriTemplate('{scheme}://dynamic') // false (scheme must be static)
|
|
45
|
+
*/
|
|
46
|
+
export declare function isValidMcpUriTemplate(uriTemplate: string): boolean;
|