@elqnt/docs
Document management and processing for the Eloquent platform. Handle document libraries, folders, file uploads, content extraction, projects, and AI-powered analysis.
Installation
npm install @elqnt/docs
Entry Points
| Import | Description |
|---|---|
@elqnt/docs | All exports |
@elqnt/docs/hooks | React hooks (useLibraries, useFolders, useDocuments, useProjects) |
@elqnt/docs/models | TypeScript types |
@elqnt/docs/api | Internal API functions (use hooks instead) |
@elqnt/docs/transport | Analysis SSE transport (createAnalysisTransport, createFetchAnalysisTransport) |
React Hooks
useLibraries
Hook for document library CRUD operations with loading/error states.
import { useLibraries } from "@elqnt/docs/hooks";
const {
loading,
error,
listLibraries,
getLibrary,
getDefaultLibrary,
createLibrary,
updateLibrary,
deleteLibrary,
} = useLibraries({
baseUrl: apiGatewayUrl,
orgId: selectedOrgId,
});
// List all libraries
const libraries = await listLibraries();
// Get library by ID
const library = await getLibrary("library-uuid");
// Get or create default library for current user
const defaultLib = await getDefaultLibrary();
// Create library
const newLib = await createLibrary({
name: "My Documents",
description: "Personal files",
permissionLevel: "user",
});
// Update library
const updated = await updateLibrary("library-uuid", { name: "Renamed Library" });
// Delete library
const success = await deleteLibrary("library-uuid");
Methods:
| Method | Parameters | Returns | Description |
|---|---|---|---|
listLibraries | - | DocLibrary[] | List all accessible libraries |
getLibrary | libraryId: string | DocLibrary | null | Get library by ID |
getDefaultLibrary | - | DocLibrary | null | Get or create user's default library |
createLibrary | library: Partial<DocLibrary> | DocLibrary | null | Create a new library |
updateLibrary | libraryId: string, updates: Partial<DocLibrary> | DocLibrary | null | Update a library |
deleteLibrary | libraryId: string | boolean | Delete a library |
useFolders
Hook for folder CRUD operations with loading/error states.
import { useFolders } from "@elqnt/docs/hooks";
const {
loading,
error,
listFolders,
createFolder,
updateFolder,
deleteFolder,
moveFolder,
copyFolder,
} = useFolders({
baseUrl: apiGatewayUrl,
orgId: selectedOrgId,
libraryId: selectedLibraryId,
});
// List folders in root (no parentFolderId) or in a specific folder
const rootFolders = await listFolders();
const subFolders = await listFolders("parent-folder-uuid");
// Create folder
const newFolder = await createFolder({
name: "Reports",
libraryId: selectedLibraryId,
parentFolderId: "", // Empty = root
});
// Update folder
const updated = await updateFolder("folder-uuid", { name: "Q4 Reports" });
// Delete folder (with optional recursive delete)
const success = await deleteFolder("folder-uuid", true); // recursive = true
// Move folder to new location
const moved = await moveFolder("folder-uuid", {
newParentFolderId: "target-folder-uuid",
newLibraryId: "target-library-uuid",
});
// Copy folder
const copied = await copyFolder("folder-uuid", {
newParentFolderId: "target-folder-uuid",
});
Methods:
| Method | Parameters | Returns | Description |
|---|---|---|---|
listFolders | parentFolderId?: string | DocFolder[] | List folders (root or in parent) |
createFolder | folder: Partial<DocFolder> | DocFolder | null | Create a new folder |
updateFolder | folderId: string, updates: Partial<DocFolder> | DocFolder | null | Update a folder |
deleteFolder | folderId: string, recursive?: boolean | boolean | Delete folder (optionally with contents) |
moveFolder | folderId: string, destination: {...} | DocFolder | null | Move folder to new location |
copyFolder | folderId: string, destination: {...} | DocFolder | null | Copy folder to new location |
useDocuments
Hook for document CRUD operations with loading/error states.
import { useDocuments } from "@elqnt/docs/hooks";
const {
loading,
error,
listDocuments,
createDocument,
updateDocument,
deleteDocument,
moveDocument,
copyDocument,
} = useDocuments({
baseUrl: apiGatewayUrl,
orgId: selectedOrgId,
libraryId: selectedLibraryId,
});
// List documents with pagination
const { references, totalCount } = await listDocuments({
folderId: "folder-uuid", // Optional: filter by folder
page: 1,
pageSize: 20,
});
// Create document reference
const newDoc = await createDocument({
title: "Report.pdf",
libraryId: selectedLibraryId,
docUrl: "https://storage.example.com/file.pdf",
mimeType: "application/pdf",
fileSize: 1024000,
});
// Update document
const updated = await updateDocument("doc-uuid", { title: "Updated Report.pdf" });
// Delete document
const success = await deleteDocument("doc-uuid");
// Move document to new location
const moved = await moveDocument("doc-uuid", {
newLibraryId: "target-library-uuid",
newFolderId: "target-folder-uuid",
});
// Copy document
const copied = await copyDocument("doc-uuid", {
newFolderId: "target-folder-uuid",
});
Methods:
| Method | Parameters | Returns | Description |
|---|---|---|---|
listDocuments | params?: ListDocumentsParams | { references, totalCount } | List documents with pagination |
createDocument | document: Partial<DocReference> | DocReference | null | Create a document reference |
updateDocument | referenceId: string, updates: Partial<DocReference> | DocReference | null | Update a document |
deleteDocument | referenceId: string | boolean | Delete a document |
moveDocument | referenceId: string, destination: {...} | DocReference | null | Move document to new location |
copyDocument | referenceId: string, destination: {...} | DocReference | null | Copy document to new location |
useProjects
Hook for Eloquent project CRUD operations with loading/error states.
import { useProjects } from "@elqnt/docs/hooks";
const {
loading,
error,
listProjects,
getProject,
createProject,
updateProject,
deleteProject,
persistProjectSources,
saveDocumentToProject,
} = useProjects({
baseUrl: apiGatewayUrl,
orgId: selectedOrgId,
});
// List projects with pagination
const { projects, totalCount, totalPages } = await listProjects({
page: 1,
pageSize: 20,
});
// Get project by ID
const project = await getProject("project-uuid");
// Create project
const newProject = await createProject({
name: "Q4 Analysis",
description: "Quarterly analysis project",
icon: "chart",
color: "#3b82f6",
});
// Update project
const updated = await updateProject("project-uuid", {
name: "Updated Project Name",
description: "New description",
});
// Delete project
const success = await deleteProject("project-uuid");
// Persist project sources (replace all sources)
const sourcesUpdated = await persistProjectSources("project-uuid", [
{ id: "src-1", type: "document", referenceId: "doc-uuid", name: "Report.pdf", addedAt: new Date().toISOString() },
{ id: "src-2", type: "library", referenceId: "lib-uuid", name: "Team Docs", addedAt: new Date().toISOString() },
{ id: "src-3", type: "kg", referenceId: "kg-uuid", name: "Knowledge Base", addedAt: new Date().toISOString() },
]);
// Add single document to project sources
const docAdded = await saveDocumentToProject("project-uuid", "doc-uuid");
Methods:
| Method | Parameters | Returns | Description |
|---|---|---|---|
listProjects | { page?, pageSize? } | ProjectsListResult | List projects with pagination |
getProject | projectId: string | EloquentProject | null | Get project by ID |
createProject | project: Partial<EloquentProject> | EloquentProject | null | Create a new project |
updateProject | projectId: string, updates: Partial<EloquentProject> | EloquentProject | null | Update a project |
deleteProject | projectId: string | boolean | Delete a project |
persistProjectSources | projectId: string, sources: ProjectSource[] | boolean | Replace all project sources |
saveDocumentToProject | projectId: string, documentId: string | boolean | Add document to project sources |
ProjectsListResult:
interface ProjectsListResult {
projects: EloquentProject[];
totalCount: number;
currentPage: number;
pageSize: number;
totalPages: number;
}
Document Analysis API
Functions for AI-powered document analysis (not CRUD, so exposed as API functions).
import { getRawDocumentAnalysisApi } from "@elqnt/docs/api";
// Analyze document with AI
const analysis = await getRawDocumentAnalysisApi(
{
fileUrl: "https://storage.example.com/document.pdf",
model: "claude-3-haiku-20240307",
fromPage: 1,
toPage: 10,
outputMarkdown: true,
},
{
baseUrl: config.apiGatewayUrl,
orgId: config.orgId,
}
);
Transport Layer
Platform-agnostic transport abstractions for document analysis SSE streaming. Supports both browser (EventSource) and React Native (fetch-based) environments.
createAnalysisTransport (Browser)
SSE transport using native EventSource for browser environments.
import { createAnalysisTransport } from "@elqnt/docs/transport";
const transport = createAnalysisTransport({ debug: true });
await transport.connect({ baseUrl: "https://api.example.com", orgId: "org-123" });
// Subscribe to events
transport.on("progress", (event) => {
console.log(`Progress: ${event.percentage}% - ${event.message}`);
});
transport.on("completed", (event) => {
console.log("Analysis complete:", event.result);
});
transport.on("error", (event) => {
console.error("Analysis failed:", event.error);
});
// Start standard analysis
const jobId = await transport.startAnalysis({
documentUrl: "https://storage.example.com/document.pdf",
outputMarkdown: true,
});
// Or use smart analysis with AI processing
const smartJobId = await transport.startSmartAnalysis({
documentUrl: "https://storage.example.com/document.pdf",
title: "Financial Report Q4 2024",
metadata: { fileSize: 1024000, mimeType: "application/pdf" },
});
// Clean up when done
transport.disconnect();
createFetchAnalysisTransport (React Native)
Fetch-based SSE transport for React Native and environments without native EventSource.
import { createFetchAnalysisTransport } from "@elqnt/docs/transport";
// Use fetch-based transport for React Native
const transport = createFetchAnalysisTransport({
debug: true,
customFetch: fetch, // Optional: pass custom fetch implementation
analysisTimeout: 300000, // 5 minutes (default)
});
await transport.connect({ baseUrl, orgId });
transport.on("progress", (e) => console.log(`${e.percentage}%`));
transport.on("completed", (e) => console.log("Done:", e.result));
await transport.startSmartAnalysis({ documentUrl });
React Hook Integration
import { useState, useCallback } from "react";
import { createAnalysisTransport } from "@elqnt/docs/transport";
function useDocumentAnalysis(baseUrl: string, orgId: string) {
const [progress, setProgress] = useState(0);
const [result, setResult] = useState(null);
const [error, setError] = useState(null);
const [analyzing, setAnalyzing] = useState(false);
const analyze = useCallback(async (documentUrl: string) => {
const transport = createAnalysisTransport();
await transport.connect({ baseUrl, orgId });
setAnalyzing(true);
setProgress(0);
setError(null);
transport.on("progress", (e) => setProgress(e.percentage));
transport.on("completed", (e) => {
setResult(e.result);
setAnalyzing(false);
transport.disconnect();
});
transport.on("error", (e) => {
setError(e.error);
setAnalyzing(false);
transport.disconnect();
});
await transport.startSmartAnalysis({ documentUrl });
}, [baseUrl, orgId]);
return { analyze, progress, result, error, analyzing };
}
Transport Interface
interface AnalysisTransport {
connect(config: AnalysisTransportConfig): Promise<void>;
disconnect(): void;
startAnalysis(options: StartAnalysisOptions): Promise<string>;
startSmartAnalysis(options: StartSmartAnalysisOptions): Promise<string>;
onEvent(handler: EventHandler): Unsubscribe;
on<T extends AnalysisEvent["type"]>(eventType: T, handler: EventHandler<T>): Unsubscribe;
getState(): TransportState;
getMetrics(): ConnectionMetrics;
getError(): TransportError | undefined;
clearError(): void;
}
Transport States:
| State | Description |
|---|---|
disconnected | Not connected |
connecting | Connection in progress |
connected | Ready to start analysis |
analyzing | Analysis in progress |
Event Types:
| Event | Description |
|---|---|
progress | Progress update with percentage and message |
status | Processing status change |
started | Analysis job started |
completed | Analysis completed with result |
error | Analysis failed |
page_processed | Single page processed (multi-page docs) |
chunk_created | Chunk created (embedding strategy) |
Transport Types
import type {
AnalysisTransport,
AnalysisTransportConfig,
TransportState,
TransportError,
ConnectionMetrics,
AnalysisEvent,
AnalysisProgressEvent,
AnalysisCompletedEvent,
AnalysisErrorEvent,
StartAnalysisOptions,
StartSmartAnalysisOptions,
} from "@elqnt/docs/transport";
interface AnalysisTransportConfig {
baseUrl: string;
orgId: string;
userId?: string;
debug?: boolean;
}
interface StartAnalysisOptions {
documentUrl: string;
model?: string;
fromPage?: number;
toPage?: number;
outputMarkdown?: boolean;
}
interface StartSmartAnalysisOptions {
documentUrl: string;
title?: string;
metadata?: {
fileSize?: number;
mimeType?: string;
extension?: string;
};
strategy?: string;
}
interface AnalysisProgressEvent {
type: "progress";
timestamp: number;
jobId?: string;
percentage: number;
message: string;
currentStep?: string;
totalSteps?: number;
}
interface AnalysisCompletedEvent {
type: "completed";
timestamp: number;
jobId: string;
result: DocumentAnalysisResult | ProcessingResult;
}
interface TransportError {
code: "CONNECTION_FAILED" | "PARSE_ERROR" | "ANALYSIS_FAILED" | "TIMEOUT" | "NETWORK_ERROR" | "AUTH_FAILED";
message: string;
retryable: boolean;
timestamp: number;
}
Models
DocLibrary
import type { DocLibrary } from "@elqnt/docs/models";
interface DocLibrary {
id?: string;
name: string;
description: string;
icon: string;
color: string;
ownerEmail: string;
permissionLevel: string; // "user" | "team" | "public"
teamMembers: string[];
isDefault: boolean;
docCount: number;
folderCount: number;
totalSizeBytes: number;
createdAt: string;
updatedAt: string;
}
DocFolder
import type { DocFolder, FolderTreeNode } from "@elqnt/docs/models";
interface DocFolder {
id?: string;
libraryId: string;
parentFolderId: string; // Empty string = root
name: string;
path: string; // Full path: /folder1/folder2/
depth: number;
icon: string;
color: string;
inheritPermissions: boolean;
permissionLevel: string; // Only if !inheritPermissions
teamMembers: string[]; // Only if !inheritPermissions
ownerEmail: string;
docCount: number;
subfolderCount: number;
createdAt: string;
updatedAt: string;
}
interface FolderTreeNode {
folder: DocFolder;
children: FolderTreeNode[];
documents: DocReference[];
}
DocReference
import type { DocReference } from "@elqnt/docs/models";
interface DocReference {
id?: string;
docId: string; // References doc_metadata in ClickHouse
libraryId: string;
folderId: string; // Empty = library root
title: string;
docUrl: string;
fileSize: number;
mimeType: string;
ownerEmail: string;
status: string; // "processing" | "completed" | "failed"
createdAt: string;
updatedAt: string;
}
Project Types
import type {
EloquentProject,
ProjectSource,
ProjectChatSummary,
} from "@elqnt/docs/models";
interface EloquentProject {
id?: string;
name: string;
description: string;
icon: string;
color: string;
ownerEmail: string;
permissionLevel: string;
teamMembers: string[];
systemPrompt: string;
chatKeys: string[];
chats: ProjectChatSummary[];
libraryId: string;
linkedLibraryIds: string[];
sources: ProjectSource[];
chatCount: number;
sourceCount: number;
fileCount: number;
createdAt: string;
updatedAt: string;
}
interface ProjectSource {
id: string;
type: string; // "document" | "library" | "folder" | "kg" | "upload"
referenceId: string;
name: string;
addedAt: string;
}
interface ProjectChatSummary {
chatKey: string;
title: string;
agentName?: string;
agentId?: string;
createdAt: number;
}
Document Analysis Types
import type {
DocumentAnalysisProgressEvent,
DocumentAnalysisProgress,
DocumentAnalysisResultSSE,
SmartAnalysisRequest,
SmartAnalysisProgressEvent,
} from "@elqnt/docs/models";
interface DocumentAnalysisProgressEvent {
jobId: string;
type: string; // "started" | "extracting" | "extracted" | "chunking" | "chunked" | "embedding" | "storing" | "completed" | "error"
message: string;
progress?: DocumentAnalysisProgress;
result?: DocumentAnalysisResultSSE;
timestamp: string;
}
interface DocumentAnalysisProgress {
stage: string; // "extraction" | "chunking" | "embedding" | "storing"
currentStep: number;
totalSteps: number;
pageCount?: number;
chunksCreated?: number;
chunksEmbedded?: number;
percentComplete: number;
}
interface SmartAnalysisRequest {
url: string;
fileName: string;
metadata?: AttachmentFileMetadata;
chatKey?: string;
messageId?: string;
orgId?: string;
userEmail?: string;
}
Permission Levels
import {
PermissionUser,
PermissionTeam,
PermissionPublic,
} from "@elqnt/docs/models";
PermissionUser; // "user" - Only owner
PermissionTeam; // "team" - Owner + team members
PermissionPublic; // "public" - All org members
Progress Event Types
import {
ProgressTypeStarted,
ProgressTypeExtracting,
ProgressTypeExtracted,
ProgressTypeChunking,
ProgressTypeChunked,
ProgressTypeEmbedding,
ProgressTypeStoring,
ProgressTypeCompleted,
ProgressTypeError,
StageExtraction,
StageChunking,
StageEmbedding,
StageStoring,
} from "@elqnt/docs/models";
NATS Subjects
For backend service communication:
import {
// Library subjects
CreateLibrarySubject,
GetLibrarySubject,
UpdateLibrarySubject,
DeleteLibrarySubject,
QueryLibrariesSubject,
GetOrCreateDefaultLibrarySubject,
// Folder subjects
CreateFolderSubject,
GetFolderSubject,
UpdateFolderSubject,
DeleteFolderSubject,
QueryFoldersSubject,
GetFolderTreeSubject,
MoveFolderSubject,
CopyFolderSubject,
// Document subjects
CreateDocReferenceSubject,
UpdateDocReferenceSubject,
CopyDocReferenceSubject,
MoveDocumentSubject,
MoveDocumentsBulkSubject,
QueryDocReferencesSubject,
DeleteDocReferenceSubject,
TrashDocReferenceSubject,
RestoreDocReferenceSubject,
// Project subjects
CreateProjectSubject,
GetProjectSubject,
UpdateProjectSubject,
DeleteProjectSubject,
QueryProjectsSubject,
} from "@elqnt/docs/models";
API Gateway Routes
| Function | Method | Gateway Route |
|---|---|---|
| Libraries | ||
| List | GET | /api/v1/libraries |
| Get Default | GET | /api/v1/libraries/default |
| Get | GET | /api/v1/libraries/{libraryId} |
| Create | POST | /api/v1/libraries |
| Update | PUT | /api/v1/libraries/{libraryId} |
| Delete | DELETE | /api/v1/libraries/{libraryId} |
| Folders | ||
| List | GET | /api/v1/libraries/{libraryId}/folders |
| Create | POST | /api/v1/folders |
| Update | PUT | /api/v1/folders/{folderId} |
| Delete | DELETE | /api/v1/folders/{folderId} |
| Move | POST | /api/v1/folders/{folderId}/move |
| Copy | POST | /api/v1/folders/{folderId}/copy |
| Documents | ||
| List | GET | /api/v1/libraries/{libraryId}/documents |
| Create | POST | /api/v1/documents |
| Update | PUT | /api/v1/documents/{referenceId} |
| Delete | DELETE | /api/v1/documents/{referenceId} |
| Move | POST | /api/v1/documents/{referenceId}/move |
| Copy | POST | /api/v1/documents/{referenceId}/copy |
| Projects | ||
| List | GET | /api/v1/projects |
| Get | GET | /api/v1/projects/{projectId} |
| Create | POST | /api/v1/projects |
| Update | PUT | /api/v1/projects/{projectId} |
| Delete | DELETE | /api/v1/projects/{projectId} |
| Persist Sources | PUT | /api/v1/projects/{projectId}/sources |
| Add Document | POST | /api/v1/projects/{projectId}/sources/document |
| Analysis | ||
| Analyze | POST | /api/v1/documents/analyze |
| Start Analysis | POST | /api/v1/documents/analyze/start |
| Analysis Stream | GET | /api/v1/documents/analyze/stream |
| Start Smart Analysis | POST | /api/v1/documents/analyze/smart |
| Smart Analysis Stream | GET | /api/v1/documents/analyze/smart/stream |
Type Generation
Document types are generated from Go using tygo:
cd backend && tygo generate
| Go Package | TypeScript Output |
|---|---|
blazi/common/docs | @elqnt/docs/models/docs.ts |
blazi/services/doc-libraries/models | @elqnt/docs/models/document-libraries.ts |
See Also
- @elqnt/kg - Knowledge graph integration
- @elqnt/agents - Document tools for agents
- @elqnt/api-client - HTTP client used internally