@frontmcp/utils 0.12.2 → 1.0.0-beta.10
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/async-context/browser-async-context.d.ts +12 -0
- package/async-context/browser-async-context.js +49 -0
- package/async-context/index.d.ts +1 -0
- package/async-context/node-async-context.d.ts +1 -0
- package/async-context/node-async-context.js +30 -0
- package/crypto/browser.d.ts +16 -0
- package/crypto/browser.js +160 -0
- package/crypto/index.d.ts +15 -6
- package/crypto/jwt-alg.d.ts +5 -0
- package/crypto/key-persistence/factory.d.ts +8 -1
- package/crypto/key-persistence/types.d.ts +10 -2
- package/crypto/node.d.ts +2 -0
- package/crypto/node.js +185 -0
- package/env/browser-env.d.ts +17 -0
- package/env/browser-env.js +78 -0
- package/env/index.d.ts +1 -0
- package/env/node-env.d.ts +14 -0
- package/env/node-env.js +85 -0
- package/esm/async-context/browser-async-context.mjs +24 -0
- package/esm/async-context/node-async-context.mjs +5 -0
- package/esm/crypto/browser.mjs +131 -0
- package/esm/crypto/node.mjs +143 -0
- package/esm/env/browser-env.mjs +44 -0
- package/esm/env/node-env.mjs +51 -0
- package/esm/event-emitter/browser-event-emitter.mjs +49 -0
- package/esm/event-emitter/node-event-emitter.mjs +5 -0
- package/esm/index.mjs +3887 -3064
- package/event-emitter/browser-event-emitter.d.ts +19 -0
- package/event-emitter/browser-event-emitter.js +74 -0
- package/event-emitter/index.d.ts +1 -0
- package/event-emitter/node-event-emitter.d.ts +1 -0
- package/event-emitter/node-event-emitter.js +30 -0
- package/index.d.ts +14 -5
- package/index.js +4144 -3314
- package/llm/index.d.ts +2 -0
- package/llm/llm-tool-handler.types.d.ts +48 -0
- package/llm/llm-tool-handlers.d.ts +10 -0
- package/naming/index.d.ts +2 -1
- package/package.json +24 -2
- package/path/browser-path.d.ts +5 -0
- package/path/index.d.ts +1 -0
- package/path/node-path.d.ts +1 -0
- package/storage/adapters/index.d.ts +4 -0
- package/storage/adapters/indexeddb.d.ts +77 -0
- package/storage/adapters/localstorage.d.ts +84 -0
- package/storage/index.d.ts +2 -2
- package/uri/index.d.ts +2 -1
- package/esm/package.json +0 -69
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser polyfill for AsyncLocalStorage.
|
|
3
|
+
*
|
|
4
|
+
* Uses a simple stack-based approach, which is safe in single-threaded
|
|
5
|
+
* browser environments. Does not support `enterWith()` or `disable()`
|
|
6
|
+
* (neither is used in the FrontMCP codebase).
|
|
7
|
+
*/
|
|
8
|
+
export declare class AsyncLocalStorage<T> {
|
|
9
|
+
private stack;
|
|
10
|
+
run<R>(store: T, callback: (...args: unknown[]) => R, ...args: unknown[]): R;
|
|
11
|
+
getStore(): T | undefined;
|
|
12
|
+
}
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/async-context/browser-async-context.ts
|
|
21
|
+
var browser_async_context_exports = {};
|
|
22
|
+
__export(browser_async_context_exports, {
|
|
23
|
+
AsyncLocalStorage: () => AsyncLocalStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(browser_async_context_exports);
|
|
26
|
+
var AsyncLocalStorage = class {
|
|
27
|
+
stack = [];
|
|
28
|
+
run(store, callback, ...args) {
|
|
29
|
+
this.stack.push(store);
|
|
30
|
+
try {
|
|
31
|
+
const result = callback(...args);
|
|
32
|
+
if (result instanceof Promise) {
|
|
33
|
+
return result.finally(() => this.stack.pop());
|
|
34
|
+
}
|
|
35
|
+
this.stack.pop();
|
|
36
|
+
return result;
|
|
37
|
+
} catch (err) {
|
|
38
|
+
this.stack.pop();
|
|
39
|
+
throw err;
|
|
40
|
+
}
|
|
41
|
+
}
|
|
42
|
+
getStore() {
|
|
43
|
+
return this.stack.length > 0 ? this.stack[this.stack.length - 1] : void 0;
|
|
44
|
+
}
|
|
45
|
+
};
|
|
46
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
47
|
+
0 && (module.exports = {
|
|
48
|
+
AsyncLocalStorage
|
|
49
|
+
});
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AsyncLocalStorage } from '#async-context';
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { AsyncLocalStorage } from 'node:async_hooks';
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/async-context/node-async-context.ts
|
|
21
|
+
var node_async_context_exports = {};
|
|
22
|
+
__export(node_async_context_exports, {
|
|
23
|
+
AsyncLocalStorage: () => import_node_async_hooks.AsyncLocalStorage
|
|
24
|
+
});
|
|
25
|
+
module.exports = __toCommonJS(node_async_context_exports);
|
|
26
|
+
var import_node_async_hooks = require("node:async_hooks");
|
|
27
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
28
|
+
0 && (module.exports = {
|
|
29
|
+
AsyncLocalStorage
|
|
30
|
+
});
|
package/crypto/browser.d.ts
CHANGED
|
@@ -9,3 +9,19 @@ import type { CryptoProvider } from './types';
|
|
|
9
9
|
* Browser-compatible crypto provider using @noble libraries.
|
|
10
10
|
*/
|
|
11
11
|
export declare const browserCrypto: CryptoProvider;
|
|
12
|
+
/** Alias for conditional import resolution via `#crypto-provider`. */
|
|
13
|
+
export { browserCrypto as cryptoProvider };
|
|
14
|
+
export { isRsaPssAlg, jwtAlgToWebCryptoAlg } from './jwt-alg';
|
|
15
|
+
/**
|
|
16
|
+
* Verify an RSA signature using WebCrypto.
|
|
17
|
+
*
|
|
18
|
+
* Supports RS256/RS384/RS512 (RSASSA-PKCS1-v1_5) and PS256/PS384/PS512 (RSA-PSS).
|
|
19
|
+
* Works in both browsers and Node.js environments that provide `crypto.subtle`.
|
|
20
|
+
*
|
|
21
|
+
* @param jwtAlg - JWT algorithm identifier (e.g. 'RS256', 'PS256')
|
|
22
|
+
* @param data - The signed data (e.g. `headerB64.payloadB64`)
|
|
23
|
+
* @param publicJwk - Public key in JWK format
|
|
24
|
+
* @param signature - The signature bytes
|
|
25
|
+
* @returns true if the signature is valid
|
|
26
|
+
*/
|
|
27
|
+
export declare function rsaVerifyBrowser(jwtAlg: string, data: Uint8Array, publicJwk: JsonWebKey, signature: Uint8Array): Promise<boolean>;
|
|
@@ -0,0 +1,160 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/crypto/browser.ts
|
|
21
|
+
var browser_exports = {};
|
|
22
|
+
__export(browser_exports, {
|
|
23
|
+
browserCrypto: () => browserCrypto,
|
|
24
|
+
cryptoProvider: () => browserCrypto,
|
|
25
|
+
isRsaPssAlg: () => isRsaPssAlg,
|
|
26
|
+
jwtAlgToWebCryptoAlg: () => jwtAlgToWebCryptoAlg,
|
|
27
|
+
rsaVerifyBrowser: () => rsaVerifyBrowser
|
|
28
|
+
});
|
|
29
|
+
module.exports = __toCommonJS(browser_exports);
|
|
30
|
+
var import_sha2 = require("@noble/hashes/sha2.js");
|
|
31
|
+
var import_hmac = require("@noble/hashes/hmac.js");
|
|
32
|
+
var import_hkdf = require("@noble/hashes/hkdf.js");
|
|
33
|
+
var import_utils = require("@noble/hashes/utils.js");
|
|
34
|
+
var import_aes = require("@noble/ciphers/aes.js");
|
|
35
|
+
|
|
36
|
+
// libs/utils/src/crypto/jwt-alg.ts
|
|
37
|
+
function isRsaPssAlg(jwtAlg) {
|
|
38
|
+
return jwtAlg.startsWith("PS");
|
|
39
|
+
}
|
|
40
|
+
var JWT_ALG_TO_WEB_CRYPTO = {
|
|
41
|
+
RS256: "SHA-256",
|
|
42
|
+
RS384: "SHA-384",
|
|
43
|
+
RS512: "SHA-512",
|
|
44
|
+
PS256: "SHA-256",
|
|
45
|
+
PS384: "SHA-384",
|
|
46
|
+
PS512: "SHA-512"
|
|
47
|
+
};
|
|
48
|
+
function jwtAlgToWebCryptoAlg(jwtAlg) {
|
|
49
|
+
const webAlg = JWT_ALG_TO_WEB_CRYPTO[jwtAlg];
|
|
50
|
+
if (!webAlg) {
|
|
51
|
+
throw new Error(`Unsupported JWT algorithm for WebCrypto: ${jwtAlg}`);
|
|
52
|
+
}
|
|
53
|
+
return webAlg;
|
|
54
|
+
}
|
|
55
|
+
|
|
56
|
+
// libs/utils/src/crypto/browser.ts
|
|
57
|
+
function toBytes(data) {
|
|
58
|
+
if (typeof data === "string") {
|
|
59
|
+
return new TextEncoder().encode(data);
|
|
60
|
+
}
|
|
61
|
+
return data;
|
|
62
|
+
}
|
|
63
|
+
function toHex(bytes) {
|
|
64
|
+
return Array.from(bytes).map((b) => b.toString(16).padStart(2, "0")).join("");
|
|
65
|
+
}
|
|
66
|
+
function generateUUID() {
|
|
67
|
+
if (typeof crypto !== "undefined" && typeof crypto.randomUUID === "function") {
|
|
68
|
+
return crypto.randomUUID();
|
|
69
|
+
}
|
|
70
|
+
const bytes = (0, import_utils.randomBytes)(16);
|
|
71
|
+
bytes[6] = bytes[6] & 15 | 64;
|
|
72
|
+
bytes[8] = bytes[8] & 63 | 128;
|
|
73
|
+
const hex = toHex(bytes);
|
|
74
|
+
return `${hex.slice(0, 8)}-${hex.slice(8, 12)}-${hex.slice(12, 16)}-${hex.slice(16, 20)}-${hex.slice(20)}`;
|
|
75
|
+
}
|
|
76
|
+
function constantTimeEqual(a, b) {
|
|
77
|
+
if (a.length !== b.length) return false;
|
|
78
|
+
let result = 0;
|
|
79
|
+
for (let i = 0; i < a.length; i++) {
|
|
80
|
+
result |= a[i] ^ b[i];
|
|
81
|
+
}
|
|
82
|
+
return result === 0;
|
|
83
|
+
}
|
|
84
|
+
var browserCrypto = {
|
|
85
|
+
randomUUID() {
|
|
86
|
+
return generateUUID();
|
|
87
|
+
},
|
|
88
|
+
randomBytes(length) {
|
|
89
|
+
return (0, import_utils.randomBytes)(length);
|
|
90
|
+
},
|
|
91
|
+
sha256(data) {
|
|
92
|
+
return (0, import_sha2.sha256)(toBytes(data));
|
|
93
|
+
},
|
|
94
|
+
sha256Hex(data) {
|
|
95
|
+
return toHex((0, import_sha2.sha256)(toBytes(data)));
|
|
96
|
+
},
|
|
97
|
+
hmacSha256(key, data) {
|
|
98
|
+
return (0, import_hmac.hmac)(import_sha2.sha256, key, data);
|
|
99
|
+
},
|
|
100
|
+
hkdfSha256(ikm, salt, info, length) {
|
|
101
|
+
const effectiveSalt = salt.length > 0 ? salt : new Uint8Array(32);
|
|
102
|
+
return (0, import_hkdf.hkdf)(import_sha2.sha256, ikm, effectiveSalt, info, length);
|
|
103
|
+
},
|
|
104
|
+
encryptAesGcm(key, plaintext, iv) {
|
|
105
|
+
const cipher = (0, import_aes.gcm)(key, iv);
|
|
106
|
+
const sealed = cipher.encrypt(plaintext);
|
|
107
|
+
const ciphertext = sealed.slice(0, -16);
|
|
108
|
+
const tag = sealed.slice(-16);
|
|
109
|
+
return { ciphertext, tag };
|
|
110
|
+
},
|
|
111
|
+
decryptAesGcm(key, ciphertext, iv, tag) {
|
|
112
|
+
const cipher = (0, import_aes.gcm)(key, iv);
|
|
113
|
+
const sealed = new Uint8Array(ciphertext.length + tag.length);
|
|
114
|
+
sealed.set(ciphertext);
|
|
115
|
+
sealed.set(tag, ciphertext.length);
|
|
116
|
+
return cipher.decrypt(sealed);
|
|
117
|
+
},
|
|
118
|
+
timingSafeEqual(a, b) {
|
|
119
|
+
return constantTimeEqual(a, b);
|
|
120
|
+
}
|
|
121
|
+
};
|
|
122
|
+
async function rsaVerifyBrowser(jwtAlg, data, publicJwk, signature) {
|
|
123
|
+
if (typeof globalThis.crypto?.subtle === "undefined") {
|
|
124
|
+
throw new Error("WebCrypto API (crypto.subtle) is not available in this environment");
|
|
125
|
+
}
|
|
126
|
+
const webAlg = jwtAlgToWebCryptoAlg(jwtAlg);
|
|
127
|
+
const isPss = isRsaPssAlg(jwtAlg);
|
|
128
|
+
const algorithm = {
|
|
129
|
+
name: isPss ? "RSA-PSS" : "RSASSA-PKCS1-v1_5",
|
|
130
|
+
hash: { name: webAlg }
|
|
131
|
+
};
|
|
132
|
+
const key = await globalThis.crypto.subtle.importKey("jwk", publicJwk, algorithm, false, ["verify"]);
|
|
133
|
+
const verifyAlgorithm = isPss ? { name: "RSA-PSS", saltLength: getSaltLength(jwtAlg) } : { name: "RSASSA-PKCS1-v1_5" };
|
|
134
|
+
const sigBuf = new Uint8Array(signature).buffer;
|
|
135
|
+
const dataBuf = new Uint8Array(data).buffer;
|
|
136
|
+
return globalThis.crypto.subtle.verify(verifyAlgorithm, key, sigBuf, dataBuf);
|
|
137
|
+
}
|
|
138
|
+
function getSaltLength(jwtAlg) {
|
|
139
|
+
switch (jwtAlg) {
|
|
140
|
+
case "PS256":
|
|
141
|
+
return 32;
|
|
142
|
+
// SHA-256 digest length
|
|
143
|
+
case "PS384":
|
|
144
|
+
return 48;
|
|
145
|
+
// SHA-384 digest length
|
|
146
|
+
case "PS512":
|
|
147
|
+
return 64;
|
|
148
|
+
// SHA-512 digest length
|
|
149
|
+
default:
|
|
150
|
+
return 32;
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
154
|
+
0 && (module.exports = {
|
|
155
|
+
browserCrypto,
|
|
156
|
+
cryptoProvider,
|
|
157
|
+
isRsaPssAlg,
|
|
158
|
+
jwtAlgToWebCryptoAlg,
|
|
159
|
+
rsaVerifyBrowser
|
|
160
|
+
});
|
package/crypto/index.d.ts
CHANGED
|
@@ -5,16 +5,25 @@
|
|
|
5
5
|
* Uses native crypto in Node.js and @noble/hashes + @noble/ciphers in browsers.
|
|
6
6
|
*/
|
|
7
7
|
import type { CryptoProvider, EncBlob } from './types';
|
|
8
|
-
export { isRsaPssAlg, jwtAlgToNodeAlg } from './jwt-alg';
|
|
8
|
+
export { isRsaPssAlg, jwtAlgToNodeAlg, jwtAlgToWebCryptoAlg } from './jwt-alg';
|
|
9
9
|
/**
|
|
10
10
|
* Get the crypto provider for the current runtime environment.
|
|
11
|
-
*
|
|
12
|
-
*
|
|
13
|
-
* Note: this module intentionally avoids importing any Node-only crypto modules
|
|
14
|
-
* at module-load time so it can be used in browser builds without pulling them in.
|
|
11
|
+
* Resolved at build time via the `#crypto-provider` conditional import.
|
|
15
12
|
*/
|
|
16
13
|
export declare function getCrypto(): CryptoProvider;
|
|
17
|
-
|
|
14
|
+
/**
|
|
15
|
+
* Verify an RSA signature.
|
|
16
|
+
*
|
|
17
|
+
* Cross-platform: uses Node.js `crypto` module in Node environments,
|
|
18
|
+
* and WebCrypto `crypto.subtle.verify()` in browsers.
|
|
19
|
+
*
|
|
20
|
+
* @param jwtAlg - JWT algorithm identifier (e.g. 'RS256', 'PS256')
|
|
21
|
+
* @param data - The signed data bytes
|
|
22
|
+
* @param publicJwk - Public key in JWK format
|
|
23
|
+
* @param signature - The signature bytes
|
|
24
|
+
* @returns Promise resolving to true if the signature is valid
|
|
25
|
+
*/
|
|
26
|
+
export declare function rsaVerify(jwtAlg: string, data: Buffer | Uint8Array, publicJwk: JsonWebKey, signature: Buffer | Uint8Array): Promise<boolean>;
|
|
18
27
|
/**
|
|
19
28
|
* Generate a UUID v4 string.
|
|
20
29
|
*/
|
package/crypto/jwt-alg.d.ts
CHANGED
|
@@ -6,3 +6,8 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export declare function jwtAlgToNodeAlg(jwtAlg: string): string;
|
|
8
8
|
export declare function isRsaPssAlg(jwtAlg: string): boolean;
|
|
9
|
+
/**
|
|
10
|
+
* Map a JWT algorithm to a WebCrypto hash algorithm name.
|
|
11
|
+
* Used for `crypto.subtle.importKey()` and `crypto.subtle.verify()`.
|
|
12
|
+
*/
|
|
13
|
+
export declare function jwtAlgToWebCryptoAlg(jwtAlg: string): string;
|
|
@@ -13,7 +13,8 @@ import type { CreateKeyPersistenceOptions } from './types';
|
|
|
13
13
|
* Create a KeyPersistence instance with auto-detected storage.
|
|
14
14
|
*
|
|
15
15
|
* In Node.js: Uses filesystem storage at `.frontmcp/keys/` by default
|
|
16
|
-
* In browser: Uses
|
|
16
|
+
* In browser: Uses IndexedDB (persistent) with localStorage fallback
|
|
17
|
+
* Fallback: Memory storage (keys lost on restart)
|
|
17
18
|
*
|
|
18
19
|
* @param options - Configuration options
|
|
19
20
|
* @returns KeyPersistence instance (storage already connected)
|
|
@@ -26,6 +27,12 @@ import type { CreateKeyPersistenceOptions } from './types';
|
|
|
26
27
|
* // Force memory storage
|
|
27
28
|
* const memKeys = await createKeyPersistence({ type: 'memory' });
|
|
28
29
|
*
|
|
30
|
+
* // Force IndexedDB (browser)
|
|
31
|
+
* const idbKeys = await createKeyPersistence({ type: 'indexeddb' });
|
|
32
|
+
*
|
|
33
|
+
* // Force localStorage (browser)
|
|
34
|
+
* const lsKeys = await createKeyPersistence({ type: 'localstorage' });
|
|
35
|
+
*
|
|
29
36
|
* // Custom directory for filesystem
|
|
30
37
|
* const fsKeys = await createKeyPersistence({
|
|
31
38
|
* type: 'filesystem',
|
|
@@ -75,12 +75,14 @@ export interface KeyPersistenceOptions {
|
|
|
75
75
|
export interface CreateKeyPersistenceOptions {
|
|
76
76
|
/**
|
|
77
77
|
* Storage type.
|
|
78
|
-
* - 'auto': Auto-detect based on environment (filesystem in Node.js,
|
|
78
|
+
* - 'auto': Auto-detect based on environment (filesystem in Node.js, indexeddb in browser)
|
|
79
79
|
* - 'memory': Always use memory (keys lost on restart)
|
|
80
80
|
* - 'filesystem': Always use filesystem (Node.js only)
|
|
81
|
+
* - 'indexeddb': Use IndexedDB (browser only, persistent)
|
|
82
|
+
* - 'localstorage': Use localStorage (browser only, persistent, ~5MB limit)
|
|
81
83
|
* @default 'auto'
|
|
82
84
|
*/
|
|
83
|
-
type?: 'auto' | 'memory' | 'filesystem';
|
|
85
|
+
type?: 'auto' | 'memory' | 'filesystem' | 'indexeddb' | 'localstorage';
|
|
84
86
|
/**
|
|
85
87
|
* Base directory for filesystem storage.
|
|
86
88
|
* Only used when type is 'filesystem' or 'auto' in Node.js.
|
|
@@ -97,6 +99,12 @@ export interface CreateKeyPersistenceOptions {
|
|
|
97
99
|
* @default true
|
|
98
100
|
*/
|
|
99
101
|
enableCache?: boolean;
|
|
102
|
+
/**
|
|
103
|
+
* Optional 32-byte AES-256-GCM key for encrypting values at rest in localStorage.
|
|
104
|
+
* Only used when type is 'localstorage' or 'auto' with localStorage fallback.
|
|
105
|
+
* If not provided, HKDF-SHA256 derives a key from a fixed IKM using the page origin.
|
|
106
|
+
*/
|
|
107
|
+
encryptionKey?: Uint8Array;
|
|
100
108
|
}
|
|
101
109
|
/**
|
|
102
110
|
* Options for creating a secret key.
|
package/crypto/node.d.ts
CHANGED
|
@@ -10,6 +10,8 @@ export { isRsaPssAlg, jwtAlgToNodeAlg } from './jwt-alg';
|
|
|
10
10
|
* Node.js crypto provider implementation.
|
|
11
11
|
*/
|
|
12
12
|
export declare const nodeCrypto: CryptoProvider;
|
|
13
|
+
/** Alias for conditional import resolution via `#crypto-provider`. */
|
|
14
|
+
export { nodeCrypto as cryptoProvider };
|
|
13
15
|
/**
|
|
14
16
|
* RSA JWK structure for public keys
|
|
15
17
|
*/
|
package/crypto/node.js
ADDED
|
@@ -0,0 +1,185 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __create = Object.create;
|
|
3
|
+
var __defProp = Object.defineProperty;
|
|
4
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
5
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
6
|
+
var __getProtoOf = Object.getPrototypeOf;
|
|
7
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
8
|
+
var __export = (target, all) => {
|
|
9
|
+
for (var name in all)
|
|
10
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
11
|
+
};
|
|
12
|
+
var __copyProps = (to, from, except, desc) => {
|
|
13
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
14
|
+
for (let key of __getOwnPropNames(from))
|
|
15
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
16
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
17
|
+
}
|
|
18
|
+
return to;
|
|
19
|
+
};
|
|
20
|
+
var __toESM = (mod, isNodeMode, target) => (target = mod != null ? __create(__getProtoOf(mod)) : {}, __copyProps(
|
|
21
|
+
// If the importer is in node compatibility mode or this is not an ESM
|
|
22
|
+
// file that has been converted to a CommonJS file using a Babel-
|
|
23
|
+
// compatible transform (i.e. "__esModule" has not been set), then set
|
|
24
|
+
// "default" to the CommonJS "module.exports" for node compatibility.
|
|
25
|
+
isNodeMode || !mod || !mod.__esModule ? __defProp(target, "default", { value: mod, enumerable: true }) : target,
|
|
26
|
+
mod
|
|
27
|
+
));
|
|
28
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
29
|
+
|
|
30
|
+
// libs/utils/src/crypto/node.ts
|
|
31
|
+
var node_exports = {};
|
|
32
|
+
__export(node_exports, {
|
|
33
|
+
createSignedJwt: () => createSignedJwt,
|
|
34
|
+
cryptoProvider: () => nodeCrypto,
|
|
35
|
+
generateRsaKeyPair: () => generateRsaKeyPair,
|
|
36
|
+
isRsaPssAlg: () => isRsaPssAlg,
|
|
37
|
+
jwtAlgToNodeAlg: () => jwtAlgToNodeAlg,
|
|
38
|
+
nodeCrypto: () => nodeCrypto,
|
|
39
|
+
rsaSign: () => rsaSign,
|
|
40
|
+
rsaVerify: () => rsaVerify
|
|
41
|
+
});
|
|
42
|
+
module.exports = __toCommonJS(node_exports);
|
|
43
|
+
var import_node_crypto = __toESM(require("node:crypto"));
|
|
44
|
+
|
|
45
|
+
// libs/utils/src/crypto/jwt-alg.ts
|
|
46
|
+
var JWT_ALG_TO_NODE_DIGEST = {
|
|
47
|
+
RS256: "RSA-SHA256",
|
|
48
|
+
RS384: "RSA-SHA384",
|
|
49
|
+
RS512: "RSA-SHA512",
|
|
50
|
+
// For RSA-PSS, Node's crypto.sign/verify uses the digest algorithm + explicit PSS padding options.
|
|
51
|
+
PS256: "RSA-SHA256",
|
|
52
|
+
PS384: "RSA-SHA384",
|
|
53
|
+
PS512: "RSA-SHA512"
|
|
54
|
+
};
|
|
55
|
+
function jwtAlgToNodeAlg(jwtAlg) {
|
|
56
|
+
const nodeAlg = JWT_ALG_TO_NODE_DIGEST[jwtAlg];
|
|
57
|
+
if (!nodeAlg) {
|
|
58
|
+
throw new Error(`Unsupported JWT algorithm: ${jwtAlg}`);
|
|
59
|
+
}
|
|
60
|
+
return nodeAlg;
|
|
61
|
+
}
|
|
62
|
+
function isRsaPssAlg(jwtAlg) {
|
|
63
|
+
return jwtAlg.startsWith("PS");
|
|
64
|
+
}
|
|
65
|
+
|
|
66
|
+
// libs/utils/src/crypto/node.ts
|
|
67
|
+
function toUint8Array(buf) {
|
|
68
|
+
return new Uint8Array(buf.buffer, buf.byteOffset, buf.byteLength);
|
|
69
|
+
}
|
|
70
|
+
function toBuffer(data) {
|
|
71
|
+
if (typeof data === "string") {
|
|
72
|
+
return Buffer.from(data, "utf8");
|
|
73
|
+
}
|
|
74
|
+
return Buffer.from(data);
|
|
75
|
+
}
|
|
76
|
+
var nodeCrypto = {
|
|
77
|
+
randomUUID() {
|
|
78
|
+
return import_node_crypto.default.randomUUID();
|
|
79
|
+
},
|
|
80
|
+
randomBytes(length) {
|
|
81
|
+
return toUint8Array(import_node_crypto.default.randomBytes(length));
|
|
82
|
+
},
|
|
83
|
+
sha256(data) {
|
|
84
|
+
const hash = import_node_crypto.default.createHash("sha256").update(toBuffer(data)).digest();
|
|
85
|
+
return toUint8Array(hash);
|
|
86
|
+
},
|
|
87
|
+
sha256Hex(data) {
|
|
88
|
+
return import_node_crypto.default.createHash("sha256").update(toBuffer(data)).digest("hex");
|
|
89
|
+
},
|
|
90
|
+
hmacSha256(key, data) {
|
|
91
|
+
const hmac = import_node_crypto.default.createHmac("sha256", Buffer.from(key)).update(Buffer.from(data)).digest();
|
|
92
|
+
return toUint8Array(hmac);
|
|
93
|
+
},
|
|
94
|
+
hkdfSha256(ikm, salt, info, length) {
|
|
95
|
+
const ikmBuf = Buffer.from(ikm);
|
|
96
|
+
const saltBuf = salt.length > 0 ? Buffer.from(salt) : Buffer.alloc(32);
|
|
97
|
+
const prk = import_node_crypto.default.createHmac("sha256", saltBuf).update(ikmBuf).digest();
|
|
98
|
+
const hashLen = 32;
|
|
99
|
+
const n = Math.ceil(length / hashLen);
|
|
100
|
+
const chunks = [];
|
|
101
|
+
let prev = Buffer.alloc(0);
|
|
102
|
+
for (let i = 1; i <= n; i++) {
|
|
103
|
+
prev = import_node_crypto.default.createHmac("sha256", prk).update(Buffer.concat([prev, Buffer.from(info), Buffer.from([i])])).digest();
|
|
104
|
+
chunks.push(prev);
|
|
105
|
+
}
|
|
106
|
+
return toUint8Array(Buffer.concat(chunks).subarray(0, length));
|
|
107
|
+
},
|
|
108
|
+
encryptAesGcm(key, plaintext, iv) {
|
|
109
|
+
const cipher = import_node_crypto.default.createCipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
|
|
110
|
+
const encrypted = Buffer.concat([cipher.update(Buffer.from(plaintext)), cipher.final()]);
|
|
111
|
+
const tag = cipher.getAuthTag();
|
|
112
|
+
return {
|
|
113
|
+
ciphertext: toUint8Array(encrypted),
|
|
114
|
+
tag: toUint8Array(tag)
|
|
115
|
+
};
|
|
116
|
+
},
|
|
117
|
+
decryptAesGcm(key, ciphertext, iv, tag) {
|
|
118
|
+
const decipher = import_node_crypto.default.createDecipheriv("aes-256-gcm", Buffer.from(key), Buffer.from(iv));
|
|
119
|
+
decipher.setAuthTag(Buffer.from(tag));
|
|
120
|
+
const decrypted = Buffer.concat([decipher.update(Buffer.from(ciphertext)), decipher.final()]);
|
|
121
|
+
return toUint8Array(decrypted);
|
|
122
|
+
},
|
|
123
|
+
timingSafeEqual(a, b) {
|
|
124
|
+
if (a.length !== b.length) return false;
|
|
125
|
+
return import_node_crypto.default.timingSafeEqual(Buffer.from(a), Buffer.from(b));
|
|
126
|
+
}
|
|
127
|
+
};
|
|
128
|
+
function generateRsaKeyPair(modulusLength = 2048, alg = "RS256") {
|
|
129
|
+
const kid = `rsa-key-${Date.now()}-${import_node_crypto.default.randomBytes(8).toString("hex")}`;
|
|
130
|
+
const { privateKey, publicKey } = import_node_crypto.default.generateKeyPairSync("rsa", {
|
|
131
|
+
modulusLength
|
|
132
|
+
});
|
|
133
|
+
const exported = publicKey.export({ format: "jwk" });
|
|
134
|
+
const publicJwk = {
|
|
135
|
+
...exported,
|
|
136
|
+
kid,
|
|
137
|
+
alg,
|
|
138
|
+
use: "sig",
|
|
139
|
+
kty: "RSA"
|
|
140
|
+
};
|
|
141
|
+
return { privateKey, publicKey, publicJwk };
|
|
142
|
+
}
|
|
143
|
+
function rsaSign(algorithm, data, privateKey, options) {
|
|
144
|
+
const signingKey = options ? { key: privateKey, ...options } : privateKey;
|
|
145
|
+
return import_node_crypto.default.sign(algorithm, data, signingKey);
|
|
146
|
+
}
|
|
147
|
+
function rsaVerify(jwtAlg, data, publicJwk, signature) {
|
|
148
|
+
const publicKey = import_node_crypto.default.createPublicKey({ key: publicJwk, format: "jwk" });
|
|
149
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(jwtAlg);
|
|
150
|
+
const verifyKey = isRsaPssAlg(jwtAlg) ? {
|
|
151
|
+
key: publicKey,
|
|
152
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
153
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
154
|
+
} : publicKey;
|
|
155
|
+
return import_node_crypto.default.verify(nodeAlgorithm, data, verifyKey, signature);
|
|
156
|
+
}
|
|
157
|
+
function createSignedJwt(payload, privateKey, kid, alg = "RS256") {
|
|
158
|
+
const header = { alg, typ: "JWT", kid };
|
|
159
|
+
const headerB64 = Buffer.from(JSON.stringify(header)).toString("base64url");
|
|
160
|
+
const payloadB64 = Buffer.from(JSON.stringify(payload)).toString("base64url");
|
|
161
|
+
const signatureInput = `${headerB64}.${payloadB64}`;
|
|
162
|
+
const nodeAlgorithm = jwtAlgToNodeAlg(alg);
|
|
163
|
+
const signature = rsaSign(
|
|
164
|
+
nodeAlgorithm,
|
|
165
|
+
Buffer.from(signatureInput),
|
|
166
|
+
privateKey,
|
|
167
|
+
isRsaPssAlg(alg) ? {
|
|
168
|
+
padding: import_node_crypto.default.constants.RSA_PKCS1_PSS_PADDING,
|
|
169
|
+
saltLength: import_node_crypto.default.constants.RSA_PSS_SALTLEN_DIGEST
|
|
170
|
+
} : void 0
|
|
171
|
+
);
|
|
172
|
+
const signatureB64 = signature.toString("base64url");
|
|
173
|
+
return `${headerB64}.${payloadB64}.${signatureB64}`;
|
|
174
|
+
}
|
|
175
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
176
|
+
0 && (module.exports = {
|
|
177
|
+
createSignedJwt,
|
|
178
|
+
cryptoProvider,
|
|
179
|
+
generateRsaKeyPair,
|
|
180
|
+
isRsaPssAlg,
|
|
181
|
+
jwtAlgToNodeAlg,
|
|
182
|
+
nodeCrypto,
|
|
183
|
+
rsaSign,
|
|
184
|
+
rsaVerify
|
|
185
|
+
});
|
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Browser environment stubs.
|
|
3
|
+
*
|
|
4
|
+
* Returns safe defaults when running in a browser context
|
|
5
|
+
* where `process` is not available.
|
|
6
|
+
*/
|
|
7
|
+
export declare function getEnv(_key: string): string | undefined;
|
|
8
|
+
export declare function getEnv(_key: string, defaultValue: string): string;
|
|
9
|
+
export declare function getCwd(): string;
|
|
10
|
+
export declare function isProduction(): boolean;
|
|
11
|
+
export declare function isDevelopment(): boolean;
|
|
12
|
+
export declare function getEnvFlag(_key: string): boolean;
|
|
13
|
+
export declare function isDebug(): boolean;
|
|
14
|
+
export declare function setEnv(_key: string, _value: string): void;
|
|
15
|
+
export declare function isEdgeRuntime(): boolean;
|
|
16
|
+
export declare function isServerless(): boolean;
|
|
17
|
+
export declare function supportsAnsi(): boolean;
|
|
@@ -0,0 +1,78 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __defProp = Object.defineProperty;
|
|
3
|
+
var __getOwnPropDesc = Object.getOwnPropertyDescriptor;
|
|
4
|
+
var __getOwnPropNames = Object.getOwnPropertyNames;
|
|
5
|
+
var __hasOwnProp = Object.prototype.hasOwnProperty;
|
|
6
|
+
var __export = (target, all) => {
|
|
7
|
+
for (var name in all)
|
|
8
|
+
__defProp(target, name, { get: all[name], enumerable: true });
|
|
9
|
+
};
|
|
10
|
+
var __copyProps = (to, from, except, desc) => {
|
|
11
|
+
if (from && typeof from === "object" || typeof from === "function") {
|
|
12
|
+
for (let key of __getOwnPropNames(from))
|
|
13
|
+
if (!__hasOwnProp.call(to, key) && key !== except)
|
|
14
|
+
__defProp(to, key, { get: () => from[key], enumerable: !(desc = __getOwnPropDesc(from, key)) || desc.enumerable });
|
|
15
|
+
}
|
|
16
|
+
return to;
|
|
17
|
+
};
|
|
18
|
+
var __toCommonJS = (mod) => __copyProps(__defProp({}, "__esModule", { value: true }), mod);
|
|
19
|
+
|
|
20
|
+
// libs/utils/src/env/browser-env.ts
|
|
21
|
+
var browser_env_exports = {};
|
|
22
|
+
__export(browser_env_exports, {
|
|
23
|
+
getCwd: () => getCwd,
|
|
24
|
+
getEnv: () => getEnv,
|
|
25
|
+
getEnvFlag: () => getEnvFlag,
|
|
26
|
+
isDebug: () => isDebug,
|
|
27
|
+
isDevelopment: () => isDevelopment,
|
|
28
|
+
isEdgeRuntime: () => isEdgeRuntime,
|
|
29
|
+
isProduction: () => isProduction,
|
|
30
|
+
isServerless: () => isServerless,
|
|
31
|
+
setEnv: () => setEnv,
|
|
32
|
+
supportsAnsi: () => supportsAnsi
|
|
33
|
+
});
|
|
34
|
+
module.exports = __toCommonJS(browser_env_exports);
|
|
35
|
+
function getEnv(_key, defaultValue) {
|
|
36
|
+
return defaultValue;
|
|
37
|
+
}
|
|
38
|
+
function getCwd() {
|
|
39
|
+
return "/";
|
|
40
|
+
}
|
|
41
|
+
function isProduction() {
|
|
42
|
+
return false;
|
|
43
|
+
}
|
|
44
|
+
function isDevelopment() {
|
|
45
|
+
return false;
|
|
46
|
+
}
|
|
47
|
+
function getEnvFlag(_key) {
|
|
48
|
+
return false;
|
|
49
|
+
}
|
|
50
|
+
function isDebug() {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
function setEnv(_key, _value) {
|
|
54
|
+
}
|
|
55
|
+
function isEdgeRuntime() {
|
|
56
|
+
if (typeof globalThis !== "undefined" && "EdgeRuntime" in globalThis) return true;
|
|
57
|
+
if (typeof globalThis !== "undefined" && "caches" in globalThis && !("window" in globalThis)) return true;
|
|
58
|
+
return false;
|
|
59
|
+
}
|
|
60
|
+
function isServerless() {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
function supportsAnsi() {
|
|
64
|
+
return false;
|
|
65
|
+
}
|
|
66
|
+
// Annotate the CommonJS export names for ESM import in node:
|
|
67
|
+
0 && (module.exports = {
|
|
68
|
+
getCwd,
|
|
69
|
+
getEnv,
|
|
70
|
+
getEnvFlag,
|
|
71
|
+
isDebug,
|
|
72
|
+
isDevelopment,
|
|
73
|
+
isEdgeRuntime,
|
|
74
|
+
isProduction,
|
|
75
|
+
isServerless,
|
|
76
|
+
setEnv,
|
|
77
|
+
supportsAnsi
|
|
78
|
+
});
|
package/env/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export { getEnv, getCwd, isProduction, isDevelopment, getEnvFlag, isDebug, setEnv, isEdgeRuntime, isServerless, supportsAnsi, } from '#env';
|