@robosystems/client 0.2.0 → 0.2.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/extensions/GraphClient.d.ts +71 -0
- package/extensions/GraphClient.js +176 -0
- package/extensions/GraphClient.test.ts +285 -0
- package/extensions/GraphClient.ts +281 -0
- package/extensions/TableIngestClient.d.ts +1 -1
- package/extensions/TableIngestClient.js +20 -20
- package/extensions/TableIngestClient.test.ts +1 -1
- package/extensions/TableIngestClient.ts +23 -28
- package/extensions/hooks.d.ts +1 -1
- package/extensions/index.d.ts +5 -1
- package/extensions/index.js +14 -1
- package/extensions/index.test.ts +22 -0
- package/extensions/index.ts +15 -1
- package/package.json +1 -1
- package/sdk/sdk.gen.d.ts +528 -26
- package/sdk/sdk.gen.js +534 -32
- package/sdk/sdk.gen.ts +532 -30
- package/sdk/types.gen.d.ts +289 -82
- package/sdk/types.gen.ts +293 -82
- package/sdk-extensions/GraphClient.d.ts +71 -0
- package/sdk-extensions/GraphClient.js +176 -0
- package/sdk-extensions/GraphClient.test.ts +285 -0
- package/sdk-extensions/GraphClient.ts +281 -0
- package/sdk-extensions/TableIngestClient.d.ts +1 -1
- package/sdk-extensions/TableIngestClient.js +20 -20
- package/sdk-extensions/TableIngestClient.test.ts +1 -1
- package/sdk-extensions/TableIngestClient.ts +23 -28
- package/sdk-extensions/hooks.d.ts +1 -1
- package/sdk-extensions/index.d.ts +5 -1
- package/sdk-extensions/index.js +14 -1
- package/sdk-extensions/index.test.ts +22 -0
- package/sdk-extensions/index.ts +15 -1
- package/sdk.gen.d.ts +528 -26
- package/sdk.gen.js +534 -32
- package/sdk.gen.ts +532 -30
- package/types.gen.d.ts +289 -82
- package/types.gen.ts +293 -82
|
@@ -0,0 +1,281 @@
|
|
|
1
|
+
'use client'
|
|
2
|
+
|
|
3
|
+
/**
|
|
4
|
+
* Graph Management Client
|
|
5
|
+
* Provides high-level graph management operations with automatic operation monitoring
|
|
6
|
+
*/
|
|
7
|
+
|
|
8
|
+
import { createGraph, getGraphs, getOperationStatus } from '../sdk/sdk.gen'
|
|
9
|
+
import type { GraphMetadata, InitialEntityData } from '../sdk/types.gen'
|
|
10
|
+
import { OperationClient } from './OperationClient'
|
|
11
|
+
|
|
12
|
+
// API Response Types
|
|
13
|
+
interface GraphCreateResponse {
|
|
14
|
+
graph_id?: string
|
|
15
|
+
operation_id?: string
|
|
16
|
+
}
|
|
17
|
+
|
|
18
|
+
interface OperationStatusResponse {
|
|
19
|
+
status?: 'pending' | 'completed' | 'failed' | string
|
|
20
|
+
result?: {
|
|
21
|
+
graph_id?: string
|
|
22
|
+
}
|
|
23
|
+
error?: string
|
|
24
|
+
message?: string
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
interface GraphApiData {
|
|
28
|
+
graph_id?: string
|
|
29
|
+
id?: string
|
|
30
|
+
graph_name?: string
|
|
31
|
+
name?: string
|
|
32
|
+
description?: string
|
|
33
|
+
schema_extensions?: string[]
|
|
34
|
+
tags?: string[]
|
|
35
|
+
created_at?: string
|
|
36
|
+
status?: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
interface GetGraphsResponse {
|
|
40
|
+
graphs?: GraphApiData[]
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
export interface GraphMetadataInput {
|
|
44
|
+
graphName: string
|
|
45
|
+
description?: string
|
|
46
|
+
schemaExtensions?: string[]
|
|
47
|
+
tags?: string[]
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
export interface InitialEntityInput {
|
|
51
|
+
name: string
|
|
52
|
+
uri: string
|
|
53
|
+
category?: string
|
|
54
|
+
sic?: string
|
|
55
|
+
sicDescription?: string
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
export interface GraphInfo {
|
|
59
|
+
graphId: string
|
|
60
|
+
graphName: string
|
|
61
|
+
description?: string
|
|
62
|
+
schemaExtensions?: string[]
|
|
63
|
+
tags?: string[]
|
|
64
|
+
createdAt?: string
|
|
65
|
+
status?: string
|
|
66
|
+
}
|
|
67
|
+
|
|
68
|
+
export interface CreateGraphOptions {
|
|
69
|
+
createEntity?: boolean
|
|
70
|
+
timeout?: number
|
|
71
|
+
pollInterval?: number
|
|
72
|
+
onProgress?: (message: string) => void
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
export class GraphClient {
|
|
76
|
+
private operationClient: OperationClient
|
|
77
|
+
private config: {
|
|
78
|
+
baseUrl: string
|
|
79
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
80
|
+
headers?: Record<string, string>
|
|
81
|
+
token?: string
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
constructor(config: {
|
|
85
|
+
baseUrl: string
|
|
86
|
+
credentials?: 'include' | 'same-origin' | 'omit'
|
|
87
|
+
headers?: Record<string, string>
|
|
88
|
+
token?: string
|
|
89
|
+
}) {
|
|
90
|
+
this.config = config
|
|
91
|
+
this.operationClient = new OperationClient(config)
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
/**
|
|
95
|
+
* Create a graph and wait for completion
|
|
96
|
+
*
|
|
97
|
+
* @param metadata - Graph metadata (name, description, etc.)
|
|
98
|
+
* @param initialEntity - Optional initial entity to create
|
|
99
|
+
* @param options - Additional options including:
|
|
100
|
+
* - createEntity: Whether to create the entity node and upload initial data.
|
|
101
|
+
* Only applies when initialEntity is provided. Set to false to
|
|
102
|
+
* create graph without populating entity data (useful for file-based ingestion).
|
|
103
|
+
* Defaults to true.
|
|
104
|
+
* - timeout: Maximum time to wait in milliseconds (default: 60000)
|
|
105
|
+
* - pollInterval: Time between status checks in milliseconds (default: 2000)
|
|
106
|
+
* - onProgress: Callback for progress updates
|
|
107
|
+
* @returns The graph ID when creation completes
|
|
108
|
+
*/
|
|
109
|
+
async createGraphAndWait(
|
|
110
|
+
metadata: GraphMetadataInput,
|
|
111
|
+
initialEntity?: InitialEntityInput,
|
|
112
|
+
options: CreateGraphOptions = {}
|
|
113
|
+
): Promise<string> {
|
|
114
|
+
const { createEntity = true, timeout = 60000, pollInterval = 2000, onProgress } = options
|
|
115
|
+
|
|
116
|
+
if (!this.config.token) {
|
|
117
|
+
throw new Error('No API key provided. Set token in config.')
|
|
118
|
+
}
|
|
119
|
+
|
|
120
|
+
// Build initial entity if provided
|
|
121
|
+
let initialEntityData: InitialEntityData | undefined
|
|
122
|
+
if (initialEntity) {
|
|
123
|
+
initialEntityData = {
|
|
124
|
+
name: initialEntity.name,
|
|
125
|
+
uri: initialEntity.uri,
|
|
126
|
+
category: initialEntity.category,
|
|
127
|
+
sic: initialEntity.sic,
|
|
128
|
+
sic_description: initialEntity.sicDescription,
|
|
129
|
+
}
|
|
130
|
+
}
|
|
131
|
+
|
|
132
|
+
// Build API metadata
|
|
133
|
+
const apiMetadata: GraphMetadata = {
|
|
134
|
+
graph_name: metadata.graphName,
|
|
135
|
+
description: metadata.description,
|
|
136
|
+
schema_extensions: metadata.schemaExtensions || [],
|
|
137
|
+
tags: metadata.tags || [],
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
if (onProgress) {
|
|
141
|
+
onProgress(`Creating graph: ${metadata.graphName}`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// Create graph request - SDK expects options format, not data format
|
|
145
|
+
const response = await createGraph({
|
|
146
|
+
body: {
|
|
147
|
+
metadata: apiMetadata,
|
|
148
|
+
initial_entity: initialEntityData || null,
|
|
149
|
+
create_entity: createEntity,
|
|
150
|
+
},
|
|
151
|
+
})
|
|
152
|
+
|
|
153
|
+
// Check if we got immediate graph_id
|
|
154
|
+
const responseData = response.data as GraphCreateResponse
|
|
155
|
+
if (responseData?.graph_id) {
|
|
156
|
+
if (onProgress) {
|
|
157
|
+
onProgress(`Graph created: ${responseData.graph_id}`)
|
|
158
|
+
}
|
|
159
|
+
return responseData.graph_id
|
|
160
|
+
}
|
|
161
|
+
|
|
162
|
+
// Otherwise, we have an operation_id to monitor
|
|
163
|
+
if (responseData?.operation_id) {
|
|
164
|
+
const operationId = responseData.operation_id
|
|
165
|
+
|
|
166
|
+
if (onProgress) {
|
|
167
|
+
onProgress(`Graph creation queued (operation: ${operationId})`)
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
// Poll operation status
|
|
171
|
+
const maxAttempts = Math.floor(timeout / pollInterval)
|
|
172
|
+
for (let attempt = 0; attempt < maxAttempts; attempt++) {
|
|
173
|
+
await new Promise((resolve) => setTimeout(resolve, pollInterval))
|
|
174
|
+
|
|
175
|
+
const statusResponse = await getOperationStatus({
|
|
176
|
+
path: { operation_id: operationId },
|
|
177
|
+
})
|
|
178
|
+
|
|
179
|
+
const statusData = statusResponse.data as OperationStatusResponse
|
|
180
|
+
const status = statusData?.status
|
|
181
|
+
|
|
182
|
+
if (onProgress) {
|
|
183
|
+
onProgress(`Status: ${status} (attempt ${attempt + 1}/${maxAttempts})`)
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
if (status === 'completed') {
|
|
187
|
+
const result = statusData?.result
|
|
188
|
+
const graphId = result?.graph_id
|
|
189
|
+
|
|
190
|
+
if (graphId) {
|
|
191
|
+
if (onProgress) {
|
|
192
|
+
onProgress(`Graph created: ${graphId}`)
|
|
193
|
+
}
|
|
194
|
+
return graphId
|
|
195
|
+
} else {
|
|
196
|
+
throw new Error('Operation completed but no graph_id in result')
|
|
197
|
+
}
|
|
198
|
+
} else if (status === 'failed') {
|
|
199
|
+
const error = statusData?.error || statusData?.message || 'Unknown error'
|
|
200
|
+
throw new Error(`Graph creation failed: ${error}`)
|
|
201
|
+
}
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
throw new Error(`Graph creation timed out after ${timeout}ms`)
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
throw new Error('No graph_id or operation_id in response')
|
|
208
|
+
}
|
|
209
|
+
|
|
210
|
+
/**
|
|
211
|
+
* Get information about a graph
|
|
212
|
+
*/
|
|
213
|
+
async getGraphInfo(graphId: string): Promise<GraphInfo> {
|
|
214
|
+
if (!this.config.token) {
|
|
215
|
+
throw new Error('No API key provided. Set token in config.')
|
|
216
|
+
}
|
|
217
|
+
|
|
218
|
+
// Use getGraphs to list all graphs and find the one we want
|
|
219
|
+
// Note: This is a workaround since there's no dedicated getGraph endpoint yet
|
|
220
|
+
const response = await getGraphs()
|
|
221
|
+
const graphs = (response.data as GetGraphsResponse)?.graphs || []
|
|
222
|
+
|
|
223
|
+
const graph = graphs.find((g) => g.graph_id === graphId || g.id === graphId)
|
|
224
|
+
|
|
225
|
+
if (!graph) {
|
|
226
|
+
throw new Error(`Graph not found: ${graphId}`)
|
|
227
|
+
}
|
|
228
|
+
|
|
229
|
+
return {
|
|
230
|
+
graphId: graph.graph_id || graph.id,
|
|
231
|
+
graphName: graph.graph_name || graph.name,
|
|
232
|
+
description: graph.description,
|
|
233
|
+
schemaExtensions: graph.schema_extensions,
|
|
234
|
+
tags: graph.tags,
|
|
235
|
+
createdAt: graph.created_at,
|
|
236
|
+
status: graph.status,
|
|
237
|
+
}
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
/**
|
|
241
|
+
* List all graphs
|
|
242
|
+
*/
|
|
243
|
+
async listGraphs(): Promise<GraphInfo[]> {
|
|
244
|
+
if (!this.config.token) {
|
|
245
|
+
throw new Error('No API key provided. Set token in config.')
|
|
246
|
+
}
|
|
247
|
+
|
|
248
|
+
const response = await getGraphs()
|
|
249
|
+
const graphs = (response.data as GetGraphsResponse)?.graphs || []
|
|
250
|
+
|
|
251
|
+
return graphs.map((graph) => ({
|
|
252
|
+
graphId: graph.graph_id || graph.id,
|
|
253
|
+
graphName: graph.graph_name || graph.name,
|
|
254
|
+
description: graph.description,
|
|
255
|
+
schemaExtensions: graph.schema_extensions,
|
|
256
|
+
tags: graph.tags,
|
|
257
|
+
createdAt: graph.created_at,
|
|
258
|
+
status: graph.status,
|
|
259
|
+
}))
|
|
260
|
+
}
|
|
261
|
+
|
|
262
|
+
/**
|
|
263
|
+
* Delete a graph
|
|
264
|
+
* Note: This will be implemented when the deleteGraph endpoint is available in the SDK
|
|
265
|
+
*/
|
|
266
|
+
async deleteGraph(_graphId: string): Promise<void> {
|
|
267
|
+
throw new Error('deleteGraph is not yet implemented - waiting for SDK endpoint to be generated')
|
|
268
|
+
// TODO: Implement when deleteGraph endpoint is available
|
|
269
|
+
// const response = await deleteGraph({ path: { graph_id: _graphId } })
|
|
270
|
+
// if (response.status !== 200 && response.status !== 204) {
|
|
271
|
+
// throw new Error(`Failed to delete graph: ${response.status}`)
|
|
272
|
+
// }
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
/**
|
|
276
|
+
* Clean up resources
|
|
277
|
+
*/
|
|
278
|
+
close(): void {
|
|
279
|
+
this.operationClient.closeAll()
|
|
280
|
+
}
|
|
281
|
+
}
|
|
@@ -44,7 +44,7 @@ export declare class TableIngestClient {
|
|
|
44
44
|
* This method handles the complete 3-step upload process:
|
|
45
45
|
* 1. Get presigned upload URL
|
|
46
46
|
* 2. Upload file to S3
|
|
47
|
-
* 3.
|
|
47
|
+
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
48
48
|
*
|
|
49
49
|
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
50
50
|
*/
|
|
@@ -19,7 +19,7 @@ class TableIngestClient {
|
|
|
19
19
|
* This method handles the complete 3-step upload process:
|
|
20
20
|
* 1. Get presigned upload URL
|
|
21
21
|
* 2. Upload file to S3
|
|
22
|
-
* 3.
|
|
22
|
+
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
23
23
|
*
|
|
24
24
|
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
25
25
|
*/
|
|
@@ -32,7 +32,7 @@ class TableIngestClient {
|
|
|
32
32
|
file_name: fileName,
|
|
33
33
|
content_type: 'application/x-parquet',
|
|
34
34
|
};
|
|
35
|
-
const uploadUrlResponse = await (0, sdk_gen_1.
|
|
35
|
+
const uploadUrlResponse = await (0, sdk_gen_1.getUploadUrl)({
|
|
36
36
|
path: { graph_id: graphId, table_name: tableName },
|
|
37
37
|
body: uploadRequest,
|
|
38
38
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
@@ -77,36 +77,36 @@ class TableIngestClient {
|
|
|
77
77
|
error: `S3 upload failed: ${s3Response.status} ${s3Response.statusText}`,
|
|
78
78
|
};
|
|
79
79
|
}
|
|
80
|
-
// Step 3:
|
|
81
|
-
options.onProgress?.(`
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
const estimatedRowCount = Math.floor(fileSize / 100);
|
|
85
|
-
const metadataUpdate = {
|
|
86
|
-
file_size_bytes: fileSize,
|
|
87
|
-
row_count: estimatedRowCount,
|
|
80
|
+
// Step 3: Mark file as uploaded (backend validates and calculates size/row count)
|
|
81
|
+
options.onProgress?.(`Marking ${fileName} as uploaded...`);
|
|
82
|
+
const statusUpdate = {
|
|
83
|
+
status: 'uploaded',
|
|
88
84
|
};
|
|
89
|
-
const updateResponse = await (0, sdk_gen_1.
|
|
85
|
+
const updateResponse = await (0, sdk_gen_1.updateFileStatus)({
|
|
90
86
|
path: { graph_id: graphId, file_id: fileId },
|
|
91
|
-
body:
|
|
87
|
+
body: statusUpdate,
|
|
92
88
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
93
89
|
});
|
|
94
|
-
if (updateResponse.error) {
|
|
90
|
+
if (updateResponse.error || !updateResponse.data) {
|
|
95
91
|
return {
|
|
96
92
|
fileId,
|
|
97
93
|
fileSize,
|
|
98
|
-
rowCount:
|
|
94
|
+
rowCount: 0,
|
|
99
95
|
tableName,
|
|
100
96
|
fileName,
|
|
101
97
|
success: false,
|
|
102
|
-
error: 'Failed to
|
|
98
|
+
error: 'Failed to complete file upload',
|
|
103
99
|
};
|
|
104
100
|
}
|
|
105
|
-
|
|
101
|
+
// Extract size and row count from response (calculated by backend)
|
|
102
|
+
const responseData = updateResponse.data;
|
|
103
|
+
const actualFileSize = responseData.file_size_bytes || 0;
|
|
104
|
+
const actualRowCount = responseData.row_count || 0;
|
|
105
|
+
options.onProgress?.(`✅ Uploaded ${fileName} (${actualFileSize.toLocaleString()} bytes, ${actualRowCount.toLocaleString()} rows)`);
|
|
106
106
|
return {
|
|
107
107
|
fileId,
|
|
108
|
-
fileSize,
|
|
109
|
-
rowCount:
|
|
108
|
+
fileSize: actualFileSize,
|
|
109
|
+
rowCount: actualRowCount,
|
|
110
110
|
tableName,
|
|
111
111
|
fileName,
|
|
112
112
|
success: true,
|
|
@@ -129,7 +129,7 @@ class TableIngestClient {
|
|
|
129
129
|
*/
|
|
130
130
|
async listStagingTables(graphId) {
|
|
131
131
|
try {
|
|
132
|
-
const response = await (0, sdk_gen_1.
|
|
132
|
+
const response = await (0, sdk_gen_1.listTables)({
|
|
133
133
|
path: { graph_id: graphId },
|
|
134
134
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
135
135
|
});
|
|
@@ -160,7 +160,7 @@ class TableIngestClient {
|
|
|
160
160
|
ignore_errors: options.ignoreErrors ?? true,
|
|
161
161
|
rebuild: options.rebuild ?? false,
|
|
162
162
|
};
|
|
163
|
-
const response = await (0, sdk_gen_1.
|
|
163
|
+
const response = await (0, sdk_gen_1.ingestTables)({
|
|
164
164
|
path: { graph_id: graphId },
|
|
165
165
|
body: ingestRequest,
|
|
166
166
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
@@ -153,7 +153,7 @@ describe('TableIngestClient', () => {
|
|
|
153
153
|
const result = await tableClient.uploadParquetFile('graph_123', 'Entity', buffer)
|
|
154
154
|
|
|
155
155
|
expect(result.success).toBe(false)
|
|
156
|
-
expect(result.error).toContain('Failed to
|
|
156
|
+
expect(result.error).toContain('Failed to complete file upload')
|
|
157
157
|
})
|
|
158
158
|
})
|
|
159
159
|
|
|
@@ -7,15 +7,10 @@
|
|
|
7
7
|
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
8
8
|
*/
|
|
9
9
|
|
|
10
|
-
import {
|
|
11
|
-
getUploadUrlV1GraphsGraphIdTablesTableNameFilesPost,
|
|
12
|
-
ingestTablesV1GraphsGraphIdTablesIngestPost,
|
|
13
|
-
listTablesV1GraphsGraphIdTablesGet,
|
|
14
|
-
updateFileV1GraphsGraphIdTablesFilesFileIdPatch,
|
|
15
|
-
} from '../sdk/sdk.gen'
|
|
10
|
+
import { getUploadUrl, ingestTables, listTables, updateFileStatus } from '../sdk/sdk.gen'
|
|
16
11
|
import type {
|
|
17
12
|
BulkIngestRequest,
|
|
18
|
-
|
|
13
|
+
FileStatusUpdate,
|
|
19
14
|
FileUploadRequest,
|
|
20
15
|
FileUploadResponse,
|
|
21
16
|
TableListResponse,
|
|
@@ -83,7 +78,7 @@ export class TableIngestClient {
|
|
|
83
78
|
* This method handles the complete 3-step upload process:
|
|
84
79
|
* 1. Get presigned upload URL
|
|
85
80
|
* 2. Upload file to S3
|
|
86
|
-
* 3.
|
|
81
|
+
* 3. Mark file as 'uploaded' (backend validates, calculates size/row count)
|
|
87
82
|
*
|
|
88
83
|
* Supports File (browser), Blob (browser), Buffer (Node.js), and ReadableStream.
|
|
89
84
|
*/
|
|
@@ -104,7 +99,7 @@ export class TableIngestClient {
|
|
|
104
99
|
content_type: 'application/x-parquet',
|
|
105
100
|
}
|
|
106
101
|
|
|
107
|
-
const uploadUrlResponse = await
|
|
102
|
+
const uploadUrlResponse = await getUploadUrl({
|
|
108
103
|
path: { graph_id: graphId, table_name: tableName },
|
|
109
104
|
body: uploadRequest,
|
|
110
105
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
@@ -157,44 +152,44 @@ export class TableIngestClient {
|
|
|
157
152
|
}
|
|
158
153
|
}
|
|
159
154
|
|
|
160
|
-
// Step 3:
|
|
161
|
-
options.onProgress?.(`
|
|
155
|
+
// Step 3: Mark file as uploaded (backend validates and calculates size/row count)
|
|
156
|
+
options.onProgress?.(`Marking ${fileName} as uploaded...`)
|
|
162
157
|
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
const estimatedRowCount = Math.floor(fileSize / 100)
|
|
166
|
-
|
|
167
|
-
const metadataUpdate: FileUpdateRequest = {
|
|
168
|
-
file_size_bytes: fileSize,
|
|
169
|
-
row_count: estimatedRowCount,
|
|
158
|
+
const statusUpdate: FileStatusUpdate = {
|
|
159
|
+
status: 'uploaded',
|
|
170
160
|
}
|
|
171
161
|
|
|
172
|
-
const updateResponse = await
|
|
162
|
+
const updateResponse = await updateFileStatus({
|
|
173
163
|
path: { graph_id: graphId, file_id: fileId },
|
|
174
|
-
body:
|
|
164
|
+
body: statusUpdate,
|
|
175
165
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
176
166
|
})
|
|
177
167
|
|
|
178
|
-
if (updateResponse.error) {
|
|
168
|
+
if (updateResponse.error || !updateResponse.data) {
|
|
179
169
|
return {
|
|
180
170
|
fileId,
|
|
181
171
|
fileSize,
|
|
182
|
-
rowCount:
|
|
172
|
+
rowCount: 0,
|
|
183
173
|
tableName,
|
|
184
174
|
fileName,
|
|
185
175
|
success: false,
|
|
186
|
-
error: 'Failed to
|
|
176
|
+
error: 'Failed to complete file upload',
|
|
187
177
|
}
|
|
188
178
|
}
|
|
189
179
|
|
|
180
|
+
// Extract size and row count from response (calculated by backend)
|
|
181
|
+
const responseData = updateResponse.data as any
|
|
182
|
+
const actualFileSize = responseData.file_size_bytes || 0
|
|
183
|
+
const actualRowCount = responseData.row_count || 0
|
|
184
|
+
|
|
190
185
|
options.onProgress?.(
|
|
191
|
-
`✅ Uploaded ${fileName} (${
|
|
186
|
+
`✅ Uploaded ${fileName} (${actualFileSize.toLocaleString()} bytes, ${actualRowCount.toLocaleString()} rows)`
|
|
192
187
|
)
|
|
193
188
|
|
|
194
189
|
return {
|
|
195
190
|
fileId,
|
|
196
|
-
fileSize,
|
|
197
|
-
rowCount:
|
|
191
|
+
fileSize: actualFileSize,
|
|
192
|
+
rowCount: actualRowCount,
|
|
198
193
|
tableName,
|
|
199
194
|
fileName,
|
|
200
195
|
success: true,
|
|
@@ -217,7 +212,7 @@ export class TableIngestClient {
|
|
|
217
212
|
*/
|
|
218
213
|
async listStagingTables(graphId: string): Promise<TableInfo[]> {
|
|
219
214
|
try {
|
|
220
|
-
const response = await
|
|
215
|
+
const response = await listTables({
|
|
221
216
|
path: { graph_id: graphId },
|
|
222
217
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
223
218
|
})
|
|
@@ -255,7 +250,7 @@ export class TableIngestClient {
|
|
|
255
250
|
rebuild: options.rebuild ?? false,
|
|
256
251
|
}
|
|
257
252
|
|
|
258
|
-
const response = await
|
|
253
|
+
const response = await ingestTables({
|
|
259
254
|
path: { graph_id: graphId },
|
|
260
255
|
body: ingestRequest,
|
|
261
256
|
query: this.config.token ? { token: this.config.token } : undefined,
|
|
@@ -63,7 +63,7 @@ export declare function useStreamingQuery(graphId: string): {
|
|
|
63
63
|
export declare function useOperation<T = any>(operationId?: string): {
|
|
64
64
|
monitor: (id: string, timeout?: number) => Promise<OperationResult<T> | null>;
|
|
65
65
|
cancel: (id: string) => Promise<void>;
|
|
66
|
-
status: "error" | "
|
|
66
|
+
status: "error" | "completed" | "idle" | "running";
|
|
67
67
|
progress: OperationProgress;
|
|
68
68
|
error: Error;
|
|
69
69
|
result: OperationResult<T>;
|
|
@@ -6,6 +6,7 @@ import { OperationClient } from './OperationClient';
|
|
|
6
6
|
import { QueryClient } from './QueryClient';
|
|
7
7
|
import { SSEClient } from './SSEClient';
|
|
8
8
|
import { TableIngestClient } from './TableIngestClient';
|
|
9
|
+
import { GraphClient } from './GraphClient';
|
|
9
10
|
export interface RoboSystemsExtensionConfig {
|
|
10
11
|
baseUrl?: string;
|
|
11
12
|
credentials?: 'include' | 'same-origin' | 'omit';
|
|
@@ -18,6 +19,7 @@ export declare class RoboSystemsExtensions {
|
|
|
18
19
|
readonly query: QueryClient;
|
|
19
20
|
readonly operations: OperationClient;
|
|
20
21
|
readonly tables: TableIngestClient;
|
|
22
|
+
readonly graphs: GraphClient;
|
|
21
23
|
private config;
|
|
22
24
|
constructor(config?: RoboSystemsExtensionConfig);
|
|
23
25
|
/**
|
|
@@ -37,11 +39,13 @@ export * from './OperationClient';
|
|
|
37
39
|
export * from './QueryClient';
|
|
38
40
|
export * from './SSEClient';
|
|
39
41
|
export * from './TableIngestClient';
|
|
40
|
-
export
|
|
42
|
+
export * from './GraphClient';
|
|
43
|
+
export { OperationClient, QueryClient, SSEClient, TableIngestClient, GraphClient };
|
|
41
44
|
export { useMultipleOperations, useOperation, useQuery, useSDKClients, useStreamingQuery, useTableUpload, } from './hooks';
|
|
42
45
|
export declare const extensions: {
|
|
43
46
|
readonly query: QueryClient;
|
|
44
47
|
readonly operations: OperationClient;
|
|
48
|
+
readonly graphs: GraphClient;
|
|
45
49
|
monitorOperation: (operationId: string, onProgress?: (progress: any) => void) => Promise<any>;
|
|
46
50
|
createSSEClient: () => SSEClient;
|
|
47
51
|
close: () => void;
|
package/sdk-extensions/index.js
CHANGED
|
@@ -18,7 +18,7 @@ var __exportStar = (this && this.__exportStar) || function(m, exports) {
|
|
|
18
18
|
for (var p in m) if (p !== "default" && !Object.prototype.hasOwnProperty.call(exports, p)) __createBinding(exports, m, p);
|
|
19
19
|
};
|
|
20
20
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
21
|
-
exports.streamQuery = exports.executeQuery = exports.monitorOperation = exports.extensions = exports.useTableUpload = exports.useStreamingQuery = exports.useSDKClients = exports.useQuery = exports.useOperation = exports.useMultipleOperations = exports.TableIngestClient = exports.SSEClient = exports.QueryClient = exports.OperationClient = exports.RoboSystemsExtensions = void 0;
|
|
21
|
+
exports.streamQuery = exports.executeQuery = exports.monitorOperation = exports.extensions = exports.useTableUpload = exports.useStreamingQuery = exports.useSDKClients = exports.useQuery = exports.useOperation = exports.useMultipleOperations = exports.GraphClient = exports.TableIngestClient = exports.SSEClient = exports.QueryClient = exports.OperationClient = exports.RoboSystemsExtensions = void 0;
|
|
22
22
|
const client_gen_1 = require("../sdk/client.gen");
|
|
23
23
|
const config_1 = require("./config");
|
|
24
24
|
const OperationClient_1 = require("./OperationClient");
|
|
@@ -29,6 +29,8 @@ const SSEClient_1 = require("./SSEClient");
|
|
|
29
29
|
Object.defineProperty(exports, "SSEClient", { enumerable: true, get: function () { return SSEClient_1.SSEClient; } });
|
|
30
30
|
const TableIngestClient_1 = require("./TableIngestClient");
|
|
31
31
|
Object.defineProperty(exports, "TableIngestClient", { enumerable: true, get: function () { return TableIngestClient_1.TableIngestClient; } });
|
|
32
|
+
const GraphClient_1 = require("./GraphClient");
|
|
33
|
+
Object.defineProperty(exports, "GraphClient", { enumerable: true, get: function () { return GraphClient_1.GraphClient; } });
|
|
32
34
|
class RoboSystemsExtensions {
|
|
33
35
|
constructor(config = {}) {
|
|
34
36
|
// Get base URL from SDK client config or use provided/default
|
|
@@ -62,6 +64,12 @@ class RoboSystemsExtensions {
|
|
|
62
64
|
token: this.config.token,
|
|
63
65
|
headers: this.config.headers,
|
|
64
66
|
});
|
|
67
|
+
this.graphs = new GraphClient_1.GraphClient({
|
|
68
|
+
baseUrl: this.config.baseUrl,
|
|
69
|
+
credentials: this.config.credentials,
|
|
70
|
+
token: this.config.token,
|
|
71
|
+
headers: this.config.headers,
|
|
72
|
+
});
|
|
65
73
|
}
|
|
66
74
|
/**
|
|
67
75
|
* Convenience method to monitor any operation
|
|
@@ -88,6 +96,7 @@ class RoboSystemsExtensions {
|
|
|
88
96
|
close() {
|
|
89
97
|
this.query.close();
|
|
90
98
|
this.operations.closeAll();
|
|
99
|
+
this.graphs.close();
|
|
91
100
|
}
|
|
92
101
|
}
|
|
93
102
|
exports.RoboSystemsExtensions = RoboSystemsExtensions;
|
|
@@ -96,6 +105,7 @@ __exportStar(require("./OperationClient"), exports);
|
|
|
96
105
|
__exportStar(require("./QueryClient"), exports);
|
|
97
106
|
__exportStar(require("./SSEClient"), exports);
|
|
98
107
|
__exportStar(require("./TableIngestClient"), exports);
|
|
108
|
+
__exportStar(require("./GraphClient"), exports);
|
|
99
109
|
// Export React hooks
|
|
100
110
|
var hooks_1 = require("./hooks");
|
|
101
111
|
Object.defineProperty(exports, "useMultipleOperations", { enumerable: true, get: function () { return hooks_1.useMultipleOperations; } });
|
|
@@ -119,6 +129,9 @@ exports.extensions = {
|
|
|
119
129
|
get operations() {
|
|
120
130
|
return getExtensions().operations;
|
|
121
131
|
},
|
|
132
|
+
get graphs() {
|
|
133
|
+
return getExtensions().graphs;
|
|
134
|
+
},
|
|
122
135
|
monitorOperation: (operationId, onProgress) => getExtensions().monitorOperation(operationId, onProgress),
|
|
123
136
|
createSSEClient: () => getExtensions().createSSEClient(),
|
|
124
137
|
close: () => getExtensions().close(),
|
|
@@ -24,10 +24,12 @@ describe('RoboSystemsExtensions', () => {
|
|
|
24
24
|
expect(extensions.query).toBeDefined()
|
|
25
25
|
expect(extensions.operations).toBeDefined()
|
|
26
26
|
expect(extensions.tables).toBeDefined()
|
|
27
|
+
expect(extensions.graphs).toBeDefined()
|
|
27
28
|
// Verify clients have expected methods
|
|
28
29
|
expect(typeof extensions.query.executeQuery).toBe('function')
|
|
29
30
|
expect(typeof extensions.operations.monitorOperation).toBe('function')
|
|
30
31
|
expect(typeof extensions.tables.uploadParquetFile).toBe('function')
|
|
32
|
+
expect(typeof extensions.graphs.createGraphAndWait).toBe('function')
|
|
31
33
|
})
|
|
32
34
|
|
|
33
35
|
it('should create instance with custom baseUrl', () => {
|
|
@@ -38,6 +40,7 @@ describe('RoboSystemsExtensions', () => {
|
|
|
38
40
|
expect(extensions.query).toBeDefined()
|
|
39
41
|
expect(extensions.operations).toBeDefined()
|
|
40
42
|
expect(extensions.tables).toBeDefined()
|
|
43
|
+
expect(extensions.graphs).toBeDefined()
|
|
41
44
|
})
|
|
42
45
|
|
|
43
46
|
it('should create instance with JWT token', () => {
|
|
@@ -88,6 +91,7 @@ describe('RoboSystemsExtensions', () => {
|
|
|
88
91
|
expect(extensions.query).toBeDefined()
|
|
89
92
|
expect(extensions.operations).toBeDefined()
|
|
90
93
|
expect(extensions.tables).toBeDefined()
|
|
94
|
+
expect(extensions.graphs).toBeDefined()
|
|
91
95
|
})
|
|
92
96
|
})
|
|
93
97
|
|
|
@@ -152,11 +156,13 @@ describe('RoboSystemsExtensions', () => {
|
|
|
152
156
|
|
|
153
157
|
const queryCloseSpy = vi.spyOn(extensions.query, 'close')
|
|
154
158
|
const operationsCloseSpy = vi.spyOn(extensions.operations, 'closeAll')
|
|
159
|
+
const graphsCloseSpy = vi.spyOn(extensions.graphs, 'close')
|
|
155
160
|
|
|
156
161
|
extensions.close()
|
|
157
162
|
|
|
158
163
|
expect(queryCloseSpy).toHaveBeenCalled()
|
|
159
164
|
expect(operationsCloseSpy).toHaveBeenCalled()
|
|
165
|
+
expect(graphsCloseSpy).toHaveBeenCalled()
|
|
160
166
|
})
|
|
161
167
|
|
|
162
168
|
it('should not throw when called multiple times', () => {
|
|
@@ -188,9 +194,11 @@ describe('RoboSystemsExtensions', () => {
|
|
|
188
194
|
expect(extensions.query).toBeDefined()
|
|
189
195
|
expect(extensions.operations).toBeDefined()
|
|
190
196
|
expect(extensions.tables).toBeDefined()
|
|
197
|
+
expect(extensions.graphs).toBeDefined()
|
|
191
198
|
expect(typeof extensions.query.executeQuery).toBe('function')
|
|
192
199
|
expect(typeof extensions.operations.monitorOperation).toBe('function')
|
|
193
200
|
expect(typeof extensions.tables.uploadParquetFile).toBe('function')
|
|
201
|
+
expect(typeof extensions.graphs.createGraphAndWait).toBe('function')
|
|
194
202
|
})
|
|
195
203
|
|
|
196
204
|
it('should use SDK client baseUrl when no baseUrl provided', () => {
|
|
@@ -200,6 +208,20 @@ describe('RoboSystemsExtensions', () => {
|
|
|
200
208
|
expect(extensions.query).toBeDefined()
|
|
201
209
|
expect(extensions.operations).toBeDefined()
|
|
202
210
|
expect(extensions.tables).toBeDefined()
|
|
211
|
+
expect(extensions.graphs).toBeDefined()
|
|
212
|
+
})
|
|
213
|
+
})
|
|
214
|
+
|
|
215
|
+
describe('graphs client', () => {
|
|
216
|
+
it('should have graphs client with all methods', () => {
|
|
217
|
+
const extensions = new RoboSystemsExtensions()
|
|
218
|
+
|
|
219
|
+
expect(extensions.graphs).toBeDefined()
|
|
220
|
+
expect(typeof extensions.graphs.createGraphAndWait).toBe('function')
|
|
221
|
+
expect(typeof extensions.graphs.getGraphInfo).toBe('function')
|
|
222
|
+
expect(typeof extensions.graphs.listGraphs).toBe('function')
|
|
223
|
+
expect(typeof extensions.graphs.deleteGraph).toBe('function')
|
|
224
|
+
expect(typeof extensions.graphs.close).toBe('function')
|
|
203
225
|
})
|
|
204
226
|
})
|
|
205
227
|
})
|