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:
Vincent Koc
2026-04-02 14:37:12 +09:00
committed by GitHub
parent ed6012eb5b
commit 52a018680d
27 changed files with 509 additions and 57 deletions

View 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");
});
});

View 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"];

View File

@@ -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,

View File

@@ -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",
});

View 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"];

View File

@@ -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",
});

View File

@@ -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"];

View File

@@ -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);
});
});

View File

@@ -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);
}

View File

@@ -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";

View File

@@ -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",
});

View File

@@ -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";

View File

@@ -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",
});

View File

@@ -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",
});

View File

@@ -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",
});

View File

@@ -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",
});

View File

@@ -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";

View File

@@ -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";

View File

@@ -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",
});

View File

@@ -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",
});