{"version":3,"file":"impl-Bur_bNXN.mjs","names":[],"sources":["../src/commands/consent/generate-access-tokens/impl.ts"],"sourcesContent":["import { existsSync } from 'node:fs';\n\nimport { SombraStandardScope } from '@transcend-io/privacy-types';\nimport {\n  buildTranscendGraphQLClient,\n  createPreferenceAccessTokens,\n  type PreferenceAccessTokenInputWithIndex,\n} from '@transcend-io/sdk';\nimport cliProgress from 'cli-progress';\nimport colors from 'colors';\nimport * as t from 'io-ts';\n\nimport type { LocalContext } from '../../../context.js';\nimport { doneInputValidation } from '../../../lib/cli/done-input-validation.js';\nimport { writeCsv } from '../../../lib/helpers/index.js';\nimport { readCsv } from '../../../lib/requests/index.js';\nimport { logger } from '../../../logger.js';\n\n/**\n * CLI flags accepted by the `generate-access-tokens` command.\n *\n * These are passed down from the CLI parser into the parent process.\n */\nexport type GenerateAccessTokenCommandFlags = {\n  auth: string;\n  file: string;\n  duration: number;\n  transcendUrl: string;\n  subjectType: string;\n  emailColumnName: string;\n  coreIdentifierColumnName?: string;\n};\n\n/**\n * Take in a CSV of user identifiers and generate access tokens for each user.\n *\n * Expected CSV columns:\n *   - [emailColumnName] (required)\n *   - [coreIdentifierColumnName] (optional)\n *\n * @param this  - Bound CLI context (provides process exit + logging).\n * @param flags - CLI options for the run.\n */\nexport async function generateAccessTokens(\n  this: LocalContext,\n  {\n    auth,\n    file,\n    transcendUrl,\n    duration,\n    subjectType,\n    emailColumnName,\n    coreIdentifierColumnName,\n  }: GenerateAccessTokenCommandFlags,\n): Promise<void> {\n  doneInputValidation(this.process.exit);\n  if (!existsSync(file)) {\n    logger.error(\n      colors.red(`File does not exist: \"${file}\". Please provide a valid path to a CSV file.`),\n    );\n    this.process.exit(1);\n  }\n\n  try {\n    // Create a GraphQL client\n    const client = buildTranscendGraphQLClient(transcendUrl, auth);\n\n    // Read + parse CSV\n    const codec = t.type({\n      [emailColumnName]: t.string,\n      ...(coreIdentifierColumnName ? { [coreIdentifierColumnName]: t.string } : {}),\n    });\n    const rows: Array<Record<string, string>> = readCsv(file, codec);\n    if (!rows.length) {\n      throw new Error('Input CSV is empty.');\n    }\n\n    // Ensure emails and core identifiers exist\n    const missingEmail = rows\n      .map((r, i) => [r, i] as const)\n      .filter(([r]) => !r[emailColumnName]?.trim());\n    if (missingEmail.length) {\n      const rowNumbers = missingEmail\n        .map(([, i]) => i + 2) // +2 to account for header row and 0-indexing\n        .join(', ');\n      throw new Error(\n        `The following rows are missing the required \"${emailColumnName}\" column: ${rowNumbers}`,\n      );\n    }\n    if (coreIdentifierColumnName) {\n      const missingCoreId = rows\n        .map((r, i) => [r, i] as const)\n        .filter(([r]) => !r[coreIdentifierColumnName]?.trim());\n      if (missingCoreId.length) {\n        const rowNumbers = missingCoreId\n          .map(([, i]) => i + 2) // +2 to account for header row and 0-indexing\n          .join(', ');\n        throw new Error(\n          `The following rows are missing the required \"${coreIdentifierColumnName}\" column: ${rowNumbers}`,\n        );\n      }\n    }\n\n    // Duration provided by CLI is in ms; GraphQL expects seconds\n    const expiresInSeconds = Math.max(1, Math.floor(duration / 1000));\n\n    // Build inputs for GraphQL\n    const inputs = rows.map((r, index): PreferenceAccessTokenInputWithIndex => {\n      const email = r[emailColumnName].trim();\n      const coreIdentifier = coreIdentifierColumnName\n        ? r[coreIdentifierColumnName]?.trim()\n        : undefined;\n      const scopes = [SombraStandardScope.PreferenceManagement];\n      return {\n        subjectType,\n        scopes,\n        expiresIn: expiresInSeconds,\n        email,\n        ...(coreIdentifier ? { coreIdentifier } : {}),\n        index,\n      };\n    });\n\n    // Progress bar\n    const progressBar = new cliProgress.SingleBar({}, cliProgress.Presets.shades_classic);\n    progressBar.start(inputs.length, 0);\n\n    // Kick off token creation (batched internally)\n    const t0 = Date.now();\n    const results = await createPreferenceAccessTokens(client, {\n      records: inputs,\n      logger,\n      emitProgress: (progress) => {\n        progressBar.update(progress);\n      },\n    });\n    progressBar.update(inputs.length);\n    progressBar.stop();\n\n    // Prepare output CSV rows\n    const outputRows = results.map(({ accessToken, input }) => {\n      if (typeof input.index !== 'number') {\n        throw new Error('Internal error: missing input index.');\n      }\n      return {\n        ...rows[input.index],\n        token: accessToken,\n      };\n    });\n\n    logger.info(colors.magenta(`Writing access tokens to file \"${file}\"...`));\n    await writeCsv(file, outputRows, true);\n\n    const totalTimeSec = Math.round((Date.now() - t0) / 1000);\n    logger.info(\n      colors.green(\n        `Successfully generated ${results.length} access tokens to \"${file}\" in ${totalTimeSec}s!`,\n      ),\n    );\n    // eslint-disable-next-line @typescript-eslint/no-explicit-any\n  } catch (err: any) {\n    logger.error(\n      colors.red(\n        `An error occurred while generating access tokens: ${err?.message || String(err)}`,\n      ),\n    );\n    this.process.exit(1);\n  }\n}\n"],"mappings":"wcA2CA,eAAsB,EAEpB,CACE,OACA,OACA,eACA,WACA,cACA,kBACA,4BAEa,CACf,EAAoB,KAAK,QAAQ,KAAK,CACjC,EAAW,EAAK,GACnB,EAAO,MACL,EAAO,IAAI,yBAAyB,EAAK,+CAA+C,CACzF,CACD,KAAK,QAAQ,KAAK,EAAE,EAGtB,GAAI,CAEF,IAAM,EAAS,EAA4B,EAAc,EAAK,CAOxD,EAAsC,EAAQ,EAJtC,EAAE,KAAK,EAClB,GAAkB,EAAE,OACrB,GAAI,EAA2B,EAAG,GAA2B,EAAE,OAAQ,CAAG,EAAE,CAC7E,CAC8D,CAAC,CAChE,GAAI,CAAC,EAAK,OACR,MAAU,MAAM,sBAAsB,CAIxC,IAAM,EAAe,EAClB,KAAK,EAAG,IAAM,CAAC,EAAG,EAAE,CAAU,CAC9B,QAAQ,CAAC,KAAO,CAAC,EAAE,IAAkB,MAAM,CAAC,CAC/C,GAAI,EAAa,OAAQ,CACvB,IAAM,EAAa,EAChB,KAAK,EAAG,KAAO,EAAI,EAAE,CACrB,KAAK,KAAK,CACb,MAAU,MACR,gDAAgD,EAAgB,YAAY,IAC7E,CAEH,GAAI,EAA0B,CAC5B,IAAM,EAAgB,EACnB,KAAK,EAAG,IAAM,CAAC,EAAG,EAAE,CAAU,CAC9B,QAAQ,CAAC,KAAO,CAAC,EAAE,IAA2B,MAAM,CAAC,CACxD,GAAI,EAAc,OAAQ,CACxB,IAAM,EAAa,EAChB,KAAK,EAAG,KAAO,EAAI,EAAE,CACrB,KAAK,KAAK,CACb,MAAU,MACR,gDAAgD,EAAyB,YAAY,IACtF,EAKL,IAAM,EAAmB,KAAK,IAAI,EAAG,KAAK,MAAM,EAAW,IAAK,CAAC,CAG3D,EAAS,EAAK,KAAK,EAAG,IAA+C,CACzE,IAAM,EAAQ,EAAE,GAAiB,MAAM,CACjC,EAAiB,EACnB,EAAE,IAA2B,MAAM,CACnC,IAAA,GAEJ,MAAO,CACL,cACA,OAAA,CAHc,EAAoB,qBAG5B,CACN,UAAW,EACX,QACA,GAAI,EAAiB,CAAE,iBAAgB,CAAG,EAAE,CAC5C,QACD,EACD,CAGI,EAAc,IAAI,EAAY,UAAU,EAAE,CAAE,EAAY,QAAQ,eAAe,CACrF,EAAY,MAAM,EAAO,OAAQ,EAAE,CAGnC,IAAM,EAAK,KAAK,KAAK,CACf,EAAU,MAAM,EAA6B,EAAQ,CACzD,QAAS,EACT,SACA,aAAe,GAAa,CAC1B,EAAY,OAAO,EAAS,EAE/B,CAAC,CACF,EAAY,OAAO,EAAO,OAAO,CACjC,EAAY,MAAM,CAGlB,IAAM,EAAa,EAAQ,KAAK,CAAE,cAAa,WAAY,CACzD,GAAI,OAAO,EAAM,OAAU,SACzB,MAAU,MAAM,uCAAuC,CAEzD,MAAO,CACL,GAAG,EAAK,EAAM,OACd,MAAO,EACR,EACD,CAEF,EAAO,KAAK,EAAO,QAAQ,kCAAkC,EAAK,MAAM,CAAC,CACzE,MAAM,EAAS,EAAM,EAAY,GAAK,CAEtC,IAAM,EAAe,KAAK,OAAO,KAAK,KAAK,CAAG,GAAM,IAAK,CACzD,EAAO,KACL,EAAO,MACL,0BAA0B,EAAQ,OAAO,qBAAqB,EAAK,OAAO,EAAa,IACxF,CACF,OAEM,EAAU,CACjB,EAAO,MACL,EAAO,IACL,qDAAqD,GAAK,SAAW,OAAO,EAAI,GACjF,CACF,CACD,KAAK,QAAQ,KAAK,EAAE"}