@unityclaw/sdk 1.0.0

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.
package/dist/index.js ADDED
@@ -0,0 +1,902 @@
1
+ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
2
+ get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
3
+ }) : x)(function(x) {
4
+ if (typeof require !== "undefined") return require.apply(this, arguments);
5
+ throw Error('Dynamic require of "' + x + '" is not supported');
6
+ });
7
+
8
+ // src/client.ts
9
+ import axios2, { AxiosError } from "axios";
10
+
11
+ // src/task-folder.ts
12
+ import { mkdir, writeFile, appendFile, readdir } from "fs/promises";
13
+ import { existsSync } from "fs";
14
+ import { join, basename } from "path";
15
+ import { format } from "date-fns";
16
+ import { v4 as uuidv4 } from "uuid";
17
+ import axios from "axios";
18
+ var TaskFolderManager = class {
19
+ options;
20
+ constructor(options) {
21
+ this.options = options;
22
+ }
23
+ /**
24
+ * Create a new task folder with timestamp and unique ID
25
+ */
26
+ async createTaskFolder() {
27
+ const timestamp = format(/* @__PURE__ */ new Date(), "yyyyMMdd_HHmmss");
28
+ const taskId = uuidv4().slice(0, 8);
29
+ const folderName = `${timestamp}_${taskId}`;
30
+ const folderPath = join(this.options.taskDir, folderName);
31
+ const attachmentsPath = join(folderPath, "attachments");
32
+ const logsPath = join(folderPath, "logs");
33
+ await mkdir(attachmentsPath, { recursive: true });
34
+ await mkdir(logsPath, { recursive: true });
35
+ return {
36
+ taskId,
37
+ folderPath,
38
+ attachmentsPath,
39
+ logsPath,
40
+ startTime: Date.now(),
41
+ logs: [],
42
+ downloadedFiles: []
43
+ };
44
+ }
45
+ /**
46
+ * Log a message to the task folder
47
+ */
48
+ async log(ctx, level, message, data) {
49
+ const logEntry = {
50
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
51
+ level,
52
+ message,
53
+ data
54
+ };
55
+ ctx.logs.push(logEntry);
56
+ const logFile = join(ctx.logsPath, "execution.log");
57
+ const logLine = `${logEntry.timestamp} [${level.toUpperCase()}] ${message}${data ? "\n" + JSON.stringify(data, null, 2) : ""}
58
+ `;
59
+ await appendFile(logFile, logLine, "utf-8");
60
+ }
61
+ /**
62
+ * Download an attachment from URL to local folder
63
+ * Important: Downloads attachments to avoid tmp_url expiration
64
+ */
65
+ async downloadAttachment(ctx, attachment) {
66
+ if (!this.options.downloadAttachments || !attachment.tmp_url) {
67
+ return attachment.tmp_url;
68
+ }
69
+ try {
70
+ const url = attachment.tmp_url;
71
+ const urlPath = url.split("?")[0];
72
+ const baseName = urlPath ? basename(urlPath) : "";
73
+ const filename = attachment.name || baseName || `file_${Date.now()}`;
74
+ const localPath = join(ctx.attachmentsPath, filename);
75
+ const response = await axios.get(url, {
76
+ responseType: "arraybuffer",
77
+ timeout: 6e4
78
+ });
79
+ await writeFile(localPath, Buffer.from(response.data));
80
+ ctx.downloadedFiles.push(localPath);
81
+ return localPath;
82
+ } catch (error) {
83
+ await this.log(ctx, "warn", `Failed to download attachment: ${attachment.name}`, {
84
+ error: error instanceof Error ? error.message : error
85
+ });
86
+ return attachment.tmp_url;
87
+ }
88
+ }
89
+ /**
90
+ * Download multiple attachments
91
+ */
92
+ async downloadAttachments(ctx, attachments) {
93
+ const results = [];
94
+ for (const attachment of attachments) {
95
+ const localPath = await this.downloadAttachment(ctx, attachment);
96
+ if (localPath) {
97
+ results.push(localPath);
98
+ }
99
+ }
100
+ return results;
101
+ }
102
+ /**
103
+ * Write request details to task folder
104
+ */
105
+ async writeRequest(ctx, endpoint, params, context) {
106
+ const requestFile = join(ctx.logsPath, "request.json");
107
+ await writeFile(
108
+ requestFile,
109
+ JSON.stringify(
110
+ {
111
+ timestamp: (/* @__PURE__ */ new Date()).toISOString(),
112
+ endpoint,
113
+ params,
114
+ context
115
+ },
116
+ null,
117
+ 2
118
+ ),
119
+ "utf-8"
120
+ );
121
+ }
122
+ /**
123
+ * Write response details to task folder
124
+ */
125
+ async writeResponse(ctx, response) {
126
+ const responseFile = join(ctx.logsPath, "response.json");
127
+ await writeFile(responseFile, JSON.stringify(response, null, 2), "utf-8");
128
+ }
129
+ /**
130
+ * Finalize task folder and return result
131
+ */
132
+ async finalizeTaskFolder(ctx, response, success) {
133
+ const duration = Date.now() - ctx.startTime;
134
+ const summaryFile = join(ctx.logsPath, "summary.json");
135
+ await writeFile(
136
+ summaryFile,
137
+ JSON.stringify(
138
+ {
139
+ taskId: ctx.taskId,
140
+ success,
141
+ duration,
142
+ startTime: new Date(ctx.startTime).toISOString(),
143
+ endTime: (/* @__PURE__ */ new Date()).toISOString(),
144
+ logsCount: ctx.logs.length,
145
+ attachmentsCount: ctx.downloadedFiles.length
146
+ },
147
+ null,
148
+ 2
149
+ ),
150
+ "utf-8"
151
+ );
152
+ return {
153
+ taskId: ctx.taskId,
154
+ success,
155
+ response,
156
+ duration,
157
+ taskFolder: ctx.folderPath,
158
+ logs: ctx.logs,
159
+ attachments: ctx.downloadedFiles
160
+ };
161
+ }
162
+ /**
163
+ * Clean up old task folders (optional utility)
164
+ */
165
+ async cleanOldFolders(maxAge) {
166
+ if (!existsSync(this.options.taskDir)) {
167
+ return 0;
168
+ }
169
+ const now = Date.now();
170
+ const folders = await readdir(this.options.taskDir, { withFileTypes: true });
171
+ let deletedCount = 0;
172
+ for (const folder of folders) {
173
+ if (!folder.isDirectory()) continue;
174
+ const folderPath = join(this.options.taskDir, folder.name);
175
+ const { rm } = await import("fs/promises");
176
+ const match = folder.name.match(/^(\d{8}_\d{6})/);
177
+ if (match && match[1]) {
178
+ try {
179
+ const folderDate = new Date(
180
+ match[1].replace(/(\d{4})(\d{2})(\d{2})_(\d{2})(\d{2})(\d{2})/, "$1-$2-$3T$4:$5:$6")
181
+ );
182
+ if (now - folderDate.getTime() > maxAge) {
183
+ await rm(folderPath, { recursive: true });
184
+ deletedCount++;
185
+ }
186
+ } catch {
187
+ }
188
+ }
189
+ }
190
+ return deletedCount;
191
+ }
192
+ };
193
+
194
+ // src/apis/image.ts
195
+ var ImageAPI = class {
196
+ constructor(client) {
197
+ this.client = client;
198
+ }
199
+ /**
200
+ * Generate image using Gemini API
201
+ * @see /api/gemini/image
202
+ *
203
+ * @example
204
+ * ```typescript
205
+ * const result = await client.image.gemini({
206
+ * prompt: 'A beautiful sunset over mountains',
207
+ * size: { value: '2K', label: '2K' }
208
+ * });
209
+ * ```
210
+ */
211
+ async gemini(params) {
212
+ const taskResult = await this.client.request("/api/gemini/image", {
213
+ prompt: params.prompt,
214
+ attachment: params.attachment,
215
+ model: params.model,
216
+ aspect_ratio: params.aspect_ratio,
217
+ size: params.size
218
+ });
219
+ return taskResult.response;
220
+ }
221
+ /**
222
+ * Generate image using Gemini API v2
223
+ * @see /api/gemini/image/v2
224
+ */
225
+ async geminiV2(params) {
226
+ const taskResult = await this.client.request("/api/gemini/image/v2", {
227
+ prompt: params.prompt,
228
+ attachment: params.attachment,
229
+ model: params.model,
230
+ aspect_ratio: params.aspect_ratio,
231
+ size: params.size
232
+ });
233
+ return taskResult.response;
234
+ }
235
+ /**
236
+ * Generate image using JiMeng (Doubao) API
237
+ * @see /api/jimeng/image
238
+ *
239
+ * @example
240
+ * ```typescript
241
+ * const result = await client.image.jimeng({
242
+ * prompt: '一只可爱的猫咪',
243
+ * size: { value: '1024x1024', label: '1:1' }
244
+ * });
245
+ * ```
246
+ */
247
+ async jimeng(params) {
248
+ const taskResult = await this.client.request("/api/jimeng/image", {
249
+ prompt: params.prompt,
250
+ attachment: params.attachment,
251
+ size: params.size,
252
+ model_selector: params.model_selector,
253
+ web_search: params.web_search,
254
+ image_count: params.image_count,
255
+ model: params.model
256
+ });
257
+ return taskResult.response;
258
+ }
259
+ /**
260
+ * Generate image using JiMeng V3 API
261
+ * @see /api/jimeng/image/v3
262
+ */
263
+ async jimengV3(params) {
264
+ const taskResult = await this.client.request("/api/jimeng/image/v3", {
265
+ prompt: params.prompt,
266
+ attachment: params.attachment,
267
+ size: params.size,
268
+ model_selector: params.model_selector,
269
+ web_search: params.web_search,
270
+ image_count: params.image_count,
271
+ model: params.model
272
+ });
273
+ return taskResult.response;
274
+ }
275
+ /**
276
+ * Compress image
277
+ * @see /api/image/compress
278
+ */
279
+ async compress(params) {
280
+ const taskResult = await this.client.request("/api/image/compress", {
281
+ attachment: params.attachment,
282
+ quality: params.quality
283
+ });
284
+ return taskResult.response;
285
+ }
286
+ };
287
+
288
+ // src/apis/video.ts
289
+ var VideoAPI = class {
290
+ constructor(client) {
291
+ this.client = client;
292
+ }
293
+ /**
294
+ * Generate video using Sora API
295
+ * @see /api/sora/video
296
+ *
297
+ * @example
298
+ * ```typescript
299
+ * const result = await client.video.sora({
300
+ * prompt: 'A cat playing piano',
301
+ * orientation: { value: 'landscape', label: 'Landscape' }
302
+ * });
303
+ * ```
304
+ */
305
+ async sora(params) {
306
+ const taskResult = await this.client.request("/api/sora/video", {
307
+ attachment: params.attachment,
308
+ prompt: params.prompt,
309
+ orientation: params.orientation
310
+ });
311
+ return taskResult.response;
312
+ }
313
+ /**
314
+ * Generate video using Sora Stable API
315
+ * @see /api/sora/video/stable
316
+ */
317
+ async soraStable(params) {
318
+ const taskResult = await this.client.request("/api/sora/video/stable", {
319
+ attachment: params.attachment,
320
+ prompt: params.prompt,
321
+ size: params.size,
322
+ seconds: params.seconds
323
+ });
324
+ return taskResult.response;
325
+ }
326
+ /**
327
+ * Generate video using Veo API
328
+ * @see /api/veo/video
329
+ *
330
+ * @example
331
+ * ```typescript
332
+ * const result = await client.video.veo({
333
+ * prompt: 'A beautiful sunset over the ocean',
334
+ * aspect_ratio: { value: '16:9', label: '16:9' },
335
+ * duration: { value: '8', label: '8s' }
336
+ * });
337
+ * ```
338
+ */
339
+ async veo(params) {
340
+ const taskResult = await this.client.request("/api/veo/video", {
341
+ prompt: params.prompt,
342
+ attachment: params.attachment,
343
+ first_frame: params.first_frame,
344
+ last_frame: params.last_frame,
345
+ aspect_ratio: params.aspect_ratio,
346
+ resolution: params.resolution,
347
+ duration: params.duration
348
+ });
349
+ return taskResult.response;
350
+ }
351
+ /**
352
+ * Generate video using Kling API
353
+ * @see /api/kling/video
354
+ *
355
+ * @example
356
+ * ```typescript
357
+ * const result = await client.video.kling({
358
+ * prompt: 'A dog running in the park',
359
+ * aspect_ratio: { value: '16:9', label: '16:9' },
360
+ * duration: { value: '5', label: '5s' },
361
+ * model: { value: 'kling-v1', label: 'V1' }
362
+ * });
363
+ * ```
364
+ */
365
+ async kling(params) {
366
+ const taskResult = await this.client.request("/api/kling/video", {
367
+ attachment: params.attachment,
368
+ prompt: params.prompt,
369
+ aspect_ratio: params.aspect_ratio,
370
+ duration: params.duration,
371
+ model: params.model
372
+ });
373
+ return taskResult.response;
374
+ }
375
+ /**
376
+ * Generate video using JiMeng API
377
+ * @see /api/jimeng/video
378
+ *
379
+ * @example
380
+ * ```typescript
381
+ * const result = await client.video.jimeng({
382
+ * action: { value: 't2v', label: 'Text to Video' },
383
+ * prompt: 'A beautiful landscape',
384
+ * aspect_ratio: { value: '16:9', label: '16:9' }
385
+ * });
386
+ * ```
387
+ */
388
+ async jimeng(params) {
389
+ const taskResult = await this.client.request("/api/jimeng/video", {
390
+ action: params.action,
391
+ attachment: params.attachment,
392
+ prompt: params.prompt,
393
+ aspect_ratio: params.aspect_ratio
394
+ });
395
+ return taskResult.response;
396
+ }
397
+ /**
398
+ * Generate video using Doubao API
399
+ * @see /api/doubao/video
400
+ *
401
+ * @example
402
+ * ```typescript
403
+ * const result = await client.video.doubao({
404
+ * prompt: 'A cinematic drone shot of mountains',
405
+ * resolution: { value: '1080p', label: '1080p' },
406
+ * ratio: { value: '16:9', label: '16:9' }
407
+ * });
408
+ * ```
409
+ */
410
+ async doubao(params) {
411
+ const taskResult = await this.client.request("/api/doubao/video", {
412
+ action: params.action,
413
+ attachment: params.attachment,
414
+ prompt: params.prompt,
415
+ resolution: params.resolution,
416
+ ratio: params.ratio,
417
+ duration: params.duration
418
+ });
419
+ return taskResult.response;
420
+ }
421
+ /**
422
+ * Generate video using Wan API (Alibaba)
423
+ * @see /api/wan/video
424
+ *
425
+ * @example
426
+ * ```typescript
427
+ * const result = await client.video.wan({
428
+ * prompt: 'A futuristic city at night',
429
+ * size: { value: '1280*720', label: '720p' },
430
+ * duration: { value: '5', label: '5s' },
431
+ * model: { value: 'wan2.6-t2v', label: 'Wan 2.6' }
432
+ * });
433
+ * ```
434
+ */
435
+ async wan(params) {
436
+ const taskResult = await this.client.request("/api/wan/video", {
437
+ attachment: params.attachment,
438
+ prompt: params.prompt,
439
+ size: params.size,
440
+ duration: params.duration,
441
+ model: params.model,
442
+ shot_type: params.shot_type
443
+ });
444
+ return taskResult.response;
445
+ }
446
+ /**
447
+ * Generate video using MiniMax API
448
+ * @see /api/minimax/video
449
+ *
450
+ * @example
451
+ * ```typescript
452
+ * const result = await client.video.minimax({
453
+ * prompt: 'A person walking through a forest',
454
+ * size: { value: '1360*768', label: '768p' },
455
+ * model: { value: 'MiniMax-Hailuo-2.3', label: 'Hailuo 2.3' }
456
+ * });
457
+ * ```
458
+ */
459
+ async minimax(params) {
460
+ const taskResult = await this.client.request("/api/minimax/video", {
461
+ attachment: params.attachment,
462
+ prompt: params.prompt,
463
+ size: params.size,
464
+ duration: params.duration,
465
+ model: params.model
466
+ });
467
+ return taskResult.response;
468
+ }
469
+ };
470
+
471
+ // src/apis/document.ts
472
+ var DocumentAPI = class {
473
+ constructor(client) {
474
+ this.client = client;
475
+ }
476
+ /**
477
+ * Translate document
478
+ * @see /api/doc/translate
479
+ *
480
+ * @example
481
+ * ```typescript
482
+ * const result = await client.document.translate({
483
+ * attachment: [{ tmp_url: 'https://...', name: 'document.pdf' }],
484
+ * source_language: { value: 'en', label: 'English' },
485
+ * target_language: { value: 'zh', label: 'Chinese' }
486
+ * });
487
+ * ```
488
+ */
489
+ async translate(params) {
490
+ const taskResult = await this.client.request("/api/doc/translate", {
491
+ attachment: params.attachment,
492
+ source_language: params.source_language,
493
+ target_language: params.target_language
494
+ });
495
+ return taskResult.response;
496
+ }
497
+ /**
498
+ * Convert image to Word document
499
+ * @see /api/doc_convert/image2word
500
+ */
501
+ async image2Word(params) {
502
+ const taskResult = await this.client.request(
503
+ "/api/doc_convert/image2word",
504
+ {
505
+ attachment: params.attachment
506
+ }
507
+ );
508
+ return taskResult.response;
509
+ }
510
+ /**
511
+ * Convert image to PowerPoint
512
+ * @see /api/doc_convert/image2ppt
513
+ */
514
+ async image2Ppt(params) {
515
+ const taskResult = await this.client.request(
516
+ "/api/doc_convert/image2ppt",
517
+ {
518
+ attachment: params.attachment
519
+ }
520
+ );
521
+ return taskResult.response;
522
+ }
523
+ /**
524
+ * Convert image to Excel
525
+ * @see /api/doc_convert/image2excel
526
+ */
527
+ async image2Excel(params) {
528
+ const taskResult = await this.client.request(
529
+ "/api/doc_convert/image2excel",
530
+ {
531
+ attachment: params.attachment
532
+ }
533
+ );
534
+ return taskResult.response;
535
+ }
536
+ /**
537
+ * Convert image to PDF
538
+ * @see /api/doc_convert/image2pdf
539
+ */
540
+ async image2Pdf(params) {
541
+ const taskResult = await this.client.request(
542
+ "/api/doc_convert/image2pdf",
543
+ {
544
+ attachment: params.attachment
545
+ }
546
+ );
547
+ return taskResult.response;
548
+ }
549
+ /**
550
+ * Convert PDF to Word document
551
+ * @see /api/doc_convert/pdf2word
552
+ */
553
+ async pdf2Word(params) {
554
+ const taskResult = await this.client.request(
555
+ "/api/doc_convert/pdf2word",
556
+ {
557
+ attachment: params.attachment
558
+ }
559
+ );
560
+ return taskResult.response;
561
+ }
562
+ /**
563
+ * Convert PDF to PowerPoint
564
+ * @see /api/doc_convert/pdf2ppt
565
+ */
566
+ async pdf2Ppt(params) {
567
+ const taskResult = await this.client.request(
568
+ "/api/doc_convert/pdf2ppt",
569
+ {
570
+ attachment: params.attachment
571
+ }
572
+ );
573
+ return taskResult.response;
574
+ }
575
+ /**
576
+ * Convert PDF to Excel
577
+ * @see /api/doc_convert/pdf2excel
578
+ */
579
+ async pdf2Excel(params) {
580
+ const taskResult = await this.client.request(
581
+ "/api/doc_convert/pdf2excel",
582
+ {
583
+ attachment: params.attachment
584
+ }
585
+ );
586
+ return taskResult.response;
587
+ }
588
+ /**
589
+ * Convert PDF to image
590
+ * @see /api/doc_convert/pdf2image
591
+ */
592
+ async pdf2Image(params) {
593
+ const taskResult = await this.client.request(
594
+ "/api/doc_convert/pdf2image",
595
+ {
596
+ attachment: params.attachment
597
+ }
598
+ );
599
+ return taskResult.response;
600
+ }
601
+ /**
602
+ * Generic document conversion
603
+ * @see /api/doc_convert/image
604
+ * @see /api/doc_convert/pdf
605
+ */
606
+ async convert(params) {
607
+ const isImage = params.input_format === "image" || !params.input_format;
608
+ const endpoint = isImage ? "/api/doc_convert/image" : "/api/doc_convert/pdf";
609
+ const taskResult = await this.client.request(endpoint, {
610
+ attachment: params.attachment,
611
+ input_format: params.input_format,
612
+ output_format: params.output_format
613
+ });
614
+ return taskResult.response;
615
+ }
616
+ };
617
+
618
+ // src/apis/media.ts
619
+ var MediaAPI = class {
620
+ constructor(client) {
621
+ this.client = client;
622
+ }
623
+ /**
624
+ * Analyze media (video/audio) from URL or file
625
+ * @see /api/media_analysis
626
+ *
627
+ * @example
628
+ * ```typescript
629
+ * // Analyze from URL
630
+ * const result = await client.media.analyze({
631
+ * url: [{ link: 'https://youtube.com/watch?v=...' }]
632
+ * });
633
+ *
634
+ * // Analyze from uploaded file
635
+ * const result = await client.media.analyze({
636
+ * url: [{ tmp_url: 'https://...', type: 'video/mp4', name: 'video.mp4' }]
637
+ * });
638
+ * ```
639
+ */
640
+ async analyze(params) {
641
+ const taskResult = await this.client.request("/api/media_analysis", {
642
+ url: params.url
643
+ });
644
+ return taskResult.response;
645
+ }
646
+ /**
647
+ * Analyze video file directly
648
+ * @see /api/video_analysis (internal)
649
+ *
650
+ * @example
651
+ * ```typescript
652
+ * const result = await client.media.analyzeVideo({
653
+ * file: { tmp_url: 'https://...', type: 'video/mp4', name: 'video.mp4' },
654
+ * prompt: 'Summarize this video'
655
+ * });
656
+ * ```
657
+ */
658
+ async analyzeVideo(params) {
659
+ const taskResult = await this.client.request("/api/media_analysis", {
660
+ url: [
661
+ {
662
+ tmp_url: params.file.tmp_url,
663
+ type: params.file.type,
664
+ name: params.file.name,
665
+ size: params.file.size
666
+ }
667
+ ]
668
+ });
669
+ return taskResult.response;
670
+ }
671
+ /**
672
+ * Analyze social media video (TikTok, YouTube, etc.)
673
+ * @see /api/media_analysis
674
+ *
675
+ * @example
676
+ * ```typescript
677
+ * const result = await client.media.analyzeSocialVideo({
678
+ * url: 'https://www.tiktok.com/@user/video/123456'
679
+ * });
680
+ * ```
681
+ */
682
+ async analyzeSocialVideo(params) {
683
+ const taskResult = await this.client.request("/api/media_analysis", {
684
+ url: [{ link: params.url, type: "url" }]
685
+ });
686
+ return taskResult.response;
687
+ }
688
+ };
689
+
690
+ // src/client.ts
691
+ var DEFAULT_BASE_URL = "https://unityclaw.com";
692
+ var DEFAULT_TIMEOUT = 3e5;
693
+ var UnityClawClient = class {
694
+ config;
695
+ httpClient;
696
+ taskFolderManager;
697
+ // API modules
698
+ image;
699
+ video;
700
+ document;
701
+ media;
702
+ constructor(config = {}) {
703
+ const apiKey = config.apiKey ?? process.env.UNITYCLAW_API_KEY ?? "";
704
+ const baseUrl = config.baseUrl ?? process.env.UNITYCLAW_BASE_URL ?? DEFAULT_BASE_URL;
705
+ if (!apiKey) {
706
+ throw new Error("API key is required. Set UNITYCLAW_API_KEY environment variable or pass apiKey in config.");
707
+ }
708
+ this.config = {
709
+ apiKey,
710
+ baseUrl,
711
+ taskDir: config.taskDir ?? (() => {
712
+ const path = __require("path");
713
+ const os = __require("os");
714
+ try {
715
+ return path.join(process.cwd(), "tasks");
716
+ } catch {
717
+ return path.join(os.homedir(), "tasks");
718
+ }
719
+ })(),
720
+ timeout: config.timeout ?? DEFAULT_TIMEOUT,
721
+ downloadAttachments: config.downloadAttachments ?? true,
722
+ context: config.context ?? {}
723
+ };
724
+ this.httpClient = axios2.create({
725
+ baseURL: this.config.baseUrl,
726
+ timeout: this.config.timeout,
727
+ headers: {
728
+ "Content-Type": "application/json",
729
+ "X-Api-Key": this.config.apiKey
730
+ }
731
+ });
732
+ this.taskFolderManager = new TaskFolderManager({
733
+ taskDir: this.config.taskDir,
734
+ downloadAttachments: this.config.downloadAttachments
735
+ });
736
+ this.image = new ImageAPI(this);
737
+ this.video = new VideoAPI(this);
738
+ this.document = new DocumentAPI(this);
739
+ this.media = new MediaAPI(this);
740
+ }
741
+ /**
742
+ * Get the underlying HTTP client for custom requests
743
+ */
744
+ getHttpClient() {
745
+ return this.httpClient;
746
+ }
747
+ /**
748
+ * Get the task folder manager
749
+ */
750
+ getTaskFolderManager() {
751
+ return this.taskFolderManager;
752
+ }
753
+ /**
754
+ * Get current configuration
755
+ */
756
+ getConfig() {
757
+ return this.config;
758
+ }
759
+ /**
760
+ * Build context object from config defaults
761
+ */
762
+ buildContext(overrides) {
763
+ const now = Date.now();
764
+ const defaultContext = {
765
+ logID: `sdk_${now}_${Math.random().toString(36).slice(2, 10)}`,
766
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
767
+ baseID: "",
768
+ tableID: "",
769
+ bitable: {
770
+ logID: `sdk_${now}`,
771
+ timeZone: Intl.DateTimeFormat().resolvedOptions().timeZone,
772
+ baseID: "",
773
+ tableID: ""
774
+ },
775
+ tenantKey: "",
776
+ userID: this.config.context.userID ?? "",
777
+ packID: "",
778
+ extensionID: "sdk",
779
+ baseSignature: "",
780
+ baseOwnerID: this.config.context.userID ?? ""
781
+ };
782
+ if (this.config.context) {
783
+ Object.assign(defaultContext, this.config.context);
784
+ }
785
+ if (overrides) {
786
+ Object.assign(defaultContext, overrides);
787
+ }
788
+ return defaultContext;
789
+ }
790
+ /**
791
+ * Make a request to the UnityClaw API
792
+ * This is the core method that handles task folder creation, logging, and error handling
793
+ */
794
+ async request(endpoint, params, contextOverrides) {
795
+ const taskCtx = await this.taskFolderManager.createTaskFolder();
796
+ try {
797
+ await this.taskFolderManager.log(taskCtx, "info", `Starting request to ${endpoint}`);
798
+ const context = this.buildContext(contextOverrides);
799
+ const requestBody = {
800
+ formItemParams: params,
801
+ context
802
+ };
803
+ await this.taskFolderManager.writeRequest(taskCtx, endpoint, params, context);
804
+ await this.taskFolderManager.log(taskCtx, "info", "Request prepared", { endpoint, params });
805
+ const response = await this.httpClient.post(endpoint, requestBody);
806
+ await this.taskFolderManager.writeResponse(taskCtx, response.data);
807
+ await this.taskFolderManager.log(taskCtx, "info", "Response received", {
808
+ code: response.data.code,
809
+ hasData: !!response.data.data
810
+ });
811
+ if (response.data.data && Array.isArray(response.data.data)) {
812
+ for (const item of response.data.data) {
813
+ if (item && typeof item === "object" && "content" in item && "contentType" in item) {
814
+ const attachmentItem = item;
815
+ if (attachmentItem.contentType === "attachment/url" && attachmentItem.content) {
816
+ const localPath = await this.taskFolderManager.downloadAttachment(taskCtx, {
817
+ tmp_url: attachmentItem.content,
818
+ name: attachmentItem.name
819
+ });
820
+ if (localPath) {
821
+ attachmentItem.localPath = localPath;
822
+ }
823
+ }
824
+ }
825
+ }
826
+ }
827
+ return await this.taskFolderManager.finalizeTaskFolder(
828
+ taskCtx,
829
+ response.data,
830
+ response.data.code === 0
831
+ );
832
+ } catch (error) {
833
+ const errorMessage = error instanceof AxiosError ? error.response?.data?.msg || error.message : error instanceof Error ? error.message : String(error);
834
+ await this.taskFolderManager.log(taskCtx, "error", `Request failed: ${errorMessage}`, {
835
+ error: error instanceof AxiosError ? { status: error.response?.status, data: error.response?.data } : error
836
+ });
837
+ const errorResponse = {
838
+ code: -1,
839
+ msg: errorMessage
840
+ };
841
+ return await this.taskFolderManager.finalizeTaskFolder(taskCtx, errorResponse, false);
842
+ }
843
+ }
844
+ // ==================== Convenience Methods ====================
845
+ /**
846
+ * Generate image using Gemini API
847
+ * @deprecated Use client.image.gemini() instead
848
+ */
849
+ async generateImage(params) {
850
+ return this.image.gemini(params);
851
+ }
852
+ /**
853
+ * Generate image using JiMeng API
854
+ * @deprecated Use client.image.jimeng() instead
855
+ */
856
+ async generateJiMengImage(params) {
857
+ return this.image.jimeng(params);
858
+ }
859
+ /**
860
+ * Generate video using Sora API
861
+ * @deprecated Use client.video.sora() instead
862
+ */
863
+ async generateSoraVideo(params) {
864
+ return this.video.sora(params);
865
+ }
866
+ /**
867
+ * Generate video using Veo API
868
+ * @deprecated Use client.video.veo() instead
869
+ */
870
+ async generateVeoVideo(params) {
871
+ return this.video.veo(params);
872
+ }
873
+ /**
874
+ * Generate video using Kling API
875
+ * @deprecated Use client.video.kling() instead
876
+ */
877
+ async generateKlingVideo(params) {
878
+ return this.video.kling(params);
879
+ }
880
+ /**
881
+ * Translate document
882
+ * @deprecated Use client.document.translate() instead
883
+ */
884
+ async translateDocument(params) {
885
+ return this.document.translate(params);
886
+ }
887
+ /**
888
+ * Analyze media (video/audio from URL)
889
+ * @deprecated Use client.media.analyze() instead
890
+ */
891
+ async analyzeMedia(params) {
892
+ return this.media.analyze(params);
893
+ }
894
+ };
895
+ export {
896
+ DocumentAPI,
897
+ ImageAPI,
898
+ MediaAPI,
899
+ TaskFolderManager,
900
+ UnityClawClient,
901
+ VideoAPI
902
+ };