@frontmcp/utils 1.11.2 → 1.12.0-rc.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +4 -2
- package/browser/crypto/encrypted-blob.mjs +1 -1
- package/browser/crypto/hmac-signing.mjs +1 -3
- package/browser/crypto/index.mjs +25 -1
- package/browser/crypto/key-persistence/factory.mjs +2 -2
- package/browser/crypto/key-persistence/key-persistence.mjs +2 -2
- package/browser/crypto/pkce/pkce.mjs +1 -1
- package/browser/crypto/secret-persistence/persistence.mjs +3 -3
- package/browser/crypto/standard-webhooks.mjs +96 -0
- package/browser/fs/index.mjs +3 -0
- package/browser/fs/watch-files.mjs +177 -0
- package/browser/index.mjs +45 -2
- package/browser/net/index.mjs +15 -2
- package/browser/net/ip-address.mjs +30 -0
- package/browser/net/outbound-request.mjs +190 -0
- package/browser/net/outbound-url.mjs +43 -0
- package/browser/serialization/canonical-json.mjs +35 -0
- package/browser/serialization/index.mjs +2 -0
- package/browser/stdio-bridge/claude-code-channels.mjs +73 -0
- package/browser/stdio-bridge/notification-stream.mjs +111 -0
- package/browser/stdio-bridge/sse-frames.mjs +48 -0
- package/browser/stdio-bridge/upstream-client.mjs +89 -37
- package/browser/storage/adapters/filesystem.mjs +3 -3
- package/browser/storage/adapters/indexeddb.mjs +1 -1
- package/browser/storage/adapters/localstorage.mjs +2 -2
- package/browser/storage/encrypted-typed-storage.mjs +1 -1
- package/crypto/index.d.ts +1 -0
- package/crypto/key-persistence/key-persistence.d.ts +1 -1
- package/crypto/standard-webhooks.d.ts +35 -0
- package/env/browser-runtime-context.d.ts +1 -1
- package/env/runtime-context.d.ts +1 -1
- package/esm/index.mjs +1 -1
- package/fs/index.d.ts +2 -0
- package/fs/watch-files.d.ts +22 -0
- package/index.d.ts +6 -6
- package/index.js +1 -1
- package/llm/llm-tool-handlers.d.ts +1 -1
- package/net/index.d.ts +5 -1
- package/net/ip-address.d.ts +2 -0
- package/net/outbound-request.d.ts +46 -0
- package/net/outbound-url.d.ts +18 -0
- package/package.json +3 -3
- package/serialization/canonical-json.d.ts +2 -0
- package/serialization/index.d.ts +1 -0
- package/stdio-bridge/claude-code-channels.d.ts +28 -0
- package/stdio-bridge/notification-stream.d.ts +29 -0
- package/stdio-bridge/sse-frames.d.ts +8 -0
- package/stdio-bridge/upstream-client.d.ts +13 -0
- package/storage/adapters/filesystem.d.ts +1 -1
- package/storage/adapters/indexeddb.d.ts +1 -1
- package/storage/adapters/localstorage.d.ts +1 -1
- package/storage/encrypted-typed-storage.d.ts +2 -2
- package/storage/typed-storage.d.ts +2 -2
|
@@ -1,10 +1,20 @@
|
|
|
1
1
|
// libs/utils/src/stdio-bridge/upstream-client.ts
|
|
2
|
-
|
|
2
|
+
import {
|
|
3
|
+
advertisesChannels,
|
|
4
|
+
declaringChannels,
|
|
5
|
+
DISCOVER_HEADERS,
|
|
6
|
+
discoverRequest,
|
|
7
|
+
namesProtocol20260728,
|
|
8
|
+
serverRevisionsOf,
|
|
9
|
+
unsupportedProtocolVersion
|
|
10
|
+
} from "./claude-code-channels.mjs";
|
|
11
|
+
import { createNotificationStream, SESSION_HEADER } from "./notification-stream.mjs";
|
|
12
|
+
import { relaySseFrames } from "./sse-frames.mjs";
|
|
3
13
|
var END_SESSION_TIMEOUT_MS = 2e3;
|
|
4
|
-
var
|
|
5
|
-
function
|
|
6
|
-
|
|
7
|
-
return `frontmcp-dev-bridge
|
|
14
|
+
var bridgeRequestCounter = 0;
|
|
15
|
+
function nextBridgeId(purpose) {
|
|
16
|
+
bridgeRequestCounter += 1;
|
|
17
|
+
return `frontmcp-dev-bridge:${purpose}:${bridgeRequestCounter}`;
|
|
8
18
|
}
|
|
9
19
|
function initializedNotification() {
|
|
10
20
|
return { jsonrpc: "2.0", method: "notifications/initialized" };
|
|
@@ -18,17 +28,31 @@ function createHttpUpstream(options) {
|
|
|
18
28
|
const { log, url, onFrame } = options;
|
|
19
29
|
const abortControllers = /* @__PURE__ */ new Set();
|
|
20
30
|
let sessionId;
|
|
21
|
-
|
|
31
|
+
let revisions;
|
|
32
|
+
let streamAnswered = Promise.resolve();
|
|
33
|
+
const notifications = createNotificationStream({
|
|
34
|
+
url,
|
|
35
|
+
headers: options.headers,
|
|
36
|
+
fetch: options.fetch,
|
|
37
|
+
log,
|
|
38
|
+
onFrame,
|
|
39
|
+
onLost: options.onNotificationStreamLost
|
|
40
|
+
});
|
|
41
|
+
function sessionHeaders(frame) {
|
|
42
|
+
return sessionId && frame.method !== "initialize" ? { [SESSION_HEADER]: sessionId } : {};
|
|
43
|
+
}
|
|
44
|
+
async function post(frame, deliver, statelessHeaders) {
|
|
22
45
|
const abortController = new AbortController();
|
|
23
46
|
abortControllers.add(abortController);
|
|
24
47
|
const signal = abortController.signal;
|
|
25
48
|
try {
|
|
49
|
+
if (frame.method !== "initialize") await streamAnswered;
|
|
26
50
|
const headers = {
|
|
27
51
|
...options.headers,
|
|
52
|
+
...statelessHeaders ?? sessionHeaders(frame),
|
|
28
53
|
"content-type": "application/json",
|
|
29
54
|
accept: "application/json, text/event-stream"
|
|
30
55
|
};
|
|
31
|
-
if (sessionId && frame.method !== "initialize") headers[SESSION_HEADER] = sessionId;
|
|
32
56
|
const res = await (options.fetch ?? fetch)(url, {
|
|
33
57
|
method: "POST",
|
|
34
58
|
redirect: "error",
|
|
@@ -40,40 +64,21 @@ function createHttpUpstream(options) {
|
|
|
40
64
|
log.warn("http-upstream-non-ok", { status: res.status, method: frame.method });
|
|
41
65
|
throw new Error(`upstream returned ${res.status} for ${frame.method ?? "request"}`);
|
|
42
66
|
}
|
|
43
|
-
const
|
|
44
|
-
if (
|
|
45
|
-
sessionId =
|
|
67
|
+
const startedSession = frame.method === "initialize" ? res.headers.get(SESSION_HEADER) : null;
|
|
68
|
+
if (startedSession) {
|
|
69
|
+
sessionId = startedSession;
|
|
46
70
|
log.info("http-upstream-session");
|
|
47
71
|
}
|
|
72
|
+
const streamOfSession = startedSession && !signal.aborted ? notifications.follow(startedSession) : void 0;
|
|
73
|
+
if (streamOfSession) streamAnswered = streamOfSession;
|
|
48
74
|
const contentType = res.headers.get("content-type") ?? "";
|
|
49
75
|
if (contentType.includes("text/event-stream")) {
|
|
50
|
-
|
|
51
|
-
if (!reader) return;
|
|
52
|
-
const decoder = new TextDecoder();
|
|
53
|
-
let buffer = "";
|
|
54
|
-
while (true) {
|
|
55
|
-
const { done, value } = await reader.read();
|
|
56
|
-
if (done) break;
|
|
57
|
-
buffer += decoder.decode(value, { stream: true });
|
|
58
|
-
let nl;
|
|
59
|
-
while ((nl = buffer.indexOf("\n")) >= 0) {
|
|
60
|
-
const line = buffer.slice(0, nl).trim();
|
|
61
|
-
buffer = buffer.slice(nl + 1);
|
|
62
|
-
if (!line.startsWith("data:")) continue;
|
|
63
|
-
const json = line.slice(5).trim();
|
|
64
|
-
if (!json) continue;
|
|
65
|
-
try {
|
|
66
|
-
const parsed = JSON.parse(json);
|
|
67
|
-
await deliver(parsed);
|
|
68
|
-
} catch (err) {
|
|
69
|
-
log.warn("sse-parse-error", { error: err.message, raw: json.slice(0, 200) });
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
}
|
|
76
|
+
if (res.body) await relaySseFrames(res.body, deliver, log);
|
|
73
77
|
} else if (contentType.includes("application/json")) {
|
|
74
78
|
const body = await res.json();
|
|
75
79
|
await deliver(body);
|
|
76
80
|
}
|
|
81
|
+
await streamOfSession;
|
|
77
82
|
} catch (err) {
|
|
78
83
|
if (err.name === "AbortError") {
|
|
79
84
|
log.info("http-upstream-aborted", { method: frame.method });
|
|
@@ -85,23 +90,69 @@ function createHttpUpstream(options) {
|
|
|
85
90
|
abortControllers.delete(abortController);
|
|
86
91
|
}
|
|
87
92
|
}
|
|
93
|
+
function toServer(initialize) {
|
|
94
|
+
return options.claudeCodeChannels ? declaringChannels(initialize) : initialize;
|
|
95
|
+
}
|
|
96
|
+
function refreshRevisions(initializeResult) {
|
|
97
|
+
if (revisions && revisions.pushesChannels !== advertisesChannels(initializeResult)) revisions = void 0;
|
|
98
|
+
}
|
|
99
|
+
async function discoverRevisions() {
|
|
100
|
+
const request = discoverRequest(nextBridgeId("discover"));
|
|
101
|
+
let result;
|
|
102
|
+
try {
|
|
103
|
+
await post(
|
|
104
|
+
request,
|
|
105
|
+
(frame) => {
|
|
106
|
+
if (frame.id === request.id) result = frame.result;
|
|
107
|
+
},
|
|
108
|
+
DISCOVER_HEADERS
|
|
109
|
+
);
|
|
110
|
+
} catch {
|
|
111
|
+
return void 0;
|
|
112
|
+
}
|
|
113
|
+
return serverRevisionsOf(result);
|
|
114
|
+
}
|
|
115
|
+
async function declined(frame) {
|
|
116
|
+
revisions ??= await discoverRevisions();
|
|
117
|
+
if (!revisions?.pushesChannels) return false;
|
|
118
|
+
if (frame.id !== void 0 && frame.id !== null) {
|
|
119
|
+
await onFrame(unsupportedProtocolVersion(frame, revisions.supported));
|
|
120
|
+
}
|
|
121
|
+
return true;
|
|
122
|
+
}
|
|
123
|
+
async function sendInitialize(initialize) {
|
|
124
|
+
await post(toServer(initialize), async (frame) => {
|
|
125
|
+
if (frame.id === initialize.id) refreshRevisions(frame.result);
|
|
126
|
+
await onFrame(frame);
|
|
127
|
+
});
|
|
128
|
+
}
|
|
88
129
|
return {
|
|
89
|
-
send
|
|
130
|
+
async send(frame) {
|
|
131
|
+
if (frame.method === "initialize") return sendInitialize(frame);
|
|
132
|
+
if (options.claudeCodeChannels && namesProtocol20260728(frame) && await declined(frame)) return;
|
|
133
|
+
await post(frame, onFrame);
|
|
134
|
+
},
|
|
90
135
|
async reinitialize(initialize, initialized) {
|
|
91
|
-
const id =
|
|
136
|
+
const id = nextBridgeId("reinitialize");
|
|
92
137
|
let response;
|
|
93
|
-
await post({ ...initialize, id }, async (frame) => {
|
|
138
|
+
await post({ ...toServer(initialize), id }, async (frame) => {
|
|
94
139
|
if (frame.id === id) response = frame;
|
|
95
140
|
else await onFrame(frame);
|
|
96
141
|
});
|
|
97
142
|
const result = resultOf(response, "initialize");
|
|
143
|
+
refreshRevisions(result);
|
|
98
144
|
if (initialized) await post(initializedNotification(), onFrame);
|
|
99
145
|
return result;
|
|
100
146
|
},
|
|
147
|
+
leaveSession() {
|
|
148
|
+
sessionId = void 0;
|
|
149
|
+
void notifications.follow(void 0);
|
|
150
|
+
},
|
|
101
151
|
async endSession() {
|
|
102
152
|
const ending = sessionId;
|
|
103
153
|
if (!ending) return;
|
|
104
154
|
sessionId = void 0;
|
|
155
|
+
void notifications.follow(void 0);
|
|
105
156
|
try {
|
|
106
157
|
const res = await (options.fetch ?? fetch)(url, {
|
|
107
158
|
method: "DELETE",
|
|
@@ -115,6 +166,7 @@ function createHttpUpstream(options) {
|
|
|
115
166
|
}
|
|
116
167
|
},
|
|
117
168
|
close: async () => {
|
|
169
|
+
void notifications.follow(void 0);
|
|
118
170
|
for (const ac of abortControllers) ac.abort();
|
|
119
171
|
abortControllers.clear();
|
|
120
172
|
}
|
|
@@ -158,7 +210,7 @@ function createPipeUpstream(options) {
|
|
|
158
210
|
return {
|
|
159
211
|
send,
|
|
160
212
|
async reinitialize(initialize, initialized) {
|
|
161
|
-
const id =
|
|
213
|
+
const id = nextBridgeId("reinitialize");
|
|
162
214
|
let timer;
|
|
163
215
|
const response = new Promise((resolve, reject) => {
|
|
164
216
|
pending.set(id, resolve);
|
|
@@ -1,9 +1,9 @@
|
|
|
1
1
|
// libs/utils/src/storage/adapters/filesystem.ts
|
|
2
|
-
import {
|
|
2
|
+
import { bytesToHex, randomBytes } from "../../crypto/index.mjs";
|
|
3
|
+
import { ensureDir, fileExists, mkdir, readdir, readJSON, rename, unlink, writeFile } from "../../fs/index.mjs";
|
|
3
4
|
import { StorageOperationError } from "../errors.mjs";
|
|
4
5
|
import { globToRegex } from "../utils/pattern.mjs";
|
|
5
|
-
import {
|
|
6
|
-
import { randomBytes, bytesToHex } from "../../crypto/index.mjs";
|
|
6
|
+
import { BaseStorageAdapter } from "./base.mjs";
|
|
7
7
|
var FileSystemStorageAdapter = class extends BaseStorageAdapter {
|
|
8
8
|
backendName = "filesystem";
|
|
9
9
|
baseDir;
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
// libs/utils/src/storage/adapters/indexeddb.ts
|
|
2
|
-
import { BaseStorageAdapter } from "./base.mjs";
|
|
3
2
|
import { matchesPattern } from "../utils/pattern.mjs";
|
|
3
|
+
import { BaseStorageAdapter } from "./base.mjs";
|
|
4
4
|
var IndexedDBStorageAdapter = class extends BaseStorageAdapter {
|
|
5
5
|
backendName = "indexeddb";
|
|
6
6
|
dbName;
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
// libs/utils/src/storage/adapters/localstorage.ts
|
|
2
|
-
import {
|
|
3
|
-
import { encryptAesGcm, decryptAesGcm, randomBytes, base64urlEncode, base64urlDecode } from "../../crypto/index.mjs";
|
|
2
|
+
import { base64urlDecode, base64urlEncode, decryptAesGcm, encryptAesGcm, randomBytes } from "../../crypto/index.mjs";
|
|
4
3
|
import { matchesPattern } from "../utils/pattern.mjs";
|
|
4
|
+
import { BaseStorageAdapter } from "./base.mjs";
|
|
5
5
|
var LocalStorageAdapter = class extends BaseStorageAdapter {
|
|
6
6
|
backendName = "localstorage";
|
|
7
7
|
prefix;
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
// libs/utils/src/storage/encrypted-typed-storage.ts
|
|
2
|
-
import {
|
|
2
|
+
import { base64urlDecode, base64urlEncode, decryptAesGcm, encryptAesGcm, hkdfSha256, randomBytes } from "../crypto/index.mjs";
|
|
3
3
|
import { EncryptedStorageError } from "./errors.mjs";
|
|
4
4
|
var textEncoder = new TextEncoder();
|
|
5
5
|
var textDecoder = new TextDecoder();
|
package/crypto/index.d.ts
CHANGED
|
@@ -162,4 +162,5 @@ export { type EncryptedBlob, EncryptedBlobError, encryptValue, decryptValue, try
|
|
|
162
162
|
export { MIN_CODE_VERIFIER_LENGTH, MAX_CODE_VERIFIER_LENGTH, DEFAULT_CODE_VERIFIER_LENGTH, PkceError, generateCodeVerifier, generateCodeChallenge, verifyCodeChallenge, generatePkcePair, isValidCodeVerifier, isValidCodeChallenge, type PkcePair, } from './pkce';
|
|
163
163
|
export { type SecretData, type SecretPersistenceOptions, type SecretValidationResult, secretDataSchema, validateSecretData, parseSecretData, isSecretPersistenceEnabled, resolveSecretPath, loadSecret, saveSecret, deleteSecret, generateSecret, createSecretData, getOrCreateSecret, clearCachedSecret, isSecretCached, } from './secret-persistence';
|
|
164
164
|
export { type SignedData, type HmacSigningConfig, signData, verifyData, isSignedData, verifyOrParseData, } from './hmac-signing';
|
|
165
|
+
export { WEBHOOK_ID_HEADER, WEBHOOK_TIMESTAMP_HEADER, WEBHOOK_SIGNATURE_HEADER, WEBHOOK_SIGNATURE_TOLERANCE_SECONDS, signingKeyOf, isStandardWebhookSecret, generateStandardWebhookSecret, generateWebhookMessageId, signWebhookMessage, webhookSignatureHeaders, verifyWebhookSignature, type WebhookMessage, type SignedWebhookMessage, type WebhookSignatureCheck, } from './standard-webhooks';
|
|
165
166
|
export { 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 './key-persistence';
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @module @frontmcp/utils/key-persistence
|
|
8
8
|
*/
|
|
9
9
|
import type { StorageAdapter } from '../../storage/types';
|
|
10
|
-
import type { AnyKeyData,
|
|
10
|
+
import type { AnyKeyData, AsymmetricKeyData, CreateSecretOptions, KeyPersistenceOptions, SecretKeyData } from './types';
|
|
11
11
|
/**
|
|
12
12
|
* KeyPersistence provides a unified API for storing and retrieving
|
|
13
13
|
* cryptographic keys with any storage backend.
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/** Standard Webhooks signatures (https://www.standardwebhooks.com): HMAC-SHA256 over `<id>.<timestamp>.<body>`. */
|
|
2
|
+
export declare const WEBHOOK_ID_HEADER = "webhook-id";
|
|
3
|
+
export declare const WEBHOOK_TIMESTAMP_HEADER = "webhook-timestamp";
|
|
4
|
+
export declare const WEBHOOK_SIGNATURE_HEADER = "webhook-signature";
|
|
5
|
+
/** How far a signed timestamp may be from the verifier's clock, in seconds. */
|
|
6
|
+
export declare const WEBHOOK_SIGNATURE_TOLERANCE_SECONDS = 300;
|
|
7
|
+
export interface WebhookMessage {
|
|
8
|
+
/** The `webhook-id`, kept across the retries of one message. */
|
|
9
|
+
id: string;
|
|
10
|
+
/** The Unix time of this attempt, in whole seconds. */
|
|
11
|
+
timestamp: number;
|
|
12
|
+
/** The request body, exactly as it is sent. */
|
|
13
|
+
body: string;
|
|
14
|
+
}
|
|
15
|
+
export interface SignedWebhookMessage {
|
|
16
|
+
id?: string;
|
|
17
|
+
timestamp?: string;
|
|
18
|
+
signature?: string;
|
|
19
|
+
body: string;
|
|
20
|
+
}
|
|
21
|
+
export type WebhookSignatureCheck = 'valid' | 'missing' | 'stale' | 'mismatch';
|
|
22
|
+
/** The HMAC key of a secret: a `whsec_` secret is base64 after the prefix, any other its UTF-8 bytes; never empty. */
|
|
23
|
+
export declare function signingKeyOf(secret: string): Uint8Array;
|
|
24
|
+
/** Whether a secret is `whsec_` followed by base64, padded or not, that decodes to 24 to 64 bytes. */
|
|
25
|
+
export declare function isStandardWebhookSecret(secret: string): boolean;
|
|
26
|
+
/** A new `whsec_` secret of 32 random bytes. */
|
|
27
|
+
export declare function generateStandardWebhookSecret(): string;
|
|
28
|
+
/** A new `webhook-id`, `msg_<random>` or `msg_<kind>_<random>`: ASCII letters, digits, `_` and `-` only. */
|
|
29
|
+
export declare function generateWebhookMessageId(kind?: string): string;
|
|
30
|
+
/** The `webhook-signature` of a message: one `v1,<base64>` per signing key, separated by a space. */
|
|
31
|
+
export declare function signWebhookMessage(message: WebhookMessage, signingKeys: readonly Uint8Array[]): string;
|
|
32
|
+
/** The three headers that sign a message with every signing key. */
|
|
33
|
+
export declare function webhookSignatureHeaders(message: WebhookMessage, signingKeys: readonly Uint8Array[]): Record<string, string>;
|
|
34
|
+
/** Checks a signed message: a timestamp within the tolerance of `now`, and a `v1` signature one of the keys gives. */
|
|
35
|
+
export declare function verifyWebhookSignature(message: SignedWebhookMessage, signingKeys: readonly Uint8Array[], now?: number): WebhookSignatureCheck;
|
|
@@ -42,11 +42,11 @@ export declare const entryAvailabilitySchema: import("@frontmcp/lazy-zod").ZodOb
|
|
|
42
42
|
provider: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
43
43
|
target: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
44
44
|
surface: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodEnum<{
|
|
45
|
+
agent: "agent";
|
|
45
46
|
cli: "cli";
|
|
46
47
|
mcp: "mcp";
|
|
47
48
|
"http-trigger": "http-trigger";
|
|
48
49
|
job: "job";
|
|
49
|
-
agent: "agent";
|
|
50
50
|
webmcp: "webmcp";
|
|
51
51
|
}>>>;
|
|
52
52
|
env: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
package/env/runtime-context.d.ts
CHANGED
|
@@ -98,11 +98,11 @@ export declare const entryAvailabilitySchema: import("@frontmcp/lazy-zod").ZodOb
|
|
|
98
98
|
provider: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
99
99
|
target: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|
|
100
100
|
surface: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodEnum<{
|
|
101
|
+
agent: "agent";
|
|
101
102
|
cli: "cli";
|
|
102
103
|
mcp: "mcp";
|
|
103
104
|
"http-trigger": "http-trigger";
|
|
104
105
|
job: "job";
|
|
105
|
-
agent: "agent";
|
|
106
106
|
webmcp: "webmcp";
|
|
107
107
|
}>>>;
|
|
108
108
|
env: import("@frontmcp/lazy-zod").ZodOptional<import("@frontmcp/lazy-zod").ZodArray<import("@frontmcp/lazy-zod").ZodString>>;
|