@vertesia/client 1.5.0-dev.20260717.131047Z → 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.
Files changed (57) hide show
  1. package/lib/AppsApi.d.ts +34 -6
  2. package/lib/AppsApi.d.ts.map +1 -1
  3. package/lib/AppsApi.js +60 -7
  4. package/lib/AppsApi.js.map +1 -1
  5. package/lib/AuditTrailApi.d.ts +2 -1
  6. package/lib/AuditTrailApi.d.ts.map +1 -1
  7. package/lib/AuditTrailApi.js +3 -0
  8. package/lib/AuditTrailApi.js.map +1 -1
  9. package/lib/ProjectsApi.d.ts +3 -1
  10. package/lib/ProjectsApi.d.ts.map +1 -1
  11. package/lib/ProjectsApi.js +16 -8
  12. package/lib/ProjectsApi.js.map +1 -1
  13. package/lib/ViewsApi.d.ts +21 -0
  14. package/lib/ViewsApi.d.ts.map +1 -0
  15. package/lib/ViewsApi.js +41 -0
  16. package/lib/ViewsApi.js.map +1 -0
  17. package/lib/client.d.ts +3 -1
  18. package/lib/client.d.ts.map +1 -1
  19. package/lib/client.js +4 -1
  20. package/lib/client.js.map +1 -1
  21. package/lib/index.d.ts +1 -0
  22. package/lib/index.d.ts.map +1 -1
  23. package/lib/index.js +1 -0
  24. package/lib/index.js.map +1 -1
  25. package/lib/store/AnalyzeDocApi.d.ts +9 -11
  26. package/lib/store/AnalyzeDocApi.d.ts.map +1 -1
  27. package/lib/store/AnalyzeDocApi.js +12 -36
  28. package/lib/store/AnalyzeDocApi.js.map +1 -1
  29. package/lib/store/ViewsApi.d.ts +12 -0
  30. package/lib/store/ViewsApi.d.ts.map +1 -0
  31. package/lib/store/ViewsApi.js +17 -0
  32. package/lib/store/ViewsApi.js.map +1 -0
  33. package/lib/store/client.d.ts +2 -0
  34. package/lib/store/client.d.ts.map +1 -1
  35. package/lib/store/client.js +2 -0
  36. package/lib/store/client.js.map +1 -1
  37. package/lib/store/index.d.ts +1 -0
  38. package/lib/store/index.d.ts.map +1 -1
  39. package/lib/store/index.js +1 -0
  40. package/lib/store/index.js.map +1 -1
  41. package/lib/vertesia-client.js +5 -5
  42. package/lib/vertesia-client.js.map +1 -1
  43. package/package.json +8 -8
  44. package/src/AppsApi.test.ts +124 -0
  45. package/src/AppsApi.ts +81 -9
  46. package/src/AuditTrailApi.ts +10 -1
  47. package/src/ProjectsApi.test.ts +33 -0
  48. package/src/ProjectsApi.ts +19 -8
  49. package/src/ViewsApi.test.ts +36 -0
  50. package/src/ViewsApi.ts +60 -0
  51. package/src/client.ts +4 -1
  52. package/src/index.ts +1 -0
  53. package/src/store/AnalyzeDocApi.ts +16 -54
  54. package/src/store/ViewsApi.test.ts +33 -0
  55. package/src/store/ViewsApi.ts +20 -0
  56. package/src/store/client.ts +2 -0
  57. package/src/store/index.ts +1 -0
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@vertesia/client",
3
- "version": "1.5.0-dev.20260717.131047Z",
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.2",
15
- "rolldown": "1.1.4",
14
+ "@types/node": "^24.13.3",
15
+ "rolldown": "1.1.5",
16
16
  "typescript": "^6.0.3",
17
- "vitest": "^4.1.9",
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.20260713.114357Z",
23
- "@vertesia/common": "1.5.0-dev.20260717.131047Z",
24
- "@vertesia/api-fetch-client": "1.5.0-dev.20260717.131047Z"
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,7 +48,7 @@
48
48
  "ai",
49
49
  "typescript"
50
50
  ],
51
- "gitHead": "8aaad228827b2927db8e6aa75b27bfac90fec36f",
51
+ "gitHead": "203c30e5a8ddc583ac9f1acce0f5445eb38a9551",
52
52
  "scripts": {
53
53
  "lint": "biome lint src",
54
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,6 +1,5 @@
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,
6
5
  AppInspectionResult,
@@ -13,17 +12,23 @@ import type {
13
12
  AppManifestData,
14
13
  AppPackage,
15
14
  AppPackageScope,
16
- AppRepoFile,
15
+ AppRepoCommits,
16
+ AppRepoDocumentCommit,
17
17
  AppRepoRefs,
18
18
  AppRepoTree,
19
+ AppScaffoldProgress,
19
20
  AppToolCollection,
20
21
  AppVersionListQuery,
21
22
  AppVersionRecord,
22
23
  CountResult,
24
+ DeleteAppVersionResponse,
23
25
  ProjectRef,
26
+ PromoteAppVersionResponse,
24
27
  RequireAtLeastOne,
25
28
  StartAppBuildRequest,
26
29
  StartAppBuildResponse,
30
+ StartAppScaffoldRequest,
31
+ StartAppScaffoldResponse,
27
32
  UpdateAppInstallationToolAllowlistPayload,
28
33
  UpsertAppVersionRequest,
29
34
  ValidateUrlRequest,
@@ -83,8 +88,16 @@ export default class AppsApi extends ApiTopic {
83
88
  return this.get(`/versions/${recordId}`);
84
89
  }
85
90
 
86
- activateVersion(recordId: string): Promise<ActivateAppVersionResponse> {
87
- return this.post(`/versions/${recordId}/activate`);
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}`);
88
101
  }
89
102
 
90
103
  startBuild(appIdOrRecordId: string, payload: StartAppBuildRequest): Promise<StartAppBuildResponse> {
@@ -97,6 +110,14 @@ export default class AppsApi extends ApiTopic {
97
110
  );
98
111
  }
99
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
+
100
121
  /**
101
122
  * Get the list if tools provided by the given app.
102
123
  * @param appId
@@ -128,12 +149,63 @@ export default class AppsApi extends ApiTopic {
128
149
  }
129
150
 
130
151
  /**
131
- * Read the UTF-8 content of a single file in the app's git repository (default
132
- * branch unless `ref` is given). Read-only; reads live from the git server.
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.
133
155
  */
134
- getRepoFile(appIdOrName: string, path: string, options?: { ref?: string }): Promise<AppRepoFile> {
135
- return this.get(`/${encodeURIComponent(appIdOrName)}/repo/file`, {
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, {
136
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 },
137
209
  });
138
210
  }
139
211
 
@@ -147,7 +219,7 @@ export default class AppsApi extends ApiTopic {
147
219
  }
148
220
 
149
221
  /**
150
- * Get the published package an app exposes, filtered by scope. App-owned (in-code) artifacts are
222
+ * Get the promoted package an app exposes, filtered by scope. App-owned (in-code) artifacts are
151
223
  * package-resolved (no per-id route), so this is how a client reads the full definition — type
152
224
  * schema, interaction prompt, process definition, dashboard spec — to visualize an exposed id.
153
225
  */
@@ -1,5 +1,10 @@
1
1
  import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
- import type { AuditTrailQuery, AuditTrailResponse } from '@vertesia/common';
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
+ });
@@ -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
+ });
@@ -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
- * published version (candidate testing) instead of current. Pass null/empty to clear (→ current).
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 };
@@ -1,16 +1,10 @@
1
- import { ApiTopic, type ClientBase, type IRequestParams } from '@vertesia/api-fetch-client';
1
+ import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
2
  import type {
3
- AdaptedTable,
4
- AdaptTablesRequest,
5
3
  DocAnalyzeRunStatusResponse,
6
- DocAnalyzerResultResponse,
7
- DocImage,
8
- DocTableCsv,
9
- DocTableJson,
10
- ExportTableFormats,
11
- GetAdaptedTablesRequestQuery,
12
- PdfToRichtextOptions,
13
- WorkflowRunStatus,
4
+ DocumentPrepOptions,
5
+ GroundedAssistantResponse,
6
+ GroundedExtractionRequest,
7
+ GroundedExtractionResultResponse,
14
8
  } from '@vertesia/common';
15
9
 
16
10
  export class AnalyzeDocApi extends ApiTopic {
@@ -21,7 +15,7 @@ export class AnalyzeDocApi extends ApiTopic {
21
15
  super(parent, `/${objectId}/analyze`);
22
16
  }
23
17
 
24
- async start(payload: PdfToRichtextOptions): Promise<DocAnalyzeRunStatusResponse> {
18
+ async start(payload: DocumentPrepOptions): Promise<DocAnalyzeRunStatusResponse> {
25
19
  return this.post('/', { payload });
26
20
  }
27
21
 
@@ -29,51 +23,19 @@ export class AnalyzeDocApi extends ApiTopic {
29
23
  return this.get('/status');
30
24
  }
31
25
 
32
- async getResults(): Promise<DocAnalyzerResultResponse> {
33
- return this.get('/results');
26
+ async startGroundedExtraction(payload?: GroundedExtractionRequest): Promise<DocAnalyzeRunStatusResponse> {
27
+ return this.post('/grounded', { payload: payload ?? {} });
34
28
  }
35
29
 
36
- async adaptTables(payload: AdaptTablesRequest): Promise<WorkflowRunStatus> {
37
- return this.post('/adapt_tables', { payload });
30
+ async getGroundedExtractionResult(): Promise<GroundedExtractionResultResponse> {
31
+ return this.get('/grounded/result');
38
32
  }
39
33
 
40
- async getAdaptedTables(
41
- runId?: string,
42
- query?: GetAdaptedTablesRequestQuery,
43
- ): Promise<Record<number, AdaptedTable>> {
44
- const path = runId ? `/adapt_tables/${runId}` : '/adapt_tables';
45
-
46
- // Build query parameters
47
- const queryParams: NonNullable<IRequestParams['query']> = {};
48
- if (query?.format) queryParams.format = query.format;
49
- if (query?.raw !== undefined) queryParams.raw = query.raw;
50
-
51
- // If format is CSV, set response type to text to avoid automatic JSON parsing
52
- const options: IRequestParams & { responseType?: 'text' } = { query: queryParams };
53
- if (query?.format === 'csv') {
54
- options.responseType = 'text';
55
- }
56
-
57
- return this.get(path, options);
58
- }
59
-
60
- async getXml(): Promise<string> {
61
- return this.get('/xml');
62
- }
63
-
64
- async getTables(format?: ExportTableFormats): Promise<DocTableCsv[] | DocTableJson[]> {
65
- const options: IRequestParams = {};
66
- if (format) {
67
- options.query = { format: format };
68
- }
69
- return this.get('/tables', options);
70
- }
71
-
72
- async getImages(): Promise<DocImage[]> {
73
- return this.get('/images');
74
- }
75
-
76
- async getAnnotated(): Promise<{ url: string }> {
77
- return this.get('/annotated');
34
+ /**
35
+ * Launch the interactive grounded extraction assistant for this document.
36
+ * Returns the agent_run_id used to stream/render the conversation.
37
+ */
38
+ async startGroundedAssistant(payload?: GroundedExtractionRequest): Promise<GroundedAssistantResponse> {
39
+ return this.post('/grounded/assistant', { payload: payload ?? {} });
78
40
  }
79
41
  }