@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,25 @@
1
+ /**
2
+ * Secret persistence utilities for storing encryption secrets.
3
+ *
4
+ * Provides a secure way to persist secrets to disk for development environments.
5
+ * In production, use environment variables instead.
6
+ *
7
+ * @module @frontmcp/utils/secret-persistence
8
+ *
9
+ * @example
10
+ * ```typescript
11
+ * import { getOrCreateSecret } from '@frontmcp/utils';
12
+ *
13
+ * // Get or create a persisted secret
14
+ * const secret = await getOrCreateSecret({
15
+ * name: 'remember',
16
+ * secretPath: '.frontmcp/remember-secret.json',
17
+ * });
18
+ *
19
+ * // Use the secret for encryption
20
+ * const key = await deriveKey(secret);
21
+ * ```
22
+ */
23
+ export type { SecretData, SecretPersistenceOptions, SecretValidationResult } from './types';
24
+ export { secretDataSchema, validateSecretData, parseSecretData } from './schema';
25
+ export { isSecretPersistenceEnabled, resolveSecretPath, loadSecret, saveSecret, deleteSecret, generateSecret, createSecretData, getOrCreateSecret, clearCachedSecret, isSecretCached, } from './persistence';
@@ -0,0 +1,97 @@
1
+ /**
2
+ * Secret persistence utilities for storing encryption secrets.
3
+ *
4
+ * Follows the same pattern as OAuth JWK dev-key-persistence for consistency.
5
+ * Stores a random secret to a JSON file for use when no environment variable is set.
6
+ *
7
+ * This enables development environments to have consistent encryption keys
8
+ * without requiring manual configuration.
9
+ *
10
+ * @module @frontmcp/utils/secret-persistence
11
+ */
12
+ import type { SecretData, SecretPersistenceOptions } from './types';
13
+ /**
14
+ * Check if secret persistence is enabled based on environment and options.
15
+ *
16
+ * By default, persistence is:
17
+ * - Enabled in development (NODE_ENV !== 'production')
18
+ * - Disabled in production unless forceEnable is true
19
+ *
20
+ * @param options - Persistence options
21
+ * @returns true if persistence is enabled
22
+ */
23
+ export declare function isSecretPersistenceEnabled(options?: SecretPersistenceOptions): boolean;
24
+ /**
25
+ * Resolve the secret file path.
26
+ *
27
+ * @param options - Persistence options
28
+ * @returns Absolute path to secret file
29
+ */
30
+ export declare function resolveSecretPath(options?: SecretPersistenceOptions): string;
31
+ /**
32
+ * Load persisted secret from file.
33
+ *
34
+ * @param options - Persistence options
35
+ * @returns The loaded secret data or null if not found/invalid
36
+ */
37
+ export declare function loadSecret(options?: SecretPersistenceOptions): Promise<SecretData | null>;
38
+ /**
39
+ * Save secret to file.
40
+ *
41
+ * Uses atomic write (temp file + rename) to prevent corruption.
42
+ * Sets file permissions to 0o600 (owner read/write only) for security.
43
+ *
44
+ * @param secretData - Secret data to persist
45
+ * @param options - Persistence options
46
+ * @returns true if save succeeded, false otherwise
47
+ */
48
+ export declare function saveSecret(secretData: SecretData, options?: SecretPersistenceOptions): Promise<boolean>;
49
+ /**
50
+ * Delete persisted secret.
51
+ *
52
+ * @param options - Persistence options
53
+ * @returns true if deleted or didn't exist, false on error
54
+ */
55
+ export declare function deleteSecret(options?: SecretPersistenceOptions): Promise<boolean>;
56
+ /**
57
+ * Generate a new random secret.
58
+ *
59
+ * @param bytes - Number of random bytes (default 32 = 256 bits)
60
+ * @returns Base64url-encoded random string
61
+ */
62
+ export declare function generateSecret(bytes?: number): string;
63
+ /**
64
+ * Create a new secret data object with current timestamp.
65
+ *
66
+ * @param options - Options including secret bytes
67
+ * @returns New SecretData object
68
+ */
69
+ export declare function createSecretData(options?: SecretPersistenceOptions): SecretData;
70
+ /**
71
+ * Get or create a persisted secret.
72
+ *
73
+ * This is the main entry point for getting a secret.
74
+ * It will:
75
+ * 1. Return cached secret if available (for this name)
76
+ * 2. Load from file if exists
77
+ * 3. Generate new secret and persist it
78
+ *
79
+ * Thread-safe: concurrent calls will share the same generation promise.
80
+ *
81
+ * @param options - Persistence options
82
+ * @returns The secret string
83
+ */
84
+ export declare function getOrCreateSecret(options?: SecretPersistenceOptions): Promise<string>;
85
+ /**
86
+ * Clear the cached secret (for testing).
87
+ *
88
+ * @param options - Options to identify which secret to clear (by path)
89
+ */
90
+ export declare function clearCachedSecret(options?: SecretPersistenceOptions): void;
91
+ /**
92
+ * Check if a secret is cached.
93
+ *
94
+ * @param options - Options to identify which secret to check
95
+ * @returns true if cached
96
+ */
97
+ export declare function isSecretCached(options?: SecretPersistenceOptions): boolean;
@@ -0,0 +1,34 @@
1
+ /**
2
+ * Validation schema for secret data.
3
+ *
4
+ * @module @frontmcp/utils/secret-persistence
5
+ */
6
+ import { z } from 'zod';
7
+ import type { SecretData, SecretValidationResult } from './types';
8
+ /**
9
+ * Zod schema for SecretData.
10
+ */
11
+ export declare const secretDataSchema: z.ZodObject<{
12
+ secret: z.ZodString;
13
+ createdAt: z.ZodNumber;
14
+ version: z.ZodNumber;
15
+ }, z.core.$strict>;
16
+ /**
17
+ * Validate secret data structure.
18
+ *
19
+ * Checks:
20
+ * - Schema validation
21
+ * - createdAt is not in the future (with 1 minute drift allowance)
22
+ * - createdAt is not too old (100 years)
23
+ *
24
+ * @param data - Data to validate
25
+ * @returns Validation result
26
+ */
27
+ export declare function validateSecretData(data: unknown): SecretValidationResult;
28
+ /**
29
+ * Parse and validate secret data.
30
+ *
31
+ * @param data - Raw data to parse
32
+ * @returns Parsed secret data or null if invalid
33
+ */
34
+ export declare function parseSecretData(data: unknown): SecretData | null;
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Types for secret persistence utilities.
3
+ *
4
+ * @module @frontmcp/utils/secret-persistence
5
+ */
6
+ /**
7
+ * Data structure for a persisted secret.
8
+ */
9
+ export interface SecretData {
10
+ /** Random secret, base64url encoded (typically 32 bytes = 256 bits) */
11
+ secret: string;
12
+ /** Creation timestamp (ms since epoch) */
13
+ createdAt: number;
14
+ /** Version for future migrations */
15
+ version: number;
16
+ }
17
+ /**
18
+ * Options for secret persistence operations.
19
+ */
20
+ export interface SecretPersistenceOptions {
21
+ /**
22
+ * Path to store the secret file.
23
+ * If relative, resolved from current working directory.
24
+ * @default '.frontmcp/<name>-secret.json'
25
+ */
26
+ secretPath?: string;
27
+ /**
28
+ * Secret name used in default path and log messages.
29
+ * @default 'default'
30
+ */
31
+ name?: string;
32
+ /**
33
+ * Enable persistence in production (NOT RECOMMENDED for multi-server).
34
+ * In production, use environment variables instead.
35
+ * @default false
36
+ */
37
+ forceEnable?: boolean;
38
+ /**
39
+ * Number of bytes to generate for new secrets.
40
+ * @default 32 (256 bits)
41
+ */
42
+ secretBytes?: number;
43
+ /**
44
+ * Enable logging of persistence operations.
45
+ * @default true
46
+ */
47
+ enableLogging?: boolean;
48
+ /**
49
+ * Custom logger for persistence messages.
50
+ * Defaults to console.warn/console.error.
51
+ */
52
+ logger?: {
53
+ warn: (message: string) => void;
54
+ error: (message: string) => void;
55
+ };
56
+ }
57
+ /**
58
+ * Result of validating secret data.
59
+ */
60
+ export interface SecretValidationResult {
61
+ /** Whether the secret data is valid */
62
+ valid: boolean;
63
+ /** Error message if invalid */
64
+ error?: string;
65
+ }
@@ -0,0 +1,61 @@
1
+ /**
2
+ * Crypto Provider Types
3
+ *
4
+ * Defines the interface for cryptographic operations that work across
5
+ * Node.js and browser environments.
6
+ */
7
+ /**
8
+ * Encrypted blob structure for AES-256-GCM encryption.
9
+ * All fields are base64url encoded.
10
+ */
11
+ export interface EncBlob {
12
+ alg: 'A256GCM';
13
+ iv: string;
14
+ tag: string;
15
+ data: string;
16
+ }
17
+ /**
18
+ * Crypto provider interface for cross-platform cryptographic operations.
19
+ * All operations are synchronous for consistency across platforms.
20
+ */
21
+ export interface CryptoProvider {
22
+ /**
23
+ * Generate a UUID v4 string.
24
+ */
25
+ randomUUID(): string;
26
+ /**
27
+ * Generate cryptographically secure random bytes.
28
+ */
29
+ randomBytes(length: number): Uint8Array;
30
+ /**
31
+ * Compute SHA-256 hash.
32
+ */
33
+ sha256(data: string | Uint8Array): Uint8Array;
34
+ /**
35
+ * Compute SHA-256 hash and return as hex string.
36
+ */
37
+ sha256Hex(data: string | Uint8Array): string;
38
+ /**
39
+ * Compute HMAC-SHA256.
40
+ */
41
+ hmacSha256(key: Uint8Array, data: Uint8Array): Uint8Array;
42
+ /**
43
+ * HKDF-SHA256 key derivation (RFC 5869).
44
+ */
45
+ hkdfSha256(ikm: Uint8Array, salt: Uint8Array, info: Uint8Array, length: number): Uint8Array;
46
+ /**
47
+ * Encrypt using AES-256-GCM.
48
+ */
49
+ encryptAesGcm(key: Uint8Array, plaintext: Uint8Array, iv: Uint8Array): {
50
+ ciphertext: Uint8Array;
51
+ tag: Uint8Array;
52
+ };
53
+ /**
54
+ * Decrypt using AES-256-GCM.
55
+ */
56
+ decryptAesGcm(key: Uint8Array, ciphertext: Uint8Array, iv: Uint8Array, tag: Uint8Array): Uint8Array;
57
+ /**
58
+ * Constant-time comparison to prevent timing attacks.
59
+ */
60
+ timingSafeEqual(a: Uint8Array, b: Uint8Array): boolean;
61
+ }
@@ -0,0 +1,101 @@
1
+ /**
2
+ * HTML and JavaScript Escaping Utilities
3
+ *
4
+ * Functions for escaping strings to prevent XSS attacks in HTML output.
5
+ *
6
+ * @packageDocumentation
7
+ */
8
+ /**
9
+ * Escape HTML special characters to prevent XSS.
10
+ *
11
+ * Handles null/undefined by returning empty string.
12
+ * Converts non-string values to string before escaping.
13
+ *
14
+ * @param str - Value to escape (will be converted to string)
15
+ * @returns Escaped string safe for HTML content
16
+ *
17
+ * @example
18
+ * ```typescript
19
+ * escapeHtml('<script>alert("xss")</script>')
20
+ * // Returns: '&lt;script&gt;alert(&quot;xss&quot;)&lt;/script&gt;'
21
+ *
22
+ * escapeHtml(null) // Returns: ''
23
+ * escapeHtml(123) // Returns: '123'
24
+ * ```
25
+ */
26
+ export declare function escapeHtml(str: unknown): string;
27
+ /**
28
+ * Escape string for use in HTML attributes.
29
+ *
30
+ * Lighter version that only escapes & and " characters,
31
+ * suitable for attribute values that are already quoted.
32
+ *
33
+ * @param str - String to escape
34
+ * @returns Escaped string safe for HTML attributes
35
+ *
36
+ * @example
37
+ * ```typescript
38
+ * escapeHtmlAttr('value with "quotes" & ampersand')
39
+ * // Returns: 'value with &quot;quotes&quot; &amp; ampersand'
40
+ * ```
41
+ */
42
+ export declare function escapeHtmlAttr(str: string): string;
43
+ /**
44
+ * Escape string for use in JavaScript string literals.
45
+ *
46
+ * Escapes characters that could break out of a JS string context.
47
+ *
48
+ * @param str - String to escape
49
+ * @returns Escaped string safe for JS string literals
50
+ *
51
+ * @example
52
+ * ```typescript
53
+ * escapeJsString("it's a \"test\"")
54
+ * // Returns: "it\\'s a \\\"test\\\""
55
+ * ```
56
+ */
57
+ export declare function escapeJsString(str: string): string;
58
+ /**
59
+ * Escape script closing tags in JSON strings to prevent XSS.
60
+ *
61
+ * When embedding JSON in a <script> tag, the string `</script>` will
62
+ * prematurely close the script block. This function escapes the closing
63
+ * tag by replacing `</` with `<\/`.
64
+ *
65
+ * @param jsonString - JSON string (already passed through JSON.stringify)
66
+ * @returns Escaped JSON string safe for embedding in script tags
67
+ *
68
+ * @example
69
+ * ```typescript
70
+ * const json = JSON.stringify({ html: '</script><script>alert(1)</script>' });
71
+ * escapeScriptClose(json);
72
+ * // Returns: '{"html":"<\\/script><script>alert(1)<\\/script>"}'
73
+ * ```
74
+ */
75
+ export declare function escapeScriptClose(jsonString: string): string;
76
+ /**
77
+ * Safely serialize a value to JSON for embedding in HTML <script> tags.
78
+ *
79
+ * Combines JSON.stringify with escapeScriptClose to prevent XSS attacks
80
+ * where malicious data contains `</script>` or other HTML-sensitive sequences.
81
+ *
82
+ * Handles edge cases:
83
+ * - undefined: Returns 'null' (since undefined is not valid JSON)
84
+ * - Circular references: Returns error placeholder
85
+ * - BigInt: Converted to string representation
86
+ * - Functions/Symbols: Omitted (standard JSON.stringify behavior)
87
+ *
88
+ * @param value - Value to serialize
89
+ * @returns Escaped JSON string safe for embedding in script tags
90
+ *
91
+ * @example
92
+ * ```typescript
93
+ * const data = { html: '</script><script>alert("xss")</script>' };
94
+ * const safe = safeJsonForScript(data);
95
+ * // Returns: '{"html":"<\\/script><script>alert(\\"xss\\")<\\/script>"}'
96
+ *
97
+ * // Safe to use in:
98
+ * // <script>const data = ${safeJsonForScript(data)};</script>
99
+ * ```
100
+ */
101
+ export declare function safeJsonForScript(value: unknown): string;
@@ -0,0 +1 @@
1
+ export { escapeHtml, escapeHtmlAttr, escapeJsString, escapeScriptClose, safeJsonForScript } from './escape';