@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.
Files changed (87) hide show
  1. package/lib/AppsApi.d.ts +89 -5
  2. package/lib/AppsApi.d.ts.map +1 -1
  3. package/lib/AppsApi.js +153 -4
  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/RunsApi.d.ts +8 -2
  14. package/lib/RunsApi.d.ts.map +1 -1
  15. package/lib/RunsApi.js +6 -2
  16. package/lib/RunsApi.js.map +1 -1
  17. package/lib/ViewsApi.d.ts +21 -0
  18. package/lib/ViewsApi.d.ts.map +1 -0
  19. package/lib/ViewsApi.js +41 -0
  20. package/lib/ViewsApi.js.map +1 -0
  21. package/lib/client.d.ts +10 -1
  22. package/lib/client.d.ts.map +1 -1
  23. package/lib/client.js +20 -0
  24. package/lib/client.js.map +1 -1
  25. package/lib/index.d.ts +2 -0
  26. package/lib/index.d.ts.map +1 -1
  27. package/lib/index.js +2 -0
  28. package/lib/index.js.map +1 -1
  29. package/lib/managed-sse.d.ts +27 -0
  30. package/lib/managed-sse.d.ts.map +1 -0
  31. package/lib/managed-sse.js +159 -0
  32. package/lib/managed-sse.js.map +1 -0
  33. package/lib/store/AgentsApi.d.ts.map +1 -1
  34. package/lib/store/AgentsApi.js +61 -6
  35. package/lib/store/AgentsApi.js.map +1 -1
  36. package/lib/store/AnalyzeDocApi.d.ts +9 -11
  37. package/lib/store/AnalyzeDocApi.d.ts.map +1 -1
  38. package/lib/store/AnalyzeDocApi.js +12 -36
  39. package/lib/store/AnalyzeDocApi.js.map +1 -1
  40. package/lib/store/EventsApi.d.ts +15 -1
  41. package/lib/store/EventsApi.d.ts.map +1 -1
  42. package/lib/store/EventsApi.js +57 -0
  43. package/lib/store/EventsApi.js.map +1 -1
  44. package/lib/store/FilesApi.d.ts.map +1 -1
  45. package/lib/store/FilesApi.js +6 -0
  46. package/lib/store/FilesApi.js.map +1 -1
  47. package/lib/store/ViewsApi.d.ts +12 -0
  48. package/lib/store/ViewsApi.d.ts.map +1 -0
  49. package/lib/store/ViewsApi.js +17 -0
  50. package/lib/store/ViewsApi.js.map +1 -0
  51. package/lib/store/client.d.ts +5 -1
  52. package/lib/store/client.d.ts.map +1 -1
  53. package/lib/store/client.js +13 -0
  54. package/lib/store/client.js.map +1 -1
  55. package/lib/store/index.d.ts +2 -0
  56. package/lib/store/index.d.ts.map +1 -1
  57. package/lib/store/index.js +2 -0
  58. package/lib/store/index.js.map +1 -1
  59. package/lib/store/version.d.ts +1 -0
  60. package/lib/store/version.d.ts.map +1 -1
  61. package/lib/store/version.js +1 -0
  62. package/lib/store/version.js.map +1 -1
  63. package/lib/vertesia-client.js +10 -10
  64. package/lib/vertesia-client.js.map +1 -1
  65. package/package.json +8 -7
  66. package/src/AppsApi.test.ts +124 -0
  67. package/src/AppsApi.ts +205 -4
  68. package/src/AuditTrailApi.ts +10 -1
  69. package/src/ProjectsApi.test.ts +33 -0
  70. package/src/ProjectsApi.ts +19 -8
  71. package/src/RunsApi.ts +12 -2
  72. package/src/ViewsApi.test.ts +36 -0
  73. package/src/ViewsApi.ts +60 -0
  74. package/src/client.ts +21 -2
  75. package/src/index.ts +2 -0
  76. package/src/managed-sse.ts +205 -0
  77. package/src/store/AgentsApi.ts +57 -6
  78. package/src/store/AnalyzeDocApi.ts +16 -54
  79. package/src/store/EventsApi.test.ts +131 -0
  80. package/src/store/EventsApi.ts +80 -0
  81. package/src/store/FilesApi.test.ts +69 -0
  82. package/src/store/FilesApi.ts +8 -1
  83. package/src/store/ViewsApi.test.ts +33 -0
  84. package/src/store/ViewsApi.ts +20 -0
  85. package/src/store/client.ts +13 -1
  86. package/src/store/index.ts +2 -0
  87. package/src/store/version.ts +1 -0
