learning_ai_notes/web/src/lib/intake-client.ts

199 lines
5.5 KiB
TypeScript

"use client";
import { createNotesApiClient } from "@/lib/api-helpers";
import { RETRY_WHEN_ONLINE_MESSAGE, withMutationRetry } from "@/lib/mutation-retry";
// ── Types ────────────────────────────────────────────────────────
export type IntakeContentType =
| "youtube"
| "article"
| "pdf"
| "tweet"
| "reddit"
| "github"
| "generic";
export type IntakeJobStatus =
| "queued"
| "extracting"
| "processing"
| "complete"
| "failed";
export interface IntakeSubmitResult {
jobId: string;
noteId: string;
contentType: IntakeContentType;
ruleMatched: string | null;
templateSlug: string;
status: "queued";
}
export interface IntakeJob {
id: string;
noteId: string;
url: string;
contentType: IntakeContentType;
templateSlug: string;
status: IntakeJobStatus;
error?: string;
startedAt: string;
completedAt?: string;
}
export interface IntakeRule {
id: string;
userId: string;
name: string;
urlPattern: string;
contentType: IntakeContentType;
templateId: string;
enabled: boolean;
priority: number;
}
// ── API Calls ────────────────────────────────────────────────────
export async function submitIntake(
url: string,
workspaceId?: string,
templateOverride?: string,
): Promise<IntakeSubmitResult> {
const api = createNotesApiClient();
const payload: Record<string, string> = { url };
if (workspaceId) payload.workspaceId = workspaceId;
if (templateOverride) payload.templateOverride = templateOverride;
return withMutationRetry({
run: () => api.fetch("/intake", {
method: "POST",
body: JSON.stringify(payload),
}),
offlineMessage: RETRY_WHEN_ONLINE_MESSAGE,
});
}
export async function listIntakeJobs(options?: {
status?: IntakeJobStatus;
limit?: number;
}): Promise<{ items: IntakeJob[]; total: number }> {
const api = createNotesApiClient();
const params = new URLSearchParams();
if (options?.status) params.set("status", options.status);
if (options?.limit) params.set("limit", String(options.limit));
const qs = params.toString();
return api.fetch(`/intake/jobs${qs ? `?${qs}` : ""}`);
}
export async function getIntakeJob(id: string): Promise<IntakeJob> {
const api = createNotesApiClient();
return api.fetch(`/intake/jobs/${encodeURIComponent(id)}`);
}
export async function listIntakeRules(): Promise<{
items: IntakeRule[];
total: number;
}> {
const api = createNotesApiClient();
return api.fetch("/intake-rules");
}
export async function createIntakeRule(
rule: Omit<IntakeRule, "id" | "userId">,
): Promise<IntakeRule> {
const api = createNotesApiClient();
return withMutationRetry({
run: () => api.fetch("/intake-rules", {
method: "POST",
body: JSON.stringify(rule),
}),
queue: { id: rule.name, action: "post", path: "/intake-rules", payload: rule },
});
}
export async function deleteIntakeRule(id: string): Promise<void> {
const api = createNotesApiClient();
const path = `/intake-rules/${encodeURIComponent(id)}`;
await withMutationRetry({
run: () => api.fetch(path, {
method: "DELETE",
}),
queue: { id, action: "delete", path, payload: {} },
});
}
// ── Sharing helpers ──────────────────────────────────────────────
export async function shareNoteWithUser(
noteId: string,
workspaceId: string,
sharedWithUserId: string,
permission: "view" | "comment" | "edit" = "view",
): Promise<unknown> {
const api = createNotesApiClient();
const path = `/notes/${encodeURIComponent(noteId)}/share-with-user`;
return withMutationRetry({
run: () => api.fetch(path, {
method: "POST",
body: JSON.stringify({ workspaceId, sharedWithUserId, permission }),
}),
offlineMessage: RETRY_WHEN_ONLINE_MESSAGE,
});
}
export async function listCollaborators(
noteId: string,
workspaceId: string,
): Promise<{ items: unknown[]; total: number }> {
const api = createNotesApiClient();
return api.fetch(`/notes/${encodeURIComponent(noteId)}/collaborators?workspaceId=${encodeURIComponent(workspaceId)}`);
}
export async function listSharedWithMe(): Promise<{
items: unknown[];
total: number;
}> {
const api = createNotesApiClient();
return api.fetch("/shared-with-me");
}
export async function removeCollaborator(
noteId: string,
userId: string,
): Promise<void> {
const api = createNotesApiClient();
const path = `/notes/${encodeURIComponent(noteId)}/collaborators/${encodeURIComponent(userId)}`;
await withMutationRetry({
run: () => api.fetch(path, {
method: "DELETE",
}),
offlineMessage: RETRY_WHEN_ONLINE_MESSAGE,
});
}
export async function exportNoteText(
noteId: string,
workspaceId: string,
): Promise<{
title: string;
markdown: string;
plaintext: string;
html: string;
}> {
const api = createNotesApiClient();
return api.fetch(`/notes/${encodeURIComponent(noteId)}/export-text`, {
method: "POST",
body: JSON.stringify({ workspaceId }),
});
}
export async function getNoteDeepLinks(
noteId: string,
workspaceId: string,
): Promise<{ web: string; mobile: string; public: string | null }> {
const api = createNotesApiClient();
return api.fetch(
`/notes/${encodeURIComponent(noteId)}/deep-link?workspaceId=${encodeURIComponent(workspaceId)}`,
);
}