mirror of
https://github.com/stack-auth/stack.git
synced 2026-06-19 21:00:40 +08:00
Some checks failed
all-good: Did all the other checks pass? / all-good (push) Has been cancelled
Ensure Prisma migrations are in sync with the schema / check_prisma_migrations (22.x) (push) Has been cancelled
DB migration compat / Check if migrations changed (push) Has been cancelled
Docker Server Build and Push / Docker Build and Push Server (push) Has been cancelled
Docker Server Build and Run / docker (push) Has been cancelled
Runs E2E API Tests (Local Emulator) / E2E Tests (Local Emulator, Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (mock, 22.x) (push) Has been cancelled
Runs E2E API Tests / E2E Tests (Node ${{ matrix.node-version }}, Freestyle ${{ matrix.freestyle-mode }}) (prod, 22.x) (push) Has been cancelled
Runs E2E API Tests with custom port prefix / build (22.x) (push) Has been cancelled
Runs E2E Fallback Tests / E2E Fallback Tests (Node ${{ matrix.node-version }}) (22.x) (push) Has been cancelled
Lint & build / lint_and_build (24) (push) Has been cancelled
TOC Generator / TOC Generator (push) Has been cancelled
DB migration compat / Back-compat — Current branch migrations with ${{ needs.check-migrations-changed.outputs.base_branch }} branch code (push) Has been cancelled
DB migration compat / Forward-compat — Current branch code with ${{ needs.check-migrations-changed.outputs.base_branch }} branch migrations (push) Has been cancelled
DB migration compat / No migration changes (skipped) (push) Has been cancelled
121 lines
3.9 KiB
TypeScript
121 lines
3.9 KiB
TypeScript
import { buildStackAuthHeaders, type CurrentUser } from "@/lib/api-headers";
|
|
import { getPublicEnvVar } from "@/lib/env";
|
|
import type {
|
|
ConversationDetailResponse,
|
|
ConversationListResponse,
|
|
ConversationPriority,
|
|
ConversationStatus,
|
|
} from "@/lib/conversation-types";
|
|
import { throwErr } from "@hexclave/shared/dist/utils/errors";
|
|
|
|
type ListConversationsOptions = {
|
|
projectId: string,
|
|
query?: string,
|
|
status?: ConversationStatus,
|
|
userId?: string,
|
|
limit?: number,
|
|
offset?: number,
|
|
};
|
|
|
|
function getBaseUrl() {
|
|
return getPublicEnvVar("NEXT_PUBLIC_STACK_API_URL") ?? throwErr("NEXT_PUBLIC_STACK_API_URL is not set");
|
|
}
|
|
|
|
async function apiFetch(
|
|
currentUser: CurrentUser | null,
|
|
path: string,
|
|
options: RequestInit = {},
|
|
) {
|
|
const headers = await buildStackAuthHeaders(currentUser);
|
|
const response = await fetch(`${getBaseUrl()}/api/latest/internal/conversations${path}`, {
|
|
...options,
|
|
headers: {
|
|
...(options.body != null ? { "content-type": "application/json" } : {}),
|
|
...headers,
|
|
...options.headers,
|
|
},
|
|
});
|
|
if (!response.ok) {
|
|
const errorText = await response.text();
|
|
throw new Error(errorText || `Conversations API error: ${response.status}`);
|
|
}
|
|
return response;
|
|
}
|
|
|
|
export async function listConversations(currentUser: CurrentUser | null, options: ListConversationsOptions) {
|
|
const params = new URLSearchParams();
|
|
params.set("projectId", options.projectId);
|
|
if (options.query) params.set("query", options.query);
|
|
if (options.status) params.set("status", options.status);
|
|
if (options.userId) params.set("userId", options.userId);
|
|
if (options.limit != null) params.set("limit", options.limit.toString());
|
|
if (options.offset != null) params.set("offset", options.offset.toString());
|
|
|
|
const response = await apiFetch(currentUser, `?${params.toString()}`);
|
|
return await response.json() as ConversationListResponse;
|
|
}
|
|
|
|
export async function getConversation(currentUser: CurrentUser | null, options: {
|
|
projectId: string,
|
|
conversationId: string,
|
|
}) {
|
|
const params = new URLSearchParams();
|
|
params.set("projectId", options.projectId);
|
|
const response = await apiFetch(currentUser, `/${encodeURIComponent(options.conversationId)}?${params.toString()}`);
|
|
return await response.json() as ConversationDetailResponse;
|
|
}
|
|
|
|
export async function createConversation(currentUser: CurrentUser | null, options: {
|
|
projectId: string,
|
|
userId: string,
|
|
subject: string,
|
|
initialMessage: string,
|
|
priority: ConversationPriority,
|
|
}) {
|
|
const response = await apiFetch(currentUser, "", {
|
|
method: "POST",
|
|
body: JSON.stringify(options),
|
|
});
|
|
return await response.json() as { conversationId: string };
|
|
}
|
|
|
|
export async function appendConversationUpdate(currentUser: CurrentUser | null, options:
|
|
| { projectId: string, conversationId: string, type: "internal-note", body: string }
|
|
| { projectId: string, conversationId: string, type: "reply", body: string }
|
|
| { projectId: string, conversationId: string, type: "status", status: ConversationStatus }
|
|
| {
|
|
projectId: string,
|
|
conversationId: string,
|
|
type: "metadata",
|
|
assignedToUserId?: string | null,
|
|
assignedToDisplayName?: string | null,
|
|
priority?: ConversationPriority,
|
|
tags?: string[],
|
|
}
|
|
) {
|
|
const payload = (() => {
|
|
if ("body" in options) {
|
|
return { body: options.body };
|
|
}
|
|
if ("status" in options) {
|
|
return { status: options.status };
|
|
}
|
|
return {
|
|
assignedToUserId: options.assignedToUserId,
|
|
assignedToDisplayName: options.assignedToDisplayName,
|
|
priority: options.priority,
|
|
tags: options.tags,
|
|
};
|
|
})();
|
|
|
|
const response = await apiFetch(currentUser, `/${encodeURIComponent(options.conversationId)}`, {
|
|
method: "PATCH",
|
|
body: JSON.stringify({
|
|
projectId: options.projectId,
|
|
type: options.type,
|
|
...payload,
|
|
}),
|
|
});
|
|
return await response.json() as ConversationDetailResponse;
|
|
}
|