@frontmcp/utils 1.12.0-rc.1 → 1.12.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/browser/escape/escape.mjs +25 -0
- package/browser/escape/index.mjs +9 -1
- package/browser/http/index.mjs +4 -0
- package/browser/http/limited-body.mjs +74 -0
- package/browser/index.mjs +28 -2
- package/browser/optional-module/index.mjs +6 -0
- package/browser/optional-module/optional-module.mjs +18 -0
- package/browser/redaction/redaction.mjs +6 -4
- package/browser/stdio-bridge/sse-frames.mjs +3 -1
- package/browser/stdio-bridge/stdio-framer.mjs +4 -1
- package/browser/storage/adapters/filesystem.mjs +31 -9
- package/browser/storage/adapters/memory.mjs +25 -26
- package/browser/storage/factory.mjs +2 -1
- package/browser/storage/index.mjs +2 -1
- package/browser/storage/utils/index.mjs +2 -1
- package/browser/storage/utils/pattern.mjs +71 -24
- package/browser/uri/uri-template.mjs +93 -15
- package/crypto/key-persistence/types.d.ts +4 -1
- package/escape/escape.d.ts +19 -0
- package/escape/index.d.ts +1 -1
- package/esm/index.mjs +1 -1
- package/http/index.d.ts +2 -0
- package/http/limited-body.d.ts +56 -0
- package/index.d.ts +5 -4
- package/index.js +1 -1
- package/optional-module/index.d.ts +1 -0
- package/optional-module/optional-module.d.ts +12 -0
- package/package.json +3 -3
- package/redaction/redaction.d.ts +1 -1
- package/storage/adapters/filesystem.d.ts +11 -0
- package/storage/adapters/memory.d.ts +6 -2
- package/storage/index.d.ts +1 -1
- package/storage/utils/index.d.ts +1 -1
- package/storage/utils/pattern.d.ts +31 -4
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { registerOptionalModule, requireOptionalModule } from './optional-module';
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Hand FrontMCP an optional package (`@frontmcp/observability`, `@frontmcp/storage-sqlite`) that the
|
|
3
|
+
* bundle already contains. On Cloudflare Workers `require()` cannot reach bundled
|
|
4
|
+
* modules, so the worker entry registers them here (#768). Kept on
|
|
5
|
+
* `globalThis` so a second copy of a FrontMCP package in the same bundle sees it too.
|
|
6
|
+
*/
|
|
7
|
+
export declare function registerOptionalModule(moduleName: string, moduleExports: unknown): void;
|
|
8
|
+
/**
|
|
9
|
+
* Return a module registered with {@link registerOptionalModule}, or run
|
|
10
|
+
* `load` — pass a literal `() => require('pkg')` so bundlers still see it.
|
|
11
|
+
*/
|
|
12
|
+
export declare function requireOptionalModule<T>(moduleName: string, load: () => T): T;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.12.
|
|
3
|
+
"version": "1.12.1",
|
|
4
4
|
"description": "Shared helpers for FrontMCP: URI templates, naming, cross-platform crypto and PKCE, key-value storage, file system and environment detection",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -28,12 +28,12 @@
|
|
|
28
28
|
"node": ">=24.0.0"
|
|
29
29
|
},
|
|
30
30
|
"dependencies": {
|
|
31
|
-
"@enclave-vm/ast": "^2.
|
|
31
|
+
"@enclave-vm/ast": "^2.19.2",
|
|
32
32
|
"@noble/ciphers": "^2.1.1",
|
|
33
33
|
"@noble/hashes": "^2.0.1"
|
|
34
34
|
},
|
|
35
35
|
"peerDependencies": {
|
|
36
|
-
"@frontmcp/lazy-zod": "1.12.
|
|
36
|
+
"@frontmcp/lazy-zod": "1.12.1",
|
|
37
37
|
"@upstash/redis": "^1.34.0",
|
|
38
38
|
"@vercel/kv": "^2.0.0 || ^3.0.0",
|
|
39
39
|
"ioredis": "^5.0.0"
|
package/redaction/redaction.d.ts
CHANGED
|
@@ -12,7 +12,7 @@ export type RedactedFields = readonly string[] | ((key: string) => boolean);
|
|
|
12
12
|
*
|
|
13
13
|
* @param obj - Object to redact fields from
|
|
14
14
|
* @param fields - Field names to redact (case-insensitive), or a test on each key
|
|
15
|
-
* @param maxDepth - Maximum recursion depth (default: 5)
|
|
15
|
+
* @param maxDepth - Maximum recursion depth (default: 5); an object or list below it becomes '[TRUNCATED]'
|
|
16
16
|
* @returns New object with sensitive fields replaced by '[REDACTED]'
|
|
17
17
|
*/
|
|
18
18
|
export declare function redactFields(obj: Record<string, unknown>, fields: RedactedFields, maxDepth?: number): Record<string, unknown>;
|
|
@@ -88,6 +88,8 @@ export declare class FileSystemStorageAdapter extends BaseStorageAdapter {
|
|
|
88
88
|
private readonly extension;
|
|
89
89
|
private readonly dirMode;
|
|
90
90
|
private readonly fileMode;
|
|
91
|
+
/** The last update queued for each key, so a counter's read and write never interleave with another update. */
|
|
92
|
+
private readonly keyUpdates;
|
|
91
93
|
constructor(options: FileSystemAdapterOptions);
|
|
92
94
|
connect(): Promise<void>;
|
|
93
95
|
disconnect(): Promise<void>;
|
|
@@ -97,11 +99,20 @@ export declare class FileSystemStorageAdapter extends BaseStorageAdapter {
|
|
|
97
99
|
delete(key: string): Promise<boolean>;
|
|
98
100
|
exists(key: string): Promise<boolean>;
|
|
99
101
|
expire(key: string, ttlSeconds: number): Promise<boolean>;
|
|
102
|
+
/** Set the expiry of `key` from its current entry; run only through {@link updateInTurn}. */
|
|
103
|
+
private expireNow;
|
|
100
104
|
ttl(key: string): Promise<number | null>;
|
|
101
105
|
keys(pattern?: string): Promise<string[]>;
|
|
102
106
|
incr(key: string): Promise<number>;
|
|
103
107
|
decr(key: string): Promise<number>;
|
|
104
108
|
incrBy(key: string, amount: number): Promise<number>;
|
|
109
|
+
/** Add `amount` to the counter at `key`; run only through {@link updateInTurn}. */
|
|
110
|
+
private incrByNow;
|
|
111
|
+
/**
|
|
112
|
+
* Run `update` once the updates of `key` queued before it in this process have finished, so two updates of
|
|
113
|
+
* one key never read the same entry. Processes that share a directory are not coordinated.
|
|
114
|
+
*/
|
|
115
|
+
private updateInTurn;
|
|
105
116
|
/**
|
|
106
117
|
* Convert a storage key to a file path.
|
|
107
118
|
* Sanitizes the key to be filesystem-safe.
|
|
@@ -34,7 +34,7 @@ export declare class MemoryStorageAdapter extends BaseStorageAdapter {
|
|
|
34
34
|
private readonly emitter;
|
|
35
35
|
private sweepInterval?;
|
|
36
36
|
private readonly options;
|
|
37
|
-
private accessOrder;
|
|
37
|
+
private readonly accessOrder;
|
|
38
38
|
constructor(options?: MemoryAdapterOptions);
|
|
39
39
|
connect(): Promise<void>;
|
|
40
40
|
disconnect(): Promise<void>;
|
|
@@ -76,7 +76,11 @@ export declare class MemoryStorageAdapter extends BaseStorageAdapter {
|
|
|
76
76
|
*/
|
|
77
77
|
private removeLRU;
|
|
78
78
|
/**
|
|
79
|
-
* Evict
|
|
79
|
+
* Evict least recently used entries until a new key fits within maxEntries.
|
|
80
|
+
*/
|
|
81
|
+
private makeRoomFor;
|
|
82
|
+
/**
|
|
83
|
+
* Evict the least recently used entry. Returns false when no entry is left to evict.
|
|
80
84
|
*/
|
|
81
85
|
private evictOldest;
|
|
82
86
|
/**
|
package/storage/index.d.ts
CHANGED
|
@@ -20,5 +20,5 @@ export { EncryptedTypedStorage } from './encrypted-typed-storage';
|
|
|
20
20
|
export type { EncryptedTypedStorageOptions, EncryptedSetOptions, EncryptedSetEntry, EncryptionKey, StoredEncryptedBlob, ClientKeyBinding, } from './encrypted-typed-storage.types';
|
|
21
21
|
export { BaseStorageAdapter, MemoryStorageAdapter, RedisStorageAdapter, createRedisClient, VercelKvStorageAdapter, createVercelKvClient, UpstashStorageAdapter, FileSystemStorageAdapter, LocalStorageAdapter, IndexedDBStorageAdapter, } from './adapters';
|
|
22
22
|
export type { CreateRedisClientOptions, VercelKvConnection, FileSystemAdapterOptions, LocalStorageAdapterOptions, IndexedDBAdapterOptions, } from './adapters';
|
|
23
|
-
export { globToRegex, matchesPattern, validatePattern, escapeGlob } from './utils/pattern';
|
|
23
|
+
export { createGlobMatcher, globToRegex, matchesPattern, validatePattern, escapeGlob } from './utils/pattern';
|
|
24
24
|
export { MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, } from './utils/ttl';
|
package/storage/utils/index.d.ts
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Storage Utilities
|
|
3
3
|
*/
|
|
4
|
-
export { globToRegex, matchesPattern, validatePattern, escapeGlob } from './pattern';
|
|
4
|
+
export { createGlobMatcher, globToRegex, matchesPattern, validatePattern, escapeGlob } from './pattern';
|
|
5
5
|
export { MAX_TTL_SECONDS, validateTTL, validateOptionalTTL, ttlToExpiresAt, expiresAtToTTL, isExpired, normalizeTTL, } from './ttl';
|
|
@@ -1,15 +1,41 @@
|
|
|
1
1
|
/**
|
|
2
2
|
* Pattern Matching Utilities
|
|
3
3
|
*
|
|
4
|
-
*
|
|
5
|
-
*
|
|
4
|
+
* Glob patterns for key matching: `*` matches any sequence, `?` matches one character, and a backslash makes the
|
|
5
|
+
* next character literal, as in Redis `SCAN MATCH`, so `escapeGlob()` output means the same thing on every backend.
|
|
6
|
+
* Matching runs without regular expressions, in time bounded by the key length times the pattern length.
|
|
6
7
|
*/
|
|
7
8
|
/**
|
|
8
|
-
*
|
|
9
|
+
* Compile a glob pattern into a function that tests whole keys.
|
|
9
10
|
*
|
|
10
11
|
* Supports:
|
|
11
12
|
* - `*` matches any sequence of characters (including empty)
|
|
12
13
|
* - `?` matches exactly one character
|
|
14
|
+
* - a backslash makes the next character literal, so `escapeGlob(value)` matches exactly `value`
|
|
15
|
+
*
|
|
16
|
+
* Unlike {@link globToRegex}, the matcher never backtracks: a pattern with many wildcards cannot stall the process.
|
|
17
|
+
*
|
|
18
|
+
* @param pattern - Glob pattern (e.g., "user:*:profile")
|
|
19
|
+
* @returns A function that reports whether a key matches the whole pattern
|
|
20
|
+
* @throws StoragePatternError if the pattern is too long or has too many wildcards
|
|
21
|
+
*
|
|
22
|
+
* @example
|
|
23
|
+
* ```typescript
|
|
24
|
+
* const isProfile = createGlobMatcher('user:*:profile');
|
|
25
|
+
* isProfile('user:123:profile'); // true
|
|
26
|
+
* isProfile('user:profile'); // false
|
|
27
|
+
*
|
|
28
|
+
* const exact = createGlobMatcher(`id:${escapeGlob('a*b')}`);
|
|
29
|
+
* exact('id:a*b'); // true
|
|
30
|
+
* exact('id:axxb'); // false
|
|
31
|
+
* ```
|
|
32
|
+
*/
|
|
33
|
+
export declare function createGlobMatcher(pattern: string): (key: string) => boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Convert a glob pattern to a RegExp.
|
|
36
|
+
*
|
|
37
|
+
* Supports `*`, `?` and backslash escapes, as {@link createGlobMatcher} does. The result is a backtracking regular
|
|
38
|
+
* expression; to test keys, use {@link createGlobMatcher} or {@link matchesPattern}, which do not backtrack.
|
|
13
39
|
*
|
|
14
40
|
* @param pattern - Glob pattern (e.g., "user:*:profile")
|
|
15
41
|
* @returns RegExp for matching keys
|
|
@@ -56,7 +82,8 @@ export declare function validatePattern(pattern: string): {
|
|
|
56
82
|
};
|
|
57
83
|
/**
|
|
58
84
|
* Escape a string for use as a literal in a glob pattern.
|
|
59
|
-
* Escapes
|
|
85
|
+
* Escapes `*`, `?`, `[`, `]` and backslash (Redis `SCAN MATCH` reads `[` as the start of a character class). Every
|
|
86
|
+
* matcher in this module, and Redis `SCAN MATCH`, reads the result as the literal string.
|
|
60
87
|
*
|
|
61
88
|
* @param literal - String to escape
|
|
62
89
|
* @returns Escaped string safe for use in patterns
|