diff --git a/src/index.new.test.ts b/src/index.new.test.ts index 62b0713..83733ed 100644 --- a/src/index.new.test.ts +++ b/src/index.new.test.ts @@ -88,9 +88,6 @@ describe('Core Index Tests', () => { test('startSyncJob', () => { expect(j1).toHaveProperty('startSyncJob'); }); - test('uploadGraphObjectsForDeleteSyncJob', () => { - expect(j1).toHaveProperty('uploadGraphObjectsForDeleteSyncJob'); - }); test('uploadGraphObjectsForSyncJob', () => { expect(j1).toHaveProperty('uploadGraphObjectsForSyncJob'); }); @@ -103,9 +100,6 @@ describe('Core Index Tests', () => { test('bulkUpload', () => { expect(j1).toHaveProperty('bulkUpload'); }); - test('bulkDelete', () => { - expect(j1).toHaveProperty('bulkDelete'); - }); test('--api-base-url properly sets URLs', () => { const jupiterOneCustomURLClient = new JupiterOneClient({ @@ -273,7 +267,7 @@ describe('Core Index Tests', () => { const argumentOne = { syncJobOptions: { scope: 'an_example_scope', - syncMode: SyncJobModes.CREATE_OR_UPDATE, + syncMode: 'DIFF', }, entities: [exampleEntity], }; @@ -287,7 +281,7 @@ describe('Core Index Tests', () => { const expectedArgument = { source: SyncJobSources.API, scope: 'an_example_scope', - syncMode: SyncJobModes.CREATE_OR_UPDATE, + syncMode: 'DIFF', }; expect(j1.startSyncJob).toHaveBeenCalledWith(expectedArgument); diff --git a/src/index.ts b/src/index.ts index 1f62e2c..20f1edc 100644 --- a/src/index.ts +++ b/src/index.ts @@ -13,9 +13,7 @@ import Logger, { createLogger } from 'bunyan-category'; import { networkRequest } from './networkRequest'; import { - Entity, EntityForSync, - Relationship, RelationshipForSync, IntegrationDefinition, ListIntegrationDefinitions, @@ -74,8 +72,10 @@ export class FetchError extends Error { nameForLogging?: string; }) { super( - `JupiterOne API error. Response not OK (requestName=${options.nameForLogging || '(none)' - }, status=${options.response.status}, url=${options.url}, method=${options.method + `JupiterOne API error. Response not OK (requestName=${ + options.nameForLogging || '(none)' + }, status=${options.response.status}, url=${options.url}, method=${ + options.method }). Response: ${options.responseBody}`, ); this.httpStatusCode = options.response.status; @@ -252,7 +252,6 @@ export enum SyncJobSources { export enum SyncJobModes { DIFF = 'DIFF', - CREATE_OR_UPDATE = 'CREATE_OR_UPDATE', } export type SyncJobResponse = { @@ -363,7 +362,6 @@ export class JupiterOneClient { */ startPage = 0, ) { - let cursor: string; let complete = false; let results: any[] = []; @@ -379,9 +377,9 @@ export class JupiterOneClient { query: j1ql, deferredResponse: 'FORCE', flags: { - variableResultSize: true + variableResultSize: true, }, - cursor + cursor, }, ...options, }); @@ -396,7 +394,8 @@ export class JupiterOneClient { do { if (Date.now() - startTimeInMs > QUERY_RESULTS_TIMEOUT) { throw new Error( - `Exceeded request timeout of ${QUERY_RESULTS_TIMEOUT / 1000 + `Exceeded request timeout of ${ + QUERY_RESULTS_TIMEOUT / 1000 } seconds.`, ); } @@ -408,27 +407,31 @@ export class JupiterOneClient { } while (status === JobStatus.IN_PROGRESS); if (status === JobStatus.FAILED) { - throw new Error(`JupiterOne returned error(s) for query: '${statusFile.error}'`); + throw new Error( + `JupiterOne returned error(s) for query: '${statusFile.error}'`, + ); } const result = statusFile.data; if (showProgress && !limitCheck) { if (results.length === 0) { - progress = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic); + progress = new cliProgress.SingleBar( + {}, + cliProgress.Presets.shades_classic, + ); progress.start(Number(statusFile.totalCount), 0); } progress.update(results.length); } if (result) { - results = results.concat(result) + results = results.concat(result); } if (status === JobStatus.COMPLETED && (cursor == null || limitCheck)) { complete = true; } - } while (complete === false); return results; } @@ -866,38 +869,6 @@ export class JupiterOneClient { return validateSyncJobResponse(response); } - async uploadGraphObjectsForDeleteSyncJob(options: { - syncJobId: string; - entities?: Entity[]; - relationships?: Relationship[]; - }): Promise { - const upload: GraphObjectDeletionPayload = { - deleteEntities: [], - deleteRelationships: [], - }; - for (const e of options.entities || []) { - upload.deleteEntities.push({ _id: e?.['_id'] }); - } - - for (const r of options.relationships || []) { - upload.deleteRelationships.push({ _id: r?.['_id'] }); - } - - this.logger.trace(upload, 'Full upload of deletion sync job'); - this.logger.info('uploading deletion sync job'); - const headers = this.headers; - const response = await makeFetchRequest( - this.apiUrl + - `/persister/synchronization/jobs/${options.syncJobId}/upload`, - { - method: 'POST', - headers, - body: JSON.stringify(upload), - }, - ); - return validateSyncJobResponse(response); - } - async uploadGraphObjectsForSyncJob(options: { syncJobId: string; entities?: EntityForSync[]; @@ -905,18 +876,37 @@ export class JupiterOneClient { }): Promise { const { syncJobId, entities, relationships } = options; const headers = this.headers; - const response = await makeFetchRequest( - this.apiUrl + `/persister/synchronization/jobs/${syncJobId}/upload`, - { - method: 'POST', - headers, - body: JSON.stringify({ - entities, - relationships, - }), - }, - ); - return validateSyncJobResponse(response); + let response: SyncJobResponse | undefined = undefined; + if (entities.length) { + const entitiesResponse = await makeFetchRequest( + this.apiUrl + `/persister/synchronization/jobs/${syncJobId}/entities`, + { + method: 'POST', + headers, + body: JSON.stringify({ + entities, + }), + }, + ); + response = await validateSyncJobResponse(entitiesResponse); + } + + if (relationships.length) { + const relationshipsResponse = await makeFetchRequest( + this.apiUrl + + `/persister/synchronization/jobs/${syncJobId}/relationships`, + { + method: 'POST', + headers, + body: JSON.stringify({ + relationships, + }), + }, + ); + + response = await validateSyncJobResponse(relationshipsResponse); + } + return response; } async finalizeSyncJob(options: { @@ -1031,29 +1021,4 @@ export class JupiterOneClient { finalizeResult, }; } - - async bulkDelete(data: { - entities?: Entity[]; - relationships?: Relationship[]; - }): Promise { - if (data.entities || data.relationships) { - const { job: syncJob } = await this.startSyncJob({ - source: SyncJobSources.API, - syncMode: SyncJobModes.CREATE_OR_UPDATE, - }); - const syncJobId = syncJob.id; - await this.uploadGraphObjectsForDeleteSyncJob({ - syncJobId, - entities: data.entities, - relationships: data.relationships, - }); - const finalizeResult = await this.finalizeSyncJob({ syncJobId }); - return { - syncJobId, - finalizeResult, - }; - } else { - this.logger.info('No entities or relationships to upload.'); - } - } }