From 79d943a8fa3b41a7c6d8600636250f2c72e1766d Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Fri, 6 Sep 2024 19:09:40 +0530 Subject: [PATCH 01/11] feat: updated types for v2 Signed-off-by: Adithya Krishna --- src/types.ts | 200 ++++++++++++++++++--------------------------------- 1 file changed, 70 insertions(+), 130 deletions(-) diff --git a/src/types.ts b/src/types.ts index 1478549..ed6bb30 100644 --- a/src/types.ts +++ b/src/types.ts @@ -1,175 +1,115 @@ -import ExtractionGraph from "./ExtractionGraph"; - -interface IBase { - id: string; - namespace: string; -} - -interface IMetadata extends IBase { - name: string; - labels: Record; - created_at: number; -} - -export interface INamespace { +export interface ComputeFn { name: string; - extraction_graphs: ExtractionGraph[]; -} - -export interface IEmbeddingSchema { - distance: string; - dim: number; -} - -export interface IExtractorSchema { - outputs: Record>; + fn_name: string; + description: string; } -export interface IExtractor { +export interface DynamicRouter { name: string; - input_mime_types: string[]; + source_fn: string; description: string; - input_params: Record; - outputs: IExtractorSchema; + target_fns: string[]; } -export interface ISchema extends IBase { - extraction_graph_name: string; - columns: Record< - string, - { - type: string; - comment?: string; - } - >; -} +export type Node = + | { dynamic_router: DynamicRouter } + | { compute_fn: ComputeFn }; -export interface IIndex { +export interface ComputeGraph { name: string; - schema: Record; -} - -export interface IBaseContentMetadata extends IMetadata { - parent_id: string; - ingested_content_id: string; - mime_type: string; - storage_url: string; - source: string; - size: number; - hash: string; - extraction_graph_names: string[]; + namespace: string; + description: string; + start_node: Node; + edges: Record; + created_at?: number; } -export interface IContentMetadata extends IBaseContentMetadata { - content_url: string; +export interface ComputeGraphCreateType { + compute_graph: ComputeGraph; + code: string; // This will be a file in the actual request } -export interface IExtractedMetadata extends IBase { - content_id: string; - metadata: Record; - extractor_name: string; +export interface ComputeGraphsList { + compute_graphs: ComputeGraph[]; + cursor?: string | null; } -export interface IExtractionPolicy { - id?: string; - extractor: string; +export interface CreateNamespace { name: string; - labels_eq?: string; - input_params?: Record; - content_source?: string; - graph_name?: string; } -export interface ITaskContentMetadata extends IMetadata { - parent_id: string; - root_content_id: string; - content_type: string; - storage_url: string; - source: string; - size_bytes: number; - tombstoned: boolean; - hash: string; - extraction_policy_ids: Record; +export interface DataObject { + id: string; + payload: any; + payload_size: number; + payload_sha_256: string; } -export enum TaskStatus { - Unknown = 0, - Failure = 1, - Success = 2, +export interface GraphInvocations { + invocations: DataObject[]; + cursor?: string | null; } -export interface ITask extends IBase { - extractor: string; - extraction_policy_id: string; - output_index_table_mapping: Record; - content_metadata: ITaskContentMetadata; - input_params: Record; - outcome: TaskStatus; - index_tables: string[]; +export interface IndexifyAPIError { + status_code: number; // Assuming StatusCode is a number + message: string; } -export interface IDocument { - text: string; - labels: Record; - id?: string; +export interface InvocationResult { + outputs: Record; + cursor?: string | null; } -export interface IFeature { - feature_type: "embedding" | "metadata" | "unknown"; +export interface Namespace { name: string; - data: Record; + created_at: number; } -export interface IContent { - content_type: string; - bytes: string | number[]; - features?: IFeature[]; - labels?: Record; +export interface NamespaceList { + namespaces: Namespace[]; } -export interface IContentResp extends Omit { - bytes: number[]; -} +export type TaskOutcome = "Unknown" | "Success" | "Failure"; -export interface IExtractResponse { - features: IFeature[]; - content: IContentResp[]; +export interface Task { + id: string; + status: TaskOutcome; + created_at: number; + updated_at: number; } -export interface ISearchIndexResponse { - content_id: string; - text: string; - confidence_score: number; - labels: Record; - content_metadata: IContentMetadata; - root_content_metadata?: IContentMetadata; +export interface Tasks { + tasks: Task[]; + cursor?: string | null; } -export interface IAddExtractorGraphResponse { - indexes: string[]; -} +// Additional types that were used in the IndexifyClient but not explicitly defined in the OpenAPI spec export interface IMtlsConfig { certPath: string; keyPath: string; - caPath?: string; // Optional, only if using a custom CA + caPath?: string; } -export interface StateChange extends IBase { - change_type: string; - created_at: number; - processed_at: number; - refcnt_object_id: string | null; -} - -export interface ExtractionPolicyStatus { - pending: number; - success: number; - failure: number; +export interface IDocument { + text: string; + labels: Record; + id?: string; } -export interface ExtractionGraphAnalytics { - task_analytics: { - [policyName: string]: ExtractionPolicyStatus; - }; +export interface IContentMetadata { + id: string; + parent_id?: string; + ingested_content_id: string; + namespace: string; + name: string; + mime_type: string; + labels: Record; + storage_url: string; + content_url: string; + created_at: number; + source: string; + size: number; + hash: string; + extraction_graph_names: string[]; } From 2ab30884c9c7bf8f488ac481f4a2c19f81c9d993 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Fri, 6 Sep 2024 20:46:40 +0530 Subject: [PATCH 02/11] feat: updated client for new API Signed-off-by: Adithya Krishna --- src/client.ts | 551 +------------------------------------------------- 1 file changed, 10 insertions(+), 541 deletions(-) diff --git a/src/client.ts b/src/client.ts index 16e8ca9..82b1a90 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,39 +1,29 @@ import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; -import Extractor from "./extractor"; import { IContentMetadata, - IExtractor, - IIndex, - INamespace, - ITask, - IAddExtractorGraphResponse, + Namespace as INamespace, + Task as ITask, IDocument, - ISearchIndexResponse, - IBaseContentMetadata, - ISchema, IMtlsConfig, - IContent, - IExtractResponse, - IExtractedMetadata, - ExtractionGraphAnalytics, + ComputeGraph, + CreateNamespace, + GraphInvocations, + InvocationResult, + Task, } from "./types"; import { v4 as uuidv4 } from "uuid"; import CryptoJS from "crypto-js"; -import ExtractionGraph from "./ExtractionGraph"; const DEFAULT_SERVICE_URL = "http://localhost:8900"; class IndexifyClient { private client: AxiosInstance; - private extractionGraphs: ExtractionGraph[]; constructor( public serviceUrl: string = DEFAULT_SERVICE_URL, public namespace: string = "default", - extractionGraphs: ExtractionGraph[], httpsAgent?: any ) { - this.extractionGraphs = extractionGraphs; this.client = axios.create({ baseURL: `${serviceUrl}/namespaces/${namespace}`, httpsAgent, @@ -52,7 +42,6 @@ class IndexifyClient { return new IndexifyClient( serviceUrl, namespace, - [], IndexifyClient.getHttpsAgent({ mtlsConfig }) ); } @@ -65,7 +54,7 @@ class IndexifyClient { try { return await this.client.request({ method, - url: `${this.serviceUrl}/${endpoint}`, + url: endpoint, ...options, }); } catch (error) { @@ -76,15 +65,6 @@ class IndexifyClient { } } - private baseContentToContentMetadata( - content: IBaseContentMetadata - ): IContentMetadata { - const content_url = content.storage_url.startsWith("http") - ? content.storage_url - : `${this.serviceUrl}/namespaces/${this.namespace}/content/${content.id}/download`; - return { ...content, content_url }; - } - static getHttpsAgent({ mtlsConfig }: { mtlsConfig?: IMtlsConfig }): any | undefined { if (!mtlsConfig) return undefined; if (typeof window !== "undefined") { @@ -108,517 +88,6 @@ class IndexifyClient { return this.request("POST", endpoint, { data }); } - async delete(endpoint: string, headers?: Record): Promise { - return this.request("DELETE", endpoint, { headers }); - } - - async put(endpoint: string, data: any, config?: AxiosRequestConfig): Promise { - return this.request("PUT", endpoint, { ...config, data }); - } - - static async namespaces({ - serviceUrl = DEFAULT_SERVICE_URL, - mtlsConfig, - }: { - serviceUrl?: string; - mtlsConfig?: IMtlsConfig; - } = {}): Promise { - const response = await axios.get(`${serviceUrl}/namespaces`, { - httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }), - }); - return response.data.namespaces; - } - - static async createNamespace({ - name, - extractionGraphs, - labels, - mtlsConfig, - }: { - name: string; - extractionGraphs?: ExtractionGraph[]; - labels?: Record; - mtlsConfig?: IMtlsConfig; - }) { - await axios.post( - `${DEFAULT_SERVICE_URL}/namespaces`, - { - name, - extraction_graphs: extractionGraphs ?? [], - labels: labels ?? {}, - }, - { httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }) } - ); - return IndexifyClient.createClient({ namespace: name }); - } - - async indexes(): Promise { - const resp = await this.client.get("indexes"); - return resp.data.indexes; - } - - async extractors(): Promise { - const response = await this.client.get(`${this.serviceUrl}/extractors`); - return (response.data.extractors as IExtractor[]).map((data) => new Extractor(data)); - } - - async searchIndex( - name: string, - query: string, - topK: number, - filters?: string[], - include_content: boolean = true - ): Promise { - const resp = await this.client.post(`/indexes/${name}/search`, { - query, - k: topK, - ...(filters !== undefined && { filters }), - include_content, - }); - return resp.data["results"]; - } - - async createExtractionGraph( - extractionGraph: ExtractionGraph - ): Promise { - const data = { - name: extractionGraph.name, - extraction_policies: extractionGraph.extraction_policies, - }; - const resp = await this.client.post("extraction_graphs", data); - await this.getExtractionGraphs(); - return resp.data; - } - - async getExtractedContent({ - contentId, - graphName, - policyName, - blocking = false - }: { - contentId: string; - graphName: string; - policyName: string; - blocking?: boolean; - }): Promise<{ contentList: IContentMetadata[]; total?: number }> { - if (blocking) { - await this.waitForExtraction(contentId); - } - - const response = await this.client.get( - `/extraction_graphs/${graphName}/extraction_policies/${policyName}/content/${contentId}`, - ); - - const contentList: IContentMetadata[] = response.data.content_tree_metadata - .filter((item: any) => item.extraction_graph_names.includes(graphName) && item.source === policyName) - .map((item: any) => this.baseContentToContentMetadata({ - id: item.id, - parent_id: item.parent_id, - ingested_content_id: contentId, - namespace: item.namespace, - name: item.name, - mime_type: item.mime_type, - labels: item.labels, - storage_url: item.storage_url, - created_at: item.created_at, - source: item.source, - size: item.size, - hash: item.hash, - extraction_graph_names: item.extraction_graph_names, - })); - - return { contentList }; - } - - async getExtractionPolicyContent({ - contentId, - graphName, - policyName, - }: { - contentId: string; - graphName: string; - policyName: string; - }): Promise { - const response = await this.client.get( - `extraction_graphs/${graphName}/content/${contentId}/extraction_policies/${policyName}`, - ); - - return response.data.content_tree_metadata - .filter((item: IContentMetadata) => - item.extraction_graph_names.includes(graphName) && item.source === policyName - ) - .map((item: IContentMetadata) => ({ - id: item.id, - parent_id: item.parent_id, - ingested_content_id: contentId, - namespace: item.namespace, - name: item.name, - mime_type: item.mime_type, - labels: item.labels, - storage_url: item.storage_url, - created_at: item.created_at, - source: item.source, - size: item.size, - hash: item.hash, - extraction_graph_names: item.extraction_graph_names, - })); - } - - async addDocuments( - extractionGraphs: string | string[], - documents: IDocument | string | (IDocument | string)[], - docId?: string - ): Promise { - const extractionGraphsArray = Array.isArray(extractionGraphs) ? extractionGraphs : [extractionGraphs]; - const documentsArray = Array.isArray(documents) ? documents : [documents]; - - const processedDocuments = documentsArray.map(doc => { - const processedDoc = typeof doc === 'string' ? { text: doc, labels: {}, id: docId } : doc; - processedDoc.labels['mime_type'] = 'text/plain'; - return processedDoc; - }); - - const contentIds: string[] = []; - - for (const extractionGraph of extractionGraphsArray) { - for (const document of processedDocuments) { - const formData = new FormData(); - formData.append('file', new Blob([document.text], { type: 'text/plain' }), 'document.txt'); - formData.append('labels', JSON.stringify(document.labels)); - - const response = await this.client.post( - `namespaces/${this.namespace}/extraction_graphs/${extractionGraph}/extract`, - formData, - { - headers: { - 'Content-Type': 'multipart/form-data', - }, - } - ); - - contentIds.push(response.data.content_id); - } - } - - return contentIds; - } - - async getContentMetadata(id: string): Promise { - const resp = await this.client.get(`content/${id}/metadata`); - return this.baseContentToContentMetadata(resp.data.content_metadata); - } - - async getStructuredMetadata(id: string): Promise { - const resp = await this.client.get(`content/${id}/metadata`); - return resp.data.metadata; - } - - async downloadContent(id: string): Promise { - try { - const response = await this.client.get(`content/${id}/download`); - return response.data; - } catch (error) { - throw new Error(`Failed to download content ${id}: ${error}`); - } + async delete(endpoint: string): Promise { + return this.request("DELETE", endpoint); } - - async getTasks( - extractionGraph: string, - extractionPolicy: string, - params?: { - namespace: string; - extractionGraph: string; - extractionPolicy: string; - contentId?: string; - outcome?: string; - startId?: string; - limit?: number; - returnTotal?: boolean; - } - ): Promise<{ tasks: ITask[], totalTasks?: number }> { - const defaultParams = { - namespace: this.namespace, - extraction_graph: extractionGraph, - extraction_policy: extractionPolicy, - return_total: false, - }; - - const mergedParams = { - ...defaultParams, - ...params, - namespace: params?.namespace || this.namespace, - extraction_graph: params?.extractionGraph || extractionGraph, - extraction_policy: params?.extractionPolicy || extractionPolicy, - content_id: params?.contentId, - start_id: params?.startId, - }; - - const response = await this.client.get( - `/extraction_graphs/${mergedParams.extraction_graph}/extraction_policies/${mergedParams.extraction_policy}/tasks`, - { params: mergedParams } - ); - - return { - tasks: response.data.tasks, - totalTasks: mergedParams.return_total ? response.data.total : undefined - }; - } - - async getSchemas(): Promise { - const resp = await this.client.get("schemas"); - return resp.data.schemas; - } - - async uploadFile( - extractionGraphNames: string, - fileInput: string | Blob, - labels: Record = {}, - newContentId?: string - ): Promise { - const isNodeEnv = typeof window === "undefined"; - let formData: any; - - if (isNodeEnv) { - if (typeof fileInput !== "string") { - throw Error("Expected string for file path in Node environment"); - } - const fs = require("fs"); - const FormData = require("form-data"); - formData = new FormData(); - formData.append("labels", JSON.stringify(labels)); - formData.append("file", fs.createReadStream(fileInput)); - } else { - if (!(fileInput instanceof Blob)) { - throw Error("Expected Blob in browser environment"); - } - formData = new FormData(); - formData.append("labels", JSON.stringify(labels)); - formData.append("file", fileInput); - } - - try { - const response = await this.client.post( - `/extraction_graphs/${extractionGraphNames}/extract`, - formData, - { - params: newContentId ? { id: newContentId } : undefined, - headers: { - "Content-Type": "multipart/form-data", - "accept": "*/*" - } - } - ); - - const contentId = response.data.content_id; - - if (contentId) { - console.log(`Content ID retrieved: ${contentId}`); - return contentId; - } else { - console.warn(`Unexpected: No content ID found in response for extraction graph: ${extractionGraphNames}`); - return ""; - } - } catch (error) { - console.error(`Error during extraction for graph ${extractionGraphNames}:`, error); - throw error; // Re-throw the error to be handled by the caller - } - } - - async getExtractionGraphs(): Promise { - const response = await this.client.get(`/extraction_graphs`); - return response.data.extraction_graphs ?? []; - } - - async extract({ - name, - input_params, - content: { content_type, bytes, features = [], labels = {} }, - }: { - name: string; - input_params?: Record; - content: IContent; - }): Promise { - const resp = await this.client.post( - `${DEFAULT_SERVICE_URL}/extractors/extract`, - { - name, - content: { - content_type, - bytes, - features, - labels, - }, - input_params: JSON.stringify(input_params), - } - ); - - return resp.data; - } - - async getExtractionGraphAnalytics({ - namespace, - extractionGraph, - }: { - namespace: string; - extractionGraph: string; - }): Promise { - const response = await this.client.get( - `/extraction_graphs/${extractionGraph}/analytics` - ); - - return response.data; - } - - async waitForExtraction(contentIds: string | string[]): Promise { - const ids = Array.isArray(contentIds) ? contentIds : [contentIds]; - - console.log("Waiting for extraction to complete for content id: ", ids.join(",")); - - for (const contentId of ids) { - try { - const response = await this.client.get( - `/content/${contentId}/wait` - ); - - console.log("Extraction completed for content id: ", contentId); - if (response.status >= 400) { - throw new Error(`HTTP error! status: ${response.status}`); - } - } catch (error) { - console.error(`Error waiting for extraction of content id ${contentId}:`, error); - throw error; - } - } - } - - async ingestRemoteFile( - url: string, - mime_type: string, - labels: Record, - extractionGraphNames: string | string[], - id?: string - ): Promise { - const extractionGraphNamesArray = Array.isArray(extractionGraphNames) - ? extractionGraphNames - : [extractionGraphNames]; - return this.client.post("ingest_remote_file", { - url, - mime_type, - labels, - extraction_graph_names: extractionGraphNamesArray, - id, - }); - } - - generateUniqueHexId(): string { - return uuidv4().replace(/-/g, "").substring(0, 16); - } - - generateHashFromString(inputString: string): string { - return CryptoJS.SHA256(inputString).toString(CryptoJS.enc.Hex).substring(0, 16); - } - - async deleteContent(namespace: string, contentId: string): Promise { - await this.delete(`namespaces/${namespace}/content/${contentId}`, { - "Content-Type": "application/json" - }); - } - - async deleteExtractionGraph(namespace: string, extractionGraph: string): Promise { - await this.delete(`namespaces/${namespace}/extraction_graphs/${extractionGraph}`, { - "Content-Type": "application/json" - }); - } - - async updateLabels(documentId: string, labels: Record): Promise { - await this.client.put( - `namespaces/${this.namespace}/content/${documentId}/labels`, - { labels }, - { headers: { "Content-Type": "application/json" } } - ); - } - - async updateContent(documentId: string, path: string): Promise { - const fs = require("fs"); - const formData = new FormData(); - formData.append("file", fs.createReadStream(path)); - await this.put( - `namespaces/${this.namespace}/content/${documentId}`, - formData, - { headers: { "Content-Type": "multipart/form-data" } } - ); - } - - async listContent( - extractionGraph: string, - namespace?: string, - params?: { - namespace: string; - extractionGraph: string; - source?: string; - ingestedContentId?: string; - parentId?: string; - labelsFilter?: string[]; - startId?: string; - limit?: number; - returnTotal?: boolean; - } - ): Promise<{ contentList: IContentMetadata[]; total?: number }> { - const defaultParams = { - namespace: namespace || this.namespace, - extraction_graph: extractionGraph, - return_total: false, - }; - - const mergedParams = { - ...defaultParams, - ...params, - namespace: params?.namespace || namespace || this.namespace, - extraction_graph: params?.extractionGraph || extractionGraph, - labels_filter: params?.labelsFilter, - ingested_content_id: params?.ingestedContentId, - parent_id: params?.parentId, - start_id: params?.startId, - }; - - const response = await this.client.get( - `extraction_graphs/${mergedParams.extraction_graph}/content`, - { params: mergedParams } - ); - - const contentList = response.data.content_list.map((item: IBaseContentMetadata) => - this.baseContentToContentMetadata(item) - ); - - return { - contentList, - total: mergedParams.return_total ? response.data.total : undefined - }; - } - - async sqlQuery(query: string): Promise { - const response = await this.client.post( - `namespaces/${this.namespace}/sql_query`, - { query }, - { headers: { "Content-Type": "application/json" } } - ); - return response.data.rows.map((row: any) => row.data); - } - - async linkExtractionGraphs( - sourceGraph: string, - contentSource: string, - linkedGraph: string - ): Promise { - await this.client.post( - `namespaces/${this.namespace}/extraction_graphs/${sourceGraph}/links`, - { - content_source: contentSource, - linked_graph_name: linkedGraph, - }, - { headers: { "Content-Type": "application/json" } } - ); - } -} - -export default IndexifyClient; From 3dd6c2bc5a153d809f965b1214e79b9831416635 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Mon, 9 Sep 2024 17:17:49 +0530 Subject: [PATCH 03/11] feat: added more functions Signed-off-by: Adithya Krishna --- src/client.ts | 109 ++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 109 insertions(+) diff --git a/src/client.ts b/src/client.ts index 82b1a90..bd176e9 100644 --- a/src/client.ts +++ b/src/client.ts @@ -91,3 +91,112 @@ class IndexifyClient { async delete(endpoint: string): Promise { return this.request("DELETE", endpoint); } + + static async namespaces({ + serviceUrl = DEFAULT_SERVICE_URL, + mtlsConfig, + }: { + serviceUrl?: string; + mtlsConfig?: IMtlsConfig; + } = {}): Promise { + const response = await axios.get(`${serviceUrl}/namespaces`, { + httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }), + }); + return response.data.namespaces; + } + + static async createNamespace({ + name, + mtlsConfig, + }: { + name: string; + mtlsConfig?: IMtlsConfig; + }): Promise { + await axios.post( + `${DEFAULT_SERVICE_URL}/namespaces`, + { name } as CreateNamespace, + { httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }) } + ); + return IndexifyClient.createClient({ namespace: name }); + } + + async computeGraphs(): Promise { + const resp = await this.client.get("compute_graphs"); + return resp.data.compute_graphs; + } + + async createComputeGraph(computeGraph: ComputeGraph, code: string): Promise { + const formData = new FormData(); + formData.append('compute_graph', JSON.stringify(computeGraph)); + formData.append('code', new Blob([code], { type: 'text/plain' }), 'code.py'); + + await this.client.post("compute_graphs", formData, { + headers: { 'Content-Type': 'multipart/form-data' } + }); + } + + async getComputeGraph(computeGraph: string): Promise { + const resp = await this.client.get(`compute_graphs/${computeGraph}`); + return resp.data; + } + + async getGraphInvocations(computeGraph: string): Promise { + const resp = await this.client.get(`compute_graphs/${computeGraph}/invocations`); + return resp.data; + } + + async getInvocationResult(computeGraph: string, invocationId: string): Promise { + const resp = await this.client.get(`compute_graphs/${computeGraph}/invocations/${invocationId}`); + return resp.data; + } + + async deleteInvocation(computeGraph: string, invocationId: string): Promise { + await this.client.delete(`compute_graphs/${computeGraph}/invocations/${invocationId}`); + } + + async invokeWithFile(computeGraph: string, file: Blob | string, metadata?: Record): Promise { + const formData = new FormData(); + + if (typeof file === 'string') { + // Assume it's a file path in Node.js environment + const fs = require('fs'); + formData.append('file', fs.createReadStream(file)); + } else { + formData.append('file', file); + } + + if (metadata) { + formData.append('metadata', JSON.stringify(metadata)); + } + + const resp = await this.client.post(`compute_graphs/${computeGraph}/invoke_file`, formData, { + headers: { 'Content-Type': 'multipart/form-data' } + }); + + return resp.data.invocation_id; + } + + async invokeWithObject(computeGraph: string, object: any): Promise { + const resp = await this.client.post(`compute_graphs/${computeGraph}/invoke_object`, object); + return resp.data.invocation_id; + } + + async listTasks(computeGraph: string): Promise { + const resp = await this.client.get(`compute_graphs/${computeGraph}/tasks`); + return resp.data.tasks; + } + + async deleteComputeGraph(name: string): Promise { + await this.client.delete(`compute_graphs/${name}`); + } + + generateUniqueHexId(): string { + return uuidv4().replace(/-/g, "").substring(0, 16); + } + + generateHashFromString(inputString: string): string { + return CryptoJS.SHA256(inputString).toString(CryptoJS.enc.Hex).substring(0, 16); + } +} + +export default IndexifyClient; From 16737caae170e96347ed7b088ed78fb506fed94b Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Sep 2024 14:34:38 +0530 Subject: [PATCH 04/11] feat: updated client to v0.1.0 Signed-off-by: Adithya Krishna --- src/client.ts | 326 ++++++++++++++++++++++++++++++-------------------- src/index.ts | 62 +++++----- src/types.ts | 50 ++------ 3 files changed, 238 insertions(+), 200 deletions(-) diff --git a/src/client.ts b/src/client.ts index bd176e9..a6ce94a 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,193 +1,223 @@ -import axios, { AxiosInstance, AxiosRequestConfig, AxiosResponse } from "axios"; +import axios, { AxiosInstance, AxiosRequestConfig, AxiosError } from "axios"; +import { v4 as uuidv4 } from "uuid"; +import CryptoJS from "crypto-js"; import { - IContentMetadata, - Namespace as INamespace, - Task as ITask, - IDocument, - IMtlsConfig, + Namespace, ComputeGraph, CreateNamespace, - GraphInvocations, + IndexifyAPIError, InvocationResult, - Task, + Tasks, + ComputeGraphCreateType, + ComputeGraphsList, + GraphInvocations, + NamespaceList } from "./types"; -import { v4 as uuidv4 } from "uuid"; -import CryptoJS from "crypto-js"; const DEFAULT_SERVICE_URL = "http://localhost:8900"; +class IndexifyError extends Error { + constructor(message: string, public statusCode?: number, public response?: any) { + super(message); + this.name = "IndexifyError"; + } +} + class IndexifyClient { - private client: AxiosInstance; + private axiosInstance: AxiosInstance; - constructor( - public serviceUrl: string = DEFAULT_SERVICE_URL, - public namespace: string = "default", - httpsAgent?: any + private constructor( + private readonly serviceUrl: string = DEFAULT_SERVICE_URL, + private readonly _namespace: string = "default", + config?: AxiosRequestConfig ) { - this.client = axios.create({ - baseURL: `${serviceUrl}/namespaces/${namespace}`, - httpsAgent, + this.axiosInstance = axios.create({ + baseURL: `${serviceUrl}/namespaces/${_namespace}`, + ...config, }); } - static async createClient({ + static async namespaces({ serviceUrl = DEFAULT_SERVICE_URL, - namespace = "default", - mtlsConfig, + config, }: { serviceUrl?: string; - namespace?: string; - mtlsConfig?: IMtlsConfig; - } = {}): Promise { - return new IndexifyClient( - serviceUrl, - namespace, - IndexifyClient.getHttpsAgent({ mtlsConfig }) - ); - } - - private async request( - method: string, - endpoint: string, - options: any = {} - ): Promise { + config?: AxiosRequestConfig; + } = {}): Promise { try { - return await this.client.request({ - method, - url: endpoint, - ...options, - }); + const response = await axios.get(`${serviceUrl}/namespaces`, config); + return response.data.namespaces; } catch (error) { if (axios.isAxiosError(error)) { - console.error(`Error: ${error.message}`); + throw new IndexifyError(error.message, error.response?.status, error.response?.data); } - throw error; - } - } - - static getHttpsAgent({ mtlsConfig }: { mtlsConfig?: IMtlsConfig }): any | undefined { - if (!mtlsConfig) return undefined; - if (typeof window !== "undefined") { - throw new Error("mTLS support is not available in browser environments."); + throw new IndexifyError("Failed to list namespaces"); } - const fs = require("fs"); - const { Agent } = require("https"); - return new Agent({ - cert: fs.readFileSync(mtlsConfig.certPath), - key: fs.readFileSync(mtlsConfig.keyPath), - ...(mtlsConfig.caPath && { ca: fs.readFileSync(mtlsConfig.caPath) }), - rejectUnauthorized: true, - }); - } - - async get(endpoint: string): Promise { - return this.request("GET", endpoint); } - async post(endpoint: string, data?: any): Promise { - return this.request("POST", endpoint, { data }); + public get namespace(): string { + return this._namespace; } - async delete(endpoint: string): Promise { - return this.request("DELETE", endpoint); - } - - static async namespaces({ + static createClient({ serviceUrl = DEFAULT_SERVICE_URL, - mtlsConfig, + namespace = "default", + config, }: { serviceUrl?: string; - mtlsConfig?: IMtlsConfig; - } = {}): Promise { - const response = await axios.get(`${serviceUrl}/namespaces`, { - httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }), - }); - return response.data.namespaces; + namespace?: string; + config?: AxiosRequestConfig; + } = {}): IndexifyClient { + return new IndexifyClient(serviceUrl, namespace, config); } - static async createNamespace({ - name, - mtlsConfig, - }: { - name: string; - mtlsConfig?: IMtlsConfig; - }): Promise { - await axios.post( - `${DEFAULT_SERVICE_URL}/namespaces`, - { name } as CreateNamespace, - { httpsAgent: IndexifyClient.getHttpsAgent({ mtlsConfig }) } - ); - return IndexifyClient.createClient({ namespace: name }); + private handleAxiosError(error: AxiosError): never { + if (error.response) { + const { status, data } = error.response; + throw new IndexifyError(data.message || "Unknown API error", status, data); + } else if (error.request) { + throw new IndexifyError("No response received from the server"); + } else { + throw new IndexifyError(`Error setting up the request: ${error.message}`); + } } - async computeGraphs(): Promise { - const resp = await this.client.get("compute_graphs"); - return resp.data.compute_graphs; + async listComputeGraphs(): Promise { + try { + const response = await this.axiosInstance.get('compute_graphs'); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError("Failed to fetch compute graphs"); + } } - async createComputeGraph(computeGraph: ComputeGraph, code: string): Promise { - const formData = new FormData(); - formData.append('compute_graph', JSON.stringify(computeGraph)); - formData.append('code', new Blob([code], { type: 'text/plain' }), 'code.py'); + async createComputeGraph(computeGraphCreate: ComputeGraphCreateType): Promise { + try { + const formData = new FormData(); + formData.append('compute_graph', JSON.stringify(computeGraphCreate.compute_graph)); + formData.append('code', new Blob([computeGraphCreate.code], { type: 'text/plain' }), 'code.py'); - await this.client.post("compute_graphs", formData, { - headers: { 'Content-Type': 'multipart/form-data' } - }); + await this.axiosInstance.post('compute_graphs', formData, { + headers: { 'Content-Type': 'multipart/form-data' } + }); + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to create compute graph: ${computeGraphCreate.compute_graph.name}`); + } } async getComputeGraph(computeGraph: string): Promise { - const resp = await this.client.get(`compute_graphs/${computeGraph}`); - return resp.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch compute graph: ${computeGraph}`); + } } async getGraphInvocations(computeGraph: string): Promise { - const resp = await this.client.get(`compute_graphs/${computeGraph}/invocations`); - return resp.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch graph invocations for: ${computeGraph}`); + } } async getInvocationResult(computeGraph: string, invocationId: string): Promise { - const resp = await this.client.get(`compute_graphs/${computeGraph}/invocations/${invocationId}`); - return resp.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/outputs`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch invocation result: ${invocationId}`); + } } async deleteInvocation(computeGraph: string, invocationId: string): Promise { - await this.client.delete(`compute_graphs/${computeGraph}/invocations/${invocationId}`); + try { + await this.axiosInstance.delete(`compute_graphs/${computeGraph}/invocations/${invocationId}`); + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to delete invocation: ${invocationId}`); + } } - async invokeWithFile(computeGraph: string, file: Blob | string, metadata?: Record): Promise { - const formData = new FormData(); - - if (typeof file === 'string') { - // Assume it's a file path in Node.js environment - const fs = require('fs'); - formData.append('file', fs.createReadStream(file)); - } else { + async invokeWithFile(computeGraph: string, file: File, metadata?: Record): Promise { + try { + const formData = new FormData(); formData.append('file', file); - } - - if (metadata) { - formData.append('metadata', JSON.stringify(metadata)); - } + + if (metadata) { + formData.append('metadata', JSON.stringify(metadata)); + } - const resp = await this.client.post(`compute_graphs/${computeGraph}/invoke_file`, formData, { - headers: { 'Content-Type': 'multipart/form-data' } - }); + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_file`, + formData, + { headers: { 'Content-Type': 'multipart/form-data' } } + ); - return resp.data.invocation_id; + return response.data.invocation_id; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to invoke compute graph with file: ${computeGraph}`); + } } async invokeWithObject(computeGraph: string, object: any): Promise { - const resp = await this.client.post(`compute_graphs/${computeGraph}/invoke_object`, object); - return resp.data.invocation_id; + try { + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_object`, + object + ); + return response.data.invocation_id; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to invoke compute graph with object: ${computeGraph}`); + } } - async listTasks(computeGraph: string): Promise { - const resp = await this.client.get(`compute_graphs/${computeGraph}/tasks`); - return resp.data.tasks; + async listTasks(computeGraph: string, invocationId: string): Promise { + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/tasks`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to list tasks for invocation: ${invocationId}`); + } } async deleteComputeGraph(name: string): Promise { - await this.client.delete(`compute_graphs/${name}`); + try { + await this.axiosInstance.delete(`compute_graphs/${name}`); + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to delete compute graph: ${name}`); + } } generateUniqueHexId(): string { @@ -199,4 +229,42 @@ class IndexifyClient { } } +export const namespaces = async ({ + serviceUrl = DEFAULT_SERVICE_URL, + config, +}: { + serviceUrl?: string; + config?: AxiosRequestConfig; +} = {}): Promise => { + try { + const response = await axios.get(`${serviceUrl}/namespaces`, config); + return response.data.namespaces; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); + } + throw new IndexifyError("Failed to list namespaces"); + } +}; + +export const createNamespace = async ( + name: string, + serviceUrl: string = DEFAULT_SERVICE_URL, + config?: AxiosRequestConfig +): Promise => { + try { + await axios.post( + `${serviceUrl}/namespaces`, + { name }, + config + ); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); + } + throw new IndexifyError(`Failed to create namespace: ${name}`); + } +}; + +export { IndexifyClient }; export default IndexifyClient; diff --git a/src/index.ts b/src/index.ts index 68fccd3..abcf10b 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,42 +1,38 @@ -import ExtractionGraph from "./ExtractionGraph"; import IndexifyClient from "./client"; -import Extractor from "./extractor"; import { - INamespace, - IEmbeddingSchema, - IExtractorSchema, - IExtractor, - IIndex, - IContentMetadata, - IExtractedMetadata, - IExtractionPolicy, - ISearchIndexResponse, - ITask, - TaskStatus, - IDocument, - ISchema, - IContent + ComputeFn, + DynamicRouter, + Node, + ComputeGraph, + ComputeGraphsList, + CreateNamespace, + DataObject, + IndexifyAPIError, + InvocationResult, + Namespace, + TaskOutcome, + Task, + Tasks, + ComputeGraphCreateType } from "./types"; export { IndexifyClient, - Extractor, - ExtractionGraph, - TaskStatus, }; export type { - INamespace, - IEmbeddingSchema, - IExtractorSchema, - ISchema, - IExtractor, - IIndex, - IContentMetadata, - IExtractedMetadata, - IExtractionPolicy, - ISearchIndexResponse, - ITask, - IDocument, - IContent -}; \ No newline at end of file + ComputeFn, + DynamicRouter, + Node, + ComputeGraph, + ComputeGraphsList, + CreateNamespace, + DataObject, + IndexifyAPIError, + InvocationResult, + Namespace, + TaskOutcome, + Task, + Tasks, + ComputeGraphCreateType +}; diff --git a/src/types.ts b/src/types.ts index ed6bb30..cd99e62 100644 --- a/src/types.ts +++ b/src/types.ts @@ -20,15 +20,11 @@ export interface ComputeGraph { namespace: string; description: string; start_node: Node; - edges: Record; + nodes: Record; + edges: Record; created_at?: number; } -export interface ComputeGraphCreateType { - compute_graph: ComputeGraph; - code: string; // This will be a file in the actual request -} - export interface ComputeGraphsList { compute_graphs: ComputeGraph[]; cursor?: string | null; @@ -51,7 +47,7 @@ export interface GraphInvocations { } export interface IndexifyAPIError { - status_code: number; // Assuming StatusCode is a number + status_code: number; message: string; } @@ -73,9 +69,12 @@ export type TaskOutcome = "Unknown" | "Success" | "Failure"; export interface Task { id: string; - status: TaskOutcome; - created_at: number; - updated_at: number; + namespace: string; + compute_fn: string; + compute_graph: string; + invocation_id: string; + input_key: string; + outcome: TaskOutcome; } export interface Tasks { @@ -83,33 +82,8 @@ export interface Tasks { cursor?: string | null; } -// Additional types that were used in the IndexifyClient but not explicitly defined in the OpenAPI spec - -export interface IMtlsConfig { - certPath: string; - keyPath: string; - caPath?: string; -} - -export interface IDocument { - text: string; - labels: Record; - id?: string; +export interface ComputeGraphCreateType { + compute_graph: ComputeGraph; + code: string; } -export interface IContentMetadata { - id: string; - parent_id?: string; - ingested_content_id: string; - namespace: string; - name: string; - mime_type: string; - labels: Record; - storage_url: string; - content_url: string; - created_at: number; - source: string; - size: number; - hash: string; - extraction_graph_names: string[]; -} From 5379858c333c220404aa01184cce0f70cc934e30 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Sep 2024 14:34:48 +0530 Subject: [PATCH 05/11] feat: updated client to v0.1.1 Signed-off-by: Adithya Krishna --- src/client.ts | 252 +++++++++++++++++++++----------------------------- 1 file changed, 104 insertions(+), 148 deletions(-) diff --git a/src/client.ts b/src/client.ts index a6ce94a..cfaa1ff 100644 --- a/src/client.ts +++ b/src/client.ts @@ -17,60 +17,61 @@ import { const DEFAULT_SERVICE_URL = "http://localhost:8900"; class IndexifyError extends Error { - constructor(message: string, public statusCode?: number, public response?: any) { + constructor(public message: string, public statusCode?: number, public response?: any) { super(message); this.name = "IndexifyError"; } } -class IndexifyClient { +class IndexifySuccess { + constructor(public message: string, public data?: any) {} +} + +export class IndexifyClient { private axiosInstance: AxiosInstance; private constructor( - private readonly serviceUrl: string = DEFAULT_SERVICE_URL, - private readonly _namespace: string = "default", + private readonly serviceUrl: string, + private readonly _namespace: string, config?: AxiosRequestConfig ) { this.axiosInstance = axios.create({ baseURL: `${serviceUrl}/namespaces/${_namespace}`, ...config, }); + + this.axiosInstance.interceptors.response.use( + response => response, + (error: AxiosError) => this.handleAxiosError(error) + ); } - static async namespaces({ + static async createClient({ serviceUrl = DEFAULT_SERVICE_URL, + namespace = "default", config, }: { serviceUrl?: string; + namespace?: string; config?: AxiosRequestConfig; - } = {}): Promise { + } = {}): Promise { + const client = new IndexifyClient(serviceUrl, namespace, config); + await client.validateConnection(); + return client; + } + + private async validateConnection(): Promise { try { - const response = await axios.get(`${serviceUrl}/namespaces`, config); - return response.data.namespaces; + await this.axiosInstance.get(""); } catch (error) { - if (axios.isAxiosError(error)) { - throw new IndexifyError(error.message, error.response?.status, error.response?.data); - } - throw new IndexifyError("Failed to list namespaces"); + throw new IndexifyError("Failed to establish connection with the server"); } } - public get namespace(): string { + get namespace(): string { return this._namespace; } - static createClient({ - serviceUrl = DEFAULT_SERVICE_URL, - namespace = "default", - config, - }: { - serviceUrl?: string; - namespace?: string; - config?: AxiosRequestConfig; - } = {}): IndexifyClient { - return new IndexifyClient(serviceUrl, namespace, config); - } - private handleAxiosError(error: AxiosError): never { if (error.response) { const { status, data } = error.response; @@ -83,140 +84,95 @@ class IndexifyClient { } async listComputeGraphs(): Promise { - try { - const response = await this.axiosInstance.get('compute_graphs'); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError("Failed to fetch compute graphs"); - } + const response = await this.axiosInstance.get('compute_graphs'); + return response.data; } - async createComputeGraph(computeGraphCreate: ComputeGraphCreateType): Promise { + async createComputeGraph(computeGraphCreate: ComputeGraphCreateType): Promise { try { const formData = new FormData(); formData.append('compute_graph', JSON.stringify(computeGraphCreate.compute_graph)); formData.append('code', new Blob([computeGraphCreate.code], { type: 'text/plain' }), 'code.py'); - await this.axiosInstance.post('compute_graphs', formData, { + const response = await this.axiosInstance.post('compute_graphs', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); + + return new IndexifySuccess(`Compute graph '${computeGraphCreate.compute_graph.name}' created successfully`, response.data); } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); + if (error instanceof IndexifyError) { + throw error; } - throw new IndexifyError(`Failed to create compute graph: ${computeGraphCreate.compute_graph.name}`); + throw new IndexifyError(`Failed to create compute graph: ${(error as Error).message}`); } } async getComputeGraph(computeGraph: string): Promise { - try { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}`); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to fetch compute graph: ${computeGraph}`); - } + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}`); + return response.data; } async getGraphInvocations(computeGraph: string): Promise { - try { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations`); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to fetch graph invocations for: ${computeGraph}`); - } + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations`); + return response.data; } async getInvocationResult(computeGraph: string, invocationId: string): Promise { - try { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/outputs`); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to fetch invocation result: ${invocationId}`); - } + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/outputs`); + return response.data; } - async deleteInvocation(computeGraph: string, invocationId: string): Promise { + async deleteInvocation(computeGraph: string, invocationId: string): Promise { try { await this.axiosInstance.delete(`compute_graphs/${computeGraph}/invocations/${invocationId}`); + return new IndexifySuccess(`Invocation '${invocationId}' for compute graph '${computeGraph}' deleted successfully`); } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); + if (error instanceof IndexifyError) { + throw error; } - throw new IndexifyError(`Failed to delete invocation: ${invocationId}`); + throw new IndexifyError(`Failed to delete invocation: ${(error as Error).message}`); } } async invokeWithFile(computeGraph: string, file: File, metadata?: Record): Promise { - try { - const formData = new FormData(); - formData.append('file', file); - - if (metadata) { - formData.append('metadata', JSON.stringify(metadata)); - } + const formData = new FormData(); + formData.append('file', file); + + if (metadata) { + formData.append('metadata', JSON.stringify(metadata)); + } - const response = await this.axiosInstance.post<{ invocation_id: string }>( - `compute_graphs/${computeGraph}/invoke_file`, - formData, - { headers: { 'Content-Type': 'multipart/form-data' } } - ); + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_file`, + formData, + { headers: { 'Content-Type': 'multipart/form-data' } } + ); - return response.data.invocation_id; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to invoke compute graph with file: ${computeGraph}`); - } + return response.data.invocation_id; } async invokeWithObject(computeGraph: string, object: any): Promise { - try { - const response = await this.axiosInstance.post<{ invocation_id: string }>( - `compute_graphs/${computeGraph}/invoke_object`, - object - ); - return response.data.invocation_id; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to invoke compute graph with object: ${computeGraph}`); - } + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_object`, + object + ); + return response.data.invocation_id; } async listTasks(computeGraph: string, invocationId: string): Promise { - try { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/tasks`); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError(`Failed to list tasks for invocation: ${invocationId}`); - } + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/tasks`); + return response.data; } - async deleteComputeGraph(name: string): Promise { + async deleteComputeGraph(name: string): Promise { try { await this.axiosInstance.delete(`compute_graphs/${name}`); + return new IndexifySuccess(`Compute graph '${name}' deleted successfully`); } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); + if (error instanceof IndexifyError) { + throw error; } - throw new IndexifyError(`Failed to delete compute graph: ${name}`); + throw new IndexifyError(`Failed to delete compute graph: ${(error as Error).message}`); } } @@ -227,44 +183,44 @@ class IndexifyClient { generateHashFromString(inputString: string): string { return CryptoJS.SHA256(inputString).toString(CryptoJS.enc.Hex).substring(0, 16); } -} -export const namespaces = async ({ - serviceUrl = DEFAULT_SERVICE_URL, - config, -}: { - serviceUrl?: string; - config?: AxiosRequestConfig; -} = {}): Promise => { - try { - const response = await axios.get(`${serviceUrl}/namespaces`, config); - return response.data.namespaces; - } catch (error) { - if (axios.isAxiosError(error)) { - throw new IndexifyError(error.message, error.response?.status, error.response?.data); + static async listNamespaces({ + serviceUrl = DEFAULT_SERVICE_URL, + config, + }: { + serviceUrl?: string; + config?: AxiosRequestConfig; + } = {}): Promise { + try { + const response = await axios.get(`${serviceUrl}/namespaces`, config); + return response.data.namespaces; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); + } + throw new IndexifyError("Failed to list namespaces"); } - throw new IndexifyError("Failed to list namespaces"); } -}; -export const createNamespace = async ( - name: string, - serviceUrl: string = DEFAULT_SERVICE_URL, - config?: AxiosRequestConfig -): Promise => { - try { - await axios.post( - `${serviceUrl}/namespaces`, - { name }, - config - ); - } catch (error) { - if (axios.isAxiosError(error)) { - throw new IndexifyError(error.message, error.response?.status, error.response?.data); + static async createNamespace( + name: string, + serviceUrl: string = DEFAULT_SERVICE_URL, + config?: AxiosRequestConfig + ): Promise { + try { + await axios.post( + `${serviceUrl}/namespaces`, + { name }, + config + ); + return new IndexifySuccess(`Namespace '${name}' created successfully`); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); + } + throw new IndexifyError(`Failed to create namespace: ${name}`); } - throw new IndexifyError(`Failed to create namespace: ${name}`); } -}; +} -export { IndexifyClient }; -export default IndexifyClient; +export default IndexifyClient; \ No newline at end of file From 6f8419861c6d7b14120d8dfca80747012b7f17a0 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 24 Sep 2024 15:31:10 +0530 Subject: [PATCH 06/11] chore: updated package.json file Signed-off-by: Adithya Krishna --- package-lock.json | 4 ++-- package.json | 2 +- 2 files changed, 3 insertions(+), 3 deletions(-) diff --git a/package-lock.json b/package-lock.json index d9a94cd..cd7ea3a 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "getindexify", - "version": "0.0.75", + "version": "0.1.0", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "getindexify", - "version": "0.0.75", + "version": "0.1.0", "license": "ISC", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index 3cf6f33..321e2d3 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "getindexify", - "version": "0.0.75", + "version": "0.1.0", "description": "This is the TypeScript client for interacting with the Indexify service.", "main": "./dist/index.js", "module": "./dist/index.mjs", From 5f2431492d88d87f85f3717f343594fa8a392101 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Thu, 26 Sep 2024 18:37:54 +0530 Subject: [PATCH 07/11] feat: updated client to v0.1.2 Signed-off-by: Adithya Krishna --- package-lock.json | 4 +- package.json | 2 +- src/client.ts | 250 +++++++++++++++++++++++++++------------------- 3 files changed, 150 insertions(+), 106 deletions(-) diff --git a/package-lock.json b/package-lock.json index cd7ea3a..c6318de 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "getindexify", - "version": "0.1.0", + "version": "0.1.2", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "getindexify", - "version": "0.1.0", + "version": "0.1.2", "license": "ISC", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index 321e2d3..d991ab2 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "getindexify", - "version": "0.1.0", + "version": "0.1.2", "description": "This is the TypeScript client for interacting with the Indexify service.", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/client.ts b/src/client.ts index cfaa1ff..783685b 100644 --- a/src/client.ts +++ b/src/client.ts @@ -17,61 +17,60 @@ import { const DEFAULT_SERVICE_URL = "http://localhost:8900"; class IndexifyError extends Error { - constructor(public message: string, public statusCode?: number, public response?: any) { + constructor(message: string, public statusCode?: number, public response?: any) { super(message); this.name = "IndexifyError"; } } -class IndexifySuccess { - constructor(public message: string, public data?: any) {} -} - -export class IndexifyClient { +class IndexifyClient { private axiosInstance: AxiosInstance; private constructor( - private readonly serviceUrl: string, - private readonly _namespace: string, + private readonly serviceUrl: string = DEFAULT_SERVICE_URL, + private readonly _namespace: string = "default", config?: AxiosRequestConfig ) { this.axiosInstance = axios.create({ baseURL: `${serviceUrl}/namespaces/${_namespace}`, ...config, }); - - this.axiosInstance.interceptors.response.use( - response => response, - (error: AxiosError) => this.handleAxiosError(error) - ); } - static async createClient({ + static async namespaces({ serviceUrl = DEFAULT_SERVICE_URL, - namespace = "default", config, }: { serviceUrl?: string; - namespace?: string; config?: AxiosRequestConfig; - } = {}): Promise { - const client = new IndexifyClient(serviceUrl, namespace, config); - await client.validateConnection(); - return client; - } - - private async validateConnection(): Promise { + } = {}): Promise { try { - await this.axiosInstance.get(""); + const response = await axios.get(`${serviceUrl}/namespaces`, config); + return response.data.namespaces; } catch (error) { - throw new IndexifyError("Failed to establish connection with the server"); + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); + } + throw new IndexifyError("Failed to list namespaces"); } } - get namespace(): string { + public get namespace(): string { return this._namespace; } + static createClient({ + serviceUrl = DEFAULT_SERVICE_URL, + namespace = "default", + config, + }: { + serviceUrl?: string; + namespace?: string; + config?: AxiosRequestConfig; + } = {}): IndexifyClient { + return new IndexifyClient(serviceUrl, namespace, config); + } + private handleAxiosError(error: AxiosError): never { if (error.response) { const { status, data } = error.response; @@ -84,95 +83,140 @@ export class IndexifyClient { } async listComputeGraphs(): Promise { - const response = await this.axiosInstance.get('compute_graphs'); - return response.data; + try { + const response = await this.axiosInstance.get('compute_graphs'); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError("Failed to fetch compute graphs"); + } } - async createComputeGraph(computeGraphCreate: ComputeGraphCreateType): Promise { + async createComputeGraph(computeGraphCreate: ComputeGraphCreateType): Promise { try { const formData = new FormData(); formData.append('compute_graph', JSON.stringify(computeGraphCreate.compute_graph)); formData.append('code', new Blob([computeGraphCreate.code], { type: 'text/plain' }), 'code.py'); - const response = await this.axiosInstance.post('compute_graphs', formData, { + await this.axiosInstance.post('compute_graphs', formData, { headers: { 'Content-Type': 'multipart/form-data' } }); - - return new IndexifySuccess(`Compute graph '${computeGraphCreate.compute_graph.name}' created successfully`, response.data); } catch (error) { - if (error instanceof IndexifyError) { - throw error; + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); } - throw new IndexifyError(`Failed to create compute graph: ${(error as Error).message}`); + throw new IndexifyError(`Failed to create compute graph: ${computeGraphCreate.compute_graph.name}`); } } async getComputeGraph(computeGraph: string): Promise { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}`); - return response.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch compute graph: ${computeGraph}`); + } } async getGraphInvocations(computeGraph: string): Promise { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations`); - return response.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch graph invocations for: ${computeGraph}`); + } } async getInvocationResult(computeGraph: string, invocationId: string): Promise { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/outputs`); - return response.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/outputs`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to fetch invocation result: ${invocationId}`); + } } - async deleteInvocation(computeGraph: string, invocationId: string): Promise { + async deleteInvocation(computeGraph: string, invocationId: string): Promise { try { await this.axiosInstance.delete(`compute_graphs/${computeGraph}/invocations/${invocationId}`); - return new IndexifySuccess(`Invocation '${invocationId}' for compute graph '${computeGraph}' deleted successfully`); } catch (error) { - if (error instanceof IndexifyError) { - throw error; + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); } - throw new IndexifyError(`Failed to delete invocation: ${(error as Error).message}`); + throw new IndexifyError(`Failed to delete invocation: ${invocationId}`); } } async invokeWithFile(computeGraph: string, file: File, metadata?: Record): Promise { - const formData = new FormData(); - formData.append('file', file); - - if (metadata) { - formData.append('metadata', JSON.stringify(metadata)); - } + try { + const formData = new FormData(); + formData.append('file', file); + + if (metadata) { + formData.append('metadata', JSON.stringify(metadata)); + } - const response = await this.axiosInstance.post<{ invocation_id: string }>( - `compute_graphs/${computeGraph}/invoke_file`, - formData, - { headers: { 'Content-Type': 'multipart/form-data' } } - ); + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_file`, + formData, + { headers: { 'Content-Type': 'multipart/form-data' } } + ); - return response.data.invocation_id; + return response.data.invocation_id; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to invoke compute graph with file: ${computeGraph}`); + } } async invokeWithObject(computeGraph: string, object: any): Promise { - const response = await this.axiosInstance.post<{ invocation_id: string }>( - `compute_graphs/${computeGraph}/invoke_object`, - object - ); - return response.data.invocation_id; + try { + const response = await this.axiosInstance.post<{ invocation_id: string }>( + `compute_graphs/${computeGraph}/invoke_object`, + object + ); + return response.data.invocation_id; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to invoke compute graph with object: ${computeGraph}`); + } } async listTasks(computeGraph: string, invocationId: string): Promise { - const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/tasks`); - return response.data; + try { + const response = await this.axiosInstance.get(`compute_graphs/${computeGraph}/invocations/${invocationId}/tasks`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to list tasks for invocation: ${invocationId}`); + } } - async deleteComputeGraph(name: string): Promise { + async deleteComputeGraph(name: string): Promise { try { await this.axiosInstance.delete(`compute_graphs/${name}`); - return new IndexifySuccess(`Compute graph '${name}' deleted successfully`); } catch (error) { - if (error instanceof IndexifyError) { - throw error; + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); } - throw new IndexifyError(`Failed to delete compute graph: ${(error as Error).message}`); + throw new IndexifyError(`Failed to delete compute graph: ${name}`); } } @@ -183,44 +227,44 @@ export class IndexifyClient { generateHashFromString(inputString: string): string { return CryptoJS.SHA256(inputString).toString(CryptoJS.enc.Hex).substring(0, 16); } +} - static async listNamespaces({ - serviceUrl = DEFAULT_SERVICE_URL, - config, - }: { - serviceUrl?: string; - config?: AxiosRequestConfig; - } = {}): Promise { - try { - const response = await axios.get(`${serviceUrl}/namespaces`, config); - return response.data.namespaces; - } catch (error) { - if (axios.isAxiosError(error)) { - throw new IndexifyError(error.message, error.response?.status, error.response?.data); - } - throw new IndexifyError("Failed to list namespaces"); +export const namespaces = async ({ + serviceUrl = DEFAULT_SERVICE_URL, + config, +}: { + serviceUrl?: string; + config?: AxiosRequestConfig; +} = {}): Promise => { + try { + const response = await axios.get(`${serviceUrl}/namespaces`, config); + return response.data.namespaces; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); } + throw new IndexifyError("Failed to list namespaces"); } +}; - static async createNamespace( - name: string, - serviceUrl: string = DEFAULT_SERVICE_URL, - config?: AxiosRequestConfig - ): Promise { - try { - await axios.post( - `${serviceUrl}/namespaces`, - { name }, - config - ); - return new IndexifySuccess(`Namespace '${name}' created successfully`); - } catch (error) { - if (axios.isAxiosError(error)) { - throw new IndexifyError(error.message, error.response?.status, error.response?.data); - } - throw new IndexifyError(`Failed to create namespace: ${name}`); +export const createNamespace = async ( + name: string, + serviceUrl: string = DEFAULT_SERVICE_URL, + config?: AxiosRequestConfig +): Promise => { + try { + await axios.post( + `${serviceUrl}/namespaces`, + { name }, + config + ); + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); } + throw new IndexifyError(`Failed to create namespace: ${name}`); } -} +}; +export { IndexifyClient }; export default IndexifyClient; \ No newline at end of file From 73edb24b52ca467d7687d912801215fef22c0c48 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Mon, 30 Sep 2024 17:01:08 +0530 Subject: [PATCH 08/11] chore: added logs and executor api Signed-off-by: Adithya Krishna --- package-lock.json | 4 ++-- package.json | 2 +- src/client.ts | 35 ++++++++++++++++++++++++++++++++++- src/types.ts | 16 +++++++++++++++- 4 files changed, 52 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index c6318de..d84f051 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "getindexify", - "version": "0.1.2", + "version": "0.1.3", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "getindexify", - "version": "0.1.2", + "version": "0.1.3", "license": "ISC", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index d991ab2..d377833 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "getindexify", - "version": "0.1.2", + "version": "0.1.3", "description": "This is the TypeScript client for interacting with the Indexify service.", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/client.ts b/src/client.ts index 783685b..1ead5a2 100644 --- a/src/client.ts +++ b/src/client.ts @@ -11,7 +11,8 @@ import { ComputeGraphCreateType, ComputeGraphsList, GraphInvocations, - NamespaceList + NamespaceList, + ExecutorMetadata } from "./types"; const DEFAULT_SERVICE_URL = "http://localhost:8900"; @@ -227,6 +228,38 @@ class IndexifyClient { generateHashFromString(inputString: string): string { return CryptoJS.SHA256(inputString).toString(CryptoJS.enc.Hex).substring(0, 16); } + + async downloadLogs( + computeGraph: string, + invocationId: string, + fnName: string, + file: string + ): Promise { + try { + const response = await this.axiosInstance.get( + `compute_graphs/${computeGraph}/invocations/${invocationId}/fn/${fnName}/logs/${file}`, + { responseType: 'text' } + ); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError(`Failed to download logs for invocation: ${invocationId}, function: ${fnName}, file: ${file}`); + } + } + + async listExecutors(): Promise { + try { + const response = await axios.get(`${this.serviceUrl}/internal/executors`); + return response.data; + } catch (error) { + if (axios.isAxiosError(error)) { + this.handleAxiosError(error); + } + throw new IndexifyError("Failed to list executors"); + } + } } export const namespaces = async ({ diff --git a/src/types.ts b/src/types.ts index cd99e62..52b6dcf 100644 --- a/src/types.ts +++ b/src/types.ts @@ -2,6 +2,9 @@ export interface ComputeFn { name: string; fn_name: string; description: string; + reducer: boolean; + payload_encoder: string; + image_name: string; } export interface DynamicRouter { @@ -9,6 +12,8 @@ export interface DynamicRouter { source_fn: string; description: string; target_fns: string[]; + payload_encoder: string; + image_name: string; } export type Node = @@ -36,7 +41,6 @@ export interface CreateNamespace { export interface DataObject { id: string; - payload: any; payload_size: number; payload_sha_256: string; } @@ -67,6 +71,8 @@ export interface NamespaceList { export type TaskOutcome = "Unknown" | "Success" | "Failure"; +export type GraphVersion = string; + export interface Task { id: string; namespace: string; @@ -75,6 +81,8 @@ export interface Task { invocation_id: string; input_key: string; outcome: TaskOutcome; + graph_version: GraphVersion; + reducer_output_id?: string | null; } export interface Tasks { @@ -87,3 +95,9 @@ export interface ComputeGraphCreateType { code: string; } +export interface ExecutorMetadata { + id: string; + addr: string; + image_name: string; + labels: Record; +} From 31fc20308676b03dd3c5f58d23a25bf3fe071d01 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Mon, 30 Sep 2024 17:09:11 +0530 Subject: [PATCH 09/11] chore: updated executors api Signed-off-by: Adithya Krishna --- src/client.ts | 26 ++++++++++++++++---------- 1 file changed, 16 insertions(+), 10 deletions(-) diff --git a/src/client.ts b/src/client.ts index 1ead5a2..2dd1011 100644 --- a/src/client.ts +++ b/src/client.ts @@ -248,19 +248,25 @@ class IndexifyClient { throw new IndexifyError(`Failed to download logs for invocation: ${invocationId}, function: ${fnName}, file: ${file}`); } } +} - async listExecutors(): Promise { - try { - const response = await axios.get(`${this.serviceUrl}/internal/executors`); - return response.data; - } catch (error) { - if (axios.isAxiosError(error)) { - this.handleAxiosError(error); - } - throw new IndexifyError("Failed to list executors"); +export const listExecutors = async ({ + serviceUrl = DEFAULT_SERVICE_URL, + config, +}: { + serviceUrl?: string; + config?: AxiosRequestConfig; +} = {}): Promise => { + try { + const response = await axios.get<{ executors: ExecutorMetadata[] }>(`${serviceUrl}/internal/executors`, config); + return response.data.executors; + } catch (error) { + if (axios.isAxiosError(error)) { + throw new IndexifyError(error.message, error.response?.status, error.response?.data); } + throw new IndexifyError("Failed to list executors"); } -} +}; export const namespaces = async ({ serviceUrl = DEFAULT_SERVICE_URL, From d6fd6f67b80d2396fe2c406062ac7d3cbe17c588 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Mon, 30 Sep 2024 17:23:45 +0530 Subject: [PATCH 10/11] chore: fix package build output Signed-off-by: Adithya Krishna --- package-lock.json | 4 ++-- package.json | 2 +- src/index.ts | 19 +++++++++++++++---- 3 files changed, 18 insertions(+), 7 deletions(-) diff --git a/package-lock.json b/package-lock.json index d84f051..523272c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "getindexify", - "version": "0.1.3", + "version": "0.1.4", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "getindexify", - "version": "0.1.3", + "version": "0.1.4", "license": "ISC", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index d377833..3ebf24b 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "getindexify", - "version": "0.1.3", + "version": "0.1.4", "description": "This is the TypeScript client for interacting with the Indexify service.", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/index.ts b/src/index.ts index abcf10b..5305a45 100644 --- a/src/index.ts +++ b/src/index.ts @@ -1,4 +1,4 @@ -import IndexifyClient from "./client"; +import IndexifyClient, { namespaces, createNamespace, listExecutors } from "./client"; import { ComputeFn, DynamicRouter, @@ -13,11 +13,18 @@ import { TaskOutcome, Task, Tasks, - ComputeGraphCreateType + ComputeGraphCreateType, + ExecutorMetadata, + GraphVersion, + NamespaceList, + GraphInvocations } from "./types"; export { IndexifyClient, + namespaces, + createNamespace, + listExecutors }; export type { @@ -34,5 +41,9 @@ export type { TaskOutcome, Task, Tasks, - ComputeGraphCreateType -}; + ComputeGraphCreateType, + ExecutorMetadata, + GraphVersion, + NamespaceList, + GraphInvocations +}; \ No newline at end of file From 1cc71f92b5d77f3a0d8e353e6d973cb53e0907b1 Mon Sep 17 00:00:00 2001 From: Adithya Krishna Date: Tue, 1 Oct 2024 01:57:43 +0530 Subject: [PATCH 11/11] chore: fix ts client Signed-off-by: Adithya Krishna --- package-lock.json | 4 ++-- package.json | 2 +- src/ExtractionGraph.ts | 3 +-- 3 files changed, 4 insertions(+), 5 deletions(-) diff --git a/package-lock.json b/package-lock.json index 523272c..51a6e3c 100644 --- a/package-lock.json +++ b/package-lock.json @@ -1,12 +1,12 @@ { "name": "getindexify", - "version": "0.1.4", + "version": "0.1.5", "lockfileVersion": 3, "requires": true, "packages": { "": { "name": "getindexify", - "version": "0.1.4", + "version": "0.1.5", "license": "ISC", "dependencies": { "axios": "^1.7.2", diff --git a/package.json b/package.json index 3ebf24b..4b37efd 100644 --- a/package.json +++ b/package.json @@ -1,6 +1,6 @@ { "name": "getindexify", - "version": "0.1.4", + "version": "0.1.5", "description": "This is the TypeScript client for interacting with the Indexify service.", "main": "./dist/index.js", "module": "./dist/index.mjs", diff --git a/src/ExtractionGraph.ts b/src/ExtractionGraph.ts index 697f309..b828e67 100644 --- a/src/ExtractionGraph.ts +++ b/src/ExtractionGraph.ts @@ -1,10 +1,9 @@ -import { IExtractionPolicy } from "./types"; import yaml from "yaml"; class ExtractionGraph { constructor( public readonly name: string, - public readonly extraction_policies: IExtractionPolicy[], + public readonly extraction_policies: any[], public readonly id?: string, public readonly namespace?: string ) {}