@vertesia/client 1.5.0-dev.20260714.072725Z → 1.5.0-dev.20260722.120446Z
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 +89 -5
- package/lib/AppsApi.d.ts.map +1 -1
- package/lib/AppsApi.js +153 -4
- 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/RunsApi.d.ts +8 -2
- package/lib/RunsApi.d.ts.map +1 -1
- package/lib/RunsApi.js +6 -2
- package/lib/RunsApi.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 +10 -1
- package/lib/client.d.ts.map +1 -1
- package/lib/client.js +20 -0
- package/lib/client.js.map +1 -1
- package/lib/index.d.ts +2 -0
- package/lib/index.d.ts.map +1 -1
- package/lib/index.js +2 -0
- package/lib/index.js.map +1 -1
- package/lib/managed-sse.d.ts +27 -0
- package/lib/managed-sse.d.ts.map +1 -0
- package/lib/managed-sse.js +159 -0
- package/lib/managed-sse.js.map +1 -0
- package/lib/store/AgentsApi.d.ts.map +1 -1
- package/lib/store/AgentsApi.js +61 -6
- 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/EventsApi.d.ts +15 -1
- package/lib/store/EventsApi.d.ts.map +1 -1
- package/lib/store/EventsApi.js +57 -0
- package/lib/store/EventsApi.js.map +1 -1
- package/lib/store/FilesApi.d.ts.map +1 -1
- package/lib/store/FilesApi.js +6 -0
- package/lib/store/FilesApi.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 +5 -1
- package/lib/store/client.d.ts.map +1 -1
- package/lib/store/client.js +13 -0
- package/lib/store/client.js.map +1 -1
- package/lib/store/index.d.ts +2 -0
- package/lib/store/index.d.ts.map +1 -1
- package/lib/store/index.js +2 -0
- package/lib/store/index.js.map +1 -1
- package/lib/store/version.d.ts +1 -0
- package/lib/store/version.d.ts.map +1 -1
- package/lib/store/version.js +1 -0
- package/lib/store/version.js.map +1 -1
- package/lib/vertesia-client.js +10 -10
- package/lib/vertesia-client.js.map +1 -1
- package/package.json +8 -7
- package/src/AppsApi.test.ts +124 -0
- package/src/AppsApi.ts +205 -4
- package/src/AuditTrailApi.ts +10 -1
- package/src/ProjectsApi.test.ts +33 -0
- package/src/ProjectsApi.ts +19 -8
- package/src/RunsApi.ts +12 -2
- package/src/ViewsApi.test.ts +36 -0
- package/src/ViewsApi.ts +60 -0
- package/src/client.ts +21 -2
- package/src/index.ts +2 -0
- package/src/managed-sse.ts +205 -0
- package/src/store/AgentsApi.ts +57 -6
- package/src/store/AnalyzeDocApi.ts +16 -54
- package/src/store/EventsApi.test.ts +131 -0
- package/src/store/EventsApi.ts +80 -0
- package/src/store/FilesApi.test.ts +69 -0
- package/src/store/FilesApi.ts +8 -1
- package/src/store/ViewsApi.test.ts +33 -0
- package/src/store/ViewsApi.ts +20 -0
- package/src/store/client.ts +13 -1
- package/src/store/index.ts +2 -0
- package/src/store/version.ts +1 -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.20260722.120446Z",
|
|
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.1.
|
|
14
|
+
"@types/node": "^24.13.3",
|
|
15
|
+
"rolldown": "1.1.5",
|
|
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.20260722.112223Z",
|
|
23
|
+
"@vertesia/common": "1.5.0-dev.20260722.120446Z",
|
|
24
|
+
"@vertesia/api-fetch-client": "1.5.0-dev.20260722.120446Z"
|
|
25
25
|
},
|
|
26
26
|
"exports": {
|
|
27
27
|
".": {
|
|
@@ -48,6 +48,7 @@
|
|
|
48
48
|
"ai",
|
|
49
49
|
"typescript"
|
|
50
50
|
],
|
|
51
|
+
"gitHead": "203c30e5a8ddc583ac9f1acce0f5445eb38a9551",
|
|
51
52
|
"scripts": {
|
|
52
53
|
"lint": "biome lint src",
|
|
53
54
|
"clean:lib": "rimraf ./lib ./tsconfig.tsbuildinfo",
|
|
@@ -0,0 +1,124 @@
|
|
|
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
|
+
expect(request?.url).toBe('https://studio.example.com/api/v1/apps/sample-app/repo/documents');
|
|
110
|
+
expect(request?.headers.get('content-type')).toContain('multipart/form-data; boundary=');
|
|
111
|
+
const form = await request?.formData();
|
|
112
|
+
expect(JSON.parse(String(form?.get('metadata')))).toEqual({
|
|
113
|
+
ref: 'main',
|
|
114
|
+
expected_head: '1'.repeat(40),
|
|
115
|
+
message: 'Add docs',
|
|
116
|
+
files: [
|
|
117
|
+
{ field: 'file_0', path: 'docs/guide.md' },
|
|
118
|
+
{ field: 'file_1', path: 'docs/diagram.png' },
|
|
119
|
+
],
|
|
120
|
+
});
|
|
121
|
+
expect((form?.get('file_0') as File).name).toBe('guide.md');
|
|
122
|
+
expect((form?.get('file_1') as File).size).toBe(3);
|
|
123
|
+
});
|
|
124
|
+
});
|
package/src/AppsApi.ts
CHANGED
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { ApiTopic, type ClientBase, type ServerError } from '@vertesia/api-fetch-client';
|
|
2
2
|
import type {
|
|
3
|
+
AppBuildProgress,
|
|
4
|
+
AppDeleteSummary,
|
|
5
|
+
AppInspectionResult,
|
|
3
6
|
AppInstallation,
|
|
4
7
|
AppInstallationKind,
|
|
5
8
|
AppInstallationListEntry,
|
|
@@ -7,11 +10,27 @@ import type {
|
|
|
7
10
|
AppInstallationWithManifest,
|
|
8
11
|
AppManifest,
|
|
9
12
|
AppManifestData,
|
|
13
|
+
AppPackage,
|
|
14
|
+
AppPackageScope,
|
|
15
|
+
AppRepoCommits,
|
|
16
|
+
AppRepoDocumentCommit,
|
|
17
|
+
AppRepoRefs,
|
|
18
|
+
AppRepoTree,
|
|
19
|
+
AppScaffoldProgress,
|
|
10
20
|
AppToolCollection,
|
|
21
|
+
AppVersionListQuery,
|
|
22
|
+
AppVersionRecord,
|
|
11
23
|
CountResult,
|
|
24
|
+
DeleteAppVersionResponse,
|
|
12
25
|
ProjectRef,
|
|
26
|
+
PromoteAppVersionResponse,
|
|
13
27
|
RequireAtLeastOne,
|
|
28
|
+
StartAppBuildRequest,
|
|
29
|
+
StartAppBuildResponse,
|
|
30
|
+
StartAppScaffoldRequest,
|
|
31
|
+
StartAppScaffoldResponse,
|
|
14
32
|
UpdateAppInstallationToolAllowlistPayload,
|
|
33
|
+
UpsertAppVersionRequest,
|
|
15
34
|
ValidateUrlRequest,
|
|
16
35
|
ValidateUrlResponse,
|
|
17
36
|
} from '@vertesia/common';
|
|
@@ -34,14 +53,71 @@ export default class AppsApi extends ApiTopic {
|
|
|
34
53
|
}
|
|
35
54
|
|
|
36
55
|
/**
|
|
37
|
-
*
|
|
38
|
-
*
|
|
39
|
-
* otherwise the server may refuse or leave orphaned installation records.
|
|
56
|
+
* Preview what the cascade delete would remove. Calls DELETE without confirm,
|
|
57
|
+
* which the server treats as a dry-run and returns counts + paths.
|
|
40
58
|
*/
|
|
41
|
-
|
|
59
|
+
previewDelete(id: string): Promise<AppDeleteSummary> {
|
|
42
60
|
return this.del(`/${id}`);
|
|
43
61
|
}
|
|
44
62
|
|
|
63
|
+
/**
|
|
64
|
+
* Cascade-delete an app and everything attached to it (versions,
|
|
65
|
+
* installations + ACEs, git repo on the app-git server). Pass through
|
|
66
|
+
* the dry-run summary; confirm flag is required server-side.
|
|
67
|
+
*/
|
|
68
|
+
deleteApp(id: string): Promise<AppDeleteSummary> {
|
|
69
|
+
return this.del(`/${id}`, { query: { confirm: 'true' } });
|
|
70
|
+
}
|
|
71
|
+
|
|
72
|
+
listVersions(query?: AppVersionListQuery): Promise<AppVersionRecord[]> {
|
|
73
|
+
return this.get('/versions', {
|
|
74
|
+
query: {
|
|
75
|
+
...(query?.app_id && { app_id: query.app_id }),
|
|
76
|
+
...(query?.kind && { kind: query.kind }),
|
|
77
|
+
...(query?.include_expired !== undefined && { include_expired: query.include_expired }),
|
|
78
|
+
...(query?.limit !== undefined && { limit: query.limit }),
|
|
79
|
+
},
|
|
80
|
+
});
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
upsertVersion(payload: UpsertAppVersionRequest): Promise<AppVersionRecord> {
|
|
84
|
+
return this.post('/versions', { payload });
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
getVersion(recordId: string): Promise<AppVersionRecord> {
|
|
88
|
+
return this.get(`/versions/${recordId}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
promoteVersion(recordId: string): Promise<PromoteAppVersionResponse> {
|
|
92
|
+
return this.post(`/versions/${recordId}/promote`);
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
rebuildVersion(recordId: string): Promise<StartAppBuildResponse> {
|
|
96
|
+
return this.post(`/versions/${recordId}/rebuild`);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
deleteVersion(recordId: string): Promise<DeleteAppVersionResponse> {
|
|
100
|
+
return this.del(`/versions/${recordId}`);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
startBuild(appIdOrRecordId: string, payload: StartAppBuildRequest): Promise<StartAppBuildResponse> {
|
|
104
|
+
return this.post(`/${encodeURIComponent(appIdOrRecordId)}/builds`, { payload });
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
getBuildProgress(appIdOrRecordId: string, workflowId: string, runId: string): Promise<AppBuildProgress> {
|
|
108
|
+
return this.get(
|
|
109
|
+
`/${encodeURIComponent(appIdOrRecordId)}/builds/${encodeURIComponent(workflowId)}/${encodeURIComponent(runId)}/progress`,
|
|
110
|
+
);
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
startScaffold(payload: StartAppScaffoldRequest): Promise<StartAppScaffoldResponse> {
|
|
114
|
+
return this.post('/scaffolds', { payload });
|
|
115
|
+
}
|
|
116
|
+
|
|
117
|
+
getScaffoldProgress(workflowId: string, runId: string): Promise<AppScaffoldProgress> {
|
|
118
|
+
return this.get(`/scaffolds/${encodeURIComponent(workflowId)}/${encodeURIComponent(runId)}/progress`);
|
|
119
|
+
}
|
|
120
|
+
|
|
45
121
|
/**
|
|
46
122
|
* Get the list if tools provided by the given app.
|
|
47
123
|
* @param appId
|
|
@@ -51,6 +127,131 @@ export default class AppsApi extends ApiTopic {
|
|
|
51
127
|
return this.get(`/installations/${appInstallId}/tools`);
|
|
52
128
|
}
|
|
53
129
|
|
|
130
|
+
/**
|
|
131
|
+
* Inspect an app's registration: resolved manifest state, what the published
|
|
132
|
+
* package actually exposes per capability, endpoint reachability, install
|
|
133
|
+
* state, and diagnostics. Use this to verify what an app registers vs what it
|
|
134
|
+
* declares, instead of inferring it from failed object/import calls.
|
|
135
|
+
*/
|
|
136
|
+
inspect(appIdOrName: string): Promise<AppInspectionResult> {
|
|
137
|
+
return this.get(`/${appIdOrName}/inspect`);
|
|
138
|
+
}
|
|
139
|
+
|
|
140
|
+
/**
|
|
141
|
+
* List files/directories under a prefix in the app's git repository (default
|
|
142
|
+
* branch unless `ref` is given). Read-only; reads live from the git server
|
|
143
|
+
* without a clone. Used by the Build > Design view to surface generated `docs/`.
|
|
144
|
+
*/
|
|
145
|
+
getRepoTree(appIdOrName: string, options?: { prefix?: string; ref?: string }): Promise<AppRepoTree> {
|
|
146
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/repo/tree`, {
|
|
147
|
+
query: { prefix: options?.prefix, ref: options?.ref },
|
|
148
|
+
});
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
/**
|
|
152
|
+
* Read the original bytes of a single file in the app's git repository (default
|
|
153
|
+
* branch unless `ref` is given). The caller decides whether to consume the
|
|
154
|
+
* successful response as text, a Blob, or an ArrayBuffer.
|
|
155
|
+
*/
|
|
156
|
+
async getRepoFile(appIdOrName: string, path: string, options?: { ref?: string }): Promise<Response> {
|
|
157
|
+
const endpoint = `/${encodeURIComponent(appIdOrName)}/repo/file`;
|
|
158
|
+
const response = await this.get<Response>(endpoint, {
|
|
159
|
+
query: { path, ref: options?.ref },
|
|
160
|
+
reader: (rawResponse) => rawResponse,
|
|
161
|
+
});
|
|
162
|
+
if (!response.ok) {
|
|
163
|
+
const payload = await this.readJSONPayload(response);
|
|
164
|
+
const request = await this.createRequest(response.url || this.getUrl(endpoint), { method: 'GET' });
|
|
165
|
+
throw this.createServerError(request, response, payload);
|
|
166
|
+
}
|
|
167
|
+
return response;
|
|
168
|
+
}
|
|
169
|
+
|
|
170
|
+
/**
|
|
171
|
+
* Commit one or more files under the repository's allowed document roots.
|
|
172
|
+
* The Git service currently permits only `docs/`. All files are written in
|
|
173
|
+
* one commit and `expectedHead` prevents overwriting a concurrent push.
|
|
174
|
+
*/
|
|
175
|
+
commitRepoDocuments(
|
|
176
|
+
appIdOrName: string,
|
|
177
|
+
files: Array<{ path: string; content: Blob; fileName?: string }>,
|
|
178
|
+
options: { ref: string; expectedHead: string; message?: string },
|
|
179
|
+
): Promise<AppRepoDocumentCommit> {
|
|
180
|
+
const form = new FormData();
|
|
181
|
+
const metadata = {
|
|
182
|
+
ref: options.ref,
|
|
183
|
+
expected_head: options.expectedHead,
|
|
184
|
+
message: options.message || 'Upload documentation',
|
|
185
|
+
files: files.map((file, index) => ({ field: `file_${index}`, path: file.path })),
|
|
186
|
+
};
|
|
187
|
+
form.append('metadata', JSON.stringify(metadata));
|
|
188
|
+
files.forEach((file, index) => {
|
|
189
|
+
form.append(`file_${index}`, file.content, file.fileName || file.path.split('/').pop() || 'document');
|
|
190
|
+
});
|
|
191
|
+
return this.post(`/${encodeURIComponent(appIdOrName)}/repo/documents`, {
|
|
192
|
+
payload: form,
|
|
193
|
+
jsonPayload: false,
|
|
194
|
+
timeoutMs: 120_000,
|
|
195
|
+
});
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
/**
|
|
199
|
+
* List repository commits newest first, optionally filtered to commits that changed a file.
|
|
200
|
+
* History starts at the default branch unless a branch, tag, or commit SHA is supplied as `ref`.
|
|
201
|
+
*/
|
|
202
|
+
getRepoCommits(
|
|
203
|
+
appIdOrName: string,
|
|
204
|
+
path?: string,
|
|
205
|
+
options?: { ref?: string; limit?: number; cursor?: string },
|
|
206
|
+
): Promise<AppRepoCommits> {
|
|
207
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/repo/commits`, {
|
|
208
|
+
query: { path, ref: options?.ref, limit: options?.limit, cursor: options?.cursor },
|
|
209
|
+
});
|
|
210
|
+
}
|
|
211
|
+
|
|
212
|
+
/**
|
|
213
|
+
* List the branches and tags of the app's git repository, each resolved to its latest commit.
|
|
214
|
+
* Read-only; reads live from the git server without a clone. Used by the Source view to let a
|
|
215
|
+
* user pick a ref to build from.
|
|
216
|
+
*/
|
|
217
|
+
getRepoRefs(appIdOrName: string): Promise<AppRepoRefs> {
|
|
218
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/repo/refs`);
|
|
219
|
+
}
|
|
220
|
+
|
|
221
|
+
/**
|
|
222
|
+
* Get the promoted package an app exposes, filtered by scope. App-owned (in-code) artifacts are
|
|
223
|
+
* package-resolved (no per-id route), so this is how a client reads the full definition — type
|
|
224
|
+
* schema, interaction prompt, process definition, dashboard spec — to visualize an exposed id.
|
|
225
|
+
*/
|
|
226
|
+
getAppPackage(appIdOrName: string, scope: AppPackageScope | AppPackageScope[] = 'all'): Promise<AppPackage> {
|
|
227
|
+
return this.get(`/${encodeURIComponent(appIdOrName)}/package`, {
|
|
228
|
+
query: { scope: Array.isArray(scope) ? scope.join(',') : scope },
|
|
229
|
+
});
|
|
230
|
+
}
|
|
231
|
+
|
|
232
|
+
/**
|
|
233
|
+
* Get package capabilities exposed by an app installation.
|
|
234
|
+
*/
|
|
235
|
+
getAppInstallationPackage(
|
|
236
|
+
appInstallId: string,
|
|
237
|
+
scope: AppPackageScope | AppPackageScope[] = 'all',
|
|
238
|
+
): Promise<AppPackage> {
|
|
239
|
+
return this.get(`/installations/${appInstallId}/package`, {
|
|
240
|
+
query: {
|
|
241
|
+
scope: Array.isArray(scope) ? scope.join(',') : scope,
|
|
242
|
+
},
|
|
243
|
+
});
|
|
244
|
+
}
|
|
245
|
+
|
|
246
|
+
/**
|
|
247
|
+
* Fetch the always-on system tools package served by studio-server.
|
|
248
|
+
* Tools and skills (`learn_*`) are returned on separate fields so UIs can
|
|
249
|
+
* render them distinctly. URLs are already resolved per deployment.
|
|
250
|
+
*/
|
|
251
|
+
getSystemToolsPackage(scope: string = 'tools'): Promise<AppPackage> {
|
|
252
|
+
return this.get('/studio-tools/package', { query: { scope } });
|
|
253
|
+
}
|
|
254
|
+
|
|
54
255
|
/**
|
|
55
256
|
* @param ids - ids to filter by
|
|
56
257
|
* @returns the app manifests but without the agent.tool property which can be big.
|
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
|
}
|
package/src/RunsApi.ts
CHANGED
|
@@ -115,9 +115,14 @@ export class RunsApi extends ApiTopic {
|
|
|
115
115
|
* @param payload
|
|
116
116
|
* @returns
|
|
117
117
|
*/
|
|
118
|
-
sendToolResults(
|
|
118
|
+
sendToolResults(
|
|
119
|
+
payload: ToolResultsPayload,
|
|
120
|
+
options?: { timeoutMs?: number | false | null; signal?: AbortSignal },
|
|
121
|
+
): Promise<ExecutionResponse> {
|
|
119
122
|
return this.post(`/tool-results`, {
|
|
120
123
|
payload,
|
|
124
|
+
timeoutMs: options?.timeoutMs,
|
|
125
|
+
signal: options?.signal,
|
|
121
126
|
});
|
|
122
127
|
}
|
|
123
128
|
|
|
@@ -126,9 +131,14 @@ export class RunsApi extends ApiTopic {
|
|
|
126
131
|
* @param payload
|
|
127
132
|
* @returns
|
|
128
133
|
*/
|
|
129
|
-
sendUserMessage(
|
|
134
|
+
sendUserMessage(
|
|
135
|
+
payload: UserMessagePayload,
|
|
136
|
+
options?: { timeoutMs?: number | false | null; signal?: AbortSignal },
|
|
137
|
+
): Promise<ExecutionResponse> {
|
|
130
138
|
return this.post(`/user-message`, {
|
|
131
139
|
payload,
|
|
140
|
+
timeoutMs: options?.timeoutMs,
|
|
141
|
+
signal: options?.signal,
|
|
132
142
|
});
|
|
133
143
|
}
|
|
134
144
|
|
|
@@ -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
|
+
}
|