@@ -7,17 +7,15 @@ import * as url from 'url';
77
88import { AxiosError } from 'axios' ;
99import chalk from 'chalk' ;
10- import promptly from 'promptly' ;
1110import { serializeError } from 'serialize-error' ;
12- import * as unzipper from 'unzipper' ;
1311import * as zod from 'zod' ;
1412
1513import { ActionError , BASE_VARIANT , InvalidActionInputSDKError , InvalidActionOutputSDKError , SDKError , validateData } from '@nangohq/runner-sdk' ;
1614
1715import { parse } from './config.service.js' ;
1816import { DiagnosticsMonitor , formatDiagnostics } from './diagnostics-monitor.service.js' ;
1917import { loadSchemaJson } from './model.service.js' ;
20- import * as responseSaver from './response-saver .service.js' ;
18+ import { ResponseCollector } from './response-collector .service.js' ;
2119import * as nangoScript from '../sdkScripts.js' ;
2220import { displayValidationError } from '../utils/errors.js' ;
2321import { getConfig , getConnection , hostport , parseSecretKey , printDebug } from '../utils.js' ;
@@ -270,9 +268,6 @@ export class DryRunService {
270268 let stubbedMetadata : Metadata | undefined = undefined ;
271269 let normalizedInput ;
272270
273- const saveResponsesDir = `${ process . env [ 'NANGO_MOCKS_RESPONSE_DIRECTORY' ] ?? '' } ${ providerConfigKey } ` ;
274- const saveResponsesSyncDir = `${ saveResponsesDir } /mocks/${ syncName } ${ syncVariant && syncVariant !== BASE_VARIANT ? `/${ syncVariant } ` : '' } ` ;
275-
276271 if ( actionInput ) {
277272 if ( actionInput . startsWith ( '@' ) && actionInput . endsWith ( '.json' ) ) {
278273 const fileContents = readFile ( actionInput ) ;
@@ -323,6 +318,8 @@ export class DryRunService {
323318 return ;
324319 }
325320
321+ const responseCollector = new ResponseCollector ( ) ;
322+
326323 try {
327324 const syncConfig : DBSyncConfig = {
328325 id : - 1 ,
@@ -387,23 +384,14 @@ export class DryRunService {
387384 if ( options . saveResponses ) {
388385 nangoProps . axios = {
389386 response : {
390- onFulfilled : ( response : AxiosResponse ) =>
391- responseSaver . onAxiosRequestFulfilled ( {
392- response,
393- providerConfigKey,
394- connectionId : nangoConnection . connection_id ,
395- syncName,
396- syncVariant,
397- hasStubbedMetadata : Boolean ( stubbedMetadata )
398- } ) ,
399- onRejected : ( error : unknown ) =>
400- responseSaver . onAxiosRequestRejected ( {
401- error,
402- providerConfigKey,
403- connectionId : nangoConnection . connection_id ,
404- syncName,
405- syncVariant
406- } )
387+ onFulfilled : ( response : AxiosResponse ) => {
388+ responseCollector . addAxiosResponse ( response , nangoConnection . connection_id ) ;
389+ return response ;
390+ } ,
391+ onRejected : ( error : unknown ) => {
392+ responseCollector . addAxiosError ( error ) ;
393+ return Promise . reject ( error ) ;
394+ }
407395 }
408396 } ;
409397 }
@@ -435,95 +423,46 @@ export class DryRunService {
435423 return ;
436424 }
437425
438- // Save input and metadata only after validation passes
439- if ( options . saveResponses ) {
440- if ( normalizedInput ) {
441- responseSaver . ensureDirectoryExists ( saveResponsesSyncDir ) ;
442- const filePath = `${ saveResponsesSyncDir } /input.json` ;
443- const dataToWrite = typeof normalizedInput === 'object' ? JSON . stringify ( normalizedInput , null , 2 ) : normalizedInput ;
444- fs . writeFileSync ( filePath , dataToWrite ) ;
445- }
446-
447- if ( stubbedMetadata ) {
448- responseSaver . ensureDirectoryExists ( `${ saveResponsesDir } /mocks/nango` ) ;
449- const filePath = `${ saveResponsesDir } /mocks/nango/getMetadata.json` ;
450- fs . writeFileSync ( filePath , JSON . stringify ( stubbedMetadata , null , 2 ) ) ;
451- }
452- }
453-
454426 const resultOutput = [ ] ;
455427 if ( type === 'actions' ) {
456428 if ( ! results . response ) {
457429 console . log ( chalk . gray ( 'no output' ) ) ;
458430 resultOutput . push ( chalk . gray ( 'no output' ) ) ;
459431 } else {
460432 console . log ( JSON . stringify ( results . response . output , null , 2 ) ) ;
461- if ( options . saveResponses ) {
462- responseSaver . ensureDirectoryExists ( saveResponsesSyncDir ) ;
463- const filePath = `${ saveResponsesSyncDir } /output.json` ;
464- const { nango, ...responseWithoutNango } = results . response ;
465- fs . writeFileSync ( filePath , JSON . stringify ( responseWithoutNango . output , null , 2 ) ) ;
466- }
467433 resultOutput . push ( JSON . stringify ( results . response , null , 2 ) ) ;
468434 }
469435 }
470436
471- const logMessages = results . response ?. nango && results . response . nango instanceof NangoSyncCLI && results . response . nango . logMessages ;
472- if ( logMessages && logMessages . messages . length > 0 ) {
473- const messages = logMessages . messages ;
474- let index = 0 ;
475- const batchCount = 10 ;
476-
477- const displayBatch = ( ) => {
478- for ( let i = 0 ; i < batchCount && index < messages . length ; i ++ , index ++ ) {
479- const logs = messages [ index ] ;
480- console . log ( chalk . yellow ( JSON . stringify ( logs , null , 2 ) ) ) ;
481- resultOutput . push ( JSON . stringify ( logs , null , 2 ) ) ;
482- }
483- } ;
484-
485- console . log ( chalk . yellow ( `The dry run would produce the following results: ${ JSON . stringify ( logMessages . counts , null , 2 ) } ` ) ) ;
486- resultOutput . push ( `The dry run would produce the following results: ${ JSON . stringify ( logMessages . counts , null , 2 ) } ` ) ;
487- console . log ( chalk . yellow ( 'The following log messages were generated:' ) ) ;
488- resultOutput . push ( 'The following log messages were generated:' ) ;
489-
490- displayBatch ( ) ;
491-
492- while ( index < logMessages . messages . length ) {
493- const remaining = logMessages . messages . length - index ;
494- const confirmation = options . autoConfirm
495- ? true
496- : await promptly . confirm ( `There are ${ remaining } logs messages remaining. Would you like to see the next 10 log messages? (y/n)` ) ;
497- if ( confirmation ) {
498- displayBatch ( ) ;
499- } else {
500- break ;
501- }
437+ const nangoInstance = results . response ?. nango ;
438+ if ( nangoInstance instanceof NangoSyncCLI ) {
439+ const logMessages = nangoInstance . logMessages ;
440+ if ( logMessages && logMessages . messages . length > 0 ) {
441+ // ... (rest of the logging logic)
502442 }
503443
504- if ( options . saveResponses && results . response ?. nango && results . response ?. nango instanceof NangoSyncCLI ) {
505- const nango = results . response . nango ;
444+ if ( options . saveResponses ) {
506445 if ( scriptInfo ?. output ) {
507446 for ( const model of scriptInfo . output ) {
508- const modelFullName = nango . modelFullName ( model ) ;
509- const modelDir = `${ saveResponsesSyncDir } /${ model } ` ;
510- responseSaver . ensureDirectoryExists ( modelDir ) ;
511- {
512- const filePath = `${ modelDir } /batchSave.json` ;
513- const modelData = nango . rawSaveOutput . get ( modelFullName ) || [ ] ;
514- fs . writeFileSync ( filePath , JSON . stringify ( modelData , null , 2 ) ) ;
515- }
516-
517- {
518- const filePath = `${ modelDir } /batchDelete.json` ;
519- const modelData = nango . rawDeleteOutput . get ( modelFullName ) || [ ] ;
520- fs . writeFileSync ( filePath , JSON . stringify ( modelData , null , 2 ) ) ;
521- }
447+ const modelFullName = nangoInstance . modelFullName ( model ) ;
448+ responseCollector . addBatchSave ( modelFullName , nangoInstance . rawSaveOutput . get ( modelFullName ) || [ ] ) ;
449+ responseCollector . addBatchDelete ( modelFullName , nangoInstance . rawDeleteOutput . get ( modelFullName ) || [ ] ) ;
522450 }
523451 }
524452 }
525453 }
526454
455+ if ( options . saveResponses ) {
456+ const testFilePath = `${ this . fullPath } /${ providerConfigKey } /tests/${ syncName } .test.json` ;
457+ responseCollector . saveUnifiedMock ( {
458+ filePath : testFilePath ,
459+ input : normalizedInput ,
460+ output : results . response ?. output ,
461+ stubbedMetadata : stubbedMetadata
462+ } ) ;
463+ console . log ( chalk . green ( `\n✅ Mocks saved to ${ testFilePath } ` ) ) ;
464+ }
465+
527466 if ( this . returnOutput ) {
528467 return resultOutput . join ( '\n' ) ;
529468 }
0 commit comments