feat: list streams and story-mode catchup

This commit is contained in:
talksik
2026-02-21 09:46:04 -08:00
parent b5f90709de
commit 0cd74c0a8a
33 changed files with 2304 additions and 41 deletions
+81
View File
@@ -1,10 +1,17 @@
import { useSessionStore } from "@/stores/session-store";
import type {
CreateStreamParticleRequest,
CreateStreamRequest,
Human,
MarkSeenBatchRequest,
PrepareUploadRequest,
PrepareUploadResponse,
RequestCodeRequest,
SignInRequest,
SignInResponse,
StartupResponse,
Stream,
StreamParticle,
} from "./types";
export class ApiError extends Error {
@@ -67,6 +74,8 @@ class ApiClient {
return response.json() as Promise<T>;
}
// --- Auth ---
async requestCode(data: RequestCodeRequest): Promise<void> {
await this.request<void>("POST", "/auth/request-code", data);
}
@@ -83,9 +92,81 @@ class ApiClient {
await this.request<void>("POST", "/auth/sign-out");
}
// --- Startup ---
async startup(): Promise<StartupResponse> {
return this.request<StartupResponse>("GET", "/startup");
}
// --- Streams ---
async createStream(
networkId: string,
data: CreateStreamRequest,
): Promise<Stream> {
return this.request<Stream>(
"POST",
`/networks/${networkId}/streams`,
data,
);
}
async createStreamParticle(
streamId: string,
data: CreateStreamParticleRequest,
): Promise<StreamParticle> {
return this.request<StreamParticle>(
"POST",
`/streams/${streamId}/particles`,
data,
);
}
// --- Particles ---
async markSeen(particleId: string): Promise<void> {
await this.request<void>("POST", `/particles/${particleId}/seen`);
}
async markSeenBatch(data: MarkSeenBatchRequest): Promise<void> {
await this.request<void>("POST", "/particles/seen", data);
}
async getParticleDownloadUrl(particleId: string): Promise<string> {
const token = this.config.getToken();
const headers: Record<string, string> = {};
if (token) {
headers["Authorization"] = `Bearer ${token}`;
}
const response = await fetch(
`${this.config.baseUrl}/particles/${particleId}/download`,
{ headers, redirect: "follow" },
);
if (response.status === 401) {
this.config.onUnauthorized();
throw new ApiError(401, "Unauthorized");
}
if (!response.ok) {
throw new ApiError(response.status, "Failed to get download URL");
}
return response.url;
}
// --- Depot ---
async prepareUpload(
data: PrepareUploadRequest,
): Promise<PrepareUploadResponse> {
return this.request<PrepareUploadResponse>("POST", "/depot/upload", data);
}
async confirmUpload(objectId: string): Promise<void> {
await this.request<void>("POST", `/depot/objects/${objectId}/confirm`);
}
}
export const apiClient = new ApiClient({