Skip to content

Commit 4ff59b4

Browse files
committed
add more apis
1 parent a97ff4a commit 4ff59b4

File tree

5 files changed

+312
-10
lines changed

5 files changed

+312
-10
lines changed

apps/array/package.json

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -94,6 +94,7 @@
9494
"@codemirror/view": "^6.38.8",
9595
"@dnd-kit/react": "^0.1.21",
9696
"@floating-ui/dom": "^1.7.4",
97+
"@octokit/rest": "^22.0.1",
9798
"@parcel/watcher": "^2.5.1",
9899
"@phosphor-icons/react": "^2.1.10",
99100
"@posthog/agent": "workspace:*",
@@ -122,12 +123,12 @@
122123
"cmdk": "^1.1.1",
123124
"date-fns": "^3.3.1",
124125
"detect-libc": "^1.0.3",
125-
"is-glob": "^4.0.3",
126-
"micromatch": "^4.0.5",
127126
"electron-log": "^5.4.3",
128127
"electron-store": "^11.0.0",
129128
"file-icon": "^6.0.0",
130129
"idb-keyval": "^6.2.2",
130+
"is-glob": "^4.0.3",
131+
"micromatch": "^4.0.5",
131132
"node-addon-api": "^8.5.0",
132133
"node-machine-id": "^1.1.12",
133134
"node-pty": "1.1.0-beta39",

apps/array/src/api/githubClient.ts

Lines changed: 51 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,51 @@
1+
import { Octokit } from "@octokit/rest";
2+
3+
export class GitHubAPIClient {
4+
private octokit: Octokit;
5+
private owner: string;
6+
private repo: string;
7+
8+
constructor(accessToken: string, owner: string, repo: string) {
9+
this.octokit = new Octokit({
10+
auth: accessToken,
11+
});
12+
this.owner = owner;
13+
this.repo = repo;
14+
}
15+
16+
async createComment(issueNumber: number, body: string) {
17+
try {
18+
const response = await this.octokit.rest.issues.createComment({
19+
owner: this.owner,
20+
repo: this.repo,
21+
issue_number: issueNumber,
22+
body,
23+
});
24+
return response.data;
25+
} catch (error) {
26+
throw new Error(`Failed to create comment: ${error}`);
27+
}
28+
}
29+
30+
async getCurrentUser() {
31+
try {
32+
const response = await this.octokit.rest.users.getAuthenticated();
33+
return response.data;
34+
} catch (error) {
35+
throw new Error(`Failed to get current user: ${error}`);
36+
}
37+
}
38+
39+
async getPullRequest(pullNumber: number) {
40+
try {
41+
const response = await this.octokit.rest.pulls.get({
42+
owner: this.owner,
43+
repo: this.repo,
44+
pull_number: pullNumber,
45+
});
46+
return response.data;
47+
} catch (error) {
48+
throw new Error(`Failed to get pull request: ${error}`);
49+
}
50+
}
51+
}

apps/array/src/api/posthogClient.ts

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -370,4 +370,25 @@ export class PostHogAPIClient {
370370
});
371371
return data.results ?? [];
372372
}
373+
374+
async getGitHubAccessToken(
375+
integrationId: string | number,
376+
): Promise<string | null> {
377+
const teamId = await this.getTeamId();
378+
const url = new URL(
379+
`${this.api.baseUrl}/api/environments/${teamId}/integrations/${integrationId}/`,
380+
);
381+
const response = await this.api.fetcher.fetch({
382+
method: "get",
383+
url,
384+
path: `/api/environments/${teamId}/integrations/${integrationId}/`,
385+
});
386+
387+
if (!response.ok) {
388+
throw new Error(`Failed to fetch integration: ${response.statusText}`);
389+
}
390+
391+
const data = await response.json();
392+
return data.access_token || null;
393+
}
373394
}

apps/array/src/renderer/features/auth/stores/authStore.ts

