Skip to content

Commit 6adfe48

Browse files
jonathanlabclaude
andauthored
fix: Bypass CORS for S3 log fetching in renderer (#204)
Co-authored-by: Claude <[email protected]>
1 parent 4e4eb4a commit 6adfe48

File tree

4 files changed

+19
-37
lines changed

4 files changed

+19
-37
lines changed

apps/array/src/main/preload.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,4 @@
11
import type { ContentBlock } from "@agentclientprotocol/sdk";
2-
import type { AgentEvent } from "@posthog/agent";
32
import { contextBridge, type IpcRendererEvent, ipcRenderer } from "electron";
43
import type {
54
CreateWorkspaceOptions,
@@ -69,7 +68,7 @@ contextBridge.exposeInMainWorld("electronAPI", {
6968
ipcRenderer.invoke("store-api-key", apiKey),
7069
retrieveApiKey: (encryptedKey: string): Promise<string | null> =>
7170
ipcRenderer.invoke("retrieve-api-key", encryptedKey),
72-
fetchS3Logs: (logUrl: string): Promise<AgentEvent[]> =>
71+
fetchS3Logs: (logUrl: string): Promise<string | null> =>
7372
ipcRenderer.invoke("fetch-s3-logs", logUrl),
7473
rendererStore: {
7574
getItem: (key: string): Promise<string | null> =>

apps/array/src/main/services/posthog.ts

Lines changed: 9 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
import { type AgentEvent, parseAgentEvents } from "@posthog/agent";
21
import { type IpcMainInvokeEvent, ipcMain, safeStorage } from "electron";
32
import { logger } from "../lib/logger";
43

@@ -35,50 +34,34 @@ export function registerPosthogIpc(): void {
3534
},
3635
);
3736

38-
// Fetch and parse S3 logs
3937
ipcMain.handle(
4038
"fetch-s3-logs",
4139
async (
4240
_event: IpcMainInvokeEvent,
4341
logUrl: string,
44-
): Promise<AgentEvent[]> => {
42+
): Promise<string | null> => {
4543
try {
4644
log.debug("Fetching S3 logs from:", logUrl);
4745
const response = await fetch(logUrl);
4846

4947
// 404 is expected for new task runs - file doesn't exist yet
5048
if (response.status === 404) {
51-
return [];
49+
return null;
5250
}
5351

5452
if (!response.ok) {
55-
throw new Error(
56-
`Failed to fetch logs: ${response.status} ${response.statusText}`,
53+
log.warn(
54+
"Failed to fetch S3 logs:",
55+
response.status,
56+
response.statusText,
5757
);
58+
return null;
5859
}
5960

60-
const content = await response.text();
61-
62-
if (!content.trim()) {
63-
return [];
64-
}
65-
66-
const rawEntries = content
67-
.trim()
68-
.split("\n")
69-
.map((line) => {
70-
try {
71-
return JSON.parse(line);
72-
} catch {
73-
return null;
74-
}
75-
})
76-
.filter(Boolean);
77-
78-
return parseAgentEvents(rawEntries);
61+
return await response.text();
7962
} catch (error) {
8063
log.error("Failed to fetch S3 logs:", error);
81-
throw error;
64+
return null;
8265
}
8366
},
8467
);

apps/array/src/renderer/features/sessions/utils/parseSessionLogs.ts

Lines changed: 8 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,4 @@
1+
/// <reference path="../../../types/electron.d.ts" />
12
import type { SessionNotification } from "@agentclientprotocol/sdk";
23

34
export interface StoredLogEntry {
@@ -26,14 +27,16 @@ export interface ParsedSessionLogs {
2627
export async function fetchSessionLogs(
2728
logUrl: string,
2829
): Promise<ParsedSessionLogs> {
29-
if (!logUrl) return { notifications: [], rawEntries: [] };
30+
if (!logUrl) {
31+
return { notifications: [], rawEntries: [] };
32+
}
3033

3134
try {
32-
const response = await fetch(logUrl);
33-
if (!response.ok) return { notifications: [], rawEntries: [] };
35+
const content = await window.electronAPI.fetchS3Logs(logUrl);
3436

35-
const content = await response.text();
36-
if (!content.trim()) return { notifications: [], rawEntries: [] };
37+
if (!content?.trim()) {
38+
return { notifications: [], rawEntries: [] };
39+
}
3740

3841
const notifications: SessionNotification[] = [];
3942
const rawEntries: StoredLogEntry[] = [];
@@ -47,7 +50,6 @@ export async function fetchSessionLogs(
4750
// - Request (has id + method) = client → agent
4851
// - Response (has id + result/error) = agent → client
4952
// - Notification (has method, no id) = agent → client
50-
// TODO: Check if this is correct.
5153
const msg = stored.notification;
5254
if (msg) {
5355
const hasId = msg.id !== undefined;
@@ -94,7 +96,6 @@ export async function fetchSessionLogs(
9496

9597
return { notifications, rawEntries, sdkSessionId };
9698
} catch {
97-
// Network error or other failure
9899
return { notifications: [], rawEntries: [] };
99100
}
100101
}

apps/array/src/renderer/types/electron.d.ts

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,6 @@ import type {
55
TabContextMenuResult,
66
TaskContextMenuResult,
77
} from "@main/services/contextMenu.types";
8-
import type { AgentEvent } from "@posthog/agent";
98
import type { ContentBlock } from "@agentclientprotocol/sdk";
109
import type {
1110
ChangedFile,
@@ -25,7 +24,7 @@ declare global {
2524
interface IElectronAPI {
2625
storeApiKey: (apiKey: string) => Promise<string>;
2726
retrieveApiKey: (encryptedKey: string) => Promise<string | null>;
28-
fetchS3Logs: (logUrl: string) => Promise<AgentEvent[]>;
27+
fetchS3Logs: (logUrl: string) => Promise<string | null>;
2928
rendererStore: {
3029
getItem: (key: string) => Promise<string | null>;
3130
setItem: (key: string, value: string) => Promise<void>;

0 commit comments

Comments
 (0)