@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.
Files changed (54) hide show
  1. package/CHANGELOG.md +12 -0
  2. package/README.md +110 -0
  3. package/content/content.d.ts +43 -0
  4. package/content/index.d.ts +1 -0
  5. package/crypto/browser.d.ts +11 -0
  6. package/crypto/encrypted-blob.d.ts +157 -0
  7. package/crypto/index.d.ts +98 -0
  8. package/crypto/jwt-alg.d.ts +8 -0
  9. package/crypto/node.d.ts +59 -0
  10. package/crypto/pkce/index.d.ts +9 -0
  11. package/crypto/pkce/pkce.d.ts +140 -0
  12. package/crypto/runtime.d.ts +18 -0
  13. package/crypto/secret-persistence/index.d.ts +25 -0
  14. package/crypto/secret-persistence/persistence.d.ts +97 -0
  15. package/crypto/secret-persistence/schema.d.ts +34 -0
  16. package/crypto/secret-persistence/types.d.ts +65 -0
  17. package/crypto/types.d.ts +61 -0
  18. package/escape/escape.d.ts +101 -0
  19. package/escape/index.d.ts +1 -0
  20. package/esm/index.mjs +3264 -0
  21. package/esm/package.json +53 -0
  22. package/fs/fs.d.ts +254 -0
  23. package/fs/index.d.ts +1 -0
  24. package/http/http.d.ts +20 -0
  25. package/http/index.d.ts +1 -0
  26. package/index.d.ts +18 -0
  27. package/index.js +3425 -0
  28. package/naming/index.d.ts +1 -0
  29. package/naming/naming.d.ts +79 -0
  30. package/package.json +3 -2
  31. package/path/index.d.ts +1 -0
  32. package/path/path.d.ts +34 -0
  33. package/regex/index.d.ts +24 -0
  34. package/regex/patterns.d.ts +155 -0
  35. package/regex/safe-regex.d.ts +179 -0
  36. package/serialization/index.d.ts +1 -0
  37. package/serialization/serialization.d.ts +33 -0
  38. package/storage/adapters/base.d.ts +90 -0
  39. package/storage/adapters/index.d.ts +10 -0
  40. package/storage/adapters/memory.d.ts +99 -0
  41. package/storage/adapters/redis.d.ts +88 -0
  42. package/storage/adapters/upstash.d.ts +81 -0
  43. package/storage/adapters/vercel-kv.d.ts +69 -0
  44. package/storage/errors.d.ts +117 -0
  45. package/storage/factory.d.ts +70 -0
  46. package/storage/index.d.ts +13 -0
  47. package/storage/namespace.d.ts +88 -0
  48. package/storage/types.d.ts +428 -0
  49. package/storage/utils/index.d.ts +5 -0
  50. package/storage/utils/pattern.d.ts +71 -0
  51. package/storage/utils/ttl.d.ts +54 -0
  52. package/uri/index.d.ts +2 -0
  53. package/uri/uri-template.d.ts +92 -0
  54. 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,5 @@
1
+ /**
2
+ * Storage Utilities
3
+ */
4
+ export { globToRegex, matchesPattern, validatePattern, escapeGlob } from './pattern';
5
+ export { MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, } from './ttl';
@@ -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,2 @@
1
+ export { isValidMcpUri, extractUriScheme, isValidMcpUriTemplate } from './uri-validation';
2
+ export { ParsedUriTemplate, parseUriTemplate, matchUriTemplate, expandUriTemplate, extractTemplateParams, isUriTemplate, } from './uri-template';
@@ -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;