From 2508cd5074ce38438d7b620dc1bf41b0649720ce Mon Sep 17 00:00:00 2001 From: skyflow-shravan Date: Tue, 10 Jun 2025 17:50:38 +0530 Subject: [PATCH] SK-2115 fix type gaps --- src/error/index.ts | 2 +- src/index.ts | 10 +- src/utils/index.ts | 26 ++-- src/utils/validations/index.ts | 6 +- src/vault/controller/connections/index.ts | 3 +- src/vault/controller/detect/index.ts | 65 ++++----- src/vault/controller/vault/index.ts | 131 ++++++++++-------- .../model/options/deidentify-file/index.ts | 2 +- src/vault/model/options/insert/index.ts | 6 +- src/vault/model/request/insert/index.ts | 8 +- .../model/response/deidentify-text/index.ts | 14 +- src/vault/model/response/delete/index.ts | 8 +- src/vault/model/response/detokenize/index.ts | 7 +- src/vault/model/response/file-upload/index.ts | 8 +- src/vault/model/response/get/index.ts | 9 +- src/vault/model/response/insert/index.ts | 9 +- src/vault/model/response/invoke/invoke.ts | 9 +- src/vault/model/response/query/index.ts | 9 +- src/vault/model/response/tokenize/index.ts | 8 +- src/vault/model/response/update/index.ts | 9 +- src/vault/types/index.ts | 86 ++++++++++-- test/vault/controller/detect.test.js | 6 - test/vault/controller/vault.test.js | 36 ++--- 23 files changed, 289 insertions(+), 188 deletions(-) diff --git a/src/error/index.ts b/src/error/index.ts index 1dce9cb5..81e633f8 100644 --- a/src/error/index.ts +++ b/src/error/index.ts @@ -4,7 +4,7 @@ class SkyflowError extends Error { error?: ISkyflowError; - constructor(errorCode: ISkyflowError, args: any[] = []) { + constructor(errorCode: ISkyflowError, args: Array = []) { const formattedError = { http_status: errorCode?.http_status || BAD_REQUEST, details: errorCode?.details || [], diff --git a/src/index.ts b/src/index.ts index 3aa94484..96c14973 100644 --- a/src/index.ts +++ b/src/index.ts @@ -28,7 +28,7 @@ import UpdateResponse from './vault/model/response/update'; import FileUploadResponse from './vault/model/response/file-upload'; import QueryResponse from './vault/model/response/query'; import InvokeConnectionResponse from './vault/model/response/invoke/invoke'; -import { SkyflowConfig, TokenizeRequestType, DetokenizeData } from './vault/types'; +import { SkyflowConfig, TokenizeRequestType, DetokenizeData, InsertResponseType, GetResponseData, QueryResponseType, IndexRange } from './vault/types'; import VaultConfig from './vault/config/vault'; import SkyflowError from './error'; import ConnectionConfig from './vault/config/connection'; @@ -46,6 +46,7 @@ import DeidentifyFileResponse from './vault/model/response/deidentify-file'; import GetDetectRunRequest from './vault/model/request/get-detect-run'; import { TokenType, MaskingMethod, DetectOutputTranscription } from './utils'; import { Bleep } from './vault/model/options/deidentify-file/bleep-audio'; +import { SkyflowRecordError } from './utils/index'; export { Env, LogLevel, @@ -113,5 +114,10 @@ export { Bleep, MaskingMethod, DetectOutputTranscription, - GetDetectRunRequest + GetDetectRunRequest, + SkyflowRecordError, + InsertResponseType, + GetResponseData, + QueryResponseType, + IndexRange }; \ No newline at end of file diff --git a/src/utils/index.ts b/src/utils/index.ts index 9b834c6c..7e6bb5dd 100644 --- a/src/utils/index.ts +++ b/src/utils/index.ts @@ -9,6 +9,7 @@ import process from "process"; import SKYFLOW_ERROR_CODE from "../error/codes"; import { isExpired } from "./jwt-utils"; import { isValidAPIKey } from "./validations"; +import { StringKeyValueMapType } from "../vault/types"; dotenv.config(); @@ -216,6 +217,14 @@ export interface ISkyflowError { details?: Array | null, } +export interface SkyflowRecordError { + error: string, + requestId: string | null, + httpCode?: string | number | null, + requestIndex?: number | null, + token?: string | null, +} + export interface AuthInfo { key: string, type: AuthType @@ -345,12 +354,12 @@ export function getBaseUrl(url: string): string { } export function fillUrlWithPathAndQueryParams(url: string, - pathParams?: object, - queryParams?: object) { + pathParams?: StringKeyValueMapType, + queryParams?: StringKeyValueMapType) { let filledUrl = url; if (pathParams) { Object.entries(pathParams).forEach(([key, value]) => { - filledUrl = url.replace(`{${key}}`, value); + filledUrl = url.replace(`{${key}}`, String(value)); }); } if (queryParams) { @@ -402,13 +411,12 @@ export const printLog = (message: string, messageType: MessageType, logLevel: Lo } }; -export const parameterizedString = (...args: any[]) => { - const str = args[0]; - const params = args.filter((arg, index) => index !== 0); +export const parameterizedString = (message: string, ...args: Array) => { + const str = message; if (!str) return ''; - return str.replace(/%s[0-9]+/g, (matchedStr: any) => { - const variableIndex = matchedStr.replace('%s', '') - 1; - return params[variableIndex]; + return str.replace(/%s[0-9]+/g, (matchedStr: string | number) => { + const variableIndex = parseInt((matchedStr as string).replace('%s', '')) - 1; + return args[variableIndex] as string; }); }; diff --git a/src/utils/validations/index.ts b/src/utils/validations/index.ts index fcabdb71..99eed5b5 100644 --- a/src/utils/validations/index.ts +++ b/src/utils/validations/index.ts @@ -499,8 +499,8 @@ export const validateInsertOptions = (insertOptions?: InsertOptions) => { }; const validateTokensMapWithTokenStrict = ( - data: object, - tokens: object + data: Record, + tokens: Record ) => { const dataKeys = Object.keys(data); @@ -1181,7 +1181,7 @@ export const validateDeidentifyFileOptions = (deidentifyFileOptions: DeidentifyF } }; -function isStringKeyValueMap(obj: any): obj is StringKeyValueMapType { +function isStringKeyValueMap(obj: unknown): obj is StringKeyValueMapType { if (typeof obj !== 'object' || obj === null || Array.isArray(obj)) { return false; } diff --git a/src/vault/controller/connections/index.ts b/src/vault/controller/connections/index.ts index 1281046d..c18abe22 100644 --- a/src/vault/controller/connections/index.ts +++ b/src/vault/controller/connections/index.ts @@ -80,7 +80,8 @@ class ConnectionController { const requestId = headers?.get(REQUEST_ID_KEY) || ''; const invokeConnectionResponse = new InvokeConnectionResponse({ data: body, - metadata: { requestId } + metadata: { requestId }, + errors: null }); resolve(invokeConnectionResponse); }).catch((err) => { diff --git a/src/vault/controller/detect/index.ts b/src/vault/controller/detect/index.ts index c7cc0cf2..bdd3c20b 100644 --- a/src/vault/controller/detect/index.ts +++ b/src/vault/controller/detect/index.ts @@ -1,7 +1,7 @@ //imports import path from "path"; -import { DeidentifyTextRequest as DeidentifyTextRequest2,DeidentifyAudioRequest, DeidentifyAudioRequestFileDataFormat, DeidentifyDocumentRequest, DeidentifyDocumentRequestFileDataFormat, DeidentifyFileRequestFileDataFormat, DeidentifyImageRequest, DeidentifyImageRequestFileDataFormat, DeidentifyImageRequestMaskingMethod, DeidentifyPdfRequest, DeidentifyPresentationRequest, DeidentifyPresentationRequestFileDataFormat, DeidentifySpreadsheetRequest, DeidentifySpreadsheetRequestFileDataFormat, DeidentifyStructuredTextRequest, DeidentifyStructuredTextRequestFileDataFormat, DetectedEntity, EntityType, GetRunRequest, Transformations as GeneratedTransformations, TokenTypeWithoutVault } from "../../../ _generated_/rest/api"; +import { DeidentifyTextRequest as DeidentifyTextRequest2,DeidentifyAudioRequest, DeidentifyAudioRequestFileDataFormat, DeidentifyDocumentRequest, DeidentifyDocumentRequestFileDataFormat, DeidentifyFileRequestFileDataFormat, DeidentifyImageRequest, DeidentifyImageRequestFileDataFormat, DeidentifyImageRequestMaskingMethod, DeidentifyPdfRequest, DeidentifyPresentationRequest, DeidentifyPresentationRequestFileDataFormat, DeidentifySpreadsheetRequest, DeidentifySpreadsheetRequestFileDataFormat, DeidentifyStructuredTextRequest, DeidentifyStructuredTextRequestFileDataFormat, DetectedEntity, EntityType, GetRunRequest, Transformations as GeneratedTransformations, TokenTypeWithoutVault, DeidentifyStringResponse, DeidentifyStatusResponse } from "../../../ _generated_/rest/api"; import { DeidentifyFileRequest as DeidentifyFileRequest2} from "../../../ _generated_/rest/api"; import { TokenType } from "../../../ _generated_/rest/api"; @@ -25,6 +25,7 @@ import SKYFLOW_ERROR_CODE from "../../../error/codes"; import GetDetectRunRequest from "../../model/request/get-detect-run"; import Transformations from "../../model/options/deidentify-text/transformations"; import { SkyflowAllError } from "../../types"; +import { DeidentifyFileDetectRunResponse, DeidentifyFileOutput, DetectTextResponse, DetectFileResponse } from "../../types"; class DetectController { @@ -267,7 +268,7 @@ class DetectController { } } - private processDeidentifyFileResponse(response: any, outputDirectory: string, fileBaseName: string) { + private processDeidentifyFileResponse(response: DeidentifyFileDetectRunResponse, outputDirectory: string, fileBaseName: string) { try { // Ensure the output directory exists if (!fs.existsSync(outputDirectory)) { @@ -275,7 +276,7 @@ class DetectController { } // Iterate over the output array in the response - response.output.forEach((fileObject: any, index: number) => { + response.output.forEach((fileObject: DeidentifyFileOutput, index: number) => { const { processedFile, processedFileExtension } = fileObject; if (!processedFile || !processedFileExtension) { @@ -334,7 +335,7 @@ class DetectController { const poll = () => { this.client.filesAPI.getRun(runId, req) - .then((response: any) => { + .then((response: DeidentifyStatusResponse) => { if (response.status === 'IN_PROGRESS') { if (currentWaitTime >= maxWaitTime) { resolve({ runId }); // Resolve with runId if max wait time is exceeded @@ -359,14 +360,14 @@ class DetectController { reject(new SkyflowError(SKYFLOW_ERROR_CODE.INTERNAL_SERVER_ERROR, [response.message])); } }) - .catch((error: any) => { + .catch((error) => { reject(error); }); }; poll(); // Start polling } - private handleRequest(apiCall: Function, requestType: string): Promise { + private handleRequest(apiCall: Function, requestType: string): Promise { return new Promise((resolve, reject) => { printLog(parameterizedString(logs.infoLogs.EMIT_REQUEST, TYPES[requestType]), MessageType.LOG, this.client.getLogLevel()); const sdkHeaders = this.createSdkHeaders(); @@ -381,7 +382,7 @@ class DetectController { switch (requestType) { case TYPES.DEIDENTIFY_TEXT: case TYPES.REIDENTIFY_TEXT: - resolve({records: data, requestId}) + resolve({records: data, requestId} as T) break; case TYPES.DEIDENTIFY_FILE: const req: GetRunRequest = { @@ -393,7 +394,7 @@ class DetectController { this.pollForProcessedFile(data.run_id, req, maxWaitTime, resolve, reject); // Call the extracted polling function break; case TYPES.DETECT_RUN: - resolve({data, requestId}) + resolve({data, requestId} as T) break; } @@ -422,29 +423,29 @@ class DetectController { }; } - private parseDeidentifyTextResponse(data: any) { + private parseDeidentifyTextResponse(records: DeidentifyStringResponse) { return { - processedText: data.records.processed_text, - entities: data.records.entities.map((entity: DetectedEntity) => ({ - token: entity.token, - value: entity.value, + processedText: records.processed_text, + entities: records.entities.map((entity: DetectedEntity) => ({ + token: entity.token!, + value: entity.value!, textIndex: { - start: entity.location?.start_index, - end: entity.location?.end_index, + start: entity.location?.start_index!, + end: entity.location?.end_index!, }, processedIndex: { - start: entity.location?.start_index_processed, - end: entity.location?.end_index_processed, + start: entity.location?.start_index_processed!, + end: entity.location?.end_index_processed!, }, - entity: entity.entity_type, - scores: entity.entity_scores, + entity: entity.entity_type!, + scores: entity.entity_scores!, })), - wordCount: data.records.word_count, - charCount: data.records.character_count, + wordCount: records.word_count, + charCount: records.character_count, }; } - private parseDeidentifyFileResponse(data: any, runId?: string, status?: string): DeidentifyFileResponse { + private parseDeidentifyFileResponse(data: DeidentifyFileDetectRunResponse, runId?: string, status?: string): DeidentifyFileResponse { return new DeidentifyFileResponse({ file: data.output?.[0]?.processedFile ?? '', type: data.output?.[0]?.processedFileType ?? '', @@ -456,12 +457,12 @@ class DetectController { pageCount: data.pages ?? 0, slideCount: data.slides ?? 0, entities: (data.output || []) - .filter((fileObject: any) => fileObject.processedFileType === 'entities') - .map((fileObject: any) => ({ - file: fileObject.processedFile, - extension: fileObject.processedFileExtension, + .filter((fileObject: DeidentifyFileOutput) => fileObject.processedFileType === 'entities') + .map((fileObject: DeidentifyFileOutput) => ({ + file: fileObject.processedFile as string, + extension: fileObject.processedFileExtension as string, })), - runId: data.runId ?? data.run_id ?? runId, // Handles both camelCase and snake_case + runId: data.runId ?? data.runId ?? runId, status: status, }); } @@ -475,13 +476,13 @@ class DetectController { validateDeIdentifyTextRequest(request, options, this.client.getLogLevel()); const requestBody = this.buildDeidentifyTextRequest(request, options); - this.handleRequest( + this.handleRequest>( () => this.client.stringsAPI.deidentifyString( requestBody ).withRawResponse(), TYPES.DEIDENTIFY_TEXT ).then(data => { - const parsedResponse = new DeidentifyTextResponse(this.parseDeidentifyTextResponse(data)) + const parsedResponse = new DeidentifyTextResponse(this.parseDeidentifyTextResponse(data.records)) resolve(parsedResponse); }).catch(error => { reject(error) @@ -510,7 +511,7 @@ class DetectController { plaintext: options?.getPlainTextEntities(), } }; - this.handleRequest( + this.handleRequest>>( () => this.client.stringsAPI.reidentifyString( requestBody ).withRawResponse(), @@ -542,7 +543,7 @@ class DetectController { vault_id: this.client.vaultId } - this.handleRequest( + this.handleRequest>( () => this.client.filesAPI.getRun( request.runId, req @@ -576,7 +577,7 @@ class DetectController { this.waitTime = options?.getWaitTime() ?? this.waitTime; var reqType : DeidenitfyFileRequestTypes = this.getReqType(fileExtension); - var promiseReq: Promise; + var promiseReq: Promise; switch (reqType){ case DeidenitfyFileRequestTypes.AUDIO: promiseReq = this.buildAudioRequest(request, options, fileExtension) diff --git a/src/vault/controller/vault/index.ts b/src/vault/controller/vault/index.ts index 82d6db59..afe3f008 100644 --- a/src/vault/controller/vault/index.ts +++ b/src/vault/controller/vault/index.ts @@ -21,8 +21,8 @@ import QueryResponse from '../../model/response/query'; import FileUploadResponse from '../../model/response/file-upload'; import TokenizeResponse from '../../model/response/tokenize'; import TokenizeRequest from '../../model/request/tokenize'; -import { ParsedDetokenizeResponse, ParsedInsertBatchResponse, TokenizeRequestType } from '../../types'; -import { generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, TYPES, SDK_METRICS_HEADER_KEY, removeSDKVersion, RedactionType, SKYFLOW_ID } from '../../../utils'; +import { InsertResponseType, ParsedDetokenizeResponse, ParsedInsertBatchResponse, RecordsResponse, SkyflowIdResponse, StringKeyValueMapType, TokenizeRequestType, TokensResponse } from '../../types'; +import { generateSDKMetrics, getBearerToken, MessageType, parameterizedString, printLog, TYPES, SDK_METRICS_HEADER_KEY, removeSDKVersion, RedactionType, SKYFLOW_ID, SkyflowRecordError } from '../../../utils'; import GetColumnRequest from '../../model/request/get-column'; import logs from '../../../utils/logs'; import VaultClient from '../../client'; @@ -43,21 +43,21 @@ class VaultController { return { [SDK_METRICS_HEADER_KEY]: JSON.stringify(generateSDKMetrics()) }; } - private handleRecordsResponse(data: any): any[] { - if (data?.records && Array.isArray(data.records) && data.records.length > 0) { - return data.records; + private handleRecordsResponse(records: Record[]): Record[] { + if (records && Array.isArray(records) && records.length > 0) { + return records; } return []; } - private handleInsertBatchResponse(data: any): any[] { - if (data?.responses && Array.isArray(data.responses) && data.responses.length > 0) { - return data.responses; + private handleInsertBatchResponse(responses: Record[]): Record[] { + if (responses && Array.isArray(responses) && responses.length > 0) { + return responses; } return []; } - private parseDetokenizeResponse(records: any[], requestId: any): ParsedDetokenizeResponse { + private parseDetokenizeResponse(records: Record[], requestId: string): ParsedDetokenizeResponse { const response: ParsedDetokenizeResponse = { success: [], errors: [] @@ -67,11 +67,12 @@ class VaultController { } records.forEach(record => { if (record.error) { - response.errors.push({ - requestId: requestId, + const detokenizeError: SkyflowRecordError = { token: record.token, - error: record.error - }); + error: record.error, + requestId: requestId + } + response.errors.push(detokenizeError); } else { response.success.push({ token: record.token, @@ -83,17 +84,17 @@ class VaultController { return response; } - private parseInsertBatchResponse(records: any[], requestId: any): InsertResponse { + private parseInsertBatchResponse(records: Record[], requestId: string): InsertResponse { const response: ParsedInsertBatchResponse = { success: [], errors: [] }; if (!records || !Array.isArray(records) || records.length === 0) { - return new InsertResponse({ insertedFields:[], errors: [] }); + return new InsertResponse({ insertedFields:null, errors: null }); } - records.forEach((record, index) => { + records.forEach((record: Record, index: number) => { if (this.isSuccess(record)) { this.processSuccess(record, index, response); @@ -102,32 +103,42 @@ class VaultController { } }); - return new InsertResponse({ insertedFields: response.success, errors: response.errors }); + return new InsertResponse({ insertedFields: response.success.length>0 ? response.success : null, errors: response.errors.length>0 ? response.errors : null }); } - private isSuccess(record: any): boolean { + private isSuccess(record: Record): boolean { return record?.Status === 200; } - private processSuccess(record: any, index: number, response: ParsedInsertBatchResponse): void { - record.Body.records.forEach((field: any) => { - response.success.push({ - skyflowId: field?.skyflow_id, - requestIndex: index, - ...field?.tokens + private processSuccess(record: Record, index: number, response: ParsedInsertBatchResponse): void { + const body = record.Body as { records: StringKeyValueMapType[] }; + if (body && Array.isArray(body.records)) { + body.records.forEach((field: StringKeyValueMapType) => { + response.success.push({ + skyflowId: String(field?.skyflow_id), + requestIndex: index, + ...(typeof field?.tokens === 'object' && field?.tokens !== null ? field.tokens : {}) + }); }); - }); + } } - private processError(record: any, index: number, requestId: any, response: ParsedInsertBatchResponse): void { - response.errors.push({ - requestId: requestId, - requestIndex: index, - error: record?.Body?.error - }); + private processError(record: Record, index: number, requestId: string, response: ParsedInsertBatchResponse): void { + let httpCode: string | number | null = null; + if (typeof record?.Status === 'string' || typeof record?.Status === 'number') { + httpCode = record.Status; + } + const recordBody = record?.Body as { error: string }; + const errorObj: SkyflowRecordError = { + httpCode, + error: recordBody?.error, + requestId: requestId ?? null, + requestIndex: index ?? null, + }; + response.errors.push(errorObj); } - private handleRequest(apiCall: Function, requestType: string): Promise { + private handleRequest(apiCall: Function, requestType: string): Promise { return new Promise((resolve, reject) => { printLog(parameterizedString(logs.infoLogs.EMIT_REQUEST, TYPES[requestType]), MessageType.LOG, this.client.getLogLevel()); const sdkHeaders = this.createSdkHeaders(); @@ -145,17 +156,17 @@ class VaultController { case TYPES.QUERY: case TYPES.DETOKENIZE: case TYPES.TOKENIZE: - resolve({records: this.handleRecordsResponse(data), requestId}) + resolve({records: this.handleRecordsResponse(data.records), requestId} as T); break; case TYPES.INSERT_BATCH: - resolve({records: this.handleInsertBatchResponse(data), requestId}) + resolve({records: this.handleInsertBatchResponse(data?.responses), requestId} as T) break; case TYPES.UPDATE: case TYPES.FILE_UPLOAD: resolve(data) break; case TYPES.DELETE: - resolve(new DeleteResponse({ deletedIds: data.RecordIDResponse, errors: [] })); + resolve(new DeleteResponse({ deletedIds: data.RecordIDResponse, errors: null }) as T); break; } }).catch((error: any) => { @@ -166,7 +177,7 @@ class VaultController { }); } - private getTokens(index:number, tokens?: Array) : object | undefined { + private getTokens(index:number, tokens?: Record[]) : Record | undefined { if(tokens && tokens.length !== 0 && tokens.length > index ) return tokens[index]; } @@ -200,12 +211,12 @@ class VaultController { }; } - private parseBulkInsertResponse(records: any[]): InsertResponse { - const insertedFields = records.map(record => ({ - skyflowId: record.skyflow_id, - ...record.tokens + private parseBulkInsertResponse(records: Record[]): InsertResponse { + const insertedFields: InsertResponseType[] = records.map(record => ({ + skyflowId: String(record.skyflow_id), + ...(typeof record.tokens === 'object' && record.tokens !== null ? record.tokens : {}) })); - return new InsertResponse({ insertedFields, errors: [] }); + return new InsertResponse({ insertedFields, errors: null }); } insert(request: InsertRequest, options?: InsertOptions): Promise { @@ -225,13 +236,13 @@ class VaultController { const operationType = isContinueOnError ? TYPES.INSERT_BATCH : TYPES.INSERT; const tableName = request.tableName; - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => isContinueOnError ? this.client.vaultAPI.recordServiceBatchOperation(this.client.vaultId, requestBody, headers).withRawResponse() : this.client.vaultAPI.recordServiceInsertRecord(this.client.vaultId, tableName, requestBody as RecordServiceInsertRecordBody, headers).withRawResponse(), operationType - ).then((resp: any) => { + ).then((resp) => { printLog(logs.infoLogs.INSERT_DATA_SUCCESS, MessageType.LOG, this.client.getLogLevel()); const parsedResponse = isContinueOnError ? this.parseInsertBatchResponse(resp.records, resp.requestId) @@ -267,7 +278,7 @@ class VaultController { byot: strictMode }; - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => this.client.vaultAPI.recordServiceUpdateRecord( this.client.vaultId, request.tableName, @@ -282,7 +293,7 @@ class VaultController { skyflowId: data.skyflow_id, ...data?.tokens }; - resolve(new UpdateResponse({ updatedField: updatedRecord, errors: [] })); + resolve(new UpdateResponse({ updatedField: updatedRecord, errors: null })); }) .catch(error => { reject(error); @@ -307,7 +318,7 @@ class VaultController { skyflow_ids: request.ids, }; - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => this.client.vaultAPI.recordServiceBulkDeleteRecord( this.client.vaultId, request.tableName, @@ -322,7 +333,7 @@ class VaultController { .catch(error => { reject(error); }); - } catch (error: any) { + } catch (error) { if (error instanceof Error) printLog(removeSDKVersion(error.message), MessageType.ERROR, this.client.getLogLevel()); reject(error); @@ -368,7 +379,7 @@ class VaultController { order_by: options?.getOrderBy(), }; - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => this.client.vaultAPI.recordServiceBulkGetRecord( this.client.vaultId, request.tableName, @@ -379,9 +390,9 @@ class VaultController { ).then(response => { printLog(logs.infoLogs.GET_SUCCESS, MessageType.LOG, this.client.getLogLevel()); const processedRecords = response.records.map(record => ({ - ...record.fields, + ...(typeof record.fields === 'object' && record.fields !== null ? record.fields : {}), })); - resolve(new GetResponse({ data: processedRecords, errors: [] })); + resolve(new GetResponse({ data: processedRecords, errors: null })); }) .catch(error => { reject(error); @@ -426,7 +437,7 @@ class VaultController { fileBlob = options?.getFileObject(); } - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => this.client.vaultAPI.fileServiceUploadFile( fileBlob as unknown as import('buffer').Blob, this.client.vaultId, @@ -439,7 +450,7 @@ class VaultController { TYPES.FILE_UPLOAD ).then(data => { printLog(logs.infoLogs.FILE_UPLOAD_DATA_SUCCESS, MessageType.LOG, this.client.getLogLevel()); - resolve(new FileUploadResponse({ skyflowId: data.skyflow_id, errors: [] })); + resolve(new FileUploadResponse({ skyflowId: data.skyflow_id, errors: null })); }) .catch(error => { reject(error); @@ -465,7 +476,7 @@ class VaultController { query: request.query, }; - this.handleRequest( + this.handleRequest( (headers: Records.RequestOptions | undefined) => this.client.queryAPI.queryServiceExecuteQuery( this.client.vaultId, query, @@ -475,12 +486,12 @@ class VaultController { ).then(response => { printLog(logs.infoLogs.QUERY_SUCCESS, MessageType.LOG, this.client.getLogLevel()); const processedRecords = response.records.map(record => ({ - ...record?.fields, + ...(typeof record.fields === 'object' && record.fields !== null ? record.fields : {}), tokenizedData: { - ...record?.tokens, + ...(typeof record.tokens === 'object' && record.tokens !== null ? record.tokens : {}), }, })); - resolve(new QueryResponse({ fields: processedRecords, errors: [] })); + resolve(new QueryResponse({ fields: processedRecords, errors: null })); }) .catch(error => { reject(error); @@ -505,13 +516,13 @@ class VaultController { const fields = request.data.map(record => ({ token: record.token, redaction: record?.redactionType || RedactionType.DEFAULT })) as Array; const detokenizePayload: V1DetokenizePayload = { detokenizationParameters: fields, continueOnError: options?.getContinueOnError(), downloadURL: options?.getDownloadURL() }; - this.handleRequest( + this.handleRequest>>( (headers: Records.RequestOptions | undefined) => this.client.tokensAPI.recordServiceDetokenize(this.client.vaultId, detokenizePayload, headers).withRawResponse(), TYPES.DETOKENIZE ).then(response => { printLog(logs.infoLogs.DETOKENIZE_SUCCESS, MessageType.LOG, this.client.getLogLevel()); const parsedResponse: ParsedDetokenizeResponse = this.parseDetokenizeResponse(response.records, response.requestId); - resolve(new DetokenizeResponse({ detokenizedFields: parsedResponse.success, errors: parsedResponse.errors })); + resolve(new DetokenizeResponse({ detokenizedFields: parsedResponse.success.length>0 ? parsedResponse.success : null, errors: parsedResponse.errors.length>0 ? parsedResponse.errors : null })); }) .catch(error => { reject(error); @@ -536,12 +547,12 @@ class VaultController { const fields = request.values.map((record: TokenizeRequestType) => ({ value: record.value, columnGroup: record.columnGroup })) as Array; const tokenizePayload: V1TokenizePayload = { tokenizationParameters: fields }; - this.handleRequest( + this.handleRequest>( (headers: Records.RequestOptions | undefined) => this.client.tokensAPI.recordServiceTokenize(this.client.vaultId, tokenizePayload,headers).withRawResponse(), TYPES.TOKENIZE ).then(response => { printLog(logs.infoLogs.TOKENIZE_SUCCESS, MessageType.LOG, this.client.getLogLevel()); - resolve(new TokenizeResponse({ tokens: response.records, errors: [] })) + resolve(new TokenizeResponse({ tokens: response.records, errors: null })) }) .catch(error => { reject(error); diff --git a/src/vault/model/options/deidentify-file/index.ts b/src/vault/model/options/deidentify-file/index.ts index 03a39170..b4cb0e7a 100644 --- a/src/vault/model/options/deidentify-file/index.ts +++ b/src/vault/model/options/deidentify-file/index.ts @@ -57,7 +57,7 @@ class DeidentifyFileOptions { this._tokenFormat = tokenFormat; } - getTransformations(): object | undefined{ + getTransformations(): Transformations | undefined{ return this._transformations; } diff --git a/src/vault/model/options/insert/index.ts b/src/vault/model/options/insert/index.ts index 14703bc2..9d0dfdcd 100644 --- a/src/vault/model/options/insert/index.ts +++ b/src/vault/model/options/insert/index.ts @@ -5,7 +5,7 @@ class InsertOptions { // Fields private returnTokens?: boolean; private upsert?: string; - private tokens?: Array; + private tokens?: Array>; private homogeneous?: boolean; private tokenMode?: TokenMode; private continueOnError?: boolean; @@ -22,7 +22,7 @@ class InsertOptions { this.upsert = upsert; } - setTokens(tokens: Array) { + setTokens(tokens: Array>) { this.tokens = tokens; } @@ -47,7 +47,7 @@ class InsertOptions { return this.upsert; } - getTokens(): Array | undefined { + getTokens(): Array> | undefined { return this.tokens; } diff --git a/src/vault/model/request/insert/index.ts b/src/vault/model/request/insert/index.ts index a97c46f9..575fcb2e 100644 --- a/src/vault/model/request/insert/index.ts +++ b/src/vault/model/request/insert/index.ts @@ -4,10 +4,10 @@ class InsertRequest { //fields private _tableName: string; - private _data: object[]; + private _data: Record[]; // Constructor - constructor(tableName: string, data: object[]) { + constructor(tableName: string, data: Record[]) { this._tableName = tableName; this._data = data; } @@ -23,12 +23,12 @@ class InsertRequest { } // Getter for _data - public get data(): object[] { + public get data(): Record[] { return this._data; } // Setter for _data - public set data(data: object[]) { + public set data(data: Record[]) { this._data = data; } diff --git a/src/vault/model/response/deidentify-text/index.ts b/src/vault/model/response/deidentify-text/index.ts index 6d370720..cecc1d3f 100644 --- a/src/vault/model/response/deidentify-text/index.ts +++ b/src/vault/model/response/deidentify-text/index.ts @@ -1,15 +1,17 @@ //imports +import { IndexRange } from "../../../types"; + class DeidentifyTextResponse { //fields processedText: string; entities: Array<{ token: string; value: string; - textIndex: object; - processedIndex: object; + textIndex: IndexRange; + processedIndex: IndexRange; entity: string; - scores: object; + scores: Record; }>; wordCount: number; charCount: number; @@ -24,10 +26,10 @@ class DeidentifyTextResponse { entities: Array<{ token: string; value: string; - textIndex: object; - processedIndex: object; + textIndex: IndexRange; + processedIndex: IndexRange; entity: string; - scores: object; + scores: Record; }>; wordCount: number; charCount: number; diff --git a/src/vault/model/response/delete/index.ts b/src/vault/model/response/delete/index.ts index b42fd70c..489384fe 100644 --- a/src/vault/model/response/delete/index.ts +++ b/src/vault/model/response/delete/index.ts @@ -1,14 +1,16 @@ //imports +import { SkyflowRecordError } from "../../../../utils"; + class DeleteResponse { //fields - deletedIds?: Array; + deletedIds: Array; - errors?: Object; + errors: Array | null; - constructor({ deletedIds, errors }: { deletedIds?: Array, errors?: object }) { + constructor({ deletedIds, errors }: { deletedIds: Array, errors: Array | null}) { this.deletedIds = deletedIds; this.errors = errors; } diff --git a/src/vault/model/response/detokenize/index.ts b/src/vault/model/response/detokenize/index.ts index 6c2f879b..99b94710 100644 --- a/src/vault/model/response/detokenize/index.ts +++ b/src/vault/model/response/detokenize/index.ts @@ -1,15 +1,16 @@ //imports +import { SkyflowRecordError } from "../../../../utils"; import { ErrorDetokenizeResponse, SuccessDetokenizeResponse } from "../../../types"; class DetokenizeResponse { //fields - detokenizedFields?: Array; + detokenizedFields: Array | null; - errors?: Array; + errors: Array | null; - constructor({ detokenizedFields, errors }: { detokenizedFields?: Array, errors?: Array }) { + constructor({ detokenizedFields, errors }: { detokenizedFields: Array | null, errors: Array | null }) { this.detokenizedFields = detokenizedFields; this.errors = errors; } diff --git a/src/vault/model/response/file-upload/index.ts b/src/vault/model/response/file-upload/index.ts index ba0bfd02..ce0ef2c8 100644 --- a/src/vault/model/response/file-upload/index.ts +++ b/src/vault/model/response/file-upload/index.ts @@ -1,13 +1,15 @@ //imports +import { SkyflowRecordError } from "../../../../utils"; + class FileUploadResponse { //fields - skyflowId?: string; + skyflowId: string; - errors?: Object; + errors: Array | null; - constructor({ skyflowId, errors }: { skyflowId?: string, errors?: object }) { + constructor({ skyflowId, errors }: { skyflowId: string, errors: Array | null }) { this.skyflowId = skyflowId; this.errors = errors; } diff --git a/src/vault/model/response/get/index.ts b/src/vault/model/response/get/index.ts index e0778f64..3a7c465f 100644 --- a/src/vault/model/response/get/index.ts +++ b/src/vault/model/response/get/index.ts @@ -1,15 +1,16 @@ //imports -import { insertResponseType } from "../../../types"; +import { SkyflowRecordError } from "../../../../utils"; +import { GetResponseData } from "../../../types"; class GetResponse { //fields - data?: Array; + data: Array; - errors?: object; + errors: Array | null; - constructor({ data, errors }: { data?: Array, errors?: object }) { + constructor({ data, errors }: { data: Array, errors: Array | null}) { this.data = data; this.errors = errors; } diff --git a/src/vault/model/response/insert/index.ts b/src/vault/model/response/insert/index.ts index 8b371064..f840eb13 100644 --- a/src/vault/model/response/insert/index.ts +++ b/src/vault/model/response/insert/index.ts @@ -1,14 +1,15 @@ //imports -import { insertResponseType } from "../../../types"; +import { SkyflowRecordError } from "../../../../utils"; +import { InsertResponseType } from "../../../types"; class InsertResponse { //fields - insertedFields: Array; + insertedFields: Array | null; - errors?: object; + errors: Array | null; - constructor({ insertedFields, errors }: { insertedFields: Array, errors?: object }) { + constructor({ insertedFields, errors }: { insertedFields: Array | null, errors: Array | null }) { this.insertedFields = insertedFields; this.errors = errors; } diff --git a/src/vault/model/response/invoke/invoke.ts b/src/vault/model/response/invoke/invoke.ts index a09cfbf1..66aab362 100644 --- a/src/vault/model/response/invoke/invoke.ts +++ b/src/vault/model/response/invoke/invoke.ts @@ -1,16 +1,17 @@ //imports -import { queryResponseType } from "../../../types"; +import { SkyflowRecordError } from "../../../../utils"; +import { QueryResponseType } from "../../../types"; class InvokeConnectionResponse { //fields data?: Object; - metadata?: Object; + metadata?: Record; - errors?: Object; + errors: Array | null; - constructor({ data, metadata, errors }: { data?: object, metadata?: Object, errors?: object }) { + constructor({ data, metadata, errors }: { data?: object, metadata?: Record, errors: Array | null }) { this.data = data; this.metadata = metadata; this.errors = errors; diff --git a/src/vault/model/response/query/index.ts b/src/vault/model/response/query/index.ts index cb8ac5b8..a67321ec 100644 --- a/src/vault/model/response/query/index.ts +++ b/src/vault/model/response/query/index.ts @@ -1,15 +1,16 @@ //imports -import { queryResponseType } from "../../../types"; +import { SkyflowRecordError } from "../../../../utils"; +import { QueryResponseType } from "../../../types"; class QueryResponse { //fields - fields?: Array; + fields: Array; - errors?: Object; + errors: Array | null; - constructor( { fields, errors }: { fields?: Array, errors?: object }) { + constructor( { fields, errors }: { fields: Array, errors: Array | null }) { this.fields = fields; this.errors = errors; } diff --git a/src/vault/model/response/tokenize/index.ts b/src/vault/model/response/tokenize/index.ts index 8f24006c..ea279e47 100644 --- a/src/vault/model/response/tokenize/index.ts +++ b/src/vault/model/response/tokenize/index.ts @@ -1,13 +1,15 @@ //imports +import { SkyflowRecordError } from "../../../../utils"; + class TokenizeResponse { //fields - tokens?: Array; + tokens: Array; - errors?: Object; + errors: Array | null; - constructor({ tokens, errors }: { tokens?: Array, errors?: object }) { + constructor({ tokens, errors }: { tokens: Array, errors: Array | null }) { this.tokens = tokens; this.errors = errors; } diff --git a/src/vault/model/response/update/index.ts b/src/vault/model/response/update/index.ts index 32d7a961..6696dffe 100644 --- a/src/vault/model/response/update/index.ts +++ b/src/vault/model/response/update/index.ts @@ -1,15 +1,16 @@ //imports -import { insertResponseType } from "../../../types"; +import { SkyflowRecordError } from "../../../../utils"; +import { InsertResponseType } from "../../../types"; class UpdateResponse { //fields - updatedField?: Array; + updatedField: InsertResponseType; - errors?: object; + errors: Array | null; - constructor({ updatedField, errors }: { updatedField?: Array, errors?: object }) { + constructor({ updatedField, errors }: { updatedField: InsertResponseType, errors: Array | null }) { this.updatedField = updatedField; this.errors = errors; } diff --git a/src/vault/types/index.ts b/src/vault/types/index.ts index ebde3819..3619bf80 100644 --- a/src/vault/types/index.ts +++ b/src/vault/types/index.ts @@ -1,4 +1,4 @@ -import { LogLevel, RedactionType } from "../../utils"; +import { LogLevel, RedactionType, SkyflowRecordError } from "../../utils"; import ConnectionConfig from "../config/connection"; import VaultConfig from "../config/vault" import Credentials from "../config/credentials"; @@ -27,15 +27,17 @@ export interface ClientObj { [vaultId: string]: ClientConfig; } -export interface insertResponseType { +export interface InsertResponseType { skyflowId: string; - [key: string]: string; + [key: string]: unknown; } -export interface queryResponseType { - skyflowId: string; - tokenizedData: insertResponseType; - [key: string]: string | insertResponseType; +export interface GetResponseData { + [key: string]: unknown; +} + +export interface QueryResponseType { + [key: string]: unknown; } export interface StringKeyValueMapType { @@ -60,7 +62,7 @@ export interface ErrorDetokenizeResponse { export interface ParsedDetokenizeResponse { success: SuccessDetokenizeResponse[]; - errors: ErrorDetokenizeResponse[]; + errors: SkyflowRecordError[]; } export interface ErrorInsertBatchResponse { @@ -70,8 +72,8 @@ export interface ErrorInsertBatchResponse { } export interface ParsedInsertBatchResponse { - success: insertResponseType[]; - errors: ErrorInsertBatchResponse[]; + success: InsertResponseType[]; + errors: SkyflowRecordError[]; } export interface DetokenizeData { @@ -138,3 +140,67 @@ export type ServiceAccountResponseError = { message: string; [key: string]: any; }; + +export interface RecordsResponse> { + records: T[]; + requestId: string; +} + +export interface DetectTextResponse { + records: T; + requestId: string; +} + +export interface DetectFileResponse { + data: T; + requestId: string; +} +export interface SkyflowIdResponse { + skyflow_id: string; +} + +export interface TokensResponse extends SkyflowIdResponse { + tokens?: Record; +} +export interface IndexRange { + start: number; + end: number; +} + +export type DeidentifyFileOutputProcessedFileType = + | "entities" + | "plaintext_transcription" + | "redacted_audio" + | "redacted_diarized_transcription" + | "redacted_file" + | "redacted_image" + | "redacted_medical_diarized_transcription" + | "redacted_medical_transcription" + | "redacted_text" + | "redacted_transcription"; + +export interface DeidentifyFileOutput { + processedFile?: string; + processedFileType?: DeidentifyFileOutputProcessedFileType; + processedFileExtension?: string; +} + +export type DeidentifyStatusResponseOutputType = "BASE64" | "EFS_PATH" | "UNKNOWN"; + +export type WordCharacterCount = { + wordCount?: number; + characterCount?: number; +} + +export interface DeidentifyFileDetectRunResponse { + status: "FAILED" | "IN_PROGRESS" | "SUCCESS"; + output: DeidentifyFileOutput[]; + outputType: DeidentifyStatusResponseOutputType; + message: string; + wordCharacterCount?: WordCharacterCount; + size?: number; + duration?: number; + pages?: number; + slides?: number; + runId?: string; +} diff --git a/test/vault/controller/detect.test.js b/test/vault/controller/detect.test.js index 30a53e0e..fbfa4ba2 100644 --- a/test/vault/controller/detect.test.js +++ b/test/vault/controller/detect.test.js @@ -514,7 +514,6 @@ describe('deidentifyFile', () => { expect(result.charCount).toBe(100); expect(result.sizeInKb).toBe(2048); expect(result.pageCount).toBe(2); - expect(result.runId).toBe('run123'); expect(result.status).toBe('SUCCESS'); }); @@ -695,7 +694,6 @@ describe('deidentifyFile', () => { expect(result.wordCount).toBe(8); expect(result.charCount).toBe(80); expect(result.sizeInKb).toBe(1024); - expect(result.runId).toBe('sheetRunId'); expect(result.status).toBe('SUCCESS'); }); @@ -744,7 +742,6 @@ describe('deidentifyFile', () => { expect(result.charCount).toBe(30); expect(result.sizeInKb).toBe(2048); expect(result.slideCount).toBe(5); - expect(result.runId).toBe('pptRunId'); expect(result.status).toBe('SUCCESS'); }); @@ -792,7 +789,6 @@ describe('deidentifyFile', () => { expect(result.wordCount).toBe(6); expect(result.charCount).toBe(60); expect(result.sizeInKb).toBe(512); - expect(result.runId).toBe('jsonRunId'); expect(result.status).toBe('SUCCESS'); }); @@ -841,7 +837,6 @@ describe('deidentifyFile', () => { expect(result.charCount).toBe(70); expect(result.sizeInKb).toBe(1024); expect(result.pageCount).toBe(1); - expect(result.runId).toBe('docRunId'); expect(result.status).toBe('SUCCESS'); }); @@ -936,7 +931,6 @@ describe('deidentifyFile', () => { expect(result.wordCount).toBe(4); expect(result.charCount).toBe(40); expect(result.sizeInKb).toBe(256); - expect(result.runId).toBe('genRunId'); expect(result.status).toBe('SUCCESS'); }); diff --git a/test/vault/controller/vault.test.js b/test/vault/controller/vault.test.js index 5fb54172..eb27e8ec 100644 --- a/test/vault/controller/vault.test.js +++ b/test/vault/controller/vault.test.js @@ -302,7 +302,7 @@ describe('VaultController insert method', () => { const response = await vaultController.insert(mockRequest, mockOptions); expect(mockVaultClient.vaultAPI.recordServiceBatchOperation).toHaveBeenCalled(); - expect(response.insertedFields).toStrictEqual([]); + expect(response.insertedFields).toBe(null); }); test('should reject insert records with batch insert', async () => { @@ -330,7 +330,7 @@ describe('VaultController insert method', () => { const response = await vaultController.insert(mockRequest, mockOptions); expect(mockVaultClient.vaultAPI.recordServiceBatchOperation).toHaveBeenCalled(); - expect(response.insertedFields).toStrictEqual([]); + expect(response.insertedFields).toStrictEqual(null); }); test('should handle validation errors', async () => { @@ -582,8 +582,8 @@ describe('VaultController detokenize method', () => { expect.anything(), // Detokenization payload expect.any(Object) // Headers ); - expect(response.detokenizedFields).toHaveLength(0); // Success responses - expect(response.errors).toHaveLength(0); // Error responses + expect(response.detokenizedFields).toBe(null); // Success responses + expect(response.errors).toBe(null); // Error responses }); test('should reject detokenize records with validation error', async () => { @@ -753,7 +753,7 @@ describe('VaultController delete method', () => { ); expect(response).toBeInstanceOf(DeleteResponse); expect(response.deletedIds).toHaveLength(1); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBe(null); }); test('should handle delete validation errors', async () => { @@ -809,7 +809,7 @@ describe('VaultController delete method', () => { const response = await vaultController.delete(mockRequest); expect(response.deletedIds).toHaveLength(0); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBe(null); }); test('should log and reject when API returns errors during delete', async () => { @@ -865,7 +865,7 @@ describe('VaultController tokenize method', () => { expect(mockVaultClient.tokensAPI.recordServiceTokenize).toHaveBeenCalled(); expect(response).toBeInstanceOf(TokenizeResponse); expect(response.tokens).toHaveLength(1); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBe(null); }); test('should handle validation errors', async () => { @@ -992,7 +992,7 @@ describe('VaultController query method', () => { expect(response.fields).toHaveLength(1); expect(response.fields[0].id).toBe('1'); expect(response.fields[0].tokenizedData.id).toBe('token123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBe(null); }); test('should successfully query records as null', async () => { @@ -1017,7 +1017,7 @@ describe('VaultController query method', () => { ); expect(response).toBeInstanceOf(QueryResponse); expect(response.fields).toHaveLength(0); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBe(null); }); test('should handle validation errors', async () => { @@ -1140,7 +1140,7 @@ describe('VaultController update method', () => { expect(response).toBeInstanceOf(UpdateResponse); expect(response.updatedField.skyflowId).toBe('id123'); expect(response.updatedField.field1).toBe('token123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully update record', async () => { @@ -1171,7 +1171,7 @@ describe('VaultController update method', () => { expect(response).toBeInstanceOf(UpdateResponse); expect(response.updatedField.skyflowId).toBe('id123'); expect(response.updatedField.field1).toBe('token123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully update record using enable tokens', async () => { const skyflowId = 'id123'; @@ -1205,7 +1205,7 @@ describe('VaultController update method', () => { expect(response).toBeInstanceOf(UpdateResponse); expect(response.updatedField.skyflowId).toBe('id123'); expect(response.updatedField.field1).toBe('token123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should handle validation errors', async () => { @@ -1355,7 +1355,7 @@ describe('VaultController uploadFile method', () => { expect(mockVaultClient.vaultAPI.fileServiceUploadFile).toHaveBeenCalled(); expect(response).toBeInstanceOf(FileUploadResponse); expect(response.skyflowId).toBe('id123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully upload file using base64', async () => { @@ -1384,7 +1384,7 @@ describe('VaultController uploadFile method', () => { expect(mockVaultClient.vaultAPI.fileServiceUploadFile).toHaveBeenCalled(); expect(response).toBeInstanceOf(FileUploadResponse); expect(response.skyflowId).toBe('id123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully upload file using fileObject', async () => { @@ -1413,7 +1413,7 @@ describe('VaultController uploadFile method', () => { expect(mockVaultClient.vaultAPI.fileServiceUploadFile).toHaveBeenCalled(); expect(response).toBeInstanceOf(FileUploadResponse); expect(response.skyflowId).toBe('id123'); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should handle validation errors during upload', async () => { @@ -1508,7 +1508,7 @@ describe('VaultController get method', () => { // Validate the response structure and content expect(response).toBeInstanceOf(GetResponse); expect(response.data).toEqual([{ field1: 'value1' }, { field2: 'value2' }]); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully get records for GetRequest with options', async () => { @@ -1539,7 +1539,7 @@ describe('VaultController get method', () => { // Validate the response structure and content expect(response).toBeInstanceOf(GetResponse); expect(response.data).toEqual([{ field1: 'value1' }, { field2: 'value2' }]); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should successfully get records for GetColumnRequest', async () => { @@ -1561,7 +1561,7 @@ describe('VaultController get method', () => { // Validate the response structure and content expect(response).toBeInstanceOf(GetResponse); expect(response.data).toEqual([{ field1: 'value1' }]); - expect(response.errors).toHaveLength(0); + expect(response.errors).toBeNull(); }); test('should handle validation errors for GetRequest', async () => {