{"version":3,"file":"buildXdiSyncEndpoint-Do_6DtLA.mjs","names":[],"sources":["../src/lib/consent-manager/domainToHost.ts","../src/lib/consent-manager/buildXdiSyncEndpoint.ts"],"sourcesContent":["/**\n * Convert a domain to host\n *\n * @param domain - e.g. test.acme.com\n * @returns Host acme.com\n */\nexport const domainToHost = (domain: string): string =>\n  new URL(`https://${domain}`).hostname.split('.').slice(-2).join('.');\n","import { buildTranscendGraphQLClient, fetchConsentManager } from '@transcend-io/sdk';\nimport { map } from '@transcend-io/utils';\nimport colors from 'colors';\nimport { difference } from 'lodash-es';\n\nimport { StoredApiKey } from '../../codecs.js';\nimport { DEFAULT_TRANSCEND_API } from '../../constants.js';\nimport { logger } from '../../logger.js';\nimport { domainToHost } from './domainToHost.js';\n\n/**\n * Sync group configuration mapping\n * e.g.\n * {\n *   \"abdb5e78-0d69-4554-a3bd-84b72ca3b3d9\": [\n *      \"test.com\"\n *   ],\n *   \"f6b3ba87-c9df-444f-b420-6fac49e35910\": [\n *     \"blue.com\"\n *   ]\n * }\n */\nexport type XdiSyncGroups = { [k in string]: string[] };\n\n/** Regular expression for IP addresses - remove these from sync endpoint */\nexport const IP_ADDRESS_REGEX =\n  // eslint-disable-next-line max-len\n  /^(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)\\.(25[0-5]|2[0-4][0-9]|[01]?[0-9][0-9]?)$/;\n\n/**\n * Build the sync endpoint definition for a set of Transcend accounts\n *\n * @param apiKeys - The API keys that will be used to pull down configurations for\n * @param options - Options\n * @returns The XDI configuration\n */\nexport async function buildXdiSyncEndpoint(\n  apiKeys: string | StoredApiKey[],\n  {\n    xdiLocation,\n    transcendUrl = DEFAULT_TRANSCEND_API,\n    removeIpAddresses = true,\n    domainBlockList = ['localhost'],\n    xdiAllowedCommands = 'ConsentManager:Sync',\n  }: {\n    /** The file location where the XDI file is hosted */\n    xdiLocation: string;\n    /** URL of Transcend API */\n    transcendUrl?: string;\n    /** When true, remove IP addresses (defaults to true) */\n    removeIpAddresses?: boolean;\n    /** Block list of domains to omit from sync endpoint - includes `localhost` by default */\n    domainBlockList?: string[];\n    /** Allows XDI commands */\n    xdiAllowedCommands?: string;\n  },\n): Promise<{\n  /** Sync group configurations */\n  syncGroups: XdiSyncGroups;\n  /** The HTML string */\n  html: string;\n}> {\n  // Convert API keys to list\n  const apiKeysAsList = Array.isArray(apiKeys)\n    ? apiKeys\n    : [{ apiKey: apiKeys, organizationId: '', organizationName: '' }];\n\n  // Fetch configuration for each account\n  const consentManagers = await map(\n    apiKeysAsList,\n    async (apiKey) => {\n      logger.info(\n        colors.magenta(`Pulling consent metadata for organization - ${apiKey.organizationName}`),\n      );\n\n      // Create a GraphQL client\n      const client = buildTranscendGraphQLClient(transcendUrl, apiKey.apiKey);\n\n      // Grab consent manager\n      const consentManager = await fetchConsentManager(client, { logger });\n      return consentManager;\n    },\n    { concurrency: 5 },\n  );\n\n  // construct the sync groups\n  const syncGroups: XdiSyncGroups = {};\n  consentManagers.forEach((consentManager) => {\n    // grab the partition key\n    const partitionKey =\n      // take explicit key first\n      consentManager.partition?.partition ||\n      // fallback to bundle ID\n      consentManager.bundleURL.split('/').reverse()[1];\n\n    // Ensure that partition exists in the sync groups\n    if (!syncGroups[partitionKey]) {\n      syncGroups[partitionKey] = [];\n    }\n\n    // Map domain list to a host list\n    const hosts = difference(\n      consentManager.configuration.domains\n        .filter(\n          // ignore IP addresses\n          (domain) => !removeIpAddresses || !IP_ADDRESS_REGEX.test(domain),\n        )\n        .map((domain) => domainToHost(domain)),\n      // ignore block list\n      domainBlockList,\n    );\n    // merge existing sync group with hosts for this consent manager\n    syncGroups[partitionKey] = [...new Set([...(syncGroups[partitionKey] || []), ...hosts])];\n  });\n\n  // Construct the HTML\n  const syncEndpointHtml = `\n<!DOCTYPE html>\n<script\nsrc=\"${xdiLocation}\"\ndata-sync-groups='${JSON.stringify(syncGroups, null, 2)}'\ndata-xdi-commands=\"${xdiAllowedCommands}\"\n></script>\n`;\n\n  return {\n    html: syncEndpointHtml,\n    syncGroups,\n  };\n}\n"],"mappings":"kRAMA,MAAa,EAAgB,GAC3B,IAAI,IAAI,WAAW,IAAS,CAAC,SAAS,MAAM,IAAI,CAAC,MAAM,GAAG,CAAC,KAAK,IAAI,CCkBzD,EAEX,mKASF,eAAsB,EACpB,EACA,CACE,cACA,eAAe,EACf,oBAAoB,GACpB,kBAAkB,CAAC,YAAY,CAC/B,qBAAqB,uBAkBtB,CAOD,IAAM,EAAkB,MAAM,EALR,MAAM,QAAQ,EAAQ,CACxC,EACA,CAAC,CAAE,OAAQ,EAAS,eAAgB,GAAI,iBAAkB,GAAI,CAAC,CAKjE,KAAO,KACL,EAAO,KACL,EAAO,QAAQ,+CAA+C,EAAO,mBAAmB,CACzF,CAOM,MADsB,EAHd,EAA4B,EAAc,EAAO,OAGT,CAAE,CAAE,SAAQ,CAAC,EAGtE,CAAE,YAAa,EAAG,CACnB,CAGK,EAA4B,EAAE,CAuCpC,OAtCA,EAAgB,QAAS,GAAmB,CAE1C,IAAM,EAEJ,EAAe,WAAW,WAE1B,EAAe,UAAU,MAAM,IAAI,CAAC,SAAS,CAAC,GAG3C,EAAW,KACd,EAAW,GAAgB,EAAE,EAI/B,IAAM,EAAQ,EACZ,EAAe,cAAc,QAC1B,OAEE,GAAW,CAAC,GAAqB,CAAC,EAAiB,KAAK,EAAO,CACjE,CACA,IAAK,GAAW,EAAa,EAAO,CAAC,CAExC,EACD,CAED,EAAW,GAAgB,CAAC,GAAG,IAAI,IAAI,CAAC,GAAI,EAAW,IAAiB,EAAE,CAAG,GAAG,EAAM,CAAC,CAAC,EACxF,CAYK,CACL,KAAM;;;OAPH,EAAY;oBACC,KAAK,UAAU,EAAY,KAAM,EAAE,CAAC;qBACnC,EAAmB;;EAMpC,aACD"}