openclaw
Version:
Multi-channel AI gateway with extensible messaging integrations
432 lines (431 loc) • 27.7 kB
JavaScript
import { c as isRecord } from "./record-coerce-DItp3I4t.js";
import { n as createLazyPromise } from "./lazy-promise-DGqyc4Y4.js";
import { l as isOperatorScope, t as ADMIN_SCOPE } from "./operator-scopes-Dw7Gu2cA.js";
import { t as ErrorCodes } from "./gateway-error-details-w0nAGBBp.js";
import { i as gatewayStartupUnavailableDetails } from "./startup-unavailable-D0-EeFjq.js";
import { c as getActivePluginHttpRouteRegistry, u as getActivePluginRegistry } from "./runtime-BL4wZfTq.js";
import { a as getPluginRuntimeGatewayRequestScope, i as getPluginRuntimeGatewayNodeAuthorities, l as withPluginRuntimeGatewayRequestScope } from "./gateway-request-scope-BCMYlsDI.js";
import { Ed as GATEWAY_SUSPEND_UNAVAILABLE_REASON, Td as GATEWAY_RESTART_UNAVAILABLE_REASON } from "./src-BiL5aQto.js";
import { d as isCoreGatewayMethodClassified, n as authorizeOperatorScopesForMethod, p as listCoreGatewayHandlerMethodNames, r as authorizeOperatorScopesForRequiredScope, s as resolveLeastPrivilegeOperatorScopesForMethod, u as createCoreGatewayMethodDescriptors } from "./method-scopes-K6J_UQGL.js";
import { i as sessionMutationTargetFields } from "./session-method-policy-BAkxsFSx.js";
import { D as tryBeginGatewayRootWorkAdmission, T as tryBeginGatewayPreparedRestartRootWorkAdmission, c as getGatewaySuspendAdmissionPhase, u as isGatewayRestartDraining } from "./gateway-work-admission-R1IpuDim.js";
import { d as errorShape, f as missingScopeErrorShape } from "./error-codes-Bo8q2D1o.js";
import { p as authenticatedProfileUnavailableError } from "./operator-role-policy-wsr1DeJv.js";
import { H as SessionMutationAuthorizationChangedError, a as resolveSessionMutationAuthorization, l as resolveDirectIncognitoTargets } from "./session-sharing-B7MI8hNo.js";
import { n as resolveControlPlaneActor, t as formatControlPlaneActor } from "./control-plane-audit-CN8L3SYx.js";
import { n as consumeControlPlaneWriteBudget, t as CONTROL_PLANE_RATE_LIMIT_WINDOW_MS } from "./control-plane-rate-limit-B1YxvgrA.js";
import { n as createGatewayMethodRegistry, r as createPluginGatewayMethodDescriptors, t as createGatewayMethodDescriptorsFromHandlers } from "./registry-CC22si3g.js";
import { n as parseGatewayRole, t as isRoleAuthorizedForMethod } from "./role-policy-B0ZcgXv3.js";
import { t as isTargetedNonSafeGatewayRestartRequest } from "./restart-request-DCnDLrlM.js";
import { n as classifyGatewayStaleInstall } from "./stale-install-EFmAbT2d.js";
//#region src/gateway/server-methods/lazy-core-handlers.ts
const preparations = /* @__PURE__ */ new WeakMap();
/** Resolve forwarding wrappers without mistaking them for actual handler entry. */
async function prepareGatewayRequestHandler(handler, entry) {
let preparedHandler = handler;
let prepare = preparations.get(preparedHandler);
while (prepare) {
entry?.assertOpen();
preparedHandler = await prepare();
prepare = preparations.get(preparedHandler);
}
return preparedHandler;
}
function createLazyCoreHandlers(params) {
return Object.fromEntries(params.methods.map((method) => {
const forwarding = async (opts) => {
const entry = opts.context.requestEntryLifetime?.enter(opts);
try {
const handler = await prepareGatewayRequestHandler(forwarding, entry);
entry?.assertOpen();
entry?.release();
await handler(opts);
} finally {
entry?.release();
}
};
preparations.set(forwarding, async () => {
const handler = (await params.loadHandlers())[method];
if (!handler) throw new Error(`lazy gateway handler not found: ${method}`);
return handler;
});
return [method, forwarding];
}));
}
//#endregion
//#region src/gateway/server-methods/core-handlers.ts
const CORE_GATEWAY_HANDLER_MODULES = {
agent: () => import("./agent-CtU_yy-h.js").then((module) => module.agentHandlers),
"agent-identity": () => import("./agent-identity-BoxxCN_8.js").then((module) => module.agentIdentityHandlers),
agents: () => import("./agents-BWKC_q_3.js").then((module) => module.agentsHandlers),
"agents-workspace": () => import("./agents-workspace-DQDAR-YJ.js").then((module) => module.agentsWorkspaceHandlers),
artifacts: () => import("./artifacts-JO9Gk5j7.js").then((module) => module.artifactsHandlers),
board: () => import("./board--_neMKy0.js").then((module) => module.boardHandlers),
audit: () => import("./audit-S_7ZZ3bC.js").then((module) => module.auditHandlers),
users: () => import("./users-D1ZRT0Go.js").then((module) => module.usersHandlers),
"users-mentionable": () => import("./users-mentionable-CgxFX-NH.js").then((module) => module.usersMentionableHandlers),
attach: () => import("./attach-Dwb-gqQ8.js").then((module) => module.attachHandlers),
channels: () => import("./channels-JO6girQU.js").then((module) => module.channelsHandlers),
"channel-pairing": () => import("./channel-pairing-BBc86pRW.js").then((module) => module.channelPairingHandlers),
chat: () => import("./chat-BbagnMEy.js").then((module) => module.chatHandlers),
"chat-abort": () => import("./chat-abort-handler-Epsorgzl.js").then((module) => ({ "chat.abort": module.handleChatAbortRequest })),
commands: () => import("./commands-gMFXplZj.js").then((module) => module.commandsHandlers),
config: () => import("./config-B59xD27I.js").then((module) => module.configHandlers),
conversations: () => import("./conversations-DeC4L5BF.js").then((module) => module.conversationHandlers),
connect: () => import("./connect-CLiHJR_e.js").then((module) => module.connectHandlers),
"control-ui": () => import("./control-ui-CEpMNhvS.js").then((module) => module.controlUiHandlers),
"plugins-control-ui": () => import("./plugins-control-ui-VpiEnQ3e.js").then((module) => module.pluginsControlUiHandlers),
cron: () => import("./cron-7U1Ew90z.js").then((module) => module.cronHandlers),
devices: () => import("./devices-DKGmwsom.js").then((module) => module.deviceHandlers),
"device-pair-setup": () => import("./device-pair-setup-CCNyHooL.js").then((module) => module.devicePairSetupHandlers),
diagnostics: () => import("./diagnostics--_sSKXjd.js").then((module) => module.diagnosticsHandlers),
doctor: () => import("./doctor-BIXdyKAO.js").then((module) => module.createDoctorHandlers()),
environments: () => import("./environments-C8MwbjM0.js").then((module) => module.environmentsHandlers),
worktrees: () => import("./worktrees-CbSMxZ9a.js").then((module) => module.worktreesHandlers),
"exec-approvals": () => import("./exec-approvals-C9Z7E1JE.js").then((module) => module.execApprovalsHandlers),
fs: () => import("./fs-D709umXk.js").then((module) => module.fsHandlers),
health: () => import("./health-DzsY_Wsm.js").then((module) => module.healthHandlers),
logs: () => import("./logs-DoEysHca.js").then((module) => module.logsHandlers),
"memory-search": () => import("./memory-search-TOiItoJ8.js").then((module) => module.memorySearchHandlers),
mentions: () => import("./mentions-CHqG2PKY.js").then((module) => module.mentionHandlers),
terminal: () => import("./terminal-nbe15MvQ.js").then((module) => module.terminalHandlers),
transcripts: () => import("./transcripts-CBKhAh9H.js").then((module) => module.transcriptsHandlers),
"ui-command": () => import("./ui-command-QHs2HB6h.js").then((module) => module.uiCommandHandlers),
"models-auth-status": () => import("./models-auth-status-DAUXVTIh.js").then((module) => module.modelsAuthStatusHandlers),
"models-auth-order": () => import("./models-auth-order-DXjqYf0q.js").then((module) => module.modelsAuthOrderHandlers),
models: () => import("./models-BpK_Unz5.js").then((module) => module.modelsHandlers),
"models-probe": () => import("./models-probe-O8Otr9Uy.js").then((module) => module.modelsProbeHandlers),
"native-hook-relay": () => import("./native-hook-relay-CuRSVc5o.js").then((module) => module.nativeHookRelayHandlers),
"nodes-pending": () => import("./nodes.pending-work-BMm67jvs.js").then((module) => module.nodePendingWorkHandlers),
nodes: () => import("./nodes-Bl7lONGY.js").then((module) => module.nodeHandlers),
"plugin-host-hooks": () => import("./plugin-host-hooks-DELHg7gq.js").then((module) => module.pluginHostHookHandlers),
plugins: () => import("./plugins-DsaV5wTw.js").then((module) => module.pluginsHandlers),
"plugins-mutations": () => import("./plugins-mutations-vY3VD5Q4.js").then((module) => module.pluginMutationHandlers),
projects: () => import("./projects-CMyeCOka.js").then((module) => module.projectsHandlers),
portals: () => import("./portals-oE7sFqMg.js").then((module) => module.portalHandlers),
"progress-card": () => import("./progress-card-8WYrncHx.js").then((module) => module.progressCardHandlers),
migrations: () => import("./migrations-C7Nxax-u.js").then((module) => module.migrationsHandlers),
push: () => import("./push-B67_vAt0.js").then((module) => module.pushHandlers),
restart: () => import("./restart-DBhDYZ5f.js").then((module) => module.restartHandlers),
suspend: () => import("./suspend-Cogfi4KK.js").then((module) => module.suspendHandlers),
send: () => import("./send-DFjT2qiq.js").then((module) => module.sendHandlers),
"sessions-files": () => import("./sessions-files-BQOjcO-8.js").then((module) => module.sessionsFilesHandlers),
"sessions-github": () => import("./sessions-github-C3TbhST1.js").then((module) => module.sessionsGitHubHandlers),
"sessions-diff": () => import("./sessions-diff-Ct-40Pvc.js").then((module) => module.sessionsDiffHandlers),
"sessions-abort": () => import("./sessions-abort-CVqBN5l0.js").then((module) => module.sessionAbortHandlers),
"sessions-compact": () => import("./sessions-compact-hR5txnt9.js").then((module) => module.sessionCompactHandlers),
"sessions-compaction-checkpoints": () => import("./sessions-compaction-checkpoints-CnbPQP12.js").then((module) => module.sessionCheckpointHandlers),
"sessions-compaction-queries": () => import("./sessions-compaction-queries-BHP7J2_m.js").then((module) => module.sessionCheckpointQueryHandlers),
"sessions-create": () => import("./sessions-create-D5ogFbhB.js").then((module) => module.sessionCreateHandlers),
"sessions-title": () => import("./sessions-title-BcO0rK2X.js").then((module) => module.sessionTitleHandlers),
"sessions-recover": () => import("./sessions-recover-CKQbl8yU.js").then((module) => module.sessionRecoverHandlers),
"sessions-delete": () => import("./sessions-delete-BdffJX6q.js").then((module) => module.sessionDeleteHandlers),
"sessions-dispatch": () => import("./sessions-dispatch-DD7xx7fP.js").then((module) => module.sessionDispatchHandlers),
"sessions-groups": () => import("./sessions-groups-CFveLpzX.js").then((module) => module.sessionGroupHandlers),
"sessions-goal": () => import("./sessions-goal-B0CjJuwo.js").then((module) => module.sessionGoalHandlers),
"sessions-messaging": () => import("./sessions-messaging-f99jHeVF.js").then((module) => module.sessionMessagingHandlers),
"sessions-mutations": () => import("./sessions-mutations-DrIj53vw.js").then((module) => module.sessionMutationHandlers),
"sessions-read": () => import("./sessions-read-BstOzUHP.js").then((module) => module.sessionReadHandlers),
"sessions-rewind": () => import("./sessions-rewind-B-Xzdagl.js").then((module) => module.sessionRewindHandlers),
"sessions-sharing": () => import("./sessions-sharing-_182TbdI.js").then((module) => module.sessionSharingHandlers),
"sessions-subscriptions": () => import("./sessions-subscriptions-WFPjDUb7.js").then((module) => module.sessionSubscriptionHandlers),
"sessions-suggestions": () => import("./sessions-suggestions-ByjF4l3U.js").then((module) => module.sessionSuggestionHandlers),
"session-catalog": () => import("./session-catalog-ldcbLNrN.js").then((module) => module.sessionCatalogHandlers),
"session-discussion": () => import("./session-discussion-BZ9hfAIb.js").then((module) => module.sessionDiscussionHandlers),
"session-observer-rpc": () => import("./session-observer-rpc-eLzdNWT1.js").then((module) => module.sessionObserverHandlers),
"session-companion-rpc": () => import("./session-companion-rpc-1V91LRwP.js").then((module) => module.sessionCompanionHandlers),
"hooks-status": () => import("./hooks-status-CSsiOuyX.js").then((module) => module.hooksStatusHandlers),
skills: () => import("./skills-BnlEnM0m.js").then((module) => module.skillsHandlers),
system: () => import("./system-CCBwaCHi.js").then((module) => module.systemHandlers),
talk: () => import("./talk-BJD_2qrq.js").then((module) => module.talkHandlers),
"talk-mode": () => import("./talk-mode-CvyTmanW.js").then((module) => module.talkModeHandlers),
tasks: () => import("./tasks-uQ2YA5MZ.js").then((module) => module.tasksHandlers),
"task-suggestions": () => import("./task-suggestions-Dly9lEbm.js").then((module) => module.taskSuggestionsHandlers),
"tools-catalog": () => import("./tools-catalog-Dg8nxOWX.js").then((module) => module.toolsCatalogHandlers),
"tools-github": () => import("./tools-github-D1EmRS7m.js").then((module) => module.toolsGitHubHandlers),
"tools-effective": () => import("./tools-effective-C3GWBlgx.js").then((module) => module.toolsEffectiveHandlers),
"tools-invoke": () => import("./tools-invoke-Db4h29JJ.js").then((module) => module.toolsInvokeHandlers),
"mcp-app": () => import("./mcp-app-x5Jax9QQ.js").then((module) => module.mcpAppHandlers),
canvas: () => import("./canvas-CDW_r_Kj.js").then((module) => module.canvasHandlers),
tts: () => import("./tts-AvdVcS8p.js").then((module) => module.ttsHandlers),
update: () => import("./update-BxCRjwo_.js").then((module) => module.updateHandlers),
usage: () => import("./usage-D9hREJA1.js").then((module) => module.usageHandlers),
"voicewake-routing": () => import("./voicewake-routing-CQ-6YIJy.js").then((module) => module.voicewakeRoutingHandlers),
voicewake: () => import("./voicewake-CcBlGwNu.js").then((module) => module.voicewakeHandlers),
web: () => import("./web-BqbkGbu0.js").then((module) => module.webHandlers),
"system-agent": () => import("./system-agent-B-RV7UxK.js").then((module) => module.systemAgentHandlers),
"system-changes": () => import("./system-changes-Bu3nCuiX.js").then((module) => module.systemChangesHandlers),
wizard: () => import("./wizard-Ba9Q3tcy.js").then((module) => module.wizardHandlers)
};
const coreGatewayHandlers = Object.fromEntries(Array.from(listCoreGatewayHandlerMethodNames()).flatMap(([family, methods]) => Object.entries(createLazyCoreHandlers({
methods,
loadHandlers: createLazyPromise(CORE_GATEWAY_HANDLER_MODULES[family], { cacheRejections: true })
}))));
//#endregion
//#region src/gateway/server-methods/session-mutation-guards.ts
/** Keep the host lifetime and operator target policy on the same commit boundary. */
function withSessionMutationCommitGuard(authorization, assertCommitAllowed) {
if (!assertCommitAllowed) return authorization;
return {
...authorization,
assertCurrent: () => {
assertCommitAllowed();
authorization?.assertCurrent();
},
assertTargetCurrent: (target) => {
assertCommitAllowed();
authorization?.assertTargetCurrent(target);
}
};
}
//#endregion
//#region src/gateway/server-methods.ts
function authorizeGatewayMethod(method, client, params, methodRegistry) {
if (!client?.connect || method === "health") return null;
const roleRaw = client.connect.role ?? "operator";
const role = parseGatewayRole(roleRaw);
if (!role) return errorShape(ErrorCodes.INVALID_REQUEST, `unauthorized role: ${roleRaw}`);
const scopes = client.connect.scopes ?? [];
if (!isRoleAuthorizedForMethod(role, method)) return errorShape(ErrorCodes.INVALID_REQUEST, `unauthorized role: ${role}`);
if (role === "node") return null;
if (method === "device.scopes.requestUpgrade" || method === "device.scopes.waitUpgrade") return null;
if (scopes.includes("operator.admin")) return null;
const registeredScope = methodRegistry.getScope(method);
const scopeAuth = isOperatorScope(registeredScope) ? authorizeOperatorScopesForRequiredScope(registeredScope, scopes) : authorizeOperatorScopesForMethod(method, scopes, params);
if (!scopeAuth.allowed) {
const resolvedRequiredScopes = isOperatorScope(registeredScope) ? [registeredScope] : resolveLeastPrivilegeOperatorScopesForMethod(method, params);
return missingScopeErrorShape({
missingScope: scopeAuth.missingScope,
requiredScopes: resolvedRequiredScopes.length > 0 ? resolvedRequiredScopes : [scopeAuth.missingScope]
});
}
return null;
}
const SUSPEND_CONTROL_METHODS = /* @__PURE__ */ new Set([
"gateway.suspend.prepare",
"gateway.suspend.status",
"gateway.suspend.resume",
"gateway.suspend.handoff"
]);
function runGatewayPendingWorkContinuation(params) {
if (!isRecord(params.requestParams)) return null;
const request = params.requestParams;
if (params.client?.connect.role === "node") {
if (params.admission !== "continuation" && getGatewaySuspendAdmissionPhase() !== "draining" && !isGatewayRestartDraining()) return null;
const invokeId = params.method === "node.invoke.progress" ? request.invokeId : params.method === "node.invoke.result" ? request.id : void 0;
if (typeof invokeId !== "string" || typeof request.nodeId !== "string") return null;
return params.context.nodeRegistry.runPendingInvokeContinuation({
invokeId,
nodeId: request.nodeId,
connId: params.client.connId,
run: params.run
});
}
if (params.admission === "continuation" || getGatewaySuspendAdmissionPhase() !== "draining" || params.client?.connect.role !== "operator" || typeof request.id !== "string") return null;
if (params.method === "question.resolve" || params.method === "question.get") return params.context.questionManager?.runPendingContinuation(request.id, params.run) ?? null;
return (params.method === "exec.approval.resolve" ? params.context.execApprovalManager : params.method === "plugin.approval.resolve" ? params.context.pluginApprovalManager : params.method === "approval.resolve" ? request.kind === "exec" ? params.context.execApprovalManager : request.kind === "plugin" ? params.context.pluginApprovalManager : request.kind === "system-agent" ? params.context.systemAgentApprovalManager : void 0 : void 0)?.runPendingContinuation(request.id, params.run) ?? null;
}
async function authorizeAuthenticatedProfileForMethod(params) {
const sync = params.client?.authenticatedGitHubIdentitySync;
if (!sync || params.client?.authenticatedUserProfile?.profileId.trim()) return null;
if (!(params.methodRegistry.requiresAuthenticatedProfile(params.method) || resolveDirectIncognitoTargets(params.method, params.requestParams).length > 0 || sessionMutationTargetFields(params.method).length > 0 && params.context.getRuntimeConfig().gateway?.roles !== void 0)) return null;
try {
await sync();
} catch {
return authenticatedProfileUnavailableError();
}
return params.client?.authenticatedUserProfile?.profileId.trim() ? null : authenticatedProfileUnavailableError();
}
/** Builds the per-request method registry from core, plugin, and explicit extra handlers. */
function createRequestGatewayMethodRegistry(extraHandlers) {
const gatewayPluginRegistry = getActivePluginHttpRouteRegistry();
const gatewayPluginHandlers = gatewayPluginRegistry?.gatewayHandlers ?? {};
const extraHandlerEntries = Object.entries(extraHandlers ?? {});
const pluginMethodNames = new Set(Object.keys(gatewayPluginHandlers));
const coreDescriptorHandlers = { ...coreGatewayHandlers };
for (const [method, extraHandler] of extraHandlerEntries) if (!pluginMethodNames.has(method) && isCoreGatewayMethodClassified(method)) coreDescriptorHandlers[method] = extraHandler;
const auxHandlers = Object.fromEntries(extraHandlerEntries.filter(([method]) => !pluginMethodNames.has(method) && !isCoreGatewayMethodClassified(method)));
return createGatewayMethodRegistry([
...createCoreGatewayMethodDescriptors(coreDescriptorHandlers),
...gatewayPluginRegistry ? createPluginGatewayMethodDescriptors(gatewayPluginRegistry) : [],
...createGatewayMethodDescriptorsFromHandlers({
handlers: auxHandlers,
owner: {
kind: "aux",
area: "gateway-extra"
},
defaultScope: ADMIN_SCOPE
})
], gatewayPluginRegistry ?? void 0);
}
/** Applies the router-owned authorization fence before any transport or typed dispatch. */
async function authorizeGatewayRequestPreDispatch(params) {
const authError = authorizeGatewayMethod(params.method, params.client, params.requestParams, params.methodRegistry);
if (authError) return { error: authError };
const profileError = await authorizeAuthenticatedProfileForMethod(params);
if (profileError) return { error: profileError };
if (params.context.unavailableGatewayMethods?.has(params.method)) return { error: errorShape(ErrorCodes.UNAVAILABLE, `${params.method} unavailable during gateway startup`, {
retryable: true,
retryAfterMs: 500,
details: {
...gatewayStartupUnavailableDetails(),
method: params.method
}
}) };
const sessionMutation = resolveSessionMutationAuthorization({
client: params.client ?? null,
method: params.method,
requestParams: params.requestParams,
context: params.context
});
if (sessionMutation.error) return { error: sessionMutation.error };
if (params.client?.connect.role === "node" && (!params.client.connId || !await params.context.nodeRegistry.isConnectionCurrentPairingState(params.client.connId))) return { error: errorShape(ErrorCodes.UNAVAILABLE, "node pairing changed before request dispatch", {
retryable: true,
details: { code: "PAIRING_CHANGED" }
}) };
return {
error: null,
...sessionMutation.authorization ? { sessionMutationAuthorization: sessionMutation.authorization } : {}
};
}
/** Runs admitted Gateway work inside the shared root and plugin request scopes. */
async function runWithGatewayRequestEnvelope(method, client, fn, options) {
const rejectRateLimitedControlPlaneWrite = () => {
if (!options.methodRegistry.isControlPlaneWrite(method)) return;
const budget = consumeControlPlaneWriteBudget({
client,
method
});
if (budget.allowed) return;
const actor = resolveControlPlaneActor(client);
options.context.logGateway.warn(`control-plane write rate-limited method=${method} ${formatControlPlaneActor(actor)} retryAfterMs=${budget.retryAfterMs} key=${budget.key}`);
return errorShape(ErrorCodes.UNAVAILABLE, `rate limit exceeded for ${method}; retry after ${Math.ceil(budget.retryAfterMs / 1e3)}s`, {
retryable: true,
retryAfterMs: budget.retryAfterMs,
details: {
method,
limit: `30 per ${CONTROL_PLANE_RATE_LIMIT_WINDOW_MS / 1e3}s`
}
});
};
const isSuspendPrepare = method === "gateway.suspend.prepare";
const preAdmissionRateLimitError = isSuspendPrepare ? rejectRateLimitedControlPlaneWrite() : void 0;
if (preAdmissionRateLimitError) return await options.reject(preAdmissionRateLimitError);
const rootWorkAdmission = options.admission === "continuation" ? null : tryBeginGatewayRootWorkAdmission(`ws:${method}`) ?? (method === "gateway.restart.request" && isTargetedNonSafeGatewayRestartRequest(options.requestParams) ? tryBeginGatewayPreparedRestartRootWorkAdmission() : null);
if (!rootWorkAdmission) {
const continuation = runGatewayPendingWorkContinuation({
method,
client,
requestParams: options.requestParams,
context: options.context,
admission: options.admission,
run: invokeWithRequestScope
});
if (continuation) return await continuation;
if (options.admission === "continuation") return await options.reject(errorShape(ErrorCodes.UNAVAILABLE, `${method} unavailable during gateway shutdown`));
}
if (isSuspendPrepare && rootWorkAdmission && !rootWorkAdmission.ownsRoot) return await options.reject(errorShape(ErrorCodes.UNAVAILABLE, "gateway suspension cannot begin from a nested request", {
retryable: true,
retryAfterMs: 1e3,
details: {
method,
reason: "nested-gateway-request"
}
}));
if (!rootWorkAdmission && !SUSPEND_CONTROL_METHODS.has(method)) {
const restartDraining = isGatewayRestartDraining();
return await options.reject(errorShape(ErrorCodes.UNAVAILABLE, `${method} unavailable during gateway ${restartDraining ? "restart" : "suspension"}`, {
retryable: true,
retryAfterMs: 1e3,
details: {
method,
reason: restartDraining ? GATEWAY_RESTART_UNAVAILABLE_REASON : GATEWAY_SUSPEND_UNAVAILABLE_REASON,
phase: getGatewaySuspendAdmissionPhase()
}
}));
}
async function invokeWithRequestScope() {
const postAdmissionRateLimitError = isSuspendPrepare ? void 0 : rejectRateLimitedControlPlaneWrite();
if (postAdmissionRateLimitError) return await options.reject(postAdmissionRateLimitError);
try {
const pluginRegistry = options.methodRegistry.pluginRegistry ?? getPluginRuntimeGatewayRequestScope()?.pluginRegistry ?? getActivePluginRegistry() ?? void 0;
return await withPluginRuntimeGatewayRequestScope({
context: options.context,
resolveGatewayContext: options.context.resolveGatewayContext,
client,
isWebchatConnect: options.isWebchatConnect,
...client?.internal?.nodeInvokeStream ? getPluginRuntimeGatewayNodeAuthorities() : {},
...pluginRegistry ? { pluginRegistry } : {}
}, fn);
} catch (error) {
if (error instanceof SessionMutationAuthorizationChangedError) return await options.reject(error.error);
const staleInstall = classifyGatewayStaleInstall(error);
if (staleInstall) return await options.reject(staleInstall.error);
throw error;
}
}
if (!rootWorkAdmission) return await invokeWithRequestScope();
try {
return await rootWorkAdmission.run(invokeWithRequestScope);
} finally {
rootWorkAdmission.release();
}
}
/** Authorizes and dispatches one gateway JSON-RPC-style request. */
async function handleGatewayRequest(opts, diagnostics) {
const { req, respond, client, isWebchatConnect, context, signal } = opts;
const entry = opts.requestEntry ?? context.requestEntryLifetime?.enter(opts);
try {
entry?.assertOpen();
const methodRegistry = opts.methodRegistry?.getHandler(req.method) !== void 0 ? opts.methodRegistry : createRequestGatewayMethodRegistry(opts.extraHandlers);
const authorization = await authorizeGatewayRequestPreDispatch({
method: req.method,
requestParams: req.params,
client,
context,
methodRegistry
});
entry?.assertOpen();
if (authorization.error) {
respond(false, void 0, authorization.error);
return;
}
const handler = methodRegistry.getHandler(req.method);
if (!handler) {
respond(false, void 0, errorShape(ErrorCodes.INVALID_REQUEST, `unknown method: ${req.method}`));
return;
}
const sessionMutationAuthorization = withSessionMutationCommitGuard(authorization.sessionMutationAuthorization, opts.sessionMutationCommitGuard);
const invokeHandler = async () => {
const preparedHandler = await prepareGatewayRequestHandler(handler, entry);
const handlerOptions = {
req,
params: req.params ?? {},
client,
isWebchatConnect,
respond,
context,
signal,
sessionMutationCommitGuard: opts.sessionMutationCommitGuard,
sessionMutationAuthorization
};
opts.sessionMutationCommitGuard?.();
entry?.assertOpen();
if (signal?.aborted) return;
entry?.release();
return diagnostics ? diagnostics.runHandler(() => preparedHandler(handlerOptions)) : preparedHandler(handlerOptions);
};
await runWithGatewayRequestEnvelope(req.method, client, invokeHandler, {
context,
isWebchatConnect,
methodRegistry,
requestParams: req.params,
admission: opts.admission,
reject: (error) => respond(false, void 0, error)
});
} finally {
if (!opts.requestEntry) entry?.release();
}
}
//#endregion
export { coreGatewayHandlers as a, runWithGatewayRequestEnvelope as i, createRequestGatewayMethodRegistry as n, handleGatewayRequest as r, authorizeGatewayRequestPreDispatch as t };