@frontmcp/utils 1.1.2-beta.1 → 1.2.0
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/crypto/index.d.ts +47 -0
- package/crypto/node.d.ts +49 -0
- package/crypto/node.js +41 -2
- package/esm/crypto/node.mjs +37 -1
- package/esm/index.mjs +115 -14
- package/fs/fs.d.ts +29 -0
- package/fs/index.d.ts +1 -1
- package/index.d.ts +3 -3
- package/index.js +122 -14
- package/package.json +2 -2
- package/path/browser-path.d.ts +1 -0
- package/path/index.d.ts +1 -1
- package/path/node-path.d.ts +1 -1
- package/uri/uri-template.d.ts +32 -11
- package/CHANGELOG.md +0 -12
package/crypto/index.d.ts
CHANGED
|
@@ -4,7 +4,10 @@
|
|
|
4
4
|
* Provides cryptographic operations that work in both Node.js and browser environments.
|
|
5
5
|
* Uses native crypto in Node.js and @noble/hashes + @noble/ciphers in browsers.
|
|
6
6
|
*/
|
|
7
|
+
import type { RsaJwk as RsaJwkNode, RsaKeyPair as RsaKeyPairNode } from './node';
|
|
7
8
|
import type { CryptoProvider, EncBlob } from './types';
|
|
9
|
+
export type RsaJwk = RsaJwkNode;
|
|
10
|
+
export type RsaKeyPair = RsaKeyPairNode;
|
|
8
11
|
export { isRsaPssAlg, jwtAlgToNodeAlg, jwtAlgToWebCryptoAlg } from './jwt-alg';
|
|
9
12
|
/**
|
|
10
13
|
* Get the crypto provider for the current runtime environment.
|
|
@@ -24,6 +27,50 @@ export declare function getCrypto(): CryptoProvider;
|
|
|
24
27
|
* @returns Promise resolving to true if the signature is valid
|
|
25
28
|
*/
|
|
26
29
|
export declare function rsaVerify(jwtAlg: string, data: Buffer | Uint8Array, publicJwk: JsonWebKey, signature: Buffer | Uint8Array): Promise<boolean>;
|
|
30
|
+
/**
|
|
31
|
+
* Sign data with an RSA private JWK and return a base64url-encoded signature.
|
|
32
|
+
*
|
|
33
|
+
* Node-only: signs synchronously using `crypto.createPrivateKey` + `crypto.sign`.
|
|
34
|
+
* Throws in non-Node runtimes since WebCrypto requires async key import and
|
|
35
|
+
* the audit signer needs a synchronous interface; production hosts that need
|
|
36
|
+
* RS256 audit signing run on Node.
|
|
37
|
+
*
|
|
38
|
+
* @param jwtAlg - JWT algorithm identifier (e.g. 'RS256', 'PS256')
|
|
39
|
+
* @param data - Bytes to sign
|
|
40
|
+
* @param privateJwk - Private key in JWK format
|
|
41
|
+
* @returns Base64url-encoded signature
|
|
42
|
+
*/
|
|
43
|
+
export declare function rsaSignBase64Url(jwtAlg: string, data: Buffer | Uint8Array, privateJwk: JsonWebKey): string;
|
|
44
|
+
/**
|
|
45
|
+
* Synchronous companion to {@link rsaVerify}. Node-only — server-side audit
|
|
46
|
+
* verifiers and bundle signature verifiers need a sync surface so the
|
|
47
|
+
* `AuditSignatureVerifier` interface stays single-await for hot paths.
|
|
48
|
+
*
|
|
49
|
+
* Accepts RSA, RSA-PSS, and EdDSA (Ed25519) keys in JWK form. Returns
|
|
50
|
+
* `false` (never throws) on malformed keys / unsupported algs.
|
|
51
|
+
*
|
|
52
|
+
* @param jwtAlg - JWT algorithm identifier (`'RS256'`, `'PS256'`, `'EdDSA'`, ...)
|
|
53
|
+
* @param data - The signed data bytes
|
|
54
|
+
* @param publicJwk - Public key in JWK format
|
|
55
|
+
* @param signature - Raw signature bytes
|
|
56
|
+
*/
|
|
57
|
+
export declare function rsaVerifySync(jwtAlg: string, data: Buffer | Uint8Array, publicJwk: JsonWebKey, signature: Buffer | Uint8Array): boolean;
|
|
58
|
+
/**
|
|
59
|
+
* Convert a PEM-encoded public key (SPKI) into a JWK so callers can route
|
|
60
|
+
* verification through {@link rsaVerifySync}. Node-only.
|
|
61
|
+
*
|
|
62
|
+
* Throws on malformed PEM — server-side callers should catch and translate
|
|
63
|
+
* to a structured failure reason.
|
|
64
|
+
*/
|
|
65
|
+
export declare function pemToPublicJwk(pem: string): JsonWebKey;
|
|
66
|
+
/**
|
|
67
|
+
* Generate an RSA key pair (Node-only). Re-exported here so test code and
|
|
68
|
+
* host bootstrap don't have to reach into `node:crypto` directly.
|
|
69
|
+
*
|
|
70
|
+
* @param modulusLength - Key size in bits (default: 2048)
|
|
71
|
+
* @param alg - JWT algorithm (default: 'RS256')
|
|
72
|
+
*/
|
|
73
|
+
export declare function generateRsaKeyPair(modulusLength?: number, alg?: string): RsaKeyPair;
|
|
27
74
|
/**
|
|
28
75
|
* Generate a UUID v4 string.
|
|
29
76
|
*/
|
package/crypto/node.d.ts
CHANGED
|
@@ -49,6 +49,55 @@ export declare function generateRsaKeyPair(modulusLength?: number, alg?: string)
|
|
|
49
49
|
*/
|
|
50
50
|
export declare function rsaSign(algorithm: string, data: Buffer, privateKey: crypto.KeyObject, options?: Omit<crypto.SignKeyObjectInput, 'key'>): Buffer;
|
|
51
51
|
export declare function rsaVerify(jwtAlg: string, data: Buffer, publicJwk: JsonWebKey, signature: Buffer): boolean;
|
|
52
|
+
/**
|
|
53
|
+
* Sign data with an RSA private JWK and return a base64url-encoded signature.
|
|
54
|
+
*
|
|
55
|
+
* Mirror of {@link rsaVerify} on the signing side: takes a JWT alg name
|
|
56
|
+
* (`RS256`/`RS384`/`RS512`/`PS256`/`PS384`/`PS512`), a private key in JWK
|
|
57
|
+
* format, and the data bytes; returns the detached signature as a base64url
|
|
58
|
+
* string suitable for inline JSON envelopes (e.g. tamper-evident audit
|
|
59
|
+
* records that re-use the same key registry as bundle signing).
|
|
60
|
+
*
|
|
61
|
+
* Node-only — `crypto.createPrivateKey({ format: 'jwk' })` is not exposed in
|
|
62
|
+
* WebCrypto with the same shape, so audit signing is gated to Node runtimes.
|
|
63
|
+
*
|
|
64
|
+
* @param jwtAlg - JWT algorithm identifier (e.g. 'RS256', 'PS256')
|
|
65
|
+
* @param data - Bytes to sign
|
|
66
|
+
* @param privateJwk - Private key in JWK format
|
|
67
|
+
* @returns Base64url-encoded signature
|
|
68
|
+
*/
|
|
69
|
+
export declare function rsaSignBase64Url(jwtAlg: string, data: Buffer | Uint8Array, privateJwk: JsonWebKey): string;
|
|
70
|
+
/**
|
|
71
|
+
* Verify an RSA / RSA-PSS / EdDSA signature synchronously.
|
|
72
|
+
*
|
|
73
|
+
* Node-only — mirrors {@link rsaSignBase64Url}'s sync, JWK-first surface so
|
|
74
|
+
* server-side callers (audit signer verifier, bundle signature verifier)
|
|
75
|
+
* have a single utility to call instead of touching `node:crypto` directly.
|
|
76
|
+
*
|
|
77
|
+
* - RS256/RS384/RS512 / PS256/PS384/PS512: pass `jwtAlg` and an RSA JWK.
|
|
78
|
+
* - EdDSA: pass `'EdDSA'` and an Ed25519 JWK (`kty: 'OKP'`, `crv: 'Ed25519'`).
|
|
79
|
+
*
|
|
80
|
+
* Returns `false` (never throws) for malformed keys / unsupported algs so
|
|
81
|
+
* callers can surface a single "verification failed" reason instead of
|
|
82
|
+
* branching on every internal crypto error.
|
|
83
|
+
*
|
|
84
|
+
* @param jwtAlg - JWT algorithm identifier (`'RS256'`, `'PS256'`, `'EdDSA'`, ...)
|
|
85
|
+
* @param data - Bytes that were signed
|
|
86
|
+
* @param publicJwk - Public key in JWK format
|
|
87
|
+
* @param signature - Signature bytes (raw, NOT base64url)
|
|
88
|
+
*/
|
|
89
|
+
export declare function rsaVerifySync(jwtAlg: string, data: Buffer | Uint8Array, publicJwk: JsonWebKey, signature: Buffer | Uint8Array): boolean;
|
|
90
|
+
/**
|
|
91
|
+
* Convert a PEM-encoded public key (SPKI) to a JWK.
|
|
92
|
+
*
|
|
93
|
+
* Node-only. Used by host code that has historically configured trust roots
|
|
94
|
+
* as PEMs (bundle-signature trust list, audit verifier trust list) so the
|
|
95
|
+
* verifier path can normalize to JWK before calling {@link rsaVerifySync}.
|
|
96
|
+
*
|
|
97
|
+
* Throws if the PEM cannot be parsed — callers should catch and translate
|
|
98
|
+
* into a structured "malformed_public_key" reason where appropriate.
|
|
99
|
+
*/
|
|
100
|
+
export declare function pemToPublicJwk(pem: string): JsonWebKey;
|
|
52
101
|
/**
|
|
53
102
|
* Create a JWT signed with an RSA key
|
|
54
103
|
*
|
package/crypto/node.js
CHANGED
|
@@ -36,8 +36,11 @@ __export(node_exports, {
|
|
|
36
36
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
37
37
|
jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
|
|
38
38
|
nodeCrypto: () => nodeCrypto,
|
|
39
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
39
40
|
rsaSign: () => rsaSign,
|
|
40
|
-
|
|
41
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
42
|
+
rsaVerify: () => rsaVerify,
|
|
43
|
+
rsaVerifySync: () => rsaVerifySync
|
|
41
44
|
});
|
|
42
45
|
module.exports = __toCommonJS(node_exports);
|
|
43
46
|
var import_node_crypto = __toESM(require("node:crypto"));
|
|
@@ -154,6 +157,39 @@ function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
|
154
157
|
} : publicKey;
|
|
155
158
|
return import_node_crypto.default.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
156
159
|
}
|
|
160
|
+
function rsaSignBase64Url(jwtAlg, data, privateJwk) {
|
|
161
|
+
const privateKey = import_node_crypto.default.createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
162
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
163
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
164
|
+
const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
|
|
165
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
166
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
167
|
+
}) : rsaSign(nodeAlgorithm, buf, privateKey);
|
|
168
|
+
return sig.toString("base64url");
|
|
169
|
+
}
|
|
170
|
+
function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
|
|
171
|
+
try {
|
|
172
|
+
const publicKey = import_node_crypto.default.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
173
|
+
const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
174
|
+
const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
175
|
+
if (jwtAlg === "EdDSA") {
|
|
176
|
+
return import_node_crypto.default.verify(null, dataBuf, publicKey, sigBuf);
|
|
177
|
+
}
|
|
178
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
179
|
+
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
180
|
+
key: publicKey,
|
|
181
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
182
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
183
|
+
} : publicKey;
|
|
184
|
+
return import_node_crypto.default.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
|
|
185
|
+
} catch {
|
|
186
|
+
return false;
|
|
187
|
+
}
|
|
188
|
+
}
|
|
189
|
+
function pemToPublicJwk(pem) {
|
|
190
|
+
const key = import_node_crypto.default.createPublicKey({ key: pem, format: "pem" });
|
|
191
|
+
return key.export({ format: "jwk" });
|
|
192
|
+
}
|
|
157
193
|
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
158
194
|
const header = { alg, typ: "JWT", kid };
|
|
159
195
|
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
@@ -180,6 +216,9 @@ function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
|
180
216
|
isRsaPssAlg,
|
|
181
217
|
jwtAlgToNodeAlg,
|
|
182
218
|
nodeCrypto,
|
|
219
|
+
pemToPublicJwk,
|
|
183
220
|
rsaSign,
|
|
184
|
-
|
|
221
|
+
rsaSignBase64Url,
|
|
222
|
+
rsaVerify,
|
|
223
|
+
rsaVerifySync
|
|
185
224
|
});
|
package/esm/crypto/node.mjs
CHANGED
|
@@ -113,6 +113,39 @@ function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
|
113
113
|
} : publicKey;
|
|
114
114
|
return crypto.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
115
115
|
}
|
|
116
|
+
function rsaSignBase64Url(jwtAlg, data, privateJwk) {
|
|
117
|
+
const privateKey = crypto.createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
118
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
119
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
120
|
+
const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
|
|
121
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
122
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
|
|
123
|
+
}) : rsaSign(nodeAlgorithm, buf, privateKey);
|
|
124
|
+
return sig.toString("base64url");
|
|
125
|
+
}
|
|
126
|
+
function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
|
|
127
|
+
try {
|
|
128
|
+
const publicKey = crypto.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
129
|
+
const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
130
|
+
const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
131
|
+
if (jwtAlg === "EdDSA") {
|
|
132
|
+
return crypto.verify(null, dataBuf, publicKey, sigBuf);
|
|
133
|
+
}
|
|
134
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
135
|
+
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
136
|
+
key: publicKey,
|
|
137
|
+
padding: crypto.constants.RSA_PKCS1_PSS_PADDING,
|
|
138
|
+
saltLength: crypto.constants.RSA_PSS_SALTLEN_DIGEST
|
|
139
|
+
} : publicKey;
|
|
140
|
+
return crypto.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
|
|
141
|
+
} catch {
|
|
142
|
+
return false;
|
|
143
|
+
}
|
|
144
|
+
}
|
|
145
|
+
function pemToPublicJwk(pem) {
|
|
146
|
+
const key = crypto.createPublicKey({ key: pem, format: "pem" });
|
|
147
|
+
return key.export({ format: "jwk" });
|
|
148
|
+
}
|
|
116
149
|
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
117
150
|
const header = { alg, typ: "JWT", kid };
|
|
118
151
|
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
@@ -138,6 +171,9 @@ export {
|
|
|
138
171
|
isRsaPssAlg,
|
|
139
172
|
jwtAlgToNodeAlg,
|
|
140
173
|
nodeCrypto,
|
|
174
|
+
pemToPublicJwk,
|
|
141
175
|
rsaSign,
|
|
142
|
-
|
|
176
|
+
rsaSignBase64Url,
|
|
177
|
+
rsaVerify,
|
|
178
|
+
rsaVerifySync
|
|
143
179
|
};
|
package/esm/index.mjs
CHANGED
|
@@ -123,6 +123,14 @@ async function stat(p) {
|
|
|
123
123
|
const fsp = getFsp();
|
|
124
124
|
return fsp.stat(p);
|
|
125
125
|
}
|
|
126
|
+
async function symlink(target, linkPath) {
|
|
127
|
+
const fsp = getFsp();
|
|
128
|
+
await fsp.symlink(target, linkPath);
|
|
129
|
+
}
|
|
130
|
+
async function realpath(p) {
|
|
131
|
+
const fsp = getFsp();
|
|
132
|
+
return fsp.realpath(p);
|
|
133
|
+
}
|
|
126
134
|
async function copyFile(src, dest) {
|
|
127
135
|
const fsp = getFsp();
|
|
128
136
|
await fsp.copyFile(src, dest);
|
|
@@ -2481,8 +2489,11 @@ __export(node_exports, {
|
|
|
2481
2489
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
2482
2490
|
jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
|
|
2483
2491
|
nodeCrypto: () => nodeCrypto,
|
|
2492
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
2484
2493
|
rsaSign: () => rsaSign,
|
|
2485
|
-
|
|
2494
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2495
|
+
rsaVerify: () => rsaVerify,
|
|
2496
|
+
rsaVerifySync: () => rsaVerifySync
|
|
2486
2497
|
});
|
|
2487
2498
|
import crypto2 from "node:crypto";
|
|
2488
2499
|
function toUint8Array(buf) {
|
|
@@ -2523,6 +2534,39 @@ function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
|
2523
2534
|
} : publicKey;
|
|
2524
2535
|
return crypto2.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
2525
2536
|
}
|
|
2537
|
+
function rsaSignBase64Url(jwtAlg, data, privateJwk) {
|
|
2538
|
+
const privateKey = crypto2.createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
2539
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2540
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2541
|
+
const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
|
|
2542
|
+
padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
|
|
2543
|
+
saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2544
|
+
}) : rsaSign(nodeAlgorithm, buf, privateKey);
|
|
2545
|
+
return sig.toString("base64url");
|
|
2546
|
+
}
|
|
2547
|
+
function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
|
|
2548
|
+
try {
|
|
2549
|
+
const publicKey = crypto2.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
2550
|
+
const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2551
|
+
const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
2552
|
+
if (jwtAlg === "EdDSA") {
|
|
2553
|
+
return crypto2.verify(null, dataBuf, publicKey, sigBuf);
|
|
2554
|
+
}
|
|
2555
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2556
|
+
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
2557
|
+
key: publicKey,
|
|
2558
|
+
padding: crypto2.constants.RSA_PKCS1_PSS_PADDING,
|
|
2559
|
+
saltLength: crypto2.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2560
|
+
} : publicKey;
|
|
2561
|
+
return crypto2.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
|
|
2562
|
+
} catch {
|
|
2563
|
+
return false;
|
|
2564
|
+
}
|
|
2565
|
+
}
|
|
2566
|
+
function pemToPublicJwk(pem) {
|
|
2567
|
+
const key = crypto2.createPublicKey({ key: pem, format: "pem" });
|
|
2568
|
+
return key.export({ format: "jwk" });
|
|
2569
|
+
}
|
|
2526
2570
|
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
2527
2571
|
const header = { alg, typ: "JWT", kid };
|
|
2528
2572
|
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
@@ -2733,6 +2777,30 @@ function rsaVerify2(jwtAlg, data, publicJwk, signature) {
|
|
|
2733
2777
|
const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
|
|
2734
2778
|
return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
|
|
2735
2779
|
}
|
|
2780
|
+
function rsaSignBase64Url2(jwtAlg, data, privateJwk) {
|
|
2781
|
+
if (!isNode()) {
|
|
2782
|
+
throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
|
|
2783
|
+
}
|
|
2784
|
+
return (init_node(), __toCommonJS(node_exports)).rsaSignBase64Url(jwtAlg, data, privateJwk);
|
|
2785
|
+
}
|
|
2786
|
+
function rsaVerifySync2(jwtAlg, data, publicJwk, signature) {
|
|
2787
|
+
if (!isNode()) {
|
|
2788
|
+
throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
|
|
2789
|
+
}
|
|
2790
|
+
return (init_node(), __toCommonJS(node_exports)).rsaVerifySync(jwtAlg, data, publicJwk, signature);
|
|
2791
|
+
}
|
|
2792
|
+
function pemToPublicJwk2(pem) {
|
|
2793
|
+
if (!isNode()) {
|
|
2794
|
+
throw new Error("pemToPublicJwk is only available in Node.js runtimes");
|
|
2795
|
+
}
|
|
2796
|
+
return (init_node(), __toCommonJS(node_exports)).pemToPublicJwk(pem);
|
|
2797
|
+
}
|
|
2798
|
+
function generateRsaKeyPair2(modulusLength, alg) {
|
|
2799
|
+
if (!isNode()) {
|
|
2800
|
+
throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
|
|
2801
|
+
}
|
|
2802
|
+
return (init_node(), __toCommonJS(node_exports)).generateRsaKeyPair(modulusLength, alg);
|
|
2803
|
+
}
|
|
2736
2804
|
function randomUUID() {
|
|
2737
2805
|
return getCrypto().randomUUID();
|
|
2738
2806
|
}
|
|
@@ -4036,19 +4104,26 @@ function parseUriTemplate(template) {
|
|
|
4036
4104
|
throw new Error("URI template has too many parameters (max 50)");
|
|
4037
4105
|
}
|
|
4038
4106
|
const paramNames = [];
|
|
4039
|
-
|
|
4040
|
-
|
|
4041
|
-
|
|
4042
|
-
|
|
4043
|
-
|
|
4044
|
-
|
|
4045
|
-
|
|
4046
|
-
|
|
4107
|
+
const placeholder = /\{([^{}]+)\}/g;
|
|
4108
|
+
let regexStr = "";
|
|
4109
|
+
let lastIndex = 0;
|
|
4110
|
+
for (let m = placeholder.exec(template); m !== null; m = placeholder.exec(template)) {
|
|
4111
|
+
regexStr += escapeRegex(template.slice(lastIndex, m.index));
|
|
4112
|
+
const raw = m[1];
|
|
4113
|
+
const reserved = raw.startsWith("+");
|
|
4114
|
+
paramNames.push(reserved ? raw.slice(1) : raw);
|
|
4115
|
+
regexStr += reserved ? "(.+?)" : "([^/]+)";
|
|
4116
|
+
lastIndex = m.index + m[0].length;
|
|
4117
|
+
}
|
|
4118
|
+
regexStr += escapeRegex(template.slice(lastIndex));
|
|
4047
4119
|
return {
|
|
4048
4120
|
pattern: new RegExp(`^${regexStr}$`),
|
|
4049
4121
|
paramNames
|
|
4050
4122
|
};
|
|
4051
4123
|
}
|
|
4124
|
+
function escapeRegex(literal) {
|
|
4125
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, (c) => `\\${c}`);
|
|
4126
|
+
}
|
|
4052
4127
|
function matchUriTemplate(template, uri) {
|
|
4053
4128
|
const { pattern, paramNames } = parseUriTemplate(template);
|
|
4054
4129
|
const match = uri.match(pattern);
|
|
@@ -4060,18 +4135,37 @@ function matchUriTemplate(template, uri) {
|
|
|
4060
4135
|
return params;
|
|
4061
4136
|
}
|
|
4062
4137
|
function expandUriTemplate(template, params) {
|
|
4063
|
-
return template.replace(/\{([^{}]+)\}/g, (_,
|
|
4138
|
+
return template.replace(/\{([^{}]+)\}/g, (_, raw) => {
|
|
4139
|
+
const reserved = raw.startsWith("+");
|
|
4140
|
+
const paramName = reserved ? raw.slice(1) : raw;
|
|
4064
4141
|
const value = params[paramName];
|
|
4065
4142
|
if (value === void 0) {
|
|
4066
4143
|
throw new Error(`Missing parameter '${paramName}' for URI template '${template}'`);
|
|
4067
4144
|
}
|
|
4068
|
-
return encodeURIComponent(value);
|
|
4145
|
+
return reserved ? encodeReserved(value) : encodeURIComponent(value);
|
|
4069
4146
|
});
|
|
4070
4147
|
}
|
|
4148
|
+
function encodeReserved(value) {
|
|
4149
|
+
const decoded = safeDecode(value);
|
|
4150
|
+
return decoded.replace(/[^A-Za-z0-9\-._~:/?#[\]@!$&'()*+,;=]/g, (c) => encodeURIComponent(c));
|
|
4151
|
+
}
|
|
4152
|
+
function safeDecode(value) {
|
|
4153
|
+
try {
|
|
4154
|
+
return decodeURIComponent(value);
|
|
4155
|
+
} catch {
|
|
4156
|
+
return value.replace(/%[0-9A-Fa-f]{2}/g, (triplet) => {
|
|
4157
|
+
try {
|
|
4158
|
+
return decodeURIComponent(triplet);
|
|
4159
|
+
} catch {
|
|
4160
|
+
return triplet;
|
|
4161
|
+
}
|
|
4162
|
+
});
|
|
4163
|
+
}
|
|
4164
|
+
}
|
|
4071
4165
|
function extractTemplateParams(template) {
|
|
4072
4166
|
const params = [];
|
|
4073
|
-
template.replace(/\{([^{}]+)\}/g, (_,
|
|
4074
|
-
params.push(
|
|
4167
|
+
template.replace(/\{([^{}]+)\}/g, (_, raw) => {
|
|
4168
|
+
params.push(raw.startsWith("+") ? raw.slice(1) : raw);
|
|
4075
4169
|
return "";
|
|
4076
4170
|
});
|
|
4077
4171
|
return params;
|
|
@@ -4090,7 +4184,7 @@ function joinPath(...parts) {
|
|
|
4090
4184
|
}
|
|
4091
4185
|
|
|
4092
4186
|
// libs/utils/src/path/node-path.ts
|
|
4093
|
-
import { resolve, join, basename, dirname, extname } from "path";
|
|
4187
|
+
import { resolve, join, basename, dirname, extname, isAbsolute } from "path";
|
|
4094
4188
|
|
|
4095
4189
|
// libs/utils/src/content/content.ts
|
|
4096
4190
|
function sanitizeToJson(value) {
|
|
@@ -5421,6 +5515,7 @@ export {
|
|
|
5421
5515
|
generateCodeChallenge,
|
|
5422
5516
|
generateCodeVerifier,
|
|
5423
5517
|
generatePkcePair,
|
|
5518
|
+
generateRsaKeyPair2 as generateRsaKeyPair,
|
|
5424
5519
|
generateSecret,
|
|
5425
5520
|
getCookie,
|
|
5426
5521
|
getCrypto,
|
|
@@ -5437,6 +5532,7 @@ export {
|
|
|
5437
5532
|
hmacSha256,
|
|
5438
5533
|
idFromString,
|
|
5439
5534
|
inferMimeType,
|
|
5535
|
+
isAbsolute,
|
|
5440
5536
|
isAsymmetricKeyData,
|
|
5441
5537
|
isBrowser,
|
|
5442
5538
|
isDebug,
|
|
@@ -5477,6 +5573,7 @@ export {
|
|
|
5477
5573
|
parseUriTemplate,
|
|
5478
5574
|
join as pathJoin,
|
|
5479
5575
|
resolve as pathResolve,
|
|
5576
|
+
pemToPublicJwk2 as pemToPublicJwk,
|
|
5480
5577
|
processPlatformToolCalls,
|
|
5481
5578
|
randomBytes,
|
|
5482
5579
|
randomUUID,
|
|
@@ -5485,11 +5582,14 @@ export {
|
|
|
5485
5582
|
readFileSync,
|
|
5486
5583
|
readJSON,
|
|
5487
5584
|
readdir,
|
|
5585
|
+
realpath,
|
|
5488
5586
|
rename,
|
|
5489
5587
|
resetRuntimeContext,
|
|
5490
5588
|
resolveSecretPath,
|
|
5491
5589
|
rm,
|
|
5590
|
+
rsaSignBase64Url2 as rsaSignBase64Url,
|
|
5492
5591
|
rsaVerify2 as rsaVerify,
|
|
5592
|
+
rsaVerifySync2 as rsaVerifySync,
|
|
5493
5593
|
runCmd,
|
|
5494
5594
|
safeExec,
|
|
5495
5595
|
safeJsonForScript,
|
|
@@ -5513,6 +5613,7 @@ export {
|
|
|
5513
5613
|
splitWords,
|
|
5514
5614
|
stat,
|
|
5515
5615
|
supportsAnsi,
|
|
5616
|
+
symlink,
|
|
5516
5617
|
timingSafeEqual,
|
|
5517
5618
|
toCase,
|
|
5518
5619
|
trimBoth,
|
package/fs/fs.d.ts
CHANGED
|
@@ -160,6 +160,35 @@ export declare function ensureDir(p: string): Promise<void>;
|
|
|
160
160
|
* if (stats.isDirectory()) { ... }
|
|
161
161
|
*/
|
|
162
162
|
export declare function stat(p: string): Promise<import('fs').Stats>;
|
|
163
|
+
/**
|
|
164
|
+
* Create a symbolic link at `linkPath` pointing to `target`.
|
|
165
|
+
*
|
|
166
|
+
* **Node.js only** - throws an error if called in browser.
|
|
167
|
+
*
|
|
168
|
+
* @param target - Path the symlink should point to
|
|
169
|
+
* @param linkPath - Where to create the symlink
|
|
170
|
+
*
|
|
171
|
+
* @example
|
|
172
|
+
* await symlink('/etc/hosts', '/tmp/hosts-link');
|
|
173
|
+
*/
|
|
174
|
+
export declare function symlink(target: string, linkPath: string): Promise<void>;
|
|
175
|
+
/**
|
|
176
|
+
* Resolve a path, following symbolic links to their final target.
|
|
177
|
+
*
|
|
178
|
+
* **Node.js only** - throws an error if called in browser.
|
|
179
|
+
*
|
|
180
|
+
* Unlike `pathResolve`, this returns the canonical path with symlinks
|
|
181
|
+
* resolved, which is what callers need when validating that a path stays
|
|
182
|
+
* inside a trusted root (`startsWith` checks on `pathResolve` are
|
|
183
|
+
* symlink-bypassable).
|
|
184
|
+
*
|
|
185
|
+
* @param p - Path to resolve
|
|
186
|
+
* @returns Canonical absolute path with symlinks resolved
|
|
187
|
+
*
|
|
188
|
+
* @example
|
|
189
|
+
* const real = await realpath('/var/log/app.log');
|
|
190
|
+
*/
|
|
191
|
+
export declare function realpath(p: string): Promise<string>;
|
|
163
192
|
/**
|
|
164
193
|
* Copy a file.
|
|
165
194
|
*
|
package/fs/index.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, rm, mkdtemp, access, fileExists, readJSON, writeJSON, ensureDir, isDirEmpty, runCmd, } from './fs';
|
|
1
|
+
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, isDirEmpty, runCmd, } from './fs';
|
package/index.d.ts
CHANGED
|
@@ -9,14 +9,14 @@ export { splitWords, toCase, sepFor, shortHash, ensureMaxLen, idFromString } fro
|
|
|
9
9
|
export type { NameCase } from './naming';
|
|
10
10
|
export { isValidMcpUri, extractUriScheme, isValidMcpUriTemplate, parseUriTemplate, matchUriTemplate, expandUriTemplate, extractTemplateParams, isUriTemplate, } from './uri';
|
|
11
11
|
export type { ParsedUriTemplate } from './uri';
|
|
12
|
-
export { trimSlashes, joinPath, pathResolve, pathJoin, basename, dirname, extname } from './path';
|
|
12
|
+
export { trimSlashes, joinPath, pathResolve, pathJoin, basename, dirname, extname, isAbsolute } from './path';
|
|
13
13
|
export { sanitizeToJson, inferMimeType, findNonFiniteNumber } from './content';
|
|
14
14
|
export { validateBaseUrl, buildSetCookie, parseCookies, getCookie, isLocalhost, isSecureRequest } from './http';
|
|
15
15
|
export type { CookieOptions, SecureDetectionRequest } from './http';
|
|
16
|
-
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, rm, mkdtemp, access, fileExists, readJSON, writeJSON, ensureDir, isDirEmpty, runCmd, } from './fs';
|
|
16
|
+
export { readFile, readFileSync, readFileBuffer, writeFile, mkdir, rename, unlink, stat, copyFile, cp, readdir, realpath, rm, mkdtemp, symlink, access, fileExists, readJSON, writeJSON, ensureDir, isDirEmpty, runCmd, } from './fs';
|
|
17
17
|
export { escapeHtml, escapeHtmlAttr, escapeJsString, escapeScriptClose, safeJsonForScript } from './escape';
|
|
18
18
|
export { safeStringify } from './serialization';
|
|
19
|
-
export { getCrypto, rsaVerify, 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';
|
|
19
|
+
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';
|
|
20
20
|
export type { CryptoProvider, EncBlob, EncryptedBlob } from './crypto';
|
|
21
21
|
export { AsyncLocalStorage } from './async-context';
|
|
22
22
|
export { EventEmitter } from './event-emitter';
|
package/index.js
CHANGED
|
@@ -128,6 +128,14 @@ async function stat(p) {
|
|
|
128
128
|
const fsp = getFsp();
|
|
129
129
|
return fsp.stat(p);
|
|
130
130
|
}
|
|
131
|
+
async function symlink(target, linkPath) {
|
|
132
|
+
const fsp = getFsp();
|
|
133
|
+
await fsp.symlink(target, linkPath);
|
|
134
|
+
}
|
|
135
|
+
async function realpath(p) {
|
|
136
|
+
const fsp = getFsp();
|
|
137
|
+
return fsp.realpath(p);
|
|
138
|
+
}
|
|
131
139
|
async function copyFile(src, dest) {
|
|
132
140
|
const fsp = getFsp();
|
|
133
141
|
await fsp.copyFile(src, dest);
|
|
@@ -2486,8 +2494,11 @@ __export(node_exports, {
|
|
|
2486
2494
|
isRsaPssAlg: () => isRsaPssAlg,
|
|
2487
2495
|
jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
|
|
2488
2496
|
nodeCrypto: () => nodeCrypto,
|
|
2497
|
+
pemToPublicJwk: () => pemToPublicJwk,
|
|
2489
2498
|
rsaSign: () => rsaSign,
|
|
2490
|
-
|
|
2499
|
+
rsaSignBase64Url: () => rsaSignBase64Url,
|
|
2500
|
+
rsaVerify: () => rsaVerify,
|
|
2501
|
+
rsaVerifySync: () => rsaVerifySync
|
|
2491
2502
|
});
|
|
2492
2503
|
function toUint8Array(buf) {
|
|
2493
2504
|
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
@@ -2527,6 +2538,39 @@ function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
|
2527
2538
|
} : publicKey;
|
|
2528
2539
|
return import_node_crypto.default.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
2529
2540
|
}
|
|
2541
|
+
function rsaSignBase64Url(jwtAlg, data, privateJwk) {
|
|
2542
|
+
const privateKey = import_node_crypto.default.createPrivateKey({ key: privateJwk, format: "jwk" });
|
|
2543
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2544
|
+
const buf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2545
|
+
const sig = isRsaPssAlg(jwtAlg) ? rsaSign(nodeAlgorithm, buf, privateKey, {
|
|
2546
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2547
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2548
|
+
}) : rsaSign(nodeAlgorithm, buf, privateKey);
|
|
2549
|
+
return sig.toString("base64url");
|
|
2550
|
+
}
|
|
2551
|
+
function rsaVerifySync(jwtAlg, data, publicJwk, signature) {
|
|
2552
|
+
try {
|
|
2553
|
+
const publicKey = import_node_crypto.default.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
2554
|
+
const dataBuf = Buffer.isBuffer(data) ? data : Buffer.from(data);
|
|
2555
|
+
const sigBuf = Buffer.isBuffer(signature) ? signature : Buffer.from(signature);
|
|
2556
|
+
if (jwtAlg === "EdDSA") {
|
|
2557
|
+
return import_node_crypto.default.verify(null, dataBuf, publicKey, sigBuf);
|
|
2558
|
+
}
|
|
2559
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
2560
|
+
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
2561
|
+
key: publicKey,
|
|
2562
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
2563
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
2564
|
+
} : publicKey;
|
|
2565
|
+
return import_node_crypto.default.verify(nodeAlgorithm, dataBuf, verifyKey, sigBuf);
|
|
2566
|
+
} catch {
|
|
2567
|
+
return false;
|
|
2568
|
+
}
|
|
2569
|
+
}
|
|
2570
|
+
function pemToPublicJwk(pem) {
|
|
2571
|
+
const key = import_node_crypto.default.createPublicKey({ key: pem, format: "pem" });
|
|
2572
|
+
return key.export({ format: "jwk" });
|
|
2573
|
+
}
|
|
2530
2574
|
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
2531
2575
|
const header = { alg, typ: "JWT", kid };
|
|
2532
2576
|
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
@@ -2737,6 +2781,30 @@ function rsaVerify2(jwtAlg, data, publicJwk, signature) {
|
|
|
2737
2781
|
const { rsaVerifyBrowser: rsaVerifyBrowser2 } = (init_browser(), __toCommonJS(browser_exports));
|
|
2738
2782
|
return rsaVerifyBrowser2(jwtAlg, data, publicJwk, signature);
|
|
2739
2783
|
}
|
|
2784
|
+
function rsaSignBase64Url2(jwtAlg, data, privateJwk) {
|
|
2785
|
+
if (!isNode()) {
|
|
2786
|
+
throw new Error("rsaSignBase64Url is only available in Node.js runtimes");
|
|
2787
|
+
}
|
|
2788
|
+
return (init_node(), __toCommonJS(node_exports)).rsaSignBase64Url(jwtAlg, data, privateJwk);
|
|
2789
|
+
}
|
|
2790
|
+
function rsaVerifySync2(jwtAlg, data, publicJwk, signature) {
|
|
2791
|
+
if (!isNode()) {
|
|
2792
|
+
throw new Error("rsaVerifySync is only available in Node.js runtimes; use the async rsaVerify in browsers");
|
|
2793
|
+
}
|
|
2794
|
+
return (init_node(), __toCommonJS(node_exports)).rsaVerifySync(jwtAlg, data, publicJwk, signature);
|
|
2795
|
+
}
|
|
2796
|
+
function pemToPublicJwk2(pem) {
|
|
2797
|
+
if (!isNode()) {
|
|
2798
|
+
throw new Error("pemToPublicJwk is only available in Node.js runtimes");
|
|
2799
|
+
}
|
|
2800
|
+
return (init_node(), __toCommonJS(node_exports)).pemToPublicJwk(pem);
|
|
2801
|
+
}
|
|
2802
|
+
function generateRsaKeyPair2(modulusLength, alg) {
|
|
2803
|
+
if (!isNode()) {
|
|
2804
|
+
throw new Error("generateRsaKeyPair is only available in Node.js runtimes");
|
|
2805
|
+
}
|
|
2806
|
+
return (init_node(), __toCommonJS(node_exports)).generateRsaKeyPair(modulusLength, alg);
|
|
2807
|
+
}
|
|
2740
2808
|
function randomUUID() {
|
|
2741
2809
|
return getCrypto().randomUUID();
|
|
2742
2810
|
}
|
|
@@ -2845,8 +2913,8 @@ var import_crypto_provider2, HKDF_SHA256_MAX_LENGTH;
|
|
|
2845
2913
|
var init_crypto = __esm({
|
|
2846
2914
|
"libs/utils/src/crypto/index.ts"() {
|
|
2847
2915
|
"use strict";
|
|
2848
|
-
init_runtime();
|
|
2849
2916
|
import_crypto_provider2 = require("#crypto-provider");
|
|
2917
|
+
init_runtime();
|
|
2850
2918
|
init_jwt_alg();
|
|
2851
2919
|
init_runtime();
|
|
2852
2920
|
init_encrypted_blob();
|
|
@@ -3809,6 +3877,7 @@ __export(index_exports, {
|
|
|
3809
3877
|
generateCodeChallenge: () => generateCodeChallenge,
|
|
3810
3878
|
generateCodeVerifier: () => generateCodeVerifier,
|
|
3811
3879
|
generatePkcePair: () => generatePkcePair,
|
|
3880
|
+
generateRsaKeyPair: () => generateRsaKeyPair2,
|
|
3812
3881
|
generateSecret: () => generateSecret,
|
|
3813
3882
|
getCookie: () => getCookie,
|
|
3814
3883
|
getCrypto: () => getCrypto,
|
|
@@ -3825,6 +3894,7 @@ __export(index_exports, {
|
|
|
3825
3894
|
hmacSha256: () => hmacSha256,
|
|
3826
3895
|
idFromString: () => idFromString,
|
|
3827
3896
|
inferMimeType: () => inferMimeType,
|
|
3897
|
+
isAbsolute: () => import_path.isAbsolute,
|
|
3828
3898
|
isAsymmetricKeyData: () => isAsymmetricKeyData,
|
|
3829
3899
|
isBrowser: () => isBrowser,
|
|
3830
3900
|
isDebug: () => import_env3.isDebug,
|
|
@@ -3865,6 +3935,7 @@ __export(index_exports, {
|
|
|
3865
3935
|
parseUriTemplate: () => parseUriTemplate,
|
|
3866
3936
|
pathJoin: () => import_path.join,
|
|
3867
3937
|
pathResolve: () => import_path.resolve,
|
|
3938
|
+
pemToPublicJwk: () => pemToPublicJwk2,
|
|
3868
3939
|
processPlatformToolCalls: () => processPlatformToolCalls,
|
|
3869
3940
|
randomBytes: () => randomBytes,
|
|
3870
3941
|
randomUUID: () => randomUUID,
|
|
@@ -3873,11 +3944,14 @@ __export(index_exports, {
|
|
|
3873
3944
|
readFileSync: () => readFileSync,
|
|
3874
3945
|
readJSON: () => readJSON,
|
|
3875
3946
|
readdir: () => readdir,
|
|
3947
|
+
realpath: () => realpath,
|
|
3876
3948
|
rename: () => rename,
|
|
3877
3949
|
resetRuntimeContext: () => resetRuntimeContext,
|
|
3878
3950
|
resolveSecretPath: () => resolveSecretPath,
|
|
3879
3951
|
rm: () => rm,
|
|
3952
|
+
rsaSignBase64Url: () => rsaSignBase64Url2,
|
|
3880
3953
|
rsaVerify: () => rsaVerify2,
|
|
3954
|
+
rsaVerifySync: () => rsaVerifySync2,
|
|
3881
3955
|
runCmd: () => runCmd,
|
|
3882
3956
|
safeExec: () => safeExec,
|
|
3883
3957
|
safeJsonForScript: () => safeJsonForScript,
|
|
@@ -3901,6 +3975,7 @@ __export(index_exports, {
|
|
|
3901
3975
|
splitWords: () => splitWords,
|
|
3902
3976
|
stat: () => stat,
|
|
3903
3977
|
supportsAnsi: () => import_env3.supportsAnsi,
|
|
3978
|
+
symlink: () => symlink,
|
|
3904
3979
|
timingSafeEqual: () => timingSafeEqual,
|
|
3905
3980
|
toCase: () => toCase,
|
|
3906
3981
|
trimBoth: () => trimBoth,
|
|
@@ -4249,19 +4324,26 @@ function parseUriTemplate(template) {
|
|
|
4249
4324
|
throw new Error("URI template has too many parameters (max 50)");
|
|
4250
4325
|
}
|
|
4251
4326
|
const paramNames = [];
|
|
4252
|
-
|
|
4253
|
-
|
|
4254
|
-
|
|
4255
|
-
|
|
4256
|
-
|
|
4257
|
-
|
|
4258
|
-
|
|
4259
|
-
|
|
4327
|
+
const placeholder = /\{([^{}]+)\}/g;
|
|
4328
|
+
let regexStr = "";
|
|
4329
|
+
let lastIndex = 0;
|
|
4330
|
+
for (let m = placeholder.exec(template); m !== null; m = placeholder.exec(template)) {
|
|
4331
|
+
regexStr += escapeRegex(template.slice(lastIndex, m.index));
|
|
4332
|
+
const raw = m[1];
|
|
4333
|
+
const reserved = raw.startsWith("+");
|
|
4334
|
+
paramNames.push(reserved ? raw.slice(1) : raw);
|
|
4335
|
+
regexStr += reserved ? "(.+?)" : "([^/]+)";
|
|
4336
|
+
lastIndex = m.index + m[0].length;
|
|
4337
|
+
}
|
|
4338
|
+
regexStr += escapeRegex(template.slice(lastIndex));
|
|
4260
4339
|
return {
|
|
4261
4340
|
pattern: new RegExp(`^${regexStr}$`),
|
|
4262
4341
|
paramNames
|
|
4263
4342
|
};
|
|
4264
4343
|
}
|
|
4344
|
+
function escapeRegex(literal) {
|
|
4345
|
+
return literal.replace(/[.*+?^${}()|[\]\\]/g, (c) => `\\${c}`);
|
|
4346
|
+
}
|
|
4265
4347
|
function matchUriTemplate(template, uri) {
|
|
4266
4348
|
const { pattern, paramNames } = parseUriTemplate(template);
|
|
4267
4349
|
const match = uri.match(pattern);
|
|
@@ -4273,18 +4355,37 @@ function matchUriTemplate(template, uri) {
|
|
|
4273
4355
|
return params;
|
|
4274
4356
|
}
|
|
4275
4357
|
function expandUriTemplate(template, params) {
|
|
4276
|
-
return template.replace(/\{([^{}]+)\}/g, (_,
|
|
4358
|
+
return template.replace(/\{([^{}]+)\}/g, (_, raw) => {
|
|
4359
|
+
const reserved = raw.startsWith("+");
|
|
4360
|
+
const paramName = reserved ? raw.slice(1) : raw;
|
|
4277
4361
|
const value = params[paramName];
|
|
4278
4362
|
if (value === void 0) {
|
|
4279
4363
|
throw new Error(`Missing parameter '${paramName}' for URI template '${template}'`);
|
|
4280
4364
|
}
|
|
4281
|
-
return encodeURIComponent(value);
|
|
4365
|
+
return reserved ? encodeReserved(value) : encodeURIComponent(value);
|
|
4282
4366
|
});
|
|
4283
4367
|
}
|
|
4368
|
+
function encodeReserved(value) {
|
|
4369
|
+
const decoded = safeDecode(value);
|
|
4370
|
+
return decoded.replace(/[^A-Za-z0-9\-._~:/?#[\]@!$&'()*+,;=]/g, (c) => encodeURIComponent(c));
|
|
4371
|
+
}
|
|
4372
|
+
function safeDecode(value) {
|
|
4373
|
+
try {
|
|
4374
|
+
return decodeURIComponent(value);
|
|
4375
|
+
} catch {
|
|
4376
|
+
return value.replace(/%[0-9A-Fa-f]{2}/g, (triplet) => {
|
|
4377
|
+
try {
|
|
4378
|
+
return decodeURIComponent(triplet);
|
|
4379
|
+
} catch {
|
|
4380
|
+
return triplet;
|
|
4381
|
+
}
|
|
4382
|
+
});
|
|
4383
|
+
}
|
|
4384
|
+
}
|
|
4284
4385
|
function extractTemplateParams(template) {
|
|
4285
4386
|
const params = [];
|
|
4286
|
-
template.replace(/\{([^{}]+)\}/g, (_,
|
|
4287
|
-
params.push(
|
|
4387
|
+
template.replace(/\{([^{}]+)\}/g, (_, raw) => {
|
|
4388
|
+
params.push(raw.startsWith("+") ? raw.slice(1) : raw);
|
|
4288
4389
|
return "";
|
|
4289
4390
|
});
|
|
4290
4391
|
return params;
|
|
@@ -5624,6 +5725,7 @@ function setMachineIdOverride(id) {
|
|
|
5624
5725
|
generateCodeChallenge,
|
|
5625
5726
|
generateCodeVerifier,
|
|
5626
5727
|
generatePkcePair,
|
|
5728
|
+
generateRsaKeyPair,
|
|
5627
5729
|
generateSecret,
|
|
5628
5730
|
getCookie,
|
|
5629
5731
|
getCrypto,
|
|
@@ -5640,6 +5742,7 @@ function setMachineIdOverride(id) {
|
|
|
5640
5742
|
hmacSha256,
|
|
5641
5743
|
idFromString,
|
|
5642
5744
|
inferMimeType,
|
|
5745
|
+
isAbsolute,
|
|
5643
5746
|
isAsymmetricKeyData,
|
|
5644
5747
|
isBrowser,
|
|
5645
5748
|
isDebug,
|
|
@@ -5680,6 +5783,7 @@ function setMachineIdOverride(id) {
|
|
|
5680
5783
|
parseUriTemplate,
|
|
5681
5784
|
pathJoin,
|
|
5682
5785
|
pathResolve,
|
|
5786
|
+
pemToPublicJwk,
|
|
5683
5787
|
processPlatformToolCalls,
|
|
5684
5788
|
randomBytes,
|
|
5685
5789
|
randomUUID,
|
|
@@ -5688,11 +5792,14 @@ function setMachineIdOverride(id) {
|
|
|
5688
5792
|
readFileSync,
|
|
5689
5793
|
readJSON,
|
|
5690
5794
|
readdir,
|
|
5795
|
+
realpath,
|
|
5691
5796
|
rename,
|
|
5692
5797
|
resetRuntimeContext,
|
|
5693
5798
|
resolveSecretPath,
|
|
5694
5799
|
rm,
|
|
5800
|
+
rsaSignBase64Url,
|
|
5695
5801
|
rsaVerify,
|
|
5802
|
+
rsaVerifySync,
|
|
5696
5803
|
runCmd,
|
|
5697
5804
|
safeExec,
|
|
5698
5805
|
safeJsonForScript,
|
|
@@ -5716,6 +5823,7 @@ function setMachineIdOverride(id) {
|
|
|
5716
5823
|
splitWords,
|
|
5717
5824
|
stat,
|
|
5718
5825
|
supportsAnsi,
|
|
5826
|
+
symlink,
|
|
5719
5827
|
timingSafeEqual,
|
|
5720
5828
|
toCase,
|
|
5721
5829
|
trimBoth,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@frontmcp/utils",
|
|
3
|
-
"version": "1.
|
|
3
|
+
"version": "1.2.0",
|
|
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",
|
|
@@ -34,7 +34,7 @@
|
|
|
34
34
|
"peerDependencies": {
|
|
35
35
|
"@vercel/kv": "^2.0.0 || ^3.0.0",
|
|
36
36
|
"ioredis": "^5.0.0",
|
|
37
|
-
"@frontmcp/lazy-zod": "1.
|
|
37
|
+
"@frontmcp/lazy-zod": "1.2.0"
|
|
38
38
|
},
|
|
39
39
|
"peerDependenciesMeta": {
|
|
40
40
|
"@vercel/kv": {
|
package/path/browser-path.d.ts
CHANGED
|
@@ -3,3 +3,4 @@ export declare function join(..._segments: string[]): string;
|
|
|
3
3
|
export declare function basename(p: string, ext?: string): string;
|
|
4
4
|
export declare function dirname(_p: string): string;
|
|
5
5
|
export declare function extname(p: string): string;
|
|
6
|
+
export declare function isAbsolute(p: string): boolean;
|
package/path/index.d.ts
CHANGED
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export { trimSlashes, joinPath } from './path';
|
|
2
|
-
export { resolve as pathResolve, join as pathJoin, basename, dirname, extname } from '#path';
|
|
2
|
+
export { resolve as pathResolve, join as pathJoin, basename, dirname, extname, isAbsolute } from '#path';
|
package/path/node-path.d.ts
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
export { resolve, join, basename, dirname, extname } from 'path';
|
|
1
|
+
export { resolve, join, basename, dirname, extname, isAbsolute } from 'path';
|
package/uri/uri-template.d.ts
CHANGED
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
/**
|
|
2
|
-
* RFC 6570
|
|
3
|
-
*
|
|
4
|
-
*
|
|
5
|
-
* string
|
|
6
|
-
*
|
|
2
|
+
* RFC 6570 URI Template utilities.
|
|
3
|
+
*
|
|
4
|
+
* Implements:
|
|
5
|
+
* - Level 1 simple string expansion (`{var}`) — value is percent-encoded,
|
|
6
|
+
* stops at `/`.
|
|
7
|
+
* - Level 2 reserved expansion (`{+var}`) — value passes reserved characters
|
|
8
|
+
* (including `/`) through unencoded, so a single template variable can
|
|
9
|
+
* span multiple path segments (e.g. `skill://{+skillPath}/SKILL.md`
|
|
10
|
+
* matches `skill://acme/billing/refunds/SKILL.md`).
|
|
11
|
+
*
|
|
12
|
+
* Other RFC 6570 operators (`{#frag}`, `{?query}`, `{&qcont}`, `{;path}`,
|
|
13
|
+
* `{.label}`, `{/path}`) are not supported.
|
|
7
14
|
*/
|
|
8
15
|
/**
|
|
9
16
|
* Parsed URI template information.
|
|
@@ -15,8 +22,8 @@ export interface ParsedUriTemplate {
|
|
|
15
22
|
paramNames: string[];
|
|
16
23
|
}
|
|
17
24
|
/**
|
|
18
|
-
* Parse a URI template (RFC 6570 Level 1) into a regex
|
|
19
|
-
*
|
|
25
|
+
* Parse a URI template (RFC 6570 Level 1 + reserved expansion) into a regex
|
|
26
|
+
* pattern and parameter names.
|
|
20
27
|
*
|
|
21
28
|
* @param template - The URI template to parse
|
|
22
29
|
* @returns Parsed template with pattern and parameter names
|
|
@@ -28,6 +35,9 @@ export interface ParsedUriTemplate {
|
|
|
28
35
|
*
|
|
29
36
|
* parseUriTemplate("users/{userId}/posts/{postId}")
|
|
30
37
|
* // { pattern: /^users\/([^/]+)\/posts\/([^/]+)$/, paramNames: ["userId", "postId"] }
|
|
38
|
+
*
|
|
39
|
+
* parseUriTemplate("skill://{+skillPath}/SKILL.md")
|
|
40
|
+
* // { pattern: /^skill:\/\/(.+?)\/SKILL\.md$/, paramNames: ["skillPath"] }
|
|
31
41
|
*/
|
|
32
42
|
export declare function parseUriTemplate(template: string): ParsedUriTemplate;
|
|
33
43
|
/**
|
|
@@ -52,12 +62,19 @@ export declare function matchUriTemplate(template: string, uri: string): Record<
|
|
|
52
62
|
/**
|
|
53
63
|
* Expand a URI template with the given parameters.
|
|
54
64
|
*
|
|
55
|
-
*
|
|
56
|
-
* `
|
|
65
|
+
* Encoding depends on the operator:
|
|
66
|
+
* - `{var}` (simple expansion): value is percent-encoded via
|
|
67
|
+
* `encodeURIComponent()` so `/`, `:`, etc. become `%2F`, `%3A`.
|
|
68
|
+
* - `{+var}` (reserved expansion): unreserved + reserved characters
|
|
69
|
+
* (per RFC 3986) pass through unencoded — only characters outside
|
|
70
|
+
* that set are percent-encoded. This lets a single variable carry
|
|
71
|
+
* a multi-segment path.
|
|
72
|
+
*
|
|
73
|
+
* Use {@link matchUriTemplate} to decode them back.
|
|
57
74
|
*
|
|
58
75
|
* @param template - The URI template
|
|
59
76
|
* @param params - Object with parameter values (raw, unencoded)
|
|
60
|
-
* @returns Expanded URI with parameters
|
|
77
|
+
* @returns Expanded URI with parameters substituted (encoding depends on operator)
|
|
61
78
|
* @throws Error if a required parameter is missing
|
|
62
79
|
*
|
|
63
80
|
* @example
|
|
@@ -67,9 +84,13 @@ export declare function matchUriTemplate(template: string, uri: string): Record<
|
|
|
67
84
|
* expandUriTemplate("users/{userId}/posts/{postId}", { userId: "123", postId: "456" })
|
|
68
85
|
* // "users/123/posts/456"
|
|
69
86
|
*
|
|
70
|
-
* //
|
|
87
|
+
* // Simple expansion percent-encodes reserved chars:
|
|
71
88
|
* expandUriTemplate("notes://{id}", { id: "x-coredata://ABC/Note/1" })
|
|
72
89
|
* // "notes://x-coredata%3A%2F%2FABC%2FNote%2F1"
|
|
90
|
+
*
|
|
91
|
+
* // Reserved expansion preserves them:
|
|
92
|
+
* expandUriTemplate("skill://{+skillPath}/SKILL.md", { skillPath: "acme/billing" })
|
|
93
|
+
* // "skill://acme/billing/SKILL.md"
|
|
73
94
|
*/
|
|
74
95
|
export declare function expandUriTemplate(template: string, params: Record<string, string>): string;
|
|
75
96
|
/**
|
package/CHANGELOG.md
DELETED
|
@@ -1,12 +0,0 @@
|
|
|
1
|
-
# Changelog
|
|
2
|
-
|
|
3
|
-
## 0.0.1
|
|
4
|
-
|
|
5
|
-
- Initial release
|
|
6
|
-
- Extracted utilities from @frontmcp/sdk, @frontmcp/cli, and @frontmcp/adapters
|
|
7
|
-
- Added naming utilities: splitWords, toCase, sepFor, shortHash, ensureMaxLen, idFromString
|
|
8
|
-
- Added URI utilities: isValidMcpUri, extractUriScheme, isValidMcpUriTemplate, parseUriTemplate, matchUriTemplate, expandUriTemplate, extractTemplateParams, isUriTemplate
|
|
9
|
-
- Added path utilities: trimSlashes, joinPath
|
|
10
|
-
- Added content utilities: sanitizeToJson, inferMimeType
|
|
11
|
-
- Added HTTP utilities: validateBaseUrl
|
|
12
|
-
- Added FS utilities: fileExists, readJSON, writeJSON, ensureDir, isDirEmpty, runCmd
|