@vertesia/client 0.77.0 → 0.78.0-dev-28b447d

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 (226) hide show
  1. package/package.json +59 -54
  2. package/src/AppsApi.ts +10 -1
  3. package/src/InteractionBase.ts +3 -3
  4. package/src/InteractionsApi.ts +19 -9
  5. package/src/RunsApi.ts +9 -2
  6. package/src/client.test.ts +2 -0
  7. package/src/client.ts +134 -56
  8. package/src/execute.ts +11 -5
  9. package/src/store/FilesApi.ts +2 -2
  10. package/src/store/ObjectsApi.ts +40 -13
  11. package/src/store/WorkflowsApi.ts +166 -0
  12. package/src/store/client.ts +8 -0
  13. package/lib/cjs/AccountApi.js +0 -85
  14. package/lib/cjs/AccountApi.js.map +0 -1
  15. package/lib/cjs/AccountsApi.js +0 -16
  16. package/lib/cjs/AccountsApi.js.map +0 -1
  17. package/lib/cjs/AnalyticsApi.js +0 -13
  18. package/lib/cjs/AnalyticsApi.js.map +0 -1
  19. package/lib/cjs/ApiKeysApi.js +0 -63
  20. package/lib/cjs/ApiKeysApi.js.map +0 -1
  21. package/lib/cjs/AppsApi.js +0 -111
  22. package/lib/cjs/AppsApi.js.map +0 -1
  23. package/lib/cjs/CommandsApi.js +0 -19
  24. package/lib/cjs/CommandsApi.js.map +0 -1
  25. package/lib/cjs/EnvironmentsApi.js +0 -58
  26. package/lib/cjs/EnvironmentsApi.js.map +0 -1
  27. package/lib/cjs/GroupsApi.js +0 -78
  28. package/lib/cjs/GroupsApi.js.map +0 -1
  29. package/lib/cjs/IamApi.js +0 -53
  30. package/lib/cjs/IamApi.js.map +0 -1
  31. package/lib/cjs/InteractionBase.js +0 -44
  32. package/lib/cjs/InteractionBase.js.map +0 -1
  33. package/lib/cjs/InteractionsApi.js +0 -209
  34. package/lib/cjs/InteractionsApi.js.map +0 -1
  35. package/lib/cjs/ProjectsApi.js +0 -48
  36. package/lib/cjs/ProjectsApi.js.map +0 -1
  37. package/lib/cjs/PromptsApi.js +0 -133
  38. package/lib/cjs/PromptsApi.js.map +0 -1
  39. package/lib/cjs/RefsApi.js +0 -14
  40. package/lib/cjs/RefsApi.js.map +0 -1
  41. package/lib/cjs/RunsApi.js +0 -105
  42. package/lib/cjs/RunsApi.js.map +0 -1
  43. package/lib/cjs/StreamSource.js +0 -17
  44. package/lib/cjs/StreamSource.js.map +0 -1
  45. package/lib/cjs/TrainingApi.js +0 -54
  46. package/lib/cjs/TrainingApi.js.map +0 -1
  47. package/lib/cjs/UsersApi.js +0 -13
  48. package/lib/cjs/UsersApi.js.map +0 -1
  49. package/lib/cjs/client.js +0 -263
  50. package/lib/cjs/client.js.map +0 -1
  51. package/lib/cjs/execute.js +0 -152
  52. package/lib/cjs/execute.js.map +0 -1
  53. package/lib/cjs/index.js +0 -21
  54. package/lib/cjs/index.js.map +0 -1
  55. package/lib/cjs/nodejs/NodeStreamSource.js +0 -45
  56. package/lib/cjs/nodejs/NodeStreamSource.js.map +0 -1
  57. package/lib/cjs/nodejs/index.js +0 -18
  58. package/lib/cjs/nodejs/index.js.map +0 -1
  59. package/lib/cjs/package.json +0 -3
  60. package/lib/cjs/store/AgentsApi.js +0 -16
  61. package/lib/cjs/store/AgentsApi.js.map +0 -1
  62. package/lib/cjs/store/AnalyzeDocApi.js +0 -56
  63. package/lib/cjs/store/AnalyzeDocApi.js.map +0 -1
  64. package/lib/cjs/store/CollectionsApi.js +0 -101
  65. package/lib/cjs/store/CollectionsApi.js.map +0 -1
  66. package/lib/cjs/store/CommandsApi.js +0 -17
  67. package/lib/cjs/store/CommandsApi.js.map +0 -1
  68. package/lib/cjs/store/EmbeddingsApi.js +0 -29
  69. package/lib/cjs/store/EmbeddingsApi.js.map +0 -1
  70. package/lib/cjs/store/FilesApi.js +0 -147
  71. package/lib/cjs/store/FilesApi.js.map +0 -1
  72. package/lib/cjs/store/ObjectsApi.js +0 -264
  73. package/lib/cjs/store/ObjectsApi.js.map +0 -1
  74. package/lib/cjs/store/TypesApi.js +0 -57
  75. package/lib/cjs/store/TypesApi.js.map +0 -1
  76. package/lib/cjs/store/WorkflowsApi.js +0 -265
  77. package/lib/cjs/store/WorkflowsApi.js.map +0 -1
  78. package/lib/cjs/store/client.js +0 -55
  79. package/lib/cjs/store/client.js.map +0 -1
  80. package/lib/cjs/store/errors.js +0 -11
  81. package/lib/cjs/store/errors.js.map +0 -1
  82. package/lib/cjs/store/index.js +0 -22
  83. package/lib/cjs/store/index.js.map +0 -1
  84. package/lib/esm/AccountApi.js +0 -82
  85. package/lib/esm/AccountApi.js.map +0 -1
  86. package/lib/esm/AccountsApi.js +0 -13
  87. package/lib/esm/AccountsApi.js.map +0 -1
  88. package/lib/esm/AnalyticsApi.js +0 -10
  89. package/lib/esm/AnalyticsApi.js.map +0 -1
  90. package/lib/esm/ApiKeysApi.js +0 -59
  91. package/lib/esm/ApiKeysApi.js.map +0 -1
  92. package/lib/esm/AppsApi.js +0 -108
  93. package/lib/esm/AppsApi.js.map +0 -1
  94. package/lib/esm/CommandsApi.js +0 -16
  95. package/lib/esm/CommandsApi.js.map +0 -1
  96. package/lib/esm/EnvironmentsApi.js +0 -55
  97. package/lib/esm/EnvironmentsApi.js.map +0 -1
  98. package/lib/esm/GroupsApi.js +0 -74
  99. package/lib/esm/GroupsApi.js.map +0 -1
  100. package/lib/esm/IamApi.js +0 -47
  101. package/lib/esm/IamApi.js.map +0 -1
  102. package/lib/esm/InteractionBase.js +0 -40
  103. package/lib/esm/InteractionBase.js.map +0 -1
  104. package/lib/esm/InteractionsApi.js +0 -206
  105. package/lib/esm/InteractionsApi.js.map +0 -1
  106. package/lib/esm/ProjectsApi.js +0 -45
  107. package/lib/esm/ProjectsApi.js.map +0 -1
  108. package/lib/esm/PromptsApi.js +0 -130
  109. package/lib/esm/PromptsApi.js.map +0 -1
  110. package/lib/esm/RefsApi.js +0 -10
  111. package/lib/esm/RefsApi.js.map +0 -1
  112. package/lib/esm/RunsApi.js +0 -101
  113. package/lib/esm/RunsApi.js.map +0 -1
  114. package/lib/esm/StreamSource.js +0 -13
  115. package/lib/esm/StreamSource.js.map +0 -1
  116. package/lib/esm/TrainingApi.js +0 -51
  117. package/lib/esm/TrainingApi.js.map +0 -1
  118. package/lib/esm/UsersApi.js +0 -10
  119. package/lib/esm/UsersApi.js.map +0 -1
  120. package/lib/esm/client.js +0 -254
  121. package/lib/esm/client.js.map +0 -1
  122. package/lib/esm/execute.js +0 -113
  123. package/lib/esm/execute.js.map +0 -1
  124. package/lib/esm/index.js +0 -5
  125. package/lib/esm/index.js.map +0 -1
  126. package/lib/esm/nodejs/NodeStreamSource.js +0 -41
  127. package/lib/esm/nodejs/NodeStreamSource.js.map +0 -1
  128. package/lib/esm/nodejs/index.js +0 -2
  129. package/lib/esm/nodejs/index.js.map +0 -1
  130. package/lib/esm/store/AgentsApi.js +0 -12
  131. package/lib/esm/store/AgentsApi.js.map +0 -1
  132. package/lib/esm/store/AnalyzeDocApi.js +0 -52
  133. package/lib/esm/store/AnalyzeDocApi.js.map +0 -1
  134. package/lib/esm/store/CollectionsApi.js +0 -97
  135. package/lib/esm/store/CollectionsApi.js.map +0 -1
  136. package/lib/esm/store/CommandsApi.js +0 -13
  137. package/lib/esm/store/CommandsApi.js.map +0 -1
  138. package/lib/esm/store/EmbeddingsApi.js +0 -25
  139. package/lib/esm/store/EmbeddingsApi.js.map +0 -1
  140. package/lib/esm/store/FilesApi.js +0 -142
  141. package/lib/esm/store/FilesApi.js.map +0 -1
  142. package/lib/esm/store/ObjectsApi.js +0 -260
  143. package/lib/esm/store/ObjectsApi.js.map +0 -1
  144. package/lib/esm/store/TypesApi.js +0 -53
  145. package/lib/esm/store/TypesApi.js.map +0 -1
  146. package/lib/esm/store/WorkflowsApi.js +0 -259
  147. package/lib/esm/store/WorkflowsApi.js.map +0 -1
  148. package/lib/esm/store/client.js +0 -51
  149. package/lib/esm/store/client.js.map +0 -1
  150. package/lib/esm/store/errors.js +0 -7
  151. package/lib/esm/store/errors.js.map +0 -1
  152. package/lib/esm/store/index.js +0 -6
  153. package/lib/esm/store/index.js.map +0 -1
  154. package/lib/tsconfig.tsbuildinfo +0 -1
  155. package/lib/types/AccountApi.d.ts +0 -59
  156. package/lib/types/AccountApi.d.ts.map +0 -1
  157. package/lib/types/AccountsApi.d.ts +0 -7
  158. package/lib/types/AccountsApi.d.ts.map +0 -1
  159. package/lib/types/AnalyticsApi.d.ts +0 -6
  160. package/lib/types/AnalyticsApi.d.ts.map +0 -1
  161. package/lib/types/ApiKeysApi.d.ts +0 -42
  162. package/lib/types/ApiKeysApi.d.ts.map +0 -1
  163. package/lib/types/AppsApi.d.ts +0 -59
  164. package/lib/types/AppsApi.d.ts.map +0 -1
  165. package/lib/types/CommandsApi.d.ts +0 -10
  166. package/lib/types/CommandsApi.d.ts.map +0 -1
  167. package/lib/types/EnvironmentsApi.d.ts +0 -30
  168. package/lib/types/EnvironmentsApi.d.ts.map +0 -1
  169. package/lib/types/GroupsApi.d.ts +0 -65
  170. package/lib/types/GroupsApi.d.ts.map +0 -1
  171. package/lib/types/IamApi.d.ts +0 -41
  172. package/lib/types/IamApi.d.ts.map +0 -1
  173. package/lib/types/InteractionBase.d.ts +0 -22
  174. package/lib/types/InteractionBase.d.ts.map +0 -1
  175. package/lib/types/InteractionsApi.d.ts +0 -150
  176. package/lib/types/InteractionsApi.d.ts.map +0 -1
  177. package/lib/types/ProjectsApi.d.ts +0 -17
  178. package/lib/types/ProjectsApi.d.ts.map +0 -1
  179. package/lib/types/PromptsApi.d.ts +0 -106
  180. package/lib/types/PromptsApi.d.ts.map +0 -1
  181. package/lib/types/RefsApi.d.ts +0 -6
  182. package/lib/types/RefsApi.d.ts.map +0 -1
  183. package/lib/types/RunsApi.d.ts +0 -77
  184. package/lib/types/RunsApi.d.ts.map +0 -1
  185. package/lib/types/StreamSource.d.ts +0 -7
  186. package/lib/types/StreamSource.d.ts.map +0 -1
  187. package/lib/types/TrainingApi.d.ts +0 -27
  188. package/lib/types/TrainingApi.d.ts.map +0 -1
  189. package/lib/types/UsersApi.d.ts +0 -6
  190. package/lib/types/UsersApi.d.ts.map +0 -1
  191. package/lib/types/client.d.ts +0 -114
  192. package/lib/types/client.d.ts.map +0 -1
  193. package/lib/types/execute.d.ts +0 -36
  194. package/lib/types/execute.d.ts.map +0 -1
  195. package/lib/types/index.d.ts +0 -8
  196. package/lib/types/index.d.ts.map +0 -1
  197. package/lib/types/nodejs/NodeStreamSource.d.ts +0 -9
  198. package/lib/types/nodejs/NodeStreamSource.d.ts.map +0 -1
  199. package/lib/types/nodejs/index.d.ts +0 -1
  200. package/lib/types/nodejs/index.d.ts.map +0 -1
  201. package/lib/types/store/AgentsApi.d.ts +0 -6
  202. package/lib/types/store/AgentsApi.d.ts.map +0 -1
  203. package/lib/types/store/AnalyzeDocApi.d.ts +0 -17
  204. package/lib/types/store/AnalyzeDocApi.d.ts.map +0 -1
  205. package/lib/types/store/CollectionsApi.d.ts +0 -66
  206. package/lib/types/store/CollectionsApi.d.ts.map +0 -1
  207. package/lib/types/store/CommandsApi.d.ts +0 -10
  208. package/lib/types/store/CommandsApi.d.ts.map +0 -1
  209. package/lib/types/store/EmbeddingsApi.d.ts +0 -12
  210. package/lib/types/store/EmbeddingsApi.d.ts.map +0 -1
  211. package/lib/types/store/FilesApi.d.ts +0 -47
  212. package/lib/types/store/FilesApi.d.ts.map +0 -1
  213. package/lib/types/store/ObjectsApi.d.ts +0 -120
  214. package/lib/types/store/ObjectsApi.d.ts.map +0 -1
  215. package/lib/types/store/TypesApi.d.ts +0 -23
  216. package/lib/types/store/TypesApi.d.ts.map +0 -1
  217. package/lib/types/store/WorkflowsApi.d.ts +0 -50
  218. package/lib/types/store/WorkflowsApi.d.ts.map +0 -1
  219. package/lib/types/store/client.d.ts +0 -29
  220. package/lib/types/store/client.d.ts.map +0 -1
  221. package/lib/types/store/errors.d.ts +0 -4
  222. package/lib/types/store/errors.d.ts.map +0 -1
  223. package/lib/types/store/index.d.ts +0 -5
  224. package/lib/types/store/index.d.ts.map +0 -1
  225. package/lib/vertesia-client.js +0 -2
  226. package/lib/vertesia-client.js.map +0 -1
