@frontmcp/utils 1.10.16 → 1.11.0-rc.2
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/README.md +1 -0
- package/browser/async-context/browser-async-context.mjs +177 -0
- package/browser/async-context/index.mjs +15 -0
- package/browser/async-context/overlap-error.mjs +10 -0
- package/browser/class-brand/class-brand.mjs +27 -0
- package/browser/class-brand/index.mjs +6 -0
- package/browser/content/content.mjs +151 -0
- package/browser/content/index.mjs +8 -0
- package/browser/crypto/browser.mjs +103 -0
- package/browser/crypto/encrypted-blob.mjs +119 -0
- package/browser/crypto/hmac-signing.mjs +70 -0
- package/browser/crypto/index.mjs +281 -0
- package/browser/crypto/jwt-alg.mjs +40 -0
- package/browser/crypto/key-persistence/factory.mjs +134 -0
- package/browser/crypto/key-persistence/index.mjs +26 -0
- package/browser/crypto/key-persistence/key-persistence.mjs +185 -0
- package/browser/crypto/key-persistence/schemas.mjs +82 -0
- package/browser/crypto/pkce/index.mjs +25 -0
- package/browser/crypto/pkce/pkce.mjs +59 -0
- package/browser/crypto/runtime.mjs +17 -0
- package/browser/crypto/secret-persistence/index.mjs +29 -0
- package/browser/crypto/secret-persistence/persistence.mjs +181 -0
- package/browser/crypto/secret-persistence/schema.mjs +40 -0
- package/browser/crypto/web-rsa.mjs +36 -0
- package/browser/env/browser-env.mjs +56 -0
- package/browser/env/browser-runtime-context.mjs +85 -0
- package/browser/env/build-target.mjs +25 -0
- package/browser/env/edge-scope.mjs +17 -0
- package/browser/env/index.mjs +47 -0
- package/browser/env/provider.mjs +46 -0
- package/browser/escape/escape.mjs +43 -0
- package/browser/escape/index.mjs +9 -0
- package/browser/event-emitter/browser-event-emitter.mjs +49 -0
- package/browser/event-emitter/index.mjs +5 -0
- package/browser/fs/fs.mjs +227 -0
- package/browser/fs/index.mjs +65 -0
- package/browser/http/cookie.mjs +85 -0
- package/browser/http/http.mjs +18 -0
- package/browser/http/index.mjs +11 -0
- package/browser/index.mjs +526 -0
- package/browser/llm/index.mjs +5 -0
- package/browser/llm/llm-tool-handlers.mjs +55 -0
- package/browser/machine-id/index.mjs +7 -0
- package/browser/machine-id/machine-id.mjs +108 -0
- package/browser/naming/index.mjs +10 -0
- package/browser/naming/naming.mjs +68 -0
- package/browser/net/index.mjs +10 -0
- package/browser/net/ip-address.mjs +128 -0
- package/browser/net/redirect.mjs +7 -0
- package/browser/path/browser-path.mjs +47 -0
- package/browser/path/index.mjs +24 -0
- package/browser/path/path.mjs +13 -0
- package/browser/process/child-process.mjs +23 -0
- package/browser/process/index.mjs +15 -0
- package/browser/process/owned-process.mjs +175 -0
- package/browser/process/process-tree.mjs +149 -0
- package/browser/process/process-watch.mjs +48 -0
- package/browser/redaction/index.mjs +6 -0
- package/browser/redaction/redaction.mjs +74 -0
- package/browser/regex/index.mjs +3 -0
- package/browser/regex/patterns.mjs +167 -0
- package/browser/regex/safe-regex.mjs +93 -0
- package/browser/serialization/index.mjs +5 -0
- package/browser/serialization/serialization.mjs +22 -0
- package/browser/stdio-bridge/errors.mjs +27 -0
- package/browser/stdio-bridge/index.mjs +24 -0
- package/browser/stdio-bridge/list-changed.mjs +21 -0
- package/browser/stdio-bridge/state-machine.mjs +211 -0
- package/browser/stdio-bridge/stdio-framer.mjs +91 -0
- package/browser/stdio-bridge/upstream-client.mjs +189 -0
- package/browser/storage/adapters/base.mjs +139 -0
- package/browser/storage/adapters/cloudflare-kv.mjs +149 -0
- package/browser/storage/adapters/filesystem.mjs +279 -0
- package/browser/storage/adapters/index.mjs +23 -0
- package/browser/storage/adapters/indexeddb.mjs +198 -0
- package/browser/storage/adapters/localstorage.mjs +222 -0
- package/browser/storage/adapters/memory.mjs +350 -0
- package/browser/storage/adapters/redis.mjs +497 -0
- package/browser/storage/adapters/upstash.mjs +299 -0
- package/browser/storage/adapters/vercel-kv.mjs +226 -0
- package/browser/storage/change-feed.mjs +189 -0
- package/browser/storage/encrypted-typed-storage.mjs +329 -0
- package/browser/storage/errors.mjs +92 -0
- package/browser/storage/factory.mjs +155 -0
- package/browser/storage/index.mjs +96 -0
- package/browser/storage/namespace.mjs +186 -0
- package/browser/storage/redis-error-listener.mjs +32 -0
- package/browser/storage/redis-url.mjs +66 -0
- package/browser/storage/typed-storage.mjs +171 -0
- package/browser/storage/utils/compare-and-delete.mjs +9 -0
- package/browser/storage/utils/index.mjs +24 -0
- package/browser/storage/utils/pattern.mjs +68 -0
- package/browser/storage/utils/ttl.mjs +48 -0
- package/browser/uri/index.mjs +19 -0
- package/browser/uri/uri-template.mjs +86 -0
- package/browser/uri/uri-validation.mjs +18 -0
- package/crypto/browser.d.ts +1 -13
- package/crypto/browser.js +1 -1
- package/crypto/node.js +1 -1
- package/crypto/web-rsa.d.ts +13 -0
- package/env/browser-runtime-context.js +1 -1
- package/env/runtime-context.js +1 -1
- package/esm/crypto/browser.mjs +1 -1
- package/esm/crypto/node.mjs +1 -1
- package/esm/env/browser-runtime-context.mjs +1 -1
- package/esm/env/runtime-context.mjs +1 -1
- package/esm/index.mjs +1 -1
- package/fs/fs.d.ts +20 -4
- package/fs/index.d.ts +1 -1
- package/index.d.ts +9 -3
- package/index.js +1 -1
- package/package.json +24 -8
- package/process/child-process.d.ts +2 -0
- package/process/index.d.ts +6 -0
- package/process/owned-process.d.ts +59 -0
- package/process/process-tree.d.ts +78 -0
- package/process/process-watch.d.ts +41 -0
- package/redaction/index.d.ts +2 -0
- package/redaction/redaction.d.ts +24 -0
- package/stdio-bridge/errors.d.ts +23 -0
- package/stdio-bridge/index.d.ts +9 -0
- package/stdio-bridge/list-changed.d.ts +3 -0
- package/stdio-bridge/state-machine.d.ts +61 -0
- package/stdio-bridge/stdio-framer.d.ts +49 -0
- package/stdio-bridge/types.d.ts +10 -0
- package/stdio-bridge/upstream-client.d.ts +66 -0
- package/storage/adapters/base.d.ts +2 -0
- package/storage/adapters/memory.d.ts +1 -0
- package/storage/adapters/redis.d.ts +3 -0
- package/storage/change-feed.d.ts +47 -0
- package/storage/factory.d.ts +6 -0
- package/storage/index.d.ts +3 -1
- package/storage/namespace.d.ts +2 -0
- package/storage/types.d.ts +46 -1
- package/storage/utils/compare-and-delete.d.ts +2 -0
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// libs/utils/src/process/process-watch.ts
|
|
2
|
+
import { isMissingSync } from "../fs/fs.mjs";
|
|
3
|
+
import { isPidRunning } from "./process-tree.mjs";
|
|
4
|
+
var DEFAULT_INTERVAL_MS = 1e3;
|
|
5
|
+
function watchParent(options, deps) {
|
|
6
|
+
const d = { ppid: () => process.ppid, kill: (pid, signal) => process.kill(pid, signal), ...deps };
|
|
7
|
+
const parentPid = d.ppid();
|
|
8
|
+
const stdin = options.stdin;
|
|
9
|
+
let timer;
|
|
10
|
+
let closed = false;
|
|
11
|
+
const close = () => {
|
|
12
|
+
closed = true;
|
|
13
|
+
clearInterval(timer);
|
|
14
|
+
stdin?.removeListener("end", onStdinEnded);
|
|
15
|
+
stdin?.removeListener("close", onStdinEnded);
|
|
16
|
+
};
|
|
17
|
+
const report = (reason) => {
|
|
18
|
+
if (closed) return;
|
|
19
|
+
close();
|
|
20
|
+
options.onGone(reason);
|
|
21
|
+
};
|
|
22
|
+
function onStdinEnded() {
|
|
23
|
+
report("stdin-ended");
|
|
24
|
+
}
|
|
25
|
+
if (stdin?.readableEnded || stdin?.destroyed) queueMicrotask(onStdinEnded);
|
|
26
|
+
stdin?.once("end", onStdinEnded);
|
|
27
|
+
stdin?.once("close", onStdinEnded);
|
|
28
|
+
if (parentPid > 1) {
|
|
29
|
+
timer = setInterval(() => {
|
|
30
|
+
if (d.ppid() !== parentPid || !isPidRunning(parentPid, d)) report("parent-exited");
|
|
31
|
+
}, options.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
32
|
+
timer.unref();
|
|
33
|
+
}
|
|
34
|
+
return { close };
|
|
35
|
+
}
|
|
36
|
+
function watchPath(path, options) {
|
|
37
|
+
const timer = setInterval(() => {
|
|
38
|
+
if (!isMissingSync(path)) return;
|
|
39
|
+
clearInterval(timer);
|
|
40
|
+
options.onGone();
|
|
41
|
+
}, options.intervalMs ?? DEFAULT_INTERVAL_MS);
|
|
42
|
+
timer.unref();
|
|
43
|
+
return { close: () => clearInterval(timer) };
|
|
44
|
+
}
|
|
45
|
+
export {
|
|
46
|
+
watchParent,
|
|
47
|
+
watchPath
|
|
48
|
+
};
|
|
@@ -0,0 +1,74 @@
|
|
|
1
|
+
// libs/utils/src/redaction/redaction.ts
|
|
2
|
+
var REDACTED = "[REDACTED]";
|
|
3
|
+
function redactFields(obj, fields, maxDepth = 5) {
|
|
4
|
+
if (typeof fields !== "function" && fields.length === 0) return obj;
|
|
5
|
+
return redactRecord(obj, 0, { isSensitive: sensitiveKeyTest(fields), maxDepth, jsonText: false });
|
|
6
|
+
}
|
|
7
|
+
function redactJson(value, fields) {
|
|
8
|
+
return redactValue(value, 0, { isSensitive: sensitiveKeyTest(fields), maxDepth: Infinity, jsonText: true });
|
|
9
|
+
}
|
|
10
|
+
function sensitiveKeyTest(fields) {
|
|
11
|
+
if (typeof fields === "function") return fields;
|
|
12
|
+
const names = new Set(fields.map((field) => field.toLowerCase()));
|
|
13
|
+
return (key) => names.has(key.toLowerCase());
|
|
14
|
+
}
|
|
15
|
+
function redactValue(value, depth, options) {
|
|
16
|
+
if (typeof value === "string") return options.jsonText ? redactJsonText(value, depth, options) : value;
|
|
17
|
+
if (Array.isArray(value)) return value.map((item) => redactValue(item, depth, options));
|
|
18
|
+
if (isPlainObject(value)) return redactRecord(value, depth, options);
|
|
19
|
+
return value;
|
|
20
|
+
}
|
|
21
|
+
function redactRecord(obj, depth, options) {
|
|
22
|
+
if (depth >= options.maxDepth) return obj;
|
|
23
|
+
const result = {};
|
|
24
|
+
for (const [key, value] of Object.entries(obj)) {
|
|
25
|
+
result[key] = options.isSensitive(key) ? REDACTED : redactValue(value, depth + 1, options);
|
|
26
|
+
}
|
|
27
|
+
return result;
|
|
28
|
+
}
|
|
29
|
+
var AUTH_SCHEME_CREDENTIAL = /\b(Bearer|Basic)([ \t]+)(?=[\w.~+/-]*[\d.~+/_-])[\w.~+/-]{8,}=*/gi;
|
|
30
|
+
var JWT = /(?<![\w-])eyJ[\w-]+(?:\.[\w-]*){2,4}/g;
|
|
31
|
+
var URL_CREDENTIALS = /(?<![a-z\d+.-])([a-z][a-z\d+.-]*:\/\/)[^\s/?#@]+@/gi;
|
|
32
|
+
var VALUE_NAME = /(?:^|[?&#;,{("'\s])(["']?)([A-Za-z_][\w.-]*)\1[ \t]*[:=][ \t]*/g;
|
|
33
|
+
var NAMED_VALUE = /"(?:[^"\\\n]|\\.)*"|'(?:[^'\\\n]|\\.)*'|[^\s"'&#;?,)}]+/y;
|
|
34
|
+
function redactNamedValues(text, isSensitive) {
|
|
35
|
+
let redacted = "";
|
|
36
|
+
let copiedUpTo = 0;
|
|
37
|
+
VALUE_NAME.lastIndex = 0;
|
|
38
|
+
for (let name = VALUE_NAME.exec(text); name; name = VALUE_NAME.exec(text)) {
|
|
39
|
+
if (!isSensitive(name[2])) continue;
|
|
40
|
+
NAMED_VALUE.lastIndex = VALUE_NAME.lastIndex;
|
|
41
|
+
const value = NAMED_VALUE.exec(text)?.[0];
|
|
42
|
+
if (value === void 0) continue;
|
|
43
|
+
const quote = value[0] === '"' || value[0] === "'" ? value[0] : "";
|
|
44
|
+
redacted += `${text.slice(copiedUpTo, VALUE_NAME.lastIndex)}${quote}${REDACTED}${quote}`;
|
|
45
|
+
copiedUpTo = VALUE_NAME.lastIndex + value.length;
|
|
46
|
+
VALUE_NAME.lastIndex = copiedUpTo;
|
|
47
|
+
}
|
|
48
|
+
return copiedUpTo === 0 ? text : redacted + text.slice(copiedUpTo);
|
|
49
|
+
}
|
|
50
|
+
function redactCredentialText(text, isSensitive) {
|
|
51
|
+
const withoutCredentials = text.replace(AUTH_SCHEME_CREDENTIAL, `$1$2${REDACTED}`).replace(JWT, REDACTED).replace(URL_CREDENTIALS, `$1${REDACTED}@`);
|
|
52
|
+
return redactNamedValues(withoutCredentials, isSensitive);
|
|
53
|
+
}
|
|
54
|
+
function redactJsonText(text, depth, options) {
|
|
55
|
+
const start = text.trimStart()[0];
|
|
56
|
+
if (start !== "{" && start !== "[") return redactCredentialText(text, options.isSensitive);
|
|
57
|
+
let parsed;
|
|
58
|
+
try {
|
|
59
|
+
parsed = JSON.parse(text);
|
|
60
|
+
} catch {
|
|
61
|
+
return redactCredentialText(text, options.isSensitive);
|
|
62
|
+
}
|
|
63
|
+
const redacted = JSON.stringify(redactValue(parsed, depth, options));
|
|
64
|
+
return redacted === JSON.stringify(parsed) ? text : redacted;
|
|
65
|
+
}
|
|
66
|
+
function isPlainObject(value) {
|
|
67
|
+
if (typeof value !== "object" || value === null) return false;
|
|
68
|
+
const proto = Object.getPrototypeOf(value);
|
|
69
|
+
return proto === Object.prototype || proto === null;
|
|
70
|
+
}
|
|
71
|
+
export {
|
|
72
|
+
redactFields,
|
|
73
|
+
redactJson
|
|
74
|
+
};
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
// libs/utils/src/regex/index.ts
|
|
2
|
+
export { DEFAULT_MAX_INPUT_LENGTH, REDOS_THRESHOLDS, analyzePattern, createSafeRegExp, isInputLengthSafe, isPatternSafe, safeExec, safeMatch, safeReplace, safeTest } from "./safe-regex.mjs";
|
|
3
|
+
export { collapseChar, collapseWhitespace, expandTemplate, extractBracedParams, hasTemplatePlaceholders, trimBoth, trimChars, trimLeading, trimTrailing } from "./patterns.mjs";
|
|
@@ -0,0 +1,167 @@
|
|
|
1
|
+
// libs/utils/src/regex/patterns.ts
|
|
2
|
+
import { DEFAULT_MAX_INPUT_LENGTH } from "./safe-regex.mjs";
|
|
3
|
+
function trimLeading(input, char) {
|
|
4
|
+
if (!input || char.length !== 1) {
|
|
5
|
+
return input ?? "";
|
|
6
|
+
}
|
|
7
|
+
let start = 0;
|
|
8
|
+
while (start < input.length && input[start] === char) {
|
|
9
|
+
start++;
|
|
10
|
+
}
|
|
11
|
+
return start === 0 ? input : input.slice(start);
|
|
12
|
+
}
|
|
13
|
+
function trimTrailing(input, char) {
|
|
14
|
+
if (!input || char.length !== 1) {
|
|
15
|
+
return input ?? "";
|
|
16
|
+
}
|
|
17
|
+
let end = input.length;
|
|
18
|
+
while (end > 0 && input[end - 1] === char) {
|
|
19
|
+
end--;
|
|
20
|
+
}
|
|
21
|
+
return end === input.length ? input : input.slice(0, end);
|
|
22
|
+
}
|
|
23
|
+
function trimBoth(input, char) {
|
|
24
|
+
return trimTrailing(trimLeading(input, char), char);
|
|
25
|
+
}
|
|
26
|
+
function trimChars(input, chars) {
|
|
27
|
+
if (!input || chars.size === 0) {
|
|
28
|
+
return input ?? "";
|
|
29
|
+
}
|
|
30
|
+
let start = 0;
|
|
31
|
+
while (start < input.length && chars.has(input[start])) {
|
|
32
|
+
start++;
|
|
33
|
+
}
|
|
34
|
+
let end = input.length;
|
|
35
|
+
while (end > start && chars.has(input[end - 1])) {
|
|
36
|
+
end--;
|
|
37
|
+
}
|
|
38
|
+
return input.slice(start, end);
|
|
39
|
+
}
|
|
40
|
+
function extractBracedParams(template, maxLength = DEFAULT_MAX_INPUT_LENGTH) {
|
|
41
|
+
if (!template || template.length > maxLength) {
|
|
42
|
+
return [];
|
|
43
|
+
}
|
|
44
|
+
const params = [];
|
|
45
|
+
let i = 0;
|
|
46
|
+
while (i < template.length) {
|
|
47
|
+
const openBrace = template.indexOf("{", i);
|
|
48
|
+
if (openBrace === -1) {
|
|
49
|
+
break;
|
|
50
|
+
}
|
|
51
|
+
const closeBrace = template.indexOf("}", openBrace + 1);
|
|
52
|
+
if (closeBrace === -1) {
|
|
53
|
+
break;
|
|
54
|
+
}
|
|
55
|
+
const nestedOpen = template.indexOf("{", openBrace + 1);
|
|
56
|
+
if (nestedOpen !== -1 && nestedOpen < closeBrace) {
|
|
57
|
+
i = nestedOpen + 1;
|
|
58
|
+
continue;
|
|
59
|
+
}
|
|
60
|
+
const paramName = template.slice(openBrace + 1, closeBrace).trim();
|
|
61
|
+
if (paramName && !paramName.includes("{") && !paramName.includes("}")) {
|
|
62
|
+
params.push(paramName);
|
|
63
|
+
}
|
|
64
|
+
i = closeBrace + 1;
|
|
65
|
+
}
|
|
66
|
+
return params;
|
|
67
|
+
}
|
|
68
|
+
function expandTemplate(template, values, maxLength = DEFAULT_MAX_INPUT_LENGTH) {
|
|
69
|
+
if (!template || template.length > maxLength) {
|
|
70
|
+
return template ?? "";
|
|
71
|
+
}
|
|
72
|
+
let result = "";
|
|
73
|
+
let i = 0;
|
|
74
|
+
while (i < template.length) {
|
|
75
|
+
const openBrace = template.indexOf("{", i);
|
|
76
|
+
if (openBrace === -1) {
|
|
77
|
+
result += template.slice(i);
|
|
78
|
+
break;
|
|
79
|
+
}
|
|
80
|
+
result += template.slice(i, openBrace);
|
|
81
|
+
const closeBrace = template.indexOf("}", openBrace + 1);
|
|
82
|
+
if (closeBrace === -1) {
|
|
83
|
+
result += template.slice(openBrace);
|
|
84
|
+
break;
|
|
85
|
+
}
|
|
86
|
+
const nestedOpen = template.indexOf("{", openBrace + 1);
|
|
87
|
+
if (nestedOpen !== -1 && nestedOpen < closeBrace) {
|
|
88
|
+
result += "{";
|
|
89
|
+
i = openBrace + 1;
|
|
90
|
+
continue;
|
|
91
|
+
}
|
|
92
|
+
const paramName = template.slice(openBrace + 1, closeBrace).trim();
|
|
93
|
+
if (paramName in values) {
|
|
94
|
+
result += values[paramName];
|
|
95
|
+
} else {
|
|
96
|
+
result += template.slice(openBrace, closeBrace + 1);
|
|
97
|
+
}
|
|
98
|
+
i = closeBrace + 1;
|
|
99
|
+
}
|
|
100
|
+
return result;
|
|
101
|
+
}
|
|
102
|
+
function hasTemplatePlaceholders(str, maxLength = DEFAULT_MAX_INPUT_LENGTH) {
|
|
103
|
+
if (!str || str.length > maxLength) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
const openBrace = str.indexOf("{");
|
|
107
|
+
if (openBrace === -1) {
|
|
108
|
+
return false;
|
|
109
|
+
}
|
|
110
|
+
const closeBrace = str.indexOf("}", openBrace + 1);
|
|
111
|
+
return closeBrace > openBrace + 1;
|
|
112
|
+
}
|
|
113
|
+
function collapseChar(input, char) {
|
|
114
|
+
if (!input || char.length !== 1) {
|
|
115
|
+
return input ?? "";
|
|
116
|
+
}
|
|
117
|
+
let result = "";
|
|
118
|
+
let lastWasChar = false;
|
|
119
|
+
for (let i = 0; i < input.length; i++) {
|
|
120
|
+
const c = input[i];
|
|
121
|
+
if (c === char) {
|
|
122
|
+
if (!lastWasChar) {
|
|
123
|
+
result += c;
|
|
124
|
+
lastWasChar = true;
|
|
125
|
+
}
|
|
126
|
+
} else {
|
|
127
|
+
result += c;
|
|
128
|
+
lastWasChar = false;
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
return result;
|
|
132
|
+
}
|
|
133
|
+
function collapseWhitespace(input, maxLength = DEFAULT_MAX_INPUT_LENGTH) {
|
|
134
|
+
if (!input) {
|
|
135
|
+
return "";
|
|
136
|
+
}
|
|
137
|
+
if (input.length > maxLength) {
|
|
138
|
+
return input;
|
|
139
|
+
}
|
|
140
|
+
let result = "";
|
|
141
|
+
let lastWasWhitespace = false;
|
|
142
|
+
for (let i = 0; i < input.length; i++) {
|
|
143
|
+
const c = input[i];
|
|
144
|
+
const isWhitespace = c === " " || c === " " || c === "\n" || c === "\r" || c === "\f" || c === "\v";
|
|
145
|
+
if (isWhitespace) {
|
|
146
|
+
if (!lastWasWhitespace) {
|
|
147
|
+
result += " ";
|
|
148
|
+
lastWasWhitespace = true;
|
|
149
|
+
}
|
|
150
|
+
} else {
|
|
151
|
+
result += c;
|
|
152
|
+
lastWasWhitespace = false;
|
|
153
|
+
}
|
|
154
|
+
}
|
|
155
|
+
return result;
|
|
156
|
+
}
|
|
157
|
+
export {
|
|
158
|
+
collapseChar,
|
|
159
|
+
collapseWhitespace,
|
|
160
|
+
expandTemplate,
|
|
161
|
+
extractBracedParams,
|
|
162
|
+
hasTemplatePlaceholders,
|
|
163
|
+
trimBoth,
|
|
164
|
+
trimChars,
|
|
165
|
+
trimLeading,
|
|
166
|
+
trimTrailing
|
|
167
|
+
};
|
|
@@ -0,0 +1,93 @@
|
|
|
1
|
+
// libs/utils/src/regex/safe-regex.ts
|
|
2
|
+
import { analyzeForReDoS, REDOS_THRESHOLDS } from "@enclave-vm/ast/redos";
|
|
3
|
+
var DEFAULT_MAX_INPUT_LENGTH = 5e4;
|
|
4
|
+
function analyzePattern(pattern, level = "polynomial") {
|
|
5
|
+
const patternStr = typeof pattern === "string" ? pattern : pattern.source;
|
|
6
|
+
try {
|
|
7
|
+
new RegExp(patternStr);
|
|
8
|
+
} catch {
|
|
9
|
+
return {
|
|
10
|
+
safe: false,
|
|
11
|
+
score: 100,
|
|
12
|
+
vulnerabilityType: "invalid_syntax",
|
|
13
|
+
explanation: "Pattern has invalid regex syntax"
|
|
14
|
+
};
|
|
15
|
+
}
|
|
16
|
+
try {
|
|
17
|
+
const result = analyzeForReDoS(patternStr, level);
|
|
18
|
+
return {
|
|
19
|
+
safe: !result.vulnerable,
|
|
20
|
+
score: result.score,
|
|
21
|
+
vulnerabilityType: result.vulnerabilityType,
|
|
22
|
+
explanation: result.explanation
|
|
23
|
+
};
|
|
24
|
+
} catch {
|
|
25
|
+
return {
|
|
26
|
+
safe: false,
|
|
27
|
+
score: 100,
|
|
28
|
+
vulnerabilityType: "analysis_failed",
|
|
29
|
+
explanation: "Pattern analysis failed - treating as potentially unsafe"
|
|
30
|
+
};
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
function isPatternSafe(pattern, level = "polynomial") {
|
|
34
|
+
return analyzePattern(pattern, level).safe;
|
|
35
|
+
}
|
|
36
|
+
function createSafeRegExp(pattern, flags, options = {}) {
|
|
37
|
+
const { level = "polynomial", throwOnVulnerable = false } = options;
|
|
38
|
+
const analysis = analyzePattern(pattern, level);
|
|
39
|
+
if (!analysis.safe) {
|
|
40
|
+
if (throwOnVulnerable) {
|
|
41
|
+
throw new Error(`Vulnerable regex pattern detected: ${analysis.explanation || analysis.vulnerabilityType}`);
|
|
42
|
+
}
|
|
43
|
+
return null;
|
|
44
|
+
}
|
|
45
|
+
try {
|
|
46
|
+
return new RegExp(pattern, flags);
|
|
47
|
+
} catch {
|
|
48
|
+
return null;
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
function safeTest(pattern, input, options = {}) {
|
|
52
|
+
const { maxInputLength = DEFAULT_MAX_INPUT_LENGTH } = options;
|
|
53
|
+
if (input.length > maxInputLength) {
|
|
54
|
+
return null;
|
|
55
|
+
}
|
|
56
|
+
return pattern.test(input);
|
|
57
|
+
}
|
|
58
|
+
function safeMatch(pattern, input, options = {}) {
|
|
59
|
+
const { maxInputLength = DEFAULT_MAX_INPUT_LENGTH } = options;
|
|
60
|
+
if (input.length > maxInputLength) {
|
|
61
|
+
return null;
|
|
62
|
+
}
|
|
63
|
+
return input.match(pattern);
|
|
64
|
+
}
|
|
65
|
+
function safeReplace(input, pattern, replacement, options = {}) {
|
|
66
|
+
const { maxInputLength = DEFAULT_MAX_INPUT_LENGTH } = options;
|
|
67
|
+
if (input.length > maxInputLength) {
|
|
68
|
+
return input;
|
|
69
|
+
}
|
|
70
|
+
return input.replace(pattern, replacement);
|
|
71
|
+
}
|
|
72
|
+
function safeExec(pattern, input, options = {}) {
|
|
73
|
+
const { maxInputLength = DEFAULT_MAX_INPUT_LENGTH } = options;
|
|
74
|
+
if (input.length > maxInputLength) {
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
return pattern.exec(input);
|
|
78
|
+
}
|
|
79
|
+
function isInputLengthSafe(input, maxLength = DEFAULT_MAX_INPUT_LENGTH) {
|
|
80
|
+
return input.length <= maxLength;
|
|
81
|
+
}
|
|
82
|
+
export {
|
|
83
|
+
DEFAULT_MAX_INPUT_LENGTH,
|
|
84
|
+
REDOS_THRESHOLDS,
|
|
85
|
+
analyzePattern,
|
|
86
|
+
createSafeRegExp,
|
|
87
|
+
isInputLengthSafe,
|
|
88
|
+
isPatternSafe,
|
|
89
|
+
safeExec,
|
|
90
|
+
safeMatch,
|
|
91
|
+
safeReplace,
|
|
92
|
+
safeTest
|
|
93
|
+
};
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
// libs/utils/src/serialization/serialization.ts
|
|
2
|
+
function safeStringify(value, space) {
|
|
3
|
+
const seen = /* @__PURE__ */ new WeakSet();
|
|
4
|
+
try {
|
|
5
|
+
return JSON.stringify(
|
|
6
|
+
value,
|
|
7
|
+
(_key, val) => {
|
|
8
|
+
if (typeof val === "object" && val !== null) {
|
|
9
|
+
if (seen.has(val)) return "[Circular]";
|
|
10
|
+
seen.add(val);
|
|
11
|
+
}
|
|
12
|
+
return val;
|
|
13
|
+
},
|
|
14
|
+
space
|
|
15
|
+
);
|
|
16
|
+
} catch {
|
|
17
|
+
return JSON.stringify({ error: "Output could not be serialized" });
|
|
18
|
+
}
|
|
19
|
+
}
|
|
20
|
+
export {
|
|
21
|
+
safeStringify
|
|
22
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
// libs/utils/src/stdio-bridge/errors.ts
|
|
2
|
+
var DEV_SERVER_UNREACHABLE = -32099;
|
|
3
|
+
var DEV_BUFFER_FULL = -32098;
|
|
4
|
+
var DEV_RELOAD_DEADLINE = -32097;
|
|
5
|
+
var DEV_ERROR_MESSAGE = {
|
|
6
|
+
[DEV_SERVER_UNREACHABLE]: "dev_server_unreachable",
|
|
7
|
+
[DEV_BUFFER_FULL]: "dev_buffer_full",
|
|
8
|
+
[DEV_RELOAD_DEADLINE]: "dev_reload_deadline"
|
|
9
|
+
};
|
|
10
|
+
function makeDevError(id, code, data) {
|
|
11
|
+
return {
|
|
12
|
+
jsonrpc: "2.0",
|
|
13
|
+
id,
|
|
14
|
+
error: {
|
|
15
|
+
code,
|
|
16
|
+
message: DEV_ERROR_MESSAGE[code] ?? "dev_error",
|
|
17
|
+
...data ? { data } : {}
|
|
18
|
+
}
|
|
19
|
+
};
|
|
20
|
+
}
|
|
21
|
+
export {
|
|
22
|
+
DEV_BUFFER_FULL,
|
|
23
|
+
DEV_ERROR_MESSAGE,
|
|
24
|
+
DEV_RELOAD_DEADLINE,
|
|
25
|
+
DEV_SERVER_UNREACHABLE,
|
|
26
|
+
makeDevError
|
|
27
|
+
};
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
// libs/utils/src/stdio-bridge/index.ts
|
|
2
|
+
import {
|
|
3
|
+
DEV_BUFFER_FULL,
|
|
4
|
+
DEV_ERROR_MESSAGE,
|
|
5
|
+
DEV_RELOAD_DEADLINE,
|
|
6
|
+
DEV_SERVER_UNREACHABLE,
|
|
7
|
+
makeDevError
|
|
8
|
+
} from "./errors.mjs";
|
|
9
|
+
import { listChangedNotifications } from "./list-changed.mjs";
|
|
10
|
+
import { createBridgeStateMachine } from "./state-machine.mjs";
|
|
11
|
+
import { createStdioFramer } from "./stdio-framer.mjs";
|
|
12
|
+
import { createHttpUpstream, createPipeUpstream } from "./upstream-client.mjs";
|
|
13
|
+
export {
|
|
14
|
+
DEV_BUFFER_FULL,
|
|
15
|
+
DEV_ERROR_MESSAGE,
|
|
16
|
+
DEV_RELOAD_DEADLINE,
|
|
17
|
+
DEV_SERVER_UNREACHABLE,
|
|
18
|
+
createBridgeStateMachine,
|
|
19
|
+
createHttpUpstream,
|
|
20
|
+
createPipeUpstream,
|
|
21
|
+
createStdioFramer,
|
|
22
|
+
listChangedNotifications,
|
|
23
|
+
makeDevError
|
|
24
|
+
};
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
// libs/utils/src/stdio-bridge/list-changed.ts
|
|
2
|
+
var LIST_CHANGED = {
|
|
3
|
+
tools: "notifications/tools/list_changed",
|
|
4
|
+
resources: "notifications/resources/list_changed",
|
|
5
|
+
prompts: "notifications/prompts/list_changed"
|
|
6
|
+
};
|
|
7
|
+
function listChangedNotifications(initializeResult) {
|
|
8
|
+
const capabilities = initializeResult?.["capabilities"];
|
|
9
|
+
if (typeof capabilities !== "object" || capabilities === null) return [];
|
|
10
|
+
const frames = [];
|
|
11
|
+
for (const [capability, method] of Object.entries(LIST_CHANGED)) {
|
|
12
|
+
const entry = capabilities[capability];
|
|
13
|
+
if (typeof entry === "object" && entry !== null && entry.listChanged === true) {
|
|
14
|
+
frames.push({ jsonrpc: "2.0", method });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
return frames;
|
|
18
|
+
}
|
|
19
|
+
export {
|
|
20
|
+
listChangedNotifications
|
|
21
|
+
};
|