mirror of https://github.com/openclaw/openclaw.git
fix(plugins): preserve lazy runtime reflection semantics
This commit is contained in:
parent
081d4fbe02
commit
8bd7d6c13b
|
|
@ -14,6 +14,7 @@ Docs: https://docs.openclaw.ai
|
|||
### Fixes
|
||||
|
||||
- Gateway/security default response headers: add `Permissions-Policy: camera=(), microphone=(), geolocation=()` to baseline gateway HTTP security headers for all responses. (#30186) thanks @habakan.
|
||||
- Plugins/startup loading: lazily initialize plugin runtime, split startup-critical plugin SDK imports into `openclaw/plugin-sdk/core` and `openclaw/plugin-sdk/telegram`, and preserve `api.runtime` reflection semantics for plugin compatibility. (#28620) thanks @hmemcpy.
|
||||
- Security/auth labels: remove token and API-key snippets from user-facing auth status labels so `/status` and `/models` do not expose credential fragments. (#33262) thanks @cu1ch3n.
|
||||
- Security/audit denyCommands guidance: suggest likely exact node command IDs for unknown `gateway.nodes.denyCommands` entries so ineffective denylist entries are easier to correct. (#29713) thanks @liquidhorizon88-bot.
|
||||
- Docs/security hardening guidance: document Docker `DOCKER-USER` + UFW policy and add cross-linking from Docker install docs for VPS/public-host setups. (#27613) thanks @dorukardahan.
|
||||
|
|
|
|||
|
|
@ -974,6 +974,37 @@ describe("loadOpenClawPlugins", () => {
|
|||
);
|
||||
});
|
||||
|
||||
it("preserves runtime reflection semantics when runtime is lazily initialized", () => {
|
||||
useNoBundledPlugins();
|
||||
const plugin = writePlugin({
|
||||
id: "runtime-introspection",
|
||||
filename: "runtime-introspection.cjs",
|
||||
body: `module.exports = { id: "runtime-introspection", register(api) {
|
||||
const runtime = api.runtime ?? {};
|
||||
const keys = Object.keys(runtime);
|
||||
if (!keys.includes("channel")) {
|
||||
throw new Error("runtime channel key missing");
|
||||
}
|
||||
if (!("channel" in runtime)) {
|
||||
throw new Error("runtime channel missing from has check");
|
||||
}
|
||||
if (!Object.getOwnPropertyDescriptor(runtime, "channel")) {
|
||||
throw new Error("runtime channel descriptor missing");
|
||||
}
|
||||
} };`,
|
||||
});
|
||||
|
||||
const registry = loadRegistryFromSinglePlugin({
|
||||
plugin,
|
||||
pluginConfig: {
|
||||
allow: ["runtime-introspection"],
|
||||
},
|
||||
});
|
||||
|
||||
const record = registry.plugins.find((entry) => entry.id === "runtime-introspection");
|
||||
expect(record?.status).toBe("loaded");
|
||||
});
|
||||
|
||||
it("prefers dist plugin-sdk alias when loader runs from dist", () => {
|
||||
const { root, distFile } = createPluginSdkAliasFixture();
|
||||
|
||||
|
|
|
|||
|
|
@ -405,10 +405,34 @@ export function loadOpenClawPlugins(options: PluginLoadOptions = {}): PluginRegi
|
|||
// Lazily initialize the runtime so startup paths that discover/skip plugins do
|
||||
// not eagerly load every channel runtime dependency.
|
||||
let resolvedRuntime: PluginRuntime | null = null;
|
||||
const resolveRuntime = (): PluginRuntime => {
|
||||
resolvedRuntime ??= createPluginRuntime();
|
||||
return resolvedRuntime;
|
||||
};
|
||||
const runtime = new Proxy({} as PluginRuntime, {
|
||||
get(_target, prop, receiver) {
|
||||
resolvedRuntime ??= createPluginRuntime();
|
||||
return Reflect.get(resolvedRuntime, prop, receiver);
|
||||
return Reflect.get(resolveRuntime(), prop, receiver);
|
||||
},
|
||||
set(_target, prop, value, receiver) {
|
||||
return Reflect.set(resolveRuntime(), prop, value, receiver);
|
||||
},
|
||||
has(_target, prop) {
|
||||
return Reflect.has(resolveRuntime(), prop);
|
||||
},
|
||||
ownKeys() {
|
||||
return Reflect.ownKeys(resolveRuntime() as object);
|
||||
},
|
||||
getOwnPropertyDescriptor(_target, prop) {
|
||||
return Reflect.getOwnPropertyDescriptor(resolveRuntime() as object, prop);
|
||||
},
|
||||
defineProperty(_target, prop, attributes) {
|
||||
return Reflect.defineProperty(resolveRuntime() as object, prop, attributes);
|
||||
},
|
||||
deleteProperty(_target, prop) {
|
||||
return Reflect.deleteProperty(resolveRuntime() as object, prop);
|
||||
},
|
||||
getPrototypeOf() {
|
||||
return Reflect.getPrototypeOf(resolveRuntime() as object);
|
||||
},
|
||||
});
|
||||
const { registry, createApi } = createPluginRegistry({
|
||||
|
|
|
|||
Loading…
Reference in New Issue