{"version":3,"file":"impl-Ca064LmU.mjs","names":[],"sources":["../src/lib/oneTrust/helpers/oneTrustAssessmentToJson.ts","../src/lib/oneTrust/helpers/syncOneTrustAssessmentToDisk.ts","../src/lib/oneTrust/endpoints/getListOfOneTrustAssessments.ts","../src/lib/oneTrust/endpoints/getOneTrustAssessment.ts","../src/lib/oneTrust/endpoints/getOneTrustRisk.ts","../src/lib/oneTrust/endpoints/getOneTrustUser.ts","../src/lib/oneTrust/helpers/enrichOneTrustAssessment.ts","../src/lib/oneTrust/helpers/syncOneTrustAssessmentToTranscend.ts","../src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromOneTrust.ts","../src/lib/oneTrust/helpers/syncOneTrustAssessmentsFromFile.ts","../src/lib/oneTrust/createOneTrustGotInstance.ts","../src/commands/migration/sync-ot/impl.ts"],"sourcesContent":["import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types';\n\n/**\n * Converts the assessment into a json entry.\n *\n * @param param - information about the assessment and amount of entries\n * @returns a stringified json entry ready to be appended to a file\n */\nexport const oneTrustAssessmentToJson = ({\n  assessment,\n  index,\n  total,\n  wrap = true,\n}: {\n  /** The assessment to convert */\n  assessment: OneTrustEnrichedAssessment;\n  /** The position of the assessment in the final Json object */\n  index: number;\n  /** The total amount of the assessments in the final Json object */\n  total?: number;\n  /** Whether to wrap every entry in brackets */\n  wrap?: boolean;\n}): string => {\n  let jsonEntry = '';\n  // start with an opening bracket\n  if (index === 0 || wrap) {\n    jsonEntry = '[\\n';\n  }\n\n  const stringifiedAssessment = JSON.stringify(assessment);\n\n  // Add comma for all items except the last one\n  const comma = total && index < total - 1 && !wrap ? ',' : '';\n\n  // write to file\n  jsonEntry = `${jsonEntry + stringifiedAssessment + comma}\\n`;\n\n  // end with closing bracket\n  if ((total && index === total - 1) || wrap) {\n    jsonEntry += '\\n]';\n  }\n\n  return jsonEntry;\n};\n","import fs from 'node:fs';\n\nimport { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types';\nimport colors from 'colors';\n\nimport { logger } from '../../../logger.js';\nimport { oneTrustAssessmentToJson } from './oneTrustAssessmentToJson.js';\n\n/**\n * Write the assessment to disk at the specified file path.\n *\n *\n * @param param - information about the assessment to write\n */\nexport const syncOneTrustAssessmentToDisk = ({\n  file,\n  assessment,\n  index,\n  total,\n}: {\n  /** The file path to write the assessment to */\n  file: string;\n  /** The basic assessment */\n  assessment: OneTrustEnrichedAssessment;\n  /** The index of the assessment being written to the file */\n  index: number;\n  /** The total amount of assessments that we will write */\n  total: number;\n}): void => {\n  logger.info(\n    colors.magenta(`Writing enriched assessment ${index + 1} of ${total} to file \"${file}\"...`),\n  );\n\n  if (index === 0) {\n    fs.writeFileSync(\n      file,\n      oneTrustAssessmentToJson({\n        assessment,\n        index,\n        total,\n        wrap: false,\n      }),\n    );\n  } else {\n    fs.appendFileSync(\n      file,\n      oneTrustAssessmentToJson({\n        assessment,\n        index,\n        total,\n        wrap: false,\n      }),\n    );\n  }\n};\n","import {\n  OneTrustAssessment,\n  OneTrustGetListOfAssessmentsResponse,\n} from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { Got } from 'got';\n\nimport { logger } from '../../../logger.js';\n\n/**\n * Fetch a list of all assessments from the OneTrust client.\n * ref: https://developer.onetrust.com/onetrust/reference/getallassessmentbasicdetailsusingget\n *\n * @param param - the information about the OneTrust client\n * @returns a list of OneTrustAssessment\n */\nexport const getListOfOneTrustAssessments = async ({\n  oneTrust,\n}: {\n  /** The OneTrust client instance */\n  oneTrust: Got;\n}): Promise<OneTrustAssessment[]> => {\n  let currentPage = 0;\n  let totalPages = 1;\n  let totalElements = 0;\n\n  const allAssessments: OneTrustAssessment[] = [];\n\n  while (currentPage < totalPages) {\n    const { body } = await oneTrust.get(\n      `api/assessment/v2/assessments?page=${currentPage}&size=2000`,\n    );\n\n    const { page, content } = decodeCodec(OneTrustGetListOfAssessmentsResponse, body);\n    allAssessments.push(...(content ?? []));\n    if (currentPage === 0) {\n      totalPages = page?.totalPages ?? 0;\n      totalElements = page?.totalElements ?? 0;\n    }\n    currentPage += 1;\n\n    // log progress\n    logger.info(`Fetched ${allAssessments.length} of ${totalElements} assessments.`);\n  }\n\n  return allAssessments;\n};\n","import { OneTrustGetAssessmentResponse } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { Got } from 'got';\n\n/**\n * Retrieve details about a particular assessment.\n * ref: https://developer.onetrust.com/onetrust/reference/exportassessmentusingget\n *\n * @param param - the information about the OneTrust client and assessment to retrieve\n * @returns details about the assessment\n */\nexport const getOneTrustAssessment = async ({\n  oneTrust,\n  assessmentId,\n}: {\n  /** The OneTrust client instance */\n  oneTrust: Got;\n  /** The ID of the assessment to retrieve */\n  assessmentId: string;\n}): Promise<OneTrustGetAssessmentResponse> => {\n  const { body } = await oneTrust.get(\n    `api/assessment/v2/assessments/${assessmentId}/export?ExcludeSkippedQuestions=false`,\n  );\n\n  return decodeCodec(OneTrustGetAssessmentResponse, body);\n};\n","import { OneTrustGetRiskResponse } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { Got } from 'got';\n\n/**\n * Retrieve details about a particular risk.\n * ref: https://developer.onetrust.com/onetrust/reference/getriskusingget\n *\n * @param param - the information about the OneTrust client and risk to retrieve\n * @returns the OneTrust risk\n */\nexport const getOneTrustRisk = async ({\n  oneTrust,\n  riskId,\n}: {\n  /** The OneTrust client instance */\n  oneTrust: Got;\n  /** The ID of the OneTrust risk to retrieve */\n  riskId: string;\n}): Promise<OneTrustGetRiskResponse> => {\n  const { body } = await oneTrust.get(`api/risk/v2/risks/${riskId}`);\n\n  return decodeCodec(OneTrustGetRiskResponse, body);\n};\n","import { OneTrustGetUserResponse } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport { Got } from 'got';\n\n/**\n * Retrieve details about a particular user.\n * ref: https://developer.onetrust.com/onetrust/reference/getriskusingget\n *\n * @param param - the information about the OneTrust client and risk to retrieve\n * @returns the OneTrust risk\n */\nexport const getOneTrustUser = async ({\n  oneTrust,\n  userId,\n}: {\n  /** The OneTrust client instance */\n  oneTrust: Got;\n  /** The ID of the OneTrust user to retrieve */\n  userId: string;\n}): Promise<OneTrustGetUserResponse> => {\n  const { body } = await oneTrust.get(`api/scim/v2/Users/${userId}`);\n\n  return decodeCodec(OneTrustGetUserResponse, body);\n};\n","import {\n  OneTrustAssessment,\n  OneTrustEnrichedAssessment,\n  OneTrustGetAssessmentResponse,\n  OneTrustGetRiskResponse,\n  OneTrustGetUserResponse,\n} from '@transcend-io/privacy-types';\nimport { keyBy } from 'lodash-es';\n\n/**\n * Merge the assessment, assessmentDetails, and riskDetails into one object.\n *\n * @param param - the assessment and risk information\n * @returns the assessment enriched with details and risk information\n */\nexport const enrichOneTrustAssessment = ({\n  assessment,\n  assessmentDetails,\n  riskDetails,\n  creatorDetails,\n  approversDetails,\n  respondentsDetails,\n}: {\n  /** The OneTrust risk details */\n  riskDetails: OneTrustGetRiskResponse[];\n  /** The OneTrust assessment as returned from Get List of Assessments endpoint */\n  assessment: OneTrustAssessment;\n  /** The OneTrust assessment details */\n  assessmentDetails: OneTrustGetAssessmentResponse;\n  /** The OneTrust assessment creator details */\n  creatorDetails: OneTrustGetUserResponse;\n  /** The OneTrust assessment approvers details */\n  approversDetails: OneTrustGetUserResponse[];\n  /** The OneTrust assessment internal respondents details */\n  respondentsDetails: OneTrustGetUserResponse[];\n}): OneTrustEnrichedAssessment => {\n  const riskDetailsById = keyBy(riskDetails, 'id');\n  const { sections, createdBy, ...restAssessmentDetails } = assessmentDetails;\n  const sectionsWithEnrichedRisk = sections.map((section) => {\n    const { questions, ...restSection } = section;\n    const enrichedQuestions = questions.map((question) => {\n      const { risks, ...restQuestion } = question;\n      const enrichedRisks = (risks ?? []).map((risk) => {\n        const details = riskDetailsById[risk.riskId];\n        return {\n          ...risk,\n          ...details,\n          level: risk.level,\n          impactLevel: risk.impactLevel ?? 0,\n        };\n      });\n      return {\n        ...restQuestion,\n        risks: enrichedRisks,\n      };\n    });\n    return {\n      ...restSection,\n      questions: enrichedQuestions,\n    };\n  });\n\n  // grab creator details\n  const enrichedCreatedBy = {\n    ...createdBy,\n    active: creatorDetails?.active ?? false,\n    userType: creatorDetails?.userType ?? 'Internal',\n    emails: creatorDetails?.emails ?? [],\n    title: creatorDetails?.title ?? null,\n    givenName: creatorDetails?.name.givenName ?? null,\n    familyName: creatorDetails?.name.familyName ?? null,\n  };\n\n  // grab approvers details\n  const approverDetailsById = keyBy(approversDetails, 'id');\n  const enrichedApprovers = assessmentDetails.approvers.flatMap((originalApprover) =>\n    approverDetailsById[originalApprover.id]\n      ? [\n          {\n            ...originalApprover,\n            approver: {\n              ...originalApprover.approver,\n              active: approverDetailsById[originalApprover.id].active,\n              userType: approverDetailsById[originalApprover.id].userType,\n              emails: approverDetailsById[originalApprover.id].emails,\n              title: approverDetailsById[originalApprover.id].title,\n              givenName: approverDetailsById[originalApprover.id].name.givenName ?? null,\n              familyName: approverDetailsById[originalApprover.id].name.familyName ?? null,\n            },\n          },\n        ]\n      : [],\n  );\n\n  // grab respondents details\n  const respondentsDetailsById = keyBy(respondentsDetails, 'id');\n  const enrichedRespondents = assessmentDetails.respondents\n    .filter((r) => !r.name.includes('@')) // search only internal respondents\n    .flatMap((respondent) =>\n      respondentsDetailsById[respondent.id]\n        ? [\n            {\n              ...respondent,\n              active: respondentsDetailsById[respondent.id].active,\n              userType: respondentsDetailsById[respondent.id].userType,\n              emails: respondentsDetailsById[respondent.id].emails,\n              title: respondentsDetailsById[respondent.id].title,\n              givenName: respondentsDetailsById[respondent.id].name.givenName ?? null,\n              familyName: respondentsDetailsById[respondent.id].name.familyName ?? null,\n            },\n          ]\n        : [],\n    );\n\n  // combine everything into a single enriched assessment\n  return {\n    ...assessment,\n    ...restAssessmentDetails,\n    approvers: enrichedApprovers,\n    respondents: enrichedRespondents,\n    createdBy: enrichedCreatedBy,\n    sections: sectionsWithEnrichedRisk,\n  };\n};\n","import { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types';\nimport { makeGraphQLRequest, IMPORT_ONE_TRUST_ASSESSMENT_FORMS } from '@transcend-io/sdk';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\n\nimport { ImportOnetrustAssessmentsInput } from '../../../codecs.js';\nimport { logger } from '../../../logger.js';\nimport { oneTrustAssessmentToJson } from './oneTrustAssessmentToJson.js';\n\nexport interface AssessmentForm {\n  /** ID of Assessment Form */\n  id: string;\n  /** Title of Assessment Form */\n  name: string;\n}\n\n/**\n * Write the assessment to a Transcend instance.\n *\n *\n * @param param - information about the assessment and Transcend instance to write to\n */\nexport const syncOneTrustAssessmentToTranscend = async ({\n  transcend,\n  assessment,\n  total,\n  index,\n}: {\n  /** the Transcend client instance */\n  transcend: GraphQLClient;\n  /** the assessment to sync to Transcend */\n  assessment: OneTrustEnrichedAssessment;\n  /** The index of the assessment being written to the file */\n  index: number;\n  /** The total amount of assessments that we will write */\n  total?: number;\n}): Promise<void> => {\n  logger.info(\n    colors.magenta(\n      `Writing enriched assessment ${index + 1} ${total ? `of ${total} ` : ' '}to Transcend...`,\n    ),\n  );\n\n  // convert the OneTrust assessment object into a json record\n  const json = oneTrustAssessmentToJson({\n    assessment,\n    index,\n    total,\n  });\n\n  // transform the json record into a valid input to the mutation\n  const input: ImportOnetrustAssessmentsInput = {\n    json,\n  };\n\n  try {\n    await makeGraphQLRequest<{\n      /** the importOneTrustAssessmentForms mutation */\n      importOneTrustAssessmentForms: {\n        /** Created Assessment Forms */\n        assessmentForms: AssessmentForm[];\n      };\n    }>(transcend, IMPORT_ONE_TRUST_ASSESSMENT_FORMS, {\n      variables: { input },\n      logger,\n    });\n  } catch (error) {\n    logger.error(\n      colors.red(\n        `Failed to sync assessment ${index + 1} ${total ? `of ${total} ` : ' '}to Transcend.\\n` +\n          `\\tAssessment Title: ${assessment.name}. Template Title: ${assessment.template.name}\\n`,\n      ),\n      error,\n    );\n  }\n};\n","import {\n  OneTrustAssessmentQuestion,\n  OneTrustAssessmentSection,\n  OneTrustEnrichedAssessment,\n  OneTrustGetRiskResponse,\n  OneTrustGetUserResponse,\n} from '@transcend-io/privacy-types';\nimport { mapSeries, map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport type { Got } from 'got';\nimport { GraphQLClient } from 'graphql-request';\nimport { uniq } from 'lodash-es';\n\nimport { logger } from '../../../logger.js';\nimport {\n  getListOfOneTrustAssessments,\n  getOneTrustAssessment,\n  getOneTrustRisk,\n  getOneTrustUser,\n} from '../endpoints/index.js';\nimport { enrichOneTrustAssessment } from './enrichOneTrustAssessment.js';\nimport { syncOneTrustAssessmentToDisk } from './syncOneTrustAssessmentToDisk.js';\nimport { syncOneTrustAssessmentToTranscend } from './syncOneTrustAssessmentToTranscend.js';\n\nexport interface AssessmentForm {\n  /** ID of Assessment Form */\n  id: string;\n  /** Title of Assessment Form */\n  name: string;\n}\n\n/**\n * Reads all the assessments from a OneTrust instance and syncs them to Transcend or to Disk.\n *\n * @param param - the information about the assessment, its OneTrust source, and destination (disk or Transcend)\n */\nexport const syncOneTrustAssessmentsFromOneTrust = async ({\n  oneTrust,\n  file,\n  dryRun,\n  transcend,\n}: {\n  /** the OneTrust client instance */\n  oneTrust: Got;\n  /** the Transcend client instance */\n  transcend?: GraphQLClient;\n  /** Whether to write to file instead of syncing to Transcend */\n  dryRun: boolean;\n  /** the path to the file in case dryRun is true */\n  file?: string;\n}): Promise<void> => {\n  // fetch the list of all assessments in the OneTrust organization\n  logger.info('Getting list of all assessments from OneTrust...');\n  const assessments = await getListOfOneTrustAssessments({ oneTrust });\n\n  // a cache of OneTrust users so we avoid requesting already fetched users\n  const oneTrustCachedUsers: Record<string, OneTrustGetUserResponse> = {};\n\n  // split all assessments in batches, so we can process some of steps in parallel\n  const BATCH_SIZE = 5;\n  const assessmentBatches = Array.from(\n    {\n      length: Math.ceil(assessments.length / BATCH_SIZE),\n    },\n    (_, i) => assessments.slice(i * BATCH_SIZE, (i + 1) * BATCH_SIZE),\n  );\n\n  // process each batch and sync the batch right away so it's garbage collected and we don't run out of memory\n  await mapSeries(assessmentBatches, async (assessmentBatch, batch) => {\n    const batchEnrichedAssessments: OneTrustEnrichedAssessment[] = [];\n\n    // fetch assessment details from OneTrust in parallel\n    await map(\n      assessmentBatch,\n      async (assessment, index) => {\n        const assessmentNumber = BATCH_SIZE * batch + index + 1;\n        logger.info(\n          `[assessment ${assessmentNumber} of ${assessments.length}]: fetching details...`,\n        );\n        const { templateName, assessmentId } = assessment;\n        const assessmentDetails = await getOneTrustAssessment({\n          oneTrust,\n          assessmentId,\n        });\n        // fetch assessment's creator information\n        const creatorId = assessmentDetails.createdBy.id;\n        let creator = oneTrustCachedUsers[creatorId];\n        if (!creator) {\n          logger.info(\n            `[assessment ${assessmentNumber} of ${assessments.length}]: fetching creator...`,\n          );\n          try {\n            creator = await getOneTrustUser({\n              oneTrust,\n              userId: creatorId,\n            });\n            oneTrustCachedUsers[creatorId] = creator;\n          } catch (error) {\n            logger.warn(\n              colors.yellow(\n                `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch form creator.` +\n                  `\\tcreatorId: ${creatorId}. Assessment Title: ${assessment.name}. Template Title: ${templateName}`,\n              ),\n              error,\n            );\n          }\n        }\n\n        // fetch assessment approvers information\n        const { approvers } = assessmentDetails;\n        let approversDetails: OneTrustGetUserResponse[][] = [];\n        if (approvers.length > 0) {\n          logger.info(\n            `[assessment ${assessmentNumber} of ${assessments.length}]: fetching approvers...`,\n          );\n          approversDetails = await map(\n            approvers.map(({ id }) => id),\n            async (userId) => {\n              try {\n                let approver = oneTrustCachedUsers[userId];\n                if (!approver) {\n                  approver = await getOneTrustUser({ oneTrust, userId });\n                  oneTrustCachedUsers[userId] = approver;\n                }\n                return [approver];\n              } catch (error) {\n                logger.warn(\n                  colors.yellow(\n                    `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch a form approver.` +\n                      `\\tapproverId: ${userId}. Assessment Title: ${assessment.name}. Template Title: ${templateName}`,\n                  ),\n                  error,\n                );\n                return [];\n              }\n            },\n            { concurrency: 5 },\n          );\n        }\n\n        // fetch assessment internal respondents information\n        const { respondents } = assessmentDetails;\n        // if a user is an internal respondents, their 'name' field can't be an email.\n        const internalRespondents = respondents.filter((r) => !r.name.includes('@'));\n        let respondentsDetails: OneTrustGetUserResponse[][] = [];\n        if (internalRespondents.length > 0) {\n          logger.info(\n            `[assessment ${assessmentNumber} of ${assessments.length}]: fetching respondents...`,\n          );\n          respondentsDetails = await map(\n            internalRespondents.map(({ id }) => id),\n            async (userId) => {\n              try {\n                let respondent = oneTrustCachedUsers[userId];\n                if (!respondent) {\n                  respondent = await getOneTrustUser({ oneTrust, userId });\n                  oneTrustCachedUsers[userId] = respondent;\n                }\n                return [respondent];\n              } catch (error) {\n                logger.warn(\n                  colors.yellow(\n                    `[assessment ${assessmentNumber} of ${assessments.length}]: failed to fetch a respondent.` +\n                      `\\trespondentId: ${userId}. Assessment Title: ${assessment.name}. Template Title: ${templateName}`,\n                  ),\n                  error,\n                );\n                return [];\n              }\n            },\n            { concurrency: 5 },\n          );\n        }\n\n        // fetch assessment risk information\n        let riskDetails: OneTrustGetRiskResponse[] = [];\n        const riskIds = uniq(\n          assessmentDetails.sections.flatMap((s: OneTrustAssessmentSection) =>\n            s.questions.flatMap((q: OneTrustAssessmentQuestion) =>\n              (q.risks ?? []).flatMap((r) => r.riskId),\n            ),\n          ),\n        );\n        if (riskIds.length > 0) {\n          logger.info(\n            `[assessment ${assessmentNumber} of ${assessments.length}]: fetching risks...`,\n          );\n          riskDetails = await map(\n            riskIds,\n            (riskId) => getOneTrustRisk({ oneTrust, riskId: riskId as string }),\n            {\n              concurrency: 5,\n            },\n          );\n        }\n\n        // enrich the assessments with user and risk details\n        const enrichedAssessment = enrichOneTrustAssessment({\n          assessment,\n          assessmentDetails,\n          riskDetails,\n          creatorDetails: creator,\n          approversDetails: approversDetails.flat(),\n          respondentsDetails: respondentsDetails.flat(),\n        });\n\n        batchEnrichedAssessments.push(enrichedAssessment);\n      },\n      { concurrency: BATCH_SIZE },\n    );\n\n    // sync assessments in series to avoid concurrency bugs\n    await mapSeries(batchEnrichedAssessments, async (enrichedAssessment, index) => {\n      // the assessment's global index takes its batch into consideration\n      const globalIndex = batch * BATCH_SIZE + index;\n\n      if (dryRun && file) {\n        // sync to file\n        syncOneTrustAssessmentToDisk({\n          assessment: enrichedAssessment,\n          index: globalIndex,\n          total: assessments.length,\n          file,\n        });\n      } else if (transcend) {\n        // sync to transcend\n        await syncOneTrustAssessmentToTranscend({\n          assessment: enrichedAssessment,\n          transcend,\n          total: assessments.length,\n          index: globalIndex,\n        });\n      }\n    });\n  });\n};\n","import { createReadStream } from 'node:fs';\n\nimport { OneTrustEnrichedAssessment } from '@transcend-io/privacy-types';\nimport { decodeCodec } from '@transcend-io/type-utils';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\nimport JSONStream from 'JSONStream';\n\nimport { logger } from '../../../logger.js';\nimport { syncOneTrustAssessmentToTranscend } from './syncOneTrustAssessmentToTranscend.js';\n\n/**\n * Reads assessments from a file and syncs them to Transcend.\n *\n * @param param - the information about the source file and Transcend instance to write them to.\n */\nexport const syncOneTrustAssessmentsFromFile = ({\n  transcend,\n  file,\n}: {\n  /** the Transcend client instance */\n  transcend: GraphQLClient;\n  /** The name of the file from which to read the OneTrust assessments */\n  file: string;\n}): Promise<void> => {\n  logger.info(`Getting list of all assessments from file ${file}...`);\n\n  return new Promise((resolve, reject) => {\n    // Create a readable stream from the file\n    const fileStream = createReadStream(file, {\n      encoding: 'utf-8',\n      highWaterMark: 64 * 1024, // 64KB chunks\n    });\n\n    // Create a JSONStream parser to parse the array of OneTrust assessments from the file\n    const parser = JSONStream.parse('*'); // '*' matches each element in the root array\n\n    let index = 0;\n\n    // Pipe the file stream into the JSON parser\n    fileStream.pipe(parser);\n\n    // Handle each parsed assessment object\n    parser.on('data', async (assessment) => {\n      try {\n        // Pause the stream while processing to avoid overwhelming memory\n        parser.pause();\n\n        // Decode and validate the assessment\n        const parsedAssessment = decodeCodec(OneTrustEnrichedAssessment, assessment);\n\n        // Sync the assessment to transcend\n        await syncOneTrustAssessmentToTranscend({\n          assessment: parsedAssessment,\n          transcend,\n          index,\n        });\n\n        index += 1;\n\n        // Resume the stream after processing\n        parser.resume();\n      } catch (e) {\n        // if failed to parse a line, report error and continue\n        logger.error(\n          colors.red(`Failed to parse the assessment ${index} from file '${file}': ${e.message}.`),\n        );\n      }\n    });\n\n    // Handle completion\n    parser.on('end', () => {\n      logger.info(`Finished processing ${index} assessments from file ${file}`);\n      resolve();\n    });\n\n    // Handle stream or parsing errors\n    parser.on('error', (error) => {\n      logger.error(colors.red(`Error parsing file '${file}': ${error.message}`));\n      reject(error);\n    });\n\n    fileStream.on('error', (error) => {\n      logger.error(colors.red(`Error reading file '${file}': ${error.message}`));\n      reject(error);\n    });\n  });\n};\n","import got, { Got } from 'got';\n\n/**\n * Instantiate an instance of got that is capable of making requests to OneTrust\n *\n * @param param - information about the OneTrust URL\n * @returns The instance of got that is capable of making requests to the customer ingress\n */\nexport const createOneTrustGotInstance = ({\n  hostname,\n  auth,\n}: {\n  /** Hostname of the OneTrust API */\n  hostname: string;\n  /** The OAuth access token */\n  auth: string;\n}): Got =>\n  got.extend({\n    prefixUrl: `https://${hostname}`,\n    headers: {\n      accept: 'application/json',\n      'content-type': 'application/json',\n      authorization: `Bearer ${auth}`,\n    },\n  });\n","import { buildTranscendGraphQLClient } from '@transcend-io/sdk';\nimport colors from 'colors';\n\nimport type { LocalContext } from '../../../context.js';\nimport { OneTrustFileFormat, OneTrustPullResource, OneTrustPullSource } from '../../../enums.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport {\n  syncOneTrustAssessmentsFromFile,\n  syncOneTrustAssessmentsFromOneTrust,\n} from '../../../lib/oneTrust/helpers/index.js';\nimport { createOneTrustGotInstance } from '../../../lib/oneTrust/index.js';\nimport { logger } from '../../../logger.js';\n\n// Command flag interface\nexport interface SyncOtCommandFlags {\n  hostname?: string;\n  oneTrustAuth?: string;\n  source: OneTrustPullSource;\n  transcendAuth?: string;\n  transcendUrl: string;\n  file?: string;\n  resource: OneTrustPullResource;\n  dryRun: boolean;\n  debug: boolean;\n}\n\n// Command implementation\nexport async function syncOt(\n  this: LocalContext,\n  {\n    hostname,\n    oneTrustAuth,\n    source,\n    transcendAuth,\n    transcendUrl,\n    resource,\n    file,\n    dryRun,\n    debug,\n  }: SyncOtCommandFlags,\n): Promise<void> {\n  // Must be able to authenticate to transcend to sync resources to it\n  if (!dryRun && !transcendAuth) {\n    throw new Error(\n      // eslint-disable-next-line no-template-curly-in-string\n      'Must specify a \"transcendAuth\" parameter to sync resources to Transcend. e.g. --transcendAuth=${TRANSCEND_API_KEY}',\n    );\n  }\n\n  // If trying to sync to disk, must specify a file path\n  if (dryRun && !file) {\n    throw new Error(\n      'Must set a \"file\" parameter when \"dryRun\" is \"true\". e.g. --file=./oneTrustAssessments.json',\n    );\n  }\n\n  if (file) {\n    const splitFile = file.split('.');\n    if (splitFile.length < 2) {\n      throw new Error(\n        'The \"file\" parameter has an invalid format. Expected a path with extensions. e.g. --file=./pathToFile.json.',\n      );\n    }\n    if (splitFile.at(-1) !== OneTrustFileFormat.Json) {\n      throw new Error(\n        `Expected the format of the \"file\" parameters '${file}' to be '${\n          OneTrustFileFormat.Json\n        }', but got '${splitFile.at(-1)}'.`,\n      );\n    }\n  }\n\n  // if reading assessments from a OneTrust\n  if (source === OneTrustPullSource.OneTrust) {\n    // must specify the OneTrust hostname\n    if (!hostname) {\n      throw new Error(\n        'Missing required parameter \"hostname\". e.g. --hostname=customer.my.onetrust.com',\n      );\n    }\n    // must specify the OneTrust auth\n    if (!oneTrustAuth) {\n      throw new Error(\n        'Missing required parameter \"oneTrustAuth\". e.g. --oneTrustAuth=$ONE_TRUST_AUTH_TOKEN',\n      );\n    }\n  } else {\n    // if reading the assessments from a file, must specify a file to read from\n    if (!file) {\n      throw new Error(\n        'Must specify a \"file\" parameter to read the OneTrust assessments from. e.g. --source=./oneTrustAssessments.json',\n      );\n    }\n\n    // Cannot try reading from file and save assessments to a file simultaneously\n    if (dryRun) {\n      throw new Error(\n        'Cannot read and write to a file simultaneously.' +\n          ` Emit the \"source\" parameter or set it to ${OneTrustPullSource.OneTrust} if \"dryRun\" is enabled.`,\n      );\n    }\n  }\n\n  doneInputValidation(this.process.exit);\n\n  // instantiate a client to talk to OneTrust\n  const oneTrust =\n    hostname && oneTrustAuth\n      ? createOneTrustGotInstance({\n          hostname,\n          auth: oneTrustAuth,\n        })\n      : undefined;\n\n  // instantiate a client to talk to Transcend\n  const transcend =\n    transcendUrl && transcendAuth\n      ? buildTranscendGraphQLClient(transcendUrl, transcendAuth)\n      : undefined;\n\n  try {\n    if (resource === OneTrustPullResource.Assessments) {\n      if (source === OneTrustPullSource.OneTrust && oneTrust) {\n        await syncOneTrustAssessmentsFromOneTrust({\n          oneTrust,\n          file,\n          dryRun,\n          ...(transcend && { transcend }),\n        });\n      } else if (source === OneTrustPullSource.File && file && transcend) {\n        await syncOneTrustAssessmentsFromFile({ file, transcend });\n      }\n    }\n  } catch (err) {\n    throw new Error(\n      `An error occurred syncing the resource ${resource} from OneTrust: ${\n        debug ? err.stack : err.message\n      }`,\n    );\n  }\n\n  // Indicate success\n  logger.info(\n    colors.green(\n      `Successfully synced OneTrust ${resource} to ${dryRun ? `disk at \"${file}\"` : 'Transcend'}!`,\n    ),\n  );\n}\n"],"mappings":"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"}