mirror of
https://github.com/openclaw/openclaw.git
synced 2026-05-06 15:40:44 +00:00
fix(infra): share diagnostic event state across loaders
This commit is contained in:
@@ -147,7 +147,24 @@ describe("diagnostic-events", () => {
|
||||
]);
|
||||
});
|
||||
|
||||
it("does not expose mutable diagnostic state on a global symbol", async () => {
|
||||
it("shares diagnostic state across duplicate module instances", async () => {
|
||||
const events: string[] = [];
|
||||
onDiagnosticEvent((event) => {
|
||||
events.push(event.type);
|
||||
});
|
||||
|
||||
vi.resetModules();
|
||||
const specifier = "./diagnostic-events.js";
|
||||
const duplicateModule = (await import(specifier)) as typeof import("./diagnostic-events.js");
|
||||
duplicateModule.emitDiagnosticEvent({
|
||||
type: "message.queued",
|
||||
source: "plugin",
|
||||
});
|
||||
|
||||
expect(events).toEqual(["message.queued"]);
|
||||
});
|
||||
|
||||
it("does not expose mutable diagnostic state on the obsolete global symbol", async () => {
|
||||
const globalStore = globalThis as Record<PropertyKey, unknown>;
|
||||
const events: boolean[] = [];
|
||||
globalStore[Symbol.for("openclaw.diagnosticEventsState")] = {
|
||||
|
||||
@@ -404,14 +404,49 @@ const ASYNC_DIAGNOSTIC_EVENT_TYPES = new Set<DiagnosticEventPayload["type"]>([
|
||||
"log.record",
|
||||
]);
|
||||
|
||||
const diagnosticEventsState: DiagnosticEventsGlobalState = {
|
||||
enabled: true,
|
||||
seq: 0,
|
||||
listeners: new Set<DiagnosticEventListener>(),
|
||||
dispatchDepth: 0,
|
||||
asyncQueue: [],
|
||||
asyncDrainScheduled: false,
|
||||
};
|
||||
const DIAGNOSTIC_EVENTS_STATE_KEY = Symbol.for("openclaw.diagnosticEvents.state.v1");
|
||||
|
||||
function createDiagnosticEventsState(): DiagnosticEventsGlobalState {
|
||||
return {
|
||||
enabled: true,
|
||||
seq: 0,
|
||||
listeners: new Set<DiagnosticEventListener>(),
|
||||
dispatchDepth: 0,
|
||||
asyncQueue: [],
|
||||
asyncDrainScheduled: false,
|
||||
};
|
||||
}
|
||||
|
||||
function isDiagnosticEventsState(value: unknown): value is DiagnosticEventsGlobalState {
|
||||
if (!value || typeof value !== "object") {
|
||||
return false;
|
||||
}
|
||||
const candidate = value as Partial<DiagnosticEventsGlobalState>;
|
||||
return (
|
||||
typeof candidate.enabled === "boolean" &&
|
||||
typeof candidate.seq === "number" &&
|
||||
candidate.listeners instanceof Set &&
|
||||
typeof candidate.dispatchDepth === "number" &&
|
||||
Array.isArray(candidate.asyncQueue) &&
|
||||
typeof candidate.asyncDrainScheduled === "boolean"
|
||||
);
|
||||
}
|
||||
|
||||
const diagnosticEventsState: DiagnosticEventsGlobalState = (() => {
|
||||
const globalStore = globalThis as Record<PropertyKey, unknown>;
|
||||
const existing = globalStore[DIAGNOSTIC_EVENTS_STATE_KEY];
|
||||
if (isDiagnosticEventsState(existing)) {
|
||||
return existing;
|
||||
}
|
||||
const created = createDiagnosticEventsState();
|
||||
Object.defineProperty(globalStore, DIAGNOSTIC_EVENTS_STATE_KEY, {
|
||||
configurable: true,
|
||||
enumerable: false,
|
||||
value: created,
|
||||
writable: false,
|
||||
});
|
||||
return created;
|
||||
})();
|
||||
|
||||
function getDiagnosticEventsState(): DiagnosticEventsGlobalState {
|
||||
return diagnosticEventsState;
|
||||
|
||||
Reference in New Issue
Block a user