{"version":3,"file":"pushManualEnrichmentIdentifiersFromCsv-CLLs3z_J.mjs","names":[],"sources":["../src/lib/manual-enrichment/enrichPrivacyRequest.ts","../src/lib/manual-enrichment/pushManualEnrichmentIdentifiersFromCsv.ts"],"sourcesContent":["import { splitCsvToList } from '@transcend-io/utils';\nimport colors from 'colors';\nimport type { Got } from 'got';\nimport * as t from 'io-ts';\nimport { uniq } from 'lodash-es';\n\nimport { logger } from '../../logger.js';\n\nconst ADMIN_URL = 'https://app.transcend.io/privacy-requests/incoming-requests/';\n/**\n * Minimal set required to mark as completed\n */\nexport const EnrichPrivacyRequest = t.record(t.string, t.string);\n\n/** Type override */\nexport type EnrichPrivacyRequest = t.TypeOf<typeof EnrichPrivacyRequest>;\n\n/**\n * Upload identifiers to a privacy request or mark request as\n *\n * @param sombra - Sombra instance configured to make requests\n * @param request - Request to enricher\n * @param enricherId - The ID of the enricher being uploaded to\n * @param index - Index of request ID\n * @returns True if enriched successfully, false if skipped, throws error if failed\n */\nexport async function enrichPrivacyRequest(\n  sombra: Got,\n  { id: rawId, ...rest }: EnrichPrivacyRequest,\n  enricherId: string,\n  index?: number,\n): Promise<boolean> {\n  if (!rawId) {\n    // error\n    const msg = `Request ID must be provided to enricher request.${\n      index ? ` Found error in row: ${index}` : ''\n    }`;\n    logger.error(colors.red(msg));\n    throw new Error(msg);\n  }\n\n  const id = rawId.toLowerCase();\n\n  // Pull out the identifiers\n  const enrichedIdentifiers = Object.entries(rest).reduce(\n    (acc, [key, value]) => {\n      const values = uniq(splitCsvToList(value));\n      return values.length === 0\n        ? acc\n        : Object.assign(acc, {\n            [key]: uniq(splitCsvToList(value)).map((val) => ({\n              value: key === 'email' ? val.toLowerCase() : val,\n            })),\n          });\n    },\n    {} as Record<string, string[]>,\n  );\n\n  // Make the GraphQL request\n  try {\n    await sombra\n      .post('v1/enrich-identifiers', {\n        headers: {\n          'x-transcend-request-id': id,\n          'x-transcend-enricher-id': enricherId,\n        },\n        json: {\n          enrichedIdentifiers,\n        },\n      })\n      .json();\n\n    logger.error(colors.green(`Successfully enriched request: ${ADMIN_URL}${id}`));\n    return true;\n  } catch (err) {\n    // skip if already enriched\n    if (\n      typeof err.response.body === 'string' &&\n      err.response.body.includes('Cannot update a resolved RequestEnricher')\n    ) {\n      logger.warn(\n        colors.magenta(\n          `Skipped enrichment for request: ${ADMIN_URL}${id}, request is no longer in the enriching phase.`,\n        ),\n      );\n      return false;\n    }\n\n    // error\n    logger.error(\n      colors.red(\n        `Failed to enricher identifiers for request with id: ${ADMIN_URL}${id} - ${err.message} - ${err.response.body}`,\n      ),\n    );\n    throw err;\n  }\n}\n","import {\n  buildTranscendGraphQLClient,\n  createSombraGotInstance,\n  makeGraphQLRequest,\n} from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport { DEFAULT_TRANSCEND_API } from '../../constants.js';\nimport { logger } from '../../logger.js';\nimport { UPDATE_PRIVACY_REQUEST } from '../graphql/index.js';\nimport { readCsv } from '../requests/index.js';\nimport { enrichPrivacyRequest, EnrichPrivacyRequest } from './enrichPrivacyRequest.js';\n\n/**\n * Push a CSV of enriched requests back into Transcend\n *\n * @param options - Options\n * @returns Number of items processed\n */\nexport async function pushManualEnrichmentIdentifiersFromCsv({\n  file,\n  auth,\n  sombraAuth,\n  enricherId,\n  markSilent,\n  concurrency = 100,\n  transcendUrl = DEFAULT_TRANSCEND_API,\n}: {\n  /** CSV file path */\n  file: string;\n  /** Transcend API key authentication */\n  auth: string;\n  /** ID of enricher being uploaded to */\n  enricherId: string;\n  /** Sombra API key authentication */\n  sombraAuth?: string;\n  /** Concurrency */\n  concurrency?: number;\n  /** API URL for Transcend backend */\n  transcendUrl?: string;\n  /** Mark requests in silent mode before enriching */\n  markSilent?: boolean;\n}): Promise<number> {\n  // Create sombra instance to communicate with\n  const sombra = await createSombraGotInstance(transcendUrl, auth, {\n    logger,\n    sombraApiKey: sombraAuth,\n    sombraUrl: process.env.SOMBRA_URL,\n  });\n  const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n  // Read from CSV\n  logger.info(colors.magenta(`Reading \"${file}\" from disk`));\n  const activeResults = readCsv(file, EnrichPrivacyRequest);\n\n  // Notify Transcend\n  logger.info(colors.magenta(`Enriching \"${activeResults.length}\" privacy requests.`));\n\n  let successCount = 0;\n  let skippedCount = 0;\n  let errorCount = 0;\n\n  await map(\n    activeResults,\n    async (request, index) => {\n      try {\n        // Mark requests in silent mode before a certain date\n        if (markSilent) {\n          await makeGraphQLRequest(client, UPDATE_PRIVACY_REQUEST, {\n            variables: {\n              input: {\n                id: request.id,\n                isSilent: true,\n              },\n            },\n            logger,\n          });\n\n          logger.info(colors.magenta(`Mark request as silent mode - ${request.id}`));\n        }\n\n        const result = await enrichPrivacyRequest(sombra, request, enricherId, index);\n        if (result) {\n          successCount += 1;\n        } else {\n          skippedCount += 1;\n        }\n      } catch {\n        errorCount += 1;\n      }\n    },\n    { concurrency },\n  );\n\n  logger.info(colors.green(`Successfully notified Transcend! \\n Success count: ${successCount}.`));\n\n  if (skippedCount > 0) {\n    logger.info(colors.magenta(`Skipped count: ${skippedCount}.`));\n  }\n\n  if (errorCount > 0) {\n    logger.info(colors.red(`Error Count: ${errorCount}.`));\n    throw new Error(`Failed to enrich: ${errorCount} requests.`);\n  }\n\n  return activeResults.length;\n}\n"],"mappings":"0aAQA,MAAM,EAAY,+DAIL,EAAuB,EAAE,OAAO,EAAE,OAAQ,EAAE,OAAO,CAchE,eAAsB,EACpB,EACA,CAAE,GAAI,EAAO,GAAG,GAChB,EACA,EACkB,CAClB,GAAI,CAAC,EAAO,CAEV,IAAM,EAAM,mDACV,EAAQ,wBAAwB,IAAU,KAG5C,MADA,EAAO,MAAM,EAAO,IAAI,EAAI,CAAC,CACnB,MAAM,EAAI,CAGtB,IAAM,EAAK,EAAM,aAAa,CAGxB,EAAsB,OAAO,QAAQ,EAAK,CAAC,QAC9C,EAAK,CAAC,EAAK,KACK,EAAK,EAAe,EAAM,CAC5B,CAAC,SAAW,EACrB,EACA,OAAO,OAAO,EAAK,EAChB,GAAM,EAAK,EAAe,EAAM,CAAC,CAAC,IAAK,IAAS,CAC/C,MAAO,IAAQ,QAAU,EAAI,aAAa,CAAG,EAC9C,EAAE,CACJ,CAAC,CAER,EAAE,CACH,CAGD,GAAI,CAcF,OAbA,MAAM,EACH,KAAK,wBAAyB,CAC7B,QAAS,CACP,yBAA0B,EAC1B,0BAA2B,EAC5B,CACD,KAAM,CACJ,sBACD,CACF,CAAC,CACD,MAAM,CAET,EAAO,MAAM,EAAO,MAAM,kCAAkC,IAAY,IAAK,CAAC,CACvE,SACA,EAAK,CAEZ,GACE,OAAO,EAAI,SAAS,MAAS,UAC7B,EAAI,SAAS,KAAK,SAAS,2CAA2C,CAOtE,OALA,EAAO,KACL,EAAO,QACL,mCAAmC,IAAY,EAAG,gDACnD,CACF,CACM,GAST,MALA,EAAO,MACL,EAAO,IACL,uDAAuD,IAAY,EAAG,KAAK,EAAI,QAAQ,KAAK,EAAI,SAAS,OAC1G,CACF,CACK,GC1EV,eAAsB,EAAuC,CAC3D,OACA,OACA,aACA,aACA,aACA,cAAc,IACd,eAAe,GAgBG,CAElB,IAAM,EAAS,MAAM,EAAwB,EAAc,EAAM,CAC/D,SACA,aAAc,EACd,UAAW,QAAQ,IAAI,WACxB,CAAC,CACI,EAAS,EAA4B,EAAc,EAAK,CAG9D,EAAO,KAAK,EAAO,QAAQ,YAAY,EAAK,aAAa,CAAC,CAC1D,IAAM,EAAgB,EAAQ,EAAM,EAAqB,CAGzD,EAAO,KAAK,EAAO,QAAQ,cAAc,EAAc,OAAO,qBAAqB,CAAC,CAEpF,IAAI,EAAe,EACf,EAAe,EACf,EAAa,EAwCjB,GAtCA,MAAM,EACJ,EACA,MAAO,EAAS,IAAU,CACxB,GAAI,CAEE,IACF,MAAM,EAAmB,EAAQ,EAAwB,CACvD,UAAW,CACT,MAAO,CACL,GAAI,EAAQ,GACZ,SAAU,GACX,CACF,CACD,SACD,CAAC,CAEF,EAAO,KAAK,EAAO,QAAQ,iCAAiC,EAAQ,KAAK,CAAC,EAIxE,MADiB,EAAqB,EAAQ,EAAS,EAAY,EAAM,CAE3E,GAAgB,EAEhB,GAAgB,OAEZ,CACN,GAAc,IAGlB,CAAE,cAAa,CAChB,CAED,EAAO,KAAK,EAAO,MAAM,sDAAsD,EAAa,GAAG,CAAC,CAE5F,EAAe,GACjB,EAAO,KAAK,EAAO,QAAQ,kBAAkB,EAAa,GAAG,CAAC,CAG5D,EAAa,EAEf,MADA,EAAO,KAAK,EAAO,IAAI,gBAAgB,EAAW,GAAG,CAAC,CAC5C,MAAM,qBAAqB,EAAW,YAAY,CAG9D,OAAO,EAAc"}