@trainly/react 1.1.3 → 1.3.1
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/README.md +587 -0
- package/dist/TrainlyProvider.js +174 -3
- package/dist/api/TrainlyClient.d.ts +4 -1
- package/dist/api/TrainlyClient.js +183 -0
- package/dist/components/TrainlyFileManager.d.ts +8 -0
- package/dist/components/TrainlyFileManager.js +304 -0
- package/dist/index.d.ts +2 -1
- package/dist/index.js +1 -0
- package/dist/types.d.ts +51 -0
- package/package.json +5 -2
package/dist/TrainlyProvider.js
CHANGED
|
@@ -389,8 +389,176 @@ export function TrainlyProvider(_a) {
|
|
|
389
389
|
}
|
|
390
390
|
});
|
|
391
391
|
}); };
|
|
392
|
+
var bulkUploadFiles = function (files) { return __awaiter(_this, void 0, void 0, function () {
|
|
393
|
+
var result, err_6, errorMessage, newToken, result, refreshError_3, error_6;
|
|
394
|
+
return __generator(this, function (_a) {
|
|
395
|
+
switch (_a.label) {
|
|
396
|
+
case 0:
|
|
397
|
+
_a.trys.push([0, 2, 10, 11]);
|
|
398
|
+
setIsLoading(true);
|
|
399
|
+
setError(null);
|
|
400
|
+
return [4 /*yield*/, client.bulkUploadFiles(files)];
|
|
401
|
+
case 1:
|
|
402
|
+
result = _a.sent();
|
|
403
|
+
return [2 /*return*/, result];
|
|
404
|
+
case 2:
|
|
405
|
+
err_6 = _a.sent();
|
|
406
|
+
errorMessage = err_6 instanceof Error ? err_6.message : String(err_6);
|
|
407
|
+
if (!(getToken &&
|
|
408
|
+
appId &&
|
|
409
|
+
(errorMessage.includes("401") ||
|
|
410
|
+
errorMessage.includes("authentication") ||
|
|
411
|
+
errorMessage.includes("Unauthorized")))) return [3 /*break*/, 9];
|
|
412
|
+
_a.label = 3;
|
|
413
|
+
case 3:
|
|
414
|
+
_a.trys.push([3, 8, , 9]);
|
|
415
|
+
console.log("🔄 Token expired during bulk upload, refreshing...");
|
|
416
|
+
return [4 /*yield*/, getToken()];
|
|
417
|
+
case 4:
|
|
418
|
+
newToken = _a.sent();
|
|
419
|
+
if (!newToken) return [3 /*break*/, 7];
|
|
420
|
+
return [4 /*yield*/, client.connectWithOAuthToken(newToken)];
|
|
421
|
+
case 5:
|
|
422
|
+
_a.sent();
|
|
423
|
+
return [4 /*yield*/, client.bulkUploadFiles(files)];
|
|
424
|
+
case 6:
|
|
425
|
+
result = _a.sent();
|
|
426
|
+
console.log("✅ Bulk upload succeeded after token refresh");
|
|
427
|
+
return [2 /*return*/, result];
|
|
428
|
+
case 7: return [3 /*break*/, 9];
|
|
429
|
+
case 8:
|
|
430
|
+
refreshError_3 = _a.sent();
|
|
431
|
+
console.error("❌ Token refresh failed during bulk upload:", refreshError_3);
|
|
432
|
+
return [3 /*break*/, 9];
|
|
433
|
+
case 9:
|
|
434
|
+
error_6 = {
|
|
435
|
+
code: "BULK_UPLOAD_FAILED",
|
|
436
|
+
message: "Failed to upload files",
|
|
437
|
+
details: err_6,
|
|
438
|
+
};
|
|
439
|
+
setError(error_6);
|
|
440
|
+
throw error_6;
|
|
441
|
+
case 10:
|
|
442
|
+
setIsLoading(false);
|
|
443
|
+
return [7 /*endfinally*/];
|
|
444
|
+
case 11: return [2 /*return*/];
|
|
445
|
+
}
|
|
446
|
+
});
|
|
447
|
+
}); };
|
|
448
|
+
var listFiles = function () { return __awaiter(_this, void 0, void 0, function () {
|
|
449
|
+
var result, err_7, errorMessage, newToken, result, refreshError_4, error_7;
|
|
450
|
+
return __generator(this, function (_a) {
|
|
451
|
+
switch (_a.label) {
|
|
452
|
+
case 0:
|
|
453
|
+
_a.trys.push([0, 2, 10, 11]);
|
|
454
|
+
setIsLoading(true);
|
|
455
|
+
setError(null);
|
|
456
|
+
return [4 /*yield*/, client.listFiles()];
|
|
457
|
+
case 1:
|
|
458
|
+
result = _a.sent();
|
|
459
|
+
return [2 /*return*/, result];
|
|
460
|
+
case 2:
|
|
461
|
+
err_7 = _a.sent();
|
|
462
|
+
errorMessage = err_7 instanceof Error ? err_7.message : String(err_7);
|
|
463
|
+
if (!(getToken &&
|
|
464
|
+
appId &&
|
|
465
|
+
(errorMessage.includes("401") ||
|
|
466
|
+
errorMessage.includes("authentication") ||
|
|
467
|
+
errorMessage.includes("Unauthorized")))) return [3 /*break*/, 9];
|
|
468
|
+
_a.label = 3;
|
|
469
|
+
case 3:
|
|
470
|
+
_a.trys.push([3, 8, , 9]);
|
|
471
|
+
console.log("🔄 Token expired during file listing, refreshing...");
|
|
472
|
+
return [4 /*yield*/, getToken()];
|
|
473
|
+
case 4:
|
|
474
|
+
newToken = _a.sent();
|
|
475
|
+
if (!newToken) return [3 /*break*/, 7];
|
|
476
|
+
return [4 /*yield*/, client.connectWithOAuthToken(newToken)];
|
|
477
|
+
case 5:
|
|
478
|
+
_a.sent();
|
|
479
|
+
return [4 /*yield*/, client.listFiles()];
|
|
480
|
+
case 6:
|
|
481
|
+
result = _a.sent();
|
|
482
|
+
console.log("✅ File listing succeeded after token refresh");
|
|
483
|
+
return [2 /*return*/, result];
|
|
484
|
+
case 7: return [3 /*break*/, 9];
|
|
485
|
+
case 8:
|
|
486
|
+
refreshError_4 = _a.sent();
|
|
487
|
+
console.error("❌ Token refresh failed:", refreshError_4);
|
|
488
|
+
return [3 /*break*/, 9];
|
|
489
|
+
case 9:
|
|
490
|
+
error_7 = {
|
|
491
|
+
code: "LIST_FILES_FAILED",
|
|
492
|
+
message: "Failed to list files",
|
|
493
|
+
details: err_7,
|
|
494
|
+
};
|
|
495
|
+
setError(error_7);
|
|
496
|
+
throw error_7;
|
|
497
|
+
case 10:
|
|
498
|
+
setIsLoading(false);
|
|
499
|
+
return [7 /*endfinally*/];
|
|
500
|
+
case 11: return [2 /*return*/];
|
|
501
|
+
}
|
|
502
|
+
});
|
|
503
|
+
}); };
|
|
504
|
+
var deleteFile = function (fileId) { return __awaiter(_this, void 0, void 0, function () {
|
|
505
|
+
var result, err_8, errorMessage, newToken, result, refreshError_5, error_8;
|
|
506
|
+
return __generator(this, function (_a) {
|
|
507
|
+
switch (_a.label) {
|
|
508
|
+
case 0:
|
|
509
|
+
_a.trys.push([0, 2, 10, 11]);
|
|
510
|
+
setIsLoading(true);
|
|
511
|
+
setError(null);
|
|
512
|
+
return [4 /*yield*/, client.deleteFile(fileId)];
|
|
513
|
+
case 1:
|
|
514
|
+
result = _a.sent();
|
|
515
|
+
return [2 /*return*/, result];
|
|
516
|
+
case 2:
|
|
517
|
+
err_8 = _a.sent();
|
|
518
|
+
errorMessage = err_8 instanceof Error ? err_8.message : String(err_8);
|
|
519
|
+
if (!(getToken &&
|
|
520
|
+
appId &&
|
|
521
|
+
(errorMessage.includes("401") ||
|
|
522
|
+
errorMessage.includes("authentication") ||
|
|
523
|
+
errorMessage.includes("Unauthorized")))) return [3 /*break*/, 9];
|
|
524
|
+
_a.label = 3;
|
|
525
|
+
case 3:
|
|
526
|
+
_a.trys.push([3, 8, , 9]);
|
|
527
|
+
console.log("🔄 Token expired during file deletion, refreshing...");
|
|
528
|
+
return [4 /*yield*/, getToken()];
|
|
529
|
+
case 4:
|
|
530
|
+
newToken = _a.sent();
|
|
531
|
+
if (!newToken) return [3 /*break*/, 7];
|
|
532
|
+
return [4 /*yield*/, client.connectWithOAuthToken(newToken)];
|
|
533
|
+
case 5:
|
|
534
|
+
_a.sent();
|
|
535
|
+
return [4 /*yield*/, client.deleteFile(fileId)];
|
|
536
|
+
case 6:
|
|
537
|
+
result = _a.sent();
|
|
538
|
+
console.log("✅ File deletion succeeded after token refresh");
|
|
539
|
+
return [2 /*return*/, result];
|
|
540
|
+
case 7: return [3 /*break*/, 9];
|
|
541
|
+
case 8:
|
|
542
|
+
refreshError_5 = _a.sent();
|
|
543
|
+
console.error("❌ Token refresh failed:", refreshError_5);
|
|
544
|
+
return [3 /*break*/, 9];
|
|
545
|
+
case 9:
|
|
546
|
+
error_8 = {
|
|
547
|
+
code: "DELETE_FILE_FAILED",
|
|
548
|
+
message: "Failed to delete file",
|
|
549
|
+
details: err_8,
|
|
550
|
+
};
|
|
551
|
+
setError(error_8);
|
|
552
|
+
throw error_8;
|
|
553
|
+
case 10:
|
|
554
|
+
setIsLoading(false);
|
|
555
|
+
return [7 /*endfinally*/];
|
|
556
|
+
case 11: return [2 /*return*/];
|
|
557
|
+
}
|
|
558
|
+
});
|
|
559
|
+
}); };
|
|
392
560
|
var sendMessage = function (content) { return __awaiter(_this, void 0, void 0, function () {
|
|
393
|
-
var userMessage, response, assistantMessage_1,
|
|
561
|
+
var userMessage, response, assistantMessage_1, err_9;
|
|
394
562
|
return __generator(this, function (_a) {
|
|
395
563
|
switch (_a.label) {
|
|
396
564
|
case 0:
|
|
@@ -417,9 +585,9 @@ export function TrainlyProvider(_a) {
|
|
|
417
585
|
setMessages(function (prev) { return __spreadArray(__spreadArray([], prev, true), [assistantMessage_1], false); });
|
|
418
586
|
return [3 /*break*/, 4];
|
|
419
587
|
case 3:
|
|
420
|
-
|
|
588
|
+
err_9 = _a.sent();
|
|
421
589
|
// Error is already set by askWithCitations
|
|
422
|
-
console.error("Failed to send message:",
|
|
590
|
+
console.error("Failed to send message:", err_9);
|
|
423
591
|
return [3 /*break*/, 4];
|
|
424
592
|
case 4: return [2 /*return*/];
|
|
425
593
|
}
|
|
@@ -432,6 +600,9 @@ export function TrainlyProvider(_a) {
|
|
|
432
600
|
ask: ask,
|
|
433
601
|
askWithCitations: askWithCitations,
|
|
434
602
|
upload: upload,
|
|
603
|
+
bulkUploadFiles: bulkUploadFiles, // NEW: Bulk file upload method
|
|
604
|
+
listFiles: listFiles, // NEW: File management methods
|
|
605
|
+
deleteFile: deleteFile,
|
|
435
606
|
connectWithOAuthToken: connectWithOAuthToken, // NEW: V1 OAuth connection method
|
|
436
607
|
isLoading: isLoading,
|
|
437
608
|
isConnected: isConnected,
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { TrainlyConfig, Citation, UploadResult } from "../types";
|
|
1
|
+
import { TrainlyConfig, Citation, UploadResult, FileListResult, FileDeleteResult, BulkUploadResult } from "../types";
|
|
2
2
|
interface QueryResponse {
|
|
3
3
|
answer: string;
|
|
4
4
|
citations?: Citation[];
|
|
@@ -19,6 +19,9 @@ export declare class TrainlyClient {
|
|
|
19
19
|
includeCitations?: boolean;
|
|
20
20
|
}): Promise<QueryResponse>;
|
|
21
21
|
upload(file: File): Promise<UploadResult>;
|
|
22
|
+
bulkUploadFiles(files: File[]): Promise<BulkUploadResult>;
|
|
23
|
+
listFiles(): Promise<FileListResult>;
|
|
24
|
+
deleteFile(fileId: string): Promise<FileDeleteResult>;
|
|
22
25
|
private extractChatId;
|
|
23
26
|
private generateAnonymousId;
|
|
24
27
|
}
|
|
@@ -324,6 +324,189 @@ var TrainlyClient = /** @class */ (function () {
|
|
|
324
324
|
});
|
|
325
325
|
});
|
|
326
326
|
};
|
|
327
|
+
TrainlyClient.prototype.bulkUploadFiles = function (files) {
|
|
328
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
329
|
+
var formData_1, response, error, data, results, successful_uploads, total_size_bytes, _i, files_1, file, uploadResult, error_1;
|
|
330
|
+
return __generator(this, function (_a) {
|
|
331
|
+
switch (_a.label) {
|
|
332
|
+
case 0:
|
|
333
|
+
if (!this.scopedToken) {
|
|
334
|
+
throw new Error("Not connected. Call connect() or connectWithOAuthToken() first.");
|
|
335
|
+
}
|
|
336
|
+
if (!files || files.length === 0) {
|
|
337
|
+
throw new Error("No files provided for bulk upload.");
|
|
338
|
+
}
|
|
339
|
+
if (files.length > 10) {
|
|
340
|
+
throw new Error("Too many files. Maximum 10 files per bulk upload.");
|
|
341
|
+
}
|
|
342
|
+
if (!(this.isV1Mode && this.config.appId)) return [3 /*break*/, 5];
|
|
343
|
+
formData_1 = new FormData();
|
|
344
|
+
// Append all files to the form data
|
|
345
|
+
files.forEach(function (file) {
|
|
346
|
+
formData_1.append("files", file);
|
|
347
|
+
});
|
|
348
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/chats/files/upload-bulk"), {
|
|
349
|
+
method: "POST",
|
|
350
|
+
headers: {
|
|
351
|
+
Authorization: "Bearer ".concat(this.scopedToken),
|
|
352
|
+
"X-App-ID": this.config.appId,
|
|
353
|
+
},
|
|
354
|
+
body: formData_1,
|
|
355
|
+
})];
|
|
356
|
+
case 1:
|
|
357
|
+
response = _a.sent();
|
|
358
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
359
|
+
return [4 /*yield*/, response.json()];
|
|
360
|
+
case 2:
|
|
361
|
+
error = _a.sent();
|
|
362
|
+
throw new Error("V1 bulk upload failed: ".concat(error.detail || response.statusText));
|
|
363
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
364
|
+
case 4:
|
|
365
|
+
data = _a.sent();
|
|
366
|
+
return [2 /*return*/, {
|
|
367
|
+
success: data.success,
|
|
368
|
+
total_files: data.total_files,
|
|
369
|
+
successful_uploads: data.successful_uploads,
|
|
370
|
+
failed_uploads: data.failed_uploads,
|
|
371
|
+
total_size_bytes: data.total_size_bytes,
|
|
372
|
+
chat_id: data.chat_id,
|
|
373
|
+
user_id: data.user_id,
|
|
374
|
+
results: data.results,
|
|
375
|
+
message: data.message,
|
|
376
|
+
}];
|
|
377
|
+
case 5:
|
|
378
|
+
results = [];
|
|
379
|
+
successful_uploads = 0;
|
|
380
|
+
total_size_bytes = 0;
|
|
381
|
+
_i = 0, files_1 = files;
|
|
382
|
+
_a.label = 6;
|
|
383
|
+
case 6:
|
|
384
|
+
if (!(_i < files_1.length)) return [3 /*break*/, 11];
|
|
385
|
+
file = files_1[_i];
|
|
386
|
+
_a.label = 7;
|
|
387
|
+
case 7:
|
|
388
|
+
_a.trys.push([7, 9, , 10]);
|
|
389
|
+
return [4 /*yield*/, this.upload(file)];
|
|
390
|
+
case 8:
|
|
391
|
+
uploadResult = _a.sent();
|
|
392
|
+
results.push({
|
|
393
|
+
filename: uploadResult.filename,
|
|
394
|
+
success: uploadResult.success,
|
|
395
|
+
error: null,
|
|
396
|
+
file_id: null, // Single upload doesn't return file_id
|
|
397
|
+
size_bytes: uploadResult.size,
|
|
398
|
+
processing_status: uploadResult.success ? "completed" : "failed",
|
|
399
|
+
message: uploadResult.message,
|
|
400
|
+
});
|
|
401
|
+
if (uploadResult.success) {
|
|
402
|
+
successful_uploads++;
|
|
403
|
+
total_size_bytes += uploadResult.size;
|
|
404
|
+
}
|
|
405
|
+
return [3 /*break*/, 10];
|
|
406
|
+
case 9:
|
|
407
|
+
error_1 = _a.sent();
|
|
408
|
+
results.push({
|
|
409
|
+
filename: file.name,
|
|
410
|
+
success: false,
|
|
411
|
+
error: error_1 instanceof Error ? error_1.message : String(error_1),
|
|
412
|
+
file_id: null,
|
|
413
|
+
size_bytes: file.size,
|
|
414
|
+
processing_status: "failed",
|
|
415
|
+
});
|
|
416
|
+
return [3 /*break*/, 10];
|
|
417
|
+
case 10:
|
|
418
|
+
_i++;
|
|
419
|
+
return [3 /*break*/, 6];
|
|
420
|
+
case 11: return [2 /*return*/, {
|
|
421
|
+
success: successful_uploads > 0,
|
|
422
|
+
total_files: files.length,
|
|
423
|
+
successful_uploads: successful_uploads,
|
|
424
|
+
failed_uploads: files.length - successful_uploads,
|
|
425
|
+
total_size_bytes: total_size_bytes,
|
|
426
|
+
chat_id: this.currentUserId || "",
|
|
427
|
+
user_id: this.currentUserId || "",
|
|
428
|
+
results: results,
|
|
429
|
+
message: "Bulk upload completed: ".concat(successful_uploads, "/").concat(files.length, " files processed successfully"),
|
|
430
|
+
}];
|
|
431
|
+
}
|
|
432
|
+
});
|
|
433
|
+
});
|
|
434
|
+
};
|
|
435
|
+
TrainlyClient.prototype.listFiles = function () {
|
|
436
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
437
|
+
var response, error, data;
|
|
438
|
+
return __generator(this, function (_a) {
|
|
439
|
+
switch (_a.label) {
|
|
440
|
+
case 0:
|
|
441
|
+
if (!this.scopedToken) {
|
|
442
|
+
throw new Error("Not connected. Call connect() or connectWithOAuthToken() first.");
|
|
443
|
+
}
|
|
444
|
+
if (!(this.isV1Mode && this.config.appId)) return [3 /*break*/, 5];
|
|
445
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/chats/files"), {
|
|
446
|
+
method: "GET",
|
|
447
|
+
headers: {
|
|
448
|
+
Authorization: "Bearer ".concat(this.scopedToken),
|
|
449
|
+
"X-App-ID": this.config.appId,
|
|
450
|
+
},
|
|
451
|
+
})];
|
|
452
|
+
case 1:
|
|
453
|
+
response = _a.sent();
|
|
454
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
455
|
+
return [4 /*yield*/, response.json()];
|
|
456
|
+
case 2:
|
|
457
|
+
error = _a.sent();
|
|
458
|
+
throw new Error("V1 list files failed: ".concat(error.detail || response.statusText));
|
|
459
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
460
|
+
case 4:
|
|
461
|
+
data = _a.sent();
|
|
462
|
+
return [2 /*return*/, data];
|
|
463
|
+
case 5:
|
|
464
|
+
// For other modes, this functionality is not yet implemented
|
|
465
|
+
// as it requires chat-specific API endpoints
|
|
466
|
+
throw new Error("File listing is currently only available in V1 Trusted Issuer mode");
|
|
467
|
+
}
|
|
468
|
+
});
|
|
469
|
+
});
|
|
470
|
+
};
|
|
471
|
+
TrainlyClient.prototype.deleteFile = function (fileId) {
|
|
472
|
+
return __awaiter(this, void 0, void 0, function () {
|
|
473
|
+
var response, error, data;
|
|
474
|
+
return __generator(this, function (_a) {
|
|
475
|
+
switch (_a.label) {
|
|
476
|
+
case 0:
|
|
477
|
+
if (!this.scopedToken) {
|
|
478
|
+
throw new Error("Not connected. Call connect() or connectWithOAuthToken() first.");
|
|
479
|
+
}
|
|
480
|
+
if (!fileId) {
|
|
481
|
+
throw new Error("File ID is required");
|
|
482
|
+
}
|
|
483
|
+
if (!(this.isV1Mode && this.config.appId)) return [3 /*break*/, 5];
|
|
484
|
+
return [4 /*yield*/, fetch("".concat(this.config.baseUrl, "/v1/me/chats/files/").concat(encodeURIComponent(fileId)), {
|
|
485
|
+
method: "DELETE",
|
|
486
|
+
headers: {
|
|
487
|
+
Authorization: "Bearer ".concat(this.scopedToken),
|
|
488
|
+
"X-App-ID": this.config.appId,
|
|
489
|
+
},
|
|
490
|
+
})];
|
|
491
|
+
case 1:
|
|
492
|
+
response = _a.sent();
|
|
493
|
+
if (!!response.ok) return [3 /*break*/, 3];
|
|
494
|
+
return [4 /*yield*/, response.json()];
|
|
495
|
+
case 2:
|
|
496
|
+
error = _a.sent();
|
|
497
|
+
throw new Error("V1 delete file failed: ".concat(error.detail || response.statusText));
|
|
498
|
+
case 3: return [4 /*yield*/, response.json()];
|
|
499
|
+
case 4:
|
|
500
|
+
data = _a.sent();
|
|
501
|
+
return [2 /*return*/, data];
|
|
502
|
+
case 5:
|
|
503
|
+
// For other modes, this functionality is not yet implemented
|
|
504
|
+
// as it requires chat-specific API endpoints
|
|
505
|
+
throw new Error("File deletion is currently only available in V1 Trusted Issuer mode");
|
|
506
|
+
}
|
|
507
|
+
});
|
|
508
|
+
});
|
|
509
|
+
};
|
|
327
510
|
TrainlyClient.prototype.extractChatId = function () {
|
|
328
511
|
if (!this.config.apiKey) {
|
|
329
512
|
throw new Error("API key not provided");
|
|
@@ -0,0 +1,8 @@
|
|
|
1
|
+
export interface TrainlyFileManagerProps {
|
|
2
|
+
className?: string;
|
|
3
|
+
onFileDeleted?: (fileId: string, filename: string) => void;
|
|
4
|
+
onError?: (error: Error) => void;
|
|
5
|
+
showUploadButton?: boolean;
|
|
6
|
+
maxFileSize?: number;
|
|
7
|
+
}
|
|
8
|
+
export declare function TrainlyFileManager({ className, onFileDeleted, onError, showUploadButton, maxFileSize, }: TrainlyFileManagerProps): import("react/jsx-runtime").JSX.Element;
|