diff --git a/extensions/tlon/src/tlon-api.test.ts b/extensions/tlon/src/tlon-api.test.ts index cab646d6e985..1ef36f978aa9 100644 --- a/extensions/tlon/src/tlon-api.test.ts +++ b/extensions/tlon/src/tlon-api.test.ts @@ -139,6 +139,7 @@ describe("uploadFile memex upload hardening", () => { expect(firstCall?.auditContext).toBe("tlon-memex-upload-url"); expect(firstCall?.capture).toBe(false); expect(firstCall?.maxRedirects).toBe(0); + expect(firstCall?.timeoutMs).toBe(30_000); const firstBodyRaw = firstCall?.init?.body; expect(typeof firstBodyRaw).toBe("string"); const firstBody = JSON.parse(firstBodyRaw as string) as Record; @@ -156,6 +157,7 @@ describe("uploadFile memex upload hardening", () => { expect(secondCall?.auditContext).toBe("tlon-memex-upload"); expect(secondCall?.capture).toBe(false); expect(secondCall?.maxRedirects).toBe(0); + expect(secondCall?.timeoutMs).toBe(300_000); expect(secondCall?.init?.body).toBeInstanceOf(Blob); expect(mockRelease).toHaveBeenCalledTimes(2); }); @@ -509,6 +511,7 @@ describe("uploadFile custom S3 upload hardening", () => { expect(uploadCall?.auditContext).toBe("tlon-custom-s3-upload"); expect(uploadCall?.capture).toBe(false); expect(uploadCall?.maxRedirects).toBe(0); + expect(uploadCall?.timeoutMs).toBe(300_000); expect(uploadCall?.policy).toBeUndefined(); expect(mockRelease).toHaveBeenCalledTimes(1); expect(vi.mocked(globalThis.fetch)).not.toHaveBeenCalled(); diff --git a/extensions/tlon/src/tlon-api.ts b/extensions/tlon/src/tlon-api.ts index 798c1fe06955..f97b761cf450 100644 --- a/extensions/tlon/src/tlon-api.ts +++ b/extensions/tlon/src/tlon-api.ts @@ -50,6 +50,12 @@ const MEMEX_BASE_URL = "https://memex.tlon.network"; /** Max bytes to read from the Memex upload JSON response. */ const MEMEX_UPLOAD_RESPONSE_MAX_BYTES = 64 * 1024; +/** Total deadline for the Memex upload URL lookup, including DNS and response reading. */ +const TLON_MEMEX_UPLOAD_URL_TIMEOUT_MS = 30_000; + +/** Total deadline for Memex and custom S3 PUTs, including DNS and the full upload. */ +const TLON_UPLOAD_TIMEOUT_MS = 300_000; + let currentClientConfig: ClientConfig | null = null; export function configureClient(params: ClientConfig): void { @@ -251,6 +257,7 @@ async function getMemexUploadUrl(params: { auditContext: "tlon-memex-upload-url", capture: false, maxRedirects: 0, + timeoutMs: TLON_MEMEX_UPLOAD_URL_TIMEOUT_MS, }); release = guarded.release; if (!guarded.response.ok) { @@ -318,6 +325,7 @@ export async function uploadFile(params: UploadFileParams): Promise