Fix SSE stream URL consistency, multi-line data parsing, and test mocks
- Use workerBaseUrl() for SSE stream URL instead of hardcoded localhost - Concatenate all SSE data: lines per frame per SSE spec - Update WhatsApp mock to accept third options argument - Restrict SSE mock server to only respond on /stream path Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
@@ -8,7 +8,7 @@ import claudeMemPlugin from "./index.js";
|
|||||||
|
|
||||||
function createMockApi(pluginConfigOverride: Record<string, any> = {}) {
|
function createMockApi(pluginConfigOverride: Record<string, any> = {}) {
|
||||||
const logs: string[] = [];
|
const logs: string[] = [];
|
||||||
const sentMessages: Array<{ to: string; text: string; channel: string }> = [];
|
const sentMessages: Array<{ to: string; text: string; channel: string; opts?: any }> = [];
|
||||||
|
|
||||||
let registeredService: any = null;
|
let registeredService: any = null;
|
||||||
const registeredCommands: Map<string, any> = new Map();
|
const registeredCommands: Map<string, any> = new Map();
|
||||||
@@ -62,8 +62,8 @@ function createMockApi(pluginConfigOverride: Record<string, any> = {}) {
|
|||||||
},
|
},
|
||||||
},
|
},
|
||||||
whatsapp: {
|
whatsapp: {
|
||||||
sendMessageWhatsApp: async (to: string, text: string) => {
|
sendMessageWhatsApp: async (to: string, text: string, opts?: { verbose: boolean }) => {
|
||||||
sentMessages.push({ to, text, channel: "whatsapp" });
|
sentMessages.push({ to, text, channel: "whatsapp", opts });
|
||||||
},
|
},
|
||||||
},
|
},
|
||||||
line: {
|
line: {
|
||||||
@@ -761,6 +761,11 @@ describe("SSE stream integration", () => {
|
|||||||
function startSSEServer(): Promise<number> {
|
function startSSEServer(): Promise<number> {
|
||||||
return new Promise((resolve) => {
|
return new Promise((resolve) => {
|
||||||
server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
server = createServer((req: IncomingMessage, res: ServerResponse) => {
|
||||||
|
if (req.url !== "/stream") {
|
||||||
|
res.writeHead(404);
|
||||||
|
res.end();
|
||||||
|
return;
|
||||||
|
}
|
||||||
res.writeHead(200, {
|
res.writeHead(200, {
|
||||||
"Content-Type": "text/event-stream",
|
"Content-Type": "text/event-stream",
|
||||||
"Cache-Control": "no-cache",
|
"Cache-Control": "no-cache",
|
||||||
@@ -923,7 +928,7 @@ describe("SSE stream integration", () => {
|
|||||||
await getService().start({});
|
await getService().start({});
|
||||||
await new Promise((resolve) => setTimeout(resolve, 200));
|
await new Promise((resolve) => setTimeout(resolve, 200));
|
||||||
|
|
||||||
assert.ok(logs.some((l) => l.includes(`localhost:${serverPort}`)));
|
assert.ok(logs.some((l) => l.includes(`127.0.0.1:${serverPort}`)));
|
||||||
|
|
||||||
await getService().stop({});
|
await getService().stop({});
|
||||||
});
|
});
|
||||||
|
|||||||
@@ -301,9 +301,9 @@ async function connectToSSEStream(
|
|||||||
while (!abortController.signal.aborted) {
|
while (!abortController.signal.aborted) {
|
||||||
try {
|
try {
|
||||||
setConnectionState("reconnecting");
|
setConnectionState("reconnecting");
|
||||||
api.logger.info(`[claude-mem] Connecting to SSE stream at http://localhost:${port}/stream`);
|
api.logger.info(`[claude-mem] Connecting to SSE stream at ${workerBaseUrl(port)}/stream`);
|
||||||
|
|
||||||
const response = await fetch(`http://localhost:${port}/stream`, {
|
const response = await fetch(`${workerBaseUrl(port)}/stream`, {
|
||||||
signal: abortController.signal,
|
signal: abortController.signal,
|
||||||
headers: { Accept: "text/event-stream" },
|
headers: { Accept: "text/event-stream" },
|
||||||
});
|
});
|
||||||
@@ -339,12 +339,14 @@ async function connectToSSEStream(
|
|||||||
buffer = frames.pop() || "";
|
buffer = frames.pop() || "";
|
||||||
|
|
||||||
for (const frame of frames) {
|
for (const frame of frames) {
|
||||||
const dataLine = frame
|
// SSE spec: concatenate all data: lines with \n
|
||||||
|
const dataLines = frame
|
||||||
.split("\n")
|
.split("\n")
|
||||||
.find((line) => line.startsWith("data:"));
|
.filter((line) => line.startsWith("data:"))
|
||||||
if (!dataLine) continue;
|
.map((line) => line.slice(5).trim());
|
||||||
|
if (dataLines.length === 0) continue;
|
||||||
|
|
||||||
const jsonStr = dataLine.slice(5).trim();
|
const jsonStr = dataLines.join("\n");
|
||||||
if (!jsonStr) continue;
|
if (!jsonStr) continue;
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
|||||||
Reference in New Issue
Block a user