@frontmcp/utils 1.9.3 → 1.9.4
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/class-brand/class-brand.d.ts +37 -0
- package/class-brand/index.d.ts +1 -0
- package/esm/index.mjs +30 -0
- package/fs/fs.d.ts +20 -0
- package/fs/index.d.ts +1 -1
- package/index.d.ts +2 -1
- package/index.js +33 -0
- package/package.json +2 -2
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Class identity shared by every copy of a package loaded in one process.
|
|
3
|
+
*
|
|
4
|
+
* A process can hold two copies of a FrontMCP package: in an ES-module project `@frontmcp/sdk`'s ESM
|
|
5
|
+
* build loads `@frontmcp/observability` with `require()`, which resolves observability's CommonJS
|
|
6
|
+
* build, which in turn loads the CommonJS builds of the SDK and of its dependencies. Each copy has its
|
|
7
|
+
* own classes, so a plain `instanceof` in one copy does not recognise an instance made by the other:
|
|
8
|
+
* an error the client was answered with as a `PublicMcpError` was recorded as an internal error with
|
|
9
|
+
* a new id (#802).
|
|
10
|
+
*
|
|
11
|
+
* A branded class answers `instanceof` for its own instances as usual, and also for an instance of
|
|
12
|
+
* the class with the same brand from another copy. The brand is an own property of the class, so a
|
|
13
|
+
* subclass is recognised only through a brand of its own: an unbranded subclass keeps the plain
|
|
14
|
+
* check, and never matches a different subclass that happens to share a branded parent.
|
|
15
|
+
*
|
|
16
|
+
* @example
|
|
17
|
+
* ```ts
|
|
18
|
+
* export class GuardError extends Error {
|
|
19
|
+
* static override [Symbol.hasInstance](value: unknown): boolean {
|
|
20
|
+
* return isBrandedInstance(this, value);
|
|
21
|
+
* }
|
|
22
|
+
* }
|
|
23
|
+
* brandClass(GuardError, '@frontmcp/guard:GuardError');
|
|
24
|
+
* ```
|
|
25
|
+
*/
|
|
26
|
+
/**
|
|
27
|
+
* Give `klass` a process-wide brand. The same class in another copy of its package carries the same
|
|
28
|
+
* brand, so each recognises the other's instances through {@link isBrandedInstance}. Namespace the
|
|
29
|
+
* brand with the package name (`'@frontmcp/sdk:McpError'`).
|
|
30
|
+
*/
|
|
31
|
+
export declare function brandClass(klass: object, brand: string): void;
|
|
32
|
+
/**
|
|
33
|
+
* `value instanceof klass`, also true when `value` is an instance of the class that carries `klass`'s
|
|
34
|
+
* own brand in another copy of the package. Meant as the `static [Symbol.hasInstance]` of a branded
|
|
35
|
+
* class (subclasses inherit it, and match through their own brand or the plain check).
|
|
36
|
+
*/
|
|
37
|
+
export declare function isBrandedInstance(klass: object, value: unknown): boolean;
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { brandClass, isBrandedInstance } from './class-brand';
|
package/esm/index.mjs
CHANGED
|
@@ -117,6 +117,9 @@ async function fileExists(p) {
|
|
|
117
117
|
return false;
|
|
118
118
|
}
|
|
119
119
|
}
|
|
120
|
+
function fileExistsSync(p) {
|
|
121
|
+
return getFs().existsSync(p);
|
|
122
|
+
}
|
|
120
123
|
async function readJSON(jsonPath) {
|
|
121
124
|
try {
|
|
122
125
|
const fsp = getFsp();
|
|
@@ -4883,6 +4886,30 @@ function safeJsonForScript(value) {
|
|
|
4883
4886
|
}
|
|
4884
4887
|
}
|
|
4885
4888
|
|
|
4889
|
+
// libs/utils/src/class-brand/class-brand.ts
|
|
4890
|
+
var CLASS_BRAND = /* @__PURE__ */ Symbol.for("@frontmcp/class-brand");
|
|
4891
|
+
var ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
|
|
4892
|
+
function ownBrandOf(klass) {
|
|
4893
|
+
if (typeof klass !== "function" || !Object.prototype.hasOwnProperty.call(klass, CLASS_BRAND)) return void 0;
|
|
4894
|
+
return klass[CLASS_BRAND];
|
|
4895
|
+
}
|
|
4896
|
+
function classOfPrototype(proto) {
|
|
4897
|
+
return Object.getOwnPropertyDescriptor(proto, "constructor")?.value;
|
|
4898
|
+
}
|
|
4899
|
+
function brandClass(klass, brand) {
|
|
4900
|
+
Object.defineProperty(klass, CLASS_BRAND, { value: brand, enumerable: false, writable: false, configurable: false });
|
|
4901
|
+
}
|
|
4902
|
+
function isBrandedInstance(klass, value) {
|
|
4903
|
+
if (ordinaryHasInstance.call(klass, value)) return true;
|
|
4904
|
+
if (typeof value !== "object" || value === null) return false;
|
|
4905
|
+
const brand = ownBrandOf(klass);
|
|
4906
|
+
if (brand === void 0) return false;
|
|
4907
|
+
for (let proto = Object.getPrototypeOf(value); proto !== null; proto = Object.getPrototypeOf(proto)) {
|
|
4908
|
+
if (ownBrandOf(classOfPrototype(proto)) === brand) return true;
|
|
4909
|
+
}
|
|
4910
|
+
return false;
|
|
4911
|
+
}
|
|
4912
|
+
|
|
4886
4913
|
// libs/utils/src/serialization/serialization.ts
|
|
4887
4914
|
function safeStringify(value, space) {
|
|
4888
4915
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -5907,6 +5934,7 @@ export {
|
|
|
5907
5934
|
base64urlDecode,
|
|
5908
5935
|
base64urlEncode,
|
|
5909
5936
|
basename,
|
|
5937
|
+
brandClass,
|
|
5910
5938
|
buildPrefix,
|
|
5911
5939
|
buildSetCookie,
|
|
5912
5940
|
bytesToHex,
|
|
@@ -5957,6 +5985,7 @@ export {
|
|
|
5957
5985
|
extractTemplateParams,
|
|
5958
5986
|
extractUriScheme,
|
|
5959
5987
|
fileExists,
|
|
5988
|
+
fileExistsSync,
|
|
5960
5989
|
findNonFiniteNumber,
|
|
5961
5990
|
generateCodeChallenge,
|
|
5962
5991
|
generateCodeVerifier,
|
|
@@ -5983,6 +6012,7 @@ export {
|
|
|
5983
6012
|
inferMimeType,
|
|
5984
6013
|
isAbsolute,
|
|
5985
6014
|
isAsymmetricKeyData,
|
|
6015
|
+
isBrandedInstance,
|
|
5986
6016
|
isBrowser,
|
|
5987
6017
|
isDebug,
|
|
5988
6018
|
isDevelopment,
|
package/fs/fs.d.ts
CHANGED
|
@@ -137,6 +137,21 @@ export declare function unlink(p: string): Promise<void>;
|
|
|
137
137
|
* await fileExists('/path/to/file.txt') // true or false
|
|
138
138
|
*/
|
|
139
139
|
export declare function fileExists(p: string): Promise<boolean>;
|
|
140
|
+
/**
|
|
141
|
+
* Check whether a file or directory exists, synchronously.
|
|
142
|
+
*
|
|
143
|
+
* **Node.js only** - throws an error if called in browser.
|
|
144
|
+
*
|
|
145
|
+
* Use this only where async is not possible (e.g. resolving a command line
|
|
146
|
+
* before a synchronous `spawn`). Prefer {@link fileExists} otherwise.
|
|
147
|
+
*
|
|
148
|
+
* @param p - Path to check
|
|
149
|
+
* @returns true if the path exists, false otherwise
|
|
150
|
+
*
|
|
151
|
+
* @example
|
|
152
|
+
* fileExistsSync('/path/to/file.txt') // true or false
|
|
153
|
+
*/
|
|
154
|
+
export declare function fileExistsSync(p: string): boolean;
|
|
140
155
|
/**
|
|
141
156
|
* Read and parse a JSON file.
|
|
142
157
|
*
|
|
@@ -343,6 +358,11 @@ export declare function access(p: string, mode?: number): Promise<void>;
|
|
|
343
358
|
export declare function runCmd(cmd: string, args: string[], opts?: {
|
|
344
359
|
cwd?: string;
|
|
345
360
|
env?: NodeJS.ProcessEnv;
|
|
361
|
+
/**
|
|
362
|
+
* Pass `args` to the child unquoted (Windows only). Set it when the arguments
|
|
363
|
+
* are already quoted for `cmd.exe /d /s /c`; ignored on other platforms.
|
|
364
|
+
*/
|
|
365
|
+
windowsVerbatimArguments?: boolean;
|
|
346
366
|
}): Promise<void>;
|
|
347
367
|
/**
|
|
348
368
|
* Handle returned by {@link watchFile}. `close()` stops the watch and is safe
|
package/fs/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
|
-
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
|
|
1
|
+
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, fileExistsSync, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
|
|
2
2
|
export type { FileWatcherHandle, SymlinkType } from './fs';
|
package/index.d.ts
CHANGED
|
@@ -15,9 +15,10 @@ export { validateBaseUrl, buildSetCookie, parseCookies, getCookie, isLocalhost,
|
|
|
15
15
|
export type { CookieOptions, SecureDetectionRequest } from './http';
|
|
16
16
|
export { classifyIpAddress, expandIpv6, extractEmbeddedIpv4, parseIpv4, isRedirectResponse } from './net';
|
|
17
17
|
export type { IpAddressClassification, IpAddressRange, SpecialPurposeIpRange, RedirectCandidate } from './net';
|
|
18
|
-
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
|
|
18
|
+
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, readdirSync, realpath, rm, mkdtemp, symlink, access, fileExists, fileExistsSync, readJSON, writeJSON, ensureDir, ensureDirSync, isDirEmpty, runCmd, watchFile, getSpawnFn, } from './fs';
|
|
19
19
|
export type { FileWatcherHandle } from './fs';
|
|
20
20
|
export { escapeHtml, escapeHtmlAttr, escapeJsString, escapeScriptClose, safeJsonForScript } from './escape';
|
|
21
|
+
export { brandClass, isBrandedInstance } from './class-brand';
|
|
21
22
|
export { safeStringify } from './serialization';
|
|
22
23
|
export { getCrypto, rsaVerify, rsaVerifySync, pemToPublicJwk, generateRsaKeyPair, rsaSignBase64Url, type RsaJwk, type RsaKeyPair, jwtAlgToNodeAlg, isRsaPssAlg, randomUUID, randomBytes, sha256, sha256Hex, sha256Base64url, hmacSha256, hkdfSha256, encryptAesGcm, decryptAesGcm, timingSafeEqual, bytesToHex, base64urlEncode, base64urlDecode, base64Encode, base64Decode, isNode, isBrowser, assertNode, EncryptedBlobError, encryptValue, decryptValue, tryDecryptValue, serializeBlob, deserializeBlob, tryDeserializeBlob, isValidEncryptedBlob, encryptAndSerialize, deserializeAndDecrypt, tryDeserializeAndDecrypt, generateCodeVerifier, generateCodeChallenge, verifyCodeChallenge, generatePkcePair, isValidCodeVerifier, isValidCodeChallenge, MIN_CODE_VERIFIER_LENGTH, MAX_CODE_VERIFIER_LENGTH, DEFAULT_CODE_VERIFIER_LENGTH, PkceError, type PkcePair, type SecretData, type SecretPersistenceOptions, type SecretValidationResult, secretDataSchema, validateSecretData, parseSecretData, isSecretPersistenceEnabled, resolveSecretPath, loadSecret, saveSecret, deleteSecret, generateSecret, createSecretData, getOrCreateSecret, clearCachedSecret, isSecretCached, type SignedData, type HmacSigningConfig, signData, verifyData, isSignedData, verifyOrParseData, type BaseKeyData, type SecretKeyData, type AsymmetricKeyData, type AnyKeyData, type KeyPersistenceOptions, type CreateKeyPersistenceOptions, type CreateSecretOptions, type CreateAsymmetricOptions, type KeyValidationResult, asymmetricAlgSchema, secretKeyDataSchema, asymmetricKeyDataSchema, anyKeyDataSchema, validateKeyData, parseKeyData, isSecretKeyData, isAsymmetricKeyData, KeyPersistence, createKeyPersistence, createKeyPersistenceWithStorage, } from './crypto';
|
|
23
24
|
export type { CryptoProvider, EncBlob, EncryptedBlob } from './crypto';
|
package/index.js
CHANGED
|
@@ -119,6 +119,9 @@ async function fileExists(p) {
|
|
|
119
119
|
return false;
|
|
120
120
|
}
|
|
121
121
|
}
|
|
122
|
+
function fileExistsSync(p) {
|
|
123
|
+
return getFs().existsSync(p);
|
|
124
|
+
}
|
|
122
125
|
async function readJSON(jsonPath) {
|
|
123
126
|
try {
|
|
124
127
|
const fsp = getFsp();
|
|
@@ -4134,6 +4137,7 @@ __export(index_exports, {
|
|
|
4134
4137
|
base64urlDecode: () => base64urlDecode,
|
|
4135
4138
|
base64urlEncode: () => base64urlEncode,
|
|
4136
4139
|
basename: () => import_path2.basename,
|
|
4140
|
+
brandClass: () => brandClass,
|
|
4137
4141
|
buildPrefix: () => buildPrefix,
|
|
4138
4142
|
buildSetCookie: () => buildSetCookie,
|
|
4139
4143
|
bytesToHex: () => bytesToHex,
|
|
@@ -4184,6 +4188,7 @@ __export(index_exports, {
|
|
|
4184
4188
|
extractTemplateParams: () => extractTemplateParams,
|
|
4185
4189
|
extractUriScheme: () => extractUriScheme,
|
|
4186
4190
|
fileExists: () => fileExists,
|
|
4191
|
+
fileExistsSync: () => fileExistsSync,
|
|
4187
4192
|
findNonFiniteNumber: () => findNonFiniteNumber,
|
|
4188
4193
|
generateCodeChallenge: () => generateCodeChallenge,
|
|
4189
4194
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
@@ -4210,6 +4215,7 @@ __export(index_exports, {
|
|
|
4210
4215
|
inferMimeType: () => inferMimeType,
|
|
4211
4216
|
isAbsolute: () => import_path2.isAbsolute,
|
|
4212
4217
|
isAsymmetricKeyData: () => isAsymmetricKeyData,
|
|
4218
|
+
isBrandedInstance: () => isBrandedInstance,
|
|
4213
4219
|
isBrowser: () => isBrowser,
|
|
4214
4220
|
isDebug: () => import_env2.isDebug,
|
|
4215
4221
|
isDevelopment: () => import_env2.isDevelopment,
|
|
@@ -5114,6 +5120,30 @@ function safeJsonForScript(value) {
|
|
|
5114
5120
|
}
|
|
5115
5121
|
}
|
|
5116
5122
|
|
|
5123
|
+
// libs/utils/src/class-brand/class-brand.ts
|
|
5124
|
+
var CLASS_BRAND = /* @__PURE__ */ Symbol.for("@frontmcp/class-brand");
|
|
5125
|
+
var ordinaryHasInstance = Function.prototype[Symbol.hasInstance];
|
|
5126
|
+
function ownBrandOf(klass) {
|
|
5127
|
+
if (typeof klass !== "function" || !Object.prototype.hasOwnProperty.call(klass, CLASS_BRAND)) return void 0;
|
|
5128
|
+
return klass[CLASS_BRAND];
|
|
5129
|
+
}
|
|
5130
|
+
function classOfPrototype(proto) {
|
|
5131
|
+
return Object.getOwnPropertyDescriptor(proto, "constructor")?.value;
|
|
5132
|
+
}
|
|
5133
|
+
function brandClass(klass, brand) {
|
|
5134
|
+
Object.defineProperty(klass, CLASS_BRAND, { value: brand, enumerable: false, writable: false, configurable: false });
|
|
5135
|
+
}
|
|
5136
|
+
function isBrandedInstance(klass, value) {
|
|
5137
|
+
if (ordinaryHasInstance.call(klass, value)) return true;
|
|
5138
|
+
if (typeof value !== "object" || value === null) return false;
|
|
5139
|
+
const brand = ownBrandOf(klass);
|
|
5140
|
+
if (brand === void 0) return false;
|
|
5141
|
+
for (let proto = Object.getPrototypeOf(value); proto !== null; proto = Object.getPrototypeOf(proto)) {
|
|
5142
|
+
if (ownBrandOf(classOfPrototype(proto)) === brand) return true;
|
|
5143
|
+
}
|
|
5144
|
+
return false;
|
|
5145
|
+
}
|
|
5146
|
+
|
|
5117
5147
|
// libs/utils/src/serialization/serialization.ts
|
|
5118
5148
|
function safeStringify(value, space) {
|
|
5119
5149
|
const seen = /* @__PURE__ */ new WeakSet();
|
|
@@ -6114,6 +6144,7 @@ function setMachineIdOverride(id) {
|
|
|
6114
6144
|
base64urlDecode,
|
|
6115
6145
|
base64urlEncode,
|
|
6116
6146
|
basename,
|
|
6147
|
+
brandClass,
|
|
6117
6148
|
buildPrefix,
|
|
6118
6149
|
buildSetCookie,
|
|
6119
6150
|
bytesToHex,
|
|
@@ -6164,6 +6195,7 @@ function setMachineIdOverride(id) {
|
|
|
6164
6195
|
extractTemplateParams,
|
|
6165
6196
|
extractUriScheme,
|
|
6166
6197
|
fileExists,
|
|
6198
|
+
fileExistsSync,
|
|
6167
6199
|
findNonFiniteNumber,
|
|
6168
6200
|
generateCodeChallenge,
|
|
6169
6201
|
generateCodeVerifier,
|
|
@@ -6190,6 +6222,7 @@ function setMachineIdOverride(id) {
|
|
|
6190
6222
|
inferMimeType,
|
|
6191
6223
|
isAbsolute,
|
|
6192
6224
|
isAsymmetricKeyData,
|
|
6225
|
+
isBrandedInstance,
|
|
6193
6226
|
isBrowser,
|
|
6194
6227
|
isDebug,
|
|
6195
6228
|
isDevelopment,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.9.
|
|
3
|
+
"version": "1.9.4",
|
|
4
4
|
"description": "Shared utility functions for FrontMCP - string manipulation, URI handling, path utilities, and more",
|
|
5
5
|
"author": "AgentFront <info@agentfront.dev>",
|
|
6
6
|
"license": "Apache-2.0",
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"@noble/hashes": "^2.0.1"
|
|
33
33
|
},
|
|
34
34
|
"peerDependencies": {
|
|
35
|
-
"@frontmcp/lazy-zod": "1.9.
|
|
35
|
+
"@frontmcp/lazy-zod": "1.9.4",
|
|
36
36
|
"@upstash/redis": "^1.34.0",
|
|
37
37
|
"@vercel/kv": "^2.0.0 || ^3.0.0",
|
|
38
38
|
"ioredis": "^5.0.0"
|