mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-09 16:21:15 +00:00
fix(plugins): guard runtime facade activation (#59412)
* fix(plugins): guard runtime facade activation * refactor(plugin-sdk): localize facade load policy * fix(plugin-sdk): narrow facade activation guards * fix(browser): keep cleanup helpers outside activation guard * style(browser): apply formatter follow-ups * chore(changelog): note plugin activation guard regressions * fix(discord): keep cleanup thread unbinds outside activation guard * fix(browser): fallback when trash exits non-zero
This commit is contained in:
66
src/plugin-sdk/browser-maintenance.test.ts
Normal file
66
src/plugin-sdk/browser-maintenance.test.ts
Normal file
@@ -0,0 +1,66 @@
|
||||
import { beforeEach, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const runCommandWithTimeout = vi.hoisted(() => vi.fn());
|
||||
const mkdir = vi.hoisted(() => vi.fn());
|
||||
const access = vi.hoisted(() => vi.fn());
|
||||
const rename = vi.hoisted(() => vi.fn());
|
||||
|
||||
vi.mock("../process/exec.js", () => ({
|
||||
runCommandWithTimeout,
|
||||
}));
|
||||
|
||||
vi.mock("node:fs/promises", () => {
|
||||
const mocked = { mkdir, access, rename };
|
||||
return { ...mocked, default: mocked };
|
||||
});
|
||||
|
||||
vi.mock("node:os", () => ({
|
||||
default: {
|
||||
homedir: () => "/home/test",
|
||||
},
|
||||
homedir: () => "/home/test",
|
||||
}));
|
||||
|
||||
describe("browser maintenance", () => {
|
||||
beforeEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
runCommandWithTimeout.mockReset();
|
||||
mkdir.mockReset();
|
||||
access.mockReset();
|
||||
rename.mockReset();
|
||||
vi.spyOn(Date, "now").mockReturnValue(123);
|
||||
});
|
||||
|
||||
it("returns the target path when trash exits successfully", async () => {
|
||||
const { movePathToTrash } = await import("./browser-maintenance.js");
|
||||
runCommandWithTimeout.mockResolvedValue({
|
||||
stdout: "",
|
||||
stderr: "",
|
||||
code: 0,
|
||||
signal: null,
|
||||
killed: false,
|
||||
termination: "exit",
|
||||
});
|
||||
|
||||
await expect(movePathToTrash("/tmp/demo")).resolves.toBe("/tmp/demo");
|
||||
expect(mkdir).not.toHaveBeenCalled();
|
||||
expect(rename).not.toHaveBeenCalled();
|
||||
});
|
||||
|
||||
it("falls back to rename when trash exits non-zero", async () => {
|
||||
const { movePathToTrash } = await import("./browser-maintenance.js");
|
||||
runCommandWithTimeout.mockResolvedValue({
|
||||
stdout: "",
|
||||
stderr: "permission denied",
|
||||
code: 1,
|
||||
signal: null,
|
||||
killed: false,
|
||||
termination: "exit",
|
||||
});
|
||||
access.mockRejectedValue(new Error("missing"));
|
||||
|
||||
await expect(movePathToTrash("/tmp/demo")).resolves.toBe("/home/test/.Trash/demo-123");
|
||||
expect(mkdir).toHaveBeenCalledWith("/home/test/.Trash", { recursive: true });
|
||||
expect(rename).toHaveBeenCalledWith("/tmp/demo", "/home/test/.Trash/demo-123");
|
||||
});
|
||||
});
|
||||
54
src/plugin-sdk/browser-maintenance.ts
Normal file
54
src/plugin-sdk/browser-maintenance.ts
Normal file
@@ -0,0 +1,54 @@
|
||||
import { randomBytes } from "node:crypto";
|
||||
import fs from "node:fs/promises";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
import { runCommandWithTimeout } from "../process/exec.js";
|
||||
import { tryLoadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
type BrowserRuntimeModule = PluginSdkFacadeTypeMap["browser-runtime"]["module"];
|
||||
|
||||
function createTrashCollisionSuffix(): string {
|
||||
return randomBytes(6).toString("hex");
|
||||
}
|
||||
|
||||
export const closeTrackedBrowserTabsForSessions: BrowserRuntimeModule["closeTrackedBrowserTabsForSessions"] =
|
||||
(async (...args) => {
|
||||
// Session reset always attempts browser cleanup, even when browser is disabled.
|
||||
// Keep that path a no-op unless the browser runtime is actually active.
|
||||
const closeTrackedTabs = tryLoadActivatedBundledPluginPublicSurfaceModuleSync<
|
||||
Pick<BrowserRuntimeModule, "closeTrackedBrowserTabsForSessions">
|
||||
>({
|
||||
dirName: "browser",
|
||||
artifactBasename: "runtime-api.js",
|
||||
})?.closeTrackedBrowserTabsForSessions;
|
||||
if (typeof closeTrackedTabs !== "function") {
|
||||
return 0;
|
||||
}
|
||||
return await closeTrackedTabs(...args);
|
||||
}) as BrowserRuntimeModule["closeTrackedBrowserTabsForSessions"];
|
||||
|
||||
export const movePathToTrash: BrowserRuntimeModule["movePathToTrash"] = (async (...args) => {
|
||||
const [targetPath] = args;
|
||||
try {
|
||||
const result = await runCommandWithTimeout(["trash", targetPath], { timeoutMs: 10_000 });
|
||||
if (result.code !== 0) {
|
||||
throw new Error(`trash exited with code ${result.code ?? "unknown"}`);
|
||||
}
|
||||
return targetPath;
|
||||
} catch {
|
||||
const trashDir = path.join(os.homedir(), ".Trash");
|
||||
await fs.mkdir(trashDir, { recursive: true });
|
||||
const base = path.basename(targetPath);
|
||||
const timestamp = Date.now();
|
||||
let destination = path.join(trashDir, `${base}-${timestamp}`);
|
||||
try {
|
||||
await fs.access(destination);
|
||||
destination = path.join(trashDir, `${base}-${timestamp}-${createTrashCollisionSuffix()}`);
|
||||
} catch {
|
||||
// The initial destination is free to use.
|
||||
}
|
||||
await fs.rename(targetPath, destination);
|
||||
return destination;
|
||||
}
|
||||
}) as BrowserRuntimeModule["movePathToTrash"];
|
||||
@@ -13,13 +13,14 @@ export {
|
||||
resolveBrowserControlAuth,
|
||||
resolveProfile,
|
||||
} from "./browser-config.js";
|
||||
export { closeTrackedBrowserTabsForSessions, movePathToTrash } from "./browser-maintenance.js";
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "browser",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
@@ -71,11 +72,6 @@ export const browserTabAction: FacadeModule["browserTabAction"] = ((...args) =>
|
||||
loadFacadeModule()["browserTabAction"](...args)) as FacadeModule["browserTabAction"];
|
||||
export const browserTabs: FacadeModule["browserTabs"] = ((...args) =>
|
||||
loadFacadeModule()["browserTabs"](...args)) as FacadeModule["browserTabs"];
|
||||
export const closeTrackedBrowserTabsForSessions: FacadeModule["closeTrackedBrowserTabsForSessions"] =
|
||||
((...args) =>
|
||||
loadFacadeModule()["closeTrackedBrowserTabsForSessions"](
|
||||
...args,
|
||||
)) as FacadeModule["closeTrackedBrowserTabsForSessions"];
|
||||
export const createBrowserControlContext: FacadeModule["createBrowserControlContext"] = ((
|
||||
...args
|
||||
) =>
|
||||
@@ -139,8 +135,6 @@ export const isPersistentBrowserProfileMutation: FacadeModule["isPersistentBrows
|
||||
loadFacadeModule()["isPersistentBrowserProfileMutation"](
|
||||
...args,
|
||||
)) as FacadeModule["isPersistentBrowserProfileMutation"];
|
||||
export const movePathToTrash: FacadeModule["movePathToTrash"] = ((...args) =>
|
||||
loadFacadeModule()["movePathToTrash"](...args)) as FacadeModule["movePathToTrash"];
|
||||
export const normalizeBrowserFormField: FacadeModule["normalizeBrowserFormField"] = ((...args) =>
|
||||
loadFacadeModule()["normalizeBrowserFormField"](
|
||||
...args,
|
||||
|
||||
@@ -4,11 +4,11 @@ type FacadeEntry = PluginSdkFacadeTypeMap["browser"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "browser",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
17
src/plugin-sdk/discord-maintenance.ts
Normal file
17
src/plugin-sdk/discord-maintenance.ts
Normal file
@@ -0,0 +1,17 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
import { tryLoadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
type DiscordThreadBindingsModule = PluginSdkFacadeTypeMap["discord-thread-bindings"]["module"];
|
||||
|
||||
export const unbindThreadBindingsBySessionKey: DiscordThreadBindingsModule["unbindThreadBindingsBySessionKey"] =
|
||||
((...args) => {
|
||||
// Session cleanup always attempts Discord thread unbinds, even when Discord is disabled.
|
||||
// Keep that path a no-op unless the Discord runtime is actually active.
|
||||
const unbindThreadBindings = tryLoadActivatedBundledPluginPublicSurfaceModuleSync<
|
||||
Pick<DiscordThreadBindingsModule, "unbindThreadBindingsBySessionKey">
|
||||
>({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
})?.unbindThreadBindingsBySessionKey;
|
||||
return typeof unbindThreadBindings === "function" ? unbindThreadBindings(...args) : [];
|
||||
}) as DiscordThreadBindingsModule["unbindThreadBindingsBySessionKey"];
|
||||
@@ -4,11 +4,11 @@ type FacadeEntry = PluginSdkFacadeTypeMap["discord-runtime-surface"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -2,10 +2,11 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["discord-thread-bindings"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
export { unbindThreadBindingsBySessionKey } from "./discord-maintenance.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
@@ -61,12 +62,6 @@ export const setThreadBindingMaxAgeBySessionKey: FacadeModule["setThreadBindingM
|
||||
loadFacadeModule()["setThreadBindingMaxAgeBySessionKey"](
|
||||
...args,
|
||||
)) as FacadeModule["setThreadBindingMaxAgeBySessionKey"];
|
||||
export const unbindThreadBindingsBySessionKey: FacadeModule["unbindThreadBindingsBySessionKey"] = ((
|
||||
...args
|
||||
) =>
|
||||
loadFacadeModule()["unbindThreadBindingsBySessionKey"](
|
||||
...args,
|
||||
)) as FacadeModule["unbindThreadBindingsBySessionKey"];
|
||||
export type ThreadBindingManager = FacadeEntry["types"]["ThreadBindingManager"];
|
||||
export type ThreadBindingRecord = FacadeEntry["types"]["ThreadBindingRecord"];
|
||||
export type ThreadBindingTargetKind = FacadeEntry["types"]["ThreadBindingTargetKind"];
|
||||
|
||||
@@ -2,7 +2,13 @@ import fs from "node:fs";
|
||||
import os from "node:os";
|
||||
import path from "node:path";
|
||||
import { afterEach, describe, expect, it, vi } from "vitest";
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { clearRuntimeConfigSnapshot, setRuntimeConfigSnapshot } from "../config/config.js";
|
||||
import {
|
||||
canLoadActivatedBundledPluginPublicSurface,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
tryLoadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
const tempDirs: string[] = [];
|
||||
const originalBundledPluginsDir = process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
@@ -63,6 +69,7 @@ function createCircularPluginDir(prefix: string): string {
|
||||
|
||||
afterEach(() => {
|
||||
vi.restoreAllMocks();
|
||||
clearRuntimeConfigSnapshot();
|
||||
if (originalBundledPluginsDir === undefined) {
|
||||
delete process.env.OPENCLAW_BUNDLED_PLUGINS_DIR;
|
||||
} else {
|
||||
@@ -140,4 +147,69 @@ describe("plugin-sdk facade runtime", () => {
|
||||
}),
|
||||
).toThrow("plugin load failure");
|
||||
});
|
||||
|
||||
it("blocks runtime-api facade loads for bundled plugins that are not activated", () => {
|
||||
setRuntimeConfigSnapshot({});
|
||||
|
||||
expect(
|
||||
canLoadActivatedBundledPluginPublicSurface({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBe(false);
|
||||
expect(() =>
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toThrow(/Bundled plugin public surface access blocked/);
|
||||
expect(
|
||||
tryLoadActivatedBundledPluginPublicSurfaceModuleSync({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBeNull();
|
||||
});
|
||||
|
||||
it("allows runtime-api facade loads when the bundled plugin is explicitly enabled", () => {
|
||||
setRuntimeConfigSnapshot({
|
||||
plugins: {
|
||||
entries: {
|
||||
discord: {
|
||||
enabled: true,
|
||||
},
|
||||
},
|
||||
},
|
||||
});
|
||||
|
||||
expect(
|
||||
canLoadActivatedBundledPluginPublicSurface({
|
||||
dirName: "discord",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
|
||||
it("keeps shared runtime-core facades available without plugin activation", () => {
|
||||
setRuntimeConfigSnapshot({});
|
||||
|
||||
expect(
|
||||
canLoadActivatedBundledPluginPublicSurface({
|
||||
dirName: "speech-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
canLoadActivatedBundledPluginPublicSurface({
|
||||
dirName: "image-generation-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBe(true);
|
||||
expect(
|
||||
canLoadActivatedBundledPluginPublicSurface({
|
||||
dirName: "media-understanding-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
}),
|
||||
).toBe(true);
|
||||
});
|
||||
});
|
||||
|
||||
@@ -2,9 +2,16 @@ import fs from "node:fs";
|
||||
import path from "node:path";
|
||||
import { fileURLToPath } from "node:url";
|
||||
import { createJiti } from "jiti";
|
||||
import { loadConfig, type OpenClawConfig } from "../config/config.js";
|
||||
import { applyPluginAutoEnable } from "../config/plugin-auto-enable.js";
|
||||
import { openBoundaryFileSync } from "../infra/boundary-file-read.js";
|
||||
import { resolveBundledPluginsDir } from "../plugins/bundled-dir.js";
|
||||
import { resolveBundledPluginPublicSurfacePath } from "../plugins/bundled-plugin-metadata.js";
|
||||
import { normalizePluginsConfig, resolveEffectiveEnableState } from "../plugins/config-state.js";
|
||||
import {
|
||||
loadPluginManifestRegistry,
|
||||
type PluginManifestRecord,
|
||||
} from "../plugins/manifest-registry.js";
|
||||
import {
|
||||
buildPluginLoaderAliasMap,
|
||||
buildPluginLoaderJitiOptions,
|
||||
@@ -19,8 +26,21 @@ const OPENCLAW_PACKAGE_ROOT =
|
||||
}) ?? fileURLToPath(new URL("../..", import.meta.url));
|
||||
const CURRENT_MODULE_PATH = fileURLToPath(import.meta.url);
|
||||
const PUBLIC_SURFACE_SOURCE_EXTENSIONS = [".ts", ".mts", ".js", ".mjs", ".cts", ".cjs"] as const;
|
||||
const ALWAYS_ALLOWED_RUNTIME_DIR_NAMES = new Set([
|
||||
"image-generation-core",
|
||||
"media-understanding-core",
|
||||
"speech-core",
|
||||
]);
|
||||
const EMPTY_FACADE_BOUNDARY_CONFIG: OpenClawConfig = {};
|
||||
const jitiLoaders = new Map<string, ReturnType<typeof createJiti>>();
|
||||
const loadedFacadeModules = new Map<string, unknown>();
|
||||
let cachedBoundaryRawConfig: OpenClawConfig | undefined;
|
||||
let cachedBoundaryResolvedConfig:
|
||||
| {
|
||||
config: OpenClawConfig;
|
||||
normalizedPluginsConfig: ReturnType<typeof normalizePluginsConfig>;
|
||||
}
|
||||
| undefined;
|
||||
|
||||
function resolveSourceFirstPublicSurfacePath(params: {
|
||||
bundledPluginsDir?: string;
|
||||
@@ -106,6 +126,88 @@ function getJiti(modulePath: string) {
|
||||
return loader;
|
||||
}
|
||||
|
||||
function readFacadeBoundaryConfigSafely(): OpenClawConfig {
|
||||
try {
|
||||
return loadConfig();
|
||||
} catch {
|
||||
return EMPTY_FACADE_BOUNDARY_CONFIG;
|
||||
}
|
||||
}
|
||||
|
||||
function getFacadeBoundaryResolvedConfig() {
|
||||
const rawConfig = readFacadeBoundaryConfigSafely();
|
||||
if (cachedBoundaryResolvedConfig && cachedBoundaryRawConfig === rawConfig) {
|
||||
return cachedBoundaryResolvedConfig;
|
||||
}
|
||||
|
||||
const config = applyPluginAutoEnable({
|
||||
config: rawConfig,
|
||||
env: process.env,
|
||||
}).config;
|
||||
const resolved = {
|
||||
config,
|
||||
normalizedPluginsConfig: normalizePluginsConfig(config.plugins),
|
||||
};
|
||||
cachedBoundaryRawConfig = rawConfig;
|
||||
cachedBoundaryResolvedConfig = resolved;
|
||||
return resolved;
|
||||
}
|
||||
|
||||
function resolveBundledPluginManifestRecordByDirName(dirName: string): PluginManifestRecord | null {
|
||||
const { config } = getFacadeBoundaryResolvedConfig();
|
||||
return (
|
||||
loadPluginManifestRegistry({
|
||||
config,
|
||||
cache: true,
|
||||
}).plugins.find(
|
||||
(plugin) => plugin.origin === "bundled" && path.basename(plugin.rootDir) === dirName,
|
||||
) ?? null
|
||||
);
|
||||
}
|
||||
|
||||
function resolveBundledPluginPublicSurfaceAccess(params: {
|
||||
dirName: string;
|
||||
artifactBasename: string;
|
||||
}): { allowed: boolean; pluginId?: string; reason?: string } {
|
||||
if (
|
||||
params.artifactBasename === "runtime-api.js" &&
|
||||
ALWAYS_ALLOWED_RUNTIME_DIR_NAMES.has(params.dirName)
|
||||
) {
|
||||
return {
|
||||
allowed: true,
|
||||
pluginId: params.dirName,
|
||||
};
|
||||
}
|
||||
|
||||
const manifestRecord = resolveBundledPluginManifestRecordByDirName(params.dirName);
|
||||
if (!manifestRecord) {
|
||||
return {
|
||||
allowed: false,
|
||||
reason: `no bundled plugin manifest found for ${params.dirName}`,
|
||||
};
|
||||
}
|
||||
const { config, normalizedPluginsConfig } = getFacadeBoundaryResolvedConfig();
|
||||
const enableState = resolveEffectiveEnableState({
|
||||
id: manifestRecord.id,
|
||||
origin: manifestRecord.origin,
|
||||
config: normalizedPluginsConfig,
|
||||
rootConfig: config,
|
||||
enabledByDefault: manifestRecord.enabledByDefault,
|
||||
});
|
||||
if (enableState.enabled) {
|
||||
return {
|
||||
allowed: true,
|
||||
pluginId: manifestRecord.id,
|
||||
};
|
||||
}
|
||||
|
||||
return {
|
||||
allowed: false,
|
||||
pluginId: manifestRecord.id,
|
||||
reason: enableState.reason ?? "plugin runtime is not activated",
|
||||
};
|
||||
}
|
||||
|
||||
function createLazyFacadeValueLoader<T>(load: () => T): () => T {
|
||||
let loaded = false;
|
||||
let value: T;
|
||||
@@ -220,3 +322,35 @@ export function loadBundledPluginPublicSurfaceModuleSync<T extends object>(param
|
||||
|
||||
return sentinel;
|
||||
}
|
||||
|
||||
export function canLoadActivatedBundledPluginPublicSurface(params: {
|
||||
dirName: string;
|
||||
artifactBasename: string;
|
||||
}): boolean {
|
||||
return resolveBundledPluginPublicSurfaceAccess(params).allowed;
|
||||
}
|
||||
|
||||
export function loadActivatedBundledPluginPublicSurfaceModuleSync<T extends object>(params: {
|
||||
dirName: string;
|
||||
artifactBasename: string;
|
||||
}): T {
|
||||
const access = resolveBundledPluginPublicSurfaceAccess(params);
|
||||
if (!access.allowed) {
|
||||
const pluginLabel = access.pluginId ?? params.dirName;
|
||||
throw new Error(
|
||||
`Bundled plugin public surface access blocked for "${pluginLabel}" via ${params.dirName}/${params.artifactBasename}: ${access.reason ?? "plugin runtime is not activated"}`,
|
||||
);
|
||||
}
|
||||
return loadBundledPluginPublicSurfaceModuleSync<T>(params);
|
||||
}
|
||||
|
||||
export function tryLoadActivatedBundledPluginPublicSurfaceModuleSync<T extends object>(params: {
|
||||
dirName: string;
|
||||
artifactBasename: string;
|
||||
}): T | null {
|
||||
const access = resolveBundledPluginPublicSurfaceAccess(params);
|
||||
if (!access.allowed) {
|
||||
return null;
|
||||
}
|
||||
return loadBundledPluginPublicSurfaceModuleSync<T>(params);
|
||||
}
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["feishu-conversation"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
createLazyFacadeArrayValue,
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["image-generation-runtime"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "image-generation-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["kilocode"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
createLazyFacadeArrayValue,
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["line-runtime"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "line",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["matrix-runtime-surface"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "matrix",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["media-understanding-runtime"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "media-understanding-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ type FacadeEntry = PluginSdkFacadeTypeMap["memory-core-engine-runtime"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "memory-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["minimax"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
createLazyFacadeArrayValue,
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
|
||||
@@ -3,8 +3,8 @@ import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["modelstudio"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
createLazyFacadeArrayValue,
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
|
||||
@@ -2,10 +2,10 @@
|
||||
import type { PluginSdkFacadeTypeMap } from "../generated/plugin-sdk-facade-type-map.generated.js";
|
||||
type FacadeEntry = PluginSdkFacadeTypeMap["slack-runtime-surface"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import { loadBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
import { loadActivatedBundledPluginPublicSurfaceModuleSync } from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "slack",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
@@ -4,11 +4,11 @@ type FacadeEntry = PluginSdkFacadeTypeMap["speech-runtime"];
|
||||
type FacadeModule = FacadeEntry["module"];
|
||||
import {
|
||||
createLazyFacadeObjectValue,
|
||||
loadBundledPluginPublicSurfaceModuleSync,
|
||||
loadActivatedBundledPluginPublicSurfaceModuleSync,
|
||||
} from "./facade-runtime.js";
|
||||
|
||||
function loadFacadeModule(): FacadeModule {
|
||||
return loadBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
return loadActivatedBundledPluginPublicSurfaceModuleSync<FacadeModule>({
|
||||
dirName: "speech-core",
|
||||
artifactBasename: "runtime-api.js",
|
||||
});
|
||||
|
||||
Reference in New Issue
Block a user