@@ -1,5 +1,6 @@
1
1
  import { ApiTopic, ClientBase } from "@vertesia/api-fetch-client";
2
2
  import {
3
+ ContentObjectApiHeaders,
3
4
  ComplexSearchPayload,
4
5
  ComputeObjectFacetPayload,
5
6
  ContentObject,
@@ -48,7 +49,7 @@ export interface ComputeFacetsResponse {
48
49
  type?: { _id: string; count: number }[];
49
50
  location?: { _id: string; count: number }[];
50
51
  status?: { _id: string; count: number }[];
51
- total?: { count: number }[];
52
+ total?: number;
52
53
  }
53
54
 
54
55
  export interface SearchResponse {
@@ -231,9 +232,18 @@ export class ObjectsApi extends ApiTopic {
231
232
  ) {
232
233
  createPayload.content = await this.upload(payload.content);
233
234
  }
235
+
236
+ const headers: Record<string, string> = {};
237
+ if (options?.processing_priority) {
238
+ headers[ContentObjectApiHeaders.PROCESSING_PRIORITY] = options.processing_priority;
239
+ }
240
+ if (options?.collection_id) {
241
+ headers[ContentObjectApiHeaders.COLLECTION_ID] = options.collection_id;
242
+ }
243
+
234
244
  return await this.post("/", {
235
245
  payload: createPayload,
236
- query: options || {},
246
+ headers: headers,
237
247
  });
238
248
  }
239
249
 
@@ -243,11 +253,16 @@ export class ObjectsApi extends ApiTopic {
243
253
  * For the s3 blobs you must use a hash with the blob #region. Ex: s3://bucket/path/to/file#us-east-1
244
254
  * @param uri
245
255
  * @param payload
256
+ * @param options
246
257
  * @returns
247
258
  */
248
259
  async createFromExternalSource(
249
260
  uri: string,
250
261
  payload: CreateContentObjectPayload = {},
262
+ options?: {
263
+ collection_id?: string;
264
+ processing_priority?: ContentObjectProcessingPriority;
265
+ },
251
266
  ): Promise<ContentObject> {
252
267
  const metadata = await (this.client as ZenoClient).files.getMetadata(
253
268
  uri,
@@ -261,8 +276,18 @@ export class ObjectsApi extends ApiTopic {
261
276
  etag: metadata.etag,
262
277
  },
263
278
  };
279
+
280
+ const headers: Record<string, string> = {};
281
+ if (options?.processing_priority) {
282
+ headers[ContentObjectApiHeaders.PROCESSING_PRIORITY] = options.processing_priority;
283
+ }
284
+ if (options?.collection_id) {
285
+ headers[ContentObjectApiHeaders.COLLECTION_ID] = options.collection_id;
286
+ }
287
+
264
288
  return await this.post("/", {
265
289
  payload: createPayload,
290
+ headers: headers,
266
291
  });
267
292
  }
268
293
 
@@ -298,19 +323,21 @@ export class ObjectsApi extends ApiTopic {
298
323
  updatePayload.content = await this.upload(payload.content);
299
324
  }
300
325
 
326
+ const headers: Record<string, string> = {};
327
+ if (options?.processing_priority) {
328
+ headers[ContentObjectApiHeaders.PROCESSING_PRIORITY] = options.processing_priority;
329
+ }
301
330
  if (options?.createRevision) {
302
- return this.put(`/${id}`, {
303
- payload: updatePayload,
304
- headers: {
305
- "x-create-revision": "true",
306
- "x-revision-label": options.revisionLabel || "",
307
- },
308
- });
309
- } else {
310
- return this.put(`/${id}`, {
311
- payload: updatePayload,
312
- });
331
+ headers[ContentObjectApiHeaders.CREATE_REVISION] = "true";
332
+ if (options.revisionLabel) {
333
+ headers[ContentObjectApiHeaders.REVISION_LABEL] = options.revisionLabel;
334
+ }
313
335
  }
336
+
337
+ return this.put(`/${id}`, {
338
+ payload: updatePayload,
339
+ headers,
340
+ });
314
341
  }
315
342
 
316
343
  /**
@@ -10,6 +10,8 @@ import {
10
10
  ListWorkflowInteractionsResponse,
11
11
  ListWorkflowRunsPayload,
12
12
  ListWorkflowRunsResponse,
13
+ WebSocketClientMessage,
14
+ WebSocketServerMessage,
13
15
  WorkflowDefinitionRef,
14
16
  WorkflowRule,
15
17
  WorkflowRuleItem,
@@ -248,6 +250,170 @@ export class WorkflowsApi extends ApiTopic {
248
250
  });
249
251
  }
250
252
 
253
+ /**
254
+ * Stream workflow messages via WebSocket (for mobile/React Native clients)
255
+ * @param workflowId The workflow ID
256
+ * @param runId The run ID
257
+ * @param onMessage Callback for incoming messages
258
+ * @param since Optional timestamp to resume from
259
+ * @returns Promise that resolves with cleanup function and sendSignal helper
260
+ */
261
+ async streamMessagesWS(
262
+ workflowId: string,
263
+ runId: string,
264
+ onMessage?: (message: AgentMessage) => void,
265
+ since?: number
266
+ ): Promise<{ cleanup: () => void; sendSignal: (signalName: string, data: any) => void }> {
267
+ return new Promise((resolve, reject) => {
268
+ let reconnectAttempts = 0;
269
+ const maxReconnectAttempts = 10;
270
+ const baseDelay = 1000;
271
+ const maxDelay = 30000;
272
+ let ws: WebSocket | null = null;
273
+ let lastMessageTimestamp = since || 0;
274
+ let isClosed = false;
275
+
276
+ const calculateBackoffDelay = (attempts: number): number => {
277
+ const exponentialDelay = Math.min(baseDelay * Math.pow(2, attempts), maxDelay);
278
+ const jitter = Math.random() * 0.1 * exponentialDelay;
279
+ return exponentialDelay + jitter;
280
+ };
281
+
282
+ const connect = async () => {
283
+ if (isClosed) return;
284
+
285
+ try {
286
+ const client = this.client as VertesiaClient;
287
+ const wsUrl = new URL(client.workflows.baseUrl + `/runs/${workflowId}/${runId}/ws`);
288
+
289
+ // Replace http/https with ws/wss
290
+ wsUrl.protocol = wsUrl.protocol.replace('http', 'ws');
291
+
292
+ // Add query parameters
293
+ if (lastMessageTimestamp > 0) {
294
+ wsUrl.searchParams.set('since', lastMessageTimestamp.toString());
295
+ }
296
+
297
+ const bearerToken = client._auth ? await client._auth() : undefined;
298
+ if (!bearerToken) {
299
+ reject(new Error('No auth token available'));
300
+ return;
301
+ }
302
+
303
+ const token = bearerToken.split(' ')[1];
304
+ wsUrl.searchParams.set('access_token', token);
305
+
306
+ if (reconnectAttempts > 0) {
307
+ console.log(`Reconnecting to WebSocket for run ${runId} (attempt ${reconnectAttempts + 1}/${maxReconnectAttempts})`);
308
+ }
309
+
310
+ ws = new WebSocket(wsUrl.href);
311
+
312
+ ws.onopen = () => {
313
+ if (reconnectAttempts > 0) {
314
+ console.log(`Successfully reconnected to WebSocket for run ${runId}`);
315
+ }
316
+ reconnectAttempts = 0;
317
+
318
+ // Resolve with helpers on first successful connection
319
+ if (!isClosed) {
320
+ resolve({
321
+ cleanup: () => {
322
+ isClosed = true;
323
+ if (ws) {
324
+ ws.close();
325
+ ws = null;
326
+ }
327
+ },
328
+ sendSignal: (signalName: string, data: any) => {
329
+ if (ws?.readyState === WebSocket.OPEN) {
330
+ const message: WebSocketClientMessage = {
331
+ type: 'signal',
332
+ signalName,
333
+ data,
334
+ requestId: Date.now()
335
+ };
336
+ ws.send(JSON.stringify(message));
337
+ } else {
338
+ console.warn('WebSocket not open, cannot send signal');
339
+ }
340
+ }
341
+ });
342
+ }
343
+ };
344
+
345
+ ws.onmessage = (event: MessageEvent) => {
346
+ try {
347
+ const message = JSON.parse(event.data) as WebSocketServerMessage;
348
+
349
+ // Handle different message types
350
+ if ('workflow_run_id' in message) {
351
+ // This is an AgentMessage
352
+ const agentMessage = message as AgentMessage;
353
+
354
+ if (agentMessage.timestamp) {
355
+ lastMessageTimestamp = Math.max(lastMessageTimestamp, agentMessage.timestamp);
356
+ }
357
+
358
+ if (onMessage) onMessage(agentMessage);
359
+
360
+ // Check for stream completion
361
+ const streamIsOver =
362
+ agentMessage.type === AgentMessageType.TERMINATED ||
363
+ (agentMessage.type === AgentMessageType.COMPLETE &&
364
+ (!agentMessage.workstream_id || agentMessage.workstream_id === 'main'));
365
+
366
+ if (streamIsOver) {
367
+ console.log('Closing WebSocket due to workflow completion');
368
+ isClosed = true;
369
+ if (ws) {
370
+ ws.close();
371
+ ws = null;
372
+ }
373
+ }
374
+ } else if (message.type === 'pong') {
375
+ // Heartbeat response
376
+ console.debug('Received pong');
377
+ } else if (message.type === 'ack') {
378
+ console.debug('Signal acknowledged', message);
379
+ } else if (message.type === 'error') {
380
+ console.error('WebSocket error message', message);
381
+ }
382
+ } catch (err) {
383
+ console.error('Failed to parse WebSocket message', err);
384
+ }
385
+ };
386
+
387
+ ws.onerror = (err) => {
388
+ console.error('WebSocket error', err);
389
+ };
390
+
391
+ ws.onclose = () => {
392
+ if (!isClosed && reconnectAttempts < maxReconnectAttempts) {
393
+ const delay = calculateBackoffDelay(reconnectAttempts);
394
+ console.log(`WebSocket closed, reconnecting in ${delay}ms (attempt ${reconnectAttempts + 1}/${maxReconnectAttempts})`);
395
+ reconnectAttempts++;
396
+ setTimeout(connect, delay);
397
+ } else if (reconnectAttempts >= maxReconnectAttempts) {
398
+ reject(new Error(`WebSocket connection failed after ${maxReconnectAttempts} attempts`));
399
+ }
400
+ };
401
+ } catch (err) {
402
+ console.error('Error setting up WebSocket', err);
403
+ if (reconnectAttempts < maxReconnectAttempts) {
404
+ const delay = calculateBackoffDelay(reconnectAttempts);
405
+ reconnectAttempts++;
406
+ setTimeout(connect, delay);
407
+ } else {
408
+ reject(err);
409
+ }
410
+ }
411
+ };
412
+
413
+ connect();
414
+ });
415
+ }
416
+
251
417
  rules = new WorkflowsRulesApi(this);
252
418
  definitions = new WorkflowsDefinitionApi(this);
253
419
  }
