@vertesia/client 1.5.0-dev.20260717.131047Z → 1.5.0-dev.20260725.083715Z
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/lib/AppsApi.d.ts +41 -7
- package/lib/AppsApi.d.ts.map +1 -1
- package/lib/AppsApi.js +72 -7
- package/lib/AppsApi.js.map +1 -1
- package/lib/AuditTrailApi.d.ts +2 -1
- package/lib/AuditTrailApi.d.ts.map +1 -1
- package/lib/AuditTrailApi.js +3 -0
- package/lib/AuditTrailApi.js.map +1 -1
- package/lib/ProjectsApi.d.ts +3 -1
- package/lib/ProjectsApi.d.ts.map +1 -1
- package/lib/ProjectsApi.js +16 -8
- package/lib/ProjectsApi.js.map +1 -1
- package/lib/ViewsApi.d.ts +21 -0
- package/lib/ViewsApi.d.ts.map +1 -0
- package/lib/ViewsApi.js +41 -0
- package/lib/ViewsApi.js.map +1 -0
- package/lib/client.d.ts +3 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +4 -1
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +1 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +1 -0
- package/lib/index.js.map +1 -1
- package/lib/store/AgentsApi.d.ts +5 -1
- package/lib/store/AgentsApi.d.ts.map +1 -1
- package/lib/store/AgentsApi.js +8 -0
- package/lib/store/AgentsApi.js.map +1 -1
- package/lib/store/AnalyzeDocApi.d.ts +9 -11
- package/lib/store/AnalyzeDocApi.d.ts.map +1 -1
- package/lib/store/AnalyzeDocApi.js +12 -36
- package/lib/store/AnalyzeDocApi.js.map +1 -1
- package/lib/store/FilesApi.d.ts.map +1 -1
- package/lib/store/FilesApi.js +10 -4
- package/lib/store/FilesApi.js.map +1 -1
- package/lib/store/ObjectsApi.d.ts.map +1 -1
- package/lib/store/ObjectsApi.js +3 -2
- package/lib/store/ObjectsApi.js.map +1 -1
- package/lib/store/ViewsApi.d.ts +12 -0
- package/lib/store/ViewsApi.d.ts.map +1 -0
- package/lib/store/ViewsApi.js +17 -0
- package/lib/store/ViewsApi.js.map +1 -0
- package/lib/store/client.d.ts +2 -0
- package/lib/store/client.d.ts.map +1 -1
- package/lib/store/client.js +2 -0
- package/lib/store/client.js.map +1 -1
- package/lib/store/index.d.ts +1 -0
- package/lib/store/index.d.ts.map +1 -1
- package/lib/store/index.js +1 -0
- package/lib/store/index.js.map +1 -1
- package/lib/store/uploadMimeType.d.ts +3 -0
- package/lib/store/uploadMimeType.d.ts.map +1 -0
- package/lib/store/uploadMimeType.js +11 -0
- package/lib/store/uploadMimeType.js.map +1 -0
- package/lib/vertesia-client.js +5 -5
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +8 -8
- package/src/AppsApi.test.ts +132 -0
- package/src/AppsApi.ts +100 -9
- package/src/AuditTrailApi.ts +10 -1
- package/src/ProjectsApi.test.ts +33 -0
- package/src/ProjectsApi.ts +19 -8
- package/src/ViewsApi.test.ts +36 -0
- package/src/ViewsApi.ts +60 -0
- package/src/client.ts +4 -1
- package/src/index.ts +1 -0
- package/src/store/AgentsApi.ts +17 -0
- package/src/store/AnalyzeDocApi.ts +16 -54
- package/src/store/FilesApi.ts +10 -4
- package/src/store/ObjectsApi.ts +3 -2
- package/src/store/ViewsApi.test.ts +33 -0
- package/src/store/ViewsApi.ts +20 -0
- package/src/store/client.ts +2 -0
- package/src/store/index.ts +1 -0
- package/src/store/uploadMimeType.test.ts +22 -0
- package/src/store/uploadMimeType.ts +16 -0
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@vertesia/client",
|
|
3
|
-
"version": "1.5.0-dev.
|
|
3
|
+
"version": "1.5.0-dev.20260725.083715Z",
|
|
4
4
|
"type": "module",
|
|
5
5
|
"main": "./lib/index.js",
|
|
6
6
|
"types": "./lib/index.d.ts",
|
|
@@ -11,17 +11,17 @@
|
|
|
11
11
|
],
|
|
12
12
|
"license": "Apache-2.0",
|
|
13
13
|
"devDependencies": {
|
|
14
|
-
"@types/node": "^24.13.
|
|
15
|
-
"rolldown": "1.
|
|
14
|
+
"@types/node": "^24.13.3",
|
|
15
|
+
"rolldown": "1.2.0",
|
|
16
16
|
"typescript": "^6.0.3",
|
|
17
|
-
"vitest": "^4.1.
|
|
17
|
+
"vitest": "^4.1.10",
|
|
18
18
|
"@vertesia/tsconfig": "0.1.0"
|
|
19
19
|
},
|
|
20
20
|
"dependencies": {
|
|
21
21
|
"eventsource": "^4.1.0",
|
|
22
|
-
"@llumiverse/common": "1.5.0-dev.
|
|
23
|
-
"@vertesia/
|
|
24
|
-
"@vertesia/
|
|
22
|
+
"@llumiverse/common": "1.5.0-dev.20260725.065646Z",
|
|
23
|
+
"@vertesia/api-fetch-client": "1.5.0-dev.20260725.083715Z",
|
|
24
|
+
"@vertesia/common": "1.5.0-dev.20260725.083715Z"
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
@@ -48,7 +48,7 @@
|
|
|
48
48
|
"ai",
|
|
49
49
|
"typescript"
|
|
50
50
|
],
|
|
51
|
-
"gitHead": "
|
|
51
|
+
"gitHead": "57bcc2f27dd17b3387f27c18e89329c4c37f98ac",
|
|
52
52
|
"scripts": {
|
|
53
53
|
"lint": "biome lint src",
|
|
54
54
|
"clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
|
|
@@ -0,0 +1,132 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { VertesiaClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
describe('AppsApi', () => {
|
|
5
|
+
it('starts an in-place version rebuild without a caller-controlled payload', async () => {
|
|
6
|
+
const requests: Request[] = [];
|
|
7
|
+
const fetchMock = vi.fn(async () =>
|
|
8
|
+
Response.json({
|
|
9
|
+
workflow_id: 'workflow-1',
|
|
10
|
+
run_id: 'run-1',
|
|
11
|
+
app_id: 'sample-app',
|
|
12
|
+
version_id: 'version-1',
|
|
13
|
+
rebuild_version_record_id: 'record-1',
|
|
14
|
+
}),
|
|
15
|
+
);
|
|
16
|
+
const client = new VertesiaClient({
|
|
17
|
+
serverUrl: 'https://studio.example.com',
|
|
18
|
+
storeUrl: 'https://zeno.example.com',
|
|
19
|
+
fetch: fetchMock,
|
|
20
|
+
onRequest: (request) => requests.push(request),
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
const result = await client.apps.rebuildVersion('record-1');
|
|
24
|
+
|
|
25
|
+
expect(result.version_id).toBe('version-1');
|
|
26
|
+
expect(requests[0]?.method).toBe('POST');
|
|
27
|
+
expect(requests[0]?.url).toBe('https://studio.example.com/api/v1/apps/versions/record-1/rebuild');
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
it('deletes a version through its dedicated endpoint', async () => {
|
|
31
|
+
const requests: Request[] = [];
|
|
32
|
+
const fetchMock = vi.fn(async () =>
|
|
33
|
+
Response.json({
|
|
34
|
+
id: 'record-1',
|
|
35
|
+
app_id: 'sample-app',
|
|
36
|
+
version_id: 'version-1',
|
|
37
|
+
deleted: true,
|
|
38
|
+
warnings: [],
|
|
39
|
+
}),
|
|
40
|
+
);
|
|
41
|
+
const client = new VertesiaClient({
|
|
42
|
+
serverUrl: 'https://studio.example.com',
|
|
43
|
+
storeUrl: 'https://zeno.example.com',
|
|
44
|
+
fetch: fetchMock,
|
|
45
|
+
onRequest: (request) => requests.push(request),
|
|
46
|
+
});
|
|
47
|
+
|
|
48
|
+
const result = await client.apps.deleteVersion('record-1');
|
|
49
|
+
|
|
50
|
+
expect(result.deleted).toBe(true);
|
|
51
|
+
expect(requests[0]?.method).toBe('DELETE');
|
|
52
|
+
expect(requests[0]?.url).toBe('https://studio.example.com/api/v1/apps/versions/record-1');
|
|
53
|
+
});
|
|
54
|
+
|
|
55
|
+
it('returns the original response bytes and content type', async () => {
|
|
56
|
+
const requests: Request[] = [];
|
|
57
|
+
const bytes = new Uint8Array([0, 255, 10, 42]);
|
|
58
|
+
const fetchMock = vi.fn(
|
|
59
|
+
async () =>
|
|
60
|
+
new Response(bytes, {
|
|
61
|
+
status: 200,
|
|
62
|
+
headers: { 'content-type': 'application/octet-stream' },
|
|
63
|
+
}),
|
|
64
|
+
);
|
|
65
|
+
const client = new VertesiaClient({
|
|
66
|
+
serverUrl: 'https://studio.example.com',
|
|
67
|
+
storeUrl: 'https://zeno.example.com',
|
|
68
|
+
fetch: fetchMock,
|
|
69
|
+
onRequest: (request) => requests.push(request),
|
|
70
|
+
});
|
|
71
|
+
|
|
72
|
+
const response = await client.apps.getRepoFile('sample-app', 'docs/file.bin', { ref: 'feature/demo' });
|
|
73
|
+
|
|
74
|
+
expect(response.headers.get('content-type')).toBe('application/octet-stream');
|
|
75
|
+
expect(new Uint8Array(await response.arrayBuffer())).toEqual(bytes);
|
|
76
|
+
expect(requests[0]?.url).toBe(
|
|
77
|
+
'https://studio.example.com/api/v1/apps/sample-app/repo/file?path=docs%2Ffile.bin&ref=feature%2Fdemo',
|
|
78
|
+
);
|
|
79
|
+
});
|
|
80
|
+
|
|
81
|
+
it('uploads multiple documents as one multipart commit request', async () => {
|
|
82
|
+
const requests: Request[] = [];
|
|
83
|
+
const fetchMock = vi.fn(async () =>
|
|
84
|
+
Response.json({
|
|
85
|
+
ref: 'main',
|
|
86
|
+
previous_commit: '1'.repeat(40),
|
|
87
|
+
commit: '2'.repeat(40),
|
|
88
|
+
paths: ['docs/guide.md', 'docs/diagram.png'],
|
|
89
|
+
}),
|
|
90
|
+
);
|
|
91
|
+
const client = new VertesiaClient({
|
|
92
|
+
serverUrl: 'https://studio.example.com',
|
|
93
|
+
storeUrl: 'https://zeno.example.com',
|
|
94
|
+
fetch: fetchMock,
|
|
95
|
+
onRequest: (request) => requests.push(request),
|
|
96
|
+
});
|
|
97
|
+
|
|
98
|
+
const result = await client.apps.commitRepoDocuments(
|
|
99
|
+
'sample-app',
|
|
100
|
+
[
|
|
101
|
+
{ path: 'docs/guide.md', content: new Blob(['# Guide']), fileName: 'guide.md' },
|
|
102
|
+
{ path: 'docs/diagram.png', content: new Blob([new Uint8Array([1, 2, 3])]), fileName: 'diagram.png' },
|
|
103
|
+
],
|
|
104
|
+
{ ref: 'main', expectedHead: '1'.repeat(40), message: 'Add docs' },
|
|
105
|
+
);
|
|
106
|
+
|
|
107
|
+
expect(result.commit).toBe('2'.repeat(40));
|
|
108
|
+
const request = requests[0];
|
|
109
|
+
if (!request) {
|
|
110
|
+
throw new Error('Expected a multipart document request');
|
|
111
|
+
}
|
|
112
|
+
expect(request.url).toBe('https://studio.example.com/api/v1/apps/sample-app/repo/documents');
|
|
113
|
+
expect(request.headers.get('content-type')).toContain('multipart/form-data; boundary=');
|
|
114
|
+
const form = await request.formData();
|
|
115
|
+
expect(JSON.parse(String(form.get('metadata')))).toEqual({
|
|
116
|
+
ref: 'main',
|
|
117
|
+
expected_head: '1'.repeat(40),
|
|
118
|
+
message: 'Add docs',
|
|
119
|
+
files: [
|
|
120
|
+
{ field: 'file_0', path: 'docs/guide.md' },
|
|
121
|
+
{ field: 'file_1', path: 'docs/diagram.png' },
|
|
122
|
+
],
|
|
123
|
+
});
|
|
124
|
+
const guideFile = form.get('file_0');
|
|
125
|
+
const diagramFile = form.get('file_1');
|
|
126
|
+
if (!(guideFile instanceof File) || !(diagramFile instanceof File)) {
|
|
127
|
+
throw new Error('Expected multipart file entries');
|
|
128
|
+
}
|
|
129
|
+
expect(guideFile.name).toBe('guide.md');
|
|
130
|
+
expect(diagramFile.size).toBe(3);
|
|
131
|
+
});
|
|
132
|
+
});
|
package/src/AppsApi.ts
CHANGED
|
@@ -1,8 +1,9 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase, type ServerError } from '@vertesia/api-fetch-client';
|
|
2
2
|
import type {
|
|
3
|
-
ActivateAppVersionResponse,
|
|
4
3
|
AppBuildProgress,
|
|
5
4
|
AppDeleteSummary,
|
|
5
|
+
AppDevelopmentTaskDetails,
|
|
6
|
+
AppDevelopmentTaskList,
|
|
6
7
|
AppInspectionResult,
|
|
7
8
|
AppInstallation,
|
|
8
9
|
AppInstallationKind,
|
|
@@ -13,17 +14,25 @@ import type {
|
|
|
13
14
|
AppManifestData,
|
|
14
15
|
AppPackage,
|
|
15
16
|
AppPackageScope,
|
|
16
|
-
|
|
17
|
+
AppRepoBranch,
|
|
18
|
+
AppRepoCommits,
|
|
19
|
+
AppRepoDocumentCommit,
|
|
17
20
|
AppRepoRefs,
|
|
18
21
|
AppRepoTree,
|
|
22
|
+
AppScaffoldProgress,
|
|
19
23
|
AppToolCollection,
|
|
20
24
|
AppVersionListQuery,
|
|
21
25
|
AppVersionRecord,
|
|
22
26
|
CountResult,
|
|
27
|
+
CreateAppRepoBranchRequest,
|
|
28
|
+
DeleteAppVersionResponse,
|
|
23
29
|
ProjectRef,
|
|
30
|
+
PromoteAppVersionResponse,
|
|
24
31
|
RequireAtLeastOne,
|
|
25
32
|
StartAppBuildRequest,
|
|
26
33
|
StartAppBuildResponse,
|
|
34
|
+
StartAppScaffoldRequest,
|
|
35
|
+
StartAppScaffoldResponse,
|
|
27
36
|
UpdateAppInstallationToolAllowlistPayload,
|
|
28
37
|
UpsertAppVersionRequest,
|
|
29
38
|
ValidateUrlRequest,
|
|
@@ -83,8 +92,16 @@ export default class AppsApi extends ApiTopic {
|
|
|
83
92
|
return this.get(`/versions/${recordId}`);
|
|
84
93
|
}
|
|
85
94
|
|
|
86
|
-
|
|
87
|
-
return this.post(`/versions/${recordId}/
|
|
95
|
+
promoteVersion(recordId: string): Promise<PromoteAppVersionResponse> {
|
|
96
|
+
return this.post(`/versions/${recordId}/promote`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
rebuildVersion(recordId: string): Promise<StartAppBuildResponse> {
|
|
100
|
+
return this.post(`/versions/${recordId}/rebuild`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
deleteVersion(recordId: string): Promise<DeleteAppVersionResponse> {
|
|
104
|
+
return this.del(`/versions/${recordId}`);
|
|
88
105
|
}
|
|
89
106
|
|
|
90
107
|
startBuild(appIdOrRecordId: string, payload: StartAppBuildRequest): Promise<StartAppBuildResponse> {
|
|
@@ -97,6 +114,14 @@ export default class AppsApi extends ApiTopic {
|
|
|
97
114
|
);
|
|
98
115
|
}
|
|
99
116
|
|
|
117
|
+
startScaffold(payload: StartAppScaffoldRequest): Promise<StartAppScaffoldResponse> {
|
|
118
|
+
return this.post('/scaffolds', { payload });
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
getScaffoldProgress(workflowId: string, runId: string): Promise<AppScaffoldProgress> {
|
|
122
|
+
return this.get(`/scaffolds/${encodeURIComponent(workflowId)}/${encodeURIComponent(runId)}/progress`);
|
|
123
|
+
}
|
|
124
|
+
|
|
100
125
|
/**
|
|
101
126
|
* Get the list if tools provided by the given app.
|
|
102
127
|
* @param appId
|
|
@@ -128,12 +153,63 @@ export default class AppsApi extends ApiTopic {
|
|
|
128
153
|
}
|
|
129
154
|
|
|
130
155
|
/**
|
|
131
|
-
* Read the
|
|
132
|
-
* branch unless `ref` is given).
|
|
156
|
+
* Read the original bytes of a single file in the app's git repository (default
|
|
157
|
+
* branch unless `ref` is given). The caller decides whether to consume the
|
|
158
|
+
* successful response as text, a Blob, or an ArrayBuffer.
|
|
133
159
|
*/
|
|
134
|
-
getRepoFile(appIdOrName: string, path: string, options?: { ref?: string }): Promise<
|
|
135
|
-
|
|
160
|
+
async getRepoFile(appIdOrName: string, path: string, options?: { ref?: string }): Promise<Response> {
|
|
161
|
+
const endpoint = `/${encodeURIComponent(appIdOrName)}/repo/file`;
|
|
162
|
+
const response = await this.get<Response>(endpoint, {
|
|
136
163
|
query: { path, ref: options?.ref },
|
|
164
|
+
reader: (rawResponse) => rawResponse,
|
|
165
|
+
});
|
|
166
|
+
if (!response.ok) {
|
|
167
|
+
const payload = await this.readJSONPayload(response);
|
|
168
|
+
const request = await this.createRequest(response.url || this.getUrl(endpoint), { method: 'GET' });
|
|
169
|
+
throw this.createServerError(request, response, payload);
|
|
170
|
+
}
|
|
171
|
+
return response;
|
|
172
|
+
}
|
|
173
|
+
|
|
174
|
+
/**
|
|
175
|
+
* Commit one or more files under the repository's allowed document roots.
|
|
176
|
+
* The Git service currently permits only `docs/`. All files are written in
|
|
177
|
+
* one commit and `expectedHead` prevents overwriting a concurrent push.
|
|
178
|
+
*/
|
|
179
|
+
commitRepoDocuments(
|
|
180
|
+
appIdOrName: string,
|
|
181
|
+
files: Array<{ path: string; content: Blob; fileName?: string }>,
|
|
182
|
+
options: { ref: string; expectedHead: string; message?: string },
|
|
183
|
+
): Promise<AppRepoDocumentCommit> {
|
|
184
|
+
const form = new FormData();
|
|
185
|
+
const metadata = {
|
|
186
|
+
ref: options.ref,
|
|
187
|
+
expected_head: options.expectedHead,
|
|
188
|
+
message: options.message || 'Upload documentation',
|
|
189
|
+
files: files.map((file, index) => ({ field: `file_${index}`, path: file.path })),
|
|
190
|
+
};
|
|
191
|
+
form.append('metadata', JSON.stringify(metadata));
|
|
192
|
+
files.forEach((file, index) => {
|
|
193
|
+
form.append(`file_${index}`, file.content, file.fileName || file.path.split('/').pop() || 'document');
|
|
194
|
+
});
|
|
195
|
+
return this.post(`/${encodeURIComponent(appIdOrName)}/repo/documents`, {
|
|
196
|
+
payload: form,
|
|
197
|
+
jsonPayload: false,
|
|
198
|
+
timeoutMs: 120_000,
|
|
199
|
+
});
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
/**
|
|
203
|
+
* List repository commits newest first, optionally filtered to commits that changed a file.
|
|
204
|
+
* History starts at the default branch unless a branch, tag, or commit SHA is supplied as `ref`.
|
|
205
|
+
*/
|
|
206
|
+
getRepoCommits(
|
|
207
|
+
appIdOrName: string,
|
|
208
|
+
path?: string,
|
|
209
|
+
options?: { ref?: string; limit?: number; cursor?: string },
|
|
210
|
+
): Promise<AppRepoCommits> {
|
|
211
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/repo/commits`, {
|
|
212
|
+
query: { path, ref: options?.ref, limit: options?.limit, cursor: options?.cursor },
|
|
137
213
|
});
|
|
138
214
|
}
|
|
139
215
|
|
|
@@ -146,8 +222,23 @@ export default class AppsApi extends ApiTopic {
|
|
|
146
222
|
return this.get(`/${encodeURIComponent(appIdOrName)}/repo/refs`);
|
|
147
223
|
}
|
|
148
224
|
|
|
225
|
+
/** List mutable development tasks represented by `agent/*` repository branches. */
|
|
226
|
+
listDevelopmentTasks(appIdOrName: string): Promise<AppDevelopmentTaskList> {
|
|
227
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/development-tasks`);
|
|
228
|
+
}
|
|
229
|
+
|
|
230
|
+
/** Get a development task and its latest parent Studio Assistant run, when started. */
|
|
231
|
+
getDevelopmentTask(appIdOrName: string, taskId: string): Promise<AppDevelopmentTaskDetails> {
|
|
232
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/development-tasks/${encodeURIComponent(taskId)}`);
|
|
233
|
+
}
|
|
234
|
+
|
|
235
|
+
/** Create a repository branch from an existing branch, tag, or commit. */
|
|
236
|
+
createRepoBranch(appIdOrName: string, payload: CreateAppRepoBranchRequest): Promise<AppRepoBranch> {
|
|
237
|
+
return this.post(`/${encodeURIComponent(appIdOrName)}/repo/branches`, { payload });
|
|
238
|
+
}
|
|
239
|
+
|
|
149
240
|
/**
|
|
150
|
-
* Get the
|
|
241
|
+
* Get the promoted package an app exposes, filtered by scope. App-owned (in-code) artifacts are
|
|
151
242
|
* package-resolved (no per-id route), so this is how a client reads the full definition — type
|
|
152
243
|
* schema, interaction prompt, process definition, dashboard spec — to visualize an exposed id.
|
|
153
244
|
*/
|
package/src/AuditTrailApi.ts
CHANGED
|
@@ -1,5 +1,10 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
|
-
import type {
|
|
2
|
+
import type {
|
|
3
|
+
AuditAggregationQuery,
|
|
4
|
+
AuditAggregationResponse,
|
|
5
|
+
AuditTrailQuery,
|
|
6
|
+
AuditTrailResponse,
|
|
7
|
+
} from '@vertesia/common';
|
|
3
8
|
|
|
4
9
|
export default class AuditTrailApi extends ApiTopic {
|
|
5
10
|
constructor(parent: ClientBase) {
|
|
@@ -24,4 +29,8 @@ export default class AuditTrailApi extends ApiTopic {
|
|
|
24
29
|
const qs = params.toString();
|
|
25
30
|
return this.get(`/${qs ? `?${qs}` : ''}`);
|
|
26
31
|
}
|
|
32
|
+
|
|
33
|
+
aggregate(query: AuditAggregationQuery): Promise<AuditAggregationResponse> {
|
|
34
|
+
return this.post('/aggregate', { payload: query });
|
|
35
|
+
}
|
|
27
36
|
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { VertesiaClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
describe('ProjectsApi', () => {
|
|
5
|
+
it('encodes app View ids as one path segment', async () => {
|
|
6
|
+
const requests: Request[] = [];
|
|
7
|
+
const fetchMock = vi.fn(async () => {
|
|
8
|
+
return new Response(
|
|
9
|
+
JSON.stringify({
|
|
10
|
+
id: 'app:content:document-lib',
|
|
11
|
+
name: 'document-lib',
|
|
12
|
+
definition: { name: 'Document library' },
|
|
13
|
+
}),
|
|
14
|
+
{
|
|
15
|
+
status: 200,
|
|
16
|
+
headers: { 'content-type': 'application/json' },
|
|
17
|
+
},
|
|
18
|
+
);
|
|
19
|
+
});
|
|
20
|
+
const client = new VertesiaClient({
|
|
21
|
+
serverUrl: 'https://api.example.com',
|
|
22
|
+
storeUrl: 'https://api.example.com',
|
|
23
|
+
fetch: fetchMock,
|
|
24
|
+
onRequest: (request) => requests.push(request),
|
|
25
|
+
});
|
|
26
|
+
|
|
27
|
+
await client.projects.getAppView('project/with/slash', 'app:content:../../environments');
|
|
28
|
+
|
|
29
|
+
expect(requests[0]?.url).toBe(
|
|
30
|
+
'https://api.example.com/api/v1/projects/project%2Fwith%2Fslash/app-views/app%3Acontent%3A..%2F..%2Fenvironments',
|
|
31
|
+
);
|
|
32
|
+
});
|
|
33
|
+
});
|
package/src/ProjectsApi.ts
CHANGED
|
@@ -7,6 +7,7 @@ import type {
|
|
|
7
7
|
ICreateProjectPayload,
|
|
8
8
|
InCodeProcessDefinition,
|
|
9
9
|
InCodeTypeDefinition,
|
|
10
|
+
InCodeViewDefinition,
|
|
10
11
|
Project,
|
|
11
12
|
ProjectConfiguration,
|
|
12
13
|
ProjectIntegrationConfigRequest,
|
|
@@ -80,44 +81,54 @@ export default class ProjectsApi extends ApiTopic {
|
|
|
80
81
|
}
|
|
81
82
|
|
|
82
83
|
listAppContentTypes(projectId: string, tag?: string): Promise<InCodeTypeDefinition[]> {
|
|
83
|
-
return this.get(`/${projectId}/app-types`, {
|
|
84
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-types`, {
|
|
84
85
|
query: { tag },
|
|
85
86
|
});
|
|
86
87
|
}
|
|
87
88
|
|
|
88
89
|
getAppContentType(projectId: string, typeId: string): Promise<InCodeTypeDefinition> {
|
|
89
|
-
return this.get(`/${projectId}/app-types/${typeId}`);
|
|
90
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-types/${encodeURIComponent(typeId)}`);
|
|
90
91
|
}
|
|
91
92
|
|
|
92
93
|
listAppProcesses(projectId: string, tag?: string): Promise<InCodeProcessDefinition[]> {
|
|
93
|
-
return this.get(`/${projectId}/app-processes`, {
|
|
94
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-processes`, {
|
|
94
95
|
query: { tag },
|
|
95
96
|
});
|
|
96
97
|
}
|
|
97
98
|
|
|
98
99
|
getAppProcess(projectId: string, processId: string): Promise<InCodeProcessDefinition> {
|
|
99
|
-
return this.get(`/${projectId}/app-processes/${processId}`);
|
|
100
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-processes/${encodeURIComponent(processId)}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
listAppViews(projectId: string, tag?: string): Promise<InCodeViewDefinition[]> {
|
|
104
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-views`, {
|
|
105
|
+
query: { tag },
|
|
106
|
+
});
|
|
107
|
+
}
|
|
108
|
+
|
|
109
|
+
getAppView(projectId: string, viewId: string): Promise<InCodeViewDefinition> {
|
|
110
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-views/${encodeURIComponent(viewId)}`);
|
|
100
111
|
}
|
|
101
112
|
|
|
102
113
|
listAppRenderingTemplates(projectId: string, tag?: string): Promise<RenderingTemplateDefinitionRef[]> {
|
|
103
|
-
return this.get(`/${projectId}/app-templates`, {
|
|
114
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-templates`, {
|
|
104
115
|
query: { tag },
|
|
105
116
|
});
|
|
106
117
|
}
|
|
107
118
|
|
|
108
119
|
getAppRenderingTemplate(projectId: string, templateUri: string): Promise<RenderingTemplateDefinition> {
|
|
109
|
-
return this.get(`/${projectId}/app-templates/${templateUri}`);
|
|
120
|
+
return this.get(`/${encodeURIComponent(projectId)}/app-templates/${encodeURIComponent(templateUri)}`);
|
|
110
121
|
}
|
|
111
122
|
|
|
112
123
|
getCompositeAppConfiguration(projectId: string): Promise<CompositeAppConfig> {
|
|
113
|
-
return this.get(`/${projectId}/composite-app`);
|
|
124
|
+
return this.get(`/${encodeURIComponent(projectId)}/composite-app`);
|
|
114
125
|
}
|
|
115
126
|
|
|
116
127
|
updateCompositeAppConfiguration(
|
|
117
128
|
projectId: string,
|
|
118
129
|
payload: CompositeAppConfigPayload,
|
|
119
130
|
): Promise<CompositeAppConfig> {
|
|
120
|
-
return this.put(`/${projectId}/composite-app`, {
|
|
131
|
+
return this.put(`/${encodeURIComponent(projectId)}/composite-app`, {
|
|
121
132
|
payload,
|
|
122
133
|
});
|
|
123
134
|
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
2
|
+
import { VertesiaClient } from './client.js';
|
|
3
|
+
|
|
4
|
+
describe('ViewsApi', () => {
|
|
5
|
+
it('keeps CRUD on Studio and proxies execution to Zeno', async () => {
|
|
6
|
+
const requests: Request[] = [];
|
|
7
|
+
const fetchMock = vi.fn(async () => {
|
|
8
|
+
return new Response(JSON.stringify({}), {
|
|
9
|
+
status: 200,
|
|
10
|
+
headers: { 'content-type': 'application/json' },
|
|
11
|
+
});
|
|
12
|
+
});
|
|
13
|
+
const client = new VertesiaClient({
|
|
14
|
+
serverUrl: 'https://studio.example.com',
|
|
15
|
+
storeUrl: 'https://zeno.example.com',
|
|
16
|
+
fetch: fetchMock,
|
|
17
|
+
onRequest: (request) => requests.push(request),
|
|
18
|
+
});
|
|
19
|
+
|
|
20
|
+
await client.views.retrieve('document-library');
|
|
21
|
+
await client.views.execute('document-library');
|
|
22
|
+
await client.views.preview({
|
|
23
|
+
configuration: {
|
|
24
|
+
name: 'Document library',
|
|
25
|
+
description: 'Browse documents.',
|
|
26
|
+
scope: {},
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
|
|
30
|
+
expect(requests.map((request) => request.url)).toEqual([
|
|
31
|
+
'https://studio.example.com/api/v1/views/document-library',
|
|
32
|
+
'https://zeno.example.com/api/v1/view-executions/document-library/execute',
|
|
33
|
+
'https://zeno.example.com/api/v1/view-executions/preview',
|
|
34
|
+
]);
|
|
35
|
+
});
|
|
36
|
+
});
|
package/src/ViewsApi.ts
ADDED
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
|
+
import type {
|
|
3
|
+
CreateViewExperienceRequest,
|
|
4
|
+
DeleteByIdResult,
|
|
5
|
+
ExecuteViewRequest,
|
|
6
|
+
PreviewViewExperienceRequest,
|
|
7
|
+
UpdateViewExperienceRequest,
|
|
8
|
+
ViewExecutionResult,
|
|
9
|
+
ViewExperience,
|
|
10
|
+
ViewExperienceListQuery,
|
|
11
|
+
} from '@vertesia/common';
|
|
12
|
+
import type { StoreViewsApi } from './store/ViewsApi.js';
|
|
13
|
+
|
|
14
|
+
export default class ViewsApi extends ApiTopic {
|
|
15
|
+
constructor(
|
|
16
|
+
parent: ClientBase,
|
|
17
|
+
private readonly executionApi: StoreViewsApi,
|
|
18
|
+
) {
|
|
19
|
+
super(parent, '/api/v1/views');
|
|
20
|
+
}
|
|
21
|
+
|
|
22
|
+
list(query: ViewExperienceListQuery = {}): Promise<ViewExperience[]> {
|
|
23
|
+
return this.get('/', {
|
|
24
|
+
query: {
|
|
25
|
+
limit: query.limit,
|
|
26
|
+
offset: query.offset,
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
}
|
|
30
|
+
|
|
31
|
+
create(payload: CreateViewExperienceRequest): Promise<ViewExperience> {
|
|
32
|
+
return this.post('/', { payload });
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
retrieve(id: string): Promise<ViewExperience> {
|
|
36
|
+
return this.get(`/${encodeURIComponent(id)}`);
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
update(id: string, payload: UpdateViewExperienceRequest): Promise<ViewExperience> {
|
|
40
|
+
return this.put(`/${encodeURIComponent(id)}`, { payload });
|
|
41
|
+
}
|
|
42
|
+
|
|
43
|
+
delete(id: string): Promise<DeleteByIdResult> {
|
|
44
|
+
return this.del(`/${encodeURIComponent(id)}`);
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
/**
|
|
48
|
+
* Execute a persisted or app-contributed View through the content service.
|
|
49
|
+
*/
|
|
50
|
+
execute(id: string, payload: ExecuteViewRequest = {}): Promise<ViewExecutionResult> {
|
|
51
|
+
return this.executionApi.execute(id, payload);
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
/**
|
|
55
|
+
* Validate and execute an unsaved View through the content service.
|
|
56
|
+
*/
|
|
57
|
+
preview(payload: PreviewViewExperienceRequest): Promise<ViewExecutionResult> {
|
|
58
|
+
return this.executionApi.preview(payload);
|
|
59
|
+
}
|
|
60
|
+
}
|
package/src/client.ts
CHANGED
|
@@ -28,6 +28,7 @@ import { VERSION, VERSION_HEADER } from './store/version.js';
|
|
|
28
28
|
import ToolsApi from './ToolsApi.js';
|
|
29
29
|
import TrainingApi from './TrainingApi.js';
|
|
30
30
|
import UsersApi from './UsersApi.js';
|
|
31
|
+
import ViewsApi from './ViewsApi.js';
|
|
31
32
|
|
|
32
33
|
/**
|
|
33
34
|
* 1 min threshold constant in ms
|
|
@@ -206,6 +207,7 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
|
|
|
206
207
|
timeout: opts.timeout,
|
|
207
208
|
fetch: opts.fetch,
|
|
208
209
|
});
|
|
210
|
+
this.views = new ViewsApi(this, this.store.views);
|
|
209
211
|
|
|
210
212
|
if (opts.retryPolicy) {
|
|
211
213
|
this.withRetryPolicy(opts.retryPolicy);
|
|
@@ -243,7 +245,7 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
|
|
|
243
245
|
/**
|
|
244
246
|
* Pin the app version this client's requests resolve against. A generated app's UI sets this from
|
|
245
247
|
* its build-time `VITE_APP_VERSION` so studio/zeno resolve its `app:<app>:…` refs against that
|
|
246
|
-
*
|
|
248
|
+
* exact built version instead of the promoted version. Pass null/empty to clear (→ promoted).
|
|
247
249
|
*/
|
|
248
250
|
withAppVersion(version: string | null | undefined) {
|
|
249
251
|
if (!version) {
|
|
@@ -425,6 +427,7 @@ export class VertesiaClient extends AbstractFetchClient<VertesiaClient> {
|
|
|
425
427
|
apps = new AppsApi(this);
|
|
426
428
|
tools = new ToolsApi(this);
|
|
427
429
|
quota = new QuotaApi(this);
|
|
430
|
+
views: ViewsApi;
|
|
428
431
|
}
|
|
429
432
|
|
|
430
433
|
function isApiKey(apiKey: string) {
|
package/src/index.ts
CHANGED
|
@@ -18,4 +18,5 @@ export type { ComputeRunFacetsResponse, FilterOption } from './RunsApi.js';
|
|
|
18
18
|
export { default as SecretsApi } from './SecretsApi.js';
|
|
19
19
|
export * from './StreamSource.js';
|
|
20
20
|
export * from './store/index.js';
|
|
21
|
+
export { default as ViewsApi } from './ViewsApi.js';
|
|
21
22
|
export type { AsyncExecutionResult };
|
package/src/store/AgentsApi.ts
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
|
|
2
2
|
import {
|
|
3
3
|
type ActiveWorkstreamsQueryResult,
|
|
4
|
+
type AgentArtifactContentResponse,
|
|
4
5
|
type AgentArtifactUrlResponse,
|
|
5
6
|
type AgentEvent,
|
|
6
7
|
type AgentMessage,
|
|
@@ -41,6 +42,8 @@ import {
|
|
|
41
42
|
type ToolParameterAnalyticsResponse,
|
|
42
43
|
type TopPrincipalsAnalyticsResponse,
|
|
43
44
|
toAgentMessage,
|
|
45
|
+
type UpdateAgentArtifactContentPayload,
|
|
46
|
+
type UpdateAgentArtifactContentResponse,
|
|
44
47
|
type UpdateAgentRunStatusPayload,
|
|
45
48
|
type WorkflowAnalyticsFilterOptionsResponse,
|
|
46
49
|
type WorkflowAnalyticsSummaryQuery,
|
|
@@ -734,6 +737,20 @@ export class AgentsApi extends ApiTopic {
|
|
|
734
737
|
return this.get(`/${id}/artifacts`, { query });
|
|
735
738
|
}
|
|
736
739
|
|
|
740
|
+
/** Read a text artifact together with its conditional-write generation token. */
|
|
741
|
+
getArtifactContent(id: string, path: string): Promise<AgentArtifactContentResponse> {
|
|
742
|
+
return this.get(`/${id}/artifact-content/${path}`);
|
|
743
|
+
}
|
|
744
|
+
|
|
745
|
+
/** Conditionally replace the text content of an agent artifact. */
|
|
746
|
+
updateArtifactContent(
|
|
747
|
+
id: string,
|
|
748
|
+
path: string,
|
|
749
|
+
payload: UpdateAgentArtifactContentPayload,
|
|
750
|
+
): Promise<UpdateAgentArtifactContentResponse> {
|
|
751
|
+
return this.put(`/${id}/artifact-content/${path}`, { payload });
|
|
752
|
+
}
|
|
753
|
+
|
|
737
754
|
/**
|
|
738
755
|
* Get a signed download URL for an artifact.
|
|
739
756
|
*/
|