@frontmcp/sdk 1.7.2 → 1.8.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/agent/agent.scope.d.ts +12 -0
- package/agent/agent.scope.d.ts.map +1 -1
- package/auth/auth.registry.d.ts.map +1 -1
- package/auth/flows/oauth.authorize.flow.d.ts.map +1 -1
- package/auth/flows/session.verify.flow.d.ts +19 -1
- package/auth/flows/session.verify.flow.d.ts.map +1 -1
- package/auth/instances/instance.local-primary-auth.d.ts +2 -2
- package/auth/instances/instance.local-primary-auth.d.ts.map +1 -1
- package/auth/session/utils/session-id.utils.d.ts +11 -4
- package/auth/session/utils/session-id.utils.d.ts.map +1 -1
- package/common/metadata/app.metadata.d.ts +24 -0
- package/common/metadata/app.metadata.d.ts.map +1 -1
- package/common/metadata/front-mcp.metadata.d.ts +105 -0
- package/common/metadata/front-mcp.metadata.d.ts.map +1 -1
- package/common/tokens/server.tokens.d.ts +1 -0
- package/common/tokens/server.tokens.d.ts.map +1 -1
- package/common/types/options/auth/index.d.ts +4 -2
- package/common/types/options/auth/index.d.ts.map +1 -1
- package/common/utils/path.utils.d.ts +29 -0
- package/common/utils/path.utils.d.ts.map +1 -1
- package/context/frontmcp-context-storage.d.ts +3 -1
- package/context/frontmcp-context-storage.d.ts.map +1 -1
- package/context/metadata.utils.d.ts +29 -6
- package/context/metadata.utils.d.ts.map +1 -1
- package/errors/auth-internal.errors.d.ts +1 -1
- package/errors/auth-internal.errors.d.ts.map +1 -1
- package/errors/index.d.ts +1 -1
- package/errors/index.d.ts.map +1 -1
- package/esm/index.mjs +468 -170
- package/flows/flow.instance.d.ts.map +1 -1
- package/front-mcp/front-mcp.d.ts.map +1 -1
- package/front-mcp/front-mcp.providers.d.ts +52 -0
- package/front-mcp/front-mcp.providers.d.ts.map +1 -1
- package/index.js +882 -581
- package/job/execution/job-execution.manager.d.ts.map +1 -1
- package/package.json +10 -10
- package/scope/flows/http.request.flow.d.ts.map +1 -1
- package/scope/scope.instance.d.ts.map +1 -1
- package/server/adapters/express.host.adapter.d.ts.map +1 -1
- package/tool/ui/ui-shared.d.ts.map +1 -1
- package/transport/web-fetch-handler.d.ts +22 -1
- package/transport/web-fetch-handler.d.ts.map +1 -1
- package/workflow/engine/workflow-step.executor.d.ts +12 -4
- package/workflow/engine/workflow-step.executor.d.ts.map +1 -1
- package/workflow/engine/workflow.engine.d.ts +2 -4
- package/workflow/engine/workflow.engine.d.ts.map +1 -1
package/esm/index.mjs
CHANGED
|
@@ -679,6 +679,7 @@ var init_server_tokens = __esm({
|
|
|
679
679
|
reinitialize: tokenFactory.meta("reinitialize"),
|
|
680
680
|
webRequest: tokenFactory.meta("webRequest"),
|
|
681
681
|
webCtx: tokenFactory.meta("webCtx"),
|
|
682
|
+
webEnv: tokenFactory.meta("webEnv"),
|
|
682
683
|
webTransport: tokenFactory.meta("webTransport")
|
|
683
684
|
};
|
|
684
685
|
}
|
|
@@ -1938,6 +1939,7 @@ import {
|
|
|
1938
1939
|
localDcrConfigSchema
|
|
1939
1940
|
} from "@frontmcp/auth";
|
|
1940
1941
|
import { publicAuthOptionsSchema } from "@frontmcp/auth";
|
|
1942
|
+
import { staticAuthOptionsSchema } from "@frontmcp/auth";
|
|
1941
1943
|
import { transparentAuthOptionsSchema } from "@frontmcp/auth";
|
|
1942
1944
|
import {
|
|
1943
1945
|
localAuthSchema,
|
|
@@ -1952,6 +1954,7 @@ import { appAuthOptionsSchema } from "@frontmcp/auth";
|
|
|
1952
1954
|
import {
|
|
1953
1955
|
parseAuthOptions,
|
|
1954
1956
|
isPublicMode,
|
|
1957
|
+
isStaticMode,
|
|
1955
1958
|
isTransparentMode,
|
|
1956
1959
|
isLocalMode,
|
|
1957
1960
|
isRemoteMode,
|
|
@@ -3152,6 +3155,10 @@ var init_front_mcp_metadata = __esm({
|
|
|
3152
3155
|
output: outputPolicySchema.optional(),
|
|
3153
3156
|
jobs: z24.object({
|
|
3154
3157
|
enabled: z24.boolean(),
|
|
3158
|
+
// Opt-in for `register_job` / `register_workflow` (GHSA-58v2-gpcc-jmqv).
|
|
3159
|
+
// Omitting it here would let Zod strip the flag before the scope reads
|
|
3160
|
+
// it, leaving the documented escape hatch permanently off.
|
|
3161
|
+
allowDynamicRegistration: z24.boolean().optional(),
|
|
3155
3162
|
store: z24.object({
|
|
3156
3163
|
redis: redisOptionsSchema.optional(),
|
|
3157
3164
|
keyPrefix: z24.string().optional()
|
|
@@ -5351,6 +5358,8 @@ import {
|
|
|
5351
5358
|
TokenStoreRequiredError,
|
|
5352
5359
|
NoProviderIdError,
|
|
5353
5360
|
TokenLeakDetectedError,
|
|
5361
|
+
JwtSecretRequiredError,
|
|
5362
|
+
JwtSecretWeakError,
|
|
5354
5363
|
SessionSecretRequiredError,
|
|
5355
5364
|
CredentialProviderAlreadyRegisteredError,
|
|
5356
5365
|
AuthProvidersNotConfiguredError,
|
|
@@ -5740,6 +5749,8 @@ __export(errors_exports, {
|
|
|
5740
5749
|
InvalidUseValueError: () => InvalidUseValueError,
|
|
5741
5750
|
InvokeStateMissingKeyError: () => InvokeStateMissingKeyError,
|
|
5742
5751
|
JobNotAuthorizedError: () => JobNotAuthorizedError,
|
|
5752
|
+
JwtSecretRequiredError: () => JwtSecretRequiredError,
|
|
5753
|
+
JwtSecretWeakError: () => JwtSecretWeakError,
|
|
5743
5754
|
MCP_ERROR_CODES: () => MCP_ERROR_CODES,
|
|
5744
5755
|
McpError: () => McpError,
|
|
5745
5756
|
MethodNotImplementedError: () => MethodNotImplementedError,
|
|
@@ -9349,22 +9360,24 @@ function hasValidSessionStructure(dec) {
|
|
|
9349
9360
|
function isValidSessionPayload(dec, sig) {
|
|
9350
9361
|
return hasValidSessionStructure(dec) && dec.authSig === sig;
|
|
9351
9362
|
}
|
|
9352
|
-
function isValidPublicSessionPayload(dec) {
|
|
9363
|
+
function isValidPublicSessionPayload(dec, expectedAuthSig = "public") {
|
|
9353
9364
|
if (typeof dec !== "object" || dec === null) return false;
|
|
9354
9365
|
const d = dec;
|
|
9355
|
-
return typeof d["nodeId"] === "string" && d["authSig"] ===
|
|
9366
|
+
return typeof d["nodeId"] === "string" && d["authSig"] === expectedAuthSig && typeof d["uuid"] === "string" && typeof d["iat"] === "number" && // `isPublic` is set only for public mode, so it must track the signature —
|
|
9367
|
+
// a static-mode session must never decrypt as a public one.
|
|
9368
|
+
d["isPublic"] === (expectedAuthSig === "public");
|
|
9356
9369
|
}
|
|
9357
9370
|
function decryptSessionId(sessionId, sig) {
|
|
9358
9371
|
const dec = safeDecrypt(sessionId);
|
|
9359
9372
|
return isValidSessionPayload(dec, sig) ? dec : null;
|
|
9360
9373
|
}
|
|
9361
|
-
function decryptPublicSession(sessionId) {
|
|
9374
|
+
function decryptPublicSession(sessionId, expectedAuthSig = "public") {
|
|
9362
9375
|
const cached = cache.get(sessionId);
|
|
9363
|
-
if (cached && isValidPublicSessionPayload(cached)) {
|
|
9376
|
+
if (cached && isValidPublicSessionPayload(cached, expectedAuthSig)) {
|
|
9364
9377
|
return cached;
|
|
9365
9378
|
}
|
|
9366
9379
|
const dec = safeDecrypt(sessionId);
|
|
9367
|
-
if (isValidPublicSessionPayload(dec)) {
|
|
9380
|
+
if (isValidPublicSessionPayload(dec, expectedAuthSig)) {
|
|
9368
9381
|
cache.set(sessionId, dec);
|
|
9369
9382
|
return dec;
|
|
9370
9383
|
}
|
|
@@ -18182,7 +18195,7 @@ function isUIResourceUri(uri) {
|
|
|
18182
18195
|
return uri.startsWith("ui://");
|
|
18183
18196
|
}
|
|
18184
18197
|
function parseWidgetUri(uri) {
|
|
18185
|
-
const match = uri.match(
|
|
18198
|
+
const match = uri.match(WIDGET_URI_PATTERN);
|
|
18186
18199
|
if (!match) return null;
|
|
18187
18200
|
return { toolName: match[1], extension: match[2] };
|
|
18188
18201
|
}
|
|
@@ -18191,7 +18204,7 @@ function getUIResourceMimeType(_platformOrUri) {
|
|
|
18191
18204
|
if (_platformOrUri?.endsWith(".css")) return "text/css";
|
|
18192
18205
|
return MCP_APPS_MIME_TYPE;
|
|
18193
18206
|
}
|
|
18194
|
-
var ToolUIRegistry;
|
|
18207
|
+
var ToolUIRegistry, WIDGET_URI_PATTERN;
|
|
18195
18208
|
var init_ui_shared = __esm({
|
|
18196
18209
|
"libs/sdk/src/tool/ui/ui-shared.ts"() {
|
|
18197
18210
|
"use strict";
|
|
@@ -18316,6 +18329,7 @@ var init_ui_shared = __esm({
|
|
|
18316
18329
|
return { meta: result.meta };
|
|
18317
18330
|
}
|
|
18318
18331
|
};
|
|
18332
|
+
WIDGET_URI_PATTERN = /^ui:\/\/widget\/([A-Za-z0-9_:@-]+)\.(html|js|css)$/;
|
|
18319
18333
|
}
|
|
18320
18334
|
});
|
|
18321
18335
|
|
|
@@ -23202,8 +23216,180 @@ var init_adapter_registry = __esm({
|
|
|
23202
23216
|
}
|
|
23203
23217
|
});
|
|
23204
23218
|
|
|
23219
|
+
// libs/sdk/src/common/utils/path.utils.ts
|
|
23220
|
+
import { joinPath, trimSlashes } from "@frontmcp/utils";
|
|
23221
|
+
import { trimSlashes as trimSlashes2, joinPath as joinPath2 } from "@frontmcp/utils";
|
|
23222
|
+
function normalizeEntryPrefix(entryPath) {
|
|
23223
|
+
const t = trimSlashes(entryPath ?? "");
|
|
23224
|
+
return t ? `/${t}` : "";
|
|
23225
|
+
}
|
|
23226
|
+
function resolveEntryPath(entryPath) {
|
|
23227
|
+
if (entryPath !== void 0) return entryPath;
|
|
23228
|
+
return process.env["FRONTMCP_HTTP_ENTRY_PATH"] ?? "";
|
|
23229
|
+
}
|
|
23230
|
+
function normalizeScopeBase(scopeBase) {
|
|
23231
|
+
const t = trimSlashes(scopeBase ?? "");
|
|
23232
|
+
return t ? `/${t}` : "";
|
|
23233
|
+
}
|
|
23234
|
+
function readPublicUrlPin() {
|
|
23235
|
+
try {
|
|
23236
|
+
if (typeof process !== "undefined" && process.env) {
|
|
23237
|
+
const v = process.env["FRONTMCP_PUBLIC_URL"];
|
|
23238
|
+
if (typeof v === "string" && v.trim()) {
|
|
23239
|
+
return v.trim().replace(/\/+$/, "");
|
|
23240
|
+
}
|
|
23241
|
+
}
|
|
23242
|
+
} catch {
|
|
23243
|
+
}
|
|
23244
|
+
return void 0;
|
|
23245
|
+
}
|
|
23246
|
+
function isPublicUrlPinned() {
|
|
23247
|
+
return readPublicUrlPin() !== void 0;
|
|
23248
|
+
}
|
|
23249
|
+
function isProxyTrusted() {
|
|
23250
|
+
try {
|
|
23251
|
+
if (typeof process !== "undefined" && process.env) {
|
|
23252
|
+
const v = process.env["FRONTMCP_TRUST_PROXY"];
|
|
23253
|
+
return typeof v === "string" && /^(1|true|yes|on)$/i.test(v.trim());
|
|
23254
|
+
}
|
|
23255
|
+
} catch {
|
|
23256
|
+
}
|
|
23257
|
+
return false;
|
|
23258
|
+
}
|
|
23259
|
+
function getRequestBaseUrl(req, entryPath) {
|
|
23260
|
+
const pin = readPublicUrlPin();
|
|
23261
|
+
if (pin) {
|
|
23262
|
+
return `${pin}${entryPath ?? ""}`;
|
|
23263
|
+
}
|
|
23264
|
+
const trustProxy = isProxyTrusted();
|
|
23265
|
+
const fwdProto = trustProxy ? req.headers["x-forwarded-proto"] : void 0;
|
|
23266
|
+
const fwdHost = trustProxy ? req.headers["x-forwarded-host"] : void 0;
|
|
23267
|
+
const proto = fwdProto || req.protocol || "http";
|
|
23268
|
+
const host = fwdHost || req.headers["host"];
|
|
23269
|
+
return `${proto}://${host}${entryPath ?? ""}`;
|
|
23270
|
+
}
|
|
23271
|
+
function computeIssuer(req, entryPath, scopeBase) {
|
|
23272
|
+
const entryPrefix = normalizeEntryPrefix(entryPath);
|
|
23273
|
+
const scope = normalizeScopeBase(scopeBase);
|
|
23274
|
+
return `${getRequestBaseUrl(req)}${entryPrefix}${scope}`;
|
|
23275
|
+
}
|
|
23276
|
+
function computeResource(req, entryPath, scopeBase) {
|
|
23277
|
+
const entryPrefix = normalizeEntryPrefix(entryPath);
|
|
23278
|
+
const scope = normalizeScopeBase(scopeBase);
|
|
23279
|
+
return `${getRequestBaseUrl(req)}${entryPrefix}${scope}`;
|
|
23280
|
+
}
|
|
23281
|
+
function normalizeResourceUri(uri) {
|
|
23282
|
+
try {
|
|
23283
|
+
const url = new URL(uri);
|
|
23284
|
+
let normalized = `${url.protocol}//${url.hostname}`;
|
|
23285
|
+
const isDefaultPort = url.protocol === "https:" && url.port === "443" || url.protocol === "http:" && url.port === "80";
|
|
23286
|
+
if (url.port && !isDefaultPort) {
|
|
23287
|
+
normalized += `:${url.port}`;
|
|
23288
|
+
}
|
|
23289
|
+
let path3 = url.pathname;
|
|
23290
|
+
if (path3.length > 1 && path3.endsWith("/")) {
|
|
23291
|
+
path3 = path3.slice(0, -1);
|
|
23292
|
+
}
|
|
23293
|
+
normalized += path3;
|
|
23294
|
+
return normalized;
|
|
23295
|
+
} catch {
|
|
23296
|
+
return uri;
|
|
23297
|
+
}
|
|
23298
|
+
}
|
|
23299
|
+
function resourceUriMatches(provided, canonical) {
|
|
23300
|
+
return normalizeResourceUri(provided) === normalizeResourceUri(canonical);
|
|
23301
|
+
}
|
|
23302
|
+
function urlToSafeId(url) {
|
|
23303
|
+
const u = new URL(url);
|
|
23304
|
+
const raw = (u.host + (u.pathname && u.pathname !== "/" ? u.pathname : "")).replace(/\/+$/, "");
|
|
23305
|
+
return trimSlashes(raw).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
23306
|
+
}
|
|
23307
|
+
function makeWellKnownPaths(name42, entryPrefix, scopeBase = "") {
|
|
23308
|
+
const prefix = normalizeEntryPrefix(entryPrefix);
|
|
23309
|
+
const scope = normalizeScopeBase(scopeBase);
|
|
23310
|
+
const reversed = joinPath(".well-known", name42) + `${prefix}${scope}`;
|
|
23311
|
+
const inPrefixRoot = `${prefix}${joinPath(".well-known", name42)}${scope}`;
|
|
23312
|
+
const inPrefixScope = `${prefix}${scope}${joinPath(".well-known", name42)}`;
|
|
23313
|
+
return /* @__PURE__ */ new Set([reversed, inPrefixRoot, inPrefixScope]);
|
|
23314
|
+
}
|
|
23315
|
+
var init_path_utils = __esm({
|
|
23316
|
+
"libs/sdk/src/common/utils/path.utils.ts"() {
|
|
23317
|
+
"use strict";
|
|
23318
|
+
}
|
|
23319
|
+
});
|
|
23320
|
+
|
|
23205
23321
|
// libs/sdk/src/context/metadata.utils.ts
|
|
23206
|
-
function
|
|
23322
|
+
function isIpv4(value) {
|
|
23323
|
+
const match = IPV4_PATTERN.exec(value);
|
|
23324
|
+
if (!match) return false;
|
|
23325
|
+
return match.slice(1).every((octet) => {
|
|
23326
|
+
if (octet.length > 1 && octet.startsWith("0")) return false;
|
|
23327
|
+
return Number(octet) <= 255;
|
|
23328
|
+
});
|
|
23329
|
+
}
|
|
23330
|
+
function isIpv6(value) {
|
|
23331
|
+
const text = value.includes("%") ? value.slice(0, value.indexOf("%")) : value;
|
|
23332
|
+
if (text.length === 0) return false;
|
|
23333
|
+
let head = text;
|
|
23334
|
+
let embedded = 0;
|
|
23335
|
+
const lastColon = head.lastIndexOf(":");
|
|
23336
|
+
const tail = lastColon === -1 ? "" : head.slice(lastColon + 1);
|
|
23337
|
+
if (tail.includes(".")) {
|
|
23338
|
+
if (!isIpv4(tail)) return false;
|
|
23339
|
+
head = head.slice(0, lastColon + 1);
|
|
23340
|
+
embedded = 2;
|
|
23341
|
+
}
|
|
23342
|
+
const halves = head.split("::");
|
|
23343
|
+
if (halves.length > 2) return false;
|
|
23344
|
+
const countGroups = (part) => {
|
|
23345
|
+
if (part === "") return 0;
|
|
23346
|
+
const groups = part.split(":").filter((group, index, all) => !(group === "" && index === all.length - 1));
|
|
23347
|
+
for (const group of groups) {
|
|
23348
|
+
if (!/^[0-9A-Fa-f]{1,4}$/.test(group)) return null;
|
|
23349
|
+
}
|
|
23350
|
+
return groups.length;
|
|
23351
|
+
};
|
|
23352
|
+
const headCount = countGroups(halves[0]);
|
|
23353
|
+
if (headCount === null) return false;
|
|
23354
|
+
if (halves.length === 1) {
|
|
23355
|
+
return headCount + embedded === 8;
|
|
23356
|
+
}
|
|
23357
|
+
const tailCount = countGroups(halves[1]);
|
|
23358
|
+
if (tailCount === null) return false;
|
|
23359
|
+
return headCount + tailCount + embedded <= 7;
|
|
23360
|
+
}
|
|
23361
|
+
function isIpAddress(value) {
|
|
23362
|
+
const candidate = value.startsWith("[") && value.endsWith("]") ? value.slice(1, -1) : value;
|
|
23363
|
+
return candidate.includes(":") ? isIpv6(candidate) : isIpv4(candidate);
|
|
23364
|
+
}
|
|
23365
|
+
function normalizeIp(value) {
|
|
23366
|
+
if (typeof value !== "string") return void 0;
|
|
23367
|
+
const trimmed = value.trim();
|
|
23368
|
+
if (!trimmed) return void 0;
|
|
23369
|
+
return isIpAddress(trimmed) ? trimmed : void 0;
|
|
23370
|
+
}
|
|
23371
|
+
function readTrustedProxyDepth() {
|
|
23372
|
+
try {
|
|
23373
|
+
if (typeof process !== "undefined" && process.env) {
|
|
23374
|
+
const parsed = Number(process.env["FRONTMCP_TRUSTED_PROXY_DEPTH"]);
|
|
23375
|
+
if (Number.isInteger(parsed) && parsed > 0) return parsed;
|
|
23376
|
+
}
|
|
23377
|
+
} catch {
|
|
23378
|
+
}
|
|
23379
|
+
return 1;
|
|
23380
|
+
}
|
|
23381
|
+
function normalizeDepth(depth) {
|
|
23382
|
+
if (depth === void 0) return readTrustedProxyDepth();
|
|
23383
|
+
return Number.isInteger(depth) && depth > 0 ? depth : readTrustedProxyDepth();
|
|
23384
|
+
}
|
|
23385
|
+
function headerValues(header) {
|
|
23386
|
+
if (typeof header === "string") return header.split(",");
|
|
23387
|
+
if (Array.isArray(header)) {
|
|
23388
|
+
return header.filter((entry) => typeof entry === "string").flatMap((entry) => entry.split(","));
|
|
23389
|
+
}
|
|
23390
|
+
return [];
|
|
23391
|
+
}
|
|
23392
|
+
function extractMetadata(headers, options) {
|
|
23207
23393
|
const customHeaders = {};
|
|
23208
23394
|
for (const [key, value] of Object.entries(headers)) {
|
|
23209
23395
|
if (key.toLowerCase().startsWith("x-frontmcp-") && typeof value === "string") {
|
|
@@ -23214,30 +23400,34 @@ function extractMetadata(headers) {
|
|
|
23214
23400
|
userAgent: typeof headers["user-agent"] === "string" ? headers["user-agent"] : void 0,
|
|
23215
23401
|
contentType: typeof headers["content-type"] === "string" ? headers["content-type"] : void 0,
|
|
23216
23402
|
accept: typeof headers["accept"] === "string" ? headers["accept"] : void 0,
|
|
23217
|
-
clientIp: extractClientIp(headers),
|
|
23403
|
+
clientIp: extractClientIp(headers, options),
|
|
23218
23404
|
customHeaders
|
|
23219
23405
|
};
|
|
23220
23406
|
}
|
|
23221
|
-
function extractClientIp(headers) {
|
|
23222
|
-
const
|
|
23223
|
-
|
|
23224
|
-
|
|
23225
|
-
|
|
23226
|
-
if (Array.isArray(xff) && typeof xff[0] === "string") {
|
|
23227
|
-
return xff[0].split(",")[0]?.trim();
|
|
23407
|
+
function extractClientIp(headers, options) {
|
|
23408
|
+
const peerIp = normalizeIp(options?.peerAddress);
|
|
23409
|
+
const trustProxy = options?.trustProxy ?? isProxyTrusted();
|
|
23410
|
+
if (!trustProxy) {
|
|
23411
|
+
return peerIp;
|
|
23228
23412
|
}
|
|
23229
|
-
const
|
|
23230
|
-
|
|
23231
|
-
|
|
23413
|
+
const depth = normalizeDepth(options?.trustedProxyDepth);
|
|
23414
|
+
const forwarded = headerValues(headers["x-forwarded-for"]).map((entry) => entry.trim()).filter((entry) => entry.length > 0);
|
|
23415
|
+
if (forwarded.length > 0) {
|
|
23416
|
+
if (forwarded.length < depth) return peerIp;
|
|
23417
|
+
return normalizeIp(forwarded[forwarded.length - depth]) ?? peerIp;
|
|
23232
23418
|
}
|
|
23233
|
-
if (
|
|
23234
|
-
|
|
23419
|
+
if (depth === 1) {
|
|
23420
|
+
const realIp = normalizeIp(headerValues(headers["x-real-ip"])[0]);
|
|
23421
|
+
if (realIp) return realIp;
|
|
23235
23422
|
}
|
|
23236
|
-
return
|
|
23423
|
+
return peerIp;
|
|
23237
23424
|
}
|
|
23425
|
+
var IPV4_PATTERN;
|
|
23238
23426
|
var init_metadata_utils = __esm({
|
|
23239
23427
|
"libs/sdk/src/context/metadata.utils.ts"() {
|
|
23240
23428
|
"use strict";
|
|
23429
|
+
init_path_utils();
|
|
23430
|
+
IPV4_PATTERN = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/;
|
|
23241
23431
|
}
|
|
23242
23432
|
});
|
|
23243
23433
|
|
|
@@ -23282,10 +23472,11 @@ var init_frontmcp_context_storage = __esm({
|
|
|
23282
23472
|
* @returns Result of the callback
|
|
23283
23473
|
*/
|
|
23284
23474
|
runFromHeaders(headers, args, fn) {
|
|
23475
|
+
const { peerAddress, ...contextArgs } = args;
|
|
23285
23476
|
const traceContext = parseTraceContext(headers);
|
|
23286
|
-
const metadata = extractMetadata(headers);
|
|
23477
|
+
const metadata = extractMetadata(headers, { peerAddress });
|
|
23287
23478
|
const context = new FrontMcpContext({
|
|
23288
|
-
...
|
|
23479
|
+
...contextArgs,
|
|
23289
23480
|
traceContext,
|
|
23290
23481
|
metadata
|
|
23291
23482
|
});
|
|
@@ -24465,11 +24656,13 @@ var init_flow_instance = __esm({
|
|
|
24465
24656
|
const headerSessionId = typeof headers["mcp-session-id"] === "string" ? headers["mcp-session-id"].trim() : "";
|
|
24466
24657
|
const sessionId = headerSessionId.length > 0 ? headerSessionId : `anon:${randomUUID13()}`;
|
|
24467
24658
|
const scope = this.globalProviders.getActiveScope();
|
|
24659
|
+
const peerAddress = request.socket?.remoteAddress;
|
|
24468
24660
|
return storage.runFromHeaders(
|
|
24469
24661
|
headers,
|
|
24470
24662
|
{
|
|
24471
24663
|
sessionId,
|
|
24472
|
-
scopeId: scope.id
|
|
24664
|
+
scopeId: scope.id,
|
|
24665
|
+
peerAddress
|
|
24473
24666
|
},
|
|
24474
24667
|
async () => {
|
|
24475
24668
|
return this.run(input, deps);
|
|
@@ -34413,13 +34606,13 @@ var init_esm_module_loader = __esm({
|
|
|
34413
34606
|
URL.revokeObjectURL(url);
|
|
34414
34607
|
}
|
|
34415
34608
|
}
|
|
34416
|
-
const { ensureDir, fileExists: fileExists9, sha256Hex:
|
|
34609
|
+
const { ensureDir, fileExists: fileExists9, sha256Hex: sha256Hex12, writeFile } = await import("@frontmcp/utils");
|
|
34417
34610
|
const nodePath = await import("node:path");
|
|
34418
34611
|
const nodeOs = await import("node:os");
|
|
34419
34612
|
const { pathToFileURL } = await import("node:url");
|
|
34420
34613
|
const dir = nodePath.join(nodeOs.tmpdir(), "frontmcp-esm-modules");
|
|
34421
34614
|
await ensureDir(dir);
|
|
34422
|
-
const tempPath = nodePath.join(dir, `${
|
|
34615
|
+
const tempPath = nodePath.join(dir, `${sha256Hex12(bundleContent)}.mjs`);
|
|
34423
34616
|
if (!await fileExists9(tempPath)) {
|
|
34424
34617
|
await writeFile(tempPath, bundleContent);
|
|
34425
34618
|
}
|
|
@@ -36340,6 +36533,7 @@ var init_oauth_authorize_flow = __esm({
|
|
|
36340
36533
|
const localAuth = auth;
|
|
36341
36534
|
const store = localAuth.authorizationStore;
|
|
36342
36535
|
let effectiveIncremental = isIncrementalAuth;
|
|
36536
|
+
let effectivePriorAppIds = priorAuthorizedAppIds;
|
|
36343
36537
|
if (incrementalTicket) {
|
|
36344
36538
|
const claimed = await localAuth.claimIncrementalTicket(
|
|
36345
36539
|
incrementalTicket.jti,
|
|
@@ -36348,7 +36542,13 @@ var init_oauth_authorize_flow = __esm({
|
|
|
36348
36542
|
if (!claimed) {
|
|
36349
36543
|
this.logger.warn("Incremental auth ticket already used \u2014 falling back to an ordinary login");
|
|
36350
36544
|
effectiveIncremental = false;
|
|
36351
|
-
|
|
36545
|
+
effectivePriorAppIds = void 0;
|
|
36546
|
+
this.state.set({
|
|
36547
|
+
isIncrementalAuth: false,
|
|
36548
|
+
targetAppId: void 0,
|
|
36549
|
+
targetToolId: void 0,
|
|
36550
|
+
priorAuthorizedAppIds: void 0
|
|
36551
|
+
});
|
|
36352
36552
|
}
|
|
36353
36553
|
}
|
|
36354
36554
|
let federatedLogin;
|
|
@@ -36407,7 +36607,7 @@ var init_oauth_authorize_flow = __esm({
|
|
|
36407
36607
|
targetAppId: effectiveIncremental ? targetAppId : void 0,
|
|
36408
36608
|
targetToolId: effectiveIncremental ? targetToolId : void 0,
|
|
36409
36609
|
existingSessionId,
|
|
36410
|
-
priorAuthorizedAppIds,
|
|
36610
|
+
priorAuthorizedAppIds: effectivePriorAppIds,
|
|
36411
36611
|
// Federated Login State
|
|
36412
36612
|
federatedLogin,
|
|
36413
36613
|
// Consent State
|
|
@@ -39585,7 +39785,23 @@ import {
|
|
|
39585
39785
|
validateAudience
|
|
39586
39786
|
} from "@frontmcp/auth";
|
|
39587
39787
|
import { z as z71 } from "@frontmcp/lazy-zod";
|
|
39588
|
-
import { getMachineId as getMachineId2, randomUUID as randomUUID20 } from "@frontmcp/utils";
|
|
39788
|
+
import { getMachineId as getMachineId2, randomUUID as randomUUID20, sha256, sha256Hex as sha256Hex9, timingSafeEqual as timingSafeEqual2 } from "@frontmcp/utils";
|
|
39789
|
+
function constantTimeEquals(a, b) {
|
|
39790
|
+
const encoder5 = new TextEncoder();
|
|
39791
|
+
return timingSafeEqual2(sha256(encoder5.encode(a)), sha256(encoder5.encode(b)));
|
|
39792
|
+
}
|
|
39793
|
+
function quoteHeaderParam(value) {
|
|
39794
|
+
return value.replace(/[^\x20-\x21\x23-\x7e]/g, "");
|
|
39795
|
+
}
|
|
39796
|
+
function buildStaticChallenge(options, description) {
|
|
39797
|
+
const scheme = options.scheme.trim();
|
|
39798
|
+
if (!scheme) return "";
|
|
39799
|
+
const parts = [`${quoteHeaderParam(scheme)} realm="${quoteHeaderParam(options.realm)}"`];
|
|
39800
|
+
if (description) {
|
|
39801
|
+
parts.push('error="invalid_token"', `error_description="${quoteHeaderParam(description)}"`);
|
|
39802
|
+
}
|
|
39803
|
+
return parts.join(", ");
|
|
39804
|
+
}
|
|
39589
39805
|
var inputSchema23, stateSchema22, UnauthorizedSchema, AuthorizedSchema, ForbiddenSchema, sessionVerifyOutputSchema, plan22, name22, Stage22, warnedUnpinnedAudience, SessionVerifyFlow;
|
|
39590
39806
|
var init_session_verify_flow = __esm({
|
|
39591
39807
|
"libs/sdk/src/auth/flows/session.verify.flow.ts"() {
|
|
@@ -39626,7 +39842,14 @@ var init_session_verify_flow = __esm({
|
|
|
39626
39842
|
}).describe("403 Forbidden \u2014 token valid but insufficient scope");
|
|
39627
39843
|
sessionVerifyOutputSchema = z71.union([UnauthorizedSchema, AuthorizedSchema, ForbiddenSchema]);
|
|
39628
39844
|
plan22 = {
|
|
39629
|
-
pre: [
|
|
39845
|
+
pre: [
|
|
39846
|
+
"parseInput",
|
|
39847
|
+
"handleStaticToken",
|
|
39848
|
+
"handlePublicMode",
|
|
39849
|
+
"handleAnonymousFallback",
|
|
39850
|
+
"requireAuthorizationHeader",
|
|
39851
|
+
"verifyIfJwt"
|
|
39852
|
+
],
|
|
39630
39853
|
execute: ["deriveUser", "parseSessionHeader", "buildAuthorizedOutput"]
|
|
39631
39854
|
};
|
|
39632
39855
|
name22 = "session:verify";
|
|
@@ -39644,14 +39867,20 @@ var init_session_verify_flow = __esm({
|
|
|
39644
39867
|
* Encapsulates the shared logic for session creation, payload encryption, and user derivation.
|
|
39645
39868
|
*/
|
|
39646
39869
|
createAnonymousSession(options) {
|
|
39647
|
-
const { authMode, issuer, scopes = ["anonymous"], sessionIdHeader } = options;
|
|
39870
|
+
const { authMode, issuer, scopes = ["anonymous"], subject, sessionIdHeader } = options;
|
|
39648
39871
|
this.logger.verbose("createAnonymousSession", { authMode, hasExistingSession: !!sessionIdHeader });
|
|
39649
39872
|
const machineId = getMachineId2();
|
|
39873
|
+
const authSignature = subject ? `${authMode}:${subject}` : authMode;
|
|
39650
39874
|
if (sessionIdHeader) {
|
|
39651
|
-
const existingPayload = decryptPublicSession(sessionIdHeader);
|
|
39875
|
+
const existingPayload = decryptPublicSession(sessionIdHeader, authSignature);
|
|
39652
39876
|
if (existingPayload && existingPayload.nodeId === machineId) {
|
|
39653
39877
|
const anonId = existingPayload.uuid ?? `${existingPayload.iat * 1e3}`;
|
|
39654
|
-
const user2 = {
|
|
39878
|
+
const user2 = {
|
|
39879
|
+
sub: subject ?? `anon:${anonId}`,
|
|
39880
|
+
iss: issuer,
|
|
39881
|
+
name: subject ? "Static token" : "Anonymous",
|
|
39882
|
+
scope: scopes.join(" ")
|
|
39883
|
+
};
|
|
39655
39884
|
this.respond({
|
|
39656
39885
|
kind: "authorized",
|
|
39657
39886
|
authorization: {
|
|
@@ -39666,9 +39895,9 @@ var init_session_verify_flow = __esm({
|
|
|
39666
39895
|
}
|
|
39667
39896
|
const now = Date.now();
|
|
39668
39897
|
const user = {
|
|
39669
|
-
sub: `anon:${randomUUID20()}`,
|
|
39898
|
+
sub: subject ?? `anon:${randomUUID20()}`,
|
|
39670
39899
|
iss: issuer,
|
|
39671
|
-
name: "Anonymous",
|
|
39900
|
+
name: subject ? "Static token" : "Anonymous",
|
|
39672
39901
|
scope: scopes.join(" ")
|
|
39673
39902
|
};
|
|
39674
39903
|
const uuid = randomUUID20();
|
|
@@ -39677,7 +39906,7 @@ var init_session_verify_flow = __esm({
|
|
|
39677
39906
|
const payload = {
|
|
39678
39907
|
uuid,
|
|
39679
39908
|
nodeId: machineId,
|
|
39680
|
-
authSig:
|
|
39909
|
+
authSig: authSignature,
|
|
39681
39910
|
iat: Math.floor(now / 1e3),
|
|
39682
39911
|
isPublic: authMode === "public",
|
|
39683
39912
|
authMode,
|
|
@@ -39727,14 +39956,68 @@ var init_session_verify_flow = __esm({
|
|
|
39727
39956
|
prmUrl
|
|
39728
39957
|
});
|
|
39729
39958
|
}
|
|
39959
|
+
async handleStaticToken() {
|
|
39960
|
+
const authOptions = this.scope.auth?.options;
|
|
39961
|
+
if (!authOptions || !isStaticMode(authOptions)) return;
|
|
39962
|
+
const options = authOptions;
|
|
39963
|
+
const presented = this.readStaticCredential(options);
|
|
39964
|
+
if (!presented) {
|
|
39965
|
+
this.logger.warn("handleStaticToken: no credential presented, returning 401");
|
|
39966
|
+
this.respond({
|
|
39967
|
+
kind: "unauthorized",
|
|
39968
|
+
prmMetadataHeader: buildStaticChallenge(options)
|
|
39969
|
+
});
|
|
39970
|
+
return;
|
|
39971
|
+
}
|
|
39972
|
+
const matched = options.tokens.reduce(
|
|
39973
|
+
(found, candidate) => constantTimeEquals(candidate, presented) ? candidate : found,
|
|
39974
|
+
void 0
|
|
39975
|
+
);
|
|
39976
|
+
if (!matched) {
|
|
39977
|
+
this.logger.warn("handleStaticToken: credential did not match, returning 401");
|
|
39978
|
+
this.respond({
|
|
39979
|
+
kind: "unauthorized",
|
|
39980
|
+
prmMetadataHeader: buildStaticChallenge(options, "The access token is invalid")
|
|
39981
|
+
});
|
|
39982
|
+
return;
|
|
39983
|
+
}
|
|
39984
|
+
this.logger.verbose("handleStaticToken: credential accepted");
|
|
39985
|
+
this.createAnonymousSession({
|
|
39986
|
+
authMode: "static",
|
|
39987
|
+
issuer: "static",
|
|
39988
|
+
scopes: options.scopes,
|
|
39989
|
+
subject: `static:${sha256Hex9(matched).slice(0, 12)}`,
|
|
39990
|
+
sessionIdHeader: this.state.sessionIdHeader
|
|
39991
|
+
});
|
|
39992
|
+
}
|
|
39993
|
+
/**
|
|
39994
|
+
* Pull the credential out of the configured header, stripping the scheme
|
|
39995
|
+
* prefix when one is configured (case-insensitively, per RFC 7235).
|
|
39996
|
+
*/
|
|
39997
|
+
readStaticCredential(options) {
|
|
39998
|
+
const headers = this.rawInput.request.headers ?? {};
|
|
39999
|
+
const raw = headers[options.header.toLowerCase()];
|
|
40000
|
+
const value = (Array.isArray(raw) ? raw[0] : raw)?.trim();
|
|
40001
|
+
if (!value) return void 0;
|
|
40002
|
+
const { scheme } = options;
|
|
40003
|
+
if (!scheme) return value;
|
|
40004
|
+
if (value.slice(0, scheme.length).toLowerCase() !== scheme.toLowerCase()) return void 0;
|
|
40005
|
+
if (value[scheme.length] !== " ") return void 0;
|
|
40006
|
+
return value.slice(scheme.length + 1).trim() || void 0;
|
|
40007
|
+
}
|
|
39730
40008
|
async handlePublicMode() {
|
|
39731
40009
|
const authOptions = this.scope.auth?.options;
|
|
39732
40010
|
if (!authOptions || !isPublicMode(authOptions)) {
|
|
39733
40011
|
return;
|
|
39734
40012
|
}
|
|
39735
|
-
if (this.state.token) {
|
|
40013
|
+
if (this.state.token && isJwt(this.state.token)) {
|
|
39736
40014
|
return;
|
|
39737
40015
|
}
|
|
40016
|
+
if (this.state.token) {
|
|
40017
|
+
this.logger.verbose(
|
|
40018
|
+
"handlePublicMode: ignoring non-JWT bearer token (public mode has nothing to verify it against)"
|
|
40019
|
+
);
|
|
40020
|
+
}
|
|
39738
40021
|
this.logger.info("handlePublicMode: allowing anonymous access (public mode)");
|
|
39739
40022
|
this.createAnonymousSession({
|
|
39740
40023
|
authMode: "public",
|
|
@@ -39908,6 +40191,14 @@ var init_session_verify_flow = __esm({
|
|
|
39908
40191
|
__decorateClass([
|
|
39909
40192
|
Stage22("parseInput")
|
|
39910
40193
|
], SessionVerifyFlow.prototype, "parseInput", 1);
|
|
40194
|
+
__decorateClass([
|
|
40195
|
+
Stage22("handleStaticToken", {
|
|
40196
|
+
filter: ({ scope }) => {
|
|
40197
|
+
const authOptions = scope.auth?.options;
|
|
40198
|
+
return !!authOptions && isStaticMode(authOptions);
|
|
40199
|
+
}
|
|
40200
|
+
})
|
|
40201
|
+
], SessionVerifyFlow.prototype, "handleStaticToken", 1);
|
|
39911
40202
|
__decorateClass([
|
|
39912
40203
|
Stage22("handlePublicMode")
|
|
39913
40204
|
], SessionVerifyFlow.prototype, "handlePublicMode", 1);
|
|
@@ -40402,7 +40693,7 @@ import {
|
|
|
40402
40693
|
MemoryStorageAdapter,
|
|
40403
40694
|
randomBytes as randomBytes6,
|
|
40404
40695
|
randomUUID as randomUUID21,
|
|
40405
|
-
sha256Hex as
|
|
40696
|
+
sha256Hex as sha256Hex10,
|
|
40406
40697
|
StorageNotSupportedError
|
|
40407
40698
|
} from "@frontmcp/utils";
|
|
40408
40699
|
function getDefaultNoAuthSecret() {
|
|
@@ -40428,13 +40719,14 @@ function validateAuthorizationIssuer(received, expected) {
|
|
|
40428
40719
|
function isUnsupportedOperation(error) {
|
|
40429
40720
|
return error instanceof StorageNotSupportedError;
|
|
40430
40721
|
}
|
|
40431
|
-
var defaultNoAuthSecret, RESERVED_JWT_CLAIMS, LocalPrimaryAuth;
|
|
40722
|
+
var MIN_HS256_SECRET_BYTES, defaultNoAuthSecret, RESERVED_JWT_CLAIMS, LocalPrimaryAuth;
|
|
40432
40723
|
var init_instance_local_primary_auth = __esm({
|
|
40433
40724
|
"libs/sdk/src/auth/instances/instance.local-primary-auth.ts"() {
|
|
40434
40725
|
"use strict";
|
|
40435
40726
|
init_common();
|
|
40436
40727
|
init_auth2();
|
|
40437
40728
|
init_context_extension();
|
|
40729
|
+
init_errors();
|
|
40438
40730
|
init_cimd();
|
|
40439
40731
|
init_credentials();
|
|
40440
40732
|
init_credentials_context_extension();
|
|
@@ -40452,6 +40744,7 @@ var init_instance_local_primary_auth = __esm({
|
|
|
40452
40744
|
init_well_known_prm_flow();
|
|
40453
40745
|
init_secure_store();
|
|
40454
40746
|
init_secure_store_context_extension();
|
|
40747
|
+
MIN_HS256_SECRET_BYTES = 32;
|
|
40455
40748
|
RESERVED_JWT_CLAIMS = /* @__PURE__ */ new Set([
|
|
40456
40749
|
"sub",
|
|
40457
40750
|
"iss",
|
|
@@ -40479,10 +40772,22 @@ var init_instance_local_primary_auth = __esm({
|
|
|
40479
40772
|
this.host = getEnv4("FRONTMCP_PUBLIC_HOST")?.trim() || "localhost";
|
|
40480
40773
|
this.issuer = this.deriveIssuer(options);
|
|
40481
40774
|
const jwtSecret = getEnv4("JWT_SECRET");
|
|
40482
|
-
|
|
40483
|
-
|
|
40775
|
+
const hasJwtSecret = !!jwtSecret?.trim();
|
|
40776
|
+
if (hasJwtSecret && jwtSecret) {
|
|
40777
|
+
const encoded = new TextEncoder().encode(jwtSecret);
|
|
40778
|
+
if (encoded.length < MIN_HS256_SECRET_BYTES) {
|
|
40779
|
+
if (isProduction4()) throw new JwtSecretWeakError(encoded.length);
|
|
40780
|
+
this.logger.warn(
|
|
40781
|
+
`JWT_SECRET is ${encoded.length} bytes; HS256 wants at least ${MIN_HS256_SECRET_BYTES} (RFC 7518). This is refused in production \u2014 generate one with \`openssl rand -hex 32\`.`
|
|
40782
|
+
);
|
|
40783
|
+
}
|
|
40784
|
+
this.secret = encoded;
|
|
40785
|
+
} else if (isProduction4() && isOrchestratedMode(options)) {
|
|
40786
|
+
throw new JwtSecretRequiredError(options.mode);
|
|
40484
40787
|
} else {
|
|
40485
|
-
this.logger.warn(
|
|
40788
|
+
this.logger.warn(
|
|
40789
|
+
"JWT_SECRET is not set; signing with a random per-process secret. Tokens will not survive a restart and will not verify across instances. Set JWT_SECRET for any deployment that mints tokens."
|
|
40790
|
+
);
|
|
40486
40791
|
this.secret = getDefaultNoAuthSecret();
|
|
40487
40792
|
}
|
|
40488
40793
|
this.tokenStorage = this.readTokenStorage(options);
|
|
@@ -41042,7 +41347,7 @@ var init_instance_local_primary_auth = __esm({
|
|
|
41042
41347
|
const pendingAuthId = `pending:${codeRecord.pendingAuthId}`;
|
|
41043
41348
|
const parts = accessToken.split(".");
|
|
41044
41349
|
const signature = parts[2] || accessToken;
|
|
41045
|
-
const newAuthId =
|
|
41350
|
+
const newAuthId = sha256Hex10(signature).substring(0, 16);
|
|
41046
41351
|
await this.orchestratedTokenStore.migrateTokens(pendingAuthId, newAuthId);
|
|
41047
41352
|
this.logger.info(`Migrated tokens from ${pendingAuthId} to ${newAuthId}`);
|
|
41048
41353
|
} catch (err) {
|
|
@@ -41754,6 +42059,9 @@ var init_auth_registry = __esm({
|
|
|
41754
42059
|
if (isPublicMode(options)) {
|
|
41755
42060
|
return new LocalPrimaryAuth(scope, providers, options);
|
|
41756
42061
|
}
|
|
42062
|
+
if (isStaticMode(options)) {
|
|
42063
|
+
return new LocalPrimaryAuth(scope, providers, options);
|
|
42064
|
+
}
|
|
41757
42065
|
if (isTransparentMode(options)) {
|
|
41758
42066
|
return new RemotePrimaryAuth(scope, providers, options);
|
|
41759
42067
|
}
|
|
@@ -45862,7 +46170,9 @@ var init_workflow_step_executor = __esm({
|
|
|
45862
46170
|
"libs/sdk/src/workflow/engine/workflow-step.executor.ts"() {
|
|
45863
46171
|
"use strict";
|
|
45864
46172
|
init_errors();
|
|
46173
|
+
init_job_errors();
|
|
45865
46174
|
init_workflow_errors();
|
|
46175
|
+
init_job_permission_guard();
|
|
45866
46176
|
WorkflowStepExecutor = class {
|
|
45867
46177
|
jobRegistry;
|
|
45868
46178
|
logger;
|
|
@@ -45877,6 +46187,16 @@ var init_workflow_step_executor = __esm({
|
|
|
45877
46187
|
if (!job) {
|
|
45878
46188
|
throw new InvalidEntityError("job", step.jobName, `a registered job (referenced by step "${step.id}")`);
|
|
45879
46189
|
}
|
|
46190
|
+
const allowed = await JobPermissionGuard.check(
|
|
46191
|
+
job.metadata.permissions,
|
|
46192
|
+
"execute",
|
|
46193
|
+
this.extra.authInfo,
|
|
46194
|
+
this.extra.authoritiesContextBuilder
|
|
46195
|
+
);
|
|
46196
|
+
if (!allowed) {
|
|
46197
|
+
this.logger.warn(`Step "${step.id}" denied: caller does not satisfy the execute permissions of "${job.name}"`);
|
|
46198
|
+
throw new JobNotAuthorizedError(job.name);
|
|
46199
|
+
}
|
|
45880
46200
|
const retryConfig = step.retry ?? job.metadata.retry ?? {};
|
|
45881
46201
|
const maxAttempts = retryConfig.maxAttempts ?? 3;
|
|
45882
46202
|
const backoffMs = retryConfig.backoffMs ?? 1e3;
|
|
@@ -46290,7 +46610,8 @@ var init_job_execution_manager = __esm({
|
|
|
46290
46610
|
try {
|
|
46291
46611
|
const engine = new WorkflowEngine(workflow.metadata, jobRegistry, this.logger, {
|
|
46292
46612
|
authInfo: opts.authInfo ?? {},
|
|
46293
|
-
contextProviders: opts.contextProviders
|
|
46613
|
+
contextProviders: opts.contextProviders,
|
|
46614
|
+
authoritiesContextBuilder: opts.authoritiesContextBuilder
|
|
46294
46615
|
});
|
|
46295
46616
|
const result = await engine.execute(opts.workflowInput);
|
|
46296
46617
|
await this.stateStore.updateRun(runId, {
|
|
@@ -49204,7 +49525,7 @@ var init_load_skill_flow = __esm({
|
|
|
49204
49525
|
});
|
|
49205
49526
|
|
|
49206
49527
|
// libs/sdk/src/skill/auth/skill-http-auth.ts
|
|
49207
|
-
import { timingSafeEqual as
|
|
49528
|
+
import { timingSafeEqual as timingSafeEqual3 } from "@frontmcp/utils";
|
|
49208
49529
|
function createSkillHttpAuthValidator(skillsConfig, logger) {
|
|
49209
49530
|
if (!skillsConfig?.auth || skillsConfig.auth === "public" || skillsConfig.auth === "inherit") {
|
|
49210
49531
|
return null;
|
|
@@ -49291,7 +49612,7 @@ var init_skill_http_auth = __esm({
|
|
|
49291
49612
|
const keyBytes = encoder5.encode(key);
|
|
49292
49613
|
if (keyBytes.length === candidateBytes.length) {
|
|
49293
49614
|
try {
|
|
49294
|
-
if (
|
|
49615
|
+
if (timingSafeEqual3(keyBytes, candidateBytes)) {
|
|
49295
49616
|
found = true;
|
|
49296
49617
|
}
|
|
49297
49618
|
} catch {
|
|
@@ -52257,104 +52578,6 @@ var init_decide_request_intent_utils = __esm({
|
|
|
52257
52578
|
}
|
|
52258
52579
|
});
|
|
52259
52580
|
|
|
52260
|
-
// libs/sdk/src/common/utils/path.utils.ts
|
|
52261
|
-
import { joinPath, trimSlashes } from "@frontmcp/utils";
|
|
52262
|
-
import { trimSlashes as trimSlashes2, joinPath as joinPath2 } from "@frontmcp/utils";
|
|
52263
|
-
function normalizeEntryPrefix(entryPath) {
|
|
52264
|
-
const t = trimSlashes(entryPath ?? "");
|
|
52265
|
-
return t ? `/${t}` : "";
|
|
52266
|
-
}
|
|
52267
|
-
function normalizeScopeBase(scopeBase) {
|
|
52268
|
-
const t = trimSlashes(scopeBase ?? "");
|
|
52269
|
-
return t ? `/${t}` : "";
|
|
52270
|
-
}
|
|
52271
|
-
function readPublicUrlPin() {
|
|
52272
|
-
try {
|
|
52273
|
-
if (typeof process !== "undefined" && process.env) {
|
|
52274
|
-
const v = process.env["FRONTMCP_PUBLIC_URL"];
|
|
52275
|
-
if (typeof v === "string" && v.trim()) {
|
|
52276
|
-
return v.trim().replace(/\/+$/, "");
|
|
52277
|
-
}
|
|
52278
|
-
}
|
|
52279
|
-
} catch {
|
|
52280
|
-
}
|
|
52281
|
-
return void 0;
|
|
52282
|
-
}
|
|
52283
|
-
function isPublicUrlPinned() {
|
|
52284
|
-
return readPublicUrlPin() !== void 0;
|
|
52285
|
-
}
|
|
52286
|
-
function isProxyTrusted() {
|
|
52287
|
-
try {
|
|
52288
|
-
if (typeof process !== "undefined" && process.env) {
|
|
52289
|
-
const v = process.env["FRONTMCP_TRUST_PROXY"];
|
|
52290
|
-
return typeof v === "string" && /^(1|true|yes|on)$/i.test(v.trim());
|
|
52291
|
-
}
|
|
52292
|
-
} catch {
|
|
52293
|
-
}
|
|
52294
|
-
return false;
|
|
52295
|
-
}
|
|
52296
|
-
function getRequestBaseUrl(req, entryPath) {
|
|
52297
|
-
const pin = readPublicUrlPin();
|
|
52298
|
-
if (pin) {
|
|
52299
|
-
return `${pin}${entryPath ?? ""}`;
|
|
52300
|
-
}
|
|
52301
|
-
const trustProxy = isProxyTrusted();
|
|
52302
|
-
const fwdProto = trustProxy ? req.headers["x-forwarded-proto"] : void 0;
|
|
52303
|
-
const fwdHost = trustProxy ? req.headers["x-forwarded-host"] : void 0;
|
|
52304
|
-
const proto = fwdProto || req.protocol || "http";
|
|
52305
|
-
const host = fwdHost || req.headers["host"];
|
|
52306
|
-
return `${proto}://${host}${entryPath ?? ""}`;
|
|
52307
|
-
}
|
|
52308
|
-
function computeIssuer(req, entryPath, scopeBase) {
|
|
52309
|
-
const entryPrefix = normalizeEntryPrefix(entryPath);
|
|
52310
|
-
const scope = normalizeScopeBase(scopeBase);
|
|
52311
|
-
return `${getRequestBaseUrl(req)}${entryPrefix}${scope}`;
|
|
52312
|
-
}
|
|
52313
|
-
function computeResource(req, entryPath, scopeBase) {
|
|
52314
|
-
const entryPrefix = normalizeEntryPrefix(entryPath);
|
|
52315
|
-
const scope = normalizeScopeBase(scopeBase);
|
|
52316
|
-
return `${getRequestBaseUrl(req)}${entryPrefix}${scope}`;
|
|
52317
|
-
}
|
|
52318
|
-
function normalizeResourceUri(uri) {
|
|
52319
|
-
try {
|
|
52320
|
-
const url = new URL(uri);
|
|
52321
|
-
let normalized = `${url.protocol}//${url.hostname}`;
|
|
52322
|
-
const isDefaultPort = url.protocol === "https:" && url.port === "443" || url.protocol === "http:" && url.port === "80";
|
|
52323
|
-
if (url.port && !isDefaultPort) {
|
|
52324
|
-
normalized += `:${url.port}`;
|
|
52325
|
-
}
|
|
52326
|
-
let path3 = url.pathname;
|
|
52327
|
-
if (path3.length > 1 && path3.endsWith("/")) {
|
|
52328
|
-
path3 = path3.slice(0, -1);
|
|
52329
|
-
}
|
|
52330
|
-
normalized += path3;
|
|
52331
|
-
return normalized;
|
|
52332
|
-
} catch {
|
|
52333
|
-
return uri;
|
|
52334
|
-
}
|
|
52335
|
-
}
|
|
52336
|
-
function resourceUriMatches(provided, canonical) {
|
|
52337
|
-
return normalizeResourceUri(provided) === normalizeResourceUri(canonical);
|
|
52338
|
-
}
|
|
52339
|
-
function urlToSafeId(url) {
|
|
52340
|
-
const u = new URL(url);
|
|
52341
|
-
const raw = (u.host + (u.pathname && u.pathname !== "/" ? u.pathname : "")).replace(/\/+$/, "");
|
|
52342
|
-
return trimSlashes(raw).replace(/[^a-zA-Z0-9_-]/g, "-");
|
|
52343
|
-
}
|
|
52344
|
-
function makeWellKnownPaths(name42, entryPrefix, scopeBase = "") {
|
|
52345
|
-
const prefix = normalizeEntryPrefix(entryPrefix);
|
|
52346
|
-
const scope = normalizeScopeBase(scopeBase);
|
|
52347
|
-
const reversed = joinPath(".well-known", name42) + `${prefix}${scope}`;
|
|
52348
|
-
const inPrefixRoot = `${prefix}${joinPath(".well-known", name42)}${scope}`;
|
|
52349
|
-
const inPrefixScope = `${prefix}${scope}${joinPath(".well-known", name42)}`;
|
|
52350
|
-
return /* @__PURE__ */ new Set([reversed, inPrefixRoot, inPrefixScope]);
|
|
52351
|
-
}
|
|
52352
|
-
var init_path_utils = __esm({
|
|
52353
|
-
"libs/sdk/src/common/utils/path.utils.ts"() {
|
|
52354
|
-
"use strict";
|
|
52355
|
-
}
|
|
52356
|
-
});
|
|
52357
|
-
|
|
52358
52581
|
// libs/sdk/src/common/utils/global-config.utils.ts
|
|
52359
52582
|
function getGlobalStoreConfig(pluginName, config) {
|
|
52360
52583
|
if (!config.redis) {
|
|
@@ -52689,7 +52912,7 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
52689
52912
|
return parseSkillMdFrontmatter(inline).body;
|
|
52690
52913
|
}
|
|
52691
52914
|
const absolutePath = entry.path;
|
|
52692
|
-
const resolvedPath =
|
|
52915
|
+
const resolvedPath = resolveEntryPath2(instance, kind, absolutePath, filename);
|
|
52693
52916
|
if (!resolvedPath) continue;
|
|
52694
52917
|
try {
|
|
52695
52918
|
const buf = await readFileBuffer(resolvedPath);
|
|
@@ -52704,7 +52927,7 @@ async function tryResolvedSubFile(instance, kind, tail) {
|
|
|
52704
52927
|
}
|
|
52705
52928
|
return void 0;
|
|
52706
52929
|
}
|
|
52707
|
-
function
|
|
52930
|
+
function resolveEntryPath2(instance, kind, absolutePath, filename) {
|
|
52708
52931
|
if (absolutePath && isAbsolute3(absolutePath)) return absolutePath;
|
|
52709
52932
|
if (!filename) return void 0;
|
|
52710
52933
|
const baseDir = instance.getBaseDir();
|
|
@@ -56845,7 +57068,7 @@ var init_transport_remote = __esm({
|
|
|
56845
57068
|
});
|
|
56846
57069
|
|
|
56847
57070
|
// libs/sdk/src/transport/transport.registry.ts
|
|
56848
|
-
import { getMachineId as getMachineId5, sha256Hex as
|
|
57071
|
+
import { getMachineId as getMachineId5, sha256Hex as sha256Hex11 } from "@frontmcp/utils";
|
|
56849
57072
|
var TransportService;
|
|
56850
57073
|
var init_transport_registry = __esm({
|
|
56851
57074
|
"libs/sdk/src/transport/transport.registry.ts"() {
|
|
@@ -57381,7 +57604,7 @@ var init_transport_registry = __esm({
|
|
|
57381
57604
|
}
|
|
57382
57605
|
/* --------------------------------- internals -------------------------------- */
|
|
57383
57606
|
sha256(value) {
|
|
57384
|
-
return
|
|
57607
|
+
return sha256Hex11(value);
|
|
57385
57608
|
}
|
|
57386
57609
|
/**
|
|
57387
57610
|
* Create a history key from components.
|
|
@@ -57674,13 +57897,28 @@ var init_http_request_flow = __esm({
|
|
|
57674
57897
|
}
|
|
57675
57898
|
async acquireQuota() {
|
|
57676
57899
|
const manager = this.scope.rateLimitManager;
|
|
57677
|
-
if (!manager
|
|
57900
|
+
if (!manager) return;
|
|
57678
57901
|
const context = this.tryGetContext();
|
|
57679
57902
|
const partitionCtx = context ? {
|
|
57680
57903
|
sessionId: context.sessionId,
|
|
57681
57904
|
clientIp: context.metadata?.clientIp,
|
|
57682
57905
|
userId: context.authInfo?.clientId
|
|
57683
57906
|
} : void 0;
|
|
57907
|
+
const ipResult = manager.checkIpFilter(partitionCtx?.clientIp);
|
|
57908
|
+
if (ipResult && !ipResult.allowed) {
|
|
57909
|
+
this.logger.warn(`[${this.requestId}] request rejected by ipFilter`, { reason: ipResult.reason });
|
|
57910
|
+
this.respond(
|
|
57911
|
+
httpRespond.json(
|
|
57912
|
+
{
|
|
57913
|
+
jsonrpc: "2.0",
|
|
57914
|
+
error: { code: -32001, message: "Forbidden: client IP rejected by ipFilter" }
|
|
57915
|
+
},
|
|
57916
|
+
{ status: 403 }
|
|
57917
|
+
)
|
|
57918
|
+
);
|
|
57919
|
+
return;
|
|
57920
|
+
}
|
|
57921
|
+
if (!manager.config?.global) return;
|
|
57684
57922
|
const result = await manager.checkGlobalRateLimit(partitionCtx);
|
|
57685
57923
|
if (!result.allowed) {
|
|
57686
57924
|
const retryAfter = Math.ceil((result.retryAfterMs ?? 6e4) / 1e3);
|
|
@@ -58301,6 +58539,7 @@ var init_scope_instance = __esm({
|
|
|
58301
58539
|
init_channel_scope_helper();
|
|
58302
58540
|
init_common();
|
|
58303
58541
|
init_sqlite();
|
|
58542
|
+
init_path_utils();
|
|
58304
58543
|
init_complete_flow();
|
|
58305
58544
|
init_context();
|
|
58306
58545
|
init_elicitation2();
|
|
@@ -58401,7 +58640,7 @@ var init_scope_instance = __esm({
|
|
|
58401
58640
|
this.logger = globalProviders.get(FrontMcpLogger).child("FrontMcp.MultiAppScope");
|
|
58402
58641
|
this.globalProviders = globalProviders;
|
|
58403
58642
|
this.server = this.globalProviders.get(FrontMcpServer);
|
|
58404
|
-
this.entryPath = rec.metadata.http?.entryPath
|
|
58643
|
+
this.entryPath = resolveEntryPath(rec.metadata.http?.entryPath);
|
|
58405
58644
|
if (rec.kind === "SPLIT_BY_APP") {
|
|
58406
58645
|
this.routeBase = `/${rec.metadata.id}`;
|
|
58407
58646
|
} else {
|
|
@@ -58505,16 +58744,25 @@ var init_scope_instance = __esm({
|
|
|
58505
58744
|
})() : void 0;
|
|
58506
58745
|
const tasksConfig = this.metadata.tasks;
|
|
58507
58746
|
const tasksExplicitlyDisabled = tasksConfig?.enabled === false;
|
|
58747
|
+
const tasksExplicitlyEnabled = tasksConfig?.enabled === true;
|
|
58508
58748
|
const isTaskWorker = !!this.metadata["__taskWorkerMode"];
|
|
58509
58749
|
const hasPersistentBackend = Boolean(
|
|
58510
58750
|
tasksConfig?.sqlite || tasksConfig?.redis || this.metadata.redis || this.metadata.sqlite
|
|
58511
58751
|
);
|
|
58512
58752
|
const tasksEnabledForCli = this.cliMode && hasPersistentBackend;
|
|
58513
|
-
const
|
|
58753
|
+
const hasDistributedTaskBackend = Boolean(tasksConfig?.redis ?? this.metadata.redis);
|
|
58754
|
+
const onEdgeRuntime = isEdgeRuntime();
|
|
58755
|
+
const tasksUnavailableOnEdge = onEdgeRuntime && !hasDistributedTaskBackend && !tasksExplicitlyEnabled;
|
|
58756
|
+
if (tasksUnavailableOnEdge) {
|
|
58757
|
+
this.logger.info(
|
|
58758
|
+
"[tasks] Background tasks are unavailable on this edge/serverless runtime: the in-process runner cannot continue past the HTTP response, and an in-memory store is not shared between isolates. Serving without tasks. Configure `tasks.redis` (Upstash Redis over HTTP works on Workers) to enable them."
|
|
58759
|
+
);
|
|
58760
|
+
}
|
|
58761
|
+
const shouldInitTasks = !tasksExplicitlyDisabled && !tasksUnavailableOnEdge && (!this.cliMode || tasksEnabledForCli || isTaskWorker);
|
|
58514
58762
|
const tasksPromise = shouldInitTasks ? (async () => {
|
|
58515
58763
|
const tasksRedis = tasksConfig?.redis ?? this.metadata.redis;
|
|
58516
58764
|
const tasksSqlite = tasksConfig?.sqlite ?? (tasksRedis ? void 0 : resolvedTopLevelSqlite);
|
|
58517
|
-
const onEdge =
|
|
58765
|
+
const onEdge = onEdgeRuntime;
|
|
58518
58766
|
if (onEdge) {
|
|
58519
58767
|
const msg = "[tasks] Background tasks are enabled on an edge/serverless runtime. The in-process runner cannot continue past the HTTP response on this platform \u2014 task bodies will not execute. Run on a long-lived Node process, or set `tasks.enabled: false`.";
|
|
58520
58768
|
if (tasksConfig?.strict) {
|
|
@@ -60660,7 +60908,7 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
60660
60908
|
while (end > 1 && withSlash.charCodeAt(end - 1) === 47) end--;
|
|
60661
60909
|
return withSlash.slice(0, end);
|
|
60662
60910
|
};
|
|
60663
|
-
const rawEntry = options.entryPath ?? (normalizeEntryPrefix(httpConfig?.entryPath) || "/");
|
|
60911
|
+
const rawEntry = options.entryPath ?? (normalizeEntryPrefix(resolveEntryPath(httpConfig?.entryPath)) || "/");
|
|
60664
60912
|
const entryPaths = new Set((Array.isArray(rawEntry) ? rawEntry : [rawEntry]).map(normalizePath));
|
|
60665
60913
|
const cors2 = options.cors ?? mapHttpCors(httpConfig?.cors, scope);
|
|
60666
60914
|
const corsEnabled = cors2?.origin !== void 0 && cors2.origin !== false;
|
|
@@ -60725,7 +60973,7 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
60725
60973
|
);
|
|
60726
60974
|
}
|
|
60727
60975
|
if (!entryPaths.has(normalizePath(url.pathname))) {
|
|
60728
|
-
const authResponse = await runMatchingHttpFlowWeb(scope, request);
|
|
60976
|
+
const authResponse = await runMatchingHttpFlowWeb(scope, request, { ctx, env });
|
|
60729
60977
|
if (authResponse) return withCors(authResponse, request);
|
|
60730
60978
|
return withCors(Response.json({ error: "Not Found", entryPaths: [...entryPaths] }, { status: 404 }), request);
|
|
60731
60979
|
}
|
|
@@ -60733,13 +60981,13 @@ function createWebFetchHandler(scope, options = {}) {
|
|
|
60733
60981
|
const routed = await options.sessionRouter(request, env, ctx);
|
|
60734
60982
|
if (routed) return withCors(routed, request);
|
|
60735
60983
|
}
|
|
60736
|
-
const rendered = await runHttpRequestFlowWeb(scope, request, { ctx });
|
|
60984
|
+
const rendered = await runHttpRequestFlowWeb(scope, request, { ctx, env });
|
|
60737
60985
|
return withCors(rendered ?? Response.json({ error: "Not Found" }, { status: 404 }), request);
|
|
60738
60986
|
};
|
|
60739
60987
|
}
|
|
60740
60988
|
async function runHttpRequestFlowWeb(scope, request, opts = {}) {
|
|
60741
60989
|
const url = new URL(request.url);
|
|
60742
|
-
const serverRequest = await toServerRequest(request, url, opts.ctx, opts.persistent);
|
|
60990
|
+
const serverRequest = await toServerRequest(request, url, opts.ctx, opts.persistent, opts.env);
|
|
60743
60991
|
let output;
|
|
60744
60992
|
try {
|
|
60745
60993
|
output = await scope.runFlow("http:request", {
|
|
@@ -60751,9 +60999,9 @@ async function runHttpRequestFlowWeb(scope, request, opts = {}) {
|
|
|
60751
60999
|
}
|
|
60752
61000
|
return output ? renderHttpOutputToWebResponse(output) : void 0;
|
|
60753
61001
|
}
|
|
60754
|
-
async function runMatchingHttpFlowWeb(scope, request) {
|
|
61002
|
+
async function runMatchingHttpFlowWeb(scope, request, opts = {}) {
|
|
60755
61003
|
const url = new URL(request.url);
|
|
60756
|
-
const serverRequest = await toServerRequest(request, url);
|
|
61004
|
+
const serverRequest = await toServerRequest(request, url, opts.ctx, void 0, opts.env);
|
|
60757
61005
|
const flowName = await scope.findHttpFlowName(serverRequest);
|
|
60758
61006
|
if (!flowName) return void 0;
|
|
60759
61007
|
let output;
|
|
@@ -60767,7 +61015,7 @@ async function runMatchingHttpFlowWeb(scope, request) {
|
|
|
60767
61015
|
}
|
|
60768
61016
|
return output ? renderHttpOutputToWebResponse(output) : void 0;
|
|
60769
61017
|
}
|
|
60770
|
-
async function toServerRequest(request, url, ctx, persistent) {
|
|
61018
|
+
async function toServerRequest(request, url, ctx, persistent, env) {
|
|
60771
61019
|
const headers = {};
|
|
60772
61020
|
request.headers.forEach((v, k) => {
|
|
60773
61021
|
headers[k] = v;
|
|
@@ -60811,10 +61059,39 @@ async function toServerRequest(request, url, ctx, persistent) {
|
|
|
60811
61059
|
const tokenized = serverRequest;
|
|
60812
61060
|
tokenized[ServerRequestTokens.webRequest] = webRequest;
|
|
60813
61061
|
tokenized[ServerRequestTokens.webCtx] = ctx;
|
|
61062
|
+
tokenized[ServerRequestTokens.webEnv] = env;
|
|
60814
61063
|
if (persistent) tokenized[ServerRequestTokens.webTransport] = persistent;
|
|
60815
61064
|
return serverRequest;
|
|
60816
61065
|
}
|
|
61066
|
+
function misconfigurationResponse(error) {
|
|
61067
|
+
const misconfiguration = findMisconfiguration(error);
|
|
61068
|
+
if (!misconfiguration) return void 0;
|
|
61069
|
+
return Response.json(
|
|
61070
|
+
{ error: "server_misconfigured", code: misconfiguration.code, message: misconfiguration.remedy },
|
|
61071
|
+
{ status: 500 }
|
|
61072
|
+
);
|
|
61073
|
+
}
|
|
61074
|
+
function findMisconfiguration(error) {
|
|
61075
|
+
let current = error;
|
|
61076
|
+
for (let depth = 0; current instanceof Error && depth < 5; depth++) {
|
|
61077
|
+
const code = current.code;
|
|
61078
|
+
if (typeof code === "string" && MISCONFIGURATION_REMEDIES[code]) {
|
|
61079
|
+
return { code, remedy: MISCONFIGURATION_REMEDIES[code] };
|
|
61080
|
+
}
|
|
61081
|
+
current = current.cause;
|
|
61082
|
+
}
|
|
61083
|
+
return void 0;
|
|
61084
|
+
}
|
|
60817
61085
|
function flowErrorToHttpOutput(error) {
|
|
61086
|
+
const misconfiguration = findMisconfiguration(error);
|
|
61087
|
+
if (misconfiguration) {
|
|
61088
|
+
return {
|
|
61089
|
+
kind: "json",
|
|
61090
|
+
status: 500,
|
|
61091
|
+
contentType: "application/json; charset=utf-8",
|
|
61092
|
+
body: { error: "server_misconfigured", code: misconfiguration.code, message: misconfiguration.remedy }
|
|
61093
|
+
};
|
|
61094
|
+
}
|
|
60818
61095
|
if (error instanceof FlowControl) {
|
|
60819
61096
|
switch (error.type) {
|
|
60820
61097
|
case "respond":
|
|
@@ -60838,6 +61115,7 @@ function flowErrorToHttpOutput(error) {
|
|
|
60838
61115
|
}
|
|
60839
61116
|
return { kind: "text", status: 500, body: "Internal Server Error", contentType: "text/plain; charset=utf-8" };
|
|
60840
61117
|
}
|
|
61118
|
+
var MISCONFIGURATION_REMEDIES;
|
|
60841
61119
|
var init_web_fetch_handler = __esm({
|
|
60842
61120
|
"libs/sdk/src/transport/web-fetch-handler.ts"() {
|
|
60843
61121
|
"use strict";
|
|
@@ -60847,6 +61125,11 @@ var init_web_fetch_handler = __esm({
|
|
|
60847
61125
|
init_errors();
|
|
60848
61126
|
init_host_validation();
|
|
60849
61127
|
init_web_response_renderer();
|
|
61128
|
+
MISCONFIGURATION_REMEDIES = {
|
|
61129
|
+
SESSION_SECRET_REQUIRED: "Set MCP_SESSION_SECRET in the deployment environment (e.g. `wrangler secret put MCP_SESSION_SECRET`). Session IDs are encrypted with it, and production refuses the development machine-id fallback.",
|
|
61130
|
+
JWT_SECRET_INVALID: "JWT_SECRET is present but too weak: HS256 requires at least 32 bytes (RFC 7518). Replace it with `openssl rand -hex 32`.",
|
|
61131
|
+
JWT_SECRET_REQUIRED: "Set JWT_SECRET in the deployment environment (e.g. `wrangler secret put JWT_SECRET`). Tokens are signed with it; production refuses the random per-process fallback because tokens would not survive a restart or verify across instances."
|
|
61132
|
+
};
|
|
60850
61133
|
}
|
|
60851
61134
|
});
|
|
60852
61135
|
|
|
@@ -61200,17 +61483,16 @@ var init_express_host_adapter = __esm({
|
|
|
61200
61483
|
});
|
|
61201
61484
|
} else {
|
|
61202
61485
|
this.deriveHostValidation = (portOrSocketPath, bindAddress) => {
|
|
61203
|
-
|
|
61486
|
+
if (typeof portOrSocketPath === "string") return void 0;
|
|
61204
61487
|
const derivation = {
|
|
61205
61488
|
// `start()` binds `bindAddress ?? '0.0.0.0'`; mirror that exactly.
|
|
61206
|
-
bindAddress:
|
|
61207
|
-
port:
|
|
61208
|
-
socketPath: isSocket ? portOrSocketPath : void 0,
|
|
61489
|
+
bindAddress: bindAddress ?? "0.0.0.0",
|
|
61490
|
+
port: portOrSocketPath,
|
|
61209
61491
|
issuer: options?.listen?.issuer
|
|
61210
61492
|
};
|
|
61211
61493
|
if (!shouldEnforceDerivedHosts(derivation)) {
|
|
61212
61494
|
console.warn(
|
|
61213
|
-
`[frontmcp] DNS-rebinding protection is not enforcing a Host allow-list: the server binds a routable address (${derivation.bindAddress
|
|
61495
|
+
`[frontmcp] DNS-rebinding protection is not enforcing a Host allow-list: the server binds a routable address (${derivation.bindAddress}) and no allowed hosts are configured. Set security.dnsRebindingProtection.allowedHosts (or FRONTMCP_ALLOWED_HOSTS) to your public hostname(s).`
|
|
61214
61496
|
);
|
|
61215
61497
|
return void 0;
|
|
61216
61498
|
}
|
|
@@ -61266,7 +61548,6 @@ var init_express_host_adapter = __esm({
|
|
|
61266
61548
|
return this.app;
|
|
61267
61549
|
}
|
|
61268
61550
|
async start(portOrSocketPath, bindAddress) {
|
|
61269
|
-
this.enableDerivedHostValidation(portOrSocketPath, bindAddress);
|
|
61270
61551
|
this.prepare();
|
|
61271
61552
|
const server = http.createServer(this.app);
|
|
61272
61553
|
server.requestTimeout = 0;
|
|
@@ -61274,6 +61555,7 @@ var init_express_host_adapter = __esm({
|
|
|
61274
61555
|
server.keepAliveTimeout = 75e3;
|
|
61275
61556
|
if (typeof portOrSocketPath === "string") {
|
|
61276
61557
|
await this.cleanupStaleSocket(portOrSocketPath);
|
|
61558
|
+
this.enableDerivedHostValidation(portOrSocketPath);
|
|
61277
61559
|
await new Promise((resolve, reject) => {
|
|
61278
61560
|
server.on("error", reject);
|
|
61279
61561
|
server.listen(portOrSocketPath, () => {
|
|
@@ -61291,7 +61573,11 @@ var init_express_host_adapter = __esm({
|
|
|
61291
61573
|
await new Promise((resolve, reject) => {
|
|
61292
61574
|
server.on("error", reject);
|
|
61293
61575
|
server.listen(portOrSocketPath, host, () => {
|
|
61294
|
-
|
|
61576
|
+
const bound = server.address();
|
|
61577
|
+
const boundPort = typeof bound === "object" && bound ? bound.port : portOrSocketPath;
|
|
61578
|
+
const boundAddress = typeof bound === "object" && bound ? bound.address : host;
|
|
61579
|
+
this.enableDerivedHostValidation(boundPort, boundAddress);
|
|
61580
|
+
console.log(`MCP HTTP (Express) on ${host}:${boundPort}`);
|
|
61295
61581
|
resolve();
|
|
61296
61582
|
});
|
|
61297
61583
|
});
|
|
@@ -61693,7 +61979,7 @@ var init_front_mcp = __esm({
|
|
|
61693
61979
|
frontMcp.log?.info("FrontMCP fetch handler created (web-standard transport)");
|
|
61694
61980
|
return createWebFetchHandler(scope);
|
|
61695
61981
|
};
|
|
61696
|
-
return async (request) => {
|
|
61982
|
+
return async (request, ctx, env) => {
|
|
61697
61983
|
if (!inner) {
|
|
61698
61984
|
if (!building) {
|
|
61699
61985
|
building = build().catch((err) => {
|
|
@@ -61701,9 +61987,15 @@ var init_front_mcp = __esm({
|
|
|
61701
61987
|
throw err;
|
|
61702
61988
|
});
|
|
61703
61989
|
}
|
|
61704
|
-
|
|
61990
|
+
try {
|
|
61991
|
+
inner = await building;
|
|
61992
|
+
} catch (err) {
|
|
61993
|
+
const misconfigured = misconfigurationResponse(err);
|
|
61994
|
+
if (misconfigured) return misconfigured;
|
|
61995
|
+
throw err;
|
|
61996
|
+
}
|
|
61705
61997
|
}
|
|
61706
|
-
return inner(request);
|
|
61998
|
+
return inner(request, ctx, env);
|
|
61707
61999
|
};
|
|
61708
62000
|
}
|
|
61709
62001
|
/**
|
|
@@ -64685,6 +64977,8 @@ export {
|
|
|
64685
64977
|
JobNotAuthorizedError,
|
|
64686
64978
|
JobPermissionGuard,
|
|
64687
64979
|
JobRegistry,
|
|
64980
|
+
JwtSecretRequiredError,
|
|
64981
|
+
JwtSecretWeakError,
|
|
64688
64982
|
LLM_ADAPTER,
|
|
64689
64983
|
LazyZodSchema,
|
|
64690
64984
|
ListJobsTool,
|
|
@@ -65112,6 +65406,7 @@ export {
|
|
|
65112
65406
|
isOrchestratedMode,
|
|
65113
65407
|
isOrchestratedRemote,
|
|
65114
65408
|
isPackageSpecifier,
|
|
65409
|
+
isProxyTrusted,
|
|
65115
65410
|
isPublicError,
|
|
65116
65411
|
isPublicMode,
|
|
65117
65412
|
isPublicUrlPinned,
|
|
@@ -65120,6 +65415,7 @@ export {
|
|
|
65120
65415
|
isRemoteMode,
|
|
65121
65416
|
isSkillDecorated,
|
|
65122
65417
|
isSkillRecord,
|
|
65418
|
+
isStaticMode,
|
|
65123
65419
|
isTaskWorkerProcess,
|
|
65124
65420
|
isTerminal,
|
|
65125
65421
|
isToolRefWithClass,
|
|
@@ -65197,6 +65493,7 @@ export {
|
|
|
65197
65493
|
remoteAuthSchema,
|
|
65198
65494
|
remoteProviderConfigSchema,
|
|
65199
65495
|
resolveDefaultSqlitePath,
|
|
65496
|
+
resolveEntryPath,
|
|
65200
65497
|
resolveNameConflicts,
|
|
65201
65498
|
resolveOutputSchemaMode,
|
|
65202
65499
|
resolvePendingTC39HooksForClass,
|
|
@@ -65239,6 +65536,7 @@ export {
|
|
|
65239
65536
|
skillsConfigOptionsSchema,
|
|
65240
65537
|
skippedAppBehaviorSchema,
|
|
65241
65538
|
sqliteOptionsSchema,
|
|
65539
|
+
staticAuthOptionsSchema,
|
|
65242
65540
|
storageProviderSchema,
|
|
65243
65541
|
supportsStreaming,
|
|
65244
65542
|
toJSONSchema9 as toJSONSchema,
|