test(media): add redirect coverage and update changelog
This commit is contained in:
@@ -11,6 +11,11 @@
|
||||
### Performance
|
||||
- Web auto-replies using the Pi agent now keep a single long-lived `tau` process in RPC mode instead of spawning per message, eliminating cold-start latency while preserving session/cwd handling.
|
||||
|
||||
### Bug Fixes
|
||||
- Media downloads now follow up to 5 redirects and still derive MIME/extension from sniffed content or headers; added regression test for redirected downloads.
|
||||
- Hosted media responses set `Content-Type` from sniffed MIME (not the file name) and still clean up single-use files after send.
|
||||
- Claude system prompt is guaranteed to be included on the first session turn even when `sendSystemOnce` is enabled, while later turns stay system-free.
|
||||
|
||||
## 1.3.0 — 2025-12-02
|
||||
|
||||
### Highlights
|
||||
|
||||
73
src/media/store.redirect.test.ts
Normal file
73
src/media/store.redirect.test.ts
Normal file
@@ -0,0 +1,73 @@
|
||||
import fs from "node:fs/promises";
|
||||
import path from "node:path";
|
||||
import { PassThrough } from "node:stream";
|
||||
|
||||
import { afterAll, beforeAll, describe, expect, it, vi } from "vitest";
|
||||
|
||||
const realOs = await vi.importActual<typeof import("node:os")>("node:os");
|
||||
const HOME = path.join(realOs.tmpdir(), "warelay-home-redirect");
|
||||
const mockRequest = vi.fn();
|
||||
|
||||
vi.doMock("node:os", () => ({
|
||||
default: { homedir: () => HOME },
|
||||
homedir: () => HOME,
|
||||
}));
|
||||
|
||||
vi.doMock("node:https", () => ({
|
||||
request: (...args: unknown[]) => mockRequest(...args),
|
||||
}));
|
||||
|
||||
const { saveMediaSource } = await import("./store.js");
|
||||
|
||||
describe("media store redirects", () => {
|
||||
beforeAll(async () => {
|
||||
await fs.rm(HOME, { recursive: true, force: true });
|
||||
});
|
||||
|
||||
afterAll(async () => {
|
||||
await fs.rm(HOME, { recursive: true, force: true });
|
||||
vi.clearAllMocks();
|
||||
});
|
||||
|
||||
it("follows redirects and keeps detected mime/extension", async () => {
|
||||
let call = 0;
|
||||
mockRequest.mockImplementation((url, _opts, cb) => {
|
||||
call += 1;
|
||||
const res = new PassThrough();
|
||||
const req = {
|
||||
on: (event: string, handler: (...args: unknown[]) => void) => {
|
||||
if (event === "error") res.on("error", handler);
|
||||
return req;
|
||||
},
|
||||
end: () => undefined,
|
||||
destroy: () => res.destroy(),
|
||||
} as const;
|
||||
|
||||
if (call === 1) {
|
||||
res.statusCode = 302;
|
||||
res.headers = { location: "https://example.com/final" };
|
||||
setImmediate(() => {
|
||||
cb(res as unknown as Parameters<typeof cb>[0]);
|
||||
res.end();
|
||||
});
|
||||
} else {
|
||||
res.statusCode = 200;
|
||||
res.headers = { "content-type": "text/plain" };
|
||||
setImmediate(() => {
|
||||
cb(res as unknown as Parameters<typeof cb>[0]);
|
||||
res.write("redirected");
|
||||
res.end();
|
||||
});
|
||||
}
|
||||
|
||||
return req;
|
||||
});
|
||||
|
||||
const saved = await saveMediaSource("https://example.com/start");
|
||||
|
||||
expect(mockRequest).toHaveBeenCalledTimes(2);
|
||||
expect(saved.contentType).toBe("text/plain");
|
||||
expect(path.extname(saved.path)).toBe(".txt");
|
||||
expect(await fs.readFile(saved.path, "utf8")).toBe("redirected");
|
||||
});
|
||||
});
|
||||
Reference in New Issue
Block a user