131 lines
3.8 KiB
TypeScript
131 lines
3.8 KiB
TypeScript
import PocketBase from "pocketbase";
|
|
import { createPlayersService } from "./services/players";
|
|
import { createTournamentsService } from "./services/tournaments";
|
|
import { createTeamsService } from "./services/teams";
|
|
import { createMatchesService } from "./services/matches";
|
|
import { createReactionsService } from "./services/reactions";
|
|
import { createActivitiesService } from "./services/activities";
|
|
import { createBadgesService } from "./services/badges";
|
|
|
|
class PocketBaseAdminClient {
|
|
private pb: PocketBase;
|
|
public authPromise: Promise<void>;
|
|
private refreshInterval: NodeJS.Timeout | null = null;
|
|
|
|
constructor() {
|
|
this.pb = new PocketBase(process.env.POCKETBASE_URL);
|
|
|
|
this.pb.beforeSend = async (url, options) => {
|
|
await this.authPromise;
|
|
|
|
if (this.pb.authStore.isValid && this.isTokenExpiringSoon()) {
|
|
try {
|
|
await this.refreshAuth();
|
|
} catch (error) {
|
|
console.error('Failed to refresh admin token, re-authenticating:', error);
|
|
await this.authenticate();
|
|
}
|
|
}
|
|
|
|
options.cache = "no-store";
|
|
options.headers = {
|
|
...options.headers,
|
|
"Cache-Control": "no-cache, no-store, must-revalidate",
|
|
Pragma: "no-cache",
|
|
Expires: "0",
|
|
};
|
|
|
|
return { url, options };
|
|
};
|
|
this.pb.autoCancellation(false);
|
|
|
|
Object.assign(this, createPlayersService(this.pb));
|
|
Object.assign(this, createTeamsService(this.pb));
|
|
Object.assign(this, createTournamentsService(this.pb));
|
|
Object.assign(this, createMatchesService(this.pb));
|
|
Object.assign(this, createReactionsService(this.pb));
|
|
Object.assign(this, createActivitiesService(this.pb));
|
|
Object.assign(this, createBadgesService(this.pb));
|
|
|
|
this.authPromise = this.authenticate();
|
|
this.authPromise.then(() => {
|
|
this.startTokenRefresh();
|
|
});
|
|
}
|
|
|
|
private async authenticate() {
|
|
try {
|
|
await this.pb
|
|
.collection("_superusers")
|
|
.authWithPassword(
|
|
process.env.POCKETBASE_ADMIN_EMAIL!,
|
|
process.env.POCKETBASE_ADMIN_PASSWORD!
|
|
);
|
|
} catch (error) {
|
|
console.error('Failed to authenticate PocketBase admin:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private async refreshAuth() {
|
|
try {
|
|
await this.pb.collection("_superusers").authRefresh();
|
|
} catch (error) {
|
|
console.error('Failed to refresh PocketBase admin token:', error);
|
|
throw error;
|
|
}
|
|
}
|
|
|
|
private isTokenExpiringSoon(): boolean {
|
|
if (!this.pb.authStore.token) return false;
|
|
|
|
try {
|
|
const payload = JSON.parse(atob(this.pb.authStore.token.split('.')[1]));
|
|
const expiresAt = payload.exp * 1000;
|
|
const now = Date.now();
|
|
const fiveMinutes = 5 * 60 * 1000;
|
|
|
|
return expiresAt - now < fiveMinutes;
|
|
} catch {
|
|
return false;
|
|
}
|
|
}
|
|
|
|
private startTokenRefresh() {
|
|
this.refreshInterval = setInterval(async () => {
|
|
try {
|
|
await this.refreshAuth();
|
|
} catch (error) {
|
|
console.error('Periodic token refresh failed, re-authenticating:', error);
|
|
try {
|
|
await this.authenticate();
|
|
} catch (authError) {
|
|
console.error('Re-authentication failed:', authError);
|
|
}
|
|
}
|
|
}, 10 * 60 * 1000);
|
|
|
|
if (typeof process !== 'undefined') {
|
|
process.on('beforeExit', () => {
|
|
if (this.refreshInterval) {
|
|
clearInterval(this.refreshInterval);
|
|
}
|
|
});
|
|
}
|
|
}
|
|
}
|
|
|
|
interface AdminClient
|
|
extends PocketBaseAdminClient,
|
|
ReturnType<typeof createPlayersService>,
|
|
ReturnType<typeof createTeamsService>,
|
|
ReturnType<typeof createTournamentsService>,
|
|
ReturnType<typeof createMatchesService>,
|
|
ReturnType<typeof createReactionsService>,
|
|
ReturnType<typeof createActivitiesService>,
|
|
ReturnType<typeof createBadgesService> {
|
|
authPromise: Promise<void>;
|
|
}
|
|
|
|
export const pbAdmin = new PocketBaseAdminClient() as AdminClient;
|