feat: implement repo fetching, add sentry
This commit is contained in:
@@ -4,37 +4,24 @@
|
||||
import type { Repository } from './types/repo';
|
||||
import { createQuery } from '@tanstack/svelte-query';
|
||||
import { authClient } from './auth-client';
|
||||
import { apiClient } from './api-client';
|
||||
|
||||
const session = authClient.useSession();
|
||||
|
||||
const query = createQuery(() => ({
|
||||
queryKey: ['github-repositories'],
|
||||
queryFn: async () => {
|
||||
const response = await fetch(`/api/${$session.data?.user.id}/repos`);
|
||||
return await response.json();
|
||||
}
|
||||
return await apiClient.request<Repository[]>(`/api/v0/user/${$session.data?.user.id}/repos`);
|
||||
},
|
||||
enabled: !!$session.data?.user.id,
|
||||
staleTime: 30000
|
||||
}));
|
||||
|
||||
$inspect(query.data);
|
||||
|
||||
const mockRepositories: Repository[] = [
|
||||
{
|
||||
id: 1,
|
||||
name: 'Mock',
|
||||
fullName: 'Mock',
|
||||
description: 'Mock Data',
|
||||
language: 'GDScript',
|
||||
stars: 42,
|
||||
updatedAt: new Date().toISOString(),
|
||||
isPrivate: false
|
||||
}
|
||||
];
|
||||
|
||||
let searchQuery = $state('');
|
||||
let adding = $state<number | null>(null);
|
||||
|
||||
const filteredRepositories = $derived(
|
||||
mockRepositories.filter(
|
||||
(query.data ?? []).filter(
|
||||
(repo) =>
|
||||
repo.name.toLowerCase().includes(searchQuery.toLowerCase()) ||
|
||||
repo.description?.toLowerCase().includes(searchQuery.toLowerCase())
|
||||
@@ -110,7 +97,7 @@
|
||||
{/if}
|
||||
<span class="flex items-center gap-1">
|
||||
<Star class="h-3.5 w-3.5" />
|
||||
{repo.stars}
|
||||
{repo.stars ?? 0}
|
||||
</span>
|
||||
<span class="flex items-center gap-1">
|
||||
<Clock class="h-3.5 w-3.5" />
|
||||
|
||||
50
src/lib/api-client.ts
Normal file
50
src/lib/api-client.ts
Normal file
@@ -0,0 +1,50 @@
|
||||
import { decodeJwt } from 'jose';
|
||||
import { authClient } from './auth-client';
|
||||
|
||||
export class ApiClient {
|
||||
private token: string | null;
|
||||
|
||||
constructor() {
|
||||
this.token = null;
|
||||
}
|
||||
|
||||
private tokenValid() {
|
||||
if (!this.token) {
|
||||
return false;
|
||||
}
|
||||
|
||||
const jwt = decodeJwt(this.token);
|
||||
if (!jwt.exp) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return jwt.exp > Date.now() / 1000 + 10;
|
||||
}
|
||||
|
||||
private async getToken() {
|
||||
if (this.tokenValid()) {
|
||||
return this.token;
|
||||
}
|
||||
|
||||
const token = (await authClient.token().then((t) => t.data?.token)) ?? null;
|
||||
this.token = token;
|
||||
|
||||
return token;
|
||||
}
|
||||
|
||||
async request<T>(url: string, options: RequestInit = {}): Promise<T> {
|
||||
const token = await this.getToken();
|
||||
|
||||
const response = await fetch(url, {
|
||||
...options,
|
||||
headers: {
|
||||
Authorization: `Bearer ${token}`
|
||||
}
|
||||
});
|
||||
|
||||
const data = await response.json();
|
||||
return data;
|
||||
}
|
||||
}
|
||||
|
||||
export const apiClient = new ApiClient();
|
||||
@@ -1,7 +1,7 @@
|
||||
import { jwt } from 'better-auth/plugins';
|
||||
import { jwtClient } from 'better-auth/client/plugins';
|
||||
import { createAuthClient } from 'better-auth/svelte';
|
||||
|
||||
export const authClient = createAuthClient({
|
||||
baseURL: 'http://localhost:5173',
|
||||
plugins: [jwt()]
|
||||
plugins: [jwtClient()]
|
||||
});
|
||||
|
||||
@@ -2,9 +2,9 @@ export type Repository = {
|
||||
id: number;
|
||||
name: string;
|
||||
fullName: string;
|
||||
description: string | null;
|
||||
language: string | null;
|
||||
stars: number;
|
||||
description?: string | null;
|
||||
language?: string | null;
|
||||
stars?: number;
|
||||
updatedAt: string;
|
||||
isPrivate: boolean;
|
||||
private: boolean;
|
||||
};
|
||||
|
||||
Reference in New Issue
Block a user