Phase 2 build initial
This commit is contained in:
77
sdks/javascript/package.json
Normal file
77
sdks/javascript/package.json
Normal file
@@ -0,0 +1,77 @@
|
||||
{
|
||||
"name": "@hcfs/sdk",
|
||||
"version": "2.0.0",
|
||||
"description": "JavaScript/TypeScript SDK for the Context-Aware Hierarchical Context File System",
|
||||
"main": "dist/index.js",
|
||||
"module": "dist/index.esm.js",
|
||||
"types": "dist/index.d.ts",
|
||||
"files": [
|
||||
"dist"
|
||||
],
|
||||
"scripts": {
|
||||
"build": "rollup -c",
|
||||
"dev": "rollup -c -w",
|
||||
"test": "jest",
|
||||
"test:watch": "jest --watch",
|
||||
"test:coverage": "jest --coverage",
|
||||
"lint": "eslint src --ext .ts,.js",
|
||||
"lint:fix": "eslint src --ext .ts,.js --fix",
|
||||
"typecheck": "tsc --noEmit",
|
||||
"docs": "typedoc src/index.ts",
|
||||
"prepublishOnly": "npm run build"
|
||||
},
|
||||
"keywords": [
|
||||
"hcfs",
|
||||
"context",
|
||||
"ai",
|
||||
"search",
|
||||
"embeddings",
|
||||
"typescript",
|
||||
"javascript",
|
||||
"sdk"
|
||||
],
|
||||
"author": "HCFS Development Team <dev@hcfs.dev>",
|
||||
"license": "MIT",
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "https://github.com/hcfs/hcfs.git",
|
||||
"directory": "sdks/javascript"
|
||||
},
|
||||
"bugs": {
|
||||
"url": "https://github.com/hcfs/hcfs/issues"
|
||||
},
|
||||
"homepage": "https://docs.hcfs.dev/sdk/javascript",
|
||||
"engines": {
|
||||
"node": ">=14.0.0"
|
||||
},
|
||||
"dependencies": {
|
||||
"axios": "^1.6.0",
|
||||
"ws": "^8.14.0",
|
||||
"eventemitter3": "^5.0.1"
|
||||
},
|
||||
"devDependencies": {
|
||||
"@types/jest": "^29.5.0",
|
||||
"@types/node": "^20.0.0",
|
||||
"@types/ws": "^8.5.0",
|
||||
"@typescript-eslint/eslint-plugin": "^6.0.0",
|
||||
"@typescript-eslint/parser": "^6.0.0",
|
||||
"eslint": "^8.50.0",
|
||||
"jest": "^29.7.0",
|
||||
"rollup": "^4.0.0",
|
||||
"@rollup/plugin-typescript": "^11.1.0",
|
||||
"@rollup/plugin-node-resolve": "^15.2.0",
|
||||
"@rollup/plugin-commonjs": "^25.0.0",
|
||||
"rollup-plugin-dts": "^6.1.0",
|
||||
"ts-jest": "^29.1.0",
|
||||
"typescript": "^5.2.0",
|
||||
"typedoc": "^0.25.0"
|
||||
},
|
||||
"peerDependencies": {
|
||||
"typescript": ">=4.5.0"
|
||||
},
|
||||
"peerDependenciesMeta": {
|
||||
"typescript": {
|
||||
"optional": true
|
||||
}
|
||||
}
|
||||
}
|
||||
574
sdks/javascript/src/client.ts
Normal file
574
sdks/javascript/src/client.ts
Normal file
@@ -0,0 +1,574 @@
|
||||
/**
|
||||
* HCFS JavaScript/TypeScript Client
|
||||
*
|
||||
* Main client class for interacting with the HCFS API
|
||||
*/
|
||||
|
||||
import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from 'axios';
|
||||
import { EventEmitter } from 'eventemitter3';
|
||||
|
||||
import {
|
||||
HCFSConfig,
|
||||
Context,
|
||||
ContextCreate,
|
||||
ContextUpdate,
|
||||
ContextFilter,
|
||||
PaginationOptions,
|
||||
SearchOptions,
|
||||
SearchResult,
|
||||
BatchResult,
|
||||
AnalyticsData,
|
||||
APIResponse,
|
||||
ListResponse,
|
||||
SearchResponse,
|
||||
HealthResponse,
|
||||
StatsResponse,
|
||||
RequestOptions,
|
||||
HttpMethod
|
||||
} from './types';
|
||||
|
||||
import {
|
||||
HCFSError,
|
||||
HCFSConnectionError,
|
||||
HCFSAuthenticationError,
|
||||
HCFSNotFoundError,
|
||||
HCFSValidationError,
|
||||
HCFSRateLimitError,
|
||||
HCFSServerError
|
||||
} from './errors';
|
||||
|
||||
import { LRUCache } from './cache';
|
||||
import { RetryManager } from './retry';
|
||||
import { validatePath, normalizePath } from './utils';
|
||||
|
||||
/**
|
||||
* Main HCFS client for JavaScript/TypeScript applications
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* const client = new HCFSClient({
|
||||
* baseUrl: 'https://api.hcfs.dev/v1',
|
||||
* apiKey: 'your-api-key',
|
||||
* timeout: 30000,
|
||||
* cache: { enabled: true, maxSize: 1000 }
|
||||
* });
|
||||
*
|
||||
* // Create a context
|
||||
* const context = await client.createContext({
|
||||
* path: '/docs/readme',
|
||||
* content: 'Hello, HCFS!',
|
||||
* summary: 'Getting started'
|
||||
* });
|
||||
*
|
||||
* // Search contexts
|
||||
* const results = await client.searchContexts('hello world', {
|
||||
* searchType: 'semantic',
|
||||
* topK: 10
|
||||
* });
|
||||
* ```
|
||||
*/
|
||||
export class HCFSClient extends EventEmitter {
|
||||
private readonly config: Required<HCFSConfig>;
|
||||
private readonly httpClient: AxiosInstance;
|
||||
private readonly cache?: LRUCache<any>;
|
||||
private readonly retryManager: RetryManager;
|
||||
private readonly analytics: AnalyticsData;
|
||||
|
||||
constructor(config: HCFSConfig) {
|
||||
super();
|
||||
|
||||
// Merge with defaults
|
||||
this.config = {
|
||||
baseUrl: config.baseUrl,
|
||||
apiKey: config.apiKey,
|
||||
jwtToken: config.jwtToken,
|
||||
timeout: config.timeout ?? 30000,
|
||||
userAgent: config.userAgent ?? `@hcfs/sdk/2.0.0`,
|
||||
|
||||
cache: {
|
||||
enabled: config.cache?.enabled ?? true,
|
||||
strategy: config.cache?.strategy ?? 'lru',
|
||||
maxSize: config.cache?.maxSize ?? 1000,
|
||||
ttl: config.cache?.ttl ?? 3600000,
|
||||
memoryLimit: config.cache?.memoryLimit ?? 100,
|
||||
...config.cache
|
||||
},
|
||||
|
||||
retry: {
|
||||
enabled: config.retry?.enabled ?? true,
|
||||
maxAttempts: config.retry?.maxAttempts ?? 3,
|
||||
baseDelay: config.retry?.baseDelay ?? 1000,
|
||||
maxDelay: config.retry?.maxDelay ?? 30000,
|
||||
backoffMultiplier: config.retry?.backoffMultiplier ?? 2,
|
||||
jitter: config.retry?.jitter ?? true,
|
||||
retryOnStatus: config.retry?.retryOnStatus ?? [429, 500, 502, 503, 504],
|
||||
retryOnTimeout: config.retry?.retryOnTimeout ?? true,
|
||||
...config.retry
|
||||
},
|
||||
|
||||
websocket: {
|
||||
autoReconnect: config.websocket?.autoReconnect ?? true,
|
||||
reconnectInterval: config.websocket?.reconnectInterval ?? 5000,
|
||||
maxReconnectAttempts: config.websocket?.maxReconnectAttempts ?? 10,
|
||||
pingInterval: config.websocket?.pingInterval ?? 30000,
|
||||
pingTimeout: config.websocket?.pingTimeout ?? 10000,
|
||||
messageQueueSize: config.websocket?.messageQueueSize ?? 1000,
|
||||
...config.websocket
|
||||
},
|
||||
|
||||
maxConcurrentRequests: config.maxConcurrentRequests ?? 100,
|
||||
keepAlive: config.keepAlive ?? true
|
||||
};
|
||||
|
||||
// Initialize HTTP client
|
||||
this.httpClient = axios.create({
|
||||
baseURL: this.config.baseUrl,
|
||||
timeout: this.config.timeout,
|
||||
headers: {
|
||||
'User-Agent': this.config.userAgent,
|
||||
'Content-Type': 'application/json',
|
||||
...(this.config.apiKey && { 'X-API-Key': this.config.apiKey }),
|
||||
...(this.config.jwtToken && { 'Authorization': `Bearer ${this.config.jwtToken}` })
|
||||
}
|
||||
});
|
||||
|
||||
// Initialize cache
|
||||
if (this.config.cache.enabled) {
|
||||
this.cache = new LRUCache(this.config.cache.maxSize, this.config.cache.ttl);
|
||||
}
|
||||
|
||||
// Initialize retry manager
|
||||
this.retryManager = new RetryManager(this.config.retry);
|
||||
|
||||
// Initialize analytics
|
||||
this.analytics = {
|
||||
operationCount: {},
|
||||
cacheStats: {},
|
||||
errorStats: {},
|
||||
performanceStats: {},
|
||||
sessionStart: new Date()
|
||||
};
|
||||
|
||||
// Setup request/response interceptors
|
||||
this.setupInterceptors();
|
||||
}
|
||||
|
||||
/**
|
||||
* Setup axios interceptors for error handling and monitoring
|
||||
*/
|
||||
private setupInterceptors(): void {
|
||||
// Request interceptor
|
||||
this.httpClient.interceptors.request.use(
|
||||
(config) => {
|
||||
// Track request
|
||||
const operation = `${config.method?.toUpperCase()} ${config.url}`;
|
||||
this.updateAnalytics(operation, true);
|
||||
|
||||
this.emit('request', { method: config.method, url: config.url });
|
||||
return config;
|
||||
},
|
||||
(error) => {
|
||||
this.updateAnalytics('request_error', false, error.message);
|
||||
return Promise.reject(error);
|
||||
}
|
||||
);
|
||||
|
||||
// Response interceptor
|
||||
this.httpClient.interceptors.response.use(
|
||||
(response) => {
|
||||
this.emit('response', {
|
||||
status: response.status,
|
||||
url: response.config.url,
|
||||
duration: Date.now() - (response.config as any).startTime
|
||||
});
|
||||
return response;
|
||||
},
|
||||
(error) => {
|
||||
const operation = `${error.config?.method?.toUpperCase()} ${error.config?.url}`;
|
||||
this.updateAnalytics(operation, false, error.message);
|
||||
|
||||
this.emit('error', {
|
||||
status: error.response?.status,
|
||||
message: error.message,
|
||||
url: error.config?.url
|
||||
});
|
||||
|
||||
return Promise.reject(this.handleApiError(error));
|
||||
}
|
||||
);
|
||||
}
|
||||
|
||||
/**
|
||||
* Handle API errors and convert to appropriate HCFS error types
|
||||
*/
|
||||
private handleApiError(error: any): HCFSError {
|
||||
if (error.code === 'ECONNABORTED' || error.code === 'ENOTFOUND') {
|
||||
return new HCFSConnectionError(`Connection failed: ${error.message}`);
|
||||
}
|
||||
|
||||
if (!error.response) {
|
||||
return new HCFSConnectionError(`Network error: ${error.message}`);
|
||||
}
|
||||
|
||||
const { status, data } = error.response;
|
||||
|
||||
switch (status) {
|
||||
case 400:
|
||||
return new HCFSValidationError(
|
||||
data.error || 'Validation failed',
|
||||
data.errorDetails || []
|
||||
);
|
||||
case 401:
|
||||
return new HCFSAuthenticationError(data.error || 'Authentication failed');
|
||||
case 404:
|
||||
return new HCFSNotFoundError(data.error || 'Resource not found');
|
||||
case 429:
|
||||
const retryAfter = error.response.headers['retry-after'];
|
||||
return new HCFSRateLimitError(
|
||||
data.error || 'Rate limit exceeded',
|
||||
retryAfter ? parseInt(retryAfter) : undefined
|
||||
);
|
||||
case 500:
|
||||
case 502:
|
||||
case 503:
|
||||
case 504:
|
||||
return new HCFSServerError(data.error || 'Server error', status);
|
||||
default:
|
||||
return new HCFSError(data.error || `HTTP ${status} error`, status.toString());
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Make an HTTP request with retry logic and caching
|
||||
*/
|
||||
private async request<T>(options: RequestOptions): Promise<T> {
|
||||
const cacheKey = this.getCacheKey(options);
|
||||
|
||||
// Try cache first for GET requests
|
||||
if (options.method === 'GET' && this.cache && cacheKey) {
|
||||
const cached = this.cache.get(cacheKey);
|
||||
if (cached) {
|
||||
this.analytics.cacheStats.hits = (this.analytics.cacheStats.hits || 0) + 1;
|
||||
return cached;
|
||||
}
|
||||
this.analytics.cacheStats.misses = (this.analytics.cacheStats.misses || 0) + 1;
|
||||
}
|
||||
|
||||
// Make request with retry logic
|
||||
const response = await this.retryManager.execute(async () => {
|
||||
const axiosConfig: AxiosRequestConfig = {
|
||||
method: options.method,
|
||||
url: options.url,
|
||||
data: options.data,
|
||||
params: options.params,
|
||||
headers: options.headers,
|
||||
timeout: options.timeout || this.config.timeout,
|
||||
startTime: Date.now()
|
||||
} as any;
|
||||
|
||||
return this.httpClient.request<APIResponse<T>>(axiosConfig);
|
||||
});
|
||||
|
||||
const result = response.data.data;
|
||||
|
||||
// Cache GET responses
|
||||
if (options.method === 'GET' && this.cache && cacheKey) {
|
||||
this.cache.set(cacheKey, result);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
/**
|
||||
* Generate cache key for request
|
||||
*/
|
||||
private getCacheKey(options: RequestOptions): string | null {
|
||||
if (options.method !== 'GET') return null;
|
||||
|
||||
const params = options.params ? JSON.stringify(options.params) : '';
|
||||
return `${options.url}:${params}`;
|
||||
}
|
||||
|
||||
/**
|
||||
* Update analytics tracking
|
||||
*/
|
||||
private updateAnalytics(operation: string, success: boolean, error?: string): void {
|
||||
this.analytics.operationCount[operation] = (this.analytics.operationCount[operation] || 0) + 1;
|
||||
|
||||
if (!success && error) {
|
||||
this.analytics.errorStats[error] = (this.analytics.errorStats[error] || 0) + 1;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Check API health status
|
||||
*/
|
||||
async healthCheck(): Promise<HealthResponse> {
|
||||
return this.request({
|
||||
method: 'GET',
|
||||
url: '/health'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Create a new context
|
||||
*/
|
||||
async createContext(contextData: ContextCreate): Promise<Context> {
|
||||
if (!validatePath(contextData.path)) {
|
||||
throw new HCFSValidationError(`Invalid context path: ${contextData.path}`);
|
||||
}
|
||||
|
||||
const normalizedData = {
|
||||
...contextData,
|
||||
path: normalizePath(contextData.path)
|
||||
};
|
||||
|
||||
const context = await this.request<Context>({
|
||||
method: 'POST',
|
||||
url: '/api/v1/contexts',
|
||||
data: normalizedData
|
||||
});
|
||||
|
||||
// Invalidate relevant cache entries
|
||||
this.invalidateCache('/api/v1/contexts');
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Get a context by ID
|
||||
*/
|
||||
async getContext(contextId: number): Promise<Context> {
|
||||
return this.request<Context>({
|
||||
method: 'GET',
|
||||
url: `/api/v1/contexts/${contextId}`
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* List contexts with filtering and pagination
|
||||
*/
|
||||
async listContexts(
|
||||
filter?: ContextFilter,
|
||||
pagination?: PaginationOptions
|
||||
): Promise<{ contexts: Context[]; pagination: any }> {
|
||||
const params: Record<string, any> = {};
|
||||
|
||||
// Add filter parameters
|
||||
if (filter) {
|
||||
if (filter.pathPrefix) params.path_prefix = filter.pathPrefix;
|
||||
if (filter.author) params.author = filter.author;
|
||||
if (filter.status) params.status = filter.status;
|
||||
if (filter.createdAfter) params.created_after = filter.createdAfter.toISOString();
|
||||
if (filter.createdBefore) params.created_before = filter.createdBefore.toISOString();
|
||||
if (filter.contentContains) params.content_contains = filter.contentContains;
|
||||
if (filter.minContentLength) params.min_content_length = filter.minContentLength;
|
||||
if (filter.maxContentLength) params.max_content_length = filter.maxContentLength;
|
||||
}
|
||||
|
||||
// Add pagination parameters
|
||||
if (pagination) {
|
||||
if (pagination.page) params.page = pagination.page;
|
||||
if (pagination.pageSize) params.page_size = pagination.pageSize;
|
||||
if (pagination.sortBy) params.sort_by = pagination.sortBy;
|
||||
if (pagination.sortOrder) params.sort_order = pagination.sortOrder;
|
||||
}
|
||||
|
||||
const response = await this.httpClient.get<ListResponse<Context>>('/api/v1/contexts', { params });
|
||||
|
||||
return {
|
||||
contexts: response.data.data,
|
||||
pagination: response.data.pagination
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Update an existing context
|
||||
*/
|
||||
async updateContext(contextId: number, updates: ContextUpdate): Promise<Context> {
|
||||
const context = await this.request<Context>({
|
||||
method: 'PUT',
|
||||
url: `/api/v1/contexts/${contextId}`,
|
||||
data: updates
|
||||
});
|
||||
|
||||
// Invalidate cache
|
||||
this.invalidateCache(`/api/v1/contexts/${contextId}`);
|
||||
this.invalidateCache('/api/v1/contexts');
|
||||
|
||||
return context;
|
||||
}
|
||||
|
||||
/**
|
||||
* Delete a context
|
||||
*/
|
||||
async deleteContext(contextId: number): Promise<void> {
|
||||
await this.request({
|
||||
method: 'DELETE',
|
||||
url: `/api/v1/contexts/${contextId}`
|
||||
});
|
||||
|
||||
// Invalidate cache
|
||||
this.invalidateCache(`/api/v1/contexts/${contextId}`);
|
||||
this.invalidateCache('/api/v1/contexts');
|
||||
}
|
||||
|
||||
/**
|
||||
* Search contexts
|
||||
*/
|
||||
async searchContexts(
|
||||
query: string,
|
||||
options?: SearchOptions
|
||||
): Promise<SearchResult[]> {
|
||||
const searchData = {
|
||||
query,
|
||||
search_type: options?.searchType || 'semantic',
|
||||
top_k: options?.topK || 10,
|
||||
similarity_threshold: options?.similarityThreshold || 0.0,
|
||||
path_prefix: options?.pathPrefix,
|
||||
semantic_weight: options?.semanticWeight || 0.7,
|
||||
include_content: options?.includeContent ?? true,
|
||||
include_highlights: options?.includeHighlights ?? true,
|
||||
max_highlights: options?.maxHighlights || 3
|
||||
};
|
||||
|
||||
const response = await this.httpClient.post<SearchResponse>('/api/v1/search', searchData);
|
||||
return response.data.data;
|
||||
}
|
||||
|
||||
/**
|
||||
* Create multiple contexts in batch
|
||||
*/
|
||||
async batchCreateContexts(contexts: ContextCreate[]): Promise<BatchResult> {
|
||||
const startTime = Date.now();
|
||||
|
||||
// Validate all contexts
|
||||
for (const context of contexts) {
|
||||
if (!validatePath(context.path)) {
|
||||
throw new HCFSValidationError(`Invalid context path: ${context.path}`);
|
||||
}
|
||||
}
|
||||
|
||||
const normalizedContexts = contexts.map(ctx => ({
|
||||
...ctx,
|
||||
path: normalizePath(ctx.path)
|
||||
}));
|
||||
|
||||
const response = await this.httpClient.post('/api/v1/contexts/batch', {
|
||||
contexts: normalizedContexts
|
||||
});
|
||||
|
||||
const executionTime = Date.now() - startTime;
|
||||
const result = response.data.data;
|
||||
|
||||
// Invalidate cache
|
||||
this.invalidateCache('/api/v1/contexts');
|
||||
|
||||
return {
|
||||
...result,
|
||||
executionTime,
|
||||
successRate: result.success_count / result.total_items
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get comprehensive statistics
|
||||
*/
|
||||
async getStatistics(): Promise<StatsResponse> {
|
||||
return this.request<StatsResponse>({
|
||||
method: 'GET',
|
||||
url: '/api/v1/stats'
|
||||
});
|
||||
}
|
||||
|
||||
/**
|
||||
* Iterate through all contexts with automatic pagination
|
||||
*/
|
||||
async *iterateContexts(
|
||||
filter?: ContextFilter,
|
||||
pageSize: number = 100
|
||||
): AsyncIterableIterator<Context> {
|
||||
let page = 1;
|
||||
|
||||
while (true) {
|
||||
const result = await this.listContexts(filter, { page, pageSize });
|
||||
|
||||
if (result.contexts.length === 0) {
|
||||
break;
|
||||
}
|
||||
|
||||
for (const context of result.contexts) {
|
||||
yield context;
|
||||
}
|
||||
|
||||
// If we got fewer contexts than requested, we've reached the end
|
||||
if (result.contexts.length < pageSize) {
|
||||
break;
|
||||
}
|
||||
|
||||
page++;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Clear cache
|
||||
*/
|
||||
clearCache(): void {
|
||||
if (this.cache) {
|
||||
this.cache.clear();
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Invalidate cache entries matching a pattern
|
||||
*/
|
||||
private invalidateCache(pattern: string): void {
|
||||
if (!this.cache) return;
|
||||
|
||||
// Simple pattern matching - remove entries that start with the pattern
|
||||
const keys = this.cache.keys();
|
||||
for (const key of keys) {
|
||||
if (key.startsWith(pattern)) {
|
||||
this.cache.delete(key);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* Get cache statistics
|
||||
*/
|
||||
getCacheStats(): Record<string, any> {
|
||||
if (!this.cache) {
|
||||
return { enabled: false };
|
||||
}
|
||||
|
||||
return {
|
||||
enabled: true,
|
||||
size: this.cache.size,
|
||||
maxSize: this.cache.maxSize,
|
||||
hitRate: this.analytics.cacheStats.hits /
|
||||
(this.analytics.cacheStats.hits + this.analytics.cacheStats.misses) || 0,
|
||||
...this.analytics.cacheStats
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Get client analytics
|
||||
*/
|
||||
getAnalytics(): AnalyticsData {
|
||||
return {
|
||||
...this.analytics,
|
||||
cacheStats: this.getCacheStats()
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Close the client and cleanup resources
|
||||
*/
|
||||
close(): void {
|
||||
this.removeAllListeners();
|
||||
if (this.cache) {
|
||||
this.cache.clear();
|
||||
}
|
||||
}
|
||||
}
|
||||
70
sdks/javascript/src/index.ts
Normal file
70
sdks/javascript/src/index.ts
Normal file
@@ -0,0 +1,70 @@
|
||||
/**
|
||||
* HCFS JavaScript/TypeScript SDK
|
||||
*
|
||||
* A comprehensive SDK for interacting with the HCFS API from JavaScript and TypeScript applications.
|
||||
* Supports both Node.js and browser environments with full TypeScript support.
|
||||
*
|
||||
* @example
|
||||
* ```typescript
|
||||
* import { HCFSClient, Context } from '@hcfs/sdk';
|
||||
*
|
||||
* const client = new HCFSClient({
|
||||
* baseUrl: 'https://api.hcfs.dev/v1',
|
||||
* apiKey: 'your-api-key'
|
||||
* });
|
||||
*
|
||||
* const context = new Context({
|
||||
* path: '/docs/readme',
|
||||
* content: 'Hello, HCFS!',
|
||||
* summary: 'Getting started guide'
|
||||
* });
|
||||
*
|
||||
* const created = await client.createContext(context);
|
||||
* console.log(`Created context: ${created.id}`);
|
||||
* ```
|
||||
*/
|
||||
|
||||
export { HCFSClient } from './client';
|
||||
export { HCFSWebSocketClient } from './websocket';
|
||||
export {
|
||||
Context,
|
||||
SearchResult,
|
||||
ContextFilter,
|
||||
PaginationOptions,
|
||||
SearchOptions,
|
||||
HCFSConfig,
|
||||
BatchResult,
|
||||
AnalyticsData
|
||||
} from './types';
|
||||
export {
|
||||
HCFSError,
|
||||
HCFSConnectionError,
|
||||
HCFSAuthenticationError,
|
||||
HCFSNotFoundError,
|
||||
HCFSValidationError,
|
||||
HCFSRateLimitError,
|
||||
HCFSServerError
|
||||
} from './errors';
|
||||
export { Cache, LRUCache } from './cache';
|
||||
export { RetryManager } from './retry';
|
||||
export {
|
||||
validatePath,
|
||||
normalizePath,
|
||||
textChunker,
|
||||
extractKeywords,
|
||||
contextSimilarity
|
||||
} from './utils';
|
||||
|
||||
// Version info
|
||||
export const VERSION = '2.0.0';
|
||||
|
||||
// Default configuration
|
||||
export const DEFAULT_CONFIG = {
|
||||
baseUrl: 'https://api.hcfs.dev/v1',
|
||||
timeout: 30000,
|
||||
retryAttempts: 3,
|
||||
retryDelay: 1000,
|
||||
cacheEnabled: true,
|
||||
cacheSize: 1000,
|
||||
cacheTTL: 3600000, // 1 hour
|
||||
} as const;
|
||||
449
sdks/javascript/src/types.ts
Normal file
449
sdks/javascript/src/types.ts
Normal file
@@ -0,0 +1,449 @@
|
||||
/**
|
||||
* TypeScript type definitions for HCFS SDK
|
||||
*/
|
||||
|
||||
/**
|
||||
* Context status enumeration
|
||||
*/
|
||||
export enum ContextStatus {
|
||||
ACTIVE = 'active',
|
||||
ARCHIVED = 'archived',
|
||||
DELETED = 'deleted',
|
||||
DRAFT = 'draft'
|
||||
}
|
||||
|
||||
/**
|
||||
* Search type enumeration
|
||||
*/
|
||||
export enum SearchType {
|
||||
SEMANTIC = 'semantic',
|
||||
KEYWORD = 'keyword',
|
||||
HYBRID = 'hybrid',
|
||||
FUZZY = 'fuzzy'
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache strategy enumeration
|
||||
*/
|
||||
export enum CacheStrategy {
|
||||
LRU = 'lru',
|
||||
LFU = 'lfu',
|
||||
TTL = 'ttl',
|
||||
FIFO = 'fifo'
|
||||
}
|
||||
|
||||
/**
|
||||
* Represents a context in the HCFS system
|
||||
*/
|
||||
export interface Context {
|
||||
/** Unique context identifier */
|
||||
id?: number;
|
||||
/** Hierarchical path of the context */
|
||||
path: string;
|
||||
/** Content of the context */
|
||||
content: string;
|
||||
/** Brief summary of the context */
|
||||
summary?: string;
|
||||
/** Author of the context */
|
||||
author?: string;
|
||||
/** Tags associated with the context */
|
||||
tags?: string[];
|
||||
/** Additional metadata */
|
||||
metadata?: Record<string, any>;
|
||||
/** Context status */
|
||||
status?: ContextStatus;
|
||||
/** Creation timestamp */
|
||||
createdAt?: Date;
|
||||
/** Last update timestamp */
|
||||
updatedAt?: Date;
|
||||
/** Context version number */
|
||||
version?: number;
|
||||
/** Similarity score (for search results) */
|
||||
similarityScore?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context creation data
|
||||
*/
|
||||
export interface ContextCreate {
|
||||
path: string;
|
||||
content: string;
|
||||
summary?: string;
|
||||
author?: string;
|
||||
tags?: string[];
|
||||
metadata?: Record<string, any>;
|
||||
}
|
||||
|
||||
/**
|
||||
* Context update data
|
||||
*/
|
||||
export interface ContextUpdate {
|
||||
content?: string;
|
||||
summary?: string;
|
||||
tags?: string[];
|
||||
metadata?: Record<string, any>;
|
||||
status?: ContextStatus;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search result containing context and relevance information
|
||||
*/
|
||||
export interface SearchResult {
|
||||
/** The context that matched the search */
|
||||
context: Context;
|
||||
/** Relevance score (0.0 to 1.0) */
|
||||
score: number;
|
||||
/** Explanation of why this result was returned */
|
||||
explanation?: string;
|
||||
/** Highlighted text snippets */
|
||||
highlights?: string[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Context filtering options
|
||||
*/
|
||||
export interface ContextFilter {
|
||||
/** Filter by path prefix */
|
||||
pathPrefix?: string;
|
||||
/** Filter by author */
|
||||
author?: string;
|
||||
/** Filter by status */
|
||||
status?: ContextStatus;
|
||||
/** Filter by tags */
|
||||
tags?: string[];
|
||||
/** Filter by creation date (after) */
|
||||
createdAfter?: Date;
|
||||
/** Filter by creation date (before) */
|
||||
createdBefore?: Date;
|
||||
/** Filter by content substring */
|
||||
contentContains?: string;
|
||||
/** Minimum content length */
|
||||
minContentLength?: number;
|
||||
/** Maximum content length */
|
||||
maxContentLength?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination options
|
||||
*/
|
||||
export interface PaginationOptions {
|
||||
/** Page number (starts from 1) */
|
||||
page?: number;
|
||||
/** Number of items per page */
|
||||
pageSize?: number;
|
||||
/** Sort field */
|
||||
sortBy?: string;
|
||||
/** Sort order */
|
||||
sortOrder?: 'asc' | 'desc';
|
||||
}
|
||||
|
||||
/**
|
||||
* Pagination metadata
|
||||
*/
|
||||
export interface PaginationMeta {
|
||||
page: number;
|
||||
pageSize: number;
|
||||
totalItems: number;
|
||||
totalPages: number;
|
||||
hasNext: boolean;
|
||||
hasPrevious: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search configuration options
|
||||
*/
|
||||
export interface SearchOptions {
|
||||
/** Type of search to perform */
|
||||
searchType?: SearchType;
|
||||
/** Maximum number of results */
|
||||
topK?: number;
|
||||
/** Minimum similarity score */
|
||||
similarityThreshold?: number;
|
||||
/** Search within path prefix */
|
||||
pathPrefix?: string;
|
||||
/** Weight for semantic search in hybrid mode */
|
||||
semanticWeight?: number;
|
||||
/** Include full content in results */
|
||||
includeContent?: boolean;
|
||||
/** Include text highlights */
|
||||
includeHighlights?: boolean;
|
||||
/** Maximum highlight snippets */
|
||||
maxHighlights?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache configuration
|
||||
*/
|
||||
export interface CacheConfig {
|
||||
/** Enable caching */
|
||||
enabled?: boolean;
|
||||
/** Cache eviction strategy */
|
||||
strategy?: CacheStrategy;
|
||||
/** Maximum cache entries */
|
||||
maxSize?: number;
|
||||
/** Time-to-live in milliseconds */
|
||||
ttl?: number;
|
||||
/** Memory limit in MB */
|
||||
memoryLimit?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Retry configuration
|
||||
*/
|
||||
export interface RetryConfig {
|
||||
/** Enable retry logic */
|
||||
enabled?: boolean;
|
||||
/** Maximum retry attempts */
|
||||
maxAttempts?: number;
|
||||
/** Base delay in milliseconds */
|
||||
baseDelay?: number;
|
||||
/** Maximum delay in milliseconds */
|
||||
maxDelay?: number;
|
||||
/** Backoff multiplier */
|
||||
backoffMultiplier?: number;
|
||||
/** Add random jitter to delays */
|
||||
jitter?: boolean;
|
||||
/** HTTP status codes to retry on */
|
||||
retryOnStatus?: number[];
|
||||
/** Retry on timeout errors */
|
||||
retryOnTimeout?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* WebSocket configuration
|
||||
*/
|
||||
export interface WebSocketConfig {
|
||||
/** Automatically reconnect on disconnect */
|
||||
autoReconnect?: boolean;
|
||||
/** Reconnect interval in milliseconds */
|
||||
reconnectInterval?: number;
|
||||
/** Maximum reconnection attempts */
|
||||
maxReconnectAttempts?: number;
|
||||
/** Ping interval in milliseconds */
|
||||
pingInterval?: number;
|
||||
/** Ping timeout in milliseconds */
|
||||
pingTimeout?: number;
|
||||
/** Maximum queued messages */
|
||||
messageQueueSize?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Main HCFS client configuration
|
||||
*/
|
||||
export interface HCFSConfig {
|
||||
/** HCFS API base URL */
|
||||
baseUrl: string;
|
||||
/** API key for authentication */
|
||||
apiKey?: string;
|
||||
/** JWT token for authentication */
|
||||
jwtToken?: string;
|
||||
/** Request timeout in milliseconds */
|
||||
timeout?: number;
|
||||
/** User agent string */
|
||||
userAgent?: string;
|
||||
|
||||
// Advanced configurations
|
||||
cache?: CacheConfig;
|
||||
retry?: RetryConfig;
|
||||
websocket?: WebSocketConfig;
|
||||
|
||||
// HTTP client options
|
||||
maxConcurrentRequests?: number;
|
||||
keepAlive?: boolean;
|
||||
}
|
||||
|
||||
/**
|
||||
* Batch operation result
|
||||
*/
|
||||
export interface BatchResult {
|
||||
/** Number of successful operations */
|
||||
successCount: number;
|
||||
/** Number of failed operations */
|
||||
errorCount: number;
|
||||
/** Total number of items processed */
|
||||
totalItems: number;
|
||||
/** Successfully created item IDs */
|
||||
successfulItems: any[];
|
||||
/** Failed items with error details */
|
||||
failedItems: Array<{
|
||||
index: number;
|
||||
item: any;
|
||||
error: string;
|
||||
}>;
|
||||
/** Execution time in milliseconds */
|
||||
executionTime: number;
|
||||
/** Success rate (0.0 to 1.0) */
|
||||
successRate: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Stream event from WebSocket
|
||||
*/
|
||||
export interface StreamEvent {
|
||||
/** Event type */
|
||||
eventType: string;
|
||||
/** Event data */
|
||||
data: any;
|
||||
/** Event timestamp */
|
||||
timestamp: Date;
|
||||
/** Related context ID */
|
||||
contextId?: number;
|
||||
/** Related context path */
|
||||
path?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Analytics and usage data
|
||||
*/
|
||||
export interface AnalyticsData {
|
||||
/** Operation counts */
|
||||
operationCount: Record<string, number>;
|
||||
/** Cache statistics */
|
||||
cacheStats: Record<string, any>;
|
||||
/** Error statistics */
|
||||
errorStats: Record<string, number>;
|
||||
/** Performance metrics */
|
||||
performanceStats: Record<string, number>;
|
||||
/** Session start time */
|
||||
sessionStart: Date;
|
||||
}
|
||||
|
||||
/**
|
||||
* API response wrapper
|
||||
*/
|
||||
export interface APIResponse<T> {
|
||||
success: boolean;
|
||||
data: T;
|
||||
timestamp: string;
|
||||
apiVersion: string;
|
||||
requestId?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* API error response
|
||||
*/
|
||||
export interface APIErrorResponse {
|
||||
success: false;
|
||||
error: string;
|
||||
errorDetails?: Array<{
|
||||
field?: string;
|
||||
message: string;
|
||||
code?: string;
|
||||
}>;
|
||||
timestamp: string;
|
||||
requestId?: string;
|
||||
apiVersion: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* List response with pagination
|
||||
*/
|
||||
export interface ListResponse<T> extends APIResponse<T[]> {
|
||||
pagination: PaginationMeta;
|
||||
}
|
||||
|
||||
/**
|
||||
* Search response
|
||||
*/
|
||||
export interface SearchResponse {
|
||||
success: boolean;
|
||||
data: SearchResult[];
|
||||
query: string;
|
||||
searchType: SearchType;
|
||||
totalResults: number;
|
||||
searchTimeMs: number;
|
||||
filtersApplied?: Record<string, any>;
|
||||
timestamp: string;
|
||||
apiVersion: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Health status
|
||||
*/
|
||||
export enum HealthStatus {
|
||||
HEALTHY = 'healthy',
|
||||
DEGRADED = 'degraded',
|
||||
UNHEALTHY = 'unhealthy'
|
||||
}
|
||||
|
||||
/**
|
||||
* Component health information
|
||||
*/
|
||||
export interface ComponentHealth {
|
||||
name: string;
|
||||
status: HealthStatus;
|
||||
responseTimeMs?: number;
|
||||
errorMessage?: string;
|
||||
}
|
||||
|
||||
/**
|
||||
* Health check response
|
||||
*/
|
||||
export interface HealthResponse {
|
||||
status: HealthStatus;
|
||||
version: string;
|
||||
uptimeSeconds: number;
|
||||
components: ComponentHealth[];
|
||||
}
|
||||
|
||||
/**
|
||||
* Statistics response
|
||||
*/
|
||||
export interface StatsResponse {
|
||||
contextStats: {
|
||||
totalContexts: number;
|
||||
contextsByStatus: Record<string, number>;
|
||||
contextsByAuthor: Record<string, number>;
|
||||
averageContentLength: number;
|
||||
mostActivePaths: string[];
|
||||
recentActivity: any[];
|
||||
};
|
||||
searchStats: {
|
||||
totalSearches: number;
|
||||
searchesByType: Record<string, number>;
|
||||
averageResponseTimeMs: number;
|
||||
popularQueries: string[];
|
||||
searchSuccessRate: number;
|
||||
};
|
||||
systemStats: {
|
||||
uptimeSeconds: number;
|
||||
memoryUsageMb: number;
|
||||
activeConnections: number;
|
||||
cacheHitRate: number;
|
||||
embeddingModelInfo: string;
|
||||
databaseSizeMb: number;
|
||||
};
|
||||
}
|
||||
|
||||
/**
|
||||
* Event listener function type
|
||||
*/
|
||||
export type EventListener<T = any> = (event: T) => void | Promise<void>;
|
||||
|
||||
/**
|
||||
* HTTP method types
|
||||
*/
|
||||
export type HttpMethod = 'GET' | 'POST' | 'PUT' | 'DELETE' | 'PATCH';
|
||||
|
||||
/**
|
||||
* Request options
|
||||
*/
|
||||
export interface RequestOptions {
|
||||
method: HttpMethod;
|
||||
url: string;
|
||||
data?: any;
|
||||
params?: Record<string, any>;
|
||||
headers?: Record<string, string>;
|
||||
timeout?: number;
|
||||
}
|
||||
|
||||
/**
|
||||
* Cache entry
|
||||
*/
|
||||
export interface CacheEntry<T = any> {
|
||||
key: string;
|
||||
value: T;
|
||||
timestamp: number;
|
||||
accessCount: number;
|
||||
ttl?: number;
|
||||
}
|
||||
Reference in New Issue
Block a user