Skip to content

Commit ad664a3

Browse files
committed
feat: add electron onboarding modes
1 parent 14c6374 commit ad664a3

12 files changed

Lines changed: 979 additions & 230 deletions

File tree

client/src/hooks/use-import-stream.ts

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,7 @@ export function useImportStream() {
4646
}
4747

4848
fetch(`${API_BASE}/api/import/scan/stream`, {
49+
method: 'POST',
4950
headers,
5051
})
5152
.then(async (res) => {

electron/ipc.ts

Lines changed: 95 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,95 @@
1+
import { ipcMain, type IpcMainInvokeEvent } from "electron";
2+
3+
export type IpcDeps = {
4+
getOnboardingOrigin: () => string;
5+
getOnboardingUrl: () => string;
6+
getState(): Promise<unknown> | unknown;
7+
saveCloudConnection(input: { baseUrl: string; token: string }): Promise<unknown>;
8+
startLocal(): Promise<unknown>;
9+
importLocalHistory(): Promise<unknown>;
10+
uploadLocalHistory(): Promise<unknown>;
11+
testModel(mode: "local" | "cloud"): Promise<unknown>;
12+
summarizeBatch(input: { mode: "local" | "cloud"; conversationIds: string[] }): Promise<unknown>;
13+
getMcpSnippet(mode: "local" | "cloud"): Promise<unknown>;
14+
openApp(mode: "local" | "cloud"): Promise<unknown>;
15+
useTemporaryLocal(): Promise<unknown>;
16+
};
17+
18+
function assertOnboardingSender(
19+
event: IpcMainInvokeEvent,
20+
expectedOrigin: string,
21+
expectedUrl: string,
22+
): void {
23+
if (
24+
!event.senderFrame ||
25+
event.senderFrame.origin !== expectedOrigin ||
26+
event.senderFrame.url !== expectedUrl
27+
) {
28+
throw new Error("Rejected onboarding IPC from unexpected origin");
29+
}
30+
}
31+
32+
function assertMode(value: unknown): asserts value is "local" | "cloud" {
33+
if (value !== "local" && value !== "cloud") {
34+
throw new Error("Invalid onboarding mode");
35+
}
36+
}
37+
38+
function assertConversationIds(value: unknown): string[] {
39+
if (!Array.isArray(value)) return [];
40+
return value.filter((id): id is string => typeof id === "string" && id.trim().length > 0);
41+
}
42+
43+
export function registerOnboardingIpc(deps: IpcDeps): void {
44+
const guard = (event: IpcMainInvokeEvent) =>
45+
assertOnboardingSender(event, deps.getOnboardingOrigin(), deps.getOnboardingUrl());
46+
47+
ipcMain.handle("onboarding:get-state", (event) => {
48+
guard(event);
49+
return deps.getState();
50+
});
51+
ipcMain.handle("onboarding:save-cloud-connection", (event, input) => {
52+
guard(event);
53+
return deps.saveCloudConnection(input);
54+
});
55+
ipcMain.handle("onboarding:start-local", (event) => {
56+
guard(event);
57+
return deps.startLocal();
58+
});
59+
ipcMain.handle("onboarding:import-local-history", (event) => {
60+
guard(event);
61+
return deps.importLocalHistory();
62+
});
63+
ipcMain.handle("onboarding:upload-local-history", (event) => {
64+
guard(event);
65+
return deps.uploadLocalHistory();
66+
});
67+
ipcMain.handle("onboarding:test-model", (event, mode) => {
68+
guard(event);
69+
assertMode(mode);
70+
return deps.testModel(mode);
71+
});
72+
ipcMain.handle("onboarding:summarize-batch", (event, input) => {
73+
guard(event);
74+
const payload = input as { mode?: unknown; conversationIds?: unknown };
75+
assertMode(payload?.mode);
76+
return deps.summarizeBatch({
77+
mode: payload.mode,
78+
conversationIds: assertConversationIds(payload.conversationIds),
79+
});
80+
});
81+
ipcMain.handle("onboarding:get-mcp-snippet", (event, mode) => {
82+
guard(event);
83+
assertMode(mode);
84+
return deps.getMcpSnippet(mode);
85+
});
86+
ipcMain.handle("onboarding:open-app", (event, mode) => {
87+
guard(event);
88+
assertMode(mode);
89+
return deps.openApp(mode);
90+
});
91+
ipcMain.handle("onboarding:use-temporary-local", (event) => {
92+
guard(event);
93+
return deps.useTemporaryLocal();
94+
});
95+
}

0 commit comments

Comments
 (0)