mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-18 09:24:45 +00:00
refactor: add gateway method dispatch contract
This commit is contained in:
@@ -480,6 +480,10 @@
|
||||
"types": "./dist/plugin-sdk/security-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/security-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/gateway-method-runtime": {
|
||||
"types": "./dist/plugin-sdk/gateway-method-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/gateway-method-runtime.js"
|
||||
},
|
||||
"./plugin-sdk/gateway-runtime": {
|
||||
"types": "./dist/plugin-sdk/gateway-runtime.d.ts",
|
||||
"default": "./dist/plugin-sdk/gateway-runtime.js"
|
||||
|
||||
@@ -108,6 +108,10 @@
|
||||
"types": "./dist/src/plugin-sdk/cli-runtime.d.ts",
|
||||
"default": "./src/cli-runtime.ts"
|
||||
},
|
||||
"./gateway-method-runtime": {
|
||||
"types": "./dist/src/plugin-sdk/gateway-method-runtime.d.ts",
|
||||
"default": "./src/gateway-method-runtime.ts"
|
||||
},
|
||||
"./error-runtime": {
|
||||
"types": "./dist/src/plugin-sdk/error-runtime.d.ts",
|
||||
"default": "./src/error-runtime.ts"
|
||||
|
||||
1
packages/plugin-sdk/src/gateway-method-runtime.ts
Normal file
1
packages/plugin-sdk/src/gateway-method-runtime.ts
Normal file
@@ -0,0 +1 @@
|
||||
export * from "../../../src/plugin-sdk/gateway-method-runtime.js";
|
||||
@@ -95,6 +95,7 @@
|
||||
"secret-ref-runtime",
|
||||
"secret-file-runtime",
|
||||
"security-runtime",
|
||||
"gateway-method-runtime",
|
||||
"gateway-runtime",
|
||||
"cli-runtime",
|
||||
"cli-backend",
|
||||
|
||||
@@ -299,17 +299,20 @@ function mergeGatewayClientInternal(
|
||||
|
||||
type DispatchGatewayMethodInProcessOptions = {
|
||||
allowSyntheticModelOverride?: boolean;
|
||||
disableSyntheticClient?: boolean;
|
||||
expectFinal?: boolean;
|
||||
forceSyntheticClient?: boolean;
|
||||
pluginRuntimeOwnerId?: string;
|
||||
requireScopedClient?: boolean;
|
||||
syntheticScopes?: string[];
|
||||
timeoutMs?: number;
|
||||
};
|
||||
|
||||
type GatewayMethodDispatchResponse = {
|
||||
export type GatewayMethodDispatchResponse = {
|
||||
ok: boolean;
|
||||
payload?: unknown;
|
||||
error?: ErrorShape;
|
||||
meta?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
function unwrapGatewayMethodDispatchResponse(
|
||||
@@ -322,11 +325,11 @@ function unwrapGatewayMethodDispatchResponse(
|
||||
return response.payload;
|
||||
}
|
||||
|
||||
async function dispatchGatewayMethod<T>(
|
||||
export async function dispatchGatewayMethodInProcessRaw(
|
||||
method: string,
|
||||
params: Record<string, unknown>,
|
||||
params: unknown,
|
||||
options?: DispatchGatewayMethodInProcessOptions,
|
||||
): Promise<T> {
|
||||
): Promise<GatewayMethodDispatchResponse> {
|
||||
const scope = getPluginRuntimeGatewayRequestScope();
|
||||
const context = scope?.context ?? getFallbackGatewayContext();
|
||||
const isWebchatConnect = scope?.isWebchatConnect ?? (() => false);
|
||||
@@ -335,6 +338,11 @@ async function dispatchGatewayMethod<T>(
|
||||
`In-process gateway dispatch requires a gateway request scope (method: ${method}). No scope set and no fallback context available.`,
|
||||
);
|
||||
}
|
||||
if (options?.requireScopedClient === true && !scope?.client) {
|
||||
throw new Error(
|
||||
`In-process gateway dispatch requires an authenticated plugin request scope (method: ${method}).`,
|
||||
);
|
||||
}
|
||||
|
||||
let firstResponse: GatewayMethodDispatchResponse | undefined;
|
||||
let finalResponse: GatewayMethodDispatchResponse | undefined;
|
||||
@@ -353,6 +361,9 @@ async function dispatchGatewayMethod<T>(
|
||||
scope?.client,
|
||||
pluginRuntimeOwnerId ? { pluginRuntimeOwnerId } : undefined,
|
||||
);
|
||||
if (options?.disableSyntheticClient === true && !scopedClient) {
|
||||
throw new Error(`In-process gateway dispatch requires a scoped client (method: ${method}).`);
|
||||
}
|
||||
await handleGatewayRequest({
|
||||
req: {
|
||||
type: "req",
|
||||
@@ -361,10 +372,12 @@ async function dispatchGatewayMethod<T>(
|
||||
params,
|
||||
},
|
||||
client:
|
||||
options?.forceSyntheticClient === true ? syntheticClient : (scopedClient ?? syntheticClient),
|
||||
options?.forceSyntheticClient === true
|
||||
? syntheticClient
|
||||
: (scopedClient ?? (options?.disableSyntheticClient === true ? null : syntheticClient)),
|
||||
isWebchatConnect,
|
||||
respond: (ok, payload, error) => {
|
||||
const response = { ok, payload, error };
|
||||
respond: (ok, payload, error, meta) => {
|
||||
const response = { ok, payload, error, ...(meta ? { meta } : {}) };
|
||||
if (!firstResponse) {
|
||||
firstResponse = response;
|
||||
return;
|
||||
@@ -382,7 +395,7 @@ async function dispatchGatewayMethod<T>(
|
||||
}
|
||||
const firstPayload = firstResponse.payload as { status?: unknown } | undefined;
|
||||
if (options?.expectFinal !== true || firstPayload?.status !== "accepted") {
|
||||
return unwrapGatewayMethodDispatchResponse(method, firstResponse) as T;
|
||||
return firstResponse;
|
||||
}
|
||||
const final =
|
||||
finalResponse ??
|
||||
@@ -412,7 +425,16 @@ async function dispatchGatewayMethod<T>(
|
||||
resolve(response);
|
||||
};
|
||||
}));
|
||||
return unwrapGatewayMethodDispatchResponse(method, final) as T;
|
||||
return final;
|
||||
}
|
||||
|
||||
async function dispatchGatewayMethod<T>(
|
||||
method: string,
|
||||
params: unknown,
|
||||
options?: DispatchGatewayMethodInProcessOptions,
|
||||
): Promise<T> {
|
||||
const response = await dispatchGatewayMethodInProcessRaw(method, params, options);
|
||||
return unwrapGatewayMethodDispatchResponse(method, response) as T;
|
||||
}
|
||||
|
||||
export async function dispatchGatewayMethodInProcess<T>(
|
||||
|
||||
@@ -20,6 +20,7 @@ function createRoute(params: {
|
||||
auth: "gateway" | "plugin";
|
||||
match?: "exact" | "prefix";
|
||||
gatewayRuntimeScopeSurface?: "write-default" | "trusted-operator";
|
||||
gatewayMethodDispatchAllowed?: boolean;
|
||||
handler?: (req: IncomingMessage, res: ServerResponse) => boolean | Promise<boolean>;
|
||||
}) {
|
||||
return {
|
||||
@@ -27,6 +28,7 @@ function createRoute(params: {
|
||||
path: params.path,
|
||||
auth: params.auth,
|
||||
gatewayRuntimeScopeSurface: params.gatewayRuntimeScopeSurface,
|
||||
gatewayMethodDispatchAllowed: params.gatewayMethodDispatchAllowed,
|
||||
match: params.match ?? "exact",
|
||||
handler: params.handler ?? (() => true),
|
||||
source: "route",
|
||||
@@ -142,6 +144,51 @@ describe("plugin HTTP route runtime scopes", () => {
|
||||
expect(log.warn).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("threads plugin route identity and gateway dispatch entitlement into runtime scope", async () => {
|
||||
let observed:
|
||||
| {
|
||||
pluginId: string | undefined;
|
||||
pluginSource: string | undefined;
|
||||
gatewayMethodDispatchAllowed: boolean | undefined;
|
||||
}
|
||||
| undefined;
|
||||
const handler = createGatewayPluginRequestHandler({
|
||||
registry: createTestRegistry({
|
||||
httpRoutes: [
|
||||
createRoute({
|
||||
path: "/secure-hook",
|
||||
auth: "gateway",
|
||||
gatewayMethodDispatchAllowed: true,
|
||||
handler: async () => {
|
||||
const scope = getPluginRuntimeGatewayRequestScope();
|
||||
observed = {
|
||||
pluginId: scope?.pluginId,
|
||||
pluginSource: scope?.pluginSource,
|
||||
gatewayMethodDispatchAllowed: scope?.gatewayMethodDispatchAllowed,
|
||||
};
|
||||
return true;
|
||||
},
|
||||
}),
|
||||
],
|
||||
}),
|
||||
log: createMockLogger(),
|
||||
});
|
||||
|
||||
const { res } = makeMockHttpResponse();
|
||||
const handled = await handler({ url: "/secure-hook" } as IncomingMessage, res, undefined, {
|
||||
gatewayAuthSatisfied: true,
|
||||
gatewayRequestOperatorScopes: ["operator.write"],
|
||||
});
|
||||
|
||||
expect(handled).toBe(true);
|
||||
expect(res.statusCode).toBe(200);
|
||||
expect(observed).toEqual({
|
||||
pluginId: "route",
|
||||
pluginSource: "route",
|
||||
gatewayMethodDispatchAllowed: true,
|
||||
});
|
||||
});
|
||||
|
||||
it("does not give approval-scoped gateway-auth routes global approval visibility", async () => {
|
||||
const manager = new ExecApprovalManager<{ command: string }>();
|
||||
const record = manager.create({ command: "echo ok" }, 60_000, "route-hidden-approval");
|
||||
|
||||
@@ -147,6 +147,11 @@ export function createGatewayPluginRequestHandler(params: {
|
||||
{
|
||||
client: runtimeClient,
|
||||
isWebchatConnect: () => false,
|
||||
...(route.pluginId ? { pluginId: route.pluginId } : {}),
|
||||
...(route.source ? { pluginSource: route.source } : {}),
|
||||
...(route.gatewayMethodDispatchAllowed === true
|
||||
? { gatewayMethodDispatchAllowed: true }
|
||||
: {}),
|
||||
},
|
||||
async () => route.handler(req, res),
|
||||
);
|
||||
@@ -243,6 +248,11 @@ export function createGatewayPluginUpgradeHandler(params: {
|
||||
{
|
||||
client: runtimeClient,
|
||||
isWebchatConnect: () => false,
|
||||
...(route.pluginId ? { pluginId: route.pluginId } : {}),
|
||||
...(route.source ? { pluginSource: route.source } : {}),
|
||||
...(route.gatewayMethodDispatchAllowed === true
|
||||
? { gatewayMethodDispatchAllowed: true }
|
||||
: {}),
|
||||
},
|
||||
async () => route.handleUpgrade?.(req, socket, head),
|
||||
);
|
||||
|
||||
@@ -47,6 +47,7 @@ vi.mock("./http-utils.js", () => ({
|
||||
authorizeScopedGatewayHttpRequestOrReply: async () => ({
|
||||
cfg: { gateway: { webchat: { chatHistoryMaxChars: 2000 } } },
|
||||
requestAuth: { trustDeclaredOperatorScopes: true },
|
||||
operatorScopes: ["operator.read"],
|
||||
}),
|
||||
checkGatewayHttpRequestAuth: async (params: {
|
||||
trustedProxies?: string[];
|
||||
|
||||
60
src/plugin-sdk/gateway-method-runtime.test.ts
Normal file
60
src/plugin-sdk/gateway-method-runtime.test.ts
Normal file
@@ -0,0 +1,60 @@
|
||||
import { describe, expect, it, vi } from "vitest";
|
||||
import { withPluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js";
|
||||
import { dispatchGatewayMethod } from "./gateway-method-runtime.js";
|
||||
|
||||
const { dispatchGatewayMethodInProcessRaw } = vi.hoisted(() => ({
|
||||
dispatchGatewayMethodInProcessRaw: vi.fn(),
|
||||
}));
|
||||
|
||||
vi.mock("../gateway/server-plugins.js", () => ({
|
||||
dispatchGatewayMethodInProcessRaw,
|
||||
}));
|
||||
|
||||
describe("plugin-sdk/gateway-method-runtime", () => {
|
||||
it("rejects callers without the gateway method dispatch contract", async () => {
|
||||
await expect(
|
||||
withPluginRuntimeGatewayRequestScope(
|
||||
{
|
||||
pluginId: "plain-plugin",
|
||||
client: {
|
||||
id: "plugin",
|
||||
connect: { scopes: ["operator.write"] },
|
||||
} as never,
|
||||
isWebchatConnect: () => false,
|
||||
},
|
||||
() => dispatchGatewayMethod("health", {}),
|
||||
),
|
||||
).rejects.toThrow(
|
||||
'contracts.gatewayMethodDispatch: ["authenticated-request"] for plugin "plain-plugin"',
|
||||
);
|
||||
expect(dispatchGatewayMethodInProcessRaw).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("dispatches through the scoped client for entitled plugin HTTP routes", async () => {
|
||||
dispatchGatewayMethodInProcessRaw.mockResolvedValueOnce({ ok: true, payload: { ok: true } });
|
||||
|
||||
const result = await withPluginRuntimeGatewayRequestScope(
|
||||
{
|
||||
pluginId: "admin-http-rpc",
|
||||
gatewayMethodDispatchAllowed: true,
|
||||
client: {
|
||||
id: "plugin",
|
||||
connect: { scopes: ["operator.admin"] },
|
||||
} as never,
|
||||
isWebchatConnect: () => false,
|
||||
},
|
||||
() => dispatchGatewayMethod("health", {}, { timeoutMs: 500 }),
|
||||
);
|
||||
|
||||
expect(result).toEqual({ ok: true, payload: { ok: true } });
|
||||
expect(dispatchGatewayMethodInProcessRaw).toHaveBeenCalledWith(
|
||||
"health",
|
||||
{},
|
||||
{
|
||||
disableSyntheticClient: true,
|
||||
requireScopedClient: true,
|
||||
timeoutMs: 500,
|
||||
},
|
||||
);
|
||||
});
|
||||
});
|
||||
45
src/plugin-sdk/gateway-method-runtime.ts
Normal file
45
src/plugin-sdk/gateway-method-runtime.ts
Normal file
@@ -0,0 +1,45 @@
|
||||
import { dispatchGatewayMethodInProcessRaw } from "../gateway/server-plugins.js";
|
||||
import { getPluginRuntimeGatewayRequestScope } from "../plugins/runtime/gateway-request-scope.js";
|
||||
|
||||
export type GatewayMethodDispatchError = {
|
||||
code: string;
|
||||
message: string;
|
||||
details?: unknown;
|
||||
retryable?: boolean;
|
||||
retryAfterMs?: number;
|
||||
};
|
||||
|
||||
export type GatewayMethodDispatchResponse = {
|
||||
ok: boolean;
|
||||
payload?: unknown;
|
||||
error?: GatewayMethodDispatchError;
|
||||
meta?: Record<string, unknown>;
|
||||
};
|
||||
|
||||
export type GatewayMethodDispatchOptions = {
|
||||
expectFinal?: boolean;
|
||||
timeoutMs?: number;
|
||||
};
|
||||
|
||||
/**
|
||||
* Dispatch a Gateway control-plane method from an authenticated plugin request scope.
|
||||
*/
|
||||
export async function dispatchGatewayMethod(
|
||||
method: string,
|
||||
params?: unknown,
|
||||
options?: GatewayMethodDispatchOptions,
|
||||
): Promise<GatewayMethodDispatchResponse> {
|
||||
const scope = getPluginRuntimeGatewayRequestScope();
|
||||
if (scope?.gatewayMethodDispatchAllowed !== true) {
|
||||
const pluginLabel = scope?.pluginId ? ` for plugin "${scope.pluginId}"` : "";
|
||||
throw new Error(
|
||||
`Gateway method dispatch is reserved for plugin HTTP routes that declare contracts.gatewayMethodDispatch: ["authenticated-request"]${pluginLabel}.`,
|
||||
);
|
||||
}
|
||||
return await dispatchGatewayMethodInProcessRaw(method, params, {
|
||||
disableSyntheticClient: true,
|
||||
requireScopedClient: true,
|
||||
...(options?.expectFinal !== undefined ? { expectFinal: options.expectFinal } : {}),
|
||||
...(options?.timeoutMs !== undefined ? { timeoutMs: options.timeoutMs } : {}),
|
||||
});
|
||||
}
|
||||
@@ -1,12 +1,16 @@
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import type { OpenClawConfig } from "../config/types.openclaw.js";
|
||||
import { registerPluginHttpRoute } from "./http-registry.js";
|
||||
import { createEmptyPluginRegistry } from "./registry-empty.js";
|
||||
import { createPluginRegistry } from "./registry.js";
|
||||
import {
|
||||
pinActivePluginHttpRouteRegistry,
|
||||
releasePinnedPluginHttpRouteRegistry,
|
||||
resetPluginRuntimeStateForTest,
|
||||
setActivePluginRegistry,
|
||||
} from "./runtime.js";
|
||||
import type { PluginRuntime } from "./runtime/types.js";
|
||||
import { createPluginRecord } from "./status.test-helpers.js";
|
||||
|
||||
function expectRouteRegistrationDenied(params: {
|
||||
replaceExisting: boolean;
|
||||
@@ -109,6 +113,51 @@ describe("registerPluginHttpRoute", () => {
|
||||
expect(registry.httpRoutes).toHaveLength(0);
|
||||
});
|
||||
|
||||
it("marks gateway method dispatch entitlement only for plugins declaring the contract", () => {
|
||||
const pluginRegistry = createPluginRegistry({
|
||||
logger: {
|
||||
info() {},
|
||||
warn() {},
|
||||
error() {},
|
||||
debug() {},
|
||||
},
|
||||
runtime: {} as PluginRuntime,
|
||||
activateGlobalSideEffects: false,
|
||||
});
|
||||
const config = {} as OpenClawConfig;
|
||||
const plainRecord = createPluginRecord({
|
||||
id: "plain-http",
|
||||
source: "/plugins/plain-http/index.ts",
|
||||
});
|
||||
const adminRecord = createPluginRecord({
|
||||
id: "admin-http",
|
||||
source: "/plugins/admin-http/index.ts",
|
||||
contracts: { gatewayMethodDispatch: ["authenticated-request"] },
|
||||
});
|
||||
|
||||
pluginRegistry.registry.plugins.push(plainRecord, adminRecord);
|
||||
pluginRegistry.createApi(plainRecord, { config }).registerHttpRoute({
|
||||
path: "/plain",
|
||||
auth: "gateway",
|
||||
handler: vi.fn(),
|
||||
});
|
||||
pluginRegistry.createApi(adminRecord, { config }).registerHttpRoute({
|
||||
path: "/admin",
|
||||
auth: "gateway",
|
||||
handler: vi.fn(),
|
||||
});
|
||||
|
||||
const plainRoute = pluginRegistry.registry.httpRoutes.find(
|
||||
(route) => route.pluginId === "plain-http",
|
||||
);
|
||||
const adminRoute = pluginRegistry.registry.httpRoutes.find(
|
||||
(route) => route.pluginId === "admin-http",
|
||||
);
|
||||
|
||||
expect(plainRoute?.gatewayMethodDispatchAllowed).toBeUndefined();
|
||||
expect(adminRoute?.gatewayMethodDispatchAllowed).toBe(true);
|
||||
});
|
||||
|
||||
it("returns noop unregister when path is missing", () => {
|
||||
const registry = createEmptyPluginRegistry();
|
||||
const logs: string[] = [];
|
||||
|
||||
@@ -165,7 +165,8 @@ export type PluginManifestContractListKey =
|
||||
| "webContentExtractors"
|
||||
| "webFetchProviders"
|
||||
| "webSearchProviders"
|
||||
| "migrationProviders";
|
||||
| "migrationProviders"
|
||||
| "gatewayMethodDispatch";
|
||||
|
||||
type SeenIdEntry = {
|
||||
candidate: PluginCandidate;
|
||||
@@ -379,6 +380,7 @@ function mergeManifestContracts(
|
||||
"webFetchProviders",
|
||||
"webSearchProviders",
|
||||
"migrationProviders",
|
||||
"gatewayMethodDispatch",
|
||||
"tools",
|
||||
] as const) {
|
||||
const merged = mergeContractLists(manifestContracts?.[key], catalogContracts[key]);
|
||||
|
||||
@@ -415,6 +415,7 @@ export type PluginManifestContracts = {
|
||||
webFetchProviders?: string[];
|
||||
webSearchProviders?: string[];
|
||||
migrationProviders?: string[];
|
||||
gatewayMethodDispatch?: string[];
|
||||
tools?: string[];
|
||||
};
|
||||
|
||||
@@ -807,6 +808,7 @@ function normalizeManifestContracts(value: unknown): PluginManifestContracts | u
|
||||
const webFetchProviders = normalizeTrimmedStringList(value.webFetchProviders);
|
||||
const webSearchProviders = normalizeTrimmedStringList(value.webSearchProviders);
|
||||
const migrationProviders = normalizeTrimmedStringList(value.migrationProviders);
|
||||
const gatewayMethodDispatch = normalizeTrimmedStringList(value.gatewayMethodDispatch);
|
||||
const tools = normalizeTrimmedStringList(value.tools);
|
||||
const contracts = {
|
||||
...(embeddedExtensionFactories.length > 0 ? { embeddedExtensionFactories } : {}),
|
||||
@@ -825,6 +827,7 @@ function normalizeManifestContracts(value: unknown): PluginManifestContracts | u
|
||||
...(webFetchProviders.length > 0 ? { webFetchProviders } : {}),
|
||||
...(webSearchProviders.length > 0 ? { webSearchProviders } : {}),
|
||||
...(migrationProviders.length > 0 ? { migrationProviders } : {}),
|
||||
...(gatewayMethodDispatch.length > 0 ? { gatewayMethodDispatch } : {}),
|
||||
...(tools.length > 0 ? { tools } : {}),
|
||||
} satisfies PluginManifestContracts;
|
||||
|
||||
|
||||
@@ -98,6 +98,7 @@ export type PluginHttpRouteRegistration = {
|
||||
auth: OpenClawPluginHttpRouteAuth;
|
||||
match: OpenClawPluginHttpRouteMatch;
|
||||
gatewayRuntimeScopeSurface?: OpenClawPluginGatewayRuntimeScopeSurface;
|
||||
gatewayMethodDispatchAllowed?: boolean;
|
||||
nodeCapability?: {
|
||||
surface: string;
|
||||
ttlMs?: number;
|
||||
|
||||
@@ -184,6 +184,9 @@ import type {
|
||||
export type PluginHttpRouteRegistration = RegistryTypesPluginHttpRouteRegistration & {
|
||||
gatewayRuntimeScopeSurface?: OpenClawPluginGatewayRuntimeScopeSurface;
|
||||
};
|
||||
|
||||
const GATEWAY_METHOD_DISPATCH_CONTRACT = "authenticated-request";
|
||||
|
||||
type PluginOwnedProviderRegistration<T extends { id: string }> = {
|
||||
pluginId: string;
|
||||
pluginName?: string;
|
||||
@@ -726,6 +729,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
return `${plugin} (${source})`;
|
||||
};
|
||||
|
||||
const canDispatchGatewayMethodsFromHttpRoute = (record: PluginRecord): boolean =>
|
||||
(record.contracts?.gatewayMethodDispatch ?? []).includes(GATEWAY_METHOD_DISPATCH_CONTRACT);
|
||||
|
||||
const registerHttpRoute = (record: PluginRecord, params: OpenClawPluginHttpRouteParams) => {
|
||||
const normalizedPath = normalizePluginHttpPath(params.path);
|
||||
if (!normalizedPath) {
|
||||
@@ -799,6 +805,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
...(params.gatewayRuntimeScopeSurface
|
||||
? { gatewayRuntimeScopeSurface: params.gatewayRuntimeScopeSurface }
|
||||
: {}),
|
||||
...(canDispatchGatewayMethodsFromHttpRoute(record)
|
||||
? { gatewayMethodDispatchAllowed: true }
|
||||
: {}),
|
||||
...(params.nodeCapability ? { nodeCapability: { ...params.nodeCapability } } : {}),
|
||||
source: record.source,
|
||||
};
|
||||
@@ -815,6 +824,9 @@ export function createPluginRegistry(registryParams: PluginRegistryParams) {
|
||||
...(params.gatewayRuntimeScopeSurface
|
||||
? { gatewayRuntimeScopeSurface: params.gatewayRuntimeScopeSurface }
|
||||
: {}),
|
||||
...(canDispatchGatewayMethodsFromHttpRoute(record)
|
||||
? { gatewayMethodDispatchAllowed: true }
|
||||
: {}),
|
||||
...(params.nodeCapability ? { nodeCapability: { ...params.nodeCapability } } : {}),
|
||||
source: record.source,
|
||||
});
|
||||
|
||||
@@ -11,6 +11,7 @@ export type PluginRuntimeGatewayRequestScope = {
|
||||
isWebchatConnect: GatewayRequestOptions["isWebchatConnect"];
|
||||
pluginId?: string;
|
||||
pluginSource?: string;
|
||||
gatewayMethodDispatchAllowed?: boolean;
|
||||
};
|
||||
|
||||
export type PluginRuntimePluginScope = {
|
||||
|
||||
Reference in New Issue
Block a user