@aviaryhq/cloudglue-js 0.0.13 → 0.0.15

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.
@@ -1,5 +1,5 @@
1
- import { FilesApi, CollectionsApi, ChatApi, TranscribeApi, ExtractApi } from '../generated';
2
- import type { File } from './types';
1
+ import { FilesApi, CollectionsApi, ChatApi, TranscribeApi, ExtractApi } from "../generated";
2
+ import type { File } from "./types";
3
3
  export declare class CloudGlueError extends Error {
4
4
  readonly statusCode?: number | undefined;
5
5
  readonly data?: string | undefined;
@@ -12,13 +12,17 @@ export declare class CloudGlueError extends Error {
12
12
  export interface CloudGlueConfig {
13
13
  apiKey?: string;
14
14
  baseUrl?: string;
15
+ /**
16
+ * Time limit in milliseconds before we timeout a request
17
+ */
18
+ timeout?: number;
15
19
  }
16
20
  interface ListFilesParams {
17
- status?: 'pending' | 'processing' | 'ready' | 'completed' | 'failed' | 'not_applicable';
21
+ status?: "pending" | "processing" | "ready" | "completed" | "failed" | "not_applicable";
18
22
  limit?: number;
19
23
  offset?: number;
20
- order?: 'created_at' | 'filename';
21
- sort?: 'asc' | 'desc';
24
+ order?: "created_at" | "filename";
25
+ sort?: "asc" | "desc";
22
26
  created_before?: string;
23
27
  created_after?: string;
24
28
  }
@@ -29,12 +33,12 @@ interface UploadFileParams {
29
33
  interface ListCollectionParams {
30
34
  limit?: number;
31
35
  offset?: number;
32
- order?: 'name' | 'created_at';
33
- sort?: 'asc' | 'desc';
34
- collection_type?: 'entities' | 'rich-transcripts';
36
+ order?: "name" | "created_at";
37
+ sort?: "asc" | "desc";
38
+ collection_type?: "entities" | "rich-transcripts";
35
39
  }
36
40
  interface CreateCollectionParams {
37
- collection_type: 'entities' | 'rich-transcripts';
41
+ collection_type: "entities" | "rich-transcripts";
38
42
  name: string;
39
43
  description?: string;
40
44
  extract_config?: {
@@ -51,16 +55,16 @@ interface CreateCollectionParams {
51
55
  interface ListCollectionVideosParams {
52
56
  limit?: number;
53
57
  offset?: number;
54
- status?: 'pending' | 'processing' | 'ready' | 'completed' | 'failed' | 'not_applicable';
55
- order?: 'added_at' | 'filename';
56
- sort?: 'asc' | 'desc';
58
+ status?: "pending" | "processing" | "ready" | "completed" | "failed" | "not_applicable";
59
+ order?: "added_at" | "filename";
60
+ sort?: "asc" | "desc";
57
61
  added_before?: string;
58
62
  added_after?: string;
59
63
  }
60
64
  interface ChatCompletionParams {
61
65
  model?: string;
62
66
  messages: Array<{
63
- role: 'system' | 'user' | 'assistant';
67
+ role: "system" | "user" | "assistant";
64
68
  content: string;
65
69
  name?: string;
66
70
  }>;
@@ -68,7 +72,7 @@ interface ChatCompletionParams {
68
72
  filter?: {
69
73
  metadata?: Array<{
70
74
  path: string;
71
- operator: 'NotEqual' | 'Equal' | 'LessThan' | 'GreaterThan' | 'In' | 'ContainsAny' | 'ContainsAll';
75
+ operator: "NotEqual" | "Equal" | "LessThan" | "GreaterThan" | "In" | "ContainsAny" | "ContainsAll";
72
76
  valueText?: string;
73
77
  valueTextArray?: string[];
74
78
  }>;
@@ -79,6 +83,12 @@ interface ChatCompletionParams {
79
83
  top_p?: number;
80
84
  max_tokens?: number;
81
85
  }
86
+ interface WaitForReadyOptions {
87
+ /** Interval in milliseconds between polling attempts. Defaults to 5000ms (5 seconds). */
88
+ pollingInterval?: number;
89
+ /** Maximum number of polling attempts before giving up. Defaults to 36 (3 minutes total with default interval). */
90
+ maxAttempts?: number;
91
+ }
82
92
  declare class EnhancedFilesApi {
83
93
  private readonly api;
84
94
  constructor(api: typeof FilesApi);
@@ -122,6 +132,43 @@ declare class EnhancedFilesApi {
122
132
  id: import("zod").ZodString;
123
133
  object: import("zod").ZodLiteral<"file">;
124
134
  }, import("zod").ZodTypeAny, "passthrough">>;
135
+ /**
136
+ * Waits for a file to finish processing by polling the getFile endpoint until the file
137
+ * reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
138
+ *
139
+ * @param fileId - The ID of the file to wait for
140
+ * @param options - Optional configuration for polling behavior
141
+ * @returns The final file object
142
+ * @throws {CloudGlueError} If the file fails to process or maxAttempts is reached
143
+ */
144
+ waitForReady(fileId: string, options?: WaitForReadyOptions): Promise<import("zod").objectOutputType<{
145
+ id: import("zod").ZodString;
146
+ status: import("zod").ZodEnum<["pending", "processing", "completed", "failed", "not_applicable"]>;
147
+ bytes: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
148
+ created_at: import("zod").ZodOptional<import("zod").ZodNumber>;
149
+ filename: import("zod").ZodOptional<import("zod").ZodString>;
150
+ uri: import("zod").ZodString;
151
+ metadata: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodObject<{}, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{}, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{}, import("zod").ZodTypeAny, "passthrough">>, import("zod").ZodNull]>>;
152
+ video_info: import("zod").ZodOptional<import("zod").ZodObject<{
153
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
154
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
155
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
156
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
157
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
158
+ }, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
159
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
160
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
161
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
162
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
163
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
164
+ }, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
165
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
166
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
167
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
168
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
169
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
170
+ }, import("zod").ZodTypeAny, "passthrough">>>;
171
+ }, import("zod").ZodTypeAny, "passthrough">>;
125
172
  }
126
173
  declare class EnhancedCollectionsApi {
127
174
  private readonly api;
@@ -258,7 +305,7 @@ declare class EnhancedCollectionsApi {
258
305
  limit: import("zod").ZodNumber;
259
306
  offset: import("zod").ZodNumber;
260
307
  }, import("zod").ZodTypeAny, "passthrough">>;
261
- getTranscripts(collectionId: string, fileId: string, limit?: number, offset?: number, response_format?: 'markdown' | 'json'): Promise<import("zod").objectOutputType<{
308
+ getTranscripts(collectionId: string, fileId: string, limit?: number, offset?: number, response_format?: "markdown" | "json"): Promise<import("zod").objectOutputType<{
262
309
  collection_id: import("zod").ZodString;
263
310
  file_id: import("zod").ZodString;
264
311
  content: import("zod").ZodOptional<import("zod").ZodString>;
@@ -314,6 +361,26 @@ declare class EnhancedCollectionsApi {
314
361
  searchable_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
315
362
  file?: File | undefined;
316
363
  }>;
364
+ /**
365
+ * Waits for a video in a collection to be ready by polling the getVideo endpoint until
366
+ * the video reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
367
+ *
368
+ * @param collectionId - The ID of the collection containing the video
369
+ * @param fileId - The ID of the video file to wait for
370
+ * @param options - Optional configuration for polling behavior
371
+ * @returns The final collection file object
372
+ * @throws {CloudGlueError} If the video fails to process or maxAttempts is reached
373
+ */
374
+ waitForReady(collectionId: string, fileId: string, options?: WaitForReadyOptions): Promise<{
375
+ collection_id: string;
376
+ file_id: string;
377
+ object: "collection_file";
378
+ added_at: number;
379
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
380
+ extract_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
381
+ searchable_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
382
+ file?: File | undefined;
383
+ }>;
317
384
  }
318
385
  declare class EnhancedChatApi {
319
386
  private readonly api;
@@ -408,7 +475,7 @@ declare class EnhancedTranscribeApi {
408
475
  error?: string | undefined;
409
476
  }>;
410
477
  getTranscribe(jobId: string, options?: {
411
- response_format?: 'json' | 'markdown';
478
+ response_format?: "json" | "markdown";
412
479
  }): Promise<{
413
480
  job_id: string;
414
481
  status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
@@ -445,11 +512,11 @@ declare class EnhancedTranscribeApi {
445
512
  listTranscribes(params?: {
446
513
  limit?: number;
447
514
  offset?: number;
448
- status?: 'pending' | 'processing' | 'completed' | 'failed' | 'not_applicable';
515
+ status?: "pending" | "processing" | "completed" | "failed" | "not_applicable";
449
516
  created_before?: string;
450
517
  created_after?: string;
451
518
  url?: string;
452
- response_format?: 'json' | 'markdown';
519
+ response_format?: "json" | "markdown";
453
520
  }): Promise<{
454
521
  object: "list";
455
522
  data: Array<{
@@ -488,6 +555,50 @@ declare class EnhancedTranscribeApi {
488
555
  total: number;
489
556
  limit: number;
490
557
  }>;
558
+ /**
559
+ * Waits for a transcription job to be ready by polling the getTranscribe endpoint until
560
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
561
+ *
562
+ * @param jobId - The ID of the transcription job to wait for
563
+ * @param options - Optional configuration for polling behavior and response format
564
+ * @returns The final transcription job object
565
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
566
+ */
567
+ waitForReady(jobId: string, options?: WaitForReadyOptions & {
568
+ response_format?: "json" | "markdown";
569
+ }): Promise<{
570
+ job_id: string;
571
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
572
+ url?: string | undefined;
573
+ created_at?: number | undefined;
574
+ transcribe_config?: Partial<{
575
+ "enable_summary ": boolean;
576
+ enable_speech: boolean;
577
+ enable_visual_scene_description: boolean;
578
+ enable_scene_text: boolean;
579
+ }> | undefined;
580
+ data?: Partial<{
581
+ content: string;
582
+ title: string;
583
+ summary: string;
584
+ speech: Array<Partial<{
585
+ text: string;
586
+ start_time: number;
587
+ end_time: number;
588
+ }>>;
589
+ visual_scene_description: Array<Partial<{
590
+ text: string;
591
+ start_time: number;
592
+ end_time: number;
593
+ }>>;
594
+ scene_text: Array<Partial<{
595
+ text: string;
596
+ start_time: number;
597
+ end_time: number;
598
+ }>>;
599
+ }> | undefined;
600
+ error?: string | undefined;
601
+ }>;
491
602
  }
492
603
  declare class EnhancedExtractApi {
493
604
  private readonly api;
@@ -538,7 +649,7 @@ declare class EnhancedExtractApi {
538
649
  listExtracts(params?: {
539
650
  limit?: number;
540
651
  offset?: number;
541
- status?: 'pending' | 'processing' | 'completed' | 'failed' | 'not_applicable';
652
+ status?: "pending" | "processing" | "completed" | "failed" | "not_applicable";
542
653
  created_before?: string;
543
654
  created_after?: string;
544
655
  url?: string;
@@ -568,6 +679,35 @@ declare class EnhancedExtractApi {
568
679
  limit: number;
569
680
  offset: number;
570
681
  }>;
682
+ /**
683
+ * Waits for an extraction job to be ready by polling the getExtract endpoint until
684
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
685
+ *
686
+ * @param jobId - The ID of the extraction job to wait for
687
+ * @param options - Optional configuration for polling behavior
688
+ * @returns The final extraction job object
689
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
690
+ */
691
+ waitForReady(jobId: string, options?: WaitForReadyOptions): Promise<{
692
+ job_id: string;
693
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
694
+ url?: string | undefined;
695
+ created_at?: number | undefined;
696
+ extract_config?: Partial<{
697
+ prompt: string;
698
+ schema: {};
699
+ }> | undefined;
700
+ data?: Partial<{
701
+ entities: {};
702
+ segment_entities: Array<Partial<{
703
+ segment_id: string | number;
704
+ start_time: number;
705
+ end_time: number;
706
+ entities: {};
707
+ }>>;
708
+ }> | undefined;
709
+ error?: string | undefined;
710
+ }>;
571
711
  }
572
712
  /**
573
713
  * Main CloudGlue client class that provides access to all API functionality
@@ -576,6 +716,7 @@ declare class EnhancedExtractApi {
576
716
  export declare class CloudGlue {
577
717
  private readonly baseUrl;
578
718
  private readonly apiKey;
719
+ private readonly timeout;
579
720
  /**
580
721
  * Files API for managing video files
581
722
  * Provides methods for uploading, listing, and managing video files
@@ -1,7 +1,11 @@
1
1
  "use strict";
2
2
  Object.defineProperty(exports, "__esModule", { value: true });
3
3
  exports.CloudGlue = exports.CloudGlueError = void 0;
4
- const generated_1 = require("../generated");
4
+ const Files_1 = require("../generated/Files");
5
+ const Collections_1 = require("../generated/Collections");
6
+ const Chat_1 = require("../generated/Chat");
7
+ const Transcribe_1 = require("../generated/Transcribe");
8
+ const Extract_1 = require("../generated/Extract");
5
9
  class CloudGlueError extends Error {
6
10
  constructor(message, statusCode, data, headers) {
7
11
  super(message);
@@ -27,26 +31,55 @@ class EnhancedFilesApi {
27
31
  // 3. Set the correct Content-Type header
28
32
  // This is why we use axios directly instead of the generated client method.
29
33
  const formData = new FormData();
30
- formData.append('file', params.file);
34
+ formData.append("file", params.file);
31
35
  // Add metadata if provided
32
36
  if (params.metadata) {
33
- formData.append('metadata', JSON.stringify(params.metadata));
37
+ formData.append("metadata", JSON.stringify(params.metadata));
34
38
  }
35
39
  // Use axios directly to bypass Zodios validation
36
40
  return this.api.axios({
37
- method: 'post',
38
- url: '/files',
41
+ method: "post",
42
+ url: "/files",
39
43
  data: formData,
40
44
  headers: {
41
- 'Content-Type': 'multipart/form-data'
42
- }
45
+ "Content-Type": "multipart/form-data",
46
+ },
43
47
  });
44
48
  }
45
49
  async getFile(fileId) {
46
50
  return this.api.getFile({ params: { file_id: fileId } });
47
51
  }
48
52
  async deleteFile(fileId) {
49
- return this.api.deleteFile({ params: { file_id: fileId } }, { params: { file_id: fileId } });
53
+ return this.api.deleteFile({ params: { file_id: fileId } }, {
54
+ params: { file_id: fileId },
55
+ });
56
+ }
57
+ /**
58
+ * Waits for a file to finish processing by polling the getFile endpoint until the file
59
+ * reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
60
+ *
61
+ * @param fileId - The ID of the file to wait for
62
+ * @param options - Optional configuration for polling behavior
63
+ * @returns The final file object
64
+ * @throws {CloudGlueError} If the file fails to process or maxAttempts is reached
65
+ */
66
+ async waitForReady(fileId, options = {}) {
67
+ const { pollingInterval = 5000, maxAttempts = 36 } = options;
68
+ let attempts = 0;
69
+ while (attempts < maxAttempts) {
70
+ const file = await this.getFile(fileId);
71
+ // If we've reached a terminal state, return the file
72
+ if (["completed", "failed", "not_applicable"].includes(file.status)) {
73
+ if (file.status === "failed") {
74
+ throw new CloudGlueError(`File processing failed: ${fileId}`);
75
+ }
76
+ return file;
77
+ }
78
+ // Wait for the polling interval before trying again
79
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval));
80
+ attempts++;
81
+ }
82
+ throw new CloudGlueError(`Timeout waiting for file ${fileId} to process after ${maxAttempts} attempts`);
50
83
  }
51
84
  }
52
85
  class EnhancedCollectionsApi {
@@ -60,7 +93,9 @@ class EnhancedCollectionsApi {
60
93
  return this.api.createCollection(params);
61
94
  }
62
95
  async getCollection(collectionId) {
63
- return this.api.getCollection({ params: { collection_id: collectionId } });
96
+ return this.api.getCollection({
97
+ params: { collection_id: collectionId },
98
+ });
64
99
  }
65
100
  async deleteCollection(collectionId) {
66
101
  return this.api.deleteCollection({ params: { collection_id: collectionId } }, { params: { collection_id: collectionId } });
@@ -71,34 +106,62 @@ class EnhancedCollectionsApi {
71
106
  async listVideos(collectionId, params = {}) {
72
107
  return this.api.listVideos({
73
108
  params: { collection_id: collectionId },
74
- queries: params
109
+ queries: params,
75
110
  });
76
111
  }
77
112
  async getVideo(collectionId, fileId) {
78
113
  return this.api.getVideo({
79
- params: { collection_id: collectionId, file_id: fileId }
114
+ params: { collection_id: collectionId, file_id: fileId },
80
115
  });
81
116
  }
82
117
  async deleteVideo(collectionId, fileId) {
83
118
  return this.api.deleteVideo({
84
- params: { collection_id: collectionId, file_id: fileId }
119
+ params: { collection_id: collectionId, file_id: fileId },
85
120
  }, { params: { collection_id: collectionId, file_id: fileId } });
86
121
  }
87
122
  async getEntities(collectionId, fileId, limit, offset) {
88
123
  return this.api.getEntities({
89
124
  params: { collection_id: collectionId, file_id: fileId },
90
- queries: { limit, offset }
125
+ queries: { limit, offset },
91
126
  });
92
127
  }
93
128
  async getTranscripts(collectionId, fileId, limit, offset, response_format) {
94
129
  return this.api.getTranscripts({
95
130
  params: { collection_id: collectionId, file_id: fileId },
96
- queries: { limit, offset, response_format }
131
+ queries: { limit, offset, response_format },
97
132
  });
98
133
  }
99
134
  async addYouTubeVideo(collectionId, url, metadata) {
100
135
  return this.api.addYouTubeVideo({ url, metadata }, { params: { collection_id: collectionId } });
101
136
  }
137
+ /**
138
+ * Waits for a video in a collection to be ready by polling the getVideo endpoint until
139
+ * the video reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
140
+ *
141
+ * @param collectionId - The ID of the collection containing the video
142
+ * @param fileId - The ID of the video file to wait for
143
+ * @param options - Optional configuration for polling behavior
144
+ * @returns The final collection file object
145
+ * @throws {CloudGlueError} If the video fails to process or maxAttempts is reached
146
+ */
147
+ async waitForReady(collectionId, fileId, options = {}) {
148
+ const { pollingInterval = 5000, maxAttempts = 36 } = options;
149
+ let attempts = 0;
150
+ while (attempts < maxAttempts) {
151
+ const video = await this.getVideo(collectionId, fileId);
152
+ // If we've reached a terminal state, return the video
153
+ if (["completed", "failed", "not_applicable"].includes(video.status)) {
154
+ if (video.status === "failed") {
155
+ throw new CloudGlueError(`Video processing failed: ${fileId} in collection ${collectionId}`);
156
+ }
157
+ return video;
158
+ }
159
+ // Wait for the polling interval before trying again
160
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval));
161
+ attempts++;
162
+ }
163
+ throw new CloudGlueError(`Timeout waiting for video ${fileId} in collection ${collectionId} to process after ${maxAttempts} attempts`);
164
+ }
102
165
  }
103
166
  class EnhancedChatApi {
104
167
  constructor(api) {
@@ -106,8 +169,8 @@ class EnhancedChatApi {
106
169
  }
107
170
  async createCompletion(params) {
108
171
  return this.api.createCompletion({
109
- model: params.model || 'nimbus-001',
110
- ...params
172
+ model: params.model || "nimbus-001",
173
+ ...params,
111
174
  });
112
175
  }
113
176
  }
@@ -118,18 +181,45 @@ class EnhancedTranscribeApi {
118
181
  async createTranscribe(url, options = {}) {
119
182
  return this.api.createTranscribe({
120
183
  url,
121
- ...options
184
+ ...options,
122
185
  });
123
186
  }
124
187
  async getTranscribe(jobId, options = {}) {
125
188
  return this.api.getTranscribe({
126
189
  params: { job_id: jobId },
127
- queries: { response_format: options.response_format }
190
+ queries: { response_format: options.response_format },
128
191
  });
129
192
  }
130
193
  async listTranscribes(params = {}) {
131
194
  return this.api.listTranscribes({ queries: params });
132
195
  }
196
+ /**
197
+ * Waits for a transcription job to be ready by polling the getTranscribe endpoint until
198
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
199
+ *
200
+ * @param jobId - The ID of the transcription job to wait for
201
+ * @param options - Optional configuration for polling behavior and response format
202
+ * @returns The final transcription job object
203
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
204
+ */
205
+ async waitForReady(jobId, options = {}) {
206
+ const { pollingInterval = 5000, maxAttempts = 36, response_format, } = options;
207
+ let attempts = 0;
208
+ while (attempts < maxAttempts) {
209
+ const job = await this.getTranscribe(jobId, { response_format });
210
+ // If we've reached a terminal state, return the job
211
+ if (["completed", "failed", "not_applicable"].includes(job.status)) {
212
+ if (job.status === "failed") {
213
+ throw new CloudGlueError(`Transcription job failed: ${jobId}`);
214
+ }
215
+ return job;
216
+ }
217
+ // Wait for the polling interval before trying again
218
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval));
219
+ attempts++;
220
+ }
221
+ throw new CloudGlueError(`Timeout waiting for transcription job ${jobId} to process after ${maxAttempts} attempts`);
222
+ }
133
223
  }
134
224
  class EnhancedExtractApi {
135
225
  constructor(api) {
@@ -138,7 +228,7 @@ class EnhancedExtractApi {
138
228
  async createExtract(url, options) {
139
229
  return this.api.createExtract({
140
230
  url,
141
- ...options
231
+ ...options,
142
232
  });
143
233
  }
144
234
  async getExtract(jobId) {
@@ -147,6 +237,33 @@ class EnhancedExtractApi {
147
237
  async listExtracts(params = {}) {
148
238
  return this.api.listExtracts({ queries: params });
149
239
  }
240
+ /**
241
+ * Waits for an extraction job to be ready by polling the getExtract endpoint until
242
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
243
+ *
244
+ * @param jobId - The ID of the extraction job to wait for
245
+ * @param options - Optional configuration for polling behavior
246
+ * @returns The final extraction job object
247
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
248
+ */
249
+ async waitForReady(jobId, options = {}) {
250
+ const { pollingInterval = 5000, maxAttempts = 36 } = options;
251
+ let attempts = 0;
252
+ while (attempts < maxAttempts) {
253
+ const job = await this.getExtract(jobId);
254
+ // If we've reached a terminal state, return the job
255
+ if (["completed", "failed", "not_applicable"].includes(job.status)) {
256
+ if (job.status === "failed") {
257
+ throw new CloudGlueError(`Extraction job failed: ${jobId}`);
258
+ }
259
+ return job;
260
+ }
261
+ // Wait for the polling interval before trying again
262
+ await new Promise((resolve) => setTimeout(resolve, pollingInterval));
263
+ attempts++;
264
+ }
265
+ throw new CloudGlueError(`Timeout waiting for extraction job ${jobId} to process after ${maxAttempts} attempts`);
266
+ }
150
267
  }
151
268
  /**
152
269
  * Main CloudGlue client class that provides access to all API functionality
@@ -154,25 +271,28 @@ class EnhancedExtractApi {
154
271
  */
155
272
  class CloudGlue {
156
273
  constructor(config = {}) {
157
- this.apiKey = config.apiKey || process.env.CLOUDGLUE_API_KEY || '';
158
- this.baseUrl = config.baseUrl || 'https://api.cloudglue.dev/v1';
274
+ this.apiKey = config.apiKey || process.env.CLOUDGLUE_API_KEY || "";
275
+ this.baseUrl = config.baseUrl || "https://api.cloudglue.dev/v1";
276
+ this.timeout = config.timeout || undefined;
159
277
  if (!this.apiKey) {
160
- throw new Error('API key is required. Please provide an API key via constructor or CLOUDGLUE_API_KEY environment variable.');
278
+ throw new Error("API key is required. Please provide an API key via constructor or CLOUDGLUE_API_KEY environment variable.");
161
279
  }
162
280
  const axiosConfig = {
163
281
  headers: {
164
- Authorization: `Bearer ${this.apiKey}`
165
- }
282
+ Authorization: `Bearer ${this.apiKey}`,
283
+ },
284
+ baseURL: this.baseUrl,
285
+ timeout: this.timeout,
166
286
  };
167
287
  // Initialize all API clients with the configured base URL and auth
168
- const filesApi = generated_1.FilesApi;
169
- const collectionsApi = generated_1.CollectionsApi;
170
- const chatApi = generated_1.ChatApi;
171
- const transcribeApi = generated_1.TranscribeApi;
172
- const extractApi = generated_1.ExtractApi;
288
+ const filesApi = (0, Files_1.createApiClient)(this.baseUrl);
289
+ const collectionsApi = (0, Collections_1.createApiClient)(this.baseUrl);
290
+ const chatApi = (0, Chat_1.createApiClient)(this.baseUrl);
291
+ const transcribeApi = (0, Transcribe_1.createApiClient)(this.baseUrl);
292
+ const extractApi = (0, Extract_1.createApiClient)(this.baseUrl);
173
293
  // Configure base URL and axios config for all clients
174
- [filesApi, collectionsApi, chatApi, transcribeApi, extractApi].forEach(client => {
175
- client.axios.defaults.baseURL = this.baseUrl;
294
+ [filesApi, collectionsApi, chatApi, transcribeApi, extractApi].forEach((client) => {
295
+ Object.assign(client.axios.defaults, axiosConfig);
176
296
  client.axios.interceptors.response.use((response) => {
177
297
  return response;
178
298
  }, (error) => {
@@ -185,7 +305,6 @@ class CloudGlue {
185
305
  // Something happened in setting up the request that triggered an Error
186
306
  return Promise.reject(new CloudGlueError(error.message, error.statusCode ?? 500, error.data, error.headers));
187
307
  });
188
- Object.assign(client.axios.defaults, axiosConfig);
189
308
  });
190
309
  // Create enhanced API clients
191
310
  this.files = new EnhancedFilesApi(filesApi);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@aviaryhq/cloudglue-js",
3
- "version": "0.0.13",
3
+ "version": "0.0.15",
4
4
  "description": "CloudGlue API client for Node.js",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",