sandbox-agent/foundry/packages/client/src/app-client.ts
2026-03-14 20:42:18 -07:00

67 lines
2.5 KiB
TypeScript

import type {
FoundryAppSnapshot,
FoundryBillingPlanId,
FoundryOrganization,
FoundryUser,
UpdateFoundryOrganizationProfileInput,
} from "@sandbox-agent/foundry-shared";
import type { BackendClient } from "./backend-client.js";
import { getMockFoundryAppClient } from "./mock-app.js";
import { createRemoteFoundryAppClient } from "./remote/app-client.js";
export interface FoundryAppClient {
getSnapshot(): FoundryAppSnapshot;
subscribe(listener: () => void): () => void;
signInWithGithub(userId?: string): Promise<void>;
signOut(): Promise<void>;
skipStarterRepo(): Promise<void>;
starStarterRepo(organizationId: string): Promise<void>;
selectOrganization(organizationId: string): Promise<void>;
updateOrganizationProfile(input: UpdateFoundryOrganizationProfileInput): Promise<void>;
triggerGithubSync(organizationId: string): Promise<void>;
completeHostedCheckout(organizationId: string, planId: FoundryBillingPlanId): Promise<void>;
openBillingPortal(organizationId: string): Promise<void>;
cancelScheduledRenewal(organizationId: string): Promise<void>;
resumeSubscription(organizationId: string): Promise<void>;
reconnectGithub(organizationId: string): Promise<void>;
recordSeatUsage(organizationId: string): Promise<void>;
}
export interface CreateFoundryAppClientOptions {
mode: "mock" | "remote";
backend?: BackendClient;
}
export function createFoundryAppClient(options: CreateFoundryAppClientOptions): FoundryAppClient {
if (options.mode === "mock") {
return getMockFoundryAppClient() as unknown as FoundryAppClient;
}
if (!options.backend) {
throw new Error("Remote app client requires a backend client");
}
return createRemoteFoundryAppClient({ backend: options.backend });
}
export function currentFoundryUser(snapshot: FoundryAppSnapshot): FoundryUser | null {
if (!snapshot.auth.currentUserId) {
return null;
}
return snapshot.users.find((candidate) => candidate.id === snapshot.auth.currentUserId) ?? null;
}
export function currentFoundryOrganization(snapshot: FoundryAppSnapshot): FoundryOrganization | null {
if (!snapshot.activeOrganizationId) {
return null;
}
return snapshot.organizations.find((candidate) => candidate.id === snapshot.activeOrganizationId) ?? null;
}
export function eligibleFoundryOrganizations(snapshot: FoundryAppSnapshot): FoundryOrganization[] {
const user = currentFoundryUser(snapshot);
if (!user) {
return [];
}
const eligible = new Set(user.eligibleOrganizationIds);
return snapshot.organizations.filter((organization) => eligible.has(organization.id));
}