mirror of
https://github.com/openclaw/openclaw.git
synced 2026-04-09 16:21:15 +00:00
fix(msteams): replace deprecated HttpPlugin with httpServerAdapter
Migrate from the deprecated `plugins: [noOpHttpPlugin]` pattern to the SDK's public `httpServerAdapter` option. This eliminates the "[DEPRECATED] HttpPlugin in plugins array" warning that fires every ~60 seconds in the gateway error log. The old NoOpHttpPlugin was a ~40-line class that used fragile reflect-metadata hacks against internal SDK decorator paths. The replacement is a simple 3-line IHttpServerAdapter stub with an empty registerRoute() — the only method the interface requires. Fixes: https://github.com/openclaw/openclaw/issues/60732 See also: https://github.com/openclaw/openclaw/issues/55161 Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -81,9 +81,8 @@ function createSdkStub(): MSTeamsTeamsSdk {
|
||||
describe("createMSTeamsApp", () => {
|
||||
it("does not crash with express 5 path-to-regexp (#55161)", async () => {
|
||||
// Regression test for: https://github.com/openclaw/openclaw/issues/55161
|
||||
// The default HttpPlugin in @microsoft/teams.apps uses `express().use('/api*', ...)`
|
||||
// which throws in express 5 (path-to-regexp v8+). createMSTeamsApp injects a no-op
|
||||
// HTTP plugin stub to prevent the SDK from creating the default HttpPlugin.
|
||||
// createMSTeamsApp passes a no-op httpServerAdapter to prevent the SDK from
|
||||
// creating its default HttpPlugin (which registers `/api*` — invalid in Express 5).
|
||||
const { App } = await import("@microsoft/teams.apps");
|
||||
const { Client } = await import("@microsoft/teams.api");
|
||||
const sdk: MSTeamsTeamsSdk = { App, Client };
|
||||
|
||||
@@ -1,3 +1,4 @@
|
||||
import type { IHttpServerAdapter } from "@microsoft/teams.apps/dist/http/index.js";
|
||||
import { formatUnknownError } from "./errors.js";
|
||||
import type { MSTeamsAdapter } from "./messenger.js";
|
||||
import type { MSTeamsCredentials } from "./token.js";
|
||||
@@ -55,65 +56,22 @@ export async function loadMSTeamsSdk(): Promise<MSTeamsTeamsSdk> {
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a lightweight no-op HTTP plugin stub that satisfies the Teams SDK's
|
||||
* plugin discovery by name ("http") but does NOT spin up an Express server.
|
||||
*
|
||||
* The default HttpPlugin in @microsoft/teams.apps registers an Express
|
||||
* middleware with the pattern `/api*`. When the host application (OpenClaw)
|
||||
* uses Express 5 — which depends on path-to-regexp v8 — that pattern is
|
||||
* invalid and throws:
|
||||
*
|
||||
* Missing parameter name at index 5: /api*
|
||||
* Create a no-op HTTP server adapter that satisfies the Teams SDK's
|
||||
* IHttpServerAdapter interface without spinning up an Express server.
|
||||
*
|
||||
* OpenClaw manages its own Express server for the Teams webhook endpoint, so
|
||||
* the SDK's built-in HTTP server is unnecessary. Passing this stub prevents
|
||||
* the SDK from creating the default HttpPlugin and avoids the crash.
|
||||
* the SDK's built-in HTTP server is unnecessary. Passing this adapter via the
|
||||
* `httpServerAdapter` option prevents the SDK from creating the default
|
||||
* HttpPlugin (which uses the deprecated `plugins` array and registers an
|
||||
* Express middleware with the pattern `/api*` — invalid in Express 5).
|
||||
*
|
||||
* See: https://github.com/openclaw/openclaw/issues/55161
|
||||
* See: https://github.com/openclaw/openclaw/issues/60732
|
||||
*/
|
||||
async function createNoOpHttpPlugin(): Promise<unknown> {
|
||||
// Lazy-import reflect-metadata (required by the Teams SDK decorator system)
|
||||
// and the decorator key constants so we can tag the stub class correctly.
|
||||
//
|
||||
// FRAGILE: these are internal SDK paths (not public API). If
|
||||
// @microsoft/teams.apps changes its dist layout, these imports will break.
|
||||
// Pin the SDK version and re-verify after any upgrade.
|
||||
await import("reflect-metadata");
|
||||
const { PLUGIN_METADATA_KEY } =
|
||||
await import("@microsoft/teams.apps/dist/types/plugin/decorators/plugin.js");
|
||||
const { PLUGIN_DEPENDENCIES_METADATA_KEY } =
|
||||
await import("@microsoft/teams.apps/dist/types/plugin/decorators/dependency.js");
|
||||
const { PLUGIN_EVENTS_METADATA_KEY } =
|
||||
await import("@microsoft/teams.apps/dist/types/plugin/decorators/event.js");
|
||||
|
||||
class NoOpHttpPlugin {
|
||||
onInit() {}
|
||||
async onStart() {}
|
||||
onStop() {}
|
||||
asServer() {
|
||||
return {
|
||||
onRequest: undefined as unknown,
|
||||
initialize: async () => {},
|
||||
start: async () => {},
|
||||
stop: async () => {},
|
||||
} as {
|
||||
onRequest: unknown;
|
||||
initialize: (opts?: unknown) => Promise<void>;
|
||||
start: (port?: number | string) => Promise<void>;
|
||||
stop: () => Promise<void>;
|
||||
};
|
||||
}
|
||||
}
|
||||
|
||||
Reflect.defineMetadata(
|
||||
PLUGIN_METADATA_KEY,
|
||||
{ name: "http", version: "0.0.0", description: "no-op stub (express 5 compat)" },
|
||||
NoOpHttpPlugin,
|
||||
);
|
||||
Reflect.defineMetadata(PLUGIN_DEPENDENCIES_METADATA_KEY, [], NoOpHttpPlugin);
|
||||
Reflect.defineMetadata(PLUGIN_EVENTS_METADATA_KEY, [], NoOpHttpPlugin);
|
||||
|
||||
return new NoOpHttpPlugin();
|
||||
function createNoOpHttpServerAdapter(): IHttpServerAdapter {
|
||||
return {
|
||||
registerRoute() {},
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
@@ -127,15 +85,11 @@ export async function createMSTeamsApp(
|
||||
creds: MSTeamsCredentials,
|
||||
sdk: MSTeamsTeamsSdk,
|
||||
): Promise<MSTeamsApp> {
|
||||
const noOpHttp = await createNoOpHttpPlugin();
|
||||
// Use type assertion: the SDK's AppOptions generic narrows `plugins` to
|
||||
// Array<TPlugin>, but our no-op stub satisfies the runtime contract without
|
||||
// matching the decorator-heavy IPlugin type at compile time.
|
||||
return new sdk.App({
|
||||
clientId: creds.appId,
|
||||
clientSecret: creds.appPassword,
|
||||
tenantId: creds.tenantId,
|
||||
plugins: [noOpHttp],
|
||||
httpServerAdapter: createNoOpHttpServerAdapter(),
|
||||
} as ConstructorParameters<MSTeamsTeamsSdk["App"]>[0]);
|
||||
}
|
||||
|
||||
|
||||
Reference in New Issue
Block a user