@aviaryhq/cloudglue-js 0.0.13 → 0.0.14

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,14 @@ export declare class CloudGlueError extends Error {
12
12
  export interface CloudGlueConfig {
13
13
  apiKey?: string;
14
14
  baseUrl?: string;
15
+ timeout?: number;
15
16
  }
16
17
  interface ListFilesParams {
17
- status?: 'pending' | 'processing' | 'ready' | 'completed' | 'failed' | 'not_applicable';
18
+ status?: "pending" | "processing" | "ready" | "completed" | "failed" | "not_applicable";
18
19
  limit?: number;
19
20
  offset?: number;
20
- order?: 'created_at' | 'filename';
21
- sort?: 'asc' | 'desc';
21
+ order?: "created_at" | "filename";
22
+ sort?: "asc" | "desc";
22
23
  created_before?: string;
23
24
  created_after?: string;
24
25
  }
@@ -29,12 +30,12 @@ interface UploadFileParams {
29
30
  interface ListCollectionParams {
30
31
  limit?: number;
31
32
  offset?: number;
32
- order?: 'name' | 'created_at';
33
- sort?: 'asc' | 'desc';
34
- collection_type?: 'entities' | 'rich-transcripts';
33
+ order?: "name" | "created_at";
34
+ sort?: "asc" | "desc";
35
+ collection_type?: "entities" | "rich-transcripts";
35
36
  }
36
37
  interface CreateCollectionParams {
37
- collection_type: 'entities' | 'rich-transcripts';
38
+ collection_type: "entities" | "rich-transcripts";
38
39
  name: string;
39
40
  description?: string;
40
41
  extract_config?: {
@@ -51,16 +52,16 @@ interface CreateCollectionParams {
51
52
  interface ListCollectionVideosParams {
52
53
  limit?: number;
53
54
  offset?: number;
54
- status?: 'pending' | 'processing' | 'ready' | 'completed' | 'failed' | 'not_applicable';
55
- order?: 'added_at' | 'filename';
56
- sort?: 'asc' | 'desc';
55
+ status?: "pending" | "processing" | "ready" | "completed" | "failed" | "not_applicable";
56
+ order?: "added_at" | "filename";
57
+ sort?: "asc" | "desc";
57
58
  added_before?: string;
58
59
  added_after?: string;
59
60
  }
60
61
  interface ChatCompletionParams {
61
62
  model?: string;
62
63
  messages: Array<{
63
- role: 'system' | 'user' | 'assistant';
64
+ role: "system" | "user" | "assistant";
64
65
  content: string;
65
66
  name?: string;
66
67
  }>;
@@ -68,7 +69,7 @@ interface ChatCompletionParams {
68
69
  filter?: {
69
70
  metadata?: Array<{
70
71
  path: string;
71
- operator: 'NotEqual' | 'Equal' | 'LessThan' | 'GreaterThan' | 'In' | 'ContainsAny' | 'ContainsAll';
72
+ operator: "NotEqual" | "Equal" | "LessThan" | "GreaterThan" | "In" | "ContainsAny" | "ContainsAll";
72
73
  valueText?: string;
73
74
  valueTextArray?: string[];
74
75
  }>;
@@ -79,6 +80,12 @@ interface ChatCompletionParams {
79
80
  top_p?: number;
80
81
  max_tokens?: number;
81
82
  }
83
+ interface WaitForReadyOptions {
84
+ /** Interval in milliseconds between polling attempts. Defaults to 5000ms (5 seconds). */
85
+ pollingInterval?: number;
86
+ /** Maximum number of polling attempts before giving up. Defaults to 36 (3 minutes total with default interval). */
87
+ maxAttempts?: number;
88
+ }
82
89
  declare class EnhancedFilesApi {
83
90
  private readonly api;
84
91
  constructor(api: typeof FilesApi);
@@ -122,6 +129,43 @@ declare class EnhancedFilesApi {
122
129
  id: import("zod").ZodString;
123
130
  object: import("zod").ZodLiteral<"file">;
124
131
  }, import("zod").ZodTypeAny, "passthrough">>;
132
+ /**
133
+ * Waits for a file to finish processing by polling the getFile endpoint until the file
134
+ * reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
135
+ *
136
+ * @param fileId - The ID of the file to wait for
137
+ * @param options - Optional configuration for polling behavior
138
+ * @returns The final file object
139
+ * @throws {CloudGlueError} If the file fails to process or maxAttempts is reached
140
+ */
141
+ waitForReady(fileId: string, options?: WaitForReadyOptions): Promise<import("zod").objectOutputType<{
142
+ id: import("zod").ZodString;
143
+ status: import("zod").ZodEnum<["pending", "processing", "completed", "failed", "not_applicable"]>;
144
+ bytes: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
145
+ created_at: import("zod").ZodOptional<import("zod").ZodNumber>;
146
+ filename: import("zod").ZodOptional<import("zod").ZodString>;
147
+ uri: import("zod").ZodString;
148
+ 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]>>;
149
+ video_info: import("zod").ZodOptional<import("zod").ZodObject<{
150
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
151
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
152
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
153
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
154
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
155
+ }, "passthrough", import("zod").ZodTypeAny, import("zod").objectOutputType<{
156
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
157
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
158
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
159
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
160
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
161
+ }, import("zod").ZodTypeAny, "passthrough">, import("zod").objectInputType<{
162
+ duration_seconds: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
163
+ height: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
164
+ width: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodNumber, import("zod").ZodNull]>>;
165
+ format: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodString, import("zod").ZodNull]>>;
166
+ has_audio: import("zod").ZodOptional<import("zod").ZodUnion<[import("zod").ZodBoolean, import("zod").ZodNull]>>;
167
+ }, import("zod").ZodTypeAny, "passthrough">>>;
168
+ }, import("zod").ZodTypeAny, "passthrough">>;
125
169
  }
126
170
  declare class EnhancedCollectionsApi {
127
171
  private readonly api;
@@ -258,7 +302,7 @@ declare class EnhancedCollectionsApi {
258
302
  limit: import("zod").ZodNumber;
259
303
  offset: import("zod").ZodNumber;
260
304
  }, import("zod").ZodTypeAny, "passthrough">>;
261
- getTranscripts(collectionId: string, fileId: string, limit?: number, offset?: number, response_format?: 'markdown' | 'json'): Promise<import("zod").objectOutputType<{
305
+ getTranscripts(collectionId: string, fileId: string, limit?: number, offset?: number, response_format?: "markdown" | "json"): Promise<import("zod").objectOutputType<{
262
306
  collection_id: import("zod").ZodString;
263
307
  file_id: import("zod").ZodString;
264
308
  content: import("zod").ZodOptional<import("zod").ZodString>;
@@ -314,6 +358,26 @@ declare class EnhancedCollectionsApi {
314
358
  searchable_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
315
359
  file?: File | undefined;
316
360
  }>;
361
+ /**
362
+ * Waits for a video in a collection to be ready by polling the getVideo endpoint until
363
+ * the video reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
364
+ *
365
+ * @param collectionId - The ID of the collection containing the video
366
+ * @param fileId - The ID of the video file to wait for
367
+ * @param options - Optional configuration for polling behavior
368
+ * @returns The final collection file object
369
+ * @throws {CloudGlueError} If the video fails to process or maxAttempts is reached
370
+ */
371
+ waitForReady(collectionId: string, fileId: string, options?: WaitForReadyOptions): Promise<{
372
+ collection_id: string;
373
+ file_id: string;
374
+ object: "collection_file";
375
+ added_at: number;
376
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
377
+ extract_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
378
+ searchable_status?: ("pending" | "processing" | "completed" | "failed" | "not_applicable") | undefined;
379
+ file?: File | undefined;
380
+ }>;
317
381
  }
318
382
  declare class EnhancedChatApi {
319
383
  private readonly api;
@@ -408,7 +472,7 @@ declare class EnhancedTranscribeApi {
408
472
  error?: string | undefined;
409
473
  }>;
410
474
  getTranscribe(jobId: string, options?: {
411
- response_format?: 'json' | 'markdown';
475
+ response_format?: "json" | "markdown";
412
476
  }): Promise<{
413
477
  job_id: string;
414
478
  status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
@@ -445,11 +509,11 @@ declare class EnhancedTranscribeApi {
445
509
  listTranscribes(params?: {
446
510
  limit?: number;
447
511
  offset?: number;
448
- status?: 'pending' | 'processing' | 'completed' | 'failed' | 'not_applicable';
512
+ status?: "pending" | "processing" | "completed" | "failed" | "not_applicable";
449
513
  created_before?: string;
450
514
  created_after?: string;
451
515
  url?: string;
452
- response_format?: 'json' | 'markdown';
516
+ response_format?: "json" | "markdown";
453
517
  }): Promise<{
454
518
  object: "list";
455
519
  data: Array<{
@@ -488,6 +552,50 @@ declare class EnhancedTranscribeApi {
488
552
  total: number;
489
553
  limit: number;
490
554
  }>;
555
+ /**
556
+ * Waits for a transcription job to be ready by polling the getTranscribe endpoint until
557
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
558
+ *
559
+ * @param jobId - The ID of the transcription job to wait for
560
+ * @param options - Optional configuration for polling behavior and response format
561
+ * @returns The final transcription job object
562
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
563
+ */
564
+ waitForReady(jobId: string, options?: WaitForReadyOptions & {
565
+ response_format?: "json" | "markdown";
566
+ }): Promise<{
567
+ job_id: string;
568
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
569
+ url?: string | undefined;
570
+ created_at?: number | undefined;
571
+ transcribe_config?: Partial<{
572
+ "enable_summary ": boolean;
573
+ enable_speech: boolean;
574
+ enable_visual_scene_description: boolean;
575
+ enable_scene_text: boolean;
576
+ }> | undefined;
577
+ data?: Partial<{
578
+ content: string;
579
+ title: string;
580
+ summary: string;
581
+ speech: Array<Partial<{
582
+ text: string;
583
+ start_time: number;
584
+ end_time: number;
585
+ }>>;
586
+ visual_scene_description: Array<Partial<{
587
+ text: string;
588
+ start_time: number;
589
+ end_time: number;
590
+ }>>;
591
+ scene_text: Array<Partial<{
592
+ text: string;
593
+ start_time: number;
594
+ end_time: number;
595
+ }>>;
596
+ }> | undefined;
597
+ error?: string | undefined;
598
+ }>;
491
599
  }
492
600
  declare class EnhancedExtractApi {
493
601
  private readonly api;
@@ -538,7 +646,7 @@ declare class EnhancedExtractApi {
538
646
  listExtracts(params?: {
539
647
  limit?: number;
540
648
  offset?: number;
541
- status?: 'pending' | 'processing' | 'completed' | 'failed' | 'not_applicable';
649
+ status?: "pending" | "processing" | "completed" | "failed" | "not_applicable";
542
650
  created_before?: string;
543
651
  created_after?: string;
544
652
  url?: string;
@@ -568,6 +676,35 @@ declare class EnhancedExtractApi {
568
676
  limit: number;
569
677
  offset: number;
570
678
  }>;
679
+ /**
680
+ * Waits for an extraction job to be ready by polling the getExtract endpoint until
681
+ * the job reaches a terminal state (completed, failed, or not_applicable) or until maxAttempts is reached.
682
+ *
683
+ * @param jobId - The ID of the extraction job to wait for
684
+ * @param options - Optional configuration for polling behavior
685
+ * @returns The final extraction job object
686
+ * @throws {CloudGlueError} If the job fails to process or maxAttempts is reached
687
+ */
688
+ waitForReady(jobId: string, options?: WaitForReadyOptions): Promise<{
689
+ job_id: string;
690
+ status: "pending" | "processing" | "completed" | "failed" | "not_applicable";
691
+ url?: string | undefined;
692
+ created_at?: number | undefined;
693
+ extract_config?: Partial<{
694
+ prompt: string;
695
+ schema: {};
696
+ }> | undefined;
697
+ data?: Partial<{
698
+ entities: {};
699
+ segment_entities: Array<Partial<{
700
+ segment_id: string | number;
701
+ start_time: number;
702
+ end_time: number;
703
+ entities: {};
704
+ }>>;
705
+ }> | undefined;
706
+ error?: string | undefined;
707
+ }>;
571
708
  }
572
709
  /**
573
710
  * Main CloudGlue client class that provides access to all API functionality
@@ -576,6 +713,7 @@ declare class EnhancedExtractApi {
576
713
  export declare class CloudGlue {
577
714
  private readonly baseUrl;
578
715
  private readonly apiKey;
716
+ private readonly timeout;
579
717
  /**
580
718
  * Files API for managing video files
581
719
  * 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 || 10000;
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.14",
4
4
  "description": "CloudGlue API client for Node.js",
5
5
  "main": "dist/src/index.js",
6
6
  "types": "dist/src/index.d.ts",