UNPKG

@maximai/maxim-js

Version:

Maxim AI JS SDK. Visit https://getmaxim.ai for more info.

383 lines 15.7 kB
"use strict"; Object.defineProperty(exports, "__esModule", { value: true }); exports.MaximDatasetAPI = void 0; const dataset_1 = require("../models/dataset"); const maxim_1 = require("./maxim"); const platform_1 = require("../platform"); class MaximDatasetAPI extends maxim_1.MaximAPI { constructor(baseUrl, apiKey, isDebug) { super(baseUrl, apiKey, isDebug); } async addDatasetEntries(datasetId, datasetEntries) { let nextRowNo = await this.getDatasetTotalRows(datasetId) + 1; const entriesWithFileAttachments = []; const transformedEntries = datasetEntries.map((entry) => { const rowNo = nextRowNo++; const isFile = entry.cellValue.type === dataset_1.VariableType.FILE; if (isFile) { entriesWithFileAttachments.push({ ...entry, rowNo }); } return { rowNo, columnName: entry.columnName, type: entry.cellValue.type, value: isFile ? [] : entry.cellValue.payload, }; }); const response = await this.fetch(`/api/sdk/v4/datasets/entries`, { method: "POST", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ datasetId, entries: transformedEntries }), }); // Handle the response if ("error" in response) { throw new Error(response.error.message); } const mapEntryIDToEntries = {}; for (const entry of entriesWithFileAttachments) { for (const cell of response.data.cells) { if (cell.columnName === entry.columnName && cell.rowNo === entry.rowNo) { entry.columnId = cell.columnId; mapEntryIDToEntries[cell.entryId] = entry; break; } } } const filePayloads = await Promise.all(Object.entries(mapEntryIDToEntries).map(([entryId, entry]) => this.uploadFileAttachments(datasetId, entryId, entry))); // Transform file payloads to the updates shape required by the API schema const transformedUpdates = filePayloads.map((payload) => ({ entryId: payload.entryId, columnName: mapEntryIDToEntries[payload.entryId].columnName, value: { type: "file", payload: payload, }, })); if (transformedUpdates.length > 0) { try { await this.updateDatasetEntries(datasetId, transformedUpdates); } catch (error) { throw new Error(`Failed to update dataset entries: ${error}`); } } } async uploadFileAttachments(datasetId, entryId, entry) { var _a; const fileAttachments = []; for (const file of entry.cellValue.payload) { let file_attachment; let { fileData, mimeType, size } = await this.processAttachment(file); if (!mimeType || mimeType === 'application/octet-stream') { const source = (_a = file.name) !== null && _a !== void 0 ? _a : (file.type === "file" ? file.path : undefined); if (source) { const inferredType = platform_1.platform.mime.lookup(source); if (inferredType) { mimeType = inferredType; } } } if (file.type !== "url") { const signedURLResponse = await this.getUploadUrlForDatasetAttachment(datasetId, entryId, entry.columnId, file.id, mimeType, size); try { await this.uploadToSignedUrl(signedURLResponse.url, fileData, mimeType, { filename: file.name, entryId: entryId }); } catch (error) { throw new Error(`Failed to upload file ${file.name} to signed URL: ${error}`); } file_attachment = { id: file.id, url: signedURLResponse.url, hosted: true, prefix: signedURLResponse.key, props: { "size": size, "type": mimeType } }; } else { file_attachment = { id: file.id, url: file.url, hosted: false, prefix: "", props: { "size": size, "type": mimeType } }; } fileAttachments.push(file_attachment); } const filePayload = { files: fileAttachments, entryId: entryId }; return filePayload; } async processAttachment(attachment) { if (attachment.type === "url") { return this.processUrlAttachment(attachment); } else if (attachment.type === "fileData" || attachment.type === "file") { return this.processFileAttachment(attachment); } else { throw new Error(`Invalid attachment type: ${attachment.type}. Expected url, fileData, or file.`); } } async processUrlAttachment(attachment) { try { // Validate URL if (!attachment.url || (!attachment.url.startsWith('http://') && !attachment.url.startsWith('https://'))) { throw new Error(`Invalid URL: ${attachment.url}`); } // Get file info from HEAD request const headResponse = await fetch(attachment.url, { method: 'HEAD' }); if (!headResponse.ok) { throw new Error(`HTTP ${headResponse.status}: ${headResponse.statusText}`); } const mimeType = headResponse.headers.get('content-type') || 'application/octet-stream'; const contentLength = headResponse.headers.get('content-length'); // Calculate size const size = contentLength ? parseInt(contentLength, 10) : 0; return { fileData: null, mimeType, size }; } catch (error) { if (error instanceof Error && error.message.includes('Invalid URL')) { throw error; } throw new Error(`Failed to download URL attachment ${attachment.url}: ${error instanceof Error ? error.message : String(error)}`); } } async processFileAttachment(attachment) { try { let fileData; let mimeType; let size; const maxFileSizeBytes = 1024 * 1024 * 100; // 100MB if (attachment.type === "fileData") { fileData = attachment.data; mimeType = attachment.mimeType || 'application/octet-stream'; size = fileData.length; if (size > maxFileSizeBytes) { throw new Error(`File size exceeds the maximum allowed size of ${maxFileSizeBytes} bytes`); } } else { if (!platform_1.platform.features.fileIoSupported) { throw new Error("File operations are not supported in this environment"); } let stats; try { stats = await platform_1.platform.fs.readFile(attachment.path); } catch (error) { throw new Error(`File not found: ${attachment.path}`); } if (stats.data.length > maxFileSizeBytes) { throw new Error(`File size exceeds the maximum allowed size of ${maxFileSizeBytes} bytes`); } try { fileData = Buffer.from(stats.data); } catch (error) { throw new Error(`File not found: ${attachment.path}`); } mimeType = attachment.mimeType || 'application/octet-stream'; size = fileData.length; } return { fileData, mimeType, size }; } catch (error) { if (error instanceof Error && (error.message.includes('File size exceeds the maximum allowed size') || error.message.includes('File not found'))) { throw error; } const attachmentName = attachment.name || 'unknown'; throw new Error(`Failed to process file attachment ${attachmentName}: ${error instanceof Error ? error.message : String(error)}`); } } async getDatasetTotalRows(datasetId) { return new Promise((resolve, reject) => { this.fetch(`/api/sdk/v1/datasets/total-rows?datasetId=${datasetId}`) .then((response) => { if ("error" in response) { reject(response.error); } else { resolve(response.data); } }) .catch((error) => { reject(error); }); }); } async getDatasetRow(datasetId, rowIndex) { return new Promise((resolve, reject) => { this.fetch(`/api/sdk/v2/datasets/row?datasetId=${datasetId}&row=${rowIndex}`) .then((response) => { if ("error" in response) { reject(response.error); } else { resolve(response.data); } }) .catch((error) => { reject(error); }); }); } async getDatasetDatastructure(datasetId) { return new Promise((resolve, reject) => { this.fetch(`/api/sdk/v1/datasets/structure?datasetId=${datasetId}`) .then((response) => { if ("error" in response) { reject(response.error); } else { resolve(response.data); } }) .catch((error) => { reject(error); }); }); } async getUploadUrlForDatasetAttachment(datasetId, entryId, columnId, key, mimeType, size) { var _a; try { const response = await this.fetch("/api/sdk/v4/datasets/entries/attachments/", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ datasetId: datasetId, entryId: entryId, columnId: columnId, file: { id: key, type: mimeType, size: size, } }), }); if (this.isDebug) { console.log("Upload URL Response: ", response); } // Handle the response if ("error" in response) { throw new Error(response.error.message); } return { url: response.data.url, key: response.data.key }; } catch (error) { // Handle axios errors with response data if (error && typeof error === 'object' && 'response' in error) { const axiosError = error; if ((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data) { const errorData = axiosError.response.data; if (errorData && typeof errorData === 'object' && 'error' in errorData && typeof errorData.error === 'object' && 'message' in errorData.error) { throw new Error(errorData.error.message); } } } // Re-throw the error if it's already an Error instance if (error instanceof Error) { throw error; } // For any other type of error, convert to Error throw new Error(String(error)); } } async uploadToSignedUrl(url, data, mimeType, fileContext) { try { const response = await this.axiosInstance.put(url, data, { headers: { "Content-Type": mimeType, "Content-Length": data.length.toString(), }, responseType: "text", timeout: 120000, transformRequest: [(data) => data], transformResponse: [(data) => data], baseURL: "", }); if (response.status >= 200 && response.status < 300) { return; } if (response.data && typeof response.data === "object" && "error" in response.data) { throw response.data.error; } throw response.data; } catch (error) { // Wrap network/DNS errors with file context for better debugging const context = fileContext ? ` (file: ${fileContext.filename || 'unknown'}, entryId: ${fileContext.entryId || 'unknown'})` : ''; if (error instanceof Error) { throw new Error(`Failed to upload file to signed URL${context}: ${error.message}`); } throw new Error(`Failed to upload file to signed URL${context}: ${String(error)}`); } } async updateDatasetEntries(datasetId, updates) { var _a; try { const response = await this.fetch("/api/sdk/v4/datasets/entries", { method: "PUT", headers: { "Content-Type": "application/json" }, body: JSON.stringify({ datasetId: datasetId, updates: updates }), }); if (this.isDebug) { console.log("Update dataset entries: ", response); } // Handle the response if (response.error) { throw new Error(response.error.message); } } catch (error) { // Handle axios errors with response data if (error && typeof error === 'object' && 'response' in error) { const axiosError = error; if ((_a = axiosError.response) === null || _a === void 0 ? void 0 : _a.data) { const errorData = axiosError.response.data; if (errorData && typeof errorData === 'object' && 'error' in errorData && typeof errorData.error === 'object' && 'message' in errorData.error) { throw new Error(errorData.error.message); } } } // Re-throw the error if it's already an Error instance if (error instanceof Error) { throw new Error(`Failed to update dataset entries with attachments: ${error.message}`); } // For any other type of error, convert to Error throw new Error(`Failed to update dataset entries with attachments: ${String(error)}`); } } } exports.MaximDatasetAPI = MaximDatasetAPI; //# sourceMappingURL=dataset.js.map