@@ -12,6 +12,7 @@ import { CollectionsApi } from "./CollectionsApi.js";
12
12
 
13
13
  export interface ZenoClientProps {
14
14
  serverUrl?: string;
15
+ tokenServerUrl?: string;
15
16
  apikey?: string;
16
17
  onRequest?: (request: Request) => void;
17
18
  onResponse?: (response: Response) => void;
@@ -56,6 +57,13 @@ export class ZenoClient extends AbstractFetchClient<ZenoClient> {
56
57
  });
57
58
  }
58
59
 
60
+ get initialHeaders() {
61
+ return {
62
+ ...super.initialHeaders,
63
+ 'X-Api-Version': '20250925' // YYYYMMDD, client versioning for API endpoints. Increment manually for breaking changes
64
+ }
65
+ }
66
+
59
67
  objects = new ObjectsApi(this);
60
68
  types = new TypesApi(this);
61
69
  workflows = new WorkflowsApi(this);
@@ -1,85 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
4
- class AccountApi extends api_fetch_client_1.ApiTopic {
5
- constructor(parent) {
6
- super(parent, "/api/v1/account");
7
- }
8
- /**
9
- * Retrieve all account information for current account
10
- * @returns Account[]
11
- */
12
- info() {
13
- return this.get('/');
14
- }
15
- /**
16
- * Update account information
17
- * @returns Account
18
- */
19
- update(payload) {
20
- return this.put('/', { payload });
21
- }
22
- /**
23
- * Get all projects for account
24
- */
25
- projects() {
26
- return this.get('/projects').then(res => res.data);
27
- }
28
- members() {
29
- return this.get('/members');
30
- }
31
- /**
32
- * Invite User to account
33
- */
34
- inviteUser(payload) {
35
- return this.post('/invites', { payload });
36
- }
37
- /**
38
- * Fetch Invites for Principal
39
- * @returns UserInviteTokenData[]
40
- * */
41
- listInvites() {
42
- return this.get('/invites');
43
- }
44
- /**
45
- * Fetch Invites for specific account or project
46
- * @param type Filter for the type of invitation, either "project" or "account"
47
- * @returns UserInviteTokenData[]
48
- * */
49
- listInvitation(type = "project") {
50
- return this.get(`/invites/${type}`);
51
- }
52
- /**
53
- * Accept Invite for account
54
- * @returns UserInviteTokenData
55
- * */
56
- acceptInvite(id) {
57
- return this.put(`/invites/${id}`);
58
- }
59
- /**
60
- * Delete Invite for account
61
- * @returns UserInviteTokenData
62
- * */
63
- rejectInvite(id) {
64
- return this.delete(`/invites/${id}`);
65
- }
66
- /**
67
- * Get Onboarding Progress for account
68
- */
69
- onboardingProgress() {
70
- return this.get('/onboarding');
71
- }
72
- /**
73
- * Get a google auth token for the current project.
74
- * This token can be used to access exposed google cloud services
75
- * @returns
76
- */
77
- getGoogleToken() {
78
- return this.get('/google-token');
79
- }
80
- getStripeBillingStatus() {
81
- return this.get('/stripe-billing-status');
82
- }
83
- }
84
- exports.default = AccountApi;
85
- //# sourceMappingURL=AccountApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AccountApi.js","sourceRoot":"","sources":["../../src/AccountApi.ts"],"names":[],"mappings":";;AAAA,iEAAkE;AAGlE,MAAqB,UAAW,SAAQ,2BAAQ;IAE5C,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAED;;;OAGG;IACH,IAAI;QACA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,OAA6B;QAChC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACtC,CAAC;IAED;;MAEE;IACF,QAAQ;QACJ,OAAO,IAAI,CAAC,GAAG,CAAC,WAAW,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;IACvD,CAAC;IAED,OAAO;QACH,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAA;IAC/B,CAAC;IAED;;OAEG;IACH,UAAU,CAAC,OAAiC;QACxC,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC9C,CAAC;IAED;;;SAGK;IACL,WAAW;QACP,OAAO,IAAI,CAAC,GAAG,CAAC,UAAU,CAAC,CAAC;IAChC,CAAC;IACD;;;;SAIK;IACL,cAAc,CAAC,OAA8B,SAAS;QAClD,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IACxC,CAAC;IAED;;;SAGK;IACL,YAAY,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACtC,CAAC;IAED;;;SAGK;IACL,YAAY,CAAC,EAAU;QACnB,OAAO,IAAI,CAAC,MAAM,CAAC,YAAY,EAAE,EAAE,CAAC,CAAC;IACzC,CAAC;IAED;;OAEG;IACH,kBAAkB;QACd,OAAO,IAAI,CAAC,GAAG,CAAC,aAAa,CAAC,CAAC;IACnC,CAAC;IAED;;;;OAIG;IACH,cAAc;QACV,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,CAAC,CAAC;IACrC,CAAC;IAED,sBAAsB;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAA;IAC7C,CAAC;CAEJ;AA5FD,6BA4FC"}
@@ -1,16 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
4
- class AccountsApi extends api_fetch_client_1.ApiTopic {
5
- constructor(parent) {
6
- super(parent, "/api/v1/accounts");
7
- }
8
- create(name) {
9
- return this.post('/', { payload: { name } });
10
- }
11
- list() {
12
- return this.get('/');
13
- }
14
- }
15
- exports.default = AccountsApi;
16
- //# sourceMappingURL=AccountsApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AccountsApi.js","sourceRoot":"","sources":["../../src/AccountsApi.ts"],"names":[],"mappings":";;AACA,iEAAkE;AAElE,MAAqB,WAAY,SAAQ,2BAAQ;IAE7C,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,MAAM,CAAC,IAAY;QACf,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,IAAI;QACA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;CAMJ;AAlBD,8BAkBC"}
@@ -1,13 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
4
- class AnalyticsApi extends api_fetch_client_1.ApiTopic {
5
- constructor(parent) {
6
- super(parent, "/api/v1/analytics");
7
- }
8
- runs(params) {
9
- return this.post('/runs', { payload: params });
10
- }
11
- }
12
- exports.default = AnalyticsApi;
13
- //# sourceMappingURL=AnalyticsApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AnalyticsApi.js","sourceRoot":"","sources":["../../src/AnalyticsApi.ts"],"names":[],"mappings":";;AACA,iEAAkE;AAKlE,MAAqB,YAAa,SAAQ,2BAAQ;IAE9C,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,mBAAmB,CAAC,CAAA;IACtC,CAAC;IAED,IAAI,CAAC,MAAyB;QAE1B,OAAO,IAAI,CAAC,IAAI,CAAC,OAAO,EAAE,EAAE,OAAO,EAAE,MAAM,EAAE,CAAC,CAAC;IAEnD,CAAC;CAGJ;AAbD,+BAaC"}
@@ -1,63 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- exports.ApiKeysApi = void 0;
4
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
5
- class ApiKeysApi extends api_fetch_client_1.ApiTopic {
6
- constructor(parent) {
7
- super(parent, "/api/v1/apikeys");
8
- }
9
- /**
10
- * List all keys for account without values
11
- * @returns ApiKey[]
12
- */
13
- list(level = 'account') {
14
- return this.get('/', { query: { level } });
15
- }
16
- /**
17
- * Create an new ApiKey for account
18
- * BE VERY CAREFUL USING THIS API
19
- * ALL REQUESTS ARE LOGGED IN SECURITY AUDIT LOG
20
- * @returns ApiKeyWithValue
21
- */
22
- create(payload) {
23
- return this.post('/', { payload });
24
- }
25
- /**
26
- * Update an existing ApiKey for account
27
- * @returns ApiKey
28
- */
29
- update(id, payload) {
30
- return this.put(`/${id}`, { payload });
31
- }
32
- /**
33
- * Retrieve an ApiKey and its value
34
- * BE VERY CAREFUL USING THIS API AS IT EXPOSE THE API KEY VALUE
35
- * ALL REQUESTS ARE LOGGED IN SECURITY AUDIT LOG
36
- * @returns ApiKeyWithValue
37
- * */
38
- retrieve(id, withValue = false) {
39
- if (withValue) {
40
- return this.get(`/${id}`, { query: { withValue: true } });
41
- }
42
- else {
43
- return this.get(`/${id}`);
44
- }
45
- }
46
- /**
47
- * get or create a temporary public key which can be used from browser to browse and execute interactions.
48
- * If a public key already exists for the given project (or for the current organization) then it is returned, otherwise a new one is created.
49
- * The payload object can contain the following properties:
50
- * - name: the name of the public key. If not specified a random name is generated.
51
- * - projectId: the id of the project to which the public key will be associated.
52
- * If not specified the key is associated with the current organization. (i.e. account).
53
- * - ttl: the time to live of the public key in seconds.
54
- * The ttl defaults to 1h.
55
- * @param opts
56
- * @returns
57
- */
58
- requestPublicKey(payload = {}) {
59
- return this.get('/pk', { query: payload });
60
- }
61
- }
62
- exports.ApiKeysApi = ApiKeysApi;
63
- //# sourceMappingURL=ApiKeysApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"ApiKeysApi.js","sourceRoot":"","sources":["../../src/ApiKeysApi.ts"],"names":[],"mappings":";;;AACA,iEAAkE;AAElE,MAAa,UAAW,SAAQ,2BAAQ;IAGpC,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,iBAAiB,CAAC,CAAA;IACpC,CAAC;IAGD;;;OAGG;IACH,IAAI,CAAC,QAA+B,SAAS;QACzC,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,EAAE,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,EAAE,CAAC,CAAC;IAC/C,CAAC;IAED;;;;;OAKG;IACH,MAAM,CAAC,OAAoC;QACvC,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IACvC,CAAC;IAED;;;OAGG;IACH,MAAM,CAAC,EAAU,EAAE,OAAoC;QACnD,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC;IAC3C,CAAC;IAED;;;;;SAKK;IACL,QAAQ,CAAC,EAAU,EAAE,YAAqB,KAAK;QAC3C,IAAI,SAAS,EAAE,CAAC;YACZ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9D,CAAC;aAAM,CAAC;YACJ,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;QAC9B,CAAC;IACL,CAAC;IAED;;;;;;;;;;;OAWG;IACH,gBAAgB,CAAC,UAAkC,EAAE;QACjD,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,EAAE,EAAE,KAAK,EAAE,OAA0C,EAAE,CAAC,CAAC;IAClF,CAAC;CACJ;AA/DD,gCA+DC"}
@@ -1,111 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
4
- class AppsApi extends api_fetch_client_1.ApiTopic {
5
- constructor(parent) {
6
- super(parent, "/api/v1/apps");
7
- }
8
- create(manifest) {
9
- return this.post('/', { payload: manifest });
10
- }
11
- update(id, manifest) {
12
- return this.put(`/${id}`, { payload: manifest });
13
- }
14
- /**
15
- * @param ids - ids to filter by
16
- * @returns the app manifests but without the agent.tool property which can be big.
17
- */
18
- list() {
19
- return this.get('/');
20
- }
21
- /**
22
- * Install the app with the given id in the current project.
23
- * @param appId - the id of the app to install
24
- */
25
- install(appId, settings) {
26
- return this.post(`/install`, {
27
- payload: {
28
- app_id: appId,
29
- settings
30
- }
31
- });
32
- }
33
- /**
34
- * Remove the given app from the current project.
35
- * @param installationId - the id of the app installation
36
- * @returns
37
- */
38
- uninstall(installationId) {
39
- return this.del(`/install/${installationId}`);
40
- }
41
- /**
42
- * get an app unstallation given its name or null if the app is not installed
43
- * @returns
44
- */
45
- getAppInstallationByName(appName) {
46
- return this.get(`/installations/name/${appName}`).catch((err) => {
47
- if (err.status === 404) {
48
- return null;
49
- }
50
- else {
51
- throw err;
52
- }
53
- });
54
- }
55
- /**
56
- * Get the project refs where the application is visible by the current user.
57
- * The application is specified either by id or by name.
58
- * @param param0
59
- * @returns
60
- */
61
- getAppInstallationProjects(app) {
62
- if (!app.id && !app.name) {
63
- throw new Error("Invalid arguments: appId or appName must be specified");
64
- }
65
- const query = app.id ? {
66
- id: app.id
67
- } : {
68
- name: app.name
69
- };
70
- return this.get("/installations/projects", {
71
- query
72
- });
73
- }
74
- /**
75
- * Get the apps installed for the current authenticated project
76
- * @param kind - the kind of app installations to filter by (e.g., 'agent', 'tool', etc.)
77
- */
78
- getInstalledApps(kind) {
79
- return this.get('/installations', {
80
- query: {
81
- kind,
82
- }
83
- });
84
- }
85
- /**
86
- * This operation will return an array of all the found AppInstallations in the current project
87
- * including orphaned installations
88
- * This requires project admin since access is not checked on the insytallations.
89
- * For a user level list of available installations (with user permission check) use getInstalledApps
90
- * @returns
91
- */
92
- getAllAppInstallations() {
93
- return this.get('/installations/all');
94
- }
95
- /**
96
- * List the app installations of the current project.
97
- */
98
- listInstallations() {
99
- return this.get('/installations/refs');
100
- }
101
- updateInstallationSettings(settingsPayload) {
102
- return this.put(`/installations/settings/${settingsPayload.app_id}`, {
103
- payload: {
104
- app_id: settingsPayload.app_id,
105
- settings: settingsPayload.settings
106
- }
107
- });
108
- }
109
- }
110
- exports.default = AppsApi;
111
- //# sourceMappingURL=AppsApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"AppsApi.js","sourceRoot":"","sources":["../../src/AppsApi.ts"],"names":[],"mappings":";;AAAA,iEAA+E;AAO/E,MAAqB,OAAQ,SAAQ,2BAAQ;IAEzC,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,cAAc,CAAC,CAAA;IACjC,CAAC;IAED,MAAM,CAAC,QAAyB;QAC5B,OAAO,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,CAAC,EAAU,EAAE,QAAyB;QACxC,OAAO,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,EAAE,EAAE,EAAE,OAAO,EAAE,QAAQ,EAAE,CAAC,CAAC;IACrD,CAAC;IAED;;;OAGG;IACH,IAAI;QACA,OAAO,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,CAAC;IACzB,CAAC;IAED;;;OAGG;IACH,OAAO,CAAC,KAAa,EAAE,QAA8B;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE;YACzB,OAAO,EAAE;gBACL,MAAM,EAAE,KAAK;gBACb,QAAQ;aACsB;SACrC,CAAC,CAAC;IACP,CAAC;IAED;;;;OAIG;IACH,SAAS,CAAC,cAAsB;QAC5B,OAAO,IAAI,CAAC,GAAG,CAAC,YAAY,cAAc,EAAE,CAAC,CAAC;IAClD,CAAC;IAED;;;OAGG;IACH,wBAAwB,CAAC,OAAe;QACpC,OAAO,IAAI,CAAC,GAAG,CAAC,uBAAuB,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,GAAgB,EAAE,EAAE;YACzE,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;gBACrB,OAAO,IAAI,CAAC;YAChB,CAAC;iBAAM,CAAC;gBACJ,MAAM,GAAG,CAAC;YACd,CAAC;QACL,CAAC,CAAC,CAAA;IACN,CAAC;IAED;;;;;OAKG;IACH,0BAA0B,CAAC,GAAqE;QAC5F,IAAI,CAAC,GAAG,CAAC,EAAE,IAAI,CAAC,GAAG,CAAC,IAAI,EAAE,CAAC;YACvB,MAAM,IAAI,KAAK,CAAC,uDAAuD,CAAC,CAAC;QAC7E,CAAC;QACD,MAAM,KAAK,GAAG,GAAG,CAAC,EAAE,CAAC,CAAC,CAAC;YACnB,EAAE,EAAE,GAAG,CAAC,EAAE;SACb,CAAC,CAAC,CAAC;YACA,IAAI,EAAE,GAAG,CAAC,IAAI;SACjB,CAAA;QACD,OAAO,IAAI,CAAC,GAAG,CAAC,yBAAyB,EAAE;YACvC,KAAK;SACR,CAAC,CAAC;IACP,CAAC;IAED;;;OAGG;IACH,gBAAgB,CAAC,IAA0B;QACvC,OAAO,IAAI,CAAC,GAAG,CAAC,gBAAgB,EAAE;YAC9B,KAAK,EAAE;gBACH,IAAI;aACP;SACJ,CAAC,CAAC;IACP,CAAC;IAED;;;;;;OAMG;IACH,sBAAsB;QAClB,OAAO,IAAI,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;IAC1C,CAAC;IAED;;OAEG;IACH,iBAAiB;QACb,OAAO,IAAI,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;IAC3C,CAAC;IAED,0BAA0B,CAAC,eAAuC;QAC9D,OAAO,IAAI,CAAC,GAAG,CAAC,2BAA2B,eAAe,CAAC,MAAM,EAAE,EAAE;YACjE,OAAO,EAAE;gBACL,MAAM,EAAE,eAAe,CAAC,MAAM;gBAC9B,QAAQ,EAAE,eAAe,CAAC,QAAQ;aACJ;SACrC,CAAC,CAAC;IACP,CAAC;CAEJ;AArHD,0BAqHC"}
@@ -1,19 +0,0 @@
1
- "use strict";
2
- Object.defineProperty(exports, "__esModule", { value: true });
3
- const api_fetch_client_1 = require("@vertesia/api-fetch-client");
4
- /**
5
- * Various utility commands
6
- */
7
- class CommandsApi extends api_fetch_client_1.ApiTopic {
8
- constructor(parent) {
9
- super(parent, "/api/v1/commands");
10
- }
11
- async isNamespaceAvailable(name) {
12
- return this.get(`/namespaces/${name}/is_available`).then((response) => response.available);
13
- }
14
- async initSamples() {
15
- return this.post("/onboarding/init-samples");
16
- }
17
- }
18
- exports.default = CommandsApi;
19
- //# sourceMappingURL=CommandsApi.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"CommandsApi.js","sourceRoot":"","sources":["../../src/CommandsApi.ts"],"names":[],"mappings":";;AAAA,iEAAkE;AAIlE;;GAEG;AAEH,MAAqB,WAAY,SAAQ,2BAAQ;IAE7C,YAAY,MAAkB;QAC1B,KAAK,CAAC,MAAM,EAAE,kBAAkB,CAAC,CAAA;IACrC,CAAC;IAED,KAAK,CAAC,oBAAoB,CAAC,IAAY;QACnC,OAAO,IAAI,CAAC,GAAG,CAAC,eAAe,IAAI,eAAe,CAAC,CAAC,IAAI,CAAC,CAAC,QAAQ,EAAE,EAAE,CAAC,QAAQ,CAAC,SAAS,CAAC,CAAC;IAC/F,CAAC;IAED,KAAK,CAAC,WAAW;QACb,OAAO,IAAI,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAC;IACjD,CAAC;CAEJ;AAdD,8BAcC"}