{"version":3,"file":"impl-C2r4O1d_.mjs","names":[],"sources":["../src/commands/consent/pull-consent-metrics/impl.ts"],"sourcesContent":["import fs, { existsSync, mkdirSync } from 'node:fs';\nimport { join } from 'node:path';\n\nimport { ConsentManagerMetricBin } from '@transcend-io/privacy-types';\nimport { buildTranscendGraphQLClient } from '@transcend-io/sdk';\nimport { map, mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\n\nimport { ADMIN_DASH_INTEGRATIONS } from '../../../constants.js';\nimport type { LocalContext } from '../../../context.js';\nimport { validateTranscendAuth } from '../../../lib/api-keys/index.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { pullConsentManagerMetrics } from '../../../lib/consent-manager/index.js';\nimport { writeCsv } from '../../../lib/helpers/index.js';\nimport { logger } from '../../../logger.js';\n\nexport interface PullConsentMetricsCommandFlags {\n  auth: string;\n  start: Date;\n  end?: Date;\n  folder: string;\n  bin: string;\n  transcendUrl: string;\n}\n\nexport async function pullConsentMetrics(\n  this: LocalContext,\n  { auth, start, end, folder, bin, transcendUrl }: PullConsentMetricsCommandFlags,\n): Promise<void> {\n  // Validate bin\n  const parsedBin = bin as ConsentManagerMetricBin;\n  if (!Object.values(ConsentManagerMetricBin).includes(parsedBin)) {\n    logger.error(\n      colors.red(\n        `Failed to parse argument \"bin\" with value \"${bin}\"\\n` +\n          `Expected one of: \\n${Object.values(ConsentManagerMetricBin).join('\\n')}`,\n      ),\n    );\n    this.process.exit(1);\n  }\n\n  // Parse the dates\n  const startDate = new Date(start);\n  const endDate = end ? new Date(end) : new Date();\n  if (Number.isNaN(startDate.getTime())) {\n    logger.error(\n      colors.red(\n        `Start date provided is invalid date. Got --start=\"${start}\" expected --start=\"01/01/2023\"`,\n      ),\n    );\n    this.process.exit(1);\n  }\n  if (Number.isNaN(endDate.getTime())) {\n    logger.error(\n      colors.red(\n        `End date provided is invalid date. Got --end=\"${end}\" expected --end=\"01/01/2023\"`,\n      ),\n    );\n    this.process.exit(1);\n  }\n  if (startDate > endDate) {\n    logger.error(\n      colors.red(\n        `Got a start date \"${startDate.toISOString()}\" that was larger than the end date \"${endDate.toISOString()}\". ` +\n          'Start date must be before end date.',\n      ),\n    );\n    this.process.exit(1);\n  }\n\n  doneInputValidation(this.process.exit);\n\n  // Parse authentication as API key or path to list of API keys\n  const apiKeyOrList = await validateTranscendAuth(auth);\n\n  // Ensure folder either does not exist or is not a file\n  if (fs.existsSync(folder) && !fs.lstatSync(folder).isDirectory()) {\n    logger.error(\n      colors.red(\n        'The provided argument \"folder\" was passed a file. expected: folder=\"./consent-metrics/\"',\n      ),\n    );\n    this.process.exit(1);\n  }\n\n  // Create the folder if it does not exist\n  if (!existsSync(folder)) {\n    mkdirSync(folder);\n  }\n\n  logger.info(\n    colors.magenta(\n      `Pulling consent metrics from start=${startDate.toString()} to end=${endDate.toISOString()} with bin size \"${bin}\"`,\n    ),\n  );\n\n  // Sync to Disk\n  if (typeof apiKeyOrList === 'string') {\n    try {\n      // Create a GraphQL client\n      const client = buildTranscendGraphQLClient(transcendUrl, apiKeyOrList);\n\n      // Pull the metrics\n      const configuration = await pullConsentManagerMetrics(client, {\n        bin: parsedBin,\n        start: startDate,\n        end: endDate,\n      });\n\n      // Write to file\n      await map(\n        Object.entries(configuration),\n        async ([metricName, metrics]) => {\n          await map(\n            metrics,\n            async ({ points, name }) => {\n              const file = join(folder, `${metricName}_${name}.csv`);\n              logger.info(colors.magenta(`Writing configuration to file \"${file}\"...`));\n              await writeCsv(\n                file,\n                points.map(({ key, value }: { key: string; value: string }) => ({\n                  timestamp: key,\n                  value,\n                })),\n              );\n            },\n            {\n              concurrency: 5,\n            },\n          );\n        },\n        { concurrency: 5 },\n      );\n    } catch (err) {\n      logger.error(colors.red(`An error occurred syncing the schema: ${err.message}`));\n      this.process.exit(1);\n    }\n\n    // Indicate success\n    logger.info(\n      colors.green(\n        `Successfully synced consent metrics to disk in folder \"${folder}\"! View at ${ADMIN_DASH_INTEGRATIONS}`,\n      ),\n    );\n  } else {\n    const encounteredErrors: string[] = [];\n    await mapSeries(apiKeyOrList, async (apiKey, ind) => {\n      const prefix = `[${ind + 1}/${apiKeyOrList.length}][${apiKey.organizationName}] `;\n      logger.info(colors.magenta(`~~~\\n\\n${prefix}Attempting to pull consent metrics...\\n\\n~~~`));\n\n      // Create a GraphQL client\n      const client = buildTranscendGraphQLClient(transcendUrl, apiKey.apiKey);\n\n      try {\n        const configuration = await pullConsentManagerMetrics(client, {\n          bin: parsedBin,\n          start: startDate,\n          end: endDate,\n        });\n\n        // ensure folder exists for that organization\n        const subFolder = join(folder, apiKey.organizationName);\n        if (!existsSync(subFolder)) {\n          mkdirSync(subFolder);\n        }\n\n        // Write to file\n        Object.entries(configuration).forEach(([metricName, metrics]) => {\n          metrics.forEach(({ points, name }) => {\n            const file = join(subFolder, `${metricName}_${name}.csv`);\n            logger.info(colors.magenta(`Writing configuration to file \"${file}\"...`));\n            writeCsv(\n              file,\n              points.map(({ key, value }: { key: string; value: string }) => ({\n                timestamp: key,\n                value,\n              })),\n            );\n          });\n        });\n\n        logger.info(colors.green(`${prefix}Successfully pulled configuration!`));\n      } catch (err) {\n        logger.error(colors.red(`${prefix}Failed to sync configuration.`), err);\n        encounteredErrors.push(apiKey.organizationName);\n      }\n    });\n\n    if (encounteredErrors.length > 0) {\n      logger.info(\n        colors.red(\n          `Sync encountered errors for \"${encounteredErrors.join(\n            ',',\n          )}\". View output above for more information, or check out ${ADMIN_DASH_INTEGRATIONS}`,\n        ),\n      );\n\n      this.process.exit(1);\n    }\n  }\n}\n"],"mappings":"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"}