Lines changed: 97 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,13 @@
1+
import { GitHubAPIClient } from "@api/githubClient";
12
import { PostHogAPIClient } from "@api/posthogClient";
23
import { identifyUser, resetUser, track } from "@renderer/lib/analytics";
34
import { electronStorage } from "@renderer/lib/electronStorage";
45
import { logger } from "@renderer/lib/logger";
56
import { queryClient } from "@renderer/lib/queryClient";
7+
import { parseRepository } from "@renderer/utils/repository";
68
import type { CloudRegion } from "@shared/types/oauth";
79
import { useNavigationStore } from "@stores/navigationStore";
10+
import { repositoryWorkspaceStore } from "@stores/repositoryWorkspaceStore";
811
import { create } from "zustand";
912
import { persist } from "zustand/middleware";
1013
import {
@@ -36,6 +39,9 @@ interface AuthState {
3639
client: PostHogAPIClient | null;
3740
projectId: number | null; // Current team/project ID
3841

42+
// GitHub client
43+
githubClient: GitHubAPIClient | null;
44+
3945
// OpenAI API key (separate concern, kept for now)
4046
openaiApiKey: string | null;
4147
encryptedOpenaiKey: string | null;
@@ -50,6 +56,9 @@ interface AuthState {
5056
// Other methods
5157
setOpenAIKey: (apiKey: string) => Promise<void>;
5258
setDefaultWorkspace: (workspace: string) => void;
59+
createGitHubClient: (accessToken: string, repository: string) => boolean;
60+
initializeGitHubClient: (accessToken: string) => boolean;
61+
initializeGitHubClientFromIntegration: () => Promise<boolean>;
5362
logout: () => void;
5463
}
5564

@@ -70,6 +79,9 @@ export const useAuthStore = create<AuthState>()(
7079
client: null,
7180
projectId: null,
7281

82+
// GitHub client
83+
githubClient: null,
84+
7385
// OpenAI key
7486
openaiApiKey: null,
7587
encryptedOpenaiKey: null,
@@ -143,6 +155,13 @@ export const useAuthStore = create<AuthState>()(
143155
project_id: projectId.toString(),
144156
region,
145157
});
158+
159+
// Initialize GitHub client if available
160+
try {
161+
await get().initializeGitHubClientFromIntegration();
162+
} catch (error) {
163+
log.warn("Failed to initialize GitHub client during login:", error);
164+
}
146165
} catch {
147166
throw new Error("Failed to authenticate with PostHog");
148167
}
@@ -316,6 +335,16 @@ export const useAuthStore = create<AuthState>()(
316335
region: tokens.cloudRegion,
317336
});
318337

338+
// Initialize GitHub client if available
339+
try {
340+
await get().initializeGitHubClientFromIntegration();
341+
} catch (error) {
342+
log.warn(
343+
"Failed to initialize GitHub client during OAuth init:",
344+
error,
345+
);
346+
}
347+
319348
if (state.encryptedOpenaiKey) {
320349
const decryptedOpenaiKey =
321350
await window.electronAPI.retrieveApiKey(
@@ -359,6 +388,73 @@ export const useAuthStore = create<AuthState>()(
359388
setDefaultWorkspace: (workspace: string) => {
360389
set({ defaultWorkspace: workspace });
361390
},
391+
392+
createGitHubClient: (accessToken: string, repository: string) => {
393+
const parsed = parseRepository(repository);
394+
if (!parsed) {
395+
log.error("Invalid repository format:", repository);
396+
return false;
397+
}
398+
399+
const githubClient = new GitHubAPIClient(
400+
accessToken,
401+
parsed.organization,
402+
parsed.repoName,
403+
);
404+
set({ githubClient });
405+
return true;
406+
},
407+
408+
initializeGitHubClient: (accessToken: string) => {
409+
const { selectedRepository } = repositoryWorkspaceStore.getState();
410+
411+
if (!selectedRepository) {
412+
log.warn("No repository selected, cannot create GitHub client");
413+
return false;
414+
}
415+
416+
return get().createGitHubClient(accessToken, selectedRepository);
417+
},
418+
419+
initializeGitHubClientFromIntegration: async () => {
420+
const { client } = get();
421+
422+
if (!client) {
423+
log.warn(
424+
"No PostHog client available, cannot fetch GitHub integration",
425+
);
426+
return false;
427+
}
428+
429+
try {
430+
const integrations = await client.getIntegrations();
431+
const githubIntegration = integrations.find(
432+
(i: any) => i.kind === "github",
433+
);
434+
435+
if (!githubIntegration) {
436+
log.warn("No GitHub integration found");
437+
return false;
438+
}
439+
440+
const accessToken = await client.getGitHubAccessToken(
441+
githubIntegration.id,
442+
);
443+
444+
if (!accessToken) {
445+
log.warn("No access token found for GitHub integration");
446+
return false;
447+
}
448+
449+
return get().initializeGitHubClient(accessToken);
450+
} catch (error) {
451+
log.error(
452+
"Failed to initialize GitHub client from integration:",
453+
error,
454+
);
455+
return false;
456+
}
457+
},
362458
logout: () => {
363459
track(ANALYTICS_EVENTS.USER_LOGGED_OUT);
364460
resetUser();
@@ -381,6 +477,7 @@ export const useAuthStore = create<AuthState>()(
381477
isAuthenticated: false,
382478
client: null,
383479
projectId: null,
480+
githubClient: null,
384481
openaiApiKey: null,
385482
encryptedOpenaiKey: null,
386483
});

0 commit comments

Comments
 (0)