API Reference
Complete API documentation for @pressw/threads.
ThreadUtilityClient
The main server-side client for managing threads.
Constructor
new ThreadUtilityClient(options: ThreadUtilityClientOptions)
Parameters
options
- Configuration optionsadapter
- Database adapter instancegetUserContext
- Function to retrieve user context for multi-tenancy
Example
const threadClient = new ThreadUtilityClient({
adapter: createAdapter({
/* adapter config */
}),
getUserContext: async (userId: string) => ({
id: userId,
organizationId: 'org_123',
tenantId: 'tenant_456',
}),
});
Methods
createThread
Creates a new thread.
async createThread(
userId: string,
options: CreateThreadOptions
): Promise<Thread>
Parameters:
userId
- The ID of the user creating the threadoptions
- Thread creation optionstitle
- Thread title (required)metadata
- Custom metadata object (optional)
Returns: The created thread object
Example:
const thread = await threadClient.createThread('user_123', {
title: 'New Discussion',
metadata: {
category: 'general',
tags: ['important', 'discussion'],
},
});
updateThread
Updates an existing thread.
async updateThread(
userId: string,
threadId: string,
options: UpdateThreadOptions
): Promise<Thread>
Parameters:
userId
- The ID of the user updating the threadthreadId
- The ID of the thread to updateoptions
- Update optionstitle
- New thread title (optional)metadata
- New metadata object (optional)
Returns: The updated thread object
Example:
const updated = await threadClient.updateThread('user_123', 'thread_456', {
title: 'Updated Title',
metadata: {
status: 'resolved',
resolvedAt: new Date().toISOString(),
},
});
getThread
Retrieves a single thread by ID.
async getThread(
userId: string,
threadId: string
): Promise<Thread | null>
Parameters:
userId
- The ID of the user requesting the threadthreadId
- The ID of the thread to retrieve
Returns: The thread object or null if not found
Example:
const thread = await threadClient.getThread('user_123', 'thread_456');
if (thread) {
console.log(thread.title);
}
listThreads
Lists threads with pagination and search.
async listThreads(
userId: string,
options?: ListThreadsOptions
): Promise<ThreadsResponse>
Parameters:
userId
- The ID of the user listing threadsoptions
- List options (optional)limit
- Number of threads to return (default: 10, max: 100)offset
- Number of threads to skipsearch
- Search query for thread titlesorderBy
- Sort order: "asc" or "desc" (default: "desc")
Returns: Paginated thread response
Example:
const response = await threadClient.listThreads('user_123', {
limit: 20,
offset: 0,
search: 'project',
orderBy: 'desc',
});
console.log(`Found ${response.total} threads`);
response.threads.forEach((thread) => {
console.log(thread.title);
});
deleteThread
Deletes a thread.
async deleteThread(
userId: string,
threadId: string
): Promise<void>
Parameters:
userId
- The ID of the user deleting the threadthreadId
- The ID of the thread to delete
Example:
await threadClient.deleteThread('user_123', 'thread_456');
Types
Thread
The main thread entity.
interface Thread {
id: string;
title: string;
userId: string;
organizationId?: string | null;
tenantId?: string | null;
metadata?: Record<string, any> | null;
createdAt: Date;
updatedAt: Date;
}
UserContext
User context for multi-tenant operations.
interface UserContext {
id: string;
organizationId?: string;
tenantId?: string;
}
CreateThreadOptions
Options for creating a thread.
interface CreateThreadOptions {
title: string;
metadata?: Record<string, any>;
}
UpdateThreadOptions
Options for updating a thread.
interface UpdateThreadOptions {
title?: string;
metadata?: Record<string, any>;
}
ListThreadsOptions
Options for listing threads.
interface ListThreadsOptions {
limit?: number;
offset?: number;
search?: string;
orderBy?: 'asc' | 'desc';
}
ThreadsResponse
Response from listing threads.
interface ThreadsResponse {
threads: Thread[];
total: number;
limit: number;
offset: number;
}
React Hooks
useThreads
Fetches a list of threads.
function useThreads(options?: ListThreadsOptions): UseQueryResult<Thread[]>;
Example:
function ThreadList() {
const {
data: threads,
isLoading,
error,
} = useThreads({
limit: 20,
search: 'important',
});
if (isLoading) return <div>Loading...</div>;
if (error) return <div>Error: {error.message}</div>;
return (
<ul>
{threads?.map((thread) => (
<li key={thread.id}>{thread.title}</li>
))}
</ul>
);
}
useThread
Fetches a single thread.
function useThread(threadId: string): UseQueryResult<Thread>;
Example:
function ThreadDetail({ threadId }: { threadId: string }) {
const { data: thread, isLoading } = useThread(threadId);
if (isLoading) return <div>Loading...</div>;
if (!thread) return <div>Thread not found</div>;
return (
<div>
<h1>{thread.title}</h1>
<p>Created: {thread.createdAt.toLocaleString()}</p>
</div>
);
}
useCreateThread
Creates a new thread with optimistic updates.
function useCreateThread(): UseMutationResult<Thread, Error, CreateThreadOptions>;
Example:
function CreateThreadForm() {
const createThread = useCreateThread();
const handleSubmit = async (e: FormEvent) => {
e.preventDefault();
const formData = new FormData(e.target as HTMLFormElement);
await createThread.mutateAsync({
title: formData.get('title') as string,
metadata: {
category: formData.get('category') as string,
},
});
};
return (
<form onSubmit={handleSubmit}>
<input name="title" placeholder="Thread title" required />
<select name="category">
<option value="general">General</option>
<option value="support">Support</option>
</select>
<button type="submit" disabled={createThread.isPending}>
Create Thread
</button>
</form>
);
}
useUpdateThread
Updates a thread with optimistic updates.
function useUpdateThread(): UseMutationResult<
Thread,
Error,
{ threadId: string } & UpdateThreadOptions
>;
Example:
function EditThreadForm({ thread }: { thread: Thread }) {
const updateThread = useUpdateThread();
const handleUpdate = async (newTitle: string) => {
await updateThread.mutateAsync({
threadId: thread.id,
title: newTitle,
});
};
return <input defaultValue={thread.title} onBlur={(e) => handleUpdate(e.target.value)} />;
}
useDeleteThread
Deletes a thread with optimistic updates.
function useDeleteThread(): UseMutationResult<void, Error, string>;
Example:
function DeleteThreadButton({ threadId }: { threadId: string }) {
const deleteThread = useDeleteThread();
const handleDelete = async () => {
if (confirm('Are you sure?')) {
await deleteThread.mutateAsync(threadId);
}
};
return (
<button onClick={handleDelete} disabled={deleteThread.isPending}>
Delete
</button>
);
}
useInfiniteThreads
Fetches threads with infinite scroll support.
function useInfiniteThreads(
options?: Omit<ListThreadsOptions, 'offset'>,
): UseInfiniteQueryResult<ThreadsResponse>;
Example:
function InfiniteThreadList() {
const { data, fetchNextPage, hasNextPage, isFetchingNextPage } = useInfiniteThreads({
limit: 20,
});
return (
<div>
{data?.pages.map((page) =>
page.threads.map((thread) => <div key={thread.id}>{thread.title}</div>),
)}
{hasNextPage && (
<button onClick={() => fetchNextPage()} disabled={isFetchingNextPage}>
Load More
</button>
)}
</div>
);
}
Adapters
createAdapter
Creates a database adapter for thread operations.
function createAdapter(options: AdapterOptions): ChatCoreAdapter;
Parameters:
options
- Adapter configurationprovider
- Database provider: "postgresql", "mysql", or "sqlite"db
- Drizzle database instanceschema
- Database schema with users, threads, and feedback tables
Example:
import { createAdapter } from '@pressw/threads/adapters';
import { drizzle } from 'drizzle-orm/postgres-js';
import postgres from 'postgres';
import * as schema from './schema';
const sql = postgres(process.env.DATABASE_URL!);
const db = drizzle(sql, { schema });
const adapter = createAdapter({
provider: 'postgresql',
db,
schema,
});
Error Handling
All methods throw errors with descriptive messages when operations fail:
try {
await threadClient.createThread(userId, {
title: 'New Thread',
});
} catch (error) {
if (error instanceof Error) {
console.error('Failed to create thread:', error.message);
}
}
Common error scenarios:
- User not found
- Thread not found
- Permission denied (multi-tenant violations)
- Validation errors (missing required fields)
- Database connection errors