@chittyos/chittycontextual-client
Version:
TypeScript client for ChittyContextul cross-source temporal intelligence platform
350 lines (348 loc) • 11.2 kB
JavaScript
// src/errors.ts
var ChittyContextualError = class _ChittyContextualError extends Error {
constructor(message, statusCode, response) {
super(message);
this.statusCode = statusCode;
this.response = response;
this.name = "ChittyContextualError";
Object.setPrototypeOf(this, _ChittyContextualError.prototype);
}
};
var NetworkError = class _NetworkError extends ChittyContextualError {
constructor(message, cause) {
super(`Network error: ${message}`, 0);
this.name = "NetworkError";
this.cause = cause;
Object.setPrototypeOf(this, _NetworkError.prototype);
}
};
var AuthenticationError = class _AuthenticationError extends ChittyContextualError {
constructor(message = "Authentication failed") {
super(message, 401);
this.name = "AuthenticationError";
Object.setPrototypeOf(this, _AuthenticationError.prototype);
}
};
var ValidationError = class _ValidationError extends ChittyContextualError {
constructor(message, errors) {
super(message, 400);
this.errors = errors;
this.name = "ValidationError";
Object.setPrototypeOf(this, _ValidationError.prototype);
}
};
var NotFoundError = class _NotFoundError extends ChittyContextualError {
constructor(resource) {
super(`Resource not found: ${resource}`, 404);
this.name = "NotFoundError";
Object.setPrototypeOf(this, _NotFoundError.prototype);
}
};
var RateLimitError = class _RateLimitError extends ChittyContextualError {
constructor(retryAfter, message = "Rate limit exceeded") {
super(message, 429);
this.retryAfter = retryAfter;
this.name = "RateLimitError";
Object.setPrototypeOf(this, _RateLimitError.prototype);
}
};
var ServerError = class _ServerError extends ChittyContextualError {
constructor(message = "Internal server error") {
super(message, 500);
this.name = "ServerError";
Object.setPrototypeOf(this, _ServerError.prototype);
}
};
var TimeoutError = class _TimeoutError extends ChittyContextualError {
constructor(timeoutMs) {
super(`Request timeout after ${timeoutMs}ms`, 0);
this.name = "TimeoutError";
Object.setPrototypeOf(this, _TimeoutError.prototype);
}
};
function handleResponseError(response, body) {
const message = body?.error || body?.message || response.statusText || "Unknown error";
switch (response.status) {
case 401:
case 403:
throw new AuthenticationError(message);
case 404:
throw new NotFoundError(message);
case 400:
throw new ValidationError(message, body?.errors);
case 429:
const retryAfter = response.headers.get("Retry-After");
throw new RateLimitError(
retryAfter ? parseInt(retryAfter, 10) : void 0,
message
);
case 500:
case 502:
case 503:
case 504:
throw new ServerError(message);
default:
throw new ChittyContextualError(message, response.status, body);
}
}
// src/client.ts
var ChittyContextualClient = class {
constructor(config = {}) {
// Messages API
this.messages = {
list: async (options) => {
const params = new URLSearchParams();
if (options?.limit) params.set("limit", options.limit.toString());
const query = params.toString() ? `?${params.toString()}` : "";
return this.request(`/api/messages${query}`);
},
search: async (params) => {
const queryParams = new URLSearchParams({ q: params.query });
if (params.timeRange) {
queryParams.set("start", this.formatDate(params.timeRange.start));
queryParams.set("end", this.formatDate(params.timeRange.end));
}
return this.request(
`/api/messages/search?${queryParams.toString()}`
);
},
timeline: async (params) => {
const queryParams = new URLSearchParams({
start: this.formatDate(params.start),
end: this.formatDate(params.end)
});
return this.request(
`/api/messages/timeline?${queryParams.toString()}`
);
}
};
// Documents API
this.documents = {
upload: async (files, onProgress) => {
const formData = new FormData();
files.forEach((file) => formData.append("files", file));
return new Promise((resolve, reject) => {
const xhr = new XMLHttpRequest();
if (onProgress) {
xhr.upload.addEventListener("progress", (e) => {
if (e.lengthComputable) {
const percentage = e.loaded / e.total * 100;
onProgress(percentage, e.loaded, e.total);
}
});
}
xhr.addEventListener("load", () => {
if (xhr.status >= 200 && xhr.status < 300) {
resolve(JSON.parse(xhr.responseText));
} else {
try {
const body = JSON.parse(xhr.responseText);
handleResponseError(
new Response(xhr.responseText, { status: xhr.status }),
body
);
} catch {
reject(
new NetworkError(`Upload failed with status ${xhr.status}`)
);
}
}
});
xhr.addEventListener("error", () => {
reject(new NetworkError("Upload failed"));
});
xhr.addEventListener("timeout", () => {
reject(new TimeoutError(this.timeout));
});
xhr.open("POST", `${this.baseUrl}/api/documents/upload`);
if (this.apiKey) {
xhr.setRequestHeader("Authorization", `Bearer ${this.apiKey}`);
}
xhr.timeout = this.timeout;
xhr.send(formData);
});
},
list: async () => {
return this.request("/api/documents");
}
};
// Topics API
this.topics = {
list: async () => {
return this.request("/api/topics");
},
analysis: async (timeRange) => {
const params = new URLSearchParams();
if (timeRange) {
params.set("start", this.formatDate(timeRange.start));
params.set("end", this.formatDate(timeRange.end));
}
const query = params.toString() ? `?${params.toString()}` : "";
return this.request(`/api/topics/analysis${query}`);
},
evolution: async (topicId, timeRange) => {
const params = new URLSearchParams({
start: this.formatDate(timeRange.start),
end: this.formatDate(timeRange.end)
});
return this.request(
`/api/topics/${topicId}/evolution?${params.toString()}`
);
}
};
// Entities API
this.entities = {
list: async () => {
return this.request("/api/entities");
},
extractions: async () => {
return this.request("/api/entities/extractions");
}
};
// Cross References API
this.crossReferences = {
list: async () => {
return this.request("/api/cross-references");
},
analyze: async (params) => {
return this.request(
"/api/cross-references/analyze",
{
method: "POST",
body: JSON.stringify({
start: this.formatDate(params.start),
end: this.formatDate(params.end)
})
}
);
}
};
// Analytics API
this.analytics = {
correlations: async () => {
return this.request("/api/analytics/correlations");
},
stats: async () => {
return this.request("/api/analytics/stats");
}
};
// Analysis API
this.analyze = {
bulk: async (params) => {
return this.request("/api/analyze/bulk", {
method: "POST",
body: JSON.stringify({
start: this.formatDate(params.start),
end: this.formatDate(params.end)
})
});
},
comprehensive: async (params) => {
return this.request(
"/api/analyze/comprehensive",
{
method: "POST",
body: JSON.stringify({
start: this.formatDate(params.start),
end: this.formatDate(params.end),
focusTopics: params.focusTopics,
focusParties: params.focusParties
})
}
);
}
};
// Intelligent Search API
this.search = {
intelligent: async (params) => {
const queryParams = new URLSearchParams({ q: params.q });
if (params.party) queryParams.set("party", params.party);
if (params.source) queryParams.set("source", params.source);
if (params.start) queryParams.set("start", this.formatDate(params.start));
if (params.end) queryParams.set("end", this.formatDate(params.end));
return this.request(
`/api/search/intelligent?${queryParams.toString()}`
);
}
};
// Party Learning API
this.parties = {
learn: async (params) => {
return this.request("/api/parties/learn", {
method: "POST",
body: JSON.stringify(params)
});
}
};
this.baseUrl = config.baseUrl || "http://localhost:5000";
this.apiKey = config.apiKey;
this.timeout = config.timeout || 3e4;
this.retryAttempts = config.retryAttempts || 3;
this.retryDelay = config.retryDelay || 1e3;
}
async request(endpoint, options = {}, attempt = 1) {
const url = `${this.baseUrl}${endpoint}`;
const headers = {
...options.headers
};
if (this.apiKey) {
headers["Authorization"] = `Bearer ${this.apiKey}`;
}
if (options.body && typeof options.body === "string") {
headers["Content-Type"] = "application/json";
}
const controller = new AbortController();
const timeoutId = setTimeout(() => controller.abort(), this.timeout);
try {
const response = await fetch(url, {
...options,
headers,
signal: controller.signal,
credentials: "include"
});
clearTimeout(timeoutId);
if (!response.ok) {
let body;
try {
body = await response.json();
} catch {
body = await response.text();
}
handleResponseError(response, body);
}
return await response.json();
} catch (error) {
clearTimeout(timeoutId);
if (error.name === "AbortError") {
throw new TimeoutError(this.timeout);
}
if (attempt < this.retryAttempts && (error instanceof NetworkError || error.name === "TypeError")) {
await new Promise(
(resolve) => setTimeout(resolve, this.retryDelay * attempt)
);
return this.request(endpoint, options, attempt + 1);
}
if (error.name === "TypeError") {
throw new NetworkError("Failed to fetch", error);
}
throw error;
}
}
formatDate(date) {
if (typeof date === "string") return date;
return date.toISOString();
}
};
export {
AuthenticationError,
ChittyContextualClient,
ChittyContextualError,
NetworkError,
NotFoundError,
RateLimitError,
ServerError,
TimeoutError,
ValidationError,
ChittyContextualClient as default,
handleResponseError
};