@@ -2,12 +2,32 @@ import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
2
  import type {
3
3
  EventDeliveryQueueSummaryPayload,
4
4
  EventDeliveryQueueSummaryResponse,
5
+ EventDeliveryStreamEnvelope,
6
+ EventDeliveryStreamItem,
7
+ EventDeliveryStreamSnapshot,
8
+ EventDeliveryStreamUpdate,
5
9
  ListEventDeliveriesPayload,
6
10
  ListEventDeliveriesResponse,
11
+ StreamEventDeliveriesQuery,
7
12
  } from '@vertesia/common';
13
+ import {
14
+ type ManagedEventSourceConnection,
15
+ type ManagedEventSourceStatus,
16
+ openManagedEventSource,
17
+ } from '../managed-sse.js';
8
18
  import { EventIngestChannelsApi } from './EventIngestChannelsApi.js';
9
19
  import { EventSubscriptionsApi } from './EventSubscriptionsApi.js';
10
20
 
21
+ export interface SubscribeEventDeliveriesOptions extends StreamEventDeliveriesQuery {
22
+ signal?: AbortSignal;
23
+ max_reconnect_attempts?: number;
24
+ on_snapshot?: (deliveries: EventDeliveryStreamItem[], envelope: EventDeliveryStreamSnapshot) => void;
25
+ on_delivery?: (delivery: EventDeliveryStreamItem, envelope: EventDeliveryStreamUpdate) => void;
26
+ on_envelope?: (envelope: EventDeliveryStreamEnvelope) => void;
27
+ on_error?: (error: unknown) => void;
28
+ on_status?: (status: ManagedEventSourceStatus) => void;
29
+ }
30
+
11
31
  export class EventsApi extends ApiTopic {
12
32
  readonly subscriptions: EventSubscriptionsApi;
13
33
  readonly channels: EventIngestChannelsApi;
@@ -25,4 +45,64 @@ export class EventsApi extends ApiTopic {
25
45
  queueSummary(payload: EventDeliveryQueueSummaryPayload = {}): Promise<EventDeliveryQueueSummaryResponse> {
26
46
  return this.post('/deliveries/queue-summary', { payload });
27
47
  }
48
+
49
+ subscribeDeliveries(options: SubscribeEventDeliveriesOptions): ManagedEventSourceConnection {
50
+ const { signal, max_reconnect_attempts, on_snapshot, on_delivery, on_envelope, on_error, on_status, ...query } =
51
+ options;
52
+
53
+ return openManagedEventSource<EventDeliveryStreamEnvelope>({
54
+ url: () => this.buildStreamUrl(query),
55
+ event_types: ['snapshot', 'event', 'heartbeat', 'error'],
56
+ signal,
57
+ max_reconnect_attempts,
58
+ last_event_id_query_param: 'since_event_id',
59
+ get_access_token: async () => {
60
+ const client = this.client as ClientBase & { _auth?: () => Promise<string> };
61
+ return client._auth ? await client._auth() : undefined;
62
+ },
63
+ get_cursor: (envelope) => envelope.cursor,
64
+ on_status,
65
+ on_error,
66
+ on_event: ({ data }) => {
67
+ on_envelope?.(data);
68
+ if (data.type === 'snapshot') {
69
+ on_snapshot?.(data.deliveries, data);
70
+ } else if (data.type === 'event') {
71
+ on_delivery?.(data.item, data);
72
+ } else if (data.type === 'error') {
73
+ on_error?.(new Error(data.error));
74
+ }
75
+ },
76
+ });
77
+ }
78
+
79
+ private buildStreamUrl(query: StreamEventDeliveriesQuery): URL {
80
+ const url = new URL(`${this.baseUrl}/stream`);
81
+ this.setStreamParam(url, 'limit', query.limit);
82
+ this.setStreamParam(url, 'event_id', query.event_id);
83
+ this.setStreamParam(url, 'resource_id', query.resource_id);
84
+ this.setStreamListParam(url, 'resource_type', query.resource_type);
85
+ this.setStreamListParam(url, 'event_category', query.event_category);
86
+ this.setStreamListParam(url, 'action', query.action);
87
+ this.setStreamListParam(url, 'outbox_status', query.outbox_status);
88
+ this.setStreamParam(url, 'since_event_id', query.since_event_id);
89
+ this.setStreamParam(url, 'since_created_at', query.since_created_at);
90
+ this.setStreamParam(url, 'include_event', query.include_event);
91
+ this.setStreamParam(url, 'poll_interval_ms', query.poll_interval_ms);
92
+ return url;
93
+ }
94
+
95
+ private setStreamParam(url: URL, key: string, value: string | number | boolean | undefined): void {
96
+ if (value === undefined || value === null || value === '') {
97
+ return;
98
+ }
99
+ url.searchParams.set(key, String(value));
100
+ }
101
+
102
+ private setStreamListParam(url: URL, key: string, value: string[] | undefined): void {
103
+ if (!value?.length) {
104
+ return;
105
+ }
106
+ url.searchParams.set(key, value.join(','));
107
+ }
28
108
  }
@@ -0,0 +1,69 @@
1
+ import { describe, expect, it } from 'vitest';
2
+ import { ZenoClient } from './client.js';
3
+
4
+ describe('FilesApi', () => {
5
+ it('retries signed upload URL creation after a transient connection failure', async () => {
6
+ let attempts = 0;
7
+ const fetchSignedUploadUrl = async (): Promise<Response> => {
8
+ attempts++;
9
+ if (attempts === 1) {
10
+ throw new TypeError('fetch failed');
11
+ }
12
+ return new Response(
13
+ JSON.stringify({ id: 'file-1', path: 'agents/run/conversation.json', url: 'https://signed' }),
14
+ {
15
+ status: 200,
16
+ headers: { 'content-type': 'application/json' },
17
+ },
18
+ );
19
+ };
20
+
21
+ const client = new ZenoClient({
22
+ serverUrl: 'https://store.test',
23
+ apikey: 'token',
24
+ fetch: fetchSignedUploadUrl,
25
+ });
26
+
27
+ const result = await client.files.getUploadUrl({
28
+ name: 'conversation.json',
29
+ id: 'agents/run/conversation.json',
30
+ });
31
+
32
+ expect(result).toEqual({ id: 'file-1', path: 'agents/run/conversation.json', url: 'https://signed' });
33
+ expect(attempts).toBe(2);
34
+ });
35
+
36
+ it('retries signed upload URL creation after a transient 503', async () => {
37
+ let attempts = 0;
38
+ const fetchSignedUploadUrl = async (): Promise<Response> => {
39
+ attempts++;
40
+ if (attempts === 1) {
41
+ return new Response(JSON.stringify({ message: 'try again' }), {
42
+ status: 503,
43
+ headers: { 'content-type': 'application/json' },
44
+ });
45
+ }
46
+ return new Response(
47
+ JSON.stringify({ id: 'file-1', path: 'agents/run/conversation.json', url: 'https://signed' }),
48
+ {
49
+ status: 200,
50
+ headers: { 'content-type': 'application/json' },
51
+ },
52
+ );
53
+ };
54
+
55
+ const client = new ZenoClient({
56
+ serverUrl: 'https://store.test',
57
+ apikey: 'token',
58
+ fetch: fetchSignedUploadUrl,
59
+ });
60
+
61
+ const result = await client.files.getUploadUrl({
62
+ name: 'conversation.json',
63
+ id: 'agents/run/conversation.json',
64
+ });
65
+
66
+ expect(result).toEqual({ id: 'file-1', path: 'agents/run/conversation.json', url: 'https://signed' });
67
+ expect(attempts).toBe(2);
68
+ });
69
+ });
@@ -1,4 +1,4 @@
1
- import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
1
+ import { ApiTopic, type ClientBase, type IRequestRetryPolicy } from '@vertesia/api-fetch-client';
2
2
  import type {
3
3
  BucketReadAccessStatusResponse,
4
4
  BulkUploadUrlsPayload,
@@ -21,6 +21,12 @@ import { fetchSignedUrl } from './signed-url.js';
21
21
  export const MEMORIES_PREFIX = 'memories';
22
22
  export const ARTIFACTS_PREFIX = 'agents';
23
23
 
24
+ const FILE_SIGNING_RETRY_POLICY: IRequestRetryPolicy = {
25
+ attempts: 3,
26
+ methods: ['POST'],
27
+ statuses: [502, 503, 504],
28
+ };
29
+
24
30
  export function getMemoryFilePath(name: string) {
25
31
  const nameWithExt = name.endsWith('.tar.gz') ? name : `${name}.tar.gz`;
26
32
  return `${MEMORIES_PREFIX}/${nameWithExt}`;
@@ -95,6 +101,7 @@ export class FilesApi extends ApiTopic {
95
101
  getUploadUrl(payload: GetUploadUrlPayload): Promise<GetFileUrlResponse> {
96
102
  return this.post('/upload-url', {
97
103
  payload,
104
+ retryPolicy: FILE_SIGNING_RETRY_POLICY,
98
105
  });
99
106
  }
100
107
 
@@ -0,0 +1,33 @@
1
+ import { describe, expect, it, vi } from 'vitest';
2
+ import { ZenoClient } from './client.js';
3
+
4
+ describe('StoreViewsApi', () => {
5
+ it('uses the View execution resource for persisted and draft execution', 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 ZenoClient({
14
+ serverUrl: 'https://api.example.com',
15
+ fetch: fetchMock,
16
+ onRequest: (request) => requests.push(request),
17
+ });
18
+
19
+ await client.views.execute('app:content:document-library');
20
+ await client.views.preview({
21
+ configuration: {
22
+ name: 'Document library',
23
+ description: 'Browse documents.',
24
+ scope: {},
25
+ },
26
+ });
27
+
28
+ expect(requests.map((request) => request.url)).toEqual([
29
+ 'https://api.example.com/api/v1/view-executions/app%3Acontent%3Adocument-library/execute',
30
+ 'https://api.example.com/api/v1/view-executions/preview',
31
+ ]);
32
+ });
33
+ });
@@ -0,0 +1,20 @@
1
+ import { ApiTopic, type ClientBase } from '@vertesia/api-fetch-client';
2
+ import type { ExecuteViewRequest, PreviewViewExperienceRequest, ViewExecutionResult } from '@vertesia/common';
3
+
4
+ export class StoreViewsApi extends ApiTopic {
5
+ constructor(parent: ClientBase) {
6
+ super(parent, '/api/v1/view-executions');
7
+ }
8
+
9
+ execute(id: string, payload: ExecuteViewRequest = {}): Promise<ViewExecutionResult> {
10
+ return this.post(`/${encodeURIComponent(id)}/execute`, { payload });
11
+ }
12
+
13
+ /**
14
+ * Validate and execute an unsaved View configuration without persisting it.
15
+ * Returns the same normalized results as {@link execute}.
16
+ */
17
+ preview(payload: PreviewViewExperienceRequest): Promise<ViewExecutionResult> {
18
+ return this.post('/preview', { payload });
19
+ }
20
+ }
@@ -4,7 +4,7 @@ import {
4
4
  type IRequestRetryPolicy,
5
5
  type RequestError,
6
6
  } from '@vertesia/api-fetch-client';
7
- import type { BulkOperationPayload, BulkOperationResponse } from '@vertesia/common';
7
+ import { APP_VERSION_HEADER, type BulkOperationPayload, type BulkOperationResponse } from '@vertesia/common';
8
8
  import { AgentsApi } from './AgentsApi.js';
9
9
  import { CollectionsApi } from './CollectionsApi.js';
10
10
  import { CostApi } from './CostApi.js';
@@ -24,6 +24,7 @@ import { RenderingApi } from './RenderingApi.js';
24
24
  import { SchedulesApi } from './SchedulesApi.js';
25
25
  import { TaskApi } from './TaskApi.js';
26
26
  import { TypesApi } from './TypesApi.js';
27
+ import { StoreViewsApi } from './ViewsApi.js';
27
28
  import { VERSION, VERSION_HEADER } from './version.js';
28
29
  import { WorkflowsApi } from './WorkflowsApi.js';
29
30
 
@@ -77,6 +78,16 @@ export class ZenoClient extends AbstractFetchClient<ZenoClient> {
77
78
  return this;
78
79
  }
79
80
 
81
+ /** Pin the app version this client's requests resolve against (see VertesiaClient.withAppVersion). */
82
+ withAppVersion(version: string | null | undefined) {
83
+ if (!version) {
84
+ delete this.headers[APP_VERSION_HEADER];
85
+ } else {
86
+ this.headers[APP_VERSION_HEADER] = String(version);
87
+ }
88
+ return this;
89
+ }
90
+
80
91
  withApiKey(apiKey: string | null) {
81
92
  return this.withAuthCallback(apiKey ? () => Promise.resolve(`Bearer ${apiKey}`) : undefined);
82
93
  }
@@ -115,4 +126,5 @@ export class ZenoClient extends AbstractFetchClient<ZenoClient> {
115
126
  query = new QueryApi(this);
116
127
  hiveMemory = new HiveMemoryApi(this);
117
128
  rendering = new RenderingApi(this);
129
+ views = new StoreViewsApi(this);
118
130
  }
@@ -20,4 +20,6 @@ export * from './signed-url.js';
20
20
  export * from './TaskApi.js';
21
21
  export * from './TypeCatalogApi.js';
22
22
  export * from './TypesApi.js';
23
+ export * from './ViewsApi.js';
24
+ export { APP_VERSION_HEADER } from './version.js';
23
25
  export * from './WorkflowsApi.js';
@@ -1,2 +1,3 @@
1
1
  export const VERSION = '20260319'; // YYYYMMDD, client versioning for API endpoints. Increment manually for breaking changes
2
2
  export const VERSION_HEADER = 'x-api-version';
3
+ export { APP_VERSION_HEADER } from '@vertesia/common';