{"version":3,"file":"syncCodePackages-Dhm5jI6B.mjs","names":[],"sources":["../src/lib/graphql/syncCodePackages.ts"],"sourcesContent":["import { CodePackageType } from '@transcend-io/privacy-types';\nimport {\n  CREATE_CODE_PACKAGE,\n  UPDATE_CODE_PACKAGES,\n  fetchAllCodePackages,\n  type CodePackage,\n  makeGraphQLRequest,\n  syncRepositories,\n  syncSoftwareDevelopmentKits,\n} from '@transcend-io/sdk';\nimport { map, mapSeries } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { GraphQLClient } from 'graphql-request';\nimport { chunk, uniq, keyBy, uniqBy } from 'lodash-es';\n\nimport { CodePackageInput, RepositoryInput } from '../../codecs.js';\nimport { logger } from '../../logger.js';\n\nconst CHUNK_SIZE = 100;\n\nconst LOOKUP_SPLIT_KEY = '%%%%';\n\n/**\n * Create a new code package\n *\n * @param client - GraphQL client\n * @param input - Code package input\n * @returns Code package ID\n */\nexport async function createCodePackage(\n  client: GraphQLClient,\n  input: {\n    /** Name of package */\n    name: string;\n    /** Description of package */\n    description?: string;\n    /** Type of package */\n    type: CodePackageType;\n    /** Relative path to package */\n    relativePath: string;\n    /** Repository ID */\n    repositoryId?: string;\n    /** Name of repository */\n    repositoryName?: string;\n    /** IDs of SDKs */\n    softwareDevelopmentKitIds?: string[];\n    /** IDs of owners */\n    ownerIds?: string[];\n    /** Emails of owners */\n    ownerEmails?: string[];\n    /** IDs of teams */\n    teamIds?: string[];\n    /** Names of teams */\n    teamNames?: string[];\n  },\n): Promise<CodePackage> {\n  const {\n    createCodePackage: { codePackage },\n  } = await makeGraphQLRequest<{\n    /** createCodePackage mutation */\n    createCodePackage: {\n      /** Code package */\n      codePackage: CodePackage;\n    };\n  }>(client, CREATE_CODE_PACKAGE, {\n    variables: { input },\n    logger,\n  });\n  logger.info(colors.green(`Successfully created code package \"${input.name}\"!`));\n  return codePackage;\n}\n\n/**\n * Update an existing code package\n *\n * @param client - GraphQL client\n * @param inputs - Code package input\n * @returns Code packages that were updated\n */\nexport async function updateCodePackages(\n  client: GraphQLClient,\n  inputs: {\n    /** ID of code package */\n    id: string;\n    /** Name of package */\n    name: string;\n    /** Description of package */\n    description?: string;\n    /** Type of package */\n    type: CodePackageType;\n    /** Relative path to package */\n    relativePath: string;\n    /** Repository ID */\n    repositoryId?: string;\n    /** Name of repository */\n    repositoryName?: string;\n    /** IDs of SDKs */\n    softwareDevelopmentKitIds?: string[];\n    /** IDs of owners */\n    ownerIds?: string[];\n    /** Emails of owners */\n    ownerEmails?: string[];\n    /** IDs of teams */\n    teamIds?: string[];\n    /** Names of teams */\n    teamNames?: string[];\n  }[],\n): Promise<CodePackage[]> {\n  const {\n    updateCodePackages: { codePackages },\n  } = await makeGraphQLRequest<{\n    /** updateCodePackages mutation */\n    updateCodePackages: {\n      /** Code packages */\n      codePackages: CodePackage[];\n    };\n  }>(client, UPDATE_CODE_PACKAGES, {\n    variables: {\n      input: {\n        codePackages: inputs,\n      },\n    },\n    logger,\n  });\n  logger.info(colors.green(`Successfully updated ${inputs.length} code packages!`));\n  return codePackages;\n}\n\n/**\n * Uploads silo discovery results for Transcend to classify\n *\n * @param client - GraphQL Client\n * @param codePackages - Packages to upload\n * @param concurrency - How many concurrent requests to make\n * @returns True if successful, false if any updates failed, or an error occurs\n */\nexport async function syncCodePackages(\n  client: GraphQLClient,\n  codePackages: CodePackageInput[],\n  concurrency = 20,\n): Promise<boolean> {\n  let encounteredError = false;\n  const [existingCodePackages, { softwareDevelopmentKits: existingSoftwareDevelopmentKits }] =\n    await Promise.all([\n      // fetch all code packages\n      fetchAllCodePackages(client, { logger }),\n      // make sure all SDKs exist\n      syncSoftwareDevelopmentKits(\n        client,\n        uniqBy(\n          codePackages\n            .map(({ type, softwareDevelopmentKits = [] }) =>\n              softwareDevelopmentKits.map(({ name }) => ({\n                name,\n                codePackageType: type,\n              })),\n            )\n            .flat(),\n          ({ name, codePackageType }) => `${name}${LOOKUP_SPLIT_KEY}${codePackageType}`,\n        ),\n        { logger, concurrency },\n      ),\n      // make sure all Repositories exist\n      syncRepositories(\n        client,\n        uniqBy(codePackages, 'repositoryName').map(\n          ({ repositoryName }) =>\n            ({\n              name: repositoryName,\n              url: `https://github.com/${repositoryName}`,\n            }) as RepositoryInput,\n        ),\n        { logger },\n      ),\n    ]);\n\n  const softwareDevelopmentKitLookup = keyBy(\n    existingSoftwareDevelopmentKits,\n    ({ name, codePackageType }) => `${name}${LOOKUP_SPLIT_KEY}${codePackageType}`,\n  );\n  const codePackagesLookup = keyBy(\n    existingCodePackages,\n    ({ name, type }) => `${name}${LOOKUP_SPLIT_KEY}${type}`,\n  );\n\n  // Determine which codePackages are new vs existing\n  const mapCodePackagesToExisting = codePackages.map((codePackageInput) => [\n    codePackageInput,\n    codePackagesLookup[`${codePackageInput.name}${LOOKUP_SPLIT_KEY}${codePackageInput.type}`]?.id,\n  ]);\n\n  // Create the new codePackages\n  const newCodePackages = mapCodePackagesToExisting\n    .filter(([, existing]) => !existing)\n    .map(([codePackageInput]) => codePackageInput as CodePackageInput);\n  try {\n    logger.info(colors.magenta(`Creating \"${newCodePackages.length}\" new code packages...`));\n    await map(\n      newCodePackages,\n      async ({ softwareDevelopmentKits, ...codePackage }) => {\n        await createCodePackage(client, {\n          ...codePackage,\n          ...(softwareDevelopmentKits\n            ? {\n                softwareDevelopmentKitIds: uniq(\n                  softwareDevelopmentKits.map(({ name }) => {\n                    const sdk =\n                      softwareDevelopmentKitLookup[`${name}${LOOKUP_SPLIT_KEY}${codePackage.type}`];\n                    if (!sdk) {\n                      throw new Error(`Failed to find SDK with name: \"${name}\"`);\n                    }\n                    return sdk.id;\n                  }),\n                ),\n              }\n            : {}),\n        });\n      },\n      {\n        concurrency,\n      },\n    );\n    logger.info(colors.green(`Successfully synced ${newCodePackages.length} code packages!`));\n  } catch (err) {\n    encounteredError = true;\n    logger.error(colors.red(`Failed to create code packages! - ${err.message}`));\n  }\n\n  // Update existing codePackages\n  const existingCodePackageInputs = mapCodePackagesToExisting.filter(\n    (x): x is [CodePackageInput, string] => !!x[1],\n  );\n  logger.info(colors.magenta(`Updating \"${existingCodePackageInputs.length}\" code packages...`));\n  const chunks = chunk(existingCodePackageInputs, CHUNK_SIZE);\n\n  await mapSeries(chunks, async (chunk) => {\n    try {\n      await updateCodePackages(\n        client,\n        chunk.map(\n          // eslint-disable-next-line @typescript-eslint/no-unused-vars\n          ([{ softwareDevelopmentKits, repositoryName, ...input }, id]) => ({\n            ...input,\n            ...(softwareDevelopmentKits\n              ? {\n                  softwareDevelopmentKitIds: uniq(\n                    softwareDevelopmentKits.map(({ name }) => {\n                      const sdk =\n                        softwareDevelopmentKitLookup[`${name}${LOOKUP_SPLIT_KEY}${input.type}`];\n                      if (!sdk) {\n                        throw new Error(`Failed to find SDK with name: \"${name}\"`);\n                      }\n                      return sdk.id;\n                    }),\n                  ),\n                }\n              : {}),\n            id,\n          }),\n        ),\n      );\n      logger.info(colors.green(`Successfully updated \"${chunk.length}\" code packages!`));\n    } catch (err) {\n      encounteredError = true;\n      logger.error(colors.red(`Failed to update code packages! - ${err.message}`));\n    }\n  });\n\n  logger.info(colors.green(`Synced \"${codePackages.length}\" code packages!`));\n  return !encounteredError;\n}\n"],"mappings":